blob: 8c311657c664ab49faaf67b4f3804fb1122cab77 [file] [log] [blame]
Austin Kinross215b37a2014-12-22 12:56:07 -08001#include "ANGLETest.h"
2
3// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
4ANGLE_TYPED_TEST_CASE(MipmapTest, ES2_D3D9, ES2_D3D11, ES2_D3D11_FL9_3);
5ANGLE_TYPED_TEST_CASE(MipmapTestES3, ES3_D3D11);
6
7template<typename T>
8class MipmapTest : public ANGLETest
9{
10 protected:
11 MipmapTest() : ANGLETest(T::GetGlesMajorVersion(), T::GetPlatform())
12 {
13 setWindowWidth(128);
14 setWindowHeight(128);
15 setConfigRedBits(8);
16 setConfigGreenBits(8);
17 setConfigBlueBits(8);
18 setConfigAlphaBits(8);
19 }
20
21 virtual void SetUp()
22 {
23 ANGLETest::SetUp();
24
25 // Vertex Shader source
26 const std::string vs = SHADER_SOURCE
27 (
28 attribute vec4 aPosition;
29 attribute vec2 aTexCoord;
30 varying vec2 vTexCoord;
31
32 void main()
33 {
34 gl_Position = aPosition;
35 vTexCoord = aTexCoord;
36 }
37 );
38
39 // Fragment Shader source
40 const std::string fs = SHADER_SOURCE
41 (
42 precision mediump float;
43
44 uniform sampler2D uTexture;
45 varying vec2 vTexCoord;
46
47 void main()
48 {
49 gl_FragColor = texture2D(uTexture, vTexCoord);
50 }
51 );
52
53 mProgram = CompileProgram(vs, fs);
54 if (mProgram == 0)
55 {
56 FAIL() << "shader compilation failed.";
57 }
58
59 mTextureUniformPosition = glGetUniformLocation(mProgram, "uTexture");
60 mPositionAttributePosition = glGetAttribLocation(mProgram, "aPosition");
61 mTexCoordAttributePosition = glGetAttribLocation(mProgram, "aTexCoord");
62
63 glGenFramebuffers(1, &mOffscreenFramebuffer);
64 glGenTextures(1, &mOffscreenTexture);
65
66 // Initialize the texture to be empty, and don't use mips.
67 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture);
68 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
71
72 ASSERT_GL_NO_ERROR();
73
74 // Bind the texture to the offscreen framebuffer's color buffer.
75 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
76 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mOffscreenTexture, 0);
77 ASSERT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
78
79 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
80 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
81 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
82 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
83 }
84
85 virtual void TearDown()
86 {
87 glDeleteProgram(mProgram);
88 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
89 glDeleteFramebuffers(1, &mOffscreenTexture);
90
91 delete mLevelZeroBlueInitData;
92 delete mLevelZeroWhiteInitData;
93 delete mLevelOneInitData;
94 delete mLevelTwoInitData;
95
96 ANGLETest::TearDown();
97 }
98
99 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
100 {
101 GLubyte *data = new GLubyte[3 * width * height];
102
103 for (int i = 0; i < width * height; i+=1)
104 {
105 data[3 * i + 0] = r;
106 data[3 * i + 1] = g;
107 data[3 * i + 2] = b;
108 }
109
110 return data;
111 }
112
113 void ClearAndDrawTexturedQuad(GLuint texture, GLsizei viewportWidth, GLsizei viewportHeight)
114 {
115 glBindFramebuffer(GL_FRAMEBUFFER, 0);
116 glClear(GL_COLOR_BUFFER_BIT);
117
118 glViewport(0, 0, viewportWidth, viewportHeight);
119
120 ASSERT_GL_NO_ERROR();
121
122 GLfloat vertexLocations[] =
123 {
124 -1.0f, 1.0f, 0.0f,
125 -1.0f, -1.0f, 0.0f,
126 1.0f, 1.0f, 0.0f,
127 1.0f, -1.0f, 0.0f,
128 };
129
130 GLfloat vertexTexCoords[] =
131 {
132 0.0f, 1.0f,
133 0.0f, 0.0f,
134 1.0f, 1.0f,
135 1.0f, 0.0f,
136 };
137
138 glUseProgram(mProgram);
139
140 glActiveTexture(GL_TEXTURE0);
141 glBindTexture(GL_TEXTURE_2D, texture);
142 glUniform1i(mTextureUniformPosition, 0);
143
144 glVertexAttribPointer(mPositionAttributePosition, 3, GL_FLOAT, GL_FALSE, 0, vertexLocations);
145 glEnableVertexAttribArray(mPositionAttributePosition);
146
147 glVertexAttribPointer(mTexCoordAttributePosition, 2, GL_FLOAT, GL_FALSE, 0, vertexTexCoords);
148 glEnableVertexAttribArray(mTexCoordAttributePosition);
149
150 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
151 }
152
153 GLuint mProgram;
154 GLuint mOffscreenFramebuffer;
155 GLuint mOffscreenTexture;
156
157 GLint mTextureUniformPosition;
158 GLint mPositionAttributePosition;
159 GLint mTexCoordAttributePosition;
160
161 GLubyte* mLevelZeroBlueInitData;
162 GLubyte* mLevelZeroWhiteInitData;
163 GLubyte* mLevelOneInitData;
164 GLubyte* mLevelTwoInitData;
165};
166
167template<typename T>
168class MipmapTestES3 : public ANGLETest
169{
170protected:
171 MipmapTestES3() : ANGLETest(T::GetGlesMajorVersion(), T::GetPlatform())
172 {
173 setWindowWidth(128);
174 setWindowHeight(128);
175 setConfigRedBits(8);
176 setConfigGreenBits(8);
177 setConfigBlueBits(8);
178 setConfigAlphaBits(8);
179 }
180
181 virtual void SetUp()
182 {
183 ANGLETest::SetUp();
184
185 glGenTextures(1, &mTextureArray);
186 EXPECT_GL_NO_ERROR();
187
188 ASSERT_GL_NO_ERROR();
189
190 const std::string vertexShaderSource = SHADER_SOURCE
191 (
192 #version 300 es\n
193 precision highp float;
194 in vec4 position;
195 out vec2 texcoord;
196
197 uniform vec2 textureScale;
198
199 void main()
200 {
201 gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
202 texcoord = (position.xy * 0.5) + 0.5;
203 }
204 );
205
206 const std::string fragmentShaderSourceArray = SHADER_SOURCE
207 (
208 #version 300 es\n
209 precision highp float;
210 uniform sampler2DArray tex;
211 uniform int slice;
212 in vec2 texcoord;
213 out vec4 out_FragColor;
214
215 void main()
216 {
217 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
218 }
219 );
220
221 mArrayProgram = CompileProgram(vertexShaderSource, fragmentShaderSourceArray);
222 if (mArrayProgram == 0)
223 {
224 FAIL() << "shader compilation failed.";
225 }
226
227 mTextureArrayUniformLocation = glGetUniformLocation(mArrayProgram, "tex");
228 ASSERT_NE(-1, mTextureArrayUniformLocation);
229
230 mTextureArrayScaleUniformLocation = glGetUniformLocation(mArrayProgram, "textureScale");
231 ASSERT_NE(-1, mTextureArrayScaleUniformLocation);
232
233 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
234 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
235
236 glUseProgram(mArrayProgram);
237 glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
238 glUseProgram(0);
239 ASSERT_GL_NO_ERROR();
240 }
241
242 virtual void TearDown()
243 {
244 glDeleteTextures(1, &mTextureArray);
245 glDeleteProgram(mArrayProgram);
246
247 ANGLETest::TearDown();
248 }
249
250 GLuint mTextureArray;
251
252 GLuint mArrayProgram;
253 GLint mTextureArrayUniformLocation;
254 GLint mTextureArrayScaleUniformLocation;
255 GLint mTextureArraySliceUniformLocation;
256};
257
258// This test uses init data for the first three levels of the texture. It passes the level 0 data in, then renders, then level 1, then renders, etc.
259// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
260// even if the the zero-LOD texture is currently in use.
Austin Kinross276171b2015-01-15 13:16:18 -0800261TYPED_TEST(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800262{
263 // Pass in level zero init data.
264 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture);
265 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
266 ASSERT_GL_NO_ERROR();
267
268 // Disable mips.
269 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
270
271 // Draw a full-sized quad, and check it's blue.
272 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
273 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
274
275 // Draw a half-sized quad, and check it's blue.
276 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
277 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
278
279 // Draw a quarter-sized quad, and check it's blue.
280 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
281 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
282
283 // Complete the texture by initializing the remaining levels.
284 int n = 1;
285 while (getWindowWidth() / pow(2, n) >= 1)
286 {
287 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / pow(2, n), getWindowWidth() / pow(2, n), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
288 ASSERT_GL_NO_ERROR();
289 n+=1;
290 }
291
292 // Pass in level one init data.
293 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
294 ASSERT_GL_NO_ERROR();
295
296 // Draw a full-sized quad, and check it's blue.
297 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
298 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
299
300 // Draw a half-sized quad, and check it's blue. We've not enabled mipmaps yet, so our init data for level one shouldn't be used.
301 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
302 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
303
304 // Enable mipmaps.
305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
306
307 // Draw a half-sized quad, and check it's green.
308 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
309 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
310
311 // Draw a quarter-sized quad, and check it's black, since we've not passed any init data for level two.
312 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
313 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 0, 255);
314
315 // Pass in level two init data.
316 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
317 ASSERT_GL_NO_ERROR();
318
319 // Draw a full-sized quad, and check it's blue.
320 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
321 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
322
323 // Draw a half-sized quad, and check it's green.
324 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
325 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
326
327 // Draw a quarter-sized quad, and check it's red.
328 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
329 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
330
331 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
333 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
334 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
335 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
336 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
337 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
338 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
339
340 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
341 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
342 ASSERT_GL_NO_ERROR();
343
344 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
345 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
346 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
347 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255);
348 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
349 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 255, 255, 255);
350
351 // Then enable mipmaps again. The quads should be white, green, red respectively.
352 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
353
354 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
355 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
356 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
357 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
358 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
359 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
360}
361
362// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
363// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
364// To do this, D3D11 has to convert the TextureStorage into a renderable one.
365// This test ensures that the conversion works correctly.
366// In particular, on D3D11 Feature Level 9_3 it ensures that both the zero LOD workaround texture AND the 'normal' texture are copied during conversion.
367TYPED_TEST(MipmapTest, GenerateMipmapFromInitDataThenRender)
368{
369 // Pass in initial data so the texture is blue.
370 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
371
372 // Then generate the mips.
373 glGenerateMipmap(GL_TEXTURE_2D);
374 ASSERT_GL_NO_ERROR();
375
376 // Enable mipmaps.
377 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
378
379 // Now draw the texture to various different sized areas.
380 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
381 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
382
383 // Use mip level 1
384 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
385 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
386
387 // Use mip level 2
388 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
389 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
390
391 ASSERT_GL_NO_ERROR();
392
393 // Disable mips. Render a quad using the texture and ensure it's blue.
394 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
395 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
396 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
397
398 // Clear level 0 of the texture.
399 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
400 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
401 glClear(GL_COLOR_BUFFER_BIT);
402
403 // Reenable mips, and try rendering different-sized quads.
404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
405
406 // Level 0 is now red, so this should render red.
407 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
408 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
409
410 // Use mip level 1, blue.
411 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
412 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
413
414 // Use mip level 2, blue.
415 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
416 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
417}
418
419// This test ensures that mips are correctly generated from a rendered image.
420// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
421// The test ensures that the zero-level texture is correctly copied into the mipped texture before the mipmaps are generated.
422TYPED_TEST(MipmapTest, GenerateMipmapFromRenderedImage)
423{
424 // Bind the offscreen framebuffer/texture.
425 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
426
427 // Clear the texture to blue.
428 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
429 glClear(GL_COLOR_BUFFER_BIT);
430
431 // Then generate the mips
432 glGenerateMipmap(GL_TEXTURE_2D);
433 ASSERT_GL_NO_ERROR();
434
435 // Enable mips.
436 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
437
438 // Now draw the texture to various different sized areas.
439 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
440 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
441
442 // Use mip level 1
443 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
444 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
445
446 // Use mip level 2
447 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
448 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
449}
450
451// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
452// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
453TYPED_TEST(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
454{
455 // Bind the offscreen texture/framebuffer.
456 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
457
458 // Clear the texture to blue.
459 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
460 glClear(GL_COLOR_BUFFER_BIT);
461
462 // From now on, default clear color is black.
463 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
464
465 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
466 // The quad should be blue.
467 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
468 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
469
470 // Now go back to the texture, and generate mips on it.
471 glGenerateMipmap(GL_TEXTURE_2D);
472 ASSERT_GL_NO_ERROR();
473
474 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
475 // The quad should be blue.
476 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
477 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
478
479 // Now tell GL to use the generated mips.
480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
481 EXPECT_EQ(glGetError(), GL_NONE);
482
483 // Now render the textured quad again. It should be still be blue.
484 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
485 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
486
487 // Now render the textured quad to an area smaller than the texture (i.e. to force minification). This should be blue.
488 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
489 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
490
491 // Now clear the texture to green. This just clears the top level. The lower mips should remain blue.
492 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
493 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
494 glClear(GL_COLOR_BUFFER_BIT);
495
496 // From now on, default clear color is black.
497 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
498
499 // Render a textured quad equal in size to the texture. This should be green, since we just cleared level 0.
500 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
501 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
502
503 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
504 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
505 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
506
507 // Disable mipmaps again
508 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
509 ASSERT_GL_NO_ERROR();
510
511 // Render a textured quad equal in size to the texture. This should be green, the color of level 0 in the texture.
512 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
513 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
514
515 // Render a small textured quad. This would force minification if mips were enabled, but they're not. Therefore, this should be green.
516 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
517 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 255, 0, 255);
518}
519
520// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
521// Then tests if the mipmaps are rendered correctly for all three layers.
522TYPED_TEST(MipmapTestES3, MipmapsForTextureArray)
523{
524 int px = getWindowWidth() / 2;
525 int py = getWindowHeight() / 2;
526
527 glActiveTexture(GL_TEXTURE0);
528 glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
529
530 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
531
532 // Fill the first layer with red
533 std::vector<GLubyte> pixels(4 * 16 * 16);
534 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
535 {
536 pixels[pixelId * 4 + 0] = 255;
537 pixels[pixelId * 4 + 1] = 0;
538 pixels[pixelId * 4 + 2] = 0;
539 pixels[pixelId * 4 + 3] = 255;
540 }
541
542 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
543
544 // Fill the second layer with green
545 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
546 {
547 pixels[pixelId * 4 + 0] = 0;
548 pixels[pixelId * 4 + 1] = 255;
549 pixels[pixelId * 4 + 2] = 0;
550 pixels[pixelId * 4 + 3] = 255;
551 }
552
553 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
554
555 // Fill the third layer 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 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
565
566 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
567 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
568
569 EXPECT_GL_NO_ERROR();
570
571 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
572
573 EXPECT_GL_NO_ERROR();
574
575 glUseProgram(mArrayProgram);
576 glUniform1i(mTextureArrayUniformLocation, 0);
577
578 EXPECT_GL_NO_ERROR();
579
580 // Draw the first slice
581 glUseProgram(mArrayProgram);
582 glUniform1i(mTextureArraySliceUniformLocation, 0);
583 drawQuad(mArrayProgram, "position", 0.5f);
584 EXPECT_GL_NO_ERROR();
585 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
586
587 // Draw the second slice
588 glUseProgram(mArrayProgram);
589 glUniform1i(mTextureArraySliceUniformLocation, 1);
590 drawQuad(mArrayProgram, "position", 0.5f);
591 EXPECT_GL_NO_ERROR();
592 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
593
594 // Draw the third slice
595 glUseProgram(mArrayProgram);
596 glUniform1i(mTextureArraySliceUniformLocation, 2);
597 drawQuad(mArrayProgram, "position", 0.5f);
598 EXPECT_GL_NO_ERROR();
599 EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
600}