Home | History | Annotate | Download | only in tests
      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 
     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
    323