blob: 7aff3f4e6e9016c3431ab475dd9f1fd0036082fb [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
Olli Etuaho4644a202016-01-12 15:12:53 +0200287class Sampler2DAsFunctionParameterTest : public Texture2DTest
288{
289 protected:
290 Sampler2DAsFunctionParameterTest() : Texture2DTest() {}
291
292 std::string getFragmentShaderSource() override
293 {
294 return std::string(SHADER_SOURCE
295 (
296 precision highp float;
297 uniform sampler2D tex;
298 varying vec2 texcoord;
299
300 vec4 computeFragColor(sampler2D aTex)
301 {
302 return texture2D(aTex, texcoord);
303 }
304
305 void main()
306 {
307 gl_FragColor = computeFragColor(tex);
308 }
309 )
310 );
311 }
312};
313
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200314class TextureCubeTest : public TexCoordDrawTest
315{
316 protected:
317 TextureCubeTest()
318 : TexCoordDrawTest(),
319 mTexture2D(0),
320 mTextureCube(0),
321 mTexture2DUniformLocation(-1),
322 mTextureCubeUniformLocation(-1)
323 {
324 }
325
326 std::string getFragmentShaderSource() override
327 {
328 return std::string(SHADER_SOURCE
329 (
330 precision highp float;
331 uniform sampler2D tex2D;
332 uniform samplerCube texCube;
333 varying vec2 texcoord;
334
335 void main()
336 {
337 gl_FragColor = texture2D(tex2D, texcoord);
338 gl_FragColor += textureCube(texCube, vec3(texcoord, 0));
339 }
340 )
341 );
342 }
343
344 void SetUp() override
345 {
346 TexCoordDrawTest::SetUp();
347
348 glGenTextures(1, &mTextureCube);
349 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
350 glTexStorage2DEXT(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, 1, 1);
351 EXPECT_GL_NO_ERROR();
352
353 mTexture2D = create2DTexture();
354
355 mTexture2DUniformLocation = glGetUniformLocation(mProgram, "tex2D");
356 ASSERT_NE(-1, mTexture2DUniformLocation);
357 mTextureCubeUniformLocation = glGetUniformLocation(mProgram, "texCube");
358 ASSERT_NE(-1, mTextureCubeUniformLocation);
359 }
360
361 void TearDown() override
362 {
363 glDeleteTextures(1, &mTextureCube);
364 TexCoordDrawTest::TearDown();
365 }
366
367 GLuint mTexture2D;
368 GLuint mTextureCube;
369 GLint mTexture2DUniformLocation;
370 GLint mTextureCubeUniformLocation;
371};
372
373class Texture2DArrayTestES3 : public TexCoordDrawTest
374{
375 protected:
376 Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
377
378 std::string getVertexShaderSource() override
379 {
380 return std::string(
Jamie Madill2453dbc2015-07-14 11:35:42 -0400381 "#version 300 es\n"
382 "out vec2 texcoord;\n"
383 "in vec4 position;\n"
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200384 "void main()\n"
385 "{\n"
386 " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
387 " texcoord = (position.xy * 0.5) + 0.5;\n"
388 "}\n");
389 }
Jamie Madill2453dbc2015-07-14 11:35:42 -0400390
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200391 std::string getFragmentShaderSource() override
392 {
393 return std::string(
Jamie Madill2453dbc2015-07-14 11:35:42 -0400394 "#version 300 es\n"
395 "precision highp float;\n"
Olli Etuaho183d7e22015-11-20 15:59:09 +0200396 "uniform highp sampler2DArray tex2DArray;\n"
Jamie Madill2453dbc2015-07-14 11:35:42 -0400397 "in vec2 texcoord;\n"
398 "out vec4 fragColor;\n"
399 "void main()\n"
400 "{\n"
401 " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200402 "}\n");
403 }
Jamie Madill2453dbc2015-07-14 11:35:42 -0400404
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200405 void SetUp() override
406 {
407 TexCoordDrawTest::SetUp();
Jamie Madill2453dbc2015-07-14 11:35:42 -0400408
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200409 mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
Jamie Madill2453dbc2015-07-14 11:35:42 -0400410 ASSERT_NE(-1, mTextureArrayLocation);
411
412 glGenTextures(1, &m2DArrayTexture);
413 ASSERT_GL_NO_ERROR();
414 }
415
416 void TearDown() override
417 {
418 glDeleteTextures(1, &m2DArrayTexture);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200419 TexCoordDrawTest::TearDown();
Jamie Madill2453dbc2015-07-14 11:35:42 -0400420 }
421
422 GLuint m2DArrayTexture;
Jamie Madill2453dbc2015-07-14 11:35:42 -0400423 GLint mTextureArrayLocation;
424};
425
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200426TEST_P(Texture2DTest, NegativeAPISubImage)
Jamie Madillf67115c2014-04-22 13:14:05 -0400427{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400428 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Jamie Madillf67115c2014-04-22 13:14:05 -0400429 EXPECT_GL_ERROR(GL_NO_ERROR);
430
431 const GLubyte *pixels[20] = { 0 };
432 glTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
433 EXPECT_GL_ERROR(GL_INVALID_VALUE);
434}
Geoff Langc41e42d2014-04-28 10:58:16 -0400435
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200436TEST_P(Texture2DTest, ZeroSizedUploads)
Geoff Langc41e42d2014-04-28 10:58:16 -0400437{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400438 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Geoff Langc41e42d2014-04-28 10:58:16 -0400439 EXPECT_GL_ERROR(GL_NO_ERROR);
440
441 // Use the texture first to make sure it's in video memory
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200442 glUseProgram(mProgram);
Jamie Madilld4cfa572014-07-08 10:00:32 -0400443 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200444 drawQuad(mProgram, "position", 0.5f);
Geoff Langc41e42d2014-04-28 10:58:16 -0400445
446 const GLubyte *pixel[4] = { 0 };
447
448 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
449 EXPECT_GL_NO_ERROR();
450
451 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
452 EXPECT_GL_NO_ERROR();
453
454 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
455 EXPECT_GL_NO_ERROR();
456}
Jamie Madilld4cfa572014-07-08 10:00:32 -0400457
458// Test drawing with two texture types, to trigger an ANGLE bug in validation
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200459TEST_P(TextureCubeTest, CubeMapBug)
Jamie Madilld4cfa572014-07-08 10:00:32 -0400460{
461 glActiveTexture(GL_TEXTURE0);
462 glBindTexture(GL_TEXTURE_2D, mTexture2D);
463 glActiveTexture(GL_TEXTURE1);
464 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
465 EXPECT_GL_ERROR(GL_NO_ERROR);
466
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200467 glUseProgram(mProgram);
468 glUniform1i(mTexture2DUniformLocation, 0);
469 glUniform1i(mTextureCubeUniformLocation, 1);
470 drawQuad(mProgram, "position", 0.5f);
Jamie Madilld4cfa572014-07-08 10:00:32 -0400471 EXPECT_GL_NO_ERROR();
472}
Jamie Madill9aca0592014-10-06 16:26:59 -0400473
Olli Etuaho53a2da12016-01-11 15:43:32 +0200474// Test drawing with two texture types accessed from the same shader and check that the result of
475// drawing is correct.
476TEST_P(TextureCubeTest, CubeMapDraw)
477{
478 GLubyte texData[4];
479 texData[0] = 0;
480 texData[1] = 60;
481 texData[2] = 0;
482 texData[3] = 255;
483
484 glActiveTexture(GL_TEXTURE0);
485 glBindTexture(GL_TEXTURE_2D, mTexture2D);
486 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, texData);
487
488 glActiveTexture(GL_TEXTURE1);
489 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
490 texData[1] = 120;
491 glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
492 texData);
493 EXPECT_GL_ERROR(GL_NO_ERROR);
494
495 glUseProgram(mProgram);
496 glUniform1i(mTexture2DUniformLocation, 0);
497 glUniform1i(mTextureCubeUniformLocation, 1);
498 drawQuad(mProgram, "position", 0.5f);
499 EXPECT_GL_NO_ERROR();
500
501 int px = getWindowWidth() - 1;
502 int py = 0;
503 EXPECT_PIXEL_NEAR(px, py, 0, 180, 0, 255, 2);
504}
505
Olli Etuaho4644a202016-01-12 15:12:53 +0200506TEST_P(Sampler2DAsFunctionParameterTest, Sampler2DAsFunctionParameter)
507{
508 glActiveTexture(GL_TEXTURE0);
509 glBindTexture(GL_TEXTURE_2D, mTexture2D);
510 GLubyte texData[4];
511 texData[0] = 0;
512 texData[1] = 128;
513 texData[2] = 0;
514 texData[3] = 255;
515 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, texData);
516 glUseProgram(mProgram);
517 glUniform1i(mTexture2DUniformLocation, 0);
518 drawQuad(mProgram, "position", 0.5f);
519 EXPECT_GL_NO_ERROR();
520
521 EXPECT_PIXEL_NEAR(0, 0, 0, 128, 0, 255, 2);
522}
523
Jamie Madill9aca0592014-10-06 16:26:59 -0400524// Copy of a test in conformance/textures/texture-mips, to test generate mipmaps
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200525TEST_P(Texture2DTestWithDrawScale, MipmapsTwice)
Jamie Madill9aca0592014-10-06 16:26:59 -0400526{
527 int px = getWindowWidth() / 2;
528 int py = getWindowHeight() / 2;
529
530 glActiveTexture(GL_TEXTURE0);
531 glBindTexture(GL_TEXTURE_2D, mTexture2D);
532
533 // Fill with red
534 std::vector<GLubyte> pixels(4 * 16 * 16);
535 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
536 {
537 pixels[pixelId * 4 + 0] = 255;
538 pixels[pixelId * 4 + 1] = 0;
539 pixels[pixelId * 4 + 2] = 0;
540 pixels[pixelId * 4 + 3] = 255;
541 }
542
543 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
545 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
546 glGenerateMipmap(GL_TEXTURE_2D);
547
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200548 glUseProgram(mProgram);
Jamie Madill9aca0592014-10-06 16:26:59 -0400549 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200550 glUniform2f(mDrawScaleUniformLocation, 0.0625f, 0.0625f);
551 drawQuad(mProgram, "position", 0.5f);
Jamie Madill9aca0592014-10-06 16:26:59 -0400552 EXPECT_GL_NO_ERROR();
553 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
554
555 // Fill with blue
556 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
557 {
558 pixels[pixelId * 4 + 0] = 0;
559 pixels[pixelId * 4 + 1] = 0;
560 pixels[pixelId * 4 + 2] = 255;
561 pixels[pixelId * 4 + 3] = 255;
562 }
563
564 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
565 glGenerateMipmap(GL_TEXTURE_2D);
566
567 // Fill with green
568 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
569 {
570 pixels[pixelId * 4 + 0] = 0;
571 pixels[pixelId * 4 + 1] = 255;
572 pixels[pixelId * 4 + 2] = 0;
573 pixels[pixelId * 4 + 3] = 255;
574 }
575
576 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
577 glGenerateMipmap(GL_TEXTURE_2D);
578
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200579 drawQuad(mProgram, "position", 0.5f);
Jamie Madill9aca0592014-10-06 16:26:59 -0400580
581 EXPECT_GL_NO_ERROR();
582 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
583}
Jamie Madillf8fccb32014-11-12 15:05:26 -0500584
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500585// Test creating a FBO with a cube map render target, to test an ANGLE bug
586// https://code.google.com/p/angleproject/issues/detail?id=849
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200587TEST_P(TextureCubeTest, CubeMapFBO)
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500588{
589 GLuint fbo;
590 glGenFramebuffers(1, &fbo);
591 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
592
593 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
594 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, mTextureCube, 0);
595
Corentin Wallez322653b2015-06-17 18:33:56 +0200596 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
Jamie Madilleb32a2e2014-12-10 14:27:53 -0500597
598 glDeleteFramebuffers(1, &fbo);
599
600 EXPECT_GL_NO_ERROR();
601}
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000602
603// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a default color.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200604TEST_P(Texture2DTest, TexStorage)
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000605{
606 int width = getWindowWidth();
607 int height = getWindowHeight();
608
609 GLuint tex2D;
610 glGenTextures(1, &tex2D);
611 glActiveTexture(GL_TEXTURE0);
612 glBindTexture(GL_TEXTURE_2D, tex2D);
613
614 // Fill with red
615 std::vector<GLubyte> pixels(3 * 16 * 16);
616 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
617 {
618 pixels[pixelId * 3 + 0] = 255;
619 pixels[pixelId * 3 + 1] = 0;
620 pixels[pixelId * 3 + 2] = 0;
621 }
622
623 // ANGLE internally uses RGBA as the DirectX format for RGB images
624 // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
625 // The data is kept in a CPU-side image and the image is marked as dirty.
626 glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
627
628 // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
629 // glTexSubImage2D should take into account that the image is dirty.
630 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
631 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
632 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
633
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200634 glUseProgram(mProgram);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000635 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200636 drawQuad(mProgram, "position", 0.5f);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000637 glDeleteTextures(1, &tex2D);
638 EXPECT_GL_NO_ERROR();
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000639 EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
Geoff Langfbfa47c2015-03-31 11:26:00 -0400640
641 // Validate that the region of the texture without data has an alpha of 1.0
642 GLubyte pixel[4];
643 glReadPixels(3 * width / 4, 3 * height / 4, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
644 EXPECT_EQ(pixel[3], 255);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000645}
646
647// 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 +0200648TEST_P(Texture2DTest, TexStorageWithPBO)
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000649{
650 if (extensionEnabled("NV_pixel_buffer_object"))
651 {
652 int width = getWindowWidth();
653 int height = getWindowHeight();
654
655 GLuint tex2D;
656 glGenTextures(1, &tex2D);
657 glActiveTexture(GL_TEXTURE0);
658 glBindTexture(GL_TEXTURE_2D, tex2D);
659
660 // Fill with red
661 std::vector<GLubyte> pixels(3 * 16 * 16);
662 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
663 {
664 pixels[pixelId * 3 + 0] = 255;
665 pixels[pixelId * 3 + 1] = 0;
666 pixels[pixelId * 3 + 2] = 0;
667 }
668
669 // Read 16x16 region from red backbuffer to PBO
670 GLuint pbo;
671 glGenBuffers(1, &pbo);
672 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
673 glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * 16 * 16, pixels.data(), GL_STATIC_DRAW);
674
675 // ANGLE internally uses RGBA as the DirectX format for RGB images
676 // therefore glTexStorage2DEXT initializes the image to a default color to get a consistent alpha color.
677 // The data is kept in a CPU-side image and the image is marked as dirty.
678 glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGB8, 16, 16);
679
680 // Initializes the color of the upper-left 8x8 pixels, leaves the other pixels untouched.
681 // glTexSubImage2D should take into account that the image is dirty.
682 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGB, GL_UNSIGNED_BYTE, NULL);
683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
685
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200686 glUseProgram(mProgram);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000687 glUniform1i(mTexture2DUniformLocation, 0);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200688 drawQuad(mProgram, "position", 0.5f);
Gregoire Payen de La Garanderie88fe1ad2015-01-19 15:09:26 +0000689 glDeleteTextures(1, &tex2D);
690 glDeleteTextures(1, &pbo);
691 EXPECT_GL_NO_ERROR();
692 EXPECT_PIXEL_EQ(3 * width / 4, 3 * height / 4, 0, 0, 0, 255);
693 EXPECT_PIXEL_EQ(width / 4, height / 4, 255, 0, 0, 255);
694 }
695}
Jamie Madillbc393df2015-01-29 13:46:07 -0500696
697// See description on testFloatCopySubImage
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200698TEST_P(Texture2DTest, CopySubImageFloat_R_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500699{
700 testFloatCopySubImage(1, 1);
701}
702
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200703TEST_P(Texture2DTest, CopySubImageFloat_RG_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500704{
705 testFloatCopySubImage(2, 1);
706}
707
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200708TEST_P(Texture2DTest, CopySubImageFloat_RG_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500709{
710 testFloatCopySubImage(2, 2);
711}
712
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200713TEST_P(Texture2DTest, CopySubImageFloat_RGB_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500714{
715 testFloatCopySubImage(3, 1);
716}
717
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200718TEST_P(Texture2DTest, CopySubImageFloat_RGB_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500719{
720 testFloatCopySubImage(3, 2);
721}
722
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200723TEST_P(Texture2DTest, CopySubImageFloat_RGB_RGB)
Jamie Madillbc393df2015-01-29 13:46:07 -0500724{
725 testFloatCopySubImage(3, 3);
726}
727
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200728TEST_P(Texture2DTest, CopySubImageFloat_RGBA_R)
Jamie Madillbc393df2015-01-29 13:46:07 -0500729{
730 testFloatCopySubImage(4, 1);
731}
732
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200733TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RG)
Jamie Madillbc393df2015-01-29 13:46:07 -0500734{
735 testFloatCopySubImage(4, 2);
736}
737
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200738TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGB)
Jamie Madillbc393df2015-01-29 13:46:07 -0500739{
740 testFloatCopySubImage(4, 3);
741}
742
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200743TEST_P(Texture2DTest, CopySubImageFloat_RGBA_RGBA)
Jamie Madillbc393df2015-01-29 13:46:07 -0500744{
745 testFloatCopySubImage(4, 4);
746}
Austin Kinross07285142015-03-26 11:36:16 -0700747
748// Port of https://www.khronos.org/registry/webgl/conformance-suites/1.0.3/conformance/textures/texture-npot.html
749// 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 +0200750TEST_P(Texture2DTest, TextureNPOT_GL_ALPHA_UBYTE)
Austin Kinross07285142015-03-26 11:36:16 -0700751{
752 const int npotTexSize = 5;
753 const int potTexSize = 4; // Should be less than npotTexSize
754 GLuint tex2D;
755
756 if (extensionEnabled("GL_OES_texture_npot"))
757 {
758 // This test isn't applicable if texture_npot is enabled
759 return;
760 }
761
762 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
763
764 glActiveTexture(GL_TEXTURE0);
765 glGenTextures(1, &tex2D);
766 glBindTexture(GL_TEXTURE_2D, tex2D);
767
768 std::vector<GLubyte> pixels(1 * npotTexSize * npotTexSize);
769 for (size_t pixelId = 0; pixelId < npotTexSize * npotTexSize; ++pixelId)
770 {
771 pixels[pixelId] = 64;
772 }
773
774 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
775 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
776
777 // Check that an NPOT texture not on level 0 generates INVALID_VALUE
778 glTexImage2D(GL_TEXTURE_2D, 1, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
779 EXPECT_GL_ERROR(GL_INVALID_VALUE);
780
781 // Check that an NPOT texture on level 0 succeeds
782 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, npotTexSize, npotTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
783 EXPECT_GL_NO_ERROR();
784
785 // Check that generateMipmap fails on NPOT
786 glGenerateMipmap(GL_TEXTURE_2D);
787 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
788
789 // Check that nothing is drawn if filtering is not correct for NPOT
790 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
791 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
792 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
793 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
794 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200795 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700796 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
797
798 // NPOT texture with TEXTURE_MIN_FILTER not NEAREST or LINEAR should draw with 0,0,0,255
799 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
800 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
801 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
802 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200803 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700804 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 255);
805
806 // NPOT texture with TEXTURE_MIN_FILTER set to LINEAR should draw
807 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
808 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200809 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700810 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
811
812 // Check that glTexImage2D for POT texture succeeds
813 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, potTexSize, potTexSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels.data());
814 EXPECT_GL_NO_ERROR();
815
816 // Check that generateMipmap for an POT texture succeeds
817 glGenerateMipmap(GL_TEXTURE_2D);
818 EXPECT_GL_NO_ERROR();
819
820 // POT texture with TEXTURE_MIN_FILTER set to LINEAR_MIPMAP_LINEAR should draw
821 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
822 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
823 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
824 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
825 glClear(GL_COLOR_BUFFER_BIT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200826 drawQuad(mProgram, "position", 1.0f);
Austin Kinross07285142015-03-26 11:36:16 -0700827 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 0, 64);
828 EXPECT_GL_NO_ERROR();
829}
Jamie Madillfa05f602015-05-07 13:47:11 -0400830
Austin Kinross08528e12015-10-07 16:24:40 -0700831// Test to ensure that glTexSubImage2D always accepts data for non-power-of-two subregions.
832// ANGLE previously rejected this if GL_OES_texture_npot wasn't active, which is incorrect.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200833TEST_P(Texture2DTest, NPOTSubImageParameters)
Austin Kinross08528e12015-10-07 16:24:40 -0700834{
835 glActiveTexture(GL_TEXTURE0);
836 glBindTexture(GL_TEXTURE_2D, mTexture2D);
837
838 // Create an 8x8 (i.e. power-of-two) texture.
839 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
840 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
841 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
842 glGenerateMipmap(GL_TEXTURE_2D);
843
844 // Supply a 3x3 (i.e. non-power-of-two) subimage to the texture.
845 // This should always work, even if GL_OES_texture_npot isn't active.
846 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, 3, 3, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
847
848 EXPECT_GL_NO_ERROR();
849}
850
Jamie Madill2453dbc2015-07-14 11:35:42 -0400851// In the D3D11 renderer, we need to initialize some texture formats, to fill empty channels. EG RBA->RGBA8, with 1.0
852// in the alpha channel. This test covers a bug where redefining array textures with these formats does not work as
853// expected.
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200854TEST_P(Texture2DArrayTestES3, RedefineInittableArray)
Jamie Madill2453dbc2015-07-14 11:35:42 -0400855{
856 std::vector<GLubyte> pixelData;
857 for (size_t count = 0; count < 5000; count++)
858 {
859 pixelData.push_back(0u);
860 pixelData.push_back(255u);
861 pixelData.push_back(0u);
862 }
863
864 glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200865 glUseProgram(mProgram);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400866 glUniform1i(mTextureArrayLocation, 0);
867
868 // The first draw worked correctly.
869 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 4, 4, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelData[0]);
870
871 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
872 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
873 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
874 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
Olli Etuaho4a8329f2016-01-11 17:12:57 +0200875 drawQuad(mProgram, "position", 1.0f);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400876 EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
877
878 // The dimension of the respecification must match the original exactly to trigger the bug.
879 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 +0200880 drawQuad(mProgram, "position", 1.0f);
Jamie Madill2453dbc2015-07-14 11:35:42 -0400881 EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
882
883 ASSERT_GL_NO_ERROR();
884}
885
Jamie Madill3d3d2f22015-09-23 16:47:51 -0400886class TextureLimitsTest : public ANGLETest
887{
888 protected:
889 struct RGBA8
890 {
891 uint8_t R, G, B, A;
892 };
893
894 TextureLimitsTest()
895 : mProgram(0), mMaxVertexTextures(0), mMaxFragmentTextures(0), mMaxCombinedTextures(0)
896 {
897 setWindowWidth(128);
898 setWindowHeight(128);
899 setConfigRedBits(8);
900 setConfigGreenBits(8);
901 setConfigBlueBits(8);
902 setConfigAlphaBits(8);
903 }
904
905 ~TextureLimitsTest()
906 {
907 if (mProgram != 0)
908 {
909 glDeleteProgram(mProgram);
910 mProgram = 0;
911
912 if (!mTextures.empty())
913 {
914 glDeleteTextures(static_cast<GLsizei>(mTextures.size()), &mTextures[0]);
915 }
916 }
917 }
918
919 void SetUp() override
920 {
921 ANGLETest::SetUp();
922
923 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mMaxVertexTextures);
924 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mMaxFragmentTextures);
925 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mMaxCombinedTextures);
926
927 ASSERT_GL_NO_ERROR();
928 }
929
930 void compileProgramWithTextureCounts(const std::string &vertexPrefix,
931 GLint vertexTextureCount,
932 GLint vertexActiveTextureCount,
933 const std::string &fragPrefix,
934 GLint fragmentTextureCount,
935 GLint fragmentActiveTextureCount)
936 {
937 std::stringstream vertexShaderStr;
938 vertexShaderStr << "attribute vec2 position;\n"
939 << "varying vec4 color;\n"
940 << "varying vec2 texCoord;\n";
941
942 for (GLint textureIndex = 0; textureIndex < vertexTextureCount; ++textureIndex)
943 {
944 vertexShaderStr << "uniform sampler2D " << vertexPrefix << textureIndex << ";\n";
945 }
946
947 vertexShaderStr << "void main() {\n"
948 << " gl_Position = vec4(position, 0, 1);\n"
949 << " texCoord = (position * 0.5) + 0.5;\n"
950 << " color = vec4(0);\n";
951
952 for (GLint textureIndex = 0; textureIndex < vertexActiveTextureCount; ++textureIndex)
953 {
954 vertexShaderStr << " color += texture2D(" << vertexPrefix << textureIndex
955 << ", texCoord);\n";
956 }
957
958 vertexShaderStr << "}";
959
960 std::stringstream fragmentShaderStr;
961 fragmentShaderStr << "varying mediump vec4 color;\n"
962 << "varying mediump vec2 texCoord;\n";
963
964 for (GLint textureIndex = 0; textureIndex < fragmentTextureCount; ++textureIndex)
965 {
966 fragmentShaderStr << "uniform sampler2D " << fragPrefix << textureIndex << ";\n";
967 }
968
969 fragmentShaderStr << "void main() {\n"
970 << " gl_FragColor = color;\n";
971
972 for (GLint textureIndex = 0; textureIndex < fragmentActiveTextureCount; ++textureIndex)
973 {
974 fragmentShaderStr << " gl_FragColor += texture2D(" << fragPrefix << textureIndex
975 << ", texCoord);\n";
976 }
977
978 fragmentShaderStr << "}";
979
980 const std::string &vertexShaderSource = vertexShaderStr.str();
981 const std::string &fragmentShaderSource = fragmentShaderStr.str();
982
983 mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
984 }
985
986 RGBA8 getPixel(GLint texIndex)
987 {
988 RGBA8 pixel = {static_cast<uint8_t>(texIndex & 0x7u), static_cast<uint8_t>(texIndex >> 3),
989 0, 255u};
990 return pixel;
991 }
992
993 void initTextures(GLint tex2DCount, GLint texCubeCount)
994 {
995 GLint totalCount = tex2DCount + texCubeCount;
996 mTextures.assign(totalCount, 0);
997 glGenTextures(totalCount, &mTextures[0]);
998 ASSERT_GL_NO_ERROR();
999
1000 std::vector<RGBA8> texData(16 * 16);
1001
1002 GLint texIndex = 0;
1003 for (; texIndex < tex2DCount; ++texIndex)
1004 {
1005 texData.assign(texData.size(), getPixel(texIndex));
1006 glActiveTexture(GL_TEXTURE0 + texIndex);
1007 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
1008 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1009 &texData[0]);
1010 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1011 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1012 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1013 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1014 }
1015
1016 ASSERT_GL_NO_ERROR();
1017
1018 for (; texIndex < texCubeCount; ++texIndex)
1019 {
1020 texData.assign(texData.size(), getPixel(texIndex));
1021 glActiveTexture(GL_TEXTURE0 + texIndex);
1022 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[texIndex]);
1023 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1024 GL_UNSIGNED_BYTE, &texData[0]);
1025 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1026 GL_UNSIGNED_BYTE, &texData[0]);
1027 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1028 GL_UNSIGNED_BYTE, &texData[0]);
1029 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1030 GL_UNSIGNED_BYTE, &texData[0]);
1031 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1032 GL_UNSIGNED_BYTE, &texData[0]);
1033 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
1034 GL_UNSIGNED_BYTE, &texData[0]);
1035 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1036 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1037 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1038 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1039 }
1040
1041 ASSERT_GL_NO_ERROR();
1042 }
1043
1044 void testWithTextures(GLint vertexTextureCount,
1045 const std::string &vertexTexturePrefix,
1046 GLint fragmentTextureCount,
1047 const std::string &fragmentTexturePrefix)
1048 {
1049 // Generate textures
1050 initTextures(vertexTextureCount + fragmentTextureCount, 0);
1051
1052 glUseProgram(mProgram);
1053 RGBA8 expectedSum = {0};
1054 for (GLint texIndex = 0; texIndex < vertexTextureCount; ++texIndex)
1055 {
1056 std::stringstream uniformNameStr;
1057 uniformNameStr << vertexTexturePrefix << texIndex;
1058 const std::string &uniformName = uniformNameStr.str();
1059 GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
1060 ASSERT_NE(-1, location);
1061
1062 glUniform1i(location, texIndex);
1063 RGBA8 contribution = getPixel(texIndex);
1064 expectedSum.R += contribution.R;
1065 expectedSum.G += contribution.G;
1066 }
1067
1068 for (GLint texIndex = 0; texIndex < fragmentTextureCount; ++texIndex)
1069 {
1070 std::stringstream uniformNameStr;
1071 uniformNameStr << fragmentTexturePrefix << texIndex;
1072 const std::string &uniformName = uniformNameStr.str();
1073 GLint location = glGetUniformLocation(mProgram, uniformName.c_str());
1074 ASSERT_NE(-1, location);
1075
1076 glUniform1i(location, texIndex + vertexTextureCount);
1077 RGBA8 contribution = getPixel(texIndex + vertexTextureCount);
1078 expectedSum.R += contribution.R;
1079 expectedSum.G += contribution.G;
1080 }
1081
1082 ASSERT_GE(256u, expectedSum.G);
1083
1084 drawQuad(mProgram, "position", 0.5f);
1085 ASSERT_GL_NO_ERROR();
1086 EXPECT_PIXEL_EQ(0, 0, expectedSum.R, expectedSum.G, 0, 255);
1087 }
1088
1089 GLuint mProgram;
1090 std::vector<GLuint> mTextures;
1091 GLint mMaxVertexTextures;
1092 GLint mMaxFragmentTextures;
1093 GLint mMaxCombinedTextures;
1094};
1095
1096// Test rendering with the maximum vertex texture units.
1097TEST_P(TextureLimitsTest, MaxVertexTextures)
1098{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001099 // TODO(jmadill): Figure out why this fails on Intel.
1100 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1101 {
1102 std::cout << "Test skipped on Intel." << std::endl;
1103 return;
1104 }
1105
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001106 compileProgramWithTextureCounts("tex", mMaxVertexTextures, mMaxVertexTextures, "tex", 0, 0);
1107 ASSERT_NE(0u, mProgram);
1108 ASSERT_GL_NO_ERROR();
1109
1110 testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
1111}
1112
1113// Test rendering with the maximum fragment texture units.
1114TEST_P(TextureLimitsTest, MaxFragmentTextures)
1115{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001116 // TODO(jmadill): Figure out why this fails on Intel.
1117 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1118 {
1119 std::cout << "Test skipped on Intel." << std::endl;
1120 return;
1121 }
1122
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001123 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures, mMaxFragmentTextures);
1124 ASSERT_NE(0u, mProgram);
1125 ASSERT_GL_NO_ERROR();
1126
1127 testWithTextures(mMaxFragmentTextures, "tex", 0, "tex");
1128}
1129
1130// Test rendering with maximum combined texture units.
1131TEST_P(TextureLimitsTest, MaxCombinedTextures)
1132{
Jamie Madill412f17d2015-09-25 08:43:54 -04001133 // TODO(jmadill): Investigate workaround.
1134 if (isIntel() && GetParam() == ES2_OPENGL())
1135 {
1136 std::cout << "Test skipped on Intel." << std::endl;
1137 return;
1138 }
1139
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001140 GLint vertexTextures = mMaxVertexTextures;
1141
1142 if (vertexTextures + mMaxFragmentTextures > mMaxCombinedTextures)
1143 {
1144 vertexTextures = mMaxCombinedTextures - mMaxFragmentTextures;
1145 }
1146
1147 compileProgramWithTextureCounts("vtex", vertexTextures, vertexTextures, "ftex",
1148 mMaxFragmentTextures, mMaxFragmentTextures);
1149 ASSERT_NE(0u, mProgram);
1150 ASSERT_GL_NO_ERROR();
1151
1152 testWithTextures(vertexTextures, "vtex", mMaxFragmentTextures, "ftex");
1153}
1154
1155// Negative test for exceeding the number of vertex textures
1156TEST_P(TextureLimitsTest, ExcessiveVertexTextures)
1157{
1158 compileProgramWithTextureCounts("tex", mMaxVertexTextures + 1, mMaxVertexTextures + 1, "tex", 0,
1159 0);
1160 ASSERT_EQ(0u, mProgram);
1161}
1162
1163// Negative test for exceeding the number of fragment textures
1164TEST_P(TextureLimitsTest, ExcessiveFragmentTextures)
1165{
1166 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 1,
1167 mMaxFragmentTextures + 1);
1168 ASSERT_EQ(0u, mProgram);
1169}
1170
1171// Test active vertex textures under the limit, but excessive textures specified.
1172TEST_P(TextureLimitsTest, MaxActiveVertexTextures)
1173{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001174 // TODO(jmadill): Figure out why this fails on Intel.
1175 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1176 {
1177 std::cout << "Test skipped on Intel." << std::endl;
1178 return;
1179 }
1180
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001181 compileProgramWithTextureCounts("tex", mMaxVertexTextures + 4, mMaxVertexTextures, "tex", 0, 0);
1182 ASSERT_NE(0u, mProgram);
1183 ASSERT_GL_NO_ERROR();
1184
1185 testWithTextures(mMaxVertexTextures, "tex", 0, "tex");
1186}
1187
1188// Test active fragment textures under the limit, but excessive textures specified.
1189TEST_P(TextureLimitsTest, MaxActiveFragmentTextures)
1190{
Jamie Madill1ea9aaa2015-10-07 11:13:55 -04001191 // TODO(jmadill): Figure out why this fails on Intel.
1192 if (isIntel() && GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
1193 {
1194 std::cout << "Test skipped on Intel." << std::endl;
1195 return;
1196 }
1197
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001198 compileProgramWithTextureCounts("tex", 0, 0, "tex", mMaxFragmentTextures + 4,
1199 mMaxFragmentTextures);
1200 ASSERT_NE(0u, mProgram);
1201 ASSERT_GL_NO_ERROR();
1202
1203 testWithTextures(0, "tex", mMaxFragmentTextures, "tex");
1204}
1205
1206// Negative test for pointing two sampler uniforms of different types to the same texture.
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001207// GLES 2.0.25 section 2.10.4 page 39.
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001208TEST_P(TextureLimitsTest, TextureTypeConflict)
1209{
1210 const std::string &vertexShader =
1211 "attribute vec2 position;\n"
1212 "varying float color;\n"
1213 "uniform sampler2D tex2D;\n"
1214 "uniform samplerCube texCube;\n"
1215 "void main() {\n"
1216 " gl_Position = vec4(position, 0, 1);\n"
1217 " vec2 texCoord = (position * 0.5) + 0.5;\n"
1218 " color = texture2D(tex2D, texCoord).x;\n"
1219 " color += textureCube(texCube, vec3(texCoord, 0)).x;\n"
1220 "}";
1221 const std::string &fragmentShader =
1222 "varying mediump float color;\n"
1223 "void main() {\n"
1224 " gl_FragColor = vec4(color, 0, 0, 1);\n"
1225 "}";
1226
1227 mProgram = CompileProgram(vertexShader, fragmentShader);
1228 ASSERT_NE(0u, mProgram);
1229
1230 initTextures(1, 0);
1231
1232 glUseProgram(mProgram);
1233 GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
1234 ASSERT_NE(-1, tex2DLocation);
1235 GLint texCubeLocation = glGetUniformLocation(mProgram, "texCube");
1236 ASSERT_NE(-1, texCubeLocation);
1237
1238 glUniform1i(tex2DLocation, 0);
1239 glUniform1i(texCubeLocation, 0);
1240 ASSERT_GL_NO_ERROR();
1241
1242 drawQuad(mProgram, "position", 0.5f);
1243 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1244}
1245
1246// Negative test for rendering with texture outside the valid range.
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001247// TODO(jmadill): Possibly adjust the test according to the spec:
1248// GLES 3.0.4 section 2.12.7 mentions that specifying an out-of-range sampler uniform value
1249// generates an INVALID_VALUE error - GLES 2.0 doesn't yet have this mention.
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001250TEST_P(TextureLimitsTest, DrawWithTexturePastMaximum)
1251{
1252 const std::string &vertexShader =
1253 "attribute vec2 position;\n"
1254 "varying float color;\n"
1255 "uniform sampler2D tex2D;\n"
1256 "void main() {\n"
1257 " gl_Position = vec4(position, 0, 1);\n"
1258 " vec2 texCoord = (position * 0.5) + 0.5;\n"
1259 " color = texture2D(tex2D, texCoord).x;\n"
1260 "}";
1261 const std::string &fragmentShader =
1262 "varying mediump float color;\n"
1263 "void main() {\n"
1264 " gl_FragColor = vec4(color, 0, 0, 1);\n"
1265 "}";
1266
1267 mProgram = CompileProgram(vertexShader, fragmentShader);
1268 ASSERT_NE(0u, mProgram);
1269
1270 glUseProgram(mProgram);
1271 GLint tex2DLocation = glGetUniformLocation(mProgram, "tex2D");
1272 ASSERT_NE(-1, tex2DLocation);
1273
1274 glUniform1i(tex2DLocation, mMaxCombinedTextures);
1275 ASSERT_GL_NO_ERROR();
1276
1277 drawQuad(mProgram, "position", 0.5f);
1278 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1279}
1280
Jamie Madillfa05f602015-05-07 13:47:11 -04001281// 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 +02001282// TODO(geofflang): Figure out why tests below fail on Intel OpenGL:
1283ANGLE_INSTANTIATE_TEST(Texture2DTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
1284ANGLE_INSTANTIATE_TEST(TextureCubeTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
1285ANGLE_INSTANTIATE_TEST(Texture2DTestWithDrawScale, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
Olli Etuaho4644a202016-01-12 15:12:53 +02001286ANGLE_INSTANTIATE_TEST(Sampler2DAsFunctionParameterTest, ES2_D3D9(), ES2_D3D11(), ES2_D3D11_FL9_3());
Olli Etuaho4a8329f2016-01-11 17:12:57 +02001287ANGLE_INSTANTIATE_TEST(Texture2DArrayTestES3, ES3_D3D11(), ES3_OPENGL());
Jamie Madill3d3d2f22015-09-23 16:47:51 -04001288ANGLE_INSTANTIATE_TEST(TextureLimitsTest, ES2_D3D11(), ES2_OPENGL());
Jamie Madillfa05f602015-05-07 13:47:11 -04001289
1290} // namespace