1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Tests of DXT texture mipmap sizes required by WebGL.
7
8 #include "test_utils/ANGLETest.h"
9 #include "test_utils/gl_raii.h"
10
11 #include "media/pixel.inc"
12
13 using namespace angle;
14
15 std::array<uint8_t, 72> k12x12DXT1Data = {
16 0xe0, 0x03, 0x00, 0x78, 0x13, 0x10, 0x15, 0x00, 0x0f, 0x00, 0xe0, 0x7b, 0x11, 0x10, 0x15,
17 0x00, 0xe0, 0x03, 0x0f, 0x78, 0x44, 0x45, 0x40, 0x55, 0x0f, 0x00, 0xef, 0x03, 0x44, 0x45,
18 0x40, 0x55, 0xe0, 0x03, 0x00, 0x78, 0x13, 0x10, 0x15, 0x00, 0x0f, 0x00, 0xe0, 0x7b, 0x11,
19 0x10, 0x15, 0x00, 0xe0, 0x03, 0x0f, 0x78, 0x44, 0x45, 0x40, 0x55, 0x0f, 0x00, 0xef, 0x03,
20 0x44, 0x45, 0x40, 0x55, 0x0f, 0x00, 0xef, 0x03, 0x44, 0x45, 0x40, 0x55,
21 };
22
23 class S3TCTextureSizesTest : public ANGLETest
24 {
25 protected:
S3TCTextureSizesTest()26 S3TCTextureSizesTest()
27 {
28 setWindowWidth(512);
29 setWindowHeight(512);
30 setConfigRedBits(8);
31 setConfigGreenBits(8);
32 setConfigBlueBits(8);
33 setConfigAlphaBits(8);
34 }
35
testSetUp()36 void testSetUp() override
37 {
38 constexpr char kVS[] = R"(precision highp float;
39 attribute vec4 position;
40 varying vec2 texcoord;
41
42 void main()
43 {
44 gl_Position = position;
45 texcoord = (position.xy * 0.5) + 0.5;
46 texcoord.y = 1.0 - texcoord.y;
47 })";
48
49 constexpr char kFS[] = R"(precision highp float;
50 uniform sampler2D tex;
51 varying vec2 texcoord;
52
53 void main()
54 {
55 gl_FragColor = texture2D(tex, texcoord);
56 })";
57
58 mTextureProgram = CompileProgram(kVS, kFS);
59 if (mTextureProgram == 0)
60 {
61 FAIL() << "shader compilation failed.";
62 }
63
64 mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
65
66 ASSERT_GL_NO_ERROR();
67 }
68
testTearDown()69 void testTearDown() override { glDeleteProgram(mTextureProgram); }
70
71 GLuint mTextureProgram;
72 GLint mTextureUniformLocation;
73 };
74
75 // Test DXT1 formats with POT sizes on all mips
TEST_P(S3TCTextureSizesTest,POT)76 TEST_P(S3TCTextureSizesTest, POT)
77 {
78 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
79
80 GLTexture texture;
81 glBindTexture(GL_TEXTURE_2D, texture);
82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
86
87 glUseProgram(mTextureProgram);
88 glUniform1i(mTextureUniformLocation, 0);
89
90 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, 8, 0, 32,
91 k12x12DXT1Data.data());
92 drawQuad(mTextureProgram, "position", 0.5f);
93 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor(0, 0, 123, 255));
94
95 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, 4, 0, 16,
96 k12x12DXT1Data.data());
97 drawQuad(mTextureProgram, "position", 0.5f);
98 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor(0, 0, 123, 255));
99
100 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, 4, 0, 16,
101 k12x12DXT1Data.data());
102 drawQuad(mTextureProgram, "position", 0.5f);
103 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor(0, 0, 123, 255));
104
105 glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 0, 8,
106 k12x12DXT1Data.data());
107 drawQuad(mTextureProgram, "position", 0.5f);
108 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor(123, 0, 0, 255));
109
110 EXPECT_GL_NO_ERROR();
111 }
112
113 // Test DXT1 formats with NPOT sizes with glTexStorage
TEST_P(S3TCTextureSizesTest,NPOTTexStorage)114 TEST_P(S3TCTextureSizesTest, NPOTTexStorage)
115 {
116 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
117
118 ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
119 (!IsGLExtensionEnabled("GL_EXT_texture_storage") ||
120 !IsGLExtensionEnabled("GL_OES_rgb8_rgba8")));
121
122 GLTexture texture;
123 glBindTexture(GL_TEXTURE_2D, texture);
124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
128
129 glUseProgram(mTextureProgram);
130 glUniform1i(mTextureUniformLocation, 0);
131
132 if (getClientMajorVersion() < 3)
133 {
134 glTexStorage2DEXT(GL_TEXTURE_2D, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 12, 12);
135 }
136 else
137 {
138 glTexStorage2D(GL_TEXTURE_2D, 4, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 12, 12);
139 }
140
141 struct levelInfo
142 {
143 size_t width;
144 size_t height;
145 size_t size;
146 GLColor expectedColor;
147 };
148 std::array<levelInfo, 4> levels{{
149 {12, 12, 72, GLColor(123, 0, 123, 255)},
150 {6, 6, 32, GLColor(123, 0, 123, 255)},
151 {3, 3, 8, GLColor(123, 0, 0, 255)},
152 {1, 1, 8, GLColor(0, 0, 0, 0)},
153 }};
154
155 for (size_t i = 0; i < levels.size(); i++)
156 {
157 const levelInfo &level = levels[i];
158 glCompressedTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, level.width, level.height,
159 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, level.size,
160 k12x12DXT1Data.data());
161 }
162 EXPECT_GL_NO_ERROR();
163
164 for (size_t i = 0; i < levels.size(); i++)
165 {
166 const levelInfo &level = levels[i];
167 glViewport(0, 0, level.width, level.height);
168 drawQuad(mTextureProgram, "position", 0.5f);
169 EXPECT_PIXEL_COLOR_EQ(0, 0, level.expectedColor) << " failed on level " << i;
170 }
171
172 EXPECT_GL_NO_ERROR();
173 }
174
175 // Test DXT1 formats with NPOT sizes with glTex[Sub]Image
TEST_P(S3TCTextureSizesTest,NPOTTexImage)176 TEST_P(S3TCTextureSizesTest, NPOTTexImage)
177 {
178 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
179
180 GLTexture texture;
181 glBindTexture(GL_TEXTURE_2D, texture);
182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
183 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
185 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
186
187 glUseProgram(mTextureProgram);
188 glUniform1i(mTextureUniformLocation, 0);
189
190 struct levelInfo
191 {
192 size_t width;
193 size_t height;
194 size_t size;
195 GLColor expectedColor;
196 };
197 std::array<levelInfo, 4> levels{{
198 {12, 12, 72, GLColor(123, 0, 123, 255)},
199 {6, 6, 32, GLColor(123, 0, 123, 255)},
200 {3, 3, 8, GLColor(123, 0, 0, 255)},
201 {1, 1, 8, GLColor(0, 0, 0, 0)},
202 }};
203
204 for (size_t i = 0; i < levels.size(); i++)
205 {
206 const levelInfo &level = levels[i];
207 glCompressedTexImage2D(GL_TEXTURE_2D, i, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, level.width,
208 level.height, 0, level.size, k12x12DXT1Data.data());
209 }
210 EXPECT_GL_NO_ERROR();
211
212 for (size_t i = 0; i < levels.size(); i++)
213 {
214 const levelInfo &level = levels[i];
215 glViewport(0, 0, level.width, level.height);
216 drawQuad(mTextureProgram, "position", 0.5f);
217 EXPECT_PIXEL_COLOR_EQ(0, 0, level.expectedColor) << " failed on level " << i;
218 }
219
220 EXPECT_GL_NO_ERROR();
221 }
222
223 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
224 // tests should be run against.
225 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(S3TCTextureSizesTest);
226