blob: 9fde0bfdee824acfe44acb0b7afafab367138cb4 [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 Etuahoa20af6d2017-09-18 13:32:29 +030078 const std::string vs =
79 R"(attribute vec4 position;
Austin Kinross215b37a2014-12-22 12:56:07 -080080 varying vec2 vTexCoord;
81
82 void main()
83 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +030084 gl_Position = position;
85 vTexCoord = (position.xy * 0.5) + 0.5;
Olli Etuahoa20af6d2017-09-18 13:32:29 +030086 })";
Austin Kinross215b37a2014-12-22 12:56:07 -080087
88 // Fragment Shader source
Olli Etuahoa20af6d2017-09-18 13:32:29 +030089 const std::string fs =
90 R"(precision mediump float;
Austin Kinross215b37a2014-12-22 12:56:07 -080091
92 uniform sampler2D uTexture;
93 varying vec2 vTexCoord;
94
95 void main()
96 {
97 gl_FragColor = texture2D(uTexture, vTexCoord);
Olli Etuahoa20af6d2017-09-18 13:32:29 +030098 })";
Austin Kinross215b37a2014-12-22 12:56:07 -080099
Austin Kinross62815bf2015-01-15 16:32:36 -0800100 m2DProgram = CompileProgram(vs, fs);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300101 ASSERT_NE(0u, m2DProgram);
102 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800103
Olli Etuahob97a3e72016-04-13 14:31:52 +0300104 void setUpCubeProgram()
105 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800106 // A simple vertex shader for the texture cube
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300107 const std::string cubeVS =
108 R"(attribute vec4 position;
Austin Kinross62815bf2015-01-15 16:32:36 -0800109 varying vec4 vPosition;
110 void main()
111 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300112 gl_Position = position;
113 vPosition = position;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300114 })";
Austin Kinross62815bf2015-01-15 16:32:36 -0800115
116 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300117 const std::string cubeFS =
118 R"(precision mediump float;
Austin Kinross62815bf2015-01-15 16:32:36 -0800119 uniform samplerCube uTexture;
120 varying vec4 vPosition;
121
122 void main()
123 {
124 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300125 })";
Austin Kinross62815bf2015-01-15 16:32:36 -0800126
127 mCubeProgram = CompileProgram(cubeVS, cubeFS);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300128 ASSERT_NE(0u, mCubeProgram);
129 }
Austin Kinross62815bf2015-01-15 16:32:36 -0800130
Olli Etuahob97a3e72016-04-13 14:31:52 +0300131 void SetUp() override
132 {
133 ANGLETest::SetUp();
Austin Kinross62815bf2015-01-15 16:32:36 -0800134
Olli Etuahob97a3e72016-04-13 14:31:52 +0300135 setUp2DProgram();
136
137 setUpCubeProgram();
Geoff Lang27359ff2015-06-02 15:42:04 -0400138
Austin Kinross62815bf2015-01-15 16:32:36 -0800139 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
140 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
141 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
142 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800143
144 glGenFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300145 glGenTextures(1, &mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800146
Austin Kinross62815bf2015-01-15 16:32:36 -0800147 // Initialize the texture2D to be empty, and don't use mips.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300148 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800149 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
150 GL_UNSIGNED_BYTE, nullptr);
Austin Kinross215b37a2014-12-22 12:56:07 -0800151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
152 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
153
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300154 ASSERT_EQ(getWindowWidth(), getWindowHeight());
155
Austin Kinross62815bf2015-01-15 16:32:36 -0800156 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300157 glGenTextures(1, &mTextureCube);
158 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300159 TexImageCubeMapFaces(0, GL_RGB, getWindowWidth(), GL_RGB, GL_UNSIGNED_BYTE, nullptr);
160 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowWidth(),
161 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
Austin Kinross62815bf2015-01-15 16:32:36 -0800162
163 // Complete the texture cube without mipmaps to start with.
164 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
165 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
166
167 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800168 }
169
Olli Etuahob97a3e72016-04-13 14:31:52 +0300170 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800171 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800172 glDeleteProgram(m2DProgram);
173 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800174 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300175 glDeleteTextures(1, &mTexture2D);
176 glDeleteTextures(1, &mTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800177
Corentin Wallez254fcea2015-08-25 15:11:07 -0400178 SafeDeleteArray(mLevelZeroBlueInitData);
179 SafeDeleteArray(mLevelZeroWhiteInitData);
180 SafeDeleteArray(mLevelOneInitData);
181 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800182
183 ANGLETest::TearDown();
184 }
185
186 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
187 {
188 GLubyte *data = new GLubyte[3 * width * height];
189
190 for (int i = 0; i < width * height; i+=1)
191 {
Minmin Gong794e0002015-04-07 18:31:54 -0700192 data[3 * i + 0] = static_cast<GLubyte>(r);
193 data[3 * i + 1] = static_cast<GLubyte>(g);
194 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800195 }
196
197 return data;
198 }
199
Olli Etuahob97a3e72016-04-13 14:31:52 +0300200 void clearTextureLevel0(GLenum textarget,
201 GLuint texture,
202 GLfloat red,
203 GLfloat green,
204 GLfloat blue,
205 GLfloat alpha)
206 {
207 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
208 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
209 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
210 glClearColor(red, green, blue, alpha);
211 glClear(GL_COLOR_BUFFER_BIT);
212 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800213 }
214
Austin Kinross62815bf2015-01-15 16:32:36 -0800215 GLuint m2DProgram;
216 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300217 GLuint mTexture2D;
218 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400219
Austin Kinross215b37a2014-12-22 12:56:07 -0800220 GLubyte* mLevelZeroBlueInitData;
221 GLubyte* mLevelZeroWhiteInitData;
222 GLubyte* mLevelOneInitData;
223 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300224
225 private:
226 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800227};
228
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300229class MipmapTestES3 : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -0800230{
Jamie Madillfa05f602015-05-07 13:47:11 -0400231 protected:
232 MipmapTestES3()
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300233 : mTexture(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300234 mArrayProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300235 mTextureArraySliceUniformLocation(-1),
236 m3DProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300237 mTexture3DSliceUniformLocation(-1),
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300238 mTexture3DLODUniformLocation(-1),
239 m2DProgram(0)
Olli Etuahob97a3e72016-04-13 14:31:52 +0300240
Austin Kinross215b37a2014-12-22 12:56:07 -0800241 {
242 setWindowWidth(128);
243 setWindowHeight(128);
244 setConfigRedBits(8);
245 setConfigGreenBits(8);
246 setConfigBlueBits(8);
247 setConfigAlphaBits(8);
248 }
249
Olli Etuahob97a3e72016-04-13 14:31:52 +0300250 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800251 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800252 // Don't put "#version ..." on its own line. See [cpp]p1:
253 // "If there are sequences of preprocessing tokens within the list of arguments that
254 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300255 return
256 R"(#version 300 es
Austin Kinross215b37a2014-12-22 12:56:07 -0800257 precision highp float;
258 in vec4 position;
259 out vec2 texcoord;
260
Austin Kinross215b37a2014-12-22 12:56:07 -0800261 void main()
262 {
Olli Etuaho190028d2016-05-13 12:11:29 +0300263 gl_Position = vec4(position.xy, 0.0, 1.0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800264 texcoord = (position.xy * 0.5) + 0.5;
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300265 })";
Olli Etuahob97a3e72016-04-13 14:31:52 +0300266 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800267
Olli Etuahob97a3e72016-04-13 14:31:52 +0300268 void setUpArrayProgram()
269 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300270 const std::string fragmentShaderSourceArray =
271 R"(#version 300 es
Austin Kinross215b37a2014-12-22 12:56:07 -0800272 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200273 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800274 uniform int slice;
275 in vec2 texcoord;
276 out vec4 out_FragColor;
277
278 void main()
279 {
280 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300281 })";
Austin Kinross215b37a2014-12-22 12:56:07 -0800282
Olli Etuahob97a3e72016-04-13 14:31:52 +0300283 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800284 if (mArrayProgram == 0)
285 {
286 FAIL() << "shader compilation failed.";
287 }
288
Austin Kinross215b37a2014-12-22 12:56:07 -0800289 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
290 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
291
292 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800293 glUseProgram(0);
294 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300295 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000296
Olli Etuahob97a3e72016-04-13 14:31:52 +0300297 void setUp3DProgram()
298 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300299 const std::string fragmentShaderSource3D =
300 R"(#version 300 es
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000301 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200302 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000303 uniform float slice;
304 uniform float lod;
305 in vec2 texcoord;
306 out vec4 out_FragColor;
307
308 void main()
309 {
310 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300311 })";
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000312
Olli Etuahob97a3e72016-04-13 14:31:52 +0300313 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000314 if (m3DProgram == 0)
315 {
316 FAIL() << "shader compilation failed.";
317 }
318
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000319 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
320 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
321
322 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
323 ASSERT_NE(-1, mTexture3DLODUniformLocation);
324
325 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000326 glUniform1f(mTexture3DLODUniformLocation, 0);
327 glUseProgram(0);
328 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800329 }
330
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300331 void setUp2DProgram()
332 {
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300333 const std::string fragmentShaderSource2D =
334 R"(#version 300 es
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300335 precision highp float;
336 uniform highp sampler2D tex;
337 in vec2 texcoord;
338 out vec4 out_FragColor;
339
340 void main()
341 {
342 out_FragColor = texture(tex, texcoord);
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300343 })";
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300344
345 m2DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource2D);
346 ASSERT_NE(0u, m2DProgram);
347
348 ASSERT_GL_NO_ERROR();
349 }
350
351 void setUpCubeProgram()
352 {
353 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300354 const std::string cubeFS =
355 R"(#version 300 es
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300356 precision mediump float;
357 uniform samplerCube uTexture;
358 in vec2 texcoord;
359 out vec4 out_FragColor;
360
361 void main()
362 {
363 out_FragColor = texture(uTexture, vec3(texcoord.x, -1, texcoord.y));
Olli Etuahoa20af6d2017-09-18 13:32:29 +0300364 })";
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300365
366 mCubeProgram = CompileProgram(vertexShaderSource(), cubeFS);
367 ASSERT_NE(0u, mCubeProgram);
368
369 ASSERT_GL_NO_ERROR();
370 }
371
Olli Etuahob97a3e72016-04-13 14:31:52 +0300372 void SetUp() override
373 {
374 ANGLETest::SetUp();
375
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300376 glGenTextures(1, &mTexture);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300377 ASSERT_GL_NO_ERROR();
378
379 setUpArrayProgram();
380 setUp3DProgram();
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300381 setUp2DProgram();
382 setUpCubeProgram();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300383 }
384
385 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800386 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300387 glDeleteTextures(1, &mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800388
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300389 glDeleteProgram(mArrayProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000390 glDeleteProgram(m3DProgram);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300391 glDeleteProgram(m2DProgram);
392 glDeleteProgram(mCubeProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000393
Austin Kinross215b37a2014-12-22 12:56:07 -0800394 ANGLETest::TearDown();
395 }
396
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300397 GLuint mTexture;
Austin Kinross215b37a2014-12-22 12:56:07 -0800398
399 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800400 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000401
402 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000403 GLint mTexture3DSliceUniformLocation;
404 GLint mTexture3DLODUniformLocation;
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300405
406 GLuint m2DProgram;
407
408 GLuint mCubeProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800409};
410
411// 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.
412// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
413// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400414TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800415{
416 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300417 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800418 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
419 ASSERT_GL_NO_ERROR();
420
421 // Disable mips.
422 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
423
424 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300425 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300426 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800427
428 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300429 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300430 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800431
432 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300433 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300434 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800435
436 // Complete the texture by initializing the remaining levels.
437 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700438 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800439 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800440 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / (1U << n),
441 getWindowWidth() / (1U << n), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
Austin Kinross215b37a2014-12-22 12:56:07 -0800442 ASSERT_GL_NO_ERROR();
443 n+=1;
444 }
445
446 // Pass in level one init data.
447 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
448 ASSERT_GL_NO_ERROR();
449
450 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300451 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300452 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800453
454 // 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 +0300455 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300456 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800457
458 // Enable mipmaps.
459 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
460
461 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300462 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300463 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800464
465 // 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 +0300466 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300467 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::black);
Austin Kinross215b37a2014-12-22 12:56:07 -0800468
469 // Pass in level two init data.
470 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
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 green.
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::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800480
481 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300482 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300483 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800484
485 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
486 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300487 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300488 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300489 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300490 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300491 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300492 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800493
494 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
495 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
496 ASSERT_GL_NO_ERROR();
497
Olli Etuahob97a3e72016-04-13 14:31:52 +0300498 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300499 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300500 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300501 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300502 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300503 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::white);
Austin Kinross215b37a2014-12-22 12:56:07 -0800504
505 // Then enable mipmaps again. The quads should be white, green, red respectively.
506 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
507
Olli Etuahob97a3e72016-04-13 14:31:52 +0300508 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300509 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300510 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300511 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300512 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300513 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800514}
515
516// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
517// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
518// To do this, D3D11 has to convert the TextureStorage into a renderable one.
519// This test ensures that the conversion works correctly.
520// 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 -0400521TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800522{
523 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300524 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800525 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
526
527 // Then generate the mips.
528 glGenerateMipmap(GL_TEXTURE_2D);
529 ASSERT_GL_NO_ERROR();
530
531 // Enable mipmaps.
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());
Olli Etuaho190028d2016-05-13 12:11:29 +0300536 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800537
538 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300539 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300540 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800541
542 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300543 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300544 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800545
546 ASSERT_GL_NO_ERROR();
547
548 // Disable mips. Render a quad using the texture and ensure it's blue.
549 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300550 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300551 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800552
Olli Etuahob97a3e72016-04-13 14:31:52 +0300553 // Clear level 0 of the texture to red.
554 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800555
556 // Reenable mips, and try rendering different-sized quads.
557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
558
559 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300560 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300561 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800562
563 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300564 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300565 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800566
567 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300568 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300569 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800570}
571
572// This test ensures that mips are correctly generated from a rendered image.
573// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
574// 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 -0400575TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800576{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300577 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800578 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300579 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800580
581 // Then generate the mips
582 glGenerateMipmap(GL_TEXTURE_2D);
583 ASSERT_GL_NO_ERROR();
584
585 // Enable mips.
586 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
587
588 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300589 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300590 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800591
592 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300593 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300594 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800595
596 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300597 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300598 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800599}
600
601// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
602// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400603TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800604{
Geoff Langf74fef52015-04-29 12:57:52 -0400605 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500606 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400607 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400608 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400609 return;
610 }
611
Olli Etuahob97a3e72016-04-13 14:31:52 +0300612 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800613
614 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300615 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800616
617 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
618 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300619 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300620 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800621
622 // Now go back to the texture, and generate mips on it.
623 glGenerateMipmap(GL_TEXTURE_2D);
624 ASSERT_GL_NO_ERROR();
625
626 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
627 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300628 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300629 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800630
631 // Now tell GL to use the generated mips.
632 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200633 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800634
635 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300636 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300637 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800638
639 // 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 +0300640 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300641 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800642
643 // 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 +0300644 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800645
646 // 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 +0300647 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300648 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800649
650 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300651 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300652 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800653
654 // Disable mipmaps again
655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
656 ASSERT_GL_NO_ERROR();
657
658 // 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 +0300659 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300660 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800661
662 // 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 +0300663 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300664 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800665}
666
Geoff Lang46258e12017-04-10 12:28:34 -0400667// Regression test for a bug that cause mipmaps to only generate using the top left corner as input.
668TEST_P(MipmapTest, MipMapGenerationD3D9Bug)
669{
670 if (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8") ||
671 !extensionEnabled("GL_ANGLE_texture_usage"))
672 {
673 std::cout << "Test skipped due to missing extensions." << std::endl;
674 return;
675 }
676
677 const GLColor mip0Color[4] = {
678 GLColor::red, GLColor::green, GLColor::red, GLColor::green,
679 };
680 const GLColor mip1Color = GLColor(127, 127, 0, 255);
681
682 GLTexture texture;
683 glBindTexture(GL_TEXTURE_2D, texture.get());
684 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
685 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
686 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA8_OES, 2, 2);
687 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, mip0Color);
688 glGenerateMipmap(GL_TEXTURE_2D);
689
690 // Only draw to a 1 pixel viewport so the lower mip is used
691 clearAndDrawQuad(m2DProgram, 1, 1);
692 EXPECT_PIXEL_COLOR_NEAR(0, 0, mip1Color, 1.0);
693}
694
Austin Kinross62815bf2015-01-15 16:32:36 -0800695// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
696// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400697TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800698{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300699 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800700
701 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300702 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300703 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800704
705 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800706 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
707 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300708 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300709 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800710
711 // 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 +0300712 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300713 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800714
715 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300716 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800717
718 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300719 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300720 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800721
722 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
723 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300724 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300725 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800726
727 // Disable mipmaps again, and draw a to a quarter-size viewport.
728 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800729 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300730 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300731 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800732}
733
734// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400735TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800736{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300737 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800738
739 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300740 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300741 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800742
743 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300744 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800745
746 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300747 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300748 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800749
750 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300751 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300752 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800753}
754
Austin Kinross215b37a2014-12-22 12:56:07 -0800755// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
756// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400757TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800758{
759 int px = getWindowWidth() / 2;
760 int py = getWindowHeight() / 2;
761
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300762 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800763
764 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
765
766 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300767 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
768 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
769 pixelsRed.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800770
771 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300772 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
773 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
774 pixelsGreen.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800775
776 // Fill the third layer with blue
Olli Etuaho190028d2016-05-13 12:11:29 +0300777 std::vector<GLColor> pixelsBlue(16 * 16, GLColor::blue);
778 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
779 pixelsBlue.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800780
781 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
782 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
783
784 EXPECT_GL_NO_ERROR();
785
786 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
787
788 EXPECT_GL_NO_ERROR();
789
790 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800791
792 EXPECT_GL_NO_ERROR();
793
794 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800795 glUniform1i(mTextureArraySliceUniformLocation, 0);
796 drawQuad(mArrayProgram, "position", 0.5f);
797 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300798 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800799
800 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800801 glUniform1i(mTextureArraySliceUniformLocation, 1);
802 drawQuad(mArrayProgram, "position", 0.5f);
803 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300804 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800805
806 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800807 glUniform1i(mTextureArraySliceUniformLocation, 2);
808 drawQuad(mArrayProgram, "position", 0.5f);
809 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300810 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::blue);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000811}
812
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300813// Create a mipmapped 2D array texture with more layers than width / height, and call
814// GenerateMipmap.
815TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
816{
817 int px = getWindowWidth() / 2;
818 int py = getWindowHeight() / 2;
819
820 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
821
822 // Fill the whole texture with red.
823 std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
824 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
825 pixelsRed.data());
826
827 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
828 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
829
830 EXPECT_GL_NO_ERROR();
831
832 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
833
834 EXPECT_GL_NO_ERROR();
835
836 glUseProgram(mArrayProgram);
837
838 EXPECT_GL_NO_ERROR();
839
840 // Draw the first slice
841 glUniform1i(mTextureArraySliceUniformLocation, 0);
842 drawQuad(mArrayProgram, "position", 0.5f);
843 EXPECT_GL_NO_ERROR();
844 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
845
846 // Draw the fourth slice
847 glUniform1i(mTextureArraySliceUniformLocation, 3);
848 drawQuad(mArrayProgram, "position", 0.5f);
849 EXPECT_GL_NO_ERROR();
850 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
851}
852
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000853// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
854// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400855TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000856{
857 int px = getWindowWidth() / 2;
858 int py = getWindowHeight() / 2;
859
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300860 glBindTexture(GL_TEXTURE_3D, mTexture);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000861
862 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
863
864 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300865 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
866 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
867 pixelsRed.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000868
869 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300870 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
871 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
872 pixelsGreen.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000873
874 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
875 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
876
877 EXPECT_GL_NO_ERROR();
878
879 glGenerateMipmap(GL_TEXTURE_3D);
880
881 EXPECT_GL_NO_ERROR();
882
883 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000884
885 EXPECT_GL_NO_ERROR();
886
887 // Mipmap level 0
888 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000889 glUniform1f(mTexture3DLODUniformLocation, 0.);
890 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
891 drawQuad(m3DProgram, "position", 0.5f);
892 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300893 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000894
895 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000896 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
897 drawQuad(m3DProgram, "position", 0.5f);
898 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300899 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000900
901 // Mipmap level 1
902 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000903 glUniform1f(mTexture3DLODUniformLocation, 1.);
904 drawQuad(m3DProgram, "position", 0.5f);
905 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500906 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000907
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000908 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
909 drawQuad(m3DProgram, "position", 0.5f);
910 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500911 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000912}
Jamie Madillfa05f602015-05-07 13:47:11 -0400913
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300914// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
915// the same, and then sample levels 0 and 2.
916// GLES 3.0.4 section 3.8.10:
917// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
918// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
919// the levelbase array, are left unchanged by this computation."
920TEST_P(MipmapTestES3, GenerateMipmapBaseLevel)
921{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400922 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300923 {
924 // Observed incorrect rendering on AMD, sampling level 2 returns black.
925 std::cout << "Test skipped on AMD OpenGL." << std::endl;
926 return;
927 }
928
929 glBindTexture(GL_TEXTURE_2D, mTexture);
930
Jamie Madille1faacb2016-12-13 12:42:14 -0500931 ASSERT_EQ(getWindowWidth(), getWindowHeight());
Olli Etuahofb80eaf2016-07-25 13:39:30 +0300932
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300933 // Fill level 0 with blue
934 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
935 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
936 GL_UNSIGNED_BYTE, pixelsBlue.data());
937
938 // Fill level 1 with red
939 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
940 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
941 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
942
943 // Fill level 2 with green
944 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
945 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
946 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
947
948 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
949 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
950 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
951
952 EXPECT_GL_NO_ERROR();
953
954 // The blue level 0 should be untouched by this since base level is 1.
955 glGenerateMipmap(GL_TEXTURE_2D);
956
957 EXPECT_GL_NO_ERROR();
958
959 // Draw using level 2. It should be set to red by GenerateMipmap.
960 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
961 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
962
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300963 // Draw using level 0. It should still be blue.
964 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
965 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
966 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
967}
968
969// Create a cube map with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
970// the same, and then sample levels 0 and 2.
971// GLES 3.0.4 section 3.8.10:
972// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
973// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
974// the levelbase array, are left unchanged by this computation."
975TEST_P(MipmapTestES3, GenerateMipmapCubeBaseLevel)
976{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400977 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300978 {
979 // Observed incorrect rendering on AMD, sampling level 2 returns black.
980 std::cout << "Test skipped on AMD OpenGL." << std::endl;
981 return;
982 }
983
984 ASSERT_EQ(getWindowWidth(), getWindowHeight());
985
986 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
987 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowWidth(), GLColor::blue);
988 TexImageCubeMapFaces(0, GL_RGBA8, getWindowWidth(), GL_RGBA, GL_UNSIGNED_BYTE,
989 pixelsBlue.data());
990
991 // Fill level 1 with red
992 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowWidth() / 4, GLColor::red);
993 TexImageCubeMapFaces(1, GL_RGBA8, getWindowWidth() / 2, GL_RGBA, GL_UNSIGNED_BYTE,
994 pixelsRed.data());
995
996 // Fill level 2 with green
997 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowWidth() / 16, GLColor::green);
998 TexImageCubeMapFaces(2, GL_RGBA8, getWindowWidth() / 4, GL_RGBA, GL_UNSIGNED_BYTE,
999 pixelsGreen.data());
1000
1001 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1002 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1003 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 1);
1004
1005 EXPECT_GL_NO_ERROR();
1006
1007 // The blue level 0 should be untouched by this since base level is 1.
1008 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
1009
1010 EXPECT_GL_NO_ERROR();
1011
1012 // Draw using level 2. It should be set to red by GenerateMipmap.
1013 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1014 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
1015
Corentin Wallezc7f59d02016-06-20 10:12:08 -04001016 if (IsNVIDIA() && IsOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +03001017 {
1018 // Observed incorrect rendering on NVIDIA, level zero seems to be incorrectly affected by
1019 // GenerateMipmap.
1020 std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
1021 return;
1022 }
1023
1024 // Draw using level 0. It should still be blue.
1025 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
1026 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
1027 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1028}
1029
1030// Create a texture with levels 0-2, call GenerateMipmap with max level 1 so that level 2 stays the
1031// same, and then sample levels 1 and 2.
1032// GLES 3.0.4 section 3.8.10:
1033// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
1034// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
1035// the levelbase array, are left unchanged by this computation."
1036TEST_P(MipmapTestES3, GenerateMipmapMaxLevel)
1037{
1038 glBindTexture(GL_TEXTURE_2D, mTexture);
1039
1040 // Fill level 0 with blue
1041 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1042 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1043 GL_UNSIGNED_BYTE, pixelsBlue.data());
1044
1045 // Fill level 1 with red
1046 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
1047 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
1048 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
1049
1050 // Fill level 2 with green
1051 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
1052 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
1053 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
1054
1055 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1056 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1057 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1058
1059 EXPECT_GL_NO_ERROR();
1060
1061 // The green level 2 should be untouched by this since max level is 1.
1062 glGenerateMipmap(GL_TEXTURE_2D);
1063
1064 EXPECT_GL_NO_ERROR();
1065
1066 // Draw using level 1. It should be set to blue by GenerateMipmap.
1067 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
1068 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1069
1070 // Draw using level 2. It should still be green.
1071 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
1072 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1073 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
1074}
1075
1076// Call GenerateMipmap with out-of-range base level. The spec is interpreted so that an out-of-range
1077// base level does not have a color-renderable/texture-filterable internal format, so the
1078// GenerateMipmap call generates INVALID_OPERATION. GLES 3.0.4 section 3.8.10:
1079// "If the levelbase array was not specified with an unsized internal format from table 3.3 or a
1080// sized internal format that is both color-renderable and texture-filterable according to table
1081// 3.13, an INVALID_OPERATION error is generated."
1082TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRange)
1083{
1084 glBindTexture(GL_TEXTURE_2D, mTexture);
1085
1086 // Fill level 0 with blue
1087 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1088 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1089 GL_UNSIGNED_BYTE, pixelsBlue.data());
1090
1091 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1092
1093 EXPECT_GL_NO_ERROR();
1094
1095 // Expecting the out-of-range base level to be treated as not color-renderable and
1096 // texture-filterable.
1097 glGenerateMipmap(GL_TEXTURE_2D);
1098 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1099
1100 // Draw using level 0. It should still be blue.
1101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1104 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1105 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1106}
1107
1108// Call GenerateMipmap with out-of-range base level on an immutable texture. The base level should
1109// be clamped, so the call doesn't generate an error.
1110TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRangeImmutableTexture)
1111{
1112 glBindTexture(GL_TEXTURE_2D, mTexture);
1113
1114 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1115 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1116
1117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1118
1119 EXPECT_GL_NO_ERROR();
1120
1121 // This is essentially a no-op, since the texture only has one level.
1122 glGenerateMipmap(GL_TEXTURE_2D);
1123
1124 EXPECT_GL_NO_ERROR();
1125
1126 // The only level of the texture should still be green.
1127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1129 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1130 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
1131}
1132
Geoff Lang66c5e612017-04-25 11:40:03 -04001133// A native version of the WebGL2 test tex-base-level-bug.html
1134TEST_P(MipmapTestES3, BaseLevelTextureBug)
1135{
Geoff Lang2aadbfc2017-04-27 10:11:27 -04001136 if (IsOpenGL() && IsAMD())
Geoff Lang66c5e612017-04-25 11:40:03 -04001137 {
1138 std::cout << "Test skipped on Windows AMD OpenGL." << std::endl;
1139 return;
1140 }
1141
Kenneth Russelle7a792c2017-04-28 16:31:03 -07001142#if defined(ANGLE_PLATFORM_APPLE)
1143 // Regression in 10.12.4 needing workaround -- crbug.com/705865.
1144 // Seems to be passing on AMD GPUs. Definitely not NVIDIA.
1145 // Probably not Intel.
1146 if (IsNVIDIA() || IsIntel())
1147 {
1148 std::cout << "Test skipped on macOS with NVIDIA and Intel GPUs." << std::endl;
1149 return;
1150 }
1151#endif
1152
Geoff Lang66c5e612017-04-25 11:40:03 -04001153 glBindTexture(GL_TEXTURE_2D, mTexture);
1154 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
1155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 2);
1156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1157 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1158 ASSERT_GL_NO_ERROR();
1159
1160 drawQuad(m2DProgram, "position", 0.5f);
1161 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1162
1163 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1164 ASSERT_GL_NO_ERROR();
1165
1166 drawQuad(m2DProgram, "position", 0.5f);
1167 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1168}
1169
Jamie Madillfa05f602015-05-07 13:47:11 -04001170// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
1171// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -05001172ANGLE_INSTANTIATE_TEST(MipmapTest,
1173 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -08001174 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
1175 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -05001176 ES2_D3D11_FL9_3_WARP(),
1177 ES2_OPENGL(),
1178 ES3_OPENGL(),
1179 ES2_OPENGLES(),
1180 ES3_OPENGLES());
1181ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());