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