Title: [295583] trunk/Source/ThirdParty/ANGLE
Revision
295583
Author
[email protected]
Date
2022-06-15 21:16:11 -0700 (Wed, 15 Jun 2022)

Log Message

Validate descriptor when creating MTLRenderPipelineState
https://bugs.webkit.org/show_bug.cgi?id=241587
rdar://problem/93820440

Patch by Dan Glastonbury <[email protected]> on 2022-06-15
Reviewed by Kimmo Kinnunen.

* Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm:
(rx::mtl::ValidateRenderPipelineState):
(rx::mtl::RenderPipelineCache::createRenderPipelineState):
Extend MTlRenderPipelineDescriptor validation to ensure that there is at least
one valid render target set for the the render pipeline. This is required for
certain families of metal devices to avoid a validation failure inside the metal
framework. Moving the failure here will cause the app using ANGLE to return a GL
error instead of crashing the process.

Canonical link: https://commits.webkit.org/251588@main

Modified Paths

Diff

Modified: trunk/Source/ThirdParty/ANGLE/changes.diff (295582 => 295583)


--- trunk/Source/ThirdParty/ANGLE/changes.diff	2022-06-16 02:18:24 UTC (rev 295582)
+++ trunk/Source/ThirdParty/ANGLE/changes.diff	2022-06-16 04:16:11 UTC (rev 295583)
@@ -538,7 +538,7 @@
    public:
      static angle::Result MakeBuffer(ContextMtl *context,
 diff --git a/src/libANGLE/renderer/metal/mtl_resources.mm b/src/libANGLE/renderer/metal/mtl_resources.mm
-index 6bcb9cd8d3e2087dd269b4c5fb8b8214c33e2f0e..9a553aba15d004adcbb81005487a48f5a25e218d 100644
+index 6bcb9cd8d3e2087dd269b4c5fb8b8214c33e2f0e..414a3d9dbb7ab125172ee99aa9df636383c3d4f5 100644
 --- a/src/libANGLE/renderer/metal/mtl_resources.mm
 +++ b/src/libANGLE/renderer/metal/mtl_resources.mm
 @@ -35,12 +35,14 @@ inline NSUInteger GetMipSize(NSUInteger baseSize, const MipmapNativeLevel level)
@@ -567,7 +567,41 @@
  {
  #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
      // Make sure GPU & CPU contents are synchronized.
-@@ -504,12 +506,12 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
+@@ -271,11 +273,10 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
+     {
+         return angle::Result::Stop;
+     }
+-    refOut->reset(new Texture(context, desc, mips, renderTargetOnly, allowFormatView, memoryLess));
+-    if (!refOut || !refOut->get())
+-    {
+-        ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
+-    }
++    ASSERT(refOut);
++    Texture *newTexture = new Texture(context, desc, mips, renderTargetOnly, allowFormatView, memoryLess);
++    ANGLE_MTL_CHECK(context, newTexture->valid(), GL_OUT_OF_MEMORY);
++    refOut->reset(newTexture);
+     if (!mtlFormat.hasDepthAndStencilBits())
+     {
+         refOut->get()->setColorWritableMask(GetEmulatedColorWriteMask(mtlFormat));
+@@ -299,13 +300,10 @@ void EnsureCPUMemWillBeSynced(ContextMtl *context, T *resource)
+                                    bool renderTargetOnly,
+                                    TextureRef *refOut)
+ {
+-
+-    refOut->reset(new Texture(context, desc, surfaceRef, slice, renderTargetOnly));
+-
+-    if (!(*refOut) || !(*refOut)->get())
+-    {
+-        ANGLE_MTL_CHECK(context, false, GL_OUT_OF_MEMORY);
+-    }
++    ASSERT(refOut);
++    Texture *newTexture = new Texture(context, desc, surfaceRef, slice, renderTargetOnly);
++    ANGLE_MTL_CHECK(context, newTexture->valid(), GL_OUT_OF_MEMORY);
++    refOut->reset(newTexture);
+     if (!mtlFormat.hasDepthAndStencilBits())
+     {
+         refOut->get()->setColorWritableMask(GetEmulatedColorWriteMask(mtlFormat));
+@@ -504,12 +502,12 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
  
  void Texture::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
  {
@@ -582,7 +616,7 @@
  }
  
  bool Texture::isCPUAccessible() const
-@@ -988,7 +990,7 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
+@@ -988,7 +986,7 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
  
  void Buffer::syncContent(ContextMtl *context, mtl::BlitCommandEncoder *blitEncoder)
  {
@@ -591,7 +625,7 @@
  }
  
  const uint8_t *Buffer::mapReadOnly(ContextMtl *context)
-@@ -1009,7 +1011,7 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
+@@ -1009,7 +1007,7 @@ bool needMultisampleColorFormatShaderReadWorkaround(ContextMtl *context, MTLText
      {
          CommandQueue &cmdQueue = context->cmdQueue();
  
@@ -600,6 +634,98 @@
  
          if (this->isBeingUsedByGPU(context))
          {
+diff --git a/src/libANGLE/renderer/metal/mtl_state_cache.mm b/src/libANGLE/renderer/metal/mtl_state_cache.mm
+index 7ef96c443d7b780ad045dfeac423ef0a86889750..625416a3ba8f1f819ecbe63e81371a5b13949b32 100644
+--- a/src/libANGLE/renderer/metal/mtl_state_cache.mm
++++ b/src/libANGLE/renderer/metal/mtl_state_cache.mm
+@@ -943,6 +943,62 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
+     return re.first->second;
+ }
+ 
++static bool ValidateRenderPipelineState(const MTLRenderPipelineDescriptor *descriptor,
++                                        ContextMtl *context,
++                                        const mtl::ContextDevice &device)
++{
++    // Ensure there is at least one valid render target.
++    bool hasValidRenderTarget = false;
++
++    const NSUInteger maxColorRenderTargets = GetMaxNumberOfRenderTargetsForDevice(device);
++    for (NSUInteger i = 0; i < maxColorRenderTargets; ++i)
++    {
++        auto colorAttachment = descriptor.colorAttachments[i];
++        if (colorAttachment && colorAttachment.pixelFormat != MTLPixelFormatInvalid)
++        {
++            hasValidRenderTarget = true;
++            break;
++        }
++    }
++
++    if (!hasValidRenderTarget && descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
++    {
++        hasValidRenderTarget = true;
++    }
++
++    if (!hasValidRenderTarget && descriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid)
++    {
++        hasValidRenderTarget = true;
++    }
++
++    if (!hasValidRenderTarget)
++    {
++        UNREACHABLE();
++        ANGLE_MTL_HANDLE_ERROR(context, "Render pipeline requires at least one render target.",
++                               GL_INVALID_OPERATION);
++        return false;
++    }
++
++    // Ensure the device can support the storage requirement for render targets.
++    if (DeviceHasMaximumRenderTargetSize(device))
++    {
++        // TODO: Is the use of NSUInteger in 32 bit systems ok without any overflow checking?
++        NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(device);
++        NSUInteger renderTargetSize =
++            ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(descriptor, context, device);
++        if (renderTargetSize > maxSize)
++        {
++            std::stringstream errorStream;
++            errorStream << "This set of render targets requires " << renderTargetSize
++                        << " bytes of pixel storage. This device supports " << maxSize << " bytes.";
++            ANGLE_MTL_HANDLE_ERROR(context, errorStream.str().c_str(), GL_INVALID_OPERATION);
++            return false;
++        }
++    }
++
++    return true;
++}
++
+ AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
+     ContextMtl *context,
+     const RenderPipelineDesc &originalDesc,
+@@ -1005,23 +1061,10 @@ void ToObjC(const RenderPassStencilAttachmentDesc &desc,
+         // Convert to Objective-C desc:
+         AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc = ToObjC(vertShader, fragShader, desc);
+ 
+-        // Validate Render Pipeline State:
+-        if (DeviceHasMaximumRenderTargetSize(metalDevice))
+-        {
+-            // TODO: Is the use of NSUInteger in 32 bit systems ok without any overflow checking?
+-            NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
+-            NSUInteger renderTargetSize =
+-                ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(objCDesc, context, metalDevice);
+-            if (renderTargetSize > maxSize)
++        if (!ValidateRenderPipelineState(objCDesc, context, metalDevice))
+         {
+-                std::stringstream errorStream;
+-                errorStream << "This set of render targets requires " << renderTargetSize
+-                            << " bytes of pixel storage. This device supports " << maxSize
+-                            << " bytes.";
+-                ANGLE_MTL_HANDLE_ERROR(context, errorStream.str().c_str(), GL_INVALID_OPERATION);
+             return nil;
+         }
+-        }
+ 
+         // Special attribute slot for default attribute
+         if (insertDefaultAttribLayout)
 diff --git a/src/libANGLE/renderer/metal/mtl_utils.h b/src/libANGLE/renderer/metal/mtl_utils.h
 index d218c13ed14be57f514cbf3c9dbeedefcdd49621..b236d92655d0307bb0b61ce51bf6406e9e934e96 100644
 --- a/src/libANGLE/renderer/metal/mtl_utils.h

Modified: trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm (295582 => 295583)


--- trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm	2022-06-16 02:18:24 UTC (rev 295582)
+++ trunk/Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/mtl_state_cache.mm	2022-06-16 04:16:11 UTC (rev 295583)
@@ -943,6 +943,62 @@
     return re.first->second;
 }
 
+static bool ValidateRenderPipelineState(const MTLRenderPipelineDescriptor *descriptor,
+                                        ContextMtl *context,
+                                        const mtl::ContextDevice &device)
+{
+    // Ensure there is at least one valid render target.
+    bool hasValidRenderTarget = false;
+
+    const NSUInteger maxColorRenderTargets = GetMaxNumberOfRenderTargetsForDevice(device);
+    for (NSUInteger i = 0; i < maxColorRenderTargets; ++i)
+    {
+        auto colorAttachment = descriptor.colorAttachments[i];
+        if (colorAttachment && colorAttachment.pixelFormat != MTLPixelFormatInvalid)
+        {
+            hasValidRenderTarget = true;
+            break;
+        }
+    }
+
+    if (!hasValidRenderTarget && descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid)
+    {
+        hasValidRenderTarget = true;
+    }
+
+    if (!hasValidRenderTarget && descriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid)
+    {
+        hasValidRenderTarget = true;
+    }
+
+    if (!hasValidRenderTarget)
+    {
+        UNREACHABLE();
+        ANGLE_MTL_HANDLE_ERROR(context, "Render pipeline requires at least one render target.",
+                               GL_INVALID_OPERATION);
+        return false;
+    }
+
+    // Ensure the device can support the storage requirement for render targets.
+    if (DeviceHasMaximumRenderTargetSize(device))
+    {
+        // TODO: Is the use of NSUInteger in 32 bit systems ok without any overflow checking?
+        NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(device);
+        NSUInteger renderTargetSize =
+            ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(descriptor, context, device);
+        if (renderTargetSize > maxSize)
+        {
+            std::stringstream errorStream;
+            errorStream << "This set of render targets requires " << renderTargetSize
+                        << " bytes of pixel storage. This device supports " << maxSize << " bytes.";
+            ANGLE_MTL_HANDLE_ERROR(context, errorStream.str().c_str(), GL_INVALID_OPERATION);
+            return false;
+        }
+    }
+
+    return true;
+}
+
 AutoObjCPtr<id<MTLRenderPipelineState>> RenderPipelineCache::createRenderPipelineState(
     ContextMtl *context,
     const RenderPipelineDesc &originalDesc,
@@ -1005,22 +1061,9 @@
         // Convert to Objective-C desc:
         AutoObjCObj<MTLRenderPipelineDescriptor> objCDesc = ToObjC(vertShader, fragShader, desc);
 
-        // Validate Render Pipeline State:
-        if (DeviceHasMaximumRenderTargetSize(metalDevice))
+        if (!ValidateRenderPipelineState(objCDesc, context, metalDevice))
         {
-            // TODO: Is the use of NSUInteger in 32 bit systems ok without any overflow checking?
-            NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
-            NSUInteger renderTargetSize =
-                ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(objCDesc, context, metalDevice);
-            if (renderTargetSize > maxSize)
-            {
-                std::stringstream errorStream;
-                errorStream << "This set of render targets requires " << renderTargetSize
-                            << " bytes of pixel storage. This device supports " << maxSize
-                            << " bytes.";
-                ANGLE_MTL_HANDLE_ERROR(context, errorStream.str().c_str(), GL_INVALID_OPERATION);
-                return nil;
-            }
+            return nil;
         }
 
         // Special attribute slot for default attribute
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to