Bug 1709951 - Make WebGPU handle GPU process loss. r=gfx-reviewers,webidl,jgilbert,smaug

Differential Revision: https://phabricator.services.mozilla.com/D143247
This commit is contained in:
Andrew Osmond 2022-04-27 21:13:21 +00:00
Родитель 3ee5a34515
Коммит 6e033cd6a3
15 изменённых файлов: 225 добавлений и 65 удалений

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

@ -41,10 +41,10 @@ Maybe<uint32_t> Adapter::MakeFeatureBits(
return Some(bits);
}
Adapter::Adapter(Instance* const aParent,
Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge,
const ffi::WGPUAdapterInformation& aInfo)
: ChildOf(aParent),
mBridge(aParent->mBridge),
mBridge(aBridge),
mId(aInfo.id),
mFeatures(new SupportedFeatures(this)),
mLimits(
@ -69,7 +69,7 @@ Adapter::Adapter(Instance* const aParent,
Adapter::~Adapter() { Cleanup(); }
void Adapter::Cleanup() {
if (mValid && mBridge && mBridge->IsOpen()) {
if (mValid && mBridge && mBridge->CanSend()) {
mValid = false;
mBridge->SendAdapterDestroy(mId);
}
@ -85,6 +85,12 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
return nullptr;
}
if (!mBridge->CanSend()) {
promise->MaybeRejectWithInvalidStateError(
"WebGPUChild cannot send, must recreate Adapter");
return promise.forget();
}
ffi::WGPULimits limits = {};
auto request = mBridge->AdapterRequestDevice(mId, aDesc, &limits);
if (request) {

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

@ -56,7 +56,8 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
const bool mIsFallbackAdapter = false;
public:
Adapter(Instance* const aParent, const ffi::WGPUAdapterInformation& aInfo);
Adapter(Instance* const aParent, WebGPUChild* const aBridge,
const ffi::WGPUAdapterInformation& aInfo);
void GetName(nsString& out) const { out = mName; }
const RefPtr<SupportedFeatures>& Features() const;
const RefPtr<SupportedLimits>& Limits() const;

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

@ -69,6 +69,11 @@ void CanvasContext::Configure(const dom::GPUCanvasConfiguration& aDesc) {
mHandle = layers::CompositableInProcessManager::GetNextHandle();
mTexture =
aDesc.mDevice->InitSwapChain(aDesc, mHandle, mGfxFormat, &actualSize);
if (!mTexture) {
Unconfigure();
return;
}
mTexture->mTargetContext = this;
mBridge = aDesc.mDevice->GetBridge();
mGfxSize = actualSize;

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

@ -100,11 +100,10 @@ CommandEncoder::CommandEncoder(Device* const aParent,
CommandEncoder::~CommandEncoder() { Cleanup(); }
void CommandEncoder::Cleanup() {
if (mValid && mParent) {
if (mValid) {
mValid = false;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendCommandEncoderDestroy(mId);
if (mBridge->IsOpen()) {
mBridge->SendCommandEncoderDestroy(mId);
}
}
}
@ -114,7 +113,7 @@ void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
const Buffer& aDestination,
BufferAddress aDestinationOffset,
BufferAddress aSize) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
ffi::wgpu_command_encoder_copy_buffer_to_buffer(
aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize,
@ -127,7 +126,7 @@ void CommandEncoder::CopyBufferToTexture(
const dom::GPUImageCopyBuffer& aSource,
const dom::GPUImageCopyTexture& aDestination,
const dom::GPUExtent3D& aCopySize) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
ffi::wgpu_command_encoder_copy_buffer_to_texture(
ConvertBufferCopyView(aSource), ConvertTextureCopyView(aDestination),
@ -144,7 +143,7 @@ void CommandEncoder::CopyTextureToBuffer(
const dom::GPUImageCopyTexture& aSource,
const dom::GPUImageCopyBuffer& aDestination,
const dom::GPUExtent3D& aCopySize) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
ffi::wgpu_command_encoder_copy_texture_to_buffer(
ConvertTextureCopyView(aSource), ConvertBufferCopyView(aDestination),
@ -156,7 +155,7 @@ void CommandEncoder::CopyTextureToTexture(
const dom::GPUImageCopyTexture& aSource,
const dom::GPUImageCopyTexture& aDestination,
const dom::GPUExtent3D& aCopySize) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
ffi::wgpu_command_encoder_copy_texture_to_texture(
ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination),
@ -171,7 +170,7 @@ void CommandEncoder::CopyTextureToTexture(
}
void CommandEncoder::PushDebugGroup(const nsAString& aString) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
const NS_ConvertUTF16toUTF8 utf8(aString);
ffi::wgpu_command_encoder_push_debug_group(utf8.get(), ToFFI(&bb));
@ -179,14 +178,14 @@ void CommandEncoder::PushDebugGroup(const nsAString& aString) {
}
}
void CommandEncoder::PopDebugGroup() {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
}
}
void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
if (mValid) {
if (mValid && mBridge->IsOpen()) {
ipc::ByteBuf bb;
const NS_ConvertUTF16toUTF8 utf8(aString);
ffi::wgpu_command_encoder_insert_debug_marker(utf8.get(), ToFFI(&bb));
@ -219,7 +218,7 @@ already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass,
ErrorResult& aRv) {
if (!mValid) {
if (!mValid || !mBridge->IsOpen()) {
return aRv.ThrowInvalidStateError("Command encoder is not valid");
}
@ -230,7 +229,7 @@ void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass,
void CommandEncoder::EndRenderPass(ffi::WGPURenderPass& aPass,
ErrorResult& aRv) {
if (!mValid) {
if (!mValid || !mBridge->IsOpen()) {
return aRv.ThrowInvalidStateError("Command encoder is not valid");
}
@ -242,7 +241,7 @@ void CommandEncoder::EndRenderPass(ffi::WGPURenderPass& aPass,
already_AddRefed<CommandBuffer> CommandEncoder::Finish(
const dom::GPUCommandBufferDescriptor& aDesc) {
RawId id = 0;
if (mValid) {
if (mValid && mBridge->IsOpen()) {
mValid = false;
id = mBridge->CommandEncoderFinish(mId, mParent->mId, aDesc);
}

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

@ -17,6 +17,7 @@
#include "Adapter.h"
#include "Buffer.h"
#include "ComputePipeline.h"
#include "DeviceLostInfo.h"
#include "Queue.h"
#include "RenderBundleEncoder.h"
#include "RenderPipeline.h"
@ -35,7 +36,7 @@ mozilla::LazyLogModule gWebGPULog("WebGPU");
GPU_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_INHERITED(Device, DOMEventTargetHelper,
mBridge, mQueue, mFeatures,
mLimits);
mLimits, mLostPromise);
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(Device, DOMEventTargetHelper)
GPU_IMPL_JS_WRAP(Device)
@ -69,10 +70,22 @@ Device::Device(Adapter* const aParent, RawId aId,
Device::~Device() { Cleanup(); }
void Device::Cleanup() {
if (mValid && mBridge) {
mValid = false;
if (!mValid) {
return;
}
mValid = false;
if (mBridge) {
mBridge->UnregisterDevice(mId);
}
if (mLostPromise) {
auto info = MakeRefPtr<DeviceLostInfo>(GetParentObject(),
dom::GPUDeviceLostReason::Destroyed,
u"Device destroyed"_ns);
mLostPromise->MaybeResolve(info);
}
}
void Device::CleanupUnregisteredInParent() {
@ -85,8 +98,25 @@ void Device::CleanupUnregisteredInParent() {
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }
dom::Promise* Device::GetLost(ErrorResult& aRv) {
if (!mLostPromise) {
mLostPromise = dom::Promise::Create(GetParentObject(), aRv);
if (mLostPromise && !mBridge->CanSend()) {
auto info = MakeRefPtr<DeviceLostInfo>(GetParentObject(),
u"WebGPUChild destroyed"_ns);
mLostPromise->MaybeResolve(info);
}
}
return mLostPromise;
}
already_AddRefed<Buffer> Device::CreateBuffer(
const dom::GPUBufferDescriptor& aDesc, ErrorResult& aRv) {
if (!mBridge->CanSend()) {
RefPtr<Buffer> buffer = new Buffer(this, 0, aDesc.mSize, false);
return buffer.forget();
}
ipc::Shmem shmem;
bool hasMapFlags = aDesc.mUsage & (dom::GPUBufferUsage_Binding::MAP_WRITE |
dom::GPUBufferUsage_Binding::MAP_READ);
@ -157,26 +187,37 @@ RefPtr<MappingPromise> Device::MapBufferAsync(RawId aId, uint32_t aMode,
void Device::UnmapBuffer(RawId aId, ipc::Shmem&& aShmem, bool aFlush,
bool aKeepShmem) {
mBridge->SendBufferUnmap(aId, std::move(aShmem), aFlush, aKeepShmem);
if (mBridge->CanSend()) {
mBridge->SendBufferUnmap(aId, std::move(aShmem), aFlush, aKeepShmem);
}
}
already_AddRefed<Texture> Device::CreateTexture(
const dom::GPUTextureDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateTexture(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateTexture(mId, aDesc);
}
RefPtr<Texture> texture = new Texture(this, id, aDesc);
return texture.forget();
}
already_AddRefed<Sampler> Device::CreateSampler(
const dom::GPUSamplerDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateSampler(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateSampler(mId, aDesc);
}
RefPtr<Sampler> sampler = new Sampler(this, id);
return sampler.forget();
}
already_AddRefed<CommandEncoder> Device::CreateCommandEncoder(
const dom::GPUCommandEncoderDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateCommandEncoder(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateCommandEncoder(mId, aDesc);
}
RefPtr<CommandEncoder> encoder = new CommandEncoder(this, mBridge, id);
return encoder.forget();
}
@ -190,19 +231,28 @@ already_AddRefed<RenderBundleEncoder> Device::CreateRenderBundleEncoder(
already_AddRefed<BindGroupLayout> Device::CreateBindGroupLayout(
const dom::GPUBindGroupLayoutDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateBindGroupLayout(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateBindGroupLayout(mId, aDesc);
}
RefPtr<BindGroupLayout> object = new BindGroupLayout(this, id, true);
return object.forget();
}
already_AddRefed<PipelineLayout> Device::CreatePipelineLayout(
const dom::GPUPipelineLayoutDescriptor& aDesc) {
RawId id = mBridge->DeviceCreatePipelineLayout(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreatePipelineLayout(mId, aDesc);
}
RefPtr<PipelineLayout> object = new PipelineLayout(this, id);
return object.forget();
}
already_AddRefed<BindGroup> Device::CreateBindGroup(
const dom::GPUBindGroupDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateBindGroup(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateBindGroup(mId, aDesc);
}
RefPtr<BindGroup> object = new BindGroup(this, id);
return object.forget();
}
@ -210,7 +260,10 @@ already_AddRefed<BindGroup> Device::CreateBindGroup(
already_AddRefed<ShaderModule> Device::CreateShaderModule(
JSContext* aCx, const dom::GPUShaderModuleDescriptor& aDesc) {
Unused << aCx;
RawId id = mBridge->DeviceCreateShaderModule(mId, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateShaderModule(mId, aDesc);
}
RefPtr<ShaderModule> object = new ShaderModule(this, id);
return object.forget();
}
@ -218,7 +271,10 @@ already_AddRefed<ShaderModule> Device::CreateShaderModule(
already_AddRefed<ComputePipeline> Device::CreateComputePipeline(
const dom::GPUComputePipelineDescriptor& aDesc) {
PipelineCreationContext context = {mId};
RawId id = mBridge->DeviceCreateComputePipeline(&context, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateComputePipeline(&context, aDesc);
}
RefPtr<ComputePipeline> object =
new ComputePipeline(this, id, context.mImplicitPipelineLayoutId,
std::move(context.mImplicitBindGroupLayoutIds));
@ -228,7 +284,10 @@ already_AddRefed<ComputePipeline> Device::CreateComputePipeline(
already_AddRefed<RenderPipeline> Device::CreateRenderPipeline(
const dom::GPURenderPipelineDescriptor& aDesc) {
PipelineCreationContext context = {mId};
RawId id = mBridge->DeviceCreateRenderPipeline(&context, aDesc);
RawId id = 0;
if (mBridge->CanSend()) {
id = mBridge->DeviceCreateRenderPipeline(&context, aDesc);
}
RefPtr<RenderPipeline> object =
new RenderPipeline(this, id, context.mImplicitPipelineLayoutId,
std::move(context.mImplicitBindGroupLayoutIds));
@ -242,6 +301,11 @@ already_AddRefed<dom::Promise> Device::CreateComputePipelineAsync(
return nullptr;
}
if (!mBridge->CanSend()) {
promise->MaybeRejectWithOperationError("Internal communication error");
return promise.forget();
}
std::shared_ptr<PipelineCreationContext> context(
new PipelineCreationContext());
context->mParentId = mId;
@ -269,6 +333,11 @@ already_AddRefed<dom::Promise> Device::CreateRenderPipelineAsync(
return nullptr;
}
if (!mBridge->CanSend()) {
promise->MaybeRejectWithOperationError("Internal communication error");
return promise.forget();
}
std::shared_ptr<PipelineCreationContext> context(
new PipelineCreationContext());
context->mParentId = mId;
@ -293,6 +362,10 @@ already_AddRefed<Texture> Device::InitSwapChain(
const dom::GPUCanvasConfiguration& aDesc,
const layers::CompositableHandle& aHandle, gfx::SurfaceFormat aFormat,
gfx::IntSize* aCanvasSize) {
if (!mBridge->CanSend()) {
return nullptr;
}
gfx::IntSize size = *aCanvasSize;
if (aDesc.mSize.WasPassed()) {
const auto& descSize = aDesc.mSize.Value();
@ -338,7 +411,9 @@ void Device::Destroy() {
}
void Device::PushErrorScope(const dom::GPUErrorFilter& aFilter) {
mBridge->SendDevicePushErrorScope(mId);
if (mBridge->CanSend()) {
mBridge->SendDevicePushErrorScope(mId);
}
}
already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) {
@ -347,6 +422,11 @@ already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) {
return nullptr;
}
if (!mBridge->CanSend()) {
promise->MaybeRejectWithOperationError("Internal communication error");
return promise.forget();
}
auto errorPromise = mBridge->SendDevicePopErrorScope(mId);
errorPromise->Then(

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

@ -118,12 +118,15 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
RefPtr<WebGPUChild> mBridge;
bool mValid = true;
nsString mLabel;
RefPtr<dom::Promise> mLostPromise;
RefPtr<Queue> mQueue;
nsTHashSet<nsCString> mKnownWarnings;
public:
void GetLabel(nsAString& aValue) const;
void SetLabel(const nsAString& aLabel);
dom::Promise* GetLost(ErrorResult& aRv);
dom::Promise* MaybeGetLost() const { return mLostPromise; }
const RefPtr<SupportedFeatures>& Features() const { return mFeatures; }
const RefPtr<SupportedLimits>& Limits() const { return mLimits; }

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

@ -4,12 +4,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DeviceLostInfo.h"
#include "mozilla/dom/WebGPUBinding.h"
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(DeviceLostInfo, mParent)
GPU_IMPL_CYCLE_COLLECTION(DeviceLostInfo, mGlobal)
GPU_IMPL_JS_WRAP(DeviceLostInfo)
} // namespace webgpu

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

@ -6,28 +6,46 @@
#ifndef GPU_DeviceLostInfo_H_
#define GPU_DeviceLostInfo_H_
#include "mozilla/dom/WebGPUBinding.h"
#include "mozilla/Maybe.h"
#include "nsWrapperCache.h"
#include "ObjectModel.h"
namespace mozilla {
namespace webgpu {
namespace mozilla::webgpu {
class Device;
class DeviceLostInfo final : public nsWrapperCache, public ChildOf<Device> {
class DeviceLostInfo final : public nsWrapperCache {
public:
GPU_DECL_CYCLE_COLLECTION(DeviceLostInfo)
GPU_DECL_JS_WRAP(DeviceLostInfo)
explicit DeviceLostInfo(nsIGlobalObject* const aGlobal,
const nsAString& aMessage)
: mGlobal(aGlobal), mMessage(aMessage) {}
DeviceLostInfo(nsIGlobalObject* const aGlobal,
dom::GPUDeviceLostReason aReason, const nsAString& aMessage)
: mGlobal(aGlobal), mReason(Some(aReason)), mMessage(aMessage) {}
private:
DeviceLostInfo() = delete;
~DeviceLostInfo() = default;
void Cleanup() {}
nsCOMPtr<nsIGlobalObject> mGlobal;
const Maybe<dom::GPUDeviceLostReason> mReason;
const nsAutoString mMessage;
public:
void GetMessage(nsAString& aValue) const {}
void GetReason(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval) {
if (!mReason || !dom::ToJSValue(aCx, mReason.value(), aRetval)) {
aRetval.setUndefined();
}
}
void GetMessage(nsAString& aValue) const { aValue = mMessage; }
nsIGlobalObject* GetParentObject() const { return mGlobal; }
};
} // namespace webgpu
} // namespace mozilla
} // namespace mozilla::webgpu
#endif // GPU_DeviceLostInfo_H_

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

@ -17,25 +17,15 @@
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(Instance, mBridge, mOwner)
GPU_IMPL_CYCLE_COLLECTION(Instance, mOwner)
/*static*/
already_AddRefed<Instance> Instance::Create(nsIGlobalObject* aOwner) {
RefPtr<WebGPUChild> bridge;
if (gfx::gfxVars::AllowWebGPU()) {
bridge = gfx::CanvasManagerChild::Get()->GetWebGPUChild();
if (NS_WARN_IF(!bridge)) {
MOZ_CRASH("Failed to create an IPDL bridge for WebGPU!");
}
}
RefPtr<Instance> result = new Instance(aOwner, bridge);
RefPtr<Instance> result = new Instance(aOwner);
return result.forget();
}
Instance::Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge)
: mBridge(aBridge), mOwner(aOwner) {}
Instance::Instance(nsIGlobalObject* aOwner) : mOwner(aOwner) {}
Instance::~Instance() { Cleanup(); }
@ -52,20 +42,34 @@ already_AddRefed<dom::Promise> Instance::RequestAdapter(
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (!mBridge) {
promise->MaybeRejectWithInvalidStateError("WebGPU is not enabled!");
if (!gfx::gfxVars::AllowWebGPU()) {
promise->MaybeRejectWithNotSupportedError("WebGPU is not enabled!");
return promise.forget();
}
auto* const canvasManager = gfx::CanvasManagerChild::Get();
if (!canvasManager) {
promise->MaybeRejectWithInvalidStateError(
"Failed to create CanavasManagerChild");
return promise.forget();
}
RefPtr<WebGPUChild> bridge = canvasManager->GetWebGPUChild();
if (!bridge) {
promise->MaybeRejectWithInvalidStateError("Failed to create WebGPUChild");
return promise.forget();
}
RefPtr<Instance> instance = this;
mBridge->InstanceRequestAdapter(aOptions)->Then(
bridge->InstanceRequestAdapter(aOptions)->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, instance](ipc::ByteBuf aInfoBuf) {
[promise, instance, bridge](ipc::ByteBuf aInfoBuf) {
ffi::WGPUAdapterInformation info = {};
ffi::wgpu_client_adapter_extract_info(ToFFI(&aInfoBuf), &info);
MOZ_ASSERT(info.id != 0);
RefPtr<Adapter> adapter = new Adapter(instance, info);
RefPtr<Adapter> adapter = new Adapter(instance, bridge, info);
promise->MaybeResolve(adapter);
},
[promise](const Maybe<ipc::ResponseRejectReason>& aResponseReason) {

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

@ -35,10 +35,8 @@ class Instance final : public nsWrapperCache {
already_AddRefed<dom::Promise> RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv);
RefPtr<WebGPUChild> mBridge;
private:
explicit Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge);
explicit Instance(nsIGlobalObject* aOwner);
virtual ~Instance();
void Cleanup();

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

@ -31,6 +31,10 @@ void ScopedFfiBundleTraits::release(ffi::WGPURenderBundleEncoder* raw) {
ffi::WGPURenderBundleEncoder* CreateRenderBundleEncoder(
RawId aDeviceId, const dom::GPURenderBundleEncoderDescriptor& aDesc,
WebGPUChild* const aBridge) {
if (!aBridge->CanSend()) {
return nullptr;
}
ffi::WGPURenderBundleEncoderDescriptor desc = {};
desc.sample_count = aDesc.mSampleCount;
@ -183,7 +187,7 @@ already_AddRefed<RenderBundle> RenderBundleEncoder::Finish(
if (mValid) {
mValid = false;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
if (bridge && bridge->CanSend()) {
auto* encoder = mEncoder.forget();
MOZ_ASSERT(encoder);
id = bridge->RenderBundleEncoderFinish(*encoder, mParent->mId, aDesc);

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

@ -105,7 +105,12 @@ void Texture::Cleanup() {
already_AddRefed<TextureView> Texture::CreateView(
const dom::GPUTextureViewDescriptor& aDesc) {
RawId id = mParent->GetBridge()->TextureCreateView(mId, mParent->mId, aDesc);
auto bridge = mParent->GetBridge();
RawId id = 0;
if (bridge->IsOpen()) {
id = bridge->TextureCreateView(mId, mParent->mId, aDesc);
}
RefPtr<TextureView> view = new TextureView(this, id);
return view.forget();
}

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

@ -6,12 +6,14 @@
#include "WebGPUChild.h"
#include "js/Warnings.h" // JS::WarnUTF8
#include "mozilla/EnumTypeTraits.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/WebGPUBinding.h"
#include "mozilla/dom/GPUUncapturedErrorEvent.h"
#include "mozilla/webgpu/ValidationError.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "Adapter.h"
#include "DeviceLostInfo.h"
#include "Sampler.h"
namespace mozilla {
@ -1050,5 +1052,34 @@ void WebGPUChild::FreeUnregisteredInParentDevice(RawId aId) {
mDeviceMap.erase(aId);
}
void WebGPUChild::ActorDestroy(ActorDestroyReason) {
// Resolving the promise could cause us to update the original map if the
// callee frees the Device objects immediately. Since any remaining entries
// in the map are no longer valid, we can just move the map onto the stack.
const auto deviceMap = std::move(mDeviceMap);
mDeviceMap.clear();
for (const auto& targetIter : deviceMap) {
RefPtr<Device> device = targetIter.second.get();
if (!device) {
// The Device may have gotten freed when we resolved the Promise for
// another Device in the map.
continue;
}
RefPtr<dom::Promise> promise = device->MaybeGetLost();
if (!promise) {
continue;
}
auto info = MakeRefPtr<DeviceLostInfo>(device->GetParentObject(),
u"WebGPUChild destroyed"_ns);
// We have strong references to both the Device and the DeviceLostInfo and
// the Promise objects on the stack which keeps them alive for long enough.
promise->MaybeResolve(info);
}
}
} // namespace webgpu
} // namespace mozilla

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

@ -133,6 +133,7 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
ipc::IPCResult RecvDeviceUncapturedError(RawId aDeviceId,
const nsACString& aMessage);
ipc::IPCResult RecvDropAction(const ipc::ByteBuf& aByteBuf);
void ActorDestroy(ActorDestroyReason) override;
};
} // namespace webgpu

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

@ -188,9 +188,14 @@ GPUDevice includes GPUObjectBase;
// ERROR HANDLING
// ****************************************************************************
enum GPUDeviceLostReason {
"destroyed",
};
[Pref="dom.webgpu.enabled",
Exposed=(Window,DedicatedWorker)]
interface GPUDeviceLostInfo {
readonly attribute any reason; // GPUDeviceLostReason or undefined
readonly attribute DOMString message;
};
@ -216,7 +221,8 @@ interface GPUValidationError {
typedef (GPUOutOfMemoryError or GPUValidationError) GPUError;
partial interface GPUDevice {
//readonly attribute Promise<GPUDeviceLostInfo> lost;
[Throws]
readonly attribute Promise<GPUDeviceLostInfo> lost;
void pushErrorScope(GPUErrorFilter filter);
[NewObject]
Promise<GPUError?> popErrorScope();