| // 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 |
| |
| |
| |
| |