mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
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:
parent
a2961d74e7
commit
3021defc28
@ -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;
|
||||
|
@ -27,6 +27,7 @@ enum class CanvasContextType : uint8_t {
|
||||
Canvas2D,
|
||||
WebGL1,
|
||||
WebGL2,
|
||||
WebGPU,
|
||||
ImageBitmap
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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) {}
|
||||
|
@ -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);
|
||||
|
@ -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]>,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>(
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user