Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 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 "base/logging.h" |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 9 | #include "base/scoped_ptr.h" |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 10 | |
| 11 | #include "main.h" |
| 12 | #include "testbase.h" |
| 13 | #include "utils.h" |
| 14 | #include "yuv2rgb.h" |
| 15 | |
| 16 | namespace glbench { |
| 17 | |
| 18 | class YuvToRgbTest : public DrawArraysTestFunc { |
| 19 | public: |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 20 | YuvToRgbTest() { |
| 21 | memset(textures_, 0, sizeof(textures_)); |
| 22 | } |
| 23 | virtual ~YuvToRgbTest() { |
| 24 | glDeleteTextures(arraysize(textures_), textures_); |
| 25 | } |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 26 | virtual bool Run(); |
Alexey Marinichev | f50ecb1 | 2010-06-14 15:21:41 -0700 | [diff] [blame^] | 27 | virtual const char* Name() const { return "yuv_to_rgb"; } |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 28 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 29 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 36 | private: |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 37 | GLuint textures_[6]; |
| 38 | YuvTestFlavor flavor_; |
| 39 | GLuint YuvToRgbShaderProgram(GLuint vertex_buffer, int width, int height); |
| 40 | bool SetupTextures(); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 41 | DISALLOW_COPY_AND_ASSIGN(YuvToRgbTest); |
| 42 | }; |
| 43 | |
| 44 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 45 | GLuint 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 69 | 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 Marinichev | 219b708 | 2010-05-24 16:18:51 -0700 | [diff] [blame] | 81 | #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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 88 | |
| 89 | int imageWidthUniform = glGetUniformLocation(program, "imageWidth"); |
| 90 | int imageHeightUniform = glGetUniformLocation(program, "imageHeight"); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 91 | |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 92 | int textureSampler = glGetUniformLocation(program, "textureSampler"); |
| 93 | int evenLinesSampler = glGetUniformLocation(program, "paritySampler"); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 94 | int ySampler = glGetUniformLocation(program, "ySampler"); |
| 95 | int uSampler = glGetUniformLocation(program, "uSampler"); |
| 96 | int vSampler = glGetUniformLocation(program, "vSampler"); |
| 97 | int uvSampler = glGetUniformLocation(program, "uvSampler"); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 98 | |
| 99 | glUniform1f(imageWidthUniform, width); |
| 100 | glUniform1f(imageHeightUniform, height); |
| 101 | glUniform1i(textureSampler, 0); |
| 102 | glUniform1i(evenLinesSampler, 1); |
| 103 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 104 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 123 | 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 | |
| 131 | done: |
| 132 | munmap(yuv_to_rgb_fragment, size_fragment); |
| 133 | munmap(yuv_to_rgb_fragment, size_vertex); |
| 134 | return program; |
| 135 | } |
| 136 | |
| 137 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 138 | bool YuvToRgbTest::SetupTextures() { |
| 139 | bool ret = false; |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 140 | size_t size = 0; |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 141 | char evenodd[2] = {0, 255}; |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 142 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 147 | 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 Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 157 | glGenTextures(arraysize(textures_), textures_); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 158 | glActiveTexture(GL_TEXTURE0); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 159 | glBindTexture(GL_TEXTURE_2D, textures_[0]); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 160 | 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 Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 164 | glBindTexture(GL_TEXTURE_2D, textures_[1]); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 165 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, |
| 166 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd); |
| 167 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 168 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 173 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 174 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 179 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 180 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 199 | } |
| 200 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 201 | 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 209 | done: |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 210 | munmap(pixels, size); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 211 | return ret; |
| 212 | } |
| 213 | |
| 214 | |
| 215 | bool 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 Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 256 | |
| 257 | return true; |
| 258 | } |
| 259 | |
| 260 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 261 | TestBase* GetYuvToRgbTest() { |
| 262 | return new YuvToRgbTest(); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | } // namespace glbench |