blob: 14fdc044646b0f38477151a8001a558077679697 [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"
Austin Kinross215b37a2014-12-22 12:56:07 -08008
Jamie Madillfa05f602015-05-07 13:47:11 -04009using namespace angle;
Austin Kinross215b37a2014-12-22 12:56:07 -080010
Austin Kinross215b37a2014-12-22 12:56:07 -080011class MipmapTest : public ANGLETest
12{
13 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040014 MipmapTest()
Austin Kinross215b37a2014-12-22 12:56:07 -080015 {
16 setWindowWidth(128);
17 setWindowHeight(128);
18 setConfigRedBits(8);
19 setConfigGreenBits(8);
20 setConfigBlueBits(8);
21 setConfigAlphaBits(8);
22 }
23
24 virtual void SetUp()
25 {
26 ANGLETest::SetUp();
27
28 // Vertex Shader source
29 const std::string vs = SHADER_SOURCE
30 (
31 attribute vec4 aPosition;
32 attribute vec2 aTexCoord;
33 varying vec2 vTexCoord;
34
35 void main()
36 {
37 gl_Position = aPosition;
38 vTexCoord = aTexCoord;
39 }
40 );
41
42 // Fragment Shader source
43 const std::string fs = SHADER_SOURCE
44 (
45 precision mediump float;
46
47 uniform sampler2D uTexture;
48 varying vec2 vTexCoord;
49
50 void main()
51 {
52 gl_FragColor = texture2D(uTexture, vTexCoord);
53 }
54 );
55
Austin Kinross62815bf2015-01-15 16:32:36 -080056 m2DProgram = CompileProgram(vs, fs);
57 if (m2DProgram == 0)
Austin Kinross215b37a2014-12-22 12:56:07 -080058 {
59 FAIL() << "shader compilation failed.";
60 }
61
Austin Kinross62815bf2015-01-15 16:32:36 -080062 // A simple vertex shader for the texture cube
63 const std::string cubeVS = SHADER_SOURCE
64 (
65 attribute vec4 aPosition;
66 varying vec4 vPosition;
67 void main()
68 {
69 gl_Position = aPosition;
70 vPosition = aPosition;
71 }
72 );
73
74 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
75 const std::string cubeFS = SHADER_SOURCE
76 (
77 precision mediump float;
78 uniform samplerCube uTexture;
79 varying vec4 vPosition;
80
81 void main()
82 {
83 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
84 }
85 );
86
87 mCubeProgram = CompileProgram(cubeVS, cubeFS);
88 if (mCubeProgram == 0)
89 {
90 FAIL() << "shader compilation failed.";
91 }
92
93 m2DTextureUniformPosition = glGetUniformLocation(m2DProgram, "uTexture");
94 m2DPositionAttributePosition = glGetAttribLocation(m2DProgram, "aPosition");
95 m2DTexCoordAttributePosition = glGetAttribLocation(m2DProgram, "aTexCoord");
96
Geoff Lang27359ff2015-06-02 15:42:04 -040097 mCubeTextureUniformPosition = glGetUniformLocation(mCubeProgram, "uTexture");
98 mCubePositionAttributePosition = glGetAttribLocation(mCubeProgram, "aPosition");
99
Austin Kinross62815bf2015-01-15 16:32:36 -0800100 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
101 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
102 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
103 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800104
105 glGenFramebuffers(1, &mOffscreenFramebuffer);
Austin Kinross62815bf2015-01-15 16:32:36 -0800106 glGenTextures(1, &mOffscreenTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800107
Austin Kinross62815bf2015-01-15 16:32:36 -0800108 // Initialize the texture2D to be empty, and don't use mips.
109 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800110 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
111 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
113
Austin Kinross62815bf2015-01-15 16:32:36 -0800114 // Bind the texture2D to the offscreen framebuffer's color buffer.
Austin Kinross215b37a2014-12-22 12:56:07 -0800115 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
Austin Kinross62815bf2015-01-15 16:32:36 -0800116 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mOffscreenTexture2D, 0);
Corentin Wallez322653b2015-06-17 18:33:56 +0200117 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
Austin Kinross215b37a2014-12-22 12:56:07 -0800118
Austin Kinross62815bf2015-01-15 16:32:36 -0800119 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
120 glGenTextures(1, &mOffscreenTextureCube);
121 glBindTexture(GL_TEXTURE_CUBE_MAP, mOffscreenTextureCube);
122 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
123 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
124 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
125 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
126 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
127 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
128
129 // Complete the texture cube without mipmaps to start with.
130 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
131 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132
133 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800134 }
135
136 virtual void TearDown()
137 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800138 glDeleteProgram(m2DProgram);
139 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800140 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Austin Kinross62815bf2015-01-15 16:32:36 -0800141 glDeleteTextures(1, &mOffscreenTexture2D);
142 glDeleteTextures(1, &mOffscreenTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800143
Corentin Wallez254fcea2015-08-25 15:11:07 -0400144 SafeDeleteArray(mLevelZeroBlueInitData);
145 SafeDeleteArray(mLevelZeroWhiteInitData);
146 SafeDeleteArray(mLevelOneInitData);
147 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800148
149 ANGLETest::TearDown();
150 }
151
152 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
153 {
154 GLubyte *data = new GLubyte[3 * width * height];
155
156 for (int i = 0; i < width * height; i+=1)
157 {
Minmin Gong794e0002015-04-07 18:31:54 -0700158 data[3 * i + 0] = static_cast<GLubyte>(r);
159 data[3 * i + 1] = static_cast<GLubyte>(g);
160 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800161 }
162
163 return data;
164 }
165
166 void ClearAndDrawTexturedQuad(GLuint texture, GLsizei viewportWidth, GLsizei viewportHeight)
167 {
168 glBindFramebuffer(GL_FRAMEBUFFER, 0);
169 glClear(GL_COLOR_BUFFER_BIT);
170
171 glViewport(0, 0, viewportWidth, viewportHeight);
172
173 ASSERT_GL_NO_ERROR();
174
175 GLfloat vertexLocations[] =
176 {
177 -1.0f, 1.0f, 0.0f,
178 -1.0f, -1.0f, 0.0f,
179 1.0f, 1.0f, 0.0f,
180 1.0f, -1.0f, 0.0f,
181 };
182
183 GLfloat vertexTexCoords[] =
184 {
185 0.0f, 1.0f,
186 0.0f, 0.0f,
187 1.0f, 1.0f,
188 1.0f, 0.0f,
189 };
190
Austin Kinross62815bf2015-01-15 16:32:36 -0800191 glUseProgram(m2DProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800192
193 glActiveTexture(GL_TEXTURE0);
194 glBindTexture(GL_TEXTURE_2D, texture);
Austin Kinross62815bf2015-01-15 16:32:36 -0800195 glUniform1i(m2DTextureUniformPosition, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800196
Austin Kinross62815bf2015-01-15 16:32:36 -0800197 glVertexAttribPointer(m2DPositionAttributePosition, 3, GL_FLOAT, GL_FALSE, 0, vertexLocations);
198 glEnableVertexAttribArray(m2DPositionAttributePosition);
Austin Kinross215b37a2014-12-22 12:56:07 -0800199
Austin Kinross62815bf2015-01-15 16:32:36 -0800200 glVertexAttribPointer(m2DTexCoordAttributePosition, 2, GL_FLOAT, GL_FALSE, 0, vertexTexCoords);
201 glEnableVertexAttribArray(m2DTexCoordAttributePosition);
Austin Kinross215b37a2014-12-22 12:56:07 -0800202
203 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
204 }
205
Austin Kinross62815bf2015-01-15 16:32:36 -0800206 GLuint m2DProgram;
207 GLuint mCubeProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800208 GLuint mOffscreenFramebuffer;
Austin Kinross62815bf2015-01-15 16:32:36 -0800209 GLuint mOffscreenTexture2D;
210 GLuint mOffscreenTextureCube;
Austin Kinross215b37a2014-12-22 12:56:07 -0800211
Austin Kinross62815bf2015-01-15 16:32:36 -0800212 GLint m2DTextureUniformPosition;
213 GLint m2DPositionAttributePosition;
214 GLint m2DTexCoordAttributePosition;
Austin Kinross215b37a2014-12-22 12:56:07 -0800215
Geoff Lang27359ff2015-06-02 15:42:04 -0400216 GLint mCubeTextureUniformPosition;
217 GLint mCubePositionAttributePosition;
218
Austin Kinross215b37a2014-12-22 12:56:07 -0800219 GLubyte* mLevelZeroBlueInitData;
220 GLubyte* mLevelZeroWhiteInitData;
221 GLubyte* mLevelOneInitData;
222 GLubyte* mLevelTwoInitData;
223};
224
Austin Kinross215b37a2014-12-22 12:56:07 -0800225class MipmapTestES3 : public ANGLETest
226{
Jamie Madillfa05f602015-05-07 13:47:11 -0400227 protected:
228 MipmapTestES3()
Austin Kinross215b37a2014-12-22 12:56:07 -0800229 {
230 setWindowWidth(128);
231 setWindowHeight(128);
232 setConfigRedBits(8);
233 setConfigGreenBits(8);
234 setConfigBlueBits(8);
235 setConfigAlphaBits(8);
236 }
237
238 virtual void SetUp()
239 {
240 ANGLETest::SetUp();
241
242 glGenTextures(1, &mTextureArray);
243 EXPECT_GL_NO_ERROR();
244
245 ASSERT_GL_NO_ERROR();
246
Austin Kinrosse8c86272015-01-15 18:55:36 -0800247 // Don't put "#version ..." on its own line. See [cpp]p1:
248 // "If there are sequences of preprocessing tokens within the list of arguments that
249 // would otherwise act as preprocessing directives, the behavior is undefined"
Austin Kinross215b37a2014-12-22 12:56:07 -0800250 const std::string vertexShaderSource = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800251 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800252 precision highp float;
253 in vec4 position;
254 out vec2 texcoord;
255
256 uniform vec2 textureScale;
257
258 void main()
259 {
260 gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
261 texcoord = (position.xy * 0.5) + 0.5;
262 }
263 );
264
265 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800266 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800267 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200268 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800269 uniform int slice;
270 in vec2 texcoord;
271 out vec4 out_FragColor;
272
273 void main()
274 {
275 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
276 }
277 );
278
279 mArrayProgram = CompileProgram(vertexShaderSource, fragmentShaderSourceArray);
280 if (mArrayProgram == 0)
281 {
282 FAIL() << "shader compilation failed.";
283 }
284
285 mTextureArrayUniformLocation = glGetUniformLocation(mArrayProgram, "tex");
286 ASSERT_NE(-1, mTextureArrayUniformLocation);
287
288 mTextureArrayScaleUniformLocation = glGetUniformLocation(mArrayProgram, "textureScale");
289 ASSERT_NE(-1, mTextureArrayScaleUniformLocation);
290
291 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
292 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
293
294 glUseProgram(mArrayProgram);
295 glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
296 glUseProgram(0);
297 ASSERT_GL_NO_ERROR();
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000298
299 glGenTextures(1, &mTexture3D);
300
301 ASSERT_GL_NO_ERROR();
302
303 const std::string fragmentShaderSource3D = SHADER_SOURCE
304 ( #version 300 es\n
305 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200306 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000307 uniform float slice;
308 uniform float lod;
309 in vec2 texcoord;
310 out vec4 out_FragColor;
311
312 void main()
313 {
314 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
315 }
316 );
317
318 m3DProgram = CompileProgram(vertexShaderSource, fragmentShaderSource3D);
319 if (m3DProgram == 0)
320 {
321 FAIL() << "shader compilation failed.";
322 }
323
324 mTexture3DUniformLocation = glGetUniformLocation(m3DProgram, "tex");
325 ASSERT_NE(-1, mTexture3DUniformLocation);
326
327 mTexture3DScaleUniformLocation = glGetUniformLocation(m3DProgram, "textureScale");
328 ASSERT_NE(-1, mTexture3DScaleUniformLocation);
329
330 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
331 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
332
333 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
334 ASSERT_NE(-1, mTexture3DLODUniformLocation);
335
336 glUseProgram(m3DProgram);
337 glUniform2f(mTexture3DScaleUniformLocation, 1.0f, 1.0f);
338 glUniform1f(mTexture3DLODUniformLocation, 0);
339 glUseProgram(0);
340 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800341 }
342
343 virtual void TearDown()
344 {
345 glDeleteTextures(1, &mTextureArray);
346 glDeleteProgram(mArrayProgram);
347
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000348 glDeleteTextures(1, &mTexture3D);
349 glDeleteProgram(m3DProgram);
350
Austin Kinross215b37a2014-12-22 12:56:07 -0800351 ANGLETest::TearDown();
352 }
353
354 GLuint mTextureArray;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000355 GLuint mTexture3D;
Austin Kinross215b37a2014-12-22 12:56:07 -0800356
357 GLuint mArrayProgram;
358 GLint mTextureArrayUniformLocation;
359 GLint mTextureArrayScaleUniformLocation;
360 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000361
362 GLuint m3DProgram;
363 GLint mTexture3DUniformLocation;
364 GLint mTexture3DScaleUniformLocation;
365 GLint mTexture3DSliceUniformLocation;
366 GLint mTexture3DLODUniformLocation;
Austin Kinross215b37a2014-12-22 12:56:07 -0800367};
368
369// 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.
370// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
371// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400372TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800373{
374 // Pass in level zero init data.
Austin Kinross62815bf2015-01-15 16:32:36 -0800375 glBindTexture(GL_TEXTURE_2D, mOffscreenTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800376 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
377 ASSERT_GL_NO_ERROR();
378
379 // Disable mips.
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
381
382 // Draw a full-sized quad, and check it's blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800383 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800384 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
385
386 // Draw a half-sized quad, and check it's blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800387 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800388 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
389
390 // Draw a quarter-sized quad, and check it's blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800391 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800392 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
393
394 // Complete the texture by initializing the remaining levels.
395 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700396 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800397 {
Minmin Gong794e0002015-04-07 18:31:54 -0700398 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / (1U << n), getWindowWidth() / (1U << n), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
Austin Kinross215b37a2014-12-22 12:56:07 -0800399 ASSERT_GL_NO_ERROR();
400 n+=1;
401 }
402
403 // Pass in level one init data.
404 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
405 ASSERT_GL_NO_ERROR();
406
407 // Draw a full-sized quad, and check it's blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800408 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800409 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
410
411 // 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.
Austin Kinross62815bf2015-01-15 16:32:36 -0800412 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800413 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
414
415 // Enable mipmaps.
416 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
417
418 // Draw a half-sized quad, and check it's green.
Austin Kinross62815bf2015-01-15 16:32:36 -0800419 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800420 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
421
422 // Draw a quarter-sized quad, and check it's black, since we've not passed any init data for level two.
Austin Kinross62815bf2015-01-15 16:32:36 -0800423 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800424 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 0, 255);
425
426 // Pass in level two init data.
427 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
428 ASSERT_GL_NO_ERROR();
429
430 // Draw a full-sized quad, and check it's blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800431 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800432 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
433
434 // Draw a half-sized quad, and check it's green.
Austin Kinross62815bf2015-01-15 16:32:36 -0800435 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800436 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
437
438 // Draw a quarter-sized quad, and check it's red.
Austin Kinross62815bf2015-01-15 16:32:36 -0800439 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800440 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
441
442 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Austin Kinross62815bf2015-01-15 16:32:36 -0800444 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800445 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800446 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800447 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800448 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800449 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
450
451 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
452 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
453 ASSERT_GL_NO_ERROR();
454
Austin Kinross62815bf2015-01-15 16:32:36 -0800455 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800456 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800457 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800458 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800459 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800460 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 255, 255, 255);
461
462 // Then enable mipmaps again. The quads should be white, green, red respectively.
463 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
464
Austin Kinross62815bf2015-01-15 16:32:36 -0800465 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800466 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800467 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800468 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800469 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800470 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
471}
472
473// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
474// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
475// To do this, D3D11 has to convert the TextureStorage into a renderable one.
476// This test ensures that the conversion works correctly.
477// 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.
Jamie Madillfa05f602015-05-07 13:47:11 -0400478TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800479{
480 // Pass in initial data so the texture is blue.
481 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
482
483 // Then generate the mips.
484 glGenerateMipmap(GL_TEXTURE_2D);
485 ASSERT_GL_NO_ERROR();
486
487 // Enable mipmaps.
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
489
490 // Now draw the texture to various different sized areas.
Austin Kinross62815bf2015-01-15 16:32:36 -0800491 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800492 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
493
494 // Use mip level 1
Austin Kinross62815bf2015-01-15 16:32:36 -0800495 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800496 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
497
498 // Use mip level 2
Austin Kinross62815bf2015-01-15 16:32:36 -0800499 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800500 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
501
502 ASSERT_GL_NO_ERROR();
503
504 // Disable mips. Render a quad using the texture and ensure it's blue.
505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Austin Kinross62815bf2015-01-15 16:32:36 -0800506 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800507 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
508
509 // Clear level 0 of the texture.
510 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
511 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
512 glClear(GL_COLOR_BUFFER_BIT);
513
514 // Reenable mips, and try rendering different-sized quads.
515 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
516
517 // Level 0 is now red, so this should render red.
Austin Kinross62815bf2015-01-15 16:32:36 -0800518 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800519 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
520
521 // Use mip level 1, blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800522 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800523 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
524
525 // Use mip level 2, blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800526 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800527 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
528}
529
530// This test ensures that mips are correctly generated from a rendered image.
531// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
532// The test ensures that the zero-level texture is correctly copied into the mipped texture before the mipmaps are generated.
Jamie Madillfa05f602015-05-07 13:47:11 -0400533TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800534{
535 // Bind the offscreen framebuffer/texture.
536 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
537
538 // Clear the texture to blue.
539 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
540 glClear(GL_COLOR_BUFFER_BIT);
541
542 // Then generate the mips
543 glGenerateMipmap(GL_TEXTURE_2D);
544 ASSERT_GL_NO_ERROR();
545
546 // Enable mips.
547 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
548
549 // Now draw the texture to various different sized areas.
Austin Kinross62815bf2015-01-15 16:32:36 -0800550 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800551 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
552
553 // Use mip level 1
Austin Kinross62815bf2015-01-15 16:32:36 -0800554 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800555 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
556
557 // Use mip level 2
Austin Kinross62815bf2015-01-15 16:32:36 -0800558 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800559 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
560}
561
562// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
563// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400564TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800565{
Geoff Langf74fef52015-04-29 12:57:52 -0400566 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill7208f692016-02-29 10:47:35 -0500567 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400568 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400569 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400570 return;
571 }
572
Austin Kinross215b37a2014-12-22 12:56:07 -0800573 // Bind the offscreen texture/framebuffer.
574 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
575
576 // Clear the texture to blue.
577 glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
578 glClear(GL_COLOR_BUFFER_BIT);
579
580 // From now on, default clear color is black.
581 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
582
583 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
584 // The quad should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800585 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800586 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
587
588 // Now go back to the texture, and generate mips on it.
589 glGenerateMipmap(GL_TEXTURE_2D);
590 ASSERT_GL_NO_ERROR();
591
592 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
593 // The quad should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800594 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800595 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
596
597 // Now tell GL to use the generated mips.
598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200599 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800600
601 // Now render the textured quad again. It should be still be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800602 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800603 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
604
605 // Now render the textured quad to an area smaller than the texture (i.e. to force minification). This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800606 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800607 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
608
609 // Now clear the texture to green. This just clears the top level. The lower mips should remain blue.
610 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
611 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
612 glClear(GL_COLOR_BUFFER_BIT);
613
614 // From now on, default clear color is black.
615 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
616
617 // Render a textured quad equal in size to the texture. This should be green, since we just cleared level 0.
Austin Kinross62815bf2015-01-15 16:32:36 -0800618 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800619 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
620
621 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Austin Kinross62815bf2015-01-15 16:32:36 -0800622 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800623 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
624
625 // Disable mipmaps again
626 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
627 ASSERT_GL_NO_ERROR();
628
629 // Render a textured quad equal in size to the texture. This should be green, the color of level 0 in the texture.
Austin Kinross62815bf2015-01-15 16:32:36 -0800630 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800631 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
632
633 // Render a small textured quad. This would force minification if mips were enabled, but they're not. Therefore, this should be green.
Austin Kinross62815bf2015-01-15 16:32:36 -0800634 ClearAndDrawTexturedQuad(mOffscreenTexture2D, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800635 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 255, 0, 255);
636}
637
Austin Kinross62815bf2015-01-15 16:32:36 -0800638// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
639// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400640TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800641{
642 GLfloat vertexLocations[] =
643 {
644 -1.0f, 1.0f, 0.0f,
645 -1.0f, -1.0f, 0.0f,
646 1.0f, 1.0f, 0.0f,
647 1.0f, -1.0f, 0.0f,
648 };
649
650 // Set up the viewport, program, attributes, sampler and texture for the cube
651 glBindFramebuffer(GL_FRAMEBUFFER, 0);
652 glViewport(0, 0, getWindowWidth(), getWindowHeight());
653 glUseProgram(mCubeProgram);
Geoff Lang27359ff2015-06-02 15:42:04 -0400654 glVertexAttribPointer(mCubePositionAttributePosition, 3, GL_FLOAT, GL_FALSE, 0, vertexLocations);
655 glEnableVertexAttribArray(mCubePositionAttributePosition);
656 glUniform1i(mCubeTextureUniformPosition, 0);
Austin Kinross62815bf2015-01-15 16:32:36 -0800657 glActiveTexture(GL_TEXTURE0);
658 glBindTexture(GL_TEXTURE_CUBE_MAP, mOffscreenTextureCube);
659
660 // Draw. Since the negative-Y face's is blue, this should be blue.
661 glClear(GL_COLOR_BUFFER_BIT);
662 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
663 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
664
665 // Generate mipmaps, and render. This should be blue.
666 glClear(GL_COLOR_BUFFER_BIT);
667 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
668 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
669 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
670 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
671 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
672
673 // Draw using a smaller viewport (to force a lower LOD of the texture). This should still be blue.
674 glClear(GL_COLOR_BUFFER_BIT);
675 glViewport(0, 0, getWindowWidth() / 4, getWindowHeight() / 4);
676 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
677 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
678
679 // Now clear the negative-Y face of the cube to red.
Austin Kinross62815bf2015-01-15 16:32:36 -0800680 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
681 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mOffscreenTextureCube, 0);
Corentin Wallez322653b2015-06-17 18:33:56 +0200682 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
Austin Kinross62815bf2015-01-15 16:32:36 -0800683 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
684 glClear(GL_COLOR_BUFFER_BIT);
685
686 // Switch back to the default framebuffer
687 glBindFramebuffer(GL_FRAMEBUFFER, 0);
688 glBindTexture(GL_TEXTURE_CUBE_MAP, mOffscreenTextureCube);
689
690 // Draw using a full-size viewport. This should be red.
691 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
692 glClear(GL_COLOR_BUFFER_BIT);
693 glViewport(0, 0, getWindowWidth(), getWindowHeight());
694 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
695 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
696
697 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
698 // of the negative-Y face to red, and left its mipmaps blue.
699 glClear(GL_COLOR_BUFFER_BIT);
700 glViewport(0, 0, getWindowWidth() / 4, getWindowHeight() / 4);
701 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
702 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
703
704 // Disable mipmaps again, and draw a to a quarter-size viewport.
705 // Since this should use level zero of the texture, this should be *RED*.
706 glClear(GL_COLOR_BUFFER_BIT);
707 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
708 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
709 glViewport(0, 0, getWindowWidth() / 4, getWindowHeight() / 4);
710 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
711}
712
713// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400714TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800715{
716 GLfloat vertexLocations[] =
717 {
718 -1.0f, 1.0f, 0.0f,
719 -1.0f, -1.0f, 0.0f,
720 1.0f, 1.0f, 0.0f,
721 1.0f, -1.0f, 0.0f,
722 };
723
724 // Set up the viewport, program, attributes, sampler and texture for the cube
725 glBindFramebuffer(GL_FRAMEBUFFER, 0);
726 glViewport(0, 0, getWindowWidth(), getWindowHeight());
727 glUseProgram(mCubeProgram);
Geoff Lang27359ff2015-06-02 15:42:04 -0400728 glVertexAttribPointer(mCubePositionAttributePosition, 3, GL_FLOAT, GL_FALSE, 0, vertexLocations);
729 glEnableVertexAttribArray(mCubePositionAttributePosition);
730 glUniform1i(mCubeTextureUniformPosition, 0);
Austin Kinross62815bf2015-01-15 16:32:36 -0800731 glActiveTexture(GL_TEXTURE0);
732 glBindTexture(GL_TEXTURE_CUBE_MAP, mOffscreenTextureCube);
733
734 // Draw. Since the negative-Y face's is blue, this should be blue.
735 glClear(GL_COLOR_BUFFER_BIT);
736 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
737 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
738
739 // Now clear the negative-Y face of the cube to red.
Austin Kinross62815bf2015-01-15 16:32:36 -0800740 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
741 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mOffscreenTextureCube, 0);
Corentin Wallez322653b2015-06-17 18:33:56 +0200742 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
Austin Kinross62815bf2015-01-15 16:32:36 -0800743 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
744 glClear(GL_COLOR_BUFFER_BIT);
745
746 // Switch back to the default framebuffer
747 glBindFramebuffer(GL_FRAMEBUFFER, 0);
748 glBindTexture(GL_TEXTURE_CUBE_MAP, mOffscreenTextureCube);
749
750 // Draw using a full-size viewport. This should be red.
751 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
752 glClear(GL_COLOR_BUFFER_BIT);
753 glViewport(0, 0, getWindowWidth(), getWindowHeight());
754 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
755 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
756
757 // Draw a to a quarter-size viewport. This should also be red.
758 glClear(GL_COLOR_BUFFER_BIT);
759 glViewport(0, 0, getWindowWidth() / 4, getWindowHeight() / 4);
760 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
761 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
762}
763
Austin Kinross215b37a2014-12-22 12:56:07 -0800764// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
765// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400766TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800767{
768 int px = getWindowWidth() / 2;
769 int py = getWindowHeight() / 2;
770
771 glActiveTexture(GL_TEXTURE0);
772 glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
773
774 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
775
776 // Fill the first layer with red
777 std::vector<GLubyte> pixels(4 * 16 * 16);
778 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
779 {
780 pixels[pixelId * 4 + 0] = 255;
781 pixels[pixelId * 4 + 1] = 0;
782 pixels[pixelId * 4 + 2] = 0;
783 pixels[pixelId * 4 + 3] = 255;
784 }
785
786 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
787
788 // Fill the second layer with green
789 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
790 {
791 pixels[pixelId * 4 + 0] = 0;
792 pixels[pixelId * 4 + 1] = 255;
793 pixels[pixelId * 4 + 2] = 0;
794 pixels[pixelId * 4 + 3] = 255;
795 }
796
797 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
798
799 // Fill the third layer with blue
800 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
801 {
802 pixels[pixelId * 4 + 0] = 0;
803 pixels[pixelId * 4 + 1] = 0;
804 pixels[pixelId * 4 + 2] = 255;
805 pixels[pixelId * 4 + 3] = 255;
806 }
807
808 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
809
810 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
811 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
812
813 EXPECT_GL_NO_ERROR();
814
815 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
816
817 EXPECT_GL_NO_ERROR();
818
819 glUseProgram(mArrayProgram);
820 glUniform1i(mTextureArrayUniformLocation, 0);
821
822 EXPECT_GL_NO_ERROR();
823
824 // Draw the first slice
825 glUseProgram(mArrayProgram);
826 glUniform1i(mTextureArraySliceUniformLocation, 0);
827 drawQuad(mArrayProgram, "position", 0.5f);
828 EXPECT_GL_NO_ERROR();
829 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
830
831 // Draw the second slice
832 glUseProgram(mArrayProgram);
833 glUniform1i(mTextureArraySliceUniformLocation, 1);
834 drawQuad(mArrayProgram, "position", 0.5f);
835 EXPECT_GL_NO_ERROR();
836 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
837
838 // Draw the third slice
839 glUseProgram(mArrayProgram);
840 glUniform1i(mTextureArraySliceUniformLocation, 2);
841 drawQuad(mArrayProgram, "position", 0.5f);
842 EXPECT_GL_NO_ERROR();
843 EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000844}
845
846// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
847// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400848TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000849{
850 int px = getWindowWidth() / 2;
851 int py = getWindowHeight() / 2;
852
853 glActiveTexture(GL_TEXTURE0);
854 glBindTexture(GL_TEXTURE_3D, mTexture3D);
855
856 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
857
858 // Fill the first layer with red
859 std::vector<GLubyte> pixels(4 * 16 * 16);
860 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
861 {
862 pixels[pixelId * 4 + 0] = 255;
863 pixels[pixelId * 4 + 1] = 0;
864 pixels[pixelId * 4 + 2] = 0;
865 pixels[pixelId * 4 + 3] = 255;
866 }
867
868 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
869
870 // Fill the second layer with green
871 for (size_t pixelId = 0; pixelId < 16 * 16; ++pixelId)
872 {
873 pixels[pixelId * 4 + 0] = 0;
874 pixels[pixelId * 4 + 1] = 255;
875 pixels[pixelId * 4 + 2] = 0;
876 pixels[pixelId * 4 + 3] = 255;
877 }
878
879 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
880
881 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
882 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
883
884 EXPECT_GL_NO_ERROR();
885
886 glGenerateMipmap(GL_TEXTURE_3D);
887
888 EXPECT_GL_NO_ERROR();
889
890 glUseProgram(m3DProgram);
891 glUniform1i(mTexture3DUniformLocation, 0);
892
893 EXPECT_GL_NO_ERROR();
894
895 // Mipmap level 0
896 // Draw the first slice
897 glUseProgram(m3DProgram);
898 glUniform1f(mTexture3DLODUniformLocation, 0.);
899 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
900 drawQuad(m3DProgram, "position", 0.5f);
901 EXPECT_GL_NO_ERROR();
902 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
903
904 // Draw the second slice
905 glUseProgram(m3DProgram);
906 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
907 drawQuad(m3DProgram, "position", 0.5f);
908 EXPECT_GL_NO_ERROR();
909 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
910
911 // Mipmap level 1
912 // The second mipmap should only have one slice.
913
914 glUseProgram(m3DProgram);
915 glUniform1f(mTexture3DLODUniformLocation, 1.);
916 drawQuad(m3DProgram, "position", 0.5f);
917 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500918 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000919
920 glUseProgram(m3DProgram);
921 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
922 drawQuad(m3DProgram, "position", 0.5f);
923 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500924 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000925}
Jamie Madillfa05f602015-05-07 13:47:11 -0400926
927// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
928// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -0500929ANGLE_INSTANTIATE_TEST(MipmapTest,
930 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800931 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
932 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -0500933 ES2_D3D11_FL9_3_WARP(),
934 ES2_OPENGL(),
935 ES3_OPENGL(),
936 ES2_OPENGLES(),
937 ES3_OPENGLES());
938ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());