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/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "gpu/command_buffer/tests/gl_manager.h"
16 #include "gpu/command_buffer/tests/gl_test_utils.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
22 class GLReadbackTest
: public testing::Test
{
24 void SetUp() override
{ gl_
.Initialize(GLManager::Options()); }
26 void TearDown() override
{ gl_
.Destroy(); }
28 static void WaitForQueryCallback(int q
, base::Closure cb
) {
29 unsigned int done
= 0;
30 glGetQueryObjectuivEXT(q
, GL_QUERY_RESULT_AVAILABLE_EXT
, &done
);
34 base::MessageLoop::current()->PostDelayedTask(
36 base::Bind(&WaitForQueryCallback
, q
, cb
),
37 base::TimeDelta::FromMilliseconds(3));
41 void WaitForQuery(int q
) {
42 base::RunLoop run_loop
;
43 WaitForQueryCallback(q
, run_loop
.QuitClosure());
51 TEST_F(GLReadbackTest
, ReadPixelsWithPBOAndQuery
) {
52 const GLint kBytesPerPixel
= 4;
53 const GLint kWidth
= 2;
54 const GLint kHeight
= 2;
57 glClearColor(0.0, 0.0, 1.0, 1.0);
58 glClear(GL_COLOR_BUFFER_BIT
);
60 glGenQueriesEXT(1, &q
);
61 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, b
);
62 glBufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
63 kWidth
* kHeight
* kBytesPerPixel
,
66 glBeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
, q
);
67 glReadPixels(0, 0, kWidth
, kHeight
, GL_RGBA
, GL_UNSIGNED_BYTE
, 0);
68 glEndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM
);
72 // TODO(hubbe): Check that glMapBufferCHROMIUM does not block here.
73 unsigned char *data
= static_cast<unsigned char *>(
75 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
,
78 EXPECT_EQ(data
[0], 0); // red
79 EXPECT_EQ(data
[1], 0); // green
80 EXPECT_EQ(data
[2], 255); // blue
81 glUnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
);
82 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM
, 0);
83 glDeleteBuffers(1, &b
);
84 glDeleteQueriesEXT(1, &q
);
85 GLTestHelper::CheckGLError("no errors", __LINE__
);
88 static float HalfToFloat32(uint16 value
) {
89 int32 s
= (value
>> 15) & 0x00000001;
90 int32 e
= (value
>> 10) & 0x0000001f;
91 int32 m
= value
& 0x000003ff;
95 uint32 result
= s
<< 31;
96 return bit_cast
<float>(result
);
98 while (!(m
& 0x00000400)) {
106 } else if (e
== 31) {
108 uint32 result
= (s
<< 31) | 0x7f800000;
109 return bit_cast
<float>(result
);
111 uint32 result
= (s
<< 31) | 0x7f800000 | (m
<< 13);
112 return bit_cast
<float>(result
);
119 uint32 result
= (s
<< 31) | (e
<< 23) | m
;
120 return bit_cast
<float>(result
);
123 static GLuint
CompileShader(GLenum type
, const char *data
) {
124 const char *shaderStrings
[1] = { data
};
126 GLuint shader
= glCreateShader(type
);
127 glShaderSource(shader
, 1, shaderStrings
, NULL
);
128 glCompileShader(shader
);
130 GLint compile_status
= 0;
131 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
132 if (compile_status
!= GL_TRUE
) {
133 glDeleteShader(shader
);
140 TEST_F(GLReadbackTest
, ReadPixelsFloat
) {
141 const GLsizei kTextureSize
= 4;
142 const GLfloat kDrawColor
[4] = { -10.9f
, 0.5f
, 10.5f
, 100.12f
};
143 const GLfloat kEpsilon
= 0.01f
;
150 TestFormat test_formats
[4];
151 size_t test_count
= 0;
152 const char *extensions
= reinterpret_cast<const char*>(
153 glGetString(GL_EXTENSIONS
));
154 if (strstr(extensions
, "GL_OES_texture_half_float") != NULL
) {
155 TestFormat rgb16f
= { GL_RGB
, GL_HALF_FLOAT_OES
, 3 };
156 test_formats
[test_count
++] = rgb16f
;
158 TestFormat rgba16f
= { GL_RGBA
, GL_HALF_FLOAT_OES
, 4 };
159 test_formats
[test_count
++] = rgba16f
;
161 if (strstr(extensions
, "GL_OES_texture_float") != NULL
) {
162 TestFormat rgb32f
= { GL_RGB
, GL_FLOAT
, 3 };
163 test_formats
[test_count
++] = rgb32f
;
165 TestFormat rgba32f
= { GL_RGBA
, GL_FLOAT
, 4 };
166 test_formats
[test_count
++] = rgba32f
;
169 const char *vs_source
=
170 "precision mediump float;\n"
171 "attribute vec4 a_position;\n"
173 " gl_Position = a_position;\n"
176 GLuint vertex_shader
= CompileShader(GL_VERTEX_SHADER
, vs_source
);
177 ASSERT_NE(vertex_shader
, GLuint(0));
179 const char *fs_source
=
180 "precision mediump float;\n"
181 "uniform vec4 u_color;\n"
183 " gl_FragColor = u_color;\n"
186 GLuint fragment_shader
= CompileShader(GL_FRAGMENT_SHADER
, fs_source
);
187 ASSERT_NE(fragment_shader
, GLuint(0));
189 GLuint program
= glCreateProgram();
190 glAttachShader(program
, vertex_shader
);
191 glDeleteShader(vertex_shader
);
192 glAttachShader(program
, fragment_shader
);
193 glDeleteShader(fragment_shader
);
194 glLinkProgram(program
);
196 GLint link_status
= 0;
197 glGetProgramiv(program
, GL_LINK_STATUS
, &link_status
);
198 if (link_status
!= GL_TRUE
) {
199 glDeleteProgram(program
);
202 ASSERT_NE(program
, GLuint(0));
204 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
206 float quad_vertices
[] = {
213 GLuint vertex_buffer
;
214 glGenBuffers(1, &vertex_buffer
);
215 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buffer
);
217 GL_ARRAY_BUFFER
, sizeof(quad_vertices
),
218 reinterpret_cast<void*>(quad_vertices
), GL_STATIC_DRAW
);
220 GLint position_location
= glGetAttribLocation(program
, "a_position");
221 glVertexAttribPointer(
222 position_location
, 2, GL_FLOAT
, GL_FALSE
, 2 * sizeof(float), NULL
);
223 glEnableVertexAttribArray(position_location
);
225 glUseProgram(program
);
226 glUniform4fv(glGetUniformLocation(program
, "u_color"), 1, kDrawColor
);
228 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
230 for (size_t ii
= 0; ii
< test_count
; ++ii
) {
231 GLuint texture_id
= 0;
232 glGenTextures(1, &texture_id
);
233 glBindTexture(GL_TEXTURE_2D
, texture_id
);
235 GL_TEXTURE_2D
, 0, test_formats
[ii
].format
, kTextureSize
, kTextureSize
,
236 0, test_formats
[ii
].format
, test_formats
[ii
].type
, NULL
);
238 GLuint framebuffer
= 0;
239 glGenFramebuffers(1, &framebuffer
);
240 glBindFramebuffer(GL_FRAMEBUFFER
, framebuffer
);
241 glFramebufferTexture2D(
242 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, texture_id
, 0);
244 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
246 // Make sure this floating point framebuffer is supported
247 if (glCheckFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
) {
248 // Check if this implementation supports reading floats back from this
250 GLint read_format
= 0;
251 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT
, &read_format
);
253 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE
, &read_type
);
255 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
257 if ((read_format
== GL_RGB
|| read_format
== GL_RGBA
) &&
258 read_type
== test_formats
[ii
].type
) {
259 glClear(GL_COLOR_BUFFER_BIT
);
260 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
262 uint32 read_comp_count
= 0;
263 switch (read_format
) {
273 case GL_HALF_FLOAT_OES
: {
274 scoped_ptr
<GLushort
[]> buf(
275 new GLushort
[kTextureSize
* kTextureSize
* read_comp_count
]);
277 0, 0, kTextureSize
, kTextureSize
, read_format
, read_type
,
279 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
280 for (uint32 jj
= 0; jj
< kTextureSize
* kTextureSize
; ++jj
) {
281 for (uint32 kk
= 0; kk
< test_formats
[ii
].comp_count
; ++kk
) {
283 std::abs(HalfToFloat32(buf
[jj
* read_comp_count
+ kk
]) -
285 std::abs(kDrawColor
[kk
] * kEpsilon
));
291 scoped_ptr
<GLfloat
[]> buf(
292 new GLfloat
[kTextureSize
* kTextureSize
* read_comp_count
]);
294 0, 0, kTextureSize
, kTextureSize
, read_format
, read_type
,
296 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR
));
297 for (uint32 jj
= 0; jj
< kTextureSize
* kTextureSize
; ++jj
) {
298 for (uint32 kk
= 0; kk
< test_formats
[ii
].comp_count
; ++kk
) {
300 std::abs(buf
[jj
* read_comp_count
+ kk
] - kDrawColor
[kk
]),
301 std::abs(kDrawColor
[kk
] * kEpsilon
));
310 glDeleteFramebuffers(1, &framebuffer
);
311 glDeleteTextures(1, &texture_id
);
314 glDeleteBuffers(1, &vertex_buffer
);
315 glDeleteProgram(program
);