1 //
2 // Copyright 2018 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
7 // DrawTextureTest.cpp: Tests basic usage of glDrawTex*.
8
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11
12 #include <memory>
13 #include <vector>
14
15 using namespace angle;
16
17 class DrawTextureTest : public ANGLETest<>
18 {
19 protected:
DrawTextureTest()20 DrawTextureTest()
21 {
22 setWindowWidth(kWindowWidth);
23 setWindowHeight(kWindowHeight);
24 setConfigRedBits(8);
25 setConfigGreenBits(8);
26 setConfigBlueBits(8);
27 setConfigAlphaBits(8);
28 setConfigDepthBits(24);
29 }
30
testSetUp()31 void testSetUp() override
32 {
33 mTexture.reset(new GLTexture());
34 glEnable(GL_TEXTURE_2D);
35 glBindTexture(GL_TEXTURE_2D, mTexture->get());
36 }
37
testTearDown()38 void testTearDown() override { mTexture.reset(); }
39
40 std::unique_ptr<GLTexture> mTexture;
41
42 static constexpr int kWindowWidth = 32;
43 static constexpr int kWindowHeight = 32;
44 };
45
46 // Negative test for invalid width/height values.
TEST_P(DrawTextureTest,NegativeValue)47 TEST_P(DrawTextureTest, NegativeValue)
48 {
49 glDrawTexiOES(0, 0, 0, 0, 0);
50 EXPECT_GL_ERROR(GL_INVALID_VALUE);
51 glDrawTexiOES(0, 0, 0, -1, 0);
52 EXPECT_GL_ERROR(GL_INVALID_VALUE);
53 glDrawTexiOES(0, 0, 0, 0, -1);
54 EXPECT_GL_ERROR(GL_INVALID_VALUE);
55 glDrawTexiOES(0, 0, 0, -1, -1);
56 EXPECT_GL_ERROR(GL_INVALID_VALUE);
57 }
58
59 // Basic draw.
TEST_P(DrawTextureTest,Basic)60 TEST_P(DrawTextureTest, Basic)
61 {
62 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
63 glDrawTexiOES(0, 0, 0, 1, 1);
64 EXPECT_GL_NO_ERROR();
65 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
66 }
67
68 // Tests that odd viewport dimensions are handled correctly.
69 // If the viewport dimension is even, then the incorrect way
70 // of getting the center screen coordinate by dividing by 2 and
71 // converting to integer will work in that case, but not if
72 // the viewport dimension is odd.
TEST_P(DrawTextureTest,CorrectNdcForOddViewportDimensions)73 TEST_P(DrawTextureTest, CorrectNdcForOddViewportDimensions)
74 {
75 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
76 glClear(GL_COLOR_BUFFER_BIT);
77
78 // clang-format off
79 std::array<GLColor, 2> textureData = {
80 GLColor::green, GLColor::green
81 };
82 // clang-format on
83
84 glViewport(0, 0, 3, 3);
85 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData.data());
86
87 GLint cropRect[] = {0, 0, 2, 1};
88 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
90 EXPECT_GL_NO_ERROR();
91
92 GLint x = 1;
93 GLint y = 1;
94 glDrawTexiOES(x, y, 0, 2, 1);
95 EXPECT_GL_NO_ERROR();
96
97 EXPECT_PIXEL_COLOR_EQ(x, y, GLColor::green);
98 EXPECT_PIXEL_COLOR_EQ(x + 1, y, GLColor::green);
99
100 EXPECT_PIXEL_COLOR_EQ(x, y + 1, GLColor::black);
101 EXPECT_PIXEL_COLOR_EQ(x + 1, y + 1, GLColor::black);
102 EXPECT_PIXEL_COLOR_EQ(x + 2, y, GLColor::black);
103 EXPECT_PIXEL_COLOR_EQ(x + 3, y, GLColor::black);
104 }
105
106 // Tests that vertex attributes enabled with fewer than 6 verts do not cause a crash.
TEST_P(DrawTextureTest,VertexAttributesNoCrash)107 TEST_P(DrawTextureTest, VertexAttributesNoCrash)
108 {
109 glEnableClientState(GL_COLOR_ARRAY);
110 glColorPointer(4, GL_FLOAT, 0, &GLColor::white);
111
112 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
113 EXPECT_GL_NO_ERROR();
114
115 glDrawTexiOES(0, 0, 0, 1, 1);
116 EXPECT_GL_NO_ERROR();
117 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
118 }
119
120 // Tests that the color array, if enabled, is not used as the vertex color.
TEST_P(DrawTextureTest,ColorArrayNotUsed)121 TEST_P(DrawTextureTest, ColorArrayNotUsed)
122 {
123 glEnableClientState(GL_COLOR_ARRAY);
124
125 // This color is set to black on purpose to ensure that the color in the upcoming vertex array
126 // is not used in the texture draw. If it is used, then the texture we want to read will be
127 // modulated with the color in the vertex array instead of GL_CURRENT_COLOR (which at the moment
128 // is white (1.0, 1.0, 1.0, 1.0).
129 glColorPointer(4, GL_FLOAT, 0, &GLColor::black);
130
131 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
132 EXPECT_GL_NO_ERROR();
133
134 glDrawTexiOES(0, 0, 0, 1, 1);
135 EXPECT_GL_NO_ERROR();
136 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
137 }
138
139 // Tests that values of differenty types are properly normalized with glColorPointer
TEST_P(DrawTextureTest,ColorArrayDifferentTypes)140 TEST_P(DrawTextureTest, ColorArrayDifferentTypes)
141 {
142 constexpr GLubyte kTextureColorData[] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
143 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF};
144 constexpr GLfloat kVertexPtrData[] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f};
145 constexpr GLfloat kTexCoordPtrData[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
146 constexpr GLubyte kGLubyteData[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
147 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
148 constexpr GLfloat kGLfloatData[] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
149 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
150 constexpr GLfixed kGLfixedData[] = {0x10000, 0x10000, 0x10000, 0x10000, 0x10000, 0x10000,
151 0x10000, 0x10000, 0x10000, 0x10000, 0x10000, 0x10000,
152 0x10000, 0x10000, 0x10000, 0x10000};
153
154 // We check a pixel coordinate at the border of where linear interpolation starts as
155 // we fail to get correct interpolated values when we do not normalize the GLbyte values.
156 constexpr GLint kCheckedPixelX = 16;
157 constexpr GLint kCheckedPixelY = 8;
158 constexpr unsigned int kPixelTolerance = 10u;
159
160 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
161 glClear(GL_COLOR_BUFFER_BIT);
162 glEnableClientState(GL_VERTEX_ARRAY);
163 glEnableClientState(GL_COLOR_ARRAY);
164 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
169 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kTextureColorData);
170 glVertexPointer(2, GL_FLOAT, 0, kVertexPtrData);
171 glTexCoordPointer(2, GL_FLOAT, 0, kTexCoordPtrData);
172
173 // Ensure the results do not change unexpectedly regardless of the color data format
174
175 // Test GLubyte
176 glColorPointer(4, GL_UNSIGNED_BYTE, 0, kGLubyteData);
177 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
178 EXPECT_GL_NO_ERROR();
179 EXPECT_PIXEL_COLOR_NEAR(kCheckedPixelX, kCheckedPixelY, GLColor::red, kPixelTolerance);
180
181 // Test GLfloat
182 glColorPointer(4, GL_FLOAT, 0, kGLfloatData);
183 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
184 EXPECT_GL_NO_ERROR();
185 EXPECT_PIXEL_COLOR_NEAR(kCheckedPixelX, kCheckedPixelY, GLColor::red, kPixelTolerance);
186
187 // Test GLfixed
188 glColorPointer(4, GL_FIXED, 0, kGLfixedData);
189 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
190 EXPECT_GL_NO_ERROR();
191 EXPECT_PIXEL_COLOR_NEAR(kCheckedPixelX, kCheckedPixelY, GLColor::red, kPixelTolerance);
192 }
193
194 // Tests that drawing a primitive works with enabled tex coord pointer, but with texture disabled.
TEST_P(DrawTextureTest,DrawWithTexCoordPtrDataAndDisabledTexture2D)195 TEST_P(DrawTextureTest, DrawWithTexCoordPtrDataAndDisabledTexture2D)
196 {
197 std::vector<GLfloat> vertexPtrData = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
198 std::vector<GLfloat> texCoordPtrData = {0.0f};
199
200 glEnableClientState(GL_VERTEX_ARRAY);
201 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
202 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
203 glClear(GL_COLOR_BUFFER_BIT);
204
205 // Draw a triangle fan that covers the entire window. GL_TEXTURE_2D is disabled even though
206 // texture coord pointer is set.
207 glVertexPointer(2, GL_FLOAT, 0, vertexPtrData.data());
208 glTexCoordPointer(2, GL_FLOAT, 0, texCoordPtrData.data());
209 glDisable(GL_TEXTURE_2D);
210 glColor4ub(0, 0xFF, 0xFF, 0xFF);
211 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
212 EXPECT_GL_NO_ERROR();
213 EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth, kWindowHeight, GLColor::cyan);
214 }
215
216 // Tests that drawing a primitive works with enabled tex coord pointer and texture environment set
217 // so the used texture replaces the current color.
TEST_P(DrawTextureTest,DrawWithTexCoordPtrDataAndEnvModeReplace)218 TEST_P(DrawTextureTest, DrawWithTexCoordPtrDataAndEnvModeReplace)
219 {
220 std::vector<GLfloat> vertexPtrData = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f};
221 std::vector<GLfloat> texCoordPtrData = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f};
222
223 glEnableClientState(GL_VERTEX_ARRAY);
224 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
225 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
226 glClear(GL_COLOR_BUFFER_BIT);
227
228 // Set up the texture. By default, the texture is multiplied by the current color set through
229 // glColor calls. Here the environment is set so it would replace the color instead.
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
234 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
235 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
236
237 // Draw a triangle fan that covers the entire window. The texture should replace the color
238 // regardless of the value of the current color.
239 glVertexPointer(2, GL_FLOAT, 0, vertexPtrData.data());
240 glTexCoordPointer(2, GL_FLOAT, 0, texCoordPtrData.data());
241 glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
242 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
243 EXPECT_GL_NO_ERROR();
244 EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth, kWindowHeight, GLColor::red);
245 }
246
247 // Tests that tex coord pointer is only used when texture is enabled, and that it is possible to
248 // disable the texture and draw another primitive by setting a color without using the texture data.
TEST_P(DrawTextureTest,DrawWithTexCoordPtrThenDisableTexture2DAndDrawAnother)249 TEST_P(DrawTextureTest, DrawWithTexCoordPtrThenDisableTexture2DAndDrawAnother)
250 {
251 // There will be two vertex arrays for triangle fan draws. Both cover the entire screen, but the
252 // one with no texture uses more vertices.
253 std::vector<GLfloat> vertexPtrDataWithTexture = {-1.0f, -1.0f, -1.0f, 1.0f,
254 1.0f, 1.0f, 1.0f, -1.0f};
255 std::vector<GLfloat> vertexPtrDataNoTexture = {-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
256 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f};
257 std::vector<GLfloat> texCoordPtrData = {0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f};
258
259 // Enable vertex and texture coordinate pointers. Also set up texture data with four colors; one
260 // color per corner.
261 glEnableClientState(GL_VERTEX_ARRAY);
262 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
263
264 constexpr GLColor kColorCornerBL = GLColor(0x11, 0x22, 0x33, 0xFF);
265 constexpr GLColor kColorCornerBR = GLColor(0x44, 0x55, 0x66, 0xFF);
266 constexpr GLColor kColorCornerTL = GLColor(0x77, 0x88, 0x99, 0xFF);
267 constexpr GLColor kColorCornerTR = GLColor(0xAA, 0xBB, 0xCC, 0xFF);
268
269 std::vector<GLColor> textureData;
270 textureData.push_back(kColorCornerBL);
271 textureData.push_back(kColorCornerBR);
272 textureData.push_back(kColorCornerTL);
273 textureData.push_back(kColorCornerTR);
274
275 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
276 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
279 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData.data());
280
281 // Draw the first triangle fan using texture coord pointer.
282 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
283 glClear(GL_COLOR_BUFFER_BIT);
284 glEnable(GL_TEXTURE_2D);
285
286 glVertexPointer(2, GL_FLOAT, 0, vertexPtrDataWithTexture.data());
287 glTexCoordPointer(2, GL_FLOAT, 0, texCoordPtrData.data());
288 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
289 EXPECT_GL_NO_ERROR();
290 EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth / 2, kWindowHeight / 2, kColorCornerBL);
291 EXPECT_PIXEL_RECT_EQ(kWindowWidth / 2, 0, kWindowWidth / 2, kWindowHeight / 2, kColorCornerBR);
292 EXPECT_PIXEL_RECT_EQ(0, kWindowHeight / 2, kWindowWidth / 2, kWindowHeight / 2, kColorCornerTL);
293 EXPECT_PIXEL_RECT_EQ(kWindowWidth / 2, kWindowHeight / 2, kWindowWidth / 2, kWindowHeight / 2,
294 kColorCornerTR);
295
296 // Disable texture and draw the second triangle fan. This time, the draw uses more vertex
297 // coordinates and a preset color. Note that the texture coord pointer must no longer be used.
298 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
299 glClear(GL_COLOR_BUFFER_BIT);
300 glDisable(GL_TEXTURE_2D);
301
302 glVertexPointer(2, GL_FLOAT, 0, vertexPtrDataNoTexture.data());
303 glColor4ub(0, 0, 0xFF, 0xFF);
304 glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
305 EXPECT_GL_NO_ERROR();
306 EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth, kWindowHeight, GLColor::blue);
307
308 // Re-enable texture and draw using the same vertex pointer. This is to make sure that enabling
309 // GL_TEXTURE_2D is enough to use the texture data.
310 // There is no need to set the texture coord pointer again. However, since GL_TEXTURE_ENV_MODE
311 // is set to the default GL_MODULATE, the effect of glColor4ub() from before should be reversed
312 // by resetting the color to the default (1, 1, 1, 1).
313 // In addition, since the tex coord pointer is not defined for the current vertex pointer, the
314 // texture colors will shift position to be mapped to the new primitive, which will only cover
315 // the top-left half of the window.
316 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
317 glClear(GL_COLOR_BUFFER_BIT);
318 glEnable(GL_TEXTURE_2D);
319
320 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
321 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
322 EXPECT_GL_NO_ERROR();
323 EXPECT_PIXEL_COLOR_EQ(0, kWindowHeight / 4, kColorCornerBL);
324 EXPECT_PIXEL_COLOR_EQ(kWindowWidth * 3 / 4, kWindowHeight - 1, kColorCornerBR);
325 EXPECT_PIXEL_COLOR_EQ(0, kWindowHeight * 3 / 4, kColorCornerTL);
326 EXPECT_PIXEL_COLOR_EQ(kWindowWidth / 2, kWindowHeight - 1, kColorCornerTR);
327
328 // Update the vertex pointer to the original and draw a final triangle fan.
329 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
330 glClear(GL_COLOR_BUFFER_BIT);
331
332 glVertexPointer(2, GL_FLOAT, 0, vertexPtrDataWithTexture.data());
333 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
334 EXPECT_GL_NO_ERROR();
335 EXPECT_PIXEL_RECT_EQ(0, 0, kWindowWidth / 2, kWindowHeight / 2, kColorCornerBL);
336 EXPECT_PIXEL_RECT_EQ(kWindowWidth / 2, 0, kWindowWidth / 2, kWindowHeight / 2, kColorCornerBR);
337 EXPECT_PIXEL_RECT_EQ(0, kWindowHeight / 2, kWindowWidth / 2, kWindowHeight / 2, kColorCornerTL);
338 EXPECT_PIXEL_RECT_EQ(kWindowWidth / 2, kWindowHeight / 2, kWindowWidth / 2, kWindowHeight / 2,
339 kColorCornerTR);
340 }
341
342 ANGLE_INSTANTIATE_TEST_ES1(DrawTextureTest);
343