[wgpu-headers] Update device lost and uncaptured error callbacks.
- Updates the callbacks to allow for 2 userdatas.
- Updates the C++ DeviceDescriptor to expose setters for the callbacks.
- Updates internal usages to remove to-be-deprecated versions.
Bug: 42241461
Change-Id: I583eb334284ee4ae8d197ed57bd5fee3048be4b8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/192741
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 322883a..9461100 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -1027,6 +1027,13 @@
return [(typ, method) for (_, typ, method) in sorted(unsorted)]
+def find_by_name(members, name):
+ for member in members:
+ if member.name.get() == name:
+ return member
+ assert False
+
+
def has_callback_arguments(method):
return any(arg.type.category == 'function pointer' for arg in method.arguments)
@@ -1047,6 +1054,7 @@
# Function pointers, callback functions, and "void *" types (i.e. userdata) cannot
# be serialized.
return (type.category != 'function pointer'
+ and type.category != 'callback info'
and type.category != 'callback function'
and type.name.get() != 'void *')
@@ -1108,6 +1116,7 @@
'decorate': decorate,
'as_ktName': as_ktName,
'has_callbackInfoStruct': has_callbackInfoStruct,
+ 'find_by_name': find_by_name,
'unreachable_code': unreachable_code
}
diff --git a/generator/templates/api.h b/generator/templates/api.h
index cfc89d2..c6c80fb 100644
--- a/generator/templates/api.h
+++ b/generator/templates/api.h
@@ -167,6 +167,26 @@
#define {{API}}_COMMA ,
+{% for type in by_category["callback info"] %}
+ typedef struct {{as_cType(type.name)}} {
+ {{API}}ChainedStruct const* nextInChain;
+ {% for member in type.members %}
+ {{as_annotated_cType(member)}};
+ {% endfor %}
+ void* userdata1;
+ void* userdata2;
+ } {{as_cType(type.name)}} {{API}}_STRUCTURE_ATTRIBUTE;
+
+ #define {{API}}_{{type.name.SNAKE_CASE()}}_INIT {{API}}_MAKE_INIT_STRUCT({{as_cType(type.name)}}, { \
+ /*.nextInChain=*/nullptr {{API}}_COMMA \
+ {% for member in type.members %}
+ /*.{{as_varName(member.name)}}=*/{{render_c_default_value(member)}} {{API}}_COMMA \
+ {% endfor %}
+ /*.userdata1=*/nullptr {{API}}_COMMA \
+ /*.userdata2=*/nullptr {{API}}_COMMA \
+ })
+
+{% endfor %}
{% for type in by_category["structure"] %}
{% for root in type.chain_roots %}
// Can be chained in {{as_cType(root.name)}}
@@ -202,28 +222,6 @@
})
{% endfor %}
-{% for type in by_category["callback info"] %}
- typedef struct {{as_cType(type.name)}} {
- {{API}}ChainedStruct const* nextInChain;
- {{as_cType(types["callback mode"].name)}} mode;
- {% for member in type.members %}
- //* Only callback function types are allowed in callback info structs.
- {{assert(member.type.category == "callback function")}}{{as_annotated_cType(member)}};
- {% endfor %}
- void* userdata1;
- void* userdata2;
- } {{as_cType(type.name)}} {{API}}_STRUCTURE_ATTRIBUTE;
-
- #define {{API}}_{{type.name.SNAKE_CASE()}}_INIT {{API}}_MAKE_INIT_STRUCT({{as_cType(type.name)}}, { \
- /*.mode=*/{{as_cEnum(types["callback mode"].name, Name("undefined"))}} {{API}}_COMMA \
- {% for member in type.members %}
- /*.{{as_varName(member.name)}}=*/{{render_c_default_value(member)}} {{API}}_COMMA \
- {% endfor %}
- /*.userdata1=*/nullptr {{API}}_COMMA \
- /*.userdata2=*/nullptr {{API}}_COMMA \
- })
-
-{% endfor %}
{% for typeDef in by_category["typedef"] %}
// {{as_cType(typeDef.name)}} is deprecated.
// Use {{as_cType(typeDef.type.name)}} instead.
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 63e097d..70f88c6 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -26,6 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% set API = metadata.api.upper() %}
{% set api = API.lower() %}
+{% set CAPI = metadata.c_prefix %}
{% if 'dawn' in enabled_tags %}
#ifdef __EMSCRIPTEN__
#error "Do not include this header. Emscripten already provides headers needed for {{metadata.api}}."
@@ -35,6 +36,7 @@
#ifndef {{PREFIX}}{{API}}_CPP_H_
#define {{PREFIX}}{{API}}_CPP_H_
+#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdint>
@@ -260,7 +262,7 @@
//* Stripping the 2 at the end of the callback functions for now until we can deprecate old ones.
//* TODO: crbug.com/dawn/2509 - Remove name handling once old APIs are deprecated.
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
{% set SfinaeArg = " = std::enable_if_t<std::is_convertible_v<F, Cb*>>" if not dfn else "" %}
template <typename F, typename T,
typename Cb
@@ -292,7 +294,7 @@
//* Stripping the 2 at the end of the callback functions for now until we can deprecate old ones.
//* TODO: crbug.com/dawn/2509 - Remove name handling once old APIs are deprecated.
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
{% set SfinaeArg = " = std::enable_if_t<std::is_convertible_v<L, Cb>>" if not dfn else "" %}
template <typename L,
typename Cb
@@ -364,7 +366,7 @@
{% macro render_cpp_callback_info_template_method_impl(type, method) %}
{{render_cpp_callback_info_template_method_declaration(type, method, dfn=True)}} {
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
{{as_cType(CallbackInfoType.name)}} callbackInfo = {};
callbackInfo.mode = static_cast<{{as_cType(types["callback mode"].name)}}>(callbackMode);
callbackInfo.callback = [](
@@ -393,7 +395,7 @@
{% macro render_cpp_callback_info_lambda_method_impl(type, method) %}
{{render_cpp_callback_info_lambda_method_declaration(type, method, dfn=True)}} {
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
using F = void (
{%- for arg in CallbackType.arguments -%}
{%- if not loop.first %}, {% endif -%}
@@ -500,7 +502,10 @@
static_assert(offsetof(ChainedStruct, sType) == offsetof({{c_prefix}}ChainedStruct, sType),
"offsetof mismatch for ChainedStruct::sType");
-{% for type in by_category["structure"] %}
+//* Special structures that require some custom code generation.
+{% set SpecialStructures = ["device descriptor"] %}
+
+{% for type in by_category["structure"] if type.name.get() not in SpecialStructures %}
{% set Out = "Out" if type.output else "" %}
{% set const = "const" if not type.output else "" %}
{% if type.chained %}
@@ -550,12 +555,64 @@
{% endfor %}
+//* Device descriptor is specially implemented in C++ in order to hide callback info. Note that
+//* this is placed at the end of the structs and works for the device descriptor because no other
+//* structs include it as a member. In the future for these special structs, we may need to add
+//* a way to order the definitions w.r.t the topology of the structs.
+{% set type = types["device descriptor"] %}
+{% set CppType = as_cppType(type.name) %}
+namespace detail {
+struct {{CppType}} {
+ ChainedStruct const * nextInChain = nullptr;
+ {% for member in type.members %}
+ {% if member.type.category != "callback info" %}
+ {{as_annotated_cppType(member, type.has_free_members_function) + render_cpp_default_value(member, True, type.has_free_members_function)}};
+ {% else %}
+ {{as_annotated_cType(member)}} = {{CAPI}}_{{member.name.SNAKE_CASE()}}_INIT;
+ {% endif %}
+ {% endfor %}
+};
+} // namespace detail
+struct {{CppType}} : protected detail::{{CppType}} {
+ inline operator const {{as_cType(type.name)}}&() const noexcept;
+
+ using detail::{{CppType}}::nextInChain;
+ {% for member in type.members %}
+ {% if member.type.category != "callback info" %}
+ using detail::{{CppType}}::{{as_varName(member.name)}};
+ {% endif %}
+ {% endfor %}
+
+ inline {{CppType}}();
+ struct Init;
+ inline {{CppType}}(Init&& init);
+
+ template <typename F, typename T,
+ typename Cb = void (const Device& device, DeviceLostReason reason, const char * message, T userdata),
+ typename = std::enable_if_t<std::is_convertible_v<F, Cb*>>>
+ void SetDeviceLostCallback(CallbackMode callbackMode, F callback, T userdata);
+ template <typename L,
+ typename Cb = std::function<void(const Device& device, DeviceLostReason reason, const char * message)>,
+ typename = std::enable_if_t<std::is_convertible_v<L, Cb>>>
+ void SetDeviceLostCallback(CallbackMode callbackMode, L callback);
+
+ template <typename F, typename T,
+ typename Cb = void (const Device& device, ErrorType type, const char * message, T userdata),
+ typename = std::enable_if_t<std::is_convertible_v<F, Cb*>>>
+ void SetUncapturedErrorCallback(F callback, T userdata);
+ template <typename L,
+ typename Cb = std::function<void(const Device& device, ErrorType type, const char * message)>,
+ typename = std::enable_if_t<std::is_convertible_v<L, Cb>>>
+ void SetUncapturedErrorCallback(L callback);
+};
+
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
// error: 'offsetof' within non-standard-layout type '{{metadata.namespace}}::XXX' is conditionally-supported
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
-{% for type in by_category["structure"] %}
+
+{% for type in by_category["structure"] if type.name.get() not in SpecialStructures %}
{% set CppType = as_cppType(type.name) %}
{% set CType = as_cType(type.name) %}
// {{CppType}} implementation
@@ -589,7 +646,7 @@
{%- endfor -%}
) {
{{as_cMethodNamespaced(type.name, Name("free members"), c_namespace)}}(
- *reinterpret_cast<{{as_cType(type.name)}}*>(this));
+ *reinterpret_cast<{{CType}}*>(this));
}
}
@@ -608,7 +665,7 @@
}
this->~{{CppType}}();
{% for member in type.members %}
- detail::AsNonConstReference(this->{{member.name.camelCase()}}) = std::move(rhs.{{member.name.camelCase()}});
+ ::{{metadata.namespace}}::detail::AsNonConstReference(this->{{member.name.camelCase()}}) = std::move(rhs.{{member.name.camelCase()}});
{% endfor %}
Reset(rhs);
return *this;
@@ -618,13 +675,13 @@
void {{CppType}}::Reset({{CppType}}& value) {
{{CppType}} defaultValue{};
{% for member in type.members %}
- detail::AsNonConstReference(value.{{member.name.camelCase()}}) = defaultValue.{{member.name.camelCase()}};
+ ::{{metadata.namespace}}::detail::AsNonConstReference(value.{{member.name.camelCase()}}) = defaultValue.{{member.name.camelCase()}};
{% endfor %}
}
{% endif %}
- {{CppType}}::operator const {{as_cType(type.name)}}&() const noexcept {
- return *reinterpret_cast<const {{as_cType(type.name)}}*>(this);
+ {{CppType}}::operator const {{CType}}&() const noexcept {
+ return *reinterpret_cast<const {{CType}}*>(this);
}
static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
@@ -640,6 +697,119 @@
{% endfor %}
{% endfor %}
+//* Special implementation for device descriptor.
+{% set type = types["device descriptor"] %}
+{% set CppType = as_cppType(type.name) %}
+{% set CType = as_cType(type.name) %}
+// {{CppType}} implementation
+
+{{CppType}}::operator const {{CType}}&() const noexcept {
+ return *reinterpret_cast<const {{CType}}*>(this);
+}
+
+{{CppType}}::{{CppType}}() : detail::{{CppType}} {} {
+ static_assert(offsetof({{CppType}}, nextInChain) == offsetof({{CType}}, nextInChain),
+ "offsetof mismatch for {{CppType}}::nextInChain");
+ {% for member in type.members %}
+ {% set memberName = member.name.camelCase() %}
+ static_assert(offsetof({{CppType}}, {{memberName}}) == offsetof({{CType}}, {{memberName}}),
+ "offsetof mismatch for {{CppType}}::{{memberName}}");
+ {% endfor %}
+}
+
+struct {{CppType}}::Init {
+ ChainedStruct const * nextInChain;
+ {% for member in type.members if member.type.category != "callback info" %}
+ {% set member_declaration = as_annotated_cppType(member, type.has_free_members_function) + render_cpp_default_value(member, True, type.has_free_members_function) %}
+ {{member_declaration}};
+ {% endfor %}
+};
+
+{{CppType}}::{{CppType}}({{CppType}}::Init&& init) : detail::{{CppType}} {
+ init.nextInChain
+ {%- for member in type.members if member.type.category != "callback info" -%},{{" "}}
+ std::move(init.{{as_varName(member.name)}})
+ {%- endfor -%}
+} {}
+
+static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
+static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
+
+template <typename F, typename T, typename Cb, typename>
+void {{CppType}}::SetDeviceLostCallback(CallbackMode callbackMode, F callback, T userdata) {
+ assert(deviceLostCallbackInfo2.callback == nullptr);
+
+ deviceLostCallbackInfo2.mode = static_cast<WGPUCallbackMode>(callbackMode);
+ deviceLostCallbackInfo2.callback = [](WGPUDevice const * device, WGPUDeviceLostReason reason, char const * message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<Cb*>(callback);
+ // We manually acquire and release the device to avoid changing any ref counts.
+ auto apiDevice = Device::Acquire(*device);
+ (*cb)(apiDevice, static_cast<DeviceLostReason>(reason), message, static_cast<T>(userdata));
+ apiDevice.MoveToCHandle();
+ };
+ deviceLostCallbackInfo2.userdata1 = reinterpret_cast<void*>(+callback);
+ deviceLostCallbackInfo2.userdata2 = reinterpret_cast<void*>(userdata);
+}
+
+template <typename L, typename Cb, typename>
+void {{CppType}}::SetDeviceLostCallback(CallbackMode callbackMode, L callback) {
+ assert(deviceLostCallbackInfo2.callback == nullptr);
+ using F = void (const Device& device, DeviceLostReason reason, const char * message);
+
+ deviceLostCallbackInfo2.mode = static_cast<WGPUCallbackMode>(callbackMode);
+ if constexpr (std::is_convertible_v<L, F*>) {
+ deviceLostCallbackInfo2.callback = [](WGPUDevice const * device, WGPUDeviceLostReason reason, char const * message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<F*>(callback);
+ // We manually acquire and release the device to avoid changing any ref counts.
+ auto apiDevice = Device::Acquire(*device);
+ (*cb)(apiDevice, static_cast<DeviceLostReason>(reason), message);
+ apiDevice.MoveToCHandle();
+ };
+ deviceLostCallbackInfo2.userdata1 = reinterpret_cast<void*>(+callback);
+ deviceLostCallbackInfo2.userdata2 = nullptr;
+ } else {
+ auto* lambda = new L(std::move(callback));
+ deviceLostCallbackInfo2.callback = [](WGPUDevice const * device, WGPUDeviceLostReason reason, char const * message, void* callback, void*) {
+ std::unique_ptr<L> lambda(reinterpret_cast<L*>(callback));
+ // We manually acquire and release the device to avoid changing any ref counts.
+ auto apiDevice = Device::Acquire(*device);
+ (*lambda)(apiDevice, static_cast<DeviceLostReason>(reason), message);
+ apiDevice.MoveToCHandle();
+ };
+ deviceLostCallbackInfo2.userdata1 = reinterpret_cast<void*>(lambda);
+ deviceLostCallbackInfo2.userdata2 = nullptr;
+ }
+}
+
+template <typename F, typename T, typename Cb, typename>
+void {{CppType}}::SetUncapturedErrorCallback(F callback, T userdata) {
+ uncapturedErrorCallbackInfo2.callback = [](WGPUDevice const * device, WGPUErrorType type, char const * message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<Cb*>(callback);
+ // We manually acquire and release the device to avoid changing any ref counts.
+ auto apiDevice = Device::Acquire(*device);
+ (*cb)(apiDevice, static_cast<ErrorType>(type), message, static_cast<T>(userdata));
+ apiDevice.MoveToCHandle();
+ };
+ uncapturedErrorCallbackInfo2.userdata1 = reinterpret_cast<void*>(+callback);
+ uncapturedErrorCallbackInfo2.userdata2 = reinterpret_cast<void*>(userdata);
+}
+
+template <typename L, typename Cb, typename>
+void {{CppType}}::SetUncapturedErrorCallback(L callback) {
+ using F = void (const Device& device, ErrorType type, const char * message);
+ static_assert(std::is_convertible_v<L, F*>, "Uncaptured error callback cannot be a binding lambda");
+
+ uncapturedErrorCallbackInfo2.callback = [](WGPUDevice const * device, WGPUErrorType type, char const * message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<F*>(callback);
+ // We manually acquire and release the device to avoid changing any ref counts.
+ auto apiDevice = Device::Acquire(*device);
+ (*cb)(apiDevice, static_cast<ErrorType>(type), message);
+ apiDevice.MoveToCHandle();
+ };
+ uncapturedErrorCallbackInfo2.userdata1 = reinterpret_cast<void*>(+callback);
+ uncapturedErrorCallbackInfo2.userdata2 = nullptr;
+}
+
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/generator/templates/art/api_kotlin_types.kt b/generator/templates/art/api_kotlin_types.kt
index d37e0ad..fa8cad2 100644
--- a/generator/templates/art/api_kotlin_types.kt
+++ b/generator/templates/art/api_kotlin_types.kt
@@ -47,7 +47,7 @@
{%- elif type.category in ['function pointer', 'object'] %}
{{- type.name.CamelCase() }}
{%- if optional or default_value %}?{{ ' = null' if emit_defaults }}{% endif %}
- {%- elif type.category == 'structure' %}
+ {%- elif type.category == 'structure' or type.category == 'callback info' %}
{{- type.name.CamelCase() }}{{ '?' if optional }}
{%- if emit_defaults -%}
{%- if type.has_basic_constructor -%}
diff --git a/generator/templates/art/structures.cpp b/generator/templates/art/structures.cpp
index af901f4..a57fb37 100644
--- a/generator/templates/art/structures.cpp
+++ b/generator/templates/art/structures.cpp
@@ -136,7 +136,7 @@
env->CallLongMethod(mObj, getHandle));
}
}
- {% elif member.type.category == 'structure' %}
+ {% elif member.type.category == 'structure' or member.type.category == 'callback info' %}
//* Mandatory structure.
Convert(env, env->CallObjectMethod(obj,
env->GetMethodID(clz, "get{{ member.name.CamelCase() }}",
diff --git a/generator/templates/dawn/native/api_structs.cpp b/generator/templates/dawn/native/api_structs.cpp
index 4b4c529..c8e7148 100644
--- a/generator/templates/dawn/native/api_structs.cpp
+++ b/generator/templates/dawn/native/api_structs.cpp
@@ -108,12 +108,12 @@
return {% if type.extensible or type.chained -%}
(nextInChain == rhs.nextInChain) &&
{%- endif %} std::tie(
- {% for member in type.members %}
+ {% for member in type.members if member.type.category != 'callback info' %}
{{member.name.camelCase()-}}
{{ "," if not loop.last else "" }}
{% endfor %}
) == std::tie(
- {% for member in type.members %}
+ {% for member in type.members if member.type.category != 'callback info' %}
rhs.{{member.name.camelCase()-}}
{{ "," if not loop.last else "" }}
{% endfor %}
diff --git a/generator/templates/dawn/native/api_structs.h b/generator/templates/dawn/native/api_structs.h
index ae28708..36f0e71 100644
--- a/generator/templates/dawn/native/api_structs.h
+++ b/generator/templates/dawn/native/api_structs.h
@@ -32,6 +32,7 @@
#define {{DIR}}_{{namespace.upper()}}_STRUCTS_H_
{% set api = metadata.api.lower() %}
+{% set CAPI = metadata.c_prefix %}
#include "dawn/{{api}}_cpp.h"
{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
{% set native_namespace = namespace_name.namespace_case() %}
@@ -46,6 +47,8 @@
{{" "}}= nullptr
{%- elif member.type.category == "object" and member.optional -%}
{{" "}}= nullptr
+ {%- elif member.type.category == "callback info" -%}
+ {{" "}}= {{CAPI}}_{{member.name.SNAKE_CASE()}}_INIT
{%- elif member.type.category in ["enum", "bitmask"] and member.default_value != None -%}
{{" "}}= {{namespace}}::{{as_cppType(member.type.name)}}::{{as_cppEnum(Name(member.default_value))}}
{%- elif member.type.category == "native" and member.default_value != None -%}
diff --git a/generator/templates/dawn/wire/WireCmd.cpp b/generator/templates/dawn/wire/WireCmd.cpp
index 0ff5801..efcfe0e 100644
--- a/generator/templates/dawn/wire/WireCmd.cpp
+++ b/generator/templates/dawn/wire/WireCmd.cpp
@@ -107,6 +107,8 @@
{%- endif -%}
));
{%- endif -%}
+ {%- elif member.type.category == 'callback info' %}
+ {{out}} = WGPU_{{member.type.name.SNAKE_CASE()}}_INIT;
{%- elif not is_wire_serializable(member.type) %}
{{out}} = nullptr;
{%- elif member.type.name.get() == "size_t" -%}
@@ -267,8 +269,8 @@
//* "length", but order is not always given.
{% for member in members | sort(reverse=true, attribute="annotation") %}
{% set memberName = as_varName(member.name) %}
- //* Skip serialization for custom serialized members.
- {% if member.skip_serialize %}
+ //* Skip serialization for custom serialized members and callback infos.
+ {% if member.skip_serialize or member.type.category == 'callback info' %}
{% continue %}
{% endif %}
//* Value types are directly in the transfer record, objects being replaced with their IDs.
diff --git a/generator/templates/mock_api.cpp b/generator/templates/mock_api.cpp
index 7cd252a..7e28170 100644
--- a/generator/templates/mock_api.cpp
+++ b/generator/templates/mock_api.cpp
@@ -76,12 +76,11 @@
//* Generate the older Call*Callback if there is no Future call equivalent.
//* Includes:
-//* - setUncapturedErrorCallback
//* - setLoggingCallback
-{% set LegacyCallbackFunctions = ['set uncaptured error callback', 'set logging callback'] %}
+{% set LegacyCallbackFunctions = ['set logging callback'] %}
//* Manually implemented mock functions due to incompatibility.
-{% set ManuallyMockedFunctions = ['set device lost callback'] %}
+{% set ManuallyMockedFunctions = ['set device lost callback', 'set uncaptured error callback'] %}
{% for type in by_category["object"] %}
{% for method in type.methods if method.name.get() not in ManuallyMockedFunctions %}
@@ -168,7 +167,7 @@
return {mNextFutureID++};
}
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
void ProcTableAsClass::Call{{Suffix}}Callback(
{{-as_cType(type.name)}} {{as_varName(type.name)}}
{%- for arg in CallbackType.arguments -%}
@@ -223,13 +222,21 @@
{% endfor %}
{% endfor %}
-// Manually implement device lost related callback helpers for testing.
+// Manually implement some callback helpers for testing.
void ProcTableAsClass::DeviceSetDeviceLostCallback(WGPUDevice device,
WGPUDeviceLostCallback callback,
void* userdata) {
ProcTableAsClass::Object* object = reinterpret_cast<ProcTableAsClass::Object*>(device);
- object->mDeviceLostOldCallback = callback;
- object->mDeviceLostUserdata = userdata;
+ object->mDeviceLostCallback = [](WGPUDevice const*, WGPUDeviceLostReason reason,
+ char const* message, void* callback, void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUDeviceLostCallback>(callback);
+ cb(reason, message, userdata);
+ };
+ object->mDeviceLostUserdata1 = reinterpret_cast<void*>(callback);
+ object->mDeviceLostUserdata2 = userdata;
OnDeviceSetDeviceLostCallback(device, callback, userdata);
}
@@ -237,12 +244,32 @@
WGPUDeviceLostReason reason,
char const* message) {
ProcTableAsClass::Object* object = reinterpret_cast<ProcTableAsClass::Object*>(device);
- // If we have an old callback set, call that one, otherwise call the new one.
- if (object->mDeviceLostOldCallback != nullptr) {
- object->mDeviceLostOldCallback(reason, message, object->mDeviceLostUserdata);
- } else {
- object->mDeviceLostCallback(&device, reason, message, object->mDeviceLostUserdata);
- }
+ object->mDeviceLostCallback(&device, reason, message, object->mDeviceLostUserdata1,
+ object->mDeviceLostUserdata2);
+}
+void ProcTableAsClass::DeviceSetUncapturedErrorCallback(WGPUDevice device,
+ WGPUErrorCallback callback,
+ void* userdata) {
+ ProcTableAsClass::Object* object = reinterpret_cast<ProcTableAsClass::Object*>(device);
+ object->mUncapturedErrorCallback = [](WGPUDevice const*, WGPUErrorType type,
+ char const* message, void* callback, void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUErrorCallback>(callback);
+ cb(type, message, userdata);
+ };
+ object->mUncapturedErrorUserdata1 = reinterpret_cast<void*>(callback);
+ object->mUncapturedErrorUserdata2 = userdata;
+
+ OnDeviceSetUncapturedErrorCallback(device, callback, userdata);
+}
+void ProcTableAsClass::CallDeviceSetUncapturedErrorCallbackCallback(WGPUDevice device,
+ WGPUErrorType type,
+ char const* message) {
+ ProcTableAsClass::Object* object = reinterpret_cast<ProcTableAsClass::Object*>(device);
+ object->mUncapturedErrorCallback(&device, type, message, object->mUncapturedErrorUserdata1,
+ object->mUncapturedErrorUserdata2);
}
{% for type in by_category["object"] %}
diff --git a/generator/templates/mock_api.h b/generator/templates/mock_api.h
index 45b5713..acaf37f 100644
--- a/generator/templates/mock_api.h
+++ b/generator/templates/mock_api.h
@@ -60,13 +60,11 @@
//* Generate the older Call*Callback if there is no Future call equivalent.
//* Includes:
- //* - setDeviceLostCallback
- //* - setUncapturedErrorCallback
//* - setLoggingCallback
- {%- set LegacyCallbackFunctions = ['set uncaptured error callback', 'set logging callback'] %}
+ {%- set LegacyCallbackFunctions = ['set logging callback'] %}
//* Manually implemented mock functions due to incompatibility.
- {% set ManuallyMockedFunctions = ['set device lost callback'] %}
+ {% set ManuallyMockedFunctions = ['set device lost callback', 'set uncaptured error callback'] %}
{%- for type in by_category["object"] %}
@@ -103,7 +101,7 @@
{%- endfor -%}
) = 0;
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
void Call{{Suffix}}Callback(
{{-as_cType(type.name)}} {{as_varName(type.name)}}
{%- for arg in CallbackType.arguments -%}
@@ -145,7 +143,7 @@
{% endfor %}
{% endfor %}
- // Manually implement device lost related callback helpers for testing.
+ // Manually implement some callback helpers for testing.
void DeviceSetDeviceLostCallback(WGPUDevice device,
WGPUDeviceLostCallback callback,
void* userdata);
@@ -155,6 +153,15 @@
void CallDeviceSetDeviceLostCallbackCallback(WGPUDevice device,
WGPUDeviceLostReason reason,
char const* message);
+ void DeviceSetUncapturedErrorCallback(WGPUDevice device,
+ WGPUErrorCallback callback,
+ void* userdata);
+ virtual void OnDeviceSetUncapturedErrorCallback(WGPUDevice device,
+ WGPUErrorCallback callback,
+ void* userdata) = 0;
+ void CallDeviceSetUncapturedErrorCallbackCallback(WGPUDevice device,
+ WGPUErrorType type,
+ char const* message);
struct Object {
ProcTableAsClass* procs = nullptr;
@@ -173,16 +180,19 @@
{% endfor %}
{% for method in type.methods if has_callbackInfoStruct(method) %}
{% set CallbackInfoType = (method.arguments|last).type %}
- {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set CallbackType = find_by_name(CallbackInfoType.members, "callback").type %}
void* m{{as_CppMethodSuffix(type.name, method.name)}}Userdata1 = 0;
void* m{{as_CppMethodSuffix(type.name, method.name)}}Userdata2 = 0;
{{as_cType(CallbackType.name)}} m{{as_CppMethodSuffix(type.name, method.name)}}Callback = nullptr;
{% endfor %}
{% endfor %}
- // Manually implement device lost related callback helpers for testing.
- WGPUDeviceLostCallback mDeviceLostOldCallback = nullptr;
- WGPUDeviceLostCallbackNew mDeviceLostCallback = nullptr;
- void* mDeviceLostUserdata = 0;
+ // Manually implement some callback helpers for testing.
+ WGPUDeviceLostCallback2 mDeviceLostCallback = nullptr;
+ void* mDeviceLostUserdata1 = 0;
+ void* mDeviceLostUserdata2 = 0;
+ WGPUUncapturedErrorCallback mUncapturedErrorCallback = nullptr;
+ void* mUncapturedErrorUserdata1 = 0;
+ void* mUncapturedErrorUserdata2 = 0;
};
private:
@@ -233,11 +243,15 @@
{% endfor %}
{% endfor %}
- // Manually implement device lost related callback helpers for testing.
+ // Manually implement some callback helpers for testing.
MOCK_METHOD(void,
OnDeviceSetDeviceLostCallback,
(WGPUDevice device, WGPUDeviceLostCallback callback, void* userdata),
(override));
+ MOCK_METHOD(void,
+ OnDeviceSetUncapturedErrorCallback,
+ (WGPUDevice device, WGPUErrorCallback callback, void* userdata),
+ (override));
};
#endif // MOCK_{{API}}_H
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 0141ecd..93c5501 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -101,7 +101,8 @@
"request adapter callback info 2": {
"category": "callback info",
"members": [
- {"name": "callback", "type": "request adapter callback 2"}
+ {"name": "mode", "type": "callback mode"},
+ {"name": "callback", "type": "request adapter callback 2"}
]
},
"request adapter status": {
@@ -258,7 +259,9 @@
{"name": "device lost callback", "type": "device lost callback", "default": "nullptr", "tags": ["deprecated"]},
{"name": "device lost userdata", "type": "void *", "default": "nullptr", "tags": ["deprecated"]},
{"name": "device lost callback info", "type": "device lost callback info"},
- {"name": "uncaptured error callback info", "type": "uncaptured error callback info"}
+ {"name": "uncaptured error callback info", "type": "uncaptured error callback info"},
+ {"name": "device lost callback info 2", "type": "device lost callback info 2"},
+ {"name": "uncaptured error callback info 2", "type": "uncaptured error callback info 2"}
]
},
"dawn toggles descriptor": {
@@ -728,6 +731,7 @@
"buffer map callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "buffer map callback 2"}
]
},
@@ -1014,6 +1018,7 @@
"compilation info callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "compilation info callback 2"}
]
},
@@ -1240,6 +1245,7 @@
"create compute pipeline async callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "create compute pipeline async callback 2"}
]
},
@@ -1285,6 +1291,7 @@
"create render pipeline async callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "create render pipeline async callback 2"}
]
},
@@ -1686,6 +1693,14 @@
{"name": "userdata", "type": "void *"}
]
},
+ "device lost callback 2": {
+ "category": "callback function",
+ "args": [
+ {"name": "device", "type": "device", "annotation": "const*", "length": 1},
+ {"name": "reason", "type": "device lost reason"},
+ {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
+ ]
+ },
"device lost callback info": {
"category": "structure",
"extensible": "in",
@@ -1695,6 +1710,13 @@
{"name": "userdata", "type": "void *", "default": "nullptr"}
]
},
+ "device lost callback info 2": {
+ "category": "callback info",
+ "members": [
+ {"name": "mode", "type": "callback mode"},
+ {"name": "callback", "type": "device lost callback 2", "default": "nullptr"}
+ ]
+ },
"device lost reason": {
"category": "enum",
"emscripten_no_enum_table": true,
@@ -1716,6 +1738,14 @@
{"name": "userdata", "type": "void *"}
]
},
+ "uncaptured error callback": {
+ "category": "callback function",
+ "args": [
+ {"name": "device", "type": "device", "annotation": "const*", "length": 1},
+ {"name": "type", "type": "error type"},
+ {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
+ ]
+ },
"uncaptured error callback info": {
"category": "structure",
"extensible": "in",
@@ -1724,6 +1754,12 @@
{"name": "userdata", "type": "void *", "default": "nullptr"}
]
},
+ "uncaptured error callback info 2": {
+ "category": "callback info",
+ "members": [
+ {"name": "callback", "type": "uncaptured error callback", "default": "nullptr"}
+ ]
+ },
"pop error scope status": {
"category": "enum",
"emscripten_no_enum_table": true,
@@ -1762,6 +1798,7 @@
"pop error scope callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "pop error scope callback 2"}
]
},
@@ -2999,6 +3036,7 @@
"queue work done callback info 2": {
"category": "callback info",
"members": [
+ {"name": "mode", "type": "callback mode"},
{"name": "callback", "type": "queue work done callback 2"}
]
},
@@ -3449,7 +3487,8 @@
"request device callback info 2": {
"category": "callback info",
"members": [
- {"name": "callback", "type": "request device callback 2"}
+ {"name": "mode", "type": "callback mode"},
+ {"name": "callback", "type": "request device callback 2"}
]
},
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index e0ac3fd..3504aab 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -165,21 +165,53 @@
raw_ptr<void> mUserdata;
};
-static constexpr UncapturedErrorCallbackInfo kEmptyUncapturedErrorCallbackInfo = {nullptr, nullptr,
- nullptr};
+void LegacyDeviceLostCallback(WGPUDevice const* device,
+ WGPUDeviceLostReason reason,
+ char const* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUDeviceLostCallback>(callback);
+ cb(reason, message, userdata);
+}
+
+void LegacyDeviceLostCallback2(WGPUDevice const* device,
+ WGPUDeviceLostReason reason,
+ char const* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUDeviceLostCallbackNew>(callback);
+ cb(device, reason, message, userdata);
+}
+
+void LegacyUncapturedErrorCallback(WGPUDevice const* device,
+ WGPUErrorType type,
+ const char* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUErrorCallback>(callback);
+ cb(type, message, userdata);
+}
+
+static constexpr WGPUUncapturedErrorCallbackInfo2 kEmptyUncapturedErrorCallbackInfo = {
+ nullptr, nullptr, nullptr, nullptr};
} // anonymous namespace
-DeviceBase::DeviceLostEvent::DeviceLostEvent(const DeviceLostCallbackInfo& callbackInfo)
- : TrackedEvent(callbackInfo.mode, SystemEvent::CreateNonProgressingEvent()),
- mCallback(callbackInfo.callback),
- mUserdata(callbackInfo.userdata) {}
-
-DeviceBase::DeviceLostEvent::DeviceLostEvent(wgpu::DeviceLostCallback oldCallback, void* userdata)
- : TrackedEvent(wgpu::CallbackMode::AllowProcessEvents,
+DeviceBase::DeviceLostEvent::DeviceLostEvent(const WGPUDeviceLostCallbackInfo2& callbackInfo)
+ : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
SystemEvent::CreateNonProgressingEvent()),
- mOldCallback(oldCallback),
- mUserdata(userdata) {}
+ mCallback(callbackInfo.callback),
+ mUserdata1(callbackInfo.userdata1),
+ mUserdata2(callbackInfo.userdata2) {}
DeviceBase::DeviceLostEvent::~DeviceLostEvent() {
EnsureComplete(EventCompletionType::Shutdown);
@@ -192,9 +224,9 @@
#if defined(DAWN_ENABLE_ASSERTS)
// TODO(crbug.com/dawn/2465) Make default AllowSpontaneous once SetDeviceLostCallback is gone.
- static constexpr DeviceLostCallbackInfo kDefaultDeviceLostCallbackInfo = {
- nullptr, wgpu::CallbackMode::AllowProcessEvents,
- [](WGPUDevice const*, WGPUDeviceLostReason, char const*, void*) {
+ static constexpr WGPUDeviceLostCallbackInfo2 kDefaultDeviceLostCallbackInfo = {
+ nullptr, WGPUCallbackMode_AllowProcessEvents,
+ [](WGPUDevice const*, WGPUDeviceLostReason, char const*, void*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
@@ -203,35 +235,31 @@
"suppress this message, set the callback explicitly.";
}
},
- nullptr};
+ nullptr, nullptr};
#else
- static constexpr DeviceLostCallbackInfo kDefaultDeviceLostCallbackInfo = {
- nullptr, wgpu::CallbackMode::AllowProcessEvents, nullptr, nullptr};
+ static constexpr WGPUDeviceLostCallbackInfo2 kDefaultDeviceLostCallbackInfo = {
+ nullptr, WGPUCallbackMode_AllowProcessEvents, nullptr, nullptr, nullptr};
#endif // DAWN_ENABLE_ASSERTS
- Ref<DeviceBase::DeviceLostEvent> lostEvent;
- if (descriptor->deviceLostCallback != nullptr) {
+ WGPUDeviceLostCallbackInfo2 deviceLostCallbackInfo = kDefaultDeviceLostCallbackInfo;
+ if (descriptor->deviceLostCallbackInfo2.callback != nullptr) {
+ deviceLostCallbackInfo = descriptor->deviceLostCallbackInfo2;
+ } else if (descriptor->deviceLostCallbackInfo.callback != nullptr) {
+ auto& callbackInfo = descriptor->deviceLostCallbackInfo;
+ deviceLostCallbackInfo = {
+ ToAPI(callbackInfo.nextInChain), ToAPI(callbackInfo.mode), &LegacyDeviceLostCallback2,
+ reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata};
+ } else if (descriptor->deviceLostCallback != nullptr) {
dawn::WarningLog()
<< "DeviceDescriptor.deviceLostCallback and DeviceDescriptor.deviceLostUserdata are "
"deprecated. Use DeviceDescriptor.deviceLostCallbackInfo instead.";
- lostEvent = AcquireRef(new DeviceBase::DeviceLostEvent(descriptor->deviceLostCallback,
- descriptor->deviceLostUserdata));
- } else {
- DeviceLostCallbackInfo deviceLostCallbackInfo = kDefaultDeviceLostCallbackInfo;
- if (descriptor->deviceLostCallbackInfo.callback != nullptr ||
- descriptor->deviceLostCallbackInfo.mode != wgpu::CallbackMode::WaitAnyOnly) {
- deviceLostCallbackInfo = descriptor->deviceLostCallbackInfo;
- if (deviceLostCallbackInfo.mode != wgpu::CallbackMode::AllowSpontaneous) {
- // TODO(dawn:2458) Currently we default the callback mode to ProcessEvents if not
- // passed for backwards compatibility. We should add warning logging for it though
- // when available.
- deviceLostCallbackInfo.mode = wgpu::CallbackMode::AllowProcessEvents;
- }
- }
- lostEvent = AcquireRef(new DeviceBase::DeviceLostEvent(deviceLostCallbackInfo));
+ deviceLostCallbackInfo = {nullptr, WGPUCallbackMode_AllowProcessEvents,
+ &LegacyDeviceLostCallback,
+ reinterpret_cast<void*>(descriptor->deviceLostCallback),
+ descriptor->deviceLostUserdata};
}
- return lostEvent;
+ return AcquireRef(new DeviceBase::DeviceLostEvent(deviceLostCallbackInfo));
}
void DeviceBase::DeviceLostEvent::Complete(EventCompletionType completionType) {
@@ -239,17 +267,25 @@
mReason = wgpu::DeviceLostReason::InstanceDropped;
mMessage = "A valid external Instance reference no longer exists.";
}
+
+ auto device = ToAPI(mDevice.Get());
+ void* userdata1 = mUserdata1.ExtractAsDangling();
+ void* userdata2 = mUserdata2.ExtractAsDangling();
+
if (mReason == wgpu::DeviceLostReason::InstanceDropped ||
mReason == wgpu::DeviceLostReason::FailedCreation) {
- mDevice = nullptr;
+ device = nullptr;
+ }
+ if (mCallback) {
+ mCallback(&device, ToAPI(mReason), mMessage.c_str(), userdata1, userdata2);
}
- if (mOldCallback) {
- mOldCallback(ToAPI(mReason), mMessage.c_str(), mUserdata.ExtractAsDangling());
- } else if (mCallback) {
- auto device = ToAPI(mDevice.Get());
- mCallback(&device, ToAPI(mReason), mMessage.c_str(), mUserdata.ExtractAsDangling());
+ // After the device lost callback fires, the uncaptured error callback is no longer valid so we
+ // unset it here.
+ if (mDevice != nullptr) {
+ mDevice->mUncapturedErrorCallbackInfo = kEmptyUncapturedErrorCallbackInfo;
}
+
mDevice = nullptr;
}
@@ -313,9 +349,9 @@
mLostEvent->mDevice = this;
#if defined(DAWN_ENABLE_ASSERTS)
- static constexpr UncapturedErrorCallbackInfo kDefaultUncapturedErrorCallbackInfo = {
+ static constexpr WGPUUncapturedErrorCallbackInfo2 kDefaultUncapturedErrorCallbackInfo = {
nullptr,
- [](WGPUErrorType, char const*, void*) {
+ [](WGPUDevice const*, WGPUErrorType, char const*, void*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
@@ -324,14 +360,19 @@
"and suppress this message, set the callback explicitly.";
}
},
- nullptr};
+ nullptr, nullptr};
#else
- static constexpr UncapturedErrorCallbackInfo kDefaultUncapturedErrorCallbackInfo =
+ static constexpr WGPUUncapturedErrorCallbackInfo2 kDefaultUncapturedErrorCallbackInfo =
kEmptyUncapturedErrorCallbackInfo;
#endif // DAWN_ENABLE_ASSERTS
mUncapturedErrorCallbackInfo = kDefaultUncapturedErrorCallbackInfo;
- if (descriptor->uncapturedErrorCallbackInfo.callback != nullptr) {
- mUncapturedErrorCallbackInfo = descriptor->uncapturedErrorCallbackInfo;
+ if (descriptor->uncapturedErrorCallbackInfo2.callback != nullptr) {
+ mUncapturedErrorCallbackInfo = descriptor->uncapturedErrorCallbackInfo2;
+ } else if (descriptor->uncapturedErrorCallbackInfo.callback != nullptr) {
+ auto& callbackInfo = descriptor->uncapturedErrorCallbackInfo;
+ mUncapturedErrorCallbackInfo = {
+ ToAPI(callbackInfo.nextInChain), &LegacyUncapturedErrorCallback,
+ reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata};
}
AdapterProperties adapterProperties;
@@ -406,7 +447,8 @@
mFormatTable = BuildFormatTable(this);
DeviceDescriptor desc = {};
- desc.deviceLostCallbackInfo = {nullptr, wgpu::CallbackMode::AllowSpontaneous};
+ desc.deviceLostCallbackInfo2 = {nullptr, WGPUCallbackMode_AllowSpontaneous, nullptr, nullptr,
+ nullptr};
mLostEvent = DeviceLostEvent::Create(&desc);
mLostEvent->mDevice = this;
}
@@ -751,9 +793,10 @@
// Only call the uncaptured error callback if the device is alive. After the
// device is lost, the uncaptured error callback should cease firing.
if (mUncapturedErrorCallbackInfo.callback != nullptr && mState == State::Alive) {
+ auto device = ToAPI(this);
mUncapturedErrorCallbackInfo.callback(
- static_cast<WGPUErrorType>(ToWGPUErrorType(type)), messageStr.c_str(),
- mUncapturedErrorCallbackInfo.userdata);
+ &device, ToAPI(ToWGPUErrorType(type)), messageStr.c_str(),
+ mUncapturedErrorCallbackInfo.userdata1, mUncapturedErrorCallbackInfo.userdata2);
}
}
}
@@ -772,6 +815,10 @@
}
void DeviceBase::APISetUncapturedErrorCallback(wgpu::ErrorCallback callback, void* userdata) {
+ GetInstance()->EmitDeprecationWarning(
+ "SetUncapturedErrorCallback is deprecated. Pass the callback in the device descriptor "
+ "instead.");
+
// The registered callback function and userdata pointer are stored and used by deferred
// callback tasks, and after setting a different callback (especially in the case of
// resetting) the resources pointed by such pointer may be freed. Flush all deferred
@@ -788,7 +835,8 @@
if (IsLost()) {
return;
}
- mUncapturedErrorCallbackInfo = {nullptr, callback, userdata};
+ mUncapturedErrorCallbackInfo = {nullptr, &LegacyUncapturedErrorCallback,
+ reinterpret_cast<void*>(callback), userdata};
}
void DeviceBase::APISetDeviceLostCallback(wgpu::DeviceLostCallback callback, void* userdata) {
@@ -806,15 +854,16 @@
// after Dawn device is destroyed and before Dawn wire server is destroyed.
if (callback == nullptr) {
mLostEvent->mCallback = nullptr;
- mLostEvent->mOldCallback = nullptr;
- mLostEvent->mUserdata = nullptr;
+ mLostEvent->mUserdata1 = nullptr;
+ mLostEvent->mUserdata2 = nullptr;
return;
}
if (IsLost()) {
return;
}
- mLostEvent->mOldCallback = callback;
- mLostEvent->mUserdata = userdata;
+ mLostEvent->mCallback = &LegacyDeviceLostCallback;
+ mLostEvent->mUserdata1 = reinterpret_cast<void*>(callback);
+ mLostEvent->mUserdata2 = userdata;
}
void DeviceBase::APIPushErrorScope(wgpu::ErrorFilter filter) {
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index f8288c5..e7d3e9c 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -96,17 +96,14 @@
wgpu::DeviceLostReason mReason;
std::string mMessage;
- wgpu::DeviceLostCallbackNew mCallback = nullptr;
- // TODO(https://crbug.com/dawn/2465): Remove old callback when setters are deprecated, and
- // move userdata into private.
- wgpu::DeviceLostCallback mOldCallback = nullptr;
- raw_ptr<void> mUserdata;
+ WGPUDeviceLostCallback2 mCallback = nullptr;
+ raw_ptr<void> mUserdata1;
+ raw_ptr<void> mUserdata2;
// Note that the device is set when the event is passed to construct a device.
Ref<DeviceBase> mDevice = nullptr;
private:
- explicit DeviceLostEvent(const DeviceLostCallbackInfo& callbackInfo);
- DeviceLostEvent(wgpu::DeviceLostCallback oldCallback, void* userdata);
+ explicit DeviceLostEvent(const WGPUDeviceLostCallbackInfo2& callbackInfo);
~DeviceLostEvent() override;
void Complete(EventCompletionType completionType) override;
@@ -550,7 +547,7 @@
const TextureCopy& dst,
const Extent3D& copySizePixels) = 0;
- UncapturedErrorCallbackInfo mUncapturedErrorCallbackInfo;
+ WGPUUncapturedErrorCallbackInfo2 mUncapturedErrorCallbackInfo;
std::shared_mutex mLoggingMutex;
wgpu::LoggingCallback mLoggingCallback = nullptr;
diff --git a/src/dawn/tests/DawnNativeTest.cpp b/src/dawn/tests/DawnNativeTest.cpp
index 3009641..89b69cf 100644
--- a/src/dawn/tests/DawnNativeTest.cpp
+++ b/src/dawn/tests/DawnNativeTest.cpp
@@ -81,7 +81,6 @@
adapter = instance->EnumerateAdapters(&options)[0];
device = wgpu::Device::Acquire(CreateTestDevice());
- device.SetUncapturedErrorCallback(DawnNativeTest::OnDeviceError, nullptr);
}
std::unique_ptr<dawn::platform::Platform> DawnNativeTest::CreateTestPlatform() {
@@ -89,11 +88,12 @@
}
WGPUDevice DawnNativeTest::CreateTestDevice() {
- return adapter.CreateDevice();
-}
+ wgpu::DeviceDescriptor desc = {};
+ desc.SetUncapturedErrorCallback(
+ [](const wgpu::Device&, wgpu::ErrorType type, const char* message) {
+ DAWN_ASSERT(type != wgpu::ErrorType::NoError);
+ FAIL() << "Unexpected error: " << message;
+ });
-// static
-void DawnNativeTest::OnDeviceError(WGPUErrorType type, const char* message, void* userdata) {
- DAWN_ASSERT(type != WGPUErrorType_NoError);
- FAIL() << "Unexpected error: " << message;
+ return adapter.CreateDevice(&desc);
}
diff --git a/src/dawn/tests/DawnNativeTest.h b/src/dawn/tests/DawnNativeTest.h
index 0dca092..831315a 100644
--- a/src/dawn/tests/DawnNativeTest.h
+++ b/src/dawn/tests/DawnNativeTest.h
@@ -53,7 +53,7 @@
void SetUp() override;
virtual std::unique_ptr<dawn::platform::Platform> CreateTestPlatform();
- virtual WGPUDevice CreateTestDevice();
+ WGPUDevice CreateTestDevice();
protected:
std::unique_ptr<dawn::platform::Platform> platform;
diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp
index fdfe569..cf6fe8e 100644
--- a/src/dawn/tests/DawnTest.cpp
+++ b/src/dawn/tests/DawnTest.cpp
@@ -1123,16 +1123,6 @@
deviceDescriptor.requiredFeatures = requiredFeatures.data();
deviceDescriptor.requiredFeatureCount = requiredFeatures.size();
- // Set up the mocks for device loss.
- void* deviceUserdata = GetUniqueUserdata();
- deviceDescriptor.deviceLostCallbackInfo.mode = wgpu::CallbackMode::AllowSpontaneous;
- deviceDescriptor.deviceLostCallbackInfo.callback = mDeviceLostCallback.Callback();
- deviceDescriptor.deviceLostCallbackInfo.userdata =
- mDeviceLostCallback.MakeUserdata(deviceUserdata);
- // The loss of the device is expected to happen at the end of the test so at it directly.
- EXPECT_CALL(mDeviceLostCallback, Call(_, WGPUDeviceLostReason_Destroyed, _, deviceUserdata))
- .Times(AtMost(1));
-
wgpu::DawnCacheDeviceDescriptor cacheDesc = {};
deviceDescriptor.nextInChain = &cacheDesc;
cacheDesc.isolationKey = isolationKey.c_str();
@@ -1155,15 +1145,22 @@
// RequestDevice is overriden by CreateDeviceImpl and device descriptor is ignored by it.
wgpu::DeviceDescriptor deviceDesc = {};
+ // Set up the mocks for device loss.
+ deviceDesc.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,
+ mDeviceLostCallback.Callback());
+ deviceDesc.SetUncapturedErrorCallback(mDeviceErrorCallback.TemplatedCallback(),
+ mDeviceErrorCallback.TemplatedCallbackUserdata());
+
adapter.RequestDevice(&deviceDesc, wgpu::CallbackMode::AllowSpontaneous,
[&apiDevice](wgpu::RequestDeviceStatus, wgpu::Device result,
const char*) { apiDevice = std::move(result); });
FlushWire();
DAWN_ASSERT(apiDevice);
- // Set up the mocks for uncaptured errors.
- apiDevice.SetUncapturedErrorCallback(mDeviceErrorCallback.Callback(),
- mDeviceErrorCallback.MakeUserdata(apiDevice.Get()));
+ // The loss of the device is expected to happen at the end of the test so add it directly.
+ EXPECT_CALL(mDeviceLostCallback,
+ Call(CHandleIs(apiDevice.Get()), wgpu::DeviceLostReason::Destroyed, _))
+ .Times(AtMost(1));
apiDevice.SetLoggingCallback(
[](WGPULoggingType type, char const* message, void*) {
@@ -1252,7 +1249,9 @@
resolvedDevice = device;
}
- EXPECT_CALL(mDeviceLostCallback, Call(_, WGPUDeviceLostReason_Unknown, _, _)).Times(1);
+ EXPECT_CALL(mDeviceLostCallback,
+ Call(CHandleIs(resolvedDevice.Get()), wgpu::DeviceLostReason::Unknown, _))
+ .Times(1);
resolvedDevice.ForceLoss(wgpu::DeviceLostReason::Unknown, "Device lost for testing");
resolvedDevice.Tick();
}
diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h
index bbc9366..7ec0386 100644
--- a/src/dawn/tests/DawnTest.h
+++ b/src/dawn/tests/DawnTest.h
@@ -122,15 +122,20 @@
#define EXPECT_TEXTURE_FLOAT16_EQ(...) \
AddTextureExpectation<float, uint16_t>(__FILE__, __LINE__, __VA_ARGS__)
-#define ASSERT_DEVICE_ERROR_MSG_ON(device, statement, matcher) \
- FlushWire(); \
- EXPECT_CALL(mDeviceErrorCallback, \
- Call(testing::Ne(WGPUErrorType_NoError), matcher, device.Get())); \
- statement; \
- instance.ProcessEvents(); \
- FlushWire(); \
- testing::Mock::VerifyAndClearExpectations(&mDeviceErrorCallback); \
- do { \
+// Matcher for C++ types to verify that their internal C-handles are identical.
+MATCHER_P(CHandleIs, cType, "") {
+ return arg.Get() == cType;
+}
+
+#define ASSERT_DEVICE_ERROR_MSG_ON(device, statement, matcher) \
+ FlushWire(); \
+ EXPECT_CALL(mDeviceErrorCallback, \
+ Call(CHandleIs(device.Get()), testing::Ne(wgpu::ErrorType::NoError), matcher)); \
+ statement; \
+ instance.ProcessEvents(); \
+ FlushWire(); \
+ testing::Mock::VerifyAndClearExpectations(&mDeviceErrorCallback); \
+ do { \
} while (0)
#define ASSERT_DEVICE_ERROR_MSG(statement, matcher) \
@@ -337,8 +342,12 @@
// Mock callbacks tracking errors and destruction. These are strict mocks because any errors or
// device loss that aren't expected should result in test failures and not just some warnings
// printed to stdout.
- testing::StrictMock<testing::MockCallback<WGPUErrorCallback>> mDeviceErrorCallback;
- testing::StrictMock<testing::MockCallback<WGPUDeviceLostCallbackNew>> mDeviceLostCallback;
+ testing::StrictMock<
+ testing::MockCppCallback<void (*)(const wgpu::Device&, wgpu::ErrorType, const char*)>>
+ mDeviceErrorCallback;
+ testing::StrictMock<testing::MockCppCallback<
+ void (*)(const wgpu::Device&, wgpu::DeviceLostReason, const char*)>>
+ mDeviceLostCallback;
// Helper methods to implement the EXPECT_ macros
std::ostringstream& AddBufferExpectation(const char* file,
diff --git a/src/dawn/tests/MockCallback.h b/src/dawn/tests/MockCallback.h
index 1638eb3..78936c0 100644
--- a/src/dawn/tests/MockCallback.h
+++ b/src/dawn/tests/MockCallback.h
@@ -124,10 +124,20 @@
// EXPECT_CALL(mock, Call(wgpu::PopErrorScopeStatus::Success, _, _));
template <typename R, typename... Args>
class MockCppCallback<R (*)(Args...)> : public ::testing::MockFunction<R(Args...)> {
+ private:
+ using TemplatedCallbackT = MockCppCallback<R (*)(Args...)>;
+
public:
auto Callback() {
return [this](Args... args) -> R { return this->Call(args...); };
}
+
+ // Returns the templated version of the callback with a static function. Useful when we cannot
+ // use a binding lambda. This must be used with TemplatedCallbackUserdata.
+ auto TemplatedCallback() {
+ return [](Args... args, TemplatedCallbackT* self) -> R { return self->Call(args...); };
+ }
+ TemplatedCallbackT* TemplatedCallbackUserdata() { return this; }
};
} // namespace testing
diff --git a/src/dawn/tests/benchmarks/NullDeviceSetup.cpp b/src/dawn/tests/benchmarks/NullDeviceSetup.cpp
index e029b7a..72630fe 100644
--- a/src/dawn/tests/benchmarks/NullDeviceSetup.cpp
+++ b/src/dawn/tests/benchmarks/NullDeviceSetup.cpp
@@ -60,21 +60,19 @@
// Create the device.
wgpu::DeviceDescriptor desc = GetDeviceDescriptor();
- desc.deviceLostCallbackInfo = {
- nullptr, wgpu::CallbackMode::AllowSpontaneous,
- [](WGPUDevice const*, WGPUDeviceLostReason reason, char const* message, void*) {
- if (reason == WGPUDeviceLostReason_Unknown) {
+ desc.SetDeviceLostCallback(
+ wgpu::CallbackMode::AllowSpontaneous,
+ [](const wgpu::Device&, wgpu::DeviceLostReason reason, char const* message) {
+ if (reason == wgpu::DeviceLostReason::Unknown) {
dawn::ErrorLog() << message;
DAWN_UNREACHABLE();
}
- },
- this};
- desc.uncapturedErrorCallbackInfo = {nullptr,
- [](WGPUErrorType, char const* message, void*) {
- dawn::ErrorLog() << message;
- DAWN_UNREACHABLE();
- },
- this};
+ });
+ desc.SetUncapturedErrorCallback(
+ [](const wgpu::Device&, wgpu::ErrorType, const char* message) {
+ dawn::ErrorLog() << message;
+ DAWN_UNREACHABLE();
+ });
adapter.RequestDevice(
&desc, wgpu::CallbackMode::AllowSpontaneous,
diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp
index d6cfd24..8ff9d0f 100644
--- a/src/dawn/tests/end2end/DeviceLostTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLostTests.cpp
@@ -52,13 +52,15 @@
class DeviceLostTest : public DawnTest {
protected:
void SetUp() override {
- DawnTest::SetUp();
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+ DawnTest::SetUp();
}
void TearDown() override {
- instance.ProcessEvents(); // Flush all callbacks.
- DawnTest::TearDown();
+ if (!UsesWire()) {
+ instance.ProcessEvents(); // Flush all callbacks.
+ DawnTest::TearDown();
+ }
}
static void MapFailCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
@@ -75,7 +77,7 @@
MockMapAsyncCallback mMapAsyncCb;
};
-// Test that DeviceLostCallback is invoked when LostForTestimg is called
+// Test that DeviceLostCallback is invoked when LostForTesting is called
TEST_P(DeviceLostTest, DeviceLostCallbackIsCalled) {
LoseDeviceForTesting();
}
diff --git a/src/dawn/tests/end2end/EventTests.cpp b/src/dawn/tests/end2end/EventTests.cpp
index 28e215b..fd11f86 100644
--- a/src/dawn/tests/end2end/EventTests.cpp
+++ b/src/dawn/tests/end2end/EventTests.cpp
@@ -152,7 +152,7 @@
void LoseTestDevice() {
EXPECT_CALL(mDeviceLostCallback,
- Call(testing::_, WGPUDeviceLostReason_Unknown, testing::_, testing::_))
+ Call(CHandleIs(testDevice.Get()), wgpu::DeviceLostReason::Unknown, testing::_))
.Times(1);
testDevice.ForceLoss(wgpu::DeviceLostReason::Unknown, "Device lost for testing");
testInstance.ProcessEvents();
diff --git a/src/dawn/tests/end2end/VideoViewsTests.cpp b/src/dawn/tests/end2end/VideoViewsTests.cpp
index 00a0c41..5011f05 100644
--- a/src/dawn/tests/end2end/VideoViewsTests.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests.cpp
@@ -1479,8 +1479,9 @@
// Tests creating a texture with a multi-plane format.
TEST_P(VideoViewsValidationTests, RenderAttachmentInvalid) {
// "Invalid Texture" error is expected if failed to create the video texture.
- EXPECT_CALL(mDeviceErrorCallback, Call(testing::Ne(WGPUErrorType_NoError),
- testing::HasSubstr("Invalid Texture"), device.Get()))
+ EXPECT_CALL(mDeviceErrorCallback,
+ Call(CHandleIs(device.Get()), testing::Ne(wgpu::ErrorType::NoError),
+ testing::HasSubstr("Invalid Texture")))
.Times(testing::AnyNumber());
// multi-planar formats are NOT allowed to be renderable by default and require
diff --git a/src/dawn/tests/unittests/native/mocks/DawnMockTest.cpp b/src/dawn/tests/unittests/native/mocks/DawnMockTest.cpp
index d4b6e14..fd50314 100644
--- a/src/dawn/tests/unittests/native/mocks/DawnMockTest.cpp
+++ b/src/dawn/tests/unittests/native/mocks/DawnMockTest.cpp
@@ -42,8 +42,21 @@
}
void DawnMockTest::DropDevice() {
+ if (device == nullptr) {
+ return;
+ }
+
+ // Since the device owns the instance in these tests, we need to explicitly verify that the
+ // instance has completed all work. To do this, we take an additional ref to the instance here
+ // and use it to process events until completion after dropping the device.
+ Ref<InstanceBase> instance = mDeviceMock->GetInstance();
+
mDeviceMock = nullptr;
device = nullptr;
+
+ do {
+ } while (instance->ProcessEvents());
+ instance = nullptr;
}
DawnMockTest::~DawnMockTest() {
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.cpp b/src/dawn/tests/unittests/validation/ValidationTest.cpp
index 7786b01..1258f4e 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.cpp
+++ b/src/dawn/tests/unittests/validation/ValidationTest.cpp
@@ -348,9 +348,33 @@
// Initialize the device.
wgpu::DeviceDescriptor deviceDescriptor = {};
- deviceDescriptor.deviceLostCallbackInfo = {nullptr, wgpu::CallbackMode::AllowSpontaneous,
- ValidationTest::OnDeviceLost, this};
- deviceDescriptor.uncapturedErrorCallbackInfo = {nullptr, ValidationTest::OnDeviceError, this};
+ deviceDescriptor.SetDeviceLostCallback(
+ wgpu::CallbackMode::AllowSpontaneous,
+ [this](const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) {
+ if (mExpectDestruction) {
+ EXPECT_EQ(reason, wgpu::DeviceLostReason::Destroyed);
+ return;
+ }
+ ADD_FAILURE() << "Device lost during test: " << message;
+ DAWN_ASSERT(false);
+ });
+ deviceDescriptor.SetUncapturedErrorCallback(
+ [](const wgpu::Device&, wgpu::ErrorType type, const char* message, ValidationTest* self) {
+ DAWN_ASSERT(type != wgpu::ErrorType::NoError);
+
+ ASSERT_TRUE(self->mExpectError) << "Got unexpected device error: " << message;
+ ASSERT_FALSE(self->mError) << "Got two errors in expect block, first one is:\n" //
+ << self->mDeviceErrorMessage //
+ << "\nsecond one is:\n" //
+ << message;
+
+ self->mDeviceErrorMessage = message;
+ if (self->mExpectError) {
+ ASSERT_THAT(message, self->mErrorMatcher);
+ }
+ self->mError = true;
+ },
+ this);
// Set the required features for the device.
auto requiredFeatures = GetRequiredFeatures();
@@ -368,37 +392,6 @@
return false;
}
-// static
-void ValidationTest::OnDeviceError(WGPUErrorType type, const char* message, void* userdata) {
- DAWN_ASSERT(type != WGPUErrorType_NoError);
- auto* self = static_cast<ValidationTest*>(userdata);
-
- ASSERT_TRUE(self->mExpectError) << "Got unexpected device error: " << message;
- ASSERT_FALSE(self->mError) << "Got two errors in expect block, first one is:\n" //
- << self->mDeviceErrorMessage //
- << "\nsecond one is:\n" //
- << message;
-
- self->mDeviceErrorMessage = message;
- if (self->mExpectError) {
- ASSERT_THAT(message, self->mErrorMatcher);
- }
- self->mError = true;
-}
-
-void ValidationTest::OnDeviceLost(WGPUDevice const* device,
- WGPUDeviceLostReason reason,
- const char* message,
- void* userdata) {
- auto* self = static_cast<ValidationTest*>(userdata);
- if (self->mExpectDestruction) {
- EXPECT_EQ(reason, WGPUDeviceLostReason_Destroyed);
- return;
- }
- ADD_FAILURE() << "Device lost during test: " << message;
- DAWN_ASSERT(false);
-}
-
ValidationTest::PlaceholderRenderPass::PlaceholderRenderPass(const wgpu::Device& device)
: attachmentFormat(wgpu::TextureFormat::RGBA8Unorm), width(400), height(400) {
wgpu::TextureDescriptor descriptor;
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.h b/src/dawn/tests/unittests/validation/ValidationTest.h
index a5e5e20..08abf58 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.h
+++ b/src/dawn/tests/unittests/validation/ValidationTest.h
@@ -180,11 +180,6 @@
const wgpu::InstanceDescriptor* wireDesc = nullptr);
wgpu::Device RequestDeviceSync(const wgpu::DeviceDescriptor& deviceDesc);
- static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata);
- static void OnDeviceLost(WGPUDevice const* device,
- WGPUDeviceLostReason reason,
- const char* message,
- void* userdata);
virtual bool UseCompatibilityMode() const;
diff --git a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
index afcfb03..7b51fbb 100644
--- a/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireAdapterTests.cpp
@@ -114,18 +114,15 @@
});
}
-static void DeviceLostCallback(WGPUDevice const* device,
- WGPUDeviceLostReason reason,
- const char* message,
- void* userdata) {}
+static void DeviceLostCallback(const wgpu::Device&,
+ wgpu::DeviceLostReason reason,
+ const char* message) {}
// Test that the DeviceDescriptor is not allowed to pass a device lost callback from the client to
// the server.
TEST_P(WireAdapterTests, RequestDeviceAssertsOnLostCallbackPointer) {
- int userdata = 1337;
wgpu::DeviceDescriptor desc = {};
- desc.deviceLostCallbackInfo.callback = DeviceLostCallback;
- desc.deviceLostCallbackInfo.userdata = &userdata;
+ desc.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, DeviceLostCallback);
AdapterRequestDevice(adapter, &desc);
@@ -134,10 +131,12 @@
EXPECT_STREQ(apiDesc->label, desc.label);
// The callback should not be passed through to the server, and it should be overridden.
- ASSERT_NE(apiDesc->deviceLostCallbackInfo.callback, nullptr);
- ASSERT_NE(apiDesc->deviceLostCallbackInfo.callback, &DeviceLostCallback);
- ASSERT_NE(apiDesc->deviceLostCallbackInfo.userdata, nullptr);
- ASSERT_NE(apiDesc->deviceLostCallbackInfo.userdata, &userdata);
+ WGPUDeviceDescriptor& inputDesc = *reinterpret_cast<WGPUDeviceDescriptor*>(&desc);
+ ASSERT_NE(apiDesc->deviceLostCallbackInfo2.callback,
+ inputDesc.deviceLostCallbackInfo2.callback);
+ ASSERT_NE(apiDesc->deviceLostCallbackInfo2.callback, nullptr);
+ ASSERT_NE(apiDesc->deviceLostCallbackInfo2.userdata1, nullptr);
+ ASSERT_EQ(apiDesc->deviceLostCallbackInfo2.userdata2, nullptr);
// Call the callback so the test doesn't wait indefinitely.
api.CallAdapterRequestDeviceCallback(apiAdapter, WGPURequestDeviceStatus_Error, nullptr,
@@ -174,8 +173,6 @@
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
// Set on device creation to forward callbacks to the client.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, NotNull(), NotNull()))
- .Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, NotNull(), NotNull())).Times(1);
EXPECT_CALL(api, DeviceGetLimits(apiDevice, NotNull()))
@@ -233,19 +230,8 @@
FlushCallbacks();
});
- // Test that callbacks can propagate from server to client.
- MockCallback<WGPUErrorCallback> errorCb;
- device.SetUncapturedErrorCallback(errorCb.Callback(), errorCb.MakeUserdata(this));
- api.CallDeviceSetUncapturedErrorCallbackCallback(apiDevice, WGPUErrorType_Validation,
- "Some error message");
-
- EXPECT_CALL(errorCb, Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
- .Times(1);
- FlushCallbacks();
-
device = nullptr;
// Cleared when the device is destroyed.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, DeviceRelease(apiDevice));
@@ -348,8 +334,6 @@
EXPECT_CALL(api, OnAdapterRequestDevice(apiAdapter, NotNull(), _))
.WillOnce(InvokeWithoutArgs([&] {
// Set on device creation to forward callbacks to the client.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, NotNull(), NotNull()))
- .Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, NotNull(), NotNull())).Times(1);
EXPECT_CALL(api, DeviceGetLimits(apiDevice, NotNull()))
@@ -387,7 +371,6 @@
device = nullptr;
// Cleared when the device is destroyed.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, DeviceRelease(apiDevice));
FlushClient();
diff --git a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
index 7b6ebe0..be8c670 100644
--- a/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireDisconnectTests.cpp
@@ -82,7 +82,7 @@
// Check that disconnecting the wire client calls the device lost callback exacty once.
TEST_F(WireDisconnectTests, CallsDeviceLostCallback) {
// Disconnect the wire client. We should receive device lost only once.
- EXPECT_CALL(deviceLostCallback, Call(_, WGPUDeviceLostReason_InstanceDropped, _, this))
+ EXPECT_CALL(deviceLostCallback, Call(_, WGPUDeviceLostReason_InstanceDropped, _, _, this))
.Times(Exactly(1));
GetWireClient()->Disconnect();
GetWireClient()->Disconnect();
@@ -96,7 +96,7 @@
// Flush the device lost return command.
EXPECT_CALL(deviceLostCallback,
- Call(_, WGPUDeviceLostReason_Unknown, StrEq("some reason"), this))
+ Call(_, WGPUDeviceLostReason_Unknown, StrEq("some reason"), _, this))
.Times(Exactly(1));
FlushServer();
@@ -166,9 +166,6 @@
// should be deleted first because it may free its reference to the default queue
// on deletion.
Sequence s1, s2, s3, s4, s5;
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
- .Times(1)
- .InSequence(s1, s2);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr))
.Times(1)
.InSequence(s1, s2);
diff --git a/src/dawn/tests/unittests/wire/WireQueueTests.cpp b/src/dawn/tests/unittests/wire/WireQueueTests.cpp
index 69142e8..ce56fc8 100644
--- a/src/dawn/tests/unittests/wire/WireQueueTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireQueueTests.cpp
@@ -174,7 +174,6 @@
EXPECT_CALL(api, QueueRelease(apiQueue));
EXPECT_CALL(api, DeviceRelease(apiDevice));
// These set X callback methods are called before the device is released.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
FlushClient();
@@ -195,7 +194,6 @@
EXPECT_CALL(api, DeviceRelease(apiDevice));
// These set X callback methods are called before the device is released.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr)).Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(1);
FlushClient();
diff --git a/src/dawn/tests/unittests/wire/WireTest.cpp b/src/dawn/tests/unittests/wire/WireTest.cpp
index 8fe6855..c339d65 100644
--- a/src/dawn/tests/unittests/wire/WireTest.cpp
+++ b/src/dawn/tests/unittests/wire/WireTest.cpp
@@ -143,12 +143,13 @@
// Create the device for testing.
apiDevice = api.GetNewDevice();
WGPUDeviceDescriptor deviceDesc = {};
- deviceDesc.deviceLostCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly;
- deviceDesc.deviceLostCallbackInfo.callback = deviceLostCallback.Callback();
- deviceDesc.deviceLostCallbackInfo.userdata = deviceLostCallback.MakeUserdata(this);
+ deviceDesc.deviceLostCallbackInfo2 = {nullptr, WGPUCallbackMode_AllowSpontaneous,
+ deviceLostCallback.Callback(), nullptr,
+ deviceLostCallback.MakeUserdata(this)};
+ deviceDesc.uncapturedErrorCallbackInfo2 = {nullptr, uncapturedErrorCallback.Callback(), nullptr,
+ uncapturedErrorCallback.MakeUserdata(this)};
EXPECT_CALL(deviceLostCallback, Call).Times(AtMost(1));
- deviceDesc.uncapturedErrorCallbackInfo.callback = uncapturedErrorCallback.Callback();
- deviceDesc.uncapturedErrorCallbackInfo.userdata = uncapturedErrorCallback.MakeUserdata(this);
+
MockCallback<WGPURequestDeviceCallback2> deviceCb;
wgpuAdapterRequestDevice2(adapter.Get(), &deviceDesc,
{nullptr, WGPUCallbackMode_AllowSpontaneous, deviceCb.Callback(),
@@ -156,16 +157,18 @@
EXPECT_CALL(api, OnAdapterRequestDevice2(apiAdapter, NotNull(), _))
.WillOnce(WithArg<1>([&](const WGPUDeviceDescriptor* desc) {
// Set on device creation to forward callbacks to the client.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, NotNull(), NotNull()))
- .Times(1);
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, NotNull(), NotNull())).Times(1);
// The mock objects currently require us to manually set the callbacks because we
- // are no longer explicitly calling SetDeviceLostCallback anymore.
+ // are no longer explicitly calling the setters anymore.
ProcTableAsClass::Object* object =
reinterpret_cast<ProcTableAsClass::Object*>(apiDevice);
- object->mDeviceLostCallback = desc->deviceLostCallbackInfo.callback;
- object->mDeviceLostUserdata = desc->deviceLostCallbackInfo.userdata;
+ object->mDeviceLostCallback = desc->deviceLostCallbackInfo2.callback;
+ object->mDeviceLostUserdata1 = desc->deviceLostCallbackInfo2.userdata1;
+ object->mDeviceLostUserdata2 = desc->deviceLostCallbackInfo2.userdata2;
+ object->mUncapturedErrorCallback = desc->uncapturedErrorCallbackInfo2.callback;
+ object->mUncapturedErrorUserdata1 = desc->uncapturedErrorCallbackInfo2.userdata1;
+ object->mUncapturedErrorUserdata2 = desc->uncapturedErrorCallbackInfo2.userdata2;
EXPECT_CALL(api, DeviceGetLimits(apiDevice, NotNull()))
.WillOnce(WithArg<1>(Invoke([&](WGPUSupportedLimits* limits) {
@@ -215,8 +218,6 @@
if (mWireServer && apiDevice) {
// These are called on server destruction to clear the callbacks. They must not be
// called after the server is destroyed.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
- .Times(Exactly(1));
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(Exactly(1));
}
mC2sBuf->SetHandler(nullptr);
@@ -263,8 +264,6 @@
if (mWireServer) {
// These are called on server destruction to clear the callbacks. They must not be
// called after the server is destroyed.
- EXPECT_CALL(api, OnDeviceSetUncapturedErrorCallback(apiDevice, nullptr, nullptr))
- .Times(Exactly(1));
EXPECT_CALL(api, OnDeviceSetLoggingCallback(apiDevice, nullptr, nullptr)).Times(Exactly(1));
}
mC2sBuf->SetHandler(nullptr);
diff --git a/src/dawn/tests/unittests/wire/WireTest.h b/src/dawn/tests/unittests/wire/WireTest.h
index c9c86a7..1680a64 100644
--- a/src/dawn/tests/unittests/wire/WireTest.h
+++ b/src/dawn/tests/unittests/wire/WireTest.h
@@ -150,8 +150,8 @@
testing::StrictMock<MockProcTable> api;
- testing::MockCallback<WGPUDeviceLostCallbackNew> deviceLostCallback;
- testing::MockCallback<WGPUErrorCallback> uncapturedErrorCallback;
+ testing::MockCallback<WGPUDeviceLostCallback2> deviceLostCallback;
+ testing::MockCallback<WGPUUncapturedErrorCallback> uncapturedErrorCallback;
WGPUInstance instance;
WGPUInstance apiInstance;
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index 6d18a37..c7337f6 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -156,8 +156,44 @@
EventType::CreateRenderPipeline,
WGPUCreateRenderPipelineAsyncCallbackInfo2>;
-static constexpr WGPUUncapturedErrorCallbackInfo kEmptyUncapturedErrorCallbackInfo = {
- nullptr, nullptr, nullptr};
+void LegacyDeviceLostCallback(WGPUDevice const*,
+ WGPUDeviceLostReason reason,
+ char const* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUDeviceLostCallback>(callback);
+ cb(reason, message, userdata);
+}
+
+void LegacyDeviceLostCallback2(WGPUDevice const* device,
+ WGPUDeviceLostReason reason,
+ char const* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUDeviceLostCallbackNew>(callback);
+ cb(device, reason, message, userdata);
+}
+
+void LegacyUncapturedErrorCallback(WGPUDevice const*,
+ WGPUErrorType type,
+ const char* message,
+ void* callback,
+ void* userdata) {
+ if (callback == nullptr) {
+ return;
+ }
+ auto cb = reinterpret_cast<WGPUErrorCallback>(callback);
+ cb(type, message, userdata);
+}
+
+static constexpr WGPUUncapturedErrorCallbackInfo2 kEmptyUncapturedErrorCallbackInfo = {
+ nullptr, nullptr, nullptr, nullptr};
} // namespace
@@ -165,10 +201,14 @@
public:
static constexpr EventType kType = EventType::DeviceLost;
- DeviceLostEvent(const WGPUDeviceLostCallbackInfo& callbackInfo, Device* device)
+ DeviceLostEvent(const WGPUDeviceLostCallbackInfo2& callbackInfo, Device* device)
: TrackedEvent(callbackInfo.mode), mDevice(device) {
DAWN_ASSERT(device != nullptr);
mDevice->AddRef();
+
+ mDevice->mDeviceLostInfo.callback = callbackInfo.callback;
+ mDevice->mDeviceLostInfo.userdata1 = callbackInfo.userdata1;
+ mDevice->mDeviceLostInfo.userdata2 = callbackInfo.userdata2;
}
~DeviceLostEvent() override { mDevice.ExtractAsDangling()->Release(); }
@@ -191,14 +231,13 @@
mMessage = "A valid external Instance reference no longer exists.";
}
- void* userdata = mDevice->mDeviceLostInfo.userdata.ExtractAsDangling();
- if (mDevice->mDeviceLostInfo.oldCallback != nullptr) {
- mDevice->mDeviceLostInfo.oldCallback(mReason, mMessage ? mMessage->c_str() : nullptr,
- userdata);
- } else if (mDevice->mDeviceLostInfo.callback != nullptr) {
+ void* userdata1 = mDevice->mDeviceLostInfo.userdata1.ExtractAsDangling();
+ void* userdata2 = mDevice->mDeviceLostInfo.userdata2.ExtractAsDangling();
+
+ if (mDevice->mDeviceLostInfo.callback != nullptr) {
auto device = mReason != WGPUDeviceLostReason_FailedCreation ? ToAPI(mDevice) : nullptr;
- mDevice->mDeviceLostInfo.callback(&device, mReason,
- mMessage ? mMessage->c_str() : nullptr, userdata);
+ mDevice->mDeviceLostInfo.callback(
+ &device, mReason, mMessage ? mMessage->c_str() : nullptr, userdata1, userdata2);
}
mDevice->mUncapturedErrorCallbackInfo = kEmptyUncapturedErrorCallbackInfo;
}
@@ -217,9 +256,9 @@
const WGPUDeviceDescriptor* descriptor)
: ObjectWithEventsBase(params, eventManagerHandle), mIsAlive(std::make_shared<bool>(true)) {
#if defined(DAWN_ENABLE_ASSERTS)
- static constexpr WGPUDeviceLostCallbackInfo kDefaultDeviceLostCallbackInfo = {
+ static constexpr WGPUDeviceLostCallbackInfo2 kDefaultDeviceLostCallbackInfo = {
nullptr, WGPUCallbackMode_AllowSpontaneous,
- [](WGPUDevice const*, WGPUDeviceLostReason, char const*, void*) {
+ [](WGPUDevice const*, WGPUDeviceLostReason, char const*, void*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
@@ -228,10 +267,10 @@
"and suppress this message, set the callback explicitly.";
}
},
- nullptr};
- static constexpr WGPUUncapturedErrorCallbackInfo kDefaultUncapturedErrorCallbackInfo = {
+ nullptr, nullptr};
+ static constexpr WGPUUncapturedErrorCallbackInfo2 kDefaultUncapturedErrorCallbackInfo = {
nullptr,
- [](WGPUErrorType, char const*, void*) {
+ [](WGPUDevice const*, WGPUErrorType, char const*, void*, void*) {
static bool calledOnce = false;
if (!calledOnce) {
calledOnce = true;
@@ -240,37 +279,42 @@
"and suppress this message, set the callback explicitly.";
}
},
- nullptr};
+ nullptr, nullptr};
#else
- static constexpr WGPUDeviceLostCallbackInfo kDefaultDeviceLostCallbackInfo = {
- nullptr, WGPUCallbackMode_AllowSpontaneous, nullptr, nullptr};
- static constexpr WGPUUncapturedErrorCallbackInfo kDefaultUncapturedErrorCallbackInfo =
+ static constexpr WGPUDeviceLostCallbackInfo2 kDefaultDeviceLostCallbackInfo = {
+ nullptr, WGPUCallbackMode_AllowSpontaneous, nullptr, nullptr, nullptr};
+ static constexpr WGPUUncapturedErrorCallbackInfo2 kDefaultUncapturedErrorCallbackInfo =
kEmptyUncapturedErrorCallbackInfo;
#endif // DAWN_ENABLE_ASSERTS
- WGPUDeviceLostCallbackInfo deviceLostCallbackInfo = kDefaultDeviceLostCallbackInfo;
+ WGPUDeviceLostCallbackInfo2 deviceLostCallbackInfo = kDefaultDeviceLostCallbackInfo;
if (descriptor != nullptr) {
- if (descriptor->deviceLostCallbackInfo.callback != nullptr) {
- deviceLostCallbackInfo = descriptor->deviceLostCallbackInfo;
- if (deviceLostCallbackInfo.mode == WGPUCallbackMode_WaitAnyOnly) {
- // TODO(dawn:2458) Currently we default the callback mode to Spontaneous if not
- // passed for backwards compatibility. We should add warning logging for it though
- // when available. Update this when we have WGPUCallbackMode_Undefined.
- deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
- }
- mDeviceLostInfo.callback = deviceLostCallbackInfo.callback;
- mDeviceLostInfo.userdata = deviceLostCallbackInfo.userdata;
+ if (descriptor->deviceLostCallbackInfo2.callback != nullptr) {
+ deviceLostCallbackInfo = descriptor->deviceLostCallbackInfo2;
+ } else if (descriptor->deviceLostCallbackInfo.callback != nullptr) {
+ auto& callbackInfo = descriptor->deviceLostCallbackInfo;
+ deviceLostCallbackInfo = {
+ callbackInfo.nextInChain, callbackInfo.mode, &LegacyDeviceLostCallback2,
+ reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata};
} else if (descriptor->deviceLostCallback != nullptr) {
- deviceLostCallbackInfo = {nullptr, WGPUCallbackMode_AllowSpontaneous, nullptr, nullptr};
- mDeviceLostInfo.oldCallback = descriptor->deviceLostCallback;
- mDeviceLostInfo.userdata = descriptor->deviceLostUserdata;
+ deviceLostCallbackInfo = {nullptr, WGPUCallbackMode_AllowSpontaneous,
+ &LegacyDeviceLostCallback,
+ reinterpret_cast<void*>(descriptor->deviceLostCallback),
+ descriptor->deviceLostUserdata};
}
}
mDeviceLostInfo.event = std::make_unique<DeviceLostEvent>(deviceLostCallbackInfo, this);
mUncapturedErrorCallbackInfo = kDefaultUncapturedErrorCallbackInfo;
- if (descriptor && descriptor->uncapturedErrorCallbackInfo.callback != nullptr) {
- mUncapturedErrorCallbackInfo = descriptor->uncapturedErrorCallbackInfo;
+ if (descriptor != nullptr) {
+ if (descriptor->uncapturedErrorCallbackInfo2.callback != nullptr) {
+ mUncapturedErrorCallbackInfo = descriptor->uncapturedErrorCallbackInfo2;
+ } else if (descriptor->uncapturedErrorCallbackInfo.callback != nullptr) {
+ auto& callbackInfo = descriptor->uncapturedErrorCallbackInfo;
+ mUncapturedErrorCallbackInfo = {
+ callbackInfo.nextInChain, &LegacyUncapturedErrorCallback,
+ reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata};
+ }
}
}
@@ -317,8 +361,10 @@
void Device::HandleError(WGPUErrorType errorType, const char* message) {
if (mUncapturedErrorCallbackInfo.callback) {
- mUncapturedErrorCallbackInfo.callback(errorType, message,
- mUncapturedErrorCallbackInfo.userdata);
+ auto device = ToAPI(this);
+ mUncapturedErrorCallbackInfo.callback(&device, errorType, message,
+ mUncapturedErrorCallbackInfo.userdata1,
+ mUncapturedErrorCallbackInfo.userdata2);
}
}
@@ -355,7 +401,8 @@
void Device::SetUncapturedErrorCallback(WGPUErrorCallback errorCallback, void* errorUserdata) {
if (mDeviceLostInfo.futureID != kNullFutureID) {
- mUncapturedErrorCallbackInfo = {nullptr, errorCallback, errorUserdata};
+ mUncapturedErrorCallbackInfo = {nullptr, &LegacyUncapturedErrorCallback,
+ reinterpret_cast<void*>(errorCallback), errorUserdata};
}
}
@@ -366,8 +413,9 @@
void Device::SetDeviceLostCallback(WGPUDeviceLostCallback callback, void* userdata) {
if (mDeviceLostInfo.futureID != kNullFutureID) {
- mDeviceLostInfo.oldCallback = callback;
- mDeviceLostInfo.userdata = userdata;
+ mDeviceLostInfo.callback = &LegacyDeviceLostCallback;
+ mDeviceLostInfo.userdata1 = reinterpret_cast<void*>(callback);
+ mDeviceLostInfo.userdata2 = userdata;
}
}
diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h
index 244d4f8..2a2d88e 100644
--- a/src/dawn/wire/client/Device.h
+++ b/src/dawn/wire/client/Device.h
@@ -113,13 +113,13 @@
struct DeviceLostInfo {
FutureID futureID = kNullFutureID;
std::unique_ptr<TrackedEvent> event = nullptr;
- WGPUDeviceLostCallbackNew callback = nullptr;
- WGPUDeviceLostCallback oldCallback = nullptr;
- raw_ptr<void> userdata = nullptr;
+ WGPUDeviceLostCallback2 callback = nullptr;
+ raw_ptr<void> userdata1 = nullptr;
+ raw_ptr<void> userdata2 = nullptr;
};
DeviceLostInfo mDeviceLostInfo;
- WGPUUncapturedErrorCallbackInfo mUncapturedErrorCallbackInfo;
+ WGPUUncapturedErrorCallbackInfo2 mUncapturedErrorCallbackInfo;
WGPULoggingCallback mLoggingCallback = nullptr;
raw_ptr<void> mLoggingUserdata = nullptr;
diff --git a/src/dawn/wire/server/Server.cpp b/src/dawn/wire/server/Server.cpp
index b363c19..bc6b6c2 100644
--- a/src/dawn/wire/server/Server.cpp
+++ b/src/dawn/wire/server/Server.cpp
@@ -170,15 +170,8 @@
// Also, the device is special-cased in Server::DoDestroyObject to call
// ClearDeviceCallbacks. This ensures that callbacks will not fire after |deviceObject|
// is freed.
- mProcs.deviceSetUncapturedErrorCallback(
- device->handle,
- [](WGPUErrorType type, const char* message, void* userdata) {
- DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
- info->server->OnUncapturedError(info->self, type, message);
- },
- device->info.get());
- // Set callback to post warning and other infomation to client.
- // Almost the same with UncapturedError.
+
+ // Set callback to post warning and other information to client.
mProcs.deviceSetLoggingCallback(
device->handle,
[](WGPULoggingType type, const char* message, void* userdata) {
@@ -189,9 +182,7 @@
}
void Server::ClearDeviceCallbacks(WGPUDevice device) {
- // Un-set the error and logging callbacks since we cannot forward them
- // after the server has been destroyed.
- mProcs.deviceSetUncapturedErrorCallback(device, nullptr, nullptr);
+ // Un-set the logging callback since we cannot forward them after the server has been destroyed.
mProcs.deviceSetLoggingCallback(device, nullptr, nullptr);
}
diff --git a/src/dawn/wire/server/ServerAdapter.cpp b/src/dawn/wire/server/ServerAdapter.cpp
index b608c9d..6f9cab2 100644
--- a/src/dawn/wire/server/ServerAdapter.cpp
+++ b/src/dawn/wire/server/ServerAdapter.cpp
@@ -56,9 +56,16 @@
deviceLostUserdata->future = deviceLostFuture;
WGPUDeviceDescriptor desc = *descriptor;
- desc.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
- desc.deviceLostCallbackInfo.callback = ForwardToServer<&Server::OnDeviceLost>;
- desc.deviceLostCallbackInfo.userdata = deviceLostUserdata.release();
+ desc.deviceLostCallbackInfo2 = {nullptr, WGPUCallbackMode_AllowProcessEvents,
+ ForwardToServer2<&Server::OnDeviceLost>,
+ deviceLostUserdata.release(), nullptr};
+ desc.uncapturedErrorCallbackInfo2 = {
+ nullptr,
+ [](WGPUDevice const*, WGPUErrorType type, const char* message, void*, void* userdata) {
+ DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
+ info->server->OnUncapturedError(info->self, type, message);
+ },
+ nullptr, device->info.get()};
if (userdataCount == 1) {
mProcs.adapterRequestDevice(adapter->handle, &desc,