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 = {};
Maybe<RawId> id = mBridge->AdapterRequestDevice(mId, aDesc, &limits);
if (id.isSome()) {
auto request = mBridge->AdapterRequestDevice(mId, aDesc, &limits);
if (request) {
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
for (const auto& feature : aDesc.mRequiredFeatures) {
NS_ConvertASCIItoUTF16 string(
@ -97,9 +97,30 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(device->mFeatures,
string, aRv);
}
request->mPromise->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, device](bool aSuccess) {
if (aSuccess) {
promise->MaybeResolve(device);
} else {
promise->MaybeRejectWithNotSupportedError("Unable to instanciate a Device");
// 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 {
promise->MaybeRejectWithNotSupportedError("Unable to instantiate a Device");
}
return promise.forget();

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

@ -63,7 +63,7 @@ Device::Device(Adapter* const aParent, RawId aId,
mLimits(new SupportedLimits(aParent, std::move(aRawLimits))),
mBridge(aParent->mBridge),
mQueue(new class Queue(this, aParent->mBridge, aId)) {
mBridge->RegisterDevice(mId, this);
mBridge->RegisterDevice(this);
}
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::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }

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

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

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

@ -38,7 +38,7 @@ parent:
async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId);
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 BufferReturnShmem(RawId selfId, Shmem shmem);
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,
ffi::WGPULimits* aLimits) {
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
ffi::WGPUDeviceDescriptor desc = {};
ffi::wgpu_client_fill_default_limits(&desc.limits);
const auto featureBits = Adapter::MakeFeatureBits(aDesc.mRequiredFeatures);
if (!featureBits) {
return {};
return Nothing();
}
desc.features = *featureBits;
@ -283,14 +281,17 @@ Maybe<RawId> WebGPUChild::AdapterRequestDevice(
}
}
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
ByteBuf bb;
ffi::wgpu_client_serialize_device_descriptor(&desc, ToFFI(&bb));
if (SendAdapterRequestDevice(aSelfId, std::move(bb), id)) {
DeviceRequest request;
request.mId = id;
request.mPromise = SendAdapterRequestDevice(aSelfId, std::move(bb), id);
*aLimits = desc.limits;
return Some(id);
}
ffi::wgpu_client_kill_device_id(mClient, id);
return Nothing();
return Some(std::move(request));
}
RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId,
@ -979,8 +980,8 @@ void WebGPUChild::SwapChainPresent(wr::ExternalImageId aExternalImageId,
SendSwapChainPresent(aExternalImageId, aTextureId, encoderId);
}
void WebGPUChild::RegisterDevice(RawId aId, Device* aDevice) {
mDeviceMap.insert({aId, aDevice});
void WebGPUChild::RegisterDevice(Device* const aDevice) {
mDeviceMap.insert({aDevice->mId, aDevice});
}
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 mozilla

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

@ -27,6 +27,7 @@ struct WGPUTextureViewDescriptor;
using AdapterPromise =
MozPromise<ipc::ByteBuf, Maybe<ipc::ResponseRejectReason>, true>;
using PipelinePromise = MozPromise<RawId, ipc::ResponseRejectReason, true>;
using DevicePromise = MozPromise<bool, ipc::ResponseRejectReason, true>;
struct PipelineCreationContext {
RawId mParentId = 0;
@ -34,6 +35,13 @@ struct PipelineCreationContext {
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);
class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
@ -50,9 +58,9 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
RefPtr<AdapterPromise> InstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions);
Maybe<RawId> AdapterRequestDevice(RawId aSelfId,
const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimtis);
Maybe<DeviceRequest> AdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimits);
RawId DeviceCreateBuffer(RawId aSelfId,
const dom::GPUBufferDescriptor& aDesc);
RawId DeviceCreateTexture(RawId aSelfId,
@ -95,8 +103,9 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
wr::ExternalImageId aExternalImageId);
void SwapChainPresent(wr::ExternalImageId aExternalImageId, RawId aTextureId);
void RegisterDevice(RawId aId, Device* aDevice);
void RegisterDevice(Device* const aDevice);
void UnregisterDevice(RawId aId);
void FreeUnregisteredInParentDevice(RawId aId);
static void ConvertTextureFormatRef(const dom::GPUTextureFormat& aInput,
ffi::WGPUTextureFormat& aOutput);

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

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

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

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