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:
Igor Nazarov 2023-01-17 17:42:59 +02:00 коммит произвёл Angle LUCI CQ
Родитель 82151df0c9
Коммит 36c3e0f546
26 изменённых файлов: 2931 добавлений и 380 удалений

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

@ -80,6 +80,8 @@ declare_args() {
# Chromium may have problems (requires verification), disabled for safety. # Chromium may have problems (requires verification), disabled for safety.
angle_enable_global_mutex_load_time_allocate = angle_enable_global_mutex_load_time_allocate =
is_android && !build_with_chromium is_android && !build_with_chromium
angle_enable_shared_context_mutex = true
} }
if (angle_build_all) { if (angle_build_all) {
@ -175,6 +177,11 @@ config("internal_config") {
defines += [ "ANGLE_ENABLE_GLOBAL_MUTEX_LOAD_TIME_ALLOCATE=1" ] defines += [ "ANGLE_ENABLE_GLOBAL_MUTEX_LOAD_TIME_ALLOCATE=1" ]
} }
if (angle_enable_shared_context_mutex && angle_enable_share_context_lock &&
!angle_force_context_check_every_call) {
defines += [ "ANGLE_ENABLE_SHARED_CONTEXT_MUTEX=1" ]
}
# Enables debug/trace-related functionality, including logging every GLES/EGL API command to the # Enables debug/trace-related functionality, including logging every GLES/EGL API command to the
# "angle_debug.txt" file on desktop. Enables debug markers for AGI, but must also set # "angle_debug.txt" file on desktop. Enables debug markers for AGI, but must also set
# angle_enable_annotator_run_time_checks to improve performance. # angle_enable_annotator_run_time_checks to improve performance.

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

@ -6,7 +6,7 @@
"scripts/entry_point_packed_gl_enums.json": "scripts/entry_point_packed_gl_enums.json":
"1c6b036918aabb9822a638fbf33f87f4", "1c6b036918aabb9822a638fbf33f87f4",
"scripts/generate_entry_points.py": "scripts/generate_entry_points.py":
"af2e7b9911842300f7cbdd3230e279cb", "b85e2df1673ba499b02d520623ff2637",
"scripts/gl_angle_ext.xml": "scripts/gl_angle_ext.xml":
"49a0bf469d6f44c532098ef3a9fd087f", "49a0bf469d6f44c532098ef3a9fd087f",
"scripts/registry_xml.py": "scripts/registry_xml.py":
@ -113,6 +113,8 @@
"f021ca1ad124333ef618080890f13582", "f021ca1ad124333ef618080890f13582",
"src/libGLESv2/cl_stubs_autogen.h": "src/libGLESv2/cl_stubs_autogen.h":
"6d880c6b65284192b5842f0e42ad2741", "6d880c6b65284192b5842f0e42ad2741",
"src/libGLESv2/egl_context_lock_autogen.h":
"4cf7d5d5e35ca438de4104ac4ceb2b89",
"src/libGLESv2/egl_ext_stubs_autogen.h": "src/libGLESv2/egl_ext_stubs_autogen.h":
"1826fdc1676e19ebf86a20ec76ea51c0", "1826fdc1676e19ebf86a20ec76ea51c0",
"src/libGLESv2/egl_get_labeled_object_data.json": "src/libGLESv2/egl_get_labeled_object_data.json":
@ -124,11 +126,11 @@
"src/libGLESv2/entry_points_cl_autogen.h": "src/libGLESv2/entry_points_cl_autogen.h":
"dde2f94c3004874a7da995dae69da811", "dde2f94c3004874a7da995dae69da811",
"src/libGLESv2/entry_points_egl_autogen.cpp": "src/libGLESv2/entry_points_egl_autogen.cpp":
"dbb7a09d338d2fb0809abddd62b2578f", "82dc17eb4990c965f98ec672b7ce9d94",
"src/libGLESv2/entry_points_egl_autogen.h": "src/libGLESv2/entry_points_egl_autogen.h":
"3bc7a8df9deadd7cfd615d0cfad0c6a8", "3bc7a8df9deadd7cfd615d0cfad0c6a8",
"src/libGLESv2/entry_points_egl_ext_autogen.cpp": "src/libGLESv2/entry_points_egl_ext_autogen.cpp":
"bff96d039ef189414bec3451c8bb379b", "d73defbc1b89b16f5de42849633d43ba",
"src/libGLESv2/entry_points_egl_ext_autogen.h": "src/libGLESv2/entry_points_egl_ext_autogen.h":
"5a212372e378e0890d2d3ac96c1a3765", "5a212372e378e0890d2d3ac96c1a3765",
"src/libGLESv2/entry_points_gl_1_autogen.cpp": "src/libGLESv2/entry_points_gl_1_autogen.cpp":
@ -168,7 +170,7 @@
"src/libGLESv2/entry_points_gles_3_2_autogen.h": "src/libGLESv2/entry_points_gles_3_2_autogen.h":
"647f932a299cdb4726b60bbba059f0d2", "647f932a299cdb4726b60bbba059f0d2",
"src/libGLESv2/entry_points_gles_ext_autogen.cpp": "src/libGLESv2/entry_points_gles_ext_autogen.cpp":
"827e15c2f31276f9207f9687a4bc4c7a", "4fb06f0ab32147310686fedf1bc116bf",
"src/libGLESv2/entry_points_gles_ext_autogen.h": "src/libGLESv2/entry_points_gles_ext_autogen.h":
"7bb44566362d1de21552faf427517085", "7bb44566362d1de21552faf427517085",
"src/libGLESv2/libGLESv2_autogen.cpp": "src/libGLESv2/libGLESv2_autogen.cpp":

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

@ -306,9 +306,13 @@ void EGLAPIENTRY EGL_{name}({params})
{packed_gl_enum_conversions} {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}); ANGLE_CAPTURE_EGL({name}, true, {egl_capture_params});
}} }}
{epilog} {epilog}
@ -327,9 +331,13 @@ TEMPLATE_EGL_ENTRY_POINT_WITH_RETURN = """\
{packed_gl_enum_conversions} {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); ANGLE_CAPTURE_EGL({name}, true, {egl_capture_params}, returnValue);
}} }}
{epilog} {epilog}
@ -588,6 +596,30 @@ namespace egl
#endif // LIBANGLE_VALIDATION_{annotation}_AUTOGEN_H_ #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 = """\ TEMPLATE_CAPTURE_HEADER = """\
// GENERATED FILE - DO NOT EDIT. // GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}. // 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/capture/capture_egl_autogen.h"
#include "libANGLE/entry_points_utils.h" #include "libANGLE/entry_points_utils.h"
#include "libANGLE/validationEGL_autogen.h" #include "libANGLE/validationEGL_autogen.h"
#include "libGLESv2/egl_context_lock_impl.h"
#include "libGLESv2/egl_stubs_autogen.h" #include "libGLESv2/egl_stubs_autogen.h"
#include "libGLESv2/egl_ext_stubs_autogen.h" #include "libGLESv2/egl_ext_stubs_autogen.h"
#include "libGLESv2/global_state.h" #include "libGLESv2/global_state.h"
@ -974,6 +1007,7 @@ EGL_EXT_SOURCE_INCLUDES = """\
#include "libANGLE/capture/capture_egl_autogen.h" #include "libANGLE/capture/capture_egl_autogen.h"
#include "libANGLE/entry_points_utils.h" #include "libANGLE/entry_points_utils.h"
#include "libANGLE/validationEGL_autogen.h" #include "libANGLE/validationEGL_autogen.h"
#include "libGLESv2/egl_context_lock_impl.h"
#include "libGLESv2/egl_ext_stubs_autogen.h" #include "libGLESv2/egl_ext_stubs_autogen.h"
#include "libGLESv2/global_state.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_VALIDATION_PROTO = "%s Validate%s(%s);"
TEMPLATE_CONTEXT_LOCK_PROTO = "ScopedContextMutexLock GetContextLock_%s(%s);"
TEMPLATE_WINDOWS_DEF_FILE = """\ TEMPLATE_WINDOWS_DEF_FILE = """\
; GENERATED FILE - DO NOT EDIT. ; GENERATED FILE - DO NOT EDIT.
; Generated by {script_name} using data from {data_source_name}. ; 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: else:
has_errcode_ret = False 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 = [] packed_gl_enum_conversions = []
for param in params: for param in params:
@ -1650,6 +1692,8 @@ def format_entry_point_def(api, command_node, cmd_name, proto, params, cmd_packe
", ".join(params), ", ".join(params),
"internal_params": "internal_params":
", ".join(internal_params), ", ".join(internal_params),
"internal_context_lock_params":
", ".join(internal_context_lock_params),
"initialization": "initialization":
initialization, initialization,
"packed_gl_enum_conversions": "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), ", ".join(pass_params),
"comma_if_needed": "comma_if_needed":
", " if len(params) > 0 else "", ", " if len(params) > 0 else "",
"comma_if_needed_context_lock":
", " if len(internal_context_lock_params) > 0 else "",
"gl_capture_params": "gl_capture_params":
", ".join(["context"] + internal_params), ", ".join(["context"] + internal_params),
"egl_capture_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, def format_context_decl(api, cmd_name, proto, params, template, cmd_packed_gl_enums,
packed_param_types): packed_param_types):
internal_params = get_internal_params(api, cmd_name, params, cmd_packed_gl_enums, 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) 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): 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' context_param_typed = 'egl::Thread *thread' if api == apis.EGL else 'const State &glState'
internal_params = get_internal_params(api, cmd_name, internal_params = get_internal_params(api, cmd_name,
@ -1905,6 +1972,7 @@ class ANGLEEntryPoints(registry_xml.EntryPoints):
self.defs = [] self.defs = []
self.export_defs = [] self.export_defs = []
self.validation_protos = [] self.validation_protos = []
self.context_lock_protos = []
self.capture_protos = [] self.capture_protos = []
self.capture_methods = [] self.capture_methods = []
self.capture_pointer_funcs = [] self.capture_pointer_funcs = []
@ -1922,6 +1990,11 @@ class ANGLEEntryPoints(registry_xml.EntryPoints):
format_validation_proto(self.api, cmd_name, proto_text, param_text, format_validation_proto(self.api, cmd_name, proto_text, param_text,
cmd_packed_enums, packed_param_types)) 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( self.capture_protos.append(
format_capture_proto(self.api, cmd_name, proto_text, param_text, cmd_packed_enums, format_capture_proto(self.api, cmd_name, proto_text, param_text, cmd_packed_enums,
packed_param_types)) packed_param_types))
@ -2196,6 +2269,22 @@ def write_validation_header(annotation, comment, protos, source, template):
out.close() 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): def write_gl_validation_header(annotation, comment, protos, source):
return write_validation_header(annotation, comment, protos, source, return write_validation_header(annotation, comment, protos, source,
TEMPLATE_GL_VALIDATION_HEADER) 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): def get_context_lock(api, cmd_name):
# EGLImage related commands need to access EGLImage and Display which should # EGLImage related commands need to access EGLImage and Display which should
# be protected with global lock # be protected with global lock
# Also handles ContexMutex marging when SharedContextMutex is enabled.
if api == apis.GLES and cmd_name.startswith("glEGLImage"): 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);" 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_3_autogen.h',
'../src/libGLESv2/entry_points_gl_4_autogen.cpp', '../src/libGLESv2/entry_points_gl_4_autogen.cpp',
'../src/libGLESv2/entry_points_gl_4_autogen.h', '../src/libGLESv2/entry_points_gl_4_autogen.h',
'../src/libGLESv2/egl_context_lock_autogen.h',
'../util/capture/frame_capture_replay_autogen.cpp', '../util/capture/frame_capture_replay_autogen.cpp',
] ]
@ -3197,6 +3288,7 @@ def main():
eglxml = registry_xml.RegistryXML('egl.xml', 'egl_angle_ext.xml') eglxml = registry_xml.RegistryXML('egl.xml', 'egl_angle_ext.xml')
egl_validation_protos = [] egl_validation_protos = []
egl_context_lock_protos = []
egl_decls = ["extern \"C\" {"] egl_decls = ["extern \"C\" {"]
egl_defs = ["extern \"C\" {"] egl_defs = ["extern \"C\" {"]
libegl_ep_defs = [] libegl_ep_defs = []
@ -3231,6 +3323,7 @@ def main():
egl_defs += [comment] + eps.defs egl_defs += [comment] + eps.defs
libegl_ep_defs += [comment] + eps.export_defs libegl_ep_defs += [comment] + eps.export_defs
egl_validation_protos += [comment] + eps.validation_protos 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]) libegl_windows_def_exports += [win_def_comment] + get_exports(eglxml.commands[version])
egl_capture_protos += eps.capture_protos egl_capture_protos += eps.capture_protos
egl_capture_methods += eps.capture_methods egl_capture_methods += eps.capture_methods
@ -3268,6 +3361,7 @@ def main():
egl_ext_defs += [comment] + eps.defs egl_ext_defs += [comment] + eps.defs
libegl_ep_defs += [comment] + eps.export_defs libegl_ep_defs += [comment] + eps.export_defs
egl_validation_protos += [comment] + eps.validation_protos 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) libegl_windows_def_exports += [win_def_comment] + get_exports(ext_cmd_names)
egl_capture_protos += eps.capture_protos egl_capture_protos += eps.capture_protos
egl_capture_methods += eps.capture_methods 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") "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", write_validation_header("EGL", "EGL", egl_validation_protos, "egl.xml and egl_angle_ext.xml",
TEMPLATE_EGL_VALIDATION_HEADER) 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", 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, EGL_EXT_STUBS_HEADER_PATH, eglxml.all_commands, egl_ext_commands,
EGLEntryPoints.get_packed_enums(), EGL_PACKED_TYPES) EGLEntryPoints.get_packed_enums(), EGL_PACKED_TYPES)

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

