1 // Copyright 2013 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 <GLES2/gl2.h>
6 #include <GLES2/gl2ext.h>
7 #include <GLES2/gl2extchromium.h>
8
9 #include "base/basictypes.h"
10 #include "gpu/command_buffer/tests/gl_manager.h"
11 #include "gpu/command_buffer/tests/gl_test_utils.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 #define SHADER(src) #src
15
16 namespace gpu {
17
18 static const uint16 kRedMask = 0xF800;
19 static const uint16 kGreenMask = 0x07E0;
20 static const uint16 kBlueMask = 0x001F;
21
22 // Color palette in 565 format.
23 static const uint16 kPalette[] = {
24 kGreenMask | kBlueMask, // Cyan.
25 kBlueMask | kRedMask, // Magenta.
26 kRedMask | kGreenMask, // Yellow.
27 0x0000, // Black.
28 kRedMask, // Red.
29 kGreenMask, // Green.
30 kBlueMask, // Blue.
31 0xFFFF, // White.
32 };
33 static const unsigned kBlockSize = 4;
34 static const unsigned kPaletteSize = sizeof(kPalette) / sizeof(kPalette[0]);
35 static const unsigned kTextureWidth = kBlockSize * kPaletteSize;
36 static const unsigned kTextureHeight = kBlockSize;
37
extension(GLenum format)38 static const char* extension(GLenum format) {
39 switch(format) {
40 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
41 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
42 return "GL_EXT_texture_compression_dxt1";
43 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
44 return "GL_CHROMIUM_texture_compression_dxt3";
45 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
46 return "GL_CHROMIUM_texture_compression_dxt5";
47 default:
48 NOTREACHED();
49 }
50 return NULL;
51 }
52
53 // Index that chooses the given colors (color_0 and color_1),
54 // not the interpolated colors (color_2 and color_3).
55 static const uint16 kColor0 = 0x0000;
56 static const uint16 kColor1 = 0x5555;
57
LoadCompressedTexture(const void * data,GLsizeiptr size,GLenum format,GLsizei width,GLsizei height)58 static GLuint LoadCompressedTexture(const void* data,
59 GLsizeiptr size,
60 GLenum format,
61 GLsizei width,
62 GLsizei height) {
63 GLuint texture;
64 glGenTextures(1, &texture);
65 glBindTexture(GL_TEXTURE_2D, texture);
66 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
67 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
70 glCompressedTexImage2D(
71 GL_TEXTURE_2D, 0, format, width, height, 0, size, data);
72 return texture;
73 }
74
LoadTextureDXT1(bool alpha)75 GLuint LoadTextureDXT1(bool alpha) {
76 const unsigned kStride = 4;
77 uint16 data[kStride * kPaletteSize];
78 for (unsigned i = 0; i < kPaletteSize; ++i) {
79 // Each iteration defines a 4x4 block of texture.
80 unsigned j = kStride * i;
81 data[j++] = kPalette[i]; // color_0.
82 data[j++] = kPalette[i]; // color_1.
83 data[j++] = kColor0; // color index.
84 data[j++] = kColor1; // color index.
85 }
86 GLenum format = alpha ?
87 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
88 return LoadCompressedTexture(
89 data, sizeof(data), format, kTextureWidth, kTextureHeight);
90 }
91
LoadTextureDXT3()92 GLuint LoadTextureDXT3() {
93 const unsigned kStride = 8;
94 const uint16 kOpaque = 0xFFFF;
95 uint16 data[kStride * kPaletteSize];
96 for (unsigned i = 0; i < kPaletteSize; ++i) {
97 // Each iteration defines a 4x4 block of texture.
98 unsigned j = kStride * i;
99 data[j++] = kOpaque; // alpha row 0.
100 data[j++] = kOpaque; // alpha row 1.
101 data[j++] = kOpaque; // alpha row 2.
102 data[j++] = kOpaque; // alpha row 3.
103 data[j++] = kPalette[i]; // color_0.
104 data[j++] = kPalette[i]; // color_1.
105 data[j++] = kColor0; // color index.
106 data[j++] = kColor1; // color index.
107 }
108 return LoadCompressedTexture(data,
109 sizeof(data),
110 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
111 kTextureWidth,
112 kTextureHeight);
113 }
114
LoadTextureDXT5()115 GLuint LoadTextureDXT5() {
116 const unsigned kStride = 8;
117 const uint16 kClear = 0x0000;
118 const uint16 kAlpha7 = 0xFFFF; // Opaque alpha index.
119 uint16 data[kStride * kPaletteSize];
120 for (unsigned i = 0; i < kPaletteSize; ++i) {
121 // Each iteration defines a 4x4 block of texture.
122 unsigned j = kStride * i;
123 data[j++] = kClear; // alpha_0 | alpha_1.
124 data[j++] = kAlpha7; // alpha index.
125 data[j++] = kAlpha7; // alpha index.
126 data[j++] = kAlpha7; // alpha index.
127 data[j++] = kPalette[i]; // color_0.
128 data[j++] = kPalette[i]; // color_1.
129 data[j++] = kColor0; // color index.
130 data[j++] = kColor1; // color index.
131 }
132 return LoadCompressedTexture(data,
133 sizeof(data),
134 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
135 kTextureWidth,
136 kTextureHeight);
137 }
138
ToRGB888(uint16 rgb565,uint8 rgb888[])139 static void ToRGB888(uint16 rgb565, uint8 rgb888[]) {
140 uint8 r5 = (rgb565 & kRedMask) >> 11;
141 uint8 g6 = (rgb565 & kGreenMask) >> 5;
142 uint8 b5 = (rgb565 & kBlueMask);
143 // Replicate upper bits to lower empty bits.
144 rgb888[0] = (r5 << 3) | (r5 >> 2);
145 rgb888[1] = (g6 << 2) | (g6 >> 4);
146 rgb888[2] = (b5 << 3) | (b5 >> 2);
147 }
148
149 class CompressedTextureTest : public ::testing::TestWithParam<GLenum> {
150 protected:
SetUp()151 virtual void SetUp() {
152 GLManager::Options options;
153 options.size = gfx::Size(kTextureWidth, kTextureHeight);
154 gl_.Initialize(options);
155 }
156
TearDown()157 virtual void TearDown() {
158 gl_.Destroy();
159 }
160
LoadProgram()161 GLuint LoadProgram() {
162 const char* v_shader_src = SHADER(
163 attribute vec2 a_position;
164 varying vec2 v_texcoord;
165 void main() {
166 gl_Position = vec4(a_position, 0.0, 1.0);
167 v_texcoord = (a_position + 1.0) * 0.5;
168 }
169 );
170 const char* f_shader_src = SHADER(
171 precision mediump float;
172 uniform sampler2D u_texture;
173 varying vec2 v_texcoord;
174 void main() {
175 gl_FragColor = texture2D(u_texture, v_texcoord);
176 }
177 );
178 return GLTestHelper::LoadProgram(v_shader_src, f_shader_src);
179 }
180
LoadTexture(GLenum format)181 GLuint LoadTexture(GLenum format) {
182 switch (format) {
183 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return LoadTextureDXT1(false);
184 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return LoadTextureDXT1(true);
185 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return LoadTextureDXT3();
186 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return LoadTextureDXT5();
187 default: NOTREACHED();
188 }
189 return 0;
190 }
191
192 private:
193 GLManager gl_;
194 };
195
196 // The test draws a texture in the given format and verifies that the drawn
197 // pixels are of the same color as the texture.
198 // The texture consists of 4x4 blocks of texels (same as DXT), one for each
199 // color defined in kPalette.
TEST_P(CompressedTextureTest,Draw)200 TEST_P(CompressedTextureTest, Draw) {
201 GLenum format = GetParam();
202
203 // This test is only valid if compressed texture extension is supported.
204 const char* ext = extension(format);
205 if (!GLTestHelper::HasExtension(ext))
206 return;
207
208 // Load shader program.
209 GLuint program = LoadProgram();
210 ASSERT_NE(program, 0u);
211 GLint position_loc = glGetAttribLocation(program, "a_position");
212 GLint texture_loc = glGetUniformLocation(program, "u_texture");
213 ASSERT_NE(position_loc, -1);
214 ASSERT_NE(texture_loc, -1);
215 glUseProgram(program);
216
217 // Load geometry.
218 GLuint vbo = GLTestHelper::SetupUnitQuad(position_loc);
219 ASSERT_NE(vbo, 0u);
220
221 // Load texture.
222 GLuint texture = LoadTexture(format);
223 ASSERT_NE(texture, 0u);
224 glActiveTexture(GL_TEXTURE0);
225 glBindTexture(GL_TEXTURE_2D, texture);
226 glUniform1i(texture_loc, 0);
227
228 // Draw.
229 glDrawArrays(GL_TRIANGLES, 0, 6);
230 glFlush();
231
232 // Verify results.
233 int origin[] = {0, 0};
234 uint8 expected_rgba[] = {0, 0, 0, 255};
235 for (unsigned i = 0; i < kPaletteSize; ++i) {
236 origin[0] = kBlockSize * i;
237 ToRGB888(kPalette[i], expected_rgba);
238 EXPECT_TRUE(GLTestHelper::CheckPixels(origin[0], origin[1],
239 kBlockSize, kBlockSize,
240 0, expected_rgba));
241 }
242 GLTestHelper::CheckGLError("CompressedTextureTest.Draw", __LINE__);
243 }
244
245 static const GLenum kFormats[] = {
246 GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
247 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
248 GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
249 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
250 };
251 INSTANTIATE_TEST_CASE_P(Format,
252 CompressedTextureTest,
253 ::testing::ValuesIn(kFormats));
254
255 } // namespace gpu
256