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" |
Chris Masone | 28cc025 | 2011-05-13 11:45:07 -0700 | [diff] [blame] | 9 | #include "base/memory/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 | { |
Stuart Abercrombie | b8f4e7a | 2011-09-26 18:07:55 -0700 | [diff] [blame] | 81 | program = InitShaderProgramWithHeader(NULL, yuv_to_rgb_vertex, |
Alexey Marinichev | 219b708 | 2010-05-24 16:18:51 -0700 | [diff] [blame] | 82 | yuv_to_rgb_fragment); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 83 | |
| 84 | int imageWidthUniform = glGetUniformLocation(program, "imageWidth"); |
| 85 | int imageHeightUniform = glGetUniformLocation(program, "imageHeight"); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 86 | |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 87 | int textureSampler = glGetUniformLocation(program, "textureSampler"); |
| 88 | int evenLinesSampler = glGetUniformLocation(program, "paritySampler"); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 89 | int ySampler = glGetUniformLocation(program, "ySampler"); |
| 90 | int uSampler = glGetUniformLocation(program, "uSampler"); |
| 91 | int vSampler = glGetUniformLocation(program, "vSampler"); |
| 92 | int uvSampler = glGetUniformLocation(program, "uvSampler"); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 93 | |
| 94 | glUniform1f(imageWidthUniform, width); |
| 95 | glUniform1f(imageHeightUniform, height); |
| 96 | glUniform1i(textureSampler, 0); |
| 97 | glUniform1i(evenLinesSampler, 1); |
| 98 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 99 | glUniform1i(ySampler, 2); |
| 100 | glUniform1i(uSampler, 3); |
| 101 | glUniform1i(vSampler, 4); |
| 102 | glUniform1i(uvSampler, 5); |
| 103 | |
| 104 | { |
| 105 | // This is used only if USE_UNIFORM_MATRIX is enabled in fragment |
| 106 | // shaders. |
| 107 | float c[] = { |
| 108 | 1.0, 1.0, 1.0, 0.0, |
| 109 | 0.0, -0.344, 1.772, 0.0, |
| 110 | 1.402, -0.714, 0.0, 0.0, |
| 111 | -0.701, 0.529, -0.886, 1.0 |
| 112 | }; |
| 113 | int conversion = glGetUniformLocation(program, "conversion"); |
| 114 | glUniformMatrix4fv(conversion, 1, GL_FALSE, c); |
| 115 | assert(glGetError() == 0); |
| 116 | } |
| 117 | |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 118 | int attribute_index = glGetAttribLocation(program, "c"); |
| 119 | glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); |
| 120 | glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); |
| 121 | glEnableVertexAttribArray(attribute_index); |
| 122 | return program; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | done: |
| 127 | munmap(yuv_to_rgb_fragment, size_fragment); |
| 128 | munmap(yuv_to_rgb_fragment, size_vertex); |
| 129 | return program; |
| 130 | } |
| 131 | |
| 132 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 133 | bool YuvToRgbTest::SetupTextures() { |
| 134 | bool ret = false; |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 135 | size_t size = 0; |
Han Shen | c2e0dc3 | 2012-07-02 16:15:46 -0700 | [diff] [blame] | 136 | char evenodd[2] = {0, static_cast<char>(-1)}; |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 137 | char* pixels = static_cast<char *>(MmapFile(YUV2RGB_NAME, &size)); |
| 138 | const int luma_size = YUV2RGB_WIDTH * YUV2RGB_PIXEL_HEIGHT; |
| 139 | const int chroma_size = YUV2RGB_WIDTH/2 * YUV2RGB_PIXEL_HEIGHT/2; |
| 140 | const char* u_plane = pixels + luma_size; |
| 141 | const char* v_plane = pixels + luma_size + chroma_size; |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 142 | if (!pixels) { |
Ilja H. Friedel | 8faad30 | 2011-04-26 14:40:49 -0700 | [diff] [blame] | 143 | printf("# Error: Could not open image file: %s\n", YUV2RGB_NAME); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 144 | goto done; |
| 145 | } |
| 146 | if (size != YUV2RGB_SIZE) { |
Ilja H. Friedel | 8faad30 | 2011-04-26 14:40:49 -0700 | [diff] [blame] | 147 | printf("# Error: Image file of wrong size, got %d, expected %d\n", |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 148 | static_cast<int>(size), YUV2RGB_SIZE); |
| 149 | goto done; |
| 150 | } |
| 151 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 152 | glGenTextures(arraysize(textures_), textures_); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 153 | glActiveTexture(GL_TEXTURE0); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 154 | glBindTexture(GL_TEXTURE_2D, textures_[0]); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 155 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH, YUV2RGB_HEIGHT, |
| 156 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); |
| 157 | |
| 158 | glActiveTexture(GL_TEXTURE1); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 159 | glBindTexture(GL_TEXTURE_2D, textures_[1]); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 160 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, |
| 161 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd); |
| 162 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 163 | glActiveTexture(GL_TEXTURE2); |
| 164 | glBindTexture(GL_TEXTURE_2D, textures_[2]); |
| 165 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, |
| 166 | YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT, |
| 167 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 168 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 169 | glActiveTexture(GL_TEXTURE3); |
| 170 | glBindTexture(GL_TEXTURE_2D, textures_[3]); |
| 171 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, |
| 172 | YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, |
| 173 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u_plane); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 174 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 175 | glActiveTexture(GL_TEXTURE4); |
| 176 | glBindTexture(GL_TEXTURE_2D, textures_[4]); |
| 177 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, |
| 178 | YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, |
| 179 | 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v_plane); |
| 180 | |
| 181 | { |
| 182 | scoped_array<char> buf_uv(new char[chroma_size * 2]); |
| 183 | char* buf_uv_ptr = buf_uv.get(); |
| 184 | for (int i = 0; i < chroma_size; i++) { |
| 185 | *buf_uv_ptr++ = u_plane[i]; |
| 186 | *buf_uv_ptr++ = v_plane[i]; |
| 187 | } |
| 188 | |
| 189 | glActiveTexture(GL_TEXTURE5); |
| 190 | glBindTexture(GL_TEXTURE_2D, textures_[5]); |
| 191 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, |
| 192 | YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, |
| 193 | 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf_uv.get()); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 194 | } |
| 195 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 196 | for (unsigned int i = 0; i < arraysize(textures_); i++) { |
| 197 | glActiveTexture(GL_TEXTURE0 + i); |
| 198 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 199 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
Allen Martin | 140559c | 2011-08-12 14:53:38 -0700 | [diff] [blame] | 200 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 201 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | ret = true; |
| 205 | |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 206 | done: |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 207 | munmap(pixels, size); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 208 | return ret; |
| 209 | } |
| 210 | |
| 211 | |
| 212 | bool YuvToRgbTest::Run() { |
Stuart Abercrombie | d5dfe5f | 2012-08-15 18:42:52 -0700 | [diff] [blame] | 213 | glClearColor(0.f, 1.f, 0.f, 1.f); |
| 214 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 215 | GLuint program = 0; |
| 216 | GLuint vertex_buffer = 0; |
| 217 | GLfloat vertices[8] = { |
| 218 | 0.f, 0.f, |
| 219 | 1.f, 0.f, |
| 220 | 0.f, 1.f, |
| 221 | 1.f, 1.f, |
| 222 | }; |
| 223 | vertex_buffer = SetupVBO(GL_ARRAY_BUFFER, sizeof(vertices), vertices); |
| 224 | |
| 225 | if (!SetupTextures()) |
| 226 | return false; |
| 227 | |
Ilja Friedel | c04bdd4 | 2013-01-30 18:55:49 -0800 | [diff] [blame^] | 228 | glViewport(0, 0, YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 229 | |
| 230 | YuvTestFlavor flavors[] = { |
| 231 | YUV_PLANAR_ONE_TEXTURE_SLOW, YUV_PLANAR_ONE_TEXTURE_FASTER, |
| 232 | YUV_PLANAR_THREE_TEXTURES, YUV_SEMIPLANAR_TWO_TEXTURES |
| 233 | }; |
| 234 | const char* flavor_names[] = { |
| 235 | "yuv_shader_1", "yuv_shader_2", "yuv_shader_3", "yuv_shader_4" |
| 236 | }; |
| 237 | for (unsigned int f = 0; f < arraysize(flavors); f++) { |
| 238 | flavor_ = flavors[f]; |
| 239 | |
| 240 | program = YuvToRgbShaderProgram(vertex_buffer, |
| 241 | YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT); |
| 242 | if (program) { |
| 243 | FillRateTestNormalSubWindow(flavor_names[f], |
| 244 | std::min(YUV2RGB_WIDTH, g_width), |
| 245 | std::min(YUV2RGB_PIXEL_HEIGHT, g_height)); |
| 246 | } else { |
Ilja H. Friedel | 8faad30 | 2011-04-26 14:40:49 -0700 | [diff] [blame] | 247 | printf("# Error: Could not set up YUV shader.\n"); |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | glDeleteProgram(program); |
| 251 | } |
| 252 | |
| 253 | glDeleteBuffers(1, &vertex_buffer); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 254 | |
| 255 | return true; |
| 256 | } |
| 257 | |
| 258 | |
Alexey Marinichev | be37f88 | 2010-06-07 20:35:07 -0700 | [diff] [blame] | 259 | TestBase* GetYuvToRgbTest() { |
| 260 | return new YuvToRgbTest(); |
Alexey Marinichev | 9f9b873 | 2010-05-20 19:33:44 -0700 | [diff] [blame] | 261 | } |
| 262 | |
| 263 | } // namespace glbench |