• 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 <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:
YuvToRgbTest()22   YuvToRgbTest() { memset(textures_, 0, sizeof(textures_)); }
~YuvToRgbTest()23   virtual ~YuvToRgbTest() { glDeleteTextures(arraysize(textures_), textures_); }
24   virtual bool Run();
Name() const25   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 
YuvToRgbShaderProgram(GLuint vertex_buffer,int width,int height)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 
SetupTextures()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 
Run()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 
GetYuvToRgbTest()247 TestBase* GetYuvToRgbTest() {
248   return new YuvToRgbTest();
249 }
250 
251 }  // namespace glbench
252