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
15const uint8 GLTestHelper::kCheckClearValue;
16#endif
17
18bool 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
24bool 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
35GLuint 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
56GLuint 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
79GLuint 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
92GLuint 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
111GLuint 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
129bool 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
161namespace {
162
163void Set16BitValue(uint8 dest[2], uint16 value) {
164  dest[0] = value & 0xFFu;
165  dest[1] = value >> 8;
166}
167
168void 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
175struct BitmapHeaderFile {
176  uint8 magic[2];
177  uint8 size[4];
178  uint8 reserved[4];
179  uint8 offset[4];
180};
181
182struct 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
198bool 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
244int GLTestHelper::RunTests(int argc, char** argv) {
245  testing::InitGoogleMock(&argc, argv);
246  return RUN_ALL_TESTS();
247}
248