1 // Copyright (c) 2012 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.
4
5 #include <GLES2/gl2.h>
6 #include <GLES2/gl2ext.h>
7 #include <GLES2/gl2extchromium.h>
8
9 #include <cmath>
10
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"
19
20 namespace gpu {
21
22 class GLReadbackTest : public testing::Test {
23 protected:
SetUp()24 virtual void SetUp() {
25 gl_.Initialize(GLManager::Options());
26 }
27
TearDown()28 virtual void TearDown() {
29 gl_.Destroy();
30 }
31
WaitForQueryCallback(int q,base::Closure cb)32 static void WaitForQueryCallback(int q, base::Closure cb) {
33 unsigned int done = 0;
34 glGetQueryObjectuivEXT(q, GL_QUERY_RESULT_AVAILABLE_EXT, &done);
35 if (done) {
36 cb.Run();
37 } else {
38 base::MessageLoop::current()->PostDelayedTask(
39 FROM_HERE,
40 base::Bind(&WaitForQueryCallback, q, cb),
41 base::TimeDelta::FromMilliseconds(3));
42 }
43 }
44
WaitForQuery(int q)45 void WaitForQuery(int q) {
46 base::RunLoop run_loop;
47 WaitForQueryCallback(q, run_loop.QuitClosure());
48 run_loop.Run();
49 }
50
51 GLManager gl_;
52 };
53
54
TEST_F(GLReadbackTest,ReadPixelsWithPBOAndQuery)55 TEST_F(GLReadbackTest, ReadPixelsWithPBOAndQuery) {
56 const GLint kBytesPerPixel = 4;
57 const GLint kWidth = 2;
58 const GLint kHeight = 2;
59
60 GLuint b, q;
61 glClearColor(0.0, 0.0, 1.0, 1.0);
62 glClear(GL_COLOR_BUFFER_BIT);
63 glGenBuffers(1, &b);
64 glGenQueriesEXT(1, &q);
65 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, b);
66 glBufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
67 kWidth * kHeight * kBytesPerPixel,
68 NULL,
69 GL_STREAM_READ);
70 glBeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, q);
71 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 0);
72 glEndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
73 glFlush();
74 WaitForQuery(q);
75
76 // TODO(hubbe): Check that glMapBufferCHROMIUM does not block here.
77 unsigned char *data = static_cast<unsigned char *>(
78 glMapBufferCHROMIUM(
79 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
80 GL_READ_ONLY));
81 EXPECT_TRUE(data);
82 EXPECT_EQ(data[0], 0); // red
83 EXPECT_EQ(data[1], 0); // green
84 EXPECT_EQ(data[2], 255); // blue
85 glUnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
86 glBindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
87 glDeleteBuffers(1, &b);
88 glDeleteQueriesEXT(1, &q);
89 GLTestHelper::CheckGLError("no errors", __LINE__);
90 }
91
HalfToFloat32(uint16 value)92 static float HalfToFloat32(uint16 value) {
93 int32 s = (value >> 15) & 0x00000001;
94 int32 e = (value >> 10) & 0x0000001f;
95 int32 m = value & 0x000003ff;
96
97 if (e == 0) {
98 if (m == 0) {
99 uint32 result = s << 31;
100 return bit_cast<float>(result);
101 } else {
102 while (!(m & 0x00000400)) {
103 m <<= 1;
104 e -= 1;
105 }
106
107 e += 1;
108 m &= ~0x00000400;
109 }
110 } else if (e == 31) {
111 if (m == 0) {
112 uint32 result = (s << 31) | 0x7f800000;
113 return bit_cast<float>(result);
114 } else {
115 uint32 result = (s << 31) | 0x7f800000 | (m << 13);
116 return bit_cast<float>(result);
117 }
118 }
119
120 e = e + (127 - 15);
121 m = m << 13;
122
123 uint32 result = (s << 31) | (e << 23) | m;
124 return bit_cast<float>(result);
125 }
126
CompileShader(GLenum type,const char * data)127 static GLuint CompileShader(GLenum type, const char *data) {
128 const char *shaderStrings[1] = { data };
129
130 GLuint shader = glCreateShader(type);
131 glShaderSource(shader, 1, shaderStrings, NULL);
132 glCompileShader(shader);
133
134 GLint compile_status = 0;
135 glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
136 if (compile_status != GL_TRUE) {
137 glDeleteShader(shader);
138 shader = 0;
139 }
140
141 return shader;
142 }
143
TEST_F(GLReadbackTest,ReadPixelsFloat)144 TEST_F(GLReadbackTest, ReadPixelsFloat) {
145 const GLsizei kTextureSize = 4;
146 const GLfloat kDrawColor[4] = { -10.9f, 0.5f, 10.5f, 100.12f };
147 const GLfloat kEpsilon = 0.01f;
148
149 struct TestFormat {
150 GLint format;
151 GLint type;
152 uint32 comp_count;
153 };
154 TestFormat test_formats[4];
155 size_t test_count = 0;
156 const char *extensions = reinterpret_cast<const char*>(
157 glGetString(GL_EXTENSIONS));
158 if (strstr(extensions, "GL_OES_texture_half_float") != NULL) {
159 TestFormat rgb16f = { GL_RGB, GL_HALF_FLOAT_OES, 3 };
160 test_formats[test_count++] = rgb16f;
161
162 TestFormat rgba16f = { GL_RGBA, GL_HALF_FLOAT_OES, 4 };
163 test_formats[test_count++] = rgba16f;
164 }
165 if (strstr(extensions, "GL_OES_texture_float") != NULL) {
166 TestFormat rgb32f = { GL_RGB, GL_FLOAT, 3 };
167 test_formats[test_count++] = rgb32f;
168
169 TestFormat rgba32f = { GL_RGBA, GL_FLOAT, 4 };
170 test_formats[test_count++] = rgba32f;
171 }
172
173 const char *vs_source =
174 "precision mediump float;\n"
175 "attribute vec4 a_position;\n"
176 "void main() {\n"
177 " gl_Position = a_position;\n"
178 "}\n";
179
180 GLuint vertex_shader = CompileShader(GL_VERTEX_SHADER, vs_source);
181 ASSERT_NE(vertex_shader, GLuint(0));
182
183 const char *fs_source =
184 "precision mediump float;\n"
185 "uniform vec4 u_color;\n"
186 "void main() {\n"
187 " gl_FragColor = u_color;\n"
188 "}\n";
189
190 GLuint fragment_shader = CompileShader(GL_FRAGMENT_SHADER, fs_source);
191 ASSERT_NE(fragment_shader, GLuint(0));
192
193 GLuint program = glCreateProgram();
194 glAttachShader(program, vertex_shader);
195 glDeleteShader(vertex_shader);
196 glAttachShader(program, fragment_shader);
197 glDeleteShader(fragment_shader);
198 glLinkProgram(program);
199
200 GLint link_status = 0;
201 glGetProgramiv(program, GL_LINK_STATUS, &link_status);
202 if (link_status != GL_TRUE) {
203 glDeleteProgram(program);
204 program = 0;
205 }
206 ASSERT_NE(program, GLuint(0));
207
208 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
209
210 float quad_vertices[] = {
211 -1.0, -1.0,
212 1.0, -1.0,
213 1.0, 1.0,
214 -1.0, 1.0
215 };
216
217 GLuint vertex_buffer;
218 glGenBuffers(1, &vertex_buffer);
219 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
220 glBufferData(
221 GL_ARRAY_BUFFER, sizeof(quad_vertices),
222 reinterpret_cast<void*>(quad_vertices), GL_STATIC_DRAW);
223
224 GLint position_location = glGetAttribLocation(program, "a_position");
225 glVertexAttribPointer(
226 position_location, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), NULL);
227 glEnableVertexAttribArray(position_location);
228
229 glUseProgram(program);
230 glUniform4fv(glGetUniformLocation(program, "u_color"), 1, kDrawColor);
231
232 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
233
234 for (size_t ii = 0; ii < test_count; ++ii) {
235 GLuint texture_id = 0;
236 glGenTextures(1, &texture_id);
237 glBindTexture(GL_TEXTURE_2D, texture_id);
238 glTexImage2D(
239 GL_TEXTURE_2D, 0, test_formats[ii].format, kTextureSize, kTextureSize,
240 0, test_formats[ii].format, test_formats[ii].type, NULL);
241
242 GLuint framebuffer = 0;
243 glGenFramebuffers(1, &framebuffer);
244 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
245 glFramebufferTexture2D(
246 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
247
248 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
249
250 // Make sure this floating point framebuffer is supported
251 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
252 // Check if this implementation supports reading floats back from this
253 // framebuffer
254 GLint read_format = 0;
255 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &read_format);
256 GLint read_type = 0;
257 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &read_type);
258
259 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
260
261 if ((read_format == GL_RGB || read_format == GL_RGBA) &&
262 read_type == test_formats[ii].type) {
263 glClear(GL_COLOR_BUFFER_BIT);
264 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
265
266 uint32 read_comp_count = 0;
267 switch (read_format) {
268 case GL_RGB:
269 read_comp_count = 3;
270 break;
271 case GL_RGBA:
272 read_comp_count = 4;
273 break;
274 }
275
276 switch (read_type) {
277 case GL_HALF_FLOAT_OES: {
278 scoped_ptr<GLushort[]> buf(
279 new GLushort[kTextureSize * kTextureSize * read_comp_count]);
280 glReadPixels(
281 0, 0, kTextureSize, kTextureSize, read_format, read_type,
282 buf.get());
283 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
284 for (uint32 jj = 0; jj < kTextureSize * kTextureSize; ++jj) {
285 for (uint32 kk = 0; kk < test_formats[ii].comp_count; ++kk) {
286 EXPECT_LE(
287 std::abs(HalfToFloat32(buf[jj * read_comp_count + kk]) -
288 kDrawColor[kk]),
289 std::abs(kDrawColor[kk] * kEpsilon));
290 }
291 }
292 break;
293 }
294 case GL_FLOAT: {
295 scoped_ptr<GLfloat[]> buf(
296 new GLfloat[kTextureSize * kTextureSize * read_comp_count]);
297 glReadPixels(
298 0, 0, kTextureSize, kTextureSize, read_format, read_type,
299 buf.get());
300 EXPECT_EQ(glGetError(), GLenum(GL_NO_ERROR));
301 for (uint32 jj = 0; jj < kTextureSize * kTextureSize; ++jj) {
302 for (uint32 kk = 0; kk < test_formats[ii].comp_count; ++kk) {
303 EXPECT_LE(
304 std::abs(buf[jj * read_comp_count + kk] - kDrawColor[kk]),
305 std::abs(kDrawColor[kk] * kEpsilon));
306 }
307 }
308 break;
309 }
310 }
311 }
312 }
313
314 glDeleteFramebuffers(1, &framebuffer);
315 glDeleteTextures(1, &texture_id);
316 }
317
318 glDeleteBuffers(1, &vertex_buffer);
319 glDeleteProgram(program);
320 }
321
322 } // namespace gpu
323