blob: cddb4152ccde7b5bc9650dd0630e857efa7d8b00 [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
2// Copyright 2015 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
Corentin Wallezd3970de2015-05-14 11:07:48 -04007#include "test_utils/ANGLETest.h"
Jamie Madillf67115c2014-04-22 13:14:05 -04008
Jamie Madillfa05f602015-05-07 13:47:11 -04009using namespace angle;
Austin Kinross18b931d2014-09-29 12:58:31 -070010
Jamie Madillfa05f602015-05-07 13:47:11 -040011namespace
12{
13
Olli Etuaho4a8329f2016-01-11 17:12:57 +020014class TexCoordDrawTest : public ANGLETest
Jamie Madillf67115c2014-04-22 13:14:05 -040015{
Jamie Madillbc393df2015-01-29 13:46:07 -050016 protected:
Olli Etuaho4a8329f2016-01-11 17:12:57 +020017 TexCoordDrawTest() : ANGLETest(), mProgram(0)
Jamie Madillf67115c2014-04-22 13:14:05 -040018 {
19 setWindowWidth(128);
20 setWindowHeight(128);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 }
26
Olli Etuaho4a8329f2016-01-11 17:12:57 +020027 virtual std::string getVertexShaderSource()
Jamie Madillf67115c2014-04-22 13:14:05 -040028 {
Olli Etuaho4a8329f2016-01-11 17:12:57 +020029 return std::string(SHADER_SOURCE
Geoff Langc41e42d2014-04-28 10:58:16 -040030 (
31 precision highp float;
32 attribute vec4 position;
33 varying vec2 texcoord;
34
35 void main()
36 {
Olli Etuaho4a8329f2016-01-11 17:12:57 +020037 gl_Position = vec4(position.xy, 0.0, 1.0);
Geoff Langc41e42d2014-04-28 10:58:16 -040038 texcoord = (position.xy * 0.5) + 0.5;
39 }
Olli Etuaho4a8329f2016-01-11 17:12:57 +020040 )
Geoff Langc41e42d2014-04-28 10:58:16 -040041 );
Olli Etuaho4a8329f2016-01-11 17:12:57 +020042 }
Geoff Langc41e42d2014-04-28 10:58:16 -040043
Olli Etuaho4a8329f2016-01-11 17:12:57 +020044 virtual std::string getFragmentShaderSource() = 0;
45
46 void SetUp() override
47 {
48 ANGLETest::SetUp();
49 const std::string vertexShaderSource = getVertexShaderSource();
50 const std::string fragmentShaderSource = getFragmentShaderSource();
51
52 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
53 ASSERT_NE(0u, mProgram);
54 ASSERT_GL_NO_ERROR();
55 }
56
57 void TearDown() override
58 {
59 glDeleteProgram(mProgram);
60 ANGLETest::TearDown();
61 }
62
63 // Returns the created texture ID.
64 GLuint create2DTexture()
65 {
66 GLuint texture2D;
67 glGenTextures(1, &texture2D);
68 glBindTexture(GL_TEXTURE_2D, texture2D);
69 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
70 EXPECT_GL_NO_ERROR();
71 return texture2D;
72 }
73
74 GLuint mProgram;
75};
76
77class Texture2DTest : public TexCoordDrawTest
78{
79 protected:
80 Texture2DTest() : TexCoordDrawTest(), mTexture2D(0), mTexture2DUniformLocation(-1) {}
81
82 std::string getFragmentShaderSource() override
83 {
84 return std::string(SHADER_SOURCE
Geoff Langc41e42d2014-04-28 10:58:16 -040085 (
86 precision highp float;
87 uniform sampler2D tex;
88 varying vec2 texcoord;
89
90 void main()
91 {
92 gl_FragColor = texture2D(tex, texcoord);
93 }
Olli Etuaho4a8329f2016-01-11 17:12:57 +020094 )
Geoff Langc41e42d2014-04-28 10:58:16 -040095 );
Olli Etuaho4a8329f2016-01-11 17:12:57 +020096 }
Geoff Langc41e42d2014-04-28 10:58:16 -040097
Olli Etuaho4a8329f2016-01-11 17:12:57 +020098 void SetUp() override
99 {
100 TexCoordDrawTest::SetUp();
101 mTexture2D = create2DTexture();
Jamie Madilld4cfa572014-07-08 10:00:32 -0400102
Jamie Madill9aca0592014-10-06 16:26:59 -0400103 ASSERT_GL_NO_ERROR();
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200104
105 mTexture2DUniformLocation = glGetUniformLocation(mProgram, "tex");
106 ASSERT_NE(-1, mTexture2DUniformLocation);
Jamie Madillf67115c2014-04-22 13:14:05 -0400107 }
108
Jamie Madillfa05f602015-05-07 13:47:11 -0400109 void TearDown() override
Jamie Madillf67115c2014-04-22 13:14:05 -0400110 {
Jamie Madilld4cfa572014-07-08 10:00:32 -0400111 glDeleteTextures(1, &mTexture2D);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200112 TexCoordDrawTest::TearDown();
Jamie Madillf67115c2014-04-22 13:14:05 -0400113 }
114
Jamie Madillbc393df2015-01-29 13:46:07 -0500115 // Tests CopyTexSubImage with floating point textures of various formats.
116 void testFloatCopySubImage(int sourceImageChannels, int destImageChannels)
117 {
Geoff Langbde666a2015-04-07 17:17:08 -0400118 // TODO(jmadill): Figure out why this is broken on Intel D3D11
119 if (isIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
120 {
121 std::cout << "Test skipped on Intel D3D11." << std::endl;
122 return;
123 }
124
Geoff Langfbfa47c2015-03-31 11:26:00 -0400125 if (getClientVersion() < 3)
126 {
127 if (!extensionEnabled("GL_OES_texture_float"))
128 {
129 std::cout << "Test skipped due to missing GL_OES_texture_float." << std::endl;
130 return;
131 }
132
133 if ((sourceImageChannels < 3 || destImageChannels < 3) && !extensionEnabled("GL_EXT_texture_rg"))
134 {
135 std::cout << "Test skipped due to missing GL_EXT_texture_rg." << std::endl;
136 return;
137 }
138 }
139
Jamie Madillbc393df2015-01-29 13:46:07 -0500140 GLfloat sourceImageData[4][16] =
141 {
142 { // R
143 1.0f,
144 0.0f,
145 0.0f,
146 1.0f
147 },
148 { // RG
149 1.0f, 0.0f,
150 0.0f, 1.0f,
151 0.0f, 0.0f,
152 1.0f, 1.0f
153 },
154 { // RGB
155 1.0f, 0.0f, 0.0f,
156 0.0f, 1.0f, 0.0f,
157 0.0f, 0.0f, 1.0f,
158 1.0f, 1.0f, 0.0f
159 },
160 { // RGBA
161 1.0f, 0.0f, 0.0f, 1.0f,
162 0.0f, 1.0f, 0.0f, 1.0f,
163 0.0f, 0.0f, 1.0f, 1.0f,
164 1.0f, 1.0f, 0.0f, 1.0f
165 },
166 };
167
168 GLenum imageFormats[] =
169 {
170 GL_R32F,
171 GL_RG32F,
172 GL_RGB32F,
173 GL_RGBA32F,
174 };
175
176 GLenum sourceUnsizedFormats[] =
177 {
178 GL_RED,
179 GL_RG,
180 GL_RGB,
181 GL_RGBA,
182 };
183
184 GLuint textures[2];
185
186 glGenTextures(2, textures);
187
188 GLfloat *imageData = sourceImageData[sourceImageChannels - 1];
189 GLenum sourceImageFormat = imageFormats[sourceImageChannels - 1];
190 GLenum sourceUnsizedFormat = sourceUnsizedFormats[sourceImageChannels - 1];
191 GLenum destImageFormat = imageFormats[destImageChannels - 1];
192
193 glBindTexture(GL_TEXTURE_2D, textures[0]);
194 glTexStorage2DEXT(GL_TEXTURE_2D, 1, sourceImageFormat, 2, 2);
195 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
197 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, sourceUnsizedFormat, GL_FLOAT, imageData);
198
hendrikwb27f79a2015-03-04 11:26:46 -0800199 if (sourceImageChannels < 3 && !extensionEnabled("GL_EXT_texture_rg"))
Jamie Madillbc393df2015-01-29 13:46:07 -0500200 {
201 // This is not supported
202 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
203 }
204 else
205 {
206 ASSERT_GL_NO_ERROR();
207 }
208
209 GLuint fbo;
210 glGenFramebuffers(1, &fbo);
211 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
212 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
213
214 glBindTexture(GL_TEXTURE_2D, textures[1]);
215 glTexStorage2DEXT(GL_TEXTURE_2D, 1, destImageFormat, 2, 2);
216 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
218
219 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 2);
220 ASSERT_GL_NO_ERROR();
221
222 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200223 drawQuad(mProgram, "position", 0.5f);
Jamie Madillbc393df2015-01-29 13:46:07 -0500224
225 int testImageChannels = std::min(sourceImageChannels, destImageChannels);
226
227 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
228 if (testImageChannels > 1)
229 {
230 EXPECT_PIXEL_EQ(getWindowHeight() - 1, 0, 0, 255, 0, 255);
231 EXPECT_PIXEL_EQ(getWindowHeight() - 1, getWindowWidth() - 1, 255, 255, 0, 255);
232 if (testImageChannels > 2)
233 {
234 EXPECT_PIXEL_EQ(0, getWindowWidth() - 1, 0, 0, 255, 255);
235 }
236 }
237
238 glDeleteFramebuffers(1, &fbo);
239 glDeleteTextures(2, textures);
240
241 ASSERT_GL_NO_ERROR();
242 }
243
Jamie Madilld4cfa572014-07-08 10:00:32 -0400244 GLuint mTexture2D;
Jamie Madilld4cfa572014-07-08 10:00:32 -0400245 GLint mTexture2DUniformLocation;
Jamie Madillf67115c2014-04-22 13:14:05 -0400246};
247
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200248class Texture2DTestWithDrawScale : public Texture2DTest
Jamie Madill2453dbc2015-07-14 11:35:42 -0400249{
250 protected:
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200251 Texture2DTestWithDrawScale() : Texture2DTest(), mDrawScaleUniformLocation(-1) {}
252
253 std::string getVertexShaderSource() override
Jamie Madill2453dbc2015-07-14 11:35:42 -0400254 {
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200255 return std::string(SHADER_SOURCE
256 (
257 precision highp float;
258 attribute vec4 position;
259 varying vec2 texcoord;
260
261 uniform vec2 drawScale;
262
263 void main()
264 {
265 gl_Position = vec4(position.xy * drawScale, 0.0, 1.0);
266 texcoord = (position.xy * 0.5) + 0.5;
267 }
268 )
269 );
Jamie Madill2453dbc2015-07-14 11:35:42 -0400270 }
271
272 void SetUp() override
273 {
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200274 Texture2DTest::SetUp();
275 mDrawScaleUniformLocation = glGetUniformLocation(mProgram, "drawScale");
276 ASSERT_NE(-1, mDrawScaleUniformLocation);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400277
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200278 glUseProgram(mProgram);
279 glUniform2f(mDrawScaleUniformLocation, 1.0f, 1.0f);
280 glUseProgram(0);
281 ASSERT_GL_NO_ERROR();
282 }
283
284 GLint mDrawScaleUniformLocation;
285};
286
287class TextureCubeTest : public TexCoordDrawTest
288{
289 protected:
290 TextureCubeTest()
291 : TexCoordDrawTest(),
292 mTexture2D(0),
293 mTextureCube(0),
294 mTexture2DUniformLocation(-1),
295 mTextureCubeUniformLocation(-1)
296 {
297 }
298
299 std::string getFragmentShaderSource() override
300 {
301 return std::string(SHADER_SOURCE
302 (
303 precision highp float;
304 uniform sampler2D tex2D;
305 uniform samplerCube texCube;
306 varying vec2 texcoord;
307
308 void main()
309 {
310 gl_FragColor = texture2D(tex2D, texcoord);
311 gl_FragColor += textureCube(texCube, vec3(texcoord, 0));
312 }
313 )
314 );
315 }
316
317 void SetUp() override
318 {
319 TexCoordDrawTest::SetUp();
320
321 glGenTextures(1, &mTextureCube);
322 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
323 glTexStorage2DEXT(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, 1, 1);
324 EXPECT_GL_NO_ERROR();
325
326 mTexture2D = create2DTexture();
327
328 mTexture2DUniformLocation = glGetUniformLocation(mProgram, "tex2D");
329 ASSERT_NE(-1, mTexture2DUniformLocation);
330 mTextureCubeUniformLocation = glGetUniformLocation(mProgram, "texCube");
331 ASSERT_NE(-1, mTextureCubeUniformLocation);
332 }
333
334 void TearDown() override
335 {
336 glDeleteTextures(1, &mTextureCube);
337 TexCoordDrawTest::TearDown();
338 }
339
340 GLuint mTexture2D;
341 GLuint mTextureCube;
342 GLint mTexture2DUniformLocation;
343 GLint mTextureCubeUniformLocation;
344};
345
346class Texture2DArrayTestES3 : public TexCoordDrawTest
347{
348 protected:
349 Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
350
351 std::string getVertexShaderSource() override
352 {
353 return std::string(
Jamie Madill2453dbc2015-07-14 11:35:42 -0400354 "#version 300 es\n"
355 "out vec2 texcoord;\n"
356 "in vec4 position;\n"
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200357 "void main()\n"
358 "{\n"
359 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
360 " texcoord = (position.xy * 0.5) + 0.5;\n"
361 "}\n");
362 }
Jamie Madill2453dbc2015-07-14 11:35:42 -0400363
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200364 std::string getFragmentShaderSource() override
365 {
366 return std::string(
Jamie Madill2453dbc2015-07-14 11:35:42 -0400367 "#version 300 es\n"
368 "precision highp float;\n"
Olli Etuaho183d7e22015-11-20 15:59:09 +0200369 "uniform highp sampler2DArray tex2DArray;\n"
Jamie Madill2453dbc2015-07-14 11:35:42 -0400370 "in vec2 texcoord;\n"
371 "out vec4 fragColor;\n"
372 "void main()\n"
373 "{\n"
374 " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200375 "}\n");
376 }
Jamie Madill2453dbc2015-07-14 11:35:42 -0400377
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200378 void SetUp() override
379 {
380 TexCoordDrawTest::SetUp();
Jamie Madill2453dbc2015-07-14 11:35:42 -0400381
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200382 mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
Jamie Madill2453dbc2015-07-14 11:35:42 -0400383 ASSERT_NE(-1, mTextureArrayLocation);
384
385 glGenTextures(1, &m2DArrayTexture);
386 ASSERT_GL_NO_ERROR();
387 }
388
389 void TearDown() override
390 {
391 glDeleteTextures(1, &m2DArrayTexture);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200392 TexCoordDrawTest::TearDown();
Jamie Madill2453dbc2015-07-14 11:35:42 -0400393 }
394
395 GLuint m2DArrayTexture;
Jamie Madill2453dbc2015-07-14 11:35:42 -0400396 GLint mTextureArrayLocation;
397};
398
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200399TEST_P(Texture2DTest, NegativeAPISubImage)
Jamie Madillf67115c2014-04-22 13:14:05 -0400400{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400401 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Jamie Madillf67115c2014-04-22 13:14:05 -0400402 EXPECT_GL_ERROR(GL_NO_ERROR);
403
404 const GLubyte *pixels[20] = { 0 };
405 glTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
406 EXPECT_GL_ERROR(GL_INVALID_VALUE);
407}
Geoff Langc41e42d2014-04-28 10:58:16 -0400408
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200409TEST_P(Texture2DTest, ZeroSizedUploads)
Geoff Langc41e42d2014-04-28 10:58:16 -0400410{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400411 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Geoff Langc41e42d2014-04-28 10:58:16 -0400412 EXPECT_GL_ERROR(GL_NO_ERROR);
413
414 // Use the texture first to make sure it's in video memory
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200415 glUseProgram(mProgram);
Jamie Madilld4cfa572014-07-08 10:00:32 -0400416 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200417 drawQuad(mProgram, "position", 0.5f);
Geoff Langc41e42d2014-04-28 10:58:16 -0400418
419 const GLubyte *pixel[4] = { 0 };
420
421 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
422 EXPECT_GL_NO_ERROR();
423
424 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
425 EXPECT_GL_NO_ERROR();
426
427 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
428 EXPECT_GL_NO_ERROR();
429}
Jamie Madilld4cfa572014-07-08 10:00:32 -0400430
431// Test drawing with two texture types, to trigger an ANGLE bug in validation
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200432TEST_P(TextureCubeTest, CubeMapBug)
Jamie Madilld4cfa572014-07-08 10:00:32 -0400433{
434 glActiveTexture(GL_TEXTURE0);
435 glBindTexture(GL_TEXTURE_2D, mTexture2D);
436 glActiveTexture(GL_TEXTURE1);
437 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
438 EXPECT_GL_ERROR(GL_NO_ERROR);
439
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200440 glUseProgram(mProgram);
441 glUniform1i(mTexture2DUniformLocation, 0);
442 glUniform1i(mTextureCubeUniformLocation, 1);
443 drawQuad(mProgram, "position", 0.5f);
Jamie Madilld4cfa572014-07-08 10:00:32 -0400444 EXPECT_GL_NO_ERROR();
445}
Jamie Madill9aca0592014-10-06 16:26:59 -0400446
Olli Etuaho53a2da12016-01-11 15:43:32 +0200447// Test drawing with two texture types accessed from the same shader and check that the result of
448// drawing is correct.
449TEST_P(TextureCubeTest, CubeMapDraw)
450{
451 GLubyte texData[4];
452 texData[0] = 0;
453 texData[1] = 60;
454 texData[2] = 0;
455 texData[3] = 255;
456
457 glActiveTexture(GL_TEXTURE0);
458 glBindTexture(GL_TEXTURE_2D, mTexture2D);
459 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, texData);
460
461 glActiveTexture(GL_TEXTURE1);
462 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
463 texData[1] = 120;
464 glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
465 texData);
466 EXPECT_GL_ERROR(GL_NO_ERROR);
467
468 glUseProgram(mProgram);
469 glUniform1i(mTexture2DUniformLocation, 0);
470 glUniform1i(mTextureCubeUniformLocation, 1);
471 drawQuad(mProgram, "position", 0.5f);
472 EXPECT_GL_NO_ERROR();
473
474 int px = getWindowWidth() - 1;
475 int py = 0;
476 EXPECT_PIXEL_NEAR(px, py, 0, 180, 0, 255, 2);
477}
478
Jamie Madill9aca0592014-10-06 16:26:59 -0400479// Copy of a test in conformance/textures/texture-mips, to test generate mipmaps
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200480TEST_P(Texture2DTestWithDrawScale, MipmapsTwice)
Jamie Madill9aca0592014-10-06 16:26:59 -0400481{
482 int px = getWindowWidth() / 2;
483 int py = getWindowHeight() / 2;
484
485 glActiveTexture(GL_TEXTURE0);
486 glBindTexture(GL_TEXTURE_2D, mTexture2D);
487
488 // Fill with red
489 std::vector<GLubyte> pixels(4 * 16 * 16);
490 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
491 {
492 pixels[pixelId * 4 + 0] = 255;
493 pixels[pixelId * 4 + 1] = 0;
494 pixels[pixelId * 4 + 2] = 0;
495 pixels[pixelId * 4 + 3] = 255;
496 }
497
498 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
501 glGenerateMipmap(GL_TEXTURE_2D);
502
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200503 glUseProgram(mProgram);
Jamie Madill9aca0592014-10-06 16:26:59 -0400504 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200505 glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f);
506 drawQuad(mProgram, "position", 0.5f);
Jamie Madill9aca0592014-10-06 16:26:59 -0400507 EXPECT_GL_NO_ERROR();
508 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
509
510 // Fill with blue
511 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
512 {
513 pixels[pixelId * 4 + 0] = 0;
514 pixels[pixelId * 4 + 1] = 0;
515 pixels[pixelId * 4 + 2] = 255;
516 pixels[pixelId * 4 + 3] = 255;
517 }
518
519 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
520 glGenerateMipmap(GL_TEXTURE_2D);
521
522 // Fill with green
523 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
524 {
525 pixels[pixelId * 4 + 0] = 0;
526 pixels[pixelId * 4 + 1] = 255;
527 pixels[pixelId * 4 + 2] = 0;
528 pixels[pixelId * 4 + 3] = 255;
529 }
530
531 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
532 glGenerateMipmap(GL_TEXTURE_2D);
533
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200534 drawQuad(mProgram, "position", 0.5f);
Jamie Madill9aca0592014-10-06 16:26:59 -0400535
536 EXPECT_GL_NO_ERROR();
537 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
538}
Jamie Madillf8fccb32014-11-12 15:05:26 -0500539
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500540// Test creating a FBO with a cube map render target, to test an ANGLE bug
541// https://code.google.com/p/angleproject/issues/detail?id=849
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200542TEST_P(TextureCubeTest, CubeMapFBO)
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500543{
544 GLuint fbo;
545 glGenFramebuffers(1, &fbo);
546 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
547
548 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
549 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, mTextureCube, 0);
550
Corentin Wallez322653b2015-06-17 18:33:56 +0200551 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500552
553 glDeleteFramebuffers(1, &fbo);
554
555 EXPECT_GL_NO_ERROR();
556}
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000557
558// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a default color.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200559TEST_P(Texture2DTest, TexStorage)
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000560{
561 int width = getWindowWidth();
562 int height = getWindowHeight();
563
564 GLuint tex2D;
565 glGenTextures(1, &tex2D);
566 glActiveTexture(GL_TEXTURE0);
567 glBindTexture(GL_TEXTURE_2D, tex2D);
568
569 // Fill with red
570 std::vector<GLubyte> pixels(3 * 16 * 16);
571 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
572 {
573 pixels[pixelId * 3 + 0] = 255;
574 pixels[pixelId * 3 + 1] = 0;
575 pixels[pixelId * 3 + 2] = 0;
576 }
577
578 // ANGLE internally uses RGBA as the DirectX format for RGB images
579 // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
580 // The data is kept in a CPU-side image and the image is marked as dirty.
581 glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
582
583 // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
584 // glTexSubImage2D should take into account that the image is dirty.
585 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
586 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
588
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200589 glUseProgram(mProgram);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000590 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200591 drawQuad(mProgram, "position", 0.5f);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000592 glDeleteTextures(1, &tex2D);
593 EXPECT_GL_NO_ERROR();
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000594 EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
Geoff Langfbfa47c2015-03-31 11:26:00 -0400595
596 // Validate that the region of the texture without data has an alpha of 1.0
597 GLubyte pixel[4];
598 glReadPixels(3 * width / 4, 3 * height / 4, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
599 EXPECT_EQ(pixel[3], 255);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000600}
601
602// Test that glTexSubImage2D combined with a PBO works properly when glTexStorage2DEXT has initialized the image with a default color.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200603TEST_P(Texture2DTest, TexStorageWithPBO)
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000604{
605 if (extensionEnabled("NV_pixel_buffer_object"))
606 {
607 int width = getWindowWidth();
608 int height = getWindowHeight();
609
610 GLuint tex2D;
611 glGenTextures(1, &tex2D);
612 glActiveTexture(GL_TEXTURE0);
613 glBindTexture(GL_TEXTURE_2D, tex2D);
614
615 // Fill with red
616 std::vector<GLubyte> pixels(3 * 16 * 16);
617 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
618 {
619 pixels[pixelId * 3 + 0] = 255;
620 pixels[pixelId * 3 + 1] = 0;
621 pixels[pixelId * 3 + 2] = 0;
622 }
623
624 // Read 16x16 region from red backbuffer to PBO
625 GLuint pbo;
626 glGenBuffers(1, &pbo);
627 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
628 glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * 16 * 16, pixels.data(), GL_STATIC_DRAW);
629
630 // ANGLE internally uses RGBA as the DirectX format for RGB images
631 // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
632 // The data is kept in a CPU-side image and the image is marked as dirty.
633 glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
634
635 // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
636 // glTexSubImage2D should take into account that the image is dirty.
637 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, NULL);
638 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
639 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
640
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200641 glUseProgram(mProgram);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000642 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200643 drawQuad(mProgram, "position", 0.5f);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000644 glDeleteTextures(1, &tex2D);
645 glDeleteTextures(1, &pbo);
646 EXPECT_GL_NO_ERROR();
647 EXPECT_PIXEL_EQ(3 * width / 4, 3 * height / 4, 0, 0, 0, 255);
648 EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
649 }
650}
Jamie Madillbc393df2015-01-29 13:46:07 -0500651
652// See description on testFloatCopySubImage
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200653TEST_P(Texture2DTest, CopySubImageFloat_R_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500654{
655 testFloatCopySubImage(1, 1);
656}
657
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200658TEST_P(Texture2DTest, CopySubImageFloat_RG_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500659{
660 testFloatCopySubImage(2, 1);
661}
662
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200663TEST_P(Texture2DTest, CopySubImageFloat_RG_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500664{
665 testFloatCopySubImage(2, 2);
666}
667
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200668TEST_P(Texture2DTest, CopySubImageFloat_RGB_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500669{
670 testFloatCopySubImage(3, 1);
671}
672
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200673TEST_P(Texture2DTest, CopySubImageFloat_RGB_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500674{
675 testFloatCopySubImage(3, 2);
676}
677
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200678TEST_P(Texture2DTest, CopySubImageFloat_RGB_RGB)
Jamie Madillbc393df2015-01-29 13:46:07 -0500679{
680 testFloatCopySubImage(3, 3);
681}
682
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200683TEST_P(Texture2DTest, CopySubImageFloat_RGBA_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500684{
685 testFloatCopySubImage(4, 1);
686}
687
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200688TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500689{
690 testFloatCopySubImage(4, 2);
691}
692
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200693TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGB)
Jamie Madillbc393df2015-01-29 13:46:07 -0500694{
695 testFloatCopySubImage(4, 3);
696}
697
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200698TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGBA)
Jamie Madillbc393df2015-01-29 13:46:07 -0500699{
700 testFloatCopySubImage(4, 4);
701}
Austin Kinross07285142015-03-26 11:36:16 -0700702
703// Port of https://www.khronos.org/registry/webgl/conformance-suites/1.0.3/conformance/textures/texture-npot.html
704// Run against GL_ALPHA/UNSIGNED_BYTE format, to ensure that D3D11 Feature Level 9_3 correctly handles GL_ALPHA
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200705TEST_P(Texture2DTest, TextureNPOT_GL_ALPHA_UBYTE)
Austin Kinross07285142015-03-26 11:36:16 -0700706{
707 const int npotTexSize = 5;
708 const int potTexSize = 4; // Should be less than npotTexSize
709 GLuint tex2D;
710
711 if (extensionEnabled("GL_OES_texture_npot"))
712 {
713 // This test isn't applicable if texture_npot is enabled
714 return;
715 }
716
717 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
718
719 glActiveTexture(GL_TEXTURE0);
720 glGenTextures(1, &tex2D);
721 glBindTexture(GL_TEXTURE_2D, tex2D);
722
723 std::vector<GLubyte> pixels(1 * npotTexSize * npotTexSize);
724 for (size_t pixelId = 0; pixelId < npotTexSize * npotTexSize; ++pixelId)
725 {
726 pixels[pixelId] = 64;
727 }
728
729 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
730 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
731
732 // Check that an NPOT texture not on level 0 generates INVALID_VALUE
733 glTexImage2D(GL_TEXTURE_2D, 1, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
734 EXPECT_GL_ERROR(GL_INVALID_VALUE);
735
736 // Check that an NPOT texture on level 0 succeeds
737 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
738 EXPECT_GL_NO_ERROR();
739
740 // Check that generateMipmap fails on NPOT
741 glGenerateMipmap(GL_TEXTURE_2D);
742 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
743
744 // Check that nothing is drawn if filtering is not correct for NPOT
745 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
746 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
747 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
748 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
749 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200750 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700751 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
752
753 // NPOT texture with TEXTURE_MIN_FILTER not NEAREST or LINEAR should draw with 0,0,0,255
754 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
755 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
756 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
757 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200758 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700759 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
760
761 // NPOT texture with TEXTURE_MIN_FILTER set to LINEAR should draw
762 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
763 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200764 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700765 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
766
767 // Check that glTexImage2D for POT texture succeeds
768 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, potTexSize, potTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
769 EXPECT_GL_NO_ERROR();
770
771 // Check that generateMipmap for an POT texture succeeds
772 glGenerateMipmap(GL_TEXTURE_2D);
773 EXPECT_GL_NO_ERROR();
774
775 // POT texture with TEXTURE_MIN_FILTER set to LINEAR_MIPMAP_LINEAR should draw
776 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
777 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
778 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
779 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
780 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200781 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700782 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
783 EXPECT_GL_NO_ERROR();
784}
Jamie Madillfa05f602015-05-07 13:47:11 -0400785
Austin Kinross08528e12015-10-07 16:24:40 -0700786// Test to ensure that glTexSubImage2D always accepts data for non-power-of-two subregions.
787// ANGLE previously rejected this if GL_OES_texture_npot wasn't active, which is incorrect.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200788TEST_P(Texture2DTest, NPOTSubImageParameters)
Austin Kinross08528e12015-10-07 16:24:40 -0700789{
790 glActiveTexture(GL_TEXTURE0);
791 glBindTexture(GL_TEXTURE_2D, mTexture2D);
792
793 // Create an 8x8 (i.e. power-of-two) texture.
794 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
795 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
796 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
797 glGenerateMipmap(GL_TEXTURE_2D);
798
799 // Supply a 3x3 (i.e. non-power-of-two) subimage to the texture.
800 // This should always work, even if GL_OES_texture_npot isn't active.
801 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
802
803 EXPECT_GL_NO_ERROR();
804}
805
Jamie Madill2453dbc2015-07-14 11:35:42 -0400806// In the D3D11 renderer, we need to initialize some texture formats, to fill empty channels. EG RBA->RGBA8, with 1.0
807// in the alpha channel. This test covers a bug where redefining array textures with these formats does not work as
808// expected.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200809TEST_P(Texture2DArrayTestES3, RedefineInittableArray)
Jamie Madill2453dbc2015-07-14 11:35:42 -0400810{
811 std::vector<GLubyte> pixelData;
812 for (size_t count = 0; count < 5000; count++)
813 {
814 pixelData.push_back(0u);
815 pixelData.push_back(255u);
816 pixelData.push_back(0u);
817 }
818
819 glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200820 glUseProgram(mProgram);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400821 glUniform1i(mTextureArrayLocation, 0);
822
823 // The first draw worked correctly.
824 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
825
826 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
827 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
828 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
829 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200830 drawQuad(mProgram, "position", 1.0f);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400831 EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
832
833 // The dimension of the respecification must match the original exactly to trigger the bug.
834 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200835 drawQuad(mProgram, "position", 1.0f);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400836 EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
837
838 ASSERT_GL_NO_ERROR();
839}
840
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400841class TextureLimitsTest : public ANGLETest
842{
843 protected:
844 struct RGBA8
845 {
846 uint8_t R, G, B, A;
847 };
848
849 TextureLimitsTest()
850 : mProgram(0), mMaxVertexTextures(0), mMaxFragmentTextures(0), mMaxCombinedTextures(0)
851 {
852 setWindowWidth(128);
853 setWindowHeight(128);
854 setConfigRedBits(8);
855 setConfigGreenBits(8);
856 setConfigBlueBits(8);
857 setConfigAlphaBits(8);
858 }
859
860 ~TextureLimitsTest()
861 {
862 if (mProgram != 0)
863 {
864 glDeleteProgram(mProgram);
865 mProgram = 0;
866
867 if (!mTextures.empty())
868 {
869 glDeleteTextures(static_cast<GLsizei>(mTextures.size()), &mTextures[0]);
870 }
871 }
872 }
873
874 void SetUp() override
875 {
876 ANGLETest::SetUp();
877
878 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mMaxVertexTextures);
879 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mMaxFragmentTextures);
880 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxCombinedTextures);
881
882 ASSERT_GL_NO_ERROR();
883 }
884
885 void compileProgramWithTextureCounts(const std::string &vertexPrefix,
886 GLint vertexTextureCount,
887 GLint vertexActiveTextureCount,
888 const std::string &fragPrefix,
889 GLint fragmentTextureCount,
890 GLint fragmentActiveTextureCount)
891 {
892 std::stringstream vertexShaderStr;
893 vertexShaderStr << "attribute vec2 position;\n"
894 << "varying vec4 color;\n"
895 << "varying vec2 texCoord;\n";
896
897 for (GLint textureIndex = 0; textureIndex < vertexTextureCount; ++textureIndex)
898 {
899 vertexShaderStr << "uniform sampler2D " << vertexPrefix << textureIndex << ";\n";
900 }
901
902 vertexShaderStr << "void main() {\n"
903 << " gl_Position = vec4(position, 0, 1);\n"
904 << " texCoord = (position * 0.5) + 0.5;\n"
905 << " color = vec4(0);\n";
906
907 for (GLint textureIndex = 0; textureIndex < vertexActiveTextureCount; ++textureIndex)
908 {
909 vertexShaderStr << " color += texture2D(" << vertexPrefix << textureIndex
910 << ", texCoord);\n";
911 }
912
913 vertexShaderStr << "}";
914
915 std::stringstream fragmentShaderStr;
916 fragmentShaderStr << "varying mediump vec4 color;\n"
917 << "varying mediump vec2 texCoord;\n";
918
919 for (GLint textureIndex = 0; textureIndex < fragmentTextureCount; ++textureIndex)
920 {
921 fragmentShaderStr << "uniform sampler2D " << fragPrefix << textureIndex << ";\n";
922 }
923
924 fragmentShaderStr << "void main() {\n"
925 << " gl_FragColor = color;\n";
926
927 for (GLint textureIndex = 0; textureIndex < fragmentActiveTextureCount; ++textureIndex)
928 {
929 fragmentShaderStr << " gl_FragColor += texture2D(" << fragPrefix << textureIndex
930 << ", texCoord);\n";
931 }
932
933 fragmentShaderStr << "}";
934
935 const std::string &vertexShaderSource = vertexShaderStr.str();
936 const std::string &fragmentShaderSource = fragmentShaderStr.str();
937
938 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
939 }
940
941 RGBA8 getPixel(GLint texIndex)
942 {
943 RGBA8 pixel = {static_cast<uint8_t>(texIndex & 0x7u), static_cast<uint8_t>(texIndex >> 3),
944 0, 255u};
945 return pixel;
946 }
947
948 void initTextures(GLint tex2DCount, GLint texCubeCount)
949 {
950 GLint totalCount = tex2DCount + texCubeCount;
951 mTextures.assign(totalCount, 0);
952 glGenTextures(totalCount, &mTextures[0]);
953 ASSERT_GL_NO_ERROR();
954
955 std::vector<RGBA8> texData(16 * 16);
956
957 GLint texIndex = 0;
958 for (; texIndex < tex2DCount; ++texIndex)
959 {
960 texData.assign(texData.size(), getPixel(texIndex));
961 glActiveTexture(GL_TEXTURE0 + texIndex);
962 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
963 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
964 &texData[0]);
965 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
966 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
967 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
968 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
969 }
970
971 ASSERT_GL_NO_ERROR();
972
973 for (; texIndex < texCubeCount; ++texIndex)
974 {
975 texData.assign(texData.size(), getPixel(texIndex));
976 glActiveTexture(GL_TEXTURE0 + texIndex);
977 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[texIndex]);
978 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
979 GL_UNSIGNED_BYTE, &texData[0]);
980 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
981 GL_UNSIGNED_BYTE, &texData[0]);
982 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
983 GL_UNSIGNED_BYTE, &texData[0]);
984 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
985 GL_UNSIGNED_BYTE, &texData[0]);
986 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
987 GL_UNSIGNED_BYTE, &texData[0]);
988 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
989 GL_UNSIGNED_BYTE, &texData[0]);
990 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
991 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
992 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
993 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
994 }
995
996 ASSERT_GL_NO_ERROR();
997 }
998
999 void testWithTextures(GLint vertexTextureCount,
1000 const std::string &vertexTexturePrefix,
1001 GLint fragmentTextureCount,
1002 const std::string &fragmentTexturePrefix)
1003 {
1004 // Generate textures
1005 initTextures(vertexTextureCount + fragmentTextureCount, 0);
1006
1007 glUseProgram(mProgram);
1008 RGBA8 expectedSum = {0};
1009 for (GLint texIndex = 0; texIndex < vertexTextureCount; ++texIndex)
1010 {
1011 std::stringstream uniformNameStr;
1012 uniformNameStr << vertexTexturePrefix << texIndex;
1013 const std::string &uniformName = uniformNameStr.str();
1014 GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
1015 ASSERT_NE(-1, location);
1016
1017 glUniform1i(location, texIndex);
1018 RGBA8 contribution = getPixel(texIndex);
1019 expectedSum.R += contribution.R;
1020 expectedSum.G += contribution.G;
1021 }
1022
1023 for (GLint texIndex = 0; texIndex < fragmentTextureCount; ++texIndex)
1024 {
1025 std::stringstream uniformNameStr;
1026 uniformNameStr << fragmentTexturePrefix << texIndex;
1027 const std::string &uniformName = uniformNameStr.str();
1028 GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
1029 ASSERT_NE(-1, location);
1030
1031 glUniform1i(location, texIndex + vertexTextureCount);
1032 RGBA8 contribution = getPixel(texIndex + vertexTextureCount);
1033 expectedSum.R += contribution.R;
1034 expectedSum.G += contribution.G;
1035 }
1036
1037 ASSERT_GE(256u, expectedSum.G);
1038
1039 drawQuad(mProgram, "position", 0.5f);
1040 ASSERT_GL_NO_ERROR();
1041 EXPECT_PIXEL_EQ(0, 0, expectedSum.R, expectedSum.G, 0, 255);
1042 }
1043
1044 GLuint mProgram;
1045 std::vector<GLuint> mTextures;
1046 GLint mMaxVertexTextures;
1047 GLint mMaxFragmentTextures;
1048 GLint mMaxCombinedTextures;
1049};
1050
1051// Test rendering with the maximum vertex texture units.
1052TEST_P(TextureLimitsTest, MaxVertexTextures)
1053{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001054 // TODO(jmadill): Figure out why this fails on Intel.
1055 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1056 {
1057 std::cout << "Test skipped on Intel." << std::endl;
1058 return;
1059 }
1060
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001061 compileProgramWithTextureCounts("tex", mMaxVertexTextures, mMaxVertexTextures, "tex", 0, 0);
1062 ASSERT_NE(0u, mProgram);
1063 ASSERT_GL_NO_ERROR();
1064
1065 testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
1066}
1067
1068// Test rendering with the maximum fragment texture units.
1069TEST_P(TextureLimitsTest, MaxFragmentTextures)
1070{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001071 // TODO(jmadill): Figure out why this fails on Intel.
1072 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1073 {
1074 std::cout << "Test skipped on Intel." << std::endl;
1075 return;
1076 }
1077
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001078 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures, mMaxFragmentTextures);
1079 ASSERT_NE(0u, mProgram);
1080 ASSERT_GL_NO_ERROR();
1081
1082 testWithTextures(mMaxFragmentTextures, "tex", 0, "tex");
1083}
1084
1085// Test rendering with maximum combined texture units.
1086TEST_P(TextureLimitsTest, MaxCombinedTextures)
1087{
Jamie Madill412f17d2015-09-25 08:43:54 -04001088 // TODO(jmadill): Investigate workaround.
1089 if (isIntel() && GetParam() == ES2_OPENGL())
1090 {
1091 std::cout << "Test skipped on Intel." << std::endl;
1092 return;
1093 }
1094
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001095 GLint vertexTextures = mMaxVertexTextures;
1096
1097 if (vertexTextures + mMaxFragmentTextures > mMaxCombinedTextures)
1098 {
1099 vertexTextures = mMaxCombinedTextures - mMaxFragmentTextures;
1100 }
1101
1102 compileProgramWithTextureCounts("vtex", vertexTextures, vertexTextures, "ftex",
1103 mMaxFragmentTextures, mMaxFragmentTextures);
1104 ASSERT_NE(0u, mProgram);
1105 ASSERT_GL_NO_ERROR();
1106
1107 testWithTextures(vertexTextures, "vtex", mMaxFragmentTextures, "ftex");
1108}
1109
1110// Negative test for exceeding the number of vertex textures
1111TEST_P(TextureLimitsTest, ExcessiveVertexTextures)
1112{
1113 compileProgramWithTextureCounts("tex", mMaxVertexTextures + 1, mMaxVertexTextures + 1, "tex", 0,
1114 0);
1115 ASSERT_EQ(0u, mProgram);
1116}
1117
1118// Negative test for exceeding the number of fragment textures
1119TEST_P(TextureLimitsTest, ExcessiveFragmentTextures)
1120{
1121 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 1,
1122 mMaxFragmentTextures + 1);
1123 ASSERT_EQ(0u, mProgram);
1124}
1125
1126// Test active vertex textures under the limit, but excessive textures specified.
1127TEST_P(TextureLimitsTest, MaxActiveVertexTextures)
1128{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001129 // TODO(jmadill): Figure out why this fails on Intel.
1130 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1131 {
1132 std::cout << "Test skipped on Intel." << std::endl;
1133 return;
1134 }
1135
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001136 compileProgramWithTextureCounts("tex", mMaxVertexTextures + 4, mMaxVertexTextures, "tex", 0, 0);
1137 ASSERT_NE(0u, mProgram);
1138 ASSERT_GL_NO_ERROR();
1139
1140 testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
1141}
1142
1143// Test active fragment textures under the limit, but excessive textures specified.
1144TEST_P(TextureLimitsTest, MaxActiveFragmentTextures)
1145{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001146 // TODO(jmadill): Figure out why this fails on Intel.
1147 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1148 {
1149 std::cout << "Test skipped on Intel." << std::endl;
1150 return;
1151 }
1152
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001153 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 4,
1154 mMaxFragmentTextures);
1155 ASSERT_NE(0u, mProgram);
1156 ASSERT_GL_NO_ERROR();
1157
1158 testWithTextures(0, "tex", mMaxFragmentTextures, "tex");
1159}
1160
1161// Negative test for pointing two sampler uniforms of different types to the same texture.
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001162// GLES 2.0.25 section 2.10.4 page 39.
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001163TEST_P(TextureLimitsTest, TextureTypeConflict)
1164{
1165 const std::string &vertexShader =
1166 "attribute vec2 position;\n"
1167 "varying float color;\n"
1168 "uniform sampler2D tex2D;\n"
1169 "uniform samplerCube texCube;\n"
1170 "void main() {\n"
1171 " gl_Position = vec4(position, 0, 1);\n"
1172 " vec2 texCoord = (position * 0.5) + 0.5;\n"
1173 " color = texture2D(tex2D, texCoord).x;\n"
1174 " color += textureCube(texCube, vec3(texCoord, 0)).x;\n"
1175 "}";
1176 const std::string &fragmentShader =
1177 "varying mediump float color;\n"
1178 "void main() {\n"
1179 " gl_FragColor = vec4(color, 0, 0, 1);\n"
1180 "}";
1181
1182 mProgram = CompileProgram(vertexShader, fragmentShader);
1183 ASSERT_NE(0u, mProgram);
1184
1185 initTextures(1, 0);
1186
1187 glUseProgram(mProgram);
1188 GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
1189 ASSERT_NE(-1, tex2DLocation);
1190 GLint texCubeLocation = glGetUniformLocation(mProgram, "texCube");
1191 ASSERT_NE(-1, texCubeLocation);
1192
1193 glUniform1i(tex2DLocation, 0);
1194 glUniform1i(texCubeLocation, 0);
1195 ASSERT_GL_NO_ERROR();
1196
1197 drawQuad(mProgram, "position", 0.5f);
1198 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1199}
1200
1201// Negative test for rendering with texture outside the valid range.
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001202// TODO(jmadill): Possibly adjust the test according to the spec:
1203// GLES 3.0.4 section 2.12.7 mentions that specifying an out-of-range sampler uniform value
1204// generates an INVALID_VALUE error - GLES 2.0 doesn't yet have this mention.
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001205TEST_P(TextureLimitsTest, DrawWithTexturePastMaximum)
1206{
1207 const std::string &vertexShader =
1208 "attribute vec2 position;\n"
1209 "varying float color;\n"
1210 "uniform sampler2D tex2D;\n"
1211 "void main() {\n"
1212 " gl_Position = vec4(position, 0, 1);\n"
1213 " vec2 texCoord = (position * 0.5) + 0.5;\n"
1214 " color = texture2D(tex2D, texCoord).x;\n"
1215 "}";
1216 const std::string &fragmentShader =
1217 "varying mediump float color;\n"
1218 "void main() {\n"
1219 " gl_FragColor = vec4(color, 0, 0, 1);\n"
1220 "}";
1221
1222 mProgram = CompileProgram(vertexShader, fragmentShader);
1223 ASSERT_NE(0u, mProgram);
1224
1225 glUseProgram(mProgram);
1226 GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
1227 ASSERT_NE(-1, tex2DLocation);
1228
1229 glUniform1i(tex2DLocation, mMaxCombinedTextures);
1230 ASSERT_GL_NO_ERROR();
1231
1232 drawQuad(mProgram, "position", 0.5f);
1233 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1234}
1235
Jamie Madillfa05f602015-05-07 13:47:11 -04001236// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001237// TODO(geofflang): Figure out why tests below fail on Intel OpenGL:
1238ANGLE_INSTANTIATE_TEST(Texture2DTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
1239ANGLE_INSTANTIATE_TEST(TextureCubeTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
1240ANGLE_INSTANTIATE_TEST(Texture2DTestWithDrawScale, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
1241ANGLE_INSTANTIATE_TEST(Texture2DArrayTestES3, ES3_D3D11(), ES3_OPENGL());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001242ANGLE_INSTANTIATE_TEST(TextureLimitsTest, ES2_D3D11(), ES2_OPENGL());
Jamie Madillfa05f602015-05-07 13:47:11 -04001243
1244} // namespace