Bug 1751718 - Reject WebGPU device promise on wrong features and limits r=jimb

Differential Revision: https://phabricator.services.mozilla.com/D136770
This commit is contained in:
Dzmitry Malyshau 2022-01-28 00:08:53 +00:00
Родитель 377caf35ba
Коммит e7c5d38a9a
8 изменённых файлов: 79 добавлений и 29 удалений

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

@ -86,10 +86,10 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
} }
ffi::WGPULimits limits = {}; ffi::WGPULimits limits = {};
Maybe<RawId> id = mBridge->AdapterRequestDevice(mId, aDesc, &limits); auto request = mBridge->AdapterRequestDevice(mId, aDesc, &limits);
if (id.isSome()) { if (request) {
RefPtr<Device> device = RefPtr<Device> device =
new Device(this, id.value(), MakeUnique<ffi::WGPULimits>(limits)); new Device(this, request->mId, MakeUnique<ffi::WGPULimits>(limits));
// copy over the features // copy over the features
for (const auto& feature : aDesc.mRequiredFeatures) { for (const auto& feature : aDesc.mRequiredFeatures) {
NS_ConvertASCIItoUTF16 string( NS_ConvertASCIItoUTF16 string(
@ -97,9 +97,30 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(device->mFeatures, dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(device->mFeatures,
string, aRv); string, aRv);
} }
promise->MaybeResolve(device);
request->mPromise->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, device](bool aSuccess) {
if (aSuccess) {
promise->MaybeResolve(device);
} else {
// In this path, request->mId has an error entry in the wgpu
// registry, so let Device::~Device clean things up on both the
// child and parent side.
promise->MaybeRejectWithInvalidStateError(
"Unable to fulfill requested features and limits");
}
},
[promise, device](const ipc::ResponseRejectReason& aReason) {
// We can't be sure how far along the WebGPUParent got in handling
// our AdapterRequestDevice message, but we can't communicate with it,
// so clear up our client state for this Device without trying to
// communicate with the parent about it.
device->CleanupUnregisteredInParent();
promise->MaybeRejectWithNotSupportedError("IPC error");
});
} else { } else {
promise->MaybeRejectWithNotSupportedError("Unable to instanciate a Device"); promise->MaybeRejectWithNotSupportedError("Unable to instantiate a Device");
} }
return promise.forget(); return promise.forget();

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

@ -63,7 +63,7 @@ Device::Device(Adapter* const aParent, RawId aId,
mLimits(new SupportedLimits(aParent, std::move(aRawLimits))), mLimits(new SupportedLimits(aParent, std::move(aRawLimits))),
mBridge(aParent->mBridge), mBridge(aParent->mBridge),
mQueue(new class Queue(this, aParent->mBridge, aId)) { mQueue(new class Queue(this, aParent->mBridge, aId)) {
mBridge->RegisterDevice(mId, this); mBridge->RegisterDevice(this);
} }
Device::~Device() { Cleanup(); } Device::~Device() { Cleanup(); }
@ -75,6 +75,13 @@ void Device::Cleanup() {
} }
} }
void Device::CleanupUnregisteredInParent() {
if (mBridge) {
mBridge->FreeUnregisteredInParentDevice(mId);
}
mValid = false;
}
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; } void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; } void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }

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

@ -106,6 +106,8 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
gfx::IntSize* aDefaultSize); gfx::IntSize* aDefaultSize);
bool CheckNewWarning(const nsACString& aMessage); bool CheckNewWarning(const nsACString& aMessage);
void CleanupUnregisteredInParent();
private: private:
~Device(); ~Device();
void Cleanup(); void Cleanup();

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

@ -38,7 +38,7 @@ parent:
async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId); async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId);
async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (ByteBuf byteBuf); async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (ByteBuf byteBuf);
async AdapterRequestDevice(RawId selfId, ByteBuf buf, RawId newId); async AdapterRequestDevice(RawId selfId, ByteBuf buf, RawId newId) returns (bool success);
async AdapterDestroy(RawId selfId); async AdapterDestroy(RawId selfId);
async BufferReturnShmem(RawId selfId, Shmem shmem); async BufferReturnShmem(RawId selfId, Shmem shmem);
async BufferMap(RawId selfId, WGPUHostMap hostMap, uint64_t offset, uint64_t size) returns (Shmem sm); async BufferMap(RawId selfId, WGPUHostMap hostMap, uint64_t offset, uint64_t size) returns (Shmem sm);

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

