зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
c2a2961493
Коммит
40c5cb255c
|
@ -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(¤tStep, &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(¤tStep, &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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче