blob: 34e1827468b677b0c04d397a2f89d45e08a9b043 [file] [log] [blame]
Alexey Marinichev9f9b8732010-05-20 19:33:44 -07001// 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"
Alexey Marinichevbe37f882010-06-07 20:35:07 -07009#include "base/scoped_ptr.h"
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070010
11#include "main.h"
12#include "testbase.h"
13#include "utils.h"
14#include "yuv2rgb.h"
15
16namespace glbench {
17
18class YuvToRgbTest : public DrawArraysTestFunc {
19 public:
Alexey Marinichevbe37f882010-06-07 20:35:07 -070020 YuvToRgbTest() {
21 memset(textures_, 0, sizeof(textures_));
22 }
23 virtual ~YuvToRgbTest() {
24 glDeleteTextures(arraysize(textures_), textures_);
25 }
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070026 virtual bool Run();
Alexey Marinichevf50ecb12010-06-14 15:21:41 -070027 virtual const char* Name() const { return "yuv_to_rgb"; }
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070028
Alexey Marinichevbe37f882010-06-07 20:35:07 -070029 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
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070036 private:
Alexey Marinichevbe37f882010-06-07 20:35:07 -070037 GLuint textures_[6];
38 YuvTestFlavor flavor_;
39 GLuint YuvToRgbShaderProgram(GLuint vertex_buffer, int width, int height);
40 bool SetupTextures();
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070041 DISALLOW_COPY_AND_ASSIGN(YuvToRgbTest);
42};
43
44
Alexey Marinichevbe37f882010-06-07 20:35:07 -070045GLuint 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
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070069 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 {
Alexey Marinichev219b7082010-05-24 16:18:51 -070081#if defined(I915_WORKAROUND)
82 const char* header = "#define I915_WORKAROUND 1\n";
83#else
84 const char* header = NULL;
85#endif
86 program = InitShaderProgramWithHeader(header, yuv_to_rgb_vertex,
87 yuv_to_rgb_fragment);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070088
89 int imageWidthUniform = glGetUniformLocation(program, "imageWidth");
90 int imageHeightUniform = glGetUniformLocation(program, "imageHeight");
Alexey Marinichevbe37f882010-06-07 20:35:07 -070091
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070092 int textureSampler = glGetUniformLocation(program, "textureSampler");
93 int evenLinesSampler = glGetUniformLocation(program, "paritySampler");
Alexey Marinichevbe37f882010-06-07 20:35:07 -070094 int ySampler = glGetUniformLocation(program, "ySampler");
95 int uSampler = glGetUniformLocation(program, "uSampler");
96 int vSampler = glGetUniformLocation(program, "vSampler");
97 int uvSampler = glGetUniformLocation(program, "uvSampler");
Alexey Marinichev9f9b8732010-05-20 19:33:44 -070098
99 glUniform1f(imageWidthUniform, width);
100 glUniform1f(imageHeightUniform, height);
101 glUniform1i(textureSampler, 0);
102 glUniform1i(evenLinesSampler, 1);
103
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700104 glUniform1i(ySampler, 2);
105 glUniform1i(uSampler, 3);
106 glUniform1i(vSampler, 4);
107 glUniform1i(uvSampler, 5);
108
109 {
110 // This is used only if USE_UNIFORM_MATRIX is enabled in fragment
111 // shaders.
112 float c[] = {
113 1.0, 1.0, 1.0, 0.0,
114 0.0, -0.344, 1.772, 0.0,
115 1.402, -0.714, 0.0, 0.0,
116 -0.701, 0.529, -0.886, 1.0
117 };
118 int conversion = glGetUniformLocation(program, "conversion");
119 glUniformMatrix4fv(conversion, 1, GL_FALSE, c);
120 assert(glGetError() == 0);
121 }
122
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700123 int attribute_index = glGetAttribLocation(program, "c");
124 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
125 glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL);
126 glEnableVertexAttribArray(attribute_index);
127 return program;
128 }
129
130
131done:
132 munmap(yuv_to_rgb_fragment, size_fragment);
133 munmap(yuv_to_rgb_fragment, size_vertex);
134 return program;
135}
136
137
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700138bool YuvToRgbTest::SetupTextures() {
139 bool ret = false;
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700140 size_t size = 0;
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700141 char evenodd[2] = {0, 255};
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700142 char* pixels = static_cast<char *>(MmapFile(YUV2RGB_NAME, &size));
143 const int luma_size = YUV2RGB_WIDTH * YUV2RGB_PIXEL_HEIGHT;
144 const int chroma_size = YUV2RGB_WIDTH/2 * YUV2RGB_PIXEL_HEIGHT/2;
145 const char* u_plane = pixels + luma_size;
146 const char* v_plane = pixels + luma_size + chroma_size;
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700147 if (!pixels) {
148 printf("# Could not open image file: %s\n", YUV2RGB_NAME);
149 goto done;
150 }
151 if (size != YUV2RGB_SIZE) {
152 printf("# Image file of wrong size, got %d, expected %d\n",
153 static_cast<int>(size), YUV2RGB_SIZE);
154 goto done;
155 }
156
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700157 glGenTextures(arraysize(textures_), textures_);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700158 glActiveTexture(GL_TEXTURE0);
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700159 glBindTexture(GL_TEXTURE_2D, textures_[0]);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700160 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH, YUV2RGB_HEIGHT,
161 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
162
163 glActiveTexture(GL_TEXTURE1);
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700164 glBindTexture(GL_TEXTURE_2D, textures_[1]);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700165 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1,
166 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd);
167
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700168 glActiveTexture(GL_TEXTURE2);
169 glBindTexture(GL_TEXTURE_2D, textures_[2]);
170 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
171 YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT,
172 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700173
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700174 glActiveTexture(GL_TEXTURE3);
175 glBindTexture(GL_TEXTURE_2D, textures_[3]);
176 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
177 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2,
178 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u_plane);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700179
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700180 glActiveTexture(GL_TEXTURE4);
181 glBindTexture(GL_TEXTURE_2D, textures_[4]);
182 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
183 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2,
184 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v_plane);
185
186 {
187 scoped_array<char> buf_uv(new char[chroma_size * 2]);
188 char* buf_uv_ptr = buf_uv.get();
189 for (int i = 0; i < chroma_size; i++) {
190 *buf_uv_ptr++ = u_plane[i];
191 *buf_uv_ptr++ = v_plane[i];
192 }
193
194 glActiveTexture(GL_TEXTURE5);
195 glBindTexture(GL_TEXTURE_2D, textures_[5]);
196 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
197 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2,
198 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf_uv.get());
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700199 }
200
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700201 for (unsigned int i = 0; i < arraysize(textures_); i++) {
202 glActiveTexture(GL_TEXTURE0 + i);
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
204 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
205 }
206
207 ret = true;
208
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700209done:
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700210 munmap(pixels, size);
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700211 return ret;
212}
213
214
215bool YuvToRgbTest::Run() {
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(-YUV2RGB_WIDTH, -YUV2RGB_PIXEL_HEIGHT,
230 YUV2RGB_WIDTH*2, YUV2RGB_PIXEL_HEIGHT * 2);
231
232 YuvTestFlavor flavors[] = {
233 YUV_PLANAR_ONE_TEXTURE_SLOW, YUV_PLANAR_ONE_TEXTURE_FASTER,
234 YUV_PLANAR_THREE_TEXTURES, YUV_SEMIPLANAR_TWO_TEXTURES
235 };
236 const char* flavor_names[] = {
237 "yuv_shader_1", "yuv_shader_2", "yuv_shader_3", "yuv_shader_4"
238 };
239 for (unsigned int f = 0; f < arraysize(flavors); f++) {
240 flavor_ = flavors[f];
241
242 program = YuvToRgbShaderProgram(vertex_buffer,
243 YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT);
244 if (program) {
245 FillRateTestNormalSubWindow(flavor_names[f],
246 std::min(YUV2RGB_WIDTH, g_width),
247 std::min(YUV2RGB_PIXEL_HEIGHT, g_height));
248 } else {
249 printf("# Could not set up YUV shader.\n");
250 }
251
252 glDeleteProgram(program);
253 }
254
255 glDeleteBuffers(1, &vertex_buffer);
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700256
257 return true;
258}
259
260
Alexey Marinichevbe37f882010-06-07 20:35:07 -0700261TestBase* GetYuvToRgbTest() {
262 return new YuvToRgbTest();
Alexey Marinichev9f9b8732010-05-20 19:33:44 -0700263}
264
265} // namespace glbench