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 <memory> 9 10#include "base/logging.h" 11 12#include "main.h" 13#include "testbase.h" 14#include "utils.h" 15#include "yuv2rgb.h" 16 17namespace glbench { 18 19class YuvToRgbTest : public DrawArraysTestFunc { 20 public: 21 YuvToRgbTest() { 22 memset(textures_, 0, sizeof(textures_)); 23 } 24 virtual ~YuvToRgbTest() { 25 glDeleteTextures(arraysize(textures_), textures_); 26 } 27 virtual bool Run(); 28 virtual const char* Name() const { return "yuv_to_rgb"; } 29 30 enum YuvTestFlavor { 31 YUV_PLANAR_ONE_TEXTURE_SLOW, 32 YUV_PLANAR_ONE_TEXTURE_FASTER, 33 YUV_PLANAR_THREE_TEXTURES, 34 YUV_SEMIPLANAR_TWO_TEXTURES, 35 }; 36 37 private: 38 GLuint textures_[6]; 39 YuvTestFlavor flavor_; 40 GLuint YuvToRgbShaderProgram(GLuint vertex_buffer, int width, int height); 41 bool SetupTextures(); 42 DISALLOW_COPY_AND_ASSIGN(YuvToRgbTest); 43}; 44 45 46GLuint YuvToRgbTest::YuvToRgbShaderProgram(GLuint vertex_buffer, 47 int width, int height) { 48 const char *vertex = NULL; 49 const char *fragment = NULL; 50 51 switch (flavor_) { 52 case YUV_PLANAR_ONE_TEXTURE_SLOW: 53 vertex = YUV2RGB_VERTEX_1; 54 fragment = YUV2RGB_FRAGMENT_1; 55 break; 56 case YUV_PLANAR_ONE_TEXTURE_FASTER: 57 vertex = YUV2RGB_VERTEX_2; 58 fragment = YUV2RGB_FRAGMENT_2; 59 break; 60 case YUV_PLANAR_THREE_TEXTURES: 61 vertex = YUV2RGB_VERTEX_34; 62 fragment = YUV2RGB_FRAGMENT_3; 63 break; 64 case YUV_SEMIPLANAR_TWO_TEXTURES: 65 vertex = YUV2RGB_VERTEX_34; 66 fragment = YUV2RGB_FRAGMENT_4; 67 break; 68 } 69 70 size_t size_vertex = 0; 71 size_t size_fragment = 0; 72 char *yuv_to_rgb_vertex = static_cast<char *>( 73 MmapFile(vertex, &size_vertex)); 74 char *yuv_to_rgb_fragment = static_cast<char *>( 75 MmapFile(fragment, &size_fragment)); 76 GLuint program = 0; 77 78 if (!yuv_to_rgb_fragment || !yuv_to_rgb_vertex) 79 goto done; 80 81 { 82 program = InitShaderProgramWithHeader(NULL, yuv_to_rgb_vertex, 83 yuv_to_rgb_fragment); 84 85 int imageWidthUniform = glGetUniformLocation(program, "imageWidth"); 86 int imageHeightUniform = glGetUniformLocation(program, "imageHeight"); 87 88 int textureSampler = glGetUniformLocation(program, "textureSampler"); 89 int evenLinesSampler = glGetUniformLocation(program, "paritySampler"); 90 int ySampler = glGetUniformLocation(program, "ySampler"); 91 int uSampler = glGetUniformLocation(program, "uSampler"); 92 int vSampler = glGetUniformLocation(program, "vSampler"); 93 int uvSampler = glGetUniformLocation(program, "uvSampler"); 94 95 glUniform1f(imageWidthUniform, width); 96 glUniform1f(imageHeightUniform, height); 97 glUniform1i(textureSampler, 0); 98 glUniform1i(evenLinesSampler, 1); 99 100 glUniform1i(ySampler, 2); 101 glUniform1i(uSampler, 3); 102 glUniform1i(vSampler, 4); 103 glUniform1i(uvSampler, 5); 104 105 { 106 // This is used only if USE_UNIFORM_MATRIX is enabled in fragment 107 // shaders. 108 float c[] = { 109 1.0, 1.0, 1.0, 0.0, 110 0.0, -0.344, 1.772, 0.0, 111 1.402, -0.714, 0.0, 0.0, 112 -0.701, 0.529, -0.886, 1.0 113 }; 114 int conversion = glGetUniformLocation(program, "conversion"); 115 glUniformMatrix4fv(conversion, 1, GL_FALSE, c); 116 assert(glGetError() == 0); 117 } 118 119 int attribute_index = glGetAttribLocation(program, "c"); 120 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 121 glVertexAttribPointer(attribute_index, 2, GL_FLOAT, GL_FALSE, 0, NULL); 122 glEnableVertexAttribArray(attribute_index); 123 return program; 124 } 125 126 127done: 128 munmap(yuv_to_rgb_fragment, size_fragment); 129 munmap(yuv_to_rgb_fragment, size_vertex); 130 return program; 131} 132 133 134bool YuvToRgbTest::SetupTextures() { 135 bool ret = false; 136 size_t size = 0; 137 char evenodd[2] = {0, static_cast<char>(-1)}; 138 char* pixels = static_cast<char *>(MmapFile(YUV2RGB_NAME, &size)); 139 const int luma_size = YUV2RGB_WIDTH * YUV2RGB_PIXEL_HEIGHT; 140 const int chroma_size = YUV2RGB_WIDTH/2 * YUV2RGB_PIXEL_HEIGHT/2; 141 const char* u_plane = pixels + luma_size; 142 const char* v_plane = pixels + luma_size + chroma_size; 143 if (!pixels) { 144 printf("# Error: Could not open image file: %s\n", YUV2RGB_NAME); 145 goto done; 146 } 147 if (size != YUV2RGB_SIZE) { 148 printf("# Error: Image file of wrong size, got %d, expected %d\n", 149 static_cast<int>(size), YUV2RGB_SIZE); 150 goto done; 151 } 152 153 glGenTextures(arraysize(textures_), textures_); 154 glActiveTexture(GL_TEXTURE0); 155 glBindTexture(GL_TEXTURE_2D, textures_[0]); 156 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, YUV2RGB_WIDTH, YUV2RGB_HEIGHT, 157 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); 158 159 glActiveTexture(GL_TEXTURE1); 160 glBindTexture(GL_TEXTURE_2D, textures_[1]); 161 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 2, 1, 162 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, evenodd); 163 164 glActiveTexture(GL_TEXTURE2); 165 glBindTexture(GL_TEXTURE_2D, textures_[2]); 166 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 167 YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT, 168 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels); 169 170 glActiveTexture(GL_TEXTURE3); 171 glBindTexture(GL_TEXTURE_2D, textures_[3]); 172 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 173 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, 174 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u_plane); 175 176 glActiveTexture(GL_TEXTURE4); 177 glBindTexture(GL_TEXTURE_2D, textures_[4]); 178 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 179 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, 180 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v_plane); 181 182 { 183 std::unique_ptr<char[]> buf_uv(new char[chroma_size * 2]); 184 char* buf_uv_ptr = buf_uv.get(); 185 for (int i = 0; i < chroma_size; i++) { 186 *buf_uv_ptr++ = u_plane[i]; 187 *buf_uv_ptr++ = v_plane[i]; 188 } 189 190 glActiveTexture(GL_TEXTURE5); 191 glBindTexture(GL_TEXTURE_2D, textures_[5]); 192 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 193 YUV2RGB_WIDTH/2, YUV2RGB_PIXEL_HEIGHT/2, 194 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf_uv.get()); 195 } 196 197 for (unsigned int i = 0; i < arraysize(textures_); i++) { 198 glActiveTexture(GL_TEXTURE0 + i); 199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 203 } 204 205 ret = true; 206 207done: 208 munmap(pixels, size); 209 return ret; 210} 211 212 213bool YuvToRgbTest::Run() { 214 glClearColor(0.f, 1.f, 0.f, 1.f); 215 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(0, 0, YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT); 230 231 YuvTestFlavor flavors[] = { 232 YUV_PLANAR_ONE_TEXTURE_SLOW, YUV_PLANAR_ONE_TEXTURE_FASTER, 233 YUV_PLANAR_THREE_TEXTURES, YUV_SEMIPLANAR_TWO_TEXTURES 234 }; 235 const char* flavor_names[] = { 236 "yuv_shader_1", "yuv_shader_2", "yuv_shader_3", "yuv_shader_4" 237 }; 238 for (unsigned int f = 0; f < arraysize(flavors); f++) { 239 flavor_ = flavors[f]; 240 241 program = YuvToRgbShaderProgram(vertex_buffer, 242 YUV2RGB_WIDTH, YUV2RGB_PIXEL_HEIGHT); 243 if (program) { 244 FillRateTestNormalSubWindow(flavor_names[f], 245 std::min(YUV2RGB_WIDTH, g_width), 246 std::min(YUV2RGB_PIXEL_HEIGHT, g_height)); 247 } else { 248 printf("# Error: Could not set up YUV shader.\n"); 249 } 250 251 glDeleteProgram(program); 252 } 253 254 glDeleteBuffers(1, &vertex_buffer); 255 256 return true; 257} 258 259 260TestBase* GetYuvToRgbTest() { 261 return new YuvToRgbTest(); 262} 263 264} // namespace glbench 265