Frontend: separate lock in swap prep

Swapchain-based backends like Vulkan might block a lot in
vkAcquireNextImageKHR, which is bad for overall fast progress if we also
hold the global EGL lock there.

This CL starts to split the global EGL lock. We release the EGL lock
when performing vkAcquireNextImageKHR, and only maintain a lock for
surfaces.

Bug: angleproject:6851
Change-Id: I329d5c4c579718a4980c4261590f77099ce1400e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3361249
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Lingfeng Yang <lfy@google.com>
This commit is contained in:
Lingfeng Yang 2022-01-06 13:31:54 -08:00 коммит произвёл Angle LUCI CQ
Родитель c2a2961493
Коммит 40c5cb255c
15 изменённых файлов: 287 добавлений и 28 удалений

Просмотреть файл

@ -10,7 +10,7 @@
"scripts/entry_point_packed_gl_enums.json":
"a1cdd1545d3095f977b9869df5513071",
"scripts/generate_entry_points.py":
"36e40f66e33d0a04355b732862b548eb",
"f673e3996c04eff652aa99d8b5e03818",
"scripts/gl.xml":
"467556b6f73fd024b08b703d0be83999",
"scripts/gl_angle_ext.xml":
@ -134,11 +134,11 @@
"src/libGLESv2/entry_points_cl_autogen.h":
"dde2f94c3004874a7da995dae69da811",
"src/libGLESv2/entry_points_egl_autogen.cpp":
"e7b708af1c8de435532058eb165d421e",
"e0656139c9611777a67c85a36e522c48",
"src/libGLESv2/entry_points_egl_autogen.h":
"3bc7a8df9deadd7cfd615d0cfad0c6a8",
"src/libGLESv2/entry_points_egl_ext_autogen.cpp":
"2bebd91dd2b256a9ddfd79b2b388453c",
"78094ed35a8a48b602d95eb45ccacf7a",
"src/libGLESv2/entry_points_egl_ext_autogen.h":
"3e1c2214810cb6b3f4820dc1d0563492",
"src/libGLESv2/entry_points_gles_1_0_autogen.cpp":

Просмотреть файл

