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