blob: d2f7ff9f5ca83a875f60db552e8950f18e8cbc8f [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);
Austin Kinross215b37a2014-12-22 12:56:07 -0800161 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
164
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300165 ASSERT_EQ(getWindowWidth(), getWindowHeight());
166
Austin Kinross62815bf2015-01-15 16:32:36 -0800167 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300168 glGenTextures(1, &mTextureCube);
169 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300170 TexImageCubeMapFaces(0, GL_RGB, getWindowWidth(), GL_RGB, GL_UNSIGNED_BYTE, nullptr);
171 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowWidth(),
172 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
Austin Kinross62815bf2015-01-15 16:32:36 -0800173
174 // Complete the texture cube without mipmaps to start with.
175 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
176 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
177
178 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800179 }
180
Olli Etuahob97a3e72016-04-13 14:31:52 +0300181 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800182 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800183 glDeleteProgram(m2DProgram);
184 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800185 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300186 glDeleteTextures(1, &mTexture2D);
187 glDeleteTextures(1, &mTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800188
Corentin Wallez254fcea2015-08-25 15:11:07 -0400189 SafeDeleteArray(mLevelZeroBlueInitData);
190 SafeDeleteArray(mLevelZeroWhiteInitData);
191 SafeDeleteArray(mLevelOneInitData);
192 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800193
194 ANGLETest::TearDown();
195 }
196
197 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
198 {
199 GLubyte *data = new GLubyte[3 * width * height];
200
201 for (int i = 0; i < width * height; i+=1)
202 {
Minmin Gong794e0002015-04-07 18:31:54 -0700203 data[3 * i + 0] = static_cast<GLubyte>(r);
204 data[3 * i + 1] = static_cast<GLubyte>(g);
205 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800206 }
207
208 return data;
209 }
210
Olli Etuahob97a3e72016-04-13 14:31:52 +0300211 void clearTextureLevel0(GLenum textarget,
212 GLuint texture,
213 GLfloat red,
214 GLfloat green,
215 GLfloat blue,
216 GLfloat alpha)
217 {
218 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
219 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
220 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
221 glClearColor(red, green, blue, alpha);
222 glClear(GL_COLOR_BUFFER_BIT);
223 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800224 }
225
Austin Kinross62815bf2015-01-15 16:32:36 -0800226 GLuint m2DProgram;
227 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300228 GLuint mTexture2D;
229 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400230
Austin Kinross215b37a2014-12-22 12:56:07 -0800231 GLubyte* mLevelZeroBlueInitData;
232 GLubyte* mLevelZeroWhiteInitData;
233 GLubyte* mLevelOneInitData;
234 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300235
236 private:
237 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800238};
239
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300240class MipmapTestES3 : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -0800241{
Jamie Madillfa05f602015-05-07 13:47:11 -0400242 protected:
243 MipmapTestES3()
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300244 : mTexture(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300245 mArrayProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300246 mTextureArraySliceUniformLocation(-1),
247 m3DProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300248 mTexture3DSliceUniformLocation(-1),
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300249 mTexture3DLODUniformLocation(-1),
250 m2DProgram(0)
Olli Etuahob97a3e72016-04-13 14:31:52 +0300251
Austin Kinross215b37a2014-12-22 12:56:07 -0800252 {
253 setWindowWidth(128);
254 setWindowHeight(128);
255 setConfigRedBits(8);
256 setConfigGreenBits(8);
257 setConfigBlueBits(8);
258 setConfigAlphaBits(8);
259 }
260
Olli Etuahob97a3e72016-04-13 14:31:52 +0300261 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800262 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800263 // Don't put "#version ..." on its own line. See [cpp]p1:
264 // "If there are sequences of preprocessing tokens within the list of arguments that
265 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuaho190028d2016-05-13 12:11:29 +0300266 // clang-format off
Olli Etuahob97a3e72016-04-13 14:31:52 +0300267 return SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800268 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800269 precision highp float;
270 in vec4 position;
271 out vec2 texcoord;
272
Austin Kinross215b37a2014-12-22 12:56:07 -0800273 void main()
274 {
Olli Etuaho190028d2016-05-13 12:11:29 +0300275 gl_Position = vec4(position.xy, 0.0, 1.0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800276 texcoord = (position.xy * 0.5) + 0.5;
277 }
278 );
Olli Etuaho190028d2016-05-13 12:11:29 +0300279 // clang-format on
Olli Etuahob97a3e72016-04-13 14:31:52 +0300280 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800281
Olli Etuahob97a3e72016-04-13 14:31:52 +0300282 void setUpArrayProgram()
283 {
Austin Kinross215b37a2014-12-22 12:56:07 -0800284 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800285 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800286 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200287 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800288 uniform int slice;
289 in vec2 texcoord;
290 out vec4 out_FragColor;
291
292 void main()
293 {
294 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
295 }
296 );
297
Olli Etuahob97a3e72016-04-13 14:31:52 +0300298 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800299 if (mArrayProgram == 0)
300 {
301 FAIL() << "shader compilation failed.";
302 }
303
Austin Kinross215b37a2014-12-22 12:56:07 -0800304 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
305 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
306
307 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800308 glUseProgram(0);
309 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300310 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000311
Olli Etuahob97a3e72016-04-13 14:31:52 +0300312 void setUp3DProgram()
313 {
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000314 const std::string fragmentShaderSource3D = SHADER_SOURCE
315 ( #version 300 es\n
316 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200317 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000318 uniform float slice;
319 uniform float lod;
320 in vec2 texcoord;
321 out vec4 out_FragColor;
322
323 void main()
324 {
325 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
326 }
327 );
328
Olli Etuahob97a3e72016-04-13 14:31:52 +0300329 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000330 if (m3DProgram == 0)
331 {
332 FAIL() << "shader compilation failed.";
333 }
334
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000335 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
336 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
337
338 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
339 ASSERT_NE(-1, mTexture3DLODUniformLocation);
340
341 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000342 glUniform1f(mTexture3DLODUniformLocation, 0);
343 glUseProgram(0);
344 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800345 }
346
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300347 void setUp2DProgram()
348 {
349 // clang-format off
350 const std::string fragmentShaderSource2D = SHADER_SOURCE
351 ( #version 300 es\n
352 precision highp float;
353 uniform highp sampler2D tex;
354 in vec2 texcoord;
355 out vec4 out_FragColor;
356
357 void main()
358 {
359 out_FragColor = texture(tex, texcoord);
360 }
361 );
362 // clang-format on
363
364 m2DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource2D);
365 ASSERT_NE(0u, m2DProgram);
366
367 ASSERT_GL_NO_ERROR();
368 }
369
370 void setUpCubeProgram()
371 {
372 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
373 // clang-format off
374 const std::string cubeFS = SHADER_SOURCE
375 ( #version 300 es\n
376 precision mediump float;
377 uniform samplerCube uTexture;
378 in vec2 texcoord;
379 out vec4 out_FragColor;
380
381 void main()
382 {
383 out_FragColor = texture(uTexture, vec3(texcoord.x, -1, texcoord.y));
384 }
385 );
386 // clang-format on
387
388 mCubeProgram = CompileProgram(vertexShaderSource(), cubeFS);
389 ASSERT_NE(0u, mCubeProgram);
390
391 ASSERT_GL_NO_ERROR();
392 }
393
Olli Etuahob97a3e72016-04-13 14:31:52 +0300394 void SetUp() override
395 {
396 ANGLETest::SetUp();
397
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300398 glGenTextures(1, &mTexture);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300399 ASSERT_GL_NO_ERROR();
400
401 setUpArrayProgram();
402 setUp3DProgram();
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300403 setUp2DProgram();
404 setUpCubeProgram();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300405 }
406
407 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800408 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300409 glDeleteTextures(1, &mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800410
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300411 glDeleteProgram(mArrayProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000412 glDeleteProgram(m3DProgram);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300413 glDeleteProgram(m2DProgram);
414 glDeleteProgram(mCubeProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000415
Austin Kinross215b37a2014-12-22 12:56:07 -0800416 ANGLETest::TearDown();
417 }
418
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300419 GLuint mTexture;
Austin Kinross215b37a2014-12-22 12:56:07 -0800420
421 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800422 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000423
424 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000425 GLint mTexture3DSliceUniformLocation;
426 GLint mTexture3DLODUniformLocation;
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300427
428 GLuint m2DProgram;
429
430 GLuint mCubeProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800431};
432
433// 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.
434// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
435// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400436TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800437{
438 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300439 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800440 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
441 ASSERT_GL_NO_ERROR();
442
443 // Disable mips.
444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
445
446 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300447 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300448 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800449
450 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300451 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300452 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800453
454 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300455 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300456 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800457
458 // Complete the texture by initializing the remaining levels.
459 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700460 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800461 {
Minmin Gong794e0002015-04-07 18:31:54 -0700462 glTexImage2D(GL_TEXTURE_2D, n, GL_RGB, getWindowWidth() / (1U << n), getWindowWidth() / (1U << n), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
Austin Kinross215b37a2014-12-22 12:56:07 -0800463 ASSERT_GL_NO_ERROR();
464 n+=1;
465 }
466
467 // Pass in level one init data.
468 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
469 ASSERT_GL_NO_ERROR();
470
471 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300472 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300473 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800474
475 // 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 +0300476 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300477 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800478
479 // Enable mipmaps.
480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
481
482 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300483 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300484 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800485
486 // 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 +0300487 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300488 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::black);
Austin Kinross215b37a2014-12-22 12:56:07 -0800489
490 // Pass in level two init data.
491 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
492 ASSERT_GL_NO_ERROR();
493
494 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300495 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300496 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800497
498 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300499 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300500 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800501
502 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300503 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300504 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800505
506 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
507 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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::blue);
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::blue);
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::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800514
515 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
516 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
517 ASSERT_GL_NO_ERROR();
518
Olli Etuahob97a3e72016-04-13 14:31:52 +0300519 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300520 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300521 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300522 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300523 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300524 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::white);
Austin Kinross215b37a2014-12-22 12:56:07 -0800525
526 // Then enable mipmaps again. The quads should be white, green, red respectively.
527 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
528
Olli Etuahob97a3e72016-04-13 14:31:52 +0300529 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300530 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300531 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300532 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300533 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300534 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800535}
536
537// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
538// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
539// To do this, D3D11 has to convert the TextureStorage into a renderable one.
540// This test ensures that the conversion works correctly.
541// 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 -0400542TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800543{
544 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300545 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800546 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
547
548 // Then generate the mips.
549 glGenerateMipmap(GL_TEXTURE_2D);
550 ASSERT_GL_NO_ERROR();
551
552 // Enable mipmaps.
553 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
554
555 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300556 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300557 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800558
559 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300560 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300561 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800562
563 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300564 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300565 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800566
567 ASSERT_GL_NO_ERROR();
568
569 // Disable mips. Render a quad using the texture and ensure it's blue.
570 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300571 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300572 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800573
Olli Etuahob97a3e72016-04-13 14:31:52 +0300574 // Clear level 0 of the texture to red.
575 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800576
577 // Reenable mips, and try rendering different-sized quads.
578 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
579
580 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300581 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300582 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800583
584 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300585 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300586 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800587
588 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300589 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300590 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800591}
592
593// This test ensures that mips are correctly generated from a rendered image.
594// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
595// 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 -0400596TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800597{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300598 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800599 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300600 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800601
602 // Then generate the mips
603 glGenerateMipmap(GL_TEXTURE_2D);
604 ASSERT_GL_NO_ERROR();
605
606 // Enable mips.
607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
608
609 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300610 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300611 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800612
613 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300614 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300615 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800616
617 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300618 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300619 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800620}
621
622// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
623// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400624TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800625{
Geoff Langf74fef52015-04-29 12:57:52 -0400626 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500627 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400628 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400629 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400630 return;
631 }
632
Olli Etuahob97a3e72016-04-13 14:31:52 +0300633 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800634
635 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300636 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800637
638 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
639 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300640 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300641 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800642
643 // Now go back to the texture, and generate mips on it.
644 glGenerateMipmap(GL_TEXTURE_2D);
645 ASSERT_GL_NO_ERROR();
646
647 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
648 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300649 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300650 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800651
652 // Now tell GL to use the generated mips.
653 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200654 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800655
656 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300657 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300658 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800659
660 // 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 +0300661 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300662 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800663
664 // 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 +0300665 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800666
667 // 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 +0300668 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300669 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800670
671 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300672 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300673 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800674
675 // Disable mipmaps again
676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
677 ASSERT_GL_NO_ERROR();
678
679 // 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 +0300680 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300681 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800682
683 // 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 +0300684 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300685 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800686}
687
Geoff Lang46258e12017-04-10 12:28:34 -0400688// Regression test for a bug that cause mipmaps to only generate using the top left corner as input.
689TEST_P(MipmapTest, MipMapGenerationD3D9Bug)
690{
691 if (!extensionEnabled("GL_EXT_texture_storage") || !extensionEnabled("GL_OES_rgb8_rgba8") ||
692 !extensionEnabled("GL_ANGLE_texture_usage"))
693 {
694 std::cout << "Test skipped due to missing extensions." << std::endl;
695 return;
696 }
697
698 const GLColor mip0Color[4] = {
699 GLColor::red, GLColor::green, GLColor::red, GLColor::green,
700 };
701 const GLColor mip1Color = GLColor(127, 127, 0, 255);
702
703 GLTexture texture;
704 glBindTexture(GL_TEXTURE_2D, texture.get());
705 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
706 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
707 glTexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGBA8_OES, 2, 2);
708 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, mip0Color);
709 glGenerateMipmap(GL_TEXTURE_2D);
710
711 // Only draw to a 1 pixel viewport so the lower mip is used
712 clearAndDrawQuad(m2DProgram, 1, 1);
713 EXPECT_PIXEL_COLOR_NEAR(0, 0, mip1Color, 1.0);
714}
715
Austin Kinross62815bf2015-01-15 16:32:36 -0800716// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
717// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400718TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800719{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300720 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800721
722 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300723 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300724 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800725
726 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800727 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
728 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300729 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300730 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800731
732 // 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 +0300733 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300734 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800735
736 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300737 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800738
739 // Draw using a full-size viewport. This should be red.
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::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800742
743 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
744 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300745 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300746 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800747
748 // Disable mipmaps again, and draw a to a quarter-size viewport.
749 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800750 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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
755// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400756TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800757{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300758 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800759
760 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300761 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300762 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800763
764 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300765 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800766
767 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300768 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300769 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800770
771 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300772 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300773 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800774}
775
Austin Kinross215b37a2014-12-22 12:56:07 -0800776// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
777// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400778TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800779{
780 int px = getWindowWidth() / 2;
781 int py = getWindowHeight() / 2;
782
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300783 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800784
785 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
786
787 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300788 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
789 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
790 pixelsRed.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800791
792 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300793 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
794 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
795 pixelsGreen.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800796
797 // Fill the third layer with blue
Olli Etuaho190028d2016-05-13 12:11:29 +0300798 std::vector<GLColor> pixelsBlue(16 * 16, GLColor::blue);
799 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
800 pixelsBlue.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800801
802 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
803 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
804
805 EXPECT_GL_NO_ERROR();
806
807 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
808
809 EXPECT_GL_NO_ERROR();
810
811 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800812
813 EXPECT_GL_NO_ERROR();
814
815 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800816 glUniform1i(mTextureArraySliceUniformLocation, 0);
817 drawQuad(mArrayProgram, "position", 0.5f);
818 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300819 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800820
821 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800822 glUniform1i(mTextureArraySliceUniformLocation, 1);
823 drawQuad(mArrayProgram, "position", 0.5f);
824 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300825 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800826
827 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800828 glUniform1i(mTextureArraySliceUniformLocation, 2);
829 drawQuad(mArrayProgram, "position", 0.5f);
830 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300831 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::blue);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000832}
833
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300834// Create a mipmapped 2D array texture with more layers than width / height, and call
835// GenerateMipmap.
836TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
837{
838 int px = getWindowWidth() / 2;
839 int py = getWindowHeight() / 2;
840
841 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
842
843 // Fill the whole texture with red.
844 std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
845 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
846 pixelsRed.data());
847
848 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
849 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
850
851 EXPECT_GL_NO_ERROR();
852
853 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
854
855 EXPECT_GL_NO_ERROR();
856
857 glUseProgram(mArrayProgram);
858
859 EXPECT_GL_NO_ERROR();
860
861 // Draw the first slice
862 glUniform1i(mTextureArraySliceUniformLocation, 0);
863 drawQuad(mArrayProgram, "position", 0.5f);
864 EXPECT_GL_NO_ERROR();
865 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
866
867 // Draw the fourth slice
868 glUniform1i(mTextureArraySliceUniformLocation, 3);
869 drawQuad(mArrayProgram, "position", 0.5f);
870 EXPECT_GL_NO_ERROR();
871 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
872}
873
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000874// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
875// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400876TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000877{
878 int px = getWindowWidth() / 2;
879 int py = getWindowHeight() / 2;
880
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300881 glBindTexture(GL_TEXTURE_3D, mTexture);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000882
883 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
884
885 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300886 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
887 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
888 pixelsRed.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000889
890 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300891 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
892 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
893 pixelsGreen.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000894
895 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
896 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
897
898 EXPECT_GL_NO_ERROR();
899
900 glGenerateMipmap(GL_TEXTURE_3D);
901
902 EXPECT_GL_NO_ERROR();
903
904 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000905
906 EXPECT_GL_NO_ERROR();
907
908 // Mipmap level 0
909 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000910 glUniform1f(mTexture3DLODUniformLocation, 0.);
911 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
912 drawQuad(m3DProgram, "position", 0.5f);
913 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300914 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000915
916 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000917 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
918 drawQuad(m3DProgram, "position", 0.5f);
919 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300920 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000921
922 // Mipmap level 1
923 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000924 glUniform1f(mTexture3DLODUniformLocation, 1.);
925 drawQuad(m3DProgram, "position", 0.5f);
926 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500927 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000928
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000929 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
930 drawQuad(m3DProgram, "position", 0.5f);
931 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500932 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000933}
Jamie Madillfa05f602015-05-07 13:47:11 -0400934
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300935// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
936// the same, and then sample levels 0 and 2.
937// GLES 3.0.4 section 3.8.10:
938// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
939// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
940// the levelbase array, are left unchanged by this computation."
941TEST_P(MipmapTestES3, GenerateMipmapBaseLevel)
942{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400943 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300944 {
945 // Observed incorrect rendering on AMD, sampling level 2 returns black.
946 std::cout << "Test skipped on AMD OpenGL." << std::endl;
947 return;
948 }
949
950 glBindTexture(GL_TEXTURE_2D, mTexture);
951
Jamie Madille1faacb2016-12-13 12:42:14 -0500952 ASSERT_EQ(getWindowWidth(), getWindowHeight());
Olli Etuahofb80eaf2016-07-25 13:39:30 +0300953
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300954 // Fill level 0 with blue
955 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
956 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
957 GL_UNSIGNED_BYTE, pixelsBlue.data());
958
959 // Fill level 1 with red
960 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
961 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
962 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
963
964 // Fill level 2 with green
965 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
966 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
967 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
968
969 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
970 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
971 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
972
973 EXPECT_GL_NO_ERROR();
974
975 // The blue level 0 should be untouched by this since base level is 1.
976 glGenerateMipmap(GL_TEXTURE_2D);
977
978 EXPECT_GL_NO_ERROR();
979
980 // Draw using level 2. It should be set to red by GenerateMipmap.
981 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
982 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
983
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300984 // Draw using level 0. It should still be blue.
985 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
986 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
987 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
988}
989
990// Create a cube map with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
991// the same, and then sample levels 0 and 2.
992// GLES 3.0.4 section 3.8.10:
993// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
994// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
995// the levelbase array, are left unchanged by this computation."
996TEST_P(MipmapTestES3, GenerateMipmapCubeBaseLevel)
997{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400998 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300999 {
1000 // Observed incorrect rendering on AMD, sampling level 2 returns black.
1001 std::cout << "Test skipped on AMD OpenGL." << std::endl;
1002 return;
1003 }
1004
1005 ASSERT_EQ(getWindowWidth(), getWindowHeight());
1006
1007 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
1008 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowWidth(), GLColor::blue);
1009 TexImageCubeMapFaces(0, GL_RGBA8, getWindowWidth(), GL_RGBA, GL_UNSIGNED_BYTE,
1010 pixelsBlue.data());
1011
1012 // Fill level 1 with red
1013 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowWidth() / 4, GLColor::red);
1014 TexImageCubeMapFaces(1, GL_RGBA8, getWindowWidth() / 2, GL_RGBA, GL_UNSIGNED_BYTE,
1015 pixelsRed.data());
1016
1017 // Fill level 2 with green
1018 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowWidth() / 16, GLColor::green);
1019 TexImageCubeMapFaces(2, GL_RGBA8, getWindowWidth() / 4, GL_RGBA, GL_UNSIGNED_BYTE,
1020 pixelsGreen.data());
1021
1022 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1023 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1024 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 1);
1025
1026 EXPECT_GL_NO_ERROR();
1027
1028 // The blue level 0 should be untouched by this since base level is 1.
1029 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
1030
1031 EXPECT_GL_NO_ERROR();
1032
1033 // Draw using level 2. It should be set to red by GenerateMipmap.
1034 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1035 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
1036
Corentin Wallezc7f59d02016-06-20 10:12:08 -04001037 if (IsNVIDIA() && IsOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +03001038 {
1039 // Observed incorrect rendering on NVIDIA, level zero seems to be incorrectly affected by
1040 // GenerateMipmap.
1041 std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
1042 return;
1043 }
1044
1045 // Draw using level 0. It should still be blue.
1046 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
1047 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
1048 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1049}
1050
1051// Create a texture with levels 0-2, call GenerateMipmap with max level 1 so that level 2 stays the
1052// same, and then sample levels 1 and 2.
1053// GLES 3.0.4 section 3.8.10:
1054// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
1055// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
1056// the levelbase array, are left unchanged by this computation."
1057TEST_P(MipmapTestES3, GenerateMipmapMaxLevel)
1058{
1059 glBindTexture(GL_TEXTURE_2D, mTexture);
1060
1061 // Fill level 0 with blue
1062 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1063 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1064 GL_UNSIGNED_BYTE, pixelsBlue.data());
1065
1066 // Fill level 1 with red
1067 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
1068 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
1069 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
1070
1071 // Fill level 2 with green
1072 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
1073 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
1074 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
1075
1076 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1077 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1078 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1079
1080 EXPECT_GL_NO_ERROR();
1081
1082 // The green level 2 should be untouched by this since max level is 1.
1083 glGenerateMipmap(GL_TEXTURE_2D);
1084
1085 EXPECT_GL_NO_ERROR();
1086
1087 // Draw using level 1. It should be set to blue by GenerateMipmap.
1088 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
1089 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1090
1091 // Draw using level 2. It should still be green.
1092 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
1093 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1094 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
1095}
1096
1097// Call GenerateMipmap with out-of-range base level. The spec is interpreted so that an out-of-range
1098// base level does not have a color-renderable/texture-filterable internal format, so the
1099// GenerateMipmap call generates INVALID_OPERATION. GLES 3.0.4 section 3.8.10:
1100// "If the levelbase array was not specified with an unsized internal format from table 3.3 or a
1101// sized internal format that is both color-renderable and texture-filterable according to table
1102// 3.13, an INVALID_OPERATION error is generated."
1103TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRange)
1104{
1105 glBindTexture(GL_TEXTURE_2D, mTexture);
1106
1107 // Fill level 0 with blue
1108 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1109 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1110 GL_UNSIGNED_BYTE, pixelsBlue.data());
1111
1112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1113
1114 EXPECT_GL_NO_ERROR();
1115
1116 // Expecting the out-of-range base level to be treated as not color-renderable and
1117 // texture-filterable.
1118 glGenerateMipmap(GL_TEXTURE_2D);
1119 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1120
1121 // Draw using level 0. It should still be blue.
1122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1125 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1126 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1127}
1128
1129// Call GenerateMipmap with out-of-range base level on an immutable texture. The base level should
1130// be clamped, so the call doesn't generate an error.
1131TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRangeImmutableTexture)
1132{
1133 glBindTexture(GL_TEXTURE_2D, mTexture);
1134
1135 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1136 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1137
1138 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1139
1140 EXPECT_GL_NO_ERROR();
1141
1142 // This is essentially a no-op, since the texture only has one level.
1143 glGenerateMipmap(GL_TEXTURE_2D);
1144
1145 EXPECT_GL_NO_ERROR();
1146
1147 // The only level of the texture should still be green.
1148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1150 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1151 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
1152}
1153
Jamie Madillfa05f602015-05-07 13:47:11 -04001154// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
1155// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -05001156ANGLE_INSTANTIATE_TEST(MipmapTest,
1157 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -08001158 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
1159 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -05001160 ES2_D3D11_FL9_3_WARP(),
1161 ES2_OPENGL(),
1162 ES3_OPENGL(),
1163 ES2_OPENGLES(),
1164 ES3_OPENGLES());
1165ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());