1 //
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 // StateChangeTest:
7 //   Specifically designed for an ANGLE implementation of GL, these tests validate that
8 //   ANGLE's dirty bits systems don't get confused by certain sequences of state changes.
9 //
10 
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/gl_raii.h"
13 
14 using namespace angle;
15 
16 namespace
17 {
18 
19 class StateChangeTest : public ANGLETest
20 {
21   protected:
StateChangeTest()22     StateChangeTest()
23     {
24         setWindowWidth(64);
25         setWindowHeight(64);
26         setConfigRedBits(8);
27         setConfigGreenBits(8);
28         setConfigBlueBits(8);
29         setConfigAlphaBits(8);
30 
31         // Enable the no error extension to avoid syncing the FBO state on validation.
32         setNoErrorEnabled(true);
33     }
34 
SetUp()35     void SetUp() override
36     {
37         ANGLETest::SetUp();
38 
39         glGenFramebuffers(1, &mFramebuffer);
40         glGenTextures(2, mTextures.data());
41         glGenRenderbuffers(1, &mRenderbuffer);
42 
43         ASSERT_GL_NO_ERROR();
44     }
45 
TearDown()46     void TearDown() override
47     {
48         if (mFramebuffer != 0)
49         {
50             glDeleteFramebuffers(1, &mFramebuffer);
51             mFramebuffer = 0;
52         }
53 
54         if (!mTextures.empty())
55         {
56             glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data());
57             mTextures.clear();
58         }
59 
60         glDeleteRenderbuffers(1, &mRenderbuffer);
61 
62         ANGLETest::TearDown();
63     }
64 
65     GLuint mFramebuffer           = 0;
66     GLuint mRenderbuffer          = 0;
67     std::vector<GLuint> mTextures = {0, 0};
68 };
69 
70 class StateChangeTestES3 : public StateChangeTest
71 {
72   protected:
StateChangeTestES3()73     StateChangeTestES3() {}
74 };
75 
76 }  // anonymous namespace
77 
78 // Ensure that CopyTexImage2D syncs framebuffer changes.
TEST_P(StateChangeTest,CopyTexImage2DSync)79 TEST_P(StateChangeTest, CopyTexImage2DSync)
80 {
81     if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
82     {
83         // TODO(geofflang): Fix on Linux AMD drivers (http://anglebug.com/1291)
84         std::cout << "Test disabled on AMD OpenGL." << std::endl;
85         return;
86     }
87 
88     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
89 
90     // Init first texture to red
91     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
92     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
93     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
94     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
95     glClear(GL_COLOR_BUFFER_BIT);
96     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
97 
98     // Init second texture to green
99     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
100     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
101     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
102     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
103     glClear(GL_COLOR_BUFFER_BIT);
104     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
105 
106     // Copy in the red texture to the green one.
107     // CopyTexImage should sync the framebuffer attachment change.
108     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
109     glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 16, 16, 0);
110     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
111     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
112 
113     ASSERT_GL_NO_ERROR();
114 }
115 
116 // Ensure that CopyTexSubImage2D syncs framebuffer changes.
TEST_P(StateChangeTest,CopyTexSubImage2DSync)117 TEST_P(StateChangeTest, CopyTexSubImage2DSync)
118 {
119     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
120 
121     // Init first texture to red
122     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
123     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
124     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
125     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
126     glClear(GL_COLOR_BUFFER_BIT);
127     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
128 
129     // Init second texture to green
130     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
131     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
132     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
133     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
134     glClear(GL_COLOR_BUFFER_BIT);
135     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
136 
137     // Copy in the red texture to the green one.
138     // CopyTexImage should sync the framebuffer attachment change.
139     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
140     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 16, 16);
141     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
142     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
143 
144     ASSERT_GL_NO_ERROR();
145 }
146 
147 // Test that Framebuffer completeness caching works when color attachments change.
TEST_P(StateChangeTest,FramebufferIncompleteColorAttachment)148 TEST_P(StateChangeTest, FramebufferIncompleteColorAttachment)
149 {
150     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
151     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
152     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
153     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
154     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
155 
156     // Change the texture at color attachment 0 to be non-color-renderable.
157     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
158     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
159                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
160 
161     ASSERT_GL_NO_ERROR();
162 }
163 
164 // Test that caching works when color attachments change with TexStorage.
TEST_P(StateChangeTest,FramebufferIncompleteWithTexStorage)165 TEST_P(StateChangeTest, FramebufferIncompleteWithTexStorage)
166 {
167     if (!extensionEnabled("GL_EXT_texture_storage"))
168     {
169         std::cout << "Test skipped because TexStorage2DEXT not available." << std::endl;
170     }
171 
172     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
173     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
174     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
175     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
176     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
177 
178     // Change the texture at color attachment 0 to be non-color-renderable.
179     glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_ALPHA8_EXT, 16, 16);
180     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
181                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
182 
183     ASSERT_GL_NO_ERROR();
184 }
185 
186 // Test that caching works when color attachments change with CompressedTexImage2D.
TEST_P(StateChangeTestES3,FramebufferIncompleteWithCompressedTex)187 TEST_P(StateChangeTestES3, FramebufferIncompleteWithCompressedTex)
188 {
189     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
190     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
191     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
192     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
193     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
194 
195     // Change the texture at color attachment 0 to be non-color-renderable.
196     glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB8_ETC2, 16, 16, 0, 64, nullptr);
197     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
198                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
199 
200     ASSERT_GL_NO_ERROR();
201 }
202 
203 // Test that caching works when color attachments are deleted.
TEST_P(StateChangeTestES3,FramebufferIncompleteWhenAttachmentDeleted)204 TEST_P(StateChangeTestES3, FramebufferIncompleteWhenAttachmentDeleted)
205 {
206     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
207     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
208     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
209     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
210     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
211 
212     // Delete the texture at color attachment 0.
213     glDeleteTextures(1, &mTextures[0]);
214     mTextures[0] = 0;
215     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,
216                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
217 
218     ASSERT_GL_NO_ERROR();
219 }
220 
221 // Test that Framebuffer completeness caching works when depth attachments change.
TEST_P(StateChangeTest,FramebufferIncompleteDepthAttachment)222 TEST_P(StateChangeTest, FramebufferIncompleteDepthAttachment)
223 {
224     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
225     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
226     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
227     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
228     glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
229     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 16, 16);
230     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mRenderbuffer);
231     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
232 
233     // Change the texture at color attachment 0 to be non-depth-renderable.
234     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
235     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
236                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
237 
238     ASSERT_GL_NO_ERROR();
239 }
240 
241 // Test that Framebuffer completeness caching works when stencil attachments change.
TEST_P(StateChangeTest,FramebufferIncompleteStencilAttachment)242 TEST_P(StateChangeTest, FramebufferIncompleteStencilAttachment)
243 {
244     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
245     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
246     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
247     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
248     glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
249     glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 16, 16);
250     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
251                               mRenderbuffer);
252     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
253 
254     // Change the texture at the stencil attachment to be non-stencil-renderable.
255     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
256     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
257                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
258 
259     ASSERT_GL_NO_ERROR();
260 }
261 
262 // Test that Framebuffer completeness caching works when depth-stencil attachments change.
TEST_P(StateChangeTest,FramebufferIncompleteDepthStencilAttachment)263 TEST_P(StateChangeTest, FramebufferIncompleteDepthStencilAttachment)
264 {
265     if (getClientMajorVersion() < 3 && !extensionEnabled("GL_OES_packed_depth_stencil"))
266     {
267         std::cout << "Test skipped because packed depth+stencil not availble." << std::endl;
268         return;
269     }
270 
271     if (IsWindows() && IsIntel() && IsOpenGL())
272     {
273         // TODO(jmadill): Investigate the failure (https://anglebug.com/1388)
274         std::cout << "Test disabled on Windows Intel OpenGL." << std::endl;
275         return;
276     }
277 
278     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
279     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
280     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
281     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
282     glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
283     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 16, 16);
284     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
285                               mRenderbuffer);
286     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
287 
288     // Change the texture the depth-stencil attachment to be non-depth-stencil-renderable.
289     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
290     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
291                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
292 
293     ASSERT_GL_NO_ERROR();
294 }
295 
296 // Ensure that CopyTexSubImage3D syncs framebuffer changes.
TEST_P(StateChangeTestES3,CopyTexSubImage3DSync)297 TEST_P(StateChangeTestES3, CopyTexSubImage3DSync)
298 {
299     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
300 
301     // Init first texture to red
302     glBindTexture(GL_TEXTURE_3D, mTextures[0]);
303     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
304     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[0], 0, 0);
305     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
306     glClear(GL_COLOR_BUFFER_BIT);
307     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
308 
309     // Init second texture to green
310     glBindTexture(GL_TEXTURE_3D, mTextures[1]);
311     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
312     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[1], 0, 0);
313     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
314     glClear(GL_COLOR_BUFFER_BIT);
315     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
316 
317     // Copy in the red texture to the green one.
318     // CopyTexImage should sync the framebuffer attachment change.
319     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[0], 0, 0);
320     glCopyTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, 0, 0, 16, 16);
321     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTextures[1], 0, 0);
322     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
323 
324     ASSERT_GL_NO_ERROR();
325 }
326 
327 // Ensure that BlitFramebuffer syncs framebuffer changes.
TEST_P(StateChangeTestES3,BlitFramebufferSync)328 TEST_P(StateChangeTestES3, BlitFramebufferSync)
329 {
330     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
331 
332     // Init first texture to red
333     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
334     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
335     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
336     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
337     glClear(GL_COLOR_BUFFER_BIT);
338     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
339 
340     // Init second texture to green
341     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
342     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
343     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1], 0);
344     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
345     glClear(GL_COLOR_BUFFER_BIT);
346     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
347 
348     // Change to the red textures and blit.
349     // BlitFramebuffer should sync the framebuffer attachment change.
350     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
351     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
352                            0);
353     glBlitFramebuffer(0, 0, 16, 16, 0, 0, 16, 16, GL_COLOR_BUFFER_BIT, GL_NEAREST);
354     glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
355     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
356 
357     ASSERT_GL_NO_ERROR();
358 }
359 
360 // Ensure that ReadBuffer and DrawBuffers sync framebuffer changes.
TEST_P(StateChangeTestES3,ReadBufferAndDrawBuffersSync)361 TEST_P(StateChangeTestES3, ReadBufferAndDrawBuffersSync)
362 {
363     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
364 
365     // Initialize two FBO attachments
366     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
367     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
368     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
369     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
370     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
371     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
372 
373     // Clear first attachment to red
374     GLenum bufs1[] = {GL_COLOR_ATTACHMENT0, GL_NONE};
375     glDrawBuffers(2, bufs1);
376     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
377     glClear(GL_COLOR_BUFFER_BIT);
378 
379     // Clear second texture to green
380     GLenum bufs2[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
381     glDrawBuffers(2, bufs2);
382     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
383     glClear(GL_COLOR_BUFFER_BIT);
384 
385     // Verify first attachment is red and second is green
386     glReadBuffer(GL_COLOR_ATTACHMENT1);
387     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
388 
389     glReadBuffer(GL_COLOR_ATTACHMENT0);
390     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
391 
392     ASSERT_GL_NO_ERROR();
393 }
394 
395 // Tests calling invalidate on incomplete framebuffers after switching attachments.
396 // Adapted partially from WebGL 2 test "renderbuffers/invalidate-framebuffer"
TEST_P(StateChangeTestES3,IncompleteRenderbufferAttachmentInvalidateSync)397 TEST_P(StateChangeTestES3, IncompleteRenderbufferAttachmentInvalidateSync)
398 {
399     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
400     glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
401     GLint samples = 0;
402     glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, 1, &samples);
403     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
404     ASSERT_GL_NO_ERROR();
405 
406     // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the
407     // attached renderbuffer
408     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,
409                      glCheckFramebufferStatus(GL_FRAMEBUFFER));
410     GLenum attachments1[] = {GL_COLOR_ATTACHMENT0};
411     glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments1);
412     ASSERT_GL_NO_ERROR();
413 
414     glRenderbufferStorageMultisample(GL_RENDERBUFFER, static_cast<GLsizei>(samples), GL_RGBA8,
415                                      getWindowWidth(), getWindowHeight());
416     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
417     glClear(GL_COLOR_BUFFER_BIT);
418     ASSERT_GL_NO_ERROR();
419 
420     GLRenderbuffer renderbuf;
421 
422     glBindRenderbuffer(GL_RENDERBUFFER, renderbuf.get());
423     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
424                               renderbuf.get());
425     ASSERT_GL_NO_ERROR();
426 
427     // invalidate the framebuffer when the attachment is incomplete: no storage allocated to the
428     // attached renderbuffer
429     // Note: the bug will only repro *without* a call to checkStatus before the invalidate.
430     GLenum attachments2[] = {GL_DEPTH_ATTACHMENT};
431     glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, attachments2);
432 
433     glRenderbufferStorageMultisample(GL_RENDERBUFFER, static_cast<GLsizei>(samples),
434                                      GL_DEPTH_COMPONENT16, getWindowWidth(), getWindowHeight());
435     EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
436     glClear(GL_DEPTH_BUFFER_BIT);
437     ASSERT_GL_NO_ERROR();
438 }
439 
440 class StateChangeRenderTest : public StateChangeTest
441 {
442   protected:
StateChangeRenderTest()443     StateChangeRenderTest() : mProgram(0), mRenderbuffer(0) {}
444 
SetUp()445     void SetUp() override
446     {
447         StateChangeTest::SetUp();
448 
449         const std::string vertexShaderSource =
450             "attribute vec2 position;\n"
451             "void main() {\n"
452             "    gl_Position = vec4(position, 0, 1);\n"
453             "}";
454         const std::string fragmentShaderSource =
455             "uniform highp vec4 uniformColor;\n"
456             "void main() {\n"
457             "    gl_FragColor = uniformColor;\n"
458             "}";
459 
460         mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
461         ASSERT_NE(0u, mProgram);
462 
463         glGenRenderbuffers(1, &mRenderbuffer);
464     }
465 
TearDown()466     void TearDown() override
467     {
468         glDeleteProgram(mProgram);
469         glDeleteRenderbuffers(1, &mRenderbuffer);
470 
471         StateChangeTest::TearDown();
472     }
473 
setUniformColor(const GLColor & color)474     void setUniformColor(const GLColor &color)
475     {
476         glUseProgram(mProgram);
477         const Vector4 &normalizedColor = color.toNormalizedVector();
478         GLint uniformLocation = glGetUniformLocation(mProgram, "uniformColor");
479         ASSERT_NE(-1, uniformLocation);
480         glUniform4fv(uniformLocation, 1, normalizedColor.data());
481     }
482 
483     GLuint mProgram;
484     GLuint mRenderbuffer;
485 };
486 
487 // Test that re-creating a currently attached texture works as expected.
TEST_P(StateChangeRenderTest,RecreateTexture)488 TEST_P(StateChangeRenderTest, RecreateTexture)
489 {
490     if (IsIntel() && IsLinux())
491     {
492         // TODO(cwallez): Fix on Linux Intel drivers (http://anglebug.com/1346)
493         std::cout << "Test disabled on Linux Intel OpenGL." << std::endl;
494         return;
495     }
496 
497     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
498 
499     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
500     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
501     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
502 
503     // Draw with red to the FBO.
504     GLColor red(255, 0, 0, 255);
505     setUniformColor(red);
506     drawQuad(mProgram, "position", 0.5f);
507     EXPECT_PIXEL_COLOR_EQ(0, 0, red);
508 
509     // Recreate the texture with green.
510     GLColor green(0, 255, 0, 255);
511     std::vector<GLColor> greenPixels(32 * 32, green);
512     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE,
513                  greenPixels.data());
514     EXPECT_PIXEL_COLOR_EQ(0, 0, green);
515 
516     // Verify drawing blue gives blue. This covers the FBO sync with D3D dirty bits.
517     GLColor blue(0, 0, 255, 255);
518     setUniformColor(blue);
519     drawQuad(mProgram, "position", 0.5f);
520     EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
521 
522     EXPECT_GL_NO_ERROR();
523 }
524 
525 // Test that re-creating a currently attached renderbuffer works as expected.
TEST_P(StateChangeRenderTest,RecreateRenderbuffer)526 TEST_P(StateChangeRenderTest, RecreateRenderbuffer)
527 {
528     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
529 
530     glBindRenderbuffer(GL_RENDERBUFFER, mRenderbuffer);
531     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
532     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mRenderbuffer);
533 
534     // Draw with red to the FBO.
535     GLColor red(255, 0, 0, 255);
536     setUniformColor(red);
537     drawQuad(mProgram, "position", 0.5f);
538     EXPECT_PIXEL_COLOR_EQ(0, 0, red);
539 
540     // Recreate the renderbuffer and clear to green.
541     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 32, 32);
542     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
543     glClear(GL_COLOR_BUFFER_BIT);
544     GLColor green(0, 255, 0, 255);
545     EXPECT_PIXEL_COLOR_EQ(0, 0, green);
546 
547     // Verify drawing blue gives blue. This covers the FBO sync with D3D dirty bits.
548     GLColor blue(0, 0, 255, 255);
549     setUniformColor(blue);
550     drawQuad(mProgram, "position", 0.5f);
551     EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
552 
553     EXPECT_GL_NO_ERROR();
554 }
555 
556 // Test that recreating a texture with GenerateMipmaps signals the FBO is dirty.
TEST_P(StateChangeRenderTest,GenerateMipmap)557 TEST_P(StateChangeRenderTest, GenerateMipmap)
558 {
559     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
560 
561     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
562     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
563     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
564     glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
565     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
566 
567     // Draw once to set the RenderTarget in D3D11
568     GLColor red(255, 0, 0, 255);
569     setUniformColor(red);
570     drawQuad(mProgram, "position", 0.5f);
571     EXPECT_PIXEL_COLOR_EQ(0, 0, red);
572 
573     // This will trigger the texture to be re-created on FL9_3.
574     glGenerateMipmap(GL_TEXTURE_2D);
575 
576     // Now ensure we don't have a stale render target.
577     GLColor blue(0, 0, 255, 255);
578     setUniformColor(blue);
579     drawQuad(mProgram, "position", 0.5f);
580     EXPECT_PIXEL_COLOR_EQ(0, 0, blue);
581 
582     EXPECT_GL_NO_ERROR();
583 }
584 
585 ANGLE_INSTANTIATE_TEST(StateChangeTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL());
586 ANGLE_INSTANTIATE_TEST(StateChangeRenderTest,
587                        ES2_D3D9(),
588                        ES2_D3D11(),
589                        ES2_OPENGL(),
590                        ES2_D3D11_FL9_3());
591 ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL());
592