mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-04 22:09:59 +03:00
Implement "Shared Context Mutex" functionality.
Existing implementation uses single `GlobalMutex` for
- EGL calls
- GL calls for Contexts with concurrent access.
This CL introduces abstract `egl::ContextMutex` with two
implementations:
- SingleContextMutex;
- SharedContextMutex<Mutex>;
Note:
`std::mutex` is used in this commit. It is very easy to change mutex
type either at compile-time or at run-time (single type per Display).
When Context:
- is not Shared;
- does not use `EGLImage`s;
- does not use EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE
- does not use EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE
then it will be using `SingleContextMutex` with minimal overhead.
Before such Context is used as `shareContext` or uses `EGLImage`
its mutex replaced by `SharedContextMutex<Mutex>`.
The `GlobalMutex` is only used for EGL calls, while `egl::ContextMutex`
implementations for GL calls. Because some EGL calls use Context,
explicit `egl::ContextMutex` lock is required. This is implemented by
generating "egl_context_mutex_autogen.h" header, and insertion of
`ANGLE_EGL_SCOPED_CONTEXT_LOCK()` macro before `ANGLE_EGL_VALIDATE()`
in each EGL entry point. Implementation in "egl_context_lock_impl.h"
returns lock for required APIs. Special cases of `egl::ContextMutex`
lock handled separately. `std::unique_lock<>` is not used for
performance reasons.
`egl::ContextMutex` explicitly locked when capturing EGL calls.
Fixes EGLImage problem:
e18240d136
Mark contexts as shared when importing EGL images.
Details:
- EGLImage inherits Context's mutex when created.
Mutex is used when the EGLImage accessed or destroyed.
- When EGLImage is used in Context with other `egl::ContextMutex`,
two mutexes are merged into one.
- After the mutex merge, Context Groups will remain separate,
but will not be able to run in parallel.
Fixes race when checking `context->isShared()` in the
`SCOPED_SHARE_CONTEXT_LOCK()` macro. One Context may start executing GL
call while not "Shared", but become "Shared" inside the call. New
(second) "Shared" Context may immediately start using GL and potentially
corrupt some "Shared" state.
Possible performance benefit: allows parallel execution in some cases,
when single `GlobalMutex` would block.
Important note:
Process of replacing the `SingleContextMutex` by
`SharedContextMutex<Mutex>` is not 100% safe. This mean that
original Context may still be using `SingleContextMutex` after
activating `SharedContextMutex<Mutex>`. However, this was always
the case before introduction of this CL. Old `Context::mShared`
member update was not synchronized in any way at all. In other
words, this solution does not 100% fix the original problem.
For 100% safe solution `SingleContextMutex` should not be used
(always pass `SharedContextMutex<Mutex>` to the `gl::Context`
constructor). See `lockAndActivateSharedContextMutex()` for more
details.
CL adds new build option:
angle_enable_shared_context_mutex = true
Behavior with other build options:
- When:
`angle_enable_shared_context_mutex` is disabled or
`angle_enable_share_context_lock` is disabled or
`angle_force_context_check_every_call` is enabled,
Contexts will always have `SingleContextMutex`, however it will be
only used in special cases. `SCOPED_SHARE_CONTEXT_LOCK()` will use
`GlobalMutex` when applicable.
- Otherwise, `SCOPED_SHARE_CONTEXT_LOCK()` will use `egl::ContextMutex`.
Some GFXBench "1080p Driver Overhead 2 Offscreen" performance numbers.
Tested on S906B (Samsung Galaxy S22+) on old ANGLE base:
807c94ea85
Capture/Replay: Adjust tests do adhere to capture limits
Each test result is an average frame number from 6 runs.
SingleContextMutex 6579 ( +0.13%)
(old) GetContextLock() (mShared is false) 6570
Forced `mShared = true` or NOT using `SingleContextMutex`.
SharedContextMutex<std::mutex> FORCE 5061 (-22.97%)
(old) GetContextLock() FORCE 4766 (-27.46%)
Bug: angleproject:6957
Bug: chromium:1336126
Change-Id: Idcd919f9d4bf482b9ae489bd8b4415ec96048e32
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4374545
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
82151df0c9
commit
36c3e0f546
@@ -6,7 +6,7 @@
|
||||
"scripts/entry_point_packed_gl_enums.json":
|
||||
"1c6b036918aabb9822a638fbf33f87f4",
|
||||
"scripts/generate_entry_points.py":
|
||||
"af2e7b9911842300f7cbdd3230e279cb",
|
||||
"b85e2df1673ba499b02d520623ff2637",
|
||||
"scripts/gl_angle_ext.xml":
|
||||
"49a0bf469d6f44c532098ef3a9fd087f",
|
||||
"scripts/registry_xml.py":
|
||||
@@ -113,6 +113,8 @@
|
||||
"f021ca1ad124333ef618080890f13582",
|
||||
"src/libGLESv2/cl_stubs_autogen.h":
|
||||
"6d880c6b65284192b5842f0e42ad2741",
|
||||
"src/libGLESv2/egl_context_lock_autogen.h":
|
||||
"4cf7d5d5e35ca438de4104ac4ceb2b89",
|
||||
"src/libGLESv2/egl_ext_stubs_autogen.h":
|
||||
"1826fdc1676e19ebf86a20ec76ea51c0",
|
||||
"src/libGLESv2/egl_get_labeled_object_data.json":
|
||||
@@ -124,11 +126,11 @@
|
||||
"src/libGLESv2/entry_points_cl_autogen.h":
|
||||
"dde2f94c3004874a7da995dae69da811",
|
||||
"src/libGLESv2/entry_points_egl_autogen.cpp":
|
||||
"dbb7a09d338d2fb0809abddd62b2578f",
|
||||
"82dc17eb4990c965f98ec672b7ce9d94",
|
||||
"src/libGLESv2/entry_points_egl_autogen.h":
|
||||
"3bc7a8df9deadd7cfd615d0cfad0c6a8",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.cpp":
|
||||
"bff96d039ef189414bec3451c8bb379b",
|
||||
"d73defbc1b89b16f5de42849633d43ba",
|
||||
"src/libGLESv2/entry_points_egl_ext_autogen.h":
|
||||
"5a212372e378e0890d2d3ac96c1a3765",
|
||||
"src/libGLESv2/entry_points_gl_1_autogen.cpp":
|
||||
@@ -168,7 +170,7 @@
|
||||
"src/libGLESv2/entry_points_gles_3_2_autogen.h":
|
||||
"647f932a299cdb4726b60bbba059f0d2",
|
||||
"src/libGLESv2/entry_points_gles_ext_autogen.cpp":
|
||||
"827e15c2f31276f9207f9687a4bc4c7a",
|
||||
"4fb06f0ab32147310686fedf1bc116bf",
|
||||
"src/libGLESv2/entry_points_gles_ext_autogen.h":
|
||||
"7bb44566362d1de21552faf427517085",
|
||||
"src/libGLESv2/libGLESv2_autogen.cpp":
|
||||
|
||||
@@ -306,9 +306,13 @@ void EGLAPIENTRY EGL_{name}({params})
|
||||
|
||||
{packed_gl_enum_conversions}
|
||||
|
||||
ANGLE_EGL_VALIDATE_VOID(thread, {name}, {labeled_object}, {internal_params});
|
||||
{{
|
||||
ANGLE_EGL_SCOPED_CONTEXT_LOCK({name}, thread{comma_if_needed_context_lock}{internal_context_lock_params});
|
||||
ANGLE_EGL_VALIDATE_VOID(thread, {name}, {labeled_object}, {internal_params});
|
||||
|
||||
{name}(thread{comma_if_needed}{internal_params});
|
||||
}}
|
||||
|
||||
{name}(thread{comma_if_needed}{internal_params});
|
||||
ANGLE_CAPTURE_EGL({name}, true, {egl_capture_params});
|
||||
}}
|
||||
{epilog}
|
||||
@@ -327,9 +331,13 @@ TEMPLATE_EGL_ENTRY_POINT_WITH_RETURN = """\
|
||||
|
||||
{packed_gl_enum_conversions}
|
||||
|
||||
ANGLE_EGL_VALIDATE(thread, {name}, {labeled_object}, {return_type}{comma_if_needed}{internal_params});
|
||||
{{
|
||||
ANGLE_EGL_SCOPED_CONTEXT_LOCK({name}, thread{comma_if_needed_context_lock}{internal_context_lock_params});
|
||||
ANGLE_EGL_VALIDATE(thread, {name}, {labeled_object}, {return_type}{comma_if_needed}{internal_params});
|
||||
|
||||
returnValue = {name}(thread{comma_if_needed}{internal_params});
|
||||
}}
|
||||
|
||||
returnValue = {name}(thread{comma_if_needed}{internal_params});
|
||||
ANGLE_CAPTURE_EGL({name}, true, {egl_capture_params}, returnValue);
|
||||
}}
|
||||
{epilog}
|
||||
@@ -588,6 +596,30 @@ namespace egl
|
||||
#endif // LIBANGLE_VALIDATION_{annotation}_AUTOGEN_H_
|
||||
"""
|
||||
|
||||
TEMPLATE_EGL_CONTEXT_LOCK_HEADER = """\
|
||||
// GENERATED FILE - DO NOT EDIT.
|
||||
// Generated by {script_name} using data from {data_source_name}.
|
||||
//
|
||||
// Copyright 2023 The ANGLE Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// {annotation_lower}_context_lock_autogen.h:
|
||||
// Context Lock functions for the {comment} entry points.
|
||||
|
||||
#ifndef LIBGLESV2_{annotation_upper}_CONTEXT_LOCK_AUTOGEN_H_
|
||||
#define LIBGLESV2_{annotation_upper}_CONTEXT_LOCK_AUTOGEN_H_
|
||||
|
||||
#include "libGLESv2/global_state.h"
|
||||
|
||||
namespace egl
|
||||
{{
|
||||
{prototypes}
|
||||
}} // namespace egl
|
||||
|
||||
#endif // LIBGLESV2_{annotation_upper}_CONTEXT_LOCK_AUTOGEN_H_
|
||||
"""
|
||||
|
||||
TEMPLATE_CAPTURE_HEADER = """\
|
||||
// GENERATED FILE - DO NOT EDIT.
|
||||
// Generated by {script_name} using data from {data_source_name}.
|
||||
@@ -955,6 +987,7 @@ EGL_SOURCE_INCLUDES = """\
|
||||
#include "libANGLE/capture/capture_egl_autogen.h"
|
||||
#include "libANGLE/entry_points_utils.h"
|
||||
#include "libANGLE/validationEGL_autogen.h"
|
||||
#include "libGLESv2/egl_context_lock_impl.h"
|
||||
#include "libGLESv2/egl_stubs_autogen.h"
|
||||
#include "libGLESv2/egl_ext_stubs_autogen.h"
|
||||
#include "libGLESv2/global_state.h"
|
||||
@@ -974,6 +1007,7 @@ EGL_EXT_SOURCE_INCLUDES = """\
|
||||
#include "libANGLE/capture/capture_egl_autogen.h"
|
||||
#include "libANGLE/entry_points_utils.h"
|
||||
#include "libANGLE/validationEGL_autogen.h"
|
||||
#include "libGLESv2/egl_context_lock_impl.h"
|
||||
#include "libGLESv2/egl_ext_stubs_autogen.h"
|
||||
#include "libGLESv2/global_state.h"
|
||||
|
||||
@@ -1074,6 +1108,8 @@ TEMPLATE_CAPTURE_PROTO = "angle::CallCapture Capture%s(%s);"
|
||||
|
||||
TEMPLATE_VALIDATION_PROTO = "%s Validate%s(%s);"
|
||||
|
||||
TEMPLATE_CONTEXT_LOCK_PROTO = "ScopedContextMutexLock GetContextLock_%s(%s);"
|
||||
|
||||
TEMPLATE_WINDOWS_DEF_FILE = """\
|
||||
; GENERATED FILE - DO NOT EDIT.
|
||||
; Generated by {script_name} using data from {data_source_name}.
|
||||
@@ -1618,6 +1654,12 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
|
||||
else:
|
||||
has_errcode_ret = False
|
||||
|
||||
internal_context_lock_params = [
|
||||
just_the_name_packed(param, packed_enums) for param in params if just_the_type_packed(
|
||||
param, packed_enums) in ["Thread *", "egl::Display *", "gl::ContextID"] or
|
||||
just_the_name_packed(param, packed_enums) in ["attribute"]
|
||||
]
|
||||
|
||||
packed_gl_enum_conversions = []
|
||||
|
||||
for param in params:
|
||||
@@ -1650,6 +1692,8 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
|
||||
", ".join(params),
|
||||
"internal_params":
|
||||
", ".join(internal_params),
|
||||
"internal_context_lock_params":
|
||||
", ".join(internal_context_lock_params),
|
||||
"initialization":
|
||||
initialization,
|
||||
"packed_gl_enum_conversions":
|
||||
@@ -1658,6 +1702,8 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
|
||||
", ".join(pass_params),
|
||||
"comma_if_needed":
|
||||
", " if len(params) > 0 else "",
|
||||
"comma_if_needed_context_lock":
|
||||
", " if len(internal_context_lock_params) > 0 else "",
|
||||
"gl_capture_params":
|
||||
", ".join(["context"] + internal_params),
|
||||
"egl_capture_params":
|
||||
@@ -1828,6 +1874,20 @@ def get_validation_params(api, cmd_name, params, cmd_packed_gl_enums, packed_par
|
||||
])
|
||||
|
||||
|
||||
def get_context_lock_params(api, cmd_name, params, cmd_packed_gl_enums, packed_param_types):
|
||||
packed_gl_enums = get_packed_enums(api, cmd_packed_gl_enums, cmd_name, packed_param_types,
|
||||
params)
|
||||
return ", ".join([
|
||||
make_param(
|
||||
just_the_type_packed(param, packed_gl_enums),
|
||||
just_the_name_packed(param, packed_gl_enums))
|
||||
for param in params
|
||||
if just_the_type_packed(
|
||||
param, packed_gl_enums) in ["Thread *", "egl::Display *", "gl::ContextID"] or
|
||||
just_the_name_packed(param, packed_gl_enums) in ["attribute"]
|
||||
])
|
||||
|
||||
|
||||
def format_context_decl(api, cmd_name, proto, params, template, cmd_packed_gl_enums,
|
||||
packed_param_types):
|
||||
internal_params = get_internal_params(api, cmd_name, params, cmd_packed_gl_enums,
|
||||
@@ -1873,6 +1933,13 @@ def format_validation_proto(api, cmd_name, proto, params, cmd_packed_gl_enums, p
|
||||
return TEMPLATE_VALIDATION_PROTO % (return_type, strip_api_prefix(cmd_name), internal_params)
|
||||
|
||||
|
||||
def format_context_lock_proto(api, cmd_name, params, cmd_packed_gl_enums, packed_param_types):
|
||||
with_extra_params = ["Thread *thread"] + params
|
||||
internal_params = get_context_lock_params(api, cmd_name, with_extra_params,
|
||||
cmd_packed_gl_enums, packed_param_types)
|
||||
return TEMPLATE_CONTEXT_LOCK_PROTO % (strip_api_prefix(cmd_name), internal_params)
|
||||
|
||||
|
||||
def format_capture_proto(api, cmd_name, proto, params, cmd_packed_gl_enums, packed_param_types):
|
||||
context_param_typed = 'egl::Thread *thread' if api == apis.EGL else 'const State &glState'
|
||||
internal_params = get_internal_params(api, cmd_name,
|
||||
@@ -1905,6 +1972,7 @@ class ANGLEEntryPoints(registry_xml.EntryPoints):
|
||||
self.defs = []
|
||||
self.export_defs = []
|
||||
self.validation_protos = []
|
||||
self.context_lock_protos = []
|
||||
self.capture_protos = []
|
||||
self.capture_methods = []
|
||||
self.capture_pointer_funcs = []
|
||||
@@ -1922,6 +1990,11 @@ class ANGLEEntryPoints(registry_xml.EntryPoints):
|
||||
format_validation_proto(self.api, cmd_name, proto_text, param_text,
|
||||
cmd_packed_enums, packed_param_types))
|
||||
|
||||
if api == apis.EGL:
|
||||
self.context_lock_protos.append(
|
||||
format_context_lock_proto(api, cmd_name, param_text, cmd_packed_enums,
|
||||
packed_param_types))
|
||||
|
||||
self.capture_protos.append(
|
||||
format_capture_proto(self.api, cmd_name, proto_text, param_text, cmd_packed_enums,
|
||||
packed_param_types))
|
||||
@@ -2196,6 +2269,22 @@ def write_validation_header(annotation, comment, protos, source, template):
|
||||
out.close()
|
||||
|
||||
|
||||
def write_context_lock_header(annotation, comment, protos, source, template):
|
||||
content = template.format(
|
||||
script_name=os.path.basename(sys.argv[0]),
|
||||
data_source_name=source,
|
||||
annotation_lower=annotation.lower(),
|
||||
annotation_upper=annotation.upper(),
|
||||
comment=comment,
|
||||
prototypes="\n".join(protos))
|
||||
|
||||
path = path_to("libGLESv2", "%s_context_lock_autogen.h" % annotation.lower())
|
||||
|
||||
with open(path, "w") as out:
|
||||
out.write(content)
|
||||
out.close()
|
||||
|
||||
|
||||
def write_gl_validation_header(annotation, comment, protos, source):
|
||||
return write_validation_header(annotation, comment, protos, source,
|
||||
TEMPLATE_GL_VALIDATION_HEADER)
|
||||
@@ -2661,8 +2750,9 @@ def get_egl_entry_point_labeled_object(ep_to_object, cmd_stripped, params, packe
|
||||
def get_context_lock(api, cmd_name):
|
||||
# EGLImage related commands need to access EGLImage and Display which should
|
||||
# be protected with global lock
|
||||
# Also handles ContexMutex marging when SharedContextMutex is enabled.
|
||||
if api == apis.GLES and cmd_name.startswith("glEGLImage"):
|
||||
return "SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context);"
|
||||
return "SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imagePacked);"
|
||||
|
||||
return "SCOPED_SHARE_CONTEXT_LOCK(context);"
|
||||
|
||||
@@ -2855,6 +2945,7 @@ def main():
|
||||
'../src/libGLESv2/entry_points_gl_3_autogen.h',
|
||||
'../src/libGLESv2/entry_points_gl_4_autogen.cpp',
|
||||
'../src/libGLESv2/entry_points_gl_4_autogen.h',
|
||||
'../src/libGLESv2/egl_context_lock_autogen.h',
|
||||
'../util/capture/frame_capture_replay_autogen.cpp',
|
||||
]
|
||||
|
||||
@@ -3197,6 +3288,7 @@ def main():
|
||||
eglxml = registry_xml.RegistryXML('egl.xml', 'egl_angle_ext.xml')
|
||||
|
||||
egl_validation_protos = []
|
||||
egl_context_lock_protos = []
|
||||
egl_decls = ["extern \"C\" {"]
|
||||
egl_defs = ["extern \"C\" {"]
|
||||
libegl_ep_defs = []
|
||||
@@ -3231,6 +3323,7 @@ def main():
|
||||
egl_defs += [comment] + eps.defs
|
||||
libegl_ep_defs += [comment] + eps.export_defs
|
||||
egl_validation_protos += [comment] + eps.validation_protos
|
||||
egl_context_lock_protos += [comment] + eps.context_lock_protos
|
||||
libegl_windows_def_exports += [win_def_comment] + get_exports(eglxml.commands[version])
|
||||
egl_capture_protos += eps.capture_protos
|
||||
egl_capture_methods += eps.capture_methods
|
||||
@@ -3268,6 +3361,7 @@ def main():
|
||||
egl_ext_defs += [comment] + eps.defs
|
||||
libegl_ep_defs += [comment] + eps.export_defs
|
||||
egl_validation_protos += [comment] + eps.validation_protos
|
||||
egl_context_lock_protos += [comment] + eps.context_lock_protos
|
||||
libegl_windows_def_exports += [win_def_comment] + get_exports(ext_cmd_names)
|
||||
egl_capture_protos += eps.capture_protos
|
||||
egl_capture_methods += eps.capture_methods
|
||||
@@ -3286,6 +3380,8 @@ def main():
|
||||
"cpp", EGL_EXT_SOURCE_INCLUDES, "libGLESv2", "egl.xml and egl_angle_ext.xml")
|
||||
write_validation_header("EGL", "EGL", egl_validation_protos, "egl.xml and egl_angle_ext.xml",
|
||||
TEMPLATE_EGL_VALIDATION_HEADER)
|
||||
write_context_lock_header("EGL", "EGL", egl_context_lock_protos,
|
||||
"egl.xml and egl_angle_ext.xml", TEMPLATE_EGL_CONTEXT_LOCK_HEADER)
|
||||
write_stubs_header("EGL", "egl_ext", "EXT extension", "egl.xml and egl_angle_ext.xml",
|
||||
EGL_EXT_STUBS_HEADER_PATH, eglxml.all_commands, egl_ext_commands,
|
||||
EGLEntryPoints.get_packed_enums(), EGL_PACKED_TYPES)
|
||||
|
||||
Reference in New Issue
Block a user