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.
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
20namespace gpu {
21
22class 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
55TEST_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
92static 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
127static 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
144TEST_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