Bug 1602133 - WebGPU presentation r=jgilbert,webidl,smaug,aosmond

This change adds support for CanvasContext presenting WebGPU via CPU readback.
The presentation is handled mostly on GPU process side by managing a list of staging buffers
and copying the contents into a WR external image (backed by an external buffer).

Differential Revision: https://phabricator.services.mozilla.com/D68032

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dzmitry Malyshau 2020-04-06 22:29:18 +00:00
parent a2961d74e7
commit 3021defc28
57 changed files with 904 additions and 194 deletions

View File

@ -10,6 +10,7 @@
#include "mozilla/GfxMessageUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/webgpu/CanvasContext.h"
#include "MozFramebuffer.h"
#include "nsContentUtils.h"
#include "nsDOMJSUtils.h"
@ -139,6 +140,15 @@ CanvasRenderingContextHelper::CreateContextHelper(
break;
case CanvasContextType::WebGPU:
// TODO
// Telemetry::Accumulate(Telemetry::CANVAS_WEBGPU_USED, 1);
ret = new webgpu::CanvasContext();
if (!ret) return nullptr;
break;
case CanvasContextType::ImageBitmap:
ret = new ImageBitmapRenderingContext();
@ -185,12 +195,18 @@ already_AddRefed<nsISupports> CanvasRenderingContextHelper::GetContext(
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0);
else if (contextType == CanvasContextType::WebGL2)
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0);
else if (contextType == CanvasContextType::WebGPU) {
// Telemetry::Accumulate(Telemetry::CANVAS_WEBGPU_SUCCESS, 0);
}
return nullptr;
}
if (contextType == CanvasContextType::WebGL1)
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1);
else if (contextType == CanvasContextType::WebGL2)
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1);
else if (contextType == CanvasContextType::WebGPU) {
// Telemetry::Accumulate(Telemetry::CANVAS_WEBGPU_SUCCESS, 1);
}
} else {
// We already have a context of some type.
if (contextType != mCurrentContextType) return nullptr;

View File

@ -27,6 +27,7 @@ enum class CanvasContextType : uint8_t {
Canvas2D,
WebGL1,
WebGL2,
WebGPU,
ImageBitmap
};

View File

@ -207,6 +207,13 @@ bool GetCanvasContextType(const nsAString& str,
}
}
if (StaticPrefs::dom_webgpu_enabled()) {
if (str.EqualsLiteral("gpupresent")) {
*out_type = dom::CanvasContextType::WebGPU;
return true;
}
}
if (str.EqualsLiteral("bitmaprenderer")) {
*out_type = dom::CanvasContextType::ImageBitmap;
return true;

View File

@ -821,12 +821,14 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
RefPtr<SourceSurface> croppedSurface;
IntRect cropRect = aCropRect.valueOr(IntRect());
// If the HTMLCanvasElement's rendering context is WebGL, then the snapshot
// we got from the HTMLCanvasElement is a DataSourceSurface which is a copy
// of the rendering context. We handle cropping in this case.
// If the HTMLCanvasElement's rendering context is WebGL/WebGPU,
// then the snapshot we got from the HTMLCanvasElement is
// a DataSourceSurface which is a copy of the rendering context.
// We handle cropping in this case.
bool needToReportMemoryAllocation = false;
if ((aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL1 ||
aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2) &&
aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2 ||
aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGPU) &&
aCropRect.isSome()) {
RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect);

View File

@ -101,6 +101,7 @@ already_AddRefed<nsISupports> OffscreenCanvas::GetContext(
if (!(contextType == CanvasContextType::WebGL1 ||
contextType == CanvasContextType::WebGL2 ||
contextType == CanvasContextType::WebGPU ||
contextType == CanvasContextType::ImageBitmap)) {
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
@ -120,6 +121,10 @@ already_AddRefed<nsISupports> OffscreenCanvas::GetContext(
MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
return nullptr;
}
if (contextType == CanvasContextType::WebGPU) {
MOZ_ASSERT_UNREACHABLE("WebGPU OffscreenCanvas not yet supported.");
return nullptr;
}
}
return result.forget();
@ -165,6 +170,10 @@ void OffscreenCanvas::CommitFrameToCompositor() {
MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
return;
}
if (mCurrentContext && (contentType == CanvasContextType::WebGPU)) {
MOZ_ASSERT_UNREACHABLE("WebGPU OffscreenCanvas not yet supported.");
return;
}
if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
mCanvasRenderer->NotifyElementAboutInvalidation();

View File

@ -33,6 +33,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "mozilla/webgpu/CanvasContext.h"
#include "nsAttrValueInlines.h"
#include "nsContentUtils.h"
#include "nsDisplayList.h"
@ -1513,5 +1514,13 @@ ClientWebGLContext* HTMLCanvasElement::GetWebGLContext() {
return static_cast<ClientWebGLContext*>(GetContextAtIndex(0));
}
webgpu::CanvasContext* HTMLCanvasElement::GetWebGPUContext() {
if (GetCurrentContextType() != CanvasContextType::WebGPU) {
return nullptr;
}
return static_cast<webgpu::CanvasContext*>(GetContextAtIndex(0));
}
} // namespace dom
} // namespace mozilla

View File

@ -43,6 +43,9 @@ namespace gfx {
class SourceSurface;
class VRLayerChild;
} // namespace gfx
namespace webgpu {
class CanvasContext;
} // namespace webgpu
namespace dom {
class BlobCallback;
@ -374,6 +377,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
public:
ClientWebGLContext* GetWebGLContext();
webgpu::CanvasContext* GetWebGPUContext();
protected:
bool mResetLayer;

View File

@ -29,7 +29,7 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
GPU_DECL_CYCLE_COLLECTION(Adapter)
GPU_DECL_JS_WRAP(Adapter)
const RefPtr<WebGPUChild> mBridge;
RefPtr<WebGPUChild> mBridge;
private:
Adapter() = delete;

View File

@ -22,7 +22,7 @@ BindGroup::~BindGroup() { Cleanup(); }
void BindGroup::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendBindGroupDestroy(mId);
}

View File

@ -22,7 +22,7 @@ BindGroupLayout::~BindGroupLayout() { Cleanup(); }
void BindGroupLayout::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendBindGroupLayoutDestroy(mId);
}

View File

@ -51,7 +51,7 @@ Buffer::~Buffer() {
void Buffer::Cleanup() {
if (mParent) {
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendBufferDestroy(mId);
}

View File

@ -5,31 +5,111 @@
#include "mozilla/dom/WebGPUBinding.h"
#include "CanvasContext.h"
#include "SwapChain.h"
#include "nsDisplayList.h"
#include "LayerUserData.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/layers/CompositorManagerChild.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
namespace mozilla {
namespace webgpu {
CanvasContext::~CanvasContext() = default;
NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasContext)
GPU_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasContext, mSwapChain,
mCanvasElement, mOffscreenCanvas)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasContext)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
CanvasContext::CanvasContext()
: mExternalImageId(layers::CompositorManagerChild::GetInstance()
->GetNextExternalImageId()) {
}
CanvasContext::~CanvasContext() { Cleanup(); }
void CanvasContext::Cleanup() {
if (mSwapChain) {
mSwapChain->Destroy(mExternalImageId);
mSwapChain = nullptr;
}
if (mRenderRootStateManager && mImageKey) {
mRenderRootStateManager->AddImageKeyForDiscard(mImageKey.value());
mRenderRootStateManager = nullptr;
mImageKey.reset();
}
}
JSObject* CanvasContext::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return dom::GPUCanvasContext_Binding::Wrap(aCx, this, aGivenProto);
}
NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasContext)
already_AddRefed<layers::Layer> CanvasContext::GetCanvasLayer(
nsDisplayListBuilder* aBuilder, layers::Layer* aOldLayer,
layers::LayerManager* aManager) {
return nullptr;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasContext)
bool CanvasContext::UpdateWebRenderCanvasData(
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
return true;
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasContext)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
// NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
// If the exact way we cast to nsISupports here ever changes, fix our
// ToSupports() method.
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,
nsICanvasRenderingContextInternal)
NS_INTERFACE_MAP_END
RefPtr<SwapChain> CanvasContext::ConfigureSwapChain(
const dom::GPUSwapChainDescriptor& aDesc, ErrorResult& aRv) {
Cleanup();
gfx::SurfaceFormat format;
switch (aDesc.mFormat) {
case dom::GPUTextureFormat::Rgba8unorm:
format = gfx::SurfaceFormat::R8G8B8A8;
break;
case dom::GPUTextureFormat::Bgra8unorm:
format = gfx::SurfaceFormat::B8G8R8A8;
break;
default:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
dom::GPUExtent3DDict extent;
extent.mWidth = mWidth;
extent.mHeight = mHeight;
extent.mDepth = 1;
mSwapChain = new SwapChain(aDesc, extent, mExternalImageId, format);
return mSwapChain;
}
Maybe<wr::ImageKey> CanvasContext::GetImageKey() const { return mImageKey; }
wr::ImageKey CanvasContext::CreateImageKey(
layers::RenderRootStateManager* aManager) {
const auto key = aManager->WrBridge()->GetNextImageKey();
mRenderRootStateManager = aManager;
mImageKey = Some(key);
return key;
}
bool CanvasContext::UpdateWebRenderLocalCanvasData(
layers::WebRenderLocalCanvasData* aCanvasData) {
if (!mSwapChain || !mSwapChain->GetGpuBridge()) {
return false;
}
aCanvasData->mGpuBridge = mSwapChain->GetGpuBridge();
aCanvasData->mGpuTextureId = mSwapChain->GetCurrentTexture()->mId;
aCanvasData->mExternalImageId = mExternalImageId;
aCanvasData->mFormat = mSwapChain->mFormat;
return true;
}
} // namespace webgpu
} // namespace mozilla

