From 2e186b9e3a5d1b6140b21c60f691851b0d2a4fbc Mon Sep 17 00:00:00 2001 From: Kelsey Gilbert Date: Fri, 9 Jun 2023 19:52:39 +0000 Subject: [PATCH] Bug 1812353 - Update GPUSupportedLimits in webgpu.webidl. r=webgpu-reviewers,webidl,saschanaz,jimb,emilio,smaug * Add validation for requested features and devices for adapter.requestDevice(). * Promote webgl's AutoAssertCast to mfbt/Casting.h/LazyAssertedCast. Differential Revision: https://phabricator.services.mozilla.com/D177110 --- dom/canvas/WebGLTypes.h | 20 +-- dom/webgpu/Adapter.cpp | 370 +++++++++++++++++++++++++++++++++------ dom/webgpu/Adapter.h | 16 +- dom/webgpu/Device.cpp | 4 +- dom/webgpu/Device.h | 3 +- dom/webgpu/ObjectModel.h | 2 + dom/webgpu/SupportedFeatures.cpp | 9 + dom/webgpu/SupportedFeatures.h | 14 ++ dom/webgpu/SupportedLimits.cpp | 302 +++++++++++++++++++++----------- dom/webgpu/SupportedLimits.h | 174 +++++++++++------- dom/webgpu/ipc/WebGPUChild.cpp | 85 +-------- dom/webgpu/ipc/WebGPUChild.h | 5 +- dom/webidl/WebGPU.webidl | 16 +- mfbt/Casting.h | 26 +++ mfbt/EnumeratedRange.h | 5 + 15 files changed, 725 insertions(+), 326 deletions(-) rewrite dom/webgpu/SupportedLimits.cpp (83%) rewrite dom/webgpu/SupportedLimits.h (63%) diff --git a/dom/canvas/WebGLTypes.h b/dom/canvas/WebGLTypes.h index b06aa8a31432..cdf255ab4427 100644 --- a/dom/canvas/WebGLTypes.h +++ b/dom/canvas/WebGLTypes.h @@ -85,26 +85,10 @@ inline void* calloc(const ForbidNarrowing n, // - -namespace detail { - -template -class AutoAssertCastT final { - const From mVal; - - public: - explicit AutoAssertCastT(const From val) : mVal(val) {} - - template - operator To() const { - return AssertedCast(mVal); - } -}; - -} // namespace detail - +// TODO: Remove this now-mere-alias. template inline auto AutoAssertCast(const From val) { - return detail::AutoAssertCastT(val); + return LazyAssertedCast(val); } const char* GetEnumName(GLenum val, const char* defaultRet = ""); diff --git a/dom/webgpu/Adapter.cpp b/dom/webgpu/Adapter.cpp index 381378206b90..d7dc3672a98c 100644 --- a/dom/webgpu/Adapter.cpp +++ b/dom/webgpu/Adapter.cpp @@ -95,25 +95,68 @@ void AdapterInfo::GetWgpuBackend(nsString& s) const { GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent, mBridge, mFeatures, mLimits) GPU_IMPL_JS_WRAP(Adapter) -Maybe Adapter::MakeFeatureBits( +static Maybe ToWGPUFeatures( + const dom::GPUFeatureName aFeature) { + switch (aFeature) { + case dom::GPUFeatureName::Depth_clip_control: + return Some(WGPUFeatures_DEPTH_CLIP_CONTROL); + + case dom::GPUFeatureName::Depth32float_stencil8: + return Some(WGPUFeatures_DEPTH32FLOAT_STENCIL8); + + case dom::GPUFeatureName::Texture_compression_bc: + return Some(WGPUFeatures_TEXTURE_COMPRESSION_BC); + + case dom::GPUFeatureName::Texture_compression_etc2: + return Some(WGPUFeatures_TEXTURE_COMPRESSION_ETC2); + + case dom::GPUFeatureName::Texture_compression_astc: + return Some(WGPUFeatures_TEXTURE_COMPRESSION_ASTC); + + case dom::GPUFeatureName::Timestamp_query: + return Some(WGPUFeatures_TIMESTAMP_QUERY); + + case dom::GPUFeatureName::Indirect_first_instance: + return Some(WGPUFeatures_INDIRECT_FIRST_INSTANCE); + + case dom::GPUFeatureName::Shader_f16: + return Some(WGPUFeatures_SHADER_F16); + + case dom::GPUFeatureName::Rg11b10ufloat_renderable: + return Some(WGPUFeatures_RG11B10UFLOAT_RENDERABLE); + + case dom::GPUFeatureName::Bgra8unorm_storage: +#ifdef WGPUFeatures_BGRA8UNORM_STORAGE +# error fix todo +#endif + return Nothing(); // TODO + + case dom::GPUFeatureName::Float32_filterable: +#ifdef WGPUFeatures_FLOAT32_FILTERABLE +# error fix todo +#endif + return Nothing(); // TODO + + case dom::GPUFeatureName::EndGuard_: + break; + } + MOZ_CRASH("Bad GPUFeatureName."); +} + +static Maybe MakeFeatureBits( const dom::Sequence& aFeatures) { - uint32_t bits = 0; + ffi::WGPUFeatures bits = 0; for (const auto& feature : aFeatures) { - if (feature == dom::GPUFeatureName::Depth_clip_control) { - bits |= WGPUFeatures_DEPTH_CLIP_CONTROL; - } else if (feature == dom::GPUFeatureName::Texture_compression_bc) { - bits |= WGPUFeatures_TEXTURE_COMPRESSION_BC; - } else if (feature == dom::GPUFeatureName::Indirect_first_instance) { - bits |= WGPUFeatures_INDIRECT_FIRST_INSTANCE; - } else if (feature == dom::GPUFeatureName::Depth32float_stencil8) { - bits |= WGPUFeatures_DEPTH32FLOAT_STENCIL8; - } else { + const auto bit = ToWGPUFeatures(feature); + if (!bit) { + const auto featureStr = dom::GPUFeatureNameValues::GetString(feature); NS_WARNING( - nsPrintfCString("Requested feature bit '%d' is not recognized.", - static_cast(feature)) + nsPrintfCString("Requested feature bit for '%s' is not implemented.", + featureStr.data()) .get()); return Nothing(); } + bits |= *bit; } return Some(bits); } @@ -124,26 +167,47 @@ Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge, mBridge(aBridge), mId(aInfo->id), mFeatures(new SupportedFeatures(this)), - mLimits(new SupportedLimits(this, - MakeUnique(aInfo->limits))), + mLimits(new SupportedLimits(this, aInfo->limits)), mInfo(aInfo) { - ErrorResult result; // TODO: should this come from outside - // This list needs to match `AdapterRequestDevice` - if (aInfo->features & WGPUFeatures_DEPTH_CLIP_CONTROL) { - dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( - mFeatures, u"depth-clip-control"_ns, result); - } - if (aInfo->features & WGPUFeatures_TEXTURE_COMPRESSION_BC) { - dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( - mFeatures, u"texture-compression-bc"_ns, result); - } - if (aInfo->features & WGPUFeatures_INDIRECT_FIRST_INSTANCE) { - dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( - mFeatures, u"indirect-first-instance"_ns, result); - } - if (aInfo->features & WGPUFeatures_DEPTH32FLOAT_STENCIL8) { - dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add( - mFeatures, u"depth32float-stencil8"_ns, result); + ErrorResult ignoredRv; // It's onerous to plumb this in from outside in this + // case, and we don't really need to. + + static const auto FEATURE_BY_BIT = []() { + auto ret = std::unordered_map{}; + + for (const auto feature : + MakeEnumeratedRange(dom::GPUFeatureName::EndGuard_)) { + const auto bitForFeature = ToWGPUFeatures(feature); + if (!bitForFeature) { + // There are some features that don't have bits. + continue; + } + ret[*bitForFeature] = feature; + } + + return ret; + }(); + + auto remainingFeatureBits = aInfo->features; + auto bitMask = decltype(remainingFeatureBits){0}; + while (remainingFeatureBits) { + if (bitMask) { + bitMask <<= 1; + } else { + bitMask = 1; + } + const auto bit = remainingFeatureBits & bitMask; + remainingFeatureBits &= ~bitMask; // Clear bit. + if (!bit) { + continue; + } + + const auto featureForBit = FEATURE_BY_BIT.find(bit); + if (featureForBit != FEATURE_BY_BIT.end()) { + mFeatures->Add(featureForBit->second, ignoredRv); + } else { + // We don't recognize that bit, but maybe it's a wpgu-native-only feature. + } } } @@ -162,6 +226,84 @@ bool Adapter::IsFallbackAdapter() const { return mInfo->device_type == ffi::WGPUDeviceType::WGPUDeviceType_Cpu; } +static std::string_view ToJsKey(const Limit limit) { + switch (limit) { + case Limit::MaxTextureDimension1D: + return "maxTextureDimension1D"; + case Limit::MaxTextureDimension2D: + return "maxTextureDimension2D"; + case Limit::MaxTextureDimension3D: + return "maxTextureDimension3D"; + case Limit::MaxTextureArrayLayers: + return "maxTextureArrayLayers"; + case Limit::MaxBindGroups: + return "maxBindGroups"; + case Limit::MaxBindGroupsPlusVertexBuffers: + return "maxBindGroupsPlusVertexBuffers"; + case Limit::MaxBindingsPerBindGroup: + return "maxBindingsPerBindGroup"; + case Limit::MaxDynamicUniformBuffersPerPipelineLayout: + return "maxDynamicUniformBuffersPerPipelineLayout"; + case Limit::MaxDynamicStorageBuffersPerPipelineLayout: + return "maxDynamicStorageBuffersPerPipelineLayout"; + case Limit::MaxSampledTexturesPerShaderStage: + return "maxSampledTexturesPerShaderStage"; + case Limit::MaxSamplersPerShaderStage: + return "maxSamplersPerShaderStage"; + case Limit::MaxStorageBuffersPerShaderStage: + return "maxStorageBuffersPerShaderStage"; + case Limit::MaxStorageTexturesPerShaderStage: + return "maxStorageTexturesPerShaderStage"; + case Limit::MaxUniformBuffersPerShaderStage: + return "maxUniformBuffersPerShaderStage"; + case Limit::MaxUniformBufferBindingSize: + return "maxUniformBufferBindingSize"; + case Limit::MaxStorageBufferBindingSize: + return "maxStorageBufferBindingSize"; + case Limit::MinUniformBufferOffsetAlignment: + return "minUniformBufferOffsetAlignment"; + case Limit::MinStorageBufferOffsetAlignment: + return "minStorageBufferOffsetAlignment"; + case Limit::MaxVertexBuffers: + return "maxVertexBuffers"; + case Limit::MaxBufferSize: + return "maxBufferSize"; + case Limit::MaxVertexAttributes: + return "maxVertexAttributes"; + case Limit::MaxVertexBufferArrayStride: + return "maxVertexBufferArrayStride"; + case Limit::MaxInterStageShaderComponents: + return "maxInterStageShaderComponents"; + case Limit::MaxInterStageShaderVariables: + return "maxInterStageShaderVariables"; + case Limit::MaxColorAttachments: + return "maxColorAttachments"; + case Limit::MaxColorAttachmentBytesPerSample: + return "maxColorAttachmentBytesPerSample"; + case Limit::MaxComputeWorkgroupStorageSize: + return "maxComputeWorkgroupStorageSize"; + case Limit::MaxComputeInvocationsPerWorkgroup: + return "maxComputeInvocationsPerWorkgroup"; + case Limit::MaxComputeWorkgroupSizeX: + return "maxComputeWorkgroupSizeX"; + case Limit::MaxComputeWorkgroupSizeY: + return "maxComputeWorkgroupSizeY"; + case Limit::MaxComputeWorkgroupSizeZ: + return "maxComputeWorkgroupSizeZ"; + case Limit::MaxComputeWorkgroupsPerDimension: + return "maxComputeWorkgroupsPerDimension"; + } + MOZ_CRASH("Bad Limit"); +} + +// - +// String helpers + +static auto ToACString(const nsAString& s) { return NS_ConvertUTF16toUTF8(s); } + +// - +// Adapter::RequestDevice + already_AddRefed Adapter::RequestDevice( const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv) { RefPtr promise = dom::Promise::Create(GetParentObject(), aRv); @@ -169,23 +311,155 @@ already_AddRefed Adapter::RequestDevice( return nullptr; } - if (!mBridge->CanSend()) { - promise->MaybeRejectWithInvalidStateError( - "WebGPUChild cannot send, must recreate Adapter"); - return promise.forget(); + ffi::WGPULimits deviceLimits = *mLimits->mFfi; + for (const auto limit : MakeInclusiveEnumeratedRange(Limit::_LAST)) { + const auto defaultValue = [&]() -> double { + switch (limit) { + // clang-format off + case Limit::MaxTextureDimension1D: return 8192; + case Limit::MaxTextureDimension2D: return 8192; + case Limit::MaxTextureDimension3D: return 2048; + case Limit::MaxTextureArrayLayers: return 256; + case Limit::MaxBindGroups: return 4; + case Limit::MaxBindGroupsPlusVertexBuffers: return 24; + case Limit::MaxBindingsPerBindGroup: return 1000; + case Limit::MaxDynamicUniformBuffersPerPipelineLayout: return 8; + case Limit::MaxDynamicStorageBuffersPerPipelineLayout: return 4; + case Limit::MaxSampledTexturesPerShaderStage: return 16; + case Limit::MaxSamplersPerShaderStage: return 16; + case Limit::MaxStorageBuffersPerShaderStage: return 8; + case Limit::MaxStorageTexturesPerShaderStage: return 4; + case Limit::MaxUniformBuffersPerShaderStage: return 12; + case Limit::MaxUniformBufferBindingSize: return 65536; + case Limit::MaxStorageBufferBindingSize: return 134217728; + case Limit::MinUniformBufferOffsetAlignment: return 256; + case Limit::MinStorageBufferOffsetAlignment: return 256; + case Limit::MaxVertexBuffers: return 8; + case Limit::MaxBufferSize: return 268435456; + case Limit::MaxVertexAttributes: return 16; + case Limit::MaxVertexBufferArrayStride: return 2048; + case Limit::MaxInterStageShaderComponents: return 60; + case Limit::MaxInterStageShaderVariables: return 16; + case Limit::MaxColorAttachments: return 8; + case Limit::MaxColorAttachmentBytesPerSample: return 32; + case Limit::MaxComputeWorkgroupStorageSize: return 16384; + case Limit::MaxComputeInvocationsPerWorkgroup: return 256; + case Limit::MaxComputeWorkgroupSizeX: return 256; + case Limit::MaxComputeWorkgroupSizeY: return 256; + case Limit::MaxComputeWorkgroupSizeZ: return 64; + case Limit::MaxComputeWorkgroupsPerDimension: return 65535; + // clang-format on + } + MOZ_CRASH("Bad Limit"); + }(); + SetLimit(&deviceLimits, limit, defaultValue); } - ffi::WGPULimits limits = {}; - auto request = mBridge->AdapterRequestDevice(mId, aDesc, &limits); - if (request) { - RefPtr device = - new Device(this, request->mId, MakeUnique(limits)); - // copy over the features + // - + + [&]() { // So that we can `return;` instead of `return promise.forget();`. + if (!mBridge->CanSend()) { + promise->MaybeRejectWithInvalidStateError( + "WebGPUChild cannot send, must recreate Adapter"); + return; + } + + // - + // Validate Features + + for (const auto requested : aDesc.mRequiredFeatures) { + const bool supported = mFeatures->Features().count(requested); + if (!supported) { + const auto fstr = dom::GPUFeatureNameValues::GetString(requested); + const auto astr = this->LabelOrId(); + nsPrintfCString msg( + "requestDevice: Feature '%s' requested must be supported by " + "adapter %s", + fstr.data(), astr.get()); + promise->MaybeRejectWithTypeError(msg); + return; + } + } + + // - + // Validate Limits + + if (aDesc.mRequiredLimits.WasPassed()) { + static const auto LIMIT_BY_JS_KEY = []() { + std::unordered_map ret; + for (const auto limit : MakeInclusiveEnumeratedRange(Limit::_LAST)) { + const auto jsKeyU8 = ToJsKey(limit); + ret[jsKeyU8] = limit; + } + return ret; + }(); + + for (const auto& entry : aDesc.mRequiredLimits.Value().Entries()) { + const auto& keyU16 = entry.mKey; + const nsCString keyU8 = ToACString(keyU16); + const auto itr = LIMIT_BY_JS_KEY.find(keyU8.get()); + if (itr == LIMIT_BY_JS_KEY.end()) { + nsPrintfCString msg("requestDevice: Limit '%s' not recognized.", + keyU8.get()); + promise->MaybeRejectWithOperationError(msg); + return; + } + + const auto& limit = itr->second; + const auto& requestedValue = entry.mValue; + const auto supportedValueF64 = GetLimit(*mLimits->mFfi, limit); + const auto supportedValue = static_cast(supportedValueF64); + if (StringBeginsWith(keyU8, "max"_ns)) { + if (requestedValue > supportedValue) { + nsPrintfCString msg( + "requestDevice: Request for limit '%s' must be <= supported " + "%s, was %s.", + keyU8.get(), std::to_string(supportedValue).c_str(), + std::to_string(requestedValue).c_str()); + promise->MaybeRejectWithOperationError(msg); + return; + } + } else { + MOZ_ASSERT(StringBeginsWith(keyU8, "min"_ns)); + if (requestedValue < supportedValue) { + nsPrintfCString msg( + "requestDevice: Request for limit '%s' must be >= supported " + "%s, was %s.", + keyU8.get(), std::to_string(supportedValue).c_str(), + std::to_string(requestedValue).c_str()); + promise->MaybeRejectWithOperationError(msg); + return; + } + } + if (StringEndsWith(keyU8, "Alignment"_ns)) { + if (!IsPowerOfTwo(requestedValue)) { + nsPrintfCString msg( + "requestDevice: Request for limit '%s' must be a power of two, " + "was %s.", + keyU8.get(), std::to_string(requestedValue).c_str()); + promise->MaybeRejectWithOperationError(msg); + return; + } + } + + SetLimit(&deviceLimits, limit, requestedValue); + } + } + + // - + + ffi::WGPUDeviceDescriptor ffiDesc = {}; + ffiDesc.features = *MakeFeatureBits(aDesc.mRequiredFeatures); + ffiDesc.limits = deviceLimits; + auto request = mBridge->AdapterRequestDevice(mId, ffiDesc); + if (!request) { + promise->MaybeRejectWithNotSupportedError( + "Unable to instantiate a Device"); + return; + } + RefPtr device = new Device(this, request->mId, ffiDesc.limits); for (const auto& feature : aDesc.mRequiredFeatures) { - NS_ConvertASCIItoUTF16 string( - dom::GPUFeatureNameValues::GetString(feature)); - dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(device->mFeatures, - string, aRv); + device->mFeatures->Add(feature, aRv); } request->mPromise->Then( @@ -209,9 +483,7 @@ already_AddRefed Adapter::RequestDevice( device->CleanupUnregisteredInParent(); promise->MaybeRejectWithNotSupportedError("IPC error"); }); - } else { - promise->MaybeRejectWithNotSupportedError("Unable to instantiate a Device"); - } + }(); return promise.forget(); } diff --git a/dom/webgpu/Adapter.h b/dom/webgpu/Adapter.h index cd46bc3ddf9d..4156588e8e3b 100644 --- a/dom/webgpu/Adapter.h +++ b/dom/webgpu/Adapter.h @@ -11,6 +11,7 @@ #include "mozilla/AlreadyAddRefed.h" #include "mozilla/dom/NonRefcountedDOMObject.h" #include "mozilla/webgpu/WebGPUTypes.h" +#include "nsPrintfCString.h" #include "nsString.h" #include "ObjectModel.h" @@ -65,6 +66,10 @@ class AdapterInfo final : public dom::NonRefcountedDOMObject { JS::MutableHandle); }; +inline auto ToHexCString(const uint64_t v) { + return nsPrintfCString("0x%" PRIx64, v); +} + class Adapter final : public ObjectBase, public ChildOf { public: GPU_DECL_CYCLE_COLLECTION(Adapter) @@ -72,9 +77,6 @@ class Adapter final : public ObjectBase, public ChildOf { RefPtr mBridge; - static Maybe MakeFeatureBits( - const dom::Sequence& aFeatures); - private: ~Adapter(); void Cleanup(); @@ -94,6 +96,14 @@ class Adapter final : public ObjectBase, public ChildOf { const RefPtr& Limits() const; bool IsFallbackAdapter() const; + nsCString LabelOrId() const { + nsCString ret = this->CLabel(); + if (ret.IsEmpty()) { + ret = ToHexCString(mId); + } + return ret; + } + already_AddRefed RequestDevice( const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv); diff --git a/dom/webgpu/Device.cpp b/dom/webgpu/Device.cpp index d1b58e5c8001..371e85d77419 100644 --- a/dom/webgpu/Device.cpp +++ b/dom/webgpu/Device.cpp @@ -43,12 +43,12 @@ GPU_IMPL_JS_WRAP(Device) RefPtr Device::GetBridge() { return mBridge; } Device::Device(Adapter* const aParent, RawId aId, - UniquePtr aRawLimits) + const ffi::WGPULimits& aRawLimits) : DOMEventTargetHelper(aParent->GetParentObject()), mId(aId), // features are filled in Adapter::RequestDevice mFeatures(new SupportedFeatures(aParent)), - mLimits(new SupportedLimits(aParent, std::move(aRawLimits))), + mLimits(new SupportedLimits(aParent, aRawLimits)), mBridge(aParent->mBridge), mQueue(new class Queue(this, aParent->mBridge, aId)) { mBridge->RegisterDevice(this); diff --git a/dom/webgpu/Device.h b/dom/webgpu/Device.h index bd247fb00e62..96cc56093138 100644 --- a/dom/webgpu/Device.h +++ b/dom/webgpu/Device.h @@ -89,8 +89,7 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr { RefPtr mFeatures; RefPtr mLimits; - explicit Device(Adapter* const aParent, RawId aId, - UniquePtr aRawLimits); + explicit Device(Adapter* const aParent, RawId aId, const ffi::WGPULimits&); RefPtr GetBridge(); already_AddRefed InitSwapChain( diff --git a/dom/webgpu/ObjectModel.h b/dom/webgpu/ObjectModel.h index d482ac16f546..ea6a086d19a0 100644 --- a/dom/webgpu/ObjectModel.h +++ b/dom/webgpu/ObjectModel.h @@ -53,6 +53,8 @@ class ObjectBase : public nsWrapperCache { void GetLabel(nsAString& aValue) const; void SetLabel(const nsAString& aLabel); + + auto CLabel() const { return NS_ConvertUTF16toUTF8(mLabel); } }; } // namespace mozilla::webgpu diff --git a/dom/webgpu/SupportedFeatures.cpp b/dom/webgpu/SupportedFeatures.cpp index 072705892e6a..294524bc8196 100644 --- a/dom/webgpu/SupportedFeatures.cpp +++ b/dom/webgpu/SupportedFeatures.cpp @@ -15,4 +15,13 @@ GPU_IMPL_JS_WRAP(SupportedFeatures) SupportedFeatures::SupportedFeatures(Adapter* const aParent) : ChildOf(aParent) {} +void SupportedFeatures::Add(const dom::GPUFeatureName aFeature, + ErrorResult& aRv) { + const auto u8 = dom::GPUFeatureNameValues::GetString(aFeature); + const auto u16 = NS_ConvertUTF8toUTF16(u8); + dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(this, u16, aRv); + + mFeatures.insert(aFeature); +} + } // namespace mozilla::webgpu diff --git a/dom/webgpu/SupportedFeatures.h b/dom/webgpu/SupportedFeatures.h index 5c12ac8d3c57..b60c554f6cde 100644 --- a/dom/webgpu/SupportedFeatures.h +++ b/dom/webgpu/SupportedFeatures.h @@ -9,6 +9,15 @@ #include "nsWrapperCache.h" #include "ObjectModel.h" +#include + +namespace mozilla { +class ErrorResult; +namespace dom { +enum class GPUFeatureName : uint8_t; +} // namespace dom +} // namespace mozilla + namespace mozilla::webgpu { class Adapter; @@ -19,9 +28,14 @@ class SupportedFeatures final : public nsWrapperCache, public ChildOf { explicit SupportedFeatures(Adapter* const aParent); + void Add(dom::GPUFeatureName, ErrorResult&); + const auto& Features() const { return mFeatures; } + private: ~SupportedFeatures() = default; void Cleanup() {} + + std::unordered_set mFeatures; }; } // namespace mozilla::webgpu diff --git a/dom/webgpu/SupportedLimits.cpp b/dom/webgpu/SupportedLimits.cpp dissimilarity index 83% index ea37dec20663..8c7987385a5d 100644 --- a/dom/webgpu/SupportedLimits.cpp +++ b/dom/webgpu/SupportedLimits.cpp @@ -1,101 +1,201 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -#include "SupportedLimits.h" -#include "Adapter.h" -#include "mozilla/dom/WebGPUBinding.h" -#include "mozilla/webgpu/ffi/wgpu.h" - -namespace mozilla::webgpu { - -GPU_IMPL_CYCLE_COLLECTION(SupportedLimits, mParent) -GPU_IMPL_JS_WRAP(SupportedLimits) - -SupportedLimits::SupportedLimits(Adapter* const aParent, - UniquePtr&& aLimits) - : ChildOf(aParent), mLimits(std::move(aLimits)) {} - -SupportedLimits::~SupportedLimits() = default; - -uint32_t SupportedLimits::MaxTextureDimension1D() const { - return mLimits->max_texture_dimension_1d; -} -uint32_t SupportedLimits::MaxTextureDimension2D() const { - return mLimits->max_texture_dimension_2d; -} -uint32_t SupportedLimits::MaxTextureDimension3D() const { - return mLimits->max_texture_dimension_3d; -} -uint32_t SupportedLimits::MaxTextureArrayLayers() const { - return mLimits->max_texture_array_layers; -} -uint32_t SupportedLimits::MaxBindGroups() const { - return mLimits->max_bind_groups; -} -uint32_t SupportedLimits::MaxDynamicUniformBuffersPerPipelineLayout() const { - return mLimits->max_dynamic_uniform_buffers_per_pipeline_layout; -} -uint32_t SupportedLimits::MaxDynamicStorageBuffersPerPipelineLayout() const { - return mLimits->max_dynamic_storage_buffers_per_pipeline_layout; -} -uint32_t SupportedLimits::MaxSampledTexturesPerShaderStage() const { - return mLimits->max_sampled_textures_per_shader_stage; -} -uint32_t SupportedLimits::MaxSamplersPerShaderStage() const { - return mLimits->max_samplers_per_shader_stage; -} -uint32_t SupportedLimits::MaxStorageBuffersPerShaderStage() const { - return mLimits->max_storage_buffers_per_shader_stage; -} -uint32_t SupportedLimits::MaxStorageTexturesPerShaderStage() const { - return mLimits->max_storage_textures_per_shader_stage; -} -uint32_t SupportedLimits::MaxUniformBuffersPerShaderStage() const { - return mLimits->max_uniform_buffers_per_shader_stage; -} -uint32_t SupportedLimits::MaxUniformBufferBindingSize() const { - return mLimits->max_uniform_buffer_binding_size; -} -uint32_t SupportedLimits::MaxStorageBufferBindingSize() const { - return mLimits->max_storage_buffer_binding_size; -} -uint32_t SupportedLimits::MinUniformBufferOffsetAlignment() const { - return mLimits->min_uniform_buffer_offset_alignment; -} -uint32_t SupportedLimits::MinStorageBufferOffsetAlignment() const { - return mLimits->min_storage_buffer_offset_alignment; -} -uint32_t SupportedLimits::MaxVertexBuffers() const { - return mLimits->max_vertex_buffers; -} -uint32_t SupportedLimits::MaxVertexAttributes() const { - return mLimits->max_vertex_attributes; -} -uint32_t SupportedLimits::MaxVertexBufferArrayStride() const { - return mLimits->max_vertex_buffer_array_stride; -} -uint32_t SupportedLimits::MaxInterStageShaderComponents() const { - return mLimits->max_inter_stage_shader_components; -} -uint32_t SupportedLimits::MaxComputeWorkgroupStorageSize() const { - return mLimits->max_compute_workgroup_storage_size; -} -uint32_t SupportedLimits::MaxComputeInvocationsPerWorkgroup() const { - return mLimits->max_compute_invocations_per_workgroup; -} -uint32_t SupportedLimits::MaxComputeWorkgroupSizeX() const { - return mLimits->max_compute_workgroup_size_x; -} -uint32_t SupportedLimits::MaxComputeWorkgroupSizeY() const { - return mLimits->max_compute_workgroup_size_y; -} -uint32_t SupportedLimits::MaxComputeWorkgroupSizeZ() const { - return mLimits->max_compute_workgroup_size_z; -} -uint32_t SupportedLimits::MaxComputeWorkgroupsPerDimension() const { - return mLimits->max_compute_workgroups_per_dimension; -} - -} // namespace mozilla::webgpu +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#include "SupportedLimits.h" +#include "Adapter.h" +#include "mozilla/dom/WebGPUBinding.h" + +namespace mozilla::webgpu { + +GPU_IMPL_CYCLE_COLLECTION(SupportedLimits, mParent) +GPU_IMPL_JS_WRAP(SupportedLimits) + +SupportedLimits::SupportedLimits(Adapter* const aParent, + const ffi::WGPULimits& aLimits) + : ChildOf(aParent), mFfi(std::make_unique(aLimits)) {} + +SupportedLimits::~SupportedLimits() = default; + +double GetLimit(const ffi::WGPULimits& limits, const Limit limit) { + switch (limit) { + case Limit::MaxTextureDimension1D: + return limits.max_texture_dimension_1d; + case Limit::MaxTextureDimension2D: + return limits.max_texture_dimension_2d; + case Limit::MaxTextureDimension3D: + return limits.max_texture_dimension_3d; + case Limit::MaxTextureArrayLayers: + return limits.max_texture_array_layers; + case Limit::MaxBindGroups: + return limits.max_bind_groups; + case Limit::MaxBindGroupsPlusVertexBuffers: + // Not in ffi::WGPULimits, so synthesize: + return GetLimit(limits, Limit::MaxBindGroups) + + GetLimit(limits, Limit::MaxVertexBuffers); + case Limit::MaxBindingsPerBindGroup: + return limits.max_bindings_per_bind_group; + case Limit::MaxDynamicUniformBuffersPerPipelineLayout: + return limits.max_dynamic_uniform_buffers_per_pipeline_layout; + case Limit::MaxDynamicStorageBuffersPerPipelineLayout: + return limits.max_dynamic_storage_buffers_per_pipeline_layout; + case Limit::MaxSampledTexturesPerShaderStage: + return limits.max_sampled_textures_per_shader_stage; + case Limit::MaxSamplersPerShaderStage: + return limits.max_samplers_per_shader_stage; + case Limit::MaxStorageBuffersPerShaderStage: + return limits.max_storage_buffers_per_shader_stage; + case Limit::MaxStorageTexturesPerShaderStage: + return limits.max_storage_textures_per_shader_stage; + case Limit::MaxUniformBuffersPerShaderStage: + return limits.max_uniform_buffers_per_shader_stage; + case Limit::MaxUniformBufferBindingSize: + return limits.max_uniform_buffer_binding_size; + case Limit::MaxStorageBufferBindingSize: + return limits.max_storage_buffer_binding_size; + case Limit::MinUniformBufferOffsetAlignment: + return limits.min_uniform_buffer_offset_alignment; + case Limit::MinStorageBufferOffsetAlignment: + return limits.min_storage_buffer_offset_alignment; + case Limit::MaxVertexBuffers: + return limits.max_vertex_buffers; + case Limit::MaxBufferSize: + return limits.max_buffer_size; + case Limit::MaxVertexAttributes: + return limits.max_vertex_attributes; + case Limit::MaxVertexBufferArrayStride: + return limits.max_vertex_buffer_array_stride; + case Limit::MaxInterStageShaderComponents: + return limits.max_inter_stage_shader_components; + case Limit::MaxInterStageShaderVariables: + return 16; // From the spec. (not in ffi::WGPULimits) + case Limit::MaxColorAttachments: + return 8; // From the spec. (not in ffi::WGPULimits) + case Limit::MaxColorAttachmentBytesPerSample: + return 32; // From the spec. (not in ffi::WGPULimits) + case Limit::MaxComputeWorkgroupStorageSize: + return limits.max_compute_workgroup_storage_size; + case Limit::MaxComputeInvocationsPerWorkgroup: + return limits.max_compute_invocations_per_workgroup; + case Limit::MaxComputeWorkgroupSizeX: + return limits.max_compute_workgroup_size_x; + case Limit::MaxComputeWorkgroupSizeY: + return limits.max_compute_workgroup_size_y; + case Limit::MaxComputeWorkgroupSizeZ: + return limits.max_compute_workgroup_size_z; + case Limit::MaxComputeWorkgroupsPerDimension: + return limits.max_compute_workgroups_per_dimension; + } + MOZ_CRASH("Bad Limit"); +} + +void SetLimit(ffi::WGPULimits* const limits, const Limit limit, + const double val) { + const auto autoVal = LazyAssertedCast(static_cast(val)); + switch (limit) { + case Limit::MaxTextureDimension1D: + limits->max_texture_dimension_1d = autoVal; + return; + case Limit::MaxTextureDimension2D: + limits->max_texture_dimension_2d = autoVal; + return; + case Limit::MaxTextureDimension3D: + limits->max_texture_dimension_3d = autoVal; + return; + case Limit::MaxTextureArrayLayers: + limits->max_texture_array_layers = autoVal; + return; + case Limit::MaxBindGroups: + limits->max_bind_groups = autoVal; + return; + case Limit::MaxBindGroupsPlusVertexBuffers: + // Not in ffi::WGPULimits, and we're allowed to give back better + // limits than requested. + return; + case Limit::MaxBindingsPerBindGroup: + limits->max_bindings_per_bind_group = autoVal; + return; + case Limit::MaxDynamicUniformBuffersPerPipelineLayout: + limits->max_dynamic_uniform_buffers_per_pipeline_layout = autoVal; + return; + case Limit::MaxDynamicStorageBuffersPerPipelineLayout: + limits->max_dynamic_storage_buffers_per_pipeline_layout = autoVal; + return; + case Limit::MaxSampledTexturesPerShaderStage: + limits->max_sampled_textures_per_shader_stage = autoVal; + return; + case Limit::MaxSamplersPerShaderStage: + limits->max_samplers_per_shader_stage = autoVal; + return; + case Limit::MaxStorageBuffersPerShaderStage: + limits->max_storage_buffers_per_shader_stage = autoVal; + return; + case Limit::MaxStorageTexturesPerShaderStage: + limits->max_storage_textures_per_shader_stage = autoVal; + return; + case Limit::MaxUniformBuffersPerShaderStage: + limits->max_uniform_buffers_per_shader_stage = autoVal; + return; + case Limit::MaxUniformBufferBindingSize: + limits->max_uniform_buffer_binding_size = autoVal; + return; + case Limit::MaxStorageBufferBindingSize: + limits->max_storage_buffer_binding_size = autoVal; + return; + case Limit::MinUniformBufferOffsetAlignment: + limits->min_uniform_buffer_offset_alignment = autoVal; + return; + case Limit::MinStorageBufferOffsetAlignment: + limits->min_storage_buffer_offset_alignment = autoVal; + return; + case Limit::MaxVertexBuffers: + limits->max_vertex_buffers = autoVal; + return; + case Limit::MaxBufferSize: + limits->max_buffer_size = autoVal; + return; + case Limit::MaxVertexAttributes: + limits->max_vertex_attributes = autoVal; + return; + case Limit::MaxVertexBufferArrayStride: + limits->max_vertex_buffer_array_stride = autoVal; + return; + case Limit::MaxInterStageShaderComponents: + limits->max_inter_stage_shader_components = autoVal; + return; + case Limit::MaxInterStageShaderVariables: + // Not in ffi::WGPULimits, and we're allowed to give back better + // limits than requested. + return; + case Limit::MaxColorAttachments: + // Not in ffi::WGPULimits, and we're allowed to give back better + // limits than requested. + return; + case Limit::MaxColorAttachmentBytesPerSample: + // Not in ffi::WGPULimits, and we're allowed to give back better + // limits than requested. + return; + case Limit::MaxComputeWorkgroupStorageSize: + limits->max_compute_workgroup_storage_size = autoVal; + return; + case Limit::MaxComputeInvocationsPerWorkgroup: + limits->max_compute_invocations_per_workgroup = autoVal; + return; + case Limit::MaxComputeWorkgroupSizeX: + limits->max_compute_workgroup_size_x = autoVal; + return; + case Limit::MaxComputeWorkgroupSizeY: + limits->max_compute_workgroup_size_y = autoVal; + return; + case Limit::MaxComputeWorkgroupSizeZ: + limits->max_compute_workgroup_size_z = autoVal; + return; + case Limit::MaxComputeWorkgroupsPerDimension: + limits->max_compute_workgroups_per_dimension = autoVal; + return; + } + MOZ_CRASH("Bad Limit"); +} + +} // namespace mozilla::webgpu diff --git a/dom/webgpu/SupportedLimits.h b/dom/webgpu/SupportedLimits.h dissimilarity index 63% index 3c38ae634315..7197c6a84fca 100644 --- a/dom/webgpu/SupportedLimits.h +++ b/dom/webgpu/SupportedLimits.h @@ -1,61 +1,113 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -#ifndef GPU_SupportedLimits_H_ -#define GPU_SupportedLimits_H_ - -#include "nsWrapperCache.h" -#include "ObjectModel.h" - -namespace mozilla::webgpu { -namespace ffi { -struct WGPULimits; -} -class Adapter; - -class SupportedLimits final : public nsWrapperCache, public ChildOf { - const UniquePtr mLimits; - - public: - GPU_DECL_CYCLE_COLLECTION(SupportedLimits) - GPU_DECL_JS_WRAP(SupportedLimits) - - uint32_t MaxTextureDimension1D() const; - uint32_t MaxTextureDimension2D() const; - uint32_t MaxTextureDimension3D() const; - uint32_t MaxTextureArrayLayers() const; - uint32_t MaxBindGroups() const; - uint32_t MaxDynamicUniformBuffersPerPipelineLayout() const; - uint32_t MaxDynamicStorageBuffersPerPipelineLayout() const; - uint32_t MaxSampledTexturesPerShaderStage() const; - uint32_t MaxSamplersPerShaderStage() const; - uint32_t MaxStorageBuffersPerShaderStage() const; - uint32_t MaxStorageTexturesPerShaderStage() const; - uint32_t MaxUniformBuffersPerShaderStage() const; - uint32_t MaxUniformBufferBindingSize() const; - uint32_t MaxStorageBufferBindingSize() const; - uint32_t MinUniformBufferOffsetAlignment() const; - uint32_t MinStorageBufferOffsetAlignment() const; - uint32_t MaxVertexBuffers() const; - uint32_t MaxVertexAttributes() const; - uint32_t MaxVertexBufferArrayStride() const; - uint32_t MaxInterStageShaderComponents() const; - uint32_t MaxComputeWorkgroupStorageSize() const; - uint32_t MaxComputeInvocationsPerWorkgroup() const; - uint32_t MaxComputeWorkgroupSizeX() const; - uint32_t MaxComputeWorkgroupSizeY() const; - uint32_t MaxComputeWorkgroupSizeZ() const; - uint32_t MaxComputeWorkgroupsPerDimension() const; - - SupportedLimits(Adapter* const aParent, UniquePtr&& aLimits); - - private: - ~SupportedLimits(); - void Cleanup() {} -}; - -} // namespace mozilla::webgpu - -#endif // GPU_SupportedLimits_H_ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#ifndef GPU_SupportedLimits_H_ +#define GPU_SupportedLimits_H_ + +#include "nsWrapperCache.h" +#include "ObjectModel.h" + +#include + +namespace mozilla::webgpu { +namespace ffi { +struct WGPULimits; +} +class Adapter; + +enum class Limit : uint8_t { + MaxTextureDimension1D, + MaxTextureDimension2D, + MaxTextureDimension3D, + MaxTextureArrayLayers, + MaxBindGroups, + MaxBindGroupsPlusVertexBuffers, + MaxBindingsPerBindGroup, + MaxDynamicUniformBuffersPerPipelineLayout, + MaxDynamicStorageBuffersPerPipelineLayout, + MaxSampledTexturesPerShaderStage, + MaxSamplersPerShaderStage, + MaxStorageBuffersPerShaderStage, + MaxStorageTexturesPerShaderStage, + MaxUniformBuffersPerShaderStage, + MaxUniformBufferBindingSize, + MaxStorageBufferBindingSize, + MinUniformBufferOffsetAlignment, + MinStorageBufferOffsetAlignment, + MaxVertexBuffers, + MaxBufferSize, + MaxVertexAttributes, + MaxVertexBufferArrayStride, + MaxInterStageShaderComponents, + MaxInterStageShaderVariables, + MaxColorAttachments, + MaxColorAttachmentBytesPerSample, + MaxComputeWorkgroupStorageSize, + MaxComputeInvocationsPerWorkgroup, + MaxComputeWorkgroupSizeX, + MaxComputeWorkgroupSizeY, + MaxComputeWorkgroupSizeZ, + MaxComputeWorkgroupsPerDimension, + _LAST = MaxComputeWorkgroupsPerDimension, +}; + +double GetLimit(const ffi::WGPULimits&, Limit); +void SetLimit(ffi::WGPULimits*, Limit, double); + +class SupportedLimits final : public nsWrapperCache, public ChildOf { + public: + const std::unique_ptr mFfi; + + GPU_DECL_CYCLE_COLLECTION(SupportedLimits) + GPU_DECL_JS_WRAP(SupportedLimits) + +#define _(X) \ + auto X() const { return GetLimit(*mFfi, Limit::X); } + + _(MaxTextureDimension1D) + _(MaxTextureDimension2D) + _(MaxTextureDimension3D) + _(MaxTextureArrayLayers) + _(MaxBindGroups) + _(MaxBindGroupsPlusVertexBuffers) + _(MaxBindingsPerBindGroup) + _(MaxDynamicUniformBuffersPerPipelineLayout) + _(MaxDynamicStorageBuffersPerPipelineLayout) + _(MaxSampledTexturesPerShaderStage) + _(MaxSamplersPerShaderStage) + _(MaxStorageBuffersPerShaderStage) + _(MaxStorageTexturesPerShaderStage) + _(MaxUniformBuffersPerShaderStage) + _(MaxUniformBufferBindingSize) + _(MaxStorageBufferBindingSize) + _(MinUniformBufferOffsetAlignment) + _(MinStorageBufferOffsetAlignment) + _(MaxVertexBuffers) + _(MaxBufferSize) + _(MaxVertexAttributes) + _(MaxVertexBufferArrayStride) + _(MaxInterStageShaderComponents) + _(MaxInterStageShaderVariables) + _(MaxColorAttachments) + _(MaxColorAttachmentBytesPerSample) + _(MaxComputeWorkgroupStorageSize) + _(MaxComputeInvocationsPerWorkgroup) + _(MaxComputeWorkgroupSizeX) + _(MaxComputeWorkgroupSizeY) + _(MaxComputeWorkgroupSizeZ) + _(MaxComputeWorkgroupsPerDimension) + +#undef _ + + SupportedLimits(Adapter* const aParent, const ffi::WGPULimits&); + + private: + ~SupportedLimits(); + void Cleanup() {} +}; + +} // namespace mozilla::webgpu + +#endif // GPU_SupportedLimits_H_ diff --git a/dom/webgpu/ipc/WebGPUChild.cpp b/dom/webgpu/ipc/WebGPUChild.cpp index fefb2e6ff673..ae076216f3d8 100644 --- a/dom/webgpu/ipc/WebGPUChild.cpp +++ b/dom/webgpu/ipc/WebGPUChild.cpp @@ -274,96 +274,15 @@ RefPtr WebGPUChild::InstanceRequestAdapter( } Maybe WebGPUChild::AdapterRequestDevice( - RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, - ffi::WGPULimits* aLimits) { - ffi::WGPUDeviceDescriptor desc = {}; - ffi::wgpu_client_fill_default_limits(&desc.limits); - - // webgpu::StringHelper label(aDesc.mLabel); - // desc.label = label.Get(); - - const auto featureBits = Adapter::MakeFeatureBits(aDesc.mRequiredFeatures); - if (!featureBits) { - return Nothing(); - } - desc.features = *featureBits; - - if (aDesc.mRequiredLimits.WasPassed()) { - for (const auto& entry : aDesc.mRequiredLimits.Value().Entries()) { - const uint32_t valueU32 = - entry.mValue < std::numeric_limits::max() - ? entry.mValue - : std::numeric_limits::max(); - if (entry.mKey == u"maxTextureDimension1D"_ns) { - desc.limits.max_texture_dimension_1d = valueU32; - } else if (entry.mKey == u"maxTextureDimension2D"_ns) { - desc.limits.max_texture_dimension_2d = valueU32; - } else if (entry.mKey == u"maxTextureDimension3D"_ns) { - desc.limits.max_texture_dimension_3d = valueU32; - } else if (entry.mKey == u"maxTextureArrayLayers"_ns) { - desc.limits.max_texture_array_layers = valueU32; - } else if (entry.mKey == u"maxBindGroups"_ns) { - desc.limits.max_bind_groups = valueU32; - } else if (entry.mKey == - u"maxDynamicUniformBuffersPerPipelineLayout"_ns) { - desc.limits.max_dynamic_uniform_buffers_per_pipeline_layout = valueU32; - } else if (entry.mKey == - u"maxDynamicStorageBuffersPerPipelineLayout"_ns) { - desc.limits.max_dynamic_storage_buffers_per_pipeline_layout = valueU32; - } else if (entry.mKey == u"maxSampledTexturesPerShaderStage"_ns) { - desc.limits.max_sampled_textures_per_shader_stage = valueU32; - } else if (entry.mKey == u"maxSamplersPerShaderStage"_ns) { - desc.limits.max_samplers_per_shader_stage = valueU32; - } else if (entry.mKey == u"maxStorageBuffersPerShaderStage"_ns) { - desc.limits.max_storage_buffers_per_shader_stage = valueU32; - } else if (entry.mKey == u"maxStorageTexturesPerShaderStage"_ns) { - desc.limits.max_storage_textures_per_shader_stage = valueU32; - } else if (entry.mKey == u"maxUniformBuffersPerShaderStage"_ns) { - desc.limits.max_uniform_buffers_per_shader_stage = valueU32; - } else if (entry.mKey == u"maxUniformBufferBindingSize"_ns) { - desc.limits.max_uniform_buffer_binding_size = entry.mValue; - } else if (entry.mKey == u"maxStorageBufferBindingSize"_ns) { - desc.limits.max_storage_buffer_binding_size = entry.mValue; - } else if (entry.mKey == u"minUniformBufferOffsetAlignment"_ns) { - desc.limits.min_uniform_buffer_offset_alignment = valueU32; - } else if (entry.mKey == u"minStorageBufferOffsetAlignment"_ns) { - desc.limits.min_storage_buffer_offset_alignment = valueU32; - } else if (entry.mKey == u"maxVertexBuffers"_ns) { - desc.limits.max_vertex_buffers = valueU32; - } else if (entry.mKey == u"maxVertexAttributes"_ns) { - desc.limits.max_vertex_attributes = valueU32; - } else if (entry.mKey == u"maxVertexBufferArrayStride"_ns) { - desc.limits.max_vertex_buffer_array_stride = valueU32; - } else if (entry.mKey == u"maxComputeWorkgroupSizeX"_ns) { - desc.limits.max_compute_workgroup_size_x = valueU32; - } else if (entry.mKey == u"maxComputeWorkgroupSizeY"_ns) { - desc.limits.max_compute_workgroup_size_y = valueU32; - } else if (entry.mKey == u"maxComputeWorkgroupSizeZ"_ns) { - desc.limits.max_compute_workgroup_size_z = valueU32; - } else if (entry.mKey == u"maxComputeWorkgroupsPerDimension"_ns) { - desc.limits.max_compute_workgroups_per_dimension = valueU32; - } else { - NS_WARNING(nsPrintfCString("Requested limit '%s' is not recognized.", - NS_ConvertUTF16toUTF8(entry.mKey).get()) - .get()); - return Nothing(); - } - - // TODO: maxInterStageShaderComponents - // TODO: maxComputeWorkgroupStorageSize - // TODO: maxComputeInvocationsPerWorkgroup - } - } - + RawId aSelfId, const ffi::WGPUDeviceDescriptor& aDesc) { RawId id = ffi::wgpu_client_make_device_id(mClient.get(), aSelfId); ByteBuf bb; - ffi::wgpu_client_serialize_device_descriptor(&desc, ToFFI(&bb)); + ffi::wgpu_client_serialize_device_descriptor(&aDesc, ToFFI(&bb)); DeviceRequest request; request.mId = id; request.mPromise = SendAdapterRequestDevice(aSelfId, std::move(bb), id); - *aLimits = desc.limits; return Some(std::move(request)); } diff --git a/dom/webgpu/ipc/WebGPUChild.h b/dom/webgpu/ipc/WebGPUChild.h index 5c091ef12e91..dbb2053b244e 100644 --- a/dom/webgpu/ipc/WebGPUChild.h +++ b/dom/webgpu/ipc/WebGPUChild.h @@ -62,9 +62,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr { RefPtr InstanceRequestAdapter( const dom::GPURequestAdapterOptions& aOptions); - Maybe AdapterRequestDevice( - RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, - ffi::WGPULimits* aLimits); + Maybe AdapterRequestDevice(RawId aSelfId, + const ffi::WGPUDeviceDescriptor&); RawId DeviceCreateBuffer(RawId aSelfId, const dom::GPUBufferDescriptor& aDesc, ipc::UnsafeSharedMemoryHandle&& aShmem); RawId DeviceCreateTexture(RawId aSelfId, diff --git a/dom/webidl/WebGPU.webidl b/dom/webidl/WebGPU.webidl index 39a9c5a4b3bc..186af9ee6594 100644 --- a/dom/webidl/WebGPU.webidl +++ b/dom/webidl/WebGPU.webidl @@ -23,6 +23,8 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxTextureDimension3D; readonly attribute unsigned long maxTextureArrayLayers; readonly attribute unsigned long maxBindGroups; + readonly attribute unsigned long maxBindGroupsPlusVertexBuffers; + readonly attribute unsigned long maxBindingsPerBindGroup; readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout; readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout; readonly attribute unsigned long maxSampledTexturesPerShaderStage; @@ -30,14 +32,18 @@ interface GPUSupportedLimits { readonly attribute unsigned long maxStorageBuffersPerShaderStage; readonly attribute unsigned long maxStorageTexturesPerShaderStage; readonly attribute unsigned long maxUniformBuffersPerShaderStage; - readonly attribute unsigned long maxUniformBufferBindingSize; - readonly attribute unsigned long maxStorageBufferBindingSize; + readonly attribute unsigned long long maxUniformBufferBindingSize; + readonly attribute unsigned long long maxStorageBufferBindingSize; readonly attribute unsigned long minUniformBufferOffsetAlignment; readonly attribute unsigned long minStorageBufferOffsetAlignment; readonly attribute unsigned long maxVertexBuffers; + readonly attribute unsigned long long maxBufferSize; readonly attribute unsigned long maxVertexAttributes; readonly attribute unsigned long maxVertexBufferArrayStride; readonly attribute unsigned long maxInterStageShaderComponents; + readonly attribute unsigned long maxInterStageShaderVariables; + readonly attribute unsigned long maxColorAttachments; + readonly attribute unsigned long maxColorAttachmentBytesPerSample; readonly attribute unsigned long maxComputeWorkgroupStorageSize; readonly attribute unsigned long maxComputeInvocationsPerWorkgroup; readonly attribute unsigned long maxComputeWorkgroupSizeX; @@ -120,14 +126,16 @@ dictionary GPUDeviceDescriptor { enum GPUFeatureName { "depth-clip-control", - "depth24unorm-stencil8", "depth32float-stencil8", - "pipeline-statistics-query", "texture-compression-bc", "texture-compression-etc2", "texture-compression-astc", "timestamp-query", "indirect-first-instance", + "shader-f16", + "rg11b10ufloat-renderable", + "bgra8unorm-storage", + "float32-filterable", }; // Device diff --git a/mfbt/Casting.h b/mfbt/Casting.h index c3341887acf8..ebb0e8bc512b 100644 --- a/mfbt/Casting.h +++ b/mfbt/Casting.h @@ -198,6 +198,32 @@ inline To ReleaseAssertedCast(const From aFrom) { return static_cast(aFrom); } +namespace detail { + +template +class LazyAssertedCastT final { + const From mVal; + + public: + explicit LazyAssertedCastT(const From val) : mVal(val) {} + + template + operator To() const { + return AssertedCast(mVal); + } +}; + +} // namespace detail + +/** + * Like AssertedCast, but infers |To| for AssertedCast lazily based on usage. + * > uint8_t foo = LazyAssertedCast(1000); // boom + */ +template +inline auto LazyAssertedCast(const From val) { + return detail::LazyAssertedCastT(val); +} + } // namespace mozilla #endif /* mozilla_Casting_h */ diff --git a/mfbt/EnumeratedRange.h b/mfbt/EnumeratedRange.h index 74d95923924f..ef0e6910ab5c 100644 --- a/mfbt/EnumeratedRange.h +++ b/mfbt/EnumeratedRange.h @@ -197,6 +197,11 @@ constexpr detail::EnumeratedRange MakeInclusiveEnumeratedRange( return MakeEnumeratedRange(aBegin, static_cast(end + 1)); } +template +constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) { + return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd); +} + #ifdef __GNUC__ # pragma GCC diagnostic pop #endif -- 2.11.4.GIT