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