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