blob: 9691b1820413acd4c7b76314a6dd37fa4cf79223 [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Corentin Wallezd3970de2015-05-14 11:07:48 -04007#include "test_utils/ANGLETest.h"
Austin Kinross215b37a2014-12-22 12:56:07 -08008
Jamie Madillfa05f602015-05-07 13:47:11 -04009using namespace angle;
Austin Kinross215b37a2014-12-22 12:56:07 -080010
Olli Etuaho0f2b1562016-05-13 16:15:35 +030011namespace
12{
13
14void TexImageCubeMapFaces(GLint level,
15 GLenum internalformat,
16 GLsizei width,
17 GLenum format,
18 GLenum type,
19 void *pixels)
20{
21 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, internalformat, width, width, 0, format,
22 type, pixels);
23 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, internalformat, width, width, 0, format,
24 type, pixels);
25 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, internalformat, width, width, 0, format,
26 type, pixels);
27 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, internalformat, width, width, 0, format,
28 type, pixels);
29 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, internalformat, width, width, 0, format,
30 type, pixels);
31 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, internalformat, width, width, 0, format,
32 type, pixels);
33}
34
35class BaseMipmapTest : public ANGLETest
36{
37 protected:
38 void clearAndDrawQuad(GLuint program, GLsizei viewportWidth, GLsizei viewportHeight)
39 {
40 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
41 glClear(GL_COLOR_BUFFER_BIT);
42 glViewport(0, 0, viewportWidth, viewportHeight);
43 ASSERT_GL_NO_ERROR();
44
45 drawQuad(program, "position", 0.0f);
46 }
47};
48
49} // namespace
50
51class MipmapTest : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -080052{
53 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040054 MipmapTest()
Olli Etuahob97a3e72016-04-13 14:31:52 +030055 : m2DProgram(0),
56 mCubeProgram(0),
57 mTexture2D(0),
58 mTextureCube(0),
59 mLevelZeroBlueInitData(nullptr),
60 mLevelZeroWhiteInitData(nullptr),
61 mLevelOneInitData(nullptr),
62 mLevelTwoInitData(nullptr),
63 mOffscreenFramebuffer(0)
Austin Kinross215b37a2014-12-22 12:56:07 -080064 {
65 setWindowWidth(128);
66 setWindowHeight(128);
67 setConfigRedBits(8);
68 setConfigGreenBits(8);
69 setConfigBlueBits(8);
70 setConfigAlphaBits(8);
71 }
72
Olli Etuahob97a3e72016-04-13 14:31:52 +030073 void setUp2DProgram()
Austin Kinross215b37a2014-12-22 12:56:07 -080074 {
Austin Kinross215b37a2014-12-22 12:56:07 -080075 // Vertex Shader source
Olli Etuaho0f2b1562016-05-13 16:15:35 +030076 // clang-format off
Austin Kinross215b37a2014-12-22 12:56:07 -080077 const std::string vs = SHADER_SOURCE
78 (
Olli Etuaho0f2b1562016-05-13 16:15:35 +030079 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;
Austin Kinross215b37a2014-12-22 12:56:07 -080086 }
87 );
88
89 // Fragment Shader source
90 const std::string fs = SHADER_SOURCE
91 (
92 precision mediump float;
93
94 uniform sampler2D uTexture;
95 varying vec2 vTexCoord;
96
97 void main()
98 {
99 gl_FragColor = texture2D(uTexture, vTexCoord);
100 }
101 );
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300102 // clang-format on
Austin Kinross215b37a2014-12-22 12:56:07 -0800103
Austin Kinross62815bf2015-01-15 16:32:36 -0800104 m2DProgram = CompileProgram(vs, fs);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300105 ASSERT_NE(0u, m2DProgram);
106 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800107
Olli Etuahob97a3e72016-04-13 14:31:52 +0300108 void setUpCubeProgram()
109 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800110 // A simple vertex shader for the texture cube
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300111 // clang-format off
Austin Kinross62815bf2015-01-15 16:32:36 -0800112 const std::string cubeVS = SHADER_SOURCE
113 (
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300114 attribute vec4 position;
Austin Kinross62815bf2015-01-15 16:32:36 -0800115 varying vec4 vPosition;
116 void main()
117 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300118 gl_Position = position;
119 vPosition = position;
Austin Kinross62815bf2015-01-15 16:32:36 -0800120 }
121 );
122
123 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
124 const std::string cubeFS = SHADER_SOURCE
125 (
126 precision mediump float;
127 uniform samplerCube uTexture;
128 varying vec4 vPosition;
129
130 void main()
131 {
132 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
133 }
134 );
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300135 // clang-format on
Austin Kinross62815bf2015-01-15 16:32:36 -0800136
137 mCubeProgram = CompileProgram(cubeVS, cubeFS);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300138 ASSERT_NE(0u, mCubeProgram);
139 }
Austin Kinross62815bf2015-01-15 16:32:36 -0800140
Olli Etuahob97a3e72016-04-13 14:31:52 +0300141 void SetUp() override
142 {
143 ANGLETest::SetUp();
Austin Kinross62815bf2015-01-15 16:32:36 -0800144
Olli Etuahob97a3e72016-04-13 14:31:52 +0300145 setUp2DProgram();
146
147 setUpCubeProgram();
Geoff Lang27359ff2015-06-02 15:42:04 -0400148
Austin Kinross62815bf2015-01-15 16:32:36 -0800149 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
150 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
151 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
152 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800153
154 glGenFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300155 glGenTextures(1, &mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800156
Austin Kinross62815bf2015-01-15 16:32:36 -0800157 // Initialize the texture2D to be empty, and don't use mips.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300158 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800159 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
160 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
161 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
162
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300163 ASSERT_EQ(getWindowWidth(), getWindowHeight());
164
Austin Kinross62815bf2015-01-15 16:32:36 -0800165 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300166 glGenTextures(1, &mTextureCube);
167 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300168 TexImageCubeMapFaces(0, GL_RGB, getWindowWidth(), GL_RGB, GL_UNSIGNED_BYTE, nullptr);
169 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowWidth(),
170 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
Austin Kinross62815bf2015-01-15 16:32:36 -0800171
172 // Complete the texture cube without mipmaps to start with.
173 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
174 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
175
176 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800177 }
178
Olli Etuahob97a3e72016-04-13 14:31:52 +0300179 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800180 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800181 glDeleteProgram(m2DProgram);
182 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800183 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300184 glDeleteTextures(1, &mTexture2D);
185 glDeleteTextures(1, &mTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800186
Corentin Wallez254fcea2015-08-25 15:11:07 -0400187 SafeDeleteArray(mLevelZeroBlueInitData);
188 SafeDeleteArray(mLevelZeroWhiteInitData);
189 SafeDeleteArray(mLevelOneInitData);
190 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800191
192 ANGLETest::TearDown();
193 }
194
195 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
196 {
197 GLubyte *data = new GLubyte[3 * width * height];
198
199 for (int i = 0; i < width * height; i+=1)
200 {
Minmin Gong794e0002015-04-07 18:31:54 -0700201 data[3 * i + 0] = static_cast<GLubyte>(r);
202 data[3 * i + 1] = static_cast<GLubyte>(g);
203 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800204 }
205
206 return data;
207 }
208
Olli Etuahob97a3e72016-04-13 14:31:52 +0300209 void clearTextureLevel0(GLenum textarget,
210 GLuint texture,
211 GLfloat red,
212 GLfloat green,
213 GLfloat blue,
214 GLfloat alpha)
215 {
216 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
217 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
218 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
219 glClearColor(red, green, blue, alpha);
220 glClear(GL_COLOR_BUFFER_BIT);
221 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800222 }
223
Austin Kinross62815bf2015-01-15 16:32:36 -0800224 GLuint m2DProgram;
225 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300226 GLuint mTexture2D;
227 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400228
Austin Kinross215b37a2014-12-22 12:56:07 -0800229 GLubyte* mLevelZeroBlueInitData;
230 GLubyte* mLevelZeroWhiteInitData;
231 GLubyte* mLevelOneInitData;
232 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300233
234 private:
235 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800236};
237
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300238class MipmapTestES3 : public BaseMipmapTest
Austin Kinross215b37a2014-12-22 12:56:07 -0800239{
Jamie Madillfa05f602015-05-07 13:47:11 -0400240 protected:
241 MipmapTestES3()
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300242 : mTexture(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300243 mArrayProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300244 mTextureArraySliceUniformLocation(-1),
245 m3DProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300246 mTexture3DSliceUniformLocation(-1),
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300247 mTexture3DLODUniformLocation(-1),
248 m2DProgram(0)
Olli Etuahob97a3e72016-04-13 14:31:52 +0300249
Austin Kinross215b37a2014-12-22 12:56:07 -0800250 {
251 setWindowWidth(128);
252 setWindowHeight(128);
253 setConfigRedBits(8);
254 setConfigGreenBits(8);
255 setConfigBlueBits(8);
256 setConfigAlphaBits(8);
257 }
258
Olli Etuahob97a3e72016-04-13 14:31:52 +0300259 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800260 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800261 // Don't put "#version ..." on its own line. See [cpp]p1:
262 // "If there are sequences of preprocessing tokens within the list of arguments that
263 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuaho190028d2016-05-13 12:11:29 +0300264 // clang-format off
Olli Etuahob97a3e72016-04-13 14:31:52 +0300265 return SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800266 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800267 precision highp float;
268 in vec4 position;
269 out vec2 texcoord;
270
Austin Kinross215b37a2014-12-22 12:56:07 -0800271 void main()
272 {
Olli Etuaho190028d2016-05-13 12:11:29 +0300273 gl_Position = vec4(position.xy, 0.0, 1.0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800274 texcoord = (position.xy * 0.5) + 0.5;
275 }
276 );
Olli Etuaho190028d2016-05-13 12:11:29 +0300277 // clang-format on
Olli Etuahob97a3e72016-04-13 14:31:52 +0300278 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800279
Olli Etuahob97a3e72016-04-13 14:31:52 +0300280 void setUpArrayProgram()
281 {
Austin Kinross215b37a2014-12-22 12:56:07 -0800282 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800283 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800284 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200285 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800286 uniform int slice;
287 in vec2 texcoord;
288 out vec4 out_FragColor;
289
290 void main()
291 {
292 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
293 }
294 );
295
Olli Etuahob97a3e72016-04-13 14:31:52 +0300296 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800297 if (mArrayProgram == 0)
298 {
299 FAIL() << "shader compilation failed.";
300 }
301
Austin Kinross215b37a2014-12-22 12:56:07 -0800302 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
303 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
304
305 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800306 glUseProgram(0);
307 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300308 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000309
Olli Etuahob97a3e72016-04-13 14:31:52 +0300310 void setUp3DProgram()
311 {
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000312 const std::string fragmentShaderSource3D = SHADER_SOURCE
313 ( #version 300 es\n
314 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200315 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000316 uniform float slice;
317 uniform float lod;
318 in vec2 texcoord;
319 out vec4 out_FragColor;
320
321 void main()
322 {
323 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
324 }
325 );
326
Olli Etuahob97a3e72016-04-13 14:31:52 +0300327 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000328 if (m3DProgram == 0)
329 {
330 FAIL() << "shader compilation failed.";
331 }
332
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000333 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
334 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
335
336 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
337 ASSERT_NE(-1, mTexture3DLODUniformLocation);
338
339 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000340 glUniform1f(mTexture3DLODUniformLocation, 0);
341 glUseProgram(0);
342 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800343 }
344
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300345 void setUp2DProgram()
346 {
347 // clang-format off
348 const std::string fragmentShaderSource2D = SHADER_SOURCE
349 ( #version 300 es\n
350 precision highp float;
351 uniform highp sampler2D tex;
352 in vec2 texcoord;
353 out vec4 out_FragColor;
354
355 void main()
356 {
357 out_FragColor = texture(tex, texcoord);
358 }
359 );
360 // clang-format on
361
362 m2DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource2D);
363 ASSERT_NE(0u, m2DProgram);
364
365 ASSERT_GL_NO_ERROR();
366 }
367
368 void setUpCubeProgram()
369 {
370 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
371 // clang-format off
372 const std::string cubeFS = SHADER_SOURCE
373 ( #version 300 es\n
374 precision mediump float;
375 uniform samplerCube uTexture;
376 in vec2 texcoord;
377 out vec4 out_FragColor;
378
379 void main()
380 {
381 out_FragColor = texture(uTexture, vec3(texcoord.x, -1, texcoord.y));
382 }
383 );
384 // clang-format on
385
386 mCubeProgram = CompileProgram(vertexShaderSource(), cubeFS);
387 ASSERT_NE(0u, mCubeProgram);
388
389 ASSERT_GL_NO_ERROR();
390 }
391
Olli Etuahob97a3e72016-04-13 14:31:52 +0300392 void SetUp() override
393 {
394 ANGLETest::SetUp();
395
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300396 glGenTextures(1, &mTexture);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300397 ASSERT_GL_NO_ERROR();
398
399 setUpArrayProgram();
400 setUp3DProgram();
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300401 setUp2DProgram();
402 setUpCubeProgram();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300403 }
404
405 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800406 {
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300407 glDeleteTextures(1, &mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800408
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300409 glDeleteProgram(mArrayProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000410 glDeleteProgram(m3DProgram);
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300411 glDeleteProgram(m2DProgram);
412 glDeleteProgram(mCubeProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000413
Austin Kinross215b37a2014-12-22 12:56:07 -0800414 ANGLETest::TearDown();
415 }
416
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300417 GLuint mTexture;
Austin Kinross215b37a2014-12-22 12:56:07 -0800418
419 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800420 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000421
422 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000423 GLint mTexture3DSliceUniformLocation;
424 GLint mTexture3DLODUniformLocation;
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300425
426 GLuint m2DProgram;
427
428 GLuint mCubeProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800429};
430
431// 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.
432// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
433// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400434TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800435{
436 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300437 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800438 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
439 ASSERT_GL_NO_ERROR();
440
441 // Disable mips.
442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
443
444 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300445 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300446 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800447
448 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300449 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300450 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800451
452 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300453 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300454 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800455
456 // Complete the texture by initializing the remaining levels.
457 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700458 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800459 {
Minmin Gong794e0002015-04-07 18:31:54 -0700460 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 -0800461 ASSERT_GL_NO_ERROR();
462 n+=1;
463 }
464
465 // Pass in level one init data.
466 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
467 ASSERT_GL_NO_ERROR();
468
469 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300470 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300471 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800472
473 // 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 +0300474 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300475 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800476
477 // Enable mipmaps.
478 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
479
480 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300481 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300482 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800483
484 // 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 +0300485 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300486 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::black);
Austin Kinross215b37a2014-12-22 12:56:07 -0800487
488 // Pass in level two init data.
489 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
490 ASSERT_GL_NO_ERROR();
491
492 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300493 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300494 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800495
496 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300497 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300498 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800499
500 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300501 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300502 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800503
504 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
505 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300506 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300507 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300508 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300509 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300510 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300511 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800512
513 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
514 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
515 ASSERT_GL_NO_ERROR();
516
Olli Etuahob97a3e72016-04-13 14:31:52 +0300517 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300518 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300519 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300520 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300521 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300522 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::white);
Austin Kinross215b37a2014-12-22 12:56:07 -0800523
524 // Then enable mipmaps again. The quads should be white, green, red respectively.
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
526
Olli Etuahob97a3e72016-04-13 14:31:52 +0300527 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300528 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300529 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300530 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300531 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300532 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800533}
534
535// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
536// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
537// To do this, D3D11 has to convert the TextureStorage into a renderable one.
538// This test ensures that the conversion works correctly.
539// 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 -0400540TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800541{
542 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300543 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800544 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
545
546 // Then generate the mips.
547 glGenerateMipmap(GL_TEXTURE_2D);
548 ASSERT_GL_NO_ERROR();
549
550 // Enable mipmaps.
551 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
552
553 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300554 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300555 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800556
557 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300558 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300559 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800560
561 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300562 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300563 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800564
565 ASSERT_GL_NO_ERROR();
566
567 // Disable mips. Render a quad using the texture and ensure it's blue.
568 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300569 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300570 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800571
Olli Etuahob97a3e72016-04-13 14:31:52 +0300572 // Clear level 0 of the texture to red.
573 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800574
575 // Reenable mips, and try rendering different-sized quads.
576 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
577
578 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300579 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300580 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800581
582 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300583 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300584 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800585
586 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300587 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300588 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800589}
590
591// This test ensures that mips are correctly generated from a rendered image.
592// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
593// 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 -0400594TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800595{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300596 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800597 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300598 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800599
600 // Then generate the mips
601 glGenerateMipmap(GL_TEXTURE_2D);
602 ASSERT_GL_NO_ERROR();
603
604 // Enable mips.
605 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
606
607 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300608 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300609 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800610
611 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300612 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300613 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800614
615 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300616 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300617 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800618}
619
620// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
621// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400622TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800623{
Geoff Langf74fef52015-04-29 12:57:52 -0400624 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500625 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400626 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400627 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400628 return;
629 }
630
Olli Etuahob97a3e72016-04-13 14:31:52 +0300631 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800632
633 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300634 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800635
636 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
637 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300638 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300639 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800640
641 // Now go back to the texture, and generate mips on it.
642 glGenerateMipmap(GL_TEXTURE_2D);
643 ASSERT_GL_NO_ERROR();
644
645 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
646 // The quad should be blue.
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::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800649
650 // Now tell GL to use the generated mips.
651 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200652 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800653
654 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300655 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300656 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800657
658 // 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 +0300659 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300660 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800661
662 // 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 +0300663 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800664
665 // 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 +0300666 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300667 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800668
669 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300670 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300671 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800672
673 // Disable mipmaps again
674 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
675 ASSERT_GL_NO_ERROR();
676
677 // 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 +0300678 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300679 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800680
681 // 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 +0300682 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300683 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800684}
685
Austin Kinross62815bf2015-01-15 16:32:36 -0800686// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
687// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400688TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800689{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300690 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800691
692 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300693 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300694 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800695
696 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800697 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
698 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300699 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300700 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800701
702 // 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 +0300703 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300704 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800705
706 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300707 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800708
709 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300710 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300711 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800712
713 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
714 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300715 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300716 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800717
718 // Disable mipmaps again, and draw a to a quarter-size viewport.
719 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800720 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300721 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300722 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800723}
724
725// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400726TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800727{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300728 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800729
730 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300731 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300732 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800733
734 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300735 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800736
737 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300738 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300739 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800740
741 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300742 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300743 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800744}
745
Austin Kinross215b37a2014-12-22 12:56:07 -0800746// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
747// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400748TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800749{
750 int px = getWindowWidth() / 2;
751 int py = getWindowHeight() / 2;
752
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300753 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
Austin Kinross215b37a2014-12-22 12:56:07 -0800754
755 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
756
757 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300758 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
759 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
760 pixelsRed.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800761
762 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300763 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
764 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
765 pixelsGreen.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800766
767 // Fill the third layer with blue
Olli Etuaho190028d2016-05-13 12:11:29 +0300768 std::vector<GLColor> pixelsBlue(16 * 16, GLColor::blue);
769 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
770 pixelsBlue.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800771
772 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
773 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
774
775 EXPECT_GL_NO_ERROR();
776
777 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
778
779 EXPECT_GL_NO_ERROR();
780
781 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800782
783 EXPECT_GL_NO_ERROR();
784
785 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800786 glUniform1i(mTextureArraySliceUniformLocation, 0);
787 drawQuad(mArrayProgram, "position", 0.5f);
788 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300789 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800790
791 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800792 glUniform1i(mTextureArraySliceUniformLocation, 1);
793 drawQuad(mArrayProgram, "position", 0.5f);
794 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300795 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800796
797 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800798 glUniform1i(mTextureArraySliceUniformLocation, 2);
799 drawQuad(mArrayProgram, "position", 0.5f);
800 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300801 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::blue);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000802}
803
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300804// Create a mipmapped 2D array texture with more layers than width / height, and call
805// GenerateMipmap.
806TEST_P(MipmapTestES3, MipmapForDeepTextureArray)
807{
808 int px = getWindowWidth() / 2;
809 int py = getWindowHeight() / 2;
810
811 glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
812
813 // Fill the whole texture with red.
814 std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
815 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
816 pixelsRed.data());
817
818 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
819 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
820
821 EXPECT_GL_NO_ERROR();
822
823 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
824
825 EXPECT_GL_NO_ERROR();
826
827 glUseProgram(mArrayProgram);
828
829 EXPECT_GL_NO_ERROR();
830
831 // Draw the first slice
832 glUniform1i(mTextureArraySliceUniformLocation, 0);
833 drawQuad(mArrayProgram, "position", 0.5f);
834 EXPECT_GL_NO_ERROR();
835 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
836
837 // Draw the fourth slice
838 glUniform1i(mTextureArraySliceUniformLocation, 3);
839 drawQuad(mArrayProgram, "position", 0.5f);
840 EXPECT_GL_NO_ERROR();
841 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
842}
843
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000844// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
845// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400846TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000847{
848 int px = getWindowWidth() / 2;
849 int py = getWindowHeight() / 2;
850
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300851 glBindTexture(GL_TEXTURE_3D, mTexture);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000852
853 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
854
855 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300856 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
857 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
858 pixelsRed.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000859
860 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300861 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
862 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
863 pixelsGreen.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000864
865 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
866 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
867
868 EXPECT_GL_NO_ERROR();
869
870 glGenerateMipmap(GL_TEXTURE_3D);
871
872 EXPECT_GL_NO_ERROR();
873
874 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000875
876 EXPECT_GL_NO_ERROR();
877
878 // Mipmap level 0
879 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000880 glUniform1f(mTexture3DLODUniformLocation, 0.);
881 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
882 drawQuad(m3DProgram, "position", 0.5f);
883 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300884 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000885
886 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000887 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
888 drawQuad(m3DProgram, "position", 0.5f);
889 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300890 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000891
892 // Mipmap level 1
893 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000894 glUniform1f(mTexture3DLODUniformLocation, 1.);
895 drawQuad(m3DProgram, "position", 0.5f);
896 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500897 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000898
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000899 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
900 drawQuad(m3DProgram, "position", 0.5f);
901 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500902 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000903}
Jamie Madillfa05f602015-05-07 13:47:11 -0400904
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300905// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
906// the same, and then sample levels 0 and 2.
907// GLES 3.0.4 section 3.8.10:
908// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
909// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
910// the levelbase array, are left unchanged by this computation."
911TEST_P(MipmapTestES3, GenerateMipmapBaseLevel)
912{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400913 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300914 {
915 // Observed incorrect rendering on AMD, sampling level 2 returns black.
916 std::cout << "Test skipped on AMD OpenGL." << std::endl;
917 return;
918 }
919
920 glBindTexture(GL_TEXTURE_2D, mTexture);
921
922 // Fill level 0 with blue
923 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
924 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
925 GL_UNSIGNED_BYTE, pixelsBlue.data());
926
927 // Fill level 1 with red
928 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
929 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
930 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
931
932 // Fill level 2 with green
933 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
934 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
935 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
936
937 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
938 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
939 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
940
941 EXPECT_GL_NO_ERROR();
942
943 // The blue level 0 should be untouched by this since base level is 1.
944 glGenerateMipmap(GL_TEXTURE_2D);
945
946 EXPECT_GL_NO_ERROR();
947
948 // Draw using level 2. It should be set to red by GenerateMipmap.
949 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
950 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
951
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400952 if (IsNVIDIA() && IsOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300953 {
954 // Observed incorrect rendering on NVIDIA, level zero seems to be incorrectly affected by
955 // GenerateMipmap.
956 std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
957 return;
958 }
959
960 // Draw using level 0. It should still be blue.
961 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
962 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
963 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
964}
965
966// Create a cube map with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
967// the same, and then sample levels 0 and 2.
968// GLES 3.0.4 section 3.8.10:
969// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
970// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
971// the levelbase array, are left unchanged by this computation."
972TEST_P(MipmapTestES3, GenerateMipmapCubeBaseLevel)
973{
Corentin Wallezc7f59d02016-06-20 10:12:08 -0400974 if (IsAMD() && IsDesktopOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +0300975 {
976 // Observed incorrect rendering on AMD, sampling level 2 returns black.
977 std::cout << "Test skipped on AMD OpenGL." << std::endl;
978 return;
979 }
980
981 ASSERT_EQ(getWindowWidth(), getWindowHeight());
982
983 glBindTexture(GL_TEXTURE_CUBE_MAP, mTexture);
984 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowWidth(), GLColor::blue);
985 TexImageCubeMapFaces(0, GL_RGBA8, getWindowWidth(), GL_RGBA, GL_UNSIGNED_BYTE,
986 pixelsBlue.data());
987
988 // Fill level 1 with red
989 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowWidth() / 4, GLColor::red);
990 TexImageCubeMapFaces(1, GL_RGBA8, getWindowWidth() / 2, GL_RGBA, GL_UNSIGNED_BYTE,
991 pixelsRed.data());
992
993 // Fill level 2 with green
994 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowWidth() / 16, GLColor::green);
995 TexImageCubeMapFaces(2, GL_RGBA8, getWindowWidth() / 4, GL_RGBA, GL_UNSIGNED_BYTE,
996 pixelsGreen.data());
997
998 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
999 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1000 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 1);
1001
1002 EXPECT_GL_NO_ERROR();
1003
1004 // The blue level 0 should be untouched by this since base level is 1.
1005 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
1006
1007 EXPECT_GL_NO_ERROR();
1008
1009 // Draw using level 2. It should be set to red by GenerateMipmap.
1010 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1011 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
1012
Corentin Wallezc7f59d02016-06-20 10:12:08 -04001013 if (IsNVIDIA() && IsOpenGL())
Olli Etuaho0f2b1562016-05-13 16:15:35 +03001014 {
1015 // Observed incorrect rendering on NVIDIA, level zero seems to be incorrectly affected by
1016 // GenerateMipmap.
1017 std::cout << "Test partially skipped on NVIDIA OpenGL." << std::endl;
1018 return;
1019 }
1020
1021 // Draw using level 0. It should still be blue.
1022 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
1023 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
1024 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1025}
1026
1027// Create a texture with levels 0-2, call GenerateMipmap with max level 1 so that level 2 stays the
1028// same, and then sample levels 1 and 2.
1029// GLES 3.0.4 section 3.8.10:
1030// "Mipmap generation replaces texel array levels levelbase + 1 through q with arrays derived from
1031// the levelbase array, regardless of their previous contents. All other mipmap arrays, including
1032// the levelbase array, are left unchanged by this computation."
1033TEST_P(MipmapTestES3, GenerateMipmapMaxLevel)
1034{
1035 glBindTexture(GL_TEXTURE_2D, mTexture);
1036
1037 // Fill level 0 with blue
1038 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1039 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1040 GL_UNSIGNED_BYTE, pixelsBlue.data());
1041
1042 // Fill level 1 with red
1043 std::vector<GLColor> pixelsRed(getWindowWidth() * getWindowHeight() / 4, GLColor::red);
1044 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth() / 2, getWindowHeight() / 2, 0,
1045 GL_RGBA, GL_UNSIGNED_BYTE, pixelsRed.data());
1046
1047 // Fill level 2 with green
1048 std::vector<GLColor> pixelsGreen(getWindowWidth() * getWindowHeight() / 16, GLColor::green);
1049 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth() / 4, getWindowHeight() / 4, 0,
1050 GL_RGBA, GL_UNSIGNED_BYTE, pixelsGreen.data());
1051
1052 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1053 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1054 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
1055
1056 EXPECT_GL_NO_ERROR();
1057
1058 // The green level 2 should be untouched by this since max level is 1.
1059 glGenerateMipmap(GL_TEXTURE_2D);
1060
1061 EXPECT_GL_NO_ERROR();
1062
1063 // Draw using level 1. It should be set to blue by GenerateMipmap.
1064 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
1065 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1066
1067 // Draw using level 2. It should still be green.
1068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
1069 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
1070 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
1071}
1072
1073// Call GenerateMipmap with out-of-range base level. The spec is interpreted so that an out-of-range
1074// base level does not have a color-renderable/texture-filterable internal format, so the
1075// GenerateMipmap call generates INVALID_OPERATION. GLES 3.0.4 section 3.8.10:
1076// "If the levelbase array was not specified with an unsized internal format from table 3.3 or a
1077// sized internal format that is both color-renderable and texture-filterable according to table
1078// 3.13, an INVALID_OPERATION error is generated."
1079TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRange)
1080{
1081 glBindTexture(GL_TEXTURE_2D, mTexture);
1082
1083 // Fill level 0 with blue
1084 std::vector<GLColor> pixelsBlue(getWindowWidth() * getWindowHeight(), GLColor::blue);
1085 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
1086 GL_UNSIGNED_BYTE, pixelsBlue.data());
1087
1088 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1089
1090 EXPECT_GL_NO_ERROR();
1091
1092 // Expecting the out-of-range base level to be treated as not color-renderable and
1093 // texture-filterable.
1094 glGenerateMipmap(GL_TEXTURE_2D);
1095 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1096
1097 // Draw using level 0. It should still be blue.
1098 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
1099 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1101 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1102 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
1103}
1104
1105// Call GenerateMipmap with out-of-range base level on an immutable texture. The base level should
1106// be clamped, so the call doesn't generate an error.
1107TEST_P(MipmapTestES3, GenerateMipmapBaseLevelOutOfRangeImmutableTexture)
1108{
1109 glBindTexture(GL_TEXTURE_2D, mTexture);
1110
1111 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1112 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green);
1113
1114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1000);
1115
1116 EXPECT_GL_NO_ERROR();
1117
1118 // This is essentially a no-op, since the texture only has one level.
1119 glGenerateMipmap(GL_TEXTURE_2D);
1120
1121 EXPECT_GL_NO_ERROR();
1122
1123 // The only level of the texture should still be green.
1124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1126 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
1127 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
1128}
1129
Jamie Madillfa05f602015-05-07 13:47:11 -04001130// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
1131// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -05001132ANGLE_INSTANTIATE_TEST(MipmapTest,
1133 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -08001134 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
1135 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -05001136 ES2_D3D11_FL9_3_WARP(),
1137 ES2_OPENGL(),
1138 ES3_OPENGL(),
1139 ES2_OPENGLES(),
1140 ES3_OPENGLES());
1141ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());