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