blob: ca4f7114089d3d9ffa0f1192ce9f1446887e52b0 [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
Geoff Lang46258e12017-04-10 12:28:34 -04009#include "test_utils/gl_raii.h"
10
Jamie Madillfa05f602015-05-07 13:47:11 -040011using namespace angle;
Austin Kinross215b37a2014-12-22 12:56:07 -080012
Olli Etuaho0f2b1562016-05-13 16:15:35 +030013namespace
14{
15
16void TexImageCubeMapFaces(GLint level,
17 GLenum internalformat,
18 GLsizei width,
19 GLenum format,
20 GLenum type,
21 void *pixels)
22{
23 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internalformat, width, width, 0, format,
24 type, pixels);
25 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internalformat, width, width, 0, format,
26 type, pixels);
27 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internalformat, width, width, 0, format,
28 type, pixels);
29 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internalformat, width, width, 0, format,
30 type, pixels);
31 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internalformat, width, width, 0, format,
32 type, pixels);
33 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internalformat, width, width, 0, format,
34 type, pixels);
35}
36
37class BaseMipmapTest : public ANGLETest
38{
39 protected:
40 void clearAndDrawQuad(GLuint program, GLsizei viewportWidth, GLsizei viewportHeight)
41 {
42 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
43 glClear(GL_COLOR_BUFFER_BIT);
44 glViewport(0, 0, viewportWidth, viewportHeight);
45 ASSERT_GL_NO_ERROR();
46
47 drawQuad(program, "position", 0.0f);
48 }
49};
50
51} // namespace
52
53class MipmapTest : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -080054{
55 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040056 MipmapTest()
Olli Etuahob97a3e72016-04-13 14:31:52 +030057 : m2DProgram(0),
58 mCubeProgram(0),
59 mTexture2D(0),
60 mTextureCube(0),
61 mLevelZeroBlueInitData(nullptr),
62 mLevelZeroWhiteInitData(nullptr),
63 mLevelOneInitData(nullptr),
64 mLevelTwoInitData(nullptr),
65 mOffscreenFramebuffer(0)
Austin Kinross215b37a2014-12-22 12:56:07 -080066 {
67 setWindowWidth(128);
68 setWindowHeight(128);
69 setConfigRedBits(8);
70 setConfigGreenBits(8);
71 setConfigBlueBits(8);
72 setConfigAlphaBits(8);
73 }
74
Olli Etuahob97a3e72016-04-13 14:31:52 +030075 void setUp2DProgram()
Austin Kinross215b37a2014-12-22 12:56:07 -080076 {
Austin Kinross215b37a2014-12-22 12:56:07 -080077 // Vertex Shader source
Olli Etuaho0f2b1562016-05-13 16:15:35 +030078 // clang-format off
Austin Kinross215b37a2014-12-22 12:56:07 -080079 const std::string vs = SHADER_SOURCE
80 (
Olli Etuaho0f2b1562016-05-13 16:15:35 +030081 attribute vec4 position;
Austin Kinross215b37a2014-12-22 12:56:07 -080082 varying vec2 vTexCoord;
83
84 void main()
85 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +030086 gl_Position = position;
87 vTexCoord = (position.xy * 0.5) + 0.5;
Austin Kinross215b37a2014-12-22 12:56:07 -080088 }
89 );
90
91 // Fragment Shader source
92 const std::string fs = SHADER_SOURCE
93 (
94 precision mediump float;
95
96 uniform sampler2D uTexture;
97 varying vec2 vTexCoord;
98
99 void main()
100 {
101 gl_FragColor = texture2D(uTexture, vTexCoord);
102 }
103 );
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300104 // clang-format on
Austin Kinross215b37a2014-12-22 12:56:07 -0800105
Austin Kinross62815bf2015-01-15 16:32:36 -0800106 m2DProgram = CompileProgram(vs, fs);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300107 ASSERT_NE(0u, m2DProgram);
108 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800109
Olli Etuahob97a3e72016-04-13 14:31:52 +0300110 void setUpCubeProgram()
111 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800112 // A simple vertex shader for the texture cube
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300113 // clang-format off
Austin Kinross62815bf2015-01-15 16:32:36 -0800114 const std::string cubeVS = SHADER_SOURCE
115 (
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300116 attribute vec4 position;
Austin Kinross62815bf2015-01-15 16:32:36 -0800117 varying vec4 vPosition;
118 void main()
119 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300120 gl_Position = position;
121 vPosition = position;
Austin Kinross62815bf2015-01-15 16:32:36 -0800122 }
123 );
124
125 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
126 const std::string cubeFS = SHADER_SOURCE
127 (
128 precision mediump float;
129 uniform samplerCube uTexture;
130 varying vec4 vPosition;
131
132 void main()
133 {
134 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
135 }
136 );
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300137 // clang-format on
Austin Kinross62815bf2015-01-15 16:32:36 -0800138
139 mCubeProgram = CompileProgram(cubeVS, cubeFS);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300140 ASSERT_NE(0u, mCubeProgram);
141 }
Austin Kinross62815bf2015-01-15 16:32:36 -0800142
Olli Etuahob97a3e72016-04-13 14:31:52 +0300143 void SetUp() override
144 {
145 ANGLETest::SetUp();
Austin Kinross62815bf2015-01-15 16:32:36 -0800146
Olli Etuahob97a3e72016-04-13 14:31:52 +0300147 setUp2DProgram();
148
149 setUpCubeProgram();
Geoff Lang27359ff2015-06-02 15:42:04 -0400150
Austin Kinross62815bf2015-01-15 16:32:36 -0800151 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
152 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
153 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
154 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800155
156 glGenFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300157 glGenTextures(1, &mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800158
Austin Kinross62815bf2015-01-15 16:32:36 -0800159 // Initialize the texture2D to be empty, and don't use mips.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300160 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800161 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
162 GL_UNSIGNED_BYTE, nullptr);
Austin Kinross215b37a2014-12-22 12:56:07 -0800163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
165
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300166 ASSERT_EQ(getWindowWidth(), getWindowHeight());
167
Austin Kinross62815bf2015-01-15 16:32:36 -0800168 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300169 glGenTextures(1, &mTextureCube);
170 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300171 TexImageCubeMapFaces(0, GL_RGB, getWindowWidth(), GL_RGB, GL_UNSIGNED_BYTE, nullptr);
172 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowWidth(),
173 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
Austin Kinross62815bf2015-01-15 16:32:36 -0800174
175 // Complete the texture cube without mipmaps to start with.
176 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
177 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
178
179 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800180 }
181
Olli Etuahob97a3e72016-04-13 14:31:52 +0300182 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800183 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800184 glDeleteProgram(m2DProgram);
185 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800186 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300187 glDeleteTextures(1, &mTexture2D);
188 glDeleteTextures(1, &mTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800189
Corentin Wallez254fcea2015-08-25 15:11:07 -0400190 SafeDeleteArray(mLevelZeroBlueInitData);
191 SafeDeleteArray(mLevelZeroWhiteInitData);
192 SafeDeleteArray(mLevelOneInitData);
193 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800194
195 ANGLETest::TearDown();
196 }
197
198 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
199 {
200 GLubyte *data = new GLubyte[3 * width * height];
201
202 for (int i = 0; i < width * height; i+=1)
203 {
Minmin Gong794e0002015-04-07 18:31:54 -0700204 data[3 * i + 0] = static_cast<GLubyte>(r);
205 data[3 * i + 1] = static_cast<GLubyte>(g);
206 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800207 }
208
209 return data;
210 }
211
Olli Etuahob97a3e72016-04-13 14:31:52 +0300212 void clearTextureLevel0(GLenum textarget,
213 GLuint texture,
214 GLfloat red,
215 GLfloat green,
216 GLfloat blue,
217 GLfloat alpha)
218 {
219 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
220 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
221 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
222 glClearColor(red, green, blue, alpha);
223 glClear(GL_COLOR_BUFFER_BIT);
224 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800225 }
226
Austin Kinross62815bf2015-01-15 16:32:36 -0800227 GLuint m2DProgram;
228 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300229 GLuint mTexture2D;
230 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400231
Austin Kinross215b37a2014-12-22 12:56:07 -0800232 GLubyte* mLevelZeroBlueInitData;
233 GLubyte* mLevelZeroWhiteInitData;
234 GLubyte* mLevelOneInitData;
235 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300236
237 private:
238 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800239};
240
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300241class MipmapTestES3 : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -0800242{
Jamie Madillfa05f602015-05-07 13:47:11 -0400243 protected:
244 MipmapTestES3()
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300245 : mTexture(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300246 mArrayProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300247 mTextureArraySliceUniformLocation(-1),
248 m3DProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300249 mTexture3DSliceUniformLocation(-1),
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300250 mTexture3DLODUniformLocation(-1),
251 m2DProgram(0)
Olli Etuahob97a3e72016-04-13 14:31:52 +0300252
Austin Kinross215b37a2014-12-22 12:56:07 -0800253 {
254 setWindowWidth(128);
255 setWindowHeight(128);
256 setConfigRedBits(8);
257 setConfigGreenBits(8);
258 setConfigBlueBits(8);
259 setConfigAlphaBits(8);
260 }
261
Olli Etuahob97a3e72016-04-13 14:31:52 +0300262 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800263 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800264 // Don't put "#version ..." on its own line. See [cpp]p1:
265 // "If there are sequences of preprocessing tokens within the list of arguments that
266 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuaho190028d2016-05-13 12:11:29 +0300267 // clang-format off
Olli Etuahob97a3e72016-04-13 14:31:52 +0300268 return SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800269 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800270 precision highp float;
271 in vec4 position;
272 out vec2 texcoord;
273
Austin Kinross215b37a2014-12-22 12:56:07 -0800274 void main()
275 {
Olli Etuaho190028d2016-05-13 12:11:29 +0300276 gl_Position = vec4(position.xy, 0.0, 1.0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800277 texcoord = (position.xy * 0.5) + 0.5;
278 }
279 );
Olli Etuaho190028d2016-05-13 12:11:29 +0300280 // clang-format on
Olli Etuahob97a3e72016-04-13 14:31:52 +0300281 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800282
Olli Etuahob97a3e72016-04-13 14:31:52 +0300283 void setUpArrayProgram()
284 {
Austin Kinross215b37a2014-12-22 12:56:07 -0800285 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800286 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800287 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200288 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800289 uniform int slice;
290 in vec2 texcoord;
291 out vec4 out_FragColor;
292
293 void main()
294 {
295 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
296 }
297 );
298
Olli Etuahob97a3e72016-04-13 14:31:52 +0300299 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800300 if (mArrayProgram == 0)
301 {
302 FAIL() << "shader compilation failed.";
303 }
304
Austin Kinross215b37a2014-12-22 12:56:07 -0800305 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
306 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
307
308 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800309 glUseProgram(0);
310 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300311 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000312
Olli Etuahob97a3e72016-04-13 14:31:52 +0300313 void setUp3DProgram()
314 {
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000315 const std::string fragmentShaderSource3D = SHADER_SOURCE
316 ( #version 300 es\n
317 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200318 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000319 uniform float slice;
320 uniform float lod;
321 in vec2 texcoord;
322 out vec4 out_FragColor;
323
324 void main()
325 {
326 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
327 }
328 );
329
Olli Etuahob97a3e72016-04-13 14:31:52 +0300330 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000331 if (m3DProgram == 0)
332 {
333 FAIL() << "shader compilation failed.";
334 }
335
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000336 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
337 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
338
339 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
340 ASSERT_NE(-1, mTexture3DLODUniformLocation);
341
342 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000343 glUniform1f(mTexture3DLODUniformLocation, 0);
344 glUseProgram(0);
345 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800346 }
347
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300348 void setUp2DProgram()
349 {
350 // clang-format off
351 const std::string fragmentShaderSource2D = SHADER_SOURCE
352 ( #version 300 es\n
353 precision highp float;
354 uniform highp sampler2D tex;
355 in vec2 texcoord;
356 out vec4 out_FragColor;
357
358 void main()
359 {
360 out_FragColor = texture(tex, texcoord);
361 }
362 );
363 // clang-format on
364
365 m2DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource2D);
366 ASSERT_NE(0u, m2DProgram);
367
368 ASSERT_GL_NO_ERROR();
369 }
370
371 void setUpCubeProgram()
372 {
373 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
374 // clang-format off
375 const std::string cubeFS = SHADER_SOURCE
376 ( #version 300 es\n
377 precision mediump float;
378 uniform samplerCube uTexture;
379 in vec2 texcoord;
380 out vec4 out_FragColor;
381
382 void main()
383 {
384 out_FragColor = texture(uTexture, vec3(texcoord.x, -1, texcoord.y));
385 }
386 );
387 // clang-format on
388
389 mCubeProgram = CompileProgram(vertexShaderSource(), cubeFS);
390 ASSERT_NE(0u, mCubeProgram);
391
392 ASSERT_GL_NO_ERROR();
393 }
394
Olli Etuahob97a3e72016-04-13 14:31:52 +0300395 void SetUp() override
396 {
397 ANGLETest::SetUp();
398
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300399 glGenTextures(1, &mTexture);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300400 ASSERT_GL_NO_ERROR();
401
402 setUpArrayProgram();
403 setUp3DProgram();
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300404 setUp2DProgram();
405 setUpCubeProgram();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300406 }
407
408 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800409 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300410 glDeleteTextures(1, &mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800411
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300412 glDeleteProgram(mArrayProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000413 glDeleteProgram(m3DProgram);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300414 glDeleteProgram(m2DProgram);
415 glDeleteProgram(mCubeProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000416
Austin Kinross215b37a2014-12-22 12:56:07 -0800417 ANGLETest::TearDown();
418 }
419
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300420 GLuint mTexture;
Austin Kinross215b37a2014-12-22 12:56:07 -0800421
422 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800423 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000424
425 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000426 GLint mTexture3DSliceUniformLocation;
427 GLint mTexture3DLODUniformLocation;
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300428
429 GLuint m2DProgram;
430
431 GLuint mCubeProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800432};
433
434// 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.
435// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
436// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400437TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800438{
439 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300440 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800441 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
442 ASSERT_GL_NO_ERROR();
443
444 // Disable mips.
445 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
446
447 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300448 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300449 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800450
451 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300452 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300453 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800454
455 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300456 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300457 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800458
459 // Complete the texture by initializing the remaining levels.
460 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700461 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800462 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800463 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / (1U << n),
464 getWindowWidth() / (1U << n), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
Austin Kinross215b37a2014-12-22 12:56:07 -0800465 ASSERT_GL_NO_ERROR();
466 n+=1;
467 }
468
469 // Pass in level one init data.
470 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
471 ASSERT_GL_NO_ERROR();
472
473 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300474 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300475 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800476
477 // 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 +0300478 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300479 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800480
481 // Enable mipmaps.
482 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
483
484 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300485 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300486 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800487
488 // 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 +0300489 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300490 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::black);
Austin Kinross215b37a2014-12-22 12:56:07 -0800491
492 // Pass in level two init data.
493 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
494 ASSERT_GL_NO_ERROR();
495
496 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300497 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300498 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800499
500 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300501 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300502 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800503
504 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300505 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300506 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800507
508 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
509 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300510 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300511 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300512 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300513 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300514 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300515 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800516
517 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
518 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
519 ASSERT_GL_NO_ERROR();
520
Olli Etuahob97a3e72016-04-13 14:31:52 +0300521 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300522 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300523 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300524 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300525 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300526 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::white);
Austin Kinross215b37a2014-12-22 12:56:07 -0800527
528 // Then enable mipmaps again. The quads should be white, green, red respectively.
529 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
530
Olli Etuahob97a3e72016-04-13 14:31:52 +0300531 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300532 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300533 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300534 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300535 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300536 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800537}
538
539// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
540// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
541// To do this, D3D11 has to convert the TextureStorage into a renderable one.
542// This test ensures that the conversion works correctly.
543// 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 -0400544TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800545{
546 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300547 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800548 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
549
550 // Then generate the mips.
551 glGenerateMipmap(GL_TEXTURE_2D);
552 ASSERT_GL_NO_ERROR();
553
554 // Enable mipmaps.
555 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
556
557 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300558 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300559 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800560
561 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300562 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300563 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800564
565 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300566 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300567 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800568
569 ASSERT_GL_NO_ERROR();
570
571 // Disable mips. Render a quad using the texture and ensure it's blue.
572 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300573 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300574 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800575
Olli Etuahob97a3e72016-04-13 14:31:52 +0300576 // Clear level 0 of the texture to red.
577 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800578
579 // Reenable mips, and try rendering different-sized quads.
580 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
581
582 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300583 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300584 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800585
586 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300587 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300588 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800589
590 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300591 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300592 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800593}
594
595// This test ensures that mips are correctly generated from a rendered image.
596// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
597// 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 -0400598TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800599{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300600 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800601 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300602 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800603
604 // Then generate the mips
605 glGenerateMipmap(GL_TEXTURE_2D);
606 ASSERT_GL_NO_ERROR();
607
608 // Enable mips.
609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
610
611 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300612 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300613 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800614
615 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300616 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300617 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800618
619 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300620 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300621 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800622}
623
624// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
625// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400626TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800627{
Geoff Langf74fef52015-04-29 12:57:52 -0400628 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500629 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400630 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400631 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400632 return;
633 }
634
Olli Etuahob97a3e72016-04-13 14:31:52 +0300635 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800636
637 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300638 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800639
640 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
641 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300642 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300643 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800644
645 // Now go back to the texture, and generate mips on it.
646 glGenerateMipmap(GL_TEXTURE_2D);
647 ASSERT_GL_NO_ERROR();
648
649 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
650 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300651 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300652 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800653
654 // Now tell GL to use the generated mips.
655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200656 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800657
658 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300659 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300660 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800661
662 // 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 +0300663 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300664 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800665
666 // 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 +0300667 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800668
669 // 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 +0300670 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300671 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800672
673 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300674 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300675 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800676
677 // Disable mipmaps again
678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
679 ASSERT_GL_NO_ERROR();
680
681 // 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 +0300682 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300683 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800684
685 // 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 +0300686 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300687 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800688}
689
Geoff Lang46258e12017-04-10 12:28:34 -0400690// Regression test for a bug that cause mipmaps to only generate using the top left corner as input.
691TEST_P(MipmapTest, MipMapGenerationD3D9Bug)
692{
693 if (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8") ||
694 !extensionEnabled("GL_ANGLE_texture_usage"))
695 {
696 std::cout << "Test skipped due to missing extensions." << std::endl;
697 return;
698 }
699
700 const GLColor mip0Color[4] = {
701 GLColor::red, GLColor::green, GLColor::red, GLColor::green,
702 };
703 const GLColor mip1Color = GLColor(127, 127, 0, 255);
704
705 GLTexture texture;
706 glBindTexture(GL_TEXTURE_2D, texture.get());
707 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
708 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
709 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA8_OES, 2, 2);
710 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, mip0Color);
711 glGenerateMipmap(GL_TEXTURE_2D);
712
713 // Only draw to a 1 pixel viewport so the lower mip is used
714 clearAndDrawQuad(m2DProgram, 1, 1);
715 EXPECT_PIXEL_COLOR_NEAR(0, 0, mip1Color, 1.0);
716}
717
Austin Kinross62815bf2015-01-15 16:32:36 -0800718// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
719// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400720TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800721{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300722 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800723
724 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300725 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300726 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800727
728 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800729 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
730 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300731 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300732 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800733
734 // 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 +0300735 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300736 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800737
738 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300739 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800740
741 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300742 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300743 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800744
745 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
746 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300747 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300748 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800749
750 // Disable mipmaps again, and draw a to a quarter-size viewport.
751 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800752 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300753 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300754 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800755}
756
757// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400758TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800759{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300760 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800761
762 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300763 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300764 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800765
766 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300767 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800768
769 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300770 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300771 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800772
773 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300774 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300775 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800776}
777
Austin Kinross215b37a2014-12-22 12:56:07 -0800778// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
779// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400780TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800781{
782 int px = getWindowWidth() / 2;
783 int py = getWindowHeight() / 2;
784
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300785 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800786
787 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
788
789 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300790 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
791 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
792 pixelsRed.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800793
794 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300795 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
796 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
797 pixelsGreen.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800798
799 // Fill the third layer with blue
Olli Etuaho190028d2016-05-13 12:11:29 +0300800 std::vector<GLColor> pixelsBlue(16 * 16, GLColor::blue);
801 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
802 pixelsBlue.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800803
804 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
805 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
806
807 EXPECT_GL_NO_ERROR();
808
809 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
810
811 EXPECT_GL_NO_ERROR();
812
813 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800814
815 EXPECT_GL_NO_ERROR();
816
817 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800818 glUniform1i(mTextureArraySliceUniformLocation, 0);
819 drawQuad(mArrayProgram, "position", 0.5f);
820 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300821 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800822
823 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800824 glUniform1i(mTextureArraySliceUniformLocation, 1);
825 drawQuad(mArrayProgram, "position", 0.5f);
826 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300827 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800828
829 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800830 glUniform1i(mTextureArraySliceUniformLocation, 2);
831 drawQuad(mArrayProgram, "position", 0.5f);
832 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300833 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::blue);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000834}
835
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300836// Create a mipmapped 2D array texture with more layers than width / height, and call
837// GenerateMipmap.
838TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
839{
840 int px = getWindowWidth() / 2;
841 int py = getWindowHeight() / 2;
842
843 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
844
845 // Fill the whole texture with red.
846 std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
847 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
848 pixelsRed.data());
849
850 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
851 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
852
853 EXPECT_GL_NO_ERROR();
854
855 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
856
857 EXPECT_GL_NO_ERROR();
858
859 glUseProgram(mArrayProgram);
860
861 EXPECT_GL_NO_ERROR();
862
863 // Draw the first slice
864 glUniform1i(mTextureArraySliceUniformLocation, 0);
865 drawQuad(mArrayProgram, "position", 0.5f);
866 EXPECT_GL_NO_ERROR();
867 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
868
869 // Draw the fourth slice
870 glUniform1i(mTextureArraySliceUniformLocation, 3);
871 drawQuad(mArrayProgram, "position", 0.5f);
872 EXPECT_GL_NO_ERROR();
873 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
874}
875
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000876// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
877// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400878TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000879{
880 int px = getWindowWidth() / 2;
881 int py = getWindowHeight() / 2;
882
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300883 glBindTexture(GL_TEXTURE_3D, mTexture);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000884
885 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
886
887 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300888 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
889 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
890 pixelsRed.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000891
892 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300893 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
894 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
895 pixelsGreen.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000896
897 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
898 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
899
900 EXPECT_GL_NO_ERROR();
901
902 glGenerateMipmap(GL_TEXTURE_3D);
903
904 EXPECT_GL_NO_ERROR();
905
906 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000907
908 EXPECT_GL_NO_ERROR();
909
910 // Mipmap level 0
911 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000912 glUniform1f(mTexture3DLODUniformLocation, 0.);
913 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
914 drawQuad(m3DProgram, "position", 0.5f);
915 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300916 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000917
918 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000919 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
920 drawQuad(m3DProgram, "position", 0.5f);
921 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300922 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000923
924 // Mipmap level 1
925 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000926 glUniform1f(mTexture3DLODUniformLocation, 1.);
927 drawQuad(m3DProgram, "position", 0.5f);
928 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500929 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000930
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000931 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
932 drawQuad(m3DProgram, "position", 0.5f);
933 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500934 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000935}
Jamie Madillfa05f602015-05-07 13:47:11 -0400936
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300937// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
938// the same, and then sample levels 0 and 2.
939// GLES 3.0.4 section 3.8.10:
940// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
941// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
942// the levelbase array, are left unchanged by this computation."
943TEST_P(MipmapTestES3, GenerateMipmapBaseLevel)
944{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400945 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300946 {
947 // Observed incorrect rendering on AMD, sampling level 2 returns black.
948 std::cout << "Test skipped on AMD OpenGL." << std::endl;
949 return;
950 }
951
952 glBindTexture(GL_TEXTURE_2D, mTexture);
953
Jamie Madille1faacb2016-12-13 12:42:14 -0500954 ASSERT_EQ(getWindowWidth(), getWindowHeight());
Olli Etuahofb80eaf2016-07-25 13:39:30 +0300955
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300956 // Fill level 0 with blue
957 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
958 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
959 GL_UNSIGNED_BYTE, pixelsBlue.data());
960
961 // Fill level 1 with red
962 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
963 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
964 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
965
966 // Fill level 2 with green
967 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
968 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
969 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
970
971 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
972 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
973 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
974
975 EXPECT_GL_NO_ERROR();
976
977 // The blue level 0 should be untouched by this since base level is 1.
978 glGenerateMipmap(GL_TEXTURE_2D);
979
980 EXPECT_GL_NO_ERROR();
981
982 // Draw using level 2. It should be set to red by GenerateMipmap.
983 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
984 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
985
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300986 // Draw using level 0. It should still be blue.
987 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
988 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
989 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
990}
991
992// Create a cube map with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
993// the same, and then sample levels 0 and 2.
994// GLES 3.0.4 section 3.8.10:
995// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
996// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
997// the levelbase array, are left unchanged by this computation."
998TEST_P(MipmapTestES3, GenerateMipmapCubeBaseLevel)
999{
Corentin Wallezc7f59d02016-06-20 10:12:08 -04001000 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +03001001 {
1002 // Observed incorrect rendering on AMD, sampling level 2 returns black.
1003 std::cout << "Test skipped on AMD OpenGL." << std::endl;
1004 return;
1005 }
1006
1007 ASSERT_EQ(getWindowWidth(), getWindowHeight());
1008
1009 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
1010 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowWidth(), GLColor::blue);
1011 TexImageCubeMapFaces(0, GL_RGBA8, getWindowWidth(), GL_RGBA, GL_UNSIGNED_BYTE,
1012 pixelsBlue.data());
1013
1014 // Fill level 1 with red
1015 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowWidth() / 4, GLColor::red);
1016 TexImageCubeMapFaces(1, GL_RGBA8, getWindowWidth() / 2, GL_RGBA, GL_UNSIGNED_BYTE,
1017 pixelsRed.data());
1018
1019 // Fill level 2 with green
1020 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowWidth() / 16, GLColor::green);
1021 TexImageCubeMapFaces(2, GL_RGBA8, getWindowWidth() / 4, GL_RGBA, GL_UNSIGNED_BYTE,
1022 pixelsGreen.data());
1023
1024 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1025 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1026 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 1);
1027
1028 EXPECT_GL_NO_ERROR();
1029
1030 // The blue level 0 should be untouched by this since base level is 1.
1031 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
1032
1033 EXPECT_GL_NO_ERROR();
1034
1035 // Draw using level 2. It should be set to red by GenerateMipmap.
1036 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1037 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
1038
Corentin Wallezc7f59d02016-06-20 10:12:08 -04001039 if (IsNVIDIA() && IsOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +03001040 {
1041 // Observed incorrect rendering on NVIDIA, level zero seems to be incorrectly affected by
1042 // GenerateMipmap.
1043 std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
1044 return;
1045 }
1046
1047 // Draw using level 0. It should still be blue.
1048 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
1049 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
1050 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1051}
1052
1053// Create a texture with levels 0-2, call GenerateMipmap with max level 1 so that level 2 stays the
1054// same, and then sample levels 1 and 2.
1055// GLES 3.0.4 section 3.8.10:
1056// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
1057// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
1058// the levelbase array, are left unchanged by this computation."
1059TEST_P(MipmapTestES3, GenerateMipmapMaxLevel)
1060{
1061 glBindTexture(GL_TEXTURE_2D, mTexture);
1062
1063 // Fill level 0 with blue
1064 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1065 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1066 GL_UNSIGNED_BYTE, pixelsBlue.data());
1067
1068 // Fill level 1 with red
1069 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
1070 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
1071 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
1072
1073 // Fill level 2 with green
1074 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
1075 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
1076 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
1077
1078 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1079 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1080 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1081
1082 EXPECT_GL_NO_ERROR();
1083
1084 // The green level 2 should be untouched by this since max level is 1.
1085 glGenerateMipmap(GL_TEXTURE_2D);
1086
1087 EXPECT_GL_NO_ERROR();
1088
1089 // Draw using level 1. It should be set to blue by GenerateMipmap.
1090 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
1091 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1092
1093 // Draw using level 2. It should still be green.
1094 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
1095 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1096 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
1097}
1098
1099// Call GenerateMipmap with out-of-range base level. The spec is interpreted so that an out-of-range
1100// base level does not have a color-renderable/texture-filterable internal format, so the
1101// GenerateMipmap call generates INVALID_OPERATION. GLES 3.0.4 section 3.8.10:
1102// "If the levelbase array was not specified with an unsized internal format from table 3.3 or a
1103// sized internal format that is both color-renderable and texture-filterable according to table
1104// 3.13, an INVALID_OPERATION error is generated."
1105TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRange)
1106{
1107 glBindTexture(GL_TEXTURE_2D, mTexture);
1108
1109 // Fill level 0 with blue
1110 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1111 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1112 GL_UNSIGNED_BYTE, pixelsBlue.data());
1113
1114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1115
1116 EXPECT_GL_NO_ERROR();
1117
1118 // Expecting the out-of-range base level to be treated as not color-renderable and
1119 // texture-filterable.
1120 glGenerateMipmap(GL_TEXTURE_2D);
1121 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1122
1123 // Draw using level 0. It should still be blue.
1124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1127 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1128 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1129}
1130
1131// Call GenerateMipmap with out-of-range base level on an immutable texture. The base level should
1132// be clamped, so the call doesn't generate an error.
1133TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRangeImmutableTexture)
1134{
1135 glBindTexture(GL_TEXTURE_2D, mTexture);
1136
1137 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1138 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1139
1140 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1141
1142 EXPECT_GL_NO_ERROR();
1143
1144 // This is essentially a no-op, since the texture only has one level.
1145 glGenerateMipmap(GL_TEXTURE_2D);
1146
1147 EXPECT_GL_NO_ERROR();
1148
1149 // The only level of the texture should still be green.
1150 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1152 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1153 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
1154}
1155
Geoff Lang66c5e612017-04-25 11:40:03 -04001156// A native version of the WebGL2 test tex-base-level-bug.html
1157TEST_P(MipmapTestES3, BaseLevelTextureBug)
1158{
1159 if (IsOpenGL() && IsWindows() && IsAMD())
1160 {
1161 std::cout << "Test skipped on Windows AMD OpenGL." << std::endl;
1162 return;
1163 }
1164
1165 glBindTexture(GL_TEXTURE_2D, mTexture);
1166 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
1167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
1168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1170 ASSERT_GL_NO_ERROR();
1171
1172 drawQuad(m2DProgram, "position", 0.5f);
1173 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1174
1175 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1176 ASSERT_GL_NO_ERROR();
1177
1178 drawQuad(m2DProgram, "position", 0.5f);
1179 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1180}
1181
Jamie Madillfa05f602015-05-07 13:47:11 -04001182// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
1183// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -05001184ANGLE_INSTANTIATE_TEST(MipmapTest,
1185 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -08001186 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
1187 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -05001188 ES2_D3D11_FL9_3_WARP(),
1189 ES2_OPENGL(),
1190 ES3_OPENGL(),
1191 ES2_OPENGLES(),
1192 ES3_OPENGLES());
1193ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());