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