OLD | NEW |
| (Empty) |
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: | |
24 virtual void SetUp() { | |
25 gl_.Initialize(GLManager::Options()); | |
26 } | |
27 | |
28 virtual void TearDown() { | |
29 gl_.Destroy(); | |
30 } | |
31 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
OLD | NEW |