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" 9 #include "base/memory/scoped_ptr.h" 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: 20 YuvToRgbTest() { 21 memset(textures_, 0, sizeof(textures_)); 22 } 23 virtual ~YuvToRgbTest() { 24 glDeleteTextures(arraysize(textures_), textures_); 25 } 26 virtual bool Run(); 27 virtual const char* Name() const { return "yuv_to_rgb"; } 28 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 36 private: 37 GLuint textures_[6]; 38 YuvTestFlavor flavor_; 39 GLuint YuvToRgbShaderProgram(GLuint vertex_buffer, int width, int height); 40 bool SetupTextures(); 41 DISALLOW_COPY_AND_ASSIGN(YuvToRgbTest); 42 }; 43 44 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 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 { 81 program = InitShaderProgramWithHeader(NULL, yuv_to_rgb_vertex, 82 yuv_to_rgb_fragment); 83 84 int imageWidthUniform = glGetUniformLocation(program, "imageWidth"); 85 int imageHeightUniform = glGetUniformLocation(program, "imageHeight"); 86 87 int textureSampler = glGetUniformLocation(program, "textureSampler"); 88 int evenLinesSampler = glGetUniformLocation(program, "paritySampler"); 89 int ySampler = glGetUniformLocation(program, "ySampler"); 90 int uSampler = glGetUniformLocation(program, "uSampler"); 91 int vSampler = glGetUniformLocation(program, "vSampler"); 92 int uvSampler = glGetUniformLocation(program, "uvSampler"); 93 94 glUniform1f(imageWidthUniform, width); 95 glUniform1f(imageHeightUniform, height); 96 glUniform1i(textureSampler, 0); 97 glUniform1i(evenLinesSampler, 1); 98 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 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 133 bool YuvToRgbTest::SetupTextures() { 134 bool ret = false; 135 size_t size = 0; 136 char evenodd[2] = {0, static_cast<char>(-1)}; 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; 142 if (!pixels) { 143 printf("# Error: Could not open image file: %s\n", YUV2RGB_NAME); 144 goto done; 145 } 146 if (size != YUV2RGB_SIZE) { 147 printf("# Error: Image file of wrong size, got %d, expected %d\n", 148 static_cast<int>(size), YUV2RGB_SIZE); 149 goto done; 150 } 151 152 glGenTextures(arraysize(textures_), textures_); 153 glActiveTexture(GL_TEXTURE0); 154 glBindTexture(GL_TEXTURE_2D, textures_[0]); 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); 159 glBindTexture(GL_TEXTURE_2D, textures_[1]); 160 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, 161 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd); 162 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); 168 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); 174 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_ptr<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()); 194 } 195 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); 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); 202 } 203 204 ret = true; 205 206 done: 207 munmap(pixels, size); 208 return ret; 209 } 210 211 212 bool YuvToRgbTest::Run() { 213 glClearColor(0.f, 1.f, 0.f, 1.f); 214 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 228 glViewport(0, 0, YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT); 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 { 247 printf("# Error: Could not set up YUV shader.\n"); 248 } 249 250 glDeleteProgram(program); 251 } 252 253 glDeleteBuffers(1, &vertex_buffer); 254 255 return true; 256 } 257 258 259 TestBase* GetYuvToRgbTest() { 260 return new YuvToRgbTest(); 261 } 262 263 } // namespace glbench 264