зеркало из https://github.com/mozilla/gecko-dev.git
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
This commit is contained in:
Родитель
08e73e0c07
Коммит
0fb34553d5
|
@ -85,26 +85,10 @@ inline void* calloc(const ForbidNarrowing<size_t> n,
|
|||
|
||||
// -
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename From>
|
||||
class AutoAssertCastT final {
|
||||
const From mVal;
|
||||
|
||||
public:
|
||||
explicit AutoAssertCastT(const From val) : mVal(val) {}
|
||||
|
||||
template <typename To>
|
||||
operator To() const {
|
||||
return AssertedCast<To>(mVal);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// TODO: Remove this now-mere-alias.
|
||||
template <typename From>
|
||||
inline auto AutoAssertCast(const From val) {
|
||||
return detail::AutoAssertCastT<From>(val);
|
||||
return LazyAssertedCast(val);
|
||||
}
|
||||
|
||||
const char* GetEnumName(GLenum val, const char* defaultRet = "<unknown>");
|
||||
|
|
|
@ -95,25 +95,69 @@ void AdapterInfo::GetWgpuBackend(nsString& s) const {
|
|||
GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent, mBridge, mFeatures, mLimits)
|
||||
GPU_IMPL_JS_WRAP(Adapter)
|
||||
|
||||
Maybe<uint32_t> Adapter::MakeFeatureBits(
|
||||
static Maybe<ffi::WGPUFeatures> 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<ffi::WGPUFeatures> MakeFeatureBits(
|
||||
const dom::Sequence<dom::GPUFeatureName>& 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);
|
||||
(void)featureStr;
|
||||
NS_WARNING(
|
||||
nsPrintfCString("Requested feature bit '%d' is not recognized.",
|
||||
static_cast<int>(feature))
|
||||
nsPrintfCString("Requested feature bit for '%s' is not implemented.",
|
||||
featureStr.data())
|
||||
.get());
|
||||
return Nothing();
|
||||
}
|
||||
bits |= *bit;
|
||||
}
|
||||
return Some(bits);
|
||||
}
|
||||
|
@ -124,26 +168,47 @@ Adapter::Adapter(Instance* const aParent, WebGPUChild* const aBridge,
|
|||
mBridge(aBridge),
|
||||
mId(aInfo->id),
|
||||
mFeatures(new SupportedFeatures(this)),
|
||||
mLimits(new SupportedLimits(this,
|
||||
MakeUnique<ffi::WGPULimits>(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<ffi::WGPUFeatures, dom::GPUFeatureName>{};
|
||||
|
||||
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 +227,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<dom::Promise> Adapter::RequestDevice(
|
||||
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv) {
|
||||
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv);
|
||||
|
@ -169,23 +312,155 @@ already_AddRefed<dom::Promise> 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> device =
|
||||
new Device(this, request->mId, MakeUnique<ffi::WGPULimits>(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<std::string_view, Limit> 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<uint64_t>(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> 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 +484,7 @@ already_AddRefed<dom::Promise> Adapter::RequestDevice(
|
|||
device->CleanupUnregisteredInParent();
|
||||
promise->MaybeRejectWithNotSupportedError("IPC error");
|
||||
});
|
||||
} else {
|
||||
promise->MaybeRejectWithNotSupportedError("Unable to instantiate a Device");
|
||||
}
|
||||
}();
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
|
|
@ -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<JSObject*>);
|
||||
};
|
||||
|
||||
inline auto ToHexCString(const uint64_t v) {
|
||||
return nsPrintfCString("0x%" PRIx64, v);
|
||||
}
|
||||
|
||||
class Adapter final : public ObjectBase, public ChildOf<Instance> {
|
||||
public:
|
||||
GPU_DECL_CYCLE_COLLECTION(Adapter)
|
||||
|
@ -72,9 +77,6 @@ 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();
|
||||
|
@ -94,6 +96,14 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
|
|||
const RefPtr<SupportedLimits>& Limits() const;
|
||||
bool IsFallbackAdapter() const;
|
||||
|
||||
nsCString LabelOrId() const {
|
||||
nsCString ret = this->CLabel();
|
||||
if (ret.IsEmpty()) {
|
||||
ret = ToHexCString(mId);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> RequestDevice(
|
||||
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -43,12 +43,12 @@ GPU_IMPL_JS_WRAP(Device)
|
|||
RefPtr<WebGPUChild> Device::GetBridge() { return mBridge; }
|
||||
|
||||
Device::Device(Adapter* const aParent, RawId aId,
|
||||
UniquePtr<ffi::WGPULimits> 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);
|
||||
|
|
|
@ -89,8 +89,7 @@ class Device final : public DOMEventTargetHelper, public SupportsWeakPtr {
|
|||
RefPtr<SupportedFeatures> mFeatures;
|
||||
RefPtr<SupportedLimits> mLimits;
|
||||
|
||||
explicit Device(Adapter* const aParent, RawId aId,
|
||||
UniquePtr<ffi::WGPULimits> aRawLimits);
|
||||
explicit Device(Adapter* const aParent, RawId aId, const ffi::WGPULimits&);
|
||||
|
||||
RefPtr<WebGPUChild> GetBridge();
|
||||
already_AddRefed<Texture> InitSwapChain(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,6 +9,15 @@
|
|||
#include "nsWrapperCache.h"
|
||||
#include "ObjectModel.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
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<Adapter> {
|
|||
|
||||
explicit SupportedFeatures(Adapter* const aParent);
|
||||
|
||||
void Add(dom::GPUFeatureName, ErrorResult&);
|
||||
const auto& Features() const { return mFeatures; }
|
||||
|
||||
private:
|
||||
~SupportedFeatures() = default;
|
||||
void Cleanup() {}
|
||||
|
||||
std::unordered_set<dom::GPUFeatureName> mFeatures;
|
||||
};
|
||||
|
||||
} // namespace mozilla::webgpu
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "SupportedLimits.h"
|
||||
#include "Adapter.h"
|
||||
#include "mozilla/dom/WebGPUBinding.h"
|
||||
#include "mozilla/webgpu/ffi/wgpu.h"
|
||||
|
||||
namespace mozilla::webgpu {
|
||||
|
||||
|
@ -14,88 +13,189 @@ GPU_IMPL_CYCLE_COLLECTION(SupportedLimits, mParent)
|
|||
GPU_IMPL_JS_WRAP(SupportedLimits)
|
||||
|
||||
SupportedLimits::SupportedLimits(Adapter* const aParent,
|
||||
UniquePtr<ffi::WGPULimits>&& aLimits)
|
||||
: ChildOf(aParent), mLimits(std::move(aLimits)) {}
|
||||
const ffi::WGPULimits& aLimits)
|
||||
: ChildOf(aParent), mFfi(std::make_unique<ffi::WGPULimits>(aLimits)) {}
|
||||
|
||||
SupportedLimits::~SupportedLimits() = default;
|
||||
|
||||
uint32_t SupportedLimits::MaxTextureDimension1D() const {
|
||||
return mLimits->max_texture_dimension_1d;
|
||||
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");
|
||||
}
|
||||
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;
|
||||
|
||||
void SetLimit(ffi::WGPULimits* const limits, const Limit limit,
|
||||
const double val) {
|
||||
const auto autoVal = LazyAssertedCast(static_cast<uint64_t>(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
|
||||
|
|
|
@ -9,47 +9,99 @@
|
|||
#include "nsWrapperCache.h"
|
||||
#include "ObjectModel.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mozilla::webgpu {
|
||||
namespace ffi {
|
||||
struct WGPULimits;
|
||||
}
|
||||
class Adapter;
|
||||
|
||||
class SupportedLimits final : public nsWrapperCache, public ChildOf<Adapter> {
|
||||
const UniquePtr<ffi::WGPULimits> mLimits;
|
||||
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<Adapter> {
|
||||
public:
|
||||
const std::unique_ptr<ffi::WGPULimits> mFfi;
|
||||
|
||||
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;
|
||||
#define _(X) \
|
||||
auto X() const { return GetLimit(*mFfi, Limit::X); }
|
||||
|
||||
SupportedLimits(Adapter* const aParent, UniquePtr<ffi::WGPULimits>&& aLimits);
|
||||
_(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();
|
||||
|
|
|
@ -274,96 +274,15 @@ RefPtr<AdapterPromise> WebGPUChild::InstanceRequestAdapter(
|
|||
}
|
||||
|
||||
Maybe<DeviceRequest> 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<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
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -62,9 +62,8 @@ class WebGPUChild final : public PWebGPUChild, public SupportsWeakPtr {
|
|||
|
||||
RefPtr<AdapterPromise> InstanceRequestAdapter(
|
||||
const dom::GPURequestAdapterOptions& aOptions);
|
||||
Maybe<DeviceRequest> AdapterRequestDevice(
|
||||
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc,
|
||||
ffi::WGPULimits* aLimits);
|
||||
Maybe<DeviceRequest> AdapterRequestDevice(RawId aSelfId,
|
||||
const ffi::WGPUDeviceDescriptor&);
|
||||
RawId DeviceCreateBuffer(RawId aSelfId, const dom::GPUBufferDescriptor& aDesc,
|
||||
ipc::UnsafeSharedMemoryHandle&& aShmem);
|
||||
RawId DeviceCreateTexture(RawId aSelfId,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -198,6 +198,32 @@ inline To ReleaseAssertedCast(const From aFrom) {
|
|||
return static_cast<To>(aFrom);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename From>
|
||||
class LazyAssertedCastT final {
|
||||
const From mVal;
|
||||
|
||||
public:
|
||||
explicit LazyAssertedCastT(const From val) : mVal(val) {}
|
||||
|
||||
template <typename To>
|
||||
operator To() const {
|
||||
return AssertedCast<To>(mVal);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Like AssertedCast, but infers |To| for AssertedCast lazily based on usage.
|
||||
* > uint8_t foo = LazyAssertedCast(1000); // boom
|
||||
*/
|
||||
template <typename From>
|
||||
inline auto LazyAssertedCast(const From val) {
|
||||
return detail::LazyAssertedCastT<From>(val);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_Casting_h */
|
||||
|
|
|
@ -197,6 +197,11 @@ constexpr detail::EnumeratedRange<EnumType> MakeInclusiveEnumeratedRange(
|
|||
return MakeEnumeratedRange(aBegin, static_cast<EnumType>(end + 1));
|
||||
}
|
||||
|
||||
template <typename EnumType>
|
||||
constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) {
|
||||
return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче