mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1837557 - Productionize webgpu pushErrorScope/popErrorScope. r=webgpu-reviewers,jimb
Differential Revision: https://phabricator.services.mozilla.com/D180456
This commit is contained in:
parent
6b065a2607
commit
8ce110a8e9
@ -88,10 +88,12 @@ bool Device::IsLost() const { return !mBridge || !mBridge->CanSend(); }
|
||||
// Generate an error on the Device timeline for this device.
|
||||
//
|
||||
// aMessage is interpreted as UTF-8.
|
||||
void Device::GenerateError(const nsCString& aMessage) {
|
||||
if (mBridge->CanSend()) {
|
||||
mBridge->SendGenerateError(mId, aMessage);
|
||||
void Device::GenerateValidationError(const nsCString& aMessage) {
|
||||
if (IsLost()) {
|
||||
return; // Just drop it?
|
||||
}
|
||||
mBridge->SendGenerateError(Some(mId), dom::GPUErrorFilter::Validation,
|
||||
aMessage);
|
||||
}
|
||||
|
||||
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
|
||||
@ -322,19 +324,30 @@ void Device::Destroy() {
|
||||
}
|
||||
|
||||
void Device::PushErrorScope(const dom::GPUErrorFilter& aFilter) {
|
||||
if (mBridge->CanSend()) {
|
||||
mBridge->SendDevicePushErrorScope(mId);
|
||||
if (IsLost()) {
|
||||
return;
|
||||
}
|
||||
mBridge->SendDevicePushErrorScope(mId, aFilter);
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) {
|
||||
/*
|
||||
https://www.w3.org/TR/webgpu/#errors-and-debugging:
|
||||
> After a device is lost (described below), errors are no longer surfaced.
|
||||
> At this point, implementations do not need to run validation or error
|
||||
tracking: > popErrorScope() and uncapturederror stop reporting errors, > and
|
||||
the validity of objects on the device becomes unobservable.
|
||||
*/
|
||||
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mBridge->CanSend()) {
|
||||
promise->MaybeRejectWithOperationError("Internal communication error");
|
||||
if (IsLost()) {
|
||||
WebGPUChild::JsWarning(
|
||||
GetOwnerGlobal(),
|
||||
"popErrorScope resolving to null because device is already lost."_ns);
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -342,26 +355,50 @@ already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) {
|
||||
|
||||
errorPromise->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[self = RefPtr{this}, promise](const MaybeScopedError& aMaybeError) {
|
||||
if (aMaybeError) {
|
||||
if (aMaybeError->operationError) {
|
||||
promise->MaybeRejectWithOperationError("Stack is empty");
|
||||
} else {
|
||||
dom::OwningGPUOutOfMemoryErrorOrGPUValidationError error;
|
||||
if (aMaybeError->validationMessage.IsEmpty()) {
|
||||
error.SetAsGPUOutOfMemoryError();
|
||||
} else {
|
||||
error.SetAsGPUValidationError() = new ValidationError(
|
||||
self->GetParentObject(), aMaybeError->validationMessage);
|
||||
}
|
||||
promise->MaybeResolve(std::move(error));
|
||||
}
|
||||
} else {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
[self = RefPtr{this}, promise](const PopErrorScopeResult& aResult) {
|
||||
dom::OwningGPUOutOfMemoryErrorOrGPUValidationError error;
|
||||
|
||||
switch (aResult.resultType) {
|
||||
case PopErrorScopeResultType::NoError:
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
return;
|
||||
|
||||
case PopErrorScopeResultType::DeviceLost:
|
||||
WebGPUChild::JsWarning(
|
||||
self->GetOwnerGlobal(),
|
||||
"popErrorScope resolving to null because device was lost."_ns);
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
return;
|
||||
|
||||
case PopErrorScopeResultType::ThrowOperationError:
|
||||
promise->MaybeRejectWithOperationError(aResult.message);
|
||||
return;
|
||||
|
||||
case PopErrorScopeResultType::OutOfMemory:
|
||||
error.SetAsGPUOutOfMemoryError();
|
||||
break;
|
||||
|
||||
case PopErrorScopeResultType::ValidationError:
|
||||
error.SetAsGPUValidationError() =
|
||||
new ValidationError(self->GetParentObject(), aResult.message);
|
||||
break;
|
||||
|
||||
case PopErrorScopeResultType::InternalError:
|
||||
MOZ_CRASH("TODO");
|
||||
/*
|
||||
error.SetAsGPUInternalError() = new InternalError(
|
||||
self->GetParentObject(), aResult.message);
|
||||
break;
|
||||
*/
|
||||
}
|
||||
promise->MaybeResolve(std::move(error));
|
||||
},
|
||||
[promise](const ipc::ResponseRejectReason&) {
|
||||
promise->MaybeRejectWithOperationError("Internal communication error");
|
||||
[self = RefPtr{this}, promise](const ipc::ResponseRejectReason&) {
|
||||
// Device was lost.
|
||||
WebGPUChild::JsWarning(
|
||||
self->GetOwnerGlobal(),
|
||||
"popErrorScope resolving to null because device was just lost."_ns);
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
});
|
||||
|
||||
return promise.forget();
|
||||
|
@ -100,7 +100,7 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
|
||||
|
||||
void CleanupUnregisteredInParent();
|
||||
|
||||
void GenerateError(const nsCString& aMessage);
|
||||
void GenerateValidationError(const nsCString& aMessage);
|
||||
|
||||
bool IsLost() const;
|
||||
|
||||
|
@ -131,7 +131,7 @@ ffi::WGPURenderPass* BeginRenderPass(
|
||||
}
|
||||
|
||||
if (aDesc.mColorAttachments.Length() > WGPUMAX_COLOR_ATTACHMENTS) {
|
||||
aParent->GetDevice()->GenerateError(nsLiteralCString(
|
||||
aParent->GetDevice()->GenerateValidationError(nsLiteralCString(
|
||||
"Too many color attachments in GPURenderPassDescriptor"));
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -9,10 +9,11 @@ using mozilla::layers::RGBDescriptor from "mozilla/layers/LayersSurfaces.h";
|
||||
using mozilla::layers::RemoteTextureId from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h";
|
||||
using mozilla::webgpu::RawId from "mozilla/webgpu/WebGPUTypes.h";
|
||||
using mozilla::dom::GPUErrorFilter from "mozilla/dom/WebGPUBinding.h";
|
||||
using mozilla::dom::GPURequestAdapterOptions from "mozilla/dom/WebGPUBinding.h";
|
||||
using mozilla::dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
|
||||
using mozilla::dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
|
||||
using mozilla::webgpu::MaybeScopedError from "mozilla/webgpu/WebGPUTypes.h";
|
||||
using mozilla::webgpu::PopErrorScopeResult from "mozilla/webgpu/WebGPUTypes.h";
|
||||
using mozilla::webgpu::WebGPUCompilationMessage from "mozilla/webgpu/WebGPUTypes.h";
|
||||
[MoveOnly] using class mozilla::ipc::UnsafeSharedMemoryHandle from "mozilla/ipc/RawShmem.h";
|
||||
|
||||
@ -76,15 +77,15 @@ parent:
|
||||
async SwapChainPresent(RawId textureId, RawId commandEncoderId, RemoteTextureId remoteTextureId, RemoteTextureOwnerId remoteTextureOwnerId);
|
||||
async SwapChainDestroy(RemoteTextureOwnerId ownerId);
|
||||
|
||||
async DevicePushErrorScope(RawId selfId);
|
||||
async DevicePopErrorScope(RawId selfId) returns (MaybeScopedError maybeError);
|
||||
async DevicePushErrorScope(RawId selfId, GPUErrorFilter aFilter);
|
||||
async DevicePopErrorScope(RawId selfId) returns (PopErrorScopeResult result);
|
||||
|
||||
// Generate an error on the Device timeline for `deviceId`.
|
||||
// The `message` parameter is interpreted as UTF-8.
|
||||
async GenerateError(RawId deviceId, nsCString message);
|
||||
async GenerateError(RawId? deviceId, GPUErrorFilter type, nsCString message);
|
||||
|
||||
child:
|
||||
async DeviceUncapturedError(RawId aDeviceId, nsCString message);
|
||||
async UncapturedError(RawId? aDeviceId, nsCString message);
|
||||
async DropAction(ByteBuf buf);
|
||||
async __delete__();
|
||||
};
|
||||
|
@ -1064,25 +1064,30 @@ RefPtr<PipelinePromise> WebGPUChild::DeviceCreateRenderPipelineAsync(
|
||||
});
|
||||
}
|
||||
|
||||
ipc::IPCResult WebGPUChild::RecvDeviceUncapturedError(
|
||||
RawId aDeviceId, const nsACString& aMessage) {
|
||||
auto targetIter = mDeviceMap.find(aDeviceId);
|
||||
if (!aDeviceId || targetIter == mDeviceMap.end()) {
|
||||
ipc::IPCResult WebGPUChild::RecvUncapturedError(const Maybe<RawId> aDeviceId,
|
||||
const nsACString& aMessage) {
|
||||
RefPtr<Device> device;
|
||||
if (aDeviceId) {
|
||||
const auto itr = mDeviceMap.find(*aDeviceId);
|
||||
if (itr != mDeviceMap.end()) {
|
||||
device = itr->second.get();
|
||||
MOZ_ASSERT(device);
|
||||
}
|
||||
}
|
||||
if (!device) {
|
||||
JsWarning(nullptr, aMessage);
|
||||
} else {
|
||||
auto* target = targetIter->second.get();
|
||||
MOZ_ASSERT(target);
|
||||
// We don't want to spam the errors to the console indefinitely
|
||||
if (target->CheckNewWarning(aMessage)) {
|
||||
JsWarning(target->GetOwnerGlobal(), aMessage);
|
||||
if (device->CheckNewWarning(aMessage)) {
|
||||
JsWarning(device->GetOwnerGlobal(), aMessage);
|
||||
|
||||
dom::GPUUncapturedErrorEventInit init;
|
||||
init.mError.SetAsGPUValidationError() =
|
||||
new ValidationError(target->GetParentObject(), aMessage);
|
||||
new ValidationError(device->GetParentObject(), aMessage);
|
||||
RefPtr<mozilla::dom::GPUUncapturedErrorEvent> event =
|
||||
dom::GPUUncapturedErrorEvent::Constructor(
|
||||
target, u"uncapturederror"_ns, init);
|
||||
target->DispatchEvent(*event);
|
||||
device, u"uncapturederror"_ns, init);
|
||||
device->DispatchEvent(*event);
|
||||
}
|
||||
}
|
||||
return IPC_OK();
|
||||
|
@ -116,11 +116,11 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
|
||||
static void ConvertTextureFormatRef(const dom::GPUTextureFormat& aInput,
|
||||
ffi::WGPUTextureFormat& aOutput);
|
||||
|
||||
static void JsWarning(nsIGlobalObject* aGlobal, const nsACString& aMessage);
|
||||
|
||||
private:
|
||||
virtual ~WebGPUChild();
|
||||
|
||||
void JsWarning(nsIGlobalObject* aGlobal, const nsACString& aMessage);
|
||||
|
||||
RawId DeviceCreateComputePipelineImpl(
|
||||
PipelineCreationContext* const aContext,
|
||||
const dom::GPUComputePipelineDescriptor& aDesc,
|
||||
@ -134,8 +134,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
|
||||
std::unordered_map<RawId, WeakPtr<Device>> mDeviceMap;
|
||||
|
||||
public:
|
||||
ipc::IPCResult RecvDeviceUncapturedError(RawId aDeviceId,
|
||||
const nsACString& aMessage);
|
||||
ipc::IPCResult RecvUncapturedError(Maybe<RawId> aDeviceId,
|
||||
const nsACString& aMessage);
|
||||
ipc::IPCResult RecvDropAction(const ipc::ByteBuf& aByteBuf);
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
};
|
||||
|
@ -233,34 +233,44 @@ void WebGPUParent::MaintainDevices() {
|
||||
ffi::wgpu_server_poll_all_devices(mContext.get(), false);
|
||||
}
|
||||
|
||||
bool WebGPUParent::ForwardError(RawId aDeviceId, ErrorBuffer& aError) {
|
||||
bool WebGPUParent::ForwardError(const Maybe<RawId> aDeviceId,
|
||||
ErrorBuffer& aError) {
|
||||
// don't do anything if the error is empty
|
||||
auto cString = aError.GetError();
|
||||
if (!cString) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReportError(aDeviceId, cString.value());
|
||||
|
||||
// Risky: These are probably not all Validation errors.
|
||||
ReportError(aDeviceId, dom::GPUErrorFilter::Validation, cString.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate an error on the Device timeline of aDeviceId.
|
||||
// aMessage is interpreted as UTF-8.
|
||||
void WebGPUParent::ReportError(RawId aDeviceId, const nsCString& aMessage) {
|
||||
void WebGPUParent::ReportError(const Maybe<RawId> aDeviceId,
|
||||
const GPUErrorFilter aType,
|
||||
const nsCString& aMessage) {
|
||||
// find the appropriate error scope
|
||||
const auto& lookup = mErrorScopeMap.find(aDeviceId);
|
||||
if (lookup != mErrorScopeMap.end() && !lookup->second.mStack.IsEmpty()) {
|
||||
auto& last = lookup->second.mStack.LastElement();
|
||||
if (last.isNothing()) {
|
||||
last.emplace(ScopedError{false, aMessage});
|
||||
}
|
||||
} else {
|
||||
// fall back to the uncaptured error handler
|
||||
if (!SendDeviceUncapturedError(aDeviceId, aMessage)) {
|
||||
NS_ERROR("Unable to SendError");
|
||||
if (aDeviceId) {
|
||||
const auto& itr = mErrorScopeStackByDevice.find(*aDeviceId);
|
||||
if (itr != mErrorScopeStackByDevice.end()) {
|
||||
auto& stack = itr->second;
|
||||
for (auto& scope : Reversed(stack)) {
|
||||
if (scope.filter != aType) {
|
||||
continue;
|
||||
}
|
||||
if (!scope.firstMessage) {
|
||||
scope.firstMessage = Some(aMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// No error scope found, so fall back to the uncaptured error handler
|
||||
if (!SendUncapturedError(aDeviceId, aMessage)) {
|
||||
NS_ERROR("SendDeviceUncapturedError failed");
|
||||
}
|
||||
}
|
||||
|
||||
ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter(
|
||||
@ -312,7 +322,7 @@ ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice(
|
||||
if (ForwardError(0, error)) {
|
||||
resolver(false);
|
||||
} else {
|
||||
mErrorScopeMap.insert({aAdapterId, ErrorScopeStack()});
|
||||
mErrorScopeStackByDevice.insert({aDeviceId, {}});
|
||||
resolver(true);
|
||||
}
|
||||
return IPC_OK();
|
||||
@ -325,7 +335,7 @@ ipc::IPCResult WebGPUParent::RecvAdapterDestroy(RawId aAdapterId) {
|
||||
|
||||
ipc::IPCResult WebGPUParent::RecvDeviceDestroy(RawId aDeviceId) {
|
||||
ffi::wgpu_server_device_drop(mContext.get(), aDeviceId);
|
||||
mErrorScopeMap.erase(aDeviceId);
|
||||
mErrorScopeStackByDevice.erase(aDeviceId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -1083,45 +1093,78 @@ ipc::IPCResult WebGPUParent::RecvBumpImplicitBindGroupLayout(RawId aPipelineId,
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ipc::IPCResult WebGPUParent::RecvDevicePushErrorScope(RawId aDeviceId) {
|
||||
const auto& lookup = mErrorScopeMap.find(aDeviceId);
|
||||
if (lookup == mErrorScopeMap.end()) {
|
||||
ipc::IPCResult WebGPUParent::RecvDevicePushErrorScope(
|
||||
RawId aDeviceId, const dom::GPUErrorFilter aFilter) {
|
||||
const auto& itr = mErrorScopeStackByDevice.find(aDeviceId);
|
||||
if (itr == mErrorScopeStackByDevice.end()) {
|
||||
// Content can cause this simply by destroying a device and then
|
||||
// calling `pushErrorScope`.
|
||||
return IPC_OK();
|
||||
}
|
||||
auto& stack = itr->second;
|
||||
|
||||
lookup->second.mStack.EmplaceBack();
|
||||
// Let's prevent `while (true) { pushErrorScope(); }`.
|
||||
constexpr size_t MAX_ERROR_SCOPE_STACK_SIZE = 1'000'000;
|
||||
if (stack.size() >= MAX_ERROR_SCOPE_STACK_SIZE) {
|
||||
nsPrintfCString m("pushErrorScope: Hit MAX_ERROR_SCOPE_STACK_SIZE of %zu",
|
||||
MAX_ERROR_SCOPE_STACK_SIZE);
|
||||
ReportError(Some(aDeviceId), dom::GPUErrorFilter::Out_of_memory, m);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
const auto newScope = ErrorScope{aFilter};
|
||||
stack.push_back(newScope);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ipc::IPCResult WebGPUParent::RecvDevicePopErrorScope(
|
||||
RawId aDeviceId, DevicePopErrorScopeResolver&& aResolver) {
|
||||
const auto& lookup = mErrorScopeMap.find(aDeviceId);
|
||||
if (lookup == mErrorScopeMap.end()) {
|
||||
// Content can cause this simply by destroying a device and then
|
||||
// calling `popErrorScope`.
|
||||
ScopedError error = {true};
|
||||
aResolver(Some(error));
|
||||
return IPC_OK();
|
||||
}
|
||||
const auto popResult = [&]() {
|
||||
const auto& itr = mErrorScopeStackByDevice.find(aDeviceId);
|
||||
if (itr == mErrorScopeStackByDevice.end()) {
|
||||
// Content can cause this simply by destroying a device and then
|
||||
// calling `popErrorScope`.
|
||||
return PopErrorScopeResult{PopErrorScopeResultType::DeviceLost};
|
||||
}
|
||||
|
||||
if (lookup->second.mStack.IsEmpty()) {
|
||||
// Content can cause this simply by calling `popErrorScope` when
|
||||
// there is no error scope pushed.
|
||||
ScopedError error = {true};
|
||||
aResolver(Some(error));
|
||||
return IPC_OK();
|
||||
}
|
||||
auto& stack = itr->second;
|
||||
if (!stack.size()) {
|
||||
// Content can cause this simply by calling `popErrorScope` when
|
||||
// there is no error scope pushed.
|
||||
return PopErrorScopeResult{PopErrorScopeResultType::ThrowOperationError,
|
||||
"popErrorScope on empty stack"_ns};
|
||||
}
|
||||
|
||||
auto scope = lookup->second.mStack.PopLastElement();
|
||||
aResolver(scope);
|
||||
const auto& scope = stack.back();
|
||||
const auto popLater = MakeScopeExit([&]() { stack.pop_back(); });
|
||||
|
||||
auto ret = PopErrorScopeResult{PopErrorScopeResultType::NoError};
|
||||
if (scope.firstMessage) {
|
||||
ret.message = *scope.firstMessage;
|
||||
}
|
||||
switch (scope.filter) {
|
||||
case dom::GPUErrorFilter::Validation:
|
||||
ret.resultType = PopErrorScopeResultType::ValidationError;
|
||||
break;
|
||||
case dom::GPUErrorFilter::Out_of_memory:
|
||||
ret.resultType = PopErrorScopeResultType::OutOfMemory;
|
||||
break;
|
||||
// case dom::GPUErrorFilter::Internal:
|
||||
// ret.resultType = PopErrorScopeResultType::InternalError;
|
||||
// break;
|
||||
case dom::GPUErrorFilter::EndGuard_:
|
||||
MOZ_CRASH("Bad GPUErrorFilter");
|
||||
}
|
||||
return ret;
|
||||
}();
|
||||
aResolver(popResult);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
ipc::IPCResult WebGPUParent::RecvGenerateError(RawId aDeviceId,
|
||||
ipc::IPCResult WebGPUParent::RecvGenerateError(const Maybe<RawId> aDeviceId,
|
||||
const dom::GPUErrorFilter aType,
|
||||
const nsCString& aMessage) {
|
||||
ReportError(aDeviceId, aMessage);
|
||||
ReportError(aDeviceId, aType, aMessage);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,6 @@ namespace webgpu {
|
||||
class ErrorBuffer;
|
||||
class PresentationData;
|
||||
|
||||
struct ErrorScopeStack {
|
||||
nsTArray<MaybeScopedError> mStack;
|
||||
};
|
||||
|
||||
class WebGPUParent final : public PWebGPUParent {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGPUParent, override)
|
||||
|
||||
@ -103,10 +99,11 @@ class WebGPUParent final : public PWebGPUParent {
|
||||
uint32_t aIndex,
|
||||
RawId aAssignId);
|
||||
|
||||
ipc::IPCResult RecvDevicePushErrorScope(RawId aDeviceId);
|
||||
ipc::IPCResult RecvDevicePushErrorScope(RawId aDeviceId, dom::GPUErrorFilter);
|
||||
ipc::IPCResult RecvDevicePopErrorScope(
|
||||
RawId aDeviceId, DevicePopErrorScopeResolver&& aResolver);
|
||||
ipc::IPCResult RecvGenerateError(RawId aDeviceId, const nsCString& message);
|
||||
ipc::IPCResult RecvGenerateError(Maybe<RawId> aDeviceId, dom::GPUErrorFilter,
|
||||
const nsCString& message);
|
||||
|
||||
ipc::IPCResult GetFrontBufferSnapshot(
|
||||
IProtocol* aProtocol, const layers::RemoteTextureOwnerId& aOwnerId,
|
||||
@ -129,8 +126,14 @@ class WebGPUParent final : public PWebGPUParent {
|
||||
|
||||
virtual ~WebGPUParent();
|
||||
void MaintainDevices();
|
||||
bool ForwardError(RawId aDeviceId, ErrorBuffer& aError);
|
||||
void ReportError(RawId aDeviceId, const nsCString& message);
|
||||
|
||||
bool ForwardError(const RawId aDeviceId, ErrorBuffer& aError) {
|
||||
return ForwardError(Some(aDeviceId), aError);
|
||||
}
|
||||
bool ForwardError(Maybe<RawId> aDeviceId, ErrorBuffer& aError);
|
||||
|
||||
void ReportError(Maybe<RawId> aDeviceId, GPUErrorFilter,
|
||||
const nsCString& message);
|
||||
|
||||
UniquePtr<ffi::WGPUGlobal> mContext;
|
||||
base::RepeatingTimer<WebGPUParent> mTimer;
|
||||
@ -147,7 +150,8 @@ class WebGPUParent final : public PWebGPUParent {
|
||||
RefPtr<layers::RemoteTextureOwnerClient> mRemoteTextureOwner;
|
||||
|
||||
/// Associated stack of error scopes for each device.
|
||||
std::unordered_map<uint64_t, ErrorScopeStack> mErrorScopeMap;
|
||||
std::unordered_map<uint64_t, std::vector<ErrorScope>>
|
||||
mErrorScopeStackByDevice;
|
||||
};
|
||||
|
||||
} // namespace webgpu
|
||||
|
@ -24,6 +24,9 @@ namespace IPC {
|
||||
#define DEFINE_IPC_SERIALIZER_FFI_ENUM(something) \
|
||||
DEFINE_IPC_SERIALIZER_ENUM_GUARD(something, something##_Sentinel)
|
||||
|
||||
// -
|
||||
|
||||
DEFINE_IPC_SERIALIZER_DOM_ENUM(mozilla::dom::GPUErrorFilter);
|
||||
DEFINE_IPC_SERIALIZER_DOM_ENUM(mozilla::dom::GPUPowerPreference);
|
||||
|
||||
DEFINE_IPC_SERIALIZER_FFI_ENUM(mozilla::webgpu::ffi::WGPUHostMap);
|
||||
@ -36,8 +39,8 @@ DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPURequestAdapterOptions,
|
||||
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPUBufferDescriptor, mSize,
|
||||
mUsage, mMappedAtCreation);
|
||||
|
||||
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::ScopedError, operationError,
|
||||
validationMessage);
|
||||
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::PopErrorScopeResult,
|
||||
resultType, message);
|
||||
|
||||
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::WebGPUCompilationMessage,
|
||||
message, lineNum, linePos);
|
||||
@ -46,5 +49,15 @@ DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::WebGPUCompilationMessage,
|
||||
#undef DEFINE_IPC_SERIALIZER_DOM_ENUM
|
||||
#undef DEFINE_IPC_SERIALIZER_ENUM_GUARD
|
||||
|
||||
// -
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::webgpu::PopErrorScopeResultType>
|
||||
: public ContiguousEnumSerializerInclusive<
|
||||
mozilla::webgpu::PopErrorScopeResultType,
|
||||
mozilla::webgpu::PopErrorScopeResultType{0},
|
||||
mozilla::webgpu::PopErrorScopeResultType::_LAST> {};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // WEBGPU_SERIALIZE_H_
|
||||
|
@ -11,21 +11,34 @@
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
enum class GPUErrorFilter : uint8_t;
|
||||
} // namespace mozilla::dom
|
||||
|
||||
namespace mozilla::webgpu {
|
||||
|
||||
using RawId = uint64_t;
|
||||
using BufferAddress = uint64_t;
|
||||
|
||||
struct ScopedError {
|
||||
// Did an error occur as a result the attempt to retrieve an error
|
||||
// (e.g. from a dead device, from an empty scope stack)?
|
||||
bool operationError = false;
|
||||
|
||||
// If non-empty, the first error generated when this scope was on
|
||||
// the top of the stack. This is interpreted as UTF-8.
|
||||
nsCString validationMessage;
|
||||
struct ErrorScope {
|
||||
dom::GPUErrorFilter filter;
|
||||
Maybe<nsCString> firstMessage;
|
||||
};
|
||||
|
||||
enum class PopErrorScopeResultType : uint8_t {
|
||||
NoError,
|
||||
ThrowOperationError,
|
||||
ValidationError,
|
||||
OutOfMemory,
|
||||
InternalError,
|
||||
DeviceLost,
|
||||
_LAST = DeviceLost,
|
||||
};
|
||||
|
||||
struct PopErrorScopeResult {
|
||||
PopErrorScopeResultType resultType;
|
||||
nsCString message;
|
||||
};
|
||||
using MaybeScopedError = Maybe<ScopedError>;
|
||||
|
||||
enum class WebGPUCompilationMessageType { Error, Warning, Info };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user