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