xref: /aosp_15_r20/external/angle/src/tests/gl_tests/MultithreadingTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2018 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 // MulithreadingTest.cpp : Tests of multithreaded rendering
7*8975f5c5SAndroid Build Coastguard Worker 
8*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/ANGLETest.h"
9*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/MultiThreadSteps.h"
10*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/gl_raii.h"
11*8975f5c5SAndroid Build Coastguard Worker #include "util/EGLWindow.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "util/test_utils.h"
13*8975f5c5SAndroid Build Coastguard Worker 
14*8975f5c5SAndroid Build Coastguard Worker #include <atomic>
15*8975f5c5SAndroid Build Coastguard Worker #include <mutex>
16*8975f5c5SAndroid Build Coastguard Worker #include <thread>
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker namespace angle
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker 
21*8975f5c5SAndroid Build Coastguard Worker class MultithreadingTest : public ANGLETest<>
22*8975f5c5SAndroid Build Coastguard Worker {
23*8975f5c5SAndroid Build Coastguard Worker   public:
24*8975f5c5SAndroid Build Coastguard Worker     static constexpr uint32_t kSize = 512;
25*8975f5c5SAndroid Build Coastguard Worker 
26*8975f5c5SAndroid Build Coastguard Worker   protected:
MultithreadingTest()27*8975f5c5SAndroid Build Coastguard Worker     MultithreadingTest()
28*8975f5c5SAndroid Build Coastguard Worker     {
29*8975f5c5SAndroid Build Coastguard Worker         setWindowWidth(kSize);
30*8975f5c5SAndroid Build Coastguard Worker         setWindowHeight(kSize);
31*8975f5c5SAndroid Build Coastguard Worker         setConfigRedBits(8);
32*8975f5c5SAndroid Build Coastguard Worker         setConfigGreenBits(8);
33*8975f5c5SAndroid Build Coastguard Worker         setConfigBlueBits(8);
34*8975f5c5SAndroid Build Coastguard Worker         setConfigAlphaBits(8);
35*8975f5c5SAndroid Build Coastguard Worker     }
36*8975f5c5SAndroid Build Coastguard Worker 
hasFenceSyncExtension() const37*8975f5c5SAndroid Build Coastguard Worker     bool hasFenceSyncExtension() const
38*8975f5c5SAndroid Build Coastguard Worker     {
39*8975f5c5SAndroid Build Coastguard Worker         return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_fence_sync");
40*8975f5c5SAndroid Build Coastguard Worker     }
hasWaitSyncExtension() const41*8975f5c5SAndroid Build Coastguard Worker     bool hasWaitSyncExtension() const
42*8975f5c5SAndroid Build Coastguard Worker     {
43*8975f5c5SAndroid Build Coastguard Worker         return hasFenceSyncExtension() &&
44*8975f5c5SAndroid Build Coastguard Worker                IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), "EGL_KHR_wait_sync");
45*8975f5c5SAndroid Build Coastguard Worker     }
hasGLSyncExtension() const46*8975f5c5SAndroid Build Coastguard Worker     bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); }
47*8975f5c5SAndroid Build Coastguard Worker 
createMultithreadedContext(EGLWindow * window,EGLContext shareCtx)48*8975f5c5SAndroid Build Coastguard Worker     EGLContext createMultithreadedContext(EGLWindow *window, EGLContext shareCtx)
49*8975f5c5SAndroid Build Coastguard Worker     {
50*8975f5c5SAndroid Build Coastguard Worker         EGLint attribs[] = {EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, mVirtualizationGroup++,
51*8975f5c5SAndroid Build Coastguard Worker                             EGL_NONE};
52*8975f5c5SAndroid Build Coastguard Worker         if (!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
53*8975f5c5SAndroid Build Coastguard Worker                                           "EGL_ANGLE_context_virtualization"))
54*8975f5c5SAndroid Build Coastguard Worker         {
55*8975f5c5SAndroid Build Coastguard Worker             attribs[0] = EGL_NONE;
56*8975f5c5SAndroid Build Coastguard Worker         }
57*8975f5c5SAndroid Build Coastguard Worker 
58*8975f5c5SAndroid Build Coastguard Worker         return window->createContext(shareCtx, attribs);
59*8975f5c5SAndroid Build Coastguard Worker     }
60*8975f5c5SAndroid Build Coastguard Worker 
runMultithreadedGLTest(std::function<void (EGLSurface surface,size_t threadIndex)> testBody,size_t threadCount)61*8975f5c5SAndroid Build Coastguard Worker     void runMultithreadedGLTest(
62*8975f5c5SAndroid Build Coastguard Worker         std::function<void(EGLSurface surface, size_t threadIndex)> testBody,
63*8975f5c5SAndroid Build Coastguard Worker         size_t threadCount)
64*8975f5c5SAndroid Build Coastguard Worker     {
65*8975f5c5SAndroid Build Coastguard Worker         std::mutex mutex;
66*8975f5c5SAndroid Build Coastguard Worker 
67*8975f5c5SAndroid Build Coastguard Worker         EGLWindow *window = getEGLWindow();
68*8975f5c5SAndroid Build Coastguard Worker         EGLDisplay dpy    = window->getDisplay();
69*8975f5c5SAndroid Build Coastguard Worker         EGLConfig config  = window->getConfig();
70*8975f5c5SAndroid Build Coastguard Worker 
71*8975f5c5SAndroid Build Coastguard Worker         constexpr EGLint kPBufferSize = 256;
72*8975f5c5SAndroid Build Coastguard Worker 
73*8975f5c5SAndroid Build Coastguard Worker         std::vector<std::thread> threads(threadCount);
74*8975f5c5SAndroid Build Coastguard Worker         for (size_t threadIdx = 0; threadIdx < threadCount; threadIdx++)
75*8975f5c5SAndroid Build Coastguard Worker         {
76*8975f5c5SAndroid Build Coastguard Worker             threads[threadIdx] = std::thread([&, threadIdx]() {
77*8975f5c5SAndroid Build Coastguard Worker                 EGLSurface surface = EGL_NO_SURFACE;
78*8975f5c5SAndroid Build Coastguard Worker                 EGLContext ctx     = EGL_NO_CONTEXT;
79*8975f5c5SAndroid Build Coastguard Worker 
80*8975f5c5SAndroid Build Coastguard Worker                 {
81*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
82*8975f5c5SAndroid Build Coastguard Worker 
83*8975f5c5SAndroid Build Coastguard Worker                     // Initialize the pbuffer and context
84*8975f5c5SAndroid Build Coastguard Worker                     EGLint pbufferAttributes[] = {
85*8975f5c5SAndroid Build Coastguard Worker                         EGL_WIDTH, kPBufferSize, EGL_HEIGHT, kPBufferSize, EGL_NONE, EGL_NONE,
86*8975f5c5SAndroid Build Coastguard Worker                     };
87*8975f5c5SAndroid Build Coastguard Worker                     surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
88*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_EGL_SUCCESS();
89*8975f5c5SAndroid Build Coastguard Worker 
90*8975f5c5SAndroid Build Coastguard Worker                     ctx = createMultithreadedContext(window, EGL_NO_CONTEXT);
91*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_NE(EGL_NO_CONTEXT, ctx);
92*8975f5c5SAndroid Build Coastguard Worker 
93*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
94*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_EGL_SUCCESS();
95*8975f5c5SAndroid Build Coastguard Worker                 }
96*8975f5c5SAndroid Build Coastguard Worker 
97*8975f5c5SAndroid Build Coastguard Worker                 testBody(surface, threadIdx);
98*8975f5c5SAndroid Build Coastguard Worker 
99*8975f5c5SAndroid Build Coastguard Worker                 {
100*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
101*8975f5c5SAndroid Build Coastguard Worker 
102*8975f5c5SAndroid Build Coastguard Worker                     // Clean up
103*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_EGL_TRUE(
104*8975f5c5SAndroid Build Coastguard Worker                         eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
105*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_EGL_SUCCESS();
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker                     eglDestroySurface(dpy, surface);
108*8975f5c5SAndroid Build Coastguard Worker                     eglDestroyContext(dpy, ctx);
109*8975f5c5SAndroid Build Coastguard Worker                 }
110*8975f5c5SAndroid Build Coastguard Worker             });
111*8975f5c5SAndroid Build Coastguard Worker         }
112*8975f5c5SAndroid Build Coastguard Worker 
113*8975f5c5SAndroid Build Coastguard Worker         for (std::thread &thread : threads)
114*8975f5c5SAndroid Build Coastguard Worker         {
115*8975f5c5SAndroid Build Coastguard Worker             thread.join();
116*8975f5c5SAndroid Build Coastguard Worker         }
117*8975f5c5SAndroid Build Coastguard Worker     }
118*8975f5c5SAndroid Build Coastguard Worker 
119*8975f5c5SAndroid Build Coastguard Worker     std::atomic<EGLint> mVirtualizationGroup;
120*8975f5c5SAndroid Build Coastguard Worker };
121*8975f5c5SAndroid Build Coastguard Worker 
122*8975f5c5SAndroid Build Coastguard Worker class MultithreadingTestES3 : public MultithreadingTest
123*8975f5c5SAndroid Build Coastguard Worker {
124*8975f5c5SAndroid Build Coastguard Worker   public:
125*8975f5c5SAndroid Build Coastguard Worker     void textureThreadFunction(bool useDraw);
126*8975f5c5SAndroid Build Coastguard Worker     void mainThreadDraw(bool useDraw);
127*8975f5c5SAndroid Build Coastguard Worker 
128*8975f5c5SAndroid Build Coastguard Worker   protected:
MultithreadingTestES3()129*8975f5c5SAndroid Build Coastguard Worker     MultithreadingTestES3()
130*8975f5c5SAndroid Build Coastguard Worker         : mTexture2D(0), mExitThread(false), mMainThreadSyncObj(NULL), mSecondThreadSyncObj(NULL)
131*8975f5c5SAndroid Build Coastguard Worker     {
132*8975f5c5SAndroid Build Coastguard Worker         setWindowWidth(kSize);
133*8975f5c5SAndroid Build Coastguard Worker         setWindowHeight(kSize);
134*8975f5c5SAndroid Build Coastguard Worker         setConfigRedBits(8);
135*8975f5c5SAndroid Build Coastguard Worker         setConfigGreenBits(8);
136*8975f5c5SAndroid Build Coastguard Worker         setConfigBlueBits(8);
137*8975f5c5SAndroid Build Coastguard Worker         setConfigAlphaBits(8);
138*8975f5c5SAndroid Build Coastguard Worker     }
139*8975f5c5SAndroid Build Coastguard Worker 
create2DTexture()140*8975f5c5SAndroid Build Coastguard Worker     GLuint create2DTexture()
141*8975f5c5SAndroid Build Coastguard Worker     {
142*8975f5c5SAndroid Build Coastguard Worker         GLuint texture2D;
143*8975f5c5SAndroid Build Coastguard Worker         glGenTextures(1, &texture2D);
144*8975f5c5SAndroid Build Coastguard Worker         glActiveTexture(GL_TEXTURE0);
145*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture2D);
146*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
147*8975f5c5SAndroid Build Coastguard Worker                      nullptr);
148*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
149*8975f5c5SAndroid Build Coastguard Worker         return texture2D;
150*8975f5c5SAndroid Build Coastguard Worker     }
151*8975f5c5SAndroid Build Coastguard Worker 
testSetUp()152*8975f5c5SAndroid Build Coastguard Worker     void testSetUp() override { mTexture2D = create2DTexture(); }
153*8975f5c5SAndroid Build Coastguard Worker 
testTearDown()154*8975f5c5SAndroid Build Coastguard Worker     void testTearDown() override
155*8975f5c5SAndroid Build Coastguard Worker     {
156*8975f5c5SAndroid Build Coastguard Worker         if (mTexture2D)
157*8975f5c5SAndroid Build Coastguard Worker         {
158*8975f5c5SAndroid Build Coastguard Worker             glDeleteTextures(1, &mTexture2D);
159*8975f5c5SAndroid Build Coastguard Worker         }
160*8975f5c5SAndroid Build Coastguard Worker     }
161*8975f5c5SAndroid Build Coastguard Worker 
162*8975f5c5SAndroid Build Coastguard Worker     enum class FenceTest
163*8975f5c5SAndroid Build Coastguard Worker     {
164*8975f5c5SAndroid Build Coastguard Worker         ClientWait,
165*8975f5c5SAndroid Build Coastguard Worker         ServerWait,
166*8975f5c5SAndroid Build Coastguard Worker         GetStatus,
167*8975f5c5SAndroid Build Coastguard Worker     };
168*8975f5c5SAndroid Build Coastguard Worker     enum class FlushMethod
169*8975f5c5SAndroid Build Coastguard Worker     {
170*8975f5c5SAndroid Build Coastguard Worker         Flush,
171*8975f5c5SAndroid Build Coastguard Worker         Finish,
172*8975f5c5SAndroid Build Coastguard Worker     };
173*8975f5c5SAndroid Build Coastguard Worker     void testFenceWithOpenRenderPass(FenceTest test, FlushMethod flushMethod);
174*8975f5c5SAndroid Build Coastguard Worker 
175*8975f5c5SAndroid Build Coastguard Worker     enum class DrawOrder
176*8975f5c5SAndroid Build Coastguard Worker     {
177*8975f5c5SAndroid Build Coastguard Worker         Before,
178*8975f5c5SAndroid Build Coastguard Worker         After,
179*8975f5c5SAndroid Build Coastguard Worker     };
180*8975f5c5SAndroid Build Coastguard Worker     void testFramebufferFetch(DrawOrder drawOrder);
181*8975f5c5SAndroid Build Coastguard Worker 
182*8975f5c5SAndroid Build Coastguard Worker     std::mutex mMutex;
183*8975f5c5SAndroid Build Coastguard Worker     GLuint mTexture2D;
184*8975f5c5SAndroid Build Coastguard Worker     std::atomic<bool> mExitThread;
185*8975f5c5SAndroid Build Coastguard Worker     std::atomic<bool> mDrawGreen;  // Toggle drawing green or red
186*8975f5c5SAndroid Build Coastguard Worker     std::atomic<GLsync> mMainThreadSyncObj;
187*8975f5c5SAndroid Build Coastguard Worker     std::atomic<GLsync> mSecondThreadSyncObj;
188*8975f5c5SAndroid Build Coastguard Worker };
189*8975f5c5SAndroid Build Coastguard Worker 
190*8975f5c5SAndroid Build Coastguard Worker // Test that it's possible to make one context current on different threads
TEST_P(MultithreadingTest,MakeCurrentSingleContext)191*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MakeCurrentSingleContext)
192*8975f5c5SAndroid Build Coastguard Worker {
193*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
194*8975f5c5SAndroid Build Coastguard Worker 
195*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
196*8975f5c5SAndroid Build Coastguard Worker 
197*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window  = getEGLWindow();
198*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy     = window->getDisplay();
199*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx     = window->getContext();
200*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface = window->getSurface();
201*8975f5c5SAndroid Build Coastguard Worker 
202*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
203*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
204*8975f5c5SAndroid Build Coastguard Worker 
205*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount = 16;
206*8975f5c5SAndroid Build Coastguard Worker     std::array<std::thread, kThreadCount> threads;
207*8975f5c5SAndroid Build Coastguard Worker     for (std::thread &thread : threads)
208*8975f5c5SAndroid Build Coastguard Worker     {
209*8975f5c5SAndroid Build Coastguard Worker         thread = std::thread([&]() {
210*8975f5c5SAndroid Build Coastguard Worker             std::lock_guard<decltype(mutex)> lock(mutex);
211*8975f5c5SAndroid Build Coastguard Worker 
212*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
213*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
214*8975f5c5SAndroid Build Coastguard Worker 
215*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglSwapBuffers(dpy, surface));
216*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
217*8975f5c5SAndroid Build Coastguard Worker 
218*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
219*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
220*8975f5c5SAndroid Build Coastguard Worker         });
221*8975f5c5SAndroid Build Coastguard Worker     }
222*8975f5c5SAndroid Build Coastguard Worker 
223*8975f5c5SAndroid Build Coastguard Worker     for (std::thread &thread : threads)
224*8975f5c5SAndroid Build Coastguard Worker     {
225*8975f5c5SAndroid Build Coastguard Worker         thread.join();
226*8975f5c5SAndroid Build Coastguard Worker     }
227*8975f5c5SAndroid Build Coastguard Worker 
228*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
229*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
230*8975f5c5SAndroid Build Coastguard Worker }
231*8975f5c5SAndroid Build Coastguard Worker 
232*8975f5c5SAndroid Build Coastguard Worker // Test that multiple threads can clear and readback pixels successfully at the same time
TEST_P(MultithreadingTest,MultiContextClear)233*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiContextClear)
234*8975f5c5SAndroid Build Coastguard Worker {
235*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
236*8975f5c5SAndroid Build Coastguard Worker 
237*8975f5c5SAndroid Build Coastguard Worker     auto testBody = [](EGLSurface surface, size_t thread) {
238*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kIterationsPerThread = 32;
239*8975f5c5SAndroid Build Coastguard Worker         for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
240*8975f5c5SAndroid Build Coastguard Worker         {
241*8975f5c5SAndroid Build Coastguard Worker             // Base the clear color on the thread and iteration indexes so every clear color is
242*8975f5c5SAndroid Build Coastguard Worker             // unique
243*8975f5c5SAndroid Build Coastguard Worker             const GLColor color(static_cast<GLubyte>(thread % 255),
244*8975f5c5SAndroid Build Coastguard Worker                                 static_cast<GLubyte>(iteration % 255), 0, 255);
245*8975f5c5SAndroid Build Coastguard Worker             const angle::Vector4 floatColor = color.toNormalizedVector();
246*8975f5c5SAndroid Build Coastguard Worker 
247*8975f5c5SAndroid Build Coastguard Worker             glClearColor(floatColor[0], floatColor[1], floatColor[2], floatColor[3]);
248*8975f5c5SAndroid Build Coastguard Worker             EXPECT_GL_NO_ERROR();
249*8975f5c5SAndroid Build Coastguard Worker 
250*8975f5c5SAndroid Build Coastguard Worker             glClear(GL_COLOR_BUFFER_BIT);
251*8975f5c5SAndroid Build Coastguard Worker             EXPECT_GL_NO_ERROR();
252*8975f5c5SAndroid Build Coastguard Worker 
253*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_COLOR_EQ(0, 0, color);
254*8975f5c5SAndroid Build Coastguard Worker         }
255*8975f5c5SAndroid Build Coastguard Worker     };
256*8975f5c5SAndroid Build Coastguard Worker     runMultithreadedGLTest(
257*8975f5c5SAndroid Build Coastguard Worker         testBody,
258*8975f5c5SAndroid Build Coastguard Worker         getEGLWindow()->isFeatureEnabled(Feature::SlowAsyncCommandQueueForTesting) ? 4 : 72);
259*8975f5c5SAndroid Build Coastguard Worker }
260*8975f5c5SAndroid Build Coastguard Worker 
261*8975f5c5SAndroid Build Coastguard Worker // Verify that threads can interleave eglDestroyContext and draw calls without
262*8975f5c5SAndroid Build Coastguard Worker // any crashes.
TEST_P(MultithreadingTest,MultiContextDeleteDraw)263*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiContextDeleteDraw)
264*8975f5c5SAndroid Build Coastguard Worker {
265*8975f5c5SAndroid Build Coastguard Worker     // Skip this test on non-D3D11 backends, as it has the potential to time-out
266*8975f5c5SAndroid Build Coastguard Worker     // and this test was originally intended to catch a crash on the D3D11 backend.
267*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
268*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsD3D11());
269*8975f5c5SAndroid Build Coastguard Worker 
270*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
271*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
272*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
273*8975f5c5SAndroid Build Coastguard Worker 
274*8975f5c5SAndroid Build Coastguard Worker     std::thread t1 = std::thread([&]() {
275*8975f5c5SAndroid Build Coastguard Worker         // 5000 is chosen here as it reliably reproduces the former crash.
276*8975f5c5SAndroid Build Coastguard Worker         for (int i = 0; i < 5000; i++)
277*8975f5c5SAndroid Build Coastguard Worker         {
278*8975f5c5SAndroid Build Coastguard Worker             EGLContext ctx1 = createMultithreadedContext(window, EGL_NO_CONTEXT);
279*8975f5c5SAndroid Build Coastguard Worker             EGLContext ctx2 = createMultithreadedContext(window, EGL_NO_CONTEXT);
280*8975f5c5SAndroid Build Coastguard Worker 
281*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx2));
282*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx1));
283*8975f5c5SAndroid Build Coastguard Worker 
284*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglDestroyContext(dpy, ctx2));
285*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglDestroyContext(dpy, ctx1));
286*8975f5c5SAndroid Build Coastguard Worker         }
287*8975f5c5SAndroid Build Coastguard Worker     });
288*8975f5c5SAndroid Build Coastguard Worker 
289*8975f5c5SAndroid Build Coastguard Worker     std::thread t2 = std::thread([&]() {
290*8975f5c5SAndroid Build Coastguard Worker         EGLint pbufferAttributes[] = {
291*8975f5c5SAndroid Build Coastguard Worker             EGL_WIDTH, 256, EGL_HEIGHT, 256, EGL_NONE, EGL_NONE,
292*8975f5c5SAndroid Build Coastguard Worker         };
293*8975f5c5SAndroid Build Coastguard Worker 
294*8975f5c5SAndroid Build Coastguard Worker         EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
295*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
296*8975f5c5SAndroid Build Coastguard Worker 
297*8975f5c5SAndroid Build Coastguard Worker         auto ctx = createMultithreadedContext(window, EGL_NO_CONTEXT);
298*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
299*8975f5c5SAndroid Build Coastguard Worker 
300*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kIterationsPerThread = 512;
301*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kDrawsPerIteration   = 512;
302*8975f5c5SAndroid Build Coastguard Worker 
303*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
304*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
305*8975f5c5SAndroid Build Coastguard Worker 
306*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
307*8975f5c5SAndroid Build Coastguard Worker 
308*8975f5c5SAndroid Build Coastguard Worker         auto quadVertices = GetQuadVertices();
309*8975f5c5SAndroid Build Coastguard Worker 
310*8975f5c5SAndroid Build Coastguard Worker         GLBuffer vertexBuffer;
311*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
312*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
313*8975f5c5SAndroid Build Coastguard Worker 
314*8975f5c5SAndroid Build Coastguard Worker         GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
315*8975f5c5SAndroid Build Coastguard Worker         glEnableVertexAttribArray(positionLocation);
316*8975f5c5SAndroid Build Coastguard Worker         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
317*8975f5c5SAndroid Build Coastguard Worker         for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
318*8975f5c5SAndroid Build Coastguard Worker         {
319*8975f5c5SAndroid Build Coastguard Worker             const GLColor color(static_cast<GLubyte>(15151 % 255),
320*8975f5c5SAndroid Build Coastguard Worker                                 static_cast<GLubyte>(iteration % 255), 0, 255);
321*8975f5c5SAndroid Build Coastguard Worker             const angle::Vector4 floatColor = color.toNormalizedVector();
322*8975f5c5SAndroid Build Coastguard Worker             glUniform4fv(colorLocation, 1, floatColor.data());
323*8975f5c5SAndroid Build Coastguard Worker             for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
324*8975f5c5SAndroid Build Coastguard Worker             {
325*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
326*8975f5c5SAndroid Build Coastguard Worker                 glDrawArrays(GL_TRIANGLES, 0, 6);
327*8975f5c5SAndroid Build Coastguard Worker             }
328*8975f5c5SAndroid Build Coastguard Worker         }
329*8975f5c5SAndroid Build Coastguard Worker     });
330*8975f5c5SAndroid Build Coastguard Worker 
331*8975f5c5SAndroid Build Coastguard Worker     t1.join();
332*8975f5c5SAndroid Build Coastguard Worker     t2.join();
333*8975f5c5SAndroid Build Coastguard Worker }
334*8975f5c5SAndroid Build Coastguard Worker 
335*8975f5c5SAndroid Build Coastguard Worker // Test that multiple threads can draw and readback pixels successfully at the same time
TEST_P(MultithreadingTest,MultiContextDraw)336*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiContextDraw)
337*8975f5c5SAndroid Build Coastguard Worker {
338*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
339*8975f5c5SAndroid Build Coastguard Worker 
340*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(isSwiftshader());
341*8975f5c5SAndroid Build Coastguard Worker 
342*8975f5c5SAndroid Build Coastguard Worker     auto testBody = [](EGLSurface surface, size_t thread) {
343*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kIterationsPerThread = 32;
344*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kDrawsPerIteration   = 500;
345*8975f5c5SAndroid Build Coastguard Worker 
346*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
347*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
348*8975f5c5SAndroid Build Coastguard Worker 
349*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
350*8975f5c5SAndroid Build Coastguard Worker 
351*8975f5c5SAndroid Build Coastguard Worker         auto quadVertices = GetQuadVertices();
352*8975f5c5SAndroid Build Coastguard Worker 
353*8975f5c5SAndroid Build Coastguard Worker         GLBuffer vertexBuffer;
354*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
355*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
356*8975f5c5SAndroid Build Coastguard Worker 
357*8975f5c5SAndroid Build Coastguard Worker         GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
358*8975f5c5SAndroid Build Coastguard Worker         glEnableVertexAttribArray(positionLocation);
359*8975f5c5SAndroid Build Coastguard Worker         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
360*8975f5c5SAndroid Build Coastguard Worker 
361*8975f5c5SAndroid Build Coastguard Worker         for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
362*8975f5c5SAndroid Build Coastguard Worker         {
363*8975f5c5SAndroid Build Coastguard Worker             // Base the clear color on the thread and iteration indexes so every clear color is
364*8975f5c5SAndroid Build Coastguard Worker             // unique
365*8975f5c5SAndroid Build Coastguard Worker             const GLColor color(static_cast<GLubyte>(thread % 255),
366*8975f5c5SAndroid Build Coastguard Worker                                 static_cast<GLubyte>(iteration % 255), 0, 255);
367*8975f5c5SAndroid Build Coastguard Worker             const angle::Vector4 floatColor = color.toNormalizedVector();
368*8975f5c5SAndroid Build Coastguard Worker             glUniform4fv(colorLocation, 1, floatColor.data());
369*8975f5c5SAndroid Build Coastguard Worker 
370*8975f5c5SAndroid Build Coastguard Worker             for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
371*8975f5c5SAndroid Build Coastguard Worker             {
372*8975f5c5SAndroid Build Coastguard Worker                 glDrawArrays(GL_TRIANGLES, 0, 6);
373*8975f5c5SAndroid Build Coastguard Worker             }
374*8975f5c5SAndroid Build Coastguard Worker 
375*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_COLOR_EQ(0, 0, color);
376*8975f5c5SAndroid Build Coastguard Worker         }
377*8975f5c5SAndroid Build Coastguard Worker     };
378*8975f5c5SAndroid Build Coastguard Worker     runMultithreadedGLTest(testBody, 4);
379*8975f5c5SAndroid Build Coastguard Worker }
380*8975f5c5SAndroid Build Coastguard Worker 
381*8975f5c5SAndroid Build Coastguard Worker // Test that multiple threads can draw and read back pixels correctly.
382*8975f5c5SAndroid Build Coastguard Worker // Using eglSwapBuffers stresses race conditions around use of QueueSerials.
TEST_P(MultithreadingTest,MultiContextDrawWithSwapBuffers)383*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiContextDrawWithSwapBuffers)
384*8975f5c5SAndroid Build Coastguard Worker {
385*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
386*8975f5c5SAndroid Build Coastguard Worker 
387*8975f5c5SAndroid Build Coastguard Worker     // http://anglebug.com/42263666
388*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
389*8975f5c5SAndroid Build Coastguard Worker 
390*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
391*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
392*8975f5c5SAndroid Build Coastguard Worker 
393*8975f5c5SAndroid Build Coastguard Worker     auto testBody = [dpy](EGLSurface surface, size_t thread) {
394*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kIterationsPerThread = 100;
395*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kDrawsPerIteration   = 10;
396*8975f5c5SAndroid Build Coastguard Worker 
397*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
398*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
399*8975f5c5SAndroid Build Coastguard Worker 
400*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
401*8975f5c5SAndroid Build Coastguard Worker 
402*8975f5c5SAndroid Build Coastguard Worker         auto quadVertices = GetQuadVertices();
403*8975f5c5SAndroid Build Coastguard Worker 
404*8975f5c5SAndroid Build Coastguard Worker         GLBuffer vertexBuffer;
405*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
406*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
407*8975f5c5SAndroid Build Coastguard Worker 
408*8975f5c5SAndroid Build Coastguard Worker         GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
409*8975f5c5SAndroid Build Coastguard Worker         glEnableVertexAttribArray(positionLocation);
410*8975f5c5SAndroid Build Coastguard Worker         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
411*8975f5c5SAndroid Build Coastguard Worker 
412*8975f5c5SAndroid Build Coastguard Worker         for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
413*8975f5c5SAndroid Build Coastguard Worker         {
414*8975f5c5SAndroid Build Coastguard Worker             // Base the clear color on the thread and iteration indexes so every clear color is
415*8975f5c5SAndroid Build Coastguard Worker             // unique
416*8975f5c5SAndroid Build Coastguard Worker             const GLColor color(static_cast<GLubyte>(thread % 255),
417*8975f5c5SAndroid Build Coastguard Worker                                 static_cast<GLubyte>(iteration % 255), 0, 255);
418*8975f5c5SAndroid Build Coastguard Worker             const angle::Vector4 floatColor = color.toNormalizedVector();
419*8975f5c5SAndroid Build Coastguard Worker             glUniform4fv(colorLocation, 1, floatColor.data());
420*8975f5c5SAndroid Build Coastguard Worker 
421*8975f5c5SAndroid Build Coastguard Worker             for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
422*8975f5c5SAndroid Build Coastguard Worker             {
423*8975f5c5SAndroid Build Coastguard Worker                 glDrawArrays(GL_TRIANGLES, 0, 6);
424*8975f5c5SAndroid Build Coastguard Worker             }
425*8975f5c5SAndroid Build Coastguard Worker 
426*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglSwapBuffers(dpy, surface));
427*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
428*8975f5c5SAndroid Build Coastguard Worker 
429*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_COLOR_EQ(0, 0, color);
430*8975f5c5SAndroid Build Coastguard Worker         }
431*8975f5c5SAndroid Build Coastguard Worker     };
432*8975f5c5SAndroid Build Coastguard Worker     runMultithreadedGLTest(
433*8975f5c5SAndroid Build Coastguard Worker         testBody,
434*8975f5c5SAndroid Build Coastguard Worker         getEGLWindow()->isFeatureEnabled(Feature::SlowAsyncCommandQueueForTesting) ? 4 : 32);
435*8975f5c5SAndroid Build Coastguard Worker }
436*8975f5c5SAndroid Build Coastguard Worker 
437*8975f5c5SAndroid Build Coastguard Worker // Test that ANGLE handles multiple threads creating and destroying resources (vertex buffer in this
438*8975f5c5SAndroid Build Coastguard Worker // case).
TEST_P(MultithreadingTest,MultiContextCreateAndDeleteResources)439*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiContextCreateAndDeleteResources)
440*8975f5c5SAndroid Build Coastguard Worker {
441*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
442*8975f5c5SAndroid Build Coastguard Worker 
443*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
444*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
445*8975f5c5SAndroid Build Coastguard Worker 
446*8975f5c5SAndroid Build Coastguard Worker     auto testBody = [dpy](EGLSurface surface, size_t thread) {
447*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kIterationsPerThread = 32;
448*8975f5c5SAndroid Build Coastguard Worker         constexpr size_t kDrawsPerIteration   = 1;
449*8975f5c5SAndroid Build Coastguard Worker 
450*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
451*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
452*8975f5c5SAndroid Build Coastguard Worker 
453*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
454*8975f5c5SAndroid Build Coastguard Worker 
455*8975f5c5SAndroid Build Coastguard Worker         auto quadVertices = GetQuadVertices();
456*8975f5c5SAndroid Build Coastguard Worker 
457*8975f5c5SAndroid Build Coastguard Worker         for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
458*8975f5c5SAndroid Build Coastguard Worker         {
459*8975f5c5SAndroid Build Coastguard Worker             GLBuffer vertexBuffer;
460*8975f5c5SAndroid Build Coastguard Worker             glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
461*8975f5c5SAndroid Build Coastguard Worker             glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(),
462*8975f5c5SAndroid Build Coastguard Worker                          GL_STATIC_DRAW);
463*8975f5c5SAndroid Build Coastguard Worker 
464*8975f5c5SAndroid Build Coastguard Worker             GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
465*8975f5c5SAndroid Build Coastguard Worker             glEnableVertexAttribArray(positionLocation);
466*8975f5c5SAndroid Build Coastguard Worker             glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
467*8975f5c5SAndroid Build Coastguard Worker 
468*8975f5c5SAndroid Build Coastguard Worker             // Base the clear color on the thread and iteration indexes so every clear color is
469*8975f5c5SAndroid Build Coastguard Worker             // unique
470*8975f5c5SAndroid Build Coastguard Worker             const GLColor color(static_cast<GLubyte>(thread % 255),
471*8975f5c5SAndroid Build Coastguard Worker                                 static_cast<GLubyte>(iteration % 255), 0, 255);
472*8975f5c5SAndroid Build Coastguard Worker             const angle::Vector4 floatColor = color.toNormalizedVector();
473*8975f5c5SAndroid Build Coastguard Worker             glUniform4fv(colorLocation, 1, floatColor.data());
474*8975f5c5SAndroid Build Coastguard Worker 
475*8975f5c5SAndroid Build Coastguard Worker             for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
476*8975f5c5SAndroid Build Coastguard Worker             {
477*8975f5c5SAndroid Build Coastguard Worker                 glDrawArrays(GL_TRIANGLES, 0, 6);
478*8975f5c5SAndroid Build Coastguard Worker             }
479*8975f5c5SAndroid Build Coastguard Worker 
480*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglSwapBuffers(dpy, surface));
481*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
482*8975f5c5SAndroid Build Coastguard Worker 
483*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_COLOR_EQ(0, 0, color);
484*8975f5c5SAndroid Build Coastguard Worker         }
485*8975f5c5SAndroid Build Coastguard Worker         glFinish();
486*8975f5c5SAndroid Build Coastguard Worker     };
487*8975f5c5SAndroid Build Coastguard Worker     runMultithreadedGLTest(
488*8975f5c5SAndroid Build Coastguard Worker         testBody,
489*8975f5c5SAndroid Build Coastguard Worker         getEGLWindow()->isFeatureEnabled(Feature::SlowAsyncCommandQueueForTesting) ? 4 : 32);
490*8975f5c5SAndroid Build Coastguard Worker }
491*8975f5c5SAndroid Build Coastguard Worker 
TEST_P(MultithreadingTest,MultiCreateContext)492*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, MultiCreateContext)
493*8975f5c5SAndroid Build Coastguard Worker {
494*8975f5c5SAndroid Build Coastguard Worker     // Supported by CGL, GLX, and WGL (https://anglebug.com/42263324)
495*8975f5c5SAndroid Build Coastguard Worker     // Not supported on Ozone (https://crbug.com/1103009)
496*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!(IsWindows() || IsLinux() || IsMac()) || IsOzone());
497*8975f5c5SAndroid Build Coastguard Worker 
498*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window  = getEGLWindow();
499*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy     = window->getDisplay();
500*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx     = window->getContext();
501*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface = window->getSurface();
502*8975f5c5SAndroid Build Coastguard Worker 
503*8975f5c5SAndroid Build Coastguard Worker     // Un-makeCurrent the test window's context
504*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
505*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
506*8975f5c5SAndroid Build Coastguard Worker 
507*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount = 16;
508*8975f5c5SAndroid Build Coastguard Worker     std::atomic<uint32_t> barrier(0);
509*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::thread> threads(kThreadCount);
510*8975f5c5SAndroid Build Coastguard Worker     std::vector<EGLContext> contexts(kThreadCount);
511*8975f5c5SAndroid Build Coastguard Worker     for (size_t threadIdx = 0; threadIdx < kThreadCount; threadIdx++)
512*8975f5c5SAndroid Build Coastguard Worker     {
513*8975f5c5SAndroid Build Coastguard Worker         threads[threadIdx] = std::thread([&, threadIdx]() {
514*8975f5c5SAndroid Build Coastguard Worker             contexts[threadIdx] = EGL_NO_CONTEXT;
515*8975f5c5SAndroid Build Coastguard Worker             {
516*8975f5c5SAndroid Build Coastguard Worker                 contexts[threadIdx] = createMultithreadedContext(window, EGL_NO_CONTEXT);
517*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_NE(EGL_NO_CONTEXT, contexts[threadIdx]);
518*8975f5c5SAndroid Build Coastguard Worker 
519*8975f5c5SAndroid Build Coastguard Worker                 barrier++;
520*8975f5c5SAndroid Build Coastguard Worker             }
521*8975f5c5SAndroid Build Coastguard Worker 
522*8975f5c5SAndroid Build Coastguard Worker             while (barrier < kThreadCount)
523*8975f5c5SAndroid Build Coastguard Worker             {
524*8975f5c5SAndroid Build Coastguard Worker             }
525*8975f5c5SAndroid Build Coastguard Worker 
526*8975f5c5SAndroid Build Coastguard Worker             {
527*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_TRUE(eglDestroyContext(dpy, contexts[threadIdx]));
528*8975f5c5SAndroid Build Coastguard Worker             }
529*8975f5c5SAndroid Build Coastguard Worker         });
530*8975f5c5SAndroid Build Coastguard Worker     }
531*8975f5c5SAndroid Build Coastguard Worker 
532*8975f5c5SAndroid Build Coastguard Worker     for (std::thread &thread : threads)
533*8975f5c5SAndroid Build Coastguard Worker     {
534*8975f5c5SAndroid Build Coastguard Worker         thread.join();
535*8975f5c5SAndroid Build Coastguard Worker     }
536*8975f5c5SAndroid Build Coastguard Worker 
537*8975f5c5SAndroid Build Coastguard Worker     // Re-make current the test window's context for teardown.
538*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
539*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
540*8975f5c5SAndroid Build Coastguard Worker }
541*8975f5c5SAndroid Build Coastguard Worker 
542*8975f5c5SAndroid Build Coastguard Worker // Create multiple shared context and draw with shared vertex buffer simutanously
TEST_P(MultithreadingTest,CreateMultiSharedContextAndDraw)543*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, CreateMultiSharedContextAndDraw)
544*8975f5c5SAndroid Build Coastguard Worker {
545*8975f5c5SAndroid Build Coastguard Worker     // Supported by CGL, GLX, and WGL (https://anglebug.com/42263324)
546*8975f5c5SAndroid Build Coastguard Worker     // Not supported on Ozone (https://crbug.com/1103009)
547*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!(IsWindows() || IsLinux() || IsMac()) || IsOzone());
548*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window             = getEGLWindow();
549*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy                = window->getDisplay();
550*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config              = window->getConfig();
551*8975f5c5SAndroid Build Coastguard Worker     constexpr EGLint kPBufferSize = 256;
552*8975f5c5SAndroid Build Coastguard Worker 
553*8975f5c5SAndroid Build Coastguard Worker     // Initialize the pbuffer and context
554*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[] = {
555*8975f5c5SAndroid Build Coastguard Worker         EGL_WIDTH, kPBufferSize, EGL_HEIGHT, kPBufferSize, EGL_NONE, EGL_NONE,
556*8975f5c5SAndroid Build Coastguard Worker     };
557*8975f5c5SAndroid Build Coastguard Worker     EGLSurface sharedSurface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
558*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
559*8975f5c5SAndroid Build Coastguard Worker     EGLContext sharedCtx = createMultithreadedContext(window, EGL_NO_CONTEXT);
560*8975f5c5SAndroid Build Coastguard Worker     EXPECT_NE(EGL_NO_CONTEXT, sharedCtx);
561*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, sharedSurface, sharedSurface, sharedCtx));
562*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
563*8975f5c5SAndroid Build Coastguard Worker 
564*8975f5c5SAndroid Build Coastguard Worker     // Create a shared vertextBuffer
565*8975f5c5SAndroid Build Coastguard Worker     auto quadVertices = GetQuadVertices();
566*8975f5c5SAndroid Build Coastguard Worker     GLBuffer sharedVertexBuffer;
567*8975f5c5SAndroid Build Coastguard Worker     glBindBuffer(GL_ARRAY_BUFFER, sharedVertexBuffer);
568*8975f5c5SAndroid Build Coastguard Worker     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
569*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
570*8975f5c5SAndroid Build Coastguard Worker 
571*8975f5c5SAndroid Build Coastguard Worker     // Now draw with the buffer and verify
572*8975f5c5SAndroid Build Coastguard Worker     {
573*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(sharedProgram, essl1_shaders::vs::Simple(),
574*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::UniformColor());
575*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(sharedProgram);
576*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(sharedProgram, essl1_shaders::ColorUniform());
577*8975f5c5SAndroid Build Coastguard Worker         GLint positionLocation =
578*8975f5c5SAndroid Build Coastguard Worker             glGetAttribLocation(sharedProgram, essl1_shaders::PositionAttrib());
579*8975f5c5SAndroid Build Coastguard Worker         glEnableVertexAttribArray(positionLocation);
580*8975f5c5SAndroid Build Coastguard Worker         glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
581*8975f5c5SAndroid Build Coastguard Worker         const GLColor color(0, 0, 0, 255);
582*8975f5c5SAndroid Build Coastguard Worker         const angle::Vector4 floatColor = color.toNormalizedVector();
583*8975f5c5SAndroid Build Coastguard Worker         glUniform4fv(colorLocation, 1, floatColor.data());
584*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLES, 0, 6);
585*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, color);
586*8975f5c5SAndroid Build Coastguard Worker     }
587*8975f5c5SAndroid Build Coastguard Worker 
588*8975f5c5SAndroid Build Coastguard Worker     // Create shared context in their own threads and draw with the shared vertex buffer at the same
589*8975f5c5SAndroid Build Coastguard Worker     // time.
590*8975f5c5SAndroid Build Coastguard Worker     size_t threadCount                    = 16;
591*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kIterationsPerThread = 3;
592*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kDrawsPerIteration   = 50;
593*8975f5c5SAndroid Build Coastguard Worker     std::vector<std::thread> threads(threadCount);
594*8975f5c5SAndroid Build Coastguard Worker     std::atomic<uint32_t> numOfContextsCreated(0);
595*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
596*8975f5c5SAndroid Build Coastguard Worker     for (size_t threadIdx = 0; threadIdx < threadCount; threadIdx++)
597*8975f5c5SAndroid Build Coastguard Worker     {
598*8975f5c5SAndroid Build Coastguard Worker         threads[threadIdx] = std::thread([&, threadIdx]() {
599*8975f5c5SAndroid Build Coastguard Worker             EGLSurface surface = EGL_NO_SURFACE;
600*8975f5c5SAndroid Build Coastguard Worker             EGLContext ctx     = EGL_NO_CONTEXT;
601*8975f5c5SAndroid Build Coastguard Worker 
602*8975f5c5SAndroid Build Coastguard Worker             {
603*8975f5c5SAndroid Build Coastguard Worker                 std::lock_guard<decltype(mutex)> lock(mutex);
604*8975f5c5SAndroid Build Coastguard Worker                 // Initialize the pbuffer and context
605*8975f5c5SAndroid Build Coastguard Worker                 surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
606*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
607*8975f5c5SAndroid Build Coastguard Worker                 ctx = createMultithreadedContext(window, /*EGL_NO_CONTEXT*/ sharedCtx);
608*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_NE(EGL_NO_CONTEXT, ctx);
609*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
610*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
611*8975f5c5SAndroid Build Coastguard Worker                 numOfContextsCreated++;
612*8975f5c5SAndroid Build Coastguard Worker             }
613*8975f5c5SAndroid Build Coastguard Worker 
614*8975f5c5SAndroid Build Coastguard Worker             // Wait for all contexts created.
615*8975f5c5SAndroid Build Coastguard Worker             while (numOfContextsCreated < threadCount)
616*8975f5c5SAndroid Build Coastguard Worker             {
617*8975f5c5SAndroid Build Coastguard Worker             }
618*8975f5c5SAndroid Build Coastguard Worker 
619*8975f5c5SAndroid Build Coastguard Worker             // Now draw with shared vertex buffer
620*8975f5c5SAndroid Build Coastguard Worker             {
621*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(),
622*8975f5c5SAndroid Build Coastguard Worker                                  essl1_shaders::fs::UniformColor());
623*8975f5c5SAndroid Build Coastguard Worker                 glUseProgram(program);
624*8975f5c5SAndroid Build Coastguard Worker 
625*8975f5c5SAndroid Build Coastguard Worker                 GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
626*8975f5c5SAndroid Build Coastguard Worker                 GLint positionLocation =
627*8975f5c5SAndroid Build Coastguard Worker                     glGetAttribLocation(program, essl1_shaders::PositionAttrib());
628*8975f5c5SAndroid Build Coastguard Worker 
629*8975f5c5SAndroid Build Coastguard Worker                 // Use sharedVertexBuffer
630*8975f5c5SAndroid Build Coastguard Worker                 glBindBuffer(GL_ARRAY_BUFFER, sharedVertexBuffer);
631*8975f5c5SAndroid Build Coastguard Worker                 glEnableVertexAttribArray(positionLocation);
632*8975f5c5SAndroid Build Coastguard Worker                 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
633*8975f5c5SAndroid Build Coastguard Worker 
634*8975f5c5SAndroid Build Coastguard Worker                 for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
635*8975f5c5SAndroid Build Coastguard Worker                 {
636*8975f5c5SAndroid Build Coastguard Worker                     // Base the clear color on the thread and iteration indexes so every clear color
637*8975f5c5SAndroid Build Coastguard Worker                     // is unique
638*8975f5c5SAndroid Build Coastguard Worker                     const GLColor color(static_cast<GLubyte>(threadIdx % 255),
639*8975f5c5SAndroid Build Coastguard Worker                                         static_cast<GLubyte>(iteration % 255), 0, 255);
640*8975f5c5SAndroid Build Coastguard Worker                     const angle::Vector4 floatColor = color.toNormalizedVector();
641*8975f5c5SAndroid Build Coastguard Worker                     glUniform4fv(colorLocation, 1, floatColor.data());
642*8975f5c5SAndroid Build Coastguard Worker 
643*8975f5c5SAndroid Build Coastguard Worker                     for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
644*8975f5c5SAndroid Build Coastguard Worker                     {
645*8975f5c5SAndroid Build Coastguard Worker                         glDrawArrays(GL_TRIANGLES, 0, 6);
646*8975f5c5SAndroid Build Coastguard Worker                     }
647*8975f5c5SAndroid Build Coastguard Worker 
648*8975f5c5SAndroid Build Coastguard Worker                     EXPECT_PIXEL_COLOR_EQ(0, 0, color);
649*8975f5c5SAndroid Build Coastguard Worker                 }
650*8975f5c5SAndroid Build Coastguard Worker             }
651*8975f5c5SAndroid Build Coastguard Worker 
652*8975f5c5SAndroid Build Coastguard Worker             // tear down shared context
653*8975f5c5SAndroid Build Coastguard Worker             {
654*8975f5c5SAndroid Build Coastguard Worker                 std::lock_guard<decltype(mutex)> lock(mutex);
655*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_TRUE(
656*8975f5c5SAndroid Build Coastguard Worker                     eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
657*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
658*8975f5c5SAndroid Build Coastguard Worker                 eglDestroySurface(dpy, surface);
659*8975f5c5SAndroid Build Coastguard Worker                 eglDestroyContext(dpy, ctx);
660*8975f5c5SAndroid Build Coastguard Worker             }
661*8975f5c5SAndroid Build Coastguard Worker         });
662*8975f5c5SAndroid Build Coastguard Worker     }
663*8975f5c5SAndroid Build Coastguard Worker 
664*8975f5c5SAndroid Build Coastguard Worker     for (std::thread &thread : threads)
665*8975f5c5SAndroid Build Coastguard Worker     {
666*8975f5c5SAndroid Build Coastguard Worker         thread.join();
667*8975f5c5SAndroid Build Coastguard Worker     }
668*8975f5c5SAndroid Build Coastguard Worker 
669*8975f5c5SAndroid Build Coastguard Worker     eglDestroySurface(dpy, sharedSurface);
670*8975f5c5SAndroid Build Coastguard Worker     eglDestroyContext(dpy, sharedCtx);
671*8975f5c5SAndroid Build Coastguard Worker 
672*8975f5c5SAndroid Build Coastguard Worker     // Re-make current the test window's context for teardown.
673*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(
674*8975f5c5SAndroid Build Coastguard Worker         eglMakeCurrent(dpy, window->getSurface(), window->getSurface(), window->getContext()));
675*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
676*8975f5c5SAndroid Build Coastguard Worker }
677*8975f5c5SAndroid Build Coastguard Worker 
678*8975f5c5SAndroid Build Coastguard Worker // Producer/Consumer test using EGLImages and EGLSyncs
TEST_P(MultithreadingTest,EGLImageProduceConsume)679*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, EGLImageProduceConsume)
680*8975f5c5SAndroid Build Coastguard Worker {
681*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window  = getEGLWindow();
682*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy     = window->getDisplay();
683*8975f5c5SAndroid Build Coastguard Worker     EGLContext rootCtx = window->getContext();
684*8975f5c5SAndroid Build Coastguard Worker 
685*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_image"));
686*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_gl_texture_2D_image"));
687*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_fence_sync"));
688*8975f5c5SAndroid Build Coastguard Worker 
689*8975f5c5SAndroid Build Coastguard Worker     struct sharedImage
690*8975f5c5SAndroid Build Coastguard Worker     {
691*8975f5c5SAndroid Build Coastguard Worker         EGLImage image;
692*8975f5c5SAndroid Build Coastguard Worker         EGLSync sync;
693*8975f5c5SAndroid Build Coastguard Worker         GLuint rootTexture;
694*8975f5c5SAndroid Build Coastguard Worker     };
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
697*8975f5c5SAndroid Build Coastguard Worker     std::vector<sharedImage> waitingForProduce;
698*8975f5c5SAndroid Build Coastguard Worker     std::vector<sharedImage> waitingForConsume;
699*8975f5c5SAndroid Build Coastguard Worker 
700*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kNumImages = 10;
701*8975f5c5SAndroid Build Coastguard Worker     for (size_t i = 0; i < kNumImages; i++)
702*8975f5c5SAndroid Build Coastguard Worker     {
703*8975f5c5SAndroid Build Coastguard Worker         GLuint texture;
704*8975f5c5SAndroid Build Coastguard Worker         glGenTextures(1, &texture);
705*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
706*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
707*8975f5c5SAndroid Build Coastguard Worker 
708*8975f5c5SAndroid Build Coastguard Worker         sharedImage img;
709*8975f5c5SAndroid Build Coastguard Worker         img.image       = eglCreateImageKHR(dpy, rootCtx, EGL_GL_TEXTURE_2D_KHR,
710*8975f5c5SAndroid Build Coastguard Worker                                             reinterpret_cast<EGLClientBuffer>(texture), nullptr);
711*8975f5c5SAndroid Build Coastguard Worker         img.sync        = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
712*8975f5c5SAndroid Build Coastguard Worker         img.rootTexture = texture;
713*8975f5c5SAndroid Build Coastguard Worker 
714*8975f5c5SAndroid Build Coastguard Worker         waitingForProduce.push_back(std::move(img));
715*8975f5c5SAndroid Build Coastguard Worker     }
716*8975f5c5SAndroid Build Coastguard Worker 
717*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kIterations = 10000;
718*8975f5c5SAndroid Build Coastguard Worker 
719*8975f5c5SAndroid Build Coastguard Worker     std::thread producerThread([&]() {
720*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx = createMultithreadedContext(window, EGL_NO_CONTEXT);
721*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx));
722*8975f5c5SAndroid Build Coastguard Worker 
723*8975f5c5SAndroid Build Coastguard Worker         {
724*8975f5c5SAndroid Build Coastguard Worker             ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(),
725*8975f5c5SAndroid Build Coastguard Worker                              essl1_shaders::fs::UniformColor());
726*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(drawColor);
727*8975f5c5SAndroid Build Coastguard Worker             GLint colorUniformLocation =
728*8975f5c5SAndroid Build Coastguard Worker                 glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform());
729*8975f5c5SAndroid Build Coastguard Worker             ASSERT_NE(colorUniformLocation, -1);
730*8975f5c5SAndroid Build Coastguard Worker 
731*8975f5c5SAndroid Build Coastguard Worker             size_t iteration = 0;
732*8975f5c5SAndroid Build Coastguard Worker             while (iteration < kIterations)
733*8975f5c5SAndroid Build Coastguard Worker             {
734*8975f5c5SAndroid Build Coastguard Worker                 sharedImage img;
735*8975f5c5SAndroid Build Coastguard Worker                 {
736*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
737*8975f5c5SAndroid Build Coastguard Worker                     if (waitingForProduce.empty())
738*8975f5c5SAndroid Build Coastguard Worker                     {
739*8975f5c5SAndroid Build Coastguard Worker                         continue;
740*8975f5c5SAndroid Build Coastguard Worker                     }
741*8975f5c5SAndroid Build Coastguard Worker                     img = std::move(waitingForProduce.back());
742*8975f5c5SAndroid Build Coastguard Worker                     waitingForProduce.pop_back();
743*8975f5c5SAndroid Build Coastguard Worker                 }
744*8975f5c5SAndroid Build Coastguard Worker 
745*8975f5c5SAndroid Build Coastguard Worker                 eglWaitSync(dpy, img.sync, 0);
746*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
747*8975f5c5SAndroid Build Coastguard Worker 
748*8975f5c5SAndroid Build Coastguard Worker                 eglDestroySync(dpy, img.sync);
749*8975f5c5SAndroid Build Coastguard Worker 
750*8975f5c5SAndroid Build Coastguard Worker                 GLTexture texture;
751*8975f5c5SAndroid Build Coastguard Worker                 glBindTexture(GL_TEXTURE_2D, texture);
752*8975f5c5SAndroid Build Coastguard Worker                 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img.image);
753*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_GL_NO_ERROR();
754*8975f5c5SAndroid Build Coastguard Worker 
755*8975f5c5SAndroid Build Coastguard Worker                 GLFramebuffer fbo;
756*8975f5c5SAndroid Build Coastguard Worker                 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
757*8975f5c5SAndroid Build Coastguard Worker                 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
758*8975f5c5SAndroid Build Coastguard Worker                                        0);
759*8975f5c5SAndroid Build Coastguard Worker 
760*8975f5c5SAndroid Build Coastguard Worker                 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
761*8975f5c5SAndroid Build Coastguard Worker                 glClear(GL_COLOR_BUFFER_BIT);
762*8975f5c5SAndroid Build Coastguard Worker 
763*8975f5c5SAndroid Build Coastguard Worker                 glUniform4f(colorUniformLocation, float(iteration) / kIterations, 0.0f, 0.0f, 1.0f);
764*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0);
765*8975f5c5SAndroid Build Coastguard Worker 
766*8975f5c5SAndroid Build Coastguard Worker                 glBindTexture(GL_TEXTURE_2D, 0);
767*8975f5c5SAndroid Build Coastguard Worker                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
768*8975f5c5SAndroid Build Coastguard Worker 
769*8975f5c5SAndroid Build Coastguard Worker                 img.sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
770*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
771*8975f5c5SAndroid Build Coastguard Worker                 glFlush();
772*8975f5c5SAndroid Build Coastguard Worker 
773*8975f5c5SAndroid Build Coastguard Worker                 {
774*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
775*8975f5c5SAndroid Build Coastguard Worker                     waitingForConsume.insert(waitingForConsume.begin(), std::move(img));
776*8975f5c5SAndroid Build Coastguard Worker                 }
777*8975f5c5SAndroid Build Coastguard Worker 
778*8975f5c5SAndroid Build Coastguard Worker                 iteration++;
779*8975f5c5SAndroid Build Coastguard Worker             }
780*8975f5c5SAndroid Build Coastguard Worker         }
781*8975f5c5SAndroid Build Coastguard Worker 
782*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx);
783*8975f5c5SAndroid Build Coastguard Worker     });
784*8975f5c5SAndroid Build Coastguard Worker 
785*8975f5c5SAndroid Build Coastguard Worker     std::thread consumerThread([&]() {
786*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx = createMultithreadedContext(window, EGL_NO_CONTEXT);
787*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx));
788*8975f5c5SAndroid Build Coastguard Worker 
789*8975f5c5SAndroid Build Coastguard Worker         {
790*8975f5c5SAndroid Build Coastguard Worker             ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
791*8975f5c5SAndroid Build Coastguard Worker                              essl1_shaders::fs::Texture2D());
792*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(drawTexture);
793*8975f5c5SAndroid Build Coastguard Worker             GLint textureUniformLocation =
794*8975f5c5SAndroid Build Coastguard Worker                 glGetUniformLocation(drawTexture, angle::essl1_shaders::Texture2DUniform());
795*8975f5c5SAndroid Build Coastguard Worker             ASSERT_NE(textureUniformLocation, -1);
796*8975f5c5SAndroid Build Coastguard Worker             glUniform1i(textureUniformLocation, 0);
797*8975f5c5SAndroid Build Coastguard Worker             glActiveTexture(GL_TEXTURE0);
798*8975f5c5SAndroid Build Coastguard Worker 
799*8975f5c5SAndroid Build Coastguard Worker             GLTexture backbufferTexture;
800*8975f5c5SAndroid Build Coastguard Worker             glBindTexture(GL_TEXTURE_2D, backbufferTexture);
801*8975f5c5SAndroid Build Coastguard Worker             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE,
802*8975f5c5SAndroid Build Coastguard Worker                          nullptr);
803*8975f5c5SAndroid Build Coastguard Worker 
804*8975f5c5SAndroid Build Coastguard Worker             GLFramebuffer fbo;
805*8975f5c5SAndroid Build Coastguard Worker             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
806*8975f5c5SAndroid Build Coastguard Worker             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
807*8975f5c5SAndroid Build Coastguard Worker                                    backbufferTexture, 0);
808*8975f5c5SAndroid Build Coastguard Worker 
809*8975f5c5SAndroid Build Coastguard Worker             size_t iteration = 0;
810*8975f5c5SAndroid Build Coastguard Worker             while (iteration < kIterations)
811*8975f5c5SAndroid Build Coastguard Worker             {
812*8975f5c5SAndroid Build Coastguard Worker                 sharedImage img;
813*8975f5c5SAndroid Build Coastguard Worker                 {
814*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
815*8975f5c5SAndroid Build Coastguard Worker                     if (waitingForConsume.empty())
816*8975f5c5SAndroid Build Coastguard Worker                     {
817*8975f5c5SAndroid Build Coastguard Worker                         continue;
818*8975f5c5SAndroid Build Coastguard Worker                     }
819*8975f5c5SAndroid Build Coastguard Worker                     img = std::move(waitingForConsume.back());
820*8975f5c5SAndroid Build Coastguard Worker                     waitingForConsume.pop_back();
821*8975f5c5SAndroid Build Coastguard Worker                 }
822*8975f5c5SAndroid Build Coastguard Worker 
823*8975f5c5SAndroid Build Coastguard Worker                 eglWaitSync(dpy, img.sync, 0);
824*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
825*8975f5c5SAndroid Build Coastguard Worker                 eglDestroySync(dpy, img.sync);
826*8975f5c5SAndroid Build Coastguard Worker 
827*8975f5c5SAndroid Build Coastguard Worker                 GLTexture texture;
828*8975f5c5SAndroid Build Coastguard Worker                 glBindTexture(GL_TEXTURE_2D, texture);
829*8975f5c5SAndroid Build Coastguard Worker                 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img.image);
830*8975f5c5SAndroid Build Coastguard Worker                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
831*8975f5c5SAndroid Build Coastguard Worker                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
832*8975f5c5SAndroid Build Coastguard Worker 
833*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0);
834*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_GL_NO_ERROR();
835*8975f5c5SAndroid Build Coastguard Worker 
836*8975f5c5SAndroid Build Coastguard Worker                 glBindTexture(GL_TEXTURE_2D, 0);
837*8975f5c5SAndroid Build Coastguard Worker 
838*8975f5c5SAndroid Build Coastguard Worker                 img.sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
839*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_EGL_SUCCESS();
840*8975f5c5SAndroid Build Coastguard Worker                 glFlush();
841*8975f5c5SAndroid Build Coastguard Worker 
842*8975f5c5SAndroid Build Coastguard Worker                 {
843*8975f5c5SAndroid Build Coastguard Worker                     std::lock_guard<decltype(mutex)> lock(mutex);
844*8975f5c5SAndroid Build Coastguard Worker                     waitingForProduce.insert(waitingForProduce.begin(), std::move(img));
845*8975f5c5SAndroid Build Coastguard Worker                 }
846*8975f5c5SAndroid Build Coastguard Worker 
847*8975f5c5SAndroid Build Coastguard Worker                 iteration++;
848*8975f5c5SAndroid Build Coastguard Worker             }
849*8975f5c5SAndroid Build Coastguard Worker         }
850*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx);
851*8975f5c5SAndroid Build Coastguard Worker     });
852*8975f5c5SAndroid Build Coastguard Worker 
853*8975f5c5SAndroid Build Coastguard Worker     producerThread.join();
854*8975f5c5SAndroid Build Coastguard Worker     consumerThread.join();
855*8975f5c5SAndroid Build Coastguard Worker 
856*8975f5c5SAndroid Build Coastguard Worker     // Clean up
857*8975f5c5SAndroid Build Coastguard Worker     {
858*8975f5c5SAndroid Build Coastguard Worker         for (auto &img : waitingForProduce)
859*8975f5c5SAndroid Build Coastguard Worker         {
860*8975f5c5SAndroid Build Coastguard Worker             eglDestroyImageKHR(dpy, img.image);
861*8975f5c5SAndroid Build Coastguard Worker             eglDestroySync(dpy, img.sync);
862*8975f5c5SAndroid Build Coastguard Worker             glDeleteTextures(1, &img.rootTexture);
863*8975f5c5SAndroid Build Coastguard Worker         }
864*8975f5c5SAndroid Build Coastguard Worker         for (auto &img : waitingForConsume)
865*8975f5c5SAndroid Build Coastguard Worker         {
866*8975f5c5SAndroid Build Coastguard Worker             eglDestroyImageKHR(dpy, img.image);
867*8975f5c5SAndroid Build Coastguard Worker             eglDestroySync(dpy, img.sync);
868*8975f5c5SAndroid Build Coastguard Worker             glDeleteTextures(1, &img.rootTexture);
869*8975f5c5SAndroid Build Coastguard Worker         }
870*8975f5c5SAndroid Build Coastguard Worker     }
871*8975f5c5SAndroid Build Coastguard Worker }
872*8975f5c5SAndroid Build Coastguard Worker 
textureThreadFunction(bool useDraw)873*8975f5c5SAndroid Build Coastguard Worker void MultithreadingTestES3::textureThreadFunction(bool useDraw)
874*8975f5c5SAndroid Build Coastguard Worker {
875*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window  = getEGLWindow();
876*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy     = window->getDisplay();
877*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config   = window->getConfig();
878*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface = EGL_NO_SURFACE;
879*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx     = EGL_NO_CONTEXT;
880*8975f5c5SAndroid Build Coastguard Worker 
881*8975f5c5SAndroid Build Coastguard Worker     // Initialize the pbuffer and context
882*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[] = {
883*8975f5c5SAndroid Build Coastguard Worker         EGL_WIDTH, kSize, EGL_HEIGHT, kSize, EGL_NONE, EGL_NONE,
884*8975f5c5SAndroid Build Coastguard Worker     };
885*8975f5c5SAndroid Build Coastguard Worker     surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
886*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
887*8975f5c5SAndroid Build Coastguard Worker     EXPECT_NE(EGL_NO_SURFACE, surface);
888*8975f5c5SAndroid Build Coastguard Worker 
889*8975f5c5SAndroid Build Coastguard Worker     ctx = createMultithreadedContext(window, window->getContext());
890*8975f5c5SAndroid Build Coastguard Worker     EXPECT_NE(EGL_NO_CONTEXT, ctx);
891*8975f5c5SAndroid Build Coastguard Worker 
892*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
893*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
894*8975f5c5SAndroid Build Coastguard Worker 
895*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> greenColor(kSize * kSize, GLColor::green);
896*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> redColor(kSize * kSize, GLColor::red);
897*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
898*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
899*8975f5c5SAndroid Build Coastguard Worker 
900*8975f5c5SAndroid Build Coastguard Worker     glBindTexture(GL_TEXTURE_2D, mTexture2D);
901*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
902*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
903*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
904*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
905*8975f5c5SAndroid Build Coastguard Worker 
906*8975f5c5SAndroid Build Coastguard Worker     GLFramebuffer fbo;
907*8975f5c5SAndroid Build Coastguard Worker     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
908*8975f5c5SAndroid Build Coastguard Worker     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture2D, 0);
909*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
910*8975f5c5SAndroid Build Coastguard Worker 
911*8975f5c5SAndroid Build Coastguard Worker     mSecondThreadSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
912*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
913*8975f5c5SAndroid Build Coastguard Worker 
914*8975f5c5SAndroid Build Coastguard Worker     // Draw something
915*8975f5c5SAndroid Build Coastguard Worker     while (!mExitThread)
916*8975f5c5SAndroid Build Coastguard Worker     {
917*8975f5c5SAndroid Build Coastguard Worker         if (mMainThreadSyncObj == nullptr)
918*8975f5c5SAndroid Build Coastguard Worker         {
919*8975f5c5SAndroid Build Coastguard Worker             angle::Sleep(0);
920*8975f5c5SAndroid Build Coastguard Worker         }
921*8975f5c5SAndroid Build Coastguard Worker 
922*8975f5c5SAndroid Build Coastguard Worker         std::lock_guard<decltype(mMutex)> lock(mMutex);
923*8975f5c5SAndroid Build Coastguard Worker 
924*8975f5c5SAndroid Build Coastguard Worker         if (mMainThreadSyncObj != nullptr)
925*8975f5c5SAndroid Build Coastguard Worker         {
926*8975f5c5SAndroid Build Coastguard Worker             glWaitSync(mMainThreadSyncObj, 0, GL_TIMEOUT_IGNORED);
927*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
928*8975f5c5SAndroid Build Coastguard Worker             glDeleteSync(mMainThreadSyncObj);
929*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
930*8975f5c5SAndroid Build Coastguard Worker             mMainThreadSyncObj = nullptr;
931*8975f5c5SAndroid Build Coastguard Worker         }
932*8975f5c5SAndroid Build Coastguard Worker         else
933*8975f5c5SAndroid Build Coastguard Worker         {
934*8975f5c5SAndroid Build Coastguard Worker             continue;
935*8975f5c5SAndroid Build Coastguard Worker         }
936*8975f5c5SAndroid Build Coastguard Worker 
937*8975f5c5SAndroid Build Coastguard Worker         mDrawGreen = !mDrawGreen;
938*8975f5c5SAndroid Build Coastguard Worker 
939*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, mTexture2D);
940*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
941*8975f5c5SAndroid Build Coastguard Worker 
942*8975f5c5SAndroid Build Coastguard Worker         if (mDrawGreen)
943*8975f5c5SAndroid Build Coastguard Worker         {
944*8975f5c5SAndroid Build Coastguard Worker             if (useDraw)
945*8975f5c5SAndroid Build Coastguard Worker             {
946*8975f5c5SAndroid Build Coastguard Worker                 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
947*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.0f);
948*8975f5c5SAndroid Build Coastguard Worker             }
949*8975f5c5SAndroid Build Coastguard Worker             else
950*8975f5c5SAndroid Build Coastguard Worker             {
951*8975f5c5SAndroid Build Coastguard Worker                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
952*8975f5c5SAndroid Build Coastguard Worker                              greenColor.data());
953*8975f5c5SAndroid Build Coastguard Worker             }
954*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
955*8975f5c5SAndroid Build Coastguard Worker         }
956*8975f5c5SAndroid Build Coastguard Worker         else
957*8975f5c5SAndroid Build Coastguard Worker         {
958*8975f5c5SAndroid Build Coastguard Worker             if (useDraw)
959*8975f5c5SAndroid Build Coastguard Worker             {
960*8975f5c5SAndroid Build Coastguard Worker                 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
961*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.0f);
962*8975f5c5SAndroid Build Coastguard Worker             }
963*8975f5c5SAndroid Build Coastguard Worker             else
964*8975f5c5SAndroid Build Coastguard Worker             {
965*8975f5c5SAndroid Build Coastguard Worker                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
966*8975f5c5SAndroid Build Coastguard Worker                              redColor.data());
967*8975f5c5SAndroid Build Coastguard Worker             }
968*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
969*8975f5c5SAndroid Build Coastguard Worker         }
970*8975f5c5SAndroid Build Coastguard Worker 
971*8975f5c5SAndroid Build Coastguard Worker         ASSERT_EQ(mSecondThreadSyncObj.load(), nullptr);
972*8975f5c5SAndroid Build Coastguard Worker         mSecondThreadSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
973*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
974*8975f5c5SAndroid Build Coastguard Worker     }
975*8975f5c5SAndroid Build Coastguard Worker 
976*8975f5c5SAndroid Build Coastguard Worker     // Clean up
977*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
978*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
979*8975f5c5SAndroid Build Coastguard Worker 
980*8975f5c5SAndroid Build Coastguard Worker     eglDestroySurface(dpy, surface);
981*8975f5c5SAndroid Build Coastguard Worker     eglDestroyContext(dpy, ctx);
982*8975f5c5SAndroid Build Coastguard Worker }
983*8975f5c5SAndroid Build Coastguard Worker 
984*8975f5c5SAndroid Build Coastguard Worker // Test fence sync with multiple threads drawing
mainThreadDraw(bool useDraw)985*8975f5c5SAndroid Build Coastguard Worker void MultithreadingTestES3::mainThreadDraw(bool useDraw)
986*8975f5c5SAndroid Build Coastguard Worker {
987*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window  = getEGLWindow();
988*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy     = window->getDisplay();
989*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx     = window->getContext();
990*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface = window->getSurface();
991*8975f5c5SAndroid Build Coastguard Worker     // Use odd numbers so we bounce between red and green in the final image
992*8975f5c5SAndroid Build Coastguard Worker     constexpr int kNumIterations = 5;
993*8975f5c5SAndroid Build Coastguard Worker     constexpr int kNumDraws      = 5;
994*8975f5c5SAndroid Build Coastguard Worker 
995*8975f5c5SAndroid Build Coastguard Worker     mDrawGreen = false;
996*8975f5c5SAndroid Build Coastguard Worker 
997*8975f5c5SAndroid Build Coastguard Worker     std::thread textureThread(&MultithreadingTestES3::textureThreadFunction, this, true);
998*8975f5c5SAndroid Build Coastguard Worker 
999*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(texProgram, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
1000*8975f5c5SAndroid Build Coastguard Worker 
1001*8975f5c5SAndroid Build Coastguard Worker     for (int iterations = 0; iterations < kNumIterations; ++iterations)
1002*8975f5c5SAndroid Build Coastguard Worker     {
1003*8975f5c5SAndroid Build Coastguard Worker         GLColor expectedDrawColor;
1004*8975f5c5SAndroid Build Coastguard Worker 
1005*8975f5c5SAndroid Build Coastguard Worker         for (int draws = 0; draws < kNumDraws;)
1006*8975f5c5SAndroid Build Coastguard Worker         {
1007*8975f5c5SAndroid Build Coastguard Worker             if (mSecondThreadSyncObj == nullptr)
1008*8975f5c5SAndroid Build Coastguard Worker             {
1009*8975f5c5SAndroid Build Coastguard Worker                 angle::Sleep(0);
1010*8975f5c5SAndroid Build Coastguard Worker             }
1011*8975f5c5SAndroid Build Coastguard Worker 
1012*8975f5c5SAndroid Build Coastguard Worker             std::lock_guard<decltype(mMutex)> lock(mMutex);
1013*8975f5c5SAndroid Build Coastguard Worker 
1014*8975f5c5SAndroid Build Coastguard Worker             if (mSecondThreadSyncObj != nullptr)
1015*8975f5c5SAndroid Build Coastguard Worker             {
1016*8975f5c5SAndroid Build Coastguard Worker                 glWaitSync(mSecondThreadSyncObj, 0, GL_TIMEOUT_IGNORED);
1017*8975f5c5SAndroid Build Coastguard Worker                 ASSERT_GL_NO_ERROR();
1018*8975f5c5SAndroid Build Coastguard Worker                 glDeleteSync(mSecondThreadSyncObj);
1019*8975f5c5SAndroid Build Coastguard Worker                 ASSERT_GL_NO_ERROR();
1020*8975f5c5SAndroid Build Coastguard Worker                 mSecondThreadSyncObj = nullptr;
1021*8975f5c5SAndroid Build Coastguard Worker             }
1022*8975f5c5SAndroid Build Coastguard Worker             else
1023*8975f5c5SAndroid Build Coastguard Worker             {
1024*8975f5c5SAndroid Build Coastguard Worker                 continue;
1025*8975f5c5SAndroid Build Coastguard Worker             }
1026*8975f5c5SAndroid Build Coastguard Worker 
1027*8975f5c5SAndroid Build Coastguard Worker             glBindFramebuffer(GL_FRAMEBUFFER, 0);
1028*8975f5c5SAndroid Build Coastguard Worker             glBindTexture(GL_TEXTURE_2D, mTexture2D);
1029*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(texProgram);
1030*8975f5c5SAndroid Build Coastguard Worker             drawQuad(texProgram, essl1_shaders::PositionAttrib(), 0.0f);
1031*8975f5c5SAndroid Build Coastguard Worker 
1032*8975f5c5SAndroid Build Coastguard Worker             // mDrawGreen will be changed by the background thread past mMainThreadSyncObj
1033*8975f5c5SAndroid Build Coastguard Worker             // as it will start drawing the next color to fbo. This shouldn't affect
1034*8975f5c5SAndroid Build Coastguard Worker             // pixels of the current frame so save the expected color before unblocking the thread
1035*8975f5c5SAndroid Build Coastguard Worker             expectedDrawColor = mDrawGreen ? GLColor::green : GLColor::red;
1036*8975f5c5SAndroid Build Coastguard Worker 
1037*8975f5c5SAndroid Build Coastguard Worker             ASSERT_EQ(mMainThreadSyncObj.load(), nullptr);
1038*8975f5c5SAndroid Build Coastguard Worker             mMainThreadSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1039*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
1040*8975f5c5SAndroid Build Coastguard Worker 
1041*8975f5c5SAndroid Build Coastguard Worker             ++draws;
1042*8975f5c5SAndroid Build Coastguard Worker         }
1043*8975f5c5SAndroid Build Coastguard Worker 
1044*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1045*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kSize, kSize, expectedDrawColor);
1046*8975f5c5SAndroid Build Coastguard Worker 
1047*8975f5c5SAndroid Build Coastguard Worker         swapBuffers();
1048*8975f5c5SAndroid Build Coastguard Worker     }
1049*8975f5c5SAndroid Build Coastguard Worker 
1050*8975f5c5SAndroid Build Coastguard Worker     mExitThread = true;
1051*8975f5c5SAndroid Build Coastguard Worker     textureThread.join();
1052*8975f5c5SAndroid Build Coastguard Worker 
1053*8975f5c5SAndroid Build Coastguard Worker     // Re-make current the test window's context for teardown.
1054*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx));
1055*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
1056*8975f5c5SAndroid Build Coastguard Worker }
1057*8975f5c5SAndroid Build Coastguard Worker 
1058*8975f5c5SAndroid Build Coastguard Worker // Test that glFenceSync/glWaitSync works correctly with multithreading.
1059*8975f5c5SAndroid Build Coastguard Worker // Main thread: Samples from the shared texture to draw to the default FBO.
1060*8975f5c5SAndroid Build Coastguard Worker // Secondary (Texture) thread: Draws to the shared texture, which the Main thread samples from.
1061*8975f5c5SAndroid Build Coastguard Worker // The overall execution flow is:
1062*8975f5c5SAndroid Build Coastguard Worker // Main Thread:
1063*8975f5c5SAndroid Build Coastguard Worker // 1. Wait for the mSecondThreadSyncObj fence object to be created.
1064*8975f5c5SAndroid Build Coastguard Worker //    - This fence object is used by synchronize access to the shared texture by indicating that the
1065*8975f5c5SAndroid Build Coastguard Worker //    Secondary thread's draws to the texture have all completed and it's now safe to sample from
1066*8975f5c5SAndroid Build Coastguard Worker //    it.
1067*8975f5c5SAndroid Build Coastguard Worker // 2. Once the fence is created, add a glWaitSync(mSecondThreadSyncObj) to the command stream and
1068*8975f5c5SAndroid Build Coastguard Worker //    then delete it.
1069*8975f5c5SAndroid Build Coastguard Worker // 3. Draw, sampling from the shared texture.
1070*8975f5c5SAndroid Build Coastguard Worker // 4. Create a new mMainThreadSyncObj.
1071*8975f5c5SAndroid Build Coastguard Worker //    - This fence object is used to synchronize access to the shared texture by indicating that the
1072*8975f5c5SAndroid Build Coastguard Worker //    Main thread's draws are no longer sampling from the texture, so it's now safe for the
1073*8975f5c5SAndroid Build Coastguard Worker //    Secondary thread to draw to it again with a new color.
1074*8975f5c5SAndroid Build Coastguard Worker // Secondary (Texture) Thread:
1075*8975f5c5SAndroid Build Coastguard Worker // 1. Wait for the mMainThreadSyncObj fence object to be created.
1076*8975f5c5SAndroid Build Coastguard Worker // 2. Once the fence is created, add a glWaitSync(mMainThreadSyncObj) to the command stream and then
1077*8975f5c5SAndroid Build Coastguard Worker //    delete it.
1078*8975f5c5SAndroid Build Coastguard Worker // 3. Draw/Fill the texture.
1079*8975f5c5SAndroid Build Coastguard Worker // 4. Create a new mSecondThreadSyncObj.
1080*8975f5c5SAndroid Build Coastguard Worker //
1081*8975f5c5SAndroid Build Coastguard Worker // These threads loop for the specified number of iterations, drawing/sampling the shared texture
1082*8975f5c5SAndroid Build Coastguard Worker // with the necessary glFlush()s and occasional eglSwapBuffers() to mimic a real multithreaded GLES
1083*8975f5c5SAndroid Build Coastguard Worker // application.
TEST_P(MultithreadingTestES3,MultithreadFenceDraw)1084*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, MultithreadFenceDraw)
1085*8975f5c5SAndroid Build Coastguard Worker {
1086*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1087*8975f5c5SAndroid Build Coastguard Worker 
1088*8975f5c5SAndroid Build Coastguard Worker     // Have the secondary thread use glDrawArrays()
1089*8975f5c5SAndroid Build Coastguard Worker     mainThreadDraw(true);
1090*8975f5c5SAndroid Build Coastguard Worker }
1091*8975f5c5SAndroid Build Coastguard Worker 
1092*8975f5c5SAndroid Build Coastguard Worker // Same as MultithreadFenceDraw, but with the secondary thread using glTexImage2D rather than
1093*8975f5c5SAndroid Build Coastguard Worker // glDrawArrays.
TEST_P(MultithreadingTestES3,MultithreadFenceTexImage)1094*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, MultithreadFenceTexImage)
1095*8975f5c5SAndroid Build Coastguard Worker {
1096*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1097*8975f5c5SAndroid Build Coastguard Worker 
1098*8975f5c5SAndroid Build Coastguard Worker     // Have the secondary thread use glTexImage2D()
1099*8975f5c5SAndroid Build Coastguard Worker     mainThreadDraw(false);
1100*8975f5c5SAndroid Build Coastguard Worker }
1101*8975f5c5SAndroid Build Coastguard Worker 
1102*8975f5c5SAndroid Build Coastguard Worker // Test that waiting on a sync object that hasn't been flushed and without a current context returns
1103*8975f5c5SAndroid Build Coastguard Worker // TIMEOUT_EXPIRED or CONDITION_SATISFIED, but doesn't generate an error or crash.
TEST_P(MultithreadingTest,NoFlushNoContextReturnsTimeout)1104*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, NoFlushNoContextReturnsTimeout)
1105*8975f5c5SAndroid Build Coastguard Worker {
1106*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1107*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1108*8975f5c5SAndroid Build Coastguard Worker 
1109*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1110*8975f5c5SAndroid Build Coastguard Worker 
1111*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
1112*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
1113*8975f5c5SAndroid Build Coastguard Worker 
1114*8975f5c5SAndroid Build Coastguard Worker     glClearColor(1.0f, 0.0f, 1.0f, 1.0f);
1115*8975f5c5SAndroid Build Coastguard Worker     glClear(GL_COLOR_BUFFER_BIT);
1116*8975f5c5SAndroid Build Coastguard Worker 
1117*8975f5c5SAndroid Build Coastguard Worker     EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
1118*8975f5c5SAndroid Build Coastguard Worker     EXPECT_NE(sync, EGL_NO_SYNC_KHR);
1119*8975f5c5SAndroid Build Coastguard Worker 
1120*8975f5c5SAndroid Build Coastguard Worker     std::thread thread = std::thread([&]() {
1121*8975f5c5SAndroid Build Coastguard Worker         std::lock_guard<decltype(mutex)> lock(mutex);
1122*8975f5c5SAndroid Build Coastguard Worker         // Make sure there is no active context on this thread.
1123*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1124*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
1125*8975f5c5SAndroid Build Coastguard Worker         // Don't wait forever to make sure the test terminates
1126*8975f5c5SAndroid Build Coastguard Worker         constexpr GLuint64 kTimeout = 1'000'000'000;  // 1 second
1127*8975f5c5SAndroid Build Coastguard Worker         int result                  = eglClientWaitSyncKHR(dpy, sync, 0, kTimeout);
1128*8975f5c5SAndroid Build Coastguard Worker         // We typically expect to get back TIMEOUT_EXPIRED since the sync object was never flushed.
1129*8975f5c5SAndroid Build Coastguard Worker         // However, the OpenGL ES backend returns CONDITION_SATISFIED, which is also a passing
1130*8975f5c5SAndroid Build Coastguard Worker         // result.
1131*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(result == EGL_TIMEOUT_EXPIRED_KHR || result == EGL_CONDITION_SATISFIED_KHR);
1132*8975f5c5SAndroid Build Coastguard Worker     });
1133*8975f5c5SAndroid Build Coastguard Worker 
1134*8975f5c5SAndroid Build Coastguard Worker     thread.join();
1135*8975f5c5SAndroid Build Coastguard Worker 
1136*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroySyncKHR(dpy, sync));
1137*8975f5c5SAndroid Build Coastguard Worker }
1138*8975f5c5SAndroid Build Coastguard Worker 
1139*8975f5c5SAndroid Build Coastguard Worker // Test that waiting on sync object that hasn't been flushed yet, but is later flushed by another
1140*8975f5c5SAndroid Build Coastguard Worker // thread, correctly returns when the fence is signalled without a timeout.
TEST_P(MultithreadingTest,CreateFenceThreadAClientWaitSyncThreadBDelayedFlush)1141*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, CreateFenceThreadAClientWaitSyncThreadBDelayedFlush)
1142*8975f5c5SAndroid Build Coastguard Worker {
1143*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1144*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1145*8975f5c5SAndroid Build Coastguard Worker 
1146*8975f5c5SAndroid Build Coastguard Worker     EGLSyncKHR sync = EGL_NO_SYNC_KHR;
1147*8975f5c5SAndroid Build Coastguard Worker 
1148*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1149*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1150*8975f5c5SAndroid Build Coastguard Worker 
1151*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1152*8975f5c5SAndroid Build Coastguard Worker     {
1153*8975f5c5SAndroid Build Coastguard Worker         Start,
1154*8975f5c5SAndroid Build Coastguard Worker         Thread0Clear,
1155*8975f5c5SAndroid Build Coastguard Worker         Thread1CreateFence,
1156*8975f5c5SAndroid Build Coastguard Worker         Thread0ClientWaitSync,
1157*8975f5c5SAndroid Build Coastguard Worker         Thread1Flush,
1158*8975f5c5SAndroid Build Coastguard Worker         Finish,
1159*8975f5c5SAndroid Build Coastguard Worker         Abort,
1160*8975f5c5SAndroid Build Coastguard Worker     };
1161*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1162*8975f5c5SAndroid Build Coastguard Worker 
1163*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1164*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1165*8975f5c5SAndroid Build Coastguard Worker 
1166*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1167*8975f5c5SAndroid Build Coastguard Worker 
1168*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1169*8975f5c5SAndroid Build Coastguard Worker 
1170*8975f5c5SAndroid Build Coastguard Worker         // Do work.
1171*8975f5c5SAndroid Build Coastguard Worker         glClearColor(1.0, 0.0, 0.0, 1.0);
1172*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
1173*8975f5c5SAndroid Build Coastguard Worker 
1174*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 1 to clear.
1175*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Clear);
1176*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1CreateFence));
1177*8975f5c5SAndroid Build Coastguard Worker 
1178*8975f5c5SAndroid Build Coastguard Worker         // Wait on the sync object, but do *not* flush it, since the other thread will flush.
1179*8975f5c5SAndroid Build Coastguard Worker         constexpr GLuint64 kTimeout = 2'000'000'000;  // 2 seconds
1180*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0ClientWaitSync);
1181*8975f5c5SAndroid Build Coastguard Worker         ASSERT_EQ(EGL_CONDITION_SATISFIED_KHR, eglClientWaitSyncKHR(dpy, sync, 0, kTimeout));
1182*8975f5c5SAndroid Build Coastguard Worker 
1183*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1184*8975f5c5SAndroid Build Coastguard Worker     };
1185*8975f5c5SAndroid Build Coastguard Worker 
1186*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1187*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1188*8975f5c5SAndroid Build Coastguard Worker 
1189*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to clear.
1190*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Clear));
1191*8975f5c5SAndroid Build Coastguard Worker 
1192*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1193*8975f5c5SAndroid Build Coastguard Worker 
1194*8975f5c5SAndroid Build Coastguard Worker         // Do work.
1195*8975f5c5SAndroid Build Coastguard Worker         glClearColor(0.0, 1.0, 0.0, 1.0);
1196*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
1197*8975f5c5SAndroid Build Coastguard Worker 
1198*8975f5c5SAndroid Build Coastguard Worker         sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
1199*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(sync, EGL_NO_SYNC_KHR);
1200*8975f5c5SAndroid Build Coastguard Worker 
1201*8975f5c5SAndroid Build Coastguard Worker         // Wait for the thread 0 to eglClientWaitSyncKHR().
1202*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1CreateFence);
1203*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0ClientWaitSync));
1204*8975f5c5SAndroid Build Coastguard Worker 
1205*8975f5c5SAndroid Build Coastguard Worker         // Wait a little to give thread 1 time to wait on the sync object before flushing it.
1206*8975f5c5SAndroid Build Coastguard Worker         angle::Sleep(500);
1207*8975f5c5SAndroid Build Coastguard Worker         glFlush();
1208*8975f5c5SAndroid Build Coastguard Worker 
1209*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1210*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1211*8975f5c5SAndroid Build Coastguard Worker 
1212*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1213*8975f5c5SAndroid Build Coastguard Worker     };
1214*8975f5c5SAndroid Build Coastguard Worker 
1215*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1216*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1217*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1218*8975f5c5SAndroid Build Coastguard Worker     };
1219*8975f5c5SAndroid Build Coastguard Worker 
1220*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1221*8975f5c5SAndroid Build Coastguard Worker 
1222*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1223*8975f5c5SAndroid Build Coastguard Worker }
1224*8975f5c5SAndroid Build Coastguard Worker 
1225*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1226*8975f5c5SAndroid Build Coastguard Worker // that.
testFenceWithOpenRenderPass(FenceTest test,FlushMethod flushMethod)1227*8975f5c5SAndroid Build Coastguard Worker void MultithreadingTestES3::testFenceWithOpenRenderPass(FenceTest test, FlushMethod flushMethod)
1228*8975f5c5SAndroid Build Coastguard Worker {
1229*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1230*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1231*8975f5c5SAndroid Build Coastguard Worker 
1232*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kWidth  = 100;
1233*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kHeight = 200;
1234*8975f5c5SAndroid Build Coastguard Worker 
1235*8975f5c5SAndroid Build Coastguard Worker     GLsync sync    = 0;
1236*8975f5c5SAndroid Build Coastguard Worker     GLuint texture = 0;
1237*8975f5c5SAndroid Build Coastguard Worker 
1238*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1239*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1240*8975f5c5SAndroid Build Coastguard Worker 
1241*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1242*8975f5c5SAndroid Build Coastguard Worker     {
1243*8975f5c5SAndroid Build Coastguard Worker         Start,
1244*8975f5c5SAndroid Build Coastguard Worker         Thread0CreateFence,
1245*8975f5c5SAndroid Build Coastguard Worker         Thread1WaitFence,
1246*8975f5c5SAndroid Build Coastguard Worker         Thread0Finish,
1247*8975f5c5SAndroid Build Coastguard Worker         Finish,
1248*8975f5c5SAndroid Build Coastguard Worker         Abort,
1249*8975f5c5SAndroid Build Coastguard Worker     };
1250*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1251*8975f5c5SAndroid Build Coastguard Worker 
1252*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1253*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1254*8975f5c5SAndroid Build Coastguard Worker 
1255*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1256*8975f5c5SAndroid Build Coastguard Worker 
1257*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1258*8975f5c5SAndroid Build Coastguard Worker 
1259*8975f5c5SAndroid Build Coastguard Worker         // Create a shared texture to test synchronization
1260*8975f5c5SAndroid Build Coastguard Worker         GLTexture color;
1261*8975f5c5SAndroid Build Coastguard Worker         texture = color;
1262*8975f5c5SAndroid Build Coastguard Worker 
1263*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1264*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kWidth, kHeight);
1265*8975f5c5SAndroid Build Coastguard Worker 
1266*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
1267*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1268*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1269*8975f5c5SAndroid Build Coastguard Worker 
1270*8975f5c5SAndroid Build Coastguard Worker         // Draw to shared texture.
1271*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1272*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
1273*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1274*8975f5c5SAndroid Build Coastguard Worker 
1275*8975f5c5SAndroid Build Coastguard Worker         // Issue a fence.  A render pass is currently open, so the fence is not actually submitted
1276*8975f5c5SAndroid Build Coastguard Worker         // in the Vulkan backend.
1277*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1278*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
1279*8975f5c5SAndroid Build Coastguard Worker 
1280*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 1 to wait on it.
1281*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreateFence);
1282*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1WaitFence));
1283*8975f5c5SAndroid Build Coastguard Worker 
1284*8975f5c5SAndroid Build Coastguard Worker         // Wait a little to give thread 1 time to wait on the sync object before flushing it.
1285*8975f5c5SAndroid Build Coastguard Worker         angle::Sleep(500);
1286*8975f5c5SAndroid Build Coastguard Worker         switch (flushMethod)
1287*8975f5c5SAndroid Build Coastguard Worker         {
1288*8975f5c5SAndroid Build Coastguard Worker             case FlushMethod::Flush:
1289*8975f5c5SAndroid Build Coastguard Worker                 glFlush();
1290*8975f5c5SAndroid Build Coastguard Worker                 break;
1291*8975f5c5SAndroid Build Coastguard Worker             case FlushMethod::Finish:
1292*8975f5c5SAndroid Build Coastguard Worker                 glFinish();
1293*8975f5c5SAndroid Build Coastguard Worker                 break;
1294*8975f5c5SAndroid Build Coastguard Worker         }
1295*8975f5c5SAndroid Build Coastguard Worker 
1296*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1297*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1298*8975f5c5SAndroid Build Coastguard Worker 
1299*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Finish);
1300*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.waitForStep(Step::Finish);
1301*8975f5c5SAndroid Build Coastguard Worker     };
1302*8975f5c5SAndroid Build Coastguard Worker 
1303*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1304*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1305*8975f5c5SAndroid Build Coastguard Worker 
1306*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1307*8975f5c5SAndroid Build Coastguard Worker 
1308*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to create the fence object.
1309*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreateFence));
1310*8975f5c5SAndroid Build Coastguard Worker 
1311*8975f5c5SAndroid Build Coastguard Worker         // Test access to the fence object
1312*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1WaitFence);
1313*8975f5c5SAndroid Build Coastguard Worker 
1314*8975f5c5SAndroid Build Coastguard Worker         constexpr GLuint64 kTimeout = 2'000'000'000;  // 2 seconds
1315*8975f5c5SAndroid Build Coastguard Worker         GLenum result               = GL_CONDITION_SATISFIED;
1316*8975f5c5SAndroid Build Coastguard Worker         switch (test)
1317*8975f5c5SAndroid Build Coastguard Worker         {
1318*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::ClientWait:
1319*8975f5c5SAndroid Build Coastguard Worker                 result = glClientWaitSync(sync, 0, kTimeout);
1320*8975f5c5SAndroid Build Coastguard Worker                 break;
1321*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::ServerWait:
1322*8975f5c5SAndroid Build Coastguard Worker                 glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
1323*8975f5c5SAndroid Build Coastguard Worker                 break;
1324*8975f5c5SAndroid Build Coastguard Worker             case FenceTest::GetStatus:
1325*8975f5c5SAndroid Build Coastguard Worker             {
1326*8975f5c5SAndroid Build Coastguard Worker                 GLint value;
1327*8975f5c5SAndroid Build Coastguard Worker                 glGetSynciv(sync, GL_SYNC_STATUS, 1, nullptr, &value);
1328*8975f5c5SAndroid Build Coastguard Worker                 if (value != GL_SIGNALED)
1329*8975f5c5SAndroid Build Coastguard Worker                 {
1330*8975f5c5SAndroid Build Coastguard Worker                     result = glClientWaitSync(sync, 0, kTimeout);
1331*8975f5c5SAndroid Build Coastguard Worker                 }
1332*8975f5c5SAndroid Build Coastguard Worker                 break;
1333*8975f5c5SAndroid Build Coastguard Worker             }
1334*8975f5c5SAndroid Build Coastguard Worker         }
1335*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(result == GL_CONDITION_SATISFIED || result == GL_ALREADY_SIGNALED);
1336*8975f5c5SAndroid Build Coastguard Worker 
1337*8975f5c5SAndroid Build Coastguard Worker         // Verify the shared texture is drawn to.
1338*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1339*8975f5c5SAndroid Build Coastguard Worker 
1340*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
1341*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1342*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1343*8975f5c5SAndroid Build Coastguard Worker 
1344*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
1345*8975f5c5SAndroid Build Coastguard Worker 
1346*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1347*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1348*8975f5c5SAndroid Build Coastguard Worker 
1349*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Finish));
1350*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1351*8975f5c5SAndroid Build Coastguard Worker     };
1352*8975f5c5SAndroid Build Coastguard Worker 
1353*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1354*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1355*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1356*8975f5c5SAndroid Build Coastguard Worker     };
1357*8975f5c5SAndroid Build Coastguard Worker 
1358*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1359*8975f5c5SAndroid Build Coastguard Worker 
1360*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1361*8975f5c5SAndroid Build Coastguard Worker }
1362*8975f5c5SAndroid Build Coastguard Worker 
1363*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1364*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBClientWaitBeforeThreadASyncFlush)1365*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBClientWaitBeforeThreadASyncFlush)
1366*8975f5c5SAndroid Build Coastguard Worker {
1367*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ClientWait, FlushMethod::Flush);
1368*8975f5c5SAndroid Build Coastguard Worker }
1369*8975f5c5SAndroid Build Coastguard Worker 
1370*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1371*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBServerWaitBeforeThreadASyncFlush)1372*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBServerWaitBeforeThreadASyncFlush)
1373*8975f5c5SAndroid Build Coastguard Worker {
1374*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ServerWait, FlushMethod::Flush);
1375*8975f5c5SAndroid Build Coastguard Worker }
1376*8975f5c5SAndroid Build Coastguard Worker 
1377*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1378*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBGetStatusBeforeThreadASyncFlush)1379*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBGetStatusBeforeThreadASyncFlush)
1380*8975f5c5SAndroid Build Coastguard Worker {
1381*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::GetStatus, FlushMethod::Flush);
1382*8975f5c5SAndroid Build Coastguard Worker }
1383*8975f5c5SAndroid Build Coastguard Worker 
1384*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1385*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBClientWaitBeforeThreadASyncFinish)1386*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBClientWaitBeforeThreadASyncFinish)
1387*8975f5c5SAndroid Build Coastguard Worker {
1388*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ClientWait, FlushMethod::Finish);
1389*8975f5c5SAndroid Build Coastguard Worker }
1390*8975f5c5SAndroid Build Coastguard Worker 
1391*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1392*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBServerWaitBeforeThreadASyncFinish)1393*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBServerWaitBeforeThreadASyncFinish)
1394*8975f5c5SAndroid Build Coastguard Worker {
1395*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::ServerWait, FlushMethod::Finish);
1396*8975f5c5SAndroid Build Coastguard Worker }
1397*8975f5c5SAndroid Build Coastguard Worker 
1398*8975f5c5SAndroid Build Coastguard Worker // Test that thread B can wait on thread A's sync before thread A flushes it, and wakes up after
1399*8975f5c5SAndroid Build Coastguard Worker // that.
TEST_P(MultithreadingTestES3,ThreadBGetStatusBeforeThreadASyncFinish)1400*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadBGetStatusBeforeThreadASyncFinish)
1401*8975f5c5SAndroid Build Coastguard Worker {
1402*8975f5c5SAndroid Build Coastguard Worker     testFenceWithOpenRenderPass(FenceTest::GetStatus, FlushMethod::Finish);
1403*8975f5c5SAndroid Build Coastguard Worker }
1404*8975f5c5SAndroid Build Coastguard Worker 
1405*8975f5c5SAndroid Build Coastguard Worker // Test the following scenario:
1406*8975f5c5SAndroid Build Coastguard Worker //
1407*8975f5c5SAndroid Build Coastguard Worker // - Thread A opens a render pass, and flushes it.  In the Vulkan backend, this may make the flush
1408*8975f5c5SAndroid Build Coastguard Worker //   deferred.
1409*8975f5c5SAndroid Build Coastguard Worker // - Thread B opens a render pass and creates a fence.  In the Vulkan backend, this also defers the
1410*8975f5c5SAndroid Build Coastguard Worker //   flush.
1411*8975f5c5SAndroid Build Coastguard Worker // - Thread C waits on fence
1412*8975f5c5SAndroid Build Coastguard Worker //
1413*8975f5c5SAndroid Build Coastguard Worker // In the Vulkan backend, submission of the fence is implied by thread C's wait, and thread A may
1414*8975f5c5SAndroid Build Coastguard Worker // also be flushed as collateral.  If the fence's serial is updated based on thread A's submission,
1415*8975f5c5SAndroid Build Coastguard Worker // synchronization between B and C would be broken.
TEST_P(MultithreadingTestES3,ThreadCWaitBeforeThreadBSyncFinish)1416*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ThreadCWaitBeforeThreadBSyncFinish)
1417*8975f5c5SAndroid Build Coastguard Worker {
1418*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1419*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1420*8975f5c5SAndroid Build Coastguard Worker 
1421*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kWidth  = 100;
1422*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kHeight = 200;
1423*8975f5c5SAndroid Build Coastguard Worker 
1424*8975f5c5SAndroid Build Coastguard Worker     GLsync sync    = 0;
1425*8975f5c5SAndroid Build Coastguard Worker     GLuint texture = 0;
1426*8975f5c5SAndroid Build Coastguard Worker 
1427*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1428*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1429*8975f5c5SAndroid Build Coastguard Worker 
1430*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1431*8975f5c5SAndroid Build Coastguard Worker     {
1432*8975f5c5SAndroid Build Coastguard Worker         Start,
1433*8975f5c5SAndroid Build Coastguard Worker         Thread0DrawAndFlush,
1434*8975f5c5SAndroid Build Coastguard Worker         Thread1CreateFence,
1435*8975f5c5SAndroid Build Coastguard Worker         Thread2WaitFence,
1436*8975f5c5SAndroid Build Coastguard Worker         Thread2Finished,
1437*8975f5c5SAndroid Build Coastguard Worker         Finish,
1438*8975f5c5SAndroid Build Coastguard Worker         Abort,
1439*8975f5c5SAndroid Build Coastguard Worker     };
1440*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1441*8975f5c5SAndroid Build Coastguard Worker 
1442*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1443*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1444*8975f5c5SAndroid Build Coastguard Worker 
1445*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1446*8975f5c5SAndroid Build Coastguard Worker 
1447*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1448*8975f5c5SAndroid Build Coastguard Worker 
1449*8975f5c5SAndroid Build Coastguard Worker         // Open a render pass and flush it.
1450*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1451*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
1452*8975f5c5SAndroid Build Coastguard Worker         glFlush();
1453*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1454*8975f5c5SAndroid Build Coastguard Worker 
1455*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0DrawAndFlush);
1456*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1457*8975f5c5SAndroid Build Coastguard Worker 
1458*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1459*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1460*8975f5c5SAndroid Build Coastguard Worker     };
1461*8975f5c5SAndroid Build Coastguard Worker 
1462*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1463*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1464*8975f5c5SAndroid Build Coastguard Worker 
1465*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1466*8975f5c5SAndroid Build Coastguard Worker 
1467*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to set up
1468*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0DrawAndFlush));
1469*8975f5c5SAndroid Build Coastguard Worker 
1470*8975f5c5SAndroid Build Coastguard Worker         // Create a shared texture to test synchronization
1471*8975f5c5SAndroid Build Coastguard Worker         GLTexture color;
1472*8975f5c5SAndroid Build Coastguard Worker         texture = color;
1473*8975f5c5SAndroid Build Coastguard Worker 
1474*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1475*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kWidth, kHeight);
1476*8975f5c5SAndroid Build Coastguard Worker 
1477*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
1478*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1479*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1480*8975f5c5SAndroid Build Coastguard Worker 
1481*8975f5c5SAndroid Build Coastguard Worker         // Draw to shared texture.
1482*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1483*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
1484*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1485*8975f5c5SAndroid Build Coastguard Worker 
1486*8975f5c5SAndroid Build Coastguard Worker         // Issue a fence.  A render pass is currently open, so the fence is not actually submitted
1487*8975f5c5SAndroid Build Coastguard Worker         // in the Vulkan backend.
1488*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1489*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
1490*8975f5c5SAndroid Build Coastguard Worker 
1491*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 1 to wait on it.
1492*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1CreateFence);
1493*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread2WaitFence));
1494*8975f5c5SAndroid Build Coastguard Worker 
1495*8975f5c5SAndroid Build Coastguard Worker         // Wait a little to give thread 1 time to wait on the sync object before flushing it.
1496*8975f5c5SAndroid Build Coastguard Worker         angle::Sleep(500);
1497*8975f5c5SAndroid Build Coastguard Worker         glFlush();
1498*8975f5c5SAndroid Build Coastguard Worker 
1499*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1500*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1501*8975f5c5SAndroid Build Coastguard Worker 
1502*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread2Finished);
1503*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1504*8975f5c5SAndroid Build Coastguard Worker     };
1505*8975f5c5SAndroid Build Coastguard Worker 
1506*8975f5c5SAndroid Build Coastguard Worker     auto thread2 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1507*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1508*8975f5c5SAndroid Build Coastguard Worker 
1509*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1510*8975f5c5SAndroid Build Coastguard Worker 
1511*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to create the fence object.
1512*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1CreateFence));
1513*8975f5c5SAndroid Build Coastguard Worker 
1514*8975f5c5SAndroid Build Coastguard Worker         // Test access to the fence object
1515*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread2WaitFence);
1516*8975f5c5SAndroid Build Coastguard Worker 
1517*8975f5c5SAndroid Build Coastguard Worker         constexpr GLuint64 kTimeout = 2'000'000'000;  // 2 seconds
1518*8975f5c5SAndroid Build Coastguard Worker         GLenum result               = glClientWaitSync(sync, 0, kTimeout);
1519*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(result == GL_CONDITION_SATISFIED || result == GL_ALREADY_SIGNALED);
1520*8975f5c5SAndroid Build Coastguard Worker 
1521*8975f5c5SAndroid Build Coastguard Worker         // Verify the shared texture is drawn to.
1522*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1523*8975f5c5SAndroid Build Coastguard Worker 
1524*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
1525*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1526*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1527*8975f5c5SAndroid Build Coastguard Worker 
1528*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
1529*8975f5c5SAndroid Build Coastguard Worker 
1530*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1531*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1532*8975f5c5SAndroid Build Coastguard Worker 
1533*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread2Finished));
1534*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1535*8975f5c5SAndroid Build Coastguard Worker     };
1536*8975f5c5SAndroid Build Coastguard Worker 
1537*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 3> threadFuncs = {
1538*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1539*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1540*8975f5c5SAndroid Build Coastguard Worker         std::move(thread2),
1541*8975f5c5SAndroid Build Coastguard Worker     };
1542*8975f5c5SAndroid Build Coastguard Worker 
1543*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1544*8975f5c5SAndroid Build Coastguard Worker 
1545*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1546*8975f5c5SAndroid Build Coastguard Worker }
1547*8975f5c5SAndroid Build Coastguard Worker 
1548*8975f5c5SAndroid Build Coastguard Worker // Test that having commands recorded but not submitted on one thread using a texture, does not
1549*8975f5c5SAndroid Build Coastguard Worker // interfere with similar commands on another thread using the same texture.  Regression test for a
1550*8975f5c5SAndroid Build Coastguard Worker // bug in the Vulkan backend where the first thread would batch updates to a descriptor set not
1551*8975f5c5SAndroid Build Coastguard Worker // visible to the other thread, while the other thread picks up the (unupdated) descriptor set from
1552*8975f5c5SAndroid Build Coastguard Worker // a shared cache.
TEST_P(MultithreadingTestES3,UnsynchronizedTextureReads)1553*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, UnsynchronizedTextureReads)
1554*8975f5c5SAndroid Build Coastguard Worker {
1555*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1556*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1557*8975f5c5SAndroid Build Coastguard Worker 
1558*8975f5c5SAndroid Build Coastguard Worker     GLsync sync    = 0;
1559*8975f5c5SAndroid Build Coastguard Worker     GLuint texture = 0;
1560*8975f5c5SAndroid Build Coastguard Worker 
1561*8975f5c5SAndroid Build Coastguard Worker     constexpr GLubyte kInitialData[4] = {127, 63, 191, 255};
1562*8975f5c5SAndroid Build Coastguard Worker 
1563*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1564*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1565*8975f5c5SAndroid Build Coastguard Worker 
1566*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1567*8975f5c5SAndroid Build Coastguard Worker     {
1568*8975f5c5SAndroid Build Coastguard Worker         Start,
1569*8975f5c5SAndroid Build Coastguard Worker         Thread0CreateTextureAndDraw,
1570*8975f5c5SAndroid Build Coastguard Worker         Thread1DrawAndFlush,
1571*8975f5c5SAndroid Build Coastguard Worker         Finish,
1572*8975f5c5SAndroid Build Coastguard Worker         Abort,
1573*8975f5c5SAndroid Build Coastguard Worker     };
1574*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1575*8975f5c5SAndroid Build Coastguard Worker 
1576*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1577*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1578*8975f5c5SAndroid Build Coastguard Worker 
1579*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1580*8975f5c5SAndroid Build Coastguard Worker 
1581*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1582*8975f5c5SAndroid Build Coastguard Worker 
1583*8975f5c5SAndroid Build Coastguard Worker         // Create a texture, and record a command that draws into it.
1584*8975f5c5SAndroid Build Coastguard Worker         GLTexture color;
1585*8975f5c5SAndroid Build Coastguard Worker         texture = color;
1586*8975f5c5SAndroid Build Coastguard Worker 
1587*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1588*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1589*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1590*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1591*8975f5c5SAndroid Build Coastguard Worker         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData);
1592*8975f5c5SAndroid Build Coastguard Worker 
1593*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1594*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
1595*8975f5c5SAndroid Build Coastguard Worker 
1596*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1597*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1598*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1599*8975f5c5SAndroid Build Coastguard Worker 
1600*8975f5c5SAndroid Build Coastguard Worker         // Don't flush yet; this leaves the descriptor set updates to the texture pending in the
1601*8975f5c5SAndroid Build Coastguard Worker         // Vulkan backend.
1602*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreateTextureAndDraw);
1603*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1DrawAndFlush));
1604*8975f5c5SAndroid Build Coastguard Worker 
1605*8975f5c5SAndroid Build Coastguard Worker         // Flush after thread 1
1606*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(
1607*8975f5c5SAndroid Build Coastguard Worker             0, 0, GLColor(kInitialData[0], kInitialData[1], kInitialData[2], kInitialData[3]), 1);
1608*8975f5c5SAndroid Build Coastguard Worker 
1609*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1610*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1611*8975f5c5SAndroid Build Coastguard Worker 
1612*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1613*8975f5c5SAndroid Build Coastguard Worker     };
1614*8975f5c5SAndroid Build Coastguard Worker 
1615*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1616*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1617*8975f5c5SAndroid Build Coastguard Worker 
1618*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1619*8975f5c5SAndroid Build Coastguard Worker 
1620*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to set up
1621*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreateTextureAndDraw));
1622*8975f5c5SAndroid Build Coastguard Worker 
1623*8975f5c5SAndroid Build Coastguard Worker         // Synchronize with the texture upload (but not the concurrent read)
1624*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
1625*8975f5c5SAndroid Build Coastguard Worker 
1626*8975f5c5SAndroid Build Coastguard Worker         // Draw with the same texture, in the same way as thread 0.  This ensures that the
1627*8975f5c5SAndroid Build Coastguard Worker         // descriptor sets used in the Vulkan backend are identical.
1628*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1629*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1630*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1631*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1632*8975f5c5SAndroid Build Coastguard Worker 
1633*8975f5c5SAndroid Build Coastguard Worker         // Flush
1634*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(
1635*8975f5c5SAndroid Build Coastguard Worker             0, 0, GLColor(kInitialData[0], kInitialData[1], kInitialData[2], kInitialData[3]), 1);
1636*8975f5c5SAndroid Build Coastguard Worker 
1637*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1DrawAndFlush);
1638*8975f5c5SAndroid Build Coastguard Worker 
1639*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1640*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1641*8975f5c5SAndroid Build Coastguard Worker 
1642*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1643*8975f5c5SAndroid Build Coastguard Worker     };
1644*8975f5c5SAndroid Build Coastguard Worker 
1645*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1646*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1647*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1648*8975f5c5SAndroid Build Coastguard Worker     };
1649*8975f5c5SAndroid Build Coastguard Worker 
1650*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1651*8975f5c5SAndroid Build Coastguard Worker 
1652*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1653*8975f5c5SAndroid Build Coastguard Worker }
1654*8975f5c5SAndroid Build Coastguard Worker 
1655*8975f5c5SAndroid Build Coastguard Worker // Similar to UnsynchronizedTextureReads, but the texture update is done through framebuffer write.
TEST_P(MultithreadingTestES3,UnsynchronizedTextureReads2)1656*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, UnsynchronizedTextureReads2)
1657*8975f5c5SAndroid Build Coastguard Worker {
1658*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1659*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasFenceSyncExtension() || !hasGLSyncExtension());
1660*8975f5c5SAndroid Build Coastguard Worker 
1661*8975f5c5SAndroid Build Coastguard Worker     GLsync sync    = 0;
1662*8975f5c5SAndroid Build Coastguard Worker     GLuint texture = 0;
1663*8975f5c5SAndroid Build Coastguard Worker 
1664*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1665*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1666*8975f5c5SAndroid Build Coastguard Worker 
1667*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1668*8975f5c5SAndroid Build Coastguard Worker     {
1669*8975f5c5SAndroid Build Coastguard Worker         Start,
1670*8975f5c5SAndroid Build Coastguard Worker         Thread0CreateTextureAndDraw,
1671*8975f5c5SAndroid Build Coastguard Worker         Thread1DrawAndFlush,
1672*8975f5c5SAndroid Build Coastguard Worker         Finish,
1673*8975f5c5SAndroid Build Coastguard Worker         Abort,
1674*8975f5c5SAndroid Build Coastguard Worker     };
1675*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1676*8975f5c5SAndroid Build Coastguard Worker 
1677*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1678*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1679*8975f5c5SAndroid Build Coastguard Worker 
1680*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1681*8975f5c5SAndroid Build Coastguard Worker 
1682*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1683*8975f5c5SAndroid Build Coastguard Worker 
1684*8975f5c5SAndroid Build Coastguard Worker         // Create a texture, and record a command that draws into it.
1685*8975f5c5SAndroid Build Coastguard Worker         GLTexture color;
1686*8975f5c5SAndroid Build Coastguard Worker         texture = color;
1687*8975f5c5SAndroid Build Coastguard Worker 
1688*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1689*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1690*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1691*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1692*8975f5c5SAndroid Build Coastguard Worker 
1693*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
1694*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1695*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1696*8975f5c5SAndroid Build Coastguard Worker 
1697*8975f5c5SAndroid Build Coastguard Worker         glClearColor(1, 0, 0, 1);
1698*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
1699*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1700*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1701*8975f5c5SAndroid Build Coastguard Worker 
1702*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1703*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
1704*8975f5c5SAndroid Build Coastguard Worker 
1705*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1706*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1707*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1708*8975f5c5SAndroid Build Coastguard Worker 
1709*8975f5c5SAndroid Build Coastguard Worker         // Don't flush yet; this leaves the descriptor set updates to the texture pending in the
1710*8975f5c5SAndroid Build Coastguard Worker         // Vulkan backend.
1711*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreateTextureAndDraw);
1712*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1DrawAndFlush));
1713*8975f5c5SAndroid Build Coastguard Worker 
1714*8975f5c5SAndroid Build Coastguard Worker         // Flush after thread 1
1715*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1716*8975f5c5SAndroid Build Coastguard Worker 
1717*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1718*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1719*8975f5c5SAndroid Build Coastguard Worker 
1720*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1721*8975f5c5SAndroid Build Coastguard Worker     };
1722*8975f5c5SAndroid Build Coastguard Worker 
1723*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1724*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1725*8975f5c5SAndroid Build Coastguard Worker 
1726*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1727*8975f5c5SAndroid Build Coastguard Worker 
1728*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to set up
1729*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreateTextureAndDraw));
1730*8975f5c5SAndroid Build Coastguard Worker 
1731*8975f5c5SAndroid Build Coastguard Worker         // Synchronize with the texture update (but not the concurrent read)
1732*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
1733*8975f5c5SAndroid Build Coastguard Worker 
1734*8975f5c5SAndroid Build Coastguard Worker         // Draw with the same texture, in the same way as thread 0.  This ensures that the
1735*8975f5c5SAndroid Build Coastguard Worker         // descriptor sets used in the Vulkan backend are identical.
1736*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1737*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1738*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1739*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1740*8975f5c5SAndroid Build Coastguard Worker 
1741*8975f5c5SAndroid Build Coastguard Worker         // Flush
1742*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
1743*8975f5c5SAndroid Build Coastguard Worker 
1744*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1DrawAndFlush);
1745*8975f5c5SAndroid Build Coastguard Worker 
1746*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1747*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1748*8975f5c5SAndroid Build Coastguard Worker 
1749*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1750*8975f5c5SAndroid Build Coastguard Worker     };
1751*8975f5c5SAndroid Build Coastguard Worker 
1752*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1753*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1754*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1755*8975f5c5SAndroid Build Coastguard Worker     };
1756*8975f5c5SAndroid Build Coastguard Worker 
1757*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1758*8975f5c5SAndroid Build Coastguard Worker 
1759*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1760*8975f5c5SAndroid Build Coastguard Worker }
1761*8975f5c5SAndroid Build Coastguard Worker 
1762*8975f5c5SAndroid Build Coastguard Worker // Similar to UnsynchronizedTextureReads, but the texture is used once.  This is because
1763*8975f5c5SAndroid Build Coastguard Worker // UnsynchronizedTextureRead hits a different bug than it intends to test.  This test makes sure the
1764*8975f5c5SAndroid Build Coastguard Worker // image is put in the right layout, by using it together with another texture (i.e. a different
1765*8975f5c5SAndroid Build Coastguard Worker // descriptor set).
TEST_P(MultithreadingTestES3,UnsynchronizedTextureReads3)1766*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, UnsynchronizedTextureReads3)
1767*8975f5c5SAndroid Build Coastguard Worker {
1768*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1769*8975f5c5SAndroid Build Coastguard Worker 
1770*8975f5c5SAndroid Build Coastguard Worker     constexpr GLubyte kInitialData[4] = {127, 63, 191, 255};
1771*8975f5c5SAndroid Build Coastguard Worker 
1772*8975f5c5SAndroid Build Coastguard Worker     GLuint texture = 0;
1773*8975f5c5SAndroid Build Coastguard Worker 
1774*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1775*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1776*8975f5c5SAndroid Build Coastguard Worker 
1777*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1778*8975f5c5SAndroid Build Coastguard Worker     {
1779*8975f5c5SAndroid Build Coastguard Worker         Start,
1780*8975f5c5SAndroid Build Coastguard Worker         Thread0CreateTextureAndDraw,
1781*8975f5c5SAndroid Build Coastguard Worker         Thread1DrawAndFlush,
1782*8975f5c5SAndroid Build Coastguard Worker         Finish,
1783*8975f5c5SAndroid Build Coastguard Worker         Abort,
1784*8975f5c5SAndroid Build Coastguard Worker     };
1785*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1786*8975f5c5SAndroid Build Coastguard Worker 
1787*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1788*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1789*8975f5c5SAndroid Build Coastguard Worker 
1790*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1791*8975f5c5SAndroid Build Coastguard Worker 
1792*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1793*8975f5c5SAndroid Build Coastguard Worker 
1794*8975f5c5SAndroid Build Coastguard Worker         // Create a texture, and record a command that draws into it.
1795*8975f5c5SAndroid Build Coastguard Worker         GLTexture color;
1796*8975f5c5SAndroid Build Coastguard Worker         texture = color;
1797*8975f5c5SAndroid Build Coastguard Worker 
1798*8975f5c5SAndroid Build Coastguard Worker         glActiveTexture(GL_TEXTURE0);
1799*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1800*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1801*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1802*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1803*8975f5c5SAndroid Build Coastguard Worker         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData);
1804*8975f5c5SAndroid Build Coastguard Worker 
1805*8975f5c5SAndroid Build Coastguard Worker         glActiveTexture(GL_TEXTURE1);
1806*8975f5c5SAndroid Build Coastguard Worker         GLTexture color2;
1807*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, color2);
1808*8975f5c5SAndroid Build Coastguard Worker         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1809*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1810*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1811*8975f5c5SAndroid Build Coastguard Worker         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, kInitialData);
1812*8975f5c5SAndroid Build Coastguard Worker 
1813*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(setupTexture, essl1_shaders::vs::Texture2D(),
1814*8975f5c5SAndroid Build Coastguard Worker                          R"(precision mediump float;
1815*8975f5c5SAndroid Build Coastguard Worker uniform sampler2D tex2D;
1816*8975f5c5SAndroid Build Coastguard Worker uniform sampler2D tex2D2;
1817*8975f5c5SAndroid Build Coastguard Worker varying vec2 v_texCoord;
1818*8975f5c5SAndroid Build Coastguard Worker 
1819*8975f5c5SAndroid Build Coastguard Worker void main()
1820*8975f5c5SAndroid Build Coastguard Worker {
1821*8975f5c5SAndroid Build Coastguard Worker     gl_FragColor = texture2D(tex2D, v_texCoord) + texture2D(tex2D2, v_texCoord);
1822*8975f5c5SAndroid Build Coastguard Worker })");
1823*8975f5c5SAndroid Build Coastguard Worker         drawQuad(setupTexture, essl1_shaders::PositionAttrib(), 0.0f);
1824*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1825*8975f5c5SAndroid Build Coastguard Worker 
1826*8975f5c5SAndroid Build Coastguard Worker         glFinish();
1827*8975f5c5SAndroid Build Coastguard Worker 
1828*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1829*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1830*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1831*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1832*8975f5c5SAndroid Build Coastguard Worker 
1833*8975f5c5SAndroid Build Coastguard Worker         // Don't flush yet; this leaves the descriptor set updates to the texture pending in the
1834*8975f5c5SAndroid Build Coastguard Worker         // Vulkan backend.
1835*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreateTextureAndDraw);
1836*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1DrawAndFlush));
1837*8975f5c5SAndroid Build Coastguard Worker 
1838*8975f5c5SAndroid Build Coastguard Worker         // Flush after thread 1
1839*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(
1840*8975f5c5SAndroid Build Coastguard Worker             0, 0, GLColor(kInitialData[0], kInitialData[1], kInitialData[2], kInitialData[3]), 1);
1841*8975f5c5SAndroid Build Coastguard Worker 
1842*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1843*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1844*8975f5c5SAndroid Build Coastguard Worker 
1845*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1846*8975f5c5SAndroid Build Coastguard Worker     };
1847*8975f5c5SAndroid Build Coastguard Worker 
1848*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1849*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1850*8975f5c5SAndroid Build Coastguard Worker 
1851*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1852*8975f5c5SAndroid Build Coastguard Worker 
1853*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to set up
1854*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreateTextureAndDraw));
1855*8975f5c5SAndroid Build Coastguard Worker 
1856*8975f5c5SAndroid Build Coastguard Worker         // Draw with the same texture, in the same way as thread 0.  This ensures that the
1857*8975f5c5SAndroid Build Coastguard Worker         // descriptor sets used in the Vulkan backend are identical.
1858*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
1859*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(drawTexture, essl1_shaders::vs::Texture2D(),
1860*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
1861*8975f5c5SAndroid Build Coastguard Worker         drawQuad(drawTexture, essl1_shaders::PositionAttrib(), 0.0f);
1862*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1863*8975f5c5SAndroid Build Coastguard Worker 
1864*8975f5c5SAndroid Build Coastguard Worker         // Flush
1865*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(
1866*8975f5c5SAndroid Build Coastguard Worker             0, 0, GLColor(kInitialData[0], kInitialData[1], kInitialData[2], kInitialData[3]), 1);
1867*8975f5c5SAndroid Build Coastguard Worker 
1868*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1DrawAndFlush);
1869*8975f5c5SAndroid Build Coastguard Worker 
1870*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1871*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1872*8975f5c5SAndroid Build Coastguard Worker 
1873*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1874*8975f5c5SAndroid Build Coastguard Worker     };
1875*8975f5c5SAndroid Build Coastguard Worker 
1876*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1877*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1878*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1879*8975f5c5SAndroid Build Coastguard Worker     };
1880*8975f5c5SAndroid Build Coastguard Worker 
1881*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1882*8975f5c5SAndroid Build Coastguard Worker 
1883*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
1884*8975f5c5SAndroid Build Coastguard Worker }
1885*8975f5c5SAndroid Build Coastguard Worker 
1886*8975f5c5SAndroid Build Coastguard Worker // Test framebuffer fetch program used between share groups.
testFramebufferFetch(DrawOrder drawOrder)1887*8975f5c5SAndroid Build Coastguard Worker void MultithreadingTestES3::testFramebufferFetch(DrawOrder drawOrder)
1888*8975f5c5SAndroid Build Coastguard Worker {
1889*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1890*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
1891*8975f5c5SAndroid Build Coastguard Worker 
1892*8975f5c5SAndroid Build Coastguard Worker     GLProgram framebufferFetchProgram;
1893*8975f5c5SAndroid Build Coastguard Worker 
1894*8975f5c5SAndroid Build Coastguard Worker     constexpr char kFS[] = R"(#version 300 es
1895*8975f5c5SAndroid Build Coastguard Worker #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
1896*8975f5c5SAndroid Build Coastguard Worker layout(noncoherent, location = 0) inout highp vec4 o_color;
1897*8975f5c5SAndroid Build Coastguard Worker 
1898*8975f5c5SAndroid Build Coastguard Worker uniform highp vec4 u_color;
1899*8975f5c5SAndroid Build Coastguard Worker void main (void)
1900*8975f5c5SAndroid Build Coastguard Worker {
1901*8975f5c5SAndroid Build Coastguard Worker     o_color += u_color;
1902*8975f5c5SAndroid Build Coastguard Worker })";
1903*8975f5c5SAndroid Build Coastguard Worker 
1904*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
1905*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
1906*8975f5c5SAndroid Build Coastguard Worker 
1907*8975f5c5SAndroid Build Coastguard Worker     enum class Step
1908*8975f5c5SAndroid Build Coastguard Worker     {
1909*8975f5c5SAndroid Build Coastguard Worker         Start,
1910*8975f5c5SAndroid Build Coastguard Worker         Thread0PreCreateProgram,
1911*8975f5c5SAndroid Build Coastguard Worker         Thread1CreateProgram,
1912*8975f5c5SAndroid Build Coastguard Worker         Finish,
1913*8975f5c5SAndroid Build Coastguard Worker         Abort,
1914*8975f5c5SAndroid Build Coastguard Worker     };
1915*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
1916*8975f5c5SAndroid Build Coastguard Worker 
1917*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1918*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1919*8975f5c5SAndroid Build Coastguard Worker 
1920*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1921*8975f5c5SAndroid Build Coastguard Worker 
1922*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1923*8975f5c5SAndroid Build Coastguard Worker 
1924*8975f5c5SAndroid Build Coastguard Worker         // Open a render pass, if requested.
1925*8975f5c5SAndroid Build Coastguard Worker         if (drawOrder == DrawOrder::Before)
1926*8975f5c5SAndroid Build Coastguard Worker         {
1927*8975f5c5SAndroid Build Coastguard Worker             ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1928*8975f5c5SAndroid Build Coastguard Worker             drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
1929*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
1930*8975f5c5SAndroid Build Coastguard Worker         }
1931*8975f5c5SAndroid Build Coastguard Worker 
1932*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0PreCreateProgram);
1933*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1CreateProgram));
1934*8975f5c5SAndroid Build Coastguard Worker 
1935*8975f5c5SAndroid Build Coastguard Worker         // Render using the framebuffer fetch program
1936*8975f5c5SAndroid Build Coastguard Worker         if (drawOrder == DrawOrder::After)
1937*8975f5c5SAndroid Build Coastguard Worker         {
1938*8975f5c5SAndroid Build Coastguard Worker             ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1939*8975f5c5SAndroid Build Coastguard Worker             drawQuad(program, essl1_shaders::PositionAttrib(), 0.0f);
1940*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
1941*8975f5c5SAndroid Build Coastguard Worker         }
1942*8975f5c5SAndroid Build Coastguard Worker 
1943*8975f5c5SAndroid Build Coastguard Worker         glFramebufferFetchBarrierEXT();
1944*8975f5c5SAndroid Build Coastguard Worker 
1945*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(framebufferFetchProgram);
1946*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(framebufferFetchProgram, "u_color");
1947*8975f5c5SAndroid Build Coastguard Worker         glUniform4f(colorLocation, 1, 0, 0, 0);
1948*8975f5c5SAndroid Build Coastguard Worker         drawQuad(framebufferFetchProgram, essl1_shaders::PositionAttrib(), 0.0f);
1949*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1950*8975f5c5SAndroid Build Coastguard Worker 
1951*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1952*8975f5c5SAndroid Build Coastguard Worker 
1953*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
1954*8975f5c5SAndroid Build Coastguard Worker 
1955*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1956*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1957*8975f5c5SAndroid Build Coastguard Worker     };
1958*8975f5c5SAndroid Build Coastguard Worker 
1959*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
1960*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
1961*8975f5c5SAndroid Build Coastguard Worker 
1962*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
1963*8975f5c5SAndroid Build Coastguard Worker 
1964*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to set up
1965*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0PreCreateProgram));
1966*8975f5c5SAndroid Build Coastguard Worker 
1967*8975f5c5SAndroid Build Coastguard Worker         // Create the framebuffer fetch program
1968*8975f5c5SAndroid Build Coastguard Worker         framebufferFetchProgram.makeRaster(essl3_shaders::vs::Simple(), kFS);
1969*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(framebufferFetchProgram);
1970*8975f5c5SAndroid Build Coastguard Worker 
1971*8975f5c5SAndroid Build Coastguard Worker         // Notify the other thread to use it
1972*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1CreateProgram);
1973*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1974*8975f5c5SAndroid Build Coastguard Worker 
1975*8975f5c5SAndroid Build Coastguard Worker         glClearColor(0, 0, 0, 1);
1976*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
1977*8975f5c5SAndroid Build Coastguard Worker 
1978*8975f5c5SAndroid Build Coastguard Worker         glFramebufferFetchBarrierEXT();
1979*8975f5c5SAndroid Build Coastguard Worker 
1980*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(framebufferFetchProgram);
1981*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(framebufferFetchProgram, "u_color");
1982*8975f5c5SAndroid Build Coastguard Worker         glUniform4f(colorLocation, 0, 0, 1, 0);
1983*8975f5c5SAndroid Build Coastguard Worker         drawQuad(framebufferFetchProgram, essl1_shaders::PositionAttrib(), 0.0f);
1984*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
1985*8975f5c5SAndroid Build Coastguard Worker 
1986*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1987*8975f5c5SAndroid Build Coastguard Worker 
1988*8975f5c5SAndroid Build Coastguard Worker         // Clean up
1989*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1990*8975f5c5SAndroid Build Coastguard Worker     };
1991*8975f5c5SAndroid Build Coastguard Worker 
1992*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
1993*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
1994*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
1995*8975f5c5SAndroid Build Coastguard Worker     };
1996*8975f5c5SAndroid Build Coastguard Worker 
1997*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
1998*8975f5c5SAndroid Build Coastguard Worker 
1999*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2000*8975f5c5SAndroid Build Coastguard Worker }
2001*8975f5c5SAndroid Build Coastguard Worker 
2002*8975f5c5SAndroid Build Coastguard Worker // Thread 1 creates the framebuffer fetch program.  Thread 0 proceeds to use it.
TEST_P(MultithreadingTestES3,CreateFramebufferFetchBeforeRenderPass)2003*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, CreateFramebufferFetchBeforeRenderPass)
2004*8975f5c5SAndroid Build Coastguard Worker {
2005*8975f5c5SAndroid Build Coastguard Worker     testFramebufferFetch(DrawOrder::After);
2006*8975f5c5SAndroid Build Coastguard Worker }
2007*8975f5c5SAndroid Build Coastguard Worker 
2008*8975f5c5SAndroid Build Coastguard Worker // Thread 1 creates the framebuffer fetch program while thread 0 is mid render pass.  Thread 0
2009*8975f5c5SAndroid Build Coastguard Worker // proceeds to use the framebuffer fetch program in the rest of its render pass.
TEST_P(MultithreadingTestES3,CreateFramebufferFetchMidRenderPass)2010*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, CreateFramebufferFetchMidRenderPass)
2011*8975f5c5SAndroid Build Coastguard Worker {
2012*8975f5c5SAndroid Build Coastguard Worker     testFramebufferFetch(DrawOrder::Before);
2013*8975f5c5SAndroid Build Coastguard Worker }
2014*8975f5c5SAndroid Build Coastguard Worker 
2015*8975f5c5SAndroid Build Coastguard Worker // Test async monolithic pipeline creation in the Vulkan backend vs shared programs.  This test
2016*8975f5c5SAndroid Build Coastguard Worker // makes one context/thread create a set of programs, then has another context/thread use them a few
2017*8975f5c5SAndroid Build Coastguard Worker // times, and then the original context destroys them.
TEST_P(MultithreadingTestES3,ProgramUseAndDestroyInTwoContexts)2018*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ProgramUseAndDestroyInTwoContexts)
2019*8975f5c5SAndroid Build Coastguard Worker {
2020*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2021*8975f5c5SAndroid Build Coastguard Worker 
2022*8975f5c5SAndroid Build Coastguard Worker     GLProgram programs[6];
2023*8975f5c5SAndroid Build Coastguard Worker 
2024*8975f5c5SAndroid Build Coastguard Worker     GLsync sync = 0;
2025*8975f5c5SAndroid Build Coastguard Worker 
2026*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2027*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2028*8975f5c5SAndroid Build Coastguard Worker 
2029*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2030*8975f5c5SAndroid Build Coastguard Worker     {
2031*8975f5c5SAndroid Build Coastguard Worker         Start,
2032*8975f5c5SAndroid Build Coastguard Worker         Thread0CreatePrograms,
2033*8975f5c5SAndroid Build Coastguard Worker         Thread1UsePrograms,
2034*8975f5c5SAndroid Build Coastguard Worker         Finish,
2035*8975f5c5SAndroid Build Coastguard Worker         Abort,
2036*8975f5c5SAndroid Build Coastguard Worker     };
2037*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2038*8975f5c5SAndroid Build Coastguard Worker 
2039*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
2040*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2041*8975f5c5SAndroid Build Coastguard Worker 
2042*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
2043*8975f5c5SAndroid Build Coastguard Worker 
2044*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
2045*8975f5c5SAndroid Build Coastguard Worker 
2046*8975f5c5SAndroid Build Coastguard Worker         // Create the programs
2047*8975f5c5SAndroid Build Coastguard Worker         programs[0].makeRaster(essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
2048*8975f5c5SAndroid Build Coastguard Worker         programs[1].makeRaster(essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
2049*8975f5c5SAndroid Build Coastguard Worker         programs[2].makeRaster(essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
2050*8975f5c5SAndroid Build Coastguard Worker         programs[3].makeRaster(essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Checkered());
2051*8975f5c5SAndroid Build Coastguard Worker         programs[4].makeRaster(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
2052*8975f5c5SAndroid Build Coastguard Worker         programs[5].makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
2053*8975f5c5SAndroid Build Coastguard Worker 
2054*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[0].valid());
2055*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[1].valid());
2056*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[2].valid());
2057*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[3].valid());
2058*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[4].valid());
2059*8975f5c5SAndroid Build Coastguard Worker         EXPECT_TRUE(programs[5].valid());
2060*8975f5c5SAndroid Build Coastguard Worker 
2061*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0CreatePrograms);
2062*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to use the programs
2063*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1UsePrograms));
2064*8975f5c5SAndroid Build Coastguard Worker 
2065*8975f5c5SAndroid Build Coastguard Worker         // Destroy them
2066*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
2067*8975f5c5SAndroid Build Coastguard Worker         programs[0].reset();
2068*8975f5c5SAndroid Build Coastguard Worker         programs[1].reset();
2069*8975f5c5SAndroid Build Coastguard Worker         programs[2].reset();
2070*8975f5c5SAndroid Build Coastguard Worker         programs[3].reset();
2071*8975f5c5SAndroid Build Coastguard Worker         programs[4].reset();
2072*8975f5c5SAndroid Build Coastguard Worker         programs[5].reset();
2073*8975f5c5SAndroid Build Coastguard Worker 
2074*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
2075*8975f5c5SAndroid Build Coastguard Worker 
2076*8975f5c5SAndroid Build Coastguard Worker         // Clean up
2077*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2078*8975f5c5SAndroid Build Coastguard Worker     };
2079*8975f5c5SAndroid Build Coastguard Worker 
2080*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
2081*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2082*8975f5c5SAndroid Build Coastguard Worker 
2083*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 0 to create the programs
2084*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0CreatePrograms));
2085*8975f5c5SAndroid Build Coastguard Worker 
2086*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
2087*8975f5c5SAndroid Build Coastguard Worker 
2088*8975f5c5SAndroid Build Coastguard Worker         // Use them a few times.
2089*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[0], essl1_shaders::PositionAttrib(), 0.0f);
2090*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[1], essl1_shaders::PositionAttrib(), 0.0f);
2091*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[2], essl1_shaders::PositionAttrib(), 0.0f);
2092*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[3], essl1_shaders::PositionAttrib(), 0.0f);
2093*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[4], essl1_shaders::PositionAttrib(), 0.0f);
2094*8975f5c5SAndroid Build Coastguard Worker 
2095*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[0], essl1_shaders::PositionAttrib(), 0.0f);
2096*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[1], essl1_shaders::PositionAttrib(), 0.0f);
2097*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[2], essl1_shaders::PositionAttrib(), 0.0f);
2098*8975f5c5SAndroid Build Coastguard Worker 
2099*8975f5c5SAndroid Build Coastguard Worker         drawQuad(programs[0], essl1_shaders::PositionAttrib(), 0.0f);
2100*8975f5c5SAndroid Build Coastguard Worker 
2101*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
2102*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
2103*8975f5c5SAndroid Build Coastguard Worker 
2104*8975f5c5SAndroid Build Coastguard Worker         // Notify the other thread to destroy the programs.
2105*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1UsePrograms);
2106*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
2107*8975f5c5SAndroid Build Coastguard Worker 
2108*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
2109*8975f5c5SAndroid Build Coastguard Worker 
2110*8975f5c5SAndroid Build Coastguard Worker         // Clean up
2111*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2112*8975f5c5SAndroid Build Coastguard Worker     };
2113*8975f5c5SAndroid Build Coastguard Worker 
2114*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
2115*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
2116*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
2117*8975f5c5SAndroid Build Coastguard Worker     };
2118*8975f5c5SAndroid Build Coastguard Worker 
2119*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
2120*8975f5c5SAndroid Build Coastguard Worker 
2121*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2122*8975f5c5SAndroid Build Coastguard Worker }
2123*8975f5c5SAndroid Build Coastguard Worker 
2124*8975f5c5SAndroid Build Coastguard Worker // Tests that Context with High Priority will correctly sample Texture rendered by Share Context
2125*8975f5c5SAndroid Build Coastguard Worker // with Low Priority.
TEST_P(MultithreadingTestES3,RenderThenSampleDifferentContextPriority)2126*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, RenderThenSampleDifferentContextPriority)
2127*8975f5c5SAndroid Build Coastguard Worker {
2128*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2129*8975f5c5SAndroid Build Coastguard Worker 
2130*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kIterationCountMax = 10;
2131*8975f5c5SAndroid Build Coastguard Worker 
2132*8975f5c5SAndroid Build Coastguard Worker     const bool reduceLoad       = isSwiftshader();
2133*8975f5c5SAndroid Build Coastguard Worker     const size_t iterationCount = reduceLoad ? 3 : kIterationCountMax;
2134*8975f5c5SAndroid Build Coastguard Worker     const size_t heavyDrawCount = reduceLoad ? 25 : 100;
2135*8975f5c5SAndroid Build Coastguard Worker 
2136*8975f5c5SAndroid Build Coastguard Worker     // Initialize contexts
2137*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
2138*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
2139*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
2140*8975f5c5SAndroid Build Coastguard Worker 
2141*8975f5c5SAndroid Build Coastguard Worker     // Large enough texture to catch timing problems.
2142*8975f5c5SAndroid Build Coastguard Worker     constexpr GLsizei kTexSize       = 1024;
2143*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount    = 2;
2144*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
2145*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx[kThreadCount]     = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
2146*8975f5c5SAndroid Build Coastguard Worker 
2147*8975f5c5SAndroid Build Coastguard Worker     EGLint priorities[kThreadCount] = {EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG};
2148*8975f5c5SAndroid Build Coastguard Worker 
2149*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[kThreadCount][6] = {
2150*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE},
2151*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, kTexSize, EGL_HEIGHT, kTexSize, EGL_NONE, EGL_NONE}};
2152*8975f5c5SAndroid Build Coastguard Worker 
2153*8975f5c5SAndroid Build Coastguard Worker     EGLint attributes[]     = {EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_NONE,
2154*8975f5c5SAndroid Build Coastguard Worker                                EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_NONE, EGL_NONE};
2155*8975f5c5SAndroid Build Coastguard Worker     EGLint *extraAttributes = attributes;
2156*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization"))
2157*8975f5c5SAndroid Build Coastguard Worker     {
2158*8975f5c5SAndroid Build Coastguard Worker         attributes[2] = EGL_NONE;
2159*8975f5c5SAndroid Build Coastguard Worker     }
2160*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_IMG_context_priority"))
2161*8975f5c5SAndroid Build Coastguard Worker     {
2162*8975f5c5SAndroid Build Coastguard Worker         // Run tests with single priority anyway.
2163*8975f5c5SAndroid Build Coastguard Worker         extraAttributes += 2;
2164*8975f5c5SAndroid Build Coastguard Worker     }
2165*8975f5c5SAndroid Build Coastguard Worker 
2166*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2167*8975f5c5SAndroid Build Coastguard Worker     {
2168*8975f5c5SAndroid Build Coastguard Worker         surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes[t]);
2169*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2170*8975f5c5SAndroid Build Coastguard Worker 
2171*8975f5c5SAndroid Build Coastguard Worker         attributes[1] = priorities[t];
2172*8975f5c5SAndroid Build Coastguard Worker         attributes[3] = mVirtualizationGroup++;
2173*8975f5c5SAndroid Build Coastguard Worker 
2174*8975f5c5SAndroid Build Coastguard Worker         ctx[t] = window->createContext(t == 0 ? EGL_NO_CONTEXT : ctx[0], extraAttributes);
2175*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
2176*8975f5c5SAndroid Build Coastguard Worker     }
2177*8975f5c5SAndroid Build Coastguard Worker 
2178*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
2179*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2180*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2181*8975f5c5SAndroid Build Coastguard Worker 
2182*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2183*8975f5c5SAndroid Build Coastguard Worker     {
2184*8975f5c5SAndroid Build Coastguard Worker         Start,
2185*8975f5c5SAndroid Build Coastguard Worker         Thread0Init,
2186*8975f5c5SAndroid Build Coastguard Worker         Thread1Init,
2187*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw,
2188*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw,
2189*8975f5c5SAndroid Build Coastguard Worker         Finish = Thread0Draw + kIterationCountMax * 2,
2190*8975f5c5SAndroid Build Coastguard Worker         Abort,
2191*8975f5c5SAndroid Build Coastguard Worker     };
2192*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2193*8975f5c5SAndroid Build Coastguard Worker 
2194*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture;
2195*8975f5c5SAndroid Build Coastguard Worker     GLsync thread0DrawSyncObj;
2196*8975f5c5SAndroid Build Coastguard Worker 
2197*8975f5c5SAndroid Build Coastguard Worker     auto calculateTestColor = [](size_t i) {
2198*8975f5c5SAndroid Build Coastguard Worker         return GLColor(i % 256, (i + 1) % 256, (i + 2) % 256, 255);
2199*8975f5c5SAndroid Build Coastguard Worker     };
2200*8975f5c5SAndroid Build Coastguard Worker     auto makeStep = [](Step base, size_t i) {
2201*8975f5c5SAndroid Build Coastguard Worker         return static_cast<Step>(static_cast<size_t>(base) + i * 2);
2202*8975f5c5SAndroid Build Coastguard Worker     };
2203*8975f5c5SAndroid Build Coastguard Worker 
2204*8975f5c5SAndroid Build Coastguard Worker     // Render to the texture.
2205*8975f5c5SAndroid Build Coastguard Worker     std::thread thread0 = std::thread([&]() {
2206*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2207*8975f5c5SAndroid Build Coastguard Worker 
2208*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2209*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2210*8975f5c5SAndroid Build Coastguard Worker 
2211*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2212*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2213*8975f5c5SAndroid Build Coastguard Worker                      nullptr);
2214*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2215*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2216*8975f5c5SAndroid Build Coastguard Worker 
2217*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
2218*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2219*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2220*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2221*8975f5c5SAndroid Build Coastguard Worker 
2222*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(colorProgram, essl1_shaders::vs::Simple(),
2223*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::UniformColor());
2224*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation =
2225*8975f5c5SAndroid Build Coastguard Worker             glGetUniformLocation(colorProgram, angle::essl1_shaders::ColorUniform());
2226*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(-1, colorLocation);
2227*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(colorProgram);
2228*8975f5c5SAndroid Build Coastguard Worker 
2229*8975f5c5SAndroid Build Coastguard Worker         // Notify second thread that initialization is finished.
2230*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Init);
2231*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Init));
2232*8975f5c5SAndroid Build Coastguard Worker 
2233*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < iterationCount; ++i)
2234*8975f5c5SAndroid Build Coastguard Worker         {
2235*8975f5c5SAndroid Build Coastguard Worker             // Simulate heavy work...
2236*8975f5c5SAndroid Build Coastguard Worker             glUniform4f(colorLocation, 0.0f, 0.0f, 0.0f, 0.0f);
2237*8975f5c5SAndroid Build Coastguard Worker             for (size_t j = 0; j < heavyDrawCount; ++j)
2238*8975f5c5SAndroid Build Coastguard Worker             {
2239*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(colorProgram, essl1_shaders::PositionAttrib(), 0.5f);
2240*8975f5c5SAndroid Build Coastguard Worker             }
2241*8975f5c5SAndroid Build Coastguard Worker 
2242*8975f5c5SAndroid Build Coastguard Worker             // Draw with test color.
2243*8975f5c5SAndroid Build Coastguard Worker             Vector4 color = calculateTestColor(i).toNormalizedVector();
2244*8975f5c5SAndroid Build Coastguard Worker             glUniform4f(colorLocation, color.x(), color.y(), color.z(), color.w());
2245*8975f5c5SAndroid Build Coastguard Worker             drawQuad(colorProgram, essl1_shaders::PositionAttrib(), 0.5f);
2246*8975f5c5SAndroid Build Coastguard Worker 
2247*8975f5c5SAndroid Build Coastguard Worker             thread0DrawSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
2248*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2249*8975f5c5SAndroid Build Coastguard Worker 
2250*8975f5c5SAndroid Build Coastguard Worker             // Notify second thread that draw is finished.
2251*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(makeStep(Step::Thread0Draw, i));
2252*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(
2253*8975f5c5SAndroid Build Coastguard Worker                 (i == iterationCount - 1) ? Step::Finish : makeStep(Step::Thread1Draw, i)));
2254*8975f5c5SAndroid Build Coastguard Worker         }
2255*8975f5c5SAndroid Build Coastguard Worker 
2256*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2257*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2258*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2259*8975f5c5SAndroid Build Coastguard Worker     });
2260*8975f5c5SAndroid Build Coastguard Worker 
2261*8975f5c5SAndroid Build Coastguard Worker     // Sample texture
2262*8975f5c5SAndroid Build Coastguard Worker     std::thread thread1 = std::thread([&]() {
2263*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2264*8975f5c5SAndroid Build Coastguard Worker 
2265*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
2266*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2267*8975f5c5SAndroid Build Coastguard Worker 
2268*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2269*8975f5c5SAndroid Build Coastguard Worker 
2270*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(textureProgram, essl1_shaders::vs::Texture2D(),
2271*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
2272*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureProgram);
2273*8975f5c5SAndroid Build Coastguard Worker 
2274*8975f5c5SAndroid Build Coastguard Worker         // Wait for first thread to finish initializing.
2275*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Init));
2276*8975f5c5SAndroid Build Coastguard Worker 
2277*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2278*8975f5c5SAndroid Build Coastguard Worker 
2279*8975f5c5SAndroid Build Coastguard Worker         // Wait for first thread to draw using the shared texture.
2280*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Init);
2281*8975f5c5SAndroid Build Coastguard Worker 
2282*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < iterationCount; ++i)
2283*8975f5c5SAndroid Build Coastguard Worker         {
2284*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(makeStep(Step::Thread0Draw, i)));
2285*8975f5c5SAndroid Build Coastguard Worker 
2286*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(thread0DrawSyncObj != nullptr);
2287*8975f5c5SAndroid Build Coastguard Worker             glWaitSync(thread0DrawSyncObj, 0, GL_TIMEOUT_IGNORED);
2288*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2289*8975f5c5SAndroid Build Coastguard Worker 
2290*8975f5c5SAndroid Build Coastguard Worker             // Should draw test color.
2291*8975f5c5SAndroid Build Coastguard Worker             drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
2292*8975f5c5SAndroid Build Coastguard Worker 
2293*8975f5c5SAndroid Build Coastguard Worker             // Check test color in four corners.
2294*8975f5c5SAndroid Build Coastguard Worker             GLColor color = calculateTestColor(i);
2295*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(0, 0, color.R, color.G, color.B, color.A);
2296*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(0, kTexSize - 1, color.R, color.G, color.B, color.A);
2297*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(kTexSize - 1, 0, color.R, color.G, color.B, color.A);
2298*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(kTexSize - 1, kTexSize - 1, color.R, color.G, color.B, color.A);
2299*8975f5c5SAndroid Build Coastguard Worker 
2300*8975f5c5SAndroid Build Coastguard Worker             glDeleteSync(thread0DrawSyncObj);
2301*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2302*8975f5c5SAndroid Build Coastguard Worker             thread0DrawSyncObj = nullptr;
2303*8975f5c5SAndroid Build Coastguard Worker 
2304*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(
2305*8975f5c5SAndroid Build Coastguard Worker                 (i == iterationCount - 1) ? Step::Finish : makeStep(Step::Thread1Draw, i));
2306*8975f5c5SAndroid Build Coastguard Worker         }
2307*8975f5c5SAndroid Build Coastguard Worker 
2308*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2309*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2310*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2311*8975f5c5SAndroid Build Coastguard Worker     });
2312*8975f5c5SAndroid Build Coastguard Worker 
2313*8975f5c5SAndroid Build Coastguard Worker     thread0.join();
2314*8975f5c5SAndroid Build Coastguard Worker     thread1.join();
2315*8975f5c5SAndroid Build Coastguard Worker 
2316*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2317*8975f5c5SAndroid Build Coastguard Worker 
2318*8975f5c5SAndroid Build Coastguard Worker     // Clean up
2319*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2320*8975f5c5SAndroid Build Coastguard Worker     {
2321*8975f5c5SAndroid Build Coastguard Worker         eglDestroySurface(dpy, surface[t]);
2322*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx[t]);
2323*8975f5c5SAndroid Build Coastguard Worker     }
2324*8975f5c5SAndroid Build Coastguard Worker }
2325*8975f5c5SAndroid Build Coastguard Worker 
2326*8975f5c5SAndroid Build Coastguard Worker // Tests that newly created Context with High Priority will correctly sample Texture already
2327*8975f5c5SAndroid Build Coastguard Worker // rendered by Share Context with Low Priority.
TEST_P(MultithreadingTestES3,RenderThenSampleInNewContextWithDifferentPriority)2328*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, RenderThenSampleInNewContextWithDifferentPriority)
2329*8975f5c5SAndroid Build Coastguard Worker {
2330*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2331*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
2332*8975f5c5SAndroid Build Coastguard Worker 
2333*8975f5c5SAndroid Build Coastguard Worker     const bool reduceLoad       = isSwiftshader();
2334*8975f5c5SAndroid Build Coastguard Worker     const size_t heavyDrawCount = reduceLoad ? 75 : 1000;
2335*8975f5c5SAndroid Build Coastguard Worker 
2336*8975f5c5SAndroid Build Coastguard Worker     // Initialize contexts
2337*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
2338*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
2339*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
2340*8975f5c5SAndroid Build Coastguard Worker 
2341*8975f5c5SAndroid Build Coastguard Worker     // Large enough texture to catch timing problems.
2342*8975f5c5SAndroid Build Coastguard Worker     constexpr GLsizei kTexSize       = 1024;
2343*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount    = 2;
2344*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
2345*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx[kThreadCount]     = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
2346*8975f5c5SAndroid Build Coastguard Worker 
2347*8975f5c5SAndroid Build Coastguard Worker     EGLint priorities[kThreadCount] = {EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG};
2348*8975f5c5SAndroid Build Coastguard Worker 
2349*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[kThreadCount][6] = {
2350*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE},
2351*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, kTexSize, EGL_HEIGHT, kTexSize, EGL_NONE, EGL_NONE}};
2352*8975f5c5SAndroid Build Coastguard Worker 
2353*8975f5c5SAndroid Build Coastguard Worker     EGLint attributes[]     = {EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_NONE,
2354*8975f5c5SAndroid Build Coastguard Worker                                EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_NONE, EGL_NONE};
2355*8975f5c5SAndroid Build Coastguard Worker     EGLint *extraAttributes = attributes;
2356*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization"))
2357*8975f5c5SAndroid Build Coastguard Worker     {
2358*8975f5c5SAndroid Build Coastguard Worker         attributes[2] = EGL_NONE;
2359*8975f5c5SAndroid Build Coastguard Worker     }
2360*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_IMG_context_priority"))
2361*8975f5c5SAndroid Build Coastguard Worker     {
2362*8975f5c5SAndroid Build Coastguard Worker         // Run tests with single priority anyway.
2363*8975f5c5SAndroid Build Coastguard Worker         extraAttributes += 2;
2364*8975f5c5SAndroid Build Coastguard Worker     }
2365*8975f5c5SAndroid Build Coastguard Worker 
2366*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2367*8975f5c5SAndroid Build Coastguard Worker     {
2368*8975f5c5SAndroid Build Coastguard Worker         surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes[t]);
2369*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2370*8975f5c5SAndroid Build Coastguard Worker 
2371*8975f5c5SAndroid Build Coastguard Worker         attributes[1] = priorities[t];
2372*8975f5c5SAndroid Build Coastguard Worker         attributes[3] = mVirtualizationGroup++;
2373*8975f5c5SAndroid Build Coastguard Worker 
2374*8975f5c5SAndroid Build Coastguard Worker         // Second context will be created in a thread 1
2375*8975f5c5SAndroid Build Coastguard Worker         if (t == 0)
2376*8975f5c5SAndroid Build Coastguard Worker         {
2377*8975f5c5SAndroid Build Coastguard Worker             ctx[t] = window->createContext(t == 0 ? EGL_NO_CONTEXT : ctx[0], extraAttributes);
2378*8975f5c5SAndroid Build Coastguard Worker             EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
2379*8975f5c5SAndroid Build Coastguard Worker         }
2380*8975f5c5SAndroid Build Coastguard Worker     }
2381*8975f5c5SAndroid Build Coastguard Worker 
2382*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
2383*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2384*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2385*8975f5c5SAndroid Build Coastguard Worker 
2386*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2387*8975f5c5SAndroid Build Coastguard Worker     {
2388*8975f5c5SAndroid Build Coastguard Worker         Start,
2389*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw,
2390*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw,
2391*8975f5c5SAndroid Build Coastguard Worker         Finish,
2392*8975f5c5SAndroid Build Coastguard Worker         Abort,
2393*8975f5c5SAndroid Build Coastguard Worker     };
2394*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2395*8975f5c5SAndroid Build Coastguard Worker 
2396*8975f5c5SAndroid Build Coastguard Worker     // Create shared resources before threads to minimize timing delays.
2397*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2398*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
2399*8975f5c5SAndroid Build Coastguard Worker 
2400*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
2401*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
2402*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
2403*8975f5c5SAndroid Build Coastguard Worker     ANGLE_GL_PROGRAM(textureProgram, essl1_shaders::vs::Texture2D(),
2404*8975f5c5SAndroid Build Coastguard Worker                      essl1_shaders::fs::Texture2D());
2405*8975f5c5SAndroid Build Coastguard Worker 
2406*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture;
2407*8975f5c5SAndroid Build Coastguard Worker     glBindTexture(GL_TEXTURE_2D, texture);
2408*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2409*8975f5c5SAndroid Build Coastguard Worker                  nullptr);
2410*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2411*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2412*8975f5c5SAndroid Build Coastguard Worker 
2413*8975f5c5SAndroid Build Coastguard Worker     GLFramebuffer fbo;
2414*8975f5c5SAndroid Build Coastguard Worker     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2415*8975f5c5SAndroid Build Coastguard Worker     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2416*8975f5c5SAndroid Build Coastguard Worker     glViewport(0, 0, kTexSize, kTexSize);
2417*8975f5c5SAndroid Build Coastguard Worker 
2418*8975f5c5SAndroid Build Coastguard Worker     EXPECT_GL_NO_ERROR();
2419*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(window->makeCurrent());
2420*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
2421*8975f5c5SAndroid Build Coastguard Worker 
2422*8975f5c5SAndroid Build Coastguard Worker     GLsync thread0DrawSyncObj;
2423*8975f5c5SAndroid Build Coastguard Worker 
2424*8975f5c5SAndroid Build Coastguard Worker     // Render to the texture.
2425*8975f5c5SAndroid Build Coastguard Worker     std::thread thread0 = std::thread([&]() {
2426*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2427*8975f5c5SAndroid Build Coastguard Worker 
2428*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2429*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2430*8975f5c5SAndroid Build Coastguard Worker 
2431*8975f5c5SAndroid Build Coastguard Worker         // Enable additive blend
2432*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_BLEND);
2433*8975f5c5SAndroid Build Coastguard Worker         glBlendFunc(GL_ONE, GL_ONE);
2434*8975f5c5SAndroid Build Coastguard Worker 
2435*8975f5c5SAndroid Build Coastguard Worker         GLuint query;
2436*8975f5c5SAndroid Build Coastguard Worker         glGenQueries(1, &query);
2437*8975f5c5SAndroid Build Coastguard Worker         glBeginQuery(GL_TIME_ELAPSED_EXT, query);
2438*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2439*8975f5c5SAndroid Build Coastguard Worker 
2440*8975f5c5SAndroid Build Coastguard Worker         // Simulate heavy work...
2441*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(redProgram);
2442*8975f5c5SAndroid Build Coastguard Worker         for (size_t j = 0; j < heavyDrawCount; ++j)
2443*8975f5c5SAndroid Build Coastguard Worker         {
2444*8975f5c5SAndroid Build Coastguard Worker             // Draw with Red color.
2445*8975f5c5SAndroid Build Coastguard Worker             drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
2446*8975f5c5SAndroid Build Coastguard Worker         }
2447*8975f5c5SAndroid Build Coastguard Worker 
2448*8975f5c5SAndroid Build Coastguard Worker         // Draw with Green color.
2449*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(greenProgram);
2450*8975f5c5SAndroid Build Coastguard Worker         drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
2451*8975f5c5SAndroid Build Coastguard Worker 
2452*8975f5c5SAndroid Build Coastguard Worker         // This should force "flushToPrimary()"
2453*8975f5c5SAndroid Build Coastguard Worker         glEndQuery(GL_TIME_ELAPSED_EXT);
2454*8975f5c5SAndroid Build Coastguard Worker         glDeleteQueries(1, &query);
2455*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2456*8975f5c5SAndroid Build Coastguard Worker 
2457*8975f5c5SAndroid Build Coastguard Worker         // Continue draw with Blue color after flush...
2458*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(blueProgram);
2459*8975f5c5SAndroid Build Coastguard Worker         drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
2460*8975f5c5SAndroid Build Coastguard Worker 
2461*8975f5c5SAndroid Build Coastguard Worker         thread0DrawSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
2462*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2463*8975f5c5SAndroid Build Coastguard Worker 
2464*8975f5c5SAndroid Build Coastguard Worker         // Notify second thread that draw is finished.
2465*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Draw);
2466*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
2467*8975f5c5SAndroid Build Coastguard Worker 
2468*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2469*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2470*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2471*8975f5c5SAndroid Build Coastguard Worker     });
2472*8975f5c5SAndroid Build Coastguard Worker 
2473*8975f5c5SAndroid Build Coastguard Worker     // Sample texture
2474*8975f5c5SAndroid Build Coastguard Worker     std::thread thread1 = std::thread([&]() {
2475*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2476*8975f5c5SAndroid Build Coastguard Worker 
2477*8975f5c5SAndroid Build Coastguard Worker         // Wait for first thread to finish draw.
2478*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw));
2479*8975f5c5SAndroid Build Coastguard Worker 
2480*8975f5c5SAndroid Build Coastguard Worker         // Create High priority Context when Low priority Context already rendered to the texture.
2481*8975f5c5SAndroid Build Coastguard Worker         ctx[1] = window->createContext(ctx[0], extraAttributes);
2482*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(EGL_NO_CONTEXT, ctx[1]);
2483*8975f5c5SAndroid Build Coastguard Worker 
2484*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
2485*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2486*8975f5c5SAndroid Build Coastguard Worker 
2487*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2488*8975f5c5SAndroid Build Coastguard Worker 
2489*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(thread0DrawSyncObj != nullptr);
2490*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(thread0DrawSyncObj, 0, GL_TIMEOUT_IGNORED);
2491*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2492*8975f5c5SAndroid Build Coastguard Worker 
2493*8975f5c5SAndroid Build Coastguard Worker         // Should draw test color.
2494*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureProgram);
2495*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2496*8975f5c5SAndroid Build Coastguard Worker         drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
2497*8975f5c5SAndroid Build Coastguard Worker 
2498*8975f5c5SAndroid Build Coastguard Worker         // Check test color in four corners.
2499*8975f5c5SAndroid Build Coastguard Worker         GLColor color = GLColor::white;
2500*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(0, 0, color.R, color.G, color.B, color.A);
2501*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(0, kTexSize - 1, color.R, color.G, color.B, color.A);
2502*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(kTexSize - 1, 0, color.R, color.G, color.B, color.A);
2503*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(kTexSize - 1, kTexSize - 1, color.R, color.G, color.B, color.A);
2504*8975f5c5SAndroid Build Coastguard Worker 
2505*8975f5c5SAndroid Build Coastguard Worker         glDeleteSync(thread0DrawSyncObj);
2506*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2507*8975f5c5SAndroid Build Coastguard Worker         thread0DrawSyncObj = nullptr;
2508*8975f5c5SAndroid Build Coastguard Worker 
2509*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
2510*8975f5c5SAndroid Build Coastguard Worker 
2511*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2512*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2513*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2514*8975f5c5SAndroid Build Coastguard Worker     });
2515*8975f5c5SAndroid Build Coastguard Worker 
2516*8975f5c5SAndroid Build Coastguard Worker     thread0.join();
2517*8975f5c5SAndroid Build Coastguard Worker     thread1.join();
2518*8975f5c5SAndroid Build Coastguard Worker 
2519*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2520*8975f5c5SAndroid Build Coastguard Worker 
2521*8975f5c5SAndroid Build Coastguard Worker     // Clean up
2522*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2523*8975f5c5SAndroid Build Coastguard Worker     {
2524*8975f5c5SAndroid Build Coastguard Worker         eglDestroySurface(dpy, surface[t]);
2525*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx[t]);
2526*8975f5c5SAndroid Build Coastguard Worker     }
2527*8975f5c5SAndroid Build Coastguard Worker }
2528*8975f5c5SAndroid Build Coastguard Worker 
2529*8975f5c5SAndroid Build Coastguard Worker // Tests that Context with High Priority will correctly sample EGLImage target Texture rendered by
2530*8975f5c5SAndroid Build Coastguard Worker // other Context with Low Priority into EGLImage source texture.
TEST_P(MultithreadingTestES3,RenderThenSampleDifferentContextPriorityUsingEGLImage)2531*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, RenderThenSampleDifferentContextPriorityUsingEGLImage)
2532*8975f5c5SAndroid Build Coastguard Worker {
2533*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2534*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!hasWaitSyncExtension() || !hasGLSyncExtension());
2535*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_EGL_image"));
2536*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
2537*8975f5c5SAndroid Build Coastguard Worker 
2538*8975f5c5SAndroid Build Coastguard Worker     const bool reduceLoad       = isSwiftshader();
2539*8975f5c5SAndroid Build Coastguard Worker     const size_t heavyDrawCount = reduceLoad ? 75 : 1000;
2540*8975f5c5SAndroid Build Coastguard Worker 
2541*8975f5c5SAndroid Build Coastguard Worker     // Initialize contexts
2542*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
2543*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
2544*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
2545*8975f5c5SAndroid Build Coastguard Worker 
2546*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_image_base"));
2547*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_gl_texture_2D_image"));
2548*8975f5c5SAndroid Build Coastguard Worker 
2549*8975f5c5SAndroid Build Coastguard Worker     // Large enough texture to catch timing problems.
2550*8975f5c5SAndroid Build Coastguard Worker     constexpr GLsizei kTexSize       = 1024;
2551*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount    = 2;
2552*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
2553*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx[kThreadCount]     = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
2554*8975f5c5SAndroid Build Coastguard Worker 
2555*8975f5c5SAndroid Build Coastguard Worker     EGLint priorities[kThreadCount] = {EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG};
2556*8975f5c5SAndroid Build Coastguard Worker 
2557*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[kThreadCount][6] = {
2558*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE},
2559*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, kTexSize, EGL_HEIGHT, kTexSize, EGL_NONE, EGL_NONE}};
2560*8975f5c5SAndroid Build Coastguard Worker 
2561*8975f5c5SAndroid Build Coastguard Worker     EGLint attributes[]     = {EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_NONE,
2562*8975f5c5SAndroid Build Coastguard Worker                                EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_NONE, EGL_NONE};
2563*8975f5c5SAndroid Build Coastguard Worker     EGLint *extraAttributes = attributes;
2564*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization"))
2565*8975f5c5SAndroid Build Coastguard Worker     {
2566*8975f5c5SAndroid Build Coastguard Worker         attributes[2] = EGL_NONE;
2567*8975f5c5SAndroid Build Coastguard Worker     }
2568*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_IMG_context_priority"))
2569*8975f5c5SAndroid Build Coastguard Worker     {
2570*8975f5c5SAndroid Build Coastguard Worker         // Run tests with single priority anyway.
2571*8975f5c5SAndroid Build Coastguard Worker         extraAttributes += 2;
2572*8975f5c5SAndroid Build Coastguard Worker     }
2573*8975f5c5SAndroid Build Coastguard Worker 
2574*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2575*8975f5c5SAndroid Build Coastguard Worker     {
2576*8975f5c5SAndroid Build Coastguard Worker         surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes[t]);
2577*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2578*8975f5c5SAndroid Build Coastguard Worker 
2579*8975f5c5SAndroid Build Coastguard Worker         attributes[1] = priorities[t];
2580*8975f5c5SAndroid Build Coastguard Worker         attributes[3] = mVirtualizationGroup++;
2581*8975f5c5SAndroid Build Coastguard Worker 
2582*8975f5c5SAndroid Build Coastguard Worker         // Contexts not shared
2583*8975f5c5SAndroid Build Coastguard Worker         ctx[t] = window->createContext(EGL_NO_CONTEXT, extraAttributes);
2584*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
2585*8975f5c5SAndroid Build Coastguard Worker     }
2586*8975f5c5SAndroid Build Coastguard Worker 
2587*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
2588*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2589*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2590*8975f5c5SAndroid Build Coastguard Worker 
2591*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2592*8975f5c5SAndroid Build Coastguard Worker     {
2593*8975f5c5SAndroid Build Coastguard Worker         Start,
2594*8975f5c5SAndroid Build Coastguard Worker         Thread1Init,
2595*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw,
2596*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw,
2597*8975f5c5SAndroid Build Coastguard Worker         Finish,
2598*8975f5c5SAndroid Build Coastguard Worker         Abort,
2599*8975f5c5SAndroid Build Coastguard Worker     };
2600*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2601*8975f5c5SAndroid Build Coastguard Worker 
2602*8975f5c5SAndroid Build Coastguard Worker     EGLImage image  = EGL_NO_IMAGE_KHR;
2603*8975f5c5SAndroid Build Coastguard Worker     EGLSyncKHR sync = EGL_NO_SYNC_KHR;
2604*8975f5c5SAndroid Build Coastguard Worker 
2605*8975f5c5SAndroid Build Coastguard Worker     // Render to the EGLImage source texture.
2606*8975f5c5SAndroid Build Coastguard Worker     std::thread thread0 = std::thread([&]() {
2607*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2608*8975f5c5SAndroid Build Coastguard Worker 
2609*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2610*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2611*8975f5c5SAndroid Build Coastguard Worker 
2612*8975f5c5SAndroid Build Coastguard Worker         // Create source texture.
2613*8975f5c5SAndroid Build Coastguard Worker         GLTexture texture;
2614*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2615*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2616*8975f5c5SAndroid Build Coastguard Worker                      nullptr);
2617*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2618*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2619*8975f5c5SAndroid Build Coastguard Worker 
2620*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
2621*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2622*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2623*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2624*8975f5c5SAndroid Build Coastguard Worker 
2625*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
2626*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
2627*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
2628*8975f5c5SAndroid Build Coastguard Worker 
2629*8975f5c5SAndroid Build Coastguard Worker         // Wait for second thread to finish initializing.
2630*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Init));
2631*8975f5c5SAndroid Build Coastguard Worker 
2632*8975f5c5SAndroid Build Coastguard Worker         // Enable additive blend
2633*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_BLEND);
2634*8975f5c5SAndroid Build Coastguard Worker         glBlendFunc(GL_ONE, GL_ONE);
2635*8975f5c5SAndroid Build Coastguard Worker 
2636*8975f5c5SAndroid Build Coastguard Worker         GLuint query;
2637*8975f5c5SAndroid Build Coastguard Worker         glGenQueries(1, &query);
2638*8975f5c5SAndroid Build Coastguard Worker         glBeginQuery(GL_TIME_ELAPSED_EXT, query);
2639*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2640*8975f5c5SAndroid Build Coastguard Worker 
2641*8975f5c5SAndroid Build Coastguard Worker         // Simulate heavy work...
2642*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(redProgram);
2643*8975f5c5SAndroid Build Coastguard Worker         for (size_t j = 0; j < heavyDrawCount; ++j)
2644*8975f5c5SAndroid Build Coastguard Worker         {
2645*8975f5c5SAndroid Build Coastguard Worker             // Draw with Red color.
2646*8975f5c5SAndroid Build Coastguard Worker             drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
2647*8975f5c5SAndroid Build Coastguard Worker         }
2648*8975f5c5SAndroid Build Coastguard Worker 
2649*8975f5c5SAndroid Build Coastguard Worker         // Draw with Green color.
2650*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(greenProgram);
2651*8975f5c5SAndroid Build Coastguard Worker         drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
2652*8975f5c5SAndroid Build Coastguard Worker 
2653*8975f5c5SAndroid Build Coastguard Worker         // This should force "flushToPrimary()"
2654*8975f5c5SAndroid Build Coastguard Worker         glEndQuery(GL_TIME_ELAPSED_EXT);
2655*8975f5c5SAndroid Build Coastguard Worker         glDeleteQueries(1, &query);
2656*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2657*8975f5c5SAndroid Build Coastguard Worker 
2658*8975f5c5SAndroid Build Coastguard Worker         // Continue draw with Blue color after flush...
2659*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(blueProgram);
2660*8975f5c5SAndroid Build Coastguard Worker         drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
2661*8975f5c5SAndroid Build Coastguard Worker 
2662*8975f5c5SAndroid Build Coastguard Worker         sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
2663*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(sync, EGL_NO_SYNC_KHR);
2664*8975f5c5SAndroid Build Coastguard Worker 
2665*8975f5c5SAndroid Build Coastguard Worker         // Create EGLImage.
2666*8975f5c5SAndroid Build Coastguard Worker         image = eglCreateImageKHR(
2667*8975f5c5SAndroid Build Coastguard Worker             dpy, ctx[0], EGL_GL_TEXTURE_2D_KHR,
2668*8975f5c5SAndroid Build Coastguard Worker             reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(texture)), nullptr);
2669*8975f5c5SAndroid Build Coastguard Worker         ASSERT_EGL_SUCCESS();
2670*8975f5c5SAndroid Build Coastguard Worker 
2671*8975f5c5SAndroid Build Coastguard Worker         // Notify second thread that draw is finished.
2672*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Draw);
2673*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
2674*8975f5c5SAndroid Build Coastguard Worker 
2675*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2676*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2677*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2678*8975f5c5SAndroid Build Coastguard Worker     });
2679*8975f5c5SAndroid Build Coastguard Worker 
2680*8975f5c5SAndroid Build Coastguard Worker     // Sample texture
2681*8975f5c5SAndroid Build Coastguard Worker     std::thread thread1 = std::thread([&]() {
2682*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2683*8975f5c5SAndroid Build Coastguard Worker 
2684*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
2685*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2686*8975f5c5SAndroid Build Coastguard Worker 
2687*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2688*8975f5c5SAndroid Build Coastguard Worker 
2689*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(textureProgram, essl1_shaders::vs::Texture2D(),
2690*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
2691*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureProgram);
2692*8975f5c5SAndroid Build Coastguard Worker 
2693*8975f5c5SAndroid Build Coastguard Worker         // Create target texture.
2694*8975f5c5SAndroid Build Coastguard Worker         GLTexture texture;
2695*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2696*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2697*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2698*8975f5c5SAndroid Build Coastguard Worker 
2699*8975f5c5SAndroid Build Coastguard Worker         // Wait for first thread to draw into the source texture.
2700*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Init);
2701*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw));
2702*8975f5c5SAndroid Build Coastguard Worker 
2703*8975f5c5SAndroid Build Coastguard Worker         // Wait for draw to complete
2704*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(eglWaitSyncKHR(dpy, sync, 0));
2705*8975f5c5SAndroid Build Coastguard Worker 
2706*8975f5c5SAndroid Build Coastguard Worker         // Specify target texture from EGLImage.
2707*8975f5c5SAndroid Build Coastguard Worker         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
2708*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2709*8975f5c5SAndroid Build Coastguard Worker 
2710*8975f5c5SAndroid Build Coastguard Worker         // Should draw test color.
2711*8975f5c5SAndroid Build Coastguard Worker         drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
2712*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2713*8975f5c5SAndroid Build Coastguard Worker 
2714*8975f5c5SAndroid Build Coastguard Worker         // Check test color in four corners.
2715*8975f5c5SAndroid Build Coastguard Worker         GLColor color = GLColor::white;
2716*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(0, 0, color.R, color.G, color.B, color.A);
2717*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(0, kTexSize - 1, color.R, color.G, color.B, color.A);
2718*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(kTexSize - 1, 0, color.R, color.G, color.B, color.A);
2719*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_EQ(kTexSize - 1, kTexSize - 1, color.R, color.G, color.B, color.A);
2720*8975f5c5SAndroid Build Coastguard Worker 
2721*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglDestroyImageKHR(dpy, image));
2722*8975f5c5SAndroid Build Coastguard Worker         image = EGL_NO_IMAGE_KHR;
2723*8975f5c5SAndroid Build Coastguard Worker 
2724*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglDestroySyncKHR(dpy, sync));
2725*8975f5c5SAndroid Build Coastguard Worker         sync = EGL_NO_SYNC_KHR;
2726*8975f5c5SAndroid Build Coastguard Worker 
2727*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
2728*8975f5c5SAndroid Build Coastguard Worker 
2729*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2730*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2731*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2732*8975f5c5SAndroid Build Coastguard Worker     });
2733*8975f5c5SAndroid Build Coastguard Worker 
2734*8975f5c5SAndroid Build Coastguard Worker     thread0.join();
2735*8975f5c5SAndroid Build Coastguard Worker     thread1.join();
2736*8975f5c5SAndroid Build Coastguard Worker 
2737*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2738*8975f5c5SAndroid Build Coastguard Worker 
2739*8975f5c5SAndroid Build Coastguard Worker     // Clean up
2740*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2741*8975f5c5SAndroid Build Coastguard Worker     {
2742*8975f5c5SAndroid Build Coastguard Worker         eglDestroySurface(dpy, surface[t]);
2743*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx[t]);
2744*8975f5c5SAndroid Build Coastguard Worker     }
2745*8975f5c5SAndroid Build Coastguard Worker }
2746*8975f5c5SAndroid Build Coastguard Worker 
2747*8975f5c5SAndroid Build Coastguard Worker // Tests mixing commands of Contexts with different Priorities in a single Command Buffers (Vulkan).
TEST_P(MultithreadingTestES3,ContextPriorityMixing)2748*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, ContextPriorityMixing)
2749*8975f5c5SAndroid Build Coastguard Worker {
2750*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2751*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_disjoint_timer_query"));
2752*8975f5c5SAndroid Build Coastguard Worker 
2753*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kIterationCountMax = 10;
2754*8975f5c5SAndroid Build Coastguard Worker 
2755*8975f5c5SAndroid Build Coastguard Worker     const bool reduceLoad       = isSwiftshader();
2756*8975f5c5SAndroid Build Coastguard Worker     const size_t iterationCount = reduceLoad ? 3 : kIterationCountMax;
2757*8975f5c5SAndroid Build Coastguard Worker     const size_t heavyDrawCount = reduceLoad ? 25 : 100;
2758*8975f5c5SAndroid Build Coastguard Worker 
2759*8975f5c5SAndroid Build Coastguard Worker     // Initialize contexts
2760*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
2761*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
2762*8975f5c5SAndroid Build Coastguard Worker     EGLConfig config  = window->getConfig();
2763*8975f5c5SAndroid Build Coastguard Worker 
2764*8975f5c5SAndroid Build Coastguard Worker     // Large enough texture to catch timing problems.
2765*8975f5c5SAndroid Build Coastguard Worker     constexpr GLsizei kTexSize       = 1024;
2766*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kThreadCount    = 2;
2767*8975f5c5SAndroid Build Coastguard Worker     EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
2768*8975f5c5SAndroid Build Coastguard Worker     EGLContext ctx[kThreadCount]     = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
2769*8975f5c5SAndroid Build Coastguard Worker 
2770*8975f5c5SAndroid Build Coastguard Worker     EGLint priorities[kThreadCount] = {EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG};
2771*8975f5c5SAndroid Build Coastguard Worker 
2772*8975f5c5SAndroid Build Coastguard Worker     EGLint pbufferAttributes[kThreadCount][6] = {
2773*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE},
2774*8975f5c5SAndroid Build Coastguard Worker         {EGL_WIDTH, kTexSize, EGL_HEIGHT, kTexSize, EGL_NONE, EGL_NONE}};
2775*8975f5c5SAndroid Build Coastguard Worker 
2776*8975f5c5SAndroid Build Coastguard Worker     EGLint attributes[]     = {EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_NONE,
2777*8975f5c5SAndroid Build Coastguard Worker                                EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_NONE, EGL_NONE};
2778*8975f5c5SAndroid Build Coastguard Worker     EGLint *extraAttributes = attributes;
2779*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_ANGLE_context_virtualization"))
2780*8975f5c5SAndroid Build Coastguard Worker     {
2781*8975f5c5SAndroid Build Coastguard Worker         attributes[2] = EGL_NONE;
2782*8975f5c5SAndroid Build Coastguard Worker     }
2783*8975f5c5SAndroid Build Coastguard Worker     if (!IsEGLDisplayExtensionEnabled(dpy, "EGL_IMG_context_priority"))
2784*8975f5c5SAndroid Build Coastguard Worker     {
2785*8975f5c5SAndroid Build Coastguard Worker         // Run tests with single priority anyway.
2786*8975f5c5SAndroid Build Coastguard Worker         extraAttributes += 2;
2787*8975f5c5SAndroid Build Coastguard Worker     }
2788*8975f5c5SAndroid Build Coastguard Worker 
2789*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2790*8975f5c5SAndroid Build Coastguard Worker     {
2791*8975f5c5SAndroid Build Coastguard Worker         surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes[t]);
2792*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2793*8975f5c5SAndroid Build Coastguard Worker 
2794*8975f5c5SAndroid Build Coastguard Worker         attributes[1] = priorities[t];
2795*8975f5c5SAndroid Build Coastguard Worker         attributes[3] = mVirtualizationGroup++;
2796*8975f5c5SAndroid Build Coastguard Worker 
2797*8975f5c5SAndroid Build Coastguard Worker         // Contexts not shared
2798*8975f5c5SAndroid Build Coastguard Worker         ctx[t] = window->createContext(EGL_NO_CONTEXT, extraAttributes);
2799*8975f5c5SAndroid Build Coastguard Worker         EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
2800*8975f5c5SAndroid Build Coastguard Worker     }
2801*8975f5c5SAndroid Build Coastguard Worker 
2802*8975f5c5SAndroid Build Coastguard Worker     // Synchronization tools to ensure the two threads are interleaved as designed by this test.
2803*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2804*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2805*8975f5c5SAndroid Build Coastguard Worker 
2806*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2807*8975f5c5SAndroid Build Coastguard Worker     {
2808*8975f5c5SAndroid Build Coastguard Worker         Start,
2809*8975f5c5SAndroid Build Coastguard Worker         Thread1DrawColor,
2810*8975f5c5SAndroid Build Coastguard Worker         Thread0Iterate,
2811*8975f5c5SAndroid Build Coastguard Worker         Finish = Thread1DrawColor + kIterationCountMax * 2,
2812*8975f5c5SAndroid Build Coastguard Worker         Abort,
2813*8975f5c5SAndroid Build Coastguard Worker     };
2814*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2815*8975f5c5SAndroid Build Coastguard Worker 
2816*8975f5c5SAndroid Build Coastguard Worker     auto makeStep = [](Step base, size_t i) {
2817*8975f5c5SAndroid Build Coastguard Worker         return static_cast<Step>(static_cast<size_t>(base) + i * 2);
2818*8975f5c5SAndroid Build Coastguard Worker     };
2819*8975f5c5SAndroid Build Coastguard Worker 
2820*8975f5c5SAndroid Build Coastguard Worker     // Triggers commands submission.
2821*8975f5c5SAndroid Build Coastguard Worker     std::thread thread0 = std::thread([&]() {
2822*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2823*8975f5c5SAndroid Build Coastguard Worker 
2824*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2825*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2826*8975f5c5SAndroid Build Coastguard Worker 
2827*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
2828*8975f5c5SAndroid Build Coastguard Worker 
2829*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < iterationCount; ++i)
2830*8975f5c5SAndroid Build Coastguard Worker         {
2831*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(makeStep(Step::Thread1DrawColor, i)));
2832*8975f5c5SAndroid Build Coastguard Worker 
2833*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(redProgram);
2834*8975f5c5SAndroid Build Coastguard Worker             drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
2835*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2836*8975f5c5SAndroid Build Coastguard Worker 
2837*8975f5c5SAndroid Build Coastguard Worker             // This should perform commands submission.
2838*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2839*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
2840*8975f5c5SAndroid Build Coastguard Worker 
2841*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(makeStep(Step::Thread0Iterate, i));
2842*8975f5c5SAndroid Build Coastguard Worker 
2843*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
2844*8975f5c5SAndroid Build Coastguard Worker             EXPECT_EGL_SUCCESS();
2845*8975f5c5SAndroid Build Coastguard Worker         }
2846*8975f5c5SAndroid Build Coastguard Worker 
2847*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
2848*8975f5c5SAndroid Build Coastguard Worker 
2849*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2850*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2851*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2852*8975f5c5SAndroid Build Coastguard Worker     });
2853*8975f5c5SAndroid Build Coastguard Worker 
2854*8975f5c5SAndroid Build Coastguard Worker     // Render and then sample texture.
2855*8975f5c5SAndroid Build Coastguard Worker     std::thread thread1 = std::thread([&]() {
2856*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2857*8975f5c5SAndroid Build Coastguard Worker 
2858*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
2859*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2860*8975f5c5SAndroid Build Coastguard Worker 
2861*8975f5c5SAndroid Build Coastguard Worker         glDisable(GL_DEPTH_TEST);
2862*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, kTexSize, kTexSize);
2863*8975f5c5SAndroid Build Coastguard Worker 
2864*8975f5c5SAndroid Build Coastguard Worker         GLTexture texture;
2865*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
2866*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2867*8975f5c5SAndroid Build Coastguard Worker                      nullptr);
2868*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2869*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2870*8975f5c5SAndroid Build Coastguard Worker 
2871*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
2872*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2873*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2874*8975f5c5SAndroid Build Coastguard Worker 
2875*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(colorProgram, essl1_shaders::vs::Simple(),
2876*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::UniformColor());
2877*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation =
2878*8975f5c5SAndroid Build Coastguard Worker             glGetUniformLocation(colorProgram, angle::essl1_shaders::ColorUniform());
2879*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(-1, colorLocation);
2880*8975f5c5SAndroid Build Coastguard Worker 
2881*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(textureProgram, essl1_shaders::vs::Texture2D(),
2882*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
2883*8975f5c5SAndroid Build Coastguard Worker 
2884*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < iterationCount; ++i)
2885*8975f5c5SAndroid Build Coastguard Worker         {
2886*8975f5c5SAndroid Build Coastguard Worker             glBindFramebuffer(GL_FRAMEBUFFER, fbo);
2887*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(colorProgram);
2888*8975f5c5SAndroid Build Coastguard Worker 
2889*8975f5c5SAndroid Build Coastguard Worker             GLuint query;
2890*8975f5c5SAndroid Build Coastguard Worker             glGenQueries(1, &query);
2891*8975f5c5SAndroid Build Coastguard Worker             glBeginQuery(GL_TIME_ELAPSED_EXT, query);
2892*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2893*8975f5c5SAndroid Build Coastguard Worker 
2894*8975f5c5SAndroid Build Coastguard Worker             // Simulate heavy work...
2895*8975f5c5SAndroid Build Coastguard Worker             glUniform4f(colorLocation, 0.0f, 0.0f, 0.0f, 0.0f);
2896*8975f5c5SAndroid Build Coastguard Worker             for (size_t j = 0; j < heavyDrawCount; ++j)
2897*8975f5c5SAndroid Build Coastguard Worker             {
2898*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(colorProgram, essl1_shaders::PositionAttrib(), 0.5f);
2899*8975f5c5SAndroid Build Coastguard Worker             }
2900*8975f5c5SAndroid Build Coastguard Worker 
2901*8975f5c5SAndroid Build Coastguard Worker             // Draw with test color.
2902*8975f5c5SAndroid Build Coastguard Worker             GLColor color(i % 256, (i + 1) % 256, (i + 2) % 256, 255);
2903*8975f5c5SAndroid Build Coastguard Worker             Vector4 colorF = color.toNormalizedVector();
2904*8975f5c5SAndroid Build Coastguard Worker             glUniform4f(colorLocation, colorF.x(), colorF.y(), colorF.z(), colorF.w());
2905*8975f5c5SAndroid Build Coastguard Worker             drawQuad(colorProgram, essl1_shaders::PositionAttrib(), 0.5f);
2906*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2907*8975f5c5SAndroid Build Coastguard Worker 
2908*8975f5c5SAndroid Build Coastguard Worker             // This should force "flushToPrimary()"
2909*8975f5c5SAndroid Build Coastguard Worker             glEndQuery(GL_TIME_ELAPSED_EXT);
2910*8975f5c5SAndroid Build Coastguard Worker             glDeleteQueries(1, &query);
2911*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2912*8975f5c5SAndroid Build Coastguard Worker 
2913*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(makeStep(Step::Thread1DrawColor, i));
2914*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(makeStep(Step::Thread0Iterate, i)));
2915*8975f5c5SAndroid Build Coastguard Worker 
2916*8975f5c5SAndroid Build Coastguard Worker             glBindFramebuffer(GL_FRAMEBUFFER, 0);
2917*8975f5c5SAndroid Build Coastguard Worker             glUseProgram(textureProgram);
2918*8975f5c5SAndroid Build Coastguard Worker 
2919*8975f5c5SAndroid Build Coastguard Worker             // Should draw test color.
2920*8975f5c5SAndroid Build Coastguard Worker             drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
2921*8975f5c5SAndroid Build Coastguard Worker             ASSERT_GL_NO_ERROR();
2922*8975f5c5SAndroid Build Coastguard Worker 
2923*8975f5c5SAndroid Build Coastguard Worker             // Check test color in four corners.
2924*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(0, 0, color.R, color.G, color.B, color.A);
2925*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(0, kTexSize - 1, color.R, color.G, color.B, color.A);
2926*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(kTexSize - 1, 0, color.R, color.G, color.B, color.A);
2927*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_EQ(kTexSize - 1, kTexSize - 1, color.R, color.G, color.B, color.A);
2928*8975f5c5SAndroid Build Coastguard Worker         }
2929*8975f5c5SAndroid Build Coastguard Worker 
2930*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
2931*8975f5c5SAndroid Build Coastguard Worker 
2932*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
2933*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
2934*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
2935*8975f5c5SAndroid Build Coastguard Worker     });
2936*8975f5c5SAndroid Build Coastguard Worker 
2937*8975f5c5SAndroid Build Coastguard Worker     thread0.join();
2938*8975f5c5SAndroid Build Coastguard Worker     thread1.join();
2939*8975f5c5SAndroid Build Coastguard Worker 
2940*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
2941*8975f5c5SAndroid Build Coastguard Worker 
2942*8975f5c5SAndroid Build Coastguard Worker     // Clean up
2943*8975f5c5SAndroid Build Coastguard Worker     for (size_t t = 0; t < kThreadCount; ++t)
2944*8975f5c5SAndroid Build Coastguard Worker     {
2945*8975f5c5SAndroid Build Coastguard Worker         eglDestroySurface(dpy, surface[t]);
2946*8975f5c5SAndroid Build Coastguard Worker         eglDestroyContext(dpy, ctx[t]);
2947*8975f5c5SAndroid Build Coastguard Worker     }
2948*8975f5c5SAndroid Build Coastguard Worker }
2949*8975f5c5SAndroid Build Coastguard Worker 
2950*8975f5c5SAndroid Build Coastguard Worker // Test that it is possible to upload textures in one thread and use them in another with
2951*8975f5c5SAndroid Build Coastguard Worker // synchronization.
TEST_P(MultithreadingTestES3,MultithreadedTextureUploadAndDraw)2952*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, MultithreadedTextureUploadAndDraw)
2953*8975f5c5SAndroid Build Coastguard Worker {
2954*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
2955*8975f5c5SAndroid Build Coastguard Worker 
2956*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kTexSize = 4;
2957*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture1;
2958*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture2;
2959*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors1(kTexSize * kTexSize, GLColor::red);
2960*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors2(kTexSize * kTexSize, GLColor::green);
2961*8975f5c5SAndroid Build Coastguard Worker 
2962*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
2963*8975f5c5SAndroid Build Coastguard Worker     GLsync sync = nullptr;
2964*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
2965*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
2966*8975f5c5SAndroid Build Coastguard Worker 
2967*8975f5c5SAndroid Build Coastguard Worker     enum class Step
2968*8975f5c5SAndroid Build Coastguard Worker     {
2969*8975f5c5SAndroid Build Coastguard Worker         Start,
2970*8975f5c5SAndroid Build Coastguard Worker         Thread0UploadFinish,
2971*8975f5c5SAndroid Build Coastguard Worker         Finish,
2972*8975f5c5SAndroid Build Coastguard Worker         Abort,
2973*8975f5c5SAndroid Build Coastguard Worker     };
2974*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
2975*8975f5c5SAndroid Build Coastguard Worker 
2976*8975f5c5SAndroid Build Coastguard Worker     // Threads to upload and draw with textures.
2977*8975f5c5SAndroid Build Coastguard Worker     auto thread0Upload = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
2978*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
2979*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
2980*8975f5c5SAndroid Build Coastguard Worker 
2981*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
2982*8975f5c5SAndroid Build Coastguard Worker 
2983*8975f5c5SAndroid Build Coastguard Worker         // Two mipmap textures are defined here. They are used for drawing in the other thread.
2984*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture1);
2985*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2986*8975f5c5SAndroid Build Coastguard Worker                      textureColors1.data());
2987*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
2988*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors1.data());
2989*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kTexSize / 4, kTexSize / 4, 0, GL_RGBA,
2990*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors1.data());
2991*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2992*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2993*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
2994*8975f5c5SAndroid Build Coastguard Worker 
2995*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture2);
2996*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
2997*8975f5c5SAndroid Build Coastguard Worker                      textureColors2.data());
2998*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
2999*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors2.data());
3000*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, kTexSize / 4, kTexSize / 4, 0, GL_RGBA,
3001*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors2.data());
3002*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3003*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3004*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3005*8975f5c5SAndroid Build Coastguard Worker 
3006*8975f5c5SAndroid Build Coastguard Worker         // Create a sync object to be used for the draw thread.
3007*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
3008*8975f5c5SAndroid Build Coastguard Worker         glFlush();
3009*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
3010*8975f5c5SAndroid Build Coastguard Worker 
3011*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0UploadFinish);
3012*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3013*8975f5c5SAndroid Build Coastguard Worker     };
3014*8975f5c5SAndroid Build Coastguard Worker 
3015*8975f5c5SAndroid Build Coastguard Worker     auto thread1Draw = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3016*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3017*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0UploadFinish));
3018*8975f5c5SAndroid Build Coastguard Worker 
3019*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3020*8975f5c5SAndroid Build Coastguard Worker 
3021*8975f5c5SAndroid Build Coastguard Worker         // Wait for the sync object to be signaled.
3022*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
3023*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3024*8975f5c5SAndroid Build Coastguard Worker 
3025*8975f5c5SAndroid Build Coastguard Worker         // Draw using the textures from the texture upload thread.
3026*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(textureProgram, essl1_shaders::vs::Texture2D(),
3027*8975f5c5SAndroid Build Coastguard Worker                          essl1_shaders::fs::Texture2D());
3028*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureProgram);
3029*8975f5c5SAndroid Build Coastguard Worker 
3030*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture1);
3031*8975f5c5SAndroid Build Coastguard Worker         drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
3032*8975f5c5SAndroid Build Coastguard Worker         glFlush();
3033*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3034*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::red);
3035*8975f5c5SAndroid Build Coastguard Worker 
3036*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture2);
3037*8975f5c5SAndroid Build Coastguard Worker         drawQuad(textureProgram, essl1_shaders::PositionAttrib(), 0.5f);
3038*8975f5c5SAndroid Build Coastguard Worker         glFlush();
3039*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3040*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::green);
3041*8975f5c5SAndroid Build Coastguard Worker 
3042*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3043*8975f5c5SAndroid Build Coastguard Worker     };
3044*8975f5c5SAndroid Build Coastguard Worker 
3045*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3046*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0Upload),
3047*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1Draw),
3048*8975f5c5SAndroid Build Coastguard Worker     };
3049*8975f5c5SAndroid Build Coastguard Worker 
3050*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
3051*8975f5c5SAndroid Build Coastguard Worker 
3052*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3053*8975f5c5SAndroid Build Coastguard Worker }
3054*8975f5c5SAndroid Build Coastguard Worker 
3055*8975f5c5SAndroid Build Coastguard Worker // Test that it is possible to create a new context after uploading mutable mipmap textures in the
3056*8975f5c5SAndroid Build Coastguard Worker // previous context, and use them in the new context.
TEST_P(MultithreadingTestES3,CreateNewContextAfterTextureUploadOnNewThread)3057*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, CreateNewContextAfterTextureUploadOnNewThread)
3058*8975f5c5SAndroid Build Coastguard Worker {
3059*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3060*8975f5c5SAndroid Build Coastguard Worker 
3061*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kTexSize = 4;
3062*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture1;
3063*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture2;
3064*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors1(kTexSize * kTexSize, GLColor::red);
3065*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors2(kTexSize * kTexSize, GLColor::green);
3066*8975f5c5SAndroid Build Coastguard Worker 
3067*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
3068*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
3069*8975f5c5SAndroid Build Coastguard Worker 
3070*8975f5c5SAndroid Build Coastguard Worker     std::thread thread = std::thread([&]() {
3071*8975f5c5SAndroid Build Coastguard Worker         // Create a context and upload the textures.
3072*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx1 = createMultithreadedContext(window, EGL_NO_CONTEXT);
3073*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx1));
3074*8975f5c5SAndroid Build Coastguard Worker 
3075*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture1);
3076*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
3077*8975f5c5SAndroid Build Coastguard Worker                      textureColors1.data());
3078*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
3079*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors1.data());
3080*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3081*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3082*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3083*8975f5c5SAndroid Build Coastguard Worker 
3084*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture2);
3085*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
3086*8975f5c5SAndroid Build Coastguard Worker                      textureColors2.data());
3087*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
3088*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, textureColors2.data());
3089*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3090*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3091*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3092*8975f5c5SAndroid Build Coastguard Worker 
3093*8975f5c5SAndroid Build Coastguard Worker         // Create a new context and use the uploaded textures.
3094*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx2 = createMultithreadedContext(window, ctx1);
3095*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx2));
3096*8975f5c5SAndroid Build Coastguard Worker 
3097*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
3098*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3099*8975f5c5SAndroid Build Coastguard Worker 
3100*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3101*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::red);
3102*8975f5c5SAndroid Build Coastguard Worker 
3103*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3104*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::green);
3105*8975f5c5SAndroid Build Coastguard Worker 
3106*8975f5c5SAndroid Build Coastguard Worker         // Destroy the contexts.
3107*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglDestroyContext(dpy, ctx2));
3108*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglDestroyContext(dpy, ctx1));
3109*8975f5c5SAndroid Build Coastguard Worker     });
3110*8975f5c5SAndroid Build Coastguard Worker 
3111*8975f5c5SAndroid Build Coastguard Worker     thread.join();
3112*8975f5c5SAndroid Build Coastguard Worker }
3113*8975f5c5SAndroid Build Coastguard Worker 
3114*8975f5c5SAndroid Build Coastguard Worker // Test that it is possible to create a new context after uploading mutable mipmap textures in the
3115*8975f5c5SAndroid Build Coastguard Worker // main thread, and use them in the new context.
TEST_P(MultithreadingTestES3,CreateNewContextAfterTextureUploadOnMainThread)3116*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, CreateNewContextAfterTextureUploadOnMainThread)
3117*8975f5c5SAndroid Build Coastguard Worker {
3118*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3119*8975f5c5SAndroid Build Coastguard Worker 
3120*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window = getEGLWindow();
3121*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy    = window->getDisplay();
3122*8975f5c5SAndroid Build Coastguard Worker 
3123*8975f5c5SAndroid Build Coastguard Worker     // Upload the textures.
3124*8975f5c5SAndroid Build Coastguard Worker     constexpr size_t kTexSize = 4;
3125*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture1;
3126*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture2;
3127*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors1(kTexSize * kTexSize, GLColor::red);
3128*8975f5c5SAndroid Build Coastguard Worker     std::vector<GLColor> textureColors2(kTexSize * kTexSize, GLColor::green);
3129*8975f5c5SAndroid Build Coastguard Worker 
3130*8975f5c5SAndroid Build Coastguard Worker     glBindTexture(GL_TEXTURE_2D, texture1);
3131*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
3132*8975f5c5SAndroid Build Coastguard Worker                  textureColors1.data());
3133*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
3134*8975f5c5SAndroid Build Coastguard Worker                  GL_UNSIGNED_BYTE, textureColors1.data());
3135*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3136*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3137*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
3138*8975f5c5SAndroid Build Coastguard Worker 
3139*8975f5c5SAndroid Build Coastguard Worker     glBindTexture(GL_TEXTURE_2D, texture2);
3140*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
3141*8975f5c5SAndroid Build Coastguard Worker                  textureColors2.data());
3142*8975f5c5SAndroid Build Coastguard Worker     glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kTexSize / 2, kTexSize / 2, 0, GL_RGBA,
3143*8975f5c5SAndroid Build Coastguard Worker                  GL_UNSIGNED_BYTE, textureColors2.data());
3144*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3145*8975f5c5SAndroid Build Coastguard Worker     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3146*8975f5c5SAndroid Build Coastguard Worker     ASSERT_GL_NO_ERROR();
3147*8975f5c5SAndroid Build Coastguard Worker 
3148*8975f5c5SAndroid Build Coastguard Worker     GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
3149*8975f5c5SAndroid Build Coastguard Worker 
3150*8975f5c5SAndroid Build Coastguard Worker     std::thread thread = std::thread([&]() {
3151*8975f5c5SAndroid Build Coastguard Worker         // Create a context.
3152*8975f5c5SAndroid Build Coastguard Worker         EGLContext ctx1 = createMultithreadedContext(window, window->getContext());
3153*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx1));
3154*8975f5c5SAndroid Build Coastguard Worker 
3155*8975f5c5SAndroid Build Coastguard Worker         // Wait for the sync object to be signaled.
3156*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
3157*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3158*8975f5c5SAndroid Build Coastguard Worker 
3159*8975f5c5SAndroid Build Coastguard Worker         // Use the uploaded textures in the main thread.
3160*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer fbo;
3161*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
3162*8975f5c5SAndroid Build Coastguard Worker 
3163*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
3164*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::red);
3165*8975f5c5SAndroid Build Coastguard Worker 
3166*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
3167*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kTexSize, kTexSize, GLColor::green);
3168*8975f5c5SAndroid Build Coastguard Worker 
3169*8975f5c5SAndroid Build Coastguard Worker         // Destroy the context.
3170*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglDestroyContext(dpy, ctx1));
3171*8975f5c5SAndroid Build Coastguard Worker     });
3172*8975f5c5SAndroid Build Coastguard Worker 
3173*8975f5c5SAndroid Build Coastguard Worker     thread.join();
3174*8975f5c5SAndroid Build Coastguard Worker }
3175*8975f5c5SAndroid Build Coastguard Worker 
3176*8975f5c5SAndroid Build Coastguard Worker // Test when lots of upload happens on a different thread at the same time as the main thread doing
3177*8975f5c5SAndroid Build Coastguard Worker // draws.
TEST_P(MultithreadingTestES3,SimultaneousUploadAndDraw)3178*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, SimultaneousUploadAndDraw)
3179*8975f5c5SAndroid Build Coastguard Worker {
3180*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3181*8975f5c5SAndroid Build Coastguard Worker 
3182*8975f5c5SAndroid Build Coastguard Worker     // The following shader is used to create busy work while the worker thread is doing something.
3183*8975f5c5SAndroid Build Coastguard Worker     // It intentionally spreads its uniforms and inputs so the main thread has to make many GL
3184*8975f5c5SAndroid Build Coastguard Worker     // calls.
3185*8975f5c5SAndroid Build Coastguard Worker     constexpr char kBusyDrawVS[] = R"(#version 300 es
3186*8975f5c5SAndroid Build Coastguard Worker uniform mediump float x0;
3187*8975f5c5SAndroid Build Coastguard Worker uniform mediump float y0;
3188*8975f5c5SAndroid Build Coastguard Worker uniform mediump float x1;
3189*8975f5c5SAndroid Build Coastguard Worker uniform mediump float y1;
3190*8975f5c5SAndroid Build Coastguard Worker 
3191*8975f5c5SAndroid Build Coastguard Worker in mediump float r;
3192*8975f5c5SAndroid Build Coastguard Worker in mediump float g;
3193*8975f5c5SAndroid Build Coastguard Worker in mediump float b;
3194*8975f5c5SAndroid Build Coastguard Worker in mediump float a;
3195*8975f5c5SAndroid Build Coastguard Worker 
3196*8975f5c5SAndroid Build Coastguard Worker out mediump vec4 color;
3197*8975f5c5SAndroid Build Coastguard Worker 
3198*8975f5c5SAndroid Build Coastguard Worker void main()
3199*8975f5c5SAndroid Build Coastguard Worker {
3200*8975f5c5SAndroid Build Coastguard Worker     // gl_VertexID    x    y
3201*8975f5c5SAndroid Build Coastguard Worker     //      0        -1   -1
3202*8975f5c5SAndroid Build Coastguard Worker     //      1         1   -1
3203*8975f5c5SAndroid Build Coastguard Worker     //      2        -1    1
3204*8975f5c5SAndroid Build Coastguard Worker     //      3         1    1
3205*8975f5c5SAndroid Build Coastguard Worker     int bit0 = gl_VertexID & 1;
3206*8975f5c5SAndroid Build Coastguard Worker     int bit1 = gl_VertexID >> 1;
3207*8975f5c5SAndroid Build Coastguard Worker     gl_Position.x = bit0 == 0 ? x0 : x1;
3208*8975f5c5SAndroid Build Coastguard Worker     gl_Position.y = bit1 == 0 ? y0 : y1;
3209*8975f5c5SAndroid Build Coastguard Worker     gl_Position.z = 0.;
3210*8975f5c5SAndroid Build Coastguard Worker     gl_Position.w = 1.;
3211*8975f5c5SAndroid Build Coastguard Worker 
3212*8975f5c5SAndroid Build Coastguard Worker     color = vec4(r, g, b, a);
3213*8975f5c5SAndroid Build Coastguard Worker })";
3214*8975f5c5SAndroid Build Coastguard Worker     constexpr char kBusyDrawFS[] = R"(#version 300 es
3215*8975f5c5SAndroid Build Coastguard Worker 
3216*8975f5c5SAndroid Build Coastguard Worker in mediump vec4 color;
3217*8975f5c5SAndroid Build Coastguard Worker out mediump vec4 colorOut;
3218*8975f5c5SAndroid Build Coastguard Worker 
3219*8975f5c5SAndroid Build Coastguard Worker void main()
3220*8975f5c5SAndroid Build Coastguard Worker {
3221*8975f5c5SAndroid Build Coastguard Worker     colorOut = color;
3222*8975f5c5SAndroid Build Coastguard Worker })";
3223*8975f5c5SAndroid Build Coastguard Worker 
3224*8975f5c5SAndroid Build Coastguard Worker     // The following shader is used to consume the results of texture uploads, ensuring appropriate
3225*8975f5c5SAndroid Build Coastguard Worker     // synchronization.
3226*8975f5c5SAndroid Build Coastguard Worker     constexpr char kTextureDrawVS[] = R"(#version 300 es
3227*8975f5c5SAndroid Build Coastguard Worker out mediump vec2 uv;
3228*8975f5c5SAndroid Build Coastguard Worker 
3229*8975f5c5SAndroid Build Coastguard Worker void main()
3230*8975f5c5SAndroid Build Coastguard Worker {
3231*8975f5c5SAndroid Build Coastguard Worker     // gl_VertexID    x    y
3232*8975f5c5SAndroid Build Coastguard Worker     //      0        -1   -1
3233*8975f5c5SAndroid Build Coastguard Worker     //      1         1   -1
3234*8975f5c5SAndroid Build Coastguard Worker     //      2        -1    1
3235*8975f5c5SAndroid Build Coastguard Worker     //      3         1    1
3236*8975f5c5SAndroid Build Coastguard Worker     int bit0 = gl_VertexID & 1;
3237*8975f5c5SAndroid Build Coastguard Worker     int bit1 = gl_VertexID >> 1;
3238*8975f5c5SAndroid Build Coastguard Worker     gl_Position = vec4(bit0 * 2 - 1, bit1 * 2 - 1, 0, 1);
3239*8975f5c5SAndroid Build Coastguard Worker     uv = vec2(bit0, bit1);
3240*8975f5c5SAndroid Build Coastguard Worker })";
3241*8975f5c5SAndroid Build Coastguard Worker     constexpr char kTextureDrawFS[] = R"(#version 300 es
3242*8975f5c5SAndroid Build Coastguard Worker 
3243*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s0;
3244*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s1;
3245*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s2;
3246*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s3;
3247*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s4;
3248*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s5;
3249*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s6;
3250*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s7;
3251*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s8;
3252*8975f5c5SAndroid Build Coastguard Worker uniform mediump sampler2D s9;
3253*8975f5c5SAndroid Build Coastguard Worker 
3254*8975f5c5SAndroid Build Coastguard Worker in mediump vec2 uv;
3255*8975f5c5SAndroid Build Coastguard Worker out mediump vec4 colorOut;
3256*8975f5c5SAndroid Build Coastguard Worker 
3257*8975f5c5SAndroid Build Coastguard Worker void main()
3258*8975f5c5SAndroid Build Coastguard Worker {
3259*8975f5c5SAndroid Build Coastguard Worker     highp vec4 result = texture(s0, uv) +
3260*8975f5c5SAndroid Build Coastguard Worker                         texture(s1, uv) +
3261*8975f5c5SAndroid Build Coastguard Worker                         texture(s2, uv) +
3262*8975f5c5SAndroid Build Coastguard Worker                         texture(s3, uv) +
3263*8975f5c5SAndroid Build Coastguard Worker                         texture(s4, uv) +
3264*8975f5c5SAndroid Build Coastguard Worker                         texture(s5, uv) +
3265*8975f5c5SAndroid Build Coastguard Worker                         texture(s6, uv) +
3266*8975f5c5SAndroid Build Coastguard Worker                         texture(s7, uv) +
3267*8975f5c5SAndroid Build Coastguard Worker                         texture(s8, uv) +
3268*8975f5c5SAndroid Build Coastguard Worker                         texture(s9, uv);
3269*8975f5c5SAndroid Build Coastguard Worker     result /= 10.;
3270*8975f5c5SAndroid Build Coastguard Worker 
3271*8975f5c5SAndroid Build Coastguard Worker     colorOut = result;
3272*8975f5c5SAndroid Build Coastguard Worker })";
3273*8975f5c5SAndroid Build Coastguard Worker 
3274*8975f5c5SAndroid Build Coastguard Worker     constexpr uint32_t kTextureCount = 10;
3275*8975f5c5SAndroid Build Coastguard Worker     GLuint textures[kTextureCount];
3276*8975f5c5SAndroid Build Coastguard Worker 
3277*8975f5c5SAndroid Build Coastguard Worker     ASSERT(IsGLExtensionEnabled("GL_KHR_texture_compression_astc_ldr") ||
3278*8975f5c5SAndroid Build Coastguard Worker            IsGLExtensionEnabled("GL_EXT_texture_compression_bptc"));
3279*8975f5c5SAndroid Build Coastguard Worker     // Note ASTC may be emulated in ANGLE, so check for BPTC first
3280*8975f5c5SAndroid Build Coastguard Worker     const bool hasBPTC = IsGLExtensionEnabled("GL_EXT_texture_compression_bptc");
3281*8975f5c5SAndroid Build Coastguard Worker     const GLenum compressedFormat =
3282*8975f5c5SAndroid Build Coastguard Worker         hasBPTC ? GL_COMPRESSED_RGBA_BPTC_UNORM_EXT : GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
3283*8975f5c5SAndroid Build Coastguard Worker 
3284*8975f5c5SAndroid Build Coastguard Worker     std::vector<uint8_t> textureData[kTextureCount];
3285*8975f5c5SAndroid Build Coastguard Worker 
3286*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceWidth  = 256;
3287*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceHeight = 512;
3288*8975f5c5SAndroid Build Coastguard Worker     constexpr int kTexSize       = 1024;
3289*8975f5c5SAndroid Build Coastguard Worker 
3290*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3291*8975f5c5SAndroid Build Coastguard Worker     GLsync sync = nullptr;
3292*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
3293*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
3294*8975f5c5SAndroid Build Coastguard Worker 
3295*8975f5c5SAndroid Build Coastguard Worker     enum class Step
3296*8975f5c5SAndroid Build Coastguard Worker     {
3297*8975f5c5SAndroid Build Coastguard Worker         Start,
3298*8975f5c5SAndroid Build Coastguard Worker         Thread1Ready,
3299*8975f5c5SAndroid Build Coastguard Worker         Thread0UploadFinish,
3300*8975f5c5SAndroid Build Coastguard Worker         Finish,
3301*8975f5c5SAndroid Build Coastguard Worker         Abort,
3302*8975f5c5SAndroid Build Coastguard Worker     };
3303*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
3304*8975f5c5SAndroid Build Coastguard Worker 
3305*8975f5c5SAndroid Build Coastguard Worker     // Threads to upload and draw with textures.
3306*8975f5c5SAndroid Build Coastguard Worker     auto thread0Upload = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3307*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3308*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3309*8975f5c5SAndroid Build Coastguard Worker 
3310*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to set everything up
3311*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Ready));
3312*8975f5c5SAndroid Build Coastguard Worker 
3313*8975f5c5SAndroid Build Coastguard Worker         // Perform uploads while the other thread does draws
3314*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < kTextureCount; ++i)
3315*8975f5c5SAndroid Build Coastguard Worker         {
3316*8975f5c5SAndroid Build Coastguard Worker             glBindTexture(GL_TEXTURE_2D, textures[i]);
3317*8975f5c5SAndroid Build Coastguard Worker             glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTexSize, kTexSize, compressedFormat,
3318*8975f5c5SAndroid Build Coastguard Worker                                       static_cast<GLsizei>(textureData[i].size()),
3319*8975f5c5SAndroid Build Coastguard Worker                                       textureData[i].data());
3320*8975f5c5SAndroid Build Coastguard Worker         }
3321*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3322*8975f5c5SAndroid Build Coastguard Worker 
3323*8975f5c5SAndroid Build Coastguard Worker         // Create a sync object to be used for the draw thread.
3324*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
3325*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(sync, nullptr);
3326*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3327*8975f5c5SAndroid Build Coastguard Worker 
3328*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0UploadFinish);
3329*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3330*8975f5c5SAndroid Build Coastguard Worker     };
3331*8975f5c5SAndroid Build Coastguard Worker 
3332*8975f5c5SAndroid Build Coastguard Worker     auto thread1Draw = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3333*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3334*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3335*8975f5c5SAndroid Build Coastguard Worker 
3336*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(busyDrawProgram, kBusyDrawVS, kBusyDrawFS);
3337*8975f5c5SAndroid Build Coastguard Worker 
3338*8975f5c5SAndroid Build Coastguard Worker         // Set up the test.  Don't let the other thread work yet.
3339*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(busyDrawProgram);
3340*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawX0Loc = glGetUniformLocation(busyDrawProgram, "x0");
3341*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawY0Loc = glGetUniformLocation(busyDrawProgram, "y0");
3342*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawX1Loc = glGetUniformLocation(busyDrawProgram, "x1");
3343*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawY1Loc = glGetUniformLocation(busyDrawProgram, "y1");
3344*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawRLoc  = glGetAttribLocation(busyDrawProgram, "r");
3345*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawGLoc  = glGetAttribLocation(busyDrawProgram, "g");
3346*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawBLoc  = glGetAttribLocation(busyDrawProgram, "b");
3347*8975f5c5SAndroid Build Coastguard Worker         GLuint busyDrawALoc  = glGetAttribLocation(busyDrawProgram, "a");
3348*8975f5c5SAndroid Build Coastguard Worker 
3349*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(textureDrawProgram, kTextureDrawVS, kTextureDrawFS);
3350*8975f5c5SAndroid Build Coastguard Worker         GLuint textureDrawSamplerLoc[kTextureCount] = {};
3351*8975f5c5SAndroid Build Coastguard Worker 
3352*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureDrawProgram);
3353*8975f5c5SAndroid Build Coastguard Worker         glGenTextures(kTextureCount, textures);
3354*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < kTextureCount; ++i)
3355*8975f5c5SAndroid Build Coastguard Worker         {
3356*8975f5c5SAndroid Build Coastguard Worker             std::ostringstream name;
3357*8975f5c5SAndroid Build Coastguard Worker             name << "s" << i;
3358*8975f5c5SAndroid Build Coastguard Worker 
3359*8975f5c5SAndroid Build Coastguard Worker             textureDrawSamplerLoc[i] = glGetUniformLocation(textureDrawProgram, name.str().c_str());
3360*8975f5c5SAndroid Build Coastguard Worker 
3361*8975f5c5SAndroid Build Coastguard Worker             glBindTexture(GL_TEXTURE_2D, textures[i]);
3362*8975f5c5SAndroid Build Coastguard Worker             glTexStorage2D(GL_TEXTURE_2D, 1, compressedFormat, kTexSize, kTexSize);
3363*8975f5c5SAndroid Build Coastguard Worker 
3364*8975f5c5SAndroid Build Coastguard Worker             // Both ASTC 4x4 and BPTC have 1 byte per pixel.  The textures' contents are arbitrary
3365*8975f5c5SAndroid Build Coastguard Worker             // but distinct.
3366*8975f5c5SAndroid Build Coastguard Worker             textureData[i].resize(kTexSize * kTexSize);
3367*8975f5c5SAndroid Build Coastguard Worker             for (int y = 0; y < kTexSize; ++y)
3368*8975f5c5SAndroid Build Coastguard Worker             {
3369*8975f5c5SAndroid Build Coastguard Worker                 for (int x = 0; x < kTexSize; ++x)
3370*8975f5c5SAndroid Build Coastguard Worker                 {
3371*8975f5c5SAndroid Build Coastguard Worker                     textureData[i][y * kTexSize + x] = (i * 50 + y + x) % 255;
3372*8975f5c5SAndroid Build Coastguard Worker                 }
3373*8975f5c5SAndroid Build Coastguard Worker             }
3374*8975f5c5SAndroid Build Coastguard Worker         }
3375*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3376*8975f5c5SAndroid Build Coastguard Worker 
3377*8975f5c5SAndroid Build Coastguard Worker         // Now that everything is set up, let the upload thread work while this thread does draws.
3378*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Ready);
3379*8975f5c5SAndroid Build Coastguard Worker 
3380*8975f5c5SAndroid Build Coastguard Worker         int w = kSurfaceWidth;
3381*8975f5c5SAndroid Build Coastguard Worker         int h = kSurfaceHeight;
3382*8975f5c5SAndroid Build Coastguard Worker 
3383*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
3384*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, w, h);
3385*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(busyDrawProgram);
3386*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t y = 0; y < 8; ++y)
3387*8975f5c5SAndroid Build Coastguard Worker         {
3388*8975f5c5SAndroid Build Coastguard Worker             for (uint32_t x = 0; x < 8; ++x)
3389*8975f5c5SAndroid Build Coastguard Worker             {
3390*8975f5c5SAndroid Build Coastguard Worker                 float width  = w / 4;
3391*8975f5c5SAndroid Build Coastguard Worker                 float height = h / 8;
3392*8975f5c5SAndroid Build Coastguard Worker 
3393*8975f5c5SAndroid Build Coastguard Worker                 glUniform1f(busyDrawX0Loc, x * width / w - 1);
3394*8975f5c5SAndroid Build Coastguard Worker                 glUniform1f(busyDrawY0Loc, y * height / h);
3395*8975f5c5SAndroid Build Coastguard Worker                 glUniform1f(busyDrawX1Loc, (x + 1) * width / w - 1);
3396*8975f5c5SAndroid Build Coastguard Worker                 glUniform1f(busyDrawY1Loc, (y + 1) * height / h);
3397*8975f5c5SAndroid Build Coastguard Worker 
3398*8975f5c5SAndroid Build Coastguard Worker                 glVertexAttrib1f(busyDrawRLoc, x / 8.0f);
3399*8975f5c5SAndroid Build Coastguard Worker                 glVertexAttrib1f(busyDrawGLoc, y / 8.0f);
3400*8975f5c5SAndroid Build Coastguard Worker                 glVertexAttrib1f(busyDrawBLoc, 0);
3401*8975f5c5SAndroid Build Coastguard Worker                 glVertexAttrib1f(busyDrawALoc, 1);
3402*8975f5c5SAndroid Build Coastguard Worker 
3403*8975f5c5SAndroid Build Coastguard Worker                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3404*8975f5c5SAndroid Build Coastguard Worker             }
3405*8975f5c5SAndroid Build Coastguard Worker         }
3406*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3407*8975f5c5SAndroid Build Coastguard Worker 
3408*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to finish with uploads.
3409*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.waitForStep(Step::Thread0UploadFinish);
3410*8975f5c5SAndroid Build Coastguard Worker 
3411*8975f5c5SAndroid Build Coastguard Worker         // Wait for fence and use all textures in a draw.
3412*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
3413*8975f5c5SAndroid Build Coastguard Worker 
3414*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(textureDrawProgram);
3415*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < kTextureCount; ++i)
3416*8975f5c5SAndroid Build Coastguard Worker         {
3417*8975f5c5SAndroid Build Coastguard Worker             glActiveTexture(GL_TEXTURE0 + i);
3418*8975f5c5SAndroid Build Coastguard Worker             glBindTexture(GL_TEXTURE_2D, textures[i]);
3419*8975f5c5SAndroid Build Coastguard Worker             glUniform1i(textureDrawSamplerLoc[i], i);
3420*8975f5c5SAndroid Build Coastguard Worker         }
3421*8975f5c5SAndroid Build Coastguard Worker         glViewport(0, 0, w, h / 2);
3422*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3423*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3424*8975f5c5SAndroid Build Coastguard Worker 
3425*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3426*8975f5c5SAndroid Build Coastguard Worker 
3427*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3428*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t y = 0; y < 8; ++y)
3429*8975f5c5SAndroid Build Coastguard Worker         {
3430*8975f5c5SAndroid Build Coastguard Worker             for (uint32_t x = 0; x < 8; ++x)
3431*8975f5c5SAndroid Build Coastguard Worker             {
3432*8975f5c5SAndroid Build Coastguard Worker                 int width  = w / 8;
3433*8975f5c5SAndroid Build Coastguard Worker                 int height = h / 16;
3434*8975f5c5SAndroid Build Coastguard Worker 
3435*8975f5c5SAndroid Build Coastguard Worker                 EXPECT_PIXEL_COLOR_NEAR(x * width + width / 2, h - (y * height + height / 2),
3436*8975f5c5SAndroid Build Coastguard Worker                                         GLColor(x * 255 / 8, (7 - y) * 255 / 8, 0, 255), 1);
3437*8975f5c5SAndroid Build Coastguard Worker             }
3438*8975f5c5SAndroid Build Coastguard Worker         }
3439*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3440*8975f5c5SAndroid Build Coastguard Worker 
3441*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t x = 0; x < 8; ++x)
3442*8975f5c5SAndroid Build Coastguard Worker         {
3443*8975f5c5SAndroid Build Coastguard Worker             // The compressed data is gibberish, just ensure it's not all black.
3444*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_NE(x * w / 8, h / 4, 0, 0, 0, 0);
3445*8975f5c5SAndroid Build Coastguard Worker         }
3446*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3447*8975f5c5SAndroid Build Coastguard Worker     };
3448*8975f5c5SAndroid Build Coastguard Worker 
3449*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3450*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0Upload),
3451*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1Draw),
3452*8975f5c5SAndroid Build Coastguard Worker     };
3453*8975f5c5SAndroid Build Coastguard Worker 
3454*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreadsWithSize(getEGLWindow(), kSurfaceWidth, kSurfaceHeight, threadFuncs.size(),
3455*8975f5c5SAndroid Build Coastguard Worker                                threadFuncs.data());
3456*8975f5c5SAndroid Build Coastguard Worker 
3457*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3458*8975f5c5SAndroid Build Coastguard Worker }
3459*8975f5c5SAndroid Build Coastguard Worker 
3460*8975f5c5SAndroid Build Coastguard Worker // Test that calling glUniformBlockBinding on one context affects all contexts.
TEST_P(MultithreadingTestES3,UniformBlockBinding)3461*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, UniformBlockBinding)
3462*8975f5c5SAndroid Build Coastguard Worker {
3463*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3464*8975f5c5SAndroid Build Coastguard Worker 
3465*8975f5c5SAndroid Build Coastguard Worker     constexpr char kVS[] = R"(#version 300 es
3466*8975f5c5SAndroid Build Coastguard Worker void main()
3467*8975f5c5SAndroid Build Coastguard Worker {
3468*8975f5c5SAndroid Build Coastguard Worker     vec2 pos = vec2(0.0);
3469*8975f5c5SAndroid Build Coastguard Worker     switch (gl_VertexID) {
3470*8975f5c5SAndroid Build Coastguard Worker         case 0: pos = vec2(-1.0, -1.0); break;
3471*8975f5c5SAndroid Build Coastguard Worker         case 1: pos = vec2(3.0, -1.0); break;
3472*8975f5c5SAndroid Build Coastguard Worker         case 2: pos = vec2(-1.0, 3.0); break;
3473*8975f5c5SAndroid Build Coastguard Worker     };
3474*8975f5c5SAndroid Build Coastguard Worker     gl_Position = vec4(pos, 0.0, 1.0);
3475*8975f5c5SAndroid Build Coastguard Worker })";
3476*8975f5c5SAndroid Build Coastguard Worker     constexpr char kFS[] = R"(#version 300 es
3477*8975f5c5SAndroid Build Coastguard Worker out mediump vec4 colorOut;
3478*8975f5c5SAndroid Build Coastguard Worker 
3479*8975f5c5SAndroid Build Coastguard Worker layout(std140) uniform buffer { mediump vec4 color; };
3480*8975f5c5SAndroid Build Coastguard Worker 
3481*8975f5c5SAndroid Build Coastguard Worker void main()
3482*8975f5c5SAndroid Build Coastguard Worker {
3483*8975f5c5SAndroid Build Coastguard Worker     colorOut = color;
3484*8975f5c5SAndroid Build Coastguard Worker })";
3485*8975f5c5SAndroid Build Coastguard Worker 
3486*8975f5c5SAndroid Build Coastguard Worker     GLProgram program;
3487*8975f5c5SAndroid Build Coastguard Worker     GLint uniformBufferIndex;
3488*8975f5c5SAndroid Build Coastguard Worker 
3489*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3490*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
3491*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
3492*8975f5c5SAndroid Build Coastguard Worker 
3493*8975f5c5SAndroid Build Coastguard Worker     enum class Step
3494*8975f5c5SAndroid Build Coastguard Worker     {
3495*8975f5c5SAndroid Build Coastguard Worker         Start,
3496*8975f5c5SAndroid Build Coastguard Worker         Thread1Ready,
3497*8975f5c5SAndroid Build Coastguard Worker         Thread0BindingChanged,
3498*8975f5c5SAndroid Build Coastguard Worker         Thread1FinishedDrawing,
3499*8975f5c5SAndroid Build Coastguard Worker         Finish,
3500*8975f5c5SAndroid Build Coastguard Worker         Abort,
3501*8975f5c5SAndroid Build Coastguard Worker     };
3502*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
3503*8975f5c5SAndroid Build Coastguard Worker 
3504*8975f5c5SAndroid Build Coastguard Worker     // Threads to create programs and draw with different uniform blocks.
3505*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3506*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3507*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3508*8975f5c5SAndroid Build Coastguard Worker 
3509*8975f5c5SAndroid Build Coastguard Worker         // Create buffers bound to bindings 1 and 2
3510*8975f5c5SAndroid Build Coastguard Worker         constexpr std::array<float, 4> kRed              = {1, 0, 0, 1};
3511*8975f5c5SAndroid Build Coastguard Worker         constexpr std::array<float, 4> kTransparentGreen = {0, 1, 0, 0};
3512*8975f5c5SAndroid Build Coastguard Worker         GLBuffer red, transparentGreen;
3513*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, red);
3514*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_UNIFORM_BUFFER, sizeof(kRed), kRed.data(), GL_STATIC_DRAW);
3515*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, transparentGreen);
3516*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_UNIFORM_BUFFER, sizeof(kTransparentGreen), kTransparentGreen.data(),
3517*8975f5c5SAndroid Build Coastguard Worker                      GL_STATIC_DRAW);
3518*8975f5c5SAndroid Build Coastguard Worker 
3519*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_UNIFORM_BUFFER, 1, transparentGreen);
3520*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_UNIFORM_BUFFER, 2, red);
3521*8975f5c5SAndroid Build Coastguard Worker 
3522*8975f5c5SAndroid Build Coastguard Worker         // Wait for the other thread to set everything up
3523*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Ready));
3524*8975f5c5SAndroid Build Coastguard Worker 
3525*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw call.  The buffer should be transparent green now
3526*8975f5c5SAndroid Build Coastguard Worker         glClearColor(0, 0, 0, 0);
3527*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
3528*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_BLEND);
3529*8975f5c5SAndroid Build Coastguard Worker         glBlendFunc(GL_ONE, GL_ONE);
3530*8975f5c5SAndroid Build Coastguard Worker 
3531*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3532*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLES, 0, 3);
3533*8975f5c5SAndroid Build Coastguard Worker 
3534*8975f5c5SAndroid Build Coastguard Worker         // Change the binding
3535*8975f5c5SAndroid Build Coastguard Worker         glUniformBlockBinding(program, uniformBufferIndex, 1);
3536*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3537*8975f5c5SAndroid Build Coastguard Worker 
3538*8975f5c5SAndroid Build Coastguard Worker         // Let the other thread work before any deferred operations for the binding change above are
3539*8975f5c5SAndroid Build Coastguard Worker         // processed in this context.
3540*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0BindingChanged);
3541*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1FinishedDrawing));
3542*8975f5c5SAndroid Build Coastguard Worker 
3543*8975f5c5SAndroid Build Coastguard Worker         // Draw again, it should accumulate blue and the buffer should become magenta.
3544*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLES, 0, 3);
3545*8975f5c5SAndroid Build Coastguard Worker 
3546*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3547*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
3548*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3549*8975f5c5SAndroid Build Coastguard Worker 
3550*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3551*8975f5c5SAndroid Build Coastguard Worker     };
3552*8975f5c5SAndroid Build Coastguard Worker 
3553*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3554*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3555*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3556*8975f5c5SAndroid Build Coastguard Worker 
3557*8975f5c5SAndroid Build Coastguard Worker         // Create buffers bound to bindings 1 and 2
3558*8975f5c5SAndroid Build Coastguard Worker         constexpr std::array<float, 4> kBlue           = {0, 0, 1, 1};
3559*8975f5c5SAndroid Build Coastguard Worker         constexpr std::array<float, 4> kTransparentRed = {1, 0, 0, 0};
3560*8975f5c5SAndroid Build Coastguard Worker         GLBuffer blue, transparentRed;
3561*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, blue);
3562*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_UNIFORM_BUFFER, sizeof(kBlue), kBlue.data(), GL_STATIC_DRAW);
3563*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, transparentRed);
3564*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_UNIFORM_BUFFER, sizeof(kTransparentRed), kTransparentRed.data(),
3565*8975f5c5SAndroid Build Coastguard Worker                      GL_STATIC_DRAW);
3566*8975f5c5SAndroid Build Coastguard Worker 
3567*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_UNIFORM_BUFFER, 1, blue);
3568*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_UNIFORM_BUFFER, 2, transparentRed);
3569*8975f5c5SAndroid Build Coastguard Worker 
3570*8975f5c5SAndroid Build Coastguard Worker         // Create the program
3571*8975f5c5SAndroid Build Coastguard Worker         program.makeRaster(kVS, kFS);
3572*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3573*8975f5c5SAndroid Build Coastguard Worker         uniformBufferIndex = glGetUniformBlockIndex(program, "buffer");
3574*8975f5c5SAndroid Build Coastguard Worker 
3575*8975f5c5SAndroid Build Coastguard Worker         // Configure the buffer binding to binding 2
3576*8975f5c5SAndroid Build Coastguard Worker         glUniformBlockBinding(program, uniformBufferIndex, 2);
3577*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3578*8975f5c5SAndroid Build Coastguard Worker 
3579*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw call.  The buffer should be transparent red now
3580*8975f5c5SAndroid Build Coastguard Worker         glClearColor(0, 0, 0, 0);
3581*8975f5c5SAndroid Build Coastguard Worker         glClear(GL_COLOR_BUFFER_BIT);
3582*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_BLEND);
3583*8975f5c5SAndroid Build Coastguard Worker         glBlendFunc(GL_ONE, GL_ONE);
3584*8975f5c5SAndroid Build Coastguard Worker 
3585*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLES, 0, 3);
3586*8975f5c5SAndroid Build Coastguard Worker 
3587*8975f5c5SAndroid Build Coastguard Worker         // Now that everything is set up, let the other thread continue
3588*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Ready);
3589*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0BindingChanged));
3590*8975f5c5SAndroid Build Coastguard Worker 
3591*8975f5c5SAndroid Build Coastguard Worker         // The other thread has changed the binding.  Draw again, it should accumulate blue and the
3592*8975f5c5SAndroid Build Coastguard Worker         // buffer should become magenta.
3593*8975f5c5SAndroid Build Coastguard Worker         glDrawArrays(GL_TRIANGLES, 0, 3);
3594*8975f5c5SAndroid Build Coastguard Worker 
3595*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3596*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
3597*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3598*8975f5c5SAndroid Build Coastguard Worker 
3599*8975f5c5SAndroid Build Coastguard Worker         // Tell the other thread to finish up.
3600*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1FinishedDrawing);
3601*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3602*8975f5c5SAndroid Build Coastguard Worker     };
3603*8975f5c5SAndroid Build Coastguard Worker 
3604*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3605*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
3606*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
3607*8975f5c5SAndroid Build Coastguard Worker     };
3608*8975f5c5SAndroid Build Coastguard Worker 
3609*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
3610*8975f5c5SAndroid Build Coastguard Worker 
3611*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3612*8975f5c5SAndroid Build Coastguard Worker }
3613*8975f5c5SAndroid Build Coastguard Worker 
3614*8975f5c5SAndroid Build Coastguard Worker // Test that observers are notified of a change in foveation state of a texture
TEST_P(MultithreadingTestES3,SharedFoveatedTexture)3615*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, SharedFoveatedTexture)
3616*8975f5c5SAndroid Build Coastguard Worker {
3617*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3618*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_foveated"));
3619*8975f5c5SAndroid Build Coastguard Worker 
3620*8975f5c5SAndroid Build Coastguard Worker     // Shared texture
3621*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture;
3622*8975f5c5SAndroid Build Coastguard Worker 
3623*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3624*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
3625*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
3626*8975f5c5SAndroid Build Coastguard Worker 
3627*8975f5c5SAndroid Build Coastguard Worker     enum class Step
3628*8975f5c5SAndroid Build Coastguard Worker     {
3629*8975f5c5SAndroid Build Coastguard Worker         Start,
3630*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw,
3631*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw,
3632*8975f5c5SAndroid Build Coastguard Worker         Thread0ConfiguredTextureFoveation,
3633*8975f5c5SAndroid Build Coastguard Worker         Finish,
3634*8975f5c5SAndroid Build Coastguard Worker         Abort,
3635*8975f5c5SAndroid Build Coastguard Worker     };
3636*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
3637*8975f5c5SAndroid Build Coastguard Worker 
3638*8975f5c5SAndroid Build Coastguard Worker     // Thread to configure texture foveation.
3639*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3640*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3641*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3642*8975f5c5SAndroid Build Coastguard Worker 
3643*8975f5c5SAndroid Build Coastguard Worker         // Create non-foveated framebuffer and attach shared texture as color attachment
3644*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer framebuffer;
3645*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3646*8975f5c5SAndroid Build Coastguard Worker         glActiveTexture(GL_TEXTURE0);
3647*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
3648*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
3649*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, nullptr);
3650*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3651*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3652*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3653*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3654*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3655*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
3656*8975f5c5SAndroid Build Coastguard Worker 
3657*8975f5c5SAndroid Build Coastguard Worker         // Render before configuring foveation on the texture
3658*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
3659*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(greenProgram);
3660*8975f5c5SAndroid Build Coastguard Worker 
3661*8975f5c5SAndroid Build Coastguard Worker         // Draw
3662*8975f5c5SAndroid Build Coastguard Worker         drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
3663*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3664*8975f5c5SAndroid Build Coastguard Worker 
3665*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3666*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3667*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3668*8975f5c5SAndroid Build Coastguard Worker 
3669*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Draw);
3670*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Draw));
3671*8975f5c5SAndroid Build Coastguard Worker 
3672*8975f5c5SAndroid Build Coastguard Worker         // Configure foveation for the texture
3673*8975f5c5SAndroid Build Coastguard Worker         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FOVEATED_FEATURE_BITS_QCOM,
3674*8975f5c5SAndroid Build Coastguard Worker                         GL_FOVEATION_ENABLE_BIT_QCOM);
3675*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3676*8975f5c5SAndroid Build Coastguard Worker         glTextureFoveationParametersQCOM(texture, 0, 0, 0.0f, 0.0f, 8.0f, 8.0f, 0.0f);
3677*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3678*8975f5c5SAndroid Build Coastguard Worker 
3679*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0ConfiguredTextureFoveation);
3680*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3681*8975f5c5SAndroid Build Coastguard Worker     };
3682*8975f5c5SAndroid Build Coastguard Worker 
3683*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3684*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3685*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3686*8975f5c5SAndroid Build Coastguard Worker 
3687*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw));
3688*8975f5c5SAndroid Build Coastguard Worker 
3689*8975f5c5SAndroid Build Coastguard Worker         // Create non-foveated framebuffer and attach shared texture as color attachment
3690*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer framebuffer;
3691*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3692*8975f5c5SAndroid Build Coastguard Worker         glActiveTexture(GL_TEXTURE0);
3693*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
3694*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3695*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3696*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
3697*8975f5c5SAndroid Build Coastguard Worker 
3698*8975f5c5SAndroid Build Coastguard Worker         // Render before configuring foveation on the texture
3699*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
3700*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(redProgram);
3701*8975f5c5SAndroid Build Coastguard Worker 
3702*8975f5c5SAndroid Build Coastguard Worker         // Draw
3703*8975f5c5SAndroid Build Coastguard Worker         drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
3704*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3705*8975f5c5SAndroid Build Coastguard Worker 
3706*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3707*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
3708*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3709*8975f5c5SAndroid Build Coastguard Worker 
3710*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Draw);
3711*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0ConfiguredTextureFoveation));
3712*8975f5c5SAndroid Build Coastguard Worker 
3713*8975f5c5SAndroid Build Coastguard Worker         // Render after texture foveation was configured
3714*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
3715*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(blueProgram);
3716*8975f5c5SAndroid Build Coastguard Worker 
3717*8975f5c5SAndroid Build Coastguard Worker         // Draw
3718*8975f5c5SAndroid Build Coastguard Worker         drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
3719*8975f5c5SAndroid Build Coastguard Worker         EXPECT_GL_NO_ERROR();
3720*8975f5c5SAndroid Build Coastguard Worker 
3721*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3722*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
3723*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3724*8975f5c5SAndroid Build Coastguard Worker 
3725*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3726*8975f5c5SAndroid Build Coastguard Worker     };
3727*8975f5c5SAndroid Build Coastguard Worker 
3728*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3729*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
3730*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
3731*8975f5c5SAndroid Build Coastguard Worker     };
3732*8975f5c5SAndroid Build Coastguard Worker 
3733*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
3734*8975f5c5SAndroid Build Coastguard Worker 
3735*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3736*8975f5c5SAndroid Build Coastguard Worker }
3737*8975f5c5SAndroid Build Coastguard Worker 
3738*8975f5c5SAndroid Build Coastguard Worker // Test GL_EXT_sRGB_write_control works as expected when multiple contexts are used
TEST_P(MultithreadingTestES3,SharedSrgbTextureMultipleContexts)3739*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, SharedSrgbTextureMultipleContexts)
3740*8975f5c5SAndroid Build Coastguard Worker {
3741*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3742*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB_write_control"));
3743*8975f5c5SAndroid Build Coastguard Worker 
3744*8975f5c5SAndroid Build Coastguard Worker     constexpr angle::GLColor encodedToSrgbColor(64, 127, 191, 255);
3745*8975f5c5SAndroid Build Coastguard Worker     constexpr angle::GLColor inputColor(13, 54, 133, 255);
3746*8975f5c5SAndroid Build Coastguard Worker 
3747*8975f5c5SAndroid Build Coastguard Worker     EGLWindow *window   = getEGLWindow();
3748*8975f5c5SAndroid Build Coastguard Worker     EGLDisplay dpy      = window->getDisplay();
3749*8975f5c5SAndroid Build Coastguard Worker     EGLContext context1 = window->createContext(EGL_NO_CONTEXT, nullptr);
3750*8975f5c5SAndroid Build Coastguard Worker     EGLContext context2 = window->createContext(context1, nullptr);
3751*8975f5c5SAndroid Build Coastguard Worker 
3752*8975f5c5SAndroid Build Coastguard Worker     // Shared texture
3753*8975f5c5SAndroid Build Coastguard Worker     GLTexture texture;
3754*8975f5c5SAndroid Build Coastguard Worker 
3755*8975f5c5SAndroid Build Coastguard Worker     // Shared program
3756*8975f5c5SAndroid Build Coastguard Worker     GLuint program;
3757*8975f5c5SAndroid Build Coastguard Worker 
3758*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3759*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
3760*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
3761*8975f5c5SAndroid Build Coastguard Worker 
3762*8975f5c5SAndroid Build Coastguard Worker     enum class Step
3763*8975f5c5SAndroid Build Coastguard Worker     {
3764*8975f5c5SAndroid Build Coastguard Worker         Start,
3765*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw1,
3766*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw1,
3767*8975f5c5SAndroid Build Coastguard Worker         Thread0Draw2,
3768*8975f5c5SAndroid Build Coastguard Worker         Thread1Draw2,
3769*8975f5c5SAndroid Build Coastguard Worker         Finish,
3770*8975f5c5SAndroid Build Coastguard Worker         Abort,
3771*8975f5c5SAndroid Build Coastguard Worker     };
3772*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
3773*8975f5c5SAndroid Build Coastguard Worker 
3774*8975f5c5SAndroid Build Coastguard Worker     // Thread0 rendering to shared texture.
3775*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3776*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3777*8975f5c5SAndroid Build Coastguard Worker 
3778*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context1));
3779*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
3780*8975f5c5SAndroid Build Coastguard Worker 
3781*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
3782*8975f5c5SAndroid Build Coastguard Worker         glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA_EXT, 1, 1, 0, GL_SRGB_ALPHA_EXT,
3783*8975f5c5SAndroid Build Coastguard Worker                      GL_UNSIGNED_BYTE, nullptr);
3784*8975f5c5SAndroid Build Coastguard Worker 
3785*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer framebuffer;
3786*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3787*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3788*8975f5c5SAndroid Build Coastguard Worker 
3789*8975f5c5SAndroid Build Coastguard Worker         program = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
3790*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(0u, program);
3791*8975f5c5SAndroid Build Coastguard Worker 
3792*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
3793*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(-1, colorLocation);
3794*8975f5c5SAndroid Build Coastguard Worker 
3795*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3796*8975f5c5SAndroid Build Coastguard Worker         glUniform4fv(colorLocation, 1, inputColor.toNormalizedVector().data());
3797*8975f5c5SAndroid Build Coastguard Worker 
3798*8975f5c5SAndroid Build Coastguard Worker         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
3799*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
3800*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(0, 0, inputColor, 1.0);
3801*8975f5c5SAndroid Build Coastguard Worker 
3802*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Draw1);
3803*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Draw1));
3804*8975f5c5SAndroid Build Coastguard Worker 
3805*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_FRAMEBUFFER_SRGB_EXT);
3806*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
3807*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(0, 0, encodedToSrgbColor, 1.0);
3808*8975f5c5SAndroid Build Coastguard Worker 
3809*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Draw2);
3810*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Draw2));
3811*8975f5c5SAndroid Build Coastguard Worker 
3812*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
3813*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
3814*8975f5c5SAndroid Build Coastguard Worker 
3815*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3816*8975f5c5SAndroid Build Coastguard Worker     };
3817*8975f5c5SAndroid Build Coastguard Worker 
3818*8975f5c5SAndroid Build Coastguard Worker     // Thread1 rendering to shared texture.
3819*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3820*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3821*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context2));
3822*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
3823*8975f5c5SAndroid Build Coastguard Worker 
3824*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw1));
3825*8975f5c5SAndroid Build Coastguard Worker 
3826*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
3827*8975f5c5SAndroid Build Coastguard Worker         GLFramebuffer framebuffer;
3828*8975f5c5SAndroid Build Coastguard Worker         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3829*8975f5c5SAndroid Build Coastguard Worker         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
3830*8975f5c5SAndroid Build Coastguard Worker 
3831*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(0u, program);
3832*8975f5c5SAndroid Build Coastguard Worker         GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
3833*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(-1, colorLocation);
3834*8975f5c5SAndroid Build Coastguard Worker 
3835*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3836*8975f5c5SAndroid Build Coastguard Worker         glUniform4fv(colorLocation, 1, inputColor.toNormalizedVector().data());
3837*8975f5c5SAndroid Build Coastguard Worker 
3838*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
3839*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(0, 0, encodedToSrgbColor, 1.0);
3840*8975f5c5SAndroid Build Coastguard Worker 
3841*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Draw1);
3842*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw2));
3843*8975f5c5SAndroid Build Coastguard Worker 
3844*8975f5c5SAndroid Build Coastguard Worker         glBindTexture(GL_TEXTURE_2D, texture);
3845*8975f5c5SAndroid Build Coastguard Worker         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
3846*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
3847*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_NEAR(0, 0, inputColor, 1.0);
3848*8975f5c5SAndroid Build Coastguard Worker 
3849*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Draw2);
3850*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3851*8975f5c5SAndroid Build Coastguard Worker 
3852*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
3853*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_SUCCESS();
3854*8975f5c5SAndroid Build Coastguard Worker     };
3855*8975f5c5SAndroid Build Coastguard Worker 
3856*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3857*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
3858*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
3859*8975f5c5SAndroid Build Coastguard Worker     };
3860*8975f5c5SAndroid Build Coastguard Worker 
3861*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
3862*8975f5c5SAndroid Build Coastguard Worker 
3863*8975f5c5SAndroid Build Coastguard Worker     // Cleanup
3864*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context1));
3865*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_TRUE(eglDestroyContext(dpy, context2));
3866*8975f5c5SAndroid Build Coastguard Worker     EXPECT_EGL_SUCCESS();
3867*8975f5c5SAndroid Build Coastguard Worker 
3868*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3869*8975f5c5SAndroid Build Coastguard Worker }
3870*8975f5c5SAndroid Build Coastguard Worker 
3871*8975f5c5SAndroid Build Coastguard Worker // Test that a program linked in one context can be bound in another context while link may be
3872*8975f5c5SAndroid Build Coastguard Worker // happening in parallel.
TEST_P(MultithreadingTest,ProgramLinkAndBind)3873*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTest, ProgramLinkAndBind)
3874*8975f5c5SAndroid Build Coastguard Worker {
3875*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3876*8975f5c5SAndroid Build Coastguard Worker 
3877*8975f5c5SAndroid Build Coastguard Worker     GLuint vs;
3878*8975f5c5SAndroid Build Coastguard Worker     GLuint redfs;
3879*8975f5c5SAndroid Build Coastguard Worker     GLuint greenfs;
3880*8975f5c5SAndroid Build Coastguard Worker 
3881*8975f5c5SAndroid Build Coastguard Worker     GLuint program;
3882*8975f5c5SAndroid Build Coastguard Worker 
3883*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3884*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
3885*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
3886*8975f5c5SAndroid Build Coastguard Worker 
3887*8975f5c5SAndroid Build Coastguard Worker     enum class Step
3888*8975f5c5SAndroid Build Coastguard Worker     {
3889*8975f5c5SAndroid Build Coastguard Worker         Start,
3890*8975f5c5SAndroid Build Coastguard Worker         Thread1Ready,
3891*8975f5c5SAndroid Build Coastguard Worker         Thread0ProgramLinked,
3892*8975f5c5SAndroid Build Coastguard Worker         Thread1FinishedDrawing,
3893*8975f5c5SAndroid Build Coastguard Worker         Finish,
3894*8975f5c5SAndroid Build Coastguard Worker         Abort,
3895*8975f5c5SAndroid Build Coastguard Worker     };
3896*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
3897*8975f5c5SAndroid Build Coastguard Worker 
3898*8975f5c5SAndroid Build Coastguard Worker     // Threads to create programs and draw.
3899*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3900*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3901*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3902*8975f5c5SAndroid Build Coastguard Worker 
3903*8975f5c5SAndroid Build Coastguard Worker         // Wait for thread 1 to bind the program before linking it
3904*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Ready));
3905*8975f5c5SAndroid Build Coastguard Worker 
3906*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3907*8975f5c5SAndroid Build Coastguard Worker 
3908*8975f5c5SAndroid Build Coastguard Worker         // Link a program, but don't resolve link.
3909*8975f5c5SAndroid Build Coastguard Worker         glDetachShader(program, greenfs);
3910*8975f5c5SAndroid Build Coastguard Worker         glAttachShader(program, redfs);
3911*8975f5c5SAndroid Build Coastguard Worker         glLinkProgram(program);
3912*8975f5c5SAndroid Build Coastguard Worker 
3913*8975f5c5SAndroid Build Coastguard Worker         // Let the other thread bind and use the program.
3914*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0ProgramLinked);
3915*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1FinishedDrawing));
3916*8975f5c5SAndroid Build Coastguard Worker 
3917*8975f5c5SAndroid Build Coastguard Worker         // Draw in this context too
3918*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0);
3919*8975f5c5SAndroid Build Coastguard Worker 
3920*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3921*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
3922*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3923*8975f5c5SAndroid Build Coastguard Worker 
3924*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
3925*8975f5c5SAndroid Build Coastguard Worker     };
3926*8975f5c5SAndroid Build Coastguard Worker 
3927*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
3928*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
3929*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
3930*8975f5c5SAndroid Build Coastguard Worker 
3931*8975f5c5SAndroid Build Coastguard Worker         vs      = CompileShader(GL_VERTEX_SHADER, essl1_shaders::vs::Simple());
3932*8975f5c5SAndroid Build Coastguard Worker         redfs   = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Red());
3933*8975f5c5SAndroid Build Coastguard Worker         greenfs = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Green());
3934*8975f5c5SAndroid Build Coastguard Worker         program = glCreateProgram();
3935*8975f5c5SAndroid Build Coastguard Worker 
3936*8975f5c5SAndroid Build Coastguard Worker         glAttachShader(program, vs);
3937*8975f5c5SAndroid Build Coastguard Worker         glAttachShader(program, greenfs);
3938*8975f5c5SAndroid Build Coastguard Worker         glLinkProgram(program);
3939*8975f5c5SAndroid Build Coastguard Worker         ASSERT_NE(CheckLinkStatusAndReturnProgram(program, true), 0u);
3940*8975f5c5SAndroid Build Coastguard Worker 
3941*8975f5c5SAndroid Build Coastguard Worker         // Bind the program before it's relinked.  Otherwise the program is resolved before the
3942*8975f5c5SAndroid Build Coastguard Worker         // binding happens.
3943*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3944*8975f5c5SAndroid Build Coastguard Worker 
3945*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Ready);
3946*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0ProgramLinked));
3947*8975f5c5SAndroid Build Coastguard Worker 
3948*8975f5c5SAndroid Build Coastguard Worker         // Unbind and rebind for extra testing
3949*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(0);
3950*8975f5c5SAndroid Build Coastguard Worker         glUseProgram(program);
3951*8975f5c5SAndroid Build Coastguard Worker 
3952*8975f5c5SAndroid Build Coastguard Worker         // Issue a draw call
3953*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl1_shaders::PositionAttrib(), 0);
3954*8975f5c5SAndroid Build Coastguard Worker 
3955*8975f5c5SAndroid Build Coastguard Worker         // Verify results
3956*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
3957*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
3958*8975f5c5SAndroid Build Coastguard Worker 
3959*8975f5c5SAndroid Build Coastguard Worker         // Tell the other thread to finish up.
3960*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1FinishedDrawing);
3961*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
3962*8975f5c5SAndroid Build Coastguard Worker     };
3963*8975f5c5SAndroid Build Coastguard Worker 
3964*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
3965*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
3966*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
3967*8975f5c5SAndroid Build Coastguard Worker     };
3968*8975f5c5SAndroid Build Coastguard Worker 
3969*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreads(getEGLWindow(), threadFuncs.size(), threadFuncs.data());
3970*8975f5c5SAndroid Build Coastguard Worker 
3971*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
3972*8975f5c5SAndroid Build Coastguard Worker }
3973*8975f5c5SAndroid Build Coastguard Worker 
3974*8975f5c5SAndroid Build Coastguard Worker // Test that two contexts in share group can generate, delete and bind buffers for themselves in
3975*8975f5c5SAndroid Build Coastguard Worker // parallel.
TEST_P(MultithreadingTestES3,SimultaneousBufferBindAndGen)3976*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, SimultaneousBufferBindAndGen)
3977*8975f5c5SAndroid Build Coastguard Worker {
3978*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
3979*8975f5c5SAndroid Build Coastguard Worker 
3980*8975f5c5SAndroid Build Coastguard Worker     constexpr char kFS[] = R"(#version 300 es
3981*8975f5c5SAndroid Build Coastguard Worker precision mediump float;
3982*8975f5c5SAndroid Build Coastguard Worker 
3983*8975f5c5SAndroid Build Coastguard Worker layout(std140) uniform Block
3984*8975f5c5SAndroid Build Coastguard Worker {
3985*8975f5c5SAndroid Build Coastguard Worker     vec4 colorIn;
3986*8975f5c5SAndroid Build Coastguard Worker };
3987*8975f5c5SAndroid Build Coastguard Worker 
3988*8975f5c5SAndroid Build Coastguard Worker out vec4 color;
3989*8975f5c5SAndroid Build Coastguard Worker 
3990*8975f5c5SAndroid Build Coastguard Worker void main()
3991*8975f5c5SAndroid Build Coastguard Worker {
3992*8975f5c5SAndroid Build Coastguard Worker     color = colorIn;
3993*8975f5c5SAndroid Build Coastguard Worker })";
3994*8975f5c5SAndroid Build Coastguard Worker 
3995*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceWidth  = 32;
3996*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceHeight = 128;
3997*8975f5c5SAndroid Build Coastguard Worker 
3998*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
3999*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
4000*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
4001*8975f5c5SAndroid Build Coastguard Worker 
4002*8975f5c5SAndroid Build Coastguard Worker     enum class Step
4003*8975f5c5SAndroid Build Coastguard Worker     {
4004*8975f5c5SAndroid Build Coastguard Worker         Start,
4005*8975f5c5SAndroid Build Coastguard Worker         Thread0Ready,
4006*8975f5c5SAndroid Build Coastguard Worker         Thread1Ready,
4007*8975f5c5SAndroid Build Coastguard Worker         Finish,
4008*8975f5c5SAndroid Build Coastguard Worker         Abort,
4009*8975f5c5SAndroid Build Coastguard Worker     };
4010*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
4011*8975f5c5SAndroid Build Coastguard Worker 
4012*8975f5c5SAndroid Build Coastguard Worker     auto threadFunc = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context, uint32_t index) {
4013*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
4014*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
4015*8975f5c5SAndroid Build Coastguard Worker 
4016*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
4017*8975f5c5SAndroid Build Coastguard Worker 
4018*8975f5c5SAndroid Build Coastguard Worker         // Make sure the two threads start work around the same time
4019*8975f5c5SAndroid Build Coastguard Worker         if (index == 0)
4020*8975f5c5SAndroid Build Coastguard Worker         {
4021*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(Step::Thread0Ready);
4022*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Ready));
4023*8975f5c5SAndroid Build Coastguard Worker         }
4024*8975f5c5SAndroid Build Coastguard Worker         else
4025*8975f5c5SAndroid Build Coastguard Worker         {
4026*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Ready));
4027*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(Step::Thread1Ready);
4028*8975f5c5SAndroid Build Coastguard Worker         }
4029*8975f5c5SAndroid Build Coastguard Worker 
4030*8975f5c5SAndroid Build Coastguard Worker         std::vector<GLuint> buffers(kSurfaceWidth * kSurfaceHeight);
4031*8975f5c5SAndroid Build Coastguard Worker 
4032*8975f5c5SAndroid Build Coastguard Worker         glEnable(GL_SCISSOR_TEST);
4033*8975f5c5SAndroid Build Coastguard Worker         for (int y = 0; y < kSurfaceHeight; ++y)
4034*8975f5c5SAndroid Build Coastguard Worker         {
4035*8975f5c5SAndroid Build Coastguard Worker             for (int x = 0; x < kSurfaceWidth; ++x)
4036*8975f5c5SAndroid Build Coastguard Worker             {
4037*8975f5c5SAndroid Build Coastguard Worker                 GLuint &buffer            = buffers[y * kSurfaceWidth + x];
4038*8975f5c5SAndroid Build Coastguard Worker                 const float bufferData[4] = {
4039*8975f5c5SAndroid Build Coastguard Worker                     ((y * kSurfaceWidth + x + index * 100) % 255) / 255.0f,
4040*8975f5c5SAndroid Build Coastguard Worker                     ((y * kSurfaceWidth + x + index * 100 + 1) % 255) / 255.0f,
4041*8975f5c5SAndroid Build Coastguard Worker                     ((y * kSurfaceWidth + x + index * 100 + 2) % 255) / 255.0f,
4042*8975f5c5SAndroid Build Coastguard Worker                     ((y * kSurfaceWidth + x + index * 100 + 3) % 255) / 255.0f,
4043*8975f5c5SAndroid Build Coastguard Worker                 };
4044*8975f5c5SAndroid Build Coastguard Worker 
4045*8975f5c5SAndroid Build Coastguard Worker                 // Generate one buffer per pixel and shade the pixel with it.
4046*8975f5c5SAndroid Build Coastguard Worker                 glGenBuffers(1, &buffer);
4047*8975f5c5SAndroid Build Coastguard Worker                 glBindBuffer(GL_UNIFORM_BUFFER, buffers[y * kSurfaceWidth + x]);
4048*8975f5c5SAndroid Build Coastguard Worker                 glBufferData(GL_UNIFORM_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
4049*8975f5c5SAndroid Build Coastguard Worker                 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
4050*8975f5c5SAndroid Build Coastguard Worker 
4051*8975f5c5SAndroid Build Coastguard Worker                 glScissor(x, y, 1, 1);
4052*8975f5c5SAndroid Build Coastguard Worker                 drawQuad(program, essl3_shaders::PositionAttrib(), 0);
4053*8975f5c5SAndroid Build Coastguard Worker 
4054*8975f5c5SAndroid Build Coastguard Worker                 if ((x + y) % 2 == 0)
4055*8975f5c5SAndroid Build Coastguard Worker                 {
4056*8975f5c5SAndroid Build Coastguard Worker                     glDeleteBuffers(1, &buffer);
4057*8975f5c5SAndroid Build Coastguard Worker                     buffer = 0;
4058*8975f5c5SAndroid Build Coastguard Worker                 }
4059*8975f5c5SAndroid Build Coastguard Worker             }
4060*8975f5c5SAndroid Build Coastguard Worker         }
4061*8975f5c5SAndroid Build Coastguard Worker 
4062*8975f5c5SAndroid Build Coastguard Worker         // Verify the results
4063*8975f5c5SAndroid Build Coastguard Worker         auto verify = [&](int x, int y) {
4064*8975f5c5SAndroid Build Coastguard Worker             const GLColor expect((y * kSurfaceWidth + x + index * 100) % 255,
4065*8975f5c5SAndroid Build Coastguard Worker                                  (y * kSurfaceWidth + x + index * 100 + 1) % 255,
4066*8975f5c5SAndroid Build Coastguard Worker                                  (y * kSurfaceWidth + x + index * 100 + 2) % 255,
4067*8975f5c5SAndroid Build Coastguard Worker                                  (y * kSurfaceWidth + x + index * 100 + 3) % 255);
4068*8975f5c5SAndroid Build Coastguard Worker             EXPECT_PIXEL_COLOR_EQ(x, y, expect);
4069*8975f5c5SAndroid Build Coastguard Worker         };
4070*8975f5c5SAndroid Build Coastguard Worker 
4071*8975f5c5SAndroid Build Coastguard Worker         verify(0, 0);
4072*8975f5c5SAndroid Build Coastguard Worker         verify(0, kSurfaceHeight - 1);
4073*8975f5c5SAndroid Build Coastguard Worker         verify(kSurfaceWidth - 1, 0);
4074*8975f5c5SAndroid Build Coastguard Worker         verify(kSurfaceWidth - 1, kSurfaceHeight - 1);
4075*8975f5c5SAndroid Build Coastguard Worker         verify(kSurfaceWidth / 2, kSurfaceHeight / 2);
4076*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
4077*8975f5c5SAndroid Build Coastguard Worker 
4078*8975f5c5SAndroid Build Coastguard Worker         if (index == 0)
4079*8975f5c5SAndroid Build Coastguard Worker         {
4080*8975f5c5SAndroid Build Coastguard Worker             threadSynchronization.nextStep(Step::Finish);
4081*8975f5c5SAndroid Build Coastguard Worker         }
4082*8975f5c5SAndroid Build Coastguard Worker         else
4083*8975f5c5SAndroid Build Coastguard Worker         {
4084*8975f5c5SAndroid Build Coastguard Worker             ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
4085*8975f5c5SAndroid Build Coastguard Worker         }
4086*8975f5c5SAndroid Build Coastguard Worker     };
4087*8975f5c5SAndroid Build Coastguard Worker 
4088*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
4089*8975f5c5SAndroid Build Coastguard Worker         threadFunc(dpy, surface, context, 0);
4090*8975f5c5SAndroid Build Coastguard Worker     };
4091*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
4092*8975f5c5SAndroid Build Coastguard Worker         threadFunc(dpy, surface, context, 1);
4093*8975f5c5SAndroid Build Coastguard Worker     };
4094*8975f5c5SAndroid Build Coastguard Worker 
4095*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
4096*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
4097*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
4098*8975f5c5SAndroid Build Coastguard Worker     };
4099*8975f5c5SAndroid Build Coastguard Worker 
4100*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreadsWithSize(getEGLWindow(), kSurfaceWidth, kSurfaceHeight, threadFuncs.size(),
4101*8975f5c5SAndroid Build Coastguard Worker                                threadFuncs.data());
4102*8975f5c5SAndroid Build Coastguard Worker 
4103*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
4104*8975f5c5SAndroid Build Coastguard Worker }
4105*8975f5c5SAndroid Build Coastguard Worker 
4106*8975f5c5SAndroid Build Coastguard Worker // Test that ref counting is thread-safe when the same buffer is used in multiple threads.
TEST_P(MultithreadingTestES3,SimultaneousBufferBind)4107*8975f5c5SAndroid Build Coastguard Worker TEST_P(MultithreadingTestES3, SimultaneousBufferBind)
4108*8975f5c5SAndroid Build Coastguard Worker {
4109*8975f5c5SAndroid Build Coastguard Worker     ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
4110*8975f5c5SAndroid Build Coastguard Worker 
4111*8975f5c5SAndroid Build Coastguard Worker     constexpr char kFS[] = R"(#version 300 es
4112*8975f5c5SAndroid Build Coastguard Worker precision mediump float;
4113*8975f5c5SAndroid Build Coastguard Worker 
4114*8975f5c5SAndroid Build Coastguard Worker layout(std140) uniform Block
4115*8975f5c5SAndroid Build Coastguard Worker {
4116*8975f5c5SAndroid Build Coastguard Worker     vec4 colorIn;
4117*8975f5c5SAndroid Build Coastguard Worker };
4118*8975f5c5SAndroid Build Coastguard Worker 
4119*8975f5c5SAndroid Build Coastguard Worker out vec4 color;
4120*8975f5c5SAndroid Build Coastguard Worker 
4121*8975f5c5SAndroid Build Coastguard Worker void main()
4122*8975f5c5SAndroid Build Coastguard Worker {
4123*8975f5c5SAndroid Build Coastguard Worker     color = colorIn;
4124*8975f5c5SAndroid Build Coastguard Worker })";
4125*8975f5c5SAndroid Build Coastguard Worker 
4126*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceWidth  = 32;
4127*8975f5c5SAndroid Build Coastguard Worker     constexpr int kSurfaceHeight = 128;
4128*8975f5c5SAndroid Build Coastguard Worker 
4129*8975f5c5SAndroid Build Coastguard Worker     GLuint buffer;
4130*8975f5c5SAndroid Build Coastguard Worker     GLsync sync = nullptr;
4131*8975f5c5SAndroid Build Coastguard Worker 
4132*8975f5c5SAndroid Build Coastguard Worker     // Sync primitives
4133*8975f5c5SAndroid Build Coastguard Worker     std::mutex mutex;
4134*8975f5c5SAndroid Build Coastguard Worker     std::condition_variable condVar;
4135*8975f5c5SAndroid Build Coastguard Worker 
4136*8975f5c5SAndroid Build Coastguard Worker     enum class Step
4137*8975f5c5SAndroid Build Coastguard Worker     {
4138*8975f5c5SAndroid Build Coastguard Worker         Start,
4139*8975f5c5SAndroid Build Coastguard Worker         Thread0Ready,
4140*8975f5c5SAndroid Build Coastguard Worker         Thread1Ready,
4141*8975f5c5SAndroid Build Coastguard Worker         Finish,
4142*8975f5c5SAndroid Build Coastguard Worker         Abort,
4143*8975f5c5SAndroid Build Coastguard Worker     };
4144*8975f5c5SAndroid Build Coastguard Worker     Step currentStep = Step::Start;
4145*8975f5c5SAndroid Build Coastguard Worker 
4146*8975f5c5SAndroid Build Coastguard Worker     auto thread0 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
4147*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
4148*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
4149*8975f5c5SAndroid Build Coastguard Worker 
4150*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
4151*8975f5c5SAndroid Build Coastguard Worker 
4152*8975f5c5SAndroid Build Coastguard Worker         // Create the buffer in this context
4153*8975f5c5SAndroid Build Coastguard Worker         glGenBuffers(1, &buffer);
4154*8975f5c5SAndroid Build Coastguard Worker 
4155*8975f5c5SAndroid Build Coastguard Worker         constexpr float kBufferData[4] = {
4156*8975f5c5SAndroid Build Coastguard Worker             10.0f / 255.0f,
4157*8975f5c5SAndroid Build Coastguard Worker             50.0f / 255.0f,
4158*8975f5c5SAndroid Build Coastguard Worker             130.0f / 255.0f,
4159*8975f5c5SAndroid Build Coastguard Worker             220.0f / 255.0f,
4160*8975f5c5SAndroid Build Coastguard Worker         };
4161*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, buffer);
4162*8975f5c5SAndroid Build Coastguard Worker         glBufferData(GL_UNIFORM_BUFFER, sizeof(kBufferData), kBufferData, GL_STATIC_DRAW);
4163*8975f5c5SAndroid Build Coastguard Worker 
4164*8975f5c5SAndroid Build Coastguard Worker         sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
4165*8975f5c5SAndroid Build Coastguard Worker 
4166*8975f5c5SAndroid Build Coastguard Worker         // Make sure the two threads start work around the same time
4167*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread0Ready);
4168*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Ready));
4169*8975f5c5SAndroid Build Coastguard Worker 
4170*8975f5c5SAndroid Build Coastguard Worker         // Bind and unbind the buffer many times.  If ref counting is not thread safe, chances are
4171*8975f5c5SAndroid Build Coastguard Worker         // the ref count would be incorrect in the end.  This can result in the buffer prematurely
4172*8975f5c5SAndroid Build Coastguard Worker         // getting deleted.
4173*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < 8000; ++i)
4174*8975f5c5SAndroid Build Coastguard Worker         {
4175*8975f5c5SAndroid Build Coastguard Worker             glBindBuffer(GL_UNIFORM_BUFFER, i % 2 == 0 ? 0 : buffer);
4176*8975f5c5SAndroid Build Coastguard Worker         }
4177*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
4178*8975f5c5SAndroid Build Coastguard Worker 
4179*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Finish);
4180*8975f5c5SAndroid Build Coastguard Worker     };
4181*8975f5c5SAndroid Build Coastguard Worker     auto thread1 = [&](EGLDisplay dpy, EGLSurface surface, EGLContext context) {
4182*8975f5c5SAndroid Build Coastguard Worker         ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
4183*8975f5c5SAndroid Build Coastguard Worker         EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, context));
4184*8975f5c5SAndroid Build Coastguard Worker 
4185*8975f5c5SAndroid Build Coastguard Worker         ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
4186*8975f5c5SAndroid Build Coastguard Worker 
4187*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Ready));
4188*8975f5c5SAndroid Build Coastguard Worker         threadSynchronization.nextStep(Step::Thread1Ready);
4189*8975f5c5SAndroid Build Coastguard Worker 
4190*8975f5c5SAndroid Build Coastguard Worker         glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
4191*8975f5c5SAndroid Build Coastguard Worker 
4192*8975f5c5SAndroid Build Coastguard Worker         // Bind and unbind the buffer many times.
4193*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t i = 0; i < 4000; ++i)
4194*8975f5c5SAndroid Build Coastguard Worker         {
4195*8975f5c5SAndroid Build Coastguard Worker             glBindBuffer(GL_UNIFORM_BUFFER, i % 2 == 0 ? buffer : 0);
4196*8975f5c5SAndroid Build Coastguard Worker         }
4197*8975f5c5SAndroid Build Coastguard Worker 
4198*8975f5c5SAndroid Build Coastguard Worker         // Draw with it to make sure buffer is still valid and not accidentally deleted due to bad
4199*8975f5c5SAndroid Build Coastguard Worker         // ref counting.
4200*8975f5c5SAndroid Build Coastguard Worker         glBindBuffer(GL_UNIFORM_BUFFER, buffer);
4201*8975f5c5SAndroid Build Coastguard Worker         glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
4202*8975f5c5SAndroid Build Coastguard Worker         drawQuad(program, essl3_shaders::PositionAttrib(), 0);
4203*8975f5c5SAndroid Build Coastguard Worker 
4204*8975f5c5SAndroid Build Coastguard Worker         // Verify the results
4205*8975f5c5SAndroid Build Coastguard Worker         const GLColor expect(10, 50, 130, 220);
4206*8975f5c5SAndroid Build Coastguard Worker         EXPECT_PIXEL_RECT_EQ(0, 0, kSurfaceWidth, kSurfaceHeight, expect);
4207*8975f5c5SAndroid Build Coastguard Worker         ASSERT_GL_NO_ERROR();
4208*8975f5c5SAndroid Build Coastguard Worker 
4209*8975f5c5SAndroid Build Coastguard Worker         ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
4210*8975f5c5SAndroid Build Coastguard Worker     };
4211*8975f5c5SAndroid Build Coastguard Worker 
4212*8975f5c5SAndroid Build Coastguard Worker     std::array<LockStepThreadFunc, 2> threadFuncs = {
4213*8975f5c5SAndroid Build Coastguard Worker         std::move(thread0),
4214*8975f5c5SAndroid Build Coastguard Worker         std::move(thread1),
4215*8975f5c5SAndroid Build Coastguard Worker     };
4216*8975f5c5SAndroid Build Coastguard Worker 
4217*8975f5c5SAndroid Build Coastguard Worker     RunLockStepThreadsWithSize(getEGLWindow(), kSurfaceWidth, kSurfaceHeight, threadFuncs.size(),
4218*8975f5c5SAndroid Build Coastguard Worker                                threadFuncs.data());
4219*8975f5c5SAndroid Build Coastguard Worker 
4220*8975f5c5SAndroid Build Coastguard Worker     ASSERT_NE(currentStep, Step::Abort);
4221*8975f5c5SAndroid Build Coastguard Worker }
4222*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(
4223*8975f5c5SAndroid Build Coastguard Worker     MultithreadingTest,
4224*8975f5c5SAndroid Build Coastguard Worker     ES2_METAL(),
4225*8975f5c5SAndroid Build Coastguard Worker     ES3_METAL(),
4226*8975f5c5SAndroid Build Coastguard Worker     ES2_OPENGL(),
4227*8975f5c5SAndroid Build Coastguard Worker     ES3_OPENGL(),
4228*8975f5c5SAndroid Build Coastguard Worker     ES2_OPENGLES(),
4229*8975f5c5SAndroid Build Coastguard Worker     ES3_OPENGLES(),
4230*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN(),
4231*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::AsyncCommandQueue),
4232*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4233*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::AsyncCommandQueue)
4234*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowAsyncCommandQueueForTesting),
4235*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().disable(Feature::PreferMonolithicPipelinesOverLibraries),
4236*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::PreferMonolithicPipelinesOverLibraries),
4237*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4238*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4239*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowDownMonolithicPipelineCreationForTesting),
4240*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4241*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4242*8975f5c5SAndroid Build Coastguard Worker         .disable(Feature::MergeProgramPipelineCachesToGlobalCache),
4243*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::PermanentlySwitchToFramebufferFetchMode),
4244*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4245*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PermanentlySwitchToFramebufferFetchMode)
4246*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries),
4247*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4248*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PermanentlySwitchToFramebufferFetchMode)
4249*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4250*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowDownMonolithicPipelineCreationForTesting),
4251*8975f5c5SAndroid Build Coastguard Worker     ES2_D3D11(),
4252*8975f5c5SAndroid Build Coastguard Worker     ES3_D3D11());
4253*8975f5c5SAndroid Build Coastguard Worker 
4254*8975f5c5SAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultithreadingTestES3);
4255*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(
4256*8975f5c5SAndroid Build Coastguard Worker     MultithreadingTestES3,
4257*8975f5c5SAndroid Build Coastguard Worker     ES3_OPENGL(),
4258*8975f5c5SAndroid Build Coastguard Worker     ES3_OPENGLES(),
4259*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN(),
4260*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::AsyncCommandQueue),
4261*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4262*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::AsyncCommandQueue)
4263*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowAsyncCommandQueueForTesting),
4264*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().disable(Feature::PreferMonolithicPipelinesOverLibraries),
4265*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::PreferMonolithicPipelinesOverLibraries),
4266*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4267*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4268*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowDownMonolithicPipelineCreationForTesting),
4269*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4270*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4271*8975f5c5SAndroid Build Coastguard Worker         .disable(Feature::MergeProgramPipelineCachesToGlobalCache),
4272*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER().enable(Feature::PermanentlySwitchToFramebufferFetchMode),
4273*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4274*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PermanentlySwitchToFramebufferFetchMode)
4275*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries),
4276*8975f5c5SAndroid Build Coastguard Worker     ES3_VULKAN_SWIFTSHADER()
4277*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PermanentlySwitchToFramebufferFetchMode)
4278*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::PreferMonolithicPipelinesOverLibraries)
4279*8975f5c5SAndroid Build Coastguard Worker         .enable(Feature::SlowDownMonolithicPipelineCreationForTesting),
4280*8975f5c5SAndroid Build Coastguard Worker     ES3_D3D11());
4281*8975f5c5SAndroid Build Coastguard Worker 
4282*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
4283