blob: 842e96ae2fb77438f7f8ce667e5903a18b34e882 [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
Austin Kinrosse8c86272015-01-15 18:55:36 -0800190 // Don't put "#version ..." on its own line. See [cpp]p1:
191 // "If there are sequences of preprocessing tokens within the list of arguments that
192 // would otherwise act as preprocessing directives, the behavior is undefined"
Austin Kinross215b37a2014-12-22 12:56:07 -0800193 const std::string vertexShaderSource = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800194 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800195 precision highp float;
196 in vec4 position;
197 out vec2 texcoord;
198
199 uniform vec2 textureScale;
200
201 void main()
202 {
203 gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
204 texcoord = (position.xy * 0.5) + 0.5;
205 }
206 );
207
208 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800209 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800210 precision highp float;
211 uniform sampler2DArray tex;
212 uniform int slice;
213 in vec2 texcoord;
214 out vec4 out_FragColor;
215
216 void main()
217 {
218 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
219 }
220 );
221
222 mArrayProgram = CompileProgram(vertexShaderSource, fragmentShaderSourceArray);
223 if (mArrayProgram == 0)
224 {
225 FAIL() << "shader compilation failed.";
226 }
227
228 mTextureArrayUniformLocation = glGetUniformLocation(mArrayProgram, "tex");
229 ASSERT_NE(-1, mTextureArrayUniformLocation);
230
231 mTextureArrayScaleUniformLocation = glGetUniformLocation(mArrayProgram, "textureScale");
232 ASSERT_NE(-1, mTextureArrayScaleUniformLocation);
233
234 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
235 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
236
237 glUseProgram(mArrayProgram);
238 glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
239 glUseProgram(0);
240 ASSERT_GL_NO_ERROR();
241 }
242
243 virtual void TearDown()
244 {
245 glDeleteTextures(1, &mTextureArray);
246 glDeleteProgram(mArrayProgram);
247
248 ANGLETest::TearDown();
249 }
250
251 GLuint mTextureArray;
252
253 GLuint mArrayProgram;
254 GLint mTextureArrayUniformLocation;
255 GLint mTextureArrayScaleUniformLocation;
256 GLint mTextureArraySliceUniformLocation;
257};
258
259// 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.
260// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
261// even if the the zero-LOD texture is currently in use.
Austin Kinross276171b2015-01-15 13:16:18 -0800262TYPED_TEST(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800263{
264 // Pass in level zero init data.
265 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture);
266 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
267 ASSERT_GL_NO_ERROR();
268
269 // Disable mips.
270 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
271
272 // Draw a full-sized quad, and check it's blue.
273 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
274 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
275
276 // Draw a half-sized quad, and check it's blue.
277 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
278 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
279
280 // Draw a quarter-sized quad, and check it's blue.
281 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
282 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
283
284 // Complete the texture by initializing the remaining levels.
285 int n = 1;
286 while (getWindowWidth() / pow(2, n) >= 1)
287 {
288 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / pow(2, n), getWindowWidth() / pow(2, n), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
289 ASSERT_GL_NO_ERROR();
290 n+=1;
291 }
292
293 // Pass in level one init data.
294 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
295 ASSERT_GL_NO_ERROR();
296
297 // Draw a full-sized quad, and check it's blue.
298 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
299 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
300
301 // 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.
302 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
303 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
304
305 // Enable mipmaps.
306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
307
308 // Draw a half-sized quad, and check it's green.
309 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
310 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
311
312 // Draw a quarter-sized quad, and check it's black, since we've not passed any init data for level two.
313 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
314 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 0, 255);
315
316 // Pass in level two init data.
317 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
318 ASSERT_GL_NO_ERROR();
319
320 // Draw a full-sized quad, and check it's blue.
321 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
322 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
323
324 // Draw a half-sized quad, and check it's green.
325 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
326 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
327
328 // Draw a quarter-sized quad, and check it's red.
329 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
330 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
331
332 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
334 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
335 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
336 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
337 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
338 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
339 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
340
341 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
342 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
343 ASSERT_GL_NO_ERROR();
344
345 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
346 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
347 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
348 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255);
349 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
350 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 255, 255, 255);
351
352 // Then enable mipmaps again. The quads should be white, green, red respectively.
353 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
354
355 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
356 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
357 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
358 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
359 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
360 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
361}
362
363// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
364// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
365// To do this, D3D11 has to convert the TextureStorage into a renderable one.
366// This test ensures that the conversion works correctly.
367// 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.
368TYPED_TEST(MipmapTest, GenerateMipmapFromInitDataThenRender)
369{
370 // Pass in initial data so the texture is blue.
371 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
372
373 // Then generate the mips.
374 glGenerateMipmap(GL_TEXTURE_2D);
375 ASSERT_GL_NO_ERROR();
376
377 // Enable mipmaps.
378 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
379
380 // Now draw the texture to various different sized areas.
381 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
382 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
383
384 // Use mip level 1
385 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
386 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
387
388 // Use mip level 2
389 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
390 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
391
392 ASSERT_GL_NO_ERROR();
393
394 // Disable mips. Render a quad using the texture and ensure it's blue.
395 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
396 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
397 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
398
399 // Clear level 0 of the texture.
400 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
401 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
402 glClear(GL_COLOR_BUFFER_BIT);
403
404 // Reenable mips, and try rendering different-sized quads.
405 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
406
407 // Level 0 is now red, so this should render red.
408 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
409 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
410
411 // Use mip level 1, blue.
412 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
413 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
414
415 // Use mip level 2, blue.
416 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
417 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
418}
419
420// This test ensures that mips are correctly generated from a rendered image.
421// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
422// The test ensures that the zero-level texture is correctly copied into the mipped texture before the mipmaps are generated.
423TYPED_TEST(MipmapTest, GenerateMipmapFromRenderedImage)
424{
425 // Bind the offscreen framebuffer/texture.
426 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
427
428 // Clear the texture to blue.
429 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
430 glClear(GL_COLOR_BUFFER_BIT);
431
432 // Then generate the mips
433 glGenerateMipmap(GL_TEXTURE_2D);
434 ASSERT_GL_NO_ERROR();
435
436 // Enable mips.
437 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
438
439 // Now draw the texture to various different sized areas.
440 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
441 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
442
443 // Use mip level 1
444 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 2, getWindowHeight() / 2);
445 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
446
447 // Use mip level 2
448 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
449 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
450}
451
452// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
453// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
454TYPED_TEST(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
455{
456 // Bind the offscreen texture/framebuffer.
457 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
458
459 // Clear the texture to blue.
460 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
461 glClear(GL_COLOR_BUFFER_BIT);
462
463 // From now on, default clear color is black.
464 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
465
466 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
467 // The quad should be blue.
468 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
469 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
470
471 // Now go back to the texture, and generate mips on it.
472 glGenerateMipmap(GL_TEXTURE_2D);
473 ASSERT_GL_NO_ERROR();
474
475 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
476 // The quad should be blue.
477 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
478 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
479
480 // Now tell GL to use the generated mips.
481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
482 EXPECT_EQ(glGetError(), GL_NONE);
483
484 // Now render the textured quad again. It should be still be blue.
485 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
486 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
487
488 // Now render the textured quad to an area smaller than the texture (i.e. to force minification). This should be blue.
489 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
490 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
491
492 // Now clear the texture to green. This just clears the top level. The lower mips should remain blue.
493 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
494 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
495 glClear(GL_COLOR_BUFFER_BIT);
496
497 // From now on, default clear color is black.
498 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
499
500 // Render a textured quad equal in size to the texture. This should be green, since we just cleared level 0.
501 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
502 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
503
504 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
505 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
506 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
507
508 // Disable mipmaps again
509 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
510 ASSERT_GL_NO_ERROR();
511
512 // Render a textured quad equal in size to the texture. This should be green, the color of level 0 in the texture.
513 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth(), getWindowHeight());
514 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
515
516 // Render a small textured quad. This would force minification if mips were enabled, but they're not. Therefore, this should be green.
517 ClearAndDrawTexturedQuad(mOffscreenTexture, getWindowWidth() / 4, getWindowHeight() / 4);
518 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 255, 0, 255);
519}
520
521// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
522// Then tests if the mipmaps are rendered correctly for all three layers.
523TYPED_TEST(MipmapTestES3, MipmapsForTextureArray)
524{
525 int px = getWindowWidth() / 2;
526 int py = getWindowHeight() / 2;
527
528 glActiveTexture(GL_TEXTURE0);
529 glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
530
531 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
532
533 // Fill the first layer 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 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
544
545 // Fill the second layer with green
546 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
547 {
548 pixels[pixelId * 4 + 0] = 0;
549 pixels[pixelId * 4 + 1] = 255;
550 pixels[pixelId * 4 + 2] = 0;
551 pixels[pixelId * 4 + 3] = 255;
552 }
553
554 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
555
556 // Fill the third layer with blue
557 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
558 {
559 pixels[pixelId * 4 + 0] = 0;
560 pixels[pixelId * 4 + 1] = 0;
561 pixels[pixelId * 4 + 2] = 255;
562 pixels[pixelId * 4 + 3] = 255;
563 }
564
565 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
566
567 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
568 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
569
570 EXPECT_GL_NO_ERROR();
571
572 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
573
574 EXPECT_GL_NO_ERROR();
575
576 glUseProgram(mArrayProgram);
577 glUniform1i(mTextureArrayUniformLocation, 0);
578
579 EXPECT_GL_NO_ERROR();
580
581 // Draw the first slice
582 glUseProgram(mArrayProgram);
583 glUniform1i(mTextureArraySliceUniformLocation, 0);
584 drawQuad(mArrayProgram, "position", 0.5f);
585 EXPECT_GL_NO_ERROR();
586 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
587
588 // Draw the second slice
589 glUseProgram(mArrayProgram);
590 glUniform1i(mTextureArraySliceUniformLocation, 1);
591 drawQuad(mArrayProgram, "position", 0.5f);
592 EXPECT_GL_NO_ERROR();
593 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
594
595 // Draw the third slice
596 glUseProgram(mArrayProgram);
597 glUniform1i(mTextureArraySliceUniformLocation, 2);
598 drawQuad(mArrayProgram, "position", 0.5f);
599 EXPECT_GL_NO_ERROR();
600 EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
601}