1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 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 // EGLContextSharingTest.cpp:
7*8975f5c5SAndroid Build Coastguard Worker // Tests relating to shared Contexts.
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker #include <gtest/gtest.h>
10*8975f5c5SAndroid Build Coastguard Worker
11*8975f5c5SAndroid Build Coastguard Worker #include "common/tls.h"
12*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/ANGLETest.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/MultiThreadSteps.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/angle_test_configs.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "test_utils/gl_raii.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "util/EGLWindow.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "util/OSWindow.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "util/test_utils.h"
19*8975f5c5SAndroid Build Coastguard Worker
20*8975f5c5SAndroid Build Coastguard Worker using namespace angle;
21*8975f5c5SAndroid Build Coastguard Worker
22*8975f5c5SAndroid Build Coastguard Worker namespace
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker
SafeDestroyContext(EGLDisplay display,EGLContext & context)25*8975f5c5SAndroid Build Coastguard Worker EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context)
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker EGLBoolean result = EGL_TRUE;
28*8975f5c5SAndroid Build Coastguard Worker if (context != EGL_NO_CONTEXT)
29*8975f5c5SAndroid Build Coastguard Worker {
30*8975f5c5SAndroid Build Coastguard Worker result = eglDestroyContext(display, context);
31*8975f5c5SAndroid Build Coastguard Worker context = EGL_NO_CONTEXT;
32*8975f5c5SAndroid Build Coastguard Worker }
33*8975f5c5SAndroid Build Coastguard Worker return result;
34*8975f5c5SAndroid Build Coastguard Worker }
35*8975f5c5SAndroid Build Coastguard Worker
36*8975f5c5SAndroid Build Coastguard Worker class EGLContextSharingTest : public ANGLETest<>
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker public:
EGLContextSharingTest()39*8975f5c5SAndroid Build Coastguard Worker EGLContextSharingTest() : mContexts{EGL_NO_CONTEXT, EGL_NO_CONTEXT}, mTexture(0) {}
40*8975f5c5SAndroid Build Coastguard Worker
testTearDown()41*8975f5c5SAndroid Build Coastguard Worker void testTearDown() override
42*8975f5c5SAndroid Build Coastguard Worker {
43*8975f5c5SAndroid Build Coastguard Worker glDeleteTextures(1, &mTexture);
44*8975f5c5SAndroid Build Coastguard Worker
45*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
46*8975f5c5SAndroid Build Coastguard Worker
47*8975f5c5SAndroid Build Coastguard Worker if (display != EGL_NO_DISPLAY)
48*8975f5c5SAndroid Build Coastguard Worker {
49*8975f5c5SAndroid Build Coastguard Worker for (auto &context : mContexts)
50*8975f5c5SAndroid Build Coastguard Worker {
51*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(display, context);
52*8975f5c5SAndroid Build Coastguard Worker }
53*8975f5c5SAndroid Build Coastguard Worker }
54*8975f5c5SAndroid Build Coastguard Worker
55*8975f5c5SAndroid Build Coastguard Worker // Set default test state to not give an error on shutdown.
56*8975f5c5SAndroid Build Coastguard Worker getEGLWindow()->makeCurrent();
57*8975f5c5SAndroid Build Coastguard Worker }
58*8975f5c5SAndroid Build Coastguard Worker
59*8975f5c5SAndroid Build Coastguard Worker EGLContext mContexts[2] = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
60*8975f5c5SAndroid Build Coastguard Worker GLuint mTexture;
61*8975f5c5SAndroid Build Coastguard Worker };
62*8975f5c5SAndroid Build Coastguard Worker
63*8975f5c5SAndroid Build Coastguard Worker class EGLContextSharingTestNoFixture : public EGLContextSharingTest
64*8975f5c5SAndroid Build Coastguard Worker {
65*8975f5c5SAndroid Build Coastguard Worker public:
EGLContextSharingTestNoFixture()66*8975f5c5SAndroid Build Coastguard Worker EGLContextSharingTestNoFixture() : EGLContextSharingTest() {}
67*8975f5c5SAndroid Build Coastguard Worker
testSetUp()68*8975f5c5SAndroid Build Coastguard Worker void testSetUp() override
69*8975f5c5SAndroid Build Coastguard Worker {
70*8975f5c5SAndroid Build Coastguard Worker mOsWindow = OSWindow::New();
71*8975f5c5SAndroid Build Coastguard Worker mMajorVersion = GetParam().majorVersion;
72*8975f5c5SAndroid Build Coastguard Worker }
73*8975f5c5SAndroid Build Coastguard Worker
testTearDown()74*8975f5c5SAndroid Build Coastguard Worker void testTearDown() override
75*8975f5c5SAndroid Build Coastguard Worker {
76*8975f5c5SAndroid Build Coastguard Worker if (mDisplay != EGL_NO_DISPLAY)
77*8975f5c5SAndroid Build Coastguard Worker {
78*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
79*8975f5c5SAndroid Build Coastguard Worker
80*8975f5c5SAndroid Build Coastguard Worker if (mSurface != EGL_NO_SURFACE)
81*8975f5c5SAndroid Build Coastguard Worker {
82*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, mSurface);
83*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
84*8975f5c5SAndroid Build Coastguard Worker mSurface = EGL_NO_SURFACE;
85*8975f5c5SAndroid Build Coastguard Worker }
86*8975f5c5SAndroid Build Coastguard Worker
87*8975f5c5SAndroid Build Coastguard Worker for (auto &context : mContexts)
88*8975f5c5SAndroid Build Coastguard Worker {
89*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(mDisplay, context);
90*8975f5c5SAndroid Build Coastguard Worker }
91*8975f5c5SAndroid Build Coastguard Worker
92*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
93*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
94*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
95*8975f5c5SAndroid Build Coastguard Worker eglReleaseThread();
96*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
97*8975f5c5SAndroid Build Coastguard Worker }
98*8975f5c5SAndroid Build Coastguard Worker
99*8975f5c5SAndroid Build Coastguard Worker mOsWindow->destroy();
100*8975f5c5SAndroid Build Coastguard Worker OSWindow::Delete(&mOsWindow);
101*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "Error during test TearDown";
102*8975f5c5SAndroid Build Coastguard Worker }
103*8975f5c5SAndroid Build Coastguard Worker
chooseConfig(EGLConfig * config) const104*8975f5c5SAndroid Build Coastguard Worker bool chooseConfig(EGLConfig *config) const
105*8975f5c5SAndroid Build Coastguard Worker {
106*8975f5c5SAndroid Build Coastguard Worker bool result = false;
107*8975f5c5SAndroid Build Coastguard Worker EGLint count = 0;
108*8975f5c5SAndroid Build Coastguard Worker EGLint clientVersion = mMajorVersion == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
109*8975f5c5SAndroid Build Coastguard Worker EGLint attribs[] = {EGL_RED_SIZE,
110*8975f5c5SAndroid Build Coastguard Worker 8,
111*8975f5c5SAndroid Build Coastguard Worker EGL_GREEN_SIZE,
112*8975f5c5SAndroid Build Coastguard Worker 8,
113*8975f5c5SAndroid Build Coastguard Worker EGL_BLUE_SIZE,
114*8975f5c5SAndroid Build Coastguard Worker 8,
115*8975f5c5SAndroid Build Coastguard Worker EGL_ALPHA_SIZE,
116*8975f5c5SAndroid Build Coastguard Worker 8,
117*8975f5c5SAndroid Build Coastguard Worker EGL_RENDERABLE_TYPE,
118*8975f5c5SAndroid Build Coastguard Worker clientVersion,
119*8975f5c5SAndroid Build Coastguard Worker EGL_SURFACE_TYPE,
120*8975f5c5SAndroid Build Coastguard Worker EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
121*8975f5c5SAndroid Build Coastguard Worker EGL_NONE};
122*8975f5c5SAndroid Build Coastguard Worker
123*8975f5c5SAndroid Build Coastguard Worker result = eglChooseConfig(mDisplay, attribs, config, 1, &count);
124*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(result && (count > 0));
125*8975f5c5SAndroid Build Coastguard Worker return result;
126*8975f5c5SAndroid Build Coastguard Worker }
127*8975f5c5SAndroid Build Coastguard Worker
createContext(EGLConfig config,EGLContext * context,EGLContext share_context=EGL_NO_CONTEXT)128*8975f5c5SAndroid Build Coastguard Worker bool createContext(EGLConfig config,
129*8975f5c5SAndroid Build Coastguard Worker EGLContext *context,
130*8975f5c5SAndroid Build Coastguard Worker EGLContext share_context = EGL_NO_CONTEXT)
131*8975f5c5SAndroid Build Coastguard Worker {
132*8975f5c5SAndroid Build Coastguard Worker bool result = false;
133*8975f5c5SAndroid Build Coastguard Worker EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, mMajorVersion,
134*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, mVirtualizationGroup++,
135*8975f5c5SAndroid Build Coastguard Worker EGL_NONE};
136*8975f5c5SAndroid Build Coastguard Worker
137*8975f5c5SAndroid Build Coastguard Worker if (!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANGLE_context_virtualization"))
138*8975f5c5SAndroid Build Coastguard Worker {
139*8975f5c5SAndroid Build Coastguard Worker attribs[2] = EGL_NONE;
140*8975f5c5SAndroid Build Coastguard Worker }
141*8975f5c5SAndroid Build Coastguard Worker
142*8975f5c5SAndroid Build Coastguard Worker *context = eglCreateContext(mDisplay, config, share_context, attribs);
143*8975f5c5SAndroid Build Coastguard Worker result = (*context != EGL_NO_CONTEXT);
144*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(result);
145*8975f5c5SAndroid Build Coastguard Worker return result;
146*8975f5c5SAndroid Build Coastguard Worker }
147*8975f5c5SAndroid Build Coastguard Worker
createWindowSurface(EGLConfig config,EGLNativeWindowType win,EGLSurface * surface)148*8975f5c5SAndroid Build Coastguard Worker bool createWindowSurface(EGLConfig config, EGLNativeWindowType win, EGLSurface *surface)
149*8975f5c5SAndroid Build Coastguard Worker {
150*8975f5c5SAndroid Build Coastguard Worker bool result = false;
151*8975f5c5SAndroid Build Coastguard Worker EGLint attribs[] = {EGL_NONE};
152*8975f5c5SAndroid Build Coastguard Worker
153*8975f5c5SAndroid Build Coastguard Worker *surface = eglCreateWindowSurface(mDisplay, config, win, attribs);
154*8975f5c5SAndroid Build Coastguard Worker result = (*surface != EGL_NO_SURFACE);
155*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(result);
156*8975f5c5SAndroid Build Coastguard Worker return result;
157*8975f5c5SAndroid Build Coastguard Worker }
158*8975f5c5SAndroid Build Coastguard Worker
createPbufferSurface(EGLDisplay dpy,EGLConfig config,EGLint width,EGLint height,EGLSurface * surface)159*8975f5c5SAndroid Build Coastguard Worker bool createPbufferSurface(EGLDisplay dpy,
160*8975f5c5SAndroid Build Coastguard Worker EGLConfig config,
161*8975f5c5SAndroid Build Coastguard Worker EGLint width,
162*8975f5c5SAndroid Build Coastguard Worker EGLint height,
163*8975f5c5SAndroid Build Coastguard Worker EGLSurface *surface)
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker bool result = false;
166*8975f5c5SAndroid Build Coastguard Worker EGLint attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
167*8975f5c5SAndroid Build Coastguard Worker
168*8975f5c5SAndroid Build Coastguard Worker *surface = eglCreatePbufferSurface(dpy, config, attribs);
169*8975f5c5SAndroid Build Coastguard Worker result = (*surface != EGL_NO_SURFACE);
170*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(result);
171*8975f5c5SAndroid Build Coastguard Worker return result;
172*8975f5c5SAndroid Build Coastguard Worker }
173*8975f5c5SAndroid Build Coastguard Worker
174*8975f5c5SAndroid Build Coastguard Worker OSWindow *mOsWindow;
175*8975f5c5SAndroid Build Coastguard Worker EGLDisplay mDisplay = EGL_NO_DISPLAY;
176*8975f5c5SAndroid Build Coastguard Worker EGLSurface mSurface = EGL_NO_SURFACE;
177*8975f5c5SAndroid Build Coastguard Worker const EGLint kWidth = 64;
178*8975f5c5SAndroid Build Coastguard Worker const EGLint kHeight = 64;
179*8975f5c5SAndroid Build Coastguard Worker EGLint mMajorVersion = 0;
180*8975f5c5SAndroid Build Coastguard Worker std::atomic<EGLint> mVirtualizationGroup;
181*8975f5c5SAndroid Build Coastguard Worker };
182*8975f5c5SAndroid Build Coastguard Worker
183*8975f5c5SAndroid Build Coastguard Worker // Tests that creating resources works after freeing the share context.
TEST_P(EGLContextSharingTest,BindTextureAfterShareContextFree)184*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, BindTextureAfterShareContextFree)
185*8975f5c5SAndroid Build Coastguard Worker {
186*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
187*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
188*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = getEGLWindow()->getSurface();
189*8975f5c5SAndroid Build Coastguard Worker
190*8975f5c5SAndroid Build Coastguard Worker const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION,
191*8975f5c5SAndroid Build Coastguard Worker getEGLWindow()->getClientMajorVersion(), EGL_NONE};
192*8975f5c5SAndroid Build Coastguard Worker
193*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, nullptr, contextAttribs);
194*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
195*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(mContexts[0] != EGL_NO_CONTEXT);
196*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = eglCreateContext(display, config, mContexts[1], contextAttribs);
197*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
198*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(mContexts[1] != EGL_NO_CONTEXT);
199*8975f5c5SAndroid Build Coastguard Worker
200*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(SafeDestroyContext(display, mContexts[0]));
201*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[1]));
202*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
203*8975f5c5SAndroid Build Coastguard Worker
204*8975f5c5SAndroid Build Coastguard Worker glGenTextures(1, &mTexture);
205*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, mTexture);
206*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
207*8975f5c5SAndroid Build Coastguard Worker }
208*8975f5c5SAndroid Build Coastguard Worker
209*8975f5c5SAndroid Build Coastguard Worker // Tests the creation of contexts using EGL_ANGLE_display_texture_share_group
TEST_P(EGLContextSharingTest,DisplayShareGroupContextCreation)210*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DisplayShareGroupContextCreation)
211*8975f5c5SAndroid Build Coastguard Worker {
212*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
213*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
214*8975f5c5SAndroid Build Coastguard Worker
215*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {
216*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
217*8975f5c5SAndroid Build Coastguard Worker
218*8975f5c5SAndroid Build Coastguard Worker // Check whether extension's supported to avoid clearing the EGL error state
219*8975f5c5SAndroid Build Coastguard Worker // after failed context creation.
220*8975f5c5SAndroid Build Coastguard Worker bool extensionEnabled =
221*8975f5c5SAndroid Build Coastguard Worker IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group");
222*8975f5c5SAndroid Build Coastguard Worker
223*8975f5c5SAndroid Build Coastguard Worker // Test creating two contexts in the global share group
224*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
225*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = eglCreateContext(display, config, mContexts[1], inShareGroupContextAttribs);
226*8975f5c5SAndroid Build Coastguard Worker
227*8975f5c5SAndroid Build Coastguard Worker if (!extensionEnabled)
228*8975f5c5SAndroid Build Coastguard Worker {
229*8975f5c5SAndroid Build Coastguard Worker // Make sure an error is generated and early-exit
230*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
231*8975f5c5SAndroid Build Coastguard Worker ASSERT_EQ(EGL_NO_CONTEXT, mContexts[0]);
232*8975f5c5SAndroid Build Coastguard Worker return;
233*8975f5c5SAndroid Build Coastguard Worker }
234*8975f5c5SAndroid Build Coastguard Worker
235*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
236*8975f5c5SAndroid Build Coastguard Worker
237*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_CONTEXT, mContexts[0]);
238*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_CONTEXT, mContexts[1]);
239*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(display, mContexts[0]);
240*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = EGL_NO_CONTEXT;
241*8975f5c5SAndroid Build Coastguard Worker
242*8975f5c5SAndroid Build Coastguard Worker // Try creating a context that is not in the global share group but tries to share with a
243*8975f5c5SAndroid Build Coastguard Worker // context that is
244*8975f5c5SAndroid Build Coastguard Worker const EGLint notInShareGroupContextAttribs[] = {
245*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE, EGL_NONE};
246*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, mContexts[1], notInShareGroupContextAttribs);
247*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
248*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(mContexts[0] == EGL_NO_CONTEXT);
249*8975f5c5SAndroid Build Coastguard Worker }
250*8975f5c5SAndroid Build Coastguard Worker
251*8975f5c5SAndroid Build Coastguard Worker // Tests the sharing of textures using EGL_ANGLE_display_texture_share_group
TEST_P(EGLContextSharingTest,DisplayShareGroupObjectSharing)252*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DisplayShareGroupObjectSharing)
253*8975f5c5SAndroid Build Coastguard Worker {
254*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
255*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(
256*8975f5c5SAndroid Build Coastguard Worker !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group"));
257*8975f5c5SAndroid Build Coastguard Worker
258*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
259*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = getEGLWindow()->getSurface();
260*8975f5c5SAndroid Build Coastguard Worker
261*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {
262*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
263*8975f5c5SAndroid Build Coastguard Worker
264*8975f5c5SAndroid Build Coastguard Worker // Create two contexts in the global share group but not in the same context share group
265*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
266*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
267*8975f5c5SAndroid Build Coastguard Worker
268*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
269*8975f5c5SAndroid Build Coastguard Worker
270*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_CONTEXT, mContexts[0]);
271*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_CONTEXT, mContexts[1]);
272*8975f5c5SAndroid Build Coastguard Worker
273*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
274*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
275*8975f5c5SAndroid Build Coastguard Worker
276*8975f5c5SAndroid Build Coastguard Worker // Create a texture and buffer in ctx 0
277*8975f5c5SAndroid Build Coastguard Worker GLTexture textureFromCtx0;
278*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
279*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
280*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, 0);
281*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
282*8975f5c5SAndroid Build Coastguard Worker
283*8975f5c5SAndroid Build Coastguard Worker GLBuffer bufferFromCtx0;
284*8975f5c5SAndroid Build Coastguard Worker glBindBuffer(GL_ARRAY_BUFFER, bufferFromCtx0);
285*8975f5c5SAndroid Build Coastguard Worker glBufferData(GL_ARRAY_BUFFER, 1, nullptr, GL_STATIC_DRAW);
286*8975f5c5SAndroid Build Coastguard Worker glBindBuffer(GL_ARRAY_BUFFER, 0);
287*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsBuffer(bufferFromCtx0));
288*8975f5c5SAndroid Build Coastguard Worker
289*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
290*8975f5c5SAndroid Build Coastguard Worker
291*8975f5c5SAndroid Build Coastguard Worker // Switch to context 1 and verify that the texture is accessible but the buffer is not
292*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[1]));
293*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
294*8975f5c5SAndroid Build Coastguard Worker
295*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
296*8975f5c5SAndroid Build Coastguard Worker
297*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_FALSE(glIsBuffer(bufferFromCtx0));
298*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
299*8975f5c5SAndroid Build Coastguard Worker
300*8975f5c5SAndroid Build Coastguard Worker // Call readpixels on the texture to verify that the backend has proper support
301*8975f5c5SAndroid Build Coastguard Worker GLFramebuffer fbo;
302*8975f5c5SAndroid Build Coastguard Worker glBindFramebuffer(GL_FRAMEBUFFER, fbo);
303*8975f5c5SAndroid Build Coastguard Worker glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureFromCtx0, 0);
304*8975f5c5SAndroid Build Coastguard Worker
305*8975f5c5SAndroid Build Coastguard Worker GLubyte pixel[4];
306*8975f5c5SAndroid Build Coastguard Worker glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
307*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
308*8975f5c5SAndroid Build Coastguard Worker
309*8975f5c5SAndroid Build Coastguard Worker // Switch back to context 0 and delete the buffer
310*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
311*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
312*8975f5c5SAndroid Build Coastguard Worker }
313*8975f5c5SAndroid Build Coastguard Worker
314*8975f5c5SAndroid Build Coastguard Worker // Tests that shared textures using EGL_ANGLE_display_texture_share_group are released when the last
315*8975f5c5SAndroid Build Coastguard Worker // context is destroyed
TEST_P(EGLContextSharingTest,DisplayShareGroupReleasedWithLastContext)316*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DisplayShareGroupReleasedWithLastContext)
317*8975f5c5SAndroid Build Coastguard Worker {
318*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
319*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(
320*8975f5c5SAndroid Build Coastguard Worker !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group"));
321*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
322*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = getEGLWindow()->getSurface();
323*8975f5c5SAndroid Build Coastguard Worker
324*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {
325*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
326*8975f5c5SAndroid Build Coastguard Worker
327*8975f5c5SAndroid Build Coastguard Worker // Create two contexts in the global share group but not in the same context share group
328*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
329*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
330*8975f5c5SAndroid Build Coastguard Worker
331*8975f5c5SAndroid Build Coastguard Worker // Create a texture and buffer in ctx 0
332*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
333*8975f5c5SAndroid Build Coastguard Worker GLTexture textureFromCtx0;
334*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
335*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
336*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, 0);
337*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
338*8975f5c5SAndroid Build Coastguard Worker
339*8975f5c5SAndroid Build Coastguard Worker // Switch to context 1 and verify that the texture is accessible
340*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[1]));
341*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
342*8975f5c5SAndroid Build Coastguard Worker
343*8975f5c5SAndroid Build Coastguard Worker // Destroy both contexts, the texture should be cleaned up automatically
344*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglDestroyContext(display, mContexts[0]));
345*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = EGL_NO_CONTEXT;
346*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglDestroyContext(display, mContexts[1]));
347*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = EGL_NO_CONTEXT;
348*8975f5c5SAndroid Build Coastguard Worker
349*8975f5c5SAndroid Build Coastguard Worker // Unmake current, so the context can be released.
350*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
351*8975f5c5SAndroid Build Coastguard Worker
352*8975f5c5SAndroid Build Coastguard Worker // Create a new context and verify it cannot access the texture previously created
353*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
354*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
355*8975f5c5SAndroid Build Coastguard Worker
356*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_FALSE(glIsTexture(textureFromCtx0));
357*8975f5c5SAndroid Build Coastguard Worker }
358*8975f5c5SAndroid Build Coastguard Worker
359*8975f5c5SAndroid Build Coastguard Worker // Tests that after creating a texture using EGL_ANGLE_display_texture_share_group,
360*8975f5c5SAndroid Build Coastguard Worker // and deleting the Context and the egl::ShareGroup who own a texture staged updates,
361*8975f5c5SAndroid Build Coastguard Worker // the texture staged updates are flushed, and the Context and egl::ShareGroup can be destroyed
362*8975f5c5SAndroid Build Coastguard Worker // successfully, and the texture can still be accessed from the global display texture share group
TEST_P(EGLContextSharingTest,DisplayShareGroupReleaseShareGroupThatOwnsStagedUpdates)363*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DisplayShareGroupReleaseShareGroupThatOwnsStagedUpdates)
364*8975f5c5SAndroid Build Coastguard Worker {
365*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
366*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(
367*8975f5c5SAndroid Build Coastguard Worker !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group"));
368*8975f5c5SAndroid Build Coastguard Worker
369*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
370*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = getEGLWindow()->getSurface();
371*8975f5c5SAndroid Build Coastguard Worker
372*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {
373*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
374*8975f5c5SAndroid Build Coastguard Worker
375*8975f5c5SAndroid Build Coastguard Worker // Create two contexts in the global share group, but not in the same context share group
376*8975f5c5SAndroid Build Coastguard Worker EGLContext context1 = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
377*8975f5c5SAndroid Build Coastguard Worker EGLContext context2 = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
378*8975f5c5SAndroid Build Coastguard Worker
379*8975f5c5SAndroid Build Coastguard Worker // Create a texture in context1 and stage a texture update
380*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context1));
381*8975f5c5SAndroid Build Coastguard Worker constexpr GLsizei kTexSize = 2;
382*8975f5c5SAndroid Build Coastguard Worker const GLColor kBlueData[kTexSize * kTexSize] = {GLColor::blue, GLColor::blue, GLColor::blue,
383*8975f5c5SAndroid Build Coastguard Worker GLColor::blue};
384*8975f5c5SAndroid Build Coastguard Worker GLTexture textureFromCtx0;
385*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
386*8975f5c5SAndroid Build Coastguard Worker // This will stage a texture update in context1's SharedGroup::BufferPool
387*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kBlueData);
388*8975f5c5SAndroid Build Coastguard Worker
389*8975f5c5SAndroid Build Coastguard Worker // Destroy context 1, this also destroys context1's SharedGroup and BufferPool
390*8975f5c5SAndroid Build Coastguard Worker // The texture staged update in context1's SharedGroup BufferPool will be flushed
391*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(display, context1);
392*8975f5c5SAndroid Build Coastguard Worker
393*8975f5c5SAndroid Build Coastguard Worker // Switch to context2 and verify that the texture is accessible
394*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
395*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
396*8975f5c5SAndroid Build Coastguard Worker
397*8975f5c5SAndroid Build Coastguard Worker // Sample from textureFromCtx0 and check it works properly
398*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
399*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
400*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
401*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program1, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
402*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program1);
403*8975f5c5SAndroid Build Coastguard Worker drawQuad(program1, essl1_shaders::PositionAttrib(), 0.5f);
404*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
405*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
406*8975f5c5SAndroid Build Coastguard Worker
407*8975f5c5SAndroid Build Coastguard Worker // Destroy context2
408*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(display, context2);
409*8975f5c5SAndroid Build Coastguard Worker }
410*8975f5c5SAndroid Build Coastguard Worker
411*8975f5c5SAndroid Build Coastguard Worker // Tests that after creating a texture using EGL_ANGLE_display_texture_share_group,
412*8975f5c5SAndroid Build Coastguard Worker // and use it for sampling, and then deleting the Context (which destroys shareGroup) works. If
413*8975f5c5SAndroid Build Coastguard Worker // anything cached in ShareGroup, it should be handled nicely if texture can outlive ShareGroup (for
414*8975f5c5SAndroid Build Coastguard Worker // example, bugs like angleproject:7466).
TEST_P(EGLContextSharingTest,DisplayShareGroupReleaseShareGroupThenDestroyTexture)415*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DisplayShareGroupReleaseShareGroupThenDestroyTexture)
416*8975f5c5SAndroid Build Coastguard Worker {
417*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
418*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(
419*8975f5c5SAndroid Build Coastguard Worker !IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group"));
420*8975f5c5SAndroid Build Coastguard Worker
421*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
422*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = getEGLWindow()->getSurface();
423*8975f5c5SAndroid Build Coastguard Worker
424*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {
425*8975f5c5SAndroid Build Coastguard Worker EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
426*8975f5c5SAndroid Build Coastguard Worker
427*8975f5c5SAndroid Build Coastguard Worker // Create two contexts in the global share group, but not in the same context share group
428*8975f5c5SAndroid Build Coastguard Worker EGLContext context1 = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
429*8975f5c5SAndroid Build Coastguard Worker EGLContext context2 = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
430*8975f5c5SAndroid Build Coastguard Worker
431*8975f5c5SAndroid Build Coastguard Worker // Create a texture in context1 and stage a texture update
432*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context1));
433*8975f5c5SAndroid Build Coastguard Worker constexpr GLsizei kTexSize = 2;
434*8975f5c5SAndroid Build Coastguard Worker const GLColor kBlueData[kTexSize * kTexSize] = {GLColor::blue, GLColor::blue, GLColor::blue,
435*8975f5c5SAndroid Build Coastguard Worker GLColor::blue};
436*8975f5c5SAndroid Build Coastguard Worker {
437*8975f5c5SAndroid Build Coastguard Worker GLTexture textureFromCtx1;
438*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx1);
439*8975f5c5SAndroid Build Coastguard Worker // This will stage a texture update in context1's SharedGroup::BufferPool
440*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, kBlueData);
441*8975f5c5SAndroid Build Coastguard Worker
442*8975f5c5SAndroid Build Coastguard Worker // Sample from textureFromCtx1 and check it works properly
443*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx1);
444*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
445*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
446*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program1, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
447*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program1);
448*8975f5c5SAndroid Build Coastguard Worker drawQuad(program1, essl1_shaders::PositionAttrib(), 0.5f);
449*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
450*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
451*8975f5c5SAndroid Build Coastguard Worker
452*8975f5c5SAndroid Build Coastguard Worker // Destroy context 1, this also destroys context1's SharedGroup and BufferPool
453*8975f5c5SAndroid Build Coastguard Worker // The texture staged update in context1's SharedGroup BufferPool will be flushed
454*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(display, context1);
455*8975f5c5SAndroid Build Coastguard Worker
456*8975f5c5SAndroid Build Coastguard Worker // Switch to context2 and verify that the texture is accessible
457*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2));
458*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx1));
459*8975f5c5SAndroid Build Coastguard Worker
460*8975f5c5SAndroid Build Coastguard Worker // textureFromCtx1 should be destroyed when leaving this scope
461*8975f5c5SAndroid Build Coastguard Worker }
462*8975f5c5SAndroid Build Coastguard Worker
463*8975f5c5SAndroid Build Coastguard Worker // Destroy context2
464*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(display, context2);
465*8975f5c5SAndroid Build Coastguard Worker }
466*8975f5c5SAndroid Build Coastguard Worker
467*8975f5c5SAndroid Build Coastguard Worker // Tests that deleting an object on one Context doesn't destroy it ahead-of-time. Mostly focused
468*8975f5c5SAndroid Build Coastguard Worker // on the Vulkan back-end where we manage object lifetime manually.
TEST_P(EGLContextSharingTest,TextureLifetime)469*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, TextureLifetime)
470*8975f5c5SAndroid Build Coastguard Worker {
471*8975f5c5SAndroid Build Coastguard Worker EGLWindow *eglWindow = getEGLWindow();
472*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
473*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
474*8975f5c5SAndroid Build Coastguard Worker
475*8975f5c5SAndroid Build Coastguard Worker // Create a pbuffer surface for use with a shared context.
476*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = eglWindow->getSurface();
477*8975f5c5SAndroid Build Coastguard Worker EGLContext mainContext = eglWindow->getContext();
478*8975f5c5SAndroid Build Coastguard Worker
479*8975f5c5SAndroid Build Coastguard Worker // Initialize a shared context.
480*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, mainContext, nullptr);
481*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(mContexts[0], EGL_NO_CONTEXT);
482*8975f5c5SAndroid Build Coastguard Worker
483*8975f5c5SAndroid Build Coastguard Worker // Create a Texture on the shared context.
484*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
485*8975f5c5SAndroid Build Coastguard Worker
486*8975f5c5SAndroid Build Coastguard Worker constexpr GLsizei kTexSize = 2;
487*8975f5c5SAndroid Build Coastguard Worker const GLColor kTexData[kTexSize * kTexSize] = {GLColor::red, GLColor::green, GLColor::blue,
488*8975f5c5SAndroid Build Coastguard Worker GLColor::yellow};
489*8975f5c5SAndroid Build Coastguard Worker GLTexture tex;
490*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, tex);
491*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
492*8975f5c5SAndroid Build Coastguard Worker kTexData);
493*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
494*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
495*8975f5c5SAndroid Build Coastguard Worker
496*8975f5c5SAndroid Build Coastguard Worker // Make the main Context current and draw with the texture.
497*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mainContext));
498*8975f5c5SAndroid Build Coastguard Worker
499*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, tex);
500*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
501*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program);
502*8975f5c5SAndroid Build Coastguard Worker
503*8975f5c5SAndroid Build Coastguard Worker // No uniform update because the update seems to hide the error on Vulkan.
504*8975f5c5SAndroid Build Coastguard Worker
505*8975f5c5SAndroid Build Coastguard Worker // Enqueue the draw call.
506*8975f5c5SAndroid Build Coastguard Worker drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
507*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
508*8975f5c5SAndroid Build Coastguard Worker
509*8975f5c5SAndroid Build Coastguard Worker // Delete the texture in the main context to orphan it.
510*8975f5c5SAndroid Build Coastguard Worker // Do not read back the data to keep the commands in the graph.
511*8975f5c5SAndroid Build Coastguard Worker tex.reset();
512*8975f5c5SAndroid Build Coastguard Worker
513*8975f5c5SAndroid Build Coastguard Worker // Bind and delete the test context. This should trigger texture garbage collection.
514*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
515*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(display, mContexts[0]);
516*8975f5c5SAndroid Build Coastguard Worker
517*8975f5c5SAndroid Build Coastguard Worker // Bind the main context to clean up the test.
518*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mainContext));
519*8975f5c5SAndroid Build Coastguard Worker }
520*8975f5c5SAndroid Build Coastguard Worker
521*8975f5c5SAndroid Build Coastguard Worker // Tests that deleting an object on one Context doesn't destroy it ahead-of-time. Mostly focused
522*8975f5c5SAndroid Build Coastguard Worker // on the Vulkan back-end where we manage object lifetime manually.
TEST_P(EGLContextSharingTest,SamplerLifetime)523*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, SamplerLifetime)
524*8975f5c5SAndroid Build Coastguard Worker {
525*8975f5c5SAndroid Build Coastguard Worker EGLWindow *eglWindow = getEGLWindow();
526*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
527*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
528*8975f5c5SAndroid Build Coastguard Worker
529*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
530*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_KHR_create_context"));
531*8975f5c5SAndroid Build Coastguard Worker
532*8975f5c5SAndroid Build Coastguard Worker // Create a pbuffer surface for use with a shared context.
533*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = eglWindow->getSurface();
534*8975f5c5SAndroid Build Coastguard Worker EGLContext mainContext = eglWindow->getContext();
535*8975f5c5SAndroid Build Coastguard Worker
536*8975f5c5SAndroid Build Coastguard Worker std::vector<EGLint> contextAttributes;
537*8975f5c5SAndroid Build Coastguard Worker contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
538*8975f5c5SAndroid Build Coastguard Worker contextAttributes.push_back(getClientMajorVersion());
539*8975f5c5SAndroid Build Coastguard Worker contextAttributes.push_back(EGL_NONE);
540*8975f5c5SAndroid Build Coastguard Worker
541*8975f5c5SAndroid Build Coastguard Worker // Initialize a shared context.
542*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = eglCreateContext(display, config, mainContext, contextAttributes.data());
543*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(mContexts[0], EGL_NO_CONTEXT);
544*8975f5c5SAndroid Build Coastguard Worker
545*8975f5c5SAndroid Build Coastguard Worker // Create a Texture on the shared context. Also create a Sampler object.
546*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
547*8975f5c5SAndroid Build Coastguard Worker
548*8975f5c5SAndroid Build Coastguard Worker constexpr GLsizei kTexSize = 2;
549*8975f5c5SAndroid Build Coastguard Worker const GLColor kTexData[kTexSize * kTexSize] = {GLColor::red, GLColor::green, GLColor::blue,
550*8975f5c5SAndroid Build Coastguard Worker GLColor::yellow};
551*8975f5c5SAndroid Build Coastguard Worker GLTexture tex;
552*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, tex);
553*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
554*8975f5c5SAndroid Build Coastguard Worker kTexData);
555*8975f5c5SAndroid Build Coastguard Worker
556*8975f5c5SAndroid Build Coastguard Worker GLSampler sampler;
557*8975f5c5SAndroid Build Coastguard Worker glBindSampler(0, sampler);
558*8975f5c5SAndroid Build Coastguard Worker glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
559*8975f5c5SAndroid Build Coastguard Worker glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
560*8975f5c5SAndroid Build Coastguard Worker
561*8975f5c5SAndroid Build Coastguard Worker // Make the main Context current and draw with the texture and sampler.
562*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mainContext));
563*8975f5c5SAndroid Build Coastguard Worker
564*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, tex);
565*8975f5c5SAndroid Build Coastguard Worker glBindSampler(0, sampler);
566*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
567*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program);
568*8975f5c5SAndroid Build Coastguard Worker
569*8975f5c5SAndroid Build Coastguard Worker // No uniform update because the update seems to hide the error on Vulkan.
570*8975f5c5SAndroid Build Coastguard Worker
571*8975f5c5SAndroid Build Coastguard Worker // Enqueue the draw call.
572*8975f5c5SAndroid Build Coastguard Worker drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
573*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
574*8975f5c5SAndroid Build Coastguard Worker
575*8975f5c5SAndroid Build Coastguard Worker // Delete the texture and sampler in the main context to orphan them.
576*8975f5c5SAndroid Build Coastguard Worker // Do not read back the data to keep the commands in the graph.
577*8975f5c5SAndroid Build Coastguard Worker tex.reset();
578*8975f5c5SAndroid Build Coastguard Worker sampler.reset();
579*8975f5c5SAndroid Build Coastguard Worker
580*8975f5c5SAndroid Build Coastguard Worker // Bind and delete the test context. This should trigger texture garbage collection.
581*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
582*8975f5c5SAndroid Build Coastguard Worker SafeDestroyContext(display, mContexts[0]);
583*8975f5c5SAndroid Build Coastguard Worker
584*8975f5c5SAndroid Build Coastguard Worker // Bind the main context to clean up the test.
585*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mainContext));
586*8975f5c5SAndroid Build Coastguard Worker }
587*8975f5c5SAndroid Build Coastguard Worker
588*8975f5c5SAndroid Build Coastguard Worker // Test that deleting an object reading from a shared object in one context doesn't cause the other
589*8975f5c5SAndroid Build Coastguard Worker // context to crash. Mostly focused on the Vulkan back-end where we track resource dependencies in
590*8975f5c5SAndroid Build Coastguard Worker // a graph.
TEST_P(EGLContextSharingTest,DeleteReaderOfSharedTexture)591*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, DeleteReaderOfSharedTexture)
592*8975f5c5SAndroid Build Coastguard Worker {
593*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
594*8975f5c5SAndroid Build Coastguard Worker // GL Fences require GLES 3.0+
595*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
596*8975f5c5SAndroid Build Coastguard Worker
597*8975f5c5SAndroid Build Coastguard Worker // Initialize contexts
598*8975f5c5SAndroid Build Coastguard Worker EGLWindow *window = getEGLWindow();
599*8975f5c5SAndroid Build Coastguard Worker EGLDisplay dpy = window->getDisplay();
600*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = window->getConfig();
601*8975f5c5SAndroid Build Coastguard Worker
602*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kThreadCount = 2;
603*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
604*8975f5c5SAndroid Build Coastguard Worker EGLContext ctx[kThreadCount] = {EGL_NO_CONTEXT, EGL_NO_CONTEXT};
605*8975f5c5SAndroid Build Coastguard Worker
606*8975f5c5SAndroid Build Coastguard Worker EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
607*8975f5c5SAndroid Build Coastguard Worker
608*8975f5c5SAndroid Build Coastguard Worker for (size_t t = 0; t < kThreadCount; ++t)
609*8975f5c5SAndroid Build Coastguard Worker {
610*8975f5c5SAndroid Build Coastguard Worker surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
611*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
612*8975f5c5SAndroid Build Coastguard Worker
613*8975f5c5SAndroid Build Coastguard Worker ctx[t] = window->createContext(t == 0 ? EGL_NO_CONTEXT : ctx[0], nullptr);
614*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(EGL_NO_CONTEXT, ctx[t]);
615*8975f5c5SAndroid Build Coastguard Worker }
616*8975f5c5SAndroid Build Coastguard Worker
617*8975f5c5SAndroid Build Coastguard Worker // Initialize test resources. They are done outside the threads to reduce the sources of
618*8975f5c5SAndroid Build Coastguard Worker // errors and thus deadlock-free teardown.
619*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
620*8975f5c5SAndroid Build Coastguard Worker
621*8975f5c5SAndroid Build Coastguard Worker // Shared texture to read from.
622*8975f5c5SAndroid Build Coastguard Worker constexpr GLsizei kTexSize = 1;
623*8975f5c5SAndroid Build Coastguard Worker const GLColor kTexData = GLColor::red;
624*8975f5c5SAndroid Build Coastguard Worker
625*8975f5c5SAndroid Build Coastguard Worker GLTexture sharedTex;
626*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, sharedTex);
627*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
628*8975f5c5SAndroid Build Coastguard Worker &kTexData);
629*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
630*8975f5c5SAndroid Build Coastguard Worker glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
631*8975f5c5SAndroid Build Coastguard Worker
632*8975f5c5SAndroid Build Coastguard Worker // Resources for each context.
633*8975f5c5SAndroid Build Coastguard Worker GLRenderbuffer renderbuffer[kThreadCount];
634*8975f5c5SAndroid Build Coastguard Worker GLFramebuffer fbo[kThreadCount];
635*8975f5c5SAndroid Build Coastguard Worker GLProgram program[kThreadCount];
636*8975f5c5SAndroid Build Coastguard Worker
637*8975f5c5SAndroid Build Coastguard Worker for (size_t t = 0; t < kThreadCount; ++t)
638*8975f5c5SAndroid Build Coastguard Worker {
639*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(dpy, surface[t], surface[t], ctx[t]));
640*8975f5c5SAndroid Build Coastguard Worker
641*8975f5c5SAndroid Build Coastguard Worker glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[t]);
642*8975f5c5SAndroid Build Coastguard Worker constexpr int kRenderbufferSize = 4;
643*8975f5c5SAndroid Build Coastguard Worker glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, kRenderbufferSize, kRenderbufferSize);
644*8975f5c5SAndroid Build Coastguard Worker
645*8975f5c5SAndroid Build Coastguard Worker glBindFramebuffer(GL_FRAMEBUFFER, fbo[t]);
646*8975f5c5SAndroid Build Coastguard Worker glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
647*8975f5c5SAndroid Build Coastguard Worker renderbuffer[t]);
648*8975f5c5SAndroid Build Coastguard Worker
649*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, sharedTex);
650*8975f5c5SAndroid Build Coastguard Worker program[t].makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
651*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(program[t].valid());
652*8975f5c5SAndroid Build Coastguard Worker }
653*8975f5c5SAndroid Build Coastguard Worker
654*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
655*8975f5c5SAndroid Build Coastguard Worker
656*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
657*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
658*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
659*8975f5c5SAndroid Build Coastguard Worker std::atomic<GLsync> deletingThreadSyncObj;
660*8975f5c5SAndroid Build Coastguard Worker std::atomic<GLsync> continuingThreadSyncObj;
661*8975f5c5SAndroid Build Coastguard Worker
662*8975f5c5SAndroid Build Coastguard Worker enum class Step
663*8975f5c5SAndroid Build Coastguard Worker {
664*8975f5c5SAndroid Build Coastguard Worker Start,
665*8975f5c5SAndroid Build Coastguard Worker Thread0Draw,
666*8975f5c5SAndroid Build Coastguard Worker Thread1Draw,
667*8975f5c5SAndroid Build Coastguard Worker Thread0Delete,
668*8975f5c5SAndroid Build Coastguard Worker Finish,
669*8975f5c5SAndroid Build Coastguard Worker Abort,
670*8975f5c5SAndroid Build Coastguard Worker };
671*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
672*8975f5c5SAndroid Build Coastguard Worker
673*8975f5c5SAndroid Build Coastguard Worker std::thread deletingThread = std::thread([&]() {
674*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
675*8975f5c5SAndroid Build Coastguard Worker
676*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[0], surface[0], ctx[0]));
677*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
678*8975f5c5SAndroid Build Coastguard Worker
679*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
680*8975f5c5SAndroid Build Coastguard Worker
681*8975f5c5SAndroid Build Coastguard Worker // Draw using the shared texture.
682*8975f5c5SAndroid Build Coastguard Worker drawQuad(program[0].get(), essl1_shaders::PositionAttrib(), 0.5f);
683*8975f5c5SAndroid Build Coastguard Worker
684*8975f5c5SAndroid Build Coastguard Worker deletingThreadSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
685*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
686*8975f5c5SAndroid Build Coastguard Worker // Force the fence to be created
687*8975f5c5SAndroid Build Coastguard Worker glFlush();
688*8975f5c5SAndroid Build Coastguard Worker
689*8975f5c5SAndroid Build Coastguard Worker // Wait for the other thread to also draw using the shared texture.
690*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Draw);
691*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Draw));
692*8975f5c5SAndroid Build Coastguard Worker
693*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(continuingThreadSyncObj != nullptr);
694*8975f5c5SAndroid Build Coastguard Worker glWaitSync(continuingThreadSyncObj, 0, GL_TIMEOUT_IGNORED);
695*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
696*8975f5c5SAndroid Build Coastguard Worker glDeleteSync(continuingThreadSyncObj);
697*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
698*8975f5c5SAndroid Build Coastguard Worker continuingThreadSyncObj = nullptr;
699*8975f5c5SAndroid Build Coastguard Worker
700*8975f5c5SAndroid Build Coastguard Worker // Delete this thread's framebuffer (reader of the shared texture).
701*8975f5c5SAndroid Build Coastguard Worker fbo[0].reset();
702*8975f5c5SAndroid Build Coastguard Worker
703*8975f5c5SAndroid Build Coastguard Worker // Wait for the other thread to use the shared texture again before unbinding the
704*8975f5c5SAndroid Build Coastguard Worker // context (so no implicit flush happens).
705*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Delete);
706*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
707*8975f5c5SAndroid Build Coastguard Worker
708*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
709*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
710*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
711*8975f5c5SAndroid Build Coastguard Worker });
712*8975f5c5SAndroid Build Coastguard Worker
713*8975f5c5SAndroid Build Coastguard Worker std::thread continuingThread = std::thread([&]() {
714*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
715*8975f5c5SAndroid Build Coastguard Worker
716*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface[1], surface[1], ctx[1]));
717*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
718*8975f5c5SAndroid Build Coastguard Worker
719*8975f5c5SAndroid Build Coastguard Worker // Wait for first thread to draw using the shared texture.
720*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Draw));
721*8975f5c5SAndroid Build Coastguard Worker
722*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(deletingThreadSyncObj != nullptr);
723*8975f5c5SAndroid Build Coastguard Worker glWaitSync(deletingThreadSyncObj, 0, GL_TIMEOUT_IGNORED);
724*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
725*8975f5c5SAndroid Build Coastguard Worker glDeleteSync(deletingThreadSyncObj);
726*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
727*8975f5c5SAndroid Build Coastguard Worker deletingThreadSyncObj = nullptr;
728*8975f5c5SAndroid Build Coastguard Worker
729*8975f5c5SAndroid Build Coastguard Worker // Draw using the shared texture.
730*8975f5c5SAndroid Build Coastguard Worker drawQuad(program[0].get(), essl1_shaders::PositionAttrib(), 0.5f);
731*8975f5c5SAndroid Build Coastguard Worker
732*8975f5c5SAndroid Build Coastguard Worker continuingThreadSyncObj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
733*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
734*8975f5c5SAndroid Build Coastguard Worker // Force the fence to be created
735*8975f5c5SAndroid Build Coastguard Worker glFlush();
736*8975f5c5SAndroid Build Coastguard Worker
737*8975f5c5SAndroid Build Coastguard Worker // Wait for the other thread to delete its framebuffer.
738*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread1Draw);
739*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Delete));
740*8975f5c5SAndroid Build Coastguard Worker
741*8975f5c5SAndroid Build Coastguard Worker // Write to the shared texture differently, so a dependency is created from the previous
742*8975f5c5SAndroid Build Coastguard Worker // readers of the shared texture (the two framebuffers of the two threads) to the new
743*8975f5c5SAndroid Build Coastguard Worker // commands being recorded for the shared texture.
744*8975f5c5SAndroid Build Coastguard Worker //
745*8975f5c5SAndroid Build Coastguard Worker // If the backend attempts to create a dependency from nodes associated with the
746*8975f5c5SAndroid Build Coastguard Worker // previous readers of the texture to the new node that will contain the following
747*8975f5c5SAndroid Build Coastguard Worker // commands, there will be a use-after-free error.
748*8975f5c5SAndroid Build Coastguard Worker const GLColor kTexData2 = GLColor::green;
749*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
750*8975f5c5SAndroid Build Coastguard Worker &kTexData2);
751*8975f5c5SAndroid Build Coastguard Worker drawQuad(program[0].get(), essl1_shaders::PositionAttrib(), 0.5f);
752*8975f5c5SAndroid Build Coastguard Worker
753*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
754*8975f5c5SAndroid Build Coastguard Worker
755*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
756*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
757*8975f5c5SAndroid Build Coastguard Worker });
758*8975f5c5SAndroid Build Coastguard Worker
759*8975f5c5SAndroid Build Coastguard Worker deletingThread.join();
760*8975f5c5SAndroid Build Coastguard Worker continuingThread.join();
761*8975f5c5SAndroid Build Coastguard Worker
762*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(currentStep, Step::Abort);
763*8975f5c5SAndroid Build Coastguard Worker
764*8975f5c5SAndroid Build Coastguard Worker // Clean up
765*8975f5c5SAndroid Build Coastguard Worker for (size_t t = 0; t < kThreadCount; ++t)
766*8975f5c5SAndroid Build Coastguard Worker {
767*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(dpy, surface[t]);
768*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(dpy, ctx[t]);
769*8975f5c5SAndroid Build Coastguard Worker }
770*8975f5c5SAndroid Build Coastguard Worker }
771*8975f5c5SAndroid Build Coastguard Worker
772*8975f5c5SAndroid Build Coastguard Worker // Tests that Context will be destroyed in thread cleanup callback and it is safe to call GLES APIs.
TEST_P(EGLContextSharingTest,ThreadCleanupCallback)773*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, ThreadCleanupCallback)
774*8975f5c5SAndroid Build Coastguard Worker {
775*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
776*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!IsAndroid());
777*8975f5c5SAndroid Build Coastguard Worker
778*8975f5c5SAndroid Build Coastguard Worker EGLWindow *window = getEGLWindow();
779*8975f5c5SAndroid Build Coastguard Worker EGLDisplay dpy = window->getDisplay();
780*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = window->getConfig();
781*8975f5c5SAndroid Build Coastguard Worker
782*8975f5c5SAndroid Build Coastguard Worker EGLContext context = window->createContext(EGL_NO_CONTEXT, nullptr);
783*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(context, EGL_NO_CONTEXT);
784*8975f5c5SAndroid Build Coastguard Worker
785*8975f5c5SAndroid Build Coastguard Worker EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
786*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
787*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(surface, EGL_NO_SURFACE);
788*8975f5c5SAndroid Build Coastguard Worker
789*8975f5c5SAndroid Build Coastguard Worker auto registerThreadCleanupCallback = []() {
790*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_ANDROID)
791*8975f5c5SAndroid Build Coastguard Worker static pthread_once_t once = PTHREAD_ONCE_INIT;
792*8975f5c5SAndroid Build Coastguard Worker static TLSIndex tlsIndex = TLS_INVALID_INDEX;
793*8975f5c5SAndroid Build Coastguard Worker
794*8975f5c5SAndroid Build Coastguard Worker auto createThreadCleanupTLSIndex = []() {
795*8975f5c5SAndroid Build Coastguard Worker auto threadCleanupCallback = [](void *) {
796*8975f5c5SAndroid Build Coastguard Worker // From the point of view of this test Context is still current.
797*8975f5c5SAndroid Build Coastguard Worker glFinish();
798*8975f5c5SAndroid Build Coastguard Worker // Test expects that Context will be destroyed here.
799*8975f5c5SAndroid Build Coastguard Worker eglReleaseThread();
800*8975f5c5SAndroid Build Coastguard Worker };
801*8975f5c5SAndroid Build Coastguard Worker tlsIndex = CreateTLSIndex(threadCleanupCallback);
802*8975f5c5SAndroid Build Coastguard Worker };
803*8975f5c5SAndroid Build Coastguard Worker pthread_once(&once, createThreadCleanupTLSIndex);
804*8975f5c5SAndroid Build Coastguard Worker ASSERT(tlsIndex != TLS_INVALID_INDEX);
805*8975f5c5SAndroid Build Coastguard Worker
806*8975f5c5SAndroid Build Coastguard Worker // Set any non nullptr value.
807*8975f5c5SAndroid Build Coastguard Worker SetTLSValue(tlsIndex, &once);
808*8975f5c5SAndroid Build Coastguard Worker #endif
809*8975f5c5SAndroid Build Coastguard Worker };
810*8975f5c5SAndroid Build Coastguard Worker
811*8975f5c5SAndroid Build Coastguard Worker std::thread thread([&]() {
812*8975f5c5SAndroid Build Coastguard Worker registerThreadCleanupCallback();
813*8975f5c5SAndroid Build Coastguard Worker
814*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(dpy, surface, surface, context);
815*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
816*8975f5c5SAndroid Build Coastguard Worker
817*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread uses context.
818*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 0.0, 0.0, 1.0);
819*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
820*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
821*8975f5c5SAndroid Build Coastguard Worker
822*8975f5c5SAndroid Build Coastguard Worker // Destroy context and surface while still current.
823*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(dpy, context);
824*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
825*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(dpy, surface);
826*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
827*8975f5c5SAndroid Build Coastguard Worker });
828*8975f5c5SAndroid Build Coastguard Worker
829*8975f5c5SAndroid Build Coastguard Worker thread.join();
830*8975f5c5SAndroid Build Coastguard Worker
831*8975f5c5SAndroid Build Coastguard Worker // Check if context was actually destroyed.
832*8975f5c5SAndroid Build Coastguard Worker EGLint val;
833*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_FALSE(eglQueryContext(dpy, context, EGL_CONTEXT_CLIENT_TYPE, &val));
834*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(eglGetError(), EGL_BAD_CONTEXT);
835*8975f5c5SAndroid Build Coastguard Worker }
836*8975f5c5SAndroid Build Coastguard Worker
837*8975f5c5SAndroid Build Coastguard Worker // Tests that Context will be automatically unmade from current on thread exit.
TEST_P(EGLContextSharingTest,UnmakeFromCurrentOnThreadExit)838*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTest, UnmakeFromCurrentOnThreadExit)
839*8975f5c5SAndroid Build Coastguard Worker {
840*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
841*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!IsAndroid());
842*8975f5c5SAndroid Build Coastguard Worker
843*8975f5c5SAndroid Build Coastguard Worker EGLWindow *window = getEGLWindow();
844*8975f5c5SAndroid Build Coastguard Worker EGLDisplay dpy = window->getDisplay();
845*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = window->getConfig();
846*8975f5c5SAndroid Build Coastguard Worker
847*8975f5c5SAndroid Build Coastguard Worker EGLContext context = window->createContext(EGL_NO_CONTEXT, nullptr);
848*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(context, EGL_NO_CONTEXT);
849*8975f5c5SAndroid Build Coastguard Worker
850*8975f5c5SAndroid Build Coastguard Worker EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
851*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes);
852*8975f5c5SAndroid Build Coastguard Worker EXPECT_NE(surface, EGL_NO_SURFACE);
853*8975f5c5SAndroid Build Coastguard Worker
854*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
855*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
856*8975f5c5SAndroid Build Coastguard Worker enum class Step
857*8975f5c5SAndroid Build Coastguard Worker {
858*8975f5c5SAndroid Build Coastguard Worker Start,
859*8975f5c5SAndroid Build Coastguard Worker ThreadMakeCurrent,
860*8975f5c5SAndroid Build Coastguard Worker Finish,
861*8975f5c5SAndroid Build Coastguard Worker Abort,
862*8975f5c5SAndroid Build Coastguard Worker };
863*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
864*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
865*8975f5c5SAndroid Build Coastguard Worker
866*8975f5c5SAndroid Build Coastguard Worker std::thread thread([&]() {
867*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(dpy, surface, surface, context);
868*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
869*8975f5c5SAndroid Build Coastguard Worker
870*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::ThreadMakeCurrent);
871*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
872*8975f5c5SAndroid Build Coastguard Worker
873*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread uses context.
874*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 0.0, 0.0, 1.0);
875*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
876*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
877*8975f5c5SAndroid Build Coastguard Worker });
878*8975f5c5SAndroid Build Coastguard Worker
879*8975f5c5SAndroid Build Coastguard Worker // Wait while Context is made current in the thread.
880*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::ThreadMakeCurrent));
881*8975f5c5SAndroid Build Coastguard Worker
882*8975f5c5SAndroid Build Coastguard Worker // This should fail because context is already current in other thread.
883*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(dpy, surface, surface, context);
884*8975f5c5SAndroid Build Coastguard Worker EXPECT_EQ(eglGetError(), EGL_BAD_ACCESS);
885*8975f5c5SAndroid Build Coastguard Worker
886*8975f5c5SAndroid Build Coastguard Worker // Finish the thread.
887*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
888*8975f5c5SAndroid Build Coastguard Worker thread.join();
889*8975f5c5SAndroid Build Coastguard Worker
890*8975f5c5SAndroid Build Coastguard Worker // This should succeed, because thread is finished so context is no longer current.
891*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(dpy, surface, surface, context);
892*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
893*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
894*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
895*8975f5c5SAndroid Build Coastguard Worker
896*8975f5c5SAndroid Build Coastguard Worker // Destroy context and surface.
897*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(dpy, context);
898*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
899*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(dpy, surface);
900*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
901*8975f5c5SAndroid Build Coastguard Worker }
902*8975f5c5SAndroid Build Coastguard Worker
903*8975f5c5SAndroid Build Coastguard Worker // Test that an inactive but alive thread doesn't prevent memory cleanup.
TEST_P(EGLContextSharingTestNoFixture,InactiveThreadDoesntPreventCleanup)904*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, InactiveThreadDoesntPreventCleanup)
905*8975f5c5SAndroid Build Coastguard Worker {
906*8975f5c5SAndroid Build Coastguard Worker EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
907*8975f5c5SAndroid Build Coastguard Worker EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, GetParam().getDeviceType(),
908*8975f5c5SAndroid Build Coastguard Worker EGL_NONE};
909*8975f5c5SAndroid Build Coastguard Worker
910*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
911*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
912*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
913*8975f5c5SAndroid Build Coastguard Worker
914*8975f5c5SAndroid Build Coastguard Worker enum class Step
915*8975f5c5SAndroid Build Coastguard Worker {
916*8975f5c5SAndroid Build Coastguard Worker Start,
917*8975f5c5SAndroid Build Coastguard Worker Thread0Initialize,
918*8975f5c5SAndroid Build Coastguard Worker Thread1MakeCurrent,
919*8975f5c5SAndroid Build Coastguard Worker Thread0MakeCurrent,
920*8975f5c5SAndroid Build Coastguard Worker Thread1Render,
921*8975f5c5SAndroid Build Coastguard Worker Thread0Terminate,
922*8975f5c5SAndroid Build Coastguard Worker Finish,
923*8975f5c5SAndroid Build Coastguard Worker Abort,
924*8975f5c5SAndroid Build Coastguard Worker };
925*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
926*8975f5c5SAndroid Build Coastguard Worker
927*8975f5c5SAndroid Build Coastguard Worker std::thread thread0 = std::thread([&]() {
928*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
929*8975f5c5SAndroid Build Coastguard Worker
930*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
931*8975f5c5SAndroid Build Coastguard Worker
932*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(
933*8975f5c5SAndroid Build Coastguard Worker EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
934*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
935*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
936*8975f5c5SAndroid Build Coastguard Worker
937*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Initialize);
938*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1MakeCurrent));
939*8975f5c5SAndroid Build Coastguard Worker
940*8975f5c5SAndroid Build Coastguard Worker EGLContext ctx;
941*8975f5c5SAndroid Build Coastguard Worker EGLSurface srf;
942*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
943*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
944*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &ctx));
945*8975f5c5SAndroid Build Coastguard Worker
946*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createPbufferSurface(mDisplay, config, 1280, 720, &srf));
947*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
948*8975f5c5SAndroid Build Coastguard Worker
949*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, srf, srf, ctx));
950*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0MakeCurrent);
951*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Render));
952*8975f5c5SAndroid Build Coastguard Worker
953*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
954*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
955*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
956*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Terminate);
957*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
958*8975f5c5SAndroid Build Coastguard Worker
959*8975f5c5SAndroid Build Coastguard Worker // Wait a little to simulate an inactive but alive thread.
960*8975f5c5SAndroid Build Coastguard Worker angle::Sleep(100);
961*8975f5c5SAndroid Build Coastguard Worker });
962*8975f5c5SAndroid Build Coastguard Worker
963*8975f5c5SAndroid Build Coastguard Worker std::thread thread1 = std::thread([&]() {
964*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
965*8975f5c5SAndroid Build Coastguard Worker
966*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Initialize));
967*8975f5c5SAndroid Build Coastguard Worker
968*8975f5c5SAndroid Build Coastguard Worker EGLContext ctx;
969*8975f5c5SAndroid Build Coastguard Worker EGLSurface srf;
970*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
971*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
972*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &ctx));
973*8975f5c5SAndroid Build Coastguard Worker
974*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createPbufferSurface(mDisplay, config, 1280, 720, &srf));
975*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
976*8975f5c5SAndroid Build Coastguard Worker
977*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, srf, srf, ctx));
978*8975f5c5SAndroid Build Coastguard Worker
979*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread1MakeCurrent);
980*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0MakeCurrent));
981*8975f5c5SAndroid Build Coastguard Worker
982*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread uses context and surface.
983*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 0.0, 0.0, 1.0);
984*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
985*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
986*8975f5c5SAndroid Build Coastguard Worker
987*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread1Render);
988*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Terminate));
989*8975f5c5SAndroid Build Coastguard Worker
990*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
991*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
992*8975f5c5SAndroid Build Coastguard Worker });
993*8975f5c5SAndroid Build Coastguard Worker
994*8975f5c5SAndroid Build Coastguard Worker thread1.join();
995*8975f5c5SAndroid Build Coastguard Worker thread0.join();
996*8975f5c5SAndroid Build Coastguard Worker
997*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(currentStep, Step::Abort);
998*8975f5c5SAndroid Build Coastguard Worker }
999*8975f5c5SAndroid Build Coastguard Worker
1000*8975f5c5SAndroid Build Coastguard Worker // Test that eglTerminate() with a thread doesn't cause other threads to crash.
TEST_P(EGLContextSharingTestNoFixture,EglTerminateMultiThreaded)1001*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, EglTerminateMultiThreaded)
1002*8975f5c5SAndroid Build Coastguard Worker {
1003*8975f5c5SAndroid Build Coastguard Worker // http://anglebug.com/42264731
1004*8975f5c5SAndroid Build Coastguard Worker // The following EGL calls led to a crash in eglMakeCurrent():
1005*8975f5c5SAndroid Build Coastguard Worker //
1006*8975f5c5SAndroid Build Coastguard Worker // Thread A: eglMakeCurrent(context A)
1007*8975f5c5SAndroid Build Coastguard Worker // Thread B: eglDestroyContext(context A)
1008*8975f5c5SAndroid Build Coastguard Worker // B: eglTerminate() <<--- this release context A
1009*8975f5c5SAndroid Build Coastguard Worker // Thread A: eglMakeCurrent(context B)
1010*8975f5c5SAndroid Build Coastguard Worker
1011*8975f5c5SAndroid Build Coastguard Worker EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
1012*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
1013*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1014*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1015*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1016*8975f5c5SAndroid Build Coastguard Worker
1017*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
1018*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1019*8975f5c5SAndroid Build Coastguard Worker
1020*8975f5c5SAndroid Build Coastguard Worker mOsWindow->initialize("EGLContextSharingTestNoFixture", kWidth, kHeight);
1021*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createWindowSurface(config, mOsWindow->getNativeWindow(), &mSurface));
1022*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
1023*8975f5c5SAndroid Build Coastguard Worker
1024*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[0]));
1025*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
1026*8975f5c5SAndroid Build Coastguard Worker
1027*8975f5c5SAndroid Build Coastguard Worker // Must be after the eglMakeCurrent() so renderer string is initialized.
1028*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1029*8975f5c5SAndroid Build Coastguard Worker // TODO(http://anglebug.com/42264822): Fails with OpenGL ES backend.
1030*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(IsOpenGLES());
1031*8975f5c5SAndroid Build Coastguard Worker
1032*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1033*8975f5c5SAndroid Build Coastguard Worker
1034*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
1035*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
1036*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
1037*8975f5c5SAndroid Build Coastguard Worker
1038*8975f5c5SAndroid Build Coastguard Worker enum class Step
1039*8975f5c5SAndroid Build Coastguard Worker {
1040*8975f5c5SAndroid Build Coastguard Worker Start,
1041*8975f5c5SAndroid Build Coastguard Worker Thread0Clear,
1042*8975f5c5SAndroid Build Coastguard Worker Thread1Terminate,
1043*8975f5c5SAndroid Build Coastguard Worker Thread0MakeCurrentContext1,
1044*8975f5c5SAndroid Build Coastguard Worker Finish,
1045*8975f5c5SAndroid Build Coastguard Worker Abort,
1046*8975f5c5SAndroid Build Coastguard Worker };
1047*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
1048*8975f5c5SAndroid Build Coastguard Worker
1049*8975f5c5SAndroid Build Coastguard Worker std::thread thread0 = std::thread([&]() {
1050*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1051*8975f5c5SAndroid Build Coastguard Worker
1052*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1053*8975f5c5SAndroid Build Coastguard Worker
1054*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
1055*8975f5c5SAndroid Build Coastguard Worker
1056*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread 0 uses context 0.
1057*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 0.0, 0.0, 1.0);
1058*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1059*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
1060*8975f5c5SAndroid Build Coastguard Worker
1061*8975f5c5SAndroid Build Coastguard Worker // Wait for thread 1 to clear.
1062*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Clear);
1063*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Terminate));
1064*8975f5c5SAndroid Build Coastguard Worker
1065*8975f5c5SAndroid Build Coastguard Worker // First Display was terminated, so we need to create a new one to create a new Context.
1066*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(
1067*8975f5c5SAndroid Build Coastguard Worker EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1068*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1069*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1070*8975f5c5SAndroid Build Coastguard Worker config = EGL_NO_CONFIG_KHR;
1071*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1072*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[1]));
1073*8975f5c5SAndroid Build Coastguard Worker
1074*8975f5c5SAndroid Build Coastguard Worker // Thread1's terminate call will make mSurface an invalid handle, recreate a new surface
1075*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createPbufferSurface(mDisplay, config, 1280, 720, &mSurface));
1076*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
1077*8975f5c5SAndroid Build Coastguard Worker
1078*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[1]));
1079*8975f5c5SAndroid Build Coastguard Worker
1080*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread 0 uses context 1.
1081*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 1.0, 0.0, 1.0);
1082*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1083*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 255, 0, 255);
1084*8975f5c5SAndroid Build Coastguard Worker
1085*8975f5c5SAndroid Build Coastguard Worker // Cleanup
1086*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1087*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(SafeDestroyContext(mDisplay, mContexts[1]));
1088*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, mSurface);
1089*8975f5c5SAndroid Build Coastguard Worker mSurface = EGL_NO_SURFACE;
1090*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1091*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
1092*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1093*8975f5c5SAndroid Build Coastguard Worker
1094*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0MakeCurrentContext1);
1095*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1096*8975f5c5SAndroid Build Coastguard Worker });
1097*8975f5c5SAndroid Build Coastguard Worker
1098*8975f5c5SAndroid Build Coastguard Worker std::thread thread1 = std::thread([&]() {
1099*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1100*8975f5c5SAndroid Build Coastguard Worker
1101*8975f5c5SAndroid Build Coastguard Worker // Wait for thread 0 to clear.
1102*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Clear));
1103*8975f5c5SAndroid Build Coastguard Worker
1104*8975f5c5SAndroid Build Coastguard Worker // Destroy context 0 while thread1 has it current.
1105*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1106*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(SafeDestroyContext(mDisplay, mContexts[0]));
1107*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1108*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1109*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
1110*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1111*8975f5c5SAndroid Build Coastguard Worker
1112*8975f5c5SAndroid Build Coastguard Worker // Wait for the thread 0 to make a new context and glClear().
1113*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread1Terminate);
1114*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0MakeCurrentContext1));
1115*8975f5c5SAndroid Build Coastguard Worker
1116*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
1117*8975f5c5SAndroid Build Coastguard Worker });
1118*8975f5c5SAndroid Build Coastguard Worker
1119*8975f5c5SAndroid Build Coastguard Worker thread0.join();
1120*8975f5c5SAndroid Build Coastguard Worker thread1.join();
1121*8975f5c5SAndroid Build Coastguard Worker
1122*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(currentStep, Step::Abort);
1123*8975f5c5SAndroid Build Coastguard Worker }
1124*8975f5c5SAndroid Build Coastguard Worker
1125*8975f5c5SAndroid Build Coastguard Worker // Test that eglDestoryContext() can be called multiple times on the same Context without causing
1126*8975f5c5SAndroid Build Coastguard Worker // errors.
TEST_P(EGLContextSharingTestNoFixture,EglDestoryContextManyTimesSameContext)1127*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, EglDestoryContextManyTimesSameContext)
1128*8975f5c5SAndroid Build Coastguard Worker {
1129*8975f5c5SAndroid Build Coastguard Worker EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
1130*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
1131*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1132*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1133*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1134*8975f5c5SAndroid Build Coastguard Worker
1135*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
1136*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1137*8975f5c5SAndroid Build Coastguard Worker
1138*8975f5c5SAndroid Build Coastguard Worker mOsWindow->initialize("EGLContextSharingTestNoFixture", kWidth, kHeight);
1139*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createWindowSurface(config, mOsWindow->getNativeWindow(), &mSurface));
1140*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
1141*8975f5c5SAndroid Build Coastguard Worker
1142*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[0]));
1143*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
1144*8975f5c5SAndroid Build Coastguard Worker
1145*8975f5c5SAndroid Build Coastguard Worker // Must be after the eglMakeCurrent() so renderer string is initialized.
1146*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1147*8975f5c5SAndroid Build Coastguard Worker // TODO(http://anglebug.com/42264822): Fails with OpenGL ES backend.
1148*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(IsOpenGLES());
1149*8975f5c5SAndroid Build Coastguard Worker
1150*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1151*8975f5c5SAndroid Build Coastguard Worker
1152*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
1153*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
1154*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
1155*8975f5c5SAndroid Build Coastguard Worker
1156*8975f5c5SAndroid Build Coastguard Worker enum class Step
1157*8975f5c5SAndroid Build Coastguard Worker {
1158*8975f5c5SAndroid Build Coastguard Worker Start,
1159*8975f5c5SAndroid Build Coastguard Worker Thread0Clear,
1160*8975f5c5SAndroid Build Coastguard Worker Thread1Terminate,
1161*8975f5c5SAndroid Build Coastguard Worker Thread0MakeCurrentContext1,
1162*8975f5c5SAndroid Build Coastguard Worker Finish,
1163*8975f5c5SAndroid Build Coastguard Worker Abort,
1164*8975f5c5SAndroid Build Coastguard Worker };
1165*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
1166*8975f5c5SAndroid Build Coastguard Worker
1167*8975f5c5SAndroid Build Coastguard Worker std::thread thread0 = std::thread([&]() {
1168*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1169*8975f5c5SAndroid Build Coastguard Worker
1170*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1171*8975f5c5SAndroid Build Coastguard Worker
1172*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
1173*8975f5c5SAndroid Build Coastguard Worker
1174*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread 0 uses context 0.
1175*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 0.0, 0.0, 1.0);
1176*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1177*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
1178*8975f5c5SAndroid Build Coastguard Worker
1179*8975f5c5SAndroid Build Coastguard Worker // Wait for thread 1 to clear.
1180*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0Clear);
1181*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread1Terminate));
1182*8975f5c5SAndroid Build Coastguard Worker
1183*8975f5c5SAndroid Build Coastguard Worker // First Display was terminated, so we need to create a new one to create a new Context.
1184*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(
1185*8975f5c5SAndroid Build Coastguard Worker EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1186*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1187*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1188*8975f5c5SAndroid Build Coastguard Worker config = EGL_NO_CONFIG_KHR;
1189*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1190*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[1]));
1191*8975f5c5SAndroid Build Coastguard Worker
1192*8975f5c5SAndroid Build Coastguard Worker // Thread1's terminate call will make mSurface an invalid handle, recreate a new surface
1193*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createPbufferSurface(mDisplay, config, 1280, 720, &mSurface));
1194*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreatePbufferSurface failed.";
1195*8975f5c5SAndroid Build Coastguard Worker
1196*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[1]));
1197*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1198*8975f5c5SAndroid Build Coastguard Worker
1199*8975f5c5SAndroid Build Coastguard Worker // Clear and read back to make sure thread 0 uses context 1.
1200*8975f5c5SAndroid Build Coastguard Worker glClearColor(1.0, 1.0, 0.0, 1.0);
1201*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1202*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_EQ(0, 0, 255, 255, 0, 255);
1203*8975f5c5SAndroid Build Coastguard Worker
1204*8975f5c5SAndroid Build Coastguard Worker // Cleanup
1205*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1206*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(SafeDestroyContext(mDisplay, mContexts[1]));
1207*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, mSurface);
1208*8975f5c5SAndroid Build Coastguard Worker mSurface = EGL_NO_SURFACE;
1209*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1210*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
1211*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1212*8975f5c5SAndroid Build Coastguard Worker
1213*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread0MakeCurrentContext1);
1214*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1215*8975f5c5SAndroid Build Coastguard Worker });
1216*8975f5c5SAndroid Build Coastguard Worker
1217*8975f5c5SAndroid Build Coastguard Worker std::thread thread1 = std::thread([&]() {
1218*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1219*8975f5c5SAndroid Build Coastguard Worker
1220*8975f5c5SAndroid Build Coastguard Worker // Wait for thread 0 to clear.
1221*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0Clear));
1222*8975f5c5SAndroid Build Coastguard Worker
1223*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1224*8975f5c5SAndroid Build Coastguard Worker
1225*8975f5c5SAndroid Build Coastguard Worker // Destroy context 0 5 times while thread1 has it current.
1226*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1227*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1228*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1229*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1230*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1231*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = EGL_NO_CONTEXT;
1232*8975f5c5SAndroid Build Coastguard Worker
1233*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, mSurface);
1234*8975f5c5SAndroid Build Coastguard Worker mSurface = EGL_NO_SURFACE;
1235*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1236*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
1237*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1238*8975f5c5SAndroid Build Coastguard Worker
1239*8975f5c5SAndroid Build Coastguard Worker // Wait for the thread 0 to make a new context and glClear().
1240*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Thread1Terminate);
1241*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Thread0MakeCurrentContext1));
1242*8975f5c5SAndroid Build Coastguard Worker
1243*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
1244*8975f5c5SAndroid Build Coastguard Worker });
1245*8975f5c5SAndroid Build Coastguard Worker
1246*8975f5c5SAndroid Build Coastguard Worker thread0.join();
1247*8975f5c5SAndroid Build Coastguard Worker thread1.join();
1248*8975f5c5SAndroid Build Coastguard Worker
1249*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(currentStep, Step::Abort);
1250*8975f5c5SAndroid Build Coastguard Worker }
1251*8975f5c5SAndroid Build Coastguard Worker
1252*8975f5c5SAndroid Build Coastguard Worker // Test that eglTerminate() can be called multiple times on the same Display while Contexts are
1253*8975f5c5SAndroid Build Coastguard Worker // still current without causing errors.
TEST_P(EGLContextSharingTestNoFixture,EglTerminateMultipleTimes)1254*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, EglTerminateMultipleTimes)
1255*8975f5c5SAndroid Build Coastguard Worker {
1256*8975f5c5SAndroid Build Coastguard Worker // https://bugs.chromium.org/p/skia/issues/detail?id=12413#c4
1257*8975f5c5SAndroid Build Coastguard Worker // The following sequence caused a crash with the D3D backend in the Skia infra:
1258*8975f5c5SAndroid Build Coastguard Worker // eglDestroyContext(ctx0)
1259*8975f5c5SAndroid Build Coastguard Worker // eglDestroySurface(srf0)
1260*8975f5c5SAndroid Build Coastguard Worker // eglTerminate(shared-display)
1261*8975f5c5SAndroid Build Coastguard Worker // eglDestroyContext(ctx1) // completes the cleanup from the above terminate
1262*8975f5c5SAndroid Build Coastguard Worker // eglDestroySurface(srf1)
1263*8975f5c5SAndroid Build Coastguard Worker // eglTerminate(shared-display)
1264*8975f5c5SAndroid Build Coastguard Worker
1265*8975f5c5SAndroid Build Coastguard Worker EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
1266*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
1267*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1268*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1269*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1270*8975f5c5SAndroid Build Coastguard Worker
1271*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
1272*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1273*8975f5c5SAndroid Build Coastguard Worker
1274*8975f5c5SAndroid Build Coastguard Worker mOsWindow->initialize("EGLContextSharingTestNoFixture", kWidth, kHeight);
1275*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createWindowSurface(config, mOsWindow->getNativeWindow(), &mSurface));
1276*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mSurface != EGL_NO_SURFACE);
1277*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
1278*8975f5c5SAndroid Build Coastguard Worker
1279*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[0]));
1280*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]));
1281*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[1]));
1282*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[1]));
1283*8975f5c5SAndroid Build Coastguard Worker
1284*8975f5c5SAndroid Build Coastguard Worker // Must be after the eglMakeCurrent() so renderer string is initialized.
1285*8975f5c5SAndroid Build Coastguard Worker // TODO(http://anglebug.com/42264822): Fails with Mac + OpenGL backend.
1286*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL());
1287*8975f5c5SAndroid Build Coastguard Worker
1288*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1289*8975f5c5SAndroid Build Coastguard Worker
1290*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, mSurface);
1291*8975f5c5SAndroid Build Coastguard Worker mSurface = EGL_NO_SURFACE;
1292*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglDestroyContext(mDisplay, mContexts[0]));
1293*8975f5c5SAndroid Build Coastguard Worker mContexts[0] = EGL_NO_CONTEXT;
1294*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1295*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1296*8975f5c5SAndroid Build Coastguard Worker
1297*8975f5c5SAndroid Build Coastguard Worker eglDestroyContext(mDisplay, mContexts[1]);
1298*8975f5c5SAndroid Build Coastguard Worker mContexts[1] = EGL_NO_CONTEXT;
1299*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_ERROR(EGL_NOT_INITIALIZED);
1300*8975f5c5SAndroid Build Coastguard Worker eglTerminate(mDisplay);
1301*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1302*8975f5c5SAndroid Build Coastguard Worker mDisplay = EGL_NO_DISPLAY;
1303*8975f5c5SAndroid Build Coastguard Worker }
1304*8975f5c5SAndroid Build Coastguard Worker
1305*8975f5c5SAndroid Build Coastguard Worker // Test that we can eglSwapBuffers in one thread while another thread renders to a texture.
TEST_P(EGLContextSharingTestNoFixture,SwapBuffersShared)1306*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, SwapBuffersShared)
1307*8975f5c5SAndroid Build Coastguard Worker {
1308*8975f5c5SAndroid Build Coastguard Worker EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
1309*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
1310*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1311*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1312*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1313*8975f5c5SAndroid Build Coastguard Worker
1314*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
1315*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1316*8975f5c5SAndroid Build Coastguard Worker
1317*8975f5c5SAndroid Build Coastguard Worker mOsWindow->initialize("EGLContextSharingTestNoFixture", kWidth, kHeight);
1318*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createWindowSurface(config, mOsWindow->getNativeWindow(), &mSurface));
1319*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
1320*8975f5c5SAndroid Build Coastguard Worker
1321*8975f5c5SAndroid Build Coastguard Worker EGLSurface pbufferSurface;
1322*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createPbufferSurface(mDisplay, config, kWidth, kHeight, &pbufferSurface));
1323*8975f5c5SAndroid Build Coastguard Worker
1324*8975f5c5SAndroid Build Coastguard Worker // Create the two contextss
1325*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[0]));
1326*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[1], mContexts[0]));
1327*8975f5c5SAndroid Build Coastguard Worker
1328*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]);
1329*8975f5c5SAndroid Build Coastguard Worker ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
1330*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1331*8975f5c5SAndroid Build Coastguard Worker
1332*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
1333*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
1334*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
1335*8975f5c5SAndroid Build Coastguard Worker
1336*8975f5c5SAndroid Build Coastguard Worker enum class Step
1337*8975f5c5SAndroid Build Coastguard Worker {
1338*8975f5c5SAndroid Build Coastguard Worker Start,
1339*8975f5c5SAndroid Build Coastguard Worker TextureInitialized,
1340*8975f5c5SAndroid Build Coastguard Worker Finish,
1341*8975f5c5SAndroid Build Coastguard Worker Abort,
1342*8975f5c5SAndroid Build Coastguard Worker };
1343*8975f5c5SAndroid Build Coastguard Worker
1344*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
1345*8975f5c5SAndroid Build Coastguard Worker
1346*8975f5c5SAndroid Build Coastguard Worker // Sample a texture in the swap thread.
1347*8975f5c5SAndroid Build Coastguard Worker std::thread swapThread = std::thread([&]() {
1348*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1349*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1350*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]);
1351*8975f5c5SAndroid Build Coastguard Worker
1352*8975f5c5SAndroid Build Coastguard Worker glGenTextures(1, &mTexture);
1353*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, mTexture);
1354*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1355*8975f5c5SAndroid Build Coastguard Worker nullptr);
1356*8975f5c5SAndroid Build Coastguard Worker
1357*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::TextureInitialized);
1358*8975f5c5SAndroid Build Coastguard Worker
1359*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
1360*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program);
1361*8975f5c5SAndroid Build Coastguard Worker
1362*8975f5c5SAndroid Build Coastguard Worker for (int i = 0; i < 100; ++i)
1363*8975f5c5SAndroid Build Coastguard Worker {
1364*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1365*8975f5c5SAndroid Build Coastguard Worker drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
1366*8975f5c5SAndroid Build Coastguard Worker EXPECT_GL_NO_ERROR();
1367*8975f5c5SAndroid Build Coastguard Worker eglSwapBuffers(mDisplay, mSurface);
1368*8975f5c5SAndroid Build Coastguard Worker }
1369*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1370*8975f5c5SAndroid Build Coastguard Worker eglReleaseThread();
1371*8975f5c5SAndroid Build Coastguard Worker
1372*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1373*8975f5c5SAndroid Build Coastguard Worker });
1374*8975f5c5SAndroid Build Coastguard Worker
1375*8975f5c5SAndroid Build Coastguard Worker // Render to the texture in the render thread.
1376*8975f5c5SAndroid Build Coastguard Worker std::thread renderThread = std::thread([&]() {
1377*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1378*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, pbufferSurface, pbufferSurface, mContexts[1]));
1379*8975f5c5SAndroid Build Coastguard Worker
1380*8975f5c5SAndroid Build Coastguard Worker GLFramebuffer fbo;
1381*8975f5c5SAndroid Build Coastguard Worker glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1382*8975f5c5SAndroid Build Coastguard Worker
1383*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
1384*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
1385*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
1386*8975f5c5SAndroid Build Coastguard Worker
1387*8975f5c5SAndroid Build Coastguard Worker // The render thread will draw to the texture.
1388*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::TextureInitialized));
1389*8975f5c5SAndroid Build Coastguard Worker glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
1390*8975f5c5SAndroid Build Coastguard Worker glDisable(GL_DEPTH_TEST);
1391*8975f5c5SAndroid Build Coastguard Worker
1392*8975f5c5SAndroid Build Coastguard Worker for (int i = 0; i < 400; ++i)
1393*8975f5c5SAndroid Build Coastguard Worker {
1394*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1395*8975f5c5SAndroid Build Coastguard Worker glUseProgram(redProgram);
1396*8975f5c5SAndroid Build Coastguard Worker drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
1397*8975f5c5SAndroid Build Coastguard Worker
1398*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1399*8975f5c5SAndroid Build Coastguard Worker glUseProgram(greenProgram);
1400*8975f5c5SAndroid Build Coastguard Worker drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
1401*8975f5c5SAndroid Build Coastguard Worker
1402*8975f5c5SAndroid Build Coastguard Worker glClear(GL_COLOR_BUFFER_BIT);
1403*8975f5c5SAndroid Build Coastguard Worker glUseProgram(blueProgram);
1404*8975f5c5SAndroid Build Coastguard Worker drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
1405*8975f5c5SAndroid Build Coastguard Worker }
1406*8975f5c5SAndroid Build Coastguard Worker eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1407*8975f5c5SAndroid Build Coastguard Worker eglReleaseThread();
1408*8975f5c5SAndroid Build Coastguard Worker
1409*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
1410*8975f5c5SAndroid Build Coastguard Worker });
1411*8975f5c5SAndroid Build Coastguard Worker
1412*8975f5c5SAndroid Build Coastguard Worker swapThread.join();
1413*8975f5c5SAndroid Build Coastguard Worker renderThread.join();
1414*8975f5c5SAndroid Build Coastguard Worker
1415*8975f5c5SAndroid Build Coastguard Worker eglDestroySurface(mDisplay, pbufferSurface);
1416*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1417*8975f5c5SAndroid Build Coastguard Worker }
1418*8975f5c5SAndroid Build Coastguard Worker
1419*8975f5c5SAndroid Build Coastguard Worker class EGLContextSharingTestNoSyncTextureUploads : public EGLContextSharingTest
1420*8975f5c5SAndroid Build Coastguard Worker {};
1421*8975f5c5SAndroid Build Coastguard Worker
1422*8975f5c5SAndroid Build Coastguard Worker // Test that an application that does not synchronize when using textures across shared contexts can
1423*8975f5c5SAndroid Build Coastguard Worker // still see texture updates. This behavior is not required by the GLES specification, but is
1424*8975f5c5SAndroid Build Coastguard Worker // exhibited by some applications. That application will malfunction if our implementation does not
1425*8975f5c5SAndroid Build Coastguard Worker // handle this in the way it expects. Only the vulkan backend has the workaround needed for this
1426*8975f5c5SAndroid Build Coastguard Worker // usecase.
TEST_P(EGLContextSharingTestNoSyncTextureUploads,NoSync)1427*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoSyncTextureUploads, NoSync)
1428*8975f5c5SAndroid Build Coastguard Worker {
1429*8975f5c5SAndroid Build Coastguard Worker EGLDisplay display = getEGLWindow()->getDisplay();
1430*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = getEGLWindow()->getConfig();
1431*8975f5c5SAndroid Build Coastguard Worker
1432*8975f5c5SAndroid Build Coastguard Worker const EGLint inShareGroupContextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
1433*8975f5c5SAndroid Build Coastguard Worker const EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
1434*8975f5c5SAndroid Build Coastguard Worker
1435*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kThreadCount = 2;
1436*8975f5c5SAndroid Build Coastguard Worker EGLSurface surface[kThreadCount] = {EGL_NO_SURFACE, EGL_NO_SURFACE};
1437*8975f5c5SAndroid Build Coastguard Worker
1438*8975f5c5SAndroid Build Coastguard Worker for (size_t t = 0; t < kThreadCount; ++t)
1439*8975f5c5SAndroid Build Coastguard Worker {
1440*8975f5c5SAndroid Build Coastguard Worker mContexts[t] = eglCreateContext(display, config, t == 0 ? EGL_NO_CONTEXT : mContexts[0],
1441*8975f5c5SAndroid Build Coastguard Worker inShareGroupContextAttribs);
1442*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1443*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_CONTEXT, mContexts[t]);
1444*8975f5c5SAndroid Build Coastguard Worker
1445*8975f5c5SAndroid Build Coastguard Worker surface[t] = eglCreatePbufferSurface(display, config, pbufferAttributes);
1446*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_SUCCESS();
1447*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(EGL_NO_SURFACE, surface[t]);
1448*8975f5c5SAndroid Build Coastguard Worker }
1449*8975f5c5SAndroid Build Coastguard Worker
1450*8975f5c5SAndroid Build Coastguard Worker GLTexture textureFromCtx0;
1451*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kTextureCount = 10;
1452*8975f5c5SAndroid Build Coastguard Worker GLTexture textures[kTextureCount];
1453*8975f5c5SAndroid Build Coastguard Worker
1454*8975f5c5SAndroid Build Coastguard Worker // Synchronization tools to ensure the two threads are interleaved as designed by this test.
1455*8975f5c5SAndroid Build Coastguard Worker std::mutex mutex;
1456*8975f5c5SAndroid Build Coastguard Worker std::condition_variable condVar;
1457*8975f5c5SAndroid Build Coastguard Worker enum class Step
1458*8975f5c5SAndroid Build Coastguard Worker {
1459*8975f5c5SAndroid Build Coastguard Worker Start,
1460*8975f5c5SAndroid Build Coastguard Worker Ctx0Current,
1461*8975f5c5SAndroid Build Coastguard Worker Ctx1Current,
1462*8975f5c5SAndroid Build Coastguard Worker TexturesDone,
1463*8975f5c5SAndroid Build Coastguard Worker Finish,
1464*8975f5c5SAndroid Build Coastguard Worker Abort,
1465*8975f5c5SAndroid Build Coastguard Worker };
1466*8975f5c5SAndroid Build Coastguard Worker Step currentStep = Step::Start;
1467*8975f5c5SAndroid Build Coastguard Worker
1468*8975f5c5SAndroid Build Coastguard Worker std::thread creatingThread = std::thread([&]() {
1469*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1470*8975f5c5SAndroid Build Coastguard Worker
1471*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
1472*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface[0], surface[0], mContexts[0]));
1473*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1474*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Ctx0Current);
1475*8975f5c5SAndroid Build Coastguard Worker
1476*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Ctx1Current));
1477*8975f5c5SAndroid Build Coastguard Worker
1478*8975f5c5SAndroid Build Coastguard Worker // Create the shared textures that will be accessed by the other context
1479*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
1480*8975f5c5SAndroid Build Coastguard Worker glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1481*8975f5c5SAndroid Build Coastguard Worker glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1482*8975f5c5SAndroid Build Coastguard Worker
1483*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
1484*8975f5c5SAndroid Build Coastguard Worker
1485*8975f5c5SAndroid Build Coastguard Worker glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
1486*8975f5c5SAndroid Build Coastguard Worker glFinish();
1487*8975f5c5SAndroid Build Coastguard Worker
1488*8975f5c5SAndroid Build Coastguard Worker glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::blue);
1489*8975f5c5SAndroid Build Coastguard Worker // Do not glFinish
1490*8975f5c5SAndroid Build Coastguard Worker
1491*8975f5c5SAndroid Build Coastguard Worker // We set 6 to be the threshold to flush texture updates.
1492*8975f5c5SAndroid Build Coastguard Worker // We create redundant textures here to ensure that we trigger that threshold.
1493*8975f5c5SAndroid Build Coastguard Worker for (size_t i = 0; i < kTextureCount; i++)
1494*8975f5c5SAndroid Build Coastguard Worker {
1495*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textures[i]);
1496*8975f5c5SAndroid Build Coastguard Worker glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1497*8975f5c5SAndroid Build Coastguard Worker glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1498*8975f5c5SAndroid Build Coastguard Worker
1499*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textures[i]));
1500*8975f5c5SAndroid Build Coastguard Worker
1501*8975f5c5SAndroid Build Coastguard Worker glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
1502*8975f5c5SAndroid Build Coastguard Worker &GLColor::blue);
1503*8975f5c5SAndroid Build Coastguard Worker }
1504*8975f5c5SAndroid Build Coastguard Worker
1505*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1506*8975f5c5SAndroid Build Coastguard Worker
1507*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::TexturesDone);
1508*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Finish));
1509*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1510*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1511*8975f5c5SAndroid Build Coastguard Worker });
1512*8975f5c5SAndroid Build Coastguard Worker
1513*8975f5c5SAndroid Build Coastguard Worker std::thread samplingThread = std::thread([&]() {
1514*8975f5c5SAndroid Build Coastguard Worker ThreadSynchronization<Step> threadSynchronization(¤tStep, &mutex, &condVar);
1515*8975f5c5SAndroid Build Coastguard Worker
1516*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::Ctx0Current));
1517*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, surface[1], surface[1], mContexts[1]));
1518*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1519*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Ctx1Current);
1520*8975f5c5SAndroid Build Coastguard Worker
1521*8975f5c5SAndroid Build Coastguard Worker ASSERT_TRUE(threadSynchronization.waitForStep(Step::TexturesDone));
1522*8975f5c5SAndroid Build Coastguard Worker
1523*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
1524*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1525*8975f5c5SAndroid Build Coastguard Worker
1526*8975f5c5SAndroid Build Coastguard Worker // Draw using ctx0 texture as sampler
1527*8975f5c5SAndroid Build Coastguard Worker GLTexture ctx1tex;
1528*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, ctx1tex);
1529*8975f5c5SAndroid Build Coastguard Worker glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
1530*8975f5c5SAndroid Build Coastguard Worker GLColor::black.data());
1531*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1532*8975f5c5SAndroid Build Coastguard Worker
1533*8975f5c5SAndroid Build Coastguard Worker GLFramebuffer fbo;
1534*8975f5c5SAndroid Build Coastguard Worker glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1535*8975f5c5SAndroid Build Coastguard Worker glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ctx1tex, 0);
1536*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1537*8975f5c5SAndroid Build Coastguard Worker
1538*8975f5c5SAndroid Build Coastguard Worker GLuint sampler;
1539*8975f5c5SAndroid Build Coastguard Worker glGenSamplers(1, &sampler);
1540*8975f5c5SAndroid Build Coastguard Worker
1541*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1542*8975f5c5SAndroid Build Coastguard Worker
1543*8975f5c5SAndroid Build Coastguard Worker ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
1544*8975f5c5SAndroid Build Coastguard Worker glUseProgram(program);
1545*8975f5c5SAndroid Build Coastguard Worker glActiveTexture(GL_TEXTURE0);
1546*8975f5c5SAndroid Build Coastguard Worker glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
1547*8975f5c5SAndroid Build Coastguard Worker glBindSampler(0, sampler);
1548*8975f5c5SAndroid Build Coastguard Worker glUniform1i(glGetUniformLocation(program, essl1_shaders::PositionAttrib()), 0);
1549*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1550*8975f5c5SAndroid Build Coastguard Worker
1551*8975f5c5SAndroid Build Coastguard Worker drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
1552*8975f5c5SAndroid Build Coastguard Worker ASSERT_GL_NO_ERROR();
1553*8975f5c5SAndroid Build Coastguard Worker
1554*8975f5c5SAndroid Build Coastguard Worker EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
1555*8975f5c5SAndroid Build Coastguard Worker
1556*8975f5c5SAndroid Build Coastguard Worker threadSynchronization.nextStep(Step::Finish);
1557*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
1558*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1559*8975f5c5SAndroid Build Coastguard Worker });
1560*8975f5c5SAndroid Build Coastguard Worker
1561*8975f5c5SAndroid Build Coastguard Worker creatingThread.join();
1562*8975f5c5SAndroid Build Coastguard Worker samplingThread.join();
1563*8975f5c5SAndroid Build Coastguard Worker
1564*8975f5c5SAndroid Build Coastguard Worker ASSERT_NE(currentStep, Step::Abort);
1565*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1566*8975f5c5SAndroid Build Coastguard Worker
1567*8975f5c5SAndroid Build Coastguard Worker for (size_t t = 0; t < kThreadCount; ++t)
1568*8975f5c5SAndroid Build Coastguard Worker {
1569*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_TRUE(eglDestroySurface(display, surface[t]));
1570*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1571*8975f5c5SAndroid Build Coastguard Worker }
1572*8975f5c5SAndroid Build Coastguard Worker }
1573*8975f5c5SAndroid Build Coastguard Worker
1574*8975f5c5SAndroid Build Coastguard Worker // Tests that creating a context and immediately destroying it works when no surface has been
1575*8975f5c5SAndroid Build Coastguard Worker // created.
TEST_P(EGLContextSharingTestNoFixture,ImmediateContextDestroyAfterCreation)1576*8975f5c5SAndroid Build Coastguard Worker TEST_P(EGLContextSharingTestNoFixture, ImmediateContextDestroyAfterCreation)
1577*8975f5c5SAndroid Build Coastguard Worker {
1578*8975f5c5SAndroid Build Coastguard Worker EGLAttrib dispattrs[3] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
1579*8975f5c5SAndroid Build Coastguard Worker mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
1580*8975f5c5SAndroid Build Coastguard Worker reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
1581*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
1582*8975f5c5SAndroid Build Coastguard Worker EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
1583*8975f5c5SAndroid Build Coastguard Worker
1584*8975f5c5SAndroid Build Coastguard Worker EGLConfig config = EGL_NO_CONFIG_KHR;
1585*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(chooseConfig(&config));
1586*8975f5c5SAndroid Build Coastguard Worker
1587*8975f5c5SAndroid Build Coastguard Worker // Create a context and immediately destroy it. Note that no window surface should be created
1588*8975f5c5SAndroid Build Coastguard Worker // for this test. Regression test for platforms that expose multiple queue families in Vulkan,
1589*8975f5c5SAndroid Build Coastguard Worker // and ANGLE defers creation of the device until a surface is created. In this case, the
1590*8975f5c5SAndroid Build Coastguard Worker // context is being destroyed before a queue is ever created.
1591*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(createContext(config, &mContexts[0]));
1592*8975f5c5SAndroid Build Coastguard Worker EXPECT_TRUE(SafeDestroyContext(mDisplay, mContexts[0]));
1593*8975f5c5SAndroid Build Coastguard Worker ASSERT_EGL_SUCCESS();
1594*8975f5c5SAndroid Build Coastguard Worker }
1595*8975f5c5SAndroid Build Coastguard Worker } // anonymous namespace
1596*8975f5c5SAndroid Build Coastguard Worker
1597*8975f5c5SAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLContextSharingTest);
1598*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(EGLContextSharingTest,
1599*8975f5c5SAndroid Build Coastguard Worker ES2_D3D9(),
1600*8975f5c5SAndroid Build Coastguard Worker ES2_D3D11(),
1601*8975f5c5SAndroid Build Coastguard Worker ES3_D3D11(),
1602*8975f5c5SAndroid Build Coastguard Worker ES2_METAL(),
1603*8975f5c5SAndroid Build Coastguard Worker ES3_METAL(),
1604*8975f5c5SAndroid Build Coastguard Worker ES2_OPENGL(),
1605*8975f5c5SAndroid Build Coastguard Worker ES3_OPENGL(),
1606*8975f5c5SAndroid Build Coastguard Worker ES2_VULKAN(),
1607*8975f5c5SAndroid Build Coastguard Worker ES3_VULKAN());
1608*8975f5c5SAndroid Build Coastguard Worker
1609*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(EGLContextSharingTestNoFixture,
1610*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES2_METAL()),
1611*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES3_METAL()),
1612*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES2_OPENGLES()),
1613*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES3_OPENGLES()),
1614*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES2_OPENGL()),
1615*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES3_OPENGL()),
1616*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES2_VULKAN()),
1617*8975f5c5SAndroid Build Coastguard Worker WithNoFixture(ES3_VULKAN()));
1618*8975f5c5SAndroid Build Coastguard Worker
1619*8975f5c5SAndroid Build Coastguard Worker GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLContextSharingTestNoSyncTextureUploads);
1620*8975f5c5SAndroid Build Coastguard Worker ANGLE_INSTANTIATE_TEST(EGLContextSharingTestNoSyncTextureUploads,
1621*8975f5c5SAndroid Build Coastguard Worker ES2_VULKAN().enable(Feature::ForceSubmitImmutableTextureUpdates),
1622*8975f5c5SAndroid Build Coastguard Worker ES3_VULKAN().enable(Feature::ForceSubmitImmutableTextureUpdates));
1623