Title: [292940] trunk/Source
Revision
292940
Author
[email protected]
Date
2022-04-15 21:47:58 -0700 (Fri, 15 Apr 2022)

Log Message

[WebGPU] Implement hardware limits
https://bugs.webkit.org/show_bug.cgi?id=239377

Reviewed by Darin Adler.

Source/WebCore/PAL:

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):

Source/WebGPU:

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:

Source/WTF:

Add missing #include.

* wtf/PageBlock.h:

Modified Paths

Added Paths

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 */,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to