@ -202,17 +202,15 @@ RefPtr<AdapterPromise> WebGPUChild::InstanceRequestAdapter(
}); });
} }
Maybe<RawId> WebGPUChild::AdapterRequestDevice( Maybe<DeviceRequest> WebGPUChild::AdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimits) { ffi::WGPULimits* aLimits) {
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
ffi::WGPUDeviceDescriptor desc = {}; ffi::WGPUDeviceDescriptor desc = {};
ffi::wgpu_client_fill_default_limits(&desc.limits); ffi::wgpu_client_fill_default_limits(&desc.limits);
const auto featureBits = Adapter::MakeFeatureBits(aDesc.mRequiredFeatures); const auto featureBits = Adapter::MakeFeatureBits(aDesc.mRequiredFeatures);
if (!featureBits) { if (!featureBits) {
return {}; return Nothing();
} }
desc.features = *featureBits; desc.features = *featureBits;
@ -283,14 +281,17 @@ Maybe<RawId> WebGPUChild::AdapterRequestDevice(
} }
} }
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
ByteBuf bb; ByteBuf bb;
ffi::wgpu_client_serialize_device_descriptor(&desc, ToFFI(&bb)); ffi::wgpu_client_serialize_device_descriptor(&desc, ToFFI(&bb));
if (SendAdapterRequestDevice(aSelfId, std::move(bb), id)) {
*aLimits = desc.limits; DeviceRequest request;
return Some(id); request.mId = id;
} request.mPromise = SendAdapterRequestDevice(aSelfId, std::move(bb), id);
ffi::wgpu_client_kill_device_id(mClient, id); *aLimits = desc.limits;
return Nothing();
return Some(std::move(request));
} }
RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId, RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId,
@ -979,8 +980,8 @@ void WebGPUChild::SwapChainPresent(wr::ExternalImageId aExternalImageId,
SendSwapChainPresent(aExternalImageId, aTextureId, encoderId); SendSwapChainPresent(aExternalImageId, aTextureId, encoderId);
} }
void WebGPUChild::RegisterDevice(RawId aId, Device* aDevice) { void WebGPUChild::RegisterDevice(Device* const aDevice) {
mDeviceMap.insert({aId, aDevice}); mDeviceMap.insert({aDevice->mId, aDevice});
} }
void WebGPUChild::UnregisterDevice(RawId aId) { void WebGPUChild::UnregisterDevice(RawId aId) {
@ -990,5 +991,10 @@ void WebGPUChild::UnregisterDevice(RawId aId) {
} }
} }
void WebGPUChild::FreeUnregisteredInParentDevice(RawId aId) {
ffi::wgpu_client_kill_device_id(mClient, aId);
mDeviceMap.erase(aId);
}
} // namespace webgpu } // namespace webgpu
} // namespace mozilla } // namespace mozilla

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

