blob: d720005799e32797a6602bccae07539fc0cf5327 [file] [log] [blame]
// Copyright (c) 2012 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.
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stddef.h>
#include <stdint.h>
#include "base/stl_util.h"
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#define SHADER(Src) #Src
namespace gpu {
class DepthTextureTest : public testing::Test {
protected:
static const GLsizei kResolution = 64;
void SetUp() override {
GLManager::Options options;
options.size = gfx::Size(kResolution, kResolution);
gl_.Initialize(options);
}
void TearDown() override { gl_.Destroy(); }
GLuint SetupUnitQuad(GLint position_location);
GLManager gl_;
};
GLuint DepthTextureTest::SetupUnitQuad(GLint position_location) {
GLuint vbo = 0;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
static float vertices[] = {
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 0.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(position_location);
glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
return vbo;
}
namespace {
struct FormatType {
GLenum format;
GLenum type;
};
} // anonymous namespace
TEST_F(DepthTextureTest, RenderTo) {
if (!GLTestHelper::HasExtension("GL_CHROMIUM_depth_texture")) {
return;
}
bool have_depth_stencil = GLTestHelper::HasExtension(
"GL_OES_packed_depth_stencil");
static const char* v_shader_str = SHADER(
attribute vec4 v_position;
void main()
{
gl_Position = v_position;
}
);
static const char* f_shader_str = SHADER(
precision mediump float;
uniform sampler2D u_texture;
uniform vec2 u_resolution;
void main()
{
vec2 texcoord = gl_FragCoord.xy / u_resolution;
gl_FragColor = texture2D(u_texture, texcoord);
}
);
GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
GLint position_loc = glGetAttribLocation(program, "v_position");
GLint resolution_loc = glGetUniformLocation(program, "u_resolution");
SetupUnitQuad(position_loc);
// Depth test needs to be on for the depth buffer to be updated.
glEnable(GL_DEPTH_TEST);
// create an fbo
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// create a depth texture.
GLuint color_texture = 0;
GLuint depth_texture = 0;
glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kResolution, kResolution, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
glUseProgram(program);
glUniform2f(resolution_loc, kResolution, kResolution);
static const FormatType format_types[] = {
{ GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
{ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
{ GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES },
};
for (size_t ii = 0; ii < base::size(format_types); ++ii) {
const FormatType& format_type = format_types[ii];
GLenum format = format_type.format;
GLenum type = format_type.type;
if (format == GL_DEPTH_STENCIL_OES && !have_depth_stencil) {
continue;
}
glBindTexture(GL_TEXTURE_2D, depth_texture);
glTexImage2D(GL_TEXTURE_2D, 0, format, kResolution, kResolution, 0, format,
type, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), status)
<< "iteration: " << ii;
if (status != GL_FRAMEBUFFER_COMPLETE) {
continue;
}
if (!GLTestHelper::CheckGLError("no errors after setup", __LINE__)) {
continue;
}
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Disconnect the texture so we'll render with the default texture.
glBindTexture(GL_TEXTURE_2D, 0);
// Render to the fbo.
glDrawArrays(GL_TRIANGLES, 0, 6);
if (!GLTestHelper::CheckGLError("no errors after depth draw", __LINE__)) {
continue;
}
// Render with the depth texture.
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, depth_texture);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 6);
if (!GLTestHelper::CheckGLError("no errors after texture draw", __LINE__)) {
continue;
}
uint8_t actual_pixels[kResolution * kResolution * 4] = {
0,
};
glReadPixels(
0, 0, kResolution, kResolution, GL_RGBA, GL_UNSIGNED_BYTE,
actual_pixels);
if (!GLTestHelper::CheckGLError("no errors after readpixels", __LINE__)) {
continue;
}
// Check that each pixel's red value is less than the previous pixel in
// either direction. Basically verify we have a gradient. No assumption is
// made about the other channels green, blue and alpha since, according to
// the GL_CHROMIUM_depth_texture spec, they have undefined values for
// depth textures.
int bad_count = 0; // used to not spam the log with too many messages.
for (GLint yy = 0; bad_count < 16 && yy < kResolution; ++yy) {
for (GLint xx = 0; bad_count < 16 && xx < kResolution; ++xx) {
const uint8_t* actual = &actual_pixels[(yy * kResolution + xx) * 4];
const uint8_t* left = actual - 4;
const uint8_t* down = actual - kResolution * 4;
// NOTE: Qualcomm on Nexus 4 the right most column has the same
// values as the next to right most column. (bad interpolator?)
if (xx > 0 && xx < kResolution - 1) {
EXPECT_GT(actual[0], left[0])
<< "pixel at " << xx << ", " << yy
<< " actual[0] =" << static_cast<unsigned>(actual[0])
<< " left[0] =" << static_cast<unsigned>(left[0])
<< " actual =" << reinterpret_cast<const void*>(actual)
<< " left =" << reinterpret_cast<const void*>(left);
bad_count += (actual[0] > left[0] ? 0 : 1);
}
if (yy > 0 && yy < kResolution - 1) {
EXPECT_GT(actual[0], down[0]) << "pixel at " << xx << ", " << yy;
bad_count += (actual[0] > down[0] ? 0 : 1);
}
}
}
// Check that bottom left corner is vastly different thatn top right.
EXPECT_GT(
actual_pixels[(kResolution * kResolution - 1) * 4] - actual_pixels[0],
0xC0);
GLTestHelper::CheckGLError("no errors after everything", __LINE__);
}
}
} // namespace gpu