xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLMultiContextTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // EGLMultiContextTest.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //   Tests relating to multiple non-shared Contexts.
8*8975f5c5SAndroid Build Coastguard Worker 
9*8975f5c5SAndroid Build Coastguard Worker #include <gtest/gtest.h>
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/ANGLETest.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/MultiThreadSteps.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/angle_test_configs.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/gl_raii.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "util/EGLWindow.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "util/test_utils.h"
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker using namespace angle;
19*8975f5c5SAndroid Build Coastguard Worker 
20*8975f5c5SAndroid Build Coastguard Worker namespace
21*8975f5c5SAndroid Build Coastguard Worker {
22*8975f5c5SAndroid Build Coastguard Worker 
SafeDestroyContext(EGLDisplay display,EGLContext & context)23*8975f5c5SAndroid Build Coastguard Worker EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context)
24*8975f5c5SAndroid Build Coastguard Worker {
25*8975f5c5SAndroid Build Coastguard Worker     EGLBoolean result = EGL_TRUE;
26*8975f5c5SAndroid Build Coastguard Worker     if (context != EGL_NO_CONTEXT)
27*8975f5c5SAndroid Build Coastguard Worker     {
28*8975f5c5SAndroid Build Coastguard Worker         result  = eglDestroyContext(display, context);
29*8975f5c5SAndroid Build Coastguard Worker         context = EGL_NO_CONTEXT;
30*8975f5c5SAndroid Build Coastguard Worker     }
31*8975f5c5SAndroid Build Coastguard Worker     return result;
32*8975f5c5SAndroid Build Coastguard Worker }
33*8975f5c5SAndroid Build Coastguard Worker 
34*8975f5c5SAndroid Build Coastguard Worker class EGLMultiContextTest : public ANGLETest<>
35*8975f5c5SAndroid Build Coastguard Worker {
36*8975f5c5SAndroid Build Coastguard Worker   public:
EGLMultiContextTest()37*8975f5c5SAndroid Build Coastguard Worker     EGLMultiContextTest() : mContexts{EGL_NO_CONTEXT, EGL_NO_CONTEXT}, mTexture(0) {}
38*8975f5c5SAndroid Build Coastguard Worker 
testTearDown()39*8975f5c5SAndroid Build Coastguard Worker     void testTearDown() override
40*8975f5c5SAndroid Build Coastguard Worker     {
41*8975f5c5SAndroid Build Coastguard Worker         glDeleteTextures(1, &mTexture);
42*8975f5c5SAndroid Build Coastguard Worker 
43*8975f5c5SAndroid Build Coastguard Worker         EGLDisplay display = getEGLWindow()->getDisplay();
44*8975f5c5SAndroid Build Coastguard Worker 
45*8975f5c5SAndroid Build Coastguard Worker         if (display != EGL_NO_DISPLAY)
46*8975f5c5SAndroid Build Coastguard Worker         {
47*8975f5c5SAndroid Build Coastguard Worker             for (auto &context : mContexts)
48*8975f5c5SAndroid Build Coastguard Worker             {
49*8975f5c5SAndroid Build Coastguard Worker                 SafeDestroyContext(display, context);
50*8975f5c5SAndroid Build Coastguard Worker             }
51*8975f5c5SAndroid Build Coastguard Worker         }
52*8975f5c5SAndroid Build Coastguard Worker 
53*8975f5c5SAndroid Build Coastguard Worker         // Set default test state to not give an error on shutdown.
54*8975f5c5SAndroid Build Coastguard Worker         getEGLWindow()->makeCurrent();
55*8975f5c5SAndroid Build Coastguard Worker     }
56*8975f5c5SAndroid Build Coastguard Worker 
chooseConfig(EGLDisplay dpy,EGLConfig * config) const57*8975f5c5SAndroid Build Coastguard Worker     bool chooseConfig(EGLDisplay dpy, EGLConfig *config) const
58*8975f5c5SAndroid Build Coastguard Worker     {
59*8975f5c5SAndroid Build Coastguard Worker         bool result          = false;
60*8975f5c5SAndroid Build Coastguard Worker         EGLint count         = 0;
61*8975f5c5SAndroid Build Coastguard Worker         EGLint clientVersion = EGL_OPENGL_ES3_BIT;
62*8975f5c5SAndroid Build Coastguard Worker         EGLint attribs[]     = {EGL_RED_SIZE,
63*8975f5c5SAndroid Build Coastguard Worker                                 8,
64*8975f5c5SAndroid Build Coastguard Worker                                 EGL_GREEN_SIZE,
65*8975f5c5SAndroid Build Coastguard Worker                                 8,
66*8975f5c5SAndroid Build Coastguard Worker                                 EGL_BLUE_SIZE,
67*8975f5c5SAndroid Build Coastguard Worker                                 8,
68*8975f5c5SAndroid Build Coastguard Worker                                 EGL_ALPHA_SIZE,
69*8975f5c5SAndroid Build Coastguard Worker                                 8,
70*8975f5c5SAndroid Build Coastguard Worker                                 EGL_RENDERABLE_TYPE,
71*8975f5c5SAndroid Build Coastguard Worker                                 clientVersion,
72*8975f5c5SAndroid Build Coastguard Worker                                 EGL_SURFACE_TYPE,
73*8975f5c5SAndroid Build Coastguard Worker                                 EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
74*8975f5c5SAndroid Build Coastguard Worker                                 EGL_NONE};
75*8975f5c5SAndroid Build Coastguard Worker 
76*8975f5c5SAndroid Build Coastguard Worker         result = eglChooseConfig(dpy, attribs, config, 1, &count);
77*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(result && (count > 0));
78*8975f5c5SAndroid Build Coastguard Worker         return result;
79*8975f5c5SAndroid Build Coastguard Worker     }
80*8975f5c5SAndroid Build Coastguard Worker 
createContext(EGLDisplay dpy,EGLConfig config,EGLContext * context)81*8975f5c5SAndroid Build Coastguard Worker     bool createContext(EGLDisplay dpy, EGLConfig config, EGLContext *context)
82*8975f5c5SAndroid Build Coastguard Worker     {
83*8975f5c5SAndroid Build Coastguard Worker         bool result      = false;
84*8975f5c5SAndroid Build Coastguard Worker         EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, 3, EGL_NONE};
85*8975f5c5SAndroid Build Coastguard Worker 
86*8975f5c5SAndroid Build Coastguard Worker         *context = eglCreateContext(dpy, config, nullptr, attribs);
87*8975f5c5SAndroid Build Coastguard Worker         result   = (*context != EGL_NO_CONTEXT);
88*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(result);
89*8975f5c5SAndroid Build Coastguard Worker         return result;
90*8975f5c5SAndroid Build Coastguard Worker     }
91*8975f5c5SAndroid Build Coastguard Worker 
createPbufferSurface(EGLDisplay dpy,EGLConfig config,EGLint width,EGLint height,EGLSurface * surface)92*8975f5c5SAndroid Build Coastguard Worker     bool createPbufferSurface(EGLDisplay dpy,
93*8975f5c5SAndroid Build Coastguard Worker                               EGLConfig config,
94*8975f5c5SAndroid Build Coastguard Worker                               EGLint width,
95*8975f5c5SAndroid Build Coastguard Worker                               EGLint height,
96*8975f5c5SAndroid Build Coastguard Worker                               EGLSurface *surface)
97*8975f5c5SAndroid Build Coastguard Worker     {
98*8975f5c5SAndroid Build Coastguard Worker         bool result      = false;
99*8975f5c5SAndroid Build Coastguard Worker         EGLint attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
100*8975f5c5SAndroid Build Coastguard Worker 
101*8975f5c5SAndroid Build Coastguard Worker         *surface = eglCreatePbufferSurface(dpy, config, attribs);
102*8975f5c5SAndroid Build Coastguard Worker         result   = (*surface != EGL_NO_SURFACE);
103*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(result);
104*8975f5c5SAndroid Build Coastguard Worker         return result;
105*8975f5c5SAndroid Build Coastguard Worker     }
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker     enum class FenceTest
108*8975f5c5SAndroid Build Coastguard Worker     {
109*8975f5c5SAndroid Build Coastguard Worker         ClientWait,
110*8975f5c5SAndroid Build Coastguard Worker         ServerWait,
111*8975f5c5SAndroid Build Coastguard Worker         GetStatus,
112*8975f5c5SAndroid Build Coastguard Worker     };
113*8975f5c5SAndroid Build Coastguard Worker     enum class FlushMethod
114*8975f5c5SAndroid Build Coastguard Worker     {
115*8975f5c5SAndroid Build Coastguard Worker         Flush,
116*8975f5c5SAndroid Build Coastguard Worker         Finish,
117*8975f5c5SAndroid Build Coastguard Worker     };
118*8975f5c5SAndroid Build Coastguard Worker     void testFenceWithOpenRenderPass(FenceTest test, FlushMethod flushMethod);
119*8975f5c5SAndroid Build Coastguard Worker 
120*8975f5c5SAndroid Build Coastguard Worker     EGLContext mContexts[2];
121*8975f5c5SAndroid Build Coastguard Worker     GLuint mTexture;
122*8975f5c5SAndroid Build Coastguard Worker };
123*8975f5c5SAndroid Build Coastguard Worker 
124*8975f5c5SAndroid Build Coastguard Worker // Test that calling eglDeleteContext on a context that is not current succeeds.
TEST_P(EGLMultiContextTest,TestContextDestroySimple)125*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, TestContextDestroySimple)
126*8975f5c5SAndroid Build Coastguard Worker {
127*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
128*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
129*8975f5c5SAndroid Build Coastguard Worker 
130*8975f5c5SAndroid Build Coastguard Worker     EGLContext context1 = window->createContext(EGL_NO_CONTEXT, nullptr);
131*8975f5c5SAndroid Build Coastguard Worker     EGLContext context2 = window->createContext(EGL_NO_CONTEXT, nullptr);
132*8975f5c5SAndroid Build Coastguard Worker 
133*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context1));
134*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context2));
135*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
136*8975f5c5SAndroid Build Coastguard Worker 
137*8975f5c5SAndroid Build Coastguard Worker     // Cleanup
138*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
139*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context1));
140*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
141*8975f5c5SAndroid Build Coastguard Worker }
142*8975f5c5SAndroid Build Coastguard Worker 
143*8975f5c5SAndroid Build Coastguard Worker // Test that an error is generated when using EGL objects after calling eglTerminate.
TEST_P(EGLMultiContextTest,NegativeTestAfterEglTerminate)144*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, NegativeTestAfterEglTerminate)
145*8975f5c5SAndroid Build Coastguard Worker {
146*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
147*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
148*8975f5c5SAndroid Build Coastguard Worker 
149*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config = EGL_NO_CONFIG_KHR;
150*8975f5c5SAndroid Build Coastguard Worker     EXPECT_TRUE(chooseConfig(dpy, &config));
151*8975f5c5SAndroid Build Coastguard Worker 
152*8975f5c5SAndroid Build Coastguard Worker     EGLContext context = EGL_NO_CONTEXT;
153*8975f5c5SAndroid Build Coastguard Worker     EXPECT_TRUE(createContext(dpy, config, &context));
154*8975f5c5SAndroid Build Coastguard Worker     ASSERT_EGL_SUCCESS() << "eglCreateContext failed.";
155*8975f5c5SAndroid Build Coastguard Worker 
156*8975f5c5SAndroid Build Coastguard Worker     EGLSurface drawSurface = EGL_NO_SURFACE;
157*8975f5c5SAndroid Build Coastguard Worker     EXPECT_TRUE(createPbufferSurface(dpy, config, 2560, 1080, &drawSurface));
158*8975f5c5SAndroid Build Coastguard Worker     ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
159*8975f5c5SAndroid Build Coastguard Worker 
160*8975f5c5SAndroid Build Coastguard Worker     EGLSurface readSurface = EGL_NO_SURFACE;
161*8975f5c5SAndroid Build Coastguard Worker     EXPECT_TRUE(createPbufferSurface(dpy, config, 2560, 1080, &readSurface));
162*8975f5c5SAndroid Build Coastguard Worker     ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
163*8975f5c5SAndroid Build Coastguard Worker 
164*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, drawSurface, readSurface, context));
165*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
166*8975f5c5SAndroid Build Coastguard Worker 
167*8975f5c5SAndroid Build Coastguard Worker     // Terminate the display
168*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglTerminate(dpy));
169*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
170*8975f5c5SAndroid Build Coastguard Worker 
171*8975f5c5SAndroid Build Coastguard Worker     // Try to use invalid handles
172*8975f5c5SAndroid Build Coastguard Worker     EGLint value;
173*8975f5c5SAndroid Build Coastguard Worker     eglQuerySurface(dpy, drawSurface, EGL_SWAP_BEHAVIOR, &value);
174*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
175*8975f5c5SAndroid Build Coastguard Worker     eglQuerySurface(dpy, readSurface, EGL_HEIGHT, &value);
176*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_ERROR(EGL_BAD_SURFACE);
177*8975f5c5SAndroid Build Coastguard Worker 
178*8975f5c5SAndroid Build Coastguard Worker     // Cleanup
179*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
180*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
181*8975f5c5SAndroid Build Coastguard Worker     window->destroyGL();
182*8975f5c5SAndroid Build Coastguard Worker }
183*8975f5c5SAndroid Build Coastguard Worker 
184*8975f5c5SAndroid Build Coastguard Worker // Test that a compute shader running in one thread will still work when rendering is happening in
185*8975f5c5SAndroid Build Coastguard Worker // another thread (with non-shared contexts).  The non-shared context will still share a Vulkan
186*8975f5c5SAndroid Build Coastguard Worker // command buffer.
TEST_P(EGLMultiContextTest,ComputeShaderOkayWithRendering)187*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ComputeShaderOkayWithRendering)
188*8975f5c5SAndroid Build Coastguard Worker {
189*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
190*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!isVulkanRenderer());
191*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 || getClientMinorVersion() < 1);
192*8975f5c5SAndroid Build Coastguard Worker 
193*8975f5c5SAndroid Build Coastguard Worker     // Initialize contexts
194*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
195*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
196*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
197*8975f5c5SAndroid Build Coastguard Worker 
198*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount    = 2;
199*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
200*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx[kThreadCount]     = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
201*8975f5c5SAndroid Build Coastguard Worker 
202*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
203*8975f5c5SAndroid Build Coastguard Worker 
204*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
205*8975f5c5SAndroid Build Coastguard Worker     {
206*8975f5c5SAndroid Build Coastguard Worker         surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
207*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
208*8975f5c5SAndroid Build Coastguard Worker 
209*8975f5c5SAndroid Build Coastguard Worker         ctx[t] = window->createContext(EGL_NO_CONTEXT, nullptr);
210*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
211*8975f5c5SAndroid Build Coastguard Worker     }
212*8975f5c5SAndroid Build Coastguard Worker 
213*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
214*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
215*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
216*8975f5c5SAndroid Build Coastguard Worker 
217*8975f5c5SAndroid Build Coastguard Worker     enum class Step
218*8975f5c5SAndroid Build Coastguard Worker     {
219*8975f5c5SAndroid Build Coastguard Worker         Thread0Start,
220*8975f5c5SAndroid Build Coastguard Worker         Thread0DispatchedCompute,
221*8975f5c5SAndroid Build Coastguard Worker         Thread1Drew,
222*8975f5c5SAndroid Build Coastguard Worker         Thread0DispatchedComputeAgain,
223*8975f5c5SAndroid Build Coastguard Worker         Finish,
224*8975f5c5SAndroid Build Coastguard Worker         Abort,
225*8975f5c5SAndroid Build Coastguard Worker     };
226*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Thread0Start;
227*8975f5c5SAndroid Build Coastguard Worker 
228*8975f5c5SAndroid Build Coastguard Worker     // This first thread dispatches a compute shader.  It immediately starts.
229*8975f5c5SAndroid Build Coastguard Worker     std::thread deletingThread = std::thread([&]() {
230*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
231*8975f5c5SAndroid Build Coastguard Worker 
232*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
233*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
234*8975f5c5SAndroid Build Coastguard Worker 
235*8975f5c5SAndroid Build Coastguard Worker         // Potentially wait to be signalled to start.
236*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Start));
237*8975f5c5SAndroid Build Coastguard Worker 
238*8975f5c5SAndroid Build Coastguard Worker         // Wake up and do next step: Create, detach, and dispatch a compute shader program.
239*8975f5c5SAndroid Build Coastguard Worker         constexpr char kCS[]  = R"(#version 310 es
240*8975f5c5SAndroid Build Coastguard Worker layout(local_size_x=1) in;
241*8975f5c5SAndroid Build Coastguard Worker void main()
242*8975f5c5SAndroid Build Coastguard Worker {
243*8975f5c5SAndroid Build Coastguard Worker })";
244*8975f5c5SAndroid Build Coastguard Worker         GLuint computeProgram = glCreateProgram();
245*8975f5c5SAndroid Build Coastguard Worker         GLuint cs             = CompileShader(GL_COMPUTE_SHADER, kCS);
246*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(0u, cs);
247*8975f5c5SAndroid Build Coastguard Worker 
248*8975f5c5SAndroid Build Coastguard Worker         glAttachShader(computeProgram, cs);
249*8975f5c5SAndroid Build Coastguard Worker         glDeleteShader(cs);
250*8975f5c5SAndroid Build Coastguard Worker         glLinkProgram(computeProgram);
251*8975f5c5SAndroid Build Coastguard Worker         GLint linkStatus;
252*8975f5c5SAndroid Build Coastguard Worker         glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
253*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_TRUE(linkStatus);
254*8975f5c5SAndroid Build Coastguard Worker         glDetachShader(computeProgram, cs);
255*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
256*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(computeProgram);
257*8975f5c5SAndroid Build Coastguard Worker 
258*8975f5c5SAndroid Build Coastguard Worker         glDispatchCompute(8, 4, 2);
259*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
260*8975f5c5SAndroid Build Coastguard Worker 
261*8975f5c5SAndroid Build Coastguard Worker         // Signal the second thread and wait for it to draw and flush.
262*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0DispatchedCompute);
263*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Drew));
264*8975f5c5SAndroid Build Coastguard Worker 
265*8975f5c5SAndroid Build Coastguard Worker         // Wake up and do next step: Dispatch the same compute shader again.
266*8975f5c5SAndroid Build Coastguard Worker         glDispatchCompute(8, 4, 2);
267*8975f5c5SAndroid Build Coastguard Worker 
268*8975f5c5SAndroid Build Coastguard Worker         // Signal the second thread and wait for it to draw and flush again.
269*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0DispatchedComputeAgain);
270*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
271*8975f5c5SAndroid Build Coastguard Worker 
272*8975f5c5SAndroid Build Coastguard Worker         // Wake up and do next step: Dispatch the same compute shader again, and force flush the
273*8975f5c5SAndroid Build Coastguard Worker         // underlying command buffer.
274*8975f5c5SAndroid Build Coastguard Worker         glDispatchCompute(8, 4, 2);
275*8975f5c5SAndroid Build Coastguard Worker         glFinish();
276*8975f5c5SAndroid Build Coastguard Worker 
277*8975f5c5SAndroid Build Coastguard Worker         // Clean-up and exit this thread.
278*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
279*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
280*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
281*8975f5c5SAndroid Build Coastguard Worker     });
282*8975f5c5SAndroid Build Coastguard Worker 
283*8975f5c5SAndroid Build Coastguard Worker     // This second thread renders.  It starts once the other thread does its first nextStep()
284*8975f5c5SAndroid Build Coastguard Worker     std::thread continuingThread = std::thread([&]() {
285*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
286*8975f5c5SAndroid Build Coastguard Worker 
287*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
288*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
289*8975f5c5SAndroid Build Coastguard Worker 
290*8975f5c5SAndroid Build Coastguard Worker         // Wait for first thread to create and dispatch a compute shader.
291*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0DispatchedCompute));
292*8975f5c5SAndroid Build Coastguard Worker 
293*8975f5c5SAndroid Build Coastguard Worker         // Wake up and do next step: Create graphics resources, draw, and force flush the
294*8975f5c5SAndroid Build Coastguard Worker         // underlying command buffer.
295*8975f5c5SAndroid Build Coastguard Worker         GLTexture texture;
296*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
297*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
298*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
299*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
300*8975f5c5SAndroid Build Coastguard Worker 
301*8975f5c5SAndroid Build Coastguard Worker         GLRenderbuffer renderbuffer;
302*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
303*8975f5c5SAndroid Build Coastguard Worker         glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
304*8975f5c5SAndroid Build Coastguard Worker         constexpr int kRenderbufferSize = 4;
305*8975f5c5SAndroid Build Coastguard Worker         glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kRenderbufferSize, kRenderbufferSize);
306*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
307*8975f5c5SAndroid Build Coastguard Worker         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
308*8975f5c5SAndroid Build Coastguard Worker                                   renderbuffer);
309*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
310*8975f5c5SAndroid Build Coastguard Worker 
311*8975f5c5SAndroid Build Coastguard Worker         GLProgram graphicsProgram;
312*8975f5c5SAndroid Build Coastguard Worker         graphicsProgram.makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
313*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(graphicsProgram.valid());
314*8975f5c5SAndroid Build Coastguard Worker 
315*8975f5c5SAndroid Build Coastguard Worker         drawQuad(graphicsProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
316*8975f5c5SAndroid Build Coastguard Worker         glFinish();
317*8975f5c5SAndroid Build Coastguard Worker 
318*8975f5c5SAndroid Build Coastguard Worker         // Signal the first thread and wait for it to dispatch a compute shader again.
319*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Drew);
320*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0DispatchedComputeAgain));
321*8975f5c5SAndroid Build Coastguard Worker 
322*8975f5c5SAndroid Build Coastguard Worker         // Wake up and do next step: Draw and force flush the underlying command buffer again.
323*8975f5c5SAndroid Build Coastguard Worker         drawQuad(graphicsProgram.get(), essl1_shaders::PositionAttrib(), 0.5f);
324*8975f5c5SAndroid Build Coastguard Worker         glFinish();
325*8975f5c5SAndroid Build Coastguard Worker 
326*8975f5c5SAndroid Build Coastguard Worker         // Signal the first thread and wait exit this thread.
327*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
328*8975f5c5SAndroid Build Coastguard Worker 
329*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
330*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
331*8975f5c5SAndroid Build Coastguard Worker     });
332*8975f5c5SAndroid Build Coastguard Worker 
333*8975f5c5SAndroid Build Coastguard Worker     deletingThread.join();
334*8975f5c5SAndroid Build Coastguard Worker     continuingThread.join();
335*8975f5c5SAndroid Build Coastguard Worker 
336*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
337*8975f5c5SAndroid Build Coastguard Worker 
338*8975f5c5SAndroid Build Coastguard Worker     // Clean up
339*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
340*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
341*8975f5c5SAndroid Build Coastguard Worker     {
342*8975f5c5SAndroid Build Coastguard Worker         eglDestroySurface(dpy, surface[t]);
343*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx[t]);
344*8975f5c5SAndroid Build Coastguard Worker     }
345*8975f5c5SAndroid Build Coastguard Worker }
346*8975f5c5SAndroid Build Coastguard Worker 
347*8975f5c5SAndroid Build Coastguard Worker // Test that repeated EGL init + terminate with improper cleanup doesn't cause an OOM crash.
348*8975f5c5SAndroid Build Coastguard Worker // To reproduce the OOM error -
349*8975f5c5SAndroid Build Coastguard Worker //     1. Increase the loop count to a large number
350*8975f5c5SAndroid Build Coastguard Worker //     2. Remove the call to "eglReleaseThread" in the for loop
TEST_P(EGLMultiContextTest,RepeatedEglInitAndTerminate)351*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, RepeatedEglInitAndTerminate)
352*8975f5c5SAndroid Build Coastguard Worker {
353*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker     // Release all resources in parent thread
356*8975f5c5SAndroid Build Coastguard Worker     getEGLWindow()->destroyGL();
357*8975f5c5SAndroid Build Coastguard Worker 
358*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy;
359*8975f5c5SAndroid Build Coastguard Worker     EGLSurface srf;
360*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx;
361*8975f5c5SAndroid Build Coastguard Worker     EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
362*8975f5c5SAndroid Build Coastguard Worker                           EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, GetParam().getDeviceType(),
363*8975f5c5SAndroid Build Coastguard Worker                           EGL_NONE};
364*8975f5c5SAndroid Build Coastguard Worker 
365*8975f5c5SAndroid Build Coastguard Worker     for (int i = 0; i < 50; i++)  // Note: this test is fairly slow b/303089709
366*8975f5c5SAndroid Build Coastguard Worker     {
367*8975f5c5SAndroid Build Coastguard Worker         std::thread thread = std::thread([&]() {
368*8975f5c5SAndroid Build Coastguard Worker             dpy = eglGetPlatformDisplayEXT(
369*8975f5c5SAndroid Build Coastguard Worker                 EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
370*8975f5c5SAndroid Build Coastguard Worker             EXPECT_TRUE(dpy != EGL_NO_DISPLAY);
371*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglInitialize(dpy, nullptr, nullptr));
372*8975f5c5SAndroid Build Coastguard Worker 
373*8975f5c5SAndroid Build Coastguard Worker             EGLConfig config = EGL_NO_CONFIG_KHR;
374*8975f5c5SAndroid Build Coastguard Worker             EXPECT_TRUE(chooseConfig(dpy, &config));
375*8975f5c5SAndroid Build Coastguard Worker 
376*8975f5c5SAndroid Build Coastguard Worker             EXPECT_TRUE(createPbufferSurface(dpy, config, 2560, 1080, &srf));
377*8975f5c5SAndroid Build Coastguard Worker             ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
378*8975f5c5SAndroid Build Coastguard Worker 
379*8975f5c5SAndroid Build Coastguard Worker             EXPECT_TRUE(createContext(dpy, config, &ctx));
380*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, srf, srf, ctx));
381*8975f5c5SAndroid Build Coastguard Worker 
382*8975f5c5SAndroid Build Coastguard Worker             // Clear and read back to make sure thread uses context.
383*8975f5c5SAndroid Build Coastguard Worker             glClearColor(1.0, 0.0, 0.0, 1.0);
384*8975f5c5SAndroid Build Coastguard Worker             glClear(GL_COLOR_BUFFER_BIT);
385*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
386*8975f5c5SAndroid Build Coastguard Worker 
387*8975f5c5SAndroid Build Coastguard Worker             eglTerminate(dpy);
388*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
389*8975f5c5SAndroid Build Coastguard Worker             eglReleaseThread();
390*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
391*8975f5c5SAndroid Build Coastguard Worker             dpy = EGL_NO_DISPLAY;
392*8975f5c5SAndroid Build Coastguard Worker             srf = EGL_NO_SURFACE;
393*8975f5c5SAndroid Build Coastguard Worker             ctx = EGL_NO_CONTEXT;
394*8975f5c5SAndroid Build Coastguard Worker         });
395*8975f5c5SAndroid Build Coastguard Worker 
396*8975f5c5SAndroid Build Coastguard Worker         thread.join();
397*8975f5c5SAndroid Build Coastguard Worker     }
398*8975f5c5SAndroid Build Coastguard Worker }
399*8975f5c5SAndroid Build Coastguard Worker 
400*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can reuse the unterminated display created by thread A
401*8975f5c5SAndroid Build Coastguard Worker // even after thread A is destroyed.
TEST_P(EGLMultiContextTest,ReuseUnterminatedDisplay)402*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ReuseUnterminatedDisplay)
403*8975f5c5SAndroid Build Coastguard Worker {
404*8975f5c5SAndroid Build Coastguard Worker     // Release all resources in parent thread
405*8975f5c5SAndroid Build Coastguard Worker     getEGLWindow()->destroyGL();
406*8975f5c5SAndroid Build Coastguard Worker 
407*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy;
408*8975f5c5SAndroid Build Coastguard Worker     EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
409*8975f5c5SAndroid Build Coastguard Worker                           EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, GetParam().getDeviceType(),
410*8975f5c5SAndroid Build Coastguard Worker                           EGL_NONE};
411*8975f5c5SAndroid Build Coastguard Worker 
412*8975f5c5SAndroid Build Coastguard Worker     std::thread threadA = std::thread([&]() {
413*8975f5c5SAndroid Build Coastguard Worker         dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
414*8975f5c5SAndroid Build Coastguard Worker                                        reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
415*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(dpy != EGL_NO_DISPLAY);
416*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglInitialize(dpy, nullptr, nullptr));
417*8975f5c5SAndroid Build Coastguard Worker     });
418*8975f5c5SAndroid Build Coastguard Worker     threadA.join();
419*8975f5c5SAndroid Build Coastguard Worker 
420*8975f5c5SAndroid Build Coastguard Worker     std::thread threadB = std::thread([&]() {
421*8975f5c5SAndroid Build Coastguard Worker         EGLSurface srf;
422*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx;
423*8975f5c5SAndroid Build Coastguard Worker         EGLConfig config = EGL_NO_CONFIG_KHR;
424*8975f5c5SAndroid Build Coastguard Worker         // If threadA's termination caused "dpy" to be incorrectly terminated all EGL APIs below
425*8975f5c5SAndroid Build Coastguard Worker         // staring with eglChooseConfig(...) will error out with an EGL_NOT_INITIALIZED error.
426*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(chooseConfig(dpy, &config));
427*8975f5c5SAndroid Build Coastguard Worker 
428*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(createPbufferSurface(dpy, config, 2560, 1080, &srf));
429*8975f5c5SAndroid Build Coastguard Worker         ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
430*8975f5c5SAndroid Build Coastguard Worker 
431*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(createContext(dpy, config, &ctx));
432*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, srf, srf, ctx));
433*8975f5c5SAndroid Build Coastguard Worker 
434*8975f5c5SAndroid Build Coastguard Worker         // Clear and read back to make sure thread uses context.
435*8975f5c5SAndroid Build Coastguard Worker         glClearColor(1.0, 0.0, 0.0, 1.0);
436*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
437*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
438*8975f5c5SAndroid Build Coastguard Worker 
439*8975f5c5SAndroid Build Coastguard Worker         srf = EGL_NO_SURFACE;
440*8975f5c5SAndroid Build Coastguard Worker         ctx = EGL_NO_CONTEXT;
441*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, srf, srf, ctx));
442*8975f5c5SAndroid Build Coastguard Worker         eglTerminate(dpy);
443*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
444*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
445*8975f5c5SAndroid Build Coastguard Worker         dpy = EGL_NO_DISPLAY;
446*8975f5c5SAndroid Build Coastguard Worker     });
447*8975f5c5SAndroid Build Coastguard Worker     threadB.join();
448*8975f5c5SAndroid Build Coastguard Worker }
449*8975f5c5SAndroid Build Coastguard Worker 
450*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
451*8975f5c5SAndroid Build Coastguard Worker // that.  Note that only validatity of the fence operations are tested here.  The test could
452*8975f5c5SAndroid Build Coastguard Worker // potentially be enhanced with EGL images similarly to how
453*8975f5c5SAndroid Build Coastguard Worker // MultithreadingTestES3::testFenceWithOpenRenderPass tests correctness of synchronization through
454*8975f5c5SAndroid Build Coastguard Worker // a shared texture.
testFenceWithOpenRenderPass(FenceTest test,FlushMethod flushMethod)455*8975f5c5SAndroid Build Coastguard Worker void EGLMultiContextTest::testFenceWithOpenRenderPass(FenceTest test, FlushMethod flushMethod)
456*8975f5c5SAndroid Build Coastguard Worker {
457*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
458*8975f5c5SAndroid Build Coastguard Worker 
459*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kWidth  = 100;
460*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kHeight = 200;
461*8975f5c5SAndroid Build Coastguard Worker 
462*8975f5c5SAndroid Build Coastguard Worker     EGLSyncKHR sync = EGL_NO_SYNC_KHR;
463*8975f5c5SAndroid Build Coastguard Worker 
464*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
465*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
466*8975f5c5SAndroid Build Coastguard Worker 
467*8975f5c5SAndroid Build Coastguard Worker     enum class Step
468*8975f5c5SAndroid Build Coastguard Worker     {
469*8975f5c5SAndroid Build Coastguard Worker         Start,
470*8975f5c5SAndroid Build Coastguard Worker         Thread0CreateFence,
471*8975f5c5SAndroid Build Coastguard Worker         Thread1WaitFence,
472*8975f5c5SAndroid Build Coastguard Worker         Finish,
473*8975f5c5SAndroid Build Coastguard Worker         Abort,
474*8975f5c5SAndroid Build Coastguard Worker     };
475*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
476*8975f5c5SAndroid Build Coastguard Worker 
477*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
478*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
479*8975f5c5SAndroid Build Coastguard Worker 
480*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
481*8975f5c5SAndroid Build Coastguard Worker 
482*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
483*8975f5c5SAndroid Build Coastguard Worker 
484*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw
485*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
486*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
487*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
488*8975f5c5SAndroid Build Coastguard Worker 
489*8975f5c5SAndroid Build Coastguard Worker         // Issue a fence.  A render pass is currently open, but it should be closed in the Vulkan
490*8975f5c5SAndroid Build Coastguard Worker         // backend.
491*8975f5c5SAndroid Build Coastguard Worker         sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
492*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(sync, EGL_NO_SYNC_KHR);
493*8975f5c5SAndroid Build Coastguard Worker 
494*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 1 to wait on it.
495*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreateFence);
496*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1WaitFence));
497*8975f5c5SAndroid Build Coastguard Worker 
498*8975f5c5SAndroid Build Coastguard Worker         // Wait a little to give thread 1 time to wait on the sync object before flushing it.
499*8975f5c5SAndroid Build Coastguard Worker         angle::Sleep(500);
500*8975f5c5SAndroid Build Coastguard Worker         switch (flushMethod)
501*8975f5c5SAndroid Build Coastguard Worker         {
502*8975f5c5SAndroid Build Coastguard Worker             case FlushMethod::Flush:
503*8975f5c5SAndroid Build Coastguard Worker                 glFlush();
504*8975f5c5SAndroid Build Coastguard Worker                 break;
505*8975f5c5SAndroid Build Coastguard Worker             case FlushMethod::Finish:
506*8975f5c5SAndroid Build Coastguard Worker                 glFinish();
507*8975f5c5SAndroid Build Coastguard Worker                 break;
508*8975f5c5SAndroid Build Coastguard Worker         }
509*8975f5c5SAndroid Build Coastguard Worker 
510*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
511*8975f5c5SAndroid Build Coastguard Worker 
512*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
513*8975f5c5SAndroid Build Coastguard Worker 
514*8975f5c5SAndroid Build Coastguard Worker         // Clean up
515*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
516*8975f5c5SAndroid Build Coastguard Worker     };
517*8975f5c5SAndroid Build Coastguard Worker 
518*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
519*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
520*8975f5c5SAndroid Build Coastguard Worker 
521*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
522*8975f5c5SAndroid Build Coastguard Worker 
523*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to create the fence object.
524*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreateFence));
525*8975f5c5SAndroid Build Coastguard Worker 
526*8975f5c5SAndroid Build Coastguard Worker         // Test access to the fence object
527*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1WaitFence);
528*8975f5c5SAndroid Build Coastguard Worker 
529*8975f5c5SAndroid Build Coastguard Worker         constexpr GLuint64 kTimeout = 2'000'000'000;  // 2 seconds
530*8975f5c5SAndroid Build Coastguard Worker         EGLint result               = EGL_CONDITION_SATISFIED_KHR;
531*8975f5c5SAndroid Build Coastguard Worker         switch (test)
532*8975f5c5SAndroid Build Coastguard Worker         {
533*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::ClientWait:
534*8975f5c5SAndroid Build Coastguard Worker                 result = eglClientWaitSyncKHR(dpy, sync, 0, kTimeout);
535*8975f5c5SAndroid Build Coastguard Worker                 break;
536*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::ServerWait:
537*8975f5c5SAndroid Build Coastguard Worker                 ASSERT_TRUE(eglWaitSyncKHR(dpy, sync, 0));
538*8975f5c5SAndroid Build Coastguard Worker                 break;
539*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::GetStatus:
540*8975f5c5SAndroid Build Coastguard Worker             {
541*8975f5c5SAndroid Build Coastguard Worker                 EGLint value;
542*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_TRUE(eglGetSyncAttribKHR(dpy, sync, EGL_SYNC_STATUS_KHR, &value));
543*8975f5c5SAndroid Build Coastguard Worker                 if (value != EGL_SIGNALED_KHR)
544*8975f5c5SAndroid Build Coastguard Worker                 {
545*8975f5c5SAndroid Build Coastguard Worker                     result = eglClientWaitSyncKHR(dpy, sync, 0, kTimeout);
546*8975f5c5SAndroid Build Coastguard Worker                 }
547*8975f5c5SAndroid Build Coastguard Worker                 break;
548*8975f5c5SAndroid Build Coastguard Worker             }
549*8975f5c5SAndroid Build Coastguard Worker         }
550*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(result == EGL_CONDITION_SATISFIED_KHR);
551*8975f5c5SAndroid Build Coastguard Worker 
552*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw
553*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
554*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
555*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
556*8975f5c5SAndroid Build Coastguard Worker 
557*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
558*8975f5c5SAndroid Build Coastguard Worker 
559*8975f5c5SAndroid Build Coastguard Worker         // Clean up
560*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
561*8975f5c5SAndroid Build Coastguard Worker 
562*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
563*8975f5c5SAndroid Build Coastguard Worker     };
564*8975f5c5SAndroid Build Coastguard Worker 
565*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
566*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
567*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
568*8975f5c5SAndroid Build Coastguard Worker     };
569*8975f5c5SAndroid Build Coastguard Worker 
570*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
571*8975f5c5SAndroid Build Coastguard Worker 
572*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
573*8975f5c5SAndroid Build Coastguard Worker }
574*8975f5c5SAndroid Build Coastguard Worker 
575*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
576*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBClientWaitBeforeThreadASyncFlush)577*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBClientWaitBeforeThreadASyncFlush)
578*8975f5c5SAndroid Build Coastguard Worker {
579*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ClientWait, FlushMethod::Flush);
580*8975f5c5SAndroid Build Coastguard Worker }
581*8975f5c5SAndroid Build Coastguard Worker 
582*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
583*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBServerWaitBeforeThreadASyncFlush)584*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBServerWaitBeforeThreadASyncFlush)
585*8975f5c5SAndroid Build Coastguard Worker {
586*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ServerWait, FlushMethod::Flush);
587*8975f5c5SAndroid Build Coastguard Worker }
588*8975f5c5SAndroid Build Coastguard Worker 
589*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
590*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBGetStatusBeforeThreadASyncFlush)591*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBGetStatusBeforeThreadASyncFlush)
592*8975f5c5SAndroid Build Coastguard Worker {
593*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::GetStatus, FlushMethod::Flush);
594*8975f5c5SAndroid Build Coastguard Worker }
595*8975f5c5SAndroid Build Coastguard Worker 
596*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
597*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBClientWaitBeforeThreadASyncFinish)598*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBClientWaitBeforeThreadASyncFinish)
599*8975f5c5SAndroid Build Coastguard Worker {
600*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ClientWait, FlushMethod::Finish);
601*8975f5c5SAndroid Build Coastguard Worker }
602*8975f5c5SAndroid Build Coastguard Worker 
603*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
604*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBServerWaitBeforeThreadASyncFinish)605*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBServerWaitBeforeThreadASyncFinish)
606*8975f5c5SAndroid Build Coastguard Worker {
607*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ServerWait, FlushMethod::Finish);
608*8975f5c5SAndroid Build Coastguard Worker }
609*8975f5c5SAndroid Build Coastguard Worker 
610*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
611*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(EGLMultiContextTest,ThreadBGetStatusBeforeThreadASyncFinish)612*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBGetStatusBeforeThreadASyncFinish)
613*8975f5c5SAndroid Build Coastguard Worker {
614*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::GetStatus, FlushMethod::Finish);
615*8975f5c5SAndroid Build Coastguard Worker }
616*8975f5c5SAndroid Build Coastguard Worker 
617*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can submit while three other threads are waiting for GPU to finish.
TEST_P(EGLMultiContextTest,ThreadBCanSubmitWhileThreadAWaiting)618*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, ThreadBCanSubmitWhileThreadAWaiting)
619*8975f5c5SAndroid Build Coastguard Worker {
620*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
621*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
622*8975f5c5SAndroid Build Coastguard Worker 
623*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kWidth  = 100;
624*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kHeight = 200;
625*8975f5c5SAndroid Build Coastguard Worker 
626*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
627*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
628*8975f5c5SAndroid Build Coastguard Worker 
629*8975f5c5SAndroid Build Coastguard Worker     enum class Step
630*8975f5c5SAndroid Build Coastguard Worker     {
631*8975f5c5SAndroid Build Coastguard Worker         Start,
632*8975f5c5SAndroid Build Coastguard Worker         ThreadAMapBufferBufferRange,
633*8975f5c5SAndroid Build Coastguard Worker         ThreadBSubmit,
634*8975f5c5SAndroid Build Coastguard Worker         Finish,
635*8975f5c5SAndroid Build Coastguard Worker         Abort,
636*8975f5c5SAndroid Build Coastguard Worker     };
637*8975f5c5SAndroid Build Coastguard Worker 
638*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
639*8975f5c5SAndroid Build Coastguard Worker     std::atomic<size_t> threadCountMakingMapBufferCall(0);
640*8975f5c5SAndroid Build Coastguard Worker     std::atomic<size_t> threadCountFinishedMapBufferCall(0);
641*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kMaxThreadCountMakingMapBufferCall = 3;
642*8975f5c5SAndroid Build Coastguard Worker     auto threadA = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
643*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
644*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
645*8975f5c5SAndroid Build Coastguard Worker 
646*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
647*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw
648*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
649*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
650*8975f5c5SAndroid Build Coastguard Worker         // Issue a compute shader write to a buffer
651*8975f5c5SAndroid Build Coastguard Worker         constexpr char kCS[] = R"(#version 310 es
652*8975f5c5SAndroid Build Coastguard Worker                                 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
653*8975f5c5SAndroid Build Coastguard Worker                                 layout(std140, binding = 0) buffer block {
654*8975f5c5SAndroid Build Coastguard Worker                                     uvec4 data;
655*8975f5c5SAndroid Build Coastguard Worker                                 } outBlock;
656*8975f5c5SAndroid Build Coastguard Worker                                 void main()
657*8975f5c5SAndroid Build Coastguard Worker                                 {
658*8975f5c5SAndroid Build Coastguard Worker                                     outBlock.data += uvec4(1);
659*8975f5c5SAndroid Build Coastguard Worker                                 })";
660*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_COMPUTE_PROGRAM(computeProgram, kCS);
661*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(computeProgram);
662*8975f5c5SAndroid Build Coastguard Worker         constexpr std::array<uint32_t, 4> kInitData = {};
663*8975f5c5SAndroid Build Coastguard Worker         GLBuffer coherentBuffer;
664*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
665*8975f5c5SAndroid Build Coastguard Worker         glBufferStorageEXT(GL_SHADER_STORAGE_BUFFER, sizeof(kInitData), kInitData.data(),
666*8975f5c5SAndroid Build Coastguard Worker                            GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT |
667*8975f5c5SAndroid Build Coastguard Worker                                GL_MAP_COHERENT_BIT_EXT);
668*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, coherentBuffer);
669*8975f5c5SAndroid Build Coastguard Worker         glDispatchCompute(100, 100, 100);
670*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
671*8975f5c5SAndroid Build Coastguard Worker 
672*8975f5c5SAndroid Build Coastguard Worker         // Map the buffers for read. This should trigger driver wait for GPU to finish
673*8975f5c5SAndroid Build Coastguard Worker         glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT);
674*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
675*8975f5c5SAndroid Build Coastguard Worker         if (++threadCountMakingMapBufferCall == kMaxThreadCountMakingMapBufferCall)
676*8975f5c5SAndroid Build Coastguard Worker         {
677*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(Step::ThreadAMapBufferBufferRange);
678*8975f5c5SAndroid Build Coastguard Worker         }
679*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread B to start submit commands.
680*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::ThreadBSubmit));
681*8975f5c5SAndroid Build Coastguard Worker         glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kInitData),
682*8975f5c5SAndroid Build Coastguard Worker                          GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
683*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
684*8975f5c5SAndroid Build Coastguard Worker         ++threadCountFinishedMapBufferCall;
685*8975f5c5SAndroid Build Coastguard Worker 
686*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
687*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
688*8975f5c5SAndroid Build Coastguard Worker         // Clean up
689*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
690*8975f5c5SAndroid Build Coastguard Worker     };
691*8975f5c5SAndroid Build Coastguard Worker 
692*8975f5c5SAndroid Build Coastguard Worker     auto threadB = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
693*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
694*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker         // Prepare for draw and then wait until threadA is ready to wait
697*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
698*8975f5c5SAndroid Build Coastguard Worker         glScissor(0, 0, 1, 1);
699*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::ThreadAMapBufferBufferRange));
700*8975f5c5SAndroid Build Coastguard Worker 
701*8975f5c5SAndroid Build Coastguard Worker         // Test submit in a loop
702*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::ThreadBSubmit);
703*8975f5c5SAndroid Build Coastguard Worker         for (int loop = 0;
704*8975f5c5SAndroid Build Coastguard Worker              loop < 16 && threadCountFinishedMapBufferCall < kMaxThreadCountMakingMapBufferCall;
705*8975f5c5SAndroid Build Coastguard Worker              loop++)
706*8975f5c5SAndroid Build Coastguard Worker         {
707*8975f5c5SAndroid Build Coastguard Worker             drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
708*8975f5c5SAndroid Build Coastguard Worker             glFinish();
709*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
710*8975f5c5SAndroid Build Coastguard Worker         }
711*8975f5c5SAndroid Build Coastguard Worker 
712*8975f5c5SAndroid Build Coastguard Worker         // Clean up
713*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
714*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
715*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
716*8975f5c5SAndroid Build Coastguard Worker     };
717*8975f5c5SAndroid Build Coastguard Worker 
718*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, kMaxThreadCountMakingMapBufferCall + 1> threadFuncs;
719*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < kMaxThreadCountMakingMapBufferCall; i++)
720*8975f5c5SAndroid Build Coastguard Worker     {
721*8975f5c5SAndroid Build Coastguard Worker         threadFuncs[i] = std::move(threadA);
722*8975f5c5SAndroid Build Coastguard Worker     }
723*8975f5c5SAndroid Build Coastguard Worker     threadFuncs[kMaxThreadCountMakingMapBufferCall] = std::move(threadB);
724*8975f5c5SAndroid Build Coastguard Worker 
725*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
726*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
727*8975f5c5SAndroid Build Coastguard Worker }
728*8975f5c5SAndroid Build Coastguard Worker 
729*8975f5c5SAndroid Build Coastguard Worker // Test that if there are any placeholder objects when the programs don't use any resources
730*8975f5c5SAndroid Build Coastguard Worker // (such as textures), they can correctly be used in non-shared contexts (without causing
731*8975f5c5SAndroid Build Coastguard Worker // double-free).
TEST_P(EGLMultiContextTest,NonSharedContextsReuseDescritorSetLayoutHandle)732*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLMultiContextTest, NonSharedContextsReuseDescritorSetLayoutHandle)
733*8975f5c5SAndroid Build Coastguard Worker {
734*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window   = getEGLWindow();
735*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy      = window->getDisplay();
736*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface  = window->getSurface();
737*8975f5c5SAndroid Build Coastguard Worker     EGLContext context1 = window->createContext(EGL_NO_CONTEXT, nullptr);
738*8975f5c5SAndroid Build Coastguard Worker     EGLContext context2 = window->createContext(EGL_NO_CONTEXT, nullptr);
739*8975f5c5SAndroid Build Coastguard Worker 
740*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context1));
741*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
742*8975f5c5SAndroid Build Coastguard Worker 
743*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
744*8975f5c5SAndroid Build Coastguard Worker     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
745*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
746*8975f5c5SAndroid Build Coastguard Worker 
747*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context2));
748*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
749*8975f5c5SAndroid Build Coastguard Worker 
750*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(program1, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
751*8975f5c5SAndroid Build Coastguard Worker     drawQuad(program1, essl1_shaders::PositionAttrib(), 0.5f);
752*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
753*8975f5c5SAndroid Build Coastguard Worker 
754*8975f5c5SAndroid Build Coastguard Worker     // Cleanup
755*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
756*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context1));
757*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context2));
758*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
759*8975f5c5SAndroid Build Coastguard Worker }
760*8975f5c5SAndroid Build Coastguard Worker 
761*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
762*8975f5c5SAndroid Build Coastguard Worker 
763*8975f5c5SAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLMultiContextTest);
764*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST_ES31(EGLMultiContextTest);
765