View File

@ -10,36 +10,52 @@
#include "nsWrapperCache.h"
#include "ObjectModel.h"
#include "SwapChain.h"
#include "mozilla/webrender/WebRenderAPI.h"
namespace mozilla {
namespace dom {
class Promise;
}
} // namespace dom
namespace layers {
class WebRenderLocalCanvasData;
};
namespace webgpu {
class Device;
class SwapChain;
class Texture;
class CanvasContext final : public nsICanvasRenderingContextInternal,
public nsWrapperCache {
private:
virtual ~CanvasContext();
void Cleanup();
public:
CanvasContext() = delete;
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// nsISupports interface + CC
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CanvasContext)
public:
// nsICanvasRenderingContextInternal
int32_t GetWidth() override { return 0; }
int32_t GetHeight() override { return 0; }
CanvasContext();
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
void RemoveSwapChain();
Maybe<wr::ImageKey> GetImageKey() const;
wr::ImageKey CreateImageKey(layers::RenderRootStateManager* aManager);
bool UpdateWebRenderLocalCanvasData(
layers::WebRenderLocalCanvasData* aCanvasData);
const wr::ExternalImageId mExternalImageId;
public: // nsICanvasRenderingContextInternal
int32_t GetWidth() override { return mWidth; }
int32_t GetHeight() override { return mHeight; }
NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override {
mWidth = aWidth;
mHeight = aHeight;
return NS_OK;
}
NS_IMETHOD InitializeWithDrawTarget(
@ -67,9 +83,9 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
NS_IMETHOD Reset() override { return NS_OK; }
already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
Layer* aOldLayer,
LayerManager* aManager) override {
return nullptr;
}
LayerManager* aManager) override;
bool UpdateWebRenderCanvasData(nsDisplayListBuilder* aBuilder,
WebRenderCanvasData* aCanvasData) override;
void MarkContextClean() override {}
NS_IMETHOD Redraw(const gfxRect& aDirty) override { return NS_OK; }
@ -79,6 +95,17 @@ class CanvasContext final : public nsICanvasRenderingContextInternal,
void MarkContextCleanForFrameCapture() override {}
bool IsContextCleanForFrameCapture() override { return false; }
public:
RefPtr<SwapChain> ConfigureSwapChain(const dom::GPUSwapChainDescriptor& aDesc,
ErrorResult& aRv);
private:
uint32_t mWidth = 0, mHeight = 0;
RefPtr<SwapChain> mSwapChain;
RefPtr<layers::RenderRootStateManager> mRenderRootStateManager;
Maybe<wr::ImageKey> mImageKey;
};
} // namespace webgpu

View File

@ -26,7 +26,7 @@ CommandBuffer::~CommandBuffer() { Cleanup(); }
void CommandBuffer::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendCommandBufferDestroy(mId);
}

View File

@ -27,7 +27,7 @@ CommandEncoder::~CommandEncoder() { Cleanup(); }
void CommandEncoder::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendCommandEncoderDestroy(mId);
}

View File

@ -45,7 +45,7 @@ class CommandEncoder final : public ObjectBase, public ChildOf<Device> {
~CommandEncoder();
void Cleanup();
const RefPtr<WebGPUChild> mBridge;
RefPtr<WebGPUChild> mBridge;
public:
void EndComputePass(Span<const uint8_t> aData, ErrorResult& aRv);

View File

@ -21,7 +21,7 @@ ComputePipeline::~ComputePipeline() { Cleanup(); }
void ComputePipeline::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendComputePipelineDestroy(mId);
}

View File

@ -35,6 +35,8 @@ static void mapFreeCallback(void* aContents, void* aUserData) {
Unused << aUserData;
}
RefPtr<WebGPUChild> Device::GetBridge() { return mBridge; }
JSObject* Device::CreateExternalArrayBuffer(JSContext* aCx, size_t aSize,
ipc::Shmem& aShmem) {
MOZ_ASSERT(aShmem.Size<uint8_t>() == aSize);
@ -194,5 +196,29 @@ already_AddRefed<RenderPipeline> Device::CreateRenderPipeline(
return object.forget();
}
already_AddRefed<Texture> Device::InitSwapChain(
const dom::GPUSwapChainDescriptor& aDesc,
const dom::GPUExtent3DDict& aExtent3D, wr::ExternalImageId aExternalImageId,
gfx::SurfaceFormat aFormat) {
const layers::RGBDescriptor rgbDesc(
gfx::IntSize(AssertedCast<int>(aExtent3D.mWidth),
AssertedCast<int>(aExtent3D.mHeight)),
aFormat, false);
// buffer count doesn't matter much, will be created on demand
const size_t maxBufferCount = 10;
mBridge->DeviceCreateSwapChain(mId, rgbDesc, maxBufferCount,
aExternalImageId);
dom::GPUTextureDescriptor desc;
desc.mDimension = dom::GPUTextureDimension::_2d;
desc.mSize.SetAsGPUExtent3DDict() = aExtent3D;
desc.mFormat = aDesc.mFormat;
desc.mArrayLayerCount = 1;
desc.mMipLevelCount = 1;
desc.mSampleCount = 1;
desc.mUsage = aDesc.mUsage | dom::GPUTextureUsage_Binding::COPY_SRC;
return CreateTexture(desc);
}
} // namespace webgpu
} // namespace mozilla

View File

@ -9,6 +9,7 @@
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/webgpu/WebGPUTypes.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/DOMEventTargetHelper.h"
namespace mozilla {
@ -16,6 +17,7 @@ namespace dom {
struct GPUExtensions;
struct GPUFeatures;
struct GPULimits;
struct GPUExtent3DDict;
struct GPUBufferDescriptor;
struct GPUTextureDescriptor;
@ -32,6 +34,7 @@ struct GPUComputePipelineDescriptor;
struct GPURenderBundleEncoderDescriptor;
struct GPURenderPipelineDescriptor;
struct GPUCommandEncoderDescriptor;
struct GPUSwapChainDescriptor;
class EventHandlerNonNull;
class Promise;
@ -74,22 +77,26 @@ class Device final : public DOMEventTargetHelper {
explicit Device(Adapter* const aParent, RawId aId);
RefPtr<WebGPUChild> GetBridge();
static JSObject* CreateExternalArrayBuffer(JSContext* aCx, size_t aSize,
ipc::Shmem& aShmem);
RefPtr<MappingPromise> MapBufferForReadAsync(RawId aId, size_t aSize,
ErrorResult& aRv);
void UnmapBuffer(RawId aId, UniquePtr<ipc::Shmem> aShmem);
const RefPtr<WebGPUChild> mBridge;
already_AddRefed<Texture> InitSwapChain(
const dom::GPUSwapChainDescriptor& aDesc,
const dom::GPUExtent3DDict& aExtent3D,
wr::ExternalImageId aExternalImageId, gfx::SurfaceFormat aFormat);
private:
~Device();
void Cleanup();
RefPtr<WebGPUChild> mBridge;
const RawId mId;
bool mValid = true;
nsString mLabel;
const RefPtr<Queue> mQueue;
RefPtr<Queue> mQueue;
public:
void GetLabel(nsAString& aValue) const;

View File

@ -34,7 +34,7 @@ class Instance final : public nsWrapperCache {
already_AddRefed<dom::Promise> RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv);
const RefPtr<WebGPUChild> mBridge;
RefPtr<WebGPUChild> mBridge;
private:
explicit Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge);

View File

@ -13,17 +13,16 @@ class nsIGlobalObject;
namespace mozilla {
namespace webgpu {
class WebGPUChild;
template <typename T>
class ChildOf {
public:
const RefPtr<T> mParent;
explicit ChildOf(T* const parent);
protected:
explicit ChildOf(T* const parent);
virtual ~ChildOf();
RefPtr<T> mParent;
public:
nsIGlobalObject* GetParentObject() const;
};
@ -60,26 +59,22 @@ class ObjectBase : public nsWrapperCache {
// Note: we don't use `NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE` directly
// because there is a custom action we need to always do.
#define GPU_IMPL_CYCLE_COLLECTION(T, ...) \
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(T, AddRef) \
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(T, Release) \
NS_IMPL_CYCLE_COLLECTION_CLASS(T) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(T) \
tmp->Cleanup(); \
NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(T) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
#define GPU_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(T, ...) \
NS_IMPL_CYCLE_COLLECTION_CLASS(T) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(T) \
tmp->Cleanup(); \
NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(T) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(T)
template <typename T>
void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const RefPtr<T>& field, const char* name,
uint32_t flags) {
CycleCollectionNoteChild(callback, field.get(), name, flags);
}
#define GPU_IMPL_CYCLE_COLLECTION(T, ...) \
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(T, AddRef) \
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(T, Release) \
GPU_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(T, __VA_ARGS__)
template <typename T>
void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
@ -91,12 +86,6 @@ void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
}
}
template <typename T>
void ImplCycleCollectionUnlink(const RefPtr<T>& field) {
const auto mutPtr = const_cast<RefPtr<T>*>(&field);
ImplCycleCollectionUnlink(*mutPtr);
}
template <typename T>
void ImplCycleCollectionUnlink(nsTArray<RefPtr<const T>>& field) {
for (auto& element : field) {

View File

@ -22,7 +22,7 @@ PipelineLayout::~PipelineLayout() { Cleanup(); }
void PipelineLayout::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendPipelineLayoutDestroy(mId);
}

View File

@ -21,7 +21,7 @@ RenderPipeline::~RenderPipeline() { Cleanup(); }
void RenderPipeline::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendRenderPipelineDestroy(mId);
}

View File

@ -22,7 +22,7 @@ Sampler::~Sampler() { Cleanup(); }
void Sampler::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendSamplerDestroy(mId);
}

View File

@ -22,7 +22,7 @@ ShaderModule::~ShaderModule() { Cleanup(); }
void ShaderModule::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendShaderModuleDestroy(mId);
}

View File

@ -4,14 +4,46 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SwapChain.h"
#include "Texture.h"
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(SwapChain, mParent)
GPU_IMPL_CYCLE_COLLECTION(SwapChain, mParent, mTexture)
GPU_IMPL_JS_WRAP(SwapChain)
SwapChain::~SwapChain() = default;
SwapChain::SwapChain(const dom::GPUSwapChainDescriptor& aDesc,
const dom::GPUExtent3DDict& aExtent3D,
wr::ExternalImageId aExternalImageId,
gfx::SurfaceFormat aFormat)
: ChildOf(aDesc.mDevice),
mFormat(aFormat),
mTexture(aDesc.mDevice->InitSwapChain(aDesc, aExtent3D, aExternalImageId,
aFormat)) {}
SwapChain::~SwapChain() { Cleanup(); }
void SwapChain::Cleanup() {
if (mValid) {
mValid = false;
}
}
WebGPUChild* SwapChain::GetGpuBridge() const {
return mParent ? mParent->GetBridge().get() : nullptr;
}
void SwapChain::Destroy(wr::ExternalImageId aExternalImageId) {
if (mValid && mParent && mParent->GetBridge()) {
mValid = false;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendSwapChainDestroy(aExternalImageId);
}
}
}
RefPtr<Texture> SwapChain::GetCurrentTexture() { return mTexture; }
} // namespace webgpu
} // namespace mozilla

View File

@ -8,8 +8,13 @@
#include "nsWrapperCache.h"
#include "ObjectModel.h"
#include "mozilla/webrender/WebRenderAPI.h"
namespace mozilla {
namespace dom {
struct GPUExtent3DDict;
struct GPUSwapChainDescriptor;
} // namespace dom
namespace webgpu {
class Device;
@ -20,12 +25,23 @@ class SwapChain final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(SwapChain)
GPU_DECL_JS_WRAP(SwapChain)
SwapChain(const dom::GPUSwapChainDescriptor& aDesc,
const dom::GPUExtent3DDict& aExtent3D,
wr::ExternalImageId aExternalImageId, gfx::SurfaceFormat aFormat);
WebGPUChild* GetGpuBridge() const;
void Destroy(wr::ExternalImageId aExternalImageId);
const gfx::SurfaceFormat mFormat;
private:
SwapChain() = delete;
virtual ~SwapChain();
void Cleanup() {}
void Cleanup();
RefPtr<Texture> mTexture;
public:
RefPtr<Texture> GetCurrentTexture();
};
} // namespace webgpu

View File

