blob: 94bc018aa89d462ba791525ef905b4ea53bf166e [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()
Olli Etuahob97a3e72016-04-13 14:31:52 +030015 : m2DProgram(0),
16 mCubeProgram(0),
17 mTexture2D(0),
18 mTextureCube(0),
19 mLevelZeroBlueInitData(nullptr),
20 mLevelZeroWhiteInitData(nullptr),
21 mLevelOneInitData(nullptr),
22 mLevelTwoInitData(nullptr),
23 mOffscreenFramebuffer(0)
Austin Kinross215b37a2014-12-22 12:56:07 -080024 {
25 setWindowWidth(128);
26 setWindowHeight(128);
27 setConfigRedBits(8);
28 setConfigGreenBits(8);
29 setConfigBlueBits(8);
30 setConfigAlphaBits(8);
31 }
32
Olli Etuahob97a3e72016-04-13 14:31:52 +030033 void setUp2DProgram()
Austin Kinross215b37a2014-12-22 12:56:07 -080034 {
Austin Kinross215b37a2014-12-22 12:56:07 -080035 // Vertex Shader source
36 const std::string vs = SHADER_SOURCE
37 (
38 attribute vec4 aPosition;
Austin Kinross215b37a2014-12-22 12:56:07 -080039 varying vec2 vTexCoord;
40
41 void main()
42 {
43 gl_Position = aPosition;
Olli Etuahob97a3e72016-04-13 14:31:52 +030044 vTexCoord = (aPosition.xy * 0.5) + 0.5;
Austin Kinross215b37a2014-12-22 12:56:07 -080045 }
46 );
47
48 // Fragment Shader source
49 const std::string fs = SHADER_SOURCE
50 (
51 precision mediump float;
52
53 uniform sampler2D uTexture;
54 varying vec2 vTexCoord;
55
56 void main()
57 {
58 gl_FragColor = texture2D(uTexture, vTexCoord);
59 }
60 );
61
Austin Kinross62815bf2015-01-15 16:32:36 -080062 m2DProgram = CompileProgram(vs, fs);
Olli Etuahob97a3e72016-04-13 14:31:52 +030063 ASSERT_NE(0u, m2DProgram);
64 }
Austin Kinross215b37a2014-12-22 12:56:07 -080065
Olli Etuahob97a3e72016-04-13 14:31:52 +030066 void setUpCubeProgram()
67 {
Austin Kinross62815bf2015-01-15 16:32:36 -080068 // A simple vertex shader for the texture cube
69 const std::string cubeVS = SHADER_SOURCE
70 (
71 attribute vec4 aPosition;
72 varying vec4 vPosition;
73 void main()
74 {
75 gl_Position = aPosition;
76 vPosition = aPosition;
77 }
78 );
79
80 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
81 const std::string cubeFS = SHADER_SOURCE
82 (
83 precision mediump float;
84 uniform samplerCube uTexture;
85 varying vec4 vPosition;
86
87 void main()
88 {
89 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
90 }
91 );
92
93 mCubeProgram = CompileProgram(cubeVS, cubeFS);
Olli Etuahob97a3e72016-04-13 14:31:52 +030094 ASSERT_NE(0u, mCubeProgram);
95 }
Austin Kinross62815bf2015-01-15 16:32:36 -080096
Olli Etuahob97a3e72016-04-13 14:31:52 +030097 void SetUp() override
98 {
99 ANGLETest::SetUp();
Austin Kinross62815bf2015-01-15 16:32:36 -0800100
Olli Etuahob97a3e72016-04-13 14:31:52 +0300101 setUp2DProgram();
102
103 setUpCubeProgram();
Geoff Lang27359ff2015-06-02 15:42:04 -0400104
Austin Kinross62815bf2015-01-15 16:32:36 -0800105 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
106 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
107 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
108 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800109
110 glGenFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300111 glGenTextures(1, &mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800112
Austin Kinross62815bf2015-01-15 16:32:36 -0800113 // Initialize the texture2D to be empty, and don't use mips.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300114 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800115 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
118
Austin Kinross62815bf2015-01-15 16:32:36 -0800119 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300120 glGenTextures(1, &mTextureCube);
121 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800122 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
Olli Etuahob97a3e72016-04-13 14:31:52 +0300136 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800137 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800138 glDeleteProgram(m2DProgram);
139 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800140 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300141 glDeleteTextures(1, &mTexture2D);
142 glDeleteTextures(1, &mTextureCube);
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
Olli Etuahob97a3e72016-04-13 14:31:52 +0300166 void clearAndDrawQuad(GLuint program, GLsizei viewportWidth, GLsizei viewportHeight)
Austin Kinross215b37a2014-12-22 12:56:07 -0800167 {
Olli Etuahob97a3e72016-04-13 14:31:52 +0300168 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800169 glClear(GL_COLOR_BUFFER_BIT);
Austin Kinross215b37a2014-12-22 12:56:07 -0800170 glViewport(0, 0, viewportWidth, viewportHeight);
Austin Kinross215b37a2014-12-22 12:56:07 -0800171 ASSERT_GL_NO_ERROR();
172
Olli Etuahob97a3e72016-04-13 14:31:52 +0300173 drawQuad(program, "aPosition", 0.0f);
174 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800175
Olli Etuahob97a3e72016-04-13 14:31:52 +0300176 void clearTextureLevel0(GLenum textarget,
177 GLuint texture,
178 GLfloat red,
179 GLfloat green,
180 GLfloat blue,
181 GLfloat alpha)
182 {
183 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
184 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
185 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
186 glClearColor(red, green, blue, alpha);
187 glClear(GL_COLOR_BUFFER_BIT);
188 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800189 }
190
Austin Kinross62815bf2015-01-15 16:32:36 -0800191 GLuint m2DProgram;
192 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300193 GLuint mTexture2D;
194 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400195
Austin Kinross215b37a2014-12-22 12:56:07 -0800196 GLubyte* mLevelZeroBlueInitData;
197 GLubyte* mLevelZeroWhiteInitData;
198 GLubyte* mLevelOneInitData;
199 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300200
201 private:
202 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800203};
204
Austin Kinross215b37a2014-12-22 12:56:07 -0800205class MipmapTestES3 : public ANGLETest
206{
Jamie Madillfa05f602015-05-07 13:47:11 -0400207 protected:
208 MipmapTestES3()
Olli Etuahob97a3e72016-04-13 14:31:52 +0300209 : mTextureArray(0),
210 mTexture3D(0),
211 mArrayProgram(0),
212 mTextureArrayScaleUniformLocation(-1),
213 mTextureArraySliceUniformLocation(-1),
214 m3DProgram(0),
215 mTexture3DScaleUniformLocation(-1),
216 mTexture3DSliceUniformLocation(-1),
217 mTexture3DLODUniformLocation(-1)
218
Austin Kinross215b37a2014-12-22 12:56:07 -0800219 {
220 setWindowWidth(128);
221 setWindowHeight(128);
222 setConfigRedBits(8);
223 setConfigGreenBits(8);
224 setConfigBlueBits(8);
225 setConfigAlphaBits(8);
226 }
227
Olli Etuahob97a3e72016-04-13 14:31:52 +0300228 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800229 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800230 // Don't put "#version ..." on its own line. See [cpp]p1:
231 // "If there are sequences of preprocessing tokens within the list of arguments that
232 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuahob97a3e72016-04-13 14:31:52 +0300233 return SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800234 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800235 precision highp float;
236 in vec4 position;
237 out vec2 texcoord;
238
239 uniform vec2 textureScale;
240
241 void main()
242 {
243 gl_Position = vec4(position.xy * textureScale, 0.0, 1.0);
244 texcoord = (position.xy * 0.5) + 0.5;
245 }
246 );
Olli Etuahob97a3e72016-04-13 14:31:52 +0300247 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800248
Olli Etuahob97a3e72016-04-13 14:31:52 +0300249 void setUpArrayProgram()
250 {
Austin Kinross215b37a2014-12-22 12:56:07 -0800251 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800252 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800253 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200254 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800255 uniform int slice;
256 in vec2 texcoord;
257 out vec4 out_FragColor;
258
259 void main()
260 {
261 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
262 }
263 );
264
Olli Etuahob97a3e72016-04-13 14:31:52 +0300265 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800266 if (mArrayProgram == 0)
267 {
268 FAIL() << "shader compilation failed.";
269 }
270
Austin Kinross215b37a2014-12-22 12:56:07 -0800271 mTextureArrayScaleUniformLocation = glGetUniformLocation(mArrayProgram, "textureScale");
272 ASSERT_NE(-1, mTextureArrayScaleUniformLocation);
273
274 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
275 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
276
277 glUseProgram(mArrayProgram);
278 glUniform2f(mTextureArrayScaleUniformLocation, 1.0f, 1.0f);
279 glUseProgram(0);
280 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300281 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000282
Olli Etuahob97a3e72016-04-13 14:31:52 +0300283 void setUp3DProgram()
284 {
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000285 const std::string fragmentShaderSource3D = SHADER_SOURCE
286 ( #version 300 es\n
287 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200288 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000289 uniform float slice;
290 uniform float lod;
291 in vec2 texcoord;
292 out vec4 out_FragColor;
293
294 void main()
295 {
296 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
297 }
298 );
299
Olli Etuahob97a3e72016-04-13 14:31:52 +0300300 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000301 if (m3DProgram == 0)
302 {
303 FAIL() << "shader compilation failed.";
304 }
305
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000306 mTexture3DScaleUniformLocation = glGetUniformLocation(m3DProgram, "textureScale");
307 ASSERT_NE(-1, mTexture3DScaleUniformLocation);
308
309 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
310 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
311
312 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
313 ASSERT_NE(-1, mTexture3DLODUniformLocation);
314
315 glUseProgram(m3DProgram);
316 glUniform2f(mTexture3DScaleUniformLocation, 1.0f, 1.0f);
317 glUniform1f(mTexture3DLODUniformLocation, 0);
318 glUseProgram(0);
319 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800320 }
321
Olli Etuahob97a3e72016-04-13 14:31:52 +0300322 void SetUp() override
323 {
324 ANGLETest::SetUp();
325
326 glGenTextures(1, &mTextureArray);
327 glGenTextures(1, &mTexture3D);
328 ASSERT_GL_NO_ERROR();
329
330 setUpArrayProgram();
331 setUp3DProgram();
332 }
333
334 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800335 {
336 glDeleteTextures(1, &mTextureArray);
337 glDeleteProgram(mArrayProgram);
338
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000339 glDeleteTextures(1, &mTexture3D);
340 glDeleteProgram(m3DProgram);
341
Austin Kinross215b37a2014-12-22 12:56:07 -0800342 ANGLETest::TearDown();
343 }
344
345 GLuint mTextureArray;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000346 GLuint mTexture3D;
Austin Kinross215b37a2014-12-22 12:56:07 -0800347
348 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800349 GLint mTextureArrayScaleUniformLocation;
350 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000351
352 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000353 GLint mTexture3DScaleUniformLocation;
354 GLint mTexture3DSliceUniformLocation;
355 GLint mTexture3DLODUniformLocation;
Austin Kinross215b37a2014-12-22 12:56:07 -0800356};
357
358// 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.
359// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
360// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400361TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800362{
363 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300364 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800365 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
366 ASSERT_GL_NO_ERROR();
367
368 // Disable mips.
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
370
371 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300372 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800373 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
374
375 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300376 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800377 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
378
379 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300380 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800381 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
382
383 // Complete the texture by initializing the remaining levels.
384 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700385 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800386 {
Minmin Gong794e0002015-04-07 18:31:54 -0700387 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 -0800388 ASSERT_GL_NO_ERROR();
389 n+=1;
390 }
391
392 // Pass in level one init data.
393 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
394 ASSERT_GL_NO_ERROR();
395
396 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300397 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800398 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
399
400 // 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.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300401 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800402 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
403
404 // Enable mipmaps.
405 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
406
407 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300408 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800409 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
410
411 // Draw a quarter-sized quad, and check it's black, since we've not passed any init data for level two.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300412 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800413 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 0, 255);
414
415 // Pass in level two init data.
416 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
417 ASSERT_GL_NO_ERROR();
418
419 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300420 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800421 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
422
423 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300424 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800425 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
426
427 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300428 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800429 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
430
431 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
432 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300433 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800434 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300435 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800436 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300437 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800438 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
439
440 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
441 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
442 ASSERT_GL_NO_ERROR();
443
Olli Etuahob97a3e72016-04-13 14:31:52 +0300444 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800445 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300446 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800447 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 255, 255, 255, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300448 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800449 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 255, 255, 255);
450
451 // Then enable mipmaps again. The quads should be white, green, red respectively.
452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
453
Olli Etuahob97a3e72016-04-13 14:31:52 +0300454 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800455 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 255, 255, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300456 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800457 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 255, 0, 255);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300458 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800459 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 255, 0, 0, 255);
460}
461
462// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
463// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
464// To do this, D3D11 has to convert the TextureStorage into a renderable one.
465// This test ensures that the conversion works correctly.
466// 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 -0400467TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800468{
469 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300470 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800471 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
472
473 // Then generate the mips.
474 glGenerateMipmap(GL_TEXTURE_2D);
475 ASSERT_GL_NO_ERROR();
476
477 // Enable mipmaps.
478 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
479
480 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300481 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800482 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
483
484 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300485 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800486 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
487
488 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300489 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800490 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
491
492 ASSERT_GL_NO_ERROR();
493
494 // Disable mips. Render a quad using the texture and ensure it's blue.
495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300496 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800497 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
498
Olli Etuahob97a3e72016-04-13 14:31:52 +0300499 // Clear level 0 of the texture to red.
500 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800501
502 // Reenable mips, and try rendering different-sized quads.
503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
504
505 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300506 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800507 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 0, 255);
508
509 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300510 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800511 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
512
513 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300514 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800515 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
516}
517
518// This test ensures that mips are correctly generated from a rendered image.
519// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
520// 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 -0400521TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800522{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300523 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800524 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300525 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800526
527 // Then generate the mips
528 glGenerateMipmap(GL_TEXTURE_2D);
529 ASSERT_GL_NO_ERROR();
530
531 // Enable mips.
532 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
533
534 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300535 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800536 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
537
538 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300539 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Austin Kinross215b37a2014-12-22 12:56:07 -0800540 EXPECT_PIXEL_EQ(getWindowWidth() / 4, getWindowHeight() / 4, 0, 0, 255, 255);
541
542 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300543 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800544 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
545}
546
547// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
548// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400549TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800550{
Geoff Langf74fef52015-04-29 12:57:52 -0400551 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500552 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400553 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400554 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400555 return;
556 }
557
Olli Etuahob97a3e72016-04-13 14:31:52 +0300558 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800559
560 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300561 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800562
563 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
564 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300565 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800566 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
567
568 // Now go back to the texture, and generate mips on it.
569 glGenerateMipmap(GL_TEXTURE_2D);
570 ASSERT_GL_NO_ERROR();
571
572 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
573 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300574 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800575 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
576
577 // Now tell GL to use the generated mips.
578 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200579 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800580
581 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300582 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800583 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 0, 255, 255);
584
585 // Now render the textured quad to an area smaller than the texture (i.e. to force minification). This should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300586 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800587 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
588
589 // Now clear the texture to green. This just clears the top level. The lower mips should remain blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300590 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800591
592 // Render a textured quad equal in size to the texture. This should be green, since we just cleared level 0.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300593 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800594 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
595
596 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300597 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800598 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 0, 255, 255);
599
600 // Disable mipmaps again
601 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
602 ASSERT_GL_NO_ERROR();
603
604 // Render a textured quad equal in size to the texture. This should be green, the color of level 0 in the texture.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300605 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Austin Kinross215b37a2014-12-22 12:56:07 -0800606 EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 0, 255, 0, 255);
607
608 // Render a small textured quad. This would force minification if mips were enabled, but they're not. Therefore, this should be green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300609 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross215b37a2014-12-22 12:56:07 -0800610 EXPECT_PIXEL_EQ(getWindowWidth() / 8, getWindowHeight() / 8, 0, 255, 0, 255);
611}
612
Austin Kinross62815bf2015-01-15 16:32:36 -0800613// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
614// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400615TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800616{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300617 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800618
619 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300620 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Austin Kinross62815bf2015-01-15 16:32:36 -0800621 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
622
623 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800624 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
625 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300626 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Austin Kinross62815bf2015-01-15 16:32:36 -0800627 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
628
629 // Draw using a smaller viewport (to force a lower LOD of the texture). This should still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300630 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross62815bf2015-01-15 16:32:36 -0800631 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
632
633 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300634 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800635
636 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300637 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Austin Kinross62815bf2015-01-15 16:32:36 -0800638 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
639
640 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
641 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300642 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross62815bf2015-01-15 16:32:36 -0800643 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
644
645 // Disable mipmaps again, and draw a to a quarter-size viewport.
646 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800647 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300648 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
649 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
Austin Kinross62815bf2015-01-15 16:32:36 -0800650}
651
652// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400653TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800654{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300655 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800656
657 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300658 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Austin Kinross62815bf2015-01-15 16:32:36 -0800659 EXPECT_PIXEL_EQ(0, 0, 0, 0, 255, 255);
660
661 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300662 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800663
664 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300665 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Austin Kinross62815bf2015-01-15 16:32:36 -0800666 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
667
668 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300669 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Austin Kinross62815bf2015-01-15 16:32:36 -0800670 EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
671}
672
Austin Kinross215b37a2014-12-22 12:56:07 -0800673// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
674// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400675TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800676{
677 int px = getWindowWidth() / 2;
678 int py = getWindowHeight() / 2;
679
Austin Kinross215b37a2014-12-22 12:56:07 -0800680 glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
681
682 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
683
684 // Fill the first layer with red
685 std::vector<GLubyte> pixels(4 * 16 * 16);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300686 FillWithRGBA<GLubyte>(16u * 16u, 255u, 0u, 0u, 255u, pixels.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800687
688 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
689
690 // Fill the second layer with green
Olli Etuahob97a3e72016-04-13 14:31:52 +0300691 FillWithRGBA<GLubyte>(16u * 16u, 0u, 255u, 0u, 255u, pixels.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800692
693 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
694
695 // Fill the third layer with blue
Olli Etuahob97a3e72016-04-13 14:31:52 +0300696 FillWithRGBA<GLubyte>(16u * 16u, 0u, 0u, 255u, 255u, pixels.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800697
698 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
699
700 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
701 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
702
703 EXPECT_GL_NO_ERROR();
704
705 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
706
707 EXPECT_GL_NO_ERROR();
708
709 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800710
711 EXPECT_GL_NO_ERROR();
712
713 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800714 glUniform1i(mTextureArraySliceUniformLocation, 0);
715 drawQuad(mArrayProgram, "position", 0.5f);
716 EXPECT_GL_NO_ERROR();
717 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
718
719 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800720 glUniform1i(mTextureArraySliceUniformLocation, 1);
721 drawQuad(mArrayProgram, "position", 0.5f);
722 EXPECT_GL_NO_ERROR();
723 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
724
725 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800726 glUniform1i(mTextureArraySliceUniformLocation, 2);
727 drawQuad(mArrayProgram, "position", 0.5f);
728 EXPECT_GL_NO_ERROR();
729 EXPECT_PIXEL_EQ(px, py, 0, 0, 255, 255);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000730}
731
732// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
733// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400734TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000735{
736 int px = getWindowWidth() / 2;
737 int py = getWindowHeight() / 2;
738
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000739 glBindTexture(GL_TEXTURE_3D, mTexture3D);
740
741 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
742
743 // Fill the first layer with red
744 std::vector<GLubyte> pixels(4 * 16 * 16);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300745 FillWithRGBA<GLubyte>(16u * 16u, 255u, 0u, 0u, 255u, pixels.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000746
747 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
748
749 // Fill the second layer with green
Olli Etuahob97a3e72016-04-13 14:31:52 +0300750 FillWithRGBA<GLubyte>(16u * 16u, 0u, 255u, 0u, 255u, pixels.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000751
752 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
753
754 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
755 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
756
757 EXPECT_GL_NO_ERROR();
758
759 glGenerateMipmap(GL_TEXTURE_3D);
760
761 EXPECT_GL_NO_ERROR();
762
763 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000764
765 EXPECT_GL_NO_ERROR();
766
767 // Mipmap level 0
768 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000769 glUniform1f(mTexture3DLODUniformLocation, 0.);
770 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
771 drawQuad(m3DProgram, "position", 0.5f);
772 EXPECT_GL_NO_ERROR();
773 EXPECT_PIXEL_EQ(px, py, 255, 0, 0, 255);
774
775 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000776 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
777 drawQuad(m3DProgram, "position", 0.5f);
778 EXPECT_GL_NO_ERROR();
779 EXPECT_PIXEL_EQ(px, py, 0, 255, 0, 255);
780
781 // Mipmap level 1
782 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000783 glUniform1f(mTexture3DLODUniformLocation, 1.);
784 drawQuad(m3DProgram, "position", 0.5f);
785 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500786 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000787
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000788 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
789 drawQuad(m3DProgram, "position", 0.5f);
790 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500791 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000792}
Jamie Madillfa05f602015-05-07 13:47:11 -0400793
794// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
795// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -0500796ANGLE_INSTANTIATE_TEST(MipmapTest,
797 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800798 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
799 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -0500800 ES2_D3D11_FL9_3_WARP(),
801 ES2_OPENGL(),
802 ES3_OPENGL(),
803 ES2_OPENGLES(),
804 ES3_OPENGLES());
805ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());