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:
Kelsey Gilbert 2023-06-12 21:10:11 +00:00
Родитель 08e73e0c07
Коммит 0fb34553d5
15 изменённых файлов: 672 добавлений и 272 удалений

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

@ -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