blob: dca5ca18b6dedd2f47b5f07dbbb79b4a43f6249d [file] [log] [blame]
Jamie Madillfa05f602015-05-07 13:47:11 -04001//
2// Copyright 2015 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Corentin Wallezd3970de2015-05-14 11:07:48 -04007#include "test_utils/ANGLETest.h"
Austin Kinross215b37a2014-12-22 12:56:07 -08008
Jamie Madillfa05f602015-05-07 13:47:11 -04009using namespace angle;
Austin Kinross215b37a2014-12-22 12:56:07 -080010
Austin Kinross215b37a2014-12-22 12:56:07 -080011class MipmapTest : public ANGLETest
12{
13 protected:
Jamie Madillfa05f602015-05-07 13:47:11 -040014 MipmapTest()
Olli Etuahob97a3e72016-04-13 14:31:52 +030015 : m2DProgram(0),
16 mCubeProgram(0),
17 mTexture2D(0),
18 mTextureCube(0),
19 mLevelZeroBlueInitData(nullptr),
20 mLevelZeroWhiteInitData(nullptr),
21 mLevelOneInitData(nullptr),
22 mLevelTwoInitData(nullptr),
23 mOffscreenFramebuffer(0)
Austin Kinross215b37a2014-12-22 12:56:07 -080024 {
25 setWindowWidth(128);
26 setWindowHeight(128);
27 setConfigRedBits(8);
28 setConfigGreenBits(8);
29 setConfigBlueBits(8);
30 setConfigAlphaBits(8);
31 }
32
Olli Etuahob97a3e72016-04-13 14:31:52 +030033 void setUp2DProgram()
Austin Kinross215b37a2014-12-22 12:56:07 -080034 {
Austin Kinross215b37a2014-12-22 12:56:07 -080035 // Vertex Shader source
36 const std::string vs = SHADER_SOURCE
37 (
38 attribute vec4 aPosition;
Austin Kinross215b37a2014-12-22 12:56:07 -080039 varying vec2 vTexCoord;
40
41 void main()
42 {
43 gl_Position = aPosition;
Olli Etuahob97a3e72016-04-13 14:31:52 +030044 vTexCoord = (aPosition.xy * 0.5) + 0.5;
Austin Kinross215b37a2014-12-22 12:56:07 -080045 }
46 );
47
48 // Fragment Shader source
49 const std::string fs = SHADER_SOURCE
50 (
51 precision mediump float;
52
53 uniform sampler2D uTexture;
54 varying vec2 vTexCoord;
55
56 void main()
57 {
58 gl_FragColor = texture2D(uTexture, vTexCoord);
59 }
60 );
61
Austin Kinross62815bf2015-01-15 16:32:36 -080062 m2DProgram = CompileProgram(vs, fs);
Olli Etuahob97a3e72016-04-13 14:31:52 +030063 ASSERT_NE(0u, m2DProgram);
64 }
Austin Kinross215b37a2014-12-22 12:56:07 -080065
Olli Etuahob97a3e72016-04-13 14:31:52 +030066 void setUpCubeProgram()
67 {
Austin Kinross62815bf2015-01-15 16:32:36 -080068 // A simple vertex shader for the texture cube
69 const std::string cubeVS = SHADER_SOURCE
70 (
71 attribute vec4 aPosition;
72 varying vec4 vPosition;
73 void main()
74 {
75 gl_Position = aPosition;
76 vPosition = aPosition;
77 }
78 );
79
80 // A very simple fragment shader to sample from the negative-Y face of a texture cube.
81 const std::string cubeFS = SHADER_SOURCE
82 (
83 precision mediump float;
84 uniform samplerCube uTexture;
85 varying vec4 vPosition;
86
87 void main()
88 {
89 gl_FragColor = textureCube(uTexture, vec3(vPosition.x, -1, vPosition.y));
90 }
91 );
92
93 mCubeProgram = CompileProgram(cubeVS, cubeFS);
Olli Etuahob97a3e72016-04-13 14:31:52 +030094 ASSERT_NE(0u, mCubeProgram);
95 }
Austin Kinross62815bf2015-01-15 16:32:36 -080096
Olli Etuahob97a3e72016-04-13 14:31:52 +030097 void SetUp() override
98 {
99 ANGLETest::SetUp();
Austin Kinross62815bf2015-01-15 16:32:36 -0800100
Olli Etuahob97a3e72016-04-13 14:31:52 +0300101 setUp2DProgram();
102
103 setUpCubeProgram();
Geoff Lang27359ff2015-06-02 15:42:04 -0400104
Austin Kinross62815bf2015-01-15 16:32:36 -0800105 mLevelZeroBlueInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
106 mLevelZeroWhiteInitData = createRGBInitData(getWindowWidth(), getWindowHeight(), 255, 255, 255); // White
107 mLevelOneInitData = createRGBInitData((getWindowWidth() / 2), (getWindowHeight() / 2), 0, 255, 0); // Green
108 mLevelTwoInitData = createRGBInitData((getWindowWidth() / 4), (getWindowHeight() / 4), 255, 0, 0); // Red
Austin Kinross215b37a2014-12-22 12:56:07 -0800109
110 glGenFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300111 glGenTextures(1, &mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800112
Austin Kinross62815bf2015-01-15 16:32:36 -0800113 // Initialize the texture2D to be empty, and don't use mips.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300114 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800115 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
118
Austin Kinross62815bf2015-01-15 16:32:36 -0800119 // Create a non-mipped texture cube. Set the negative-Y face to be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300120 glGenTextures(1, &mTextureCube);
121 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800122 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
123 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
124 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
125 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
126 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
127 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
128
129 // Complete the texture cube without mipmaps to start with.
130 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
131 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132
133 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800134 }
135
Olli Etuahob97a3e72016-04-13 14:31:52 +0300136 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800137 {
Austin Kinross62815bf2015-01-15 16:32:36 -0800138 glDeleteProgram(m2DProgram);
139 glDeleteProgram(mCubeProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800140 glDeleteFramebuffers(1, &mOffscreenFramebuffer);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300141 glDeleteTextures(1, &mTexture2D);
142 glDeleteTextures(1, &mTextureCube);
Austin Kinross215b37a2014-12-22 12:56:07 -0800143
Corentin Wallez254fcea2015-08-25 15:11:07 -0400144 SafeDeleteArray(mLevelZeroBlueInitData);
145 SafeDeleteArray(mLevelZeroWhiteInitData);
146 SafeDeleteArray(mLevelOneInitData);
147 SafeDeleteArray(mLevelTwoInitData);
Austin Kinross215b37a2014-12-22 12:56:07 -0800148
149 ANGLETest::TearDown();
150 }
151
152 GLubyte *createRGBInitData(GLint width, GLint height, GLint r, GLint g, GLint b)
153 {
154 GLubyte *data = new GLubyte[3 * width * height];
155
156 for (int i = 0; i < width * height; i+=1)
157 {
Minmin Gong794e0002015-04-07 18:31:54 -0700158 data[3 * i + 0] = static_cast<GLubyte>(r);
159 data[3 * i + 1] = static_cast<GLubyte>(g);
160 data[3 * i + 2] = static_cast<GLubyte>(b);
Austin Kinross215b37a2014-12-22 12:56:07 -0800161 }
162
163 return data;
164 }
165
Olli Etuahob97a3e72016-04-13 14:31:52 +0300166 void clearAndDrawQuad(GLuint program, GLsizei viewportWidth, GLsizei viewportHeight)
Austin Kinross215b37a2014-12-22 12:56:07 -0800167 {
Olli Etuahob97a3e72016-04-13 14:31:52 +0300168 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800169 glClear(GL_COLOR_BUFFER_BIT);
Austin Kinross215b37a2014-12-22 12:56:07 -0800170 glViewport(0, 0, viewportWidth, viewportHeight);
Austin Kinross215b37a2014-12-22 12:56:07 -0800171 ASSERT_GL_NO_ERROR();
172
Olli Etuahob97a3e72016-04-13 14:31:52 +0300173 drawQuad(program, "aPosition", 0.0f);
174 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800175
Olli Etuahob97a3e72016-04-13 14:31:52 +0300176 void clearTextureLevel0(GLenum textarget,
177 GLuint texture,
178 GLfloat red,
179 GLfloat green,
180 GLfloat blue,
181 GLfloat alpha)
182 {
183 glBindFramebuffer(GL_FRAMEBUFFER, mOffscreenFramebuffer);
184 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textarget, texture, 0);
185 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
186 glClearColor(red, green, blue, alpha);
187 glClear(GL_COLOR_BUFFER_BIT);
188 glBindFramebuffer(GL_FRAMEBUFFER, 0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800189 }
190
Austin Kinross62815bf2015-01-15 16:32:36 -0800191 GLuint m2DProgram;
192 GLuint mCubeProgram;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300193 GLuint mTexture2D;
194 GLuint mTextureCube;
Geoff Lang27359ff2015-06-02 15:42:04 -0400195
Austin Kinross215b37a2014-12-22 12:56:07 -0800196 GLubyte* mLevelZeroBlueInitData;
197 GLubyte* mLevelZeroWhiteInitData;
198 GLubyte* mLevelOneInitData;
199 GLubyte* mLevelTwoInitData;
Olli Etuahob97a3e72016-04-13 14:31:52 +0300200
201 private:
202 GLuint mOffscreenFramebuffer;
Austin Kinross215b37a2014-12-22 12:56:07 -0800203};
204
Austin Kinross215b37a2014-12-22 12:56:07 -0800205class MipmapTestES3 : public ANGLETest
206{
Jamie Madillfa05f602015-05-07 13:47:11 -0400207 protected:
208 MipmapTestES3()
Olli Etuahob97a3e72016-04-13 14:31:52 +0300209 : mTextureArray(0),
210 mTexture3D(0),
211 mArrayProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300212 mTextureArraySliceUniformLocation(-1),
213 m3DProgram(0),
Olli Etuahob97a3e72016-04-13 14:31:52 +0300214 mTexture3DSliceUniformLocation(-1),
215 mTexture3DLODUniformLocation(-1)
216
Austin Kinross215b37a2014-12-22 12:56:07 -0800217 {
218 setWindowWidth(128);
219 setWindowHeight(128);
220 setConfigRedBits(8);
221 setConfigGreenBits(8);
222 setConfigBlueBits(8);
223 setConfigAlphaBits(8);
224 }
225
Olli Etuahob97a3e72016-04-13 14:31:52 +0300226 std::string vertexShaderSource()
Austin Kinross215b37a2014-12-22 12:56:07 -0800227 {
Austin Kinrosse8c86272015-01-15 18:55:36 -0800228 // Don't put "#version ..." on its own line. See [cpp]p1:
229 // "If there are sequences of preprocessing tokens within the list of arguments that
230 // would otherwise act as preprocessing directives, the behavior is undefined"
Olli Etuaho190028d2016-05-13 12:11:29 +0300231 // clang-format off
Olli Etuahob97a3e72016-04-13 14:31:52 +0300232 return SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800233 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800234 precision highp float;
235 in vec4 position;
236 out vec2 texcoord;
237
Austin Kinross215b37a2014-12-22 12:56:07 -0800238 void main()
239 {
Olli Etuaho190028d2016-05-13 12:11:29 +0300240 gl_Position = vec4(position.xy, 0.0, 1.0);
Austin Kinross215b37a2014-12-22 12:56:07 -0800241 texcoord = (position.xy * 0.5) + 0.5;
242 }
243 );
Olli Etuaho190028d2016-05-13 12:11:29 +0300244 // clang-format on
Olli Etuahob97a3e72016-04-13 14:31:52 +0300245 }
Austin Kinross215b37a2014-12-22 12:56:07 -0800246
Olli Etuahob97a3e72016-04-13 14:31:52 +0300247 void setUpArrayProgram()
248 {
Austin Kinross215b37a2014-12-22 12:56:07 -0800249 const std::string fragmentShaderSourceArray = SHADER_SOURCE
Austin Kinrosse8c86272015-01-15 18:55:36 -0800250 ( #version 300 es\n
Austin Kinross215b37a2014-12-22 12:56:07 -0800251 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200252 uniform highp sampler2DArray tex;
Austin Kinross215b37a2014-12-22 12:56:07 -0800253 uniform int slice;
254 in vec2 texcoord;
255 out vec4 out_FragColor;
256
257 void main()
258 {
259 out_FragColor = texture(tex, vec3(texcoord, float(slice)));
260 }
261 );
262
Olli Etuahob97a3e72016-04-13 14:31:52 +0300263 mArrayProgram = CompileProgram(vertexShaderSource(), fragmentShaderSourceArray);
Austin Kinross215b37a2014-12-22 12:56:07 -0800264 if (mArrayProgram == 0)
265 {
266 FAIL() << "shader compilation failed.";
267 }
268
Austin Kinross215b37a2014-12-22 12:56:07 -0800269 mTextureArraySliceUniformLocation = glGetUniformLocation(mArrayProgram, "slice");
270 ASSERT_NE(-1, mTextureArraySliceUniformLocation);
271
272 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800273 glUseProgram(0);
274 ASSERT_GL_NO_ERROR();
Olli Etuahob97a3e72016-04-13 14:31:52 +0300275 }
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000276
Olli Etuahob97a3e72016-04-13 14:31:52 +0300277 void setUp3DProgram()
278 {
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000279 const std::string fragmentShaderSource3D = SHADER_SOURCE
280 ( #version 300 es\n
281 precision highp float;
Olli Etuaho183d7e22015-11-20 15:59:09 +0200282 uniform highp sampler3D tex;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000283 uniform float slice;
284 uniform float lod;
285 in vec2 texcoord;
286 out vec4 out_FragColor;
287
288 void main()
289 {
290 out_FragColor = textureLod(tex, vec3(texcoord, slice), lod);
291 }
292 );
293
Olli Etuahob97a3e72016-04-13 14:31:52 +0300294 m3DProgram = CompileProgram(vertexShaderSource(), fragmentShaderSource3D);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000295 if (m3DProgram == 0)
296 {
297 FAIL() << "shader compilation failed.";
298 }
299
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000300 mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
301 ASSERT_NE(-1, mTexture3DSliceUniformLocation);
302
303 mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
304 ASSERT_NE(-1, mTexture3DLODUniformLocation);
305
306 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000307 glUniform1f(mTexture3DLODUniformLocation, 0);
308 glUseProgram(0);
309 ASSERT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800310 }
311
Olli Etuahob97a3e72016-04-13 14:31:52 +0300312 void SetUp() override
313 {
314 ANGLETest::SetUp();
315
316 glGenTextures(1, &mTextureArray);
317 glGenTextures(1, &mTexture3D);
318 ASSERT_GL_NO_ERROR();
319
320 setUpArrayProgram();
321 setUp3DProgram();
322 }
323
324 void TearDown() override
Austin Kinross215b37a2014-12-22 12:56:07 -0800325 {
326 glDeleteTextures(1, &mTextureArray);
327 glDeleteProgram(mArrayProgram);
328
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000329 glDeleteTextures(1, &mTexture3D);
330 glDeleteProgram(m3DProgram);
331
Austin Kinross215b37a2014-12-22 12:56:07 -0800332 ANGLETest::TearDown();
333 }
334
335 GLuint mTextureArray;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000336 GLuint mTexture3D;
Austin Kinross215b37a2014-12-22 12:56:07 -0800337
338 GLuint mArrayProgram;
Austin Kinross215b37a2014-12-22 12:56:07 -0800339 GLint mTextureArraySliceUniformLocation;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000340
341 GLuint m3DProgram;
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000342 GLint mTexture3DSliceUniformLocation;
343 GLint mTexture3DLODUniformLocation;
Austin Kinross215b37a2014-12-22 12:56:07 -0800344};
345
346// 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.
347// This ensures that renderers using the zero LOD workaround (e.g. D3D11 FL9_3) correctly pass init data to the mipmapped texture,
348// even if the the zero-LOD texture is currently in use.
Jamie Madillfa05f602015-05-07 13:47:11 -0400349TEST_P(MipmapTest, DISABLED_ThreeLevelsInitData)
Austin Kinross215b37a2014-12-22 12:56:07 -0800350{
351 // Pass in level zero init data.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300352 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800353 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
354 ASSERT_GL_NO_ERROR();
355
356 // Disable mips.
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
358
359 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300360 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300361 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800362
363 // Draw a half-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300364 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300365 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800366
367 // Draw a quarter-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300368 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300369 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800370
371 // Complete the texture by initializing the remaining levels.
372 int n = 1;
Minmin Gong794e0002015-04-07 18:31:54 -0700373 while (getWindowWidth() / (1U << n) >= 1)
Austin Kinross215b37a2014-12-22 12:56:07 -0800374 {
Minmin Gong794e0002015-04-07 18:31:54 -0700375 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 -0800376 ASSERT_GL_NO_ERROR();
377 n+=1;
378 }
379
380 // Pass in level one init data.
381 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, getWindowWidth() / 2, getWindowHeight() / 2, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelOneInitData);
382 ASSERT_GL_NO_ERROR();
383
384 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300385 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300386 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800387
388 // 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 +0300389 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300390 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800391
392 // Enable mipmaps.
393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
394
395 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300396 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300397 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800398
399 // 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 +0300400 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300401 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::black);
Austin Kinross215b37a2014-12-22 12:56:07 -0800402
403 // Pass in level two init data.
404 glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, getWindowWidth() / 4, getWindowHeight() / 4, 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelTwoInitData);
405 ASSERT_GL_NO_ERROR();
406
407 // Draw a full-sized quad, and check it's blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300408 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300409 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800410
411 // Draw a half-sized quad, and check it's green.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300412 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300413 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800414
415 // Draw a quarter-sized quad, and check it's red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300416 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300417 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800418
419 // Now disable mipmaps again, and render multiple sized quads. They should all be blue, since level 0 is blue.
420 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300421 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300422 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300423 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300424 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300425 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300426 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800427
428 // Now reset level 0 to white, keeping mipmaps disabled. Then, render various sized quads. They should be white.
429 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroWhiteInitData);
430 ASSERT_GL_NO_ERROR();
431
Olli Etuahob97a3e72016-04-13 14:31:52 +0300432 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300433 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300434 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300435 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300436 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300437 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::white);
Austin Kinross215b37a2014-12-22 12:56:07 -0800438
439 // Then enable mipmaps again. The quads should be white, green, red respectively.
440 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
441
Olli Etuahob97a3e72016-04-13 14:31:52 +0300442 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300443 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300444 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300445 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300446 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300447 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800448}
449
450// This test generates (and uses) mipmaps on a texture using init data. D3D11 will use a non-renderable TextureStorage for this.
451// The test then disables mips, renders to level zero of the texture, and reenables mips before using the texture again.
452// To do this, D3D11 has to convert the TextureStorage into a renderable one.
453// This test ensures that the conversion works correctly.
454// 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 -0400455TEST_P(MipmapTest, GenerateMipmapFromInitDataThenRender)
Austin Kinross215b37a2014-12-22 12:56:07 -0800456{
457 // Pass in initial data so the texture is blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300458 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800459 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, mLevelZeroBlueInitData);
460
461 // Then generate the mips.
462 glGenerateMipmap(GL_TEXTURE_2D);
463 ASSERT_GL_NO_ERROR();
464
465 // Enable mipmaps.
466 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
467
468 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300469 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300470 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800471
472 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300473 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300474 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800475
476 // Use mip level 2
Olli Etuahob97a3e72016-04-13 14:31:52 +0300477 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300478 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800479
480 ASSERT_GL_NO_ERROR();
481
482 // Disable mips. Render a quad using the texture and ensure it's blue.
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300484 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300485 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800486
Olli Etuahob97a3e72016-04-13 14:31:52 +0300487 // Clear level 0 of the texture to red.
488 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800489
490 // Reenable mips, and try rendering different-sized quads.
491 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
492
493 // Level 0 is now red, so this should render red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300494 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300495 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800496
497 // Use mip level 1, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300498 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300499 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800500
501 // Use mip level 2, blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300502 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300503 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800504}
505
506// This test ensures that mips are correctly generated from a rendered image.
507// In particular, on D3D11 Feature Level 9_3, the clear call will be performed on the zero-level texture, rather than the mipped one.
508// 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 -0400509TEST_P(MipmapTest, GenerateMipmapFromRenderedImage)
Austin Kinross215b37a2014-12-22 12:56:07 -0800510{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300511 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800512 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300513 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800514
515 // Then generate the mips
516 glGenerateMipmap(GL_TEXTURE_2D);
517 ASSERT_GL_NO_ERROR();
518
519 // Enable mips.
520 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
521
522 // Now draw the texture to various different sized areas.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300523 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300524 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800525
526 // Use mip level 1
Olli Etuahob97a3e72016-04-13 14:31:52 +0300527 clearAndDrawQuad(m2DProgram, getWindowWidth() / 2, getWindowHeight() / 2);
Olli Etuaho190028d2016-05-13 12:11:29 +0300528 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800529
530 // Use mip level 2
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::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800533}
534
535// Test to ensure that rendering to a mipmapped texture works, regardless of whether mipmaps are enabled or not.
536// TODO: This test hits a texture rebind bug in the D3D11 renderer. Fix this.
Jamie Madillfa05f602015-05-07 13:47:11 -0400537TEST_P(MipmapTest, RenderOntoLevelZeroAfterGenerateMipmap)
Austin Kinross215b37a2014-12-22 12:56:07 -0800538{
Geoff Langf74fef52015-04-29 12:57:52 -0400539 // TODO(geofflang): Figure out why this is broken on AMD OpenGL
Jamie Madill518b9fa2016-03-02 11:26:02 -0500540 if ((IsAMD() || IsIntel()) && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
Geoff Langf74fef52015-04-29 12:57:52 -0400541 {
Geoff Lang35b08e32015-06-03 11:22:07 -0400542 std::cout << "Test skipped on Intel/AMD OpenGL." << std::endl;
Geoff Langf74fef52015-04-29 12:57:52 -0400543 return;
544 }
545
Olli Etuahob97a3e72016-04-13 14:31:52 +0300546 glBindTexture(GL_TEXTURE_2D, mTexture2D);
Austin Kinross215b37a2014-12-22 12:56:07 -0800547
548 // Clear the texture to blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300549 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 0.0f, 1.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800550
551 // Now, draw the texture to a quad that's the same size as the texture. This draws to the default framebuffer.
552 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300553 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300554 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800555
556 // Now go back to the texture, and generate mips on it.
557 glGenerateMipmap(GL_TEXTURE_2D);
558 ASSERT_GL_NO_ERROR();
559
560 // Now try rendering the textured quad again. Note: we've not told GL to use the generated mips.
561 // The quad should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300562 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300563 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800564
565 // Now tell GL to use the generated mips.
566 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Corentin Wallez322653b2015-06-17 18:33:56 +0200567 EXPECT_GL_NO_ERROR();
Austin Kinross215b37a2014-12-22 12:56:07 -0800568
569 // Now render the textured quad again. It should be still be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300570 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300571 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800572
573 // 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 +0300574 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300575 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800576
577 // 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 +0300578 clearTextureLevel0(GL_TEXTURE_2D, mTexture2D, 0.0f, 1.0f, 0.0f, 1.0f);
Austin Kinross215b37a2014-12-22 12:56:07 -0800579
580 // 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 +0300581 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300582 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800583
584 // Render a small textured quad. This forces minification, so should render blue (the color of levels 1+).
Olli Etuahob97a3e72016-04-13 14:31:52 +0300585 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300586 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::blue);
Austin Kinross215b37a2014-12-22 12:56:07 -0800587
588 // Disable mipmaps again
589 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
590 ASSERT_GL_NO_ERROR();
591
592 // 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 +0300593 clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300594 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800595
596 // 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 +0300597 clearAndDrawQuad(m2DProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300598 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800599}
600
Austin Kinross62815bf2015-01-15 16:32:36 -0800601// This test ensures that the level-zero workaround for TextureCubes (on D3D11 Feature Level 9_3)
602// works as expected. It tests enabling/disabling mipmaps, generating mipmaps, and rendering to level zero.
Jamie Madillfa05f602015-05-07 13:47:11 -0400603TEST_P(MipmapTest, TextureCubeGeneralLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800604{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300605 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800606
607 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300608 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300609 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800610
611 // Generate mipmaps, and render. This should be blue.
Austin Kinross62815bf2015-01-15 16:32:36 -0800612 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
613 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300614 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300615 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800616
617 // 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 +0300618 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300619 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800620
621 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300622 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800623
624 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300625 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300626 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800627
628 // Draw using a quarter-size viewport, to force a lower LOD. This should be *BLUE*, since we only cleared level zero
629 // of the negative-Y face to red, and left its mipmaps blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300630 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300631 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800632
633 // Disable mipmaps again, and draw a to a quarter-size viewport.
634 // Since this should use level zero of the texture, this should be *RED*.
Austin Kinross62815bf2015-01-15 16:32:36 -0800635 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Olli Etuahob97a3e72016-04-13 14:31:52 +0300636 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300637 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800638}
639
640// This test ensures that rendering to level-zero of a TextureCube works as expected.
Jamie Madillfa05f602015-05-07 13:47:11 -0400641TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
Austin Kinross62815bf2015-01-15 16:32:36 -0800642{
Olli Etuahob97a3e72016-04-13 14:31:52 +0300643 glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureCube);
Austin Kinross62815bf2015-01-15 16:32:36 -0800644
645 // Draw. Since the negative-Y face's is blue, this should be blue.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300646 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300647 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
Austin Kinross62815bf2015-01-15 16:32:36 -0800648
649 // Now clear the negative-Y face of the cube to red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300650 clearTextureLevel0(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mTextureCube, 1.0f, 0.0f, 0.0f, 1.0f);
Austin Kinross62815bf2015-01-15 16:32:36 -0800651
652 // Draw using a full-size viewport. This should be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300653 clearAndDrawQuad(mCubeProgram, getWindowWidth(), getWindowHeight());
Olli Etuaho190028d2016-05-13 12:11:29 +0300654 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800655
656 // Draw a to a quarter-size viewport. This should also be red.
Olli Etuahob97a3e72016-04-13 14:31:52 +0300657 clearAndDrawQuad(mCubeProgram, getWindowWidth() / 4, getWindowHeight() / 4);
Olli Etuaho190028d2016-05-13 12:11:29 +0300658 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
Austin Kinross62815bf2015-01-15 16:32:36 -0800659}
660
Austin Kinross215b37a2014-12-22 12:56:07 -0800661// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
662// Then tests if the mipmaps are rendered correctly for all three layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400663TEST_P(MipmapTestES3, MipmapsForTextureArray)
Austin Kinross215b37a2014-12-22 12:56:07 -0800664{
665 int px = getWindowWidth() / 2;
666 int py = getWindowHeight() / 2;
667
Austin Kinross215b37a2014-12-22 12:56:07 -0800668 glBindTexture(GL_TEXTURE_2D_ARRAY, mTextureArray);
669
670 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 5, GL_RGBA8, 16, 16, 3);
671
672 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300673 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
674 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
675 pixelsRed.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800676
677 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300678 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
679 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
680 pixelsGreen.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800681
682 // Fill the third layer with blue
Olli Etuaho190028d2016-05-13 12:11:29 +0300683 std::vector<GLColor> pixelsBlue(16 * 16, GLColor::blue);
684 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
685 pixelsBlue.data());
Austin Kinross215b37a2014-12-22 12:56:07 -0800686
687 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
688 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
689
690 EXPECT_GL_NO_ERROR();
691
692 glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
693
694 EXPECT_GL_NO_ERROR();
695
696 glUseProgram(mArrayProgram);
Austin Kinross215b37a2014-12-22 12:56:07 -0800697
698 EXPECT_GL_NO_ERROR();
699
700 // Draw the first slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800701 glUniform1i(mTextureArraySliceUniformLocation, 0);
702 drawQuad(mArrayProgram, "position", 0.5f);
703 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300704 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Austin Kinross215b37a2014-12-22 12:56:07 -0800705
706 // Draw the second slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800707 glUniform1i(mTextureArraySliceUniformLocation, 1);
708 drawQuad(mArrayProgram, "position", 0.5f);
709 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300710 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Austin Kinross215b37a2014-12-22 12:56:07 -0800711
712 // Draw the third slice
Austin Kinross215b37a2014-12-22 12:56:07 -0800713 glUniform1i(mTextureArraySliceUniformLocation, 2);
714 drawQuad(mArrayProgram, "position", 0.5f);
715 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300716 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::blue);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000717}
718
719// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
720// Then tests if the mipmaps are rendered correctly for all two layers.
Jamie Madillfa05f602015-05-07 13:47:11 -0400721TEST_P(MipmapTestES3, MipmapsForTexture3D)
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000722{
723 int px = getWindowWidth() / 2;
724 int py = getWindowHeight() / 2;
725
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000726 glBindTexture(GL_TEXTURE_3D, mTexture3D);
727
728 glTexStorage3D(GL_TEXTURE_3D, 5, GL_RGBA8, 16, 16, 2);
729
730 // Fill the first layer with red
Olli Etuaho190028d2016-05-13 12:11:29 +0300731 std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
732 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
733 pixelsRed.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000734
735 // Fill the second layer with green
Olli Etuaho190028d2016-05-13 12:11:29 +0300736 std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
737 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
738 pixelsGreen.data());
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000739
740 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
741 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
742
743 EXPECT_GL_NO_ERROR();
744
745 glGenerateMipmap(GL_TEXTURE_3D);
746
747 EXPECT_GL_NO_ERROR();
748
749 glUseProgram(m3DProgram);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000750
751 EXPECT_GL_NO_ERROR();
752
753 // Mipmap level 0
754 // Draw the first slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000755 glUniform1f(mTexture3DLODUniformLocation, 0.);
756 glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
757 drawQuad(m3DProgram, "position", 0.5f);
758 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300759 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000760
761 // Draw the second slice
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000762 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
763 drawQuad(m3DProgram, "position", 0.5f);
764 EXPECT_GL_NO_ERROR();
Olli Etuaho190028d2016-05-13 12:11:29 +0300765 EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000766
767 // Mipmap level 1
768 // The second mipmap should only have one slice.
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000769 glUniform1f(mTexture3DLODUniformLocation, 1.);
770 drawQuad(m3DProgram, "position", 0.5f);
771 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500772 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000773
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000774 glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
775 drawQuad(m3DProgram, "position", 0.5f);
776 EXPECT_GL_NO_ERROR();
Geoff Lange0cc2a42016-01-20 10:58:17 -0500777 EXPECT_PIXEL_NEAR(px, py, 127, 127, 0, 255, 1.0);
Gregoire Payen de La Garanderie32334af2015-01-30 11:38:21 +0000778}
Jamie Madillfa05f602015-05-07 13:47:11 -0400779
780// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
781// Note: we run these tests against 9_3 on WARP due to hardware driver issues on Win7
Geoff Lange0cc2a42016-01-20 10:58:17 -0500782ANGLE_INSTANTIATE_TEST(MipmapTest,
783 ES2_D3D9(),
Austin Kinross2a63b3f2016-02-08 12:29:08 -0800784 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
785 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
Geoff Lange0cc2a42016-01-20 10:58:17 -0500786 ES2_D3D11_FL9_3_WARP(),
787 ES2_OPENGL(),
788 ES3_OPENGL(),
789 ES2_OPENGLES(),
790 ES3_OPENGLES());
791ANGLE_INSTANTIATE_TEST(MipmapTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());