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