Diff
Modified: trunk/Source/WebGPU/ChangeLog (293097 => 293098)
--- trunk/Source/WebGPU/ChangeLog 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/ChangeLog 2022-04-20 16:10:11 UTC (rev 293098)
@@ -1,5 +1,73 @@
2022-04-20 Myles C. Maxfield <[email protected]>
+ [WebGPU] Expand hardware capabilities to include features (beyond just limits)
+ https://bugs.webkit.org/show_bug.cgi?id=239443
+
+ Reviewed by Kimmo Kinnunen.
+
+ Only MTLGPUFamilyApple devices support depth/stencil textures in the managed/shared address space.
+ So, we have to expand the hardware capabilities infrastructure to be able to hold this kind
+ of information (so the texture creation function can consult with this state to know what storage
+ mode to use for the created texture). This patch replaces the stored WGPULimits struct with a new
+ struct, HardwareCapabilities, which holds a WGPULimits iniside it.
+
+ While I was here, I also included a Vector<WGPUFeature> inside the HardwareCapabilities struct,
+ and hooked it up to the various places which need to be guarded by the presence of features.
+ This is needed for compressed textures to work (among other things). Because there are only
+ a handful of possible features, I elected to use a sorted Vector instead of using the big HashSet
+ hammer.
+
+ * WebGPU.xcodeproj/project.pbxproj:
+ * WebGPU/Adapter.h:
+ (WebGPU::Adapter::create):
+ * WebGPU/Adapter.mm:
+ (WebGPU::Adapter::Adapter):
+ (WebGPU::Adapter::enumerateFeatures):
+ (WebGPU::Adapter::getLimits):
+ (WebGPU::Adapter::hasFeature):
+ (WebGPU::Adapter::requestDevice):
+ * WebGPU/Device.h:
+ (WebGPU::Device::limits const):
+ (WebGPU::Device::features const):
+ (WebGPU::Device::baseCapabilities const):
+ * WebGPU/Device.mm:
+ (WebGPU::Device::create):
+ (WebGPU::Device::Device):
+ (WebGPU::Device::enumerateFeatures):
+ (WebGPU::Device::getLimits):
+ (WebGPU::Device::hasFeature):
+ * WebGPU/HardwareCapabilities.h: Renamed from Source/WebGPU/WebGPU/HardwareLimits.h.
+ * WebGPU/HardwareCapabilities.mm: Added.
+ (WebGPU::baseCapabilities):
+ (WebGPU::baseFeatures):
+ (WebGPU::apple3):
+ (WebGPU::apple4):
+ (WebGPU::apple5):
+ (WebGPU::apple6):
+ (WebGPU::apple7):
+ (WebGPU::mac2):
+ (WebGPU::mergeMaximum):
+ (WebGPU::mergeAlignment):
+ (WebGPU::mergeLimits):
+ (WebGPU::mergeFeatures):
+ (WebGPU::mergeBaseCapabilities):
+ (WebGPU::rawHardwareCapabilities):
+ (WebGPU::anyLimitIsBetterThan):
+ (WebGPU::includesUnsupportedFeatures):
+ (WebGPU::checkLimits):
+ (WebGPU::hardwareCapabilities):
+ (WebGPU::isValid):
+ * WebGPU/HardwareLimits.mm: Removed.
+ * WebGPU/Instance.mm:
+ (WebGPU::Instance::requestAdapter):
+ * WebGPU/Texture.mm:
+ (WebGPU::featureRequirementForFormat):
+ (WebGPU::Device::validateCreateTexture):
+ (WebGPU::storageMode):
+ (WebGPU::Device::createTexture):
+
+2022-04-20 Myles C. Maxfield <[email protected]>
+
[WebGPU] RGB9E5Ufloat textures are not renderable
https://bugs.webkit.org/show_bug.cgi?id=239445
Modified: trunk/Source/WebGPU/WebGPU/Adapter.h (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Adapter.h 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Adapter.h 2022-04-20 16:10:11 UTC (rev 293098)
@@ -25,6 +25,7 @@
#pragma once
+#import "HardwareCapabilities.h"
#import <wtf/CompletionHandler.h>
#import <wtf/FastMalloc.h>
#import <wtf/Ref.h>
@@ -42,9 +43,9 @@
class Adapter : public WGPUAdapterImpl, public RefCounted<Adapter> {
WTF_MAKE_FAST_ALLOCATED;
public:
- static Ref<Adapter> create(id<MTLDevice> device, Instance& instance, const WGPULimits& limits)
+ static Ref<Adapter> create(id<MTLDevice> device, Instance& instance, HardwareCapabilities&& capabilities)
{
- return adoptRef(*new Adapter(device, instance, limits));
+ return adoptRef(*new Adapter(device, instance, WTFMove(capabilities)));
}
static Ref<Adapter> createInvalid(Instance& instance)
{
@@ -67,13 +68,13 @@
private:
- Adapter(id<MTLDevice>, Instance&, const WGPULimits&);
+ Adapter(id<MTLDevice>, Instance&, HardwareCapabilities&&);
Adapter(Instance&);
id<MTLDevice> m_device { nil };
const Ref<Instance> m_instance;
- WGPULimits m_limits { };
+ HardwareCapabilities m_capabilities { };
};
} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU/Adapter.mm (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Adapter.mm 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Adapter.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -28,16 +28,16 @@
#import "APIConversions.h"
#import "Device.h"
-#import "HardwareLimits.h"
#import "Instance.h"
+#import <algorithm>
#import <wtf/StdLibExtras.h>
namespace WebGPU {
-Adapter::Adapter(id<MTLDevice> device, Instance& instance, const WGPULimits& limits)
+Adapter::Adapter(id<MTLDevice> device, Instance& instance, HardwareCapabilities&& capabilities)
: m_device(device)
, m_instance(instance)
- , m_limits(limits)
+ , m_capabilities(WTFMove(capabilities))
{
}
@@ -48,10 +48,13 @@
Adapter::~Adapter() = default;
-size_t Adapter::enumerateFeatures(WGPUFeatureName*)
+size_t Adapter::enumerateFeatures(WGPUFeatureName* features)
{
- // We support no optional features right now.
- return 0;
+ // The API contract for this requires that sufficient space has already been allocated for the output.
+ // This requires the caller calling us twice: once to get the amount of space to allocate, and once to fill the space.
+ if (features)
+ std::copy(m_capabilities.features.begin(), m_capabilities.features.end(), features);
+ return m_capabilities.features.size();
}
bool Adapter::getLimits(WGPUSupportedLimits& limits)
@@ -59,8 +62,7 @@
if (limits.nextInChain != nullptr)
return false;
- // FIXME: Implement this.
- limits.limits = { };
+ limits.limits = m_capabilities.limits;
return true;
}
@@ -75,10 +77,9 @@
properties.backendType = WGPUBackendType_Metal;
}
-bool Adapter::hasFeature(WGPUFeatureName)
+bool Adapter::hasFeature(WGPUFeatureName feature)
{
- // We support no optional features right now.
- return false;
+ return std::find(m_capabilities.features.begin(), m_capabilities.features.end(), feature);
}
void Adapter::requestDevice(const WGPUDeviceDescriptor& descriptor, CompletionHandler<void(WGPURequestDeviceStatus, Ref<Device>&&, String&&)>&& callback)
@@ -97,7 +98,7 @@
return;
}
- auto limits = m_limits;
+ WGPULimits limits { };
if (descriptor.requiredLimits) {
if (descriptor.requiredLimits->nextInChain) {
@@ -114,7 +115,7 @@
return;
}
- if (anyLimitIsBetterThan(descriptor.requiredLimits->limits, m_limits)) {
+ if (anyLimitIsBetterThan(descriptor.requiredLimits->limits, m_capabilities.limits)) {
instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Device does not support requested limits"_s);
});
@@ -122,11 +123,26 @@
}
limits = descriptor.requiredLimits->limits;
+ } else
+ limits = defaultLimits();
+
+ auto features = Vector { descriptor.requiredFeatures, descriptor.requiredFeaturesCount };
+ if (includesUnsupportedFeatures(features, m_capabilities.features)) {
+ instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Device does not support requested features"_s);
+ });
+ return;
}
+ HardwareCapabilities capabilities {
+ limits,
+ WTFMove(features),
+ m_capabilities.baseCapabilities,
+ };
+
auto label = fromAPI(descriptor.label);
- instance().scheduleWork([strongThis = Ref { *this }, label = WTFMove(label), limits = WTFMove(limits), callback = WTFMove(callback)]() mutable {
- callback(WGPURequestDeviceStatus_Success, Device::create(strongThis->m_device, WTFMove(label), WTFMove(limits), strongThis), { });
+ instance().scheduleWork([strongThis = Ref { *this }, label = WTFMove(label), capabilities = WTFMove(capabilities), callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestDeviceStatus_Success, Device::create(strongThis->m_device, WTFMove(label), WTFMove(capabilities), strongThis), { });
});
}
Modified: trunk/Source/WebGPU/WebGPU/Device.h (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Device.h 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Device.h 2022-04-20 16:10:11 UTC (rev 293098)
@@ -26,6 +26,7 @@
#pragma once
#import "Adapter.h"
+#import "HardwareCapabilities.h"
#import "Queue.h"
#import <wtf/CompletionHandler.h>
#import <wtf/FastMalloc.h>
@@ -61,7 +62,7 @@
class Device : public WGPUDeviceImpl, public ThreadSafeRefCounted<Device>, public CanMakeWeakPtr<Device> {
WTF_MAKE_FAST_ALLOCATED;
public:
- static Ref<Device> create(id<MTLDevice>, String&& deviceLabel, const WGPULimits&, Adapter&);
+ static Ref<Device> create(id<MTLDevice>, String&& deviceLabel, HardwareCapabilities&&, Adapter&);
static Ref<Device> createInvalid(Adapter& adapter)
{
return adoptRef(*new Device(adapter));
@@ -97,6 +98,9 @@
bool isValid() const { return m_device; }
bool isLost() const { return m_isLost; }
+ const WGPULimits& limits() const { return m_capabilities.limits; }
+ const Vector<WGPUFeatureName>& features() const { return m_capabilities.features; }
+ const HardwareCapabilities::BaseCapabilities& baseCapabilities() const { return m_capabilities.baseCapabilities; }
id<MTLDevice> device() const { return m_device; }
@@ -106,7 +110,7 @@
bool hasUnifiedMemory() const { return m_device.hasUnifiedMemory; }
private:
- Device(id<MTLDevice>, id<MTLCommandQueue> defaultQueue, const WGPULimits&, Adapter&);
+ Device(id<MTLDevice>, id<MTLCommandQueue> defaultQueue, HardwareCapabilities&&, Adapter&);
Device(Adapter&);
struct ErrorScope;
@@ -138,7 +142,7 @@
bool m_isLost { false };
id<NSObject> m_deviceObserver { nil };
- WGPULimits m_limits { };
+ HardwareCapabilities m_capabilities { };
const Ref<Adapter> m_adapter;
};
Modified: trunk/Source/WebGPU/WebGPU/Device.mm (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Device.mm 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Device.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -42,12 +42,13 @@
#import "Surface.h"
#import "SwapChain.h"
#import "Texture.h"
+#import <algorithm>
#import <wtf/StdLibExtras.h>
#import <wtf/WeakPtr.h>
namespace WebGPU {
-Ref<Device> Device::create(id<MTLDevice> device, String&& deviceLabel, const WGPULimits& limits, Adapter& adapter)
+Ref<Device> Device::create(id<MTLDevice> device, String&& deviceLabel, HardwareCapabilities&& capabilities, Adapter& adapter)
{
id<MTLCommandQueue> commandQueue = [device newCommandQueue];
if (!commandQueue)
@@ -59,13 +60,13 @@
if (!deviceLabel.isEmpty())
commandQueue.label = [NSString stringWithFormat:@"Default queue for device %s", deviceLabel.utf8().data()];
- return adoptRef(*new Device(device, commandQueue, limits, adapter));
+ return adoptRef(*new Device(device, commandQueue, WTFMove(capabilities), adapter));
}
-Device::Device(id<MTLDevice> device, id<MTLCommandQueue> defaultQueue, const WGPULimits& limits, Adapter& adapter)
+Device::Device(id<MTLDevice> device, id<MTLCommandQueue> defaultQueue, HardwareCapabilities&& capabilities, Adapter& adapter)
: m_device(device)
, m_defaultQueue(Queue::create(defaultQueue, *this))
- , m_limits(limits)
+ , m_capabilities(WTFMove(capabilities))
, m_adapter(adapter)
{
#if PLATFORM(MAC)
@@ -137,10 +138,13 @@
loseTheDevice(WGPUDeviceLostReason_Destroyed);
}
-size_t Device::enumerateFeatures(WGPUFeatureName*)
+size_t Device::enumerateFeatures(WGPUFeatureName* features)
{
- // We support no optional features right now.
- return 0;
+ // The API contract for this requires that sufficient space has already been allocated for the output.
+ // This requires the caller calling us twice: once to get the amount of space to allocate, and once to fill the space.
+ if (features)
+ std::copy(m_capabilities.features.begin(), m_capabilities.features.end(), features);
+ return m_capabilities.features.size();
}
bool Device::getLimits(WGPUSupportedLimits& limits)
@@ -148,8 +152,7 @@
if (limits.nextInChain != nullptr)
return false;
- // FIXME: Implement this.
- limits.limits = { };
+ limits.limits = m_capabilities.limits;
return true;
}
@@ -158,10 +161,9 @@
return m_defaultQueue;
}
-bool Device::hasFeature(WGPUFeatureName)
+bool Device::hasFeature(WGPUFeatureName feature)
{
- // We support no optional features right now.
- return false;
+ return std::find(m_capabilities.features.begin(), m_capabilities.features.end(), feature);
}
auto Device::currentErrorScope(WGPUErrorFilter type) -> ErrorScope*
Copied: trunk/Source/WebGPU/WebGPU/HardwareCapabilities.h (from rev 293096, trunk/Source/WebGPU/WebGPU/HardwareLimits.h) (0 => 293098)
--- trunk/Source/WebGPU/WebGPU/HardwareCapabilities.h (rev 0)
+++ trunk/Source/WebGPU/WebGPU/HardwareCapabilities.h 2022-04-20 16:10:11 UTC (rev 293098)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <optional>
+#include <wtf/Vector.h>
+
+namespace WebGPU {
+
+struct HardwareCapabilities {
+ WGPULimits limits { };
+ Vector<WGPUFeatureName> features;
+
+ struct BaseCapabilities {
+ MTLArgumentBuffersTier argumentBuffersTier { MTLArgumentBuffersTier1 };
+ bool supportsNonPrivateDepthStencilTextures { false };
+ id<MTLCounterSet> timestampCounterSet { nil };
+ id<MTLCounterSet> statisticCounterSet { nil };
+ } baseCapabilities;
+};
+
+std::optional<HardwareCapabilities> hardwareCapabilities(id<MTLDevice>);
+bool isValid(const WGPULimits&);
+WGPULimits defaultLimits();
+bool anyLimitIsBetterThan(const WGPULimits& target, const WGPULimits& reference);
+bool includesUnsupportedFeatures(const Vector<WGPUFeatureName>& target, const Vector<WGPUFeatureName>& reference);
+
+} // namespace WebGPU
Added: trunk/Source/WebGPU/WebGPU/HardwareCapabilities.mm (0 => 293098)
--- trunk/Source/WebGPU/WebGPU/HardwareCapabilities.mm (rev 0)
+++ trunk/Source/WebGPU/WebGPU/HardwareCapabilities.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "HardwareCapabilities.h"
+
+#import <algorithm>
+#import <limits>
+#import <wtf/MathExtras.h>
+#import <wtf/PageBlock.h>
+#import <wtf/StdLibExtras.h>
+
+namespace WebGPU {
+
+// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
+
+// FIXME: https://github.com/gpuweb/gpuweb/issues/2749 we need more limits.
+
+static HardwareCapabilities::BaseCapabilities baseCapabilities(id<MTLDevice> device)
+{
+ id<MTLCounterSet> timestampCounterSet = nil;
+ id<MTLCounterSet> statisticCounterSet = nil;
+
+ for (id<MTLCounterSet> counterSet in device.counterSets) {
+ if ([counterSet.name isEqualToString:MTLCommonCounterSetTimestamp])
+ timestampCounterSet = counterSet;
+ else if ([counterSet.name isEqualToString:MTLCommonCounterSetStatistic])
+ statisticCounterSet = counterSet;
+ }
+
+ return {
+ [device argumentBuffersSupport],
+ false, // To be filled in by the caller.
+ timestampCounterSet,
+ statisticCounterSet,
+ };
+}
+
+static Vector<WGPUFeatureName> baseFeatures(id<MTLDevice> device, const HardwareCapabilities::BaseCapabilities& baseCapabilities)
+{
+ Vector<WGPUFeatureName> features;
+
+ // FIXME: Determine if WGPUFeatureName_DepthClipControl is supported.
+
+#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
+ if (device.depth24Stencil8PixelFormatSupported)
+ features.append(WGPUFeatureName_Depth24UnormStencil8);
+#else
+ UNUSED_PARAM(device);
+#endif
+
+ features.append(WGPUFeatureName_Depth32FloatStencil8);
+
+ if (baseCapabilities.timestampCounterSet)
+ features.append(WGPUFeatureName_TimestampQuery);
+
+ if (baseCapabilities.statisticCounterSet)
+ features.append(WGPUFeatureName_PipelineStatisticsQuery);
+
+#if PLATFORM(MAC)
+ if (device.supportsBCTextureCompression)
+ features.append(WGPUFeatureName_TextureCompressionBC);
+#endif
+
+ // WGPUFeatureName_TextureCompressionETC2 and WGPUFeatureName_TextureCompressionASTC are to be filled in by the caller.
+
+ // FIXME: Determine if WGPUFeatureName_IndirectFirstInstance is supported.
+
+ return features;
+}
+
+static HardwareCapabilities apple3(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = true;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ features.append(WGPUFeatureName_TextureCompressionETC2);
+ features.append(WGPUFeatureName_TextureCompressionASTC);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * 31,
+ /* maxSamplersPerShaderStage */ maxBindGroups * 16,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * 31,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * 31,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * 31,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 4,
+ /* minStorageBufferOffsetAlignment */ 4,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 60,
+ /* maxComputeWorkgroupStorageSize */ 16 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 512,
+ /* maxComputeWorkgroupSizeX */ 512,
+ /* maxComputeWorkgroupSizeY */ 512,
+ /* maxComputeWorkgroupSizeZ */ 512,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+
+static HardwareCapabilities apple4(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = true;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ features.append(WGPUFeatureName_TextureCompressionETC2);
+ features.append(WGPUFeatureName_TextureCompressionASTC);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * 96,
+ /* maxSamplersPerShaderStage */ maxBindGroups * 16,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * 96,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * 96,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * 96,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 4,
+ /* minStorageBufferOffsetAlignment */ 4,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 124,
+ /* maxComputeWorkgroupStorageSize */ 32 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 1024,
+ /* maxComputeWorkgroupSizeX */ 1024,
+ /* maxComputeWorkgroupSizeY */ 1024,
+ /* maxComputeWorkgroupSizeZ */ 1024,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+
+static HardwareCapabilities apple5(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = true;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ features.append(WGPUFeatureName_TextureCompressionETC2);
+ features.append(WGPUFeatureName_TextureCompressionASTC);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * 96,
+ /* maxSamplersPerShaderStage */ maxBindGroups * 16,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * 96,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * 96,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * 96,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 4,
+ /* minStorageBufferOffsetAlignment */ 4,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 124,
+ /* maxComputeWorkgroupStorageSize */ 32 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 1024,
+ /* maxComputeWorkgroupSizeX */ 1024,
+ /* maxComputeWorkgroupSizeY */ 1024,
+ /* maxComputeWorkgroupSizeZ */ 1024,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+
+#if !PLATFORM(WATCHOS)
+static HardwareCapabilities apple6(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = true;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ features.append(WGPUFeatureName_TextureCompressionETC2);
+ features.append(WGPUFeatureName_TextureCompressionASTC);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxSamplersPerShaderStage */ maxBindGroups * 1024,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 4,
+ /* minStorageBufferOffsetAlignment */ 4,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 124,
+ /* maxComputeWorkgroupStorageSize */ 32 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 1024,
+ /* maxComputeWorkgroupSizeX */ 1024,
+ /* maxComputeWorkgroupSizeY */ 1024,
+ /* maxComputeWorkgroupSizeZ */ 1024,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+
+static HardwareCapabilities apple7(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = true;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ features.append(WGPUFeatureName_TextureCompressionETC2);
+ features.append(WGPUFeatureName_TextureCompressionASTC);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxSamplersPerShaderStage */ maxBindGroups * 1024,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 4,
+ /* minStorageBufferOffsetAlignment */ 4,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 124,
+ /* maxComputeWorkgroupStorageSize */ 32 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 1024,
+ /* maxComputeWorkgroupSizeX */ 1024,
+ /* maxComputeWorkgroupSizeY */ 1024,
+ /* maxComputeWorkgroupSizeZ */ 1024,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+#endif
+
+static HardwareCapabilities mac2(id<MTLDevice> device)
+{
+ auto baseCapabilities = WebGPU::baseCapabilities(device);
+
+ baseCapabilities.supportsNonPrivateDepthStencilTextures = false;
+
+ auto features = WebGPU::baseFeatures(device, baseCapabilities);
+
+ std::sort(features.begin(), features.end());
+
+ uint32_t buffersPerBindGroup = 0;
+ uint32_t texturesPerBindGroup = 0;
+ uint32_t samplersPerBindGroup = 0;
+ switch (baseCapabilities.argumentBuffersTier) {
+ case MTLArgumentBuffersTier1:
+ buffersPerBindGroup = 64;
+ texturesPerBindGroup = 128;
+ samplersPerBindGroup = 16;
+ break;
+ case MTLArgumentBuffersTier2:
+ buffersPerBindGroup = 500000 / 2;
+ texturesPerBindGroup = 500000 / 2;
+ samplersPerBindGroup = 1024;
+ break;
+ }
+
+ uint32_t maxBindGroups = 30;
+
+ return {
+ {
+ /* maxTextureDimension1D */ 16384,
+ /* maxTextureDimension2D */ 16384,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 2048,
+ /* maxBindGroups */ maxBindGroups,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
+ /* maxSampledTexturesPerShaderStage */ maxBindGroups * texturesPerBindGroup,
+ /* maxSamplersPerShaderStage */ maxBindGroups * samplersPerBindGroup,
+ /* maxStorageBuffersPerShaderStage */ maxBindGroups * buffersPerBindGroup,
+ /* maxStorageTexturesPerShaderStage */ maxBindGroups * texturesPerBindGroup,
+ /* maxUniformBuffersPerShaderStage */ maxBindGroups * buffersPerBindGroup,
+ /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
+ /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
+ /* minUniformBufferOffsetAlignment */ 256,
+ /* minStorageBufferOffsetAlignment */ 256,
+ /* maxVertexBuffers */ 30,
+ /* maxVertexAttributes */ 31,
+ /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
+ /* maxInterStageShaderComponents */ 32,
+ /* maxComputeWorkgroupStorageSize */ 32 * KB,
+ /* maxComputeInvocationsPerWorkgroup */ 1024,
+ /* maxComputeWorkgroupSizeX */ 1024,
+ /* maxComputeWorkgroupSizeY */ 1024,
+ /* maxComputeWorkgroupSizeZ */ 1024,
+ /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
+ },
+ WTFMove(features),
+ baseCapabilities,
+ };
+}
+
+template <typename T>
+static T mergeMaximum(T previous, T next)
+{
+ // https://gpuweb.github.io/gpuweb/#limit-class-maximum
+ return std::max(previous, next);
+};
+
+template <typename T>
+static T mergeAlignment(T previous, T next)
+{
+ // https://gpuweb.github.io/gpuweb/#limit-class-alignment
+ return std::min(WTF::roundUpToPowerOfTwo(previous), WTF::roundUpToPowerOfTwo(next));
+};
+
+static WGPULimits mergeLimits(const WGPULimits& previous, const WGPULimits& next)
+{
+ return {
+ mergeMaximum(previous.maxTextureDimension1D, next.maxTextureDimension1D),
+ mergeMaximum(previous.maxTextureDimension2D, next.maxTextureDimension2D),
+ mergeMaximum(previous.maxTextureDimension3D, next.maxTextureDimension3D),
+ mergeMaximum(previous.maxTextureArrayLayers, next.maxTextureArrayLayers),
+ mergeMaximum(previous.maxBindGroups, next.maxBindGroups),
+ mergeMaximum(previous.maxDynamicUniformBuffersPerPipelineLayout, next.maxDynamicUniformBuffersPerPipelineLayout),
+ mergeMaximum(previous.maxDynamicStorageBuffersPerPipelineLayout, next.maxDynamicStorageBuffersPerPipelineLayout),
+ mergeMaximum(previous.maxSampledTexturesPerShaderStage, next.maxSampledTexturesPerShaderStage),
+ mergeMaximum(previous.maxSamplersPerShaderStage, next.maxSamplersPerShaderStage),
+ mergeMaximum(previous.maxStorageBuffersPerShaderStage, next.maxStorageBuffersPerShaderStage),
+ mergeMaximum(previous.maxStorageTexturesPerShaderStage, next.maxStorageTexturesPerShaderStage),
+ mergeMaximum(previous.maxUniformBuffersPerShaderStage, next.maxUniformBuffersPerShaderStage),
+ mergeMaximum(previous.maxUniformBufferBindingSize, next.maxUniformBufferBindingSize),
+ mergeMaximum(previous.maxStorageBufferBindingSize, next.maxStorageBufferBindingSize),
+ mergeAlignment(previous.minUniformBufferOffsetAlignment, next.minUniformBufferOffsetAlignment),
+ mergeAlignment(previous.minStorageBufferOffsetAlignment, next.minStorageBufferOffsetAlignment),
+ mergeMaximum(previous.maxVertexBuffers, next.maxVertexBuffers),
+ mergeMaximum(previous.maxVertexAttributes, next.maxVertexAttributes),
+ mergeMaximum(previous.maxVertexBufferArrayStride, next.maxVertexBufferArrayStride),
+ mergeMaximum(previous.maxInterStageShaderComponents, next.maxInterStageShaderComponents),
+ mergeMaximum(previous.maxComputeWorkgroupStorageSize, next.maxComputeWorkgroupStorageSize),
+ mergeMaximum(previous.maxComputeInvocationsPerWorkgroup, next.maxComputeInvocationsPerWorkgroup),
+ mergeMaximum(previous.maxComputeWorkgroupSizeX, next.maxComputeWorkgroupSizeX),
+ mergeMaximum(previous.maxComputeWorkgroupSizeY, next.maxComputeWorkgroupSizeY),
+ mergeMaximum(previous.maxComputeWorkgroupSizeZ, next.maxComputeWorkgroupSizeZ),
+ mergeMaximum(previous.maxComputeWorkgroupsPerDimension, next.maxComputeWorkgroupsPerDimension),
+ };
+};
+
+static Vector<WGPUFeatureName> mergeFeatures(const Vector<WGPUFeatureName>& previous, const Vector<WGPUFeatureName>& next)
+{
+ ASSERT(WTF::isSortedConstExpr(previous.begin(), previous.end()));
+ ASSERT(WTF::isSortedConstExpr(next.begin(), next.end()));
+
+ Vector<WGPUFeatureName> result(previous.size() + next.size());
+ auto end = mergeDeduplicatedSorted(previous.begin(), previous.end(), next.begin(), next.end(), result.begin());
+ result.resize(end - result.begin());
+ return result;
+}
+
+static HardwareCapabilities::BaseCapabilities mergeBaseCapabilities(const HardwareCapabilities::BaseCapabilities& previous, const HardwareCapabilities::BaseCapabilities& next)
+{
+ ASSERT(previous.argumentBuffersTier == next.argumentBuffersTier);
+ ASSERT(!previous.timestampCounterSet || [previous.timestampCounterSet isEqual:next.timestampCounterSet]);
+ ASSERT(!previous.statisticCounterSet || [previous.statisticCounterSet isEqual:next.statisticCounterSet]);
+ return {
+ previous.argumentBuffersTier,
+ previous.supportsNonPrivateDepthStencilTextures || next.supportsNonPrivateDepthStencilTextures,
+ previous.timestampCounterSet,
+ previous.statisticCounterSet,
+ };
+}
+
+static std::optional<HardwareCapabilities> rawHardwareCapabilities(id<MTLDevice> device)
+{
+ std::optional<HardwareCapabilities> result;
+
+ auto merge = [&](const HardwareCapabilities& capabilities) {
+ if (!result) {
+ result = capabilities;
+ return;
+ }
+
+ result->limits = mergeLimits(result->limits, capabilities.limits);
+ result->features = mergeFeatures(result->features, capabilities.features);
+ result->baseCapabilities = mergeBaseCapabilities(result->baseCapabilities, capabilities.baseCapabilities);
+ };
+
+ // The feature set tables do not list limits for MTLGPUFamilyCommon1, MTLGPUFamilyCommon2, or MTLGPUFamilyCommon3.
+ // MTLGPUFamilyApple1 and MTLGPUFamilyApple2 are not supported.
+ if ([device supportsFamily:MTLGPUFamilyApple3])
+ merge(apple3(device));
+ if ([device supportsFamily:MTLGPUFamilyApple4])
+ merge(apple4(device));
+ if ([device supportsFamily:MTLGPUFamilyApple5])
+ merge(apple5(device));
+#if !PLATFORM(WATCHOS)
+ if ([device supportsFamily:MTLGPUFamilyApple6])
+ merge(apple6(device));
+ if ([device supportsFamily:MTLGPUFamilyApple7])
+ merge(apple7(device));
+#endif
+ // MTLGPUFamilyMac1 is not supported (yet?).
+ if ([device supportsFamily:MTLGPUFamilyMac2])
+ merge(mac2(device));
+
+ if (result) {
+ auto maxBufferLength = device.maxBufferLength;
+ result->limits.maxUniformBufferBindingSize = maxBufferLength;
+ result->limits.maxStorageBufferBindingSize = maxBufferLength;
+ }
+
+ return result;
+}
+
+bool anyLimitIsBetterThan(const WGPULimits& target, const WGPULimits& reference)
+{
+ if (target.maxTextureDimension1D > reference.maxTextureDimension1D)
+ return true;
+ if (target.maxTextureDimension2D > reference.maxTextureDimension2D)
+ return true;
+ if (target.maxTextureDimension3D > reference.maxTextureDimension3D)
+ return true;
+ if (target.maxTextureArrayLayers > reference.maxTextureArrayLayers)
+ return true;
+ if (target.maxBindGroups > reference.maxBindGroups)
+ return true;
+ if (target.maxDynamicUniformBuffersPerPipelineLayout > reference.maxDynamicUniformBuffersPerPipelineLayout)
+ return true;
+ if (target.maxDynamicStorageBuffersPerPipelineLayout > reference.maxDynamicStorageBuffersPerPipelineLayout)
+ return true;
+ if (target.maxSampledTexturesPerShaderStage > reference.maxSampledTexturesPerShaderStage)
+ return true;
+ if (target.maxSamplersPerShaderStage > reference.maxSamplersPerShaderStage)
+ return true;
+ if (target.maxStorageBuffersPerShaderStage > reference.maxStorageBuffersPerShaderStage)
+ return true;
+ if (target.maxStorageTexturesPerShaderStage > reference.maxStorageTexturesPerShaderStage)
+ return true;
+ if (target.maxUniformBuffersPerShaderStage > reference.maxUniformBuffersPerShaderStage)
+ return true;
+ if (target.maxUniformBufferBindingSize > reference.maxUniformBufferBindingSize)
+ return true;
+ if (target.maxStorageBufferBindingSize > reference.maxStorageBufferBindingSize)
+ return true;
+ if (target.minUniformBufferOffsetAlignment < reference.minUniformBufferOffsetAlignment)
+ return true;
+ if (target.minStorageBufferOffsetAlignment < reference.minStorageBufferOffsetAlignment)
+ return true;
+ if (target.maxVertexBuffers > reference.maxVertexBuffers)
+ return true;
+ if (target.maxVertexAttributes > reference.maxVertexAttributes)
+ return true;
+ if (target.maxVertexBufferArrayStride > reference.maxVertexBufferArrayStride)
+ return true;
+ if (target.maxInterStageShaderComponents > reference.maxInterStageShaderComponents)
+ return true;
+ if (target.maxComputeWorkgroupStorageSize > reference.maxComputeWorkgroupStorageSize)
+ return true;
+ if (target.maxComputeInvocationsPerWorkgroup > reference.maxComputeInvocationsPerWorkgroup)
+ return true;
+ if (target.maxComputeWorkgroupSizeX > reference.maxComputeWorkgroupSizeX)
+ return true;
+ if (target.maxComputeWorkgroupSizeY > reference.maxComputeWorkgroupSizeY)
+ return true;
+ if (target.maxComputeWorkgroupSizeZ > reference.maxComputeWorkgroupSizeZ)
+ return true;
+ if (target.maxComputeWorkgroupsPerDimension > reference.maxComputeWorkgroupsPerDimension)
+ return true;
+
+ return false;
+}
+
+bool includesUnsupportedFeatures(const Vector<WGPUFeatureName>& target, const Vector<WGPUFeatureName>& reference)
+{
+ ASSERT(WTF::isSortedConstExpr(target.begin(), target.end()));
+ ASSERT(WTF::isSortedConstExpr(reference.begin(), reference.end()));
+ for (auto feature : target) {
+ if (!std::find(reference.begin(), reference.end(), feature))
+ return true;
+ }
+ return false;
+}
+
+WGPULimits defaultLimits()
+{
+ // https://gpuweb.github.io/gpuweb/#limit-default
+
+ return {
+ /* maxTextureDimension1D */ 8192,
+ /* maxTextureDimension2D */ 8192,
+ /* maxTextureDimension3D */ 2048,
+ /* maxTextureArrayLayers */ 256,
+ /* maxBindGroups */ 4,
+ /* maxDynamicUniformBuffersPerPipelineLayout */ 8,
+ /* maxDynamicStorageBuffersPerPipelineLayout */ 4,
+ /* maxSampledTexturesPerShaderStage */ 16,
+ /* maxSamplersPerShaderStage */ 16,
+ /* maxStorageBuffersPerShaderStage */ 8,
+ /* maxStorageTexturesPerShaderStage */ 4,
+ /* maxUniformBuffersPerShaderStage */ 12,
+ /* maxUniformBufferBindingSize */ 65536,
+ /* maxStorageBufferBindingSize */ 134217728,
+ /* minUniformBufferOffsetAlignment */ 256,
+ /* minStorageBufferOffsetAlignment */ 256,
+ /* maxVertexBuffers */ 8,
+ /* maxVertexAttributes */ 16,
+ /* maxVertexBufferArrayStride */ 2048,
+ /* maxInterStageShaderComponents */ 32,
+ /* maxComputeWorkgroupStorageSize */ 16352,
+ /* maxComputeInvocationsPerWorkgroup */ 256,
+ /* maxComputeWorkgroupSizeX */ 256,
+ /* maxComputeWorkgroupSizeY */ 256,
+ /* maxComputeWorkgroupSizeZ */ 64,
+ /* maxComputeWorkgroupsPerDimension */ 65535,
+ };
+}
+
+std::optional<HardwareCapabilities> hardwareCapabilities(id<MTLDevice> device)
+{
+ auto result = rawHardwareCapabilities(device);
+
+ if (!result)
+ return std::nullopt;
+
+ if (anyLimitIsBetterThan(defaultLimits(), result->limits))
+ return std::nullopt;
+
+ return result;
+}
+
+bool isValid(const WGPULimits& limits)
+{
+ return isPowerOfTwo(limits.minUniformBufferOffsetAlignment) && isPowerOfTwo(limits.minStorageBufferOffsetAlignment);
+}
+
+} // namespace WebGPU
Deleted: trunk/Source/WebGPU/WebGPU/HardwareLimits.h (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/HardwareLimits.h 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/HardwareLimits.h 2022-04-20 16:10:11 UTC (rev 293098)
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2021-2022 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <optional>
-
-namespace WebGPU {
-
-std::optional<WGPULimits> limits(id<MTLDevice>);
-bool isValid(const WGPULimits&);
-bool anyLimitIsBetterThan(const WGPULimits& target, const WGPULimits& reference);
-
-} // namespace WebGPU
Deleted: trunk/Source/WebGPU/WebGPU/HardwareLimits.mm (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/HardwareLimits.mm 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/HardwareLimits.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -1,449 +0,0 @@
-/*
- * Copyright (c) 2022 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "config.h"
-#import "HardwareLimits.h"
-
-#import <algorithm>
-#import <limits>
-#import <wtf/MathExtras.h>
-#import <wtf/PageBlock.h>
-#import <wtf/StdLibExtras.h>
-
-namespace WebGPU {
-
-// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
-
-// FIXME: https://github.com/gpuweb/gpuweb/issues/2749 we need more limits.
-
-constexpr static WGPULimits apple3()
-{
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * 31,
- /* maxSamplersPerShaderStage */ maxBindGroups * 16,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * 31,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * 31,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * 31,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 4,
- /* minStorageBufferOffsetAlignment */ 4,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 60,
- /* maxComputeWorkgroupStorageSize */ 16 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 512,
- /* maxComputeWorkgroupSizeX */ 512,
- /* maxComputeWorkgroupSizeY */ 512,
- /* maxComputeWorkgroupSizeZ */ 512,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-
-constexpr static WGPULimits apple4()
-{
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * 96,
- /* maxSamplersPerShaderStage */ maxBindGroups * 16,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * 96,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * 96,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * 96,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 4,
- /* minStorageBufferOffsetAlignment */ 4,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 124,
- /* maxComputeWorkgroupStorageSize */ 32 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 1024,
- /* maxComputeWorkgroupSizeX */ 1024,
- /* maxComputeWorkgroupSizeY */ 1024,
- /* maxComputeWorkgroupSizeZ */ 1024,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-
-constexpr static WGPULimits apple5()
-{
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * 96,
- /* maxSamplersPerShaderStage */ maxBindGroups * 16,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * 96,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * 96,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * 96,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 4,
- /* minStorageBufferOffsetAlignment */ 4,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 124,
- /* maxComputeWorkgroupStorageSize */ 32 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 1024,
- /* maxComputeWorkgroupSizeX */ 1024,
- /* maxComputeWorkgroupSizeY */ 1024,
- /* maxComputeWorkgroupSizeZ */ 1024,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-
-#if !PLATFORM(WATCHOS)
-constexpr static WGPULimits apple6()
-{
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxSamplersPerShaderStage */ maxBindGroups * 1024,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 4,
- /* minStorageBufferOffsetAlignment */ 4,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 124,
- /* maxComputeWorkgroupStorageSize */ 32 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 1024,
- /* maxComputeWorkgroupSizeX */ 1024,
- /* maxComputeWorkgroupSizeY */ 1024,
- /* maxComputeWorkgroupSizeZ */ 1024,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-
-constexpr static WGPULimits apple7()
-{
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxSamplersPerShaderStage */ maxBindGroups * 1024,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * 500000 / 2,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 4,
- /* minStorageBufferOffsetAlignment */ 4,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 124,
- /* maxComputeWorkgroupStorageSize */ 32 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 1024,
- /* maxComputeWorkgroupSizeX */ 1024,
- /* maxComputeWorkgroupSizeY */ 1024,
- /* maxComputeWorkgroupSizeZ */ 1024,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-#endif
-
-static WGPULimits mac2(id<MTLDevice> device)
-{
- uint32_t buffersPerBindGroup = 0;
- uint32_t texturesPerBindGroup = 0;
- uint32_t samplersPerBindGroup = 0;
- switch ([device argumentBuffersSupport]) {
- case MTLArgumentBuffersTier1:
- buffersPerBindGroup = 64;
- texturesPerBindGroup = 128;
- samplersPerBindGroup = 16;
- break;
- case MTLArgumentBuffersTier2:
- buffersPerBindGroup = 500000 / 2;
- texturesPerBindGroup = 500000 / 2;
- samplersPerBindGroup = 1024;
- break;
- }
-
- uint32_t maxBindGroups = 30;
-
- return WGPULimits {
- /* maxTextureDimension1D */ 16384,
- /* maxTextureDimension2D */ 16384,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 2048,
- /* maxBindGroups */ maxBindGroups,
- /* maxDynamicUniformBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxDynamicStorageBuffersPerPipelineLayout */ std::numeric_limits<uint32_t>::max(),
- /* maxSampledTexturesPerShaderStage */ maxBindGroups * texturesPerBindGroup,
- /* maxSamplersPerShaderStage */ maxBindGroups * samplersPerBindGroup,
- /* maxStorageBuffersPerShaderStage */ maxBindGroups * buffersPerBindGroup,
- /* maxStorageTexturesPerShaderStage */ maxBindGroups * texturesPerBindGroup,
- /* maxUniformBuffersPerShaderStage */ maxBindGroups * buffersPerBindGroup,
- /* maxUniformBufferBindingSize */ 0, // To be filled in by the caller.
- /* maxStorageBufferBindingSize */ 0, // To be filled in by the caller.
- /* minUniformBufferOffsetAlignment */ 256,
- /* minStorageBufferOffsetAlignment */ 256,
- /* maxVertexBuffers */ 30,
- /* maxVertexAttributes */ 31,
- /* maxVertexBufferArrayStride */ std::numeric_limits<uint32_t>::max(),
- /* maxInterStageShaderComponents */ 32,
- /* maxComputeWorkgroupStorageSize */ 32 * KB,
- /* maxComputeInvocationsPerWorkgroup */ 1024,
- /* maxComputeWorkgroupSizeX */ 1024,
- /* maxComputeWorkgroupSizeY */ 1024,
- /* maxComputeWorkgroupSizeZ */ 1024,
- /* maxComputeWorkgroupsPerDimension */ std::numeric_limits<uint32_t>::max(),
- };
-}
-
-static std::optional<WGPULimits> rawLimits(id<MTLDevice> device)
-{
- std::optional<WGPULimits> result;
-
- auto merge = [&](const WGPULimits& limits) {
- if (!result) {
- result = limits;
- return;
- }
-
- // https://gpuweb.github.io/gpuweb/#limit-class-maximum
- auto mergeMaximum = [](auto previous, auto next) {
- return std::max(previous, next);
- };
-
- // https://gpuweb.github.io/gpuweb/#limit-class-alignment
- auto mergeAlignment = [](auto previous, auto next) {
- return std::min(WTF::roundUpToPowerOfTwo(previous), WTF::roundUpToPowerOfTwo(next));
- };
-
- result->maxTextureDimension1D = mergeMaximum(result->maxTextureDimension1D, limits.maxTextureDimension1D);
- result->maxTextureDimension2D = mergeMaximum(result->maxTextureDimension2D, limits.maxTextureDimension2D);
- result->maxTextureDimension3D = mergeMaximum(result->maxTextureDimension3D, limits.maxTextureDimension3D);
- result->maxTextureArrayLayers = mergeMaximum(result->maxTextureArrayLayers, limits.maxTextureArrayLayers);
- result->maxBindGroups = mergeMaximum(result->maxBindGroups, limits.maxBindGroups);
- result->maxDynamicUniformBuffersPerPipelineLayout = mergeMaximum(result->maxDynamicUniformBuffersPerPipelineLayout, limits.maxDynamicUniformBuffersPerPipelineLayout);
- result->maxDynamicStorageBuffersPerPipelineLayout = mergeMaximum(result->maxDynamicStorageBuffersPerPipelineLayout, limits.maxDynamicStorageBuffersPerPipelineLayout);
- result->maxSampledTexturesPerShaderStage = mergeMaximum(result->maxSampledTexturesPerShaderStage, limits.maxSampledTexturesPerShaderStage);
- result->maxSamplersPerShaderStage = mergeMaximum(result->maxSamplersPerShaderStage, limits.maxSamplersPerShaderStage);
- result->maxStorageBuffersPerShaderStage = mergeMaximum(result->maxStorageBuffersPerShaderStage, limits.maxStorageBuffersPerShaderStage);
- result->maxStorageTexturesPerShaderStage = mergeMaximum(result->maxStorageTexturesPerShaderStage, limits.maxStorageTexturesPerShaderStage);
- result->maxUniformBuffersPerShaderStage = mergeMaximum(result->maxUniformBuffersPerShaderStage, limits.maxUniformBuffersPerShaderStage);
- result->maxUniformBufferBindingSize = mergeMaximum(result->maxUniformBufferBindingSize, limits.maxUniformBufferBindingSize);
- result->maxStorageBufferBindingSize = mergeMaximum(result->maxStorageBufferBindingSize, limits.maxStorageBufferBindingSize);
- result->minUniformBufferOffsetAlignment = mergeAlignment(result->minUniformBufferOffsetAlignment, limits.minUniformBufferOffsetAlignment);
- result->minStorageBufferOffsetAlignment = mergeAlignment(result->minStorageBufferOffsetAlignment, limits.minStorageBufferOffsetAlignment);
- result->maxVertexBuffers = mergeMaximum(result->maxVertexBuffers, limits.maxVertexBuffers);
- result->maxVertexAttributes = mergeMaximum(result->maxVertexAttributes, limits.maxVertexAttributes);
- result->maxVertexBufferArrayStride = mergeMaximum(result->maxVertexBufferArrayStride, limits.maxVertexBufferArrayStride);
- result->maxInterStageShaderComponents = mergeMaximum(result->maxInterStageShaderComponents, limits.maxInterStageShaderComponents);
- result->maxComputeWorkgroupStorageSize = mergeMaximum(result->maxComputeWorkgroupStorageSize, limits.maxComputeWorkgroupStorageSize);
- result->maxComputeInvocationsPerWorkgroup = mergeMaximum(result->maxComputeInvocationsPerWorkgroup, limits.maxComputeInvocationsPerWorkgroup);
- result->maxComputeWorkgroupSizeX = mergeMaximum(result->maxComputeWorkgroupSizeX, limits.maxComputeWorkgroupSizeX);
- result->maxComputeWorkgroupSizeY = mergeMaximum(result->maxComputeWorkgroupSizeY, limits.maxComputeWorkgroupSizeY);
- result->maxComputeWorkgroupSizeZ = mergeMaximum(result->maxComputeWorkgroupSizeZ, limits.maxComputeWorkgroupSizeZ);
- result->maxComputeWorkgroupsPerDimension = mergeMaximum(result->maxComputeWorkgroupsPerDimension, limits.maxComputeWorkgroupsPerDimension);
- };
-
- // The feature set tables do not list limits for MTLGPUFamilyCommon1, MTLGPUFamilyCommon2, or MTLGPUFamilyCommon3.
- // MTLGPUFamilyApple1 and MTLGPUFamilyApple2 are not supported.
- if ([device supportsFamily:MTLGPUFamilyApple3])
- merge(apple3());
- if ([device supportsFamily:MTLGPUFamilyApple4])
- merge(apple4());
- if ([device supportsFamily:MTLGPUFamilyApple5])
- merge(apple5());
-#if !PLATFORM(WATCHOS)
- if ([device supportsFamily:MTLGPUFamilyApple6])
- merge(apple6());
- if ([device supportsFamily:MTLGPUFamilyApple7])
- merge(apple7());
-#endif
- // MTLGPUFamilyMac1 is not supported (yet?).
- if ([device supportsFamily:MTLGPUFamilyMac2])
- merge(mac2(device));
-
- if (result) {
- auto maxBufferLength = device.maxBufferLength;
- result->maxUniformBufferBindingSize = maxBufferLength;
- result->maxStorageBufferBindingSize = maxBufferLength;
- }
-
- return result;
-}
-
-static bool checkLimits(const WGPULimits& limits)
-{
- // https://gpuweb.github.io/gpuweb/#limit-default
- auto defaultLimits = WGPULimits {
- /* maxTextureDimension1D */ 8192,
- /* maxTextureDimension2D */ 8192,
- /* maxTextureDimension3D */ 2048,
- /* maxTextureArrayLayers */ 256,
- /* maxBindGroups */ 4,
- /* maxDynamicUniformBuffersPerPipelineLayout */ 8,
- /* maxDynamicStorageBuffersPerPipelineLayout */ 4,
- /* maxSampledTexturesPerShaderStage */ 16,
- /* maxSamplersPerShaderStage */ 16,
- /* maxStorageBuffersPerShaderStage */ 8,
- /* maxStorageTexturesPerShaderStage */ 4,
- /* maxUniformBuffersPerShaderStage */ 12,
- /* maxUniformBufferBindingSize */ 65536,
- /* maxStorageBufferBindingSize */ 134217728,
- /* minUniformBufferOffsetAlignment */ 256,
- /* minStorageBufferOffsetAlignment */ 256,
- /* maxVertexBuffers */ 8,
- /* maxVertexAttributes */ 16,
- /* maxVertexBufferArrayStride */ 2048,
- /* maxInterStageShaderComponents */ 32,
- /* maxComputeWorkgroupStorageSize */ 16352,
- /* maxComputeInvocationsPerWorkgroup */ 256,
- /* maxComputeWorkgroupSizeX */ 256,
- /* maxComputeWorkgroupSizeY */ 256,
- /* maxComputeWorkgroupSizeZ */ 64,
- /* maxComputeWorkgroupsPerDimension */ 65535,
- };
-
- return !anyLimitIsBetterThan(defaultLimits, limits);
-}
-
-std::optional<WGPULimits> limits(id<MTLDevice> device)
-{
- auto result = rawLimits(device);
-
- if (!result)
- return std::nullopt;
-
- if (!checkLimits(*result))
- return std::nullopt;
-
- return result;
-}
-
-bool isValid(const WGPULimits& limits)
-{
- return isPowerOfTwo(limits.minUniformBufferOffsetAlignment) && isPowerOfTwo(limits.minStorageBufferOffsetAlignment);
-}
-
-bool anyLimitIsBetterThan(const WGPULimits& target, const WGPULimits& reference)
-{
- if (target.maxTextureDimension1D > reference.maxTextureDimension1D)
- return true;
- if (target.maxTextureDimension2D > reference.maxTextureDimension2D)
- return true;
- if (target.maxTextureDimension3D > reference.maxTextureDimension3D)
- return true;
- if (target.maxTextureArrayLayers > reference.maxTextureArrayLayers)
- return true;
- if (target.maxBindGroups > reference.maxBindGroups)
- return true;
- if (target.maxDynamicUniformBuffersPerPipelineLayout > reference.maxDynamicUniformBuffersPerPipelineLayout)
- return true;
- if (target.maxDynamicStorageBuffersPerPipelineLayout > reference.maxDynamicStorageBuffersPerPipelineLayout)
- return true;
- if (target.maxSampledTexturesPerShaderStage > reference.maxSampledTexturesPerShaderStage)
- return true;
- if (target.maxSamplersPerShaderStage > reference.maxSamplersPerShaderStage)
- return true;
- if (target.maxStorageBuffersPerShaderStage > reference.maxStorageBuffersPerShaderStage)
- return true;
- if (target.maxStorageTexturesPerShaderStage > reference.maxStorageTexturesPerShaderStage)
- return true;
- if (target.maxUniformBuffersPerShaderStage > reference.maxUniformBuffersPerShaderStage)
- return true;
- if (target.maxUniformBufferBindingSize > reference.maxUniformBufferBindingSize)
- return true;
- if (target.maxStorageBufferBindingSize > reference.maxStorageBufferBindingSize)
- return true;
- if (target.minUniformBufferOffsetAlignment < reference.minUniformBufferOffsetAlignment)
- return true;
- if (target.minStorageBufferOffsetAlignment < reference.minStorageBufferOffsetAlignment)
- return true;
- if (target.maxVertexBuffers > reference.maxVertexBuffers)
- return true;
- if (target.maxVertexAttributes > reference.maxVertexAttributes)
- return true;
- if (target.maxVertexBufferArrayStride > reference.maxVertexBufferArrayStride)
- return true;
- if (target.maxInterStageShaderComponents > reference.maxInterStageShaderComponents)
- return true;
- if (target.maxComputeWorkgroupStorageSize > reference.maxComputeWorkgroupStorageSize)
- return true;
- if (target.maxComputeInvocationsPerWorkgroup > reference.maxComputeInvocationsPerWorkgroup)
- return true;
- if (target.maxComputeWorkgroupSizeX > reference.maxComputeWorkgroupSizeX)
- return true;
- if (target.maxComputeWorkgroupSizeY > reference.maxComputeWorkgroupSizeY)
- return true;
- if (target.maxComputeWorkgroupSizeZ > reference.maxComputeWorkgroupSizeZ)
- return true;
- if (target.maxComputeWorkgroupsPerDimension > reference.maxComputeWorkgroupsPerDimension)
- return true;
-
- return false;
-}
-
-} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU/Instance.mm (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Instance.mm 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Instance.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -28,7 +28,7 @@
#import "APIConversions.h"
#import "Adapter.h"
-#import "HardwareLimits.h"
+#import "HardwareCapabilities.h"
#import "Surface.h"
#import <cstring>
#import <wtf/BlockPtr.h>
@@ -186,9 +186,9 @@
auto device = sortedDevices[0];
- auto deviceLimits = limits(device);
+ auto deviceCapabilties = hardwareCapabilities(device);
- if (!deviceLimits) {
+ if (!deviceCapabilties) {
scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
callback(WGPURequestAdapterStatus_Error, Adapter::createInvalid(strongThis), "Device does not support WebGPU"_s);
});
@@ -195,8 +195,8 @@
return;
}
- scheduleWork([strongThis = Ref { *this }, device = sortedDevices[0], limits = WTFMove(*deviceLimits), callback = WTFMove(callback)]() mutable {
- callback(WGPURequestAdapterStatus_Success, Adapter::create(device, strongThis, WTFMove(limits)), { });
+ scheduleWork([strongThis = Ref { *this }, device = sortedDevices[0], deviceCapabilties = WTFMove(*deviceCapabilties), callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestAdapterStatus_Success, Adapter::create(device, strongThis, WTFMove(deviceCapabilties)), { });
});
}
Modified: trunk/Source/WebGPU/WebGPU/Texture.mm (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU/Texture.mm 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU/Texture.mm 2022-04-20 16:10:11 UTC (rev 293098)
@@ -37,7 +37,7 @@
static std::optional<WGPUFeatureName> featureRequirementForFormat(WGPUTextureFormat format)
{
switch (format) {
- case WGPUTextureFormat_Depth24UnormStencil8: // FIXME: This has to be guarded by MTLDevice.depth24Stencil8PixelFormatSupported
+ case WGPUTextureFormat_Depth24UnormStencil8:
return WGPUFeatureName_Depth24UnormStencil8;
case WGPUTextureFormat_Depth32FloatStencil8:
return WGPUFeatureName_Depth32FloatStencil8;
@@ -1246,7 +1246,7 @@
switch (descriptor.dimension) {
case WGPUTextureDimension_1D:
- if (descriptor.size.width > m_limits.maxTextureDimension1D)
+ if (descriptor.size.width > limits().maxTextureDimension1D)
return false;
if (descriptor.size.height != 1)
@@ -1262,23 +1262,23 @@
return false;
break;
case WGPUTextureDimension_2D:
- if (descriptor.size.width > m_limits.maxTextureDimension2D)
+ if (descriptor.size.width > limits().maxTextureDimension2D)
return false;
- if (descriptor.size.height > m_limits.maxTextureDimension2D)
+ if (descriptor.size.height > limits().maxTextureDimension2D)
return false;
- if (descriptor.size.depthOrArrayLayers > m_limits.maxTextureArrayLayers)
+ if (descriptor.size.depthOrArrayLayers > limits().maxTextureArrayLayers)
return false;
break;
case WGPUTextureDimension_3D:
- if (descriptor.size.width > m_limits.maxTextureDimension3D)
+ if (descriptor.size.width > limits().maxTextureDimension3D)
return false;
- if (descriptor.size.height > m_limits.maxTextureDimension3D)
+ if (descriptor.size.height > limits().maxTextureDimension3D)
return false;
- if (descriptor.size.depthOrArrayLayers > m_limits.maxTextureDimension3D)
+ if (descriptor.size.depthOrArrayLayers > limits().maxTextureDimension3D)
return false;
if (descriptor.sampleCount != 1)
@@ -1961,8 +1961,10 @@
}
}
-static MTLStorageMode storageMode(bool deviceHasUnifiedMemory)
+static MTLStorageMode storageMode(bool deviceHasUnifiedMemory, bool supportsNonPrivateDepthStencilTextures)
{
+ if (!supportsNonPrivateDepthStencilTextures)
+ return MTLStorageModePrivate;
if (deviceHasUnifiedMemory)
return MTLStorageModeShared;
#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
@@ -1987,9 +1989,11 @@
// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture
- if (featureRequirementForFormat(descriptor.format)) {
- // FIXME: "but this.[[device]].[[features]] does not contain the feature, throw a TypeError."
- return Texture::createInvalid(*this);
+ if (auto requirement = featureRequirementForFormat(descriptor.format)) {
+ if (!hasFeature(*requirement)) {
+ // FIXME: "throw a TypeError."
+ return Texture::createInvalid(*this);
+ }
}
if (!validateCreateTexture(descriptor, viewFormats)) {
@@ -2047,7 +2051,7 @@
textureDescriptor.sampleCount = descriptor.sampleCount;
- textureDescriptor.storageMode = storageMode(hasUnifiedMemory());
+ textureDescriptor.storageMode = storageMode(hasUnifiedMemory(), baseCapabilities().supportsNonPrivateDepthStencilTextures);
// FIXME(PERFORMANCE): Consider write-combining CPU cache mode.
// FIXME(PERFORMANCE): Consider implementing hazard tracking ourself.
Modified: trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj (293097 => 293098)
--- trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-04-20 16:03:21 UTC (rev 293097)
+++ trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-04-20 16:10:11 UTC (rev 293098)
@@ -10,8 +10,8 @@
1C023D3F27449070001DB734 /* WGSLLexerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C023D3E27449070001DB734 /* WGSLLexerTests.mm */; };
1C023D4027449070001DB734 /* libwgsl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CEBD7F22716B2CC00A5254D /* libwgsl.a */; };
1C023D4B274495B9001DB734 /* _javascript_Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C023D4A274495B9001DB734 /* _javascript_Core.framework */; };
- 1C0F41EE280940650005886D /* HardwareLimits.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C0F41EC280940650005886D /* HardwareLimits.mm */; };
- 1C0F41EF280940650005886D /* HardwareLimits.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0F41ED280940650005886D /* HardwareLimits.h */; };
+ 1C0F41EE280940650005886D /* HardwareCapabilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C0F41EC280940650005886D /* HardwareCapabilities.mm */; };
+ 1C0F41EF280940650005886D /* HardwareCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0F41ED280940650005886D /* HardwareCapabilities.h */; };
1C2CEDEE271E8A7300EDC16F /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C2CEDED271E8A7300EDC16F /* Metal.framework */; };
1C33755F27FA23B8002F1644 /* IsValidToUseWith.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C33755D27FA23B8002F1644 /* IsValidToUseWith.h */; };
1C5319C027BDC6CC00CD127E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5319BF27BDC6CC00CD127E /* main.swift */; };
@@ -133,8 +133,8 @@
1C023D3E27449070001DB734 /* WGSLLexerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WGSLLexerTests.mm; sourceTree = "<group>"; };
1C023D472744916D001DB734 /* WGSLUnitTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WGSLUnitTests.xcconfig; sourceTree = "<group>"; };
1C023D4A274495B9001DB734 /* _javascript_Core.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = _javascript_Core.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 1C0F41EC280940650005886D /* HardwareLimits.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = HardwareLimits.mm; sourceTree = "<group>"; };
- 1C0F41ED280940650005886D /* HardwareLimits.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HardwareLimits.h; sourceTree = "<group>"; };
+ 1C0F41EC280940650005886D /* HardwareCapabilities.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = HardwareCapabilities.mm; sourceTree = "<group>"; };
+ 1C0F41ED280940650005886D /* HardwareCapabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HardwareCapabilities.h; sourceTree = "<group>"; };
1C2CEDED271E8A7300EDC16F /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
1C33755D27FA23B8002F1644 /* IsValidToUseWith.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IsValidToUseWith.h; sourceTree = "<group>"; };
1C5319BD27BDC6CB00CD127E /* CommandLinePlayground */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLinePlayground; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -348,8 +348,8 @@
1C5ACA9B273A426D0095F8D5 /* Device.h */,
1C5ACAA3273A426D0095F8D5 /* Device.mm */,
1CEBD80B2716C37900A5254D /* ExportMacros.h */,
- 1C0F41ED280940650005886D /* HardwareLimits.h */,
- 1C0F41EC280940650005886D /* HardwareLimits.mm */,
+ 1C0F41ED280940650005886D /* HardwareCapabilities.h */,
+ 1C0F41EC280940650005886D /* HardwareCapabilities.mm */,
1C5ACAA0273A426D0095F8D5 /* Instance.h */,
1C5ACA92273A41C20095F8D5 /* Instance.mm */,
1C33755D27FA23B8002F1644 /* IsValidToUseWith.h */,
@@ -487,7 +487,7 @@
1C58301827E16823009B40F0 /* APIConversions.h in Headers */,
1C5ACAD7273A4D700095F8D5 /* BindGroup.h in Headers */,
1C582FFA27E04131009B40F0 /* CommandsMixin.h in Headers */,
- 1C0F41EF280940650005886D /* HardwareLimits.h in Headers */,
+ 1C0F41EF280940650005886D /* HardwareCapabilities.h in Headers */,
1C33755F27FA23B8002F1644 /* IsValidToUseWith.h in Headers */,
1CEBD7E72716AFBA00A5254D /* WebGPU.h in Headers */,
1C5ACAD3273A4C860095F8D5 /* WebGPUExt.h in Headers */,
@@ -737,7 +737,7 @@
1C5ACAC6273A426D0095F8D5 /* ComputePassEncoder.mm in Sources */,
1C5ACAC0273A426D0095F8D5 /* ComputePipeline.mm in Sources */,
1C5ACAC1273A426D0095F8D5 /* Device.mm in Sources */,
- 1C0F41EE280940650005886D /* HardwareLimits.mm in Sources */,
+ 1C0F41EE280940650005886D /* HardwareCapabilities.mm in Sources */,
1C5ACA94273A41C20095F8D5 /* Instance.mm in Sources */,
1C5ACAE5273A55DD0095F8D5 /* PipelineLayout.mm in Sources */,
1C5ACABD273A426D0095F8D5 /* QuerySet.mm in Sources */,