blob: 6b31c9b4cae1970c6412cb41d0cab1b0c1d34d24 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include <stdint.h>
#include <vector>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "gpu/config/gpu_switches.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_version_info.h"
namespace gpu {
// A collection of tests that exercise the glClear workaround.
class GLClearFramebufferTest : public testing::TestWithParam<bool> {
public:
GLClearFramebufferTest() : color_handle_(0u), depth_handle_(0u) {}
protected:
void SetUp() override {
if (GetParam()) {
// Force the glClear() workaround so we can test it here.
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
base::IntToString(gpu::GL_CLEAR_BROKEN));
gl_.InitializeWithCommandLine(GLManager::Options(), command_line);
DCHECK(gl_.workarounds().gl_clear_broken);
} else {
gl_.Initialize(GLManager::Options());
DCHECK(!gl_.workarounds().gl_clear_broken);
}
}
bool IsApplicable() {
// The workaround doesn't use VAOs which would cause a failure on a core
// context and the hardware for each the workaround is necessary has a buggy
// VAO implementation. So we skip testing the workaround on core profiles.
return !GetParam() ||
!gl_.context()->GetVersionInfo()->is_desktop_core_profile;
}
void InitDraw();
void SetDrawColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
void SetDrawDepth(GLfloat depth);
void DrawQuad();
void TearDown() override {
GLTestHelper::CheckGLError("no errors", __LINE__);
gl_.Destroy();
}
private:
GLManager gl_;
GLuint color_handle_;
GLuint depth_handle_;
};
void GLClearFramebufferTest::InitDraw() {
static const char* v_shader_str =
"attribute vec4 a_Position;\n"
"uniform float u_depth;\n"
"void main()\n"
"{\n"
" gl_Position = a_Position;\n"
" gl_Position.z = u_depth;\n"
"}\n";
static const char* f_shader_str =
"precision mediump float;\n"
"uniform vec4 u_draw_color;\n"
"void main()\n"
"{\n"
" gl_FragColor = u_draw_color;\n"
"}\n";
GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
DCHECK(program);
glUseProgram(program);
GLuint position_loc = glGetAttribLocation(program, "a_Position");
GLTestHelper::SetupUnitQuad(position_loc);
color_handle_ = glGetUniformLocation(program, "u_draw_color");
DCHECK(color_handle_ != static_cast<GLuint>(-1));
depth_handle_ = glGetUniformLocation(program, "u_depth");
DCHECK(depth_handle_ != static_cast<GLuint>(-1));
}
void GLClearFramebufferTest::SetDrawColor(GLfloat r,
GLfloat g,
GLfloat b,
GLfloat a) {
glUniform4f(color_handle_, r, g, b, a);
}
void GLClearFramebufferTest::SetDrawDepth(GLfloat depth) {
glUniform1f(depth_handle_, depth);
}
void GLClearFramebufferTest::DrawQuad() {
glDrawArrays(GL_TRIANGLES, 0, 6);
}
INSTANTIATE_TEST_CASE_P(GLClearFramebufferTestWithParam,
GLClearFramebufferTest,
::testing::Values(true, false));
TEST_P(GLClearFramebufferTest, ClearColor) {
if (!IsApplicable()) {
return;
}
glClearColor(1.0f, 0.5f, 0.25f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
// Verify.
const uint8_t expected[] = {255, 128, 64, 128};
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected));
}
TEST_P(GLClearFramebufferTest, ClearColorWithMask) {
if (!IsApplicable()) {
return;
}
glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Verify.
const uint8_t expected[] = {255, 0, 0, 0};
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
}
// crbug.com/434094
#if !defined(OS_MACOSX)
TEST_P(GLClearFramebufferTest, ClearColorWithScissor) {
if (!IsApplicable()) {
return;
}
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Verify.
const uint8_t expected[] = {255, 255, 255, 255};
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
glScissor(0, 0, 0, 0);
glEnable(GL_SCISSOR_TEST);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
// Verify - no changes.
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
}
#endif
TEST_P(GLClearFramebufferTest, ClearDepthStencil) {
if (!IsApplicable()) {
return;
}
const GLuint kStencilRef = 1 << 2;
InitDraw();
SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
DrawQuad();
// Verify.
const uint8_t kRed[] = {255, 0, 0, 255};
const uint8_t kGreen[] = {0, 255, 0, 255};
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
glClearStencil(kStencilRef);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_NOTEQUAL, kStencilRef, 0xFFFFFFFF);
SetDrawColor(0.0f, 1.0f, 0.0f, 1.0f);
DrawQuad();
// Verify - stencil should have failed, so still red.
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
glStencilFunc(GL_EQUAL, kStencilRef, 0xFFFFFFFF);
DrawQuad();
// Verify - stencil should have passed, so green.
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
glEnable(GL_DEPTH_TEST);
glClearDepthf(0.0f);
glClear(GL_DEPTH_BUFFER_BIT);
SetDrawDepth(0.5f);
SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
DrawQuad();
// Verify - depth test should have failed, so still green.
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
glClearDepthf(0.9f);
glClear(GL_DEPTH_BUFFER_BIT);
DrawQuad();
// Verify - depth test should have passed, so red.
EXPECT_TRUE(
GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
}
} // namespace gpu