@ -27,6 +27,7 @@ struct WGPUTextureViewDescriptor;
using AdapterPromise = using AdapterPromise =
MozPromise<ipc::ByteBuf, Maybe<ipc::ResponseRejectReason>, true>; MozPromise<ipc::ByteBuf, Maybe<ipc::ResponseRejectReason>, true>;
using PipelinePromise = MozPromise<RawId, ipc::ResponseRejectReason, true>; using PipelinePromise = MozPromise<RawId, ipc::ResponseRejectReason, true>;
using DevicePromise = MozPromise<bool, ipc::ResponseRejectReason, true>;
struct PipelineCreationContext { struct PipelineCreationContext {
RawId mParentId = 0; RawId mParentId = 0;
@ -34,6 +35,13 @@ struct PipelineCreationContext {
nsTArray<RawId> mImplicitBindGroupLayoutIds; nsTArray<RawId> mImplicitBindGroupLayoutIds;
}; };
struct DeviceRequest {
RawId mId = 0;
RefPtr<DevicePromise> mPromise;
// Note: we could put `ffi::WGPULimits` in here as well,
// but we don't want to #include ffi stuff in this header
};
ffi::WGPUByteBuf* ToFFI(ipc::ByteBuf* x); ffi::WGPUByteBuf* ToFFI(ipc::ByteBuf* x);
class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr { class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
@ -50,9 +58,9 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
RefPtr<AdapterPromise> InstanceRequestAdapter( RefPtr<AdapterPromise> InstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions); const dom::GPURequestAdapterOptions& aOptions);
Maybe<RawId> AdapterRequestDevice(RawId aSelfId, Maybe<DeviceRequest> AdapterRequestDevice(
const dom::GPUDeviceDescriptor& aDesc, RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimtis); ffi::WGPULimits* aLimits);
RawId DeviceCreateBuffer(RawId aSelfId, RawId DeviceCreateBuffer(RawId aSelfId,
const dom::GPUBufferDescriptor& aDesc); const dom::GPUBufferDescriptor& aDesc);
RawId DeviceCreateTexture(RawId aSelfId, RawId DeviceCreateTexture(RawId aSelfId,
@ -95,8 +103,9 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
wr::ExternalImageId aExternalImageId); wr::ExternalImageId aExternalImageId);
void SwapChainPresent(wr::ExternalImageId aExternalImageId, RawId aTextureId); void SwapChainPresent(wr::ExternalImageId aExternalImageId, RawId aTextureId);
void RegisterDevice(RawId aId, Device* aDevice); void RegisterDevice(Device* const aDevice);
void UnregisterDevice(RawId aId); void UnregisterDevice(RawId aId);
void FreeUnregisteredInParentDevice(RawId aId);
static void ConvertTextureFormatRef(const dom::GPUTextureFormat& aInput, static void ConvertTextureFormatRef(const dom::GPUTextureFormat& aInput,
ffi::WGPUTextureFormat& aOutput); ffi::WGPUTextureFormat& aOutput);

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

@ -281,12 +281,17 @@ ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter(
} }
ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice( ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice(
RawId aSelfId, const ipc::ByteBuf& aByteBuf, RawId aNewId) { RawId aSelfId, const ipc::ByteBuf& aByteBuf, RawId aNewId,
AdapterRequestDeviceResolver&& resolver) {
ErrorBuffer error; ErrorBuffer error;
ffi::wgpu_server_adapter_request_device(mContext, aSelfId, ToFFI(&aByteBuf), ffi::wgpu_server_adapter_request_device(mContext, aSelfId, ToFFI(&aByteBuf),
aNewId, error.ToFFI()); aNewId, error.ToFFI());
mErrorScopeMap.insert({aSelfId, ErrorScopeStack()}); if (ForwardError(0, error)) {
ForwardError(0, error); resolver(false);
} else {
mErrorScopeMap.insert({aSelfId, ErrorScopeStack()});
resolver(true);
}
return IPC_OK(); return IPC_OK();
} }

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

@ -30,9 +30,9 @@ class WebGPUParent final : public PWebGPUParent {
const dom::GPURequestAdapterOptions& aOptions, const dom::GPURequestAdapterOptions& aOptions,
const nsTArray<RawId>& aTargetIds, const nsTArray<RawId>& aTargetIds,
InstanceRequestAdapterResolver&& resolver); InstanceRequestAdapterResolver&& resolver);
ipc::IPCResult RecvAdapterRequestDevice(RawId aSelfId, ipc::IPCResult RecvAdapterRequestDevice(
const ipc::ByteBuf& aByteBuf, RawId aSelfId, const ipc::ByteBuf& aByteBuf, RawId aNewId,
RawId aNewId); AdapterRequestDeviceResolver&& resolver);
ipc::IPCResult RecvAdapterDestroy(RawId aSelfId); ipc::IPCResult RecvAdapterDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceDestroy(RawId aSelfId); ipc::IPCResult RecvDeviceDestroy(RawId aSelfId);
ipc::IPCResult RecvBufferReturnShmem(RawId aSelfId, Shmem&& aShmem); ipc::IPCResult RecvBufferReturnShmem(RawId aSelfId, Shmem&& aShmem);