@ -77,6 +77,37 @@ egl::ShareGroup *AllocateOrGetShareGroup(egl::Display *display, const gl::Contex
} }
} }
egl::ContextMutex *TryAllocateOrUseSharedContextMutex(egl::Display *display,
egl::ContextMutex *sharedContextMutex)
{
if (egl::kIsSharedContextMutexEnabled)
{
if (sharedContextMutex == nullptr)
{
ASSERT(display->getSharedContextMutexManager() != nullptr);
sharedContextMutex = display->getSharedContextMutexManager()->create();
}
sharedContextMutex->addRef();
}
else
{
ASSERT(sharedContextMutex == nullptr);
}
return sharedContextMutex;
}
egl::SingleContextMutex *TryAllocateSingleContextMutex(egl::ContextMutex *sharedContextMutex)
{
egl::SingleContextMutex *singleContextMutex = nullptr;
if (!egl::kIsSharedContextMutexEnabled || sharedContextMutex == nullptr)
{
ASSERT(sharedContextMutex == nullptr);
singleContextMutex = new egl::SingleContextMutex();
singleContextMutex->addRef();
}
return singleContextMutex;
}
template <typename T> template <typename T>
angle::Result GetQueryObjectParameter(const Context *context, Query *query, GLenum pname, T *params) angle::Result GetQueryObjectParameter(const Context *context, Query *query, GLenum pname, T *params)
{ {
@ -470,6 +501,7 @@ Context::Context(egl::Display *display,
const Context *shareContext, const Context *shareContext,
TextureManager *shareTextures, TextureManager *shareTextures,
SemaphoreManager *shareSemaphores, SemaphoreManager *shareSemaphores,
egl::ContextMutex *sharedContextMutex,
MemoryProgramCache *memoryProgramCache, MemoryProgramCache *memoryProgramCache,
MemoryShaderCache *memoryShaderCache, MemoryShaderCache *memoryShaderCache,
const EGLenum clientType, const EGLenum clientType,
@ -480,6 +512,8 @@ Context::Context(egl::Display *display,
AllocateOrGetShareGroup(display, shareContext), AllocateOrGetShareGroup(display, shareContext),
shareTextures, shareTextures,
shareSemaphores, shareSemaphores,
TryAllocateOrUseSharedContextMutex(display, sharedContextMutex),
TryAllocateSingleContextMutex(sharedContextMutex),
&mOverlay, &mOverlay,
clientType, clientType,
GetClientVersion(display, attribs, clientType), GetClientVersion(display, attribs, clientType),
@ -527,6 +561,8 @@ Context::Context(egl::Display *display,
mSaveAndRestoreState(GetSaveAndRestoreState(attribs)), mSaveAndRestoreState(GetSaveAndRestoreState(attribs)),
mIsDestroyed(false) mIsDestroyed(false)
{ {
ASSERT(mState.mSharedContextMutex != nullptr || mState.mSingleContextMutex != nullptr);
for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex; for (angle::SubjectIndex uboIndex = kUniformBuffer0SubjectIndex;
uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex) uboIndex < kUniformBufferMaxSubjectIndex; ++uboIndex)
{ {
@ -876,6 +912,15 @@ egl::Error Context::onDestroy(const egl::Display *display)
// Backend requires implementation to be destroyed first to close down all the objects // Backend requires implementation to be destroyed first to close down all the objects
mState.mShareGroup->release(display); mState.mShareGroup->release(display);
if (mState.mSharedContextMutex != nullptr)
{
mState.mSharedContextMutex->release();
}
if (mState.mSingleContextMutex != nullptr)
{
mState.mSingleContextMutex->release();
}
mOverlay.destroy(this); mOverlay.destroy(this);
return egl::NoError(); return egl::NoError();
@ -9554,6 +9599,68 @@ void Context::getFramebufferPixelLocalStorageParameterivRobust(GLint plane,
} }
} }
bool Context::isSharedContextMutexActive() const
{
if (!mState.mIsSharedContextMutexActive)
{
return false;
}
ASSERT(mState.mSharedContextMutex != nullptr);
ASSERT(getContextMutex() == mState.mSharedContextMutex);
return true;
}
egl::ScopedContextMutexLock Context::lockAndActivateSharedContextMutex()
{
constexpr uint32_t kActivationDelayMicro = 100;
ASSERT(mState.mSharedContextMutex != nullptr);
// All state updates must be protected by "SharedContextMutex".
egl::ScopedContextMutexLock lock(mState.mSharedContextMutex);
if (!mState.mIsSharedContextMutexActive)
{
ASSERT(mState.mSingleContextMutex != nullptr);
// First, start using "SharedContextMutex".
mState.mContextMutex.store(mState.mSharedContextMutex);
// Second, sleep some time so that currently active Context thread start using new mutex.
// Logic assumes that there will be no new "SingleContextMutex" locks after this.
// In very rare cases when this happens, new Context may start executing commands using the
// "SharedContextMutex", while existing Context will continue execute a command (or few) in
// parallel, because it is still using the "SingleContextMutex". Commands from new and old
// Contexts may access same shared state and cause undefined behaviour. So for a problem to
// happened, not only mutex replacement should fail (from the the point of view of existing
// Context), but also current and new Contexts must execute commands (right after mutex
// replacement) that both access shared state in a way that may cause undefined behaviour.
std::this_thread::sleep_for(std::chrono::microseconds(kActivationDelayMicro));
// Next, wait while "SingleContextMutex" is locked (until unlocked).
// In real-world applications this condition will almost always be "false"
while (mState.mSingleContextMutex->isLocked(std::memory_order_acquire))
{
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
// Finally, activate "SharedContextMutex".
mState.mIsSharedContextMutexActive = true;
}
ASSERT(getContextMutex() == mState.mSharedContextMutex);
return lock;
}
void Context::mergeSharedContextMutexes(egl::ContextMutex *otherMutex)
{
ASSERT(otherMutex != nullptr);
ASSERT(isSharedContextMutexActive());
egl::ContextMutexManager *mutexManager = mDisplay->getSharedContextMutexManager();
mutexManager->merge(mState.mSharedContextMutex, otherMutex);
}
void Context::eGLImageTargetTexStorage(GLenum target, egl::ImageID image, const GLint *attrib_list) void Context::eGLImageTargetTexStorage(GLenum target, egl::ImageID image, const GLint *attrib_list)
{ {
Texture *texture = getTextureByType(FromGLenum<TextureType>(target)); Texture *texture = getTextureByType(FromGLenum<TextureType>(target));

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

@ -37,6 +37,7 @@
#include "libANGLE/RefCountObject.h" #include "libANGLE/RefCountObject.h"
#include "libANGLE/ResourceManager.h" #include "libANGLE/ResourceManager.h"
#include "libANGLE/ResourceMap.h" #include "libANGLE/ResourceMap.h"
#include "libANGLE/SharedContextMutex.h"
#include "libANGLE/State.h" #include "libANGLE/State.h"
#include "libANGLE/VertexAttribute.h" #include "libANGLE/VertexAttribute.h"
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
@ -373,6 +374,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
const Context *shareContext, const Context *shareContext,
TextureManager *shareTextures, TextureManager *shareTextures,
SemaphoreManager *shareSemaphores, SemaphoreManager *shareSemaphores,
egl::ContextMutex *sharedContextMutex,
MemoryProgramCache *memoryProgramCache, MemoryProgramCache *memoryProgramCache,
MemoryShaderCache *memoryShaderCache, MemoryShaderCache *memoryShaderCache,
const EGLenum clientType, const EGLenum clientType,
@ -662,6 +664,27 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
egl::ShareGroup *getShareGroup() const { return mState.getShareGroup(); } egl::ShareGroup *getShareGroup() const { return mState.getShareGroup(); }
// Note: mutex may be changed during the API call, including from other thread.
egl::ContextMutex *getContextMutex() const
{
return mState.mContextMutex.load(std::memory_order_relaxed);
}
// For debugging purposes. "ContextMutex" MUST be locked during this call.
bool isSharedContextMutexActive() const;
// Important note:
// It is possible that this Context will continue to use "SingleContextMutex" in its current
// thread after this call. Probability of that is controlled by the "kActivationDelayMicro"
// constant. If problem happens or extra safety is critical - increase the
// "kActivationDelayMicro".
// For absolute 100% safety "SingleContextMutex" should not be used.
egl::ScopedContextMutexLock lockAndActivateSharedContextMutex();
// "SharedContextMutex" MUST be locked and active during this call.
// Merges "SharedContextMutex" of the Context with other "ShareContextMutex".
void mergeSharedContextMutexes(egl::ContextMutex *otherMutex);
bool supportsGeometryOrTesselation() const; bool supportsGeometryOrTesselation() const;
void dirtyAllState(); void dirtyAllState();

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

@ -91,6 +91,8 @@ namespace egl
namespace namespace
{ {
// Use standard mutex for now.
using ContextMutexType = std::mutex;
struct TLSData struct TLSData
{ {
@ -922,6 +924,7 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mDevice(eglDevice), mDevice(eglDevice),
mSurface(nullptr), mSurface(nullptr),
mPlatform(platform), mPlatform(platform),
mManagersMutex(nullptr),
mTextureManager(nullptr), mTextureManager(nullptr),
mSemaphoreManager(nullptr), mSemaphoreManager(nullptr),
mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes), mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
@ -1132,6 +1135,16 @@ Error Display::initialize()
mSingleThreadPool = angle::WorkerThreadPool::Create(1, ANGLEPlatformCurrent()); mSingleThreadPool = angle::WorkerThreadPool::Create(1, ANGLEPlatformCurrent());
mMultiThreadPool = angle::WorkerThreadPool::Create(0, ANGLEPlatformCurrent()); mMultiThreadPool = angle::WorkerThreadPool::Create(0, ANGLEPlatformCurrent());
if (kIsSharedContextMutexEnabled)
{
ASSERT(!mSharedContextMutexManager);
mSharedContextMutexManager.reset(new SharedContextMutexManager<ContextMutexType>());
ASSERT(mManagersMutex == nullptr);
mManagersMutex = mSharedContextMutexManager->create();
mManagersMutex->addRef();
}
mInitialized = true; mInitialized = true;
return NoError(); return NoError();
@ -1143,6 +1156,10 @@ Error Display::destroyInvalidEglObjects()
while (!mInvalidContextMap.empty()) while (!mInvalidContextMap.empty())
{ {
gl::Context *context = mInvalidContextMap.begin()->second; gl::Context *context = mInvalidContextMap.begin()->second;
// eglReleaseThread() may call to this method when there are still Contexts, that may
// potentially acces shared state of the "context".
// Need AddRefLock because there may be ContextMutex destruction.
ScopedContextMutexAddRefLock lock(context->getContextMutex());
context->setIsDestroyed(); context->setIsDestroyed();
ANGLE_TRY(releaseContextImpl(context, &mInvalidContextMap)); ANGLE_TRY(releaseContextImpl(context, &mInvalidContextMap));
} }
@ -1218,7 +1235,7 @@ Error Display::terminate(Thread *thread, TerminateReason terminateReason)
size_t contextSetSizeBeforeInvalidation = mState.contextMap.size() + mInvalidContextMap.size(); size_t contextSetSizeBeforeInvalidation = mState.contextMap.size() + mInvalidContextMap.size();
// If app called eglTerminate and no active threads remain, // If app called eglTerminate and no active threads remain,
// force realease any context that is still current. // force release any context that is still current.
ContextMap contextsStillCurrent = {}; ContextMap contextsStillCurrent = {};
for (auto context : mState.contextMap) for (auto context : mState.contextMap)
{ {
@ -1265,6 +1282,14 @@ Error Display::terminate(Thread *thread, TerminateReason terminateReason)
ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr); ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr); ASSERT(mGlobalSemaphoreShareGroupUsers == 0 && mSemaphoreManager == nullptr);
mSharedContextMutexManager.reset();
if (mManagersMutex != nullptr)
{
mManagersMutex->release();
mManagersMutex = nullptr;
}
// Clean up all invalid objects // Clean up all invalid objects
ANGLE_TRY(destroyInvalidEglObjects()); ANGLE_TRY(destroyInvalidEglObjects());
@ -1580,6 +1605,24 @@ Error Display::createContext(const Config *configuration,
shareSemaphores = mSemaphoreManager; shareSemaphores = mSemaphoreManager;
} }
ContextMutex *sharedContextMutex = nullptr;
if (kIsSharedContextMutexEnabled)
{
if (shareContext != nullptr)
{
ASSERT(shareContext->isSharedContextMutexActive());
sharedContextMutex = shareContext->getContextMutex();
}
else if (shareTextures != nullptr || shareSemaphores != nullptr)
{
sharedContextMutex = mManagersMutex;
}
// When using shareTextures/Semaphores all Contexts in the Group must use mManagersMutex.
ASSERT(mManagersMutex != nullptr);
ASSERT((shareTextures == nullptr && shareSemaphores == nullptr) ||
sharedContextMutex == mManagersMutex);
}
gl::MemoryProgramCache *programCachePointer = &mMemoryProgramCache; gl::MemoryProgramCache *programCachePointer = &mMemoryProgramCache;
// Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control. // Check context creation attributes to see if we are using EGL_ANGLE_program_cache_control.
// If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set // If not, keep caching enabled for EGL_ANDROID_blob_cache, which can have its callbacks set
@ -1603,9 +1646,10 @@ Error Display::createContext(const Config *configuration,
shaderCachePointer = nullptr; shaderCachePointer = nullptr;
} }
gl::Context *context = new gl::Context( gl::Context *context =
this, configuration, shareContext, shareTextures, shareSemaphores, programCachePointer, new gl::Context(this, configuration, shareContext, shareTextures, shareSemaphores,
shaderCachePointer, clientType, attribs, mDisplayExtensions, GetClientExtensions()); sharedContextMutex, programCachePointer, shaderCachePointer, clientType,
attribs, mDisplayExtensions, GetClientExtensions());
Error error = context->initialize(); Error error = context->initialize();
if (error.isError()) if (error.isError())
{ {
@ -1668,6 +1712,9 @@ Error Display::makeCurrent(Thread *thread,
bool contextChanged = context != previousContext; bool contextChanged = context != previousContext;
if (previousContext != nullptr && contextChanged) if (previousContext != nullptr && contextChanged)
{ {
// Need AddRefLock because there may be ContextMutex destruction.
ScopedContextMutexAddRefLock lock(previousContext->getContextMutex());
previousContext->release(); previousContext->release();
thread->setCurrent(nullptr); thread->setCurrent(nullptr);
@ -1681,16 +1728,22 @@ Error Display::makeCurrent(Thread *thread,
ANGLE_TRY(error); ANGLE_TRY(error);
} }
thread->setCurrent(context);
ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
if (context != nullptr)
{ {
ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface)); ASSERT(context == nullptr || context->getContextMutex() != nullptr);
if (contextChanged) ScopedContextMutexLock lock(context != nullptr ? context->getContextMutex() : nullptr,
kContextMutexMayBeNull);
thread->setCurrent(context);
ANGLE_TRY(mImplementation->makeCurrent(this, drawSurface, readSurface, context));
if (context != nullptr)
{ {
context->addRef(); ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
if (contextChanged)
{
context->addRef();
}
} }
} }
@ -1763,7 +1816,11 @@ void Display::destroyImageImpl(Image *image, ImageMap *images)
auto iter = images->find(image->id().value); auto iter = images->find(image->id().value);
ASSERT(iter != images->end()); ASSERT(iter != images->end());
mImageHandleAllocator.release(image->id().value); mImageHandleAllocator.release(image->id().value);
iter->second->release(this); {
// Need AddRefLock because there may be ContextMutex destruction.
ScopedContextMutexAddRefLock lock(image->getSharedContextMutex(), kContextMutexMayBeNull);
iter->second->release(this);
}
images->erase(iter); images->erase(iter);
} }
@ -1843,6 +1900,8 @@ Error Display::destroyContext(Thread *thread, gl::Context *context)
// make sure the native context is current. // make sure the native context is current.
if (context->isExternal()) if (context->isExternal())
{ {
// Need AddRefLock because there may be ContextMutex destruction.
ScopedContextMutexAddRefLock lock(context->getContextMutex());
ANGLE_TRY(releaseContext(context, thread)); ANGLE_TRY(releaseContext(context, thread));
} }
else else

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

@ -158,6 +158,11 @@ class Display final : public LabeledObject,
void addActiveThread(Thread *thread); void addActiveThread(Thread *thread);
void threadCleanup(Thread *thread); void threadCleanup(Thread *thread);
ContextMutexManager *getSharedContextMutexManager() const
{
return mSharedContextMutexManager.get();
}
static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap);
static Display *GetDisplayFromNativeDisplay(EGLenum platform, static Display *GetDisplayFromNativeDisplay(EGLenum platform,
EGLNativeDisplayType nativeDisplay, EGLNativeDisplayType nativeDisplay,
@ -427,8 +432,13 @@ class Display final : public LabeledObject,
EGLenum mPlatform; EGLenum mPlatform;
angle::LoggingAnnotator mAnnotator; angle::LoggingAnnotator mAnnotator;
std::unique_ptr<ContextMutexManager> mSharedContextMutexManager;
// mManagersMutex protects mTextureManager and mSemaphoreManager
ContextMutex *mManagersMutex;
gl::TextureManager *mTextureManager; gl::TextureManager *mTextureManager;
gl::SemaphoreManager *mSemaphoreManager; gl::SemaphoreManager *mSemaphoreManager;
BlobCache mBlobCache; BlobCache mBlobCache;
gl::MemoryProgramCache mMemoryProgramCache; gl::MemoryProgramCache mMemoryProgramCache;
gl::MemoryShaderCache mMemoryShaderCache; gl::MemoryShaderCache mMemoryShaderCache;

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

@ -315,6 +315,17 @@ Image::Image(rx::EGLImplFactory *factory,
ASSERT(mImplementation != nullptr); ASSERT(mImplementation != nullptr);
ASSERT(buffer != nullptr); ASSERT(buffer != nullptr);
if (kIsSharedContextMutexEnabled && context != nullptr)
{
ASSERT(context->isSharedContextMutexActive());
mSharedContextMutex = context->getContextMutex();
mSharedContextMutex->addRef();
}
else
{
mSharedContextMutex = nullptr;
}
mState.source->addImageSource(this); mState.source->addImageSource(this);
} }
@ -350,6 +361,12 @@ void Image::onDestroy(const Display *display)
Image::~Image() Image::~Image()
{ {
SafeDelete(mImplementation); SafeDelete(mImplementation);
if (mSharedContextMutex != nullptr)
{
mSharedContextMutex->release();
mSharedContextMutex = nullptr;
}
} }
void Image::setLabel(EGLLabelKHR label) void Image::setLabel(EGLLabelKHR label)

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

@ -33,6 +33,7 @@ namespace egl
{ {
class Image; class Image;
class Display; class Display;
class ContextMutex;
// Only currently Renderbuffers and Textures can be bound with images. This makes the relationship // Only currently Renderbuffers and Textures can be bound with images. This makes the relationship
// explicit, and also ensures that an image sibling can determine if it's been initialized or not, // explicit, and also ensures that an image sibling can determine if it's been initialized or not,
@ -201,6 +202,8 @@ class Image final : public RefCountObject, public LabeledObject
Error exportVkImage(void *vkImage, void *vkImageCreateInfo); Error exportVkImage(void *vkImage, void *vkImageCreateInfo);
ContextMutex *getSharedContextMutex() const { return mSharedContextMutex; }
private: private:
friend class ImageSibling; friend class ImageSibling;
@ -219,6 +222,8 @@ class Image final : public RefCountObject, public LabeledObject
bool mOrphanedAndNeedsInit; bool mOrphanedAndNeedsInit;
bool mIsTexturable = false; bool mIsTexturable = false;
bool mIsRenderable = false; bool mIsRenderable = false;
ContextMutex *mSharedContextMutex; // Reference counted
}; };
} // namespace egl } // namespace egl

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

@ -0,0 +1,362 @@
//
// 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.
//
// SharedContextMutex.cpp: Classes for protecting Shared Context access and EGLImage siblings.
#include "libANGLE/SharedContextMutex.h"
#include "common/system_utils.h"
namespace egl
{
namespace
{
bool CheckThreadIdCurrent(const std::atomic<angle::ThreadId> &threadId,
angle::ThreadId *currentThreadIdOut)
{
*currentThreadIdOut = angle::GetCurrentThreadId();
return (threadId.load(std::memory_order_relaxed) == *currentThreadIdOut);
}
bool TryUpdateThreadId(std::atomic<angle::ThreadId> *threadId,
angle::ThreadId oldThreadId,
angle::ThreadId newThreadId)
{
const bool ok = (threadId->load(std::memory_order_relaxed) == oldThreadId);
if (ok)
{
threadId->store(newThreadId, std::memory_order_relaxed);
}
return ok;
}
} // namespace
// ContextMutex
ContextMutex::~ContextMutex()
{
ASSERT(mRefCount == 0);
}
void ContextMutex::onDestroy(UnlockBehaviour unlockBehaviour)
{
if (unlockBehaviour == UnlockBehaviour::kUnlock)
{
unlock();
}
}
void ContextMutex::release(UnlockBehaviour unlockBehaviour)
{
ASSERT(isReferenced());
if (--mRefCount == 0)
{
onDestroy(unlockBehaviour);
delete this;
}
else if (unlockBehaviour == UnlockBehaviour::kUnlock)
{
unlock();
}
}
// ScopedContextMutexAddRefLock
void ScopedContextMutexAddRefLock::lock(ContextMutex *mutex)
{
ASSERT(mutex != nullptr);
ASSERT(mMutex == nullptr);
mMutex = mutex;
// lock() before addRef() - using mMutex as synchronization
mMutex->lock();
// This lock alone must not cause mutex destruction
ASSERT(mMutex->isReferenced());
mMutex->addRef();
}
// ScopedContextMutexLock
void ScopedContextMutexLock::lock(ContextMutex *mutex)
{
ASSERT(mutex != nullptr);
ASSERT(mMutex == nullptr);
mMutex = mutex;
mMutex->lock();
}
// SingleContextMutex
bool SingleContextMutex::try_lock()
{
UNREACHABLE();
return false;
}
void SingleContextMutex::lock()
{
mState.store(1, std::memory_order_relaxed);
}
void SingleContextMutex::unlock()
{
mState.store(0, std::memory_order_release);
}
// SharedContextMutex
template <class Mutex>
bool SharedContextMutex<Mutex>::try_lock()
{
SharedContextMutex *const root = getRoot();
return (root->doTryLock() != nullptr);
}
template <class Mutex>
void SharedContextMutex<Mutex>::lock()
{
SharedContextMutex *const root = getRoot();
(void)root->doLock();
}
template <class Mutex>
void SharedContextMutex<Mutex>::unlock()
{
SharedContextMutex *const root = getRoot();
// "root" is currently locked so "root->getRoot()" will return stable result.
ASSERT(root == root->getRoot());
root->doUnlock();
}
template <class Mutex>
ANGLE_INLINE SharedContextMutex<Mutex> *SharedContextMutex<Mutex>::doTryLock()
{
angle::ThreadId currentThreadId;
ASSERT(!CheckThreadIdCurrent(mOwnerThreadId, &currentThreadId));
if (mMutex.try_lock())
{
SharedContextMutex *const root = getRoot();
if (ANGLE_UNLIKELY(this != root))
{
// Unlock, so only the "stable root" mutex remains locked
mMutex.unlock();
SharedContextMutex *const lockedRoot = root->doTryLock();
ASSERT(lockedRoot == nullptr || lockedRoot == getRoot());
return lockedRoot;
}
ASSERT(TryUpdateThreadId(&mOwnerThreadId, angle::InvalidThreadId(), currentThreadId));
return this;
}
return nullptr;
}
template <class Mutex>
ANGLE_INLINE SharedContextMutex<Mutex> *SharedContextMutex<Mutex>::doLock()
{
angle::ThreadId currentThreadId;
ASSERT(!CheckThreadIdCurrent(mOwnerThreadId, &currentThreadId));
mMutex.lock();
SharedContextMutex *const root = getRoot();
if (ANGLE_UNLIKELY(this != root))
{
// Unlock, so only the "stable root" mutex remains locked
mMutex.unlock();
SharedContextMutex *const lockedRoot = root->doLock();
ASSERT(lockedRoot == getRoot());
return lockedRoot;
}
ASSERT(TryUpdateThreadId(&mOwnerThreadId, angle::InvalidThreadId(), currentThreadId));
return this;
}
template <class Mutex>
ANGLE_INLINE void SharedContextMutex<Mutex>::doUnlock()
{
ASSERT(
TryUpdateThreadId(&mOwnerThreadId, angle::GetCurrentThreadId(), angle::InvalidThreadId()));
mMutex.unlock();
}
template <class Mutex>
SharedContextMutex<Mutex>::SharedContextMutex()
: mRoot(this), mRank(0), mOwnerThreadId(angle::InvalidThreadId())
{}
template <class Mutex>
SharedContextMutex<Mutex>::~SharedContextMutex()
{
ASSERT(this == getRoot());
ASSERT(mOldRoots.empty());
ASSERT(mLeaves.empty());
}
template <class Mutex>
void SharedContextMutex<Mutex>::Merge(SharedContextMutex *lockedMutex,
SharedContextMutex *otherMutex)
{
ASSERT(lockedMutex != nullptr);
ASSERT(otherMutex != nullptr);
// Since lockedMutex is locked, its "root" pointer is stable.
SharedContextMutex *lockedRoot = lockedMutex->getRoot();
SharedContextMutex *otherLockedRoot = nullptr;
// Mutex merging will update the structure of both mutexes, therefore both mutexes must be
// locked before continuing. First mutex is already locked, need to lock the other mutex.
// Because other thread may perform merge with same mutexes reversed, we can't simply lock
// otherMutex - this may cause a deadlock. Additionally, otherMutex may have same "root" (same
// mutex or already merged), not only merging is unnecessary, but locking otherMutex will
// guarantee a deadlock.
for (;;)
{
// First, check that "root" of otherMutex is the same as "root" of lockedMutex.
// lockedRoot is stable by definition and it is safe to compare with "unstable root".
SharedContextMutex *otherRoot = otherMutex->getRoot();
if (otherRoot == lockedRoot)
{
// Do nothing if two mutexes are the same/merged.
return;
}
// Second, try to lock otherMutex "root" (can't use lock()/doLock(), see above comment).
otherLockedRoot = otherRoot->doTryLock();
if (otherLockedRoot != nullptr)
{
// otherMutex "root" can't become lockedMutex "root". For that to happen, lockedMutex
// must be locked from some other thread first, which is impossible, since it is already
// locked by this thread.
ASSERT(otherLockedRoot != lockedRoot);
// Lock is successful. Both mutexes are locked - can proceed with the merge...
break;
}
// Lock was unsuccessful - unlock and retry...
// May use "doUnlock()" because lockedRoot is a "stable root" mutex.
lockedRoot->doUnlock();
// Sleep random amount to allow one of the thread acquire the lock next time...
std::this_thread::sleep_for(std::chrono::microseconds(rand() % 91 + 10));
// Because lockedMutex was unlocked, its "root" might have been changed. Below line will
// reacquire the lock and update lockedRoot pointer.
lockedRoot = lockedRoot->getRoot()->doLock();
}
// Mutexes that are not reference counted is not supported.
ASSERT(lockedRoot->isReferenced());
ASSERT(otherLockedRoot->isReferenced());
// Decide the new "root". See mRank comment for more details...
// Make "otherLockedRoot" the root of the "merged" mutex
if (lockedRoot->mRank > otherLockedRoot->mRank)
{
// So the "lockedRoot" is lower rank.
std::swap(lockedRoot, otherLockedRoot);
}
else if (lockedRoot->mRank == otherLockedRoot->mRank)
{
++otherLockedRoot->mRank;
}
// Update the structure
for (SharedContextMutex *const leaf : lockedRoot->mLeaves)
{
ASSERT(leaf->getRoot() == lockedRoot);
leaf->setNewRoot(otherLockedRoot);
}
lockedRoot->mLeaves.clear();
lockedRoot->setNewRoot(otherLockedRoot);
// Leave only the "merged" mutex locked. "lockedRoot" already merged, need to use "doUnlock()"
lockedRoot->doUnlock();
}
template <class Mutex>
void SharedContextMutex<Mutex>::setNewRoot(SharedContextMutex *newRoot)
{
SharedContextMutex *const oldRoot = getRoot();
ASSERT(newRoot != oldRoot);
mRoot.store(newRoot, std::memory_order_relaxed);
newRoot->addRef();
newRoot->addLeaf(this);
if (oldRoot != this)
{
mOldRoots.emplace_back(oldRoot);
}
}
template <class Mutex>
void SharedContextMutex<Mutex>::addLeaf(SharedContextMutex *leaf)
{
ASSERT(this == getRoot());
ASSERT(leaf->getRoot() == this);
ASSERT(leaf->mLeaves.empty());
ASSERT(mLeaves.count(leaf) == 0);
mLeaves.emplace(leaf);
}
template <class Mutex>
void SharedContextMutex<Mutex>::removeLeaf(SharedContextMutex *leaf)
{
ASSERT(this == getRoot());
ASSERT(leaf->getRoot() == this);
ASSERT(leaf->mLeaves.empty());
ASSERT(mLeaves.count(leaf) == 1);
mLeaves.erase(leaf);
}
template <class Mutex>
void SharedContextMutex<Mutex>::onDestroy(UnlockBehaviour unlockBehaviour)
{
ASSERT(mRefCount == 0);
ASSERT(mLeaves.empty());
SharedContextMutex *const root = getRoot();
if (this == root)
{
ASSERT(mOldRoots.empty());
if (unlockBehaviour == UnlockBehaviour::kUnlock)
{
doUnlock();
}
}
else
{
for (SharedContextMutex *oldRoot : mOldRoots)
{
ASSERT(oldRoot->getRoot() == root);
ASSERT(oldRoot->mLeaves.empty());
oldRoot->release();
}
mOldRoots.clear();
root->removeLeaf(this);
root->release(unlockBehaviour);
mRoot.store(this, std::memory_order_relaxed);
}
}
template class SharedContextMutex<std::mutex>;
// SharedContextMutexManager
template <class Mutex>
ContextMutex *SharedContextMutexManager<Mutex>::create()
{
return new SharedContextMutex<Mutex>();
}
template <class Mutex>
void SharedContextMutexManager<Mutex>::merge(ContextMutex *lockedMutex, ContextMutex *otherMutex)
{
SharedContextMutex<Mutex>::Merge(static_cast<SharedContextMutex<Mutex> *>(lockedMutex),
static_cast<SharedContextMutex<Mutex> *>(otherMutex));
}
template <class Mutex>
ContextMutex *SharedContextMutexManager<Mutex>::getRootMutex(ContextMutex *mutex)
{
return static_cast<SharedContextMutex<Mutex> *>(mutex)->getRoot();
}
template class SharedContextMutexManager<std::mutex>;
} // namespace egl

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

@ -0,0 +1,263 @@
//
// 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.
//
// SharedContextMutex.h: Classes for protecting Shared Context access and EGLImage siblings.
#ifndef LIBANGLE_SHARED_CONTEXT_MUTEX_H_
#define LIBANGLE_SHARED_CONTEXT_MUTEX_H_
#include <atomic>
#include "common/debug.h"
namespace egl
{
#if defined(ANGLE_ENABLE_SHARED_CONTEXT_MUTEX)
constexpr bool kIsSharedContextMutexEnabled = true;
#else
constexpr bool kIsSharedContextMutexEnabled = false;
#endif
class ContextMutex : angle::NonCopyable
{
public:
// Below group of methods are not thread safe and requires external synchronization.
// Note: since release*() may call onDestroy(), additional synchronization requirements may be
// enforced by concrete implementations.
ANGLE_INLINE void addRef() { ++mRefCount; }
ANGLE_INLINE void release() { release(UnlockBehaviour::kNotUnlock); }
ANGLE_INLINE void releaseAndUnlock() { release(UnlockBehaviour::kUnlock); }
ANGLE_INLINE bool isReferenced() const { return mRefCount > 0; }
virtual bool try_lock() = 0;
virtual void lock() = 0;
virtual void unlock() = 0;
protected:
virtual ~ContextMutex();
enum class UnlockBehaviour
{
kNotUnlock,
kUnlock
};
void release(UnlockBehaviour unlockBehaviour);
virtual void onDestroy(UnlockBehaviour unlockBehaviour);
protected:
size_t mRefCount = 0;
};
struct ContextMutexMayBeNullTag final
{};
constexpr ContextMutexMayBeNullTag kContextMutexMayBeNull;
// Prevents destruction while locked, uses mMutex to protect addRef()/releaseAndUnlock() calls.
class [[nodiscard]] ScopedContextMutexAddRefLock final : angle::NonCopyable
{
public:
ANGLE_INLINE ScopedContextMutexAddRefLock() = default;
ANGLE_INLINE explicit ScopedContextMutexAddRefLock(ContextMutex *mutex) { lock(mutex); }
ANGLE_INLINE ScopedContextMutexAddRefLock(ContextMutex *mutex, ContextMutexMayBeNullTag)
{
if (mutex != nullptr)
{
lock(mutex);
}
}
ANGLE_INLINE ~ScopedContextMutexAddRefLock()
{
if (mMutex != nullptr)
{
mMutex->releaseAndUnlock();
}
}
private:
void lock(ContextMutex *mutex);
private:
ContextMutex *mMutex = nullptr;
};
class [[nodiscard]] ScopedContextMutexLock final
{
public:
ANGLE_INLINE ScopedContextMutexLock() = default;
ANGLE_INLINE explicit ScopedContextMutexLock(ContextMutex *mutex) { lock(mutex); }
ANGLE_INLINE ScopedContextMutexLock(ContextMutex *mutex, ContextMutexMayBeNullTag)
{
if (mutex != nullptr)
{
lock(mutex);
}
}
ANGLE_INLINE ~ScopedContextMutexLock()
{
if (mMutex != nullptr)
{
mMutex->unlock();
}
}
ANGLE_INLINE ScopedContextMutexLock(ScopedContextMutexLock &&other) : mMutex(other.mMutex)
{
other.mMutex = nullptr;
}
ANGLE_INLINE ScopedContextMutexLock &operator=(ScopedContextMutexLock &&other)
{
std::swap(mMutex, other.mMutex);
return *this;
}
private:
void lock(ContextMutex *mutex);
private:
ContextMutex *mMutex = nullptr;
};
// Mutex may be locked only by a single thread. Other threads may only check the status.
class SingleContextMutex final : public ContextMutex
{
public:
ANGLE_INLINE bool isLocked(std::memory_order order) const { return mState.load(order) != 0; }
// ContextMutex
bool try_lock() override;
void lock() override;
void unlock() override;
private:
std::atomic_int mState{0};
};
// Note: onDestroy() method must be protected by "this" mutex, since onDestroy() is called from
// release*() methods, these methods must also be protected by "this" mutex.
template <class Mutex>
class SharedContextMutex final : public ContextMutex
{
public:
SharedContextMutex();
~SharedContextMutex() override;
// Merges mutexes so they work as one.
// At the end, only single "root" mutex will be locked.
// Does nothing if two mutexes are the same or already merged (have same "root" mutex).
// Note: synchronization requirements for addRef()/release*() calls for merged mutexes are
// the same as for the single unmerged mutex. For example: can't call at the same time
// mutexA.addRef() and mutexB.release() if they are merged.
static void Merge(SharedContextMutex *lockedMutex, SharedContextMutex *otherMutex);
// Returns current "root" mutex.
// Warning! Result is only stable if mutex is locked, while may change any time if unlocked.
// May be used to compare against already locked "root" mutex.
ANGLE_INLINE SharedContextMutex *getRoot() { return mRoot.load(std::memory_order_relaxed); }
// ContextMutex
bool try_lock() override;
void lock() override;
void unlock() override;
private:
SharedContextMutex *doTryLock();
SharedContextMutex *doLock();
void doUnlock();
// All methods below must be protected by "this" mutex ("stable root" in "this" instance).
void setNewRoot(SharedContextMutex *newRoot);
void addLeaf(SharedContextMutex *leaf);
void removeLeaf(SharedContextMutex *leaf);
// ContextMutex
void onDestroy(UnlockBehaviour unlockBehaviour) override;
private:
Mutex mMutex;
// mRoot and mLeaves tree structure details:
// - used to implement primary functionality of this class;
// - initially, all mutexes are "root"s;
// - "root" mutex has "mRoot == this";
// - "root" mutex stores unreferenced pointers to all its leaves (used in merging);
// - "leaf" mutex holds reference (addRef) to the current "root" mutex in the mRoot;
// - "leaf" mutex has empty mLeaves;
// - "leaf" mutex can't become a "root" mutex;
// - before locking the mMutex, "this" is an "unstable root" or a "leaf";
// - the implementation always locks mRoot's mMutex ("unstable root");
// - if after locking the mMutex "mRoot != this", then "this" is/become a "leaf";
// - otherwise, "this" is a locked "stable root" - lock is successful.
std::atomic<SharedContextMutex *> mRoot;
std::set<SharedContextMutex *> mLeaves;
// mOldRoots is used to solve a particular problem (below example does not use mRank):
// - have "leaf" mutex_2 with a reference to mutex_1 "root";
// - the mutex_1 has no other references (only in the mutex_2);
// - have other mutex_3 "root";
// - mutex_1 pointer is cached on the stack during locking of mutex_2 (thread A);
// - marge mutex_2 and mutex_3 (thread B):
// * now "leaf" mutex_2 stores reference to mutex_3 "root";
// * old "root" mutex_1 becomes a "leaf" of mutex_3;
// * old "root" mutex_1 has no references and gets destroyed.
// - invalid pointer to destroyed mutex_1 stored on the stack and in the mLeaves of mutex_3;
// - to fix this problem, references to old "root"s are kept in the mOldRoots vector.
std::vector<SharedContextMutex *> mOldRoots;
// mRank is used to fix a problem of indefinite grows of mOldRoots:
// - merge mutex_1 and mutex_2 -> mutex_2 is "root" of mutex_1 (mOldRoots == 0);
// - destroy mutex_2;
// - merge mutex_1 and mutex_3 -> mutex_3 is "root" of mutex_1 (mOldRoots == 1);
// - destroy mutex_3;
// - merge mutex_1 and mutex_4 -> mutex_4 is "root" of mutex_1 (mOldRoots == 2);
// - destroy mutex_4;
// - continuing this pattern can lead to indefinite grows of mOldRoots, while pick number of
// mutexes is only 2.
// Fix details using mRank:
// - initially "mRank == 0" and only relevant for "root" mutexes;
// - merging mutexes with equal mRank of their "root"s, will use second (otherMutex) "root"
// mutex as a new "root" and increase its mRank by 1;
// - otherwise, "root" mutex with a highest rank will be used without changing the mRank;
// - this way, "stronger" (with a higher mRank) "root" mutex will "protect" its "leaves" from
// "mRoot" replacement and therefore - mOldRoots grows.
// Lets look at the problematic pattern with the mRank:
// - merge mutex_1 and mutex_2 -> mutex_2 is "root" (mRank == 1) of mutex_1 (mOldRoots == 0);
// - destroy mutex_2;
// - merge mutex_1 and mutex_3 -> mutex_2 is "root" (mRank == 1) of mutex_3 (mOldRoots == 0);
// - destroy mutex_3;
// - merge mutex_1 and mutex_4 -> mutex_2 is "root" (mRank == 1) of mutex_4 (mOldRoots == 0);
// - destroy mutex_4;
// - no mOldRoots grows at all;
// - minumum number of mutexes to reach mOldRoots size of N => 2^(N+1).
uint32_t mRank;
// Only used when ASSERT() is enabled.
std::atomic<angle::ThreadId> mOwnerThreadId;
};
class ContextMutexManager
{
public:
virtual ~ContextMutexManager() = default;
virtual ContextMutex *create() = 0;
virtual void merge(ContextMutex *lockedMutex, ContextMutex *otherMutex) = 0;
virtual ContextMutex *getRootMutex(ContextMutex *mutex) = 0;
};
template <class Mutex>
class SharedContextMutexManager final : public ContextMutexManager
{
public:
ContextMutex *create() override;
void merge(ContextMutex *lockedMutex, ContextMutex *otherMutex) override;
ContextMutex *getRootMutex(ContextMutex *mutex) override;
};
} // namespace egl
#endif // LIBANGLE_SHARED_CONTEXT_MUTEX_H_

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

@ -333,6 +333,8 @@ State::State(const State *shareContextState,
egl::ShareGroup *shareGroup, egl::ShareGroup *shareGroup,
TextureManager *shareTextures, TextureManager *shareTextures,
SemaphoreManager *shareSemaphores, SemaphoreManager *shareSemaphores,
egl::ContextMutex *sharedContextMutex,
egl::SingleContextMutex *singleContextMutex,
const OverlayType *overlay, const OverlayType *overlay,
const EGLenum clientType, const EGLenum clientType,
const Version &clientVersion, const Version &clientVersion,
@ -354,6 +356,10 @@ State::State(const State *shareContextState,
mIsDebugContext(debug), mIsDebugContext(debug),
mClientVersion(clientVersion), mClientVersion(clientVersion),
mShareGroup(shareGroup), mShareGroup(shareGroup),
mSharedContextMutex(sharedContextMutex),
mSingleContextMutex(singleContextMutex),
mContextMutex(singleContextMutex == nullptr ? sharedContextMutex : singleContextMutex),
mIsSharedContextMutexActive(singleContextMutex == nullptr),
mBufferManager(AllocateOrGetSharedResourceManager(shareContextState, &State::mBufferManager)), mBufferManager(AllocateOrGetSharedResourceManager(shareContextState, &State::mBufferManager)),
mShaderProgramManager( mShaderProgramManager(
AllocateOrGetSharedResourceManager(shareContextState, &State::mShaderProgramManager)), AllocateOrGetSharedResourceManager(shareContextState, &State::mShaderProgramManager)),

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

@ -33,6 +33,8 @@
namespace egl namespace egl
{ {
class ShareGroup; class ShareGroup;
class ContextMutex;
class SingleContextMutex;
} // namespace egl } // namespace egl
namespace gl namespace gl
@ -91,6 +93,8 @@ class State : angle::NonCopyable
egl::ShareGroup *shareGroup, egl::ShareGroup *shareGroup,
TextureManager *shareTextures, TextureManager *shareTextures,
SemaphoreManager *shareSemaphores, SemaphoreManager *shareSemaphores,
egl::ContextMutex *sharedContextMutex,
egl::SingleContextMutex *singleContextMutex,
const OverlayType *overlay, const OverlayType *overlay,
const EGLenum clientType, const EGLenum clientType,
const Version &clientVersion, const Version &clientVersion,
@ -1060,6 +1064,10 @@ class State : angle::NonCopyable
Limitations mLimitations; Limitations mLimitations;
egl::ShareGroup *mShareGroup; egl::ShareGroup *mShareGroup;
egl::ContextMutex *const mSharedContextMutex;
egl::SingleContextMutex *const mSingleContextMutex;
std::atomic<egl::ContextMutex *> mContextMutex; // Simple pointer without reference counting
bool mIsSharedContextMutexActive;
// Resource managers. // Resource managers.
BufferManager *mBufferManager; BufferManager *mBufferManager;

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

@ -8261,7 +8261,7 @@ void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
const gl::State &contextState = mainContext->getState(); const gl::State &contextState = mainContext->getState();
gl::State mainContextReplayState( gl::State mainContextReplayState(
nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientType(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientType(),
contextState.getClientVersion(), contextState.getProfileMask(), false, true, true, true, contextState.getClientVersion(), contextState.getProfileMask(), false, true, true, true,
false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG, contextState.hasRobustAccess(), false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG, contextState.hasRobustAccess(),
contextState.hasProtectedContent()); contextState.hasProtectedContent());
@ -8308,10 +8308,11 @@ void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
{ {
const gl::State &shareContextState = shareContext.second->getState(); const gl::State &shareContextState = shareContext.second->getState();
gl::State auxContextReplayState( gl::State auxContextReplayState(
nullptr, nullptr, nullptr, nullptr, nullptr, shareContextState.getClientType(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
shareContextState.getClientVersion(), shareContextState.getProfileMask(), false, shareContextState.getClientType(), shareContextState.getClientVersion(),
true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG, shareContextState.getProfileMask(), false, true, true, true, false,
shareContextState.hasRobustAccess(), shareContextState.hasProtectedContent()); EGL_CONTEXT_PRIORITY_MEDIUM_IMG, shareContextState.hasRobustAccess(),
shareContextState.hasProtectedContent());
auxContextReplayState.initializeForCapture(shareContext.second); auxContextReplayState.initializeForCapture(shareContext.second);
egl::Error error = shareContext.second->makeCurrent(display, draw, read); egl::Error error = shareContext.second->makeCurrent(display, draw, read);

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

@ -816,6 +816,7 @@ void CaptureEGLCallToFrameCapture(CaptureFuncT captureFunc,
{ {
return; return;
} }
std::lock_guard<egl::ContextMutex> lock(*context->getContextMutex());
angle::FrameCaptureShared *frameCaptureShared = angle::FrameCaptureShared *frameCaptureShared =
context->getShareGroup()->getFrameCaptureShared(); context->getShareGroup()->getFrameCaptureShared();

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

@ -2371,12 +2371,14 @@ const Display *GetDisplayIfValid(const Display *display)
const Surface *GetSurfaceIfValid(const Display *display, SurfaceID surfaceID) const Surface *GetSurfaceIfValid(const Display *display, SurfaceID surfaceID)
{ {
return ValidateSurface(nullptr, display, surfaceID) ? display->getSurface(surfaceID) : nullptr; // display->getSurface() - validates surfaceID
return ValidateDisplay(nullptr, display) ? display->getSurface(surfaceID) : nullptr;
} }
const Image *GetImageIfValid(const Display *display, ImageID imageID) const Image *GetImageIfValid(const Display *display, ImageID imageID)
{ {
return ValidateImage(nullptr, display, imageID) ? display->getImage(imageID) : nullptr; // display->getImage() - validates imageID
return ValidateDisplay(nullptr, display) ? display->getImage(imageID) : nullptr;
} }
const Stream *GetStreamIfValid(const Display *display, const Stream *stream) const Stream *GetStreamIfValid(const Display *display, const Stream *stream)
@ -2386,7 +2388,13 @@ const Stream *GetStreamIfValid(const Display *display, const Stream *stream)
const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID) const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID)
{ {
return ValidateContext(nullptr, display, contextID) ? display->getContext(contextID) : nullptr; // display->getContext() - validates contextID
return ValidateDisplay(nullptr, display) ? display->getContext(contextID) : nullptr;
}
gl::Context *GetContextIfValid(Display *display, gl::ContextID contextID)
{
return ValidateDisplay(nullptr, display) ? display->getContext(contextID) : nullptr;
} }
const Device *GetDeviceIfValid(const Device *device) const Device *GetDeviceIfValid(const Device *device)
@ -2396,7 +2404,8 @@ const Device *GetDeviceIfValid(const Device *device)
const Sync *GetSyncIfValid(const Display *display, SyncID syncID) const Sync *GetSyncIfValid(const Display *display, SyncID syncID)
{ {
return ValidateSync(nullptr, display, syncID) ? display->getSync(syncID) : nullptr; // display->getSync() - validates syncID
return ValidateDisplay(nullptr, display) ? display->getSync(syncID) : nullptr;
} }
const LabeledObject *GetLabeledObjectIfValid(Thread *thread, const LabeledObject *GetLabeledObjectIfValid(Thread *thread,

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

@ -70,6 +70,7 @@ const Surface *GetSurfaceIfValid(const Display *display, SurfaceID surfaceID);
const Image *GetImageIfValid(const Display *display, ImageID imageID); const Image *GetImageIfValid(const Display *display, ImageID imageID);
const Stream *GetStreamIfValid(const Display *display, const Stream *stream); const Stream *GetStreamIfValid(const Display *display, const Stream *stream);
const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID); const gl::Context *GetContextIfValid(const Display *display, gl::ContextID contextID);
gl::Context *GetContextIfValid(Display *display, gl::ContextID contextID);
const Device *GetDeviceIfValid(const Device *device); const Device *GetDeviceIfValid(const Device *device);
const Sync *GetSyncIfValid(const Display *display, SyncID sync); const Sync *GetSyncIfValid(const Display *display, SyncID sync);
const LabeledObject *GetLabeledObjectIfValid(Thread *thread, const LabeledObject *GetLabeledObjectIfValid(Thread *thread,

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

@ -298,6 +298,7 @@ libangle_headers = [
"src/libANGLE/Sampler.h", "src/libANGLE/Sampler.h",
"src/libANGLE/Semaphore.h", "src/libANGLE/Semaphore.h",
"src/libANGLE/Shader.h", "src/libANGLE/Shader.h",
"src/libANGLE/SharedContextMutex.h",
"src/libANGLE/SizedMRUCache.h", "src/libANGLE/SizedMRUCache.h",
"src/libANGLE/State.h", "src/libANGLE/State.h",
"src/libANGLE/Stream.h", "src/libANGLE/Stream.h",
@ -430,6 +431,7 @@ libangle_sources = [
"src/libANGLE/Sampler.cpp", "src/libANGLE/Sampler.cpp",
"src/libANGLE/Semaphore.cpp", "src/libANGLE/Semaphore.cpp",
"src/libANGLE/Shader.cpp", "src/libANGLE/Shader.cpp",
"src/libANGLE/SharedContextMutex.cpp",
"src/libANGLE/State.cpp", "src/libANGLE/State.cpp",
"src/libANGLE/Stream.cpp", "src/libANGLE/Stream.cpp",
"src/libANGLE/Surface.cpp", "src/libANGLE/Surface.cpp",
@ -615,6 +617,8 @@ libangle_capture_sources = [
] ]
libglesv2_sources = [ libglesv2_sources = [
"src/libGLESv2/egl_context_lock_autogen.h",
"src/libGLESv2/egl_context_lock_impl.h",
"src/libGLESv2/egl_ext_stubs.cpp", "src/libGLESv2/egl_ext_stubs.cpp",
"src/libGLESv2/egl_ext_stubs_autogen.h", "src/libGLESv2/egl_ext_stubs_autogen.h",
"src/libGLESv2/egl_stubs.cpp", "src/libGLESv2/egl_stubs.cpp",

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

@ -0,0 +1,281 @@
// GENERATED FILE - DO NOT EDIT.
// Generated by generate_entry_points.py using data from egl.xml and egl_angle_ext.xml.
//
// 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.
//
// egl_context_lock_autogen.h:
// Context Lock functions for the EGL entry points.
#ifndef LIBGLESV2_EGL_CONTEXT_LOCK_AUTOGEN_H_
#define LIBGLESV2_EGL_CONTEXT_LOCK_AUTOGEN_H_
#include "libGLESv2/global_state.h"
namespace egl
{
// EGL 1.0
ScopedContextMutexLock GetContextLock_ChooseConfig(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CopyBuffers(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreateContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID share_contextPacked);
ScopedContextMutexLock GetContextLock_CreatePbufferSurface(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreatePixmapSurface(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreateWindowSurface(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_DestroyContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_DestroySurface(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetConfigAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_GetConfigs(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetCurrentDisplay(Thread *thread);
ScopedContextMutexLock GetContextLock_GetCurrentSurface(Thread *thread);
ScopedContextMutexLock GetContextLock_GetDisplay(Thread *thread);
ScopedContextMutexLock GetContextLock_GetError(Thread *thread);
ScopedContextMutexLock GetContextLock_GetProcAddress(Thread *thread);
ScopedContextMutexLock GetContextLock_Initialize(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_MakeCurrent(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_QueryContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_QueryString(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QuerySurface(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_SwapBuffers(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_Terminate(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_WaitGL(Thread *thread);
ScopedContextMutexLock GetContextLock_WaitNative(Thread *thread);
// EGL 1.1
ScopedContextMutexLock GetContextLock_BindTexImage(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_ReleaseTexImage(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_SurfaceAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_SwapInterval(Thread *thread, egl::Display *dpyPacked);
// EGL 1.2
ScopedContextMutexLock GetContextLock_BindAPI(Thread *thread);
ScopedContextMutexLock GetContextLock_CreatePbufferFromClientBuffer(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QueryAPI(Thread *thread);
ScopedContextMutexLock GetContextLock_ReleaseThread(Thread *thread);
ScopedContextMutexLock GetContextLock_WaitClient(Thread *thread);
// EGL 1.4
ScopedContextMutexLock GetContextLock_GetCurrentContext(Thread *thread);
// EGL 1.5
ScopedContextMutexLock GetContextLock_ClientWaitSync(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreateImage(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_CreatePlatformPixmapSurface(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreatePlatformWindowSurface(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreateSync(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_DestroyImage(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_DestroySync(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetPlatformDisplay(Thread *thread);
ScopedContextMutexLock GetContextLock_GetSyncAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_WaitSync(Thread *thread, egl::Display *dpyPacked);
// EGL_ANDROID_blob_cache
ScopedContextMutexLock GetContextLock_SetBlobCacheFuncsANDROID(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANDROID_create_native_client_buffer
ScopedContextMutexLock GetContextLock_CreateNativeClientBufferANDROID(Thread *thread);
// EGL_ANDROID_get_frame_timestamps
ScopedContextMutexLock GetContextLock_GetCompositorTimingSupportedANDROID(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetCompositorTimingANDROID(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetNextFrameIdANDROID(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetFrameTimestampSupportedANDROID(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetFrameTimestampsANDROID(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANDROID_get_native_client_buffer
ScopedContextMutexLock GetContextLock_GetNativeClientBufferANDROID(Thread *thread);
// EGL_ANDROID_native_fence_sync
ScopedContextMutexLock GetContextLock_DupNativeFenceFDANDROID(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANDROID_presentation_time
ScopedContextMutexLock GetContextLock_PresentationTimeANDROID(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_device_creation
ScopedContextMutexLock GetContextLock_CreateDeviceANGLE(Thread *thread);
ScopedContextMutexLock GetContextLock_ReleaseDeviceANGLE(Thread *thread);
// EGL_ANGLE_feature_control
ScopedContextMutexLock GetContextLock_QueryStringiANGLE(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QueryDisplayAttribANGLE(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
// EGL_ANGLE_metal_shared_event_sync
ScopedContextMutexLock GetContextLock_CopyMetalSharedEventANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_power_preference
ScopedContextMutexLock GetContextLock_ReleaseHighPowerGPUANGLE(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_ReacquireHighPowerGPUANGLE(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_HandleGPUSwitchANGLE(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_ForceGPUSwitchANGLE(Thread *thread, egl::Display *dpyPacked);
// EGL_ANGLE_prepare_swap_buffers
ScopedContextMutexLock GetContextLock_PrepareSwapBuffersANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_program_cache_control
ScopedContextMutexLock GetContextLock_ProgramCacheGetAttribANGLE(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_ProgramCacheQueryANGLE(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_ProgramCachePopulateANGLE(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_ProgramCacheResizeANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_query_surface_pointer
ScopedContextMutexLock GetContextLock_QuerySurfacePointerANGLE(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
// EGL_ANGLE_stream_producer_d3d_texture
ScopedContextMutexLock GetContextLock_CreateStreamProducerD3DTextureANGLE(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_StreamPostD3DTextureANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_swap_with_frame_token
ScopedContextMutexLock GetContextLock_SwapBuffersWithFrameTokenANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_ANGLE_sync_control_rate
ScopedContextMutexLock GetContextLock_GetMscRateANGLE(Thread *thread, egl::Display *dpyPacked);
// EGL_ANGLE_vulkan_image
ScopedContextMutexLock GetContextLock_ExportVkImageANGLE(Thread *thread, egl::Display *dpyPacked);
// EGL_ANGLE_wait_until_work_scheduled
ScopedContextMutexLock GetContextLock_WaitUntilWorkScheduledANGLE(Thread *thread,
egl::Display *dpyPacked);
// EGL_CHROMIUM_sync_control
ScopedContextMutexLock GetContextLock_GetSyncValuesCHROMIUM(Thread *thread,
egl::Display *dpyPacked);
// EGL_EXT_device_query
ScopedContextMutexLock GetContextLock_QueryDeviceAttribEXT(Thread *thread, EGLint attribute);
ScopedContextMutexLock GetContextLock_QueryDeviceStringEXT(Thread *thread);
ScopedContextMutexLock GetContextLock_QueryDisplayAttribEXT(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
// EGL_EXT_image_dma_buf_import_modifiers
ScopedContextMutexLock GetContextLock_QueryDmaBufFormatsEXT(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QueryDmaBufModifiersEXT(Thread *thread,
egl::Display *dpyPacked);
// EGL_EXT_platform_base
ScopedContextMutexLock GetContextLock_CreatePlatformPixmapSurfaceEXT(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreatePlatformWindowSurfaceEXT(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetPlatformDisplayEXT(Thread *thread);
// EGL_KHR_debug
ScopedContextMutexLock GetContextLock_DebugMessageControlKHR(Thread *thread);
ScopedContextMutexLock GetContextLock_LabelObjectKHR(Thread *thread, egl::Display *displayPacked);
ScopedContextMutexLock GetContextLock_QueryDebugKHR(Thread *thread, EGLint attribute);
// EGL_KHR_fence_sync
ScopedContextMutexLock GetContextLock_ClientWaitSyncKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_CreateSyncKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_DestroySyncKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_GetSyncAttribKHR(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
// EGL_KHR_image
ScopedContextMutexLock GetContextLock_CreateImageKHR(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked);
ScopedContextMutexLock GetContextLock_DestroyImageKHR(Thread *thread, egl::Display *dpyPacked);
// EGL_KHR_lock_surface3
ScopedContextMutexLock GetContextLock_LockSurfaceKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QuerySurface64KHR(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute);
ScopedContextMutexLock GetContextLock_UnlockSurfaceKHR(Thread *thread, egl::Display *dpyPacked);
// EGL_KHR_partial_update
ScopedContextMutexLock GetContextLock_SetDamageRegionKHR(Thread *thread, egl::Display *dpyPacked);
// EGL_KHR_reusable_sync
ScopedContextMutexLock GetContextLock_SignalSyncKHR(Thread *thread, egl::Display *dpyPacked);
// EGL_KHR_stream
ScopedContextMutexLock GetContextLock_CreateStreamKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_DestroyStreamKHR(Thread *thread, egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_QueryStreamKHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute);
ScopedContextMutexLock GetContextLock_QueryStreamu64KHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute);
ScopedContextMutexLock GetContextLock_StreamAttribKHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute);
// EGL_KHR_stream_consumer_gltexture
ScopedContextMutexLock GetContextLock_StreamConsumerAcquireKHR(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_StreamConsumerGLTextureExternalKHR(Thread *thread,
egl::Display *dpyPacked);
ScopedContextMutexLock GetContextLock_StreamConsumerReleaseKHR(Thread *thread,
egl::Display *dpyPacked);
// EGL_KHR_swap_buffers_with_damage
ScopedContextMutexLock GetContextLock_SwapBuffersWithDamageKHR(Thread *thread,
egl::Display *dpyPacked);
// EGL_KHR_wait_sync
ScopedContextMutexLock GetContextLock_WaitSyncKHR(Thread *thread, egl::Display *dpyPacked);
// EGL_NV_post_sub_buffer
ScopedContextMutexLock GetContextLock_PostSubBufferNV(Thread *thread, egl::Display *dpyPacked);
// EGL_NV_stream_consumer_gltexture_yuv
ScopedContextMutexLock GetContextLock_StreamConsumerGLTextureExternalAttribsNV(
Thread *thread,
egl::Display *dpyPacked);
} // namespace egl
#endif // LIBGLESV2_EGL_CONTEXT_LOCK_AUTOGEN_H_

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

@ -0,0 +1,741 @@
//
// 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.
//
// egl_context_lock_autogen.h:
// Context Lock functions for the EGL entry points.
#ifndef LIBGLESV2_EGL_CONTEXT_LOCK_IMPL_H_
#define LIBGLESV2_EGL_CONTEXT_LOCK_IMPL_H_
#include "libGLESv2/egl_context_lock_autogen.h"
namespace egl
{
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ChooseConfig(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CopyBuffers(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID share_contextPacked)
{
return TryLockAndActivateSharedContextMutex(dpyPacked, share_contextPacked);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreatePbufferSurface(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreatePixmapSurface(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateWindowSurface(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroyContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
// Explicit lock in egl::Display::destroyContext()/makeCurrent()
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroySurface(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetConfigAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetConfigs(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetCurrentDisplay(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetCurrentSurface(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetDisplay(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetError(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetProcAddress(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_Initialize(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_MakeCurrent(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
// Explicit lock in egl::Display::makeCurrent()
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryContext(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked,
EGLint attribute)
{
// Don't lock mutex for all atributes to avoid activating SharedContextMutex when not required.
switch (attribute)
{
// Dynamic state.
case EGL_RENDER_BUFFER:
return TryLockContextForThread(thread, dpyPacked, ctxPacked);
// Rest states are static.
default:
return {};
}
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryString(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QuerySurface(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
switch (attribute)
{
// EGL_BUFFER_AGE_EXT uses current Context and therefore requires the lock.
case EGL_BUFFER_AGE_EXT:
return TryLockCurrentContext(thread);
// Other attributes are not using Context, therefore lock is not required.
default:
return {};
}
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SwapBuffers(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_Terminate(Thread *thread,
egl::Display *dpyPacked)
{
// Accesses only not curent Contexts or when TerminateReason::NoActiveThreads
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_WaitGL(Thread *thread)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_WaitNative(Thread *thread)
{
return TryLockCurrentContext(thread);
}
// EGL 1.1
ANGLE_INLINE ScopedContextMutexLock GetContextLock_BindTexImage(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ReleaseTexImage(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SurfaceAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SwapInterval(Thread *thread,
egl::Display *dpyPacked)
{
// Only checked in Validation that we have current Context
return {};
}
// EGL 1.2
ANGLE_INLINE ScopedContextMutexLock GetContextLock_BindAPI(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreatePbufferFromClientBuffer(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryAPI(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ReleaseThread(Thread *thread)
{
// Explicit lock in egl::Display::makeCurrent()
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_WaitClient(Thread *thread)
{
return TryLockCurrentContext(thread);
}
// EGL 1.4
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetCurrentContext(Thread *thread)
{
return {};
}
// EGL 1.5
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ClientWaitSync(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateImage(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
return TryLockAndActivateSharedContextMutex(dpyPacked, ctxPacked);
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreatePlatformPixmapSurface(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreatePlatformWindowSurface(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateSync(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroyImage(Thread *thread,
egl::Display *dpyPacked)
{
// Explicit lock in egl::Display::destroyImageImpl()
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroySync(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetPlatformDisplay(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetSyncAttrib(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_WaitSync(Thread *thread, egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_ANDROID_blob_cache
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SetBlobCacheFuncsANDROID(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANDROID_create_native_client_buffer
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateNativeClientBufferANDROID(Thread *thread)
{
return {};
}
// EGL_ANDROID_get_frame_timestamps
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_GetCompositorTimingSupportedANDROID(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_GetCompositorTimingANDROID(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetNextFrameIdANDROID(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_GetFrameTimestampSupportedANDROID(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_GetFrameTimestampsANDROID(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
// EGL_ANDROID_get_native_client_buffer
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetNativeClientBufferANDROID(Thread *thread)
{
return {};
}
// EGL_ANDROID_native_fence_sync
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DupNativeFenceFDANDROID(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANDROID_presentation_time
ANGLE_INLINE ScopedContextMutexLock GetContextLock_PresentationTimeANDROID(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_device_creation
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateDeviceANGLE(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ReleaseDeviceANGLE(Thread *thread)
{
return {};
}
// EGL_ANGLE_feature_control
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryStringiANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDisplayAttribANGLE(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
// EGL_ANGLE_metal_shared_event_sync
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CopyMetalSharedEventANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_power_preference
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ReleaseHighPowerGPUANGLE(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
return TryLockContextForThread(thread, dpyPacked, ctxPacked);
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_ReacquireHighPowerGPUANGLE(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
return TryLockContextForThread(thread, dpyPacked, ctxPacked);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_HandleGPUSwitchANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ForceGPUSwitchANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_prepare_swap_buffers
ANGLE_INLINE ScopedContextMutexLock GetContextLock_PrepareSwapBuffersANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_ANGLE_program_cache_control
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_ProgramCacheGetAttribANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ProgramCacheQueryANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_ProgramCachePopulateANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ProgramCacheResizeANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_query_surface_pointer
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QuerySurfacePointerANGLE(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
// EGL_ANGLE_stream_producer_d3d_texture
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreateStreamProducerD3DTextureANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_StreamPostD3DTextureANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_swap_with_frame_token
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_SwapBuffersWithFrameTokenANGLE(Thread *thread, egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_ANGLE_sync_control_rate
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetMscRateANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_vulkan_image
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ExportVkImageANGLE(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_ANGLE_wait_until_work_scheduled
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_WaitUntilWorkScheduledANGLE(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
// EGL_CHROMIUM_sync_control
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetSyncValuesCHROMIUM(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_EXT_device_query
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDeviceAttribEXT(Thread *thread,
EGLint attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDeviceStringEXT(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDisplayAttribEXT(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
// EGL_EXT_image_dma_buf_import_modifiers
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDmaBufFormatsEXT(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDmaBufModifiersEXT(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_EXT_platform_base
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreatePlatformPixmapSurfaceEXT(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_CreatePlatformWindowSurfaceEXT(Thread *thread, egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetPlatformDisplayEXT(Thread *thread)
{
return {};
}
// EGL_KHR_debug
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DebugMessageControlKHR(Thread *thread)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_LabelObjectKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryDebugKHR(Thread *thread, EGLint attribute)
{
return {};
}
// EGL_KHR_fence_sync
ANGLE_INLINE ScopedContextMutexLock GetContextLock_ClientWaitSyncKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateSyncKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroySyncKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_GetSyncAttribKHR(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
// EGL_KHR_image
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateImageKHR(Thread *thread,
egl::Display *dpyPacked,
gl::ContextID ctxPacked)
{
return TryLockAndActivateSharedContextMutex(dpyPacked, ctxPacked);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroyImageKHR(Thread *thread,
egl::Display *dpyPacked)
{
// Explicit lock in egl::Display::destroyImageImpl()
return {};
}
// EGL_KHR_lock_surface3
ANGLE_INLINE ScopedContextMutexLock GetContextLock_LockSurfaceKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QuerySurface64KHR(Thread *thread,
egl::Display *dpyPacked,
EGLint attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_UnlockSurfaceKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_KHR_partial_update
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SetDamageRegionKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
// EGL_KHR_reusable_sync
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SignalSyncKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_KHR_stream
ANGLE_INLINE ScopedContextMutexLock GetContextLock_CreateStreamKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_DestroyStreamKHR(Thread *thread,
egl::Display *dpyPacked)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryStreamKHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_QueryStreamu64KHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute)
{
return {};
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_StreamAttribKHR(Thread *thread,
egl::Display *dpyPacked,
EGLenum attribute)
{
return {};
}
// EGL_KHR_stream_consumer_gltexture
ANGLE_INLINE ScopedContextMutexLock GetContextLock_StreamConsumerAcquireKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_StreamConsumerGLTextureExternalKHR(Thread *thread, egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
ANGLE_INLINE ScopedContextMutexLock GetContextLock_StreamConsumerReleaseKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_KHR_swap_buffers_with_damage
ANGLE_INLINE ScopedContextMutexLock GetContextLock_SwapBuffersWithDamageKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_KHR_wait_sync
ANGLE_INLINE ScopedContextMutexLock GetContextLock_WaitSyncKHR(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_NV_post_sub_buffer
ANGLE_INLINE ScopedContextMutexLock GetContextLock_PostSubBufferNV(Thread *thread,
egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
// EGL_NV_stream_consumer_gltexture_yuv
ANGLE_INLINE ScopedContextMutexLock
GetContextLock_StreamConsumerGLTextureExternalAttribsNV(Thread *thread, egl::Display *dpyPacked)
{
return TryLockCurrentContext(thread);
}
} // namespace egl
#endif // LIBGLESV2_EGL_CONTEXT_LOCK_IMPL_H_

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

@ -584,9 +584,24 @@ EGLBoolean QuerySurface(Thread *thread,
ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface", ANGLE_EGL_TRY_RETURN(thread, display->prepareForCall(), "eglQuerySurface",
GetDisplayIfValid(display), EGL_FALSE); GetDisplayIfValid(display), EGL_FALSE);
ANGLE_EGL_TRY_RETURN(
thread, QuerySurfaceAttrib(display, thread->getContext(), eglSurface, attribute, value), // Update GetContextLock_QuerySurface() switch accordingly to take a ContextMutex lock for
"eglQuerySurface", GetSurfaceIfValid(display, surfaceID), EGL_FALSE); // attributes that require current Context.
const gl::Context *context;
switch (attribute)
{
// EGL_BUFFER_AGE_EXT uses Context, so lock was taken in GetContextLock_QuerySurface().
case EGL_BUFFER_AGE_EXT:
context = thread->getContext();
break;
// Other attributes are not using Context, pass nullptr to be explicit about that.
default:
context = nullptr;
break;
}
ANGLE_EGL_TRY_RETURN(thread, QuerySurfaceAttrib(display, context, eglSurface, attribute, value),
"eglQuerySurface", GetSurfaceIfValid(display, surfaceID), EGL_FALSE);
thread->setSuccess(); thread->setSuccess();
return EGL_TRUE; return EGL_TRUE;

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

@ -14,6 +14,7 @@
#include "libANGLE/capture/capture_egl_autogen.h" #include "libANGLE/capture/capture_egl_autogen.h"
#include "libANGLE/entry_points_utils.h" #include "libANGLE/entry_points_utils.h"
#include "libANGLE/validationEGL_autogen.h" #include "libANGLE/validationEGL_autogen.h"
#include "libGLESv2/egl_context_lock_impl.h"
#include "libGLESv2/egl_ext_stubs_autogen.h" #include "libGLESv2/egl_ext_stubs_autogen.h"
#include "libGLESv2/egl_stubs_autogen.h" #include "libGLESv2/egl_stubs_autogen.h"
#include "libGLESv2/global_state.h" #include "libGLESv2/global_state.h"
@ -43,11 +44,15 @@ EGLBoolean EGLAPIENTRY EGL_ChooseConfig(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, ChooseConfig, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, attrib_listPacked, configs, config_size, num_config); ANGLE_EGL_SCOPED_CONTEXT_LOCK(ChooseConfig, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, ChooseConfig, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, attrib_listPacked, configs, config_size, num_config);
returnValue = ChooseConfig(thread, dpyPacked, attrib_listPacked, configs, config_size,
num_config);
}
returnValue =
ChooseConfig(thread, dpyPacked, attrib_listPacked, configs, config_size, num_config);
ANGLE_CAPTURE_EGL(ChooseConfig, true, thread, dpyPacked, attrib_listPacked, configs, ANGLE_CAPTURE_EGL(ChooseConfig, true, thread, dpyPacked, attrib_listPacked, configs,
config_size, num_config, returnValue); config_size, num_config, returnValue);
} }
@ -72,10 +77,14 @@ EGLBoolean EGLAPIENTRY EGL_CopyBuffers(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, CopyBuffers, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
surfacePacked, target); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CopyBuffers, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CopyBuffers, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked, target);
returnValue = CopyBuffers(thread, dpyPacked, surfacePacked, target);
}
returnValue = CopyBuffers(thread, dpyPacked, surfacePacked, target);
ANGLE_CAPTURE_EGL(CopyBuffers, true, thread, dpyPacked, surfacePacked, target, returnValue); ANGLE_CAPTURE_EGL(CopyBuffers, true, thread, dpyPacked, surfacePacked, target, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -103,11 +112,15 @@ EGLContext EGLAPIENTRY EGL_CreateContext(EGLDisplay dpy,
gl::ContextID share_contextPacked = PackParam<gl::ContextID>(share_context); gl::ContextID share_contextPacked = PackParam<gl::ContextID>(share_context);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreateContext, GetDisplayIfValid(dpyPacked), EGLContext, {
dpyPacked, configPacked, share_contextPacked, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateContext, thread, dpyPacked, share_contextPacked);
ANGLE_EGL_VALIDATE(thread, CreateContext, GetDisplayIfValid(dpyPacked), EGLContext,
dpyPacked, configPacked, share_contextPacked, attrib_listPacked);
returnValue = CreateContext(thread, dpyPacked, configPacked, share_contextPacked,
attrib_listPacked);
}
returnValue =
CreateContext(thread, dpyPacked, configPacked, share_contextPacked, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreateContext, true, thread, dpyPacked, configPacked, share_contextPacked, ANGLE_CAPTURE_EGL(CreateContext, true, thread, dpyPacked, configPacked, share_contextPacked,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -133,10 +146,14 @@ EGLSurface EGLAPIENTRY EGL_CreatePbufferSurface(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreatePbufferSurface, GetDisplayIfValid(dpyPacked), EGLSurface, {
dpyPacked, configPacked, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePbufferSurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreatePbufferSurface, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, configPacked, attrib_listPacked);
returnValue = CreatePbufferSurface(thread, dpyPacked, configPacked, attrib_listPacked);
}
returnValue = CreatePbufferSurface(thread, dpyPacked, configPacked, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreatePbufferSurface, true, thread, dpyPacked, configPacked, ANGLE_CAPTURE_EGL(CreatePbufferSurface, true, thread, dpyPacked, configPacked,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -163,11 +180,15 @@ EGLSurface EGLAPIENTRY EGL_CreatePixmapSurface(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreatePixmapSurface, GetDisplayIfValid(dpyPacked), EGLSurface, {
dpyPacked, configPacked, pixmap, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePixmapSurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreatePixmapSurface, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, configPacked, pixmap, attrib_listPacked);
returnValue =
CreatePixmapSurface(thread, dpyPacked, configPacked, pixmap, attrib_listPacked);
}
returnValue =
CreatePixmapSurface(thread, dpyPacked, configPacked, pixmap, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreatePixmapSurface, true, thread, dpyPacked, configPacked, pixmap, ANGLE_CAPTURE_EGL(CreatePixmapSurface, true, thread, dpyPacked, configPacked, pixmap,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -194,10 +215,15 @@ EGLSurface EGLAPIENTRY EGL_CreateWindowSurface(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreateWindowSurface, GetDisplayIfValid(dpyPacked), EGLSurface, {
dpyPacked, configPacked, win, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateWindowSurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreateWindowSurface, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, configPacked, win, attrib_listPacked);
returnValue =
CreateWindowSurface(thread, dpyPacked, configPacked, win, attrib_listPacked);
}
returnValue = CreateWindowSurface(thread, dpyPacked, configPacked, win, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreateWindowSurface, true, thread, dpyPacked, configPacked, win, ANGLE_CAPTURE_EGL(CreateWindowSurface, true, thread, dpyPacked, configPacked, win,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -218,10 +244,14 @@ EGLBoolean EGLAPIENTRY EGL_DestroyContext(EGLDisplay dpy, EGLContext ctx)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx); gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);
ANGLE_EGL_VALIDATE(thread, DestroyContext, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, ctxPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroyContext, thread, dpyPacked, ctxPacked);
ANGLE_EGL_VALIDATE(thread, DestroyContext, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, ctxPacked);
returnValue = DestroyContext(thread, dpyPacked, ctxPacked);
}
returnValue = DestroyContext(thread, dpyPacked, ctxPacked);
ANGLE_CAPTURE_EGL(DestroyContext, true, thread, dpyPacked, ctxPacked, returnValue); ANGLE_CAPTURE_EGL(DestroyContext, true, thread, dpyPacked, ctxPacked, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -241,10 +271,14 @@ EGLBoolean EGLAPIENTRY EGL_DestroySurface(EGLDisplay dpy, EGLSurface surface)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, DestroySurface, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, surfacePacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroySurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, DestroySurface, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked);
returnValue = DestroySurface(thread, dpyPacked, surfacePacked);
}
returnValue = DestroySurface(thread, dpyPacked, surfacePacked);
ANGLE_CAPTURE_EGL(DestroySurface, true, thread, dpyPacked, surfacePacked, returnValue); ANGLE_CAPTURE_EGL(DestroySurface, true, thread, dpyPacked, surfacePacked, returnValue);
} }
egl::Display::GetCurrentThreadUnlockedTailCall()->run(); egl::Display::GetCurrentThreadUnlockedTailCall()->run();
@ -269,10 +303,14 @@ EGLBoolean EGLAPIENTRY EGL_GetConfigAttrib(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
ANGLE_EGL_VALIDATE(thread, GetConfigAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, configPacked, attribute, value); ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetConfigAttrib, thread, dpyPacked, attribute);
ANGLE_EGL_VALIDATE(thread, GetConfigAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, configPacked, attribute, value);
returnValue = GetConfigAttrib(thread, dpyPacked, configPacked, attribute, value);
}
returnValue = GetConfigAttrib(thread, dpyPacked, configPacked, attribute, value);
ANGLE_CAPTURE_EGL(GetConfigAttrib, true, thread, dpyPacked, configPacked, attribute, value, ANGLE_CAPTURE_EGL(GetConfigAttrib, true, thread, dpyPacked, configPacked, attribute, value,
returnValue); returnValue);
} }
@ -297,10 +335,14 @@ EGLBoolean EGLAPIENTRY EGL_GetConfigs(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ANGLE_EGL_VALIDATE(thread, GetConfigs, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
configs, config_size, num_config); ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetConfigs, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, GetConfigs, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, configs, config_size, num_config);
returnValue = GetConfigs(thread, dpyPacked, configs, config_size, num_config);
}
returnValue = GetConfigs(thread, dpyPacked, configs, config_size, num_config);
ANGLE_CAPTURE_EGL(GetConfigs, true, thread, dpyPacked, configs, config_size, num_config, ANGLE_CAPTURE_EGL(GetConfigs, true, thread, dpyPacked, configs, config_size, num_config,
returnValue); returnValue);
} }
@ -317,9 +359,13 @@ EGLDisplay EGLAPIENTRY EGL_GetCurrentDisplay()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetCurrentDisplay, ""); EGL_EVENT(GetCurrentDisplay, "");
ANGLE_EGL_VALIDATE(thread, GetCurrentDisplay, nullptr, EGLDisplay); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetCurrentDisplay, thread);
ANGLE_EGL_VALIDATE(thread, GetCurrentDisplay, nullptr, EGLDisplay);
returnValue = GetCurrentDisplay(thread);
}
returnValue = GetCurrentDisplay(thread);
ANGLE_CAPTURE_EGL(GetCurrentDisplay, true, thread, returnValue); ANGLE_CAPTURE_EGL(GetCurrentDisplay, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -335,9 +381,13 @@ EGLSurface EGLAPIENTRY EGL_GetCurrentSurface(EGLint readdraw)
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetCurrentSurface, "readdraw = %d", readdraw); EGL_EVENT(GetCurrentSurface, "readdraw = %d", readdraw);
ANGLE_EGL_VALIDATE(thread, GetCurrentSurface, nullptr, EGLSurface, readdraw); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetCurrentSurface, thread);
ANGLE_EGL_VALIDATE(thread, GetCurrentSurface, nullptr, EGLSurface, readdraw);
returnValue = GetCurrentSurface(thread, readdraw);
}
returnValue = GetCurrentSurface(thread, readdraw);
ANGLE_CAPTURE_EGL(GetCurrentSurface, true, thread, readdraw, returnValue); ANGLE_CAPTURE_EGL(GetCurrentSurface, true, thread, readdraw, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -353,9 +403,13 @@ EGLDisplay EGLAPIENTRY EGL_GetDisplay(EGLNativeDisplayType display_id)
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetDisplay, "display_id = 0x%016" PRIxPTR "", (uintptr_t)display_id); EGL_EVENT(GetDisplay, "display_id = 0x%016" PRIxPTR "", (uintptr_t)display_id);
ANGLE_EGL_VALIDATE(thread, GetDisplay, nullptr, EGLDisplay, display_id); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetDisplay, thread);
ANGLE_EGL_VALIDATE(thread, GetDisplay, nullptr, EGLDisplay, display_id);
returnValue = GetDisplay(thread, display_id);
}
returnValue = GetDisplay(thread, display_id);
ANGLE_CAPTURE_EGL(GetDisplay, true, thread, display_id, returnValue); ANGLE_CAPTURE_EGL(GetDisplay, true, thread, display_id, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -371,9 +425,13 @@ EGLint EGLAPIENTRY EGL_GetError()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetError, ""); EGL_EVENT(GetError, "");
ANGLE_EGL_VALIDATE(thread, GetError, nullptr, EGLint); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetError, thread);
ANGLE_EGL_VALIDATE(thread, GetError, nullptr, EGLint);
returnValue = GetError(thread);
}
returnValue = GetError(thread);
ANGLE_CAPTURE_EGL(GetError, true, thread, returnValue); ANGLE_CAPTURE_EGL(GetError, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -389,10 +447,14 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY EGL_GetProcAddress(const ch
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetProcAddress, "procname = 0x%016" PRIxPTR "", (uintptr_t)procname); EGL_EVENT(GetProcAddress, "procname = 0x%016" PRIxPTR "", (uintptr_t)procname);
ANGLE_EGL_VALIDATE(thread, GetProcAddress, nullptr, {
__eglMustCastToProperFunctionPointerType, procname); ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetProcAddress, thread);
ANGLE_EGL_VALIDATE(thread, GetProcAddress, nullptr,
__eglMustCastToProperFunctionPointerType, procname);
returnValue = GetProcAddress(thread, procname);
}
returnValue = GetProcAddress(thread, procname);
ANGLE_CAPTURE_EGL(GetProcAddress, true, thread, procname, returnValue); ANGLE_CAPTURE_EGL(GetProcAddress, true, thread, procname, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -412,10 +474,14 @@ EGLBoolean EGLAPIENTRY EGL_Initialize(EGLDisplay dpy, EGLint *major, EGLint *min
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ANGLE_EGL_VALIDATE(thread, Initialize, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
major, minor); ANGLE_EGL_SCOPED_CONTEXT_LOCK(Initialize, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, Initialize, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, major, minor);
returnValue = Initialize(thread, dpyPacked, major, minor);
}
returnValue = Initialize(thread, dpyPacked, major, minor);
ANGLE_CAPTURE_EGL(Initialize, true, thread, dpyPacked, major, minor, returnValue); ANGLE_CAPTURE_EGL(Initialize, true, thread, dpyPacked, major, minor, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -442,10 +508,14 @@ EGLBoolean EGLAPIENTRY EGL_MakeCurrent(EGLDisplay dpy,
SurfaceID readPacked = PackParam<SurfaceID>(read); SurfaceID readPacked = PackParam<SurfaceID>(read);
gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx); gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);
ANGLE_EGL_VALIDATE(thread, MakeCurrent, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
drawPacked, readPacked, ctxPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(MakeCurrent, thread, dpyPacked, ctxPacked);
ANGLE_EGL_VALIDATE(thread, MakeCurrent, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, drawPacked, readPacked, ctxPacked);
returnValue = MakeCurrent(thread, dpyPacked, drawPacked, readPacked, ctxPacked);
}
returnValue = MakeCurrent(thread, dpyPacked, drawPacked, readPacked, ctxPacked);
ANGLE_CAPTURE_EGL(MakeCurrent, true, thread, dpyPacked, drawPacked, readPacked, ctxPacked, ANGLE_CAPTURE_EGL(MakeCurrent, true, thread, dpyPacked, drawPacked, readPacked, ctxPacked,
returnValue); returnValue);
} }
@ -471,10 +541,14 @@ EGLBoolean EGLAPIENTRY EGL_QueryContext(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx); gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);
ANGLE_EGL_VALIDATE(thread, QueryContext, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, ctxPacked, attribute, value); ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryContext, thread, dpyPacked, ctxPacked, attribute);
ANGLE_EGL_VALIDATE(thread, QueryContext, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, ctxPacked, attribute, value);
returnValue = QueryContext(thread, dpyPacked, ctxPacked, attribute, value);
}
returnValue = QueryContext(thread, dpyPacked, ctxPacked, attribute, value);
ANGLE_CAPTURE_EGL(QueryContext, true, thread, dpyPacked, ctxPacked, attribute, value, ANGLE_CAPTURE_EGL(QueryContext, true, thread, dpyPacked, ctxPacked, attribute, value,
returnValue); returnValue);
} }
@ -493,10 +567,14 @@ const char *EGLAPIENTRY EGL_QueryString(EGLDisplay dpy, EGLint name)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ANGLE_EGL_VALIDATE(thread, QueryString, GetDisplayIfValid(dpyPacked), const char *, {
dpyPacked, name); ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryString, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, QueryString, GetDisplayIfValid(dpyPacked), const char *,
dpyPacked, name);
returnValue = QueryString(thread, dpyPacked, name);
}
returnValue = QueryString(thread, dpyPacked, name);
ANGLE_CAPTURE_EGL(QueryString, true, thread, dpyPacked, name, returnValue); ANGLE_CAPTURE_EGL(QueryString, true, thread, dpyPacked, name, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -521,10 +599,14 @@ EGLBoolean EGLAPIENTRY EGL_QuerySurface(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, QuerySurface, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, surfacePacked, attribute, value); ANGLE_EGL_SCOPED_CONTEXT_LOCK(QuerySurface, thread, dpyPacked, attribute);
ANGLE_EGL_VALIDATE(thread, QuerySurface, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked, attribute, value);
returnValue = QuerySurface(thread, dpyPacked, surfacePacked, attribute, value);
}
returnValue = QuerySurface(thread, dpyPacked, surfacePacked, attribute, value);
ANGLE_CAPTURE_EGL(QuerySurface, true, thread, dpyPacked, surfacePacked, attribute, value, ANGLE_CAPTURE_EGL(QuerySurface, true, thread, dpyPacked, surfacePacked, attribute, value,
returnValue); returnValue);
} }
@ -545,10 +627,14 @@ EGLBoolean EGLAPIENTRY EGL_SwapBuffers(EGLDisplay dpy, EGLSurface surface)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, SwapBuffers, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
surfacePacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(SwapBuffers, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, SwapBuffers, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked);
returnValue = SwapBuffers(thread, dpyPacked, surfacePacked);
}
returnValue = SwapBuffers(thread, dpyPacked, surfacePacked);
ANGLE_CAPTURE_EGL(SwapBuffers, true, thread, dpyPacked, surfacePacked, returnValue); ANGLE_CAPTURE_EGL(SwapBuffers, true, thread, dpyPacked, surfacePacked, returnValue);
} }
egl::Display::GetCurrentThreadUnlockedTailCall()->run(); egl::Display::GetCurrentThreadUnlockedTailCall()->run();
@ -566,9 +652,14 @@ EGLBoolean EGLAPIENTRY EGL_Terminate(EGLDisplay dpy)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ANGLE_EGL_VALIDATE(thread, Terminate, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(Terminate, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, Terminate, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked);
returnValue = Terminate(thread, dpyPacked);
}
returnValue = Terminate(thread, dpyPacked);
ANGLE_CAPTURE_EGL(Terminate, true, thread, dpyPacked, returnValue); ANGLE_CAPTURE_EGL(Terminate, true, thread, dpyPacked, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -584,9 +675,13 @@ EGLBoolean EGLAPIENTRY EGL_WaitGL()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(WaitGL, ""); EGL_EVENT(WaitGL, "");
ANGLE_EGL_VALIDATE(thread, WaitGL, nullptr, EGLBoolean); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitGL, thread);
ANGLE_EGL_VALIDATE(thread, WaitGL, nullptr, EGLBoolean);
returnValue = WaitGL(thread);
}
returnValue = WaitGL(thread);
ANGLE_CAPTURE_EGL(WaitGL, true, thread, returnValue); ANGLE_CAPTURE_EGL(WaitGL, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -602,9 +697,13 @@ EGLBoolean EGLAPIENTRY EGL_WaitNative(EGLint engine)
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(WaitNative, "engine = %d", engine); EGL_EVENT(WaitNative, "engine = %d", engine);
ANGLE_EGL_VALIDATE(thread, WaitNative, nullptr, EGLBoolean, engine); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitNative, thread);
ANGLE_EGL_VALIDATE(thread, WaitNative, nullptr, EGLBoolean, engine);
returnValue = WaitNative(thread, engine);
}
returnValue = WaitNative(thread, engine);
ANGLE_CAPTURE_EGL(WaitNative, true, thread, engine, returnValue); ANGLE_CAPTURE_EGL(WaitNative, true, thread, engine, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -625,10 +724,14 @@ EGLBoolean EGLAPIENTRY EGL_BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLi
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, BindTexImage, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, surfacePacked, buffer); ANGLE_EGL_SCOPED_CONTEXT_LOCK(BindTexImage, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, BindTexImage, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked, buffer);
returnValue = BindTexImage(thread, dpyPacked, surfacePacked, buffer);
}
returnValue = BindTexImage(thread, dpyPacked, surfacePacked, buffer);
ANGLE_CAPTURE_EGL(BindTexImage, true, thread, dpyPacked, surfacePacked, buffer, ANGLE_CAPTURE_EGL(BindTexImage, true, thread, dpyPacked, surfacePacked, buffer,
returnValue); returnValue);
} }
@ -650,10 +753,14 @@ EGLBoolean EGLAPIENTRY EGL_ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, E
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, ReleaseTexImage, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, surfacePacked, buffer); ANGLE_EGL_SCOPED_CONTEXT_LOCK(ReleaseTexImage, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, ReleaseTexImage, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked, buffer);
returnValue = ReleaseTexImage(thread, dpyPacked, surfacePacked, buffer);
}
returnValue = ReleaseTexImage(thread, dpyPacked, surfacePacked, buffer);
ANGLE_CAPTURE_EGL(ReleaseTexImage, true, thread, dpyPacked, surfacePacked, buffer, ANGLE_CAPTURE_EGL(ReleaseTexImage, true, thread, dpyPacked, surfacePacked, buffer,
returnValue); returnValue);
} }
@ -679,10 +786,14 @@ EGLBoolean EGLAPIENTRY EGL_SurfaceAttrib(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
SurfaceID surfacePacked = PackParam<SurfaceID>(surface); SurfaceID surfacePacked = PackParam<SurfaceID>(surface);
ANGLE_EGL_VALIDATE(thread, SurfaceAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, surfacePacked, attribute, value); ANGLE_EGL_SCOPED_CONTEXT_LOCK(SurfaceAttrib, thread, dpyPacked, attribute);
ANGLE_EGL_VALIDATE(thread, SurfaceAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, surfacePacked, attribute, value);
returnValue = SurfaceAttrib(thread, dpyPacked, surfacePacked, attribute, value);
}
returnValue = SurfaceAttrib(thread, dpyPacked, surfacePacked, attribute, value);
ANGLE_CAPTURE_EGL(SurfaceAttrib, true, thread, dpyPacked, surfacePacked, attribute, value, ANGLE_CAPTURE_EGL(SurfaceAttrib, true, thread, dpyPacked, surfacePacked, attribute, value,
returnValue); returnValue);
} }
@ -701,10 +812,14 @@ EGLBoolean EGLAPIENTRY EGL_SwapInterval(EGLDisplay dpy, EGLint interval)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ANGLE_EGL_VALIDATE(thread, SwapInterval, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, interval); ANGLE_EGL_SCOPED_CONTEXT_LOCK(SwapInterval, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, SwapInterval, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, interval);
returnValue = SwapInterval(thread, dpyPacked, interval);
}
returnValue = SwapInterval(thread, dpyPacked, interval);
ANGLE_CAPTURE_EGL(SwapInterval, true, thread, dpyPacked, interval, returnValue); ANGLE_CAPTURE_EGL(SwapInterval, true, thread, dpyPacked, interval, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -721,9 +836,13 @@ EGLBoolean EGLAPIENTRY EGL_BindAPI(EGLenum api)
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(BindAPI, "api = 0x%X", api); EGL_EVENT(BindAPI, "api = 0x%X", api);
ANGLE_EGL_VALIDATE(thread, BindAPI, nullptr, EGLBoolean, api); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(BindAPI, thread);
ANGLE_EGL_VALIDATE(thread, BindAPI, nullptr, EGLBoolean, api);
returnValue = BindAPI(thread, api);
}
returnValue = BindAPI(thread, api);
ANGLE_CAPTURE_EGL(BindAPI, true, thread, api, returnValue); ANGLE_CAPTURE_EGL(BindAPI, true, thread, api, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -751,11 +870,16 @@ EGLSurface EGLAPIENTRY EGL_CreatePbufferFromClientBuffer(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreatePbufferFromClientBuffer, GetDisplayIfValid(dpyPacked), {
EGLSurface, dpyPacked, buftype, buffer, configPacked, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePbufferFromClientBuffer, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreatePbufferFromClientBuffer, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, buftype, buffer, configPacked,
attrib_listPacked);
returnValue = CreatePbufferFromClientBuffer(thread, dpyPacked, buftype, buffer,
configPacked, attrib_listPacked);
}
returnValue = CreatePbufferFromClientBuffer(thread, dpyPacked, buftype, buffer,
configPacked, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreatePbufferFromClientBuffer, true, thread, dpyPacked, buftype, buffer, ANGLE_CAPTURE_EGL(CreatePbufferFromClientBuffer, true, thread, dpyPacked, buftype, buffer,
configPacked, attrib_listPacked, returnValue); configPacked, attrib_listPacked, returnValue);
} }
@ -772,9 +896,13 @@ EGLenum EGLAPIENTRY EGL_QueryAPI()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(QueryAPI, ""); EGL_EVENT(QueryAPI, "");
ANGLE_EGL_VALIDATE(thread, QueryAPI, nullptr, EGLenum); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(QueryAPI, thread);
ANGLE_EGL_VALIDATE(thread, QueryAPI, nullptr, EGLenum);
returnValue = QueryAPI(thread);
}
returnValue = QueryAPI(thread);
ANGLE_CAPTURE_EGL(QueryAPI, true, thread, returnValue); ANGLE_CAPTURE_EGL(QueryAPI, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -790,9 +918,13 @@ EGLBoolean EGLAPIENTRY EGL_ReleaseThread()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(ReleaseThread, ""); EGL_EVENT(ReleaseThread, "");
ANGLE_EGL_VALIDATE(thread, ReleaseThread, nullptr, EGLBoolean); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(ReleaseThread, thread);
ANGLE_EGL_VALIDATE(thread, ReleaseThread, nullptr, EGLBoolean);
returnValue = ReleaseThread(thread);
}
returnValue = ReleaseThread(thread);
ANGLE_CAPTURE_EGL(ReleaseThread, true, thread, returnValue); ANGLE_CAPTURE_EGL(ReleaseThread, true, thread, returnValue);
} }
egl::Display::GetCurrentThreadUnlockedTailCall()->run(); egl::Display::GetCurrentThreadUnlockedTailCall()->run();
@ -808,9 +940,13 @@ EGLBoolean EGLAPIENTRY EGL_WaitClient()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(WaitClient, ""); EGL_EVENT(WaitClient, "");
ANGLE_EGL_VALIDATE(thread, WaitClient, nullptr, EGLBoolean); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitClient, thread);
ANGLE_EGL_VALIDATE(thread, WaitClient, nullptr, EGLBoolean);
returnValue = WaitClient(thread);
}
returnValue = WaitClient(thread);
ANGLE_CAPTURE_EGL(WaitClient, true, thread, returnValue); ANGLE_CAPTURE_EGL(WaitClient, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -827,9 +963,13 @@ EGLContext EGLAPIENTRY EGL_GetCurrentContext()
ANGLE_SCOPED_GLOBAL_LOCK(); ANGLE_SCOPED_GLOBAL_LOCK();
EGL_EVENT(GetCurrentContext, ""); EGL_EVENT(GetCurrentContext, "");
ANGLE_EGL_VALIDATE(thread, GetCurrentContext, nullptr, EGLContext); {
ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetCurrentContext, thread);
ANGLE_EGL_VALIDATE(thread, GetCurrentContext, nullptr, EGLContext);
returnValue = GetCurrentContext(thread);
}
returnValue = GetCurrentContext(thread);
ANGLE_CAPTURE_EGL(GetCurrentContext, true, thread, returnValue); ANGLE_CAPTURE_EGL(GetCurrentContext, true, thread, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -851,10 +991,14 @@ EGLint EGLAPIENTRY EGL_ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
egl::SyncID syncPacked = PackParam<egl::SyncID>(sync); egl::SyncID syncPacked = PackParam<egl::SyncID>(sync);
ANGLE_EGL_VALIDATE(thread, ClientWaitSync, GetDisplayIfValid(dpyPacked), EGLint, dpyPacked, {
syncPacked, flags, timeout); ANGLE_EGL_SCOPED_CONTEXT_LOCK(ClientWaitSync, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, ClientWaitSync, GetDisplayIfValid(dpyPacked), EGLint,
dpyPacked, syncPacked, flags, timeout);
returnValue = ClientWaitSync(thread, dpyPacked, syncPacked, flags, timeout);
}
returnValue = ClientWaitSync(thread, dpyPacked, syncPacked, flags, timeout);
ANGLE_CAPTURE_EGL(ClientWaitSync, true, thread, dpyPacked, syncPacked, flags, timeout, ANGLE_CAPTURE_EGL(ClientWaitSync, true, thread, dpyPacked, syncPacked, flags, timeout,
returnValue); returnValue);
} }
@ -883,10 +1027,15 @@ EGLImage EGLAPIENTRY EGL_CreateImage(EGLDisplay dpy,
gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx); gl::ContextID ctxPacked = PackParam<gl::ContextID>(ctx);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreateImage, GetDisplayIfValid(dpyPacked), EGLImage, dpyPacked, {
ctxPacked, target, buffer, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateImage, thread, dpyPacked, ctxPacked);
ANGLE_EGL_VALIDATE(thread, CreateImage, GetDisplayIfValid(dpyPacked), EGLImage,
dpyPacked, ctxPacked, target, buffer, attrib_listPacked);
returnValue =
CreateImage(thread, dpyPacked, ctxPacked, target, buffer, attrib_listPacked);
}
returnValue = CreateImage(thread, dpyPacked, ctxPacked, target, buffer, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreateImage, true, thread, dpyPacked, ctxPacked, target, buffer, ANGLE_CAPTURE_EGL(CreateImage, true, thread, dpyPacked, ctxPacked, target, buffer,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -914,11 +1063,16 @@ EGLSurface EGLAPIENTRY EGL_CreatePlatformPixmapSurface(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreatePlatformPixmapSurface, GetDisplayIfValid(dpyPacked), {
EGLSurface, dpyPacked, configPacked, native_pixmap, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePlatformPixmapSurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreatePlatformPixmapSurface, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, configPacked, native_pixmap,
attrib_listPacked);
returnValue = CreatePlatformPixmapSurface(thread, dpyPacked, configPacked,
native_pixmap, attrib_listPacked);
}
returnValue = CreatePlatformPixmapSurface(thread, dpyPacked, configPacked, native_pixmap,
attrib_listPacked);
ANGLE_CAPTURE_EGL(CreatePlatformPixmapSurface, true, thread, dpyPacked, configPacked, ANGLE_CAPTURE_EGL(CreatePlatformPixmapSurface, true, thread, dpyPacked, configPacked,
native_pixmap, attrib_listPacked, returnValue); native_pixmap, attrib_listPacked, returnValue);
} }
@ -946,11 +1100,16 @@ EGLSurface EGLAPIENTRY EGL_CreatePlatformWindowSurface(EGLDisplay dpy,
egl::Config *configPacked = PackParam<egl::Config *>(config); egl::Config *configPacked = PackParam<egl::Config *>(config);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreatePlatformWindowSurface, GetDisplayIfValid(dpyPacked), {
EGLSurface, dpyPacked, configPacked, native_window, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreatePlatformWindowSurface, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreatePlatformWindowSurface, GetDisplayIfValid(dpyPacked),
EGLSurface, dpyPacked, configPacked, native_window,
attrib_listPacked);
returnValue = CreatePlatformWindowSurface(thread, dpyPacked, configPacked,
native_window, attrib_listPacked);
}
returnValue = CreatePlatformWindowSurface(thread, dpyPacked, configPacked, native_window,
attrib_listPacked);
ANGLE_CAPTURE_EGL(CreatePlatformWindowSurface, true, thread, dpyPacked, configPacked, ANGLE_CAPTURE_EGL(CreatePlatformWindowSurface, true, thread, dpyPacked, configPacked,
native_window, attrib_listPacked, returnValue); native_window, attrib_listPacked, returnValue);
} }
@ -972,10 +1131,14 @@ EGLSync EGLAPIENTRY EGL_CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, CreateSync, GetDisplayIfValid(dpyPacked), EGLSync, dpyPacked, {
type, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(CreateSync, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, CreateSync, GetDisplayIfValid(dpyPacked), EGLSync, dpyPacked,
type, attrib_listPacked);
returnValue = CreateSync(thread, dpyPacked, type, attrib_listPacked);
}
returnValue = CreateSync(thread, dpyPacked, type, attrib_listPacked);
ANGLE_CAPTURE_EGL(CreateSync, true, thread, dpyPacked, type, attrib_listPacked, ANGLE_CAPTURE_EGL(CreateSync, true, thread, dpyPacked, type, attrib_listPacked,
returnValue); returnValue);
} }
@ -996,10 +1159,14 @@ EGLBoolean EGLAPIENTRY EGL_DestroyImage(EGLDisplay dpy, EGLImage image)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
ImageID imagePacked = PackParam<ImageID>(image); ImageID imagePacked = PackParam<ImageID>(image);
ANGLE_EGL_VALIDATE(thread, DestroyImage, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, imagePacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroyImage, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, DestroyImage, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, imagePacked);
returnValue = DestroyImage(thread, dpyPacked, imagePacked);
}
returnValue = DestroyImage(thread, dpyPacked, imagePacked);
ANGLE_CAPTURE_EGL(DestroyImage, true, thread, dpyPacked, imagePacked, returnValue); ANGLE_CAPTURE_EGL(DestroyImage, true, thread, dpyPacked, imagePacked, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -1019,10 +1186,14 @@ EGLBoolean EGLAPIENTRY EGL_DestroySync(EGLDisplay dpy, EGLSync sync)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
egl::SyncID syncPacked = PackParam<egl::SyncID>(sync); egl::SyncID syncPacked = PackParam<egl::SyncID>(sync);
ANGLE_EGL_VALIDATE(thread, DestroySync, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
syncPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(DestroySync, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, DestroySync, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, syncPacked);
returnValue = DestroySync(thread, dpyPacked, syncPacked);
}
returnValue = DestroySync(thread, dpyPacked, syncPacked);
ANGLE_CAPTURE_EGL(DestroySync, true, thread, dpyPacked, syncPacked, returnValue); ANGLE_CAPTURE_EGL(DestroySync, true, thread, dpyPacked, syncPacked, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());
@ -1045,10 +1216,14 @@ EGLDisplay EGLAPIENTRY EGL_GetPlatformDisplay(EGLenum platform,
const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list); const AttributeMap &attrib_listPacked = PackParam<const AttributeMap &>(attrib_list);
ANGLE_EGL_VALIDATE(thread, GetPlatformDisplay, nullptr, EGLDisplay, platform, {
native_display, attrib_listPacked); ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetPlatformDisplay, thread);
ANGLE_EGL_VALIDATE(thread, GetPlatformDisplay, nullptr, EGLDisplay, platform,
native_display, attrib_listPacked);
returnValue = GetPlatformDisplay(thread, platform, native_display, attrib_listPacked);
}
returnValue = GetPlatformDisplay(thread, platform, native_display, attrib_listPacked);
ANGLE_CAPTURE_EGL(GetPlatformDisplay, true, thread, platform, native_display, ANGLE_CAPTURE_EGL(GetPlatformDisplay, true, thread, platform, native_display,
attrib_listPacked, returnValue); attrib_listPacked, returnValue);
} }
@ -1074,10 +1249,14 @@ EGLBoolean EGLAPIENTRY EGL_GetSyncAttrib(EGLDisplay dpy,
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
egl::SyncID syncPacked = PackParam<egl::SyncID>(sync); egl::SyncID syncPacked = PackParam<egl::SyncID>(sync);
ANGLE_EGL_VALIDATE(thread, GetSyncAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean, {
dpyPacked, syncPacked, attribute, value); ANGLE_EGL_SCOPED_CONTEXT_LOCK(GetSyncAttrib, thread, dpyPacked, attribute);
ANGLE_EGL_VALIDATE(thread, GetSyncAttrib, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, syncPacked, attribute, value);
returnValue = GetSyncAttrib(thread, dpyPacked, syncPacked, attribute, value);
}
returnValue = GetSyncAttrib(thread, dpyPacked, syncPacked, attribute, value);
ANGLE_CAPTURE_EGL(GetSyncAttrib, true, thread, dpyPacked, syncPacked, attribute, value, ANGLE_CAPTURE_EGL(GetSyncAttrib, true, thread, dpyPacked, syncPacked, attribute, value,
returnValue); returnValue);
} }
@ -1098,10 +1277,14 @@ EGLBoolean EGLAPIENTRY EGL_WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags)
egl::Display *dpyPacked = PackParam<egl::Display *>(dpy); egl::Display *dpyPacked = PackParam<egl::Display *>(dpy);
egl::SyncID syncPacked = PackParam<egl::SyncID>(sync); egl::SyncID syncPacked = PackParam<egl::SyncID>(sync);
ANGLE_EGL_VALIDATE(thread, WaitSync, GetDisplayIfValid(dpyPacked), EGLBoolean, dpyPacked, {
syncPacked, flags); ANGLE_EGL_SCOPED_CONTEXT_LOCK(WaitSync, thread, dpyPacked);
ANGLE_EGL_VALIDATE(thread, WaitSync, GetDisplayIfValid(dpyPacked), EGLBoolean,
dpyPacked, syncPacked, flags);
returnValue = WaitSync(thread, dpyPacked, syncPacked, flags);
}
returnValue = WaitSync(thread, dpyPacked, syncPacked, flags);
ANGLE_CAPTURE_EGL(WaitSync, true, thread, dpyPacked, syncPacked, flags, returnValue); ANGLE_CAPTURE_EGL(WaitSync, true, thread, dpyPacked, syncPacked, flags, returnValue);
} }
ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any());

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -4895,7 +4895,7 @@ void GL_APIENTRY GL_EGLImageTargetTexStorageEXT(GLenum target,
if (context) if (context)
{ {
egl::ImageID imagePacked = PackParam<egl::ImageID>(image); egl::ImageID imagePacked = PackParam<egl::ImageID>(image);
SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context); SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imagePacked);
bool isCallValid = (context->skipValidation() || bool isCallValid = (context->skipValidation() ||
(ValidatePixelLocalStorageInactive( (ValidatePixelLocalStorageInactive(
context, angle::EntryPoint::GLEGLImageTargetTexStorageEXT) && context, angle::EntryPoint::GLEGLImageTargetTexStorageEXT) &&
@ -4928,7 +4928,7 @@ void GL_APIENTRY GL_EGLImageTargetTextureStorageEXT(GLuint texture,
if (context) if (context)
{ {
egl::ImageID imagePacked = PackParam<egl::ImageID>(image); egl::ImageID imagePacked = PackParam<egl::ImageID>(image);
SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context); SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imagePacked);
bool isCallValid = (context->skipValidation() || bool isCallValid = (context->skipValidation() ||
(ValidatePixelLocalStorageInactive( (ValidatePixelLocalStorageInactive(
context, angle::EntryPoint::GLEGLImageTargetTextureStorageEXT) && context, angle::EntryPoint::GLEGLImageTargetTextureStorageEXT) &&
@ -10423,7 +10423,7 @@ void GL_APIENTRY GL_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglIma
if (context) if (context)
{ {
egl::ImageID imagePacked = PackParam<egl::ImageID>(image); egl::ImageID imagePacked = PackParam<egl::ImageID>(image);
SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context); SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imagePacked);
bool isCallValid = bool isCallValid =
(context->skipValidation() || (context->skipValidation() ||
(ValidatePixelLocalStorageInactive( (ValidatePixelLocalStorageInactive(
@ -10456,7 +10456,7 @@ void GL_APIENTRY GL_EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES imag
{ {
TextureType targetPacked = PackParam<TextureType>(target); TextureType targetPacked = PackParam<TextureType>(target);
egl::ImageID imagePacked = PackParam<egl::ImageID>(image); egl::ImageID imagePacked = PackParam<egl::ImageID>(image);
SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context); SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imagePacked);
bool isCallValid = (context->skipValidation() || bool isCallValid = (context->skipValidation() ||
(ValidatePixelLocalStorageInactive( (ValidatePixelLocalStorageInactive(
context, angle::EntryPoint::GLEGLImageTargetTexture2DOES) && context, angle::EntryPoint::GLEGLImageTargetTexture2DOES) &&

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

@ -11,7 +11,6 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/system_utils.h" #include "common/system_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/ErrorStrings.h" #include "libANGLE/ErrorStrings.h"
#include "libANGLE/Thread.h" #include "libANGLE/Thread.h"
#include "libGLESv2/resource.h" #include "libGLESv2/resource.h"

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

@ -11,9 +11,11 @@
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Debug.h" #include "libANGLE/Debug.h"
#include "libANGLE/Display.h"
#include "libANGLE/GlobalMutex.h" #include "libANGLE/GlobalMutex.h"
#include "libANGLE/Thread.h" #include "libANGLE/Thread.h"
#include "libANGLE/features.h" #include "libANGLE/features.h"
#include "libANGLE/validationEGL.h"
#if defined(ANGLE_PLATFORM_APPLE) || (ANGLE_PLATFORM_ANDROID) #if defined(ANGLE_PLATFORM_APPLE) || (ANGLE_PLATFORM_ANDROID)
# include "common/tls.h" # include "common/tls.h"
@ -49,6 +51,71 @@ class [[nodiscard]] ScopedSyncCurrentContextFromThread
egl::Thread *const mThread; egl::Thread *const mThread;
}; };
// Tries to lock "ContextMutex" of the Context current to the "thread".
ANGLE_INLINE ScopedContextMutexLock TryLockCurrentContext(Thread *thread)
{
ASSERT(kIsSharedContextMutexEnabled);
gl::Context *context = thread->getContext();
return context != nullptr ? ScopedContextMutexLock(context->getContextMutex())
: ScopedContextMutexLock();
}
// Tries to lock "ContextMutex" or "SharedContextMutex" of the Context with "contextID" if it is
// valid, in order to safely use the Context from the "thread".
// Note: this function may change mutex type to SharedContextMutex.
ANGLE_INLINE ScopedContextMutexLock TryLockContextForThread(Thread *thread,
Display *display,
gl::ContextID contextID)
{
ASSERT(kIsSharedContextMutexEnabled);
gl::Context *context = GetContextIfValid(display, contextID);
return context != nullptr ? (context == thread->getContext()
? ScopedContextMutexLock(context->getContextMutex())
: context->lockAndActivateSharedContextMutex())
: ScopedContextMutexLock();
}
// Tries to lock "SharedContextMutex" of the Context with "contextID" if it is valid.
// Note: this function will change mutex type to SharedContextMutex.
ANGLE_INLINE ScopedContextMutexLock TryLockAndActivateSharedContextMutex(Display *display,
gl::ContextID contextID)
{
ASSERT(kIsSharedContextMutexEnabled);
gl::Context *context = GetContextIfValid(display, contextID);
return context != nullptr ? context->lockAndActivateSharedContextMutex()
: ScopedContextMutexLock();
}
// Locks "SharedContextMutex" of the "context" and then tries to merge it with the
// "SharedContextMutex" of the Image with "imageID" if it is valid.
// Note: this function may change mutex type to SharedContextMutex.
ANGLE_INLINE ScopedContextMutexLock LockAndTryMergeSharedContextMutexes(gl::Context *context,
ImageID imageID)
{
ASSERT(kIsSharedContextMutexEnabled);
ASSERT(context->getDisplay() != nullptr);
const Image *image = context->getDisplay()->getImage(imageID);
if (image != nullptr)
{
ContextMutex *imageMutex = image->getSharedContextMutex();
if (imageMutex != nullptr)
{
ScopedContextMutexLock lock = context->lockAndActivateSharedContextMutex();
context->mergeSharedContextMutexes(imageMutex);
return lock;
}
}
// Do not activate "SharedContextMutex" if Image is not valid or does not have the mutex.
return ScopedContextMutexLock(context->getContextMutex());
}
#if !defined(ANGLE_ENABLE_SHARED_CONTEXT_MUTEX)
# define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...)
#else
# define ANGLE_EGL_SCOPED_CONTEXT_LOCK(EP, THREAD, ...) \
egl::ScopedContextMutexLock shareContextLock = GetContextLock_##EP(THREAD, ##__VA_ARGS__)
#endif
} // namespace egl } // namespace egl
#define ANGLE_SCOPED_GLOBAL_LOCK() egl::ScopedGlobalMutexLock globalMutexLock #define ANGLE_SCOPED_GLOBAL_LOCK() egl::ScopedGlobalMutexLock globalMutexLock
@ -103,17 +170,25 @@ static ANGLE_INLINE void DirtyContextIfNeeded(Context *context)
#if !defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK) #if !defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK)
# define SCOPED_SHARE_CONTEXT_LOCK(context) # define SCOPED_SHARE_CONTEXT_LOCK(context)
# define SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context) ANGLE_SCOPED_GLOBAL_LOCK() # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
#else #else
# if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL) # if defined(ANGLE_FORCE_CONTEXT_CHECK_EVERY_CALL)
# define SCOPED_SHARE_CONTEXT_LOCK(context) \ # define SCOPED_SHARE_CONTEXT_LOCK(context) \
egl::ScopedGlobalMutexLock shareContextLock; \ egl::ScopedGlobalMutexLock shareContextLock; \
DirtyContextIfNeeded(context) DirtyContextIfNeeded(context)
# define SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context) SCOPED_SHARE_CONTEXT_LOCK(context) # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
# else SCOPED_SHARE_CONTEXT_LOCK(context)
# elif !defined(ANGLE_ENABLE_SHARED_CONTEXT_MUTEX)
# define SCOPED_SHARE_CONTEXT_LOCK(context) \ # define SCOPED_SHARE_CONTEXT_LOCK(context) \
egl::ScopedOptionalGlobalMutexLock shareContextLock(context->isShared()) egl::ScopedOptionalGlobalMutexLock shareContextLock(context->isShared())
# define SCOPED_GLOBAL_AND_SHARE_CONTEXT_LOCK(context) ANGLE_SCOPED_GLOBAL_LOCK() # define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) ANGLE_SCOPED_GLOBAL_LOCK()
# else
# define SCOPED_SHARE_CONTEXT_LOCK(context) \
std::lock_guard<egl::ContextMutex> shareContextLock(*context->getContextMutex())
# define SCOPED_EGL_IMAGE_SHARE_CONTEXT_LOCK(context, imageID) \
ANGLE_SCOPED_GLOBAL_LOCK(); \
egl::ScopedContextMutexLock shareContextLock = \
egl::LockAndTryMergeSharedContextMutexes(context, imageID)
# endif # endif
#endif #endif