Metal: Handle failures in Texture and TextureView creation.

This includes OOM as well as internal driver failures when
creating a view of an MTLTexture. This required changing the code to use
the Create-Initialize pattern used everywhere else.

Bug: dawn:801

Change-Id: Ib8a8dec74141aacfa58a55bb8201a83351b3b739
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/58721
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn_native/metal/DeviceMTL.h b/src/dawn_native/metal/DeviceMTL.h
index 72c6443..4427418 100644
--- a/src/dawn_native/metal/DeviceMTL.h
+++ b/src/dawn_native/metal/DeviceMTL.h
@@ -53,7 +53,7 @@
         CommandRecordingContext* GetPendingCommandContext();
         void SubmitPendingCommandBuffer();
 
-        TextureBase* CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
+        Ref<Texture> CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
                                                     IOSurfaceRef ioSurface,
                                                     uint32_t plane);
         void WaitForCommandsToBeScheduled();
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 30e7f2a..0359698 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -409,7 +409,7 @@
         return {};
     }
 
-    TextureBase* Device::CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
+    Ref<Texture> Device::CreateTextureWrappingIOSurface(const ExternalImageDescriptor* descriptor,
                                                         IOSurfaceRef ioSurface,
                                                         uint32_t plane) {
         const TextureDescriptor* textureDescriptor =
@@ -423,7 +423,12 @@
             return nullptr;
         }
 
-        return new Texture(this, descriptor, ioSurface, plane);
+        Ref<Texture> result;
+        if (ConsumedError(Texture::CreateFromIOSurface(this, descriptor, ioSurface, plane),
+                          &result)) {
+            return nullptr;
+        }
+        return result;
     }
 
     void Device::WaitForCommandsToBeScheduled() {
diff --git a/src/dawn_native/metal/MetalBackend.mm b/src/dawn_native/metal/MetalBackend.mm
index 74265a23..b8fffaf 100644
--- a/src/dawn_native/metal/MetalBackend.mm
+++ b/src/dawn_native/metal/MetalBackend.mm
@@ -17,8 +17,8 @@
 
 #include "dawn_native/MetalBackend.h"
 
-#include "dawn_native/Texture.h"
 #include "dawn_native/metal/DeviceMTL.h"
+#include "dawn_native/metal/TextureMTL.h"
 
 namespace dawn_native { namespace metal {
 
@@ -34,9 +34,9 @@
     WGPUTexture WrapIOSurface(WGPUDevice cDevice,
                               const ExternalImageDescriptorIOSurface* cDescriptor) {
         Device* device = reinterpret_cast<Device*>(cDevice);
-        TextureBase* texture = device->CreateTextureWrappingIOSurface(
+        Ref<TextureBase> texture = device->CreateTextureWrappingIOSurface(
             cDescriptor, cDescriptor->ioSurface, cDescriptor->plane);
-        return reinterpret_cast<WGPUTexture>(texture);
+        return reinterpret_cast<WGPUTexture>(texture.Detach());
     }
 
     void WaitForCommandsToBeScheduled(WGPUDevice cDevice) {
diff --git a/src/dawn_native/metal/SwapChainMTL.mm b/src/dawn_native/metal/SwapChainMTL.mm
index d49ed70..84eb649 100644
--- a/src/dawn_native/metal/SwapChainMTL.mm
+++ b/src/dawn_native/metal/SwapChainMTL.mm
@@ -53,7 +53,8 @@
         }
 
         id<MTLTexture> nativeTexture = reinterpret_cast<id<MTLTexture>>(next.texture.ptr);
-        return new Texture(ToBackend(GetDevice()), descriptor, nativeTexture);
+
+        return Texture::CreateWrapping(ToBackend(GetDevice()), descriptor, nativeTexture).Detach();
     }
 
     MaybeError OldSwapChain::OnBeforePresent(TextureViewBase*) {
@@ -131,9 +132,8 @@
 
         TextureDescriptor textureDesc = GetSwapChainBaseTextureDescriptor(this);
 
-        // TODO(dawn:723): change to not use AcquireRef for reentrant object creation.
-        mTexture = AcquireRef(
-            new Texture(ToBackend(GetDevice()), &textureDesc, [*mCurrentDrawable texture]));
+        mTexture = Texture::CreateWrapping(ToBackend(GetDevice()), &textureDesc,
+                                           [*mCurrentDrawable texture]);
         // TODO(dawn:723): change to not use AcquireRef for reentrant object creation.
         return mTexture->APICreateView();
     }
diff --git a/src/dawn_native/metal/TextureMTL.h b/src/dawn_native/metal/TextureMTL.h
index c03adbf..07ffe23 100644
--- a/src/dawn_native/metal/TextureMTL.h
+++ b/src/dawn_native/metal/TextureMTL.h
@@ -38,14 +38,14 @@
       public:
         static ResultOrError<Ref<Texture>> Create(Device* device,
                                                   const TextureDescriptor* descriptor);
-
-        Texture(Device* device,
-                const TextureDescriptor* descriptor,
-                NSPRef<id<MTLTexture>> mtlTexture);
-        Texture(Device* device,
-                const ExternalImageDescriptor* descriptor,
-                IOSurfaceRef ioSurface,
-                uint32_t plane);
+        static ResultOrError<Ref<Texture>> CreateFromIOSurface(
+            Device* device,
+            const ExternalImageDescriptor* descriptor,
+            IOSurfaceRef ioSurface,
+            uint32_t plane);
+        static Ref<Texture> CreateWrapping(Device* device,
+                                           const TextureDescriptor* descriptor,
+                                           NSPRef<id<MTLTexture>> wrapped);
 
         id<MTLTexture> GetMTLTexture();
 
@@ -53,9 +53,17 @@
                                                  const SubresourceRange& range);
 
       private:
-        Texture(Device* device, const TextureDescriptor* descriptor);
+        using TextureBase::TextureBase;
         ~Texture() override;
 
+        MaybeError InitializeAsInternalTexture(const TextureDescriptor* descriptor);
+        MaybeError InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
+                                           const TextureDescriptor* textureDescriptor,
+                                           IOSurfaceRef ioSurface,
+                                           uint32_t plane);
+        void InitializeAsWrapping(const TextureDescriptor* descriptor,
+                                  NSPRef<id<MTLTexture>> wrapped);
+
         void DestroyImpl() override;
 
         MaybeError ClearTexture(CommandRecordingContext* commandContext,
@@ -74,7 +82,8 @@
         id<MTLTexture> GetMTLTexture();
 
       private:
-        TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor);
+        using TextureViewBase::TextureViewBase;
+        MaybeError Initialize(const TextureViewDescriptor* descriptor);
 
         NSPRef<id<MTLTexture>> mMtlTextureView;
     };
