1 // Copyright (c) 2012 The Chromium 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 "gpu/command_buffer/tests/gl_test_utils.h" 6 #include <string> 7 #include <stdio.h> 8 #include "base/basictypes.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "testing/gmock/include/gmock/gmock.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 13 // GCC requires these declarations, but MSVC requires they not be present. 14 #ifndef COMPILER_MSVC 15 const uint8 GLTestHelper::kCheckClearValue; 16 #endif 17 18 bool GLTestHelper::HasExtension(const char* extension) { 19 std::string extensions( 20 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); 21 return extensions.find(extension) != std::string::npos; 22 } 23 24 bool GLTestHelper::CheckGLError(const char* msg, int line) { 25 bool success = true; 26 GLenum error = GL_NO_ERROR; 27 while ((error = glGetError()) != GL_NO_ERROR) { 28 success = false; 29 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), error) 30 << "GL ERROR in " << msg << " at line " << line << " : " << error; 31 } 32 return success; 33 } 34 35 GLuint GLTestHelper::LoadShader(GLenum type, const char* shaderSrc) { 36 GLuint shader = glCreateShader(type); 37 // Load the shader source 38 glShaderSource(shader, 1, &shaderSrc, NULL); 39 // Compile the shader 40 glCompileShader(shader); 41 // Check the compile status 42 GLint value = 0; 43 glGetShaderiv(shader, GL_COMPILE_STATUS, &value); 44 if (value == 0) { 45 char buffer[1024]; 46 GLsizei length = 0; 47 glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer); 48 std::string log(buffer, length); 49 EXPECT_EQ(1, value) << "Error compiling shader: " << log; 50 glDeleteShader(shader); 51 shader = 0; 52 } 53 return shader; 54 } 55 56 GLuint GLTestHelper::SetupProgram( 57 GLuint vertex_shader, GLuint fragment_shader) { 58 // Create the program object 59 GLuint program = glCreateProgram(); 60 glAttachShader(program, vertex_shader); 61 glAttachShader(program, fragment_shader); 62 // Link the program 63 glLinkProgram(program); 64 // Check the link status 65 GLint linked = 0; 66 glGetProgramiv(program, GL_LINK_STATUS, &linked); 67 if (linked == 0) { 68 char buffer[1024]; 69 GLsizei length = 0; 70 glGetProgramInfoLog(program, sizeof(buffer), &length, buffer); 71 std::string log(buffer, length); 72 EXPECT_EQ(1, linked) << "Error linking program: " << log; 73 glDeleteProgram(program); 74 program = 0; 75 } 76 return program; 77 } 78 79 GLuint GLTestHelper::LoadProgram( 80 const char* vertex_shader_source, 81 const char* fragment_shader_source) { 82 GLuint vertex_shader = LoadShader( 83 GL_VERTEX_SHADER, vertex_shader_source); 84 GLuint fragment_shader = LoadShader( 85 GL_FRAGMENT_SHADER, fragment_shader_source); 86 if (!vertex_shader || !fragment_shader) { 87 return 0; 88 } 89 return SetupProgram(vertex_shader, fragment_shader); 90 } 91 92 GLuint GLTestHelper::SetupUnitQuad(GLint position_location) { 93 GLuint vbo = 0; 94 glGenBuffers(1, &vbo); 95 glBindBuffer(GL_ARRAY_BUFFER, vbo); 96 static float vertices[] = { 97 1.0f, 1.0f, 98 -1.0f, 1.0f, 99 -1.0f, -1.0f, 100 1.0f, 1.0f, 101 -1.0f, -1.0f, 102 1.0f, -1.0f, 103 }; 104 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 105 glEnableVertexAttribArray(position_location); 106 glVertexAttribPointer(position_location, 2, GL_FLOAT, GL_FALSE, 0, 0); 107 108 return vbo; 109 } 110 111 GLuint GLTestHelper::SetupColorsForUnitQuad( 112 GLint location, const GLfloat color[4], GLenum usage) { 113 GLuint vbo = 0; 114 glGenBuffers(1, &vbo); 115 glBindBuffer(GL_ARRAY_BUFFER, vbo); 116 GLfloat vertices[6 * 4]; 117 for (int ii = 0; ii < 6; ++ii) { 118 for (int jj = 0; jj < 4; ++jj) { 119 vertices[ii * 4 + jj] = color[jj]; 120 } 121 } 122 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, usage); 123 glEnableVertexAttribArray(location); 124 glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, 0); 125 126 return vbo; 127 } 128 129 bool GLTestHelper::CheckPixels( 130 GLint x, GLint y, GLsizei width, GLsizei height, GLint tolerance, 131 const uint8* color) { 132 GLsizei size = width * height * 4; 133 scoped_ptr<uint8[]> pixels(new uint8[size]); 134 memset(pixels.get(), kCheckClearValue, size); 135 glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); 136 int bad_count = 0; 137 for (GLint yy = 0; yy < height; ++yy) { 138 for (GLint xx = 0; xx < width; ++xx) { 139 int offset = yy * width * 4 + xx * 4; 140 for (int jj = 0; jj < 4; ++jj) { 141 uint8 actual = pixels[offset + jj]; 142 uint8 expected = color[jj]; 143 int diff = actual - expected; 144 diff = diff < 0 ? -diff: diff; 145 if (diff > tolerance) { 146 EXPECT_EQ(expected, actual) << " at " << (xx + x) << ", " << (yy + y) 147 << " channel " << jj; 148 ++bad_count; 149 // Exit early just so we don't spam the log but we print enough 150 // to hopefully make it easy to diagnose the issue. 151 if (bad_count > 16) { 152 return false; 153 } 154 } 155 } 156 } 157 } 158 return bad_count == 0; 159 } 160 161 namespace { 162 163 void Set16BitValue(uint8 dest[2], uint16 value) { 164 dest[0] = value & 0xFFu; 165 dest[1] = value >> 8; 166 } 167 168 void Set32BitValue(uint8 dest[4], uint32 value) { 169 dest[0] = (value >> 0) & 0xFFu; 170 dest[1] = (value >> 8) & 0xFFu; 171 dest[2] = (value >> 16) & 0xFFu; 172 dest[3] = (value >> 24) & 0xFFu; 173 } 174 175 struct BitmapHeaderFile { 176 uint8 magic[2]; 177 uint8 size[4]; 178 uint8 reserved[4]; 179 uint8 offset[4]; 180 }; 181 182 struct BitmapInfoHeader{ 183 uint8 size[4]; 184 uint8 width[4]; 185 uint8 height[4]; 186 uint8 planes[2]; 187 uint8 bit_count[2]; 188 uint8 compression[4]; 189 uint8 size_image[4]; 190 uint8 x_pels_per_meter[4]; 191 uint8 y_pels_per_meter[4]; 192 uint8 clr_used[4]; 193 uint8 clr_important[4]; 194 }; 195 196 } 197 198 bool GLTestHelper::SaveBackbufferAsBMP( 199 const char* filename, int width, int height) { 200 FILE* fp = fopen(filename, "wb"); 201 EXPECT_TRUE(fp != NULL); 202 glPixelStorei(GL_PACK_ALIGNMENT, 1); 203 int num_pixels = width * height; 204 int size = num_pixels * 4; 205 scoped_ptr<uint8[]> data(new uint8[size]); 206 uint8* pixels = data.get(); 207 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 208 209 // RGBA to BGRA 210 for (int ii = 0; ii < num_pixels; ++ii) { 211 int offset = ii * 4; 212 uint8 t = pixels[offset + 0]; 213 pixels[offset + 0] = pixels[offset + 2]; 214 pixels[offset + 2] = t; 215 } 216 217 BitmapHeaderFile bhf; 218 BitmapInfoHeader bih; 219 220 bhf.magic[0] = 'B'; 221 bhf.magic[1] = 'M'; 222 Set32BitValue(bhf.size, 0); 223 Set32BitValue(bhf.reserved, 0); 224 Set32BitValue(bhf.offset, sizeof(bhf) + sizeof(bih)); 225 226 Set32BitValue(bih.size, sizeof(bih)); 227 Set32BitValue(bih.width, width); 228 Set32BitValue(bih.height, height); 229 Set16BitValue(bih.planes, 1); 230 Set16BitValue(bih.bit_count, 32); 231 Set32BitValue(bih.compression, 0); 232 Set32BitValue(bih.x_pels_per_meter, 0); 233 Set32BitValue(bih.y_pels_per_meter, 0); 234 Set32BitValue(bih.clr_used, 0); 235 Set32BitValue(bih.clr_important, 0); 236 237 fwrite(&bhf, sizeof(bhf), 1, fp); 238 fwrite(&bih, sizeof(bih), 1, fp); 239 fwrite(pixels, size, 1, fp); 240 fclose(fp); 241 return true; 242 } 243 244 int GLTestHelper::RunTests(int argc, char** argv) { 245 testing::InitGoogleMock(&argc, argv); 246 return RUN_ALL_TESTS(); 247 } 248