From d2c01d2ce5022ac386832929c74d2fcb41fe1669 Mon Sep 17 00:00:00 2001 From: Geoff Lang Date: Fri, 17 Sep 2021 12:57:14 -0400 Subject: [PATCH] GL: Allow selecting virtualization groups at context creation Rewrite EGL_ANGLE_platform_angle_context_virtualization to EGL_ANGLE_context_virtualization, changing the context virtualization parameter to an identifier for what virtualization group the frontend context should be added to. This allows ANGLE's GL backend to be used by multiple threads if the user creates contexts with different virtualization groups. Bug: angleproject:6406 Change-Id: I7414d4705ce10bdf63a9b824043d5dd040dad875 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3169193 Reviewed-by: Jonah Ryan-Davis Reviewed-by: Jamie Madill Commit-Queue: Geoff Lang --- .../EGL_ANGLE_context_virtualization.txt | 79 +++++++++++++++ ..._platform_angle_context_virtualization.txt | 80 ---------------- include/EGL/eglext_angle.h | 8 +- src/libANGLE/Caps.cpp | 2 +- src/libANGLE/Caps.h | 6 +- src/libANGLE/Display.cpp | 3 - src/libANGLE/renderer/gl/egl/DisplayEGL.cpp | 95 ++++++++----------- src/libANGLE/renderer/gl/egl/DisplayEGL.h | 4 +- src/libANGLE/renderer/renderer_utils.cpp | 14 --- src/libANGLE/renderer/renderer_utils.h | 1 - src/libANGLE/validationEGL.cpp | 35 ++----- src/tests/egl_tests/EGLContextSharingTest.cpp | 4 +- src/tests/egl_tests/EGLMultiContextTest.cpp | 6 +- src/tests/egl_tests/EGLSyncTest.cpp | 4 +- src/tests/gl_tests/MultithreadingTest.cpp | 55 +++++++---- src/tests/gl_tests/StateChangeTest.cpp | 2 +- .../gl_tests/VulkanMultithreadingTest.cpp | 2 +- src/tests/test_utils/ANGLETest.cpp | 5 +- src/tests/test_utils/angle_test_configs.cpp | 5 - src/tests/test_utils/angle_test_configs.h | 7 -- util/EGLPlatformParameters.h | 9 +- util/EGLWindow.cpp | 30 ++---- util/EGLWindow.h | 2 +- 23 files changed, 201 insertions(+), 257 deletions(-) create mode 100644 extensions/EGL_ANGLE_context_virtualization.txt delete mode 100644 extensions/EGL_ANGLE_platform_angle_context_virtualization.txt diff --git a/extensions/EGL_ANGLE_context_virtualization.txt b/extensions/EGL_ANGLE_context_virtualization.txt new file mode 100644 index 000000000..6f54e23a5 --- /dev/null +++ b/extensions/EGL_ANGLE_context_virtualization.txt @@ -0,0 +1,79 @@ +Name + + ANGLE_context_virtualization + +Name Strings + + EGL_ANGLE_context_virtualization + +Contributors + + Geoff Lang, Google + +Contacts + + Geoff Lang, Google (geofflang 'at' chromium 'dot' org) + +Status + + Draft + +Version + + Version 2, 2021-09-17 + +Number + + EGL Extension XXX + +Extension Type + + EGL display extension + +Dependencies + + None + +Overview + + This extension allows the client to create contexts that are internally + virtualized on a single native context for performance or stability. + +New Types + + None + +New Procedures and Functions + + None + +New Tokens + + Accepted as an attribute name in the argument of + eglCreateContext: + + EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE 0x3481 + +Additions to the EGL Specification + + None. + +New Behavior + + To request that a context should be part of a virtualization group, + use the attribute EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE. EGL_DONT_CARE + can be used to allow the implementation to decide what virtualization + group is used. The default value of EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE + is EGL_DONT_CARE. It is undefined behaviour to have multiple contexts from + the same virtualization group current different threads simultaneously. + +Issues + + None + +Revision History + + Version 1, 2018-06-11 (Geoff Lang) + - Initial draft + Version 2, 2021-09-17 (Geoff Lang) + - Change to context creation attribute diff --git a/extensions/EGL_ANGLE_platform_angle_context_virtualization.txt b/extensions/EGL_ANGLE_platform_angle_context_virtualization.txt deleted file mode 100644 index 8a714dd92..000000000 --- a/extensions/EGL_ANGLE_platform_angle_context_virtualization.txt +++ /dev/null @@ -1,80 +0,0 @@ -Name - - ANGLE_platform_angle_context_virtualization - -Name Strings - - EGL_ANGLE_platform_angle_context_virtualization - -Contributors - - Geoff Lang, Google - -Contacts - - Geoff Lang, Google (geofflang 'at' chromium 'dot' org) - -Status - - Draft - -Version - - Version 1, 2018-06-11 - -Number - - EGL Extension XXX - -Extension Type - - EGL client extension - -Dependencies - - Requires ANGLE_platform_angle. - -Overview - - This extension allows the client to request a Display that internally - virtualizes contexts. Requesting virtualized contexts may impact - performance or ability to render from multiple threads simultaneously. - -New Types - - None - -New Procedures and Functions - - None - -New Tokens - - Accepted as an attribute name in the argument of - eglGetPlatformDisplayEXT: - - EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE 0x3481 - -Additions to the EGL Specification - - None. - -New Behavior - - To request a display that internally utilizes context virtualization, - use the attribute EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE. - EGL_TRUE enables context virtualization and EGL false disables it. - If it is set to EGL_DONT_CARE, the default setting depends on the - implementation. Any value other than these will result in an error. - The default value for EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE - is EGL_DONT_CARE. Display creation may fail if hardware limitations - prohibit the requested setting. - -Issues - - None - -Revision History - - Version 1, 2018-06-11 (Geoff Lang) - - Initial draft diff --git a/include/EGL/eglext_angle.h b/include/EGL/eglext_angle.h index ef65c2d03..bf4ef4123 100644 --- a/include/EGL/eglext_angle.h +++ b/include/EGL/eglext_angle.h @@ -115,10 +115,10 @@ #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE 0x348E #endif /* EGL_ANGLE_platform_angle_device_type_egl_angle */ -#ifndef EGL_ANGLE_platform_angle_context_virtualization -#define EGL_ANGLE_platform_angle_context_virtualization 1 -#define EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE 0x3481 -#endif /* EGL_ANGLE_platform_angle_context_virtualization */ +#ifndef EGL_ANGLE_context_virtualization +#define EGL_ANGLE_context_virtualization 1 +#define EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE 0x3481 +#endif /* EGL_ANGLE_context_virtualization */ #ifndef EGL_ANGLE_platform_angle_device_context_volatile_eagl #define EGL_ANGLE_platform_angle_device_context_volatile_eagl 1 diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp index 87706c6e0..7bf2ab54f 100644 --- a/src/libANGLE/Caps.cpp +++ b/src/libANGLE/Caps.cpp @@ -1290,6 +1290,7 @@ std::vector DisplayExtensions::getStrings() const InsertExtensionString("EGL_KHR_mutable_render_buffer", mutableRenderBufferKHR, &extensionStrings); InsertExtensionString("EGL_EXT_protected_content", protectedContentEXT, &extensionStrings); InsertExtensionString("EGL_ANGLE_create_surface_swap_interval", createSurfaceSwapIntervalANGLE, &extensionStrings); + InsertExtensionString("EGL_ANGLE_context_virtualization", contextVirtualizationANGLE, &extensionStrings); // clang-format on return extensionStrings; @@ -1335,7 +1336,6 @@ std::vector ClientExtensions::getStrings() const InsertExtensionString("EGL_ANGLE_platform_angle_null", platformANGLENULL, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_angle_vulkan", platformANGLEVulkan, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_angle_metal", platformANGLEMetal, &extensionStrings); - InsertExtensionString("EGL_ANGLE_platform_angle_context_virtualization", platformANGLEContextVirtualization, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_device_context_volatile_eagl", platformANGLEDeviceContextVolatileEagl, &extensionStrings); InsertExtensionString("EGL_ANGLE_platform_device_context_volatile_cgl", platformANGLEDeviceContextVolatileCgl, &extensionStrings); InsertExtensionString("EGL_ANGLE_device_creation", deviceCreation, &extensionStrings); diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h index 51f4eb7ad..8ebad57a1 100644 --- a/src/libANGLE/Caps.h +++ b/src/libANGLE/Caps.h @@ -633,6 +633,9 @@ struct DisplayExtensions // EGL_ANGLE_create_surface_swap_interval bool createSurfaceSwapIntervalANGLE = false; + + // EGL_ANGLE_context_virtualization + bool contextVirtualizationANGLE = false; }; struct DeviceExtensions @@ -693,9 +696,6 @@ struct ClientExtensions // EGL_ANGLE_platform_angle_metal bool platformANGLEMetal = false; - // EGL_ANGLE_platform_angle_context_virtualization - bool platformANGLEContextVirtualization = false; - // EGL_ANGLE_platform_angle_device_context_volatile_eagl bool platformANGLEDeviceContextVolatileEagl = false; diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp index 85e84cade..99a28355a 100644 --- a/src/libANGLE/Display.cpp +++ b/src/libANGLE/Display.cpp @@ -1733,9 +1733,6 @@ static ClientExtensions GenerateClientExtensions() #if defined(ANGLE_ENABLE_OPENGL) extensions.platformANGLEOpenGL = true; - - // Selecting context virtualization is currently only supported in the OpenGL backend. - extensions.platformANGLEContextVirtualization = true; #endif #if defined(ANGLE_ENABLE_NULL) diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp index 6627406d2..fdcf9f372 100644 --- a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp +++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp @@ -109,11 +109,7 @@ void WorkerContextEGL::unmakeCurrent() namespace rx { -static constexpr bool kDefaultEGLVirtualizedContexts = true; - -DisplayEGL::DisplayEGL(const egl::DisplayState &state) - : DisplayGL(state), mVirtualizedContexts(kDefaultEGLVirtualizedContexts) -{} +DisplayEGL::DisplayEGL(const egl::DisplayState &state) : DisplayGL(state) {} DisplayEGL::~DisplayEGL() {} @@ -253,9 +249,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, egl::Error DisplayEGL::initialize(egl::Display *display) { mDisplayAttributes = display->getAttributeMap(); - mVirtualizedContexts = - ShouldUseVirtualizedContexts(mDisplayAttributes, kDefaultEGLVirtualizedContexts); - mEGL = new FunctionsEGLDL(); + mEGL = new FunctionsEGLDL(); void *eglHandle = reinterpret_cast(mDisplayAttributes.get(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE, 0)); @@ -402,6 +396,7 @@ void DisplayEGL::terminate() } mRenderer.reset(); + mVirtualizationGroups.clear(); mCurrentNativeContexts.clear(); @@ -497,36 +492,47 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state, const gl::Context *shareContext, const egl::AttributeMap &attribs) { - std::shared_ptr renderer; bool usingExternalContext = attribs.get(EGL_EXTERNAL_CONTEXT_ANGLE, EGL_FALSE) == EGL_TRUE; - if (mVirtualizedContexts && !usingExternalContext) - { - renderer = mRenderer; - } - else - { - EGLContext nativeShareContext = EGL_NO_CONTEXT; - if (usingExternalContext) - { - ASSERT(!shareContext); - } - else if (shareContext) - { - ContextEGL *shareContextEGL = GetImplAs(shareContext); - nativeShareContext = shareContextEGL->getContext(); - } + EGLAttrib virtualizationGroup = + attribs.get(EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, EGL_DONT_CARE); - // Create a new renderer for this context. It only needs to share with the user's requested - // share context because there are no internal resources in DisplayEGL that are shared - // at the GL level. - egl::Error error = - createRenderer(nativeShareContext, false, usingExternalContext, &renderer); + std::shared_ptr renderer = mRenderer; + if (usingExternalContext) + { + ASSERT(!shareContext); + egl::Error error = createRenderer(EGL_NO_CONTEXT, false, true, &renderer); if (error.isError()) { ERR() << "Failed to create a shared renderer: " << error.getMessage(); return nullptr; } } + else if (virtualizationGroup != EGL_DONT_CARE) + { + renderer = mVirtualizationGroups[virtualizationGroup].lock(); + if (!renderer) + { + EGLContext nativeShareContext = EGL_NO_CONTEXT; + if (shareContext) + { + ContextEGL *shareContextEGL = GetImplAs(shareContext); + nativeShareContext = shareContextEGL->getContext(); + } + + // Create a new renderer for this context. It only needs to share with the user's + // requested share context because there are no internal resources in DisplayEGL that + // are shared at the GL level. + egl::Error error = createRenderer(nativeShareContext, false, false, &renderer); + if (error.isError()) + { + ERR() << "Failed to create a shared renderer: " << error.getMessage(); + return nullptr; + } + + mVirtualizationGroups[virtualizationGroup] = renderer; + } + } + ASSERT(renderer); RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus = GetRobustnessVideoMemoryPurge(attribs); @@ -764,31 +770,6 @@ egl::Error DisplayEGL::makeCurrent(egl::Display *display, return DisplayGL::makeCurrent(display, drawSurface, readSurface, context); } - // The context should never change when context virtualization is being used unless binding a - // null context. - if (mVirtualizedContexts && newContext != EGL_NO_CONTEXT) - { - ASSERT(currentContext.context == EGL_NO_CONTEXT || newContext == currentContext.context); - - newContext = mRenderer->getContext(); - - // If we know that we're only running on one thread (mVirtualizedContexts == true) and - // EGL_NO_SURFACE is going to be bound, we can optimize this case by not changing the - // surface binding and emulate the surfaceless extension in the frontend. - if (newSurface == EGL_NO_SURFACE) - { - newSurface = currentContext.surface; - } - - // It's possible that no surface has been created yet and the driver doesn't support - // surfaceless, bind the mock pbuffer. - if (newSurface == EGL_NO_SURFACE && !mSupportsSurfaceless) - { - newSurface = mMockPbuffer; - ASSERT(newSurface != EGL_NO_SURFACE); - } - } - if (newSurface != currentContext.surface || newContext != currentContext.context) { if (mEGL->makeCurrent(newSurface, newContext) == EGL_FALSE) @@ -900,10 +881,12 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const // Surfaceless can be support if the native driver supports it or we know that we are running on // a single thread (mVirtualizedContexts == true) - outExtensions->surfacelessContext = mSupportsSurfaceless || mVirtualizedContexts; + outExtensions->surfacelessContext = mSupportsSurfaceless; outExtensions->externalContextAndSurface = true; + outExtensions->contextVirtualizationANGLE = true; + DisplayGL::generateExtensions(outExtensions); } diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.h b/src/libANGLE/renderer/gl/egl/DisplayEGL.h index f0adac858..f771d0cd4 100644 --- a/src/libANGLE/renderer/gl/egl/DisplayEGL.h +++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.h @@ -138,6 +138,8 @@ class DisplayEGL : public DisplayGL const U &defaultValue) const; std::shared_ptr mRenderer; + std::map> mVirtualizationGroups; + FunctionsEGLDL *mEGL = nullptr; EGLConfig mConfig = EGL_NO_CONFIG_KHR; egl::AttributeMap mDisplayAttributes; @@ -160,8 +162,6 @@ class DisplayEGL : public DisplayGL bool mHasEXTCreateContextRobustness = false; bool mHasNVRobustnessVideoMemoryPurge = false; - bool mVirtualizedContexts = false; - bool mSupportsSurfaceless = false; bool mSupportsNoConfigContexts = false; diff --git a/src/libANGLE/renderer/renderer_utils.cpp b/src/libANGLE/renderer/renderer_utils.cpp index c93f8a68a..423e3f014 100644 --- a/src/libANGLE/renderer/renderer_utils.cpp +++ b/src/libANGLE/renderer/renderer_utils.cpp @@ -461,20 +461,6 @@ bool ShouldUseDebugLayers(const egl::AttributeMap &attribs) #endif // defined(ANGLE_ENABLE_ASSERTS) } -bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue) -{ - EGLAttrib virtualizedContextRequest = - attribs.get(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE, EGL_DONT_CARE); - if (defaultValue) - { - return (virtualizedContextRequest != EGL_FALSE); - } - else - { - return (virtualizedContextRequest == EGL_TRUE); - } -} - void CopyImageCHROMIUM(const uint8_t *sourceData, size_t sourceRowPitch, size_t sourcePixelBytes, diff --git a/src/libANGLE/renderer/renderer_utils.h b/src/libANGLE/renderer/renderer_utils.h index f31d66901..cf4116a09 100644 --- a/src/libANGLE/renderer/renderer_utils.h +++ b/src/libANGLE/renderer/renderer_utils.h @@ -174,7 +174,6 @@ struct LoadTextureBorderFunctionInfo using LoadTextureBorderFunctionMap = LoadTextureBorderFunctionInfo (*)(); bool ShouldUseDebugLayers(const egl::AttributeMap &attribs); -bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue); void CopyImageCHROMIUM(const uint8_t *sourceData, size_t sourceRowPitch, diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp index 8ab0879e5..b2ab42204 100644 --- a/src/libANGLE/validationEGL.cpp +++ b/src/libANGLE/validationEGL.cpp @@ -695,31 +695,6 @@ bool ValidateGetPlatformDisplayCommon(const ValidationContext *val, } break; - case EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE: - if (!clientExtensions.platformANGLEContextVirtualization) - { - val->setError(EGL_BAD_ATTRIBUTE, - "EGL_ANGLE_platform_angle_context_" - "virtualization extension not active"); - return false; - } - - switch (value) - { - case EGL_DONT_CARE: - case EGL_FALSE: - case EGL_TRUE: - break; - - default: - val->setError(EGL_BAD_ATTRIBUTE, - "Invalid value for " - "EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_" - "ANGLE attrib"); - return false; - } - break; - case EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE: case EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE: luidSpecified = true; @@ -2004,6 +1979,16 @@ bool ValidateCreateContext(const ValidationContext *val, } break; + case EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE: + if (!display->getExtensions().contextVirtualizationANGLE) + { + val->setError(EGL_BAD_ATTRIBUTE, + "Attribute EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE requires " + "extension EGL_ANGLE_context_virtualization."); + return false; + } + break; + default: val->setError(EGL_BAD_ATTRIBUTE, "Unknown attribute: 0x%04" PRIxPTR "X", attribute); return false; diff --git a/src/tests/egl_tests/EGLContextSharingTest.cpp b/src/tests/egl_tests/EGLContextSharingTest.cpp index bf9710601..b119282f9 100644 --- a/src/tests/egl_tests/EGLContextSharingTest.cpp +++ b/src/tests/egl_tests/EGLContextSharingTest.cpp @@ -484,7 +484,7 @@ TEST_P(EGLContextSharingTest, DeleteReaderOfSharedTexture) surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); - ctx[t] = window->createContext(t == 0 ? EGL_NO_CONTEXT : ctx[0]); + ctx[t] = window->createContext(t == 0 ? EGL_NO_CONTEXT : ctx[0], nullptr); EXPECT_NE(EGL_NO_CONTEXT, ctx[t]); } @@ -949,4 +949,4 @@ ANGLE_INSTANTIATE_TEST(EGLContextSharingTestNoFixture, WithNoFixture(ES2_OPENGL()), WithNoFixture(ES3_OPENGL()), WithNoFixture(ES2_VULKAN()), - WithNoFixture(ES3_VULKAN())); \ No newline at end of file + WithNoFixture(ES3_VULKAN())); diff --git a/src/tests/egl_tests/EGLMultiContextTest.cpp b/src/tests/egl_tests/EGLMultiContextTest.cpp index a8acd74fe..0685563a9 100644 --- a/src/tests/egl_tests/EGLMultiContextTest.cpp +++ b/src/tests/egl_tests/EGLMultiContextTest.cpp @@ -63,8 +63,8 @@ TEST_P(EGLMultiContextTest, TestContextDestroySimple) EGLWindow *window = getEGLWindow(); EGLDisplay dpy = window->getDisplay(); - EGLContext context1 = window->createContext(EGL_NO_CONTEXT); - EGLContext context2 = window->createContext(EGL_NO_CONTEXT); + EGLContext context1 = window->createContext(EGL_NO_CONTEXT, nullptr); + EGLContext context2 = window->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context1)); EXPECT_EGL_TRUE(eglDestroyContext(dpy, context2)); @@ -101,7 +101,7 @@ TEST_P(EGLMultiContextTest, ComputeShaderOkayWithRendering) surface[t] = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); - ctx[t] = window->createContext(EGL_NO_CONTEXT); + ctx[t] = window->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_NE(EGL_NO_CONTEXT, ctx[t]); } diff --git a/src/tests/egl_tests/EGLSyncTest.cpp b/src/tests/egl_tests/EGLSyncTest.cpp index aefa1da7c..2c570c4d0 100644 --- a/src/tests/egl_tests/EGLSyncTest.cpp +++ b/src/tests/egl_tests/EGLSyncTest.cpp @@ -378,7 +378,7 @@ TEST_P(EGLSyncTest, AndroidNativeFence_WaitSync) { EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); - EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT); + EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2)); // We can eglWaitSync on this - import FD from first sync. @@ -462,7 +462,7 @@ TEST_P(EGLSyncTest, AndroidNativeFence_withFences) { EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); - EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT); + EGLContext context2 = getEGLWindow()->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context2)); // check that Fence and Android fences work together diff --git a/src/tests/gl_tests/MultithreadingTest.cpp b/src/tests/gl_tests/MultithreadingTest.cpp index b69fda7c6..d4326703f 100644 --- a/src/tests/gl_tests/MultithreadingTest.cpp +++ b/src/tests/gl_tests/MultithreadingTest.cpp @@ -41,6 +41,19 @@ class MultithreadingTest : public ANGLETest } bool hasGLSyncExtension() const { return IsGLExtensionEnabled("GL_OES_EGL_sync"); } + EGLContext createMultithreadedContext(EGLWindow *window, EGLContext shareCtx) + { + EGLint attribs[] = {EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, mVirtualizationGroup++, + EGL_NONE}; + if (!IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), + "EGL_ANGLE_context_virtualization")) + { + attribs[0] = EGL_NONE; + } + + return window->createContext(shareCtx, attribs); + } + void runMultithreadedGLTest( std::function testBody, size_t threadCount) @@ -70,7 +83,7 @@ class MultithreadingTest : public ANGLETest surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); - ctx = window->createContext(EGL_NO_CONTEXT); + ctx = createMultithreadedContext(window, EGL_NO_CONTEXT); EXPECT_NE(EGL_NO_CONTEXT, ctx); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx)); @@ -98,6 +111,8 @@ class MultithreadingTest : public ANGLETest thread.join(); } } + + std::atomic mVirtualizationGroup; }; class MultithreadingTestES3 : public MultithreadingTest @@ -234,8 +249,8 @@ TEST_P(MultithreadingTest, MultiContextDeleteDraw) // 5000 is chosen here as it reliably reproduces the former crash. for (int i = 0; i < 5000; i++) { - EGLContext ctx1 = window->createContext(EGL_NO_CONTEXT); - EGLContext ctx2 = window->createContext(EGL_NO_CONTEXT); + EGLContext ctx1 = createMultithreadedContext(window, EGL_NO_CONTEXT); + EGLContext ctx2 = createMultithreadedContext(window, EGL_NO_CONTEXT); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx2)); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx1)); @@ -253,7 +268,7 @@ TEST_P(MultithreadingTest, MultiContextDeleteDraw) EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); - auto ctx = window->createContext(EGL_NO_CONTEXT); + auto ctx = createMultithreadedContext(window, EGL_NO_CONTEXT); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx)); constexpr size_t kIterationsPerThread = 512; @@ -469,7 +484,7 @@ TEST_P(MultithreadingTest, MultiCreateContext) threads[threadIdx] = std::thread([&, threadIdx]() { contexts[threadIdx] = EGL_NO_CONTEXT; { - contexts[threadIdx] = window->createContext(EGL_NO_CONTEXT); + contexts[threadIdx] = createMultithreadedContext(window, EGL_NO_CONTEXT); EXPECT_NE(EGL_NO_CONTEXT, contexts[threadIdx]); barrier++; @@ -511,7 +526,7 @@ void MultithreadingTestES3::textureThreadFunction(bool useDraw) EXPECT_EGL_SUCCESS(); EXPECT_NE(EGL_NO_SURFACE, surface); - ctx = window->createContext(window->getContext()); + ctx = createMultithreadedContext(window, window->getContext()); EXPECT_NE(EGL_NO_CONTEXT, ctx); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx)); @@ -791,7 +806,7 @@ TEST_P(MultithreadingTest, CreateFenceThreadAClientWaitSyncThreadBDelayedFlush) surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); // Create 2 shared contexts, one for each thread - context = window->createContext(EGL_NO_CONTEXT); + context = window->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_NE(EGL_NO_CONTEXT, context); // Sync object EGLSyncKHR sync = EGL_NO_SYNC_KHR; @@ -883,21 +898,21 @@ TEST_P(MultithreadingTest, CreateFenceThreadAClientWaitSyncThreadBDelayedFlush) // TODO(geofflang): Test sharing a program between multiple shared contexts on multiple threads ANGLE_INSTANTIATE_TEST(MultithreadingTest, - WithNoVirtualContexts(ES2_OPENGL()), - WithNoVirtualContexts(ES3_OPENGL()), - WithNoVirtualContexts(ES2_OPENGLES()), - WithNoVirtualContexts(ES3_OPENGLES()), - WithNoVirtualContexts(ES3_VULKAN()), - WithNoVirtualContexts(ES3_VULKAN_SWIFTSHADER()), - WithNoVirtualContexts(ES2_D3D11()), - WithNoVirtualContexts(ES3_D3D11())); + ES2_OPENGL(), + ES3_OPENGL(), + ES2_OPENGLES(), + ES3_OPENGLES(), + ES3_VULKAN(), + ES3_VULKAN_SWIFTSHADER(), + ES2_D3D11(), + ES3_D3D11()); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultithreadingTestES3); ANGLE_INSTANTIATE_TEST(MultithreadingTestES3, - WithNoVirtualContexts(ES3_OPENGL()), - WithNoVirtualContexts(ES3_OPENGLES()), - WithNoVirtualContexts(ES3_VULKAN()), - WithNoVirtualContexts(ES3_VULKAN_SWIFTSHADER()), - WithNoVirtualContexts(ES3_D3D11())); + ES3_OPENGL(), + ES3_OPENGLES(), + ES3_VULKAN(), + ES3_VULKAN_SWIFTSHADER(), + ES3_D3D11()); } // namespace angle diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp index d8e93bbc1..caa603711 100644 --- a/src/tests/gl_tests/StateChangeTest.cpp +++ b/src/tests/gl_tests/StateChangeTest.cpp @@ -6905,7 +6905,7 @@ void main() EGLConfig config = window->getConfig(); EGLint pbufferAttributes[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE}; EGLSurface surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes); - EGLContext ctx = window->createContext(EGL_NO_CONTEXT); + EGLContext ctx = window->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_EGL_SUCCESS(); std::thread flushThread = std::thread([&]() { EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx)); diff --git a/src/tests/gl_tests/VulkanMultithreadingTest.cpp b/src/tests/gl_tests/VulkanMultithreadingTest.cpp index 196e15dac..812778a88 100644 --- a/src/tests/gl_tests/VulkanMultithreadingTest.cpp +++ b/src/tests/gl_tests/VulkanMultithreadingTest.cpp @@ -88,7 +88,7 @@ class VulkanMultithreadingTest : public ANGLETest surface = eglCreatePbufferSurface(dpy, config, pbufferAttributes); EXPECT_EGL_SUCCESS(); - ctx = window->createContext(EGL_NO_CONTEXT); + ctx = window->createContext(EGL_NO_CONTEXT, nullptr); EXPECT_NE(EGL_NO_CONTEXT, ctx); EXPECT_EGL_TRUE(eglMakeCurrent(dpy, surface, surface, ctx)); diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp index 81b18b5c1..e6d8e519e 100644 --- a/src/tests/test_utils/ANGLETest.cpp +++ b/src/tests/test_utils/ANGLETest.cpp @@ -1222,7 +1222,10 @@ void ANGLETestBase::draw3DTexturedQuad(GLfloat positionAttribZ, bool ANGLETestBase::platformSupportsMultithreading() const { - return (IsOpenGLES() && IsAndroid()) || IsVulkan(); + return (mFixture && mFixture->eglWindow && + IsEGLDisplayExtensionEnabled(mFixture->eglWindow->getDisplay(), + "EGL_ANGLE_context_virtualization")) || + IsVulkan(); } void ANGLETestBase::checkD3D11SDKLayersMessages() diff --git a/src/tests/test_utils/angle_test_configs.cpp b/src/tests/test_utils/angle_test_configs.cpp index fa0964148..52637ccb8 100644 --- a/src/tests/test_utils/angle_test_configs.cpp +++ b/src/tests/test_utils/angle_test_configs.cpp @@ -196,11 +196,6 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) stream << "_NoFixture"; } - if (pp.eglParameters.contextVirtualization == EGL_FALSE) - { - stream << "_NoVirtual"; - } - if (pp.eglParameters.transformFeedbackFeature == EGL_FALSE) { stream << "_NoTransformFeedback"; diff --git a/src/tests/test_utils/angle_test_configs.h b/src/tests/test_utils/angle_test_configs.h index 232871990..a6ed8f312 100644 --- a/src/tests/test_utils/angle_test_configs.h +++ b/src/tests/test_utils/angle_test_configs.h @@ -191,13 +191,6 @@ PlatformParameters ES3_EGL(); const char *GetNativeEGLLibraryNameWithExtension(); -inline PlatformParameters WithNoVirtualContexts(const PlatformParameters ¶ms) -{ - PlatformParameters withNoVirtualContexts = params; - withNoVirtualContexts.eglParameters.contextVirtualization = EGL_FALSE; - return withNoVirtualContexts; -} - inline PlatformParameters WithNoFixture(const PlatformParameters ¶ms) { PlatformParameters withNoFixture = params; diff --git a/util/EGLPlatformParameters.h b/util/EGLPlatformParameters.h index e1fc10c75..9e405c48e 100644 --- a/util/EGLPlatformParameters.h +++ b/util/EGLPlatformParameters.h @@ -59,10 +59,10 @@ struct EGLPlatformParameters auto tie() const { return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath, - debugLayersEnabled, contextVirtualization, transformFeedbackFeature, - allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers, - shaderStencilOutputFeature, genMultipleMipsPerPassFeature, platformMethods, - robustness, emulatedPrerotation, asyncCommandQueueFeatureVulkan, + debugLayersEnabled, transformFeedbackFeature, allocateNonZeroMemoryFeature, + emulateCopyTexImage2DFromRenderbuffers, shaderStencilOutputFeature, + genMultipleMipsPerPassFeature, platformMethods, robustness, + emulatedPrerotation, asyncCommandQueueFeatureVulkan, hasExplicitMemBarrierFeatureMtl, hasCheapRenderPassFeatureMtl, forceBufferGPUStorageFeatureMtl, supportsVulkanViewportFlip, emulatedVAOs, generateSPIRVThroughGlslang, captureLimits, forceRobustResourceInit, @@ -75,7 +75,6 @@ struct EGLPlatformParameters EGLint deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; EGLint presentPath = EGL_DONT_CARE; EGLint debugLayersEnabled = EGL_DONT_CARE; - EGLint contextVirtualization = EGL_DONT_CARE; EGLint robustness = EGL_DONT_CARE; EGLint transformFeedbackFeature = EGL_DONT_CARE; EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE; diff --git a/util/EGLWindow.cpp b/util/EGLWindow.cpp index d61e3753e..a390b3e4c 100644 --- a/util/EGLWindow.cpp +++ b/util/EGLWindow.cpp @@ -188,23 +188,6 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, displayAttributes.push_back(params.debugLayersEnabled); } - const bool hasFeatureVirtualizationANGLE = - strstr(extensionString, "EGL_ANGLE_platform_angle_context_virtualization") != nullptr; - - if (params.contextVirtualization != EGL_DONT_CARE) - { - if (hasFeatureVirtualizationANGLE) - { - displayAttributes.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE); - displayAttributes.push_back(params.contextVirtualization); - } - else - { - fprintf(stderr, - "EGL_ANGLE_platform_angle_context_virtualization extension not active\n"); - } - } - if (params.platformMethods) { static_assert(sizeof(EGLAttrib) == sizeof(params.platformMethods), @@ -515,10 +498,10 @@ GLWindowContext EGLWindow::getCurrentContextGeneric() GLWindowContext EGLWindow::createContextGeneric(GLWindowContext share) { EGLContext shareContext = reinterpret_cast(share); - return reinterpret_cast(createContext(shareContext)); + return reinterpret_cast(createContext(shareContext, nullptr)); } -EGLContext EGLWindow::createContext(EGLContext share) +EGLContext EGLWindow::createContext(EGLContext share, EGLint *extraAttributes) { const char *displayExtensions = eglQueryString(mDisplay, EGL_EXTENSIONS); @@ -605,6 +588,13 @@ EGLContext EGLWindow::createContext(EGLContext share) } std::vector contextAttributes; + for (EGLint *extraAttrib = extraAttributes; + extraAttrib != nullptr && extraAttrib[0] != EGL_NONE; extraAttrib += 2) + { + contextAttributes.push_back(extraAttrib[0]); + contextAttributes.push_back(extraAttrib[1]); + } + if (hasKHRCreateContext) { contextAttributes.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); @@ -703,7 +693,7 @@ EGLContext EGLWindow::createContext(EGLContext share) bool EGLWindow::initializeContext() { - mContext = createContext(EGL_NO_CONTEXT); + mContext = createContext(EGL_NO_CONTEXT, nullptr); if (mContext == EGL_NO_CONTEXT) { destroyGL(); diff --git a/util/EGLWindow.h b/util/EGLWindow.h index 44a65fadf..e95137d04 100644 --- a/util/EGLWindow.h +++ b/util/EGLWindow.h @@ -174,7 +174,7 @@ class ANGLE_UTIL_EXPORT EGLWindow : public GLWindowBase const ConfigParameters ¶ms); // Create an EGL context with this window's configuration - EGLContext createContext(EGLContext share); + EGLContext createContext(EGLContext share, EGLint *extraAttributes); // Make the EGL context current bool makeCurrent(EGLContext context);