diff --git a/src/dawn_native/metal/TextureMTL.mm b/src/dawn_native/metal/TextureMTL.mm
index 8cc642e..3567738 100644
--- a/src/dawn_native/metal/TextureMTL.mm
+++ b/src/dawn_native/metal/TextureMTL.mm
@@ -352,49 +352,82 @@
     // static
     ResultOrError<Ref<Texture>> Texture::Create(Device* device,
                                                 const TextureDescriptor* descriptor) {
-        return AcquireRef(new Texture(device, descriptor));
+        Ref<Texture> texture =
+            AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal));
+        DAWN_TRY(texture->InitializeAsInternalTexture(descriptor));
+        return texture;
     }
 
-    Texture::Texture(Device* device, const TextureDescriptor* descriptor)
-        : TextureBase(device, descriptor, TextureState::OwnedInternal) {
+    // static
+    ResultOrError<Ref<Texture>> Texture::CreateFromIOSurface(
+        Device* device,
+        const ExternalImageDescriptor* descriptor,
+        IOSurfaceRef ioSurface,
+        uint32_t plane) {
+        const TextureDescriptor* textureDescriptor =
+            reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor);
+
+        Ref<Texture> texture =
+            AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedInternal));
+        DAWN_TRY(texture->InitializeFromIOSurface(descriptor, textureDescriptor, ioSurface, plane));
+        return texture;
+    }
+
+    // static
+    Ref<Texture> Texture::CreateWrapping(Device* device,
+                                         const TextureDescriptor* descriptor,
+                                         NSPRef<id<MTLTexture>> wrapped) {
+        Ref<Texture> texture =
+            AcquireRef(new Texture(device, descriptor, TextureState::OwnedInternal));
+        texture->InitializeAsWrapping(descriptor, std::move(wrapped));
+        return texture;
+    }
+
+    MaybeError Texture::InitializeAsInternalTexture(const TextureDescriptor* descriptor) {
+        Device* device = ToBackend(GetDevice());
+
         NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
+        mMtlUsage = [*mtlDesc usage];
         mMtlTexture =
             AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
-        mMtlUsage = [*mtlDesc usage];
+
+        if (mMtlTexture == nil) {
+            return DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate texture.");
+        }
 
         if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
-            device->ConsumedError(ClearTexture(device->GetPendingCommandContext(),
-                                               GetAllSubresources(),
-                                               TextureBase::ClearValue::NonZero));
+            DAWN_TRY(ClearTexture(device->GetPendingCommandContext(), GetAllSubresources(),
+                                  TextureBase::ClearValue::NonZero));
         }
