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
HasExtension(const char * extension)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
CheckGLError(const char * msg,int line)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
LoadShader(GLenum type,const char * shaderSrc)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
SetupProgram(GLuint vertex_shader,GLuint fragment_shader)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
LoadProgram(const char * vertex_shader_source,const char * fragment_shader_source)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
SetupUnitQuad(GLint position_location)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
SetupColorsForUnitQuad(GLint location,const GLfloat color[4],GLenum usage)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
CheckPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLint tolerance,const uint8 * color)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
Set16BitValue(uint8 dest[2],uint16 value)163 void Set16BitValue(uint8 dest[2], uint16 value) {
164 dest[0] = value & 0xFFu;
165 dest[1] = value >> 8;
166 }
167
Set32BitValue(uint8 dest[4],uint32 value)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
SaveBackbufferAsBMP(const char * filename,int width,int height)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
RunTests(int argc,char ** argv)244 int GLTestHelper::RunTests(int argc, char** argv) {
245 testing::InitGoogleMock(&argc, argv);
246 return RUN_ALL_TESTS();
247 }
248