Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2010 The Chromium OS 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 <stdio.h>
      6 #include <sys/mman.h>
      7 
      8 #include <assert.h>
      9 #include <string.h>
     10 #include <memory>
     11 
     12 #include "arraysize.h"
     13 #include "main.h"
     14 #include "testbase.h"
     15 #include "utils.h"
     16 #include "yuv2rgb.h"
     17 
     18 namespace glbench {
     19 
     20 class YuvToRgbTest : public DrawArraysTestFunc {
     21  public:
     22   YuvToRgbTest() { memset(textures_, 0, sizeof(textures_)); }
     23   virtual ~YuvToRgbTest() { glDeleteTextures(arraysize(textures_), textures_); }
     24   virtual bool Run();
     25   virtual const char* Name() const { return "yuv_to_rgb"; }
     26 
     27   enum YuvTestFlavor {
     28     YUV_PLANAR_ONE_TEXTURE_SLOW,
     29     YUV_PLANAR_ONE_TEXTURE_FASTER,
     30     YUV_PLANAR_THREE_TEXTURES,
     31     YUV_SEMIPLANAR_TWO_TEXTURES,
     32   };
     33 
     34  private:
     35   GLuint textures_[6];
     36   YuvTestFlavor flavor_;
     37   GLuint YuvToRgbShaderProgram(GLuint vertex_buffer, int width, int height);
     38   bool SetupTextures();
     39   DISALLOW_COPY_AND_ASSIGN(YuvToRgbTest);
     40 };
     41 
     42 GLuint YuvToRgbTest::YuvToRgbShaderProgram(GLuint vertex_buffer,
     43                                            int width,
     44                                            int height) {
     45   const char* vertex = NULL;
     46   const char* fragment = NULL;
     47 
     48   switch (flavor_) {
     49     case YUV_PLANAR_ONE_TEXTURE_SLOW:
     50       vertex = YUV2RGB_VERTEX_1;
     51       fragment = YUV2RGB_FRAGMENT_1;
     52       break;
     53     case YUV_PLANAR_ONE_TEXTURE_FASTER:
     54       vertex = YUV2RGB_VERTEX_2;
     55       fragment = YUV2RGB_FRAGMENT_2;
     56       break;
     57     case YUV_PLANAR_THREE_TEXTURES:
     58       vertex = YUV2RGB_VERTEX_34;
     59       fragment = YUV2RGB_FRAGMENT_3;
     60       break;
     61     case YUV_SEMIPLANAR_TWO_TEXTURES:
     62       vertex = YUV2RGB_VERTEX_34;
     63       fragment = YUV2RGB_FRAGMENT_4;
     64       break;
     65   }
     66 
     67   size_t size_vertex = 0;
     68   size_t size_fragment = 0;
     69   char* yuv_to_rgb_vertex = static_cast<char*>(MmapFile(vertex, &size_vertex));
     70   char* yuv_to_rgb_fragment =
     71       static_cast<char*>(MmapFile(fragment, &size_fragment));
     72   GLuint program = 0;
     73 
     74   if (!yuv_to_rgb_fragment || !yuv_to_rgb_vertex)
     75     goto done;
     76 
     77   {
     78     program = InitShaderProgramWithHeader(NULL, yuv_to_rgb_vertex,
     79                                           yuv_to_rgb_fragment);
     80 
     81     int imageWidthUniform = glGetUniformLocation(program, "imageWidth");
     82     int imageHeightUniform = glGetUniformLocation(program, "imageHeight");
     83 
     84     int textureSampler = glGetUniformLocation(program, "textureSampler");
     85     int evenLinesSampler = glGetUniformLocation(program, "paritySampler");
     86     int ySampler = glGetUniformLocation(program, "ySampler");
     87     int uSampler = glGetUniformLocation(program, "uSampler");
     88     int vSampler = glGetUniformLocation(program, "vSampler");
     89     int uvSampler = glGetUniformLocation(program, "uvSampler");
     90 
     91     glUniform1f(imageWidthUniform, width);
     92     glUniform1f(imageHeightUniform, height);
     93     glUniform1i(textureSampler, 0);
     94     glUniform1i(evenLinesSampler, 1);
     95 
     96     glUniform1i(ySampler, 2);
     97     glUniform1i(uSampler, 3);
     98     glUniform1i(vSampler, 4);
     99     glUniform1i(uvSampler, 5);
    100 
    101     {
    102       // This is used only if USE_UNIFORM_MATRIX is enabled in fragment
    103       // shaders.
    104       float c[] = {1.0,   1.0,    1.0,    0.0,
    105                    0.0,   -0.344, 1.772,  0.0,
    106                    1.402, -0.714, 0.0,    0.0,
    107                    -0.701, 0.529, -0.886, 1.0};
    108       int conversion = glGetUniformLocation(program, "conversion");
    109       glUniformMatrix4fv(conversion, 1, GL_FALSE, c);
    110       assert(glGetError() == 0);
    111     }
    112 
    113     int attribute_index = glGetAttribLocation(program, "c");
    114     glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    115     glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
    116     glEnableVertexAttribArray(attribute_index);
    117     return program;
    118   }
    119 
    120 done:
    121   munmap(yuv_to_rgb_fragment, size_fragment);
    122   munmap(yuv_to_rgb_fragment, size_vertex);
    123   return program;
    124 }
    125 
    126 bool YuvToRgbTest::SetupTextures() {
    127   bool ret = false;
    128   size_t size = 0;
    129   char evenodd[2] = {0, static_cast<char>(-1)};
    130   char* pixels = static_cast<char*>(MmapFile(YUV2RGB_NAME, &size));
    131   const int luma_size = YUV2RGB_WIDTH * YUV2RGB_PIXEL_HEIGHT;
    132   const int chroma_size = YUV2RGB_WIDTH / 2 * YUV2RGB_PIXEL_HEIGHT / 2;
    133   const char* u_plane = pixels + luma_size;
    134   const char* v_plane = pixels + luma_size + chroma_size;
    135   if (!pixels) {
    136     printf("# Error: Could not open image file: %s\n", YUV2RGB_NAME);
    137     goto done;
    138   }
    139   if (size != YUV2RGB_SIZE) {
    140     printf("# Error: Image file of wrong size, got %d, expected %d\n",
    141            static_cast<int>(size), YUV2RGB_SIZE);
    142     goto done;
    143   }
    144 
    145   glGenTextures(arraysize(textures_), textures_);
    146   glActiveTexture(GL_TEXTURE0);
    147   glBindTexture(GL_TEXTURE_2D, textures_[0]);
    148   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH, YUV2RGB_HEIGHT, 0,
    149                GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
    150 
    151   glActiveTexture(GL_TEXTURE1);
    152   glBindTexture(GL_TEXTURE_2D, textures_[1]);
    153   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, 0, GL_LUMINANCE,
    154                GL_UNSIGNED_BYTE, evenodd);
    155 
    156   glActiveTexture(GL_TEXTURE2);
    157   glBindTexture(GL_TEXTURE_2D, textures_[2]);
    158   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH,
    159                YUV2RGB_PIXEL_HEIGHT, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
    160 
    161   glActiveTexture(GL_TEXTURE3);
    162   glBindTexture(GL_TEXTURE_2D, textures_[3]);
    163   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH / 2,
    164                YUV2RGB_PIXEL_HEIGHT / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
    165                u_plane);
    166 
    167   glActiveTexture(GL_TEXTURE4);
    168   glBindTexture(GL_TEXTURE_2D, textures_[4]);
    169   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH / 2,
    170                YUV2RGB_PIXEL_HEIGHT / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
    171                v_plane);
    172 
    173   {
    174     std::unique_ptr<char[]> buf_uv(new char[chroma_size * 2]);
    175     char* buf_uv_ptr = buf_uv.get();
    176     for (int i = 0; i < chroma_size; i++) {
    177       *buf_uv_ptr++ = u_plane[i];
    178       *buf_uv_ptr++ = v_plane[i];
    179     }
    180 
    181     glActiveTexture(GL_TEXTURE5);
    182     glBindTexture(GL_TEXTURE_2D, textures_[5]);
    183     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, YUV2RGB_WIDTH / 2,
    184                  YUV2RGB_PIXEL_HEIGHT / 2, 0, GL_LUMINANCE_ALPHA,
    185                  GL_UNSIGNED_BYTE, buf_uv.get());
    186   }
    187 
    188   for (unsigned int i = 0; i < arraysize(textures_); i++) {
    189     glActiveTexture(GL_TEXTURE0 + i);
    190     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    191     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    192     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    193     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    194   }
    195 
    196   ret = true;
    197 
    198 done:
    199   munmap(pixels, size);
    200   return ret;
    201 }
    202 
    203 bool YuvToRgbTest::Run() {
    204   glClearColor(0.f, 1.f, 0.f, 1.f);
    205 
    206   GLuint program = 0;
    207   GLuint vertex_buffer = 0;
    208   GLfloat vertices[8] = {
    209       0.f, 0.f,
    210       1.f, 0.f,
    211       0.f, 1.f,
    212       1.f, 1.f,
    213   };
    214   vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, sizeof(vertices), vertices);
    215 
    216   if (!SetupTextures())
    217     return false;
    218 
    219   glViewport(0, 0, YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT);
    220 
    221   YuvTestFlavor flavors[] = {
    222       YUV_PLANAR_ONE_TEXTURE_SLOW, YUV_PLANAR_ONE_TEXTURE_FASTER,
    223       YUV_PLANAR_THREE_TEXTURES, YUV_SEMIPLANAR_TWO_TEXTURES};
    224   const char* flavor_names[] = {"yuv_shader_1", "yuv_shader_2", "yuv_shader_3",
    225                                 "yuv_shader_4"};
    226   for (unsigned int f = 0; f < arraysize(flavors); f++) {
    227     flavor_ = flavors[f];
    228 
    229     program = YuvToRgbShaderProgram(vertex_buffer, YUV2RGB_WIDTH,
    230                                     YUV2RGB_PIXEL_HEIGHT);
    231     if (program) {
    232       FillRateTestNormalSubWindow(flavor_names[f],
    233                                   std::min(YUV2RGB_WIDTH, g_width),
    234                                   std::min(YUV2RGB_PIXEL_HEIGHT, g_height));
    235     } else {
    236       printf("# Error: Could not set up YUV shader.\n");
    237     }
    238 
    239     glDeleteProgram(program);
    240   }
    241 
    242   glDeleteBuffers(1, &vertex_buffer);
    243 
    244   return true;
    245 }
    246 
    247 TestBase* GetYuvToRgbTest() {
    248   return new YuvToRgbTest();
    249 }
    250 
    251 }  // namespace glbench
    252