+
+        return {};
     }
 
-    Texture::Texture(Device* device,
-                     const TextureDescriptor* descriptor,
-                     NSPRef<id<MTLTexture>> mtlTexture)
-        : TextureBase(device, descriptor, TextureState::OwnedInternal),
-          mMtlTexture(std::move(mtlTexture)) {
-        NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
+    void Texture::InitializeAsWrapping(const TextureDescriptor* descriptor,
+                                       NSPRef<id<MTLTexture>> wrapped) {
+        NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(GetDevice(), descriptor);
         mMtlUsage = [*mtlDesc usage];
+        mMtlTexture = std::move(wrapped);
     }
 
-    Texture::Texture(Device* device,
-                     const ExternalImageDescriptor* descriptor,
-                     IOSurfaceRef ioSurface,
-                     uint32_t plane)
-        : TextureBase(device,
-                      reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor),
-                      TextureState::OwnedInternal) {
-        NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(
-            device, reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
+    MaybeError Texture::InitializeFromIOSurface(const ExternalImageDescriptor* descriptor,
+                                                const TextureDescriptor* textureDescriptor,
+                                                IOSurfaceRef ioSurface,
+                                                uint32_t plane) {
+        Device* device = ToBackend(GetDevice());
+
+        NSRef<MTLTextureDescriptor> mtlDesc =
+            CreateMetalTextureDescriptor(device, textureDescriptor);
         [*mtlDesc setStorageMode:kIOSurfaceStorageMode];
 
+        mMtlUsage = [*mtlDesc usage];
         mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
                                                                            iosurface:ioSurface
                                                                                plane:plane]);
-        mMtlUsage = [*mtlDesc usage];
 
         SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
+
+        return {};
     }
 
     Texture::~Texture() {
@@ -625,12 +658,14 @@
     // static
     ResultOrError<Ref<TextureView>> TextureView::Create(TextureBase* texture,
                                                         const TextureViewDescriptor* descriptor) {
-        return AcquireRef(new TextureView(texture, descriptor));
+        Ref<TextureView> view = AcquireRef(new TextureView(texture, descriptor));
+        DAWN_TRY(view->Initialize(descriptor));
+        return view;
     }
 
-    TextureView::TextureView(TextureBase* texture, const TextureViewDescriptor* descriptor)
-        : TextureViewBase(texture, descriptor) {
-        id<MTLTexture> mtlTexture = ToBackend(texture)->GetMTLTexture();
+    MaybeError TextureView::Initialize(const TextureViewDescriptor* descriptor) {
+        Texture* texture = ToBackend(GetTexture());
+        id<MTLTexture> mtlTexture = texture->GetMTLTexture();
 
         if (!UsageNeedsTextureView(texture->GetUsage())) {
             mMtlTextureView = nullptr;
@@ -663,7 +698,12 @@
                                                             textureType:textureViewType
                                                                  levels:mipLevelRange
                                                                  slices:arrayLayerRange]);
+            if (mMtlTextureView == nil) {
+                return DAWN_INTERNAL_ERROR("Failed to create MTLTexture view.");
+            }
         }
+
+        return {};
     }
 
     id<MTLTexture> TextureView::GetMTLTexture() {