@ -224,7 +224,7 @@ TEMPLATE_GLES_ENTRY_POINT_WITH_RETURN = """\
TEMPLATE_EGL_ENTRY_POINT_NO_RETURN = """\
void EGLAPIENTRY EGL_{name}({params})
{{
ANGLE_SCOPED_GLOBAL_LOCK();
{lock_domain}
EGL_EVENT({name}, "{format_params}"{comma_if_needed}{pass_params});
Thread *thread = egl::GetCurrentThread();
@ -240,7 +240,7 @@ void EGLAPIENTRY EGL_{name}({params})
TEMPLATE_EGL_ENTRY_POINT_WITH_RETURN = """\
{return_type} EGLAPIENTRY EGL_{name}({params})
{{
ANGLE_SCOPED_GLOBAL_LOCK();
{lock_domain}
EGL_EVENT({name}, "{format_params}"{comma_if_needed}{pass_params});
Thread *thread = egl::GetCurrentThread();
@ -1516,8 +1516,10 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
else:
has_errcode_ret = False
packed_gl_enum_conversions = []
for param in params:
name = just_the_name(param)
if name in packed_enums:
internal_name = name + "Packed"
internal_type = packed_enums[name]
@ -1568,7 +1570,9 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
"event_comment":
event_comment,
"labeled_object":
get_egl_entry_point_labeled_object(ep_to_object, cmd_name, params, packed_enums)
get_egl_entry_point_labeled_object(ep_to_object, cmd_name, params, packed_enums),
"lock_domain":
get_lock_domain(api, cmd_name, params),
}
template = get_def_template(api, return_type, has_errcode_ret)
@ -2489,6 +2493,32 @@ def get_egl_entry_point_labeled_object(ep_to_object, cmd_stripped, params, packe
return "Get%sIfValid(%s, %s)" % (category, display_param, found_param)
def get_lock_domain(api, cmd_name, params):
if api != apis.EGL:
return "ANGLE_SCOPED_GLOBAL_LOCK();"
lock_domain_global = "ANGLE_SCOPED_GLOBAL_LOCK();"
lock_domain_surface = "ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();"
custom_locking = ["eglSwapBuffers", "eglSwapBuffersWithDamageKHR"]
if cmd_name in custom_locking:
return ""
has_surface = False
for param in params:
param_type = just_the_type(param)
if param_type == "EGLSurface":
has_surface = True
if has_surface:
return lock_domain_global + lock_domain_surface
return lock_domain_global
def write_stubs_header(api, annotation, title, data_source, out_file, all_commands, commands,
cmd_packed_egl_enums, packed_param_types):

Просмотреть файл

@ -302,6 +302,12 @@ EGLint Surface::getType() const
return mType;
}
Error Surface::prepareSwap(const gl::Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::prepareSwap");
return mImplementation->prepareSwap(context);
}
Error Surface::swap(const gl::Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swap");

Просмотреть файл

@ -76,6 +76,7 @@ class Surface : public LabeledObject, public gl::FramebufferAttachmentObject
Error initialize(const Display *display);
Error makeCurrent(const gl::Context *context);
Error unMakeCurrent(const gl::Context *context);
Error prepareSwap(const gl::Context *context);
Error swap(const gl::Context *context);
Error swapWithDamage(const gl::Context *context, const EGLint *rects, EGLint n_rects);
Error swapWithFrameToken(const gl::Context *context, EGLFrameTokenANGLE frameToken);

Просмотреть файл

@ -25,6 +25,11 @@ egl::Error SurfaceImpl::unMakeCurrent(const gl::Context *context)
return egl::NoError();
}
egl::Error SurfaceImpl::prepareSwap(const gl::Context *)
{
return angle::ResultToEGL(angle::Result::Continue);
}
egl::Error SurfaceImpl::swapWithDamage(const gl::Context *context,
const EGLint *rects,
EGLint n_rects)

Просмотреть файл

@ -55,6 +55,7 @@ class SurfaceImpl : public FramebufferAttachmentObjectImpl
const gl::FramebufferState &state) = 0;
virtual egl::Error makeCurrent(const gl::Context *context);
virtual egl::Error unMakeCurrent(const gl::Context *context);
virtual egl::Error prepareSwap(const gl::Context *);
virtual egl::Error swap(const gl::Context *context) = 0;
virtual egl::Error swapWithDamage(const gl::Context *context,
const EGLint *rects,

Просмотреть файл

@ -1391,6 +1391,28 @@ FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::Context *co
return FramebufferVk::CreateDefaultFBO(renderer, state, this);
}
egl::Error WindowSurfaceVk::prepareSwap(const gl::Context *context)
{
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
angle::Result result = prepareSwapImpl(context);
return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
}
angle::Result WindowSurfaceVk::prepareSwapImpl(const gl::Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::prepareSwap");
ContextVk *contextVk = vk::GetImpl(context);
if (mNeedToAcquireNextSwapchainImage)
{
// Acquire the next image (previously deferred). The image may not have been already
// acquired if there was no rendering done at all to the default framebuffer in this frame,
// for example if all rendering was done to FBOs.
ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Acquire Swap Image Before Swap");
ANGLE_TRY(doDeferredAcquireNextImage(context, false));
}
return angle::Result::Continue;
}
egl::Error WindowSurfaceVk::swapWithDamage(const gl::Context *context,
const EGLint *rects,
EGLint n_rects)
@ -1601,15 +1623,6 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
ContextVk *contextVk = vk::GetImpl(context);
if (mNeedToAcquireNextSwapchainImage)
{
// Acquire the next image (previously deferred). The image may not have been already
// acquired if there was no rendering done at all to the default framebuffer in this frame,
// for example if all rendering was done to FBOs.
ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Acquire Swap Image Before Swap");
ANGLE_TRY(doDeferredAcquireNextImage(context, false));
}
bool presentOutOfDate = false;
ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
@ -1626,6 +1639,10 @@ angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
ANGLE_TRY(doDeferredAcquireNextImage(context, presentOutOfDate));
}
RendererVk *renderer = contextVk->getRenderer();
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk, context));
return angle::Result::Continue;
}
@ -1647,7 +1664,6 @@ angle::Result WindowSurfaceVk::doDeferredAcquireNextImage(const gl::Context *con
bool presentOutOfDate)
{
ContextVk *contextVk = vk::GetImpl(context);
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
// TODO(jmadill): Expose in CommandQueueInterface, or manage in CommandQueue. b/172704839
if (contextVk->getRenderer()->isAsyncCommandQueueEnabled())
@ -1691,9 +1707,6 @@ angle::Result WindowSurfaceVk::doDeferredAcquireNextImage(const gl::Context *con
}
mColorImageMS.invalidateSubresourceContent(contextVk, gl::LevelIndex(0), 0, 1);
RendererVk *renderer = contextVk->getRenderer();
ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk, context));
return angle::Result::Continue;
}

Просмотреть файл

@ -182,6 +182,7 @@ class WindowSurfaceVk : public SurfaceVk
FramebufferAttachmentRenderTarget **rtOut) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
egl::Error prepareSwap(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
egl::Error swapWithDamage(const gl::Context *context,
const EGLint *rects,
@ -248,6 +249,7 @@ class WindowSurfaceVk : public SurfaceVk
}
protected:
angle::Result prepareSwapImpl(const gl::Context *context);
angle::Result swapImpl(const gl::Context *context,
const EGLint *rects,
EGLint n_rects,

Просмотреть файл

@ -577,8 +577,19 @@ EGLBoolean SwapBuffersWithDamageKHR(Thread *thread,
const EGLint *rects,
EGLint n_rects)
{
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffersWithDamageEXT",
GetDisplayIfValid(display), EGL_FALSE);
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffersWithDamageEXT",
GetDisplayIfValid(display), EGL_FALSE);
}
{
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
ANGLE_EGL_TRY_RETURN(thread, eglSurface->prepareSwap(thread->getContext()), "prepareSwap",
GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
}
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_EGL_TRY_RETURN(thread, eglSurface->swapWithDamage(thread->getContext(), rects, n_rects),
"eglSwapBuffersWithDamageEXT", GetSurfaceIfValid(display, eglSurface),
EGL_FALSE);

Просмотреть файл

@ -630,9 +630,19 @@ EGLBoolean SurfaceAttrib(Thread *thread,
EGLBoolean SwapBuffers(Thread *thread, Display *display, Surface *eglSurface)
{
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffers",
GetDisplayIfValid(display), EGL_FALSE);
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglSwapBuffers",
GetDisplayIfValid(display), EGL_FALSE);
}
{
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
ANGLE_EGL_TRY_RETURN(thread, eglSurface->prepareSwap(thread->getContext()), "prepareSwap",
GetSurfaceIfValid(display, eglSurface), EGL_FALSE);
}
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_EGL_TRY_RETURN(thread, eglSurface->swap(thread->getContext()), "eglSwapBuffers",
GetSurfaceIfValid(display, eglSurface), EGL_FALSE);

Просмотреть файл

@ -49,6 +49,7 @@ EGLBoolean EGLAPIENTRY EGL_CopyBuffers(EGLDisplay dpy,
EGLNativePixmapType target)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(CopyBuffers,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", target = 0x%016" PRIxPTR "",
(uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)target);
@ -176,6 +177,7 @@ EGLBoolean EGLAPIENTRY EGL_DestroyContext(EGLDisplay dpy, EGLContext ctx)
EGLBoolean EGLAPIENTRY EGL_DestroySurface(EGLDisplay dpy, EGLSurface surface)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(DestroySurface, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR "",
(uintptr_t)dpy, (uintptr_t)surface);
@ -317,6 +319,7 @@ EGLBoolean EGLAPIENTRY EGL_MakeCurrent(EGLDisplay dpy,
EGLContext ctx)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(MakeCurrent,
"dpy = 0x%016" PRIxPTR ", draw = 0x%016" PRIxPTR ", read = 0x%016" PRIxPTR
", ctx = 0x%016" PRIxPTR "",
@ -378,6 +381,7 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurface(EGLDisplay dpy,
EGLint *value)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(QuerySurface,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", attribute = %d, value = 0x%016" PRIxPTR "",
@ -396,7 +400,7 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurface(EGLDisplay dpy,
EGLBoolean EGLAPIENTRY EGL_SwapBuffers(EGLDisplay dpy, EGLSurface surface)
{
ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(SwapBuffers, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR "", (uintptr_t)dpy,
(uintptr_t)surface);
@ -453,6 +457,7 @@ EGLBoolean EGLAPIENTRY EGL_WaitNative(EGLint engine)
EGLBoolean EGLAPIENTRY EGL_BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(BindTexImage, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", buffer = %d",
(uintptr_t)dpy, (uintptr_t)surface, buffer);
@ -470,6 +475,7 @@ EGLBoolean EGLAPIENTRY EGL_BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLi
EGLBoolean EGLAPIENTRY EGL_ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(ReleaseTexImage, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", buffer = %d",
(uintptr_t)dpy, (uintptr_t)surface, buffer);
@ -490,6 +496,7 @@ EGLBoolean EGLAPIENTRY EGL_SurfaceAttrib(EGLDisplay dpy,
EGLint value)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(SurfaceAttrib,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", attribute = %d, value = %d",
(uintptr_t)dpy, (uintptr_t)surface, attribute, value);

Просмотреть файл

@ -62,6 +62,7 @@ EGLBoolean EGLAPIENTRY EGL_GetCompositorTimingSupportedANDROID(EGLDisplay dpy,
EGLint name)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetCompositorTimingSupportedANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", name = %d", (uintptr_t)dpy,
(uintptr_t)surface, name);
@ -85,6 +86,7 @@ EGLBoolean EGLAPIENTRY EGL_GetCompositorTimingANDROID(EGLDisplay dpy,
EGLnsecsANDROID *values)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetCompositorTimingANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", numTimestamps = %d, names = 0x%016" PRIxPTR ", values = 0x%016" PRIxPTR "",
@ -108,6 +110,7 @@ EGLBoolean EGLAPIENTRY EGL_GetNextFrameIdANDROID(EGLDisplay dpy,
EGLuint64KHR *frameId)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetNextFrameIdANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", frameId = 0x%016" PRIxPTR "",
(uintptr_t)dpy, (uintptr_t)surface, (uintptr_t)frameId);
@ -128,6 +131,7 @@ EGLBoolean EGLAPIENTRY EGL_GetFrameTimestampSupportedANDROID(EGLDisplay dpy,
EGLint timestamp)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetFrameTimestampSupportedANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", timestamp = %d",
(uintptr_t)dpy, (uintptr_t)surface, timestamp);
@ -152,6 +156,7 @@ EGLBoolean EGLAPIENTRY EGL_GetFrameTimestampsANDROID(EGLDisplay dpy,
EGLnsecsANDROID *values)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetFrameTimestampsANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", frameId = %llu, numTimestamps = %d, timestamps = 0x%016" PRIxPTR
@ -208,6 +213,7 @@ EGLBoolean EGLAPIENTRY EGL_PresentationTimeANDROID(EGLDisplay dpy,
EGLnsecsANDROID time)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(PresentationTimeANDROID,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", time = %llu", (uintptr_t)dpy,
(uintptr_t)surface, static_cast<unsigned long long>(time));
@ -428,6 +434,7 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurfacePointerANGLE(EGLDisplay dpy,
void **value)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(QuerySurfacePointerANGLE,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", attribute = %d, value = 0x%016" PRIxPTR "",
@ -496,6 +503,7 @@ EGLBoolean EGLAPIENTRY EGL_SwapBuffersWithFrameTokenANGLE(EGLDisplay dpy,
EGLFrameTokenANGLE frametoken)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(SwapBuffersWithFrameTokenANGLE,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", frametoken = 0x%llX",
(uintptr_t)dpy, (uintptr_t)surface, static_cast<unsigned long long>(frametoken));
@ -518,6 +526,7 @@ EGLBoolean EGLAPIENTRY EGL_GetMscRateANGLE(EGLDisplay dpy,
EGLint *denominator)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetMscRateANGLE,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", numerator = 0x%016" PRIxPTR
", denominator = 0x%016" PRIxPTR "",
@ -566,6 +575,7 @@ EGLBoolean EGLAPIENTRY EGL_GetSyncValuesCHROMIUM(EGLDisplay dpy,
EGLuint64KHR *sbc)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(GetSyncValuesCHROMIUM,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", ust = 0x%016" PRIxPTR
", msc = 0x%016" PRIxPTR ", sbc = 0x%016" PRIxPTR "",
@ -884,6 +894,7 @@ EGLBoolean EGLAPIENTRY EGL_LockSurfaceKHR(EGLDisplay dpy,
const EGLint *attrib_list)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(LockSurfaceKHR,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", attrib_list = 0x%016" PRIxPTR
"",
@ -907,6 +918,7 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurface64KHR(EGLDisplay dpy,
EGLAttribKHR *value)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(QuerySurface64KHR,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", attribute = %d, value = 0x%016" PRIxPTR "",
@ -926,6 +938,7 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurface64KHR(EGLDisplay dpy,
EGLBoolean EGLAPIENTRY EGL_UnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(UnlockSurfaceKHR, "dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR "",
(uintptr_t)dpy, (uintptr_t)surface);
@ -1125,7 +1138,7 @@ EGLBoolean EGLAPIENTRY EGL_SwapBuffersWithDamageKHR(EGLDisplay dpy,
const EGLint *rects,
EGLint n_rects)
{
ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(SwapBuffersWithDamageKHR,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR ", rects = 0x%016" PRIxPTR
", n_rects = %d",
@ -1169,6 +1182,7 @@ EGLBoolean EGLAPIENTRY EGL_PostSubBufferNV(EGLDisplay dpy,
EGLint height)
{
ANGLE_SCOPED_GLOBAL_LOCK();
ANGLE_SCOPED_GLOBAL_SURFACE_LOCK();
EGL_EVENT(PostSubBufferNV,
"dpy = 0x%016" PRIxPTR ", surface = 0x%016" PRIxPTR
", x = %d, y = %d, width = %d, height = %d",

Просмотреть файл

@ -26,6 +26,9 @@ namespace
ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_Mutex(nullptr);
static_assert(std::is_trivially_destructible<decltype(g_Mutex)>::value,
"global mutex is not trivially destructible");
ANGLE_REQUIRE_CONSTANT_INIT std::atomic<angle::GlobalMutex *> g_SurfaceMutex(nullptr);
static_assert(std::is_trivially_destructible<decltype(g_SurfaceMutex)>::value,
"global mutex is not trivially destructible");
ANGLE_REQUIRE_CONSTANT_INIT gl::Context *g_LastContext(nullptr);
static_assert(std::is_trivially_destructible<decltype(g_LastContext)>::value,
@ -97,6 +100,19 @@ void AllocateMutex()
}
}
void AllocateSurfaceMutex()
{
if (g_SurfaceMutex == nullptr)
{
std::unique_ptr<angle::GlobalMutex> newMutex(new angle::GlobalMutex());
angle::GlobalMutex *expected = nullptr;
if (g_SurfaceMutex.compare_exchange_strong(expected, newMutex.get()))
{
newMutex.release();
}
}
}
} // anonymous namespace
#if defined(ANGLE_PLATFORM_APPLE)
@ -137,6 +153,12 @@ angle::GlobalMutex &GetGlobalMutex()
return *g_Mutex;
}
angle::GlobalMutex &GetGlobalSurfaceMutex()
{
AllocateSurfaceMutex();
return *g_SurfaceMutex;
}
gl::Context *GetGlobalLastContext()
{
return g_LastContext;
@ -231,6 +253,18 @@ void DeallocateMutex()
SafeDelete(mutex);
}
void DeallocateSurfaceMutex()
{
angle::GlobalMutex *mutex = g_SurfaceMutex.exchange(nullptr);
if (!mutex)
return;
{
// Wait for the mutex to become released by other threads before deleting.
std::lock_guard<angle::GlobalMutex> lock(*mutex);
}
SafeDelete(mutex);
}
bool InitializeProcess()
{
EnsureDebugAllocated();
@ -241,6 +275,7 @@ bool InitializeProcess()
void TerminateProcess()
{
DeallocateDebug();
DeallocateSurfaceMutex();
DeallocateMutex();
DeallocateCurrentThread();
}

Просмотреть файл

@ -101,6 +101,7 @@ extern thread_local Thread *gCurrentThread;
#endif
angle::GlobalMutex &GetGlobalMutex();
angle::GlobalMutex &GetGlobalSurfaceMutex();
gl::Context *GetGlobalLastContext();
void SetGlobalLastContext(gl::Context *context);
Thread *GetCurrentThread();
@ -122,6 +123,9 @@ class ScopedSyncCurrentContextFromThread
#define ANGLE_SCOPED_GLOBAL_LOCK() \
std::lock_guard<angle::GlobalMutex> globalMutexLock(egl::GetGlobalMutex())
#define ANGLE_SCOPED_GLOBAL_SURFACE_LOCK() \
std::lock_guard<angle::GlobalMutex> globalSurfaceMutexLock(egl::GetGlobalSurfaceMutex())
namespace gl
{
ANGLE_INLINE Context *GetGlobalContext()

Просмотреть файл

@ -123,12 +123,21 @@ class EGLContextSharingTestNoFixture : public EGLContextSharingTest
return result;
}
bool createContext(EGLConfig config, EGLContext *context)
bool createContext(EGLConfig config,
EGLContext *context,
EGLContext share_context = EGL_NO_CONTEXT)
{
bool result = false;
EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, mMajorVersion, EGL_NONE};
EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, mMajorVersion,
EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE, mVirtualizationGroup++,
EGL_NONE};
*context = eglCreateContext(mDisplay, config, nullptr, attribs);
if (!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_ANGLE_context_virtualization"))
{
attribs[2] = EGL_NONE;
}
*context = eglCreateContext(mDisplay, config, share_context, attribs);
result = (*context != EGL_NO_CONTEXT);
EXPECT_TRUE(result);
return result;
@ -166,6 +175,7 @@ class EGLContextSharingTestNoFixture : public EGLContextSharingTest
const EGLint kWidth = 64;
const EGLint kHeight = 64;
EGLint mMajorVersion = 0;
std::atomic<EGLint> mVirtualizationGroup;
};
// Tests that creating resources works after freeing the share context.
@ -962,6 +972,116 @@ TEST_P(EGLContextSharingTestNoFixture, EglTerminateMultipleTimes)
EXPECT_EGL_SUCCESS();
mDisplay = EGL_NO_DISPLAY;
}
// Test that we can eglSwapBuffers in one thread while another thread renders to a texture.
TEST_P(EGLContextSharingTestNoFixture, SwapBuffersShared)
{
EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
EXPECT_TRUE(mDisplay != EGL_NO_DISPLAY);
EXPECT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
EGLConfig config = EGL_NO_CONFIG_KHR;
EXPECT_TRUE(chooseConfig(&config));
mOsWindow->initialize("EGLContextSharingTestNoFixture", kWidth, kHeight);
EXPECT_TRUE(createWindowSurface(config, mOsWindow->getNativeWindow(), &mSurface));
ASSERT_EGL_SUCCESS() << "eglCreateWindowSurface failed.";
EGLSurface pbufferSurface;
EXPECT_TRUE(createPbufferSurface(mDisplay, config, kWidth, kHeight, &pbufferSurface));
// Create the two contextss
EXPECT_TRUE(createContext(config, &mContexts[0]));
EXPECT_TRUE(createContext(config, &mContexts[1], mContexts[0]));
eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]);
ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// Synchronization tools to ensure the two threads are interleaved as designed by this test.
std::mutex mutex;
std::condition_variable condVar;
enum class Step
{
Start,
TextureInitialized,
Finish,
Abort,
};
Step currentStep = Step::Start;
// Sample a texture in the swap thread.
std::thread swapThread = std::thread([&]() {
ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
ASSERT_TRUE(threadSynchronization.waitForStep(Step::Start));
eglMakeCurrent(mDisplay, mSurface, mSurface, mContexts[0]);
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
threadSynchronization.nextStep(Step::TextureInitialized);
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
glUseProgram(program);
for (int i = 0; i < 100; ++i)
{
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_NO_ERROR();
eglSwapBuffers(mDisplay, mSurface);
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglReleaseThread();
});
// Render to the texture in the render thread.
std::thread renderThread = std::thread([&]() {
ThreadSynchronization<Step> threadSynchronization(&currentStep, &mutex, &condVar);
ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, pbufferSurface, pbufferSurface, mContexts[1]));
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
ANGLE_GL_PROGRAM(greenProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
ANGLE_GL_PROGRAM(blueProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Blue());
// The render thread will draw to the texture.
ASSERT_TRUE(threadSynchronization.waitForStep(Step::TextureInitialized));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
glDisable(GL_DEPTH_TEST);
for (int i = 0; i < 400; ++i)
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(redProgram);
drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(greenProgram);
drawQuad(greenProgram, essl1_shaders::PositionAttrib(), 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(blueProgram);
drawQuad(blueProgram, essl1_shaders::PositionAttrib(), 0.5f);
}
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglReleaseThread();
});
swapThread.join();
renderThread.join();
eglDestroySurface(mDisplay, pbufferSurface);
ASSERT_EGL_SUCCESS();
}
} // anonymous namespace
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLContextSharingTest);