зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3ee5a34515
Коммит
6e033cd6a3
|
@ -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) {
|
||||
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) {
|
||||
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,8 +411,10 @@ void Device::Destroy() {
|
|||
}
|
||||
|
||||
void Device::PushErrorScope(const dom::GPUErrorFilter& aFilter) {
|
||||
if (mBridge->CanSend()) {
|
||||
mBridge->SendDevicePushErrorScope(mId);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> Device::PopErrorScope(ErrorResult& aRv) {
|
||||
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), 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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче