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