Diff
Modified: trunk/Source/WTF/ChangeLog (292939 => 292940)
--- trunk/Source/WTF/ChangeLog 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WTF/ChangeLog 2022-04-16 04:47:58 UTC (rev 292940)
@@ -1,3 +1,14 @@
+2022-04-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Implement hardware limits
+ https://bugs.webkit.org/show_bug.cgi?id=239377
+
+ Reviewed by Darin Adler.
+
+ Add missing #include.
+
+ * wtf/PageBlock.h:
+
2022-04-15 Michael Catanzaro <[email protected]>
IGNORE_WARNINGS_BEGIN should not warn about unrecognized warnings
Modified: trunk/Source/WTF/wtf/PageBlock.h (292939 => 292940)
--- trunk/Source/WTF/wtf/PageBlock.h 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WTF/wtf/PageBlock.h 2022-04-16 04:47:58 UTC (rev 292940)
@@ -25,6 +25,7 @@
#pragma once
+#include <wtf/FastMalloc.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
Modified: trunk/Source/WebCore/PAL/ChangeLog (292939 => 292940)
--- trunk/Source/WebCore/PAL/ChangeLog 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebCore/PAL/ChangeLog 2022-04-16 04:47:58 UTC (rev 292940)
@@ -1,3 +1,18 @@
+2022-04-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Implement hardware limits
+ https://bugs.webkit.org/show_bug.cgi?id=239377
+
+ Reviewed by Darin Adler.
+
+ This patch adds support for "limits" as described in https://gpuweb.github.io/gpuweb/#limits.
+ Various operations query the limits of the device to know whether the requested operation is
+ within range. E.g. if content tries to make a texture too big, this is how we catch it ahead of
+ time.
+
+ * pal/graphics/WebGPU/Impl/WebGPUAdapterImpl.cpp:
+ (PAL::WebGPU::AdapterImpl::requestDevice):
+
2022-04-14 Wenson Hsieh <[email protected]>
[iOS] [WK2] Managed pasteboard should function for all managed domains
Modified: trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUAdapterImpl.cpp (292939 => 292940)
--- trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUAdapterImpl.cpp 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebCore/PAL/pal/graphics/WebGPU/Impl/WebGPUAdapterImpl.cpp 2022-04-16 04:47:58 UTC (rev 292940)
@@ -149,43 +149,95 @@
return m_convertToBackingContext->convertToBacking(featureName);
});
- WGPURequiredLimits limits {
- nullptr, {
- 0, // maxTextureDimension1D
- 0, // maxTextureDimension2D
- 0, // maxTextureDimension3D
- 0, // maxTextureArrayLayers
- 0, // maxBindGroups
- 0, // maxDynamicUniformBuffersPerPipelineLayout
- 0, // maxDynamicStorageBuffersPerPipelineLayout
- 0, // maxSampledTexturesPerShaderStage
- 0, // maxSamplersPerShaderStage
- 0, // maxStorageBuffersPerShaderStage
- 0, // maxStorageTexturesPerShaderStage
- 0, // maxUniformBuffersPerShaderStage
- 0, // maxUniformBufferBindingSize
- 0, // maxStorageBufferBindingSize
- 0, // minUniformBufferOffsetAlignment
- 0, // minStorageBufferOffsetAlignment
- 0, // maxVertexBuffers
- 0, // maxVertexAttributes
- 0, // maxVertexBufferArrayStride
- 0, // maxInterStageShaderComponents
- 0, // maxComputeWorkgroupStorageSize
- 0, // maxComputeInvocationsPerWorkgroup
- 0, // maxComputeWorkgroupSizeX
- 0, // maxComputeWorkgroupSizeY
- 0, // maxComputeWorkgroupSizeZ
- 0, // maxComputeWorkgroupsPerDimension
- },
+ auto limits = 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,
};
+ auto requestInvalidDevice = [this, &callback]() {
+ wgpuAdapterRequestInvalidDeviceWithBlock(m_backing, makeBlockPtr([protectedThis = Ref { *this }, convertToBackingContext = m_convertToBackingContext.copyRef(), callback = WTFMove(callback)](WGPUDevice device) mutable {
+ callback(DeviceImpl::create(device, Ref { protectedThis->features() }, Ref { protectedThis->limits() }, convertToBackingContext));
+ }).get());
+ };
+
+ for (const auto& pair : descriptor.requiredLimits) {
+#define SET_VALUE_32(LIMIT) \
+ else if (pair.key == #LIMIT) { \
+ CheckedUint32 narrowed = pair.value; \
+ if (narrowed.hasOverflowed()) { \
+ requestInvalidDevice(); \
+ return; \
+ } \
+ limits.LIMIT = narrowed.value(); \
+ }
+#define SET_VALUE_64(LIMIT) \
+ else if (pair.key == #LIMIT) \
+ limits.LIMIT = pair.value;
+
+ if (false) { }
+ SET_VALUE_32(maxTextureDimension1D)
+ SET_VALUE_32(maxTextureDimension2D)
+ SET_VALUE_32(maxTextureDimension3D)
+ SET_VALUE_32(maxTextureArrayLayers)
+ SET_VALUE_32(maxBindGroups)
+ SET_VALUE_32(maxDynamicUniformBuffersPerPipelineLayout)
+ SET_VALUE_32(maxDynamicStorageBuffersPerPipelineLayout)
+ SET_VALUE_32(maxSampledTexturesPerShaderStage)
+ SET_VALUE_32(maxSamplersPerShaderStage)
+ SET_VALUE_32(maxStorageBuffersPerShaderStage)
+ SET_VALUE_32(maxStorageTexturesPerShaderStage)
+ SET_VALUE_32(maxUniformBuffersPerShaderStage)
+ SET_VALUE_64(maxUniformBufferBindingSize)
+ SET_VALUE_64(maxStorageBufferBindingSize)
+ SET_VALUE_32(minUniformBufferOffsetAlignment)
+ SET_VALUE_32(minStorageBufferOffsetAlignment)
+ SET_VALUE_32(maxVertexBuffers)
+ SET_VALUE_32(maxVertexAttributes)
+ SET_VALUE_32(maxVertexBufferArrayStride)
+ SET_VALUE_32(maxInterStageShaderComponents)
+ SET_VALUE_32(maxComputeWorkgroupStorageSize)
+ SET_VALUE_32(maxComputeInvocationsPerWorkgroup)
+ SET_VALUE_32(maxComputeWorkgroupSizeX)
+ SET_VALUE_32(maxComputeWorkgroupSizeY)
+ SET_VALUE_32(maxComputeWorkgroupSizeZ)
+ SET_VALUE_32(maxComputeWorkgroupsPerDimension)
+
+#undef SET_VALUE_32
+#undef SET_VALUE_64
+ }
+
+ WGPURequiredLimits requiredLimits { nullptr, WTFMove(limits) };
+
WGPUDeviceDescriptor backingDescriptor {
nullptr,
label.data(),
static_cast<uint32_t>(features.size()),
features.data(),
- &limits,
+ &requiredLimits,
};
wgpuAdapterRequestDeviceWithBlock(m_backing, &backingDescriptor, makeBlockPtr([protectedThis = Ref { *this }, convertToBackingContext = m_convertToBackingContext.copyRef(), callback = WTFMove(callback)](WGPURequestDeviceStatus, WGPUDevice device, const char*) mutable {
Modified: trunk/Source/WebGPU/ChangeLog (292939 => 292940)
--- trunk/Source/WebGPU/ChangeLog 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/ChangeLog 2022-04-16 04:47:58 UTC (rev 292940)
@@ -1,3 +1,51 @@
+2022-04-15 Myles C. Maxfield <[email protected]>
+
+ [WebGPU] Implement hardware limits
+ https://bugs.webkit.org/show_bug.cgi?id=239377
+
+ Reviewed by Darin Adler.
+
+ We gather the values of the limits from the Metal Feature Set Tables
+ at https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf.
+
+ There are no limit tables for the Common families, so we use Apple
+ and Mac families instead.
+
+ Test: webgpu/api/validation/createTexture
+
+ * WebGPU.xcodeproj/project.pbxproj:
+ * WebGPU/Adapter.h:
+ (WebGPU::Adapter::create):
+ * WebGPU/Adapter.mm:
+ (WebGPU::Adapter::Adapter):
+ (WebGPU::Adapter::requestDevice):
+ (WebGPU::Adapter::requestInvalidDevice):
+ (wgpuAdapterRequestInvalidDeviceWithBlock):
+ (WebGPU::deviceMeetsRequiredLimits): Deleted.
+ * WebGPU/Device.h:
+ * WebGPU/Device.mm:
+ (WebGPU::Device::create):
+ (WebGPU::Device::Device):
+ * WebGPU/HardwareLimits.h: Copied from Source/WebGPU/WebGPU/Adapter.h.
+ * WebGPU/HardwareLimits.mm: Added.
+ (WebGPU::apple3):
+ (WebGPU::apple4):
+ (WebGPU::apple5):
+ (WebGPU::apple6):
+ (WebGPU::apple7):
+ (WebGPU::mac2):
+ (WebGPU::rawLimits):
+ (WebGPU::checkLimits):
+ (WebGPU::limits):
+ (WebGPU::isValid):
+ (WebGPU::anyLimitIsBetterThan):
+ * WebGPU/Instance.mm:
+ (WebGPU::Instance::requestAdapter):
+ * WebGPU/Texture.mm:
+ (WebGPU::Device::validateCreateTexture):
+ (WebGPU::Texture::createView):
+ * WebGPU/WebGPUExt.h:
+
2022-04-13 Elliott Williams <[email protected]>
[Xcode] Fix public watchOS workspace build by updating scheme and build settings
Modified: trunk/Source/WebGPU/WebGPU/Adapter.h (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Adapter.h 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Adapter.h 2022-04-16 04:47:58 UTC (rev 292940)
@@ -42,9 +42,9 @@
class Adapter : public WGPUAdapterImpl, public RefCounted<Adapter> {
WTF_MAKE_FAST_ALLOCATED;
public:
- static Ref<Adapter> create(id<MTLDevice> device, Instance& instance)
+ static Ref<Adapter> create(id<MTLDevice> device, Instance& instance, const WGPULimits& limits)
{
- return adoptRef(*new Adapter(device, instance));
+ return adoptRef(*new Adapter(device, instance, limits));
}
static Ref<Adapter> createInvalid(Instance& instance)
{
@@ -58,6 +58,7 @@
void getProperties(WGPUAdapterProperties&);
bool hasFeature(WGPUFeatureName);
void requestDevice(const WGPUDeviceDescriptor&, CompletionHandler<void(WGPURequestDeviceStatus, Ref<Device>&&, String&&)>&& callback);
+ void requestInvalidDevice(CompletionHandler<void(Ref<Device>&&)>&&);
bool isValid() const { return m_device; }
void makeInvalid() { m_device = nil; }
@@ -66,11 +67,13 @@
private:
- Adapter(id<MTLDevice>, Instance&);
+ Adapter(id<MTLDevice>, Instance&, const WGPULimits&);
Adapter(Instance&);
id<MTLDevice> m_device { nil };
const Ref<Instance> m_instance;
+
+ WGPULimits m_limits { };
};
} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU/Adapter.mm (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Adapter.mm 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Adapter.mm 2022-04-16 04:47:58 UTC (rev 292940)
@@ -28,14 +28,16 @@
#import "APIConversions.h"
#import "Device.h"
+#import "HardwareLimits.h"
#import "Instance.h"
#import <wtf/StdLibExtras.h>
namespace WebGPU {
-Adapter::Adapter(id<MTLDevice> device, Instance& instance)
+Adapter::Adapter(id<MTLDevice> device, Instance& instance, const WGPULimits& limits)
: m_device(device)
, m_instance(instance)
+ , m_limits(limits)
{
}
@@ -79,38 +81,6 @@
return false;
}
-static bool deviceMeetsRequiredLimits(id<MTLDevice>, const WGPURequiredLimits& requiredLimits)
-{
- // FIXME: Implement this.
- return !requiredLimits.nextInChain
- && !requiredLimits.limits.maxTextureDimension1D
- && !requiredLimits.limits.maxTextureDimension2D
- && !requiredLimits.limits.maxTextureDimension3D
- && !requiredLimits.limits.maxTextureArrayLayers
- && !requiredLimits.limits.maxBindGroups
- && !requiredLimits.limits.maxDynamicUniformBuffersPerPipelineLayout
- && !requiredLimits.limits.maxDynamicStorageBuffersPerPipelineLayout
- && !requiredLimits.limits.maxSampledTexturesPerShaderStage
- && !requiredLimits.limits.maxSamplersPerShaderStage
- && !requiredLimits.limits.maxStorageBuffersPerShaderStage
- && !requiredLimits.limits.maxStorageTexturesPerShaderStage
- && !requiredLimits.limits.maxUniformBuffersPerShaderStage
- && !requiredLimits.limits.maxUniformBufferBindingSize
- && !requiredLimits.limits.maxStorageBufferBindingSize
- && !requiredLimits.limits.minUniformBufferOffsetAlignment
- && !requiredLimits.limits.minStorageBufferOffsetAlignment
- && !requiredLimits.limits.maxVertexBuffers
- && !requiredLimits.limits.maxVertexAttributes
- && !requiredLimits.limits.maxVertexBufferArrayStride
- && !requiredLimits.limits.maxInterStageShaderComponents
- && !requiredLimits.limits.maxComputeWorkgroupStorageSize
- && !requiredLimits.limits.maxComputeInvocationsPerWorkgroup
- && !requiredLimits.limits.maxComputeWorkgroupSizeX
- && !requiredLimits.limits.maxComputeWorkgroupSizeY
- && !requiredLimits.limits.maxComputeWorkgroupSizeZ
- && !requiredLimits.limits.maxComputeWorkgroupsPerDimension;
-}
-
void Adapter::requestDevice(const WGPUDeviceDescriptor& descriptor, CompletionHandler<void(WGPURequestDeviceStatus, Ref<Device>&&, String&&)>&& callback)
{
if (descriptor.nextInChain) {
@@ -127,19 +97,46 @@
return;
}
- if (descriptor.requiredLimits && !deviceMeetsRequiredLimits(m_device, *descriptor.requiredLimits)) {
- instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
- callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Device does not support requested limits"_s);
- });
- return;
+ auto limits = m_limits;
+
+ if (descriptor.requiredLimits) {
+ if (descriptor.requiredLimits->nextInChain) {
+ instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Unknown descriptor type"_s);
+ });
+ return;
+ }
+
+ if (!WebGPU::isValid(descriptor.requiredLimits->limits)) {
+ instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Device does not support requested limits"_s);
+ });
+ return;
+ }
+
+ if (anyLimitIsBetterThan(descriptor.requiredLimits->limits, m_limits)) {
+ instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestDeviceStatus_Error, Device::createInvalid(strongThis), "Device does not support requested limits"_s);
+ });
+ return;
+ }
+
+ limits = descriptor.requiredLimits->limits;
}
auto label = fromAPI(descriptor.label);
- instance().scheduleWork([strongThis = Ref { *this }, label = WTFMove(label), callback = WTFMove(callback)]() mutable {
- callback(WGPURequestDeviceStatus_Success, Device::create(strongThis->m_device, WTFMove(label), strongThis), { });
+ 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), { });
});
}
+void Adapter::requestInvalidDevice(CompletionHandler<void(Ref<Device>&&)>&& callback)
+{
+ instance().scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(Device::createInvalid(strongThis));
+ });
+}
+
} // namespace WebGPU
#pragma mark WGPU Stubs
@@ -182,3 +179,10 @@
callback(status, WebGPU::releaseToAPI(WTFMove(device)), message.utf8().data());
});
}
+
+void wgpuAdapterRequestInvalidDeviceWithBlock(WGPUAdapter adapter, WGPURequestInvalidDeviceBlockCallback callback)
+{
+ WebGPU::fromAPI(adapter).requestInvalidDevice([callback = WTFMove(callback)](Ref<WebGPU::Device>&& device) {
+ callback(WebGPU::releaseToAPI(WTFMove(device)));
+ });
+}
Modified: trunk/Source/WebGPU/WebGPU/Device.h (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Device.h 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Device.h 2022-04-16 04:47:58 UTC (rev 292940)
@@ -61,7 +61,7 @@
class Device : public WGPUDeviceImpl, public ThreadSafeRefCounted<Device>, public CanMakeWeakPtr<Device> {
WTF_MAKE_FAST_ALLOCATED;
public:
- static Ref<Device> create(id<MTLDevice>, String&& deviceLabel, Adapter&);
+ static Ref<Device> create(id<MTLDevice>, String&& deviceLabel, const WGPULimits&, Adapter&);
static Ref<Device> createInvalid(Adapter& adapter)
{
return adoptRef(*new Device(adapter));
@@ -106,7 +106,7 @@
bool hasUnifiedMemory() const { return m_device.hasUnifiedMemory; }
private:
- Device(id<MTLDevice>, id<MTLCommandQueue> defaultQueue, Adapter&);
+ Device(id<MTLDevice>, id<MTLCommandQueue> defaultQueue, const WGPULimits&, Adapter&);
Device(Adapter&);
struct ErrorScope;
@@ -138,6 +138,8 @@
bool m_isLost { false };
id<NSObject> m_deviceObserver { nil };
+ WGPULimits m_limits { };
+
const Ref<Adapter> m_adapter;
};
Modified: trunk/Source/WebGPU/WebGPU/Device.mm (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Device.mm 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Device.mm 2022-04-16 04:47:58 UTC (rev 292940)
@@ -47,7 +47,7 @@
namespace WebGPU {
-Ref<Device> Device::create(id<MTLDevice> device, String&& deviceLabel, Adapter& adapter)
+Ref<Device> Device::create(id<MTLDevice> device, String&& deviceLabel, const WGPULimits& limits, Adapter& adapter)
{
id<MTLCommandQueue> commandQueue = [device newCommandQueue];
if (!commandQueue)
@@ -59,12 +59,13 @@
if (!deviceLabel.isEmpty())
commandQueue.label = [NSString stringWithFormat:@"Default queue for device %s", deviceLabel.utf8().data()];
- return adoptRef(*new Device(device, commandQueue, adapter));
+ return adoptRef(*new Device(device, commandQueue, limits, adapter));
}
-Device::Device(id<MTLDevice> device, id<MTLCommandQueue> defaultQueue, Adapter& adapter)
+Device::Device(id<MTLDevice> device, id<MTLCommandQueue> defaultQueue, const WGPULimits& limits, Adapter& adapter)
: m_device(device)
, m_defaultQueue(Queue::create(defaultQueue, *this))
+ , m_limits(limits)
, m_adapter(adapter)
{
#if PLATFORM(MAC)
Copied: trunk/Source/WebGPU/WebGPU/HardwareLimits.h (from rev 292938, trunk/Source/WebGPU/WebGPU/Adapter.h) (0 => 292940)
--- trunk/Source/WebGPU/WebGPU/HardwareLimits.h (rev 0)
+++ trunk/Source/WebGPU/WebGPU/HardwareLimits.h 2022-04-16 04:47:58 UTC (rev 292940)
@@ -0,0 +1,36 @@
+/*
+ * 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
Added: trunk/Source/WebGPU/WebGPU/HardwareLimits.mm (0 => 292940)
--- trunk/Source/WebGPU/WebGPU/HardwareLimits.mm (rev 0)
+++ trunk/Source/WebGPU/WebGPU/HardwareLimits.mm 2022-04-16 04:47:58 UTC (rev 292940)
@@ -0,0 +1,449 @@
+/*
+ * 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;
+}
+
+constexpr 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 (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Instance.mm 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Instance.mm 2022-04-16 04:47:58 UTC (rev 292940)
@@ -28,6 +28,7 @@
#import "APIConversions.h"
#import "Adapter.h"
+#import "HardwareLimits.h"
#import "Surface.h"
#import <cstring>
#import <wtf/BlockPtr.h>
@@ -183,8 +184,19 @@
return;
}
- scheduleWork([strongThis = Ref { *this }, device = sortedDevices[0], callback = WTFMove(callback)]() mutable {
- callback(WGPURequestAdapterStatus_Success, Adapter::create(device, strongThis), { });
+ auto device = sortedDevices[0];
+
+ auto deviceLimits = limits(device);
+
+ if (!deviceLimits) {
+ scheduleWork([strongThis = Ref { *this }, callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestAdapterStatus_Error, Adapter::createInvalid(strongThis), "Device does not support WebGPU"_s);
+ });
+ return;
+ }
+
+ scheduleWork([strongThis = Ref { *this }, device = sortedDevices[0], limits = WTFMove(*deviceLimits), callback = WTFMove(callback)]() mutable {
+ callback(WGPURequestAdapterStatus_Success, Adapter::create(device, strongThis, WTFMove(limits)), { });
});
}
Modified: trunk/Source/WebGPU/WebGPU/Texture.mm (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/Texture.mm 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/Texture.mm 2022-04-16 04:47:58 UTC (rev 292940)
@@ -1246,7 +1246,8 @@
switch (descriptor.dimension) {
case WGPUTextureDimension_1D:
- // FIXME: "descriptor.size.width must be less than or equal to this.limits.maxTextureDimension1D."
+ if (descriptor.size.width > m_limits.maxTextureDimension1D)
+ return false;
if (descriptor.size.height != 1)
return false;
@@ -1261,18 +1262,24 @@
return false;
break;
case WGPUTextureDimension_2D:
- // FIXME: "descriptor.size.width must be less than or equal to this.limits.maxTextureDimension2D."
+ if (descriptor.size.width > m_limits.maxTextureDimension2D)
+ return false;
- // FIXME: "descriptor.size.height must be less than or equal to this.limits.maxTextureDimension2D."
+ if (descriptor.size.height > m_limits.maxTextureDimension2D)
+ return false;
- // FIXME: "descriptor.size.depthOrArrayLayers must be less than or equal to this.limits.maxTextureArrayLayers."
+ if (descriptor.size.depthOrArrayLayers > m_limits.maxTextureArrayLayers)
+ return false;
break;
case WGPUTextureDimension_3D:
- // FIXME: "descriptor.size.width must be less than or equal to this.limits.maxTextureDimension3D."
+ if (descriptor.size.width > m_limits.maxTextureDimension3D)
+ return false;
- // FIXME: "descriptor.size.height must be less than or equal to this.limits.maxTextureDimension3D."
+ if (descriptor.size.height > m_limits.maxTextureDimension3D)
+ return false;
- // FIXME: "descriptor.size.depthOrArrayLayers must be less than or equal to this.limits.maxTextureDimension3D."
+ if (descriptor.size.depthOrArrayLayers > m_limits.maxTextureDimension3D)
+ return false;
if (descriptor.sampleCount != 1)
return false;
@@ -2268,8 +2275,6 @@
if (!descriptor || !validateCreateView(*descriptor)) {
m_device->generateAValidationError("Validation failure."_s);
-
- // FIXME: "Return a new invalid GPUTextureView."
return TextureView::createInvalid(m_device);
}
Modified: trunk/Source/WebGPU/WebGPU/WebGPUExt.h (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU/WebGPUExt.h 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU/WebGPUExt.h 2022-04-16 04:47:58 UTC (rev 292940)
@@ -39,6 +39,7 @@
typedef void (^WGPUQueueWorkDoneBlockCallback)(WGPUQueueWorkDoneStatus status);
typedef void (^WGPURequestAdapterBlockCallback)(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message);
typedef void (^WGPURequestDeviceBlockCallback)(WGPURequestDeviceStatus status, WGPUDevice device, char const * message);
+typedef void (^WGPURequestInvalidDeviceBlockCallback)(WGPUDevice device);
typedef void (^WGPUWorkItem)(void);
typedef void (^WGPUScheduleWorkBlock)(WGPUWorkItem workItem);
@@ -183,6 +184,7 @@
WGPU_EXPORT void wgpuTextureViewSetLabel(WGPUTextureView sampler, char const * label);
WGPU_EXPORT void wgpuAdapterRequestDeviceWithBlock(WGPUAdapter adapter, WGPUDeviceDescriptor const * descriptor, WGPURequestDeviceBlockCallback callback);
+WGPU_EXPORT void wgpuAdapterRequestInvalidDeviceWithBlock(WGPUAdapter adapter, WGPURequestInvalidDeviceBlockCallback callback);
WGPU_EXPORT void wgpuBufferMapAsyncWithBlock(WGPUBuffer buffer, WGPUMapModeFlags mode, size_t offset, size_t size, WGPUBufferMapBlockCallback callback);
WGPU_EXPORT void wgpuDeviceCreateComputePipelineAsyncWithBlock(WGPUDevice device, WGPUComputePipelineDescriptor const * descriptor, WGPUCreateComputePipelineAsyncBlockCallback callback);
WGPU_EXPORT void wgpuDeviceCreateRenderPipelineAsyncWithBlock(WGPUDevice device, WGPURenderPipelineDescriptor const * descriptor, WGPUCreateRenderPipelineAsyncBlockCallback callback);
Modified: trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj (292939 => 292940)
--- trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-04-16 04:44:41 UTC (rev 292939)
+++ trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-04-16 04:47:58 UTC (rev 292940)
@@ -10,6 +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 */; };
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 */; };
@@ -131,6 +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>"; };
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; };
@@ -344,6 +348,8 @@
1C5ACA9B273A426D0095F8D5 /* Device.h */,
1C5ACAA3273A426D0095F8D5 /* Device.mm */,
1CEBD80B2716C37900A5254D /* ExportMacros.h */,
+ 1C0F41ED280940650005886D /* HardwareLimits.h */,
+ 1C0F41EC280940650005886D /* HardwareLimits.mm */,
1C5ACAA0273A426D0095F8D5 /* Instance.h */,
1C5ACA92273A41C20095F8D5 /* Instance.mm */,
1C33755D27FA23B8002F1644 /* IsValidToUseWith.h */,
@@ -481,6 +487,7 @@
1C58301827E16823009B40F0 /* APIConversions.h in Headers */,
1C5ACAD7273A4D700095F8D5 /* BindGroup.h in Headers */,
1C582FFA27E04131009B40F0 /* CommandsMixin.h in Headers */,
+ 1C0F41EF280940650005886D /* HardwareLimits.h in Headers */,
1C33755F27FA23B8002F1644 /* IsValidToUseWith.h in Headers */,
1CEBD7E72716AFBA00A5254D /* WebGPU.h in Headers */,
1C5ACAD3273A4C860095F8D5 /* WebGPUExt.h in Headers */,
@@ -731,6 +738,7 @@
1C5ACAC6273A426D0095F8D5 /* ComputePassEncoder.mm in Sources */,
1C5ACAC0273A426D0095F8D5 /* ComputePipeline.mm in Sources */,
1C5ACAC1273A426D0095F8D5 /* Device.mm in Sources */,
+ 1C0F41EE280940650005886D /* HardwareLimits.mm in Sources */,
1C5ACA94273A41C20095F8D5 /* Instance.mm in Sources */,
1C5ACAE5273A55DD0095F8D5 /* PipelineLayout.mm in Sources */,
1C5ACABD273A426D0095F8D5 /* QuerySet.mm in Sources */,