@ -25,7 +25,7 @@ Texture::~Texture() { Cleanup(); }
void Texture::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
auto bridge = mParent->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendTextureDestroy(mId);
}
@ -34,8 +34,8 @@ void Texture::Cleanup() {
already_AddRefed<TextureView> Texture::CreateView(
const dom::GPUTextureViewDescriptor& aDesc) {
RawId id =
mParent->mBridge->TextureCreateView(mId, aDesc, *mDefaultViewDescriptor);
RawId id = mParent->GetBridge()->TextureCreateView(mId, aDesc,
*mDefaultViewDescriptor);
RefPtr<TextureView> view = new TextureView(this, id);
return view.forget();
}

View File

@ -30,7 +30,7 @@ class Texture final : public ObjectBase, public ChildOf<Device> {
Texture(Device* const aParent, RawId aId,
const dom::GPUTextureDescriptor& aDesc);
Device* GetParentDevice() { return mParent; }
const RawId mId;
private:

View File

@ -19,9 +19,9 @@ TextureView::TextureView(Texture* const aParent, RawId aId)
TextureView::~TextureView() { Cleanup(); }
void TextureView::Cleanup() {
if (mValid && mParent && mParent->mParent) {
if (mValid && mParent && mParent->GetParentDevice()) {
mValid = false;
WebGPUChild* bridge = mParent->mParent->mBridge;
auto bridge = mParent->GetParentDevice()->GetBridge();
if (bridge && bridge->IsOpen()) {
bridge->SendTextureViewDestroy(mId);
}

View File

@ -5,6 +5,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using layers::RGBDescriptor from "mozilla/layers/LayersSurfaces.h";
using wr::ExternalImageId from "mozilla/webrender/WebRenderAPI.h";
using RawId from "mozilla/webgpu/WebGPUTypes.h";
using BufferAddress from "mozilla/webgpu/WebGPUTypes.h";
using SerialBindGroupLayoutDescriptor from "mozilla/webgpu/WebGPUTypes.h";
@ -72,6 +74,9 @@ parent:
async ComputePipelineDestroy(RawId selfId);
async DeviceCreateRenderPipeline(RawId selfId, SerialRenderPipelineDescriptor desc, RawId newId);
async RenderPipelineDestroy(RawId selfId);
async DeviceCreateSwapChain(RawId selfId, RawId queueId, RGBDescriptor desc, RawId[] bufferIds, ExternalImageId externalId);
async SwapChainPresent(ExternalImageId externalId, RawId textureId, RawId commandEncoderId);
async SwapChainDestroy(ExternalImageId externalId);
async Shutdown();
child:

View File

@ -387,10 +387,9 @@ RawId WebGPUChild::DeviceCreateRenderPipeline(
}
desc.mPrimitiveTopology =
ffi::WGPUPrimitiveTopology(aDesc.mPrimitiveTopology);
if (aDesc.mRasterizationState.WasPassed()) {
desc.mRasterizationState =
Some(ConvertRasterizationDescriptor(aDesc.mRasterizationState.Value()));
}
// TODO: expect it to be optional to begin with
desc.mRasterizationState =
Some(ConvertRasterizationDescriptor(aDesc.mRasterizationState));
for (const auto& color_state : aDesc.mColorStates) {
desc.mColorStates.AppendElement(ConvertColorDescriptor(color_state));
}
@ -474,5 +473,26 @@ ipc::IPCResult WebGPUChild::RecvFreeSampler(RawId id) {
return IPC_OK();
}
void WebGPUChild::DeviceCreateSwapChain(RawId aSelfId,
const RGBDescriptor& aRgbDesc,
size_t maxBufferCount,
wr::ExternalImageId aExternalImageId) {
RawId queueId = aSelfId; // TODO: multiple queues
nsTArray<RawId> bufferIds(maxBufferCount);
for (size_t i = 0; i < maxBufferCount; ++i) {
bufferIds.AppendElement(ffi::wgpu_client_make_buffer_id(mClient, aSelfId));
}
SendDeviceCreateSwapChain(aSelfId, queueId, aRgbDesc, bufferIds,
aExternalImageId);
}
void WebGPUChild::SwapChainPresent(wr::ExternalImageId aExternalImageId,
RawId aTextureId) {
// Hack: the function expects `DeviceId`, but it only uses it for `backend()`
// selection.
RawId encoderId = ffi::wgpu_client_make_encoder_id(mClient, aTextureId);
SendSwapChainPresent(aExternalImageId, aTextureId, encoderId);
}
} // namespace webgpu
} // namespace mozilla

View File

@ -25,7 +25,8 @@ struct WGPUTextureViewDescriptor;
struct TextureInfo;
typedef MozPromise<RawId, Maybe<ipc::ResponseRejectReason>, true> RawIdPromise;
class WebGPUChild final : public PWebGPUChild {
class WebGPUChild final : public PWebGPUChild,
public SupportsWeakPtr<WebGPUChild> {
public:
friend class layers::CompositorBridgeChild;
@ -71,6 +72,11 @@ class WebGPUChild final : public PWebGPUChild {
void QueueSubmit(RawId aSelfId, const nsTArray<RawId>& aCommandBufferIds);
void DeviceCreateSwapChain(RawId aSelfId, const RGBDescriptor& aRgbDesc,
size_t maxBufferCount,
wr::ExternalImageId aExternalImageId);
void SwapChainPresent(wr::ExternalImageId aExternalImageId, RawId aTextureId);
private:
virtual ~WebGPUChild();

View File

@ -5,12 +5,37 @@
#include "WebGPUParent.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/TextureHost.h"
namespace mozilla {
namespace webgpu {
const uint64_t POLL_TIME_MS = 100;
class PresentationData {
NS_INLINE_DECL_REFCOUNTING(PresentationData);
public:
RawId mDeviceId = 0;
RawId mQueueId = 0;
RefPtr<layers::MemoryTextureHost> mTextureHost;
uint32_t mSourcePitch = 0;
uint32_t mTargetPitch = 0;
uint32_t mRowCount = 0;
std::vector<RawId> mUnassignedBufferIds;
std::vector<RawId> mAvailableBufferIds;
std::vector<RawId> mQueuedBufferIds;
Mutex mBuffersLock;
PresentationData() : mBuffersLock("WebGPU presentation buffers") {
MOZ_COUNT_CTOR(PresentationData);
}
private:
~PresentationData() { MOZ_COUNT_DTOR(PresentationData); }
};
static void FreeAdapter(RawId id, void* param) {
if (!static_cast<WebGPUParent*>(param)->SendFreeAdapter(id)) {
MOZ_CRASH("IPC failure");
@ -201,8 +226,8 @@ struct MapReadRequest {
: mShmem(shmem), mResolver(resolver) {}
};
void MapReadCallback(ffi::WGPUBufferMapAsyncStatus status, const uint8_t* ptr,
uint8_t* userdata) {
static void MapReadCallback(ffi::WGPUBufferMapAsyncStatus status,
const uint8_t* ptr, uint8_t* userdata) {
auto req = reinterpret_cast<MapReadRequest*>(userdata);
// TODO: better handle errors
MOZ_ASSERT(status == ffi::WGPUBufferMapAsyncStatus_Success);
@ -494,8 +519,186 @@ ipc::IPCResult WebGPUParent::RecvRenderPipelineDestroy(RawId aSelfId) {
return IPC_OK();
}
// TODO: proper destruction
static const uint64_t kBufferAlignment = 0x100;
static uint64_t Align(uint64_t value) {
return (value | (kBufferAlignment - 1)) + 1;
}
ipc::IPCResult WebGPUParent::RecvDeviceCreateSwapChain(
RawId aSelfId, RawId aQueueId, const RGBDescriptor& aDesc,
const nsTArray<RawId>& aBufferIds, ExternalImageId aExternalId) {
const auto rows = aDesc.size().height;
const auto bufferStride =
Align(static_cast<uint64_t>(aDesc.size().width) * 4);
const auto textureStride = layers::ImageDataSerializer::GetRGBStride(aDesc);
const auto wholeBufferSize = CheckedInt<size_t>(textureStride) * rows;
if (!wholeBufferSize.isValid()) {
NS_ERROR("Invalid total buffer size!");
return IPC_OK();
}
auto textureHostData = new (fallible) uint8_t[wholeBufferSize.value()];
if (!textureHostData) {
NS_ERROR("Unable to allocate host data!");
return IPC_OK();
}
auto textureHost = new layers::MemoryTextureHost(
textureHostData, aDesc, layers::TextureFlags::NO_FLAGS);
textureHost->CreateRenderTexture(aExternalId);
nsTArray<RawId> bufferIds(aBufferIds);
RefPtr<PresentationData> data = new PresentationData();
data->mDeviceId = aSelfId;
data->mQueueId = aQueueId;
data->mTextureHost = textureHost;
data->mSourcePitch = bufferStride;
data->mTargetPitch = textureStride;
data->mRowCount = rows;
for (const RawId id : bufferIds) {
data->mUnassignedBufferIds.push_back(id);
}
MOZ_ASSERT(mCanvasMap.insert({AsUint64(aExternalId), data}).second);
return IPC_OK();
}
static void PresentCallback(ffi::WGPUBufferMapAsyncStatus status,
const uint8_t* ptr, uint8_t* userdata) {
auto data = reinterpret_cast<PresentationData*>(userdata);
if (status == ffi::WGPUBufferMapAsyncStatus_Success) {
uint8_t* dst = data->mTextureHost->GetBuffer();
for (uint32_t row = 0; row < data->mRowCount; ++row) {
memcpy(dst, ptr, data->mTargetPitch);
dst += data->mTargetPitch;
ptr += data->mSourcePitch;
}
} else {
// TODO: better handle errors
NS_WARNING("WebGPU frame mapping failed!");
}
data->mBuffersLock.Lock();
RawId bufferId = data->mQueuedBufferIds.back();
data->mQueuedBufferIds.pop_back();
data->mAvailableBufferIds.push_back(bufferId);
data->mBuffersLock.Unlock();
// We artificially did `AddRef` before calling `wgpu_server_buffer_map_read`.
// Now we can let it go again.
data->Release();
}
ipc::IPCResult WebGPUParent::RecvSwapChainPresent(
wr::ExternalImageId aExternalId, RawId aTextureId,
RawId aCommandEncoderId) {
// step 0: get the data associated with the swapchain
const auto& lookup = mCanvasMap.find(AsUint64(aExternalId));
if (lookup == mCanvasMap.end()) {
NS_WARNING("WebGPU presenting on a destroyed swap chain!");
return IPC_OK();
}
RefPtr<PresentationData> data = lookup->second.get();
RawId bufferId = 0;
const auto& size = data->mTextureHost->GetSize();
const auto bufferSize = data->mRowCount * data->mSourcePitch;
// step 1: find an available staging buffer, or create one
data->mBuffersLock.Lock();
if (!data->mAvailableBufferIds.empty()) {
bufferId = data->mAvailableBufferIds.back();
data->mAvailableBufferIds.pop_back();
} else if (!data->mUnassignedBufferIds.empty()) {
bufferId = data->mUnassignedBufferIds.back();
data->mUnassignedBufferIds.pop_back();
ffi::WGPUBufferUsage usage =
WGPUBufferUsage_COPY_DST | WGPUBufferUsage_MAP_READ;
const ffi::WGPUBufferDescriptor desc = {
bufferSize,
usage,
};
ffi::wgpu_server_device_create_buffer(mContext, data->mDeviceId, &desc,
bufferId);
} else {
bufferId = 0;
}
if (bufferId) {
data->mQueuedBufferIds.insert(data->mQueuedBufferIds.begin(), bufferId);
}
data->mBuffersLock.Unlock();
if (!bufferId) {
// TODO: add a warning - no buffer are available!
return IPC_OK();
}
// step 3: submit a copy command for the frame
ffi::WGPUCommandEncoderDescriptor encoderDesc = {};
ffi::wgpu_server_device_create_encoder(mContext, data->mDeviceId,
&encoderDesc, aCommandEncoderId);
const ffi::WGPUTextureCopyView texView = {
aTextureId,
};
const ffi::WGPUBufferCopyView bufView = {
bufferId,
0,
data->mSourcePitch,
0,
};
const ffi::WGPUExtent3d extent = {
static_cast<uint32_t>(size.width),
static_cast<uint32_t>(size.height),
1,
};
ffi::wgpu_server_encoder_copy_texture_to_buffer(mContext, aCommandEncoderId,
&texView, &bufView, extent);
ffi::WGPUCommandBufferDescriptor commandDesc = {};
ffi::wgpu_server_encoder_finish(mContext, aCommandEncoderId, &commandDesc);
ffi::wgpu_server_queue_submit(mContext, data->mQueueId, &aCommandEncoderId,
1);
// step 4: request the pixels to be copied into the external texture
// TODO: this isn't strictly necessary. When WR wants to Lock() the external
// texture,
// we can just give it the contents of the last mapped buffer instead of the
// copy.
// This `AddRef` is needed for passing `data` as a raw pointer to
// `wgpu_server_buffer_map_read` to serve as `userdata`. It's released at
// the end of `PresentCallback` body.
const auto userData = do_AddRef(data).take();
ffi::wgpu_server_buffer_map_read(mContext, bufferId, 0, bufferSize,
&PresentCallback,
reinterpret_cast<uint8_t*>(userData));
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvSwapChainDestroy(
wr::ExternalImageId aExternalId) {
const auto& lookup = mCanvasMap.find(AsUint64(aExternalId));
MOZ_ASSERT(lookup != mCanvasMap.end());
RefPtr<PresentationData> data = lookup->second.get();
mCanvasMap.erase(AsUint64(aExternalId));
data->mTextureHost = nullptr;
layers::BufferTextureHost::DestroyRenderTexture(aExternalId);
data->mBuffersLock.Lock();
for (const auto bid : data->mUnassignedBufferIds) {
ffi::wgpu_server_buffer_destroy(mContext, bid);
}
for (const auto bid : data->mAvailableBufferIds) {
ffi::wgpu_server_buffer_destroy(mContext, bid);
}
for (const auto bid : data->mQueuedBufferIds) {
ffi::wgpu_server_buffer_destroy(mContext, bid);
}
data->mBuffersLock.Unlock();
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvShutdown() {
mTimer.Stop();
for (const auto& p : mCanvasMap) {
const wr::ExternalImageId extId = {p.first};
layers::BufferTextureHost::DestroyRenderTexture(extId);
}
mCanvasMap.clear();
ffi::wgpu_server_poll_all_devices(mContext, true);
ffi::wgpu_server_delete(const_cast<ffi::WGPUGlobal*>(mContext));
return IPC_OK();

View File

@ -7,14 +7,13 @@
#define WEBGPU_PARENT_H_
#include "mozilla/webgpu/PWebGPUParent.h"
#include "mozilla/webrender/WebRenderAPI.h"
#include "WebGPUTypes.h"
#include "base/timer.h"
namespace mozilla {
namespace webgpu {
namespace ffi {
struct WGPUGlobal_IdentityRecyclerFactory;
} // namespace ffi
class PresentationData;
class WebGPUParent final : public PWebGPUParent {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebGPUParent)
@ -85,6 +84,14 @@ class WebGPUParent final : public PWebGPUParent {
ipc::IPCResult RecvDeviceCreateRenderPipeline(
RawId aSelfId, const SerialRenderPipelineDescriptor& aDesc, RawId aNewId);
ipc::IPCResult RecvRenderPipelineDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceCreateSwapChain(RawId aSelfId, RawId aQueueId,
const layers::RGBDescriptor& aDesc,
const nsTArray<RawId>& aBufferIds,
ExternalImageId aExternalId);
ipc::IPCResult RecvSwapChainPresent(wr::ExternalImageId aExternalId,
RawId aTextureId,
RawId aCommandEncoderId);
ipc::IPCResult RecvSwapChainDestroy(wr::ExternalImageId aExternalId);
ipc::IPCResult RecvShutdown();
private:
@ -93,6 +100,7 @@ class WebGPUParent final : public PWebGPUParent {
const ffi::WGPUGlobal_IdentityRecyclerFactory* const mContext;
base::RepeatingTimer<WebGPUParent> mTimer;
std::unordered_map<uint64_t, RefPtr<PresentationData>> mCanvasMap;
};
} // namespace webgpu

View File

@ -617,7 +617,7 @@ dictionary GPUVertexBufferLayoutDescriptor {
dictionary GPUVertexStateDescriptor {
GPUIndexFormat indexFormat = "uint32";
required sequence<GPUVertexBufferLayoutDescriptor?> vertexBuffers;
sequence<GPUVertexBufferLayoutDescriptor?> vertexBuffers = [];
};
// ShaderModule
@ -688,7 +688,7 @@ dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
GPUProgrammableStageDescriptor fragmentStage;
required GPUPrimitiveTopology primitiveTopology;
GPURasterizationStateDescriptor rasterizationState;
GPURasterizationStateDescriptor rasterizationState = {};
required sequence<GPUColorStateDescriptor> colorStates;
GPUDepthStencilStateDescriptor depthStencilState;
GPUVertexStateDescriptor vertexState = {};
@ -722,7 +722,7 @@ dictionary GPURenderPassColorAttachmentDescriptor {
GPUTextureView resolveTarget;
required (GPULoadOp or GPUColor) loadValue;
required GPUStoreOp storeOp;
GPUStoreOp storeOp = "store";
};
dictionary GPURenderPassDepthStencilAttachmentDescriptor {
@ -744,7 +744,7 @@ dictionary GPUBufferCopyView {
required GPUBuffer buffer;
u64 offset = 0;
required u32 bytesPerRow;
required u32 rowsPerImage;
u32 rowsPerImage = 0;
};
dictionary GPUTextureCopyView {
@ -935,14 +935,14 @@ GPUQueue includes GPUObjectBase;
[Pref="dom.webgpu.enabled",
Exposed=Window]
interface GPUSwapChain {
//GPUTexture getCurrentTexture();
GPUTexture getCurrentTexture();
};
GPUSwapChain includes GPUObjectBase;
dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
required GPUDevice device;
required GPUTextureFormat format;
GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.OUTPUT_ATTACHMENT
GPUTextureUsageFlags usage = 0x10; //GPUTextureUsage.OUTPUT_ATTACHMENT
};
[Pref="dom.webgpu.enabled",
@ -950,7 +950,8 @@ dictionary GPUSwapChainDescriptor : GPUObjectDescriptorBase {
interface GPUCanvasContext {
// Calling configureSwapChain a second time invalidates the previous one,
// and all of the textures it's produced.
//GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
[Throws]
GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
//Promise<GPUTextureFormat> getSwapChainPreferredFormat(GPUDevice device);
};

View File

@ -605,6 +605,12 @@ void BufferTextureHost::CreateRenderTexture(
texture.forget());
}
void BufferTextureHost::DestroyRenderTexture(
const wr::ExternalImageId& aExternalImageId) {
wr::RenderThread::Get()->UnregisterExternalImage(
wr::AsUint64(aExternalImageId));
}
uint32_t BufferTextureHost::NumSubTextures() {
if (GetFormat() == gfx::SurfaceFormat::YUV) {
return 3;

View File

@ -789,6 +789,8 @@ class BufferTextureHost : public TextureHost {
void CreateRenderTexture(
const wr::ExternalImageId& aExternalImageId) override;
static void DestroyRenderTexture(const wr::ExternalImageId& aExternalImageId);
uint32_t NumSubTextures() override;
void PushResourceUpdates(wr::TransactionBuilder& aResources,

View File

@ -121,14 +121,14 @@ wr::ImageKey SharedSurfacesChild::SharedUserData::UpdateKey(
if (!ownsKey) {
entry.mImageKey = wrBridge->GetNextImageKey();
entry.TakeDirtyRect();
aResources.AddExternalImage(mId, entry.mImageKey);
aResources.AddSharedExternalImage(mId, entry.mImageKey);
} else {
entry.MergeDirtyRect(aDirtyRect);
Maybe<IntRect> dirtyRect = entry.TakeDirtyRect();
if (dirtyRect) {
MOZ_ASSERT(mShared);
aResources.UpdateExternalImage(mId, entry.mImageKey,
ViewAs<ImagePixel>(dirtyRect.ref()));
aResources.UpdateSharedExternalImage(
mId, entry.mImageKey, ViewAs<ImagePixel>(dirtyRect.ref()));
}
}
@ -145,7 +145,7 @@ wr::ImageKey SharedSurfacesChild::SharedUserData::UpdateKey(
key = aManager->WrBridge()->GetNextImageKey();
ImageKeyData data(aManager, key);
mKeys.AppendElement(std::move(data));
aResources.AddExternalImage(mId, key);
aResources.AddSharedExternalImage(mId, key);
}
return key;
@ -557,8 +557,8 @@ nsresult SharedSurfacesAnimation::SetCurrentFrame(
if (dirtyRect) {
HoldSurfaceForRecycling(entry, aParentSurface, aSurface);
auto& resourceUpdates = entry.mManager->AsyncResourceUpdates();
resourceUpdates.UpdateExternalImage(mId, entry.mImageKey,
ViewAs<ImagePixel>(dirtyRect.ref()));
resourceUpdates.UpdateSharedExternalImage(
mId, entry.mImageKey, ViewAs<ImagePixel>(dirtyRect.ref()));
}
}
@ -604,7 +604,7 @@ nsresult SharedSurfacesAnimation::UpdateKey(
if (!ownsKey) {
entry.mImageKey = wrBridge->GetNextImageKey();
HoldSurfaceForRecycling(entry, aParentSurface, aSurface);
aResources.AddExternalImage(mId, entry.mImageKey);
aResources.AddSharedExternalImage(mId, entry.mImageKey);
} else {
MOZ_ASSERT(entry.mDirtyRect.isNothing());
}
@ -624,7 +624,7 @@ nsresult SharedSurfacesAnimation::UpdateKey(
AnimationImageKeyData data(aManager, aKey);
HoldSurfaceForRecycling(data, aParentSurface, aSurface);
mKeys.AppendElement(std::move(data));
aResources.AddExternalImage(mId, aKey);
aResources.AddSharedExternalImage(mId, aKey);
}
return NS_OK;

View File

@ -38,7 +38,13 @@ struct RefCountedShmem {
Shmem buffer;
};
struct OpAddExternalImage {
struct OpAddPrivateExternalImage {
ExternalImageId externalImageId;
ImageKey key;
ImageDescriptor descriptor;
};
struct OpAddSharedExternalImage {
ExternalImageId externalImageId;
ImageKey key;
};
@ -131,7 +137,7 @@ struct OpSetBlobImageVisibleArea {
BlobImageKey key;
};
struct OpUpdateExternalImage {
struct OpUpdateSharedExternalImage {
ExternalImageId externalImageId;
ImageKey key;
ImageIntRect dirtyRect;
@ -187,9 +193,10 @@ union OpUpdateResource {
OpDeleteFont;
OpAddFontInstance;
OpDeleteFontInstance;
OpAddExternalImage;
OpAddPrivateExternalImage;
OpAddSharedExternalImage;
OpPushExternalImageForTexture;
OpUpdateExternalImage;
OpUpdateSharedExternalImage;
};
} // namespace

View File

@ -302,9 +302,15 @@ bool IpcResourceUpdateQueue::AddBlobImage(BlobImageKey key,
return true;
}
void IpcResourceUpdateQueue::AddExternalImage(wr::ExternalImageId aExtId,
wr::ImageKey aKey) {
mUpdates.AppendElement(layers::OpAddExternalImage(aExtId, aKey));
void IpcResourceUpdateQueue::AddPrivateExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey, wr::ImageDescriptor aDesc) {
mUpdates.AppendElement(
layers::OpAddPrivateExternalImage(aExtId, aKey, aDesc));
}
void IpcResourceUpdateQueue::AddSharedExternalImage(wr::ExternalImageId aExtId,
wr::ImageKey aKey) {
mUpdates.AppendElement(layers::OpAddSharedExternalImage(aExtId, aKey));
}
void IpcResourceUpdateQueue::PushExternalImageForTexture(
@ -344,11 +350,10 @@ bool IpcResourceUpdateQueue::UpdateBlobImage(BlobImageKey aKey,
return true;
}
void IpcResourceUpdateQueue::UpdateExternalImage(wr::ExternalImageId aExtId,
wr::ImageKey aKey,
ImageIntRect aDirtyRect) {
void IpcResourceUpdateQueue::UpdateSharedExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey, ImageIntRect aDirtyRect) {
mUpdates.AppendElement(
layers::OpUpdateExternalImage(aExtId, aKey, aDirtyRect));
layers::OpUpdateSharedExternalImage(aExtId, aKey, aDirtyRect));
}
void IpcResourceUpdateQueue::SetBlobImageVisibleArea(

View File

@ -125,7 +125,10 @@ class IpcResourceUpdateQueue {
bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes, ImageIntRect aVisibleRect);
void AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
void AddPrivateExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ImageDescriptor aDesc);
void AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
void PushExternalImageForTexture(wr::ExternalImageId aExtId,
wr::ImageKey aKey,
@ -140,8 +143,8 @@ class IpcResourceUpdateQueue {
Range<uint8_t> aBytes, ImageIntRect aVisibleRect,
ImageIntRect aDirtyRect);
void UpdateExternalImage(ExternalImageId aExtID, ImageKey aKey,
ImageIntRect aDirtyRect);
void UpdateSharedExternalImage(ExternalImageId aExtID, ImageKey aKey,
ImageIntRect aDirtyRect);
void SetBlobImageVisibleArea(BlobImageKey aKey, const ImageIntRect& aArea);

View File

@ -668,9 +668,17 @@ bool WebRenderBridgeParent::UpdateResources(
wr::ToDeviceIntRect(op.area()));
break;
}
case OpUpdateResource::TOpAddExternalImage: {
const auto& op = cmd.get_OpAddExternalImage();
if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
case OpUpdateResource::TOpAddPrivateExternalImage: {
const auto& op = cmd.get_OpAddPrivateExternalImage();
if (!AddPrivateExternalImage(op.externalImageId(), op.key(),
op.descriptor(), aUpdates)) {
return false;
}
break;
}
case OpUpdateResource::TOpAddSharedExternalImage: {
const auto& op = cmd.get_OpAddSharedExternalImage();
if (!AddSharedExternalImage(op.externalImageId(), op.key(), aUpdates)) {
return false;
}
break;
@ -685,10 +693,11 @@ bool WebRenderBridgeParent::UpdateResources(
}
break;
}
case OpUpdateResource::TOpUpdateExternalImage: {
const auto& op = cmd.get_OpUpdateExternalImage();
if (!UpdateExternalImage(op.externalImageId(), op.key(), op.dirtyRect(),
aUpdates, scheduleRelease)) {
case OpUpdateResource::TOpUpdateSharedExternalImage: {
const auto& op = cmd.get_OpUpdateSharedExternalImage();
if (!UpdateSharedExternalImage(op.externalImageId(), op.key(),
op.dirtyRect(), aUpdates,
scheduleRelease)) {
return false;
}
break;
@ -755,7 +764,22 @@ bool WebRenderBridgeParent::UpdateResources(
return true;
}
bool WebRenderBridgeParent::AddExternalImage(
bool WebRenderBridgeParent::AddPrivateExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey, wr::ImageDescriptor aDesc,
wr::TransactionBuilder& aResources) {
Range<wr::ImageKey> keys(&aKey, 1);
// Check if key is obsoleted.
if (keys[0].mNamespace != mIdNamespace) {
return true;
}
aResources.AddExternalImage(aKey, aDesc, aExtId,
wr::ExternalImageType::Buffer(), 0);
return true;
}
bool WebRenderBridgeParent::AddSharedExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::TransactionBuilder& aResources) {
Range<wr::ImageKey> keys(&aKey, 1);
@ -870,7 +894,7 @@ bool WebRenderBridgeParent::PushExternalImageForTexture(
return true;
}
bool WebRenderBridgeParent::UpdateExternalImage(
bool WebRenderBridgeParent::UpdateSharedExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey,
const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources,
UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease) {

View File

@ -431,9 +431,12 @@ class WebRenderBridgeParent final
const nsTArray<RefCountedShmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems,
wr::TransactionBuilder& aUpdates);
bool AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::TransactionBuilder& aResources);
bool UpdateExternalImage(
bool AddPrivateExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::ImageDescriptor aDesc,
wr::TransactionBuilder& aResources);
bool AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
wr::TransactionBuilder& aResources);
bool UpdateSharedExternalImage(
wr::ExternalImageId aExtId, wr::ImageKey aKey,
const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources,
UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease);

View File

@ -30,10 +30,7 @@ void WebRenderCanvasRendererAsync::Initialize(
const CanvasInitializeData& aData) {
WebRenderCanvasRenderer::Initialize(aData);
if (mPipelineId.isSome()) {
mManager->RemovePipelineIdForCompositable(mPipelineId.ref());
mPipelineId.reset();
}
ClearCachedResources();
}
bool WebRenderCanvasRendererAsync::CreateCompositable() {

View File

@ -1540,6 +1540,7 @@ WebRenderCommandBuilder::WebRenderCommandBuilder(
void WebRenderCommandBuilder::Destroy() {
mLastCanvasDatas.Clear();
mLastLocalCanvasDatas.Clear();
ClearCachedResources();
}
@ -1552,10 +1553,14 @@ void WebRenderCommandBuilder::EmptyTransaction() {
canvas->UpdateCompositableClientForEmptyTransaction();
}
}
for (auto iter = mLastLocalCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
RefPtr<WebRenderLocalCanvasData> canvasData = iter.Get()->GetKey();
canvasData->Present();
}
}
bool WebRenderCommandBuilder::NeedsEmptyTransaction() {
return !mLastCanvasDatas.IsEmpty();
return !mLastCanvasDatas.IsEmpty() || !mLastLocalCanvasDatas.IsEmpty();
}
void WebRenderCommandBuilder::BuildWebRenderCommands(
@ -1578,6 +1583,7 @@ void WebRenderCommandBuilder::BuildWebRenderCommands(
}
MOZ_ASSERT(mLayerScrollDatas.IsEmpty());
mLastCanvasDatas.Clear();
mLastLocalCanvasDatas.Clear();
mLastAsr = nullptr;
mContainsSVGGroup = false;
MOZ_ASSERT(mDumpIndent == 0);
@ -2635,8 +2641,15 @@ void WebRenderCommandBuilder::RemoveUnusedAndResetWebRenderUserData() {
userDataTable = nullptr;
}
if (data->GetType() == WebRenderUserData::UserDataType::eCanvas) {
mLastCanvasDatas.RemoveEntry(data->AsCanvasData());
switch (data->GetType()) {
case WebRenderUserData::UserDataType::eCanvas:
mLastCanvasDatas.RemoveEntry(data->AsCanvasData());
break;
case WebRenderUserData::UserDataType::eLocalCanvas:
mLastLocalCanvasDatas.RemoveEntry(data->AsLocalCanvasData());
break;
default:
break;
}
iter.Remove();

View File

@ -77,6 +77,8 @@ class WebRenderCommandBuilder final {
typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>>
WebRenderUserDataRefTable;
typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
typedef nsTHashtable<nsRefPtrHashKey<WebRenderLocalCanvasData>>
LocalCanvasDataSet;
public:
explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager);
@ -199,9 +201,17 @@ class WebRenderCommandBuilder final {
// of EndTransaction.
data->SetUsed(true);
if (T::Type() == WebRenderUserData::UserDataType::eCanvas) {
mLastCanvasDatas.PutEntry(data->AsCanvasData());
switch (T::Type()) {
case WebRenderUserData::UserDataType::eCanvas:
mLastCanvasDatas.PutEntry(data->AsCanvasData());
break;
case WebRenderUserData::UserDataType::eLocalCanvas:
mLastLocalCanvasDatas.PutEntry(data->AsLocalCanvasData());
break;
default:
break;
}
RefPtr<T> res = static_cast<T*>(data.get());
return res.forget();
}
@ -234,6 +244,8 @@ class WebRenderCommandBuilder final {
// Store of WebRenderCanvasData objects for use in empty transactions
CanvasDataSet mLastCanvasDatas;
// Store of WebRenderLocalCanvasData objects for use in empty transactions
LocalCanvasDataSet mLastLocalCanvasDatas;
wr::RenderRootArray<wr::usize> mBuilderDumpIndex;
wr::usize mDumpIndent;

View File

@ -38,8 +38,7 @@ WebRenderTextureHost::WebRenderTextureHost(
WebRenderTextureHost::~WebRenderTextureHost() {
MOZ_COUNT_DTOR(WebRenderTextureHost);
wr::RenderThread::Get()->UnregisterExternalImage(
wr::AsUint64(mExternalImageId));
BufferTextureHost::DestroyRenderTexture(mExternalImageId);
}
void WebRenderTextureHost::CreateRenderTextureHost(

View File

@ -14,6 +14,7 @@
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/webgpu/WebGPUChild.h"
#include "nsDisplayListInvalidation.h"
#include "nsIFrame.h"
#include "WebRenderCanvasRenderer.h"
@ -391,6 +392,18 @@ ImageContainer* WebRenderCanvasData::GetImageContainer() {
void WebRenderCanvasData::ClearImageContainer() { mContainer = nullptr; }
WebRenderLocalCanvasData::WebRenderLocalCanvasData(
RenderRootStateManager* aManager, nsDisplayItem* aItem)
: WebRenderUserData(aManager, aItem) {}
WebRenderLocalCanvasData::~WebRenderLocalCanvasData() = default;
void WebRenderLocalCanvasData::Present() {
if (mGpuBridge) {
mGpuBridge->SwapChainPresent(mExternalImageId, mGpuTextureId);
}
}
WebRenderRemoteData::WebRenderRemoteData(RenderRootStateManager* aManager,
nsDisplayItem* aItem)
: WebRenderUserData(aManager, aItem) {}

View File

@ -20,6 +20,10 @@
class nsDisplayItemGeometry;
namespace mozilla {
namespace webgpu {
class WebGPUChild;
}
namespace wr {
class IpcResourceUpdateQueue;
}
@ -34,9 +38,10 @@ class ImageClient;
class ImageContainer;
class WebRenderBridgeChild;
class WebRenderCanvasData;
class WebRenderCanvasRendererAsync;
class WebRenderCanvasRenderer;
class WebRenderImageData;
class WebRenderFallbackData;
class WebRenderLocalCanvasData;
class RenderRootStateManager;
class WebRenderGroupData;
@ -72,6 +77,7 @@ class WebRenderUserData {
virtual WebRenderImageData* AsImageData() { return nullptr; }
virtual WebRenderFallbackData* AsFallbackData() { return nullptr; }
virtual WebRenderCanvasData* AsCanvasData() { return nullptr; }
virtual WebRenderLocalCanvasData* AsLocalCanvasData() { return nullptr; }
virtual WebRenderGroupData* AsGroupData() { return nullptr; }
enum class UserDataType {
@ -80,6 +86,7 @@ class WebRenderUserData {
eAPZAnimation,
eAnimation,
eCanvas,
eLocalCanvas,
eRemote,
eGroup,
eMask,
@ -269,6 +276,26 @@ class WebRenderCanvasData : public WebRenderUserData {
RefPtr<ImageContainer> mContainer;
};
// WebRender data assocatiated with canvases that don't need to
// synchronize across content-GPU process barrier.
class WebRenderLocalCanvasData : public WebRenderUserData {
public:
WebRenderLocalCanvasData(RenderRootStateManager* aManager,
nsDisplayItem* aItem);
virtual ~WebRenderLocalCanvasData();
WebRenderLocalCanvasData* AsLocalCanvasData() override { return this; }
UserDataType GetType() override { return UserDataType::eLocalCanvas; }
static UserDataType Type() { return UserDataType::eLocalCanvas; }
void Present();
WeakPtr<webgpu::WebGPUChild> mGpuBridge;
uint64_t mGpuTextureId = 0;
wr::ExternalImageId mExternalImageId = {0};
gfx::SurfaceFormat mFormat = gfx::SurfaceFormat::UNKNOWN;
};
class WebRenderRemoteData : public WebRenderUserData {
public:
WebRenderRemoteData(RenderRootStateManager* aManager, nsDisplayItem* aItem);

View File

@ -66,6 +66,7 @@ pub struct BindGroupLayoutDescriptor {
#[derive(Debug)]
pub struct BindGroupLayout<B: hal::Backend> {
pub(crate) raw: B::DescriptorSetLayout,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) entries: FastHashMap<u32, BindGroupLayoutEntry>,
pub(crate) desc_ranges: DescriptorRanges,
pub(crate) dynamic_count: usize,
@ -81,6 +82,7 @@ pub struct PipelineLayoutDescriptor {
#[derive(Debug)]
pub struct PipelineLayout<B: hal::Backend> {
pub(crate) raw: B::PipelineLayout,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) bind_group_layout_ids: ArrayVec<[BindGroupLayoutId; wgt::MAX_BIND_GROUPS]>,
}

View File

@ -470,6 +470,7 @@ impl<B: GfxBackend> LifetimeTracker<B> {
})
.collect::<FastHashMap<_, _>>();
log::debug!("Free framebuffers {:?}", remove_list);
for (ref key, submit_index) in remove_list {
let framebuffer = framebuffers.remove(key).unwrap();
self.active

View File

@ -479,15 +479,16 @@ impl<B: hal::Backend> Device<B> {
unsafe {
desc_alloc.dispose(&self.raw);
mem_alloc.dispose(&self.raw);
for (_, rp) in self.render_passes.lock().drain() {
self.raw.destroy_render_pass(rp);
}
for (_, fbo) in self.framebuffers.lock().drain() {
self.raw.destroy_framebuffer(fbo);
}
}
}
}
#[derive(Debug)]
pub struct ShaderModule<B: hal::Backend> {
pub(crate) raw: B::ShaderModule,
}
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_buffer<B: GfxBackend>(
@ -900,9 +901,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
})
.collect::<Vec<_>>(); //TODO: avoid heap allocation
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let raw = unsafe {
let (device_guard, _) = hub.devices.read(&mut token);
device_guard[device_id]
device
.raw
.create_descriptor_set_layout(&raw_bindings, &[])
.unwrap()
@ -910,6 +912,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let layout = binding_model::BindGroupLayout {
raw,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.add_ref(),
},
entries: entry_map,
desc_ranges: DescriptorRanges::from_bindings(&raw_bindings),
dynamic_count: entries.iter().filter(|b| b.has_dynamic_offset).count(),
@ -922,8 +928,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn bind_group_layout_destroy<B: GfxBackend>(&self, bind_group_layout_id: id::BindGroupLayoutId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.bind_group_layouts.unregister(bind_group_layout_id, &mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let (bgl, _) = hub.bind_group_layouts.unregister(bind_group_layout_id, &mut token);
unsafe {
device_guard[bgl.device_id.value].raw.destroy_descriptor_set_layout(bgl.raw);
}
}
pub fn device_create_pipeline_layout<B: GfxBackend>(
@ -960,6 +969,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let layout = binding_model::PipelineLayout {
raw: pipeline_layout,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.add_ref(),
},
bind_group_layout_ids: bind_group_layout_ids.iter().cloned().collect(),
};
hub.pipeline_layouts
@ -969,8 +982,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn pipeline_layout_destroy<B: GfxBackend>(&self, pipeline_layout_id: id::PipelineLayoutId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.pipeline_layouts.unregister(pipeline_layout_id, &mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let (pipeline_layout, _) = hub.pipeline_layouts.unregister(pipeline_layout_id, &mut token);
unsafe {
device_guard[pipeline_layout.device_id.value].raw.destroy_pipeline_layout(pipeline_layout.raw);
}
}
pub fn device_create_bind_group<B: GfxBackend>(
@ -1192,19 +1208,24 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
) -> id::ShaderModuleId {
let hub = B::hub(self);
let mut token = Token::root();
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let spv = unsafe { slice::from_raw_parts(desc.code.bytes, desc.code.length) };
let shader = {
let (device_guard, _) = hub.devices.read(&mut token);
ShaderModule {
raw: unsafe {
device_guard[device_id]
.raw
.create_shader_module(spv)
.unwrap()
},
}
let raw = unsafe {
device
.raw
.create_shader_module(spv)
.unwrap()
};
let shader = pipeline::ShaderModule {
raw,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.add_ref(),
},
};
hub.shader_modules
.register_identity(id_in, shader, &mut token)
}
@ -1212,8 +1233,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn shader_module_destroy<B: GfxBackend>(&self, shader_module_id: id::ShaderModuleId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.shader_modules.unregister(shader_module_id, &mut token);
let (device_guard, mut token) = hub.devices.read(&mut token);
let (module, _) = hub.shader_modules.unregister(shader_module_id, &mut token);
unsafe {
device_guard[module.device_id.value].raw.destroy_shader_module(module.raw);
}
}
pub fn device_create_command_encoder<B: GfxBackend>(
@ -1564,9 +1588,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth_bounds: None,
};
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let raw_pipeline = {
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let layout = &pipeline_layout_guard[desc.layout].raw;
let (shader_module_guard, _) = hub.shader_modules.read(&mut token);
@ -1712,6 +1736,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let pipeline = pipeline::RenderPipeline {
raw: raw_pipeline,
layout_id: desc.layout,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.add_ref(),
},
pass_context,
flags,
index_format: desc.vertex_state.index_format,
@ -1726,6 +1754,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn render_pipeline_destroy<B: GfxBackend>(&self, render_pipeline_id: id::RenderPipelineId) {
let hub = B::hub(self);
let mut token = Token::root();
let (_, mut token) = hub.devices.read(&mut token);
//TODO: track usage by GPU
hub.render_pipelines.unregister(render_pipeline_id, &mut token);
}
@ -1739,9 +1768,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = B::hub(self);
let mut token = Token::root();
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let raw_pipeline = {
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id].raw;
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
let layout = &pipeline_layout_guard[desc.layout].raw;
let pipeline_stage = &desc.compute_stage;
@ -1770,6 +1799,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
unsafe {
device
.raw
.create_compute_pipeline(&pipeline_desc, None)
.unwrap()
}
@ -1778,6 +1808,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let pipeline = pipeline::ComputePipeline {
raw: raw_pipeline,
layout_id: desc.layout,
device_id: Stored {
value: device_id,
ref_count: device.life_guard.add_ref(),
},
};
hub.compute_pipelines
.register_identity(id_in, pipeline, &mut token)
@ -1786,6 +1820,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn compute_pipeline_destroy<B: GfxBackend>(&self, compute_pipeline_id: id::ComputePipelineId) {
let hub = B::hub(self);
let mut token = Token::root();
let (_, mut token) = hub.devices.read(&mut token);
//TODO: track usage by GPU
hub.compute_pipelines.unregister(compute_pipeline_id, &mut token);
}
@ -1934,7 +1969,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (device, mut token) = hub.devices.unregister(device_id, &mut token);
device.maintain(self, true, &mut token);
drop(token);
device.com_allocator.destroy(&device.raw);
device.dispose();
}
pub fn buffer_map_async<B: GfxBackend>(

View File

@ -6,7 +6,7 @@ use crate::{
backend,
binding_model::{BindGroup, BindGroupLayout, PipelineLayout},
command::CommandBuffer,
device::{Device, ShaderModule},
device::Device,
id::{
AdapterId,
BindGroupId,
@ -26,7 +26,7 @@ use crate::{
TypedId,
},
instance::{Adapter, Instance, Surface},
pipeline::{ComputePipeline, RenderPipeline},
pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
resource::{Buffer, Sampler, Texture, TextureView},
swap_chain::SwapChain,
Epoch,
@ -180,11 +180,11 @@ impl<B: hal::Backend> Access<BindGroup<B>> for CommandBuffer<B> {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for Root {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for Device<B> {}
impl<B: hal::Backend> Access<CommandBuffer<B>> for SwapChain<B> {}
impl<B: hal::Backend> Access<ComputePipeline<B>> for Root {}
impl<B: hal::Backend> Access<ComputePipeline<B>> for Device<B> {}
impl<B: hal::Backend> Access<ComputePipeline<B>> for BindGroup<B> {}
impl<B: hal::Backend> Access<RenderPipeline<B>> for Root {}
impl<B: hal::Backend> Access<RenderPipeline<B>> for Device<B> {}
impl<B: hal::Backend> Access<RenderPipeline<B>> for BindGroup<B> {}
impl<B: hal::Backend> Access<ShaderModule<B>> for Root {}
impl<B: hal::Backend> Access<ShaderModule<B>> for Device<B> {}
impl<B: hal::Backend> Access<ShaderModule<B>> for PipelineLayout<B> {}
impl<B: hal::Backend> Access<Buffer<B>> for Root {}
impl<B: hal::Backend> Access<Buffer<B>> for Device<B> {}
@ -443,6 +443,7 @@ impl<B: hal::Backend, F: GlobalIdentityHandlerFactory> Drop for Hub<B, F> {
}
}
}
for (_, (texture, _)) in self.textures.data.write().map.drain() {
devices[texture.device_id.value].destroy_texture(texture);
}
@ -460,14 +461,38 @@ impl<B: hal::Backend, F: GlobalIdentityHandlerFactory> Drop for Hub<B, F> {
device.destroy_bind_group(bind_group);
}
//TODO:
// self.compute_pipelines
// self.render_pipelines
// self.bind_group_layouts
// self.pipeline_layouts
// self.shader_modules
// self.swap_chains
// self.adapters
for (_, (module, _)) in self.shader_modules.data.write().map.drain() {
let device = &devices[module.device_id.value];
unsafe {
device.raw.destroy_shader_module(module.raw);
}
}
for (_, (bgl, _)) in self.bind_group_layouts.data.write().map.drain() {
let device = &devices[bgl.device_id.value];
unsafe {
device.raw.destroy_descriptor_set_layout(bgl.raw);
}
}
for (_, (pipeline_layout, _)) in self.pipeline_layouts.data.write().map.drain() {
let device = &devices[pipeline_layout.device_id.value];
unsafe {
device.raw.destroy_pipeline_layout(pipeline_layout.raw);
}
}
for (_, (pipeline, _)) in self.compute_pipelines.data.write().map.drain() {
let device = &devices[pipeline.device_id.value];
unsafe {
device.raw.destroy_compute_pipeline(pipeline.raw);
}
}
for (_, (pipeline, _)) in self.render_pipelines.data.write().map.drain() {
let device = &devices[pipeline.device_id.value];
unsafe {
device.raw.destroy_graphics_pipeline(pipeline.raw);
}
}
//TODO: self.swap_chains
for (_, (device, _)) in devices.map.drain() {
device.dispose();

View File

@ -100,7 +100,6 @@ pub type SurfaceId = Id<crate::instance::Surface>;
// Device
pub type DeviceId = Id<crate::device::Device<Dummy>>;
pub type QueueId = DeviceId;
pub type ShaderModuleId = Id<crate::device::ShaderModule<Dummy>>;
// Resource
pub type BufferId = Id<crate::resource::Buffer<Dummy>>;
pub type TextureViewId = Id<crate::resource::TextureView<Dummy>>;
@ -111,6 +110,7 @@ pub type BindGroupLayoutId = Id<crate::binding_model::BindGroupLayout<Dummy>>;
pub type PipelineLayoutId = Id<crate::binding_model::PipelineLayout<Dummy>>;
pub type BindGroupId = Id<crate::binding_model::BindGroup<Dummy>>;
// Pipeline
pub type ShaderModuleId = Id<crate::pipeline::ShaderModule<Dummy>>;
pub type RenderPipelineId = Id<crate::pipeline::RenderPipeline<Dummy>>;
pub type ComputePipelineId = Id<crate::pipeline::ComputePipeline<Dummy>>;
// Command

View File

@ -4,8 +4,9 @@
use crate::{
device::RenderPassContext,
id::{PipelineLayoutId, ShaderModuleId},
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
RawString,
Stored,
U32Array
};
use wgt::{BufferAddress, ColorStateDescriptor, DepthStencilStateDescriptor, IndexFormat, InputStepMode, PrimitiveTopology, RasterizationStateDescriptor, VertexAttributeDescriptor};
@ -33,6 +34,12 @@ pub struct ShaderModuleDescriptor {
pub code: U32Array,
}
#[derive(Debug)]
pub struct ShaderModule<B: hal::Backend> {
pub(crate) raw: B::ShaderModule,
pub(crate) device_id: Stored<DeviceId>
}
#[repr(C)]
#[derive(Debug)]
pub struct ProgrammableStageDescriptor {
@ -51,6 +58,7 @@ pub struct ComputePipelineDescriptor {
pub struct ComputePipeline<B: hal::Backend> {
pub(crate) raw: B::ComputePipeline,
pub(crate) layout_id: PipelineLayoutId,
pub(crate) device_id: Stored<DeviceId>,
}
#[repr(C)]
@ -82,6 +90,7 @@ bitflags::bitflags! {
pub struct RenderPipeline<B: hal::Backend> {
pub(crate) raw: B::GraphicsPipeline,
pub(crate) layout_id: PipelineLayoutId,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) index_format: IndexFormat,

View File

@ -12,9 +12,11 @@
#include "mozilla/Assertions.h"
#include "mozilla/PresShell.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderCanvasRenderer.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/webgpu/CanvasContext.h"
#include "nsDisplayList.h"
#include "nsLayoutUtils.h"
#include "nsStyleUtil.h"
@ -131,9 +133,7 @@ class nsDisplayCanvas final : public nsPaintedDisplayItem {
canvasData)) {
return true;
}
WebRenderCanvasRendererAsync* data =
static_cast<WebRenderCanvasRendererAsync*>(
canvasData->GetCanvasRenderer());
WebRenderCanvasRendererAsync* data = canvasData->GetCanvasRenderer();
MOZ_ASSERT(data);
data->UpdateCompositableClient(aBuilder.GetRenderRoot());
@ -183,6 +183,65 @@ class nsDisplayCanvas final : public nsPaintedDisplayItem {
aBuilder.GetRenderRoot());
break;
}
case CanvasContextType::WebGPU: {
nsHTMLCanvasFrame* canvasFrame =
static_cast<nsHTMLCanvasFrame*>(mFrame);
HTMLCanvasElement* canvasElement =
static_cast<HTMLCanvasElement*>(canvasFrame->GetContent());
webgpu::CanvasContext* canvasContext =
canvasElement->GetWebGPUContext();
if (!canvasContext) {
return true;
}
bool isRecycled;
RefPtr<WebRenderLocalCanvasData> canvasData =
aManager->CommandBuilder()
.CreateOrRecycleWebRenderUserData<WebRenderLocalCanvasData>(
this, aBuilder.GetRenderRoot(), &isRecycled);
if (!canvasContext->UpdateWebRenderLocalCanvasData(canvasData)) {
return true;
}
canvasData->Present();
nsIntSize canvasSizeInPx = canvasFrame->GetCanvasSize();
IntrinsicSize intrinsicSize =
IntrinsicSizeFromCanvasSize(canvasSizeInPx);
AspectRatio intrinsicRatio =
IntrinsicRatioFromCanvasSize(canvasSizeInPx);
nsRect area =
mFrame->GetContentRectRelativeToSelf() + ToReferenceFrame();
nsRect dest = nsLayoutUtils::ComputeObjectDestRect(
area, intrinsicSize, intrinsicRatio, mFrame->StylePosition());
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
dest, mFrame->PresContext()->AppUnitsPerDevPixel());
wr::ImageKey imageKey;
auto imageKeyMaybe = canvasContext->GetImageKey();
// Check that the key exists, and its namespace matches the active
// bridge. It will mismatch if there was a GPU reset.
if (imageKeyMaybe &&
aManager->WrBridge()->GetNamespace() == imageKey.mNamespace) {
imageKey = imageKeyMaybe.value();
} else {
imageKey = canvasContext->CreateImageKey(aManager);
const RGBDescriptor rgbDesc(canvasSizeInPx, canvasData->mFormat,
false);
const auto targetStride = ImageDataSerializer::GetRGBStride(rgbDesc);
const wr::ImageDescriptor imageDesc(canvasSizeInPx, targetStride,
canvasData->mFormat,
wr::OpacityType::Opaque, true);
aResources.AddPrivateExternalImage(canvasContext->mExternalImageId,
imageKey, imageDesc);
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(mFrame));
aBuilder.PushImage(wr::ToLayoutRect(bounds), wr::ToLayoutRect(bounds),
!BackfaceIsHidden(), rendering, imageKey);
break;
}
case CanvasContextType::ImageBitmap: {
nsHTMLCanvasFrame* canvasFrame =
static_cast<nsHTMLCanvasFrame*>(mFrame);