• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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