Metal: Handle potential OOM in other places.

This commit adds checks to (hopefully) all the remaining places in the
Metal backend where object creation can fail.

Bug: dawn:801

Change-Id: Ic27803e956beef822f94ca8449f7816ddd17c1bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/58722
Commit-Queue: Stephen White <senorblanco@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index 65a2178..d1c5b7c 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -223,10 +223,11 @@
         }
 
         // Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
-        NSPRef<id<MTLTexture>> CreateResolveTextureForWorkaround(Device* device,
-                                                                 MTLPixelFormat mtlFormat,
-                                                                 uint32_t width,
-                                                                 uint32_t height) {
+        ResultOrError<NSPRef<id<MTLTexture>>> CreateResolveTextureForWorkaround(
+            Device* device,
+            MTLPixelFormat mtlFormat,
+            uint32_t width,
+            uint32_t height) {
             NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
             MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
 
@@ -241,7 +242,12 @@
             mtlDesc.storageMode = MTLStorageModePrivate;
             mtlDesc.sampleCount = 1;
 
-            return AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc]);
+            id<MTLTexture> texture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
+            if (texture == nil) {
+                return DAWN_OUT_OF_MEMORY_ERROR("Allocation of temporary texture failed.");
+            }
+
+            return AcquireNSPRef(texture);
         }
 
         void CopyIntoTrueResolveTarget(CommandRecordingContext* commandContext,
@@ -1144,8 +1150,8 @@
                 trueResolveSlices[i] = mtlRenderPass.colorAttachments[i].resolveSlice;
 
                 const MTLPixelFormat mtlFormat = trueResolveTextures[i].pixelFormat;
-                temporaryResolveTextures[i] =
-                    CreateResolveTextureForWorkaround(device, mtlFormat, width, height);
+                DAWN_TRY_ASSIGN(temporaryResolveTextures[i], CreateResolveTextureForWorkaround(
+                                                                 device, mtlFormat, width, height));
 
                 mtlRenderPass.colorAttachments[i].resolveTexture =
                     temporaryResolveTextures[i].Get();
diff --git a/src/dawn_native/metal/ComputePipelineMTL.mm b/src/dawn_native/metal/ComputePipelineMTL.mm
index 860aa40..b98a369 100644
--- a/src/dawn_native/metal/ComputePipelineMTL.mm
+++ b/src/dawn_native/metal/ComputePipelineMTL.mm
@@ -43,9 +43,10 @@
             newComputePipelineStateWithFunction:computeData.function.Get()
                                           error:&error]);
         if (error != nullptr) {
-            NSLog(@" error => %@", error);
-            return DAWN_INTERNAL_ERROR("Error creating pipeline state");
+            return DAWN_INTERNAL_ERROR("Error creating pipeline state" +
+                                       std::string([error.localizedDescription UTF8String]));
         }
+        ASSERT(mMtlComputePipelineState != nil);
 
         // Copy over the local workgroup size as it is passed to dispatch explicitly in Metal
         Origin3D localSize = GetStage(SingleShaderStage::Compute).metadata->localWorkgroupSize;
diff --git a/src/dawn_native/metal/QuerySetMTL.mm b/src/dawn_native/metal/QuerySetMTL.mm
index 07cd786..dc06045 100644
--- a/src/dawn_native/metal/QuerySetMTL.mm
+++ b/src/dawn_native/metal/QuerySetMTL.mm
@@ -53,8 +53,8 @@
                 [device->GetMTLDevice() newCounterSampleBufferWithDescriptor:descriptor
                                                                        error:&error];
             if (error != nullptr) {
-                const char* errorString = [error.localizedDescription UTF8String];
-                return DAWN_INTERNAL_ERROR(std::string("Error creating query set: ") + errorString);
+                return DAWN_OUT_OF_MEMORY_ERROR(std::string("Error creating query set: ") +
+                                                [error.localizedDescription UTF8String]);
             }
 
             return counterSampleBuffer;
@@ -80,6 +80,10 @@
                 mVisibilityBuffer = AcquireNSPRef([device->GetMTLDevice()
                     newBufferWithLength:bufferSize
                                 options:MTLResourceStorageModePrivate]);
+
+                if (mVisibilityBuffer == nil) {
+                    return DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate query set.");
+                }
                 break;
             }
             case wgpu::QueryType::PipelineStatistics:
diff --git a/src/dawn_native/metal/RenderPipelineMTL.mm b/src/dawn_native/metal/RenderPipelineMTL.mm
index fb596d4..9ddcb56 100644
--- a/src/dawn_native/metal/RenderPipelineMTL.mm
+++ b/src/dawn_native/metal/RenderPipelineMTL.mm
@@ -406,20 +406,19 @@
         descriptorMTL.sampleCount = GetSampleCount();
         descriptorMTL.alphaToCoverageEnabled = IsAlphaToCoverageEnabled();
 
-        {
-            NSError* error = nullptr;
-            mMtlRenderPipelineState =
-                AcquireNSPRef([mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
-                                                                        error:&error]);
-            if (error != nullptr) {
-                NSLog(@" error => %@", error);
-                return DAWN_INTERNAL_ERROR("Error creating rendering pipeline state");
-            }
+        NSError* error = nullptr;
+        mMtlRenderPipelineState =
+            AcquireNSPRef([mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
+                                                                    error:&error]);
+        if (error != nullptr) {
+            return DAWN_INTERNAL_ERROR(std::string("Error creating pipeline state") +
+                                       [error.localizedDescription UTF8String]);
         }
+        ASSERT(mMtlRenderPipelineState != nil);
 
         // Create depth stencil state and cache it, fetch the cached depth stencil state when we
-        // call setDepthStencilState() for a given render pipeline in CommandEncoder, in order to
-        // improve performance.
+        // call setDepthStencilState() for a given render pipeline in CommandEncoder, in order
+        // to improve performance.
         NSRef<MTLDepthStencilDescriptor> depthStencilDesc =
             MakeDepthStencilDesc(GetDepthStencilState());
         mMtlDepthStencilState =
diff --git a/src/dawn_native/metal/SamplerMTL.h b/src/dawn_native/metal/SamplerMTL.h
index 98565ae..274ba20 100644
--- a/src/dawn_native/metal/SamplerMTL.h
+++ b/src/dawn_native/metal/SamplerMTL.h
@@ -33,7 +33,8 @@
         id<MTLSamplerState> GetMTLSamplerState();
 
       private:
-        Sampler(Device* device, const SamplerDescriptor* descriptor);
+        using SamplerBase::SamplerBase;
+        MaybeError Initialize(const SamplerDescriptor* descriptor);
 
         NSPRef<id<MTLSamplerState>> mMtlSamplerState;
     };
diff --git a/src/dawn_native/metal/SamplerMTL.mm b/src/dawn_native/metal/SamplerMTL.mm
index f1c4779..dae8d75 100644
--- a/src/dawn_native/metal/SamplerMTL.mm
+++ b/src/dawn_native/metal/SamplerMTL.mm
@@ -58,11 +58,12 @@
             return DAWN_VALIDATION_ERROR("Sampler compare function not supported.");
         }
 
-        return AcquireRef(new Sampler(device, descriptor));
+        Ref<Sampler> sampler = AcquireRef(new Sampler(device, descriptor));
+        DAWN_TRY(sampler->Initialize(descriptor));
+        return sampler;
     }
 
-    Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor)
-        : SamplerBase(device, descriptor) {
+    MaybeError Sampler::Initialize(const SamplerDescriptor* descriptor) {
         NSRef<MTLSamplerDescriptor> mtlDescRef = AcquireNSRef([MTLSamplerDescriptor new]);
         MTLSamplerDescriptor* mtlDesc = mtlDescRef.Get();
 
@@ -87,8 +88,13 @@
             // Metal debug device errors.
         }
 
-        mMtlSamplerState =
-            AcquireNSPRef([device->GetMTLDevice() newSamplerStateWithDescriptor:mtlDesc]);
+        mMtlSamplerState = AcquireNSPRef(
+            [ToBackend(GetDevice())->GetMTLDevice() newSamplerStateWithDescriptor:mtlDesc]);
+
+        if (mMtlSamplerState == nil) {
+            return DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate sampler.");
+        }
+        return {};
     }
 
     id<MTLSamplerState> Sampler::GetMTLSamplerState() {
diff --git a/src/dawn_native/metal/ShaderModuleMTL.mm b/src/dawn_native/metal/ShaderModuleMTL.mm
index 439e783..d9a9d44 100644
--- a/src/dawn_native/metal/ShaderModuleMTL.mm
+++ b/src/dawn_native/metal/ShaderModuleMTL.mm
@@ -332,11 +332,11 @@
                                                     error:&error]);
         if (error != nullptr) {
             if (error.code != MTLLibraryErrorCompileWarning) {
-                const char* errorString = [error.localizedDescription UTF8String];
                 return DAWN_VALIDATION_ERROR(std::string("Unable to create library object: ") +
-                                             errorString);
+                                             [error.localizedDescription UTF8String]);
             }
         }
+        ASSERT(library != nil);
 
         NSRef<NSString> name =
             AcquireNSRef([[NSString alloc] initWithUTF8String:remappedEntryPointName.c_str()]);