Bug 1743667 - Hook up WebGPU device limits and features r=jgilbert,webidl,smaug

Differential Revision: https://phabricator.services.mozilla.com/D133280
This commit is contained in:
Dzmitry Malyshau 2021-12-10 01:09:04 +00:00
Родитель 7c8078f842
Коммит 0b48a2d1e1
14 изменённых файлов: 194 добавлений и 64 удалений

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

@ -1366,9 +1366,6 @@ DOMInterfaces = {
'GPUAdapter': {
'nativeType': 'mozilla::webgpu::Adapter',
},
'GPUAdapterFeatures': {
'nativeType': 'mozilla::webgpu::AdapterFeatures',
},
'GPUBindGroup': {
'nativeType': 'mozilla::webgpu::BindGroup',
},
@ -1436,6 +1433,9 @@ DOMInterfaces = {
'GPUShaderModule': {
'nativeType': 'mozilla::webgpu::ShaderModule',
},
'GPUSupportedFeatures': {
'nativeType': 'mozilla::webgpu::SupportedFeatures',
},
'GPUSupportedLimits': {
'nativeType': 'mozilla::webgpu::SupportedLimits',
},

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

@ -6,12 +6,13 @@
#include "mozilla/dom/WebGPUBinding.h"
#include "Adapter.h"
#include "AdapterFeatures.h"
#include "Device.h"
#include "Instance.h"
#include "SupportedFeatures.h"
#include "SupportedLimits.h"
#include "ipc/WebGPUChild.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace mozilla {
namespace webgpu {
@ -19,14 +20,51 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent, mBridge, mFeatures, mLimits)
GPU_IMPL_JS_WRAP(Adapter)
Maybe<uint32_t> Adapter::MakeFeatureBits(
const dom::Sequence<dom::GPUFeatureName>& aFeatures) {
uint32_t 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 {
NS_WARNING(
nsPrintfCString("Requested feature bit '%d' is not recognized.",
static_cast<int>(feature))
.get());
return Nothing();
}
}
return Some(bits);
}
Adapter::Adapter(Instance* const aParent,
const ffi::WGPUAdapterInformation& aInfo)
: ChildOf(aParent),
mBridge(aParent->mBridge),
mId(aInfo.id),
mFeatures(new AdapterFeatures(this)),
mLimits(new SupportedLimits(this, aInfo.limits)),
mIsFallbackAdapter(aInfo.ty == ffi::WGPUDeviceType_Cpu) {}
mFeatures(new SupportedFeatures(this)),
mLimits(
new SupportedLimits(this, MakeUnique<ffi::WGPULimits>(aInfo.limits))),
mIsFallbackAdapter(aInfo.ty == ffi::WGPUDeviceType_Cpu) {
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);
}
}
Adapter::~Adapter() { Cleanup(); }
@ -37,7 +75,7 @@ void Adapter::Cleanup() {
}
}
const RefPtr<AdapterFeatures>& Adapter::Features() const { return mFeatures; }
const RefPtr<SupportedFeatures>& Adapter::Features() const { return mFeatures; }
const RefPtr<SupportedLimits>& Adapter::Limits() const { return mLimits; }
already_AddRefed<dom::Promise> Adapter::RequestDevice(
@ -47,9 +85,19 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
return nullptr;
}
Maybe<RawId> id = mBridge->AdapterRequestDevice(mId, aDesc);
ffi::WGPULimits limits = {};
Maybe<RawId> id = mBridge->AdapterRequestDevice(mId, aDesc, &limits);
if (id.isSome()) {
RefPtr<Device> device = new Device(this, id.value());
RefPtr<Device> device =
new Device(this, id.value(), aDesc.mRequiredFeatures,
MakeUnique<ffi::WGPULimits>(limits));
// copy over the features
for (const auto& feature : aDesc.mRequiredFeatures) {
NS_ConvertASCIItoUTF16 string(
dom::GPUFeatureNameValues::GetString(feature));
dom::GPUSupportedFeatures_Binding::SetlikeHelpers::Add(mFeatures, string,
aRv);
}
promise->MaybeResolve(device);
} else {
promise->MaybeRejectWithNotSupportedError("Unable to instanciate a Device");

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

@ -18,12 +18,15 @@ class Promise;
struct GPUDeviceDescriptor;
struct GPUExtensions;
struct GPUFeatures;
enum class GPUFeatureName : uint8_t;
template <typename T>
class Sequence;
} // namespace dom
namespace webgpu {
class AdapterFeatures;
class Device;
class Instance;
class SupportedFeatures;
class SupportedLimits;
class WebGPUChild;
namespace ffi {
@ -37,6 +40,9 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
RefPtr<WebGPUChild> mBridge;
static Maybe<uint32_t> MakeFeatureBits(
const dom::Sequence<dom::GPUFeatureName>& aFeatures);
private:
~Adapter();
void Cleanup();
@ -45,14 +51,14 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
const nsString mName;
// Cant have them as `const` right now, since we wouldn't be able
// to unlink them in CC unlink.
RefPtr<AdapterFeatures> mFeatures;
RefPtr<SupportedFeatures> mFeatures;
RefPtr<SupportedLimits> mLimits;
const bool mIsFallbackAdapter = false;
public:
Adapter(Instance* const aParent, const ffi::WGPUAdapterInformation& aInfo);
void GetName(nsString& out) const { out = mName; }
const RefPtr<AdapterFeatures>& Features() const;
const RefPtr<SupportedFeatures>& Features() const;
const RefPtr<SupportedLimits>& Limits() const;
bool IsFallbackAdapter() const { return mIsFallbackAdapter; }

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

@ -21,6 +21,8 @@
#include "RenderBundleEncoder.h"
#include "RenderPipeline.h"
#include "Sampler.h"
#include "SupportedFeatures.h"
#include "SupportedLimits.h"
#include "Texture.h"
#include "TextureView.h"
#include "ValidationError.h"
@ -51,11 +53,16 @@ JSObject* Device::CreateExternalArrayBuffer(JSContext* aCx, size_t aOffset,
&mapFreeCallback, nullptr);
}
Device::Device(Adapter* const aParent, RawId aId)
Device::Device(Adapter* const aParent, RawId aId,
const dom::Sequence<dom::GPUFeatureName>& aRequiredFeatures,
UniquePtr<ffi::WGPULimits> aRawLimits)
: DOMEventTargetHelper(aParent->GetParentObject()),
mId(aId),
mBridge(aParent->mBridge),
mQueue(new class Queue(this, aParent->mBridge, aId)) {
mQueue(new class Queue(this, aParent->mBridge, aId)),
// features are filled in Adapter::RequestDevice
mFeatures(new SupportedFeatures(aParent)),
mLimits(new SupportedLimits(aParent, std::move(aRawLimits))) {
mBridge->RegisterDevice(mId, this);
}
@ -71,8 +78,6 @@ void Device::Cleanup() {
void Device::GetLabel(nsAString& aValue) const { aValue = mLabel; }
void Device::SetLabel(const nsAString& aLabel) { mLabel = aLabel; }
const RefPtr<Queue>& Device::GetQueue() const { return mQueue; }
already_AddRefed<Buffer> Device::CreateBuffer(
const dom::GPUBufferDescriptor& aDesc, ErrorResult& aRv) {
ipc::Shmem shmem;

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

@ -44,6 +44,7 @@ template <typename T>
class Sequence;
class GPUBufferOrGPUTexture;
enum class GPUErrorFilter : uint8_t;
enum class GPUFeatureName : uint8_t;
class GPULogCallback;
} // namespace dom
namespace ipc {
@ -52,6 +53,9 @@ class Shmem;
} // namespace ipc
namespace webgpu {
namespace ffi {
struct WGPULimits;
}
class Adapter;
class BindGroup;
class BindGroupLayout;
@ -66,6 +70,8 @@ class RenderBundleEncoder;
class RenderPipeline;
class Sampler;
class ShaderModule;
class SupportedFeatures;
class SupportedLimits;
class Texture;
class WebGPUChild;
@ -79,7 +85,9 @@ class Device final : public DOMEventTargetHelper {
const RawId mId;
explicit Device(Adapter* const aParent, RawId aId);
explicit Device(Adapter* const aParent, RawId aId,
const dom::Sequence<dom::GPUFeatureName>& aRequiredFeatures,
UniquePtr<ffi::WGPULimits> aRawLimits);
RefPtr<WebGPUChild> GetBridge();
static JSObject* CreateExternalArrayBuffer(JSContext* aCx, size_t aOffset,
@ -105,12 +113,16 @@ class Device final : public DOMEventTargetHelper {
nsString mLabel;
RefPtr<Queue> mQueue;
nsTHashSet<nsCString> mKnownWarnings;
RefPtr<SupportedFeatures> mFeatures;
RefPtr<SupportedLimits> mLimits;
public:
void GetLabel(nsAString& aValue) const;
void SetLabel(const nsAString& aLabel);
const RefPtr<Queue>& GetQueue() const;
const RefPtr<SupportedFeatures>& Features() const { return mFeatures; }
const RefPtr<SupportedLimits>& Limits() const { return mLimits; }
const RefPtr<Queue>& GetQueue() const { return mQueue; }
already_AddRefed<Buffer> CreateBuffer(const dom::GPUBufferDescriptor& aDesc,
ErrorResult& aRv);

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

@ -68,8 +68,8 @@ already_AddRefed<dom::Promise> Instance::RequestAdapter(
RefPtr<Adapter> adapter = new Adapter(instance, info);
promise->MaybeResolve(adapter);
},
[promise](const Maybe<ipc::ResponseRejectReason>& aRv) {
if (aRv.isSome()) {
[promise](const Maybe<ipc::ResponseRejectReason>& aResponseReason) {
if (aResponseReason.isSome()) {
promise->MaybeRejectWithAbortError("Internal communication error!");
} else {
promise->MaybeRejectWithInvalidStateError(

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

@ -3,17 +3,18 @@
* 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 "AdapterFeatures.h"
#include "SupportedFeatures.h"
#include "Adapter.h"
#include "mozilla/dom/WebGPUBinding.h"
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(AdapterFeatures, mParent)
GPU_IMPL_JS_WRAP(AdapterFeatures)
GPU_IMPL_CYCLE_COLLECTION(SupportedFeatures, mParent)
GPU_IMPL_JS_WRAP(SupportedFeatures)
AdapterFeatures::AdapterFeatures(Adapter* const aParent) : ChildOf(aParent) {}
SupportedFeatures::SupportedFeatures(Adapter* const aParent)
: ChildOf(aParent) {}
} // namespace webgpu
} // namespace mozilla

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

@ -3,8 +3,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/. */
#ifndef GPU_AdapterFeatures_H_
#define GPU_AdapterFeatures_H_
#ifndef GPU_SupportedFeatures_H_
#define GPU_SupportedFeatures_H_
#include "nsWrapperCache.h"
#include "ObjectModel.h"
@ -13,19 +13,19 @@ namespace mozilla {
namespace webgpu {
class Adapter;
class AdapterFeatures final : public nsWrapperCache, public ChildOf<Adapter> {
class SupportedFeatures final : public nsWrapperCache, public ChildOf<Adapter> {
public:
GPU_DECL_CYCLE_COLLECTION(AdapterFeatures)
GPU_DECL_JS_WRAP(AdapterFeatures)
GPU_DECL_CYCLE_COLLECTION(SupportedFeatures)
GPU_DECL_JS_WRAP(SupportedFeatures)
explicit AdapterFeatures(Adapter* const aParent);
explicit SupportedFeatures(Adapter* const aParent);
private:
~AdapterFeatures() = default;
~SupportedFeatures() = default;
void Cleanup() {}
};
} // namespace webgpu
} // namespace mozilla
#endif // GPU_AdapterFeatures_H_
#endif // GPU_SupportedFeatures_H_

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

@ -15,8 +15,8 @@ GPU_IMPL_CYCLE_COLLECTION(SupportedLimits, mParent)
GPU_IMPL_JS_WRAP(SupportedLimits)
SupportedLimits::SupportedLimits(Adapter* const aParent,
const ffi::WGPULimits& aLimits)
: ChildOf(aParent), mLimits(new ffi::WGPULimits(aLimits)) {}
UniquePtr<ffi::WGPULimits>&& aLimits)
: ChildOf(aParent), mLimits(std::move(aLimits)) {}
SupportedLimits::~SupportedLimits() = default;

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

@ -41,7 +41,7 @@ class SupportedLimits final : public nsWrapperCache, public ChildOf<Adapter> {
uint32_t MaxVertexAttributes() const;
uint32_t MaxVertexBufferArrayStride() const;
SupportedLimits(Adapter* const aParent, const ffi::WGPULimits& aLimits);
SupportedLimits(Adapter* const aParent, UniquePtr<ffi::WGPULimits>&& aLimits);
private:
~SupportedLimits();

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

@ -11,6 +11,7 @@
#include "mozilla/dom/GPUUncapturedErrorEvent.h"
#include "mozilla/webgpu/ValidationError.h"
#include "mozilla/webgpu/ffi/wgpu.h"
#include "Adapter.h"
#include "Sampler.h"
namespace mozilla {
@ -202,37 +203,90 @@ RefPtr<AdapterPromise> WebGPUChild::InstanceRequestAdapter(
}
Maybe<RawId> WebGPUChild::AdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc) {
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimits) {
RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
ffi::WGPUDeviceDescriptor desc = {};
ffi::wgpu_client_fill_default_limits(&desc.limits);
const auto featureBits = Adapter::MakeFeatureBits(aDesc.mRequiredFeatures);
if (!featureBits) {
return {};
}
desc.features = *featureBits;
if (aDesc.mRequiredLimits.WasPassed()) {
for (const auto& entry : aDesc.mRequiredLimits.Value().Entries()) {
Unused << entry; // TODO
const uint32_t valueU32 =
entry.mValue < std::numeric_limits<uint32_t>::max()
? entry.mValue
: std::numeric_limits<uint32_t>::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
}
/*desc.limits.max_bind_groups = lim.mMaxBindGroups;
desc.limits.max_dynamic_uniform_buffers_per_pipeline_layout =
lim.mMaxDynamicUniformBuffersPerPipelineLayout;
desc.limits.max_dynamic_storage_buffers_per_pipeline_layout =
lim.mMaxDynamicStorageBuffersPerPipelineLayout;
desc.limits.max_sampled_textures_per_shader_stage =
lim.mMaxSampledTexturesPerShaderStage;
desc.limits.max_samplers_per_shader_stage = lim.mMaxSamplersPerShaderStage;
desc.limits.max_storage_buffers_per_shader_stage =
lim.mMaxStorageBuffersPerShaderStage;
desc.limits.max_storage_textures_per_shader_stage =
lim.mMaxStorageTexturesPerShaderStage;
desc.limits.max_uniform_buffers_per_shader_stage =
lim.mMaxUniformBuffersPerShaderStage;
desc.limits.max_uniform_buffer_binding_size =
lim.mMaxUniformBufferBindingSize;*/
}
ByteBuf bb;
ffi::wgpu_client_serialize_device_descriptor(&desc, ToFFI(&bb));
if (SendAdapterRequestDevice(aSelfId, std::move(bb), id)) {
*aLimits = desc.limits;
return Some(id);
}
ffi::wgpu_client_kill_device_id(mClient, id);

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

@ -20,6 +20,7 @@ class CompositorBridgeChild;
namespace webgpu {
namespace ffi {
struct WGPUClient;
struct WGPULimits;
struct WGPUTextureViewDescriptor;
} // namespace ffi
@ -43,7 +44,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
RefPtr<AdapterPromise> InstanceRequestAdapter(
const dom::GPURequestAdapterOptions& aOptions);
Maybe<RawId> AdapterRequestDevice(RawId aSelfId,
const dom::GPUDeviceDescriptor& aDesc);
const dom::GPUDeviceDescriptor& aDesc,
ffi::WGPULimits* aLimtis);
RawId DeviceCreateBuffer(RawId aSelfId,
const dom::GPUBufferDescriptor& aDesc);
RawId DeviceCreateTexture(RawId aSelfId,

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

@ -16,7 +16,6 @@ DIRS += []
h_and_cpp = [
"Adapter",
"AdapterFeatures",
"BindGroup",
"BindGroupLayout",
"Buffer",
@ -41,6 +40,7 @@ h_and_cpp = [
"RenderPipeline",
"Sampler",
"ShaderModule",
"SupportedFeatures",
"SupportedLimits",
"Texture",
"TextureView",

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

@ -87,22 +87,25 @@ dictionary GPURequestAdapterOptions {
[Pref="dom.webgpu.enabled",
Exposed=Window]
interface GPUAdapterFeatures {
readonly setlike<GPUFeatureName>;
interface GPUSupportedFeatures {
readonly setlike<DOMString>;
};
dictionary GPUDeviceDescriptor {
sequence<GPUFeatureName> requiredFeatures = [];
record<DOMString, GPUSize32> requiredLimits;
record<DOMString, GPUSize64> requiredLimits;
};
enum GPUFeatureName {
"depth-clamping",
"depth-clip-control",
"depth24unorm-stencil8",
"depth32float-stencil8",
"pipeline-statistics-query",
"texture-compression-bc",
"texture-compression-etc2",
"texture-compression-astc",
"timestamp-query",
"indirect-first-instance",
};
[Pref="dom.webgpu.enabled",
@ -131,7 +134,7 @@ interface GPUSupportedLimits {
Exposed=Window]
interface GPUAdapter {
readonly attribute DOMString name;
[SameObject] readonly attribute GPUAdapterFeatures features;
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
readonly attribute boolean isFallbackAdapter;
@ -143,9 +146,8 @@ interface GPUAdapter {
[Pref="dom.webgpu.enabled",
Exposed=Window]
interface GPUDevice: EventTarget {
//[SameObject] readonly attribute GPUAdapter adapter;
//readonly attribute FrozenArray<GPUFeatureName> features;
//readonly attribute object limits;
[SameObject] readonly attribute GPUSupportedFeatures features;
[SameObject] readonly attribute GPUSupportedLimits limits;
// Overriding the name to avoid collision with `class Queue` in gcc
[SameObject, BinaryName="getQueue"] readonly attribute GPUQueue queue;