1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include <GLES2/gl2ext.h>
7 #include <GLES2/gl2extchromium.h>
11 #include "base/basictypes.h"
12 #include "base/bind.h"
13 #include "base/location.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "gpu/command_buffer/tests/gl_manager.h"
18 #include "gpu/command_buffer/tests/gl_test_utils.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
24 class GLReadbackTest
: public testing::Test
{
26 void SetUp() override
{ gl_
.Initialize(GLManager::Options()); }
28 void TearDown() override
{ gl_
.Destroy(); }
30 static void WaitForQueryCallback(int q
, base::Closure cb
) {
31 unsigned int done
= 0;
32 glGetQueryObjectuivEXT(q
, GL_QUERY_RESULT_AVAILABLE_EXT
, &done
);
36 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
37 FROM_HERE
, base::Bind(&WaitForQueryCallback
, q
, cb
),
38 base::TimeDelta::FromMilliseconds(3));
42 void WaitForQuery(int q
) {
43 base::RunLoop run_loop
;
44 WaitForQueryCallback(q
, run_loop
.QuitClosure());
52 TEST_F(GLReadbackTest
, ReadPixelsWithPBOAndQuery
) {
53 const GLint kBytesPerPixel
= 4;
54 const GLint kWidth
= 2;
55 const GLint kHeight
= 2;
58 glClearColor(0.0, 0.0, 1.0, 1.0);
59 glClear(GL_COLOR_BUFFER_BIT
);
61 glGenQueriesEXT(1, &q
);
62 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, b
);
63 glBufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
64 kWidth
* kHeight
* kBytesPerPixel
,
67 glBeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, q
);
68 glReadPixels(0, 0, kWidth
, kHeight
, GL_RGBA
, GL_UNSIGNED_BYTE
, 0);
69 glEndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
73 // TODO(hubbe): Check that glMapBufferCHROMIUM does not block here.
74 unsigned char *data
= static_cast<unsigned char *>(
76 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
79 EXPECT_EQ(data
[0], 0); // red
80 EXPECT_EQ(data
[1], 0); // green
81 EXPECT_EQ(data
[2], 255); // blue
82 glUnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
);
83 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
84 glDeleteBuffers(1, &b
);
85 glDeleteQueriesEXT(1, &q
);
86 GLTestHelper::CheckGLError("no errors", __LINE__
);
89 static float HalfToFloat32(uint16 value
) {
90 int32 s
= (value
>> 15) & 0x00000001;
91 int32 e
= (value
>> 10) & 0x0000001f;
92 int32 m
= value
& 0x000003ff;
96 uint32 result
= s
<< 31;
97 return bit_cast
<float>(result
);
99 while (!(m
& 0x00000400)) {
107 } else if (e
== 31) {
109 uint32 result
= (s
<< 31) | 0x7f800000;
110 return bit_cast
<float>(result
);
112 uint32 result
= (s
<< 31) | 0x7f800000 | (m
<< 13);
113 return bit_cast
<float>(result
);
120 uint32 result
= (s
<< 31) | (e
<< 23) | m
;
121 return bit_cast
<float>(result
);
124 static GLuint
CompileShader(GLenum type
, const char *data
) {
125 const char *shaderStrings
[1] = { data
};
127 GLuint shader
= glCreateShader(type
);
128 glShaderSource(shader
, 1, shaderStrings
, NULL
);
129 glCompileShader(shader
);
131 GLint compile_status
= 0;
132 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
133 if (compile_status
!= GL_TRUE
) {
134 glDeleteShader(shader
);
141 TEST_F(GLReadbackTest
, ReadPixelsFloat
) {
142 const GLsizei kTextureSize
= 4;
143 const GLfloat kDrawColor
[4] = { -10.9f
, 0.5f
, 10.5f
, 100.12f
};
144 const GLfloat kEpsilon
= 0.01f
;
151 TestFormat test_formats
[4];
152 size_t test_count
= 0;
153 const char *extensions
= reinterpret_cast<const char*>(
154 glGetString(GL_EXTENSIONS
));
155 if (strstr(extensions
, "GL_OES_texture_half_float") != NULL
) {
156 TestFormat rgb16f
= { GL_RGB
, GL_HALF_FLOAT_OES
, 3 };
157 test_formats
[test_count
++] = rgb16f
;
159 TestFormat rgba16f
= { GL_RGBA
, GL_HALF_FLOAT_OES
, 4 };
160 test_formats
[test_count
++] = rgba16f
;
162 if (strstr(extensions
, "GL_OES_texture_float") != NULL
) {
163 TestFormat rgb32f
= { GL_RGB
, GL_FLOAT
, 3 };
164 test_formats
[test_count
++] = rgb32f
;
166 TestFormat rgba32f
= { GL_RGBA
, GL_FLOAT
, 4 };
167 test_formats
[test_count
++] = rgba32f
;
170 const char *vs_source
=
171 "precision mediump float;\n"
172 "attribute vec4 a_position;\n"
174 " gl_Position = a_position;\n"
177 GLuint vertex_shader
= CompileShader(GL_VERTEX_SHADER
, vs_source
);
178 ASSERT_NE(vertex_shader
, GLuint(0));
180 const char *fs_source
=
181 "precision mediump float;\n"
182 "uniform vec4 u_color;\n"
184 " gl_FragColor = u_color;\n"
187 GLuint fragment_shader
= CompileShader(GL_FRAGMENT_SHADER
, fs_source
);
188 ASSERT_NE(fragment_shader
, GLuint(0));
190 GLuint program
= glCreateProgram();
191 glAttachShader(program
, vertex_shader
);
192 glDeleteShader(vertex_shader
);
193 glAttachShader(program
, fragment_shader
);
194 glDeleteShader(fragment_shader
);
195 glLinkProgram(program
);
197 GLint link_status
= 0;
198 glGetProgramiv(program
, GL_LINK_STATUS
, &link_status
);
199 if (link_status
!= GL_TRUE
) {
200 glDeleteProgram(program
);
203 ASSERT_NE(program
, GLuint(0));
205 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
207 float quad_vertices
[] = {
214 GLuint vertex_buffer
;
215 glGenBuffers(1, &vertex_buffer
);
216 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buffer
);
218 GL_ARRAY_BUFFER
, sizeof(quad_vertices
),
219 reinterpret_cast<void*>(quad_vertices
), GL_STATIC_DRAW
);
221 GLint position_location
= glGetAttribLocation(program
, "a_position");
222 glVertexAttribPointer(
223 position_location
, 2, GL_FLOAT
, GL_FALSE
, 2 * sizeof(float), NULL
);
224 glEnableVertexAttribArray(position_location
);
226 glUseProgram(program
);
227 glUniform4fv(glGetUniformLocation(program
, "u_color"), 1, kDrawColor
);
229 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
231 for (size_t ii
= 0; ii
< test_count
; ++ii
) {
232 GLuint texture_id
= 0;
233 glGenTextures(1, &texture_id
);
234 glBindTexture(GL_TEXTURE_2D
, texture_id
);
236 GL_TEXTURE_2D
, 0, test_formats
[ii
].format
, kTextureSize
, kTextureSize
,
237 0, test_formats
[ii
].format
, test_formats
[ii
].type
, NULL
);
239 GLuint framebuffer
= 0;
240 glGenFramebuffers(1, &framebuffer
);
241 glBindFramebuffer(GL_FRAMEBUFFER
, framebuffer
);
242 glFramebufferTexture2D(
243 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture_id
, 0);
245 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
247 // Make sure this floating point framebuffer is supported
248 if (glCheckFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
) {
249 // Check if this implementation supports reading floats back from this
251 GLint read_format
= 0;
252 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT
, &read_format
);
254 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE
, &read_type
);
256 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
258 if ((read_format
== GL_RGB
|| read_format
== GL_RGBA
) &&
259 read_type
== test_formats
[ii
].type
) {
260 glClear(GL_COLOR_BUFFER_BIT
);
261 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
263 uint32 read_comp_count
= 0;
264 switch (read_format
) {
274 case GL_HALF_FLOAT_OES
: {
275 scoped_ptr
<GLushort
[]> buf(
276 new GLushort
[kTextureSize
* kTextureSize
* read_comp_count
]);
278 0, 0, kTextureSize
, kTextureSize
, read_format
, read_type
,
280 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
281 for (uint32 jj
= 0; jj
< kTextureSize
* kTextureSize
; ++jj
) {
282 for (uint32 kk
= 0; kk
< test_formats
[ii
].comp_count
; ++kk
) {
284 std::abs(HalfToFloat32(buf
[jj
* read_comp_count
+ kk
]) -
286 std::abs(kDrawColor
[kk
] * kEpsilon
));
292 scoped_ptr
<GLfloat
[]> buf(
293 new GLfloat
[kTextureSize
* kTextureSize
* read_comp_count
]);
295 0, 0, kTextureSize
, kTextureSize
, read_format
, read_type
,
297 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
298 for (uint32 jj
= 0; jj
< kTextureSize
* kTextureSize
; ++jj
) {
299 for (uint32 kk
= 0; kk
< test_formats
[ii
].comp_count
; ++kk
) {
301 std::abs(buf
[jj
* read_comp_count
+ kk
] - kDrawColor
[kk
]),
302 std::abs(kDrawColor
[kk
] * kEpsilon
));
311 glDeleteFramebuffers(1, &framebuffer
);
312 glDeleteTextures(1, &texture_id
);
315 glDeleteBuffers(1, &vertex_buffer
);
316 glDeleteProgram(program
);