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(¤tStep, &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(¤tStep, &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(¤tStep, &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(¤tStep, &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(¤tStep, &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(¤tStep, &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