• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2023 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 
7 #include "test_utils/ANGLETest.h"
8 
9 #include "test_utils/gl_raii.h"
10 #include "util/random_utils.h"
11 #include "util/shader_utils.h"
12 #include "util/test_utils.h"
13 
14 using namespace angle;
15 
16 namespace
17 {
18 class CapturedTest : public ANGLETest<>
19 {
20   protected:
CapturedTest()21     CapturedTest()
22     {
23         setWindowWidth(128);
24         setWindowHeight(128);
25         setConfigRedBits(8);
26         setConfigGreenBits(8);
27         setConfigBlueBits(8);
28         setConfigAlphaBits(8);
29         setConfigDepthBits(24);
30         setConfigStencilBits(8);
31     }
32 
testSetUp()33     void testSetUp() override
34     {
35         // Calls not captured because we setup Start frame to MEC.
36 
37         // TODO: why are these framebuffers not showing up in the capture?
38 
39         mFBOs.resize(2, 0);
40         glGenFramebuffers(2, mFBOs.data());
41 
42         constexpr char kInactiveVS[] = R"(precision highp float;
43 void main(void) {
44    gl_Position = vec4(0.5, 0.5, 0.5, 1.0);
45 })";
46 
47         static constexpr char kInactiveDeferredVS[] = R"(attribute vec4 a_position;
48 attribute vec2 a_texCoord;
49 varying vec2 v_texCoord;
50 void main()
51 {
52     gl_Position = a_position;
53     v_texCoord = a_texCoord;
54 })";
55 
56         static constexpr char kInactiveDeferredFS[] = R"(precision mediump float;
57 varying vec2 v_texCoord;
58 uniform sampler2D s_texture;
59 void main()
60 {
61     gl_FragColor = vec4(0.4, 0.4, 0.4, 1.0);
62     gl_FragColor = texture2D(s_texture, v_texCoord);
63 })";
64 
65         static constexpr char kActiveDeferredVS[] = R"(attribute vec4 a_position;
66 attribute vec2 a_texCoord;
67 varying vec2 v_texCoord;
68 void main()
69 {
70     gl_Position = a_position;
71     v_texCoord = a_texCoord;
72 })";
73 
74         // Create shaders, program but defer compiling & linking, use before capture starts
75         // (Inactive)
76         lateLinkTestVertShaderInactive                   = glCreateShader(GL_VERTEX_SHADER);
77         const char *lateLinkTestVsSourceArrayInactive[1] = {kInactiveDeferredVS};
78         glShaderSource(lateLinkTestVertShaderInactive, 1, lateLinkTestVsSourceArrayInactive, 0);
79         lateLinkTestFragShaderInactive                   = glCreateShader(GL_FRAGMENT_SHADER);
80         const char *lateLinkTestFsSourceArrayInactive[1] = {kInactiveDeferredFS};
81         glShaderSource(lateLinkTestFragShaderInactive, 1, lateLinkTestFsSourceArrayInactive, 0);
82         lateLinkTestProgramInactive = glCreateProgram();
83         glAttachShader(lateLinkTestProgramInactive, lateLinkTestVertShaderInactive);
84         glAttachShader(lateLinkTestProgramInactive, lateLinkTestFragShaderInactive);
85 
86         // Create inactive program having shader shared with deferred linked program
87         glCompileShader(lateLinkTestVertShaderInactive);
88         glCompileShader(lateLinkTestFragShaderInactive);
89         glLinkProgram(lateLinkTestProgramInactive);
90         ASSERT_GL_NO_ERROR();
91 
92         // Create vertex shader and program but defer compiling & linking until capture time
93         // (Active) Use fragment shader attached to inactive program
94         lateLinkTestVertShaderActive                   = glCreateShader(GL_VERTEX_SHADER);
95         const char *lateLinkTestVsSourceArrayActive[1] = {kActiveDeferredVS};
96         glShaderSource(lateLinkTestVertShaderActive, 1, lateLinkTestVsSourceArrayActive, 0);
97         lateLinkTestProgramActive = glCreateProgram();
98         glAttachShader(lateLinkTestProgramActive, lateLinkTestVertShaderActive);
99         glAttachShader(lateLinkTestProgramActive, lateLinkTestFragShaderInactive);
100         ASSERT_GL_NO_ERROR();
101 
102         // Create shader that is unused during capture
103         inactiveProgram                    = glCreateProgram();
104         inactiveShader                     = glCreateShader(GL_VERTEX_SHADER);
105         const char *inactiveSourceArray[1] = {kInactiveVS};
106         glShaderSource(inactiveShader, 1, inactiveSourceArray, 0);
107         glCompileShader(inactiveShader);
108         glAttachShader(inactiveProgram, inactiveShader);
109 
110         // Create Shader Program before capture begins to use during capture
111         activeBeforeProgram                = glCreateProgram();
112         activeBeforeVertShader             = glCreateShader(GL_VERTEX_SHADER);
113         activeBeforeFragShader             = glCreateShader(GL_FRAGMENT_SHADER);
114         const char *activeVsSourceArray[1] = {kActiveVS};
115         glShaderSource(activeBeforeVertShader, 1, activeVsSourceArray, 0);
116         glCompileShader(activeBeforeVertShader);
117         glAttachShader(activeBeforeProgram, activeBeforeVertShader);
118         const char *activeFsSourceArray[1] = {kActiveFS};
119         glShaderSource(activeBeforeFragShader, 1, activeFsSourceArray, 0);
120         glCompileShader(activeBeforeFragShader);
121         glAttachShader(activeBeforeProgram, activeBeforeFragShader);
122         glLinkProgram(activeBeforeProgram);
123 
124         // Get the attr/sampler locations
125         mPositionLoc = glGetAttribLocation(activeBeforeProgram, "a_position");
126         mTexCoordLoc = glGetAttribLocation(activeBeforeProgram, "a_texCoord");
127         mSamplerLoc  = glGetUniformLocation(activeBeforeProgram, "s_texture");
128         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
129 
130         // Bind the texture object before capture begins
131         glGenTextures(1, &textureNeverBound);
132         glGenTextures(1, &textureBoundBeforeCapture);
133         glBindTexture(GL_TEXTURE_2D, textureBoundBeforeCapture);
134         ASSERT_GL_NO_ERROR();
135 
136         const size_t width                 = 2;
137         const size_t height                = 2;
138         GLubyte pixels[width * height * 3] = {
139             255, 0,   0,    // Red
140             0,   255, 0,    // Green
141             0,   0,   255,  // Blue
142             255, 255, 0,    // Yellow
143         };
144         // Populate the pre-capture bound texture
145         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
146         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
147         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
148     }
149 
testTearDown()150     void testTearDown() override
151     {
152         // Not reached during capture as we hit the End frame earlier.
153 
154         if (!mFBOs.empty())
155         {
156             glDeleteFramebuffers(static_cast<GLsizei>(mFBOs.size()), mFBOs.data());
157         }
158 
159         glDeleteTextures(1, &textureNeverBound);
160         glDeleteTextures(1, &textureBoundBeforeCapture);
161         glDeleteProgram(inactiveProgram);
162         glDeleteProgram(activeBeforeProgram);
163         glDeleteShader(inactiveShader);
164         glDeleteShader(activeBeforeVertShader);
165         glDeleteShader(activeBeforeFragShader);
166         glDeleteProgram(lateLinkTestProgramInactive);
167         glDeleteProgram(lateLinkTestProgramActive);
168         glDeleteShader(lateLinkTestVertShaderInactive);
169         glDeleteShader(lateLinkTestFragShaderInactive);
170         glDeleteShader(lateLinkTestVertShaderActive);
171     }
172 
173     static constexpr char kActiveVS[] = R"(attribute vec4 a_position;
174 attribute vec2 a_texCoord;
175 varying vec2 v_texCoord;
176 void main()
177 {
178     gl_Position = a_position;
179     v_texCoord = a_texCoord;
180 })";
181 
182     static constexpr char kActiveFS[] = R"(precision mediump float;
183 varying vec2 v_texCoord;
184 uniform sampler2D s_texture;
185 void main()
186 {
187     gl_FragColor = texture2D(s_texture, v_texCoord);
188 })";
189 
190     void frame1();
191     void frame2();
192     void frame3();
193     void frame4();
194 
195     std::vector<GLuint> mFBOs;
196 
197     // For testing deferred compile/link
198     GLuint lateLinkTestVertShaderInactive;
199     GLuint lateLinkTestFragShaderInactive;
200     GLuint lateLinkTestProgramInactive;
201     GLuint lateLinkTestVertShaderActive;
202     GLuint lateLinkTestProgramActive;
203 
204     GLuint inactiveProgram;
205     GLuint inactiveShader;
206 
207     GLuint activeBeforeProgram;
208     GLuint activeBeforeVertShader;
209     GLuint activeBeforeFragShader;
210 
211     GLuint textureNeverBound;
212     GLuint textureBoundBeforeCapture;
213     GLuint mPositionLoc;
214     GLuint mTexCoordLoc;
215     GLint mSamplerLoc;
216 };
217 
frame1()218 void CapturedTest::frame1()
219 {
220     glClearColor(0.25f, 0.5f, 0.5f, 0.5f);
221     glClear(GL_COLOR_BUFFER_BIT);
222     EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 128, 1.0);
223 
224     GLfloat vertices[] = {
225         -0.75f, 0.25f,  0.0f,  // Position 0
226         0.0f,   0.0f,          // TexCoord 0
227         -0.75f, -0.75f, 0.0f,  // Position 1
228         0.0f,   1.0f,          // TexCoord 1
229         0.25f,  -0.75f, 0.0f,  // Position 2
230         1.0f,   1.0f,          // TexCoord 2
231         0.25f,  0.25f,  0.0f,  // Position 3
232         1.0f,   0.0f           // TexCoord 3
233     };
234 
235     GLushort indices[] = {0, 1, 2, 0, 2, 3};
236 
237     glClear(GL_COLOR_BUFFER_BIT);
238     glUseProgram(activeBeforeProgram);
239     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
240     glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices + 3);
241     glEnableVertexAttribArray(mPositionLoc);
242     glEnableVertexAttribArray(mTexCoordLoc);
243     glUniform1i(mSamplerLoc, 0);
244 
245     // Draw without binding texture during capture
246     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
247     EXPECT_PIXEL_EQ(20, 20, 0, 0, 255, 255);
248 
249     glDeleteVertexArrays(1, &mPositionLoc);
250     glDeleteVertexArrays(1, &mTexCoordLoc);
251 }
252 
frame2()253 void CapturedTest::frame2()
254 {
255     // Draw using texture created and bound during capture
256 
257     GLuint activeDuringProgram;
258     GLuint activeDuringVertShader;
259     GLuint activeDuringFragShader;
260     GLuint positionLoc;
261     GLuint texCoordLoc;
262     GLuint textureBoundDuringCapture;
263     GLint samplerLoc;
264 
265     activeDuringProgram                = glCreateProgram();
266     activeDuringVertShader             = glCreateShader(GL_VERTEX_SHADER);
267     activeDuringFragShader             = glCreateShader(GL_FRAGMENT_SHADER);
268     const char *activeVsSourceArray[1] = {kActiveVS};
269     glShaderSource(activeDuringVertShader, 1, activeVsSourceArray, 0);
270     glCompileShader(activeDuringVertShader);
271     glAttachShader(activeDuringProgram, activeDuringVertShader);
272     const char *activeFsSourceArray[1] = {kActiveFS};
273     glShaderSource(activeDuringFragShader, 1, activeFsSourceArray, 0);
274     glCompileShader(activeDuringFragShader);
275     glAttachShader(activeDuringProgram, activeDuringFragShader);
276     glLinkProgram(activeDuringProgram);
277 
278     // Get the attr/sampler locations
279     positionLoc = glGetAttribLocation(activeDuringProgram, "a_position");
280     texCoordLoc = glGetAttribLocation(activeDuringProgram, "a_texCoord");
281     samplerLoc  = glGetUniformLocation(activeDuringProgram, "s_texture");
282     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
283 
284     // Bind the texture object during capture
285     glGenTextures(1, &textureBoundDuringCapture);
286     glBindTexture(GL_TEXTURE_2D, textureBoundDuringCapture);
287     ASSERT_GL_NO_ERROR();
288 
289     const size_t width                 = 2;
290     const size_t height                = 2;
291     GLubyte pixels[width * height * 3] = {
292         255, 255, 0,    // Yellow
293         0,   0,   255,  // Blue
294         0,   255, 0,    // Green
295         255, 0,   0,    // Red
296     };
297 
298     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
299     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
300     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
301 
302     GLfloat vertices[] = {
303         -0.25f, 0.75f,  0.0f,  // Position 0
304         0.0f,   0.0f,          // TexCoord 0
305         -0.25f, -0.25f, 0.0f,  // Position 1
306         0.0f,   1.0f,          // TexCoord 1
307         0.75f,  -0.25f, 0.0f,  // Position 2
308         1.0f,   1.0f,          // TexCoord 2
309         0.75f,  0.75f,  0.0f,  // Position 3
310         1.0f,   0.0f           // TexCoord 3
311     };
312     GLushort indices[] = {0, 1, 2, 0, 2, 3};
313 
314     glClear(GL_COLOR_BUFFER_BIT);
315     glUseProgram(activeDuringProgram);
316     glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
317     glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices + 3);
318     glEnableVertexAttribArray(positionLoc);
319     glEnableVertexAttribArray(texCoordLoc);
320     glUniform1i(samplerLoc, 0);
321 
322     // Draw using texture bound during capture
323     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
324     EXPECT_PIXEL_EQ(108, 108, 0, 0, 255, 255);
325 
326     glDeleteTextures(1, &textureBoundDuringCapture);
327     glDeleteVertexArrays(1, &positionLoc);
328     glDeleteVertexArrays(1, &texCoordLoc);
329     glDeleteProgram(activeDuringProgram);
330     glDeleteShader(activeDuringVertShader);
331     glDeleteShader(activeDuringFragShader);
332 }
333 
frame3()334 void CapturedTest::frame3()
335 {
336     // TODO: using local objects (with RAII helpers) here that create and destroy objects within the
337     // frame. Maybe move some of this to test Setup.
338 
339     constexpr char kVS[] = R"(precision highp float;
340 attribute vec3 attr1;
341 void main(void) {
342    gl_Position = vec4(attr1, 1.0);
343 })";
344 
345     constexpr char kFS[] = R"(precision highp float;
346 void main(void) {
347    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
348 })";
349 
350     GLBuffer emptyBuffer;
351     glBindBuffer(GL_ARRAY_BUFFER, emptyBuffer);
352 
353     ANGLE_GL_PROGRAM(program, kVS, kFS);
354     glBindAttribLocation(program, 0, "attr1");
355     glLinkProgram(program);
356     ASSERT_TRUE(CheckLinkStatusAndReturnProgram(program, true));
357     glUseProgram(program);
358 
359     // Use non-existing attribute 1.
360     glEnableVertexAttribArray(1);
361     glVertexAttribPointer(1, 3, GL_UNSIGNED_BYTE, false, 1, 0);
362 
363     glDrawArrays(GL_TRIANGLES, 0, 3);
364     EXPECT_GL_NO_ERROR();
365 
366     // Note: RAII destructors called here causing additional GL calls.
367 }
368 
frame4()369 void CapturedTest::frame4()
370 {
371     GLuint positionLoc;
372     GLuint texCoordLoc;
373     GLuint lateLinkTestTexture;
374     GLint samplerLoc;
375 
376     // Deferred compile/link
377     glCompileShader(lateLinkTestVertShaderActive);
378     glLinkProgram(lateLinkTestProgramActive);
379     ASSERT_GL_NO_ERROR();
380 
381     // Get the attr/sampler locations
382     positionLoc = glGetAttribLocation(lateLinkTestProgramActive, "a_position");
383     texCoordLoc = glGetAttribLocation(lateLinkTestProgramActive, "a_texCoord");
384     samplerLoc  = glGetUniformLocation(lateLinkTestProgramActive, "s_texture");
385     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
386 
387     // Bind the texture object during capture
388     glGenTextures(1, &lateLinkTestTexture);
389     glBindTexture(GL_TEXTURE_2D, lateLinkTestTexture);
390     ASSERT_GL_NO_ERROR();
391 
392     const size_t width                 = 2;
393     const size_t height                = 2;
394     GLubyte pixels[width * height * 3] = {
395         255, 255, 0,    // Yellow
396         0,   0,   255,  // Blue
397         0,   255, 0,    // Green
398         255, 0,   0,    // Red
399     };
400 
401     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
402     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
403     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
404 
405     GLfloat vertices[] = {
406         -0.25f, 0.75f,  0.0f,  // Position 0
407         0.0f,   0.0f,          // TexCoord 0
408         -0.25f, -0.25f, 0.0f,  // Position 1
409         0.0f,   1.0f,          // TexCoord 1
410         0.75f,  -0.25f, 0.0f,  // Position 2
411         1.0f,   1.0f,          // TexCoord 2
412         0.75f,  0.75f,  0.0f,  // Position 3
413         1.0f,   0.0f           // TexCoord 3
414     };
415     GLushort indices[] = {0, 1, 2, 0, 2, 3};
416 
417     glClear(GL_COLOR_BUFFER_BIT);
418     glUseProgram(lateLinkTestProgramActive);
419     glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
420     glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices + 3);
421     glEnableVertexAttribArray(positionLoc);
422     glEnableVertexAttribArray(texCoordLoc);
423     glUniform1i(samplerLoc, 0);
424 
425     // Draw shaders & program created before capture
426     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
427     EXPECT_PIXEL_EQ(108, 108, 0, 0, 255, 255);
428 }
429 
430 // Test captured by capture_tests.py
TEST_P(CapturedTest,MultiFrame)431 TEST_P(CapturedTest, MultiFrame)
432 {
433     // Swap before the first frame so that setup gets its own frame
434     swapBuffers();
435     frame1();
436 
437     swapBuffers();
438     frame2();
439 
440     swapBuffers();
441     frame3();
442 
443     swapBuffers();
444     frame4();
445 
446     // Empty frames to reach capture end.
447     for (int i = 0; i < 10; i++)
448     {
449         swapBuffers();
450     }
451     // Note: test teardown adds an additonal swap in
452     // ANGLETestBase::ANGLETestPreTearDown() when --angle-per-test-capture-label
453 }
454 
455 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CapturedTest);
456 // Capture is only supported on the Vulkan backend
457 ANGLE_INSTANTIATE_TEST(CapturedTest, ES3_VULKAN());
458 
459 }  // anonymous namespace
460