[graphite] Move Dawn BindGroupLayouts from ResourceProvider to SharedContext

This reduces race conditions wrt the ResourceProvider's lifetime. I've tried to make this CL as mechanical as possible.

Bug: b/434712686
Change-Id: Ifa7c860f464d710999cf109bed9526d792b9149c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1056196
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Thomas Smith <thomsmit@google.com>
diff --git a/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp b/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
index 4a4f856..2646bfb 100644
--- a/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
+++ b/src/gpu/graphite/dawn/DawnGraphicsPipeline.cpp
@@ -492,7 +492,7 @@
     skia_private::TArray<sk_sp<DawnSampler>> immutableSamplers;
     {
         SkASSERT(resourceProvider);
-        groupLayouts[0] = resourceProvider->getOrCreateUniformBuffersBindGroupLayout();
+        groupLayouts[0] = sharedContext->getUniformBuffersBindGroupLayout();
         if (!groupLayouts[0]) {
             return {};
         }
@@ -502,8 +502,7 @@
             // Check if we can optimize for the common case of a single texture + 1 dynamic sampler
             if (numTexturesAndSamplers == 2 &&
                 !(samplerDescArrPtr && samplerDescArrPtr->at(0).isImmutable())) {
-                groupLayouts[1] =
-                        resourceProvider->getOrCreateSingleTextureSamplerBindGroupLayout();
+                groupLayouts[1] = sharedContext->getSingleTextureSamplerBindGroupLayout();
             } else {
                 std::vector<wgpu::BindGroupLayoutEntry> entries(numTexturesAndSamplers);
 #if !defined(__EMSCRIPTEN__)
diff --git a/src/gpu/graphite/dawn/DawnResourceProvider.cpp b/src/gpu/graphite/dawn/DawnResourceProvider.cpp
index 5efcaaa..ed6ef53 100644
--- a/src/gpu/graphite/dawn/DawnResourceProvider.cpp
+++ b/src/gpu/graphite/dawn/DawnResourceProvider.cpp
@@ -636,93 +636,6 @@
     return sk_sp<DawnBuffer>(ptr);
 }
 
-const wgpu::BindGroupLayout& DawnResourceProvider::getOrCreateUniformBuffersBindGroupLayout() {
-    SKGPU_ASSERT_SINGLE_OWNER(fSingleOwner)
-
-    if (fUniformBuffersBindGroupLayout) {
-        return fUniformBuffersBindGroupLayout;
-    }
-
-    std::array<wgpu::BindGroupLayoutEntry, 4> entries;
-    entries[0].binding = DawnGraphicsPipeline::kIntrinsicUniformBufferIndex;
-    entries[0].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
-    entries[0].buffer.type = wgpu::BufferBindingType::Uniform;
-    entries[0].buffer.hasDynamicOffset = true;
-    entries[0].buffer.minBindingSize = 0;
-
-    entries[1].binding = DawnGraphicsPipeline::kRenderStepUniformBufferIndex;
-    entries[1].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
-    entries[1].buffer.type = fSharedContext->caps()->storageBufferSupport()
-                                     ? wgpu::BufferBindingType::ReadOnlyStorage
-                                     : wgpu::BufferBindingType::Uniform;
-    entries[1].buffer.hasDynamicOffset = true;
-    entries[1].buffer.minBindingSize = 0;
-
-    entries[2].binding = DawnGraphicsPipeline::kPaintUniformBufferIndex;
-    entries[2].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
-    entries[2].buffer.type = fSharedContext->caps()->storageBufferSupport()
-                                     ? wgpu::BufferBindingType::ReadOnlyStorage
-                                     : wgpu::BufferBindingType::Uniform;
-    entries[2].buffer.hasDynamicOffset = true;
-    entries[2].buffer.minBindingSize = 0;
-
-    // Gradient buffer will only be used when storage buffers are preferred, else large
-    // gradients use a texture fallback, set binding type as a uniform when not in use to
-    // satisfy any binding type restricions for non-supported ssbo devices.
-    entries[3].binding = DawnGraphicsPipeline::kGradientBufferIndex;
-    entries[3].visibility = wgpu::ShaderStage::Fragment;
-    entries[3].buffer.type = fSharedContext->caps()->storageBufferSupport()
-                                     ? wgpu::BufferBindingType::ReadOnlyStorage
-                                     : wgpu::BufferBindingType::Uniform;
-    entries[3].buffer.hasDynamicOffset = true;
-    entries[3].buffer.minBindingSize = 0;
-
-    wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
-    if (fSharedContext->caps()->setBackendLabels()) {
-        groupLayoutDesc.label = "Uniform buffers bind group layout";
-    }
-
-    groupLayoutDesc.entryCount = entries.size();
-    groupLayoutDesc.entries = entries.data();
-    fUniformBuffersBindGroupLayout =
-            this->dawnSharedContext()->device().CreateBindGroupLayout(&groupLayoutDesc);
-
-    return fUniformBuffersBindGroupLayout;
-}
-
-const wgpu::BindGroupLayout&
-DawnResourceProvider::getOrCreateSingleTextureSamplerBindGroupLayout() {
-    SKGPU_ASSERT_SINGLE_OWNER(fSingleOwner)
-
-    if (fSingleTextureSamplerBindGroupLayout) {
-        return fSingleTextureSamplerBindGroupLayout;
-    }
-
-    std::array<wgpu::BindGroupLayoutEntry, 2> entries;
-
-    entries[0].binding = 0;
-    entries[0].visibility = wgpu::ShaderStage::Fragment;
-    entries[0].sampler.type = wgpu::SamplerBindingType::Filtering;
-
-    entries[1].binding = 1;
-    entries[1].visibility = wgpu::ShaderStage::Fragment;
-    entries[1].texture.sampleType = wgpu::TextureSampleType::Float;
-    entries[1].texture.viewDimension = wgpu::TextureViewDimension::e2D;
-    entries[1].texture.multisampled = false;
-
-    wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
-    if (fSharedContext->caps()->setBackendLabels()) {
-        groupLayoutDesc.label = "Single texture + sampler bind group layout";
-    }
-
-    groupLayoutDesc.entryCount = entries.size();
-    groupLayoutDesc.entries = entries.data();
-    fSingleTextureSamplerBindGroupLayout =
-            this->dawnSharedContext()->device().CreateBindGroupLayout(&groupLayoutDesc);
-
-    return fSingleTextureSamplerBindGroupLayout;
-}
-
 const wgpu::Buffer& DawnResourceProvider::getOrCreateNullBuffer() {
     if (!fNullBuffer) {
         wgpu::BufferDescriptor desc;
@@ -779,7 +692,7 @@
     }
 
     wgpu::BindGroupDescriptor desc;
-    desc.layout = this->getOrCreateUniformBuffersBindGroupLayout();
+    desc.layout = this->dawnSharedContext()->getUniformBuffersBindGroupLayout();
     desc.entryCount = entries.size();
     desc.entries = entries.data();
 
@@ -808,7 +721,7 @@
     entries[1].textureView = texture->sampleTextureView();
 
     wgpu::BindGroupDescriptor desc;
-    desc.layout = getOrCreateSingleTextureSamplerBindGroupLayout();
+    desc.layout = this->dawnSharedContext()->getSingleTextureSamplerBindGroupLayout();
     desc.entryCount = entries.size();
     desc.entries = entries.data();
 
diff --git a/src/gpu/graphite/dawn/DawnResourceProvider.h b/src/gpu/graphite/dawn/DawnResourceProvider.h
index 448a6c2..ce95d21 100644
--- a/src/gpu/graphite/dawn/DawnResourceProvider.h
+++ b/src/gpu/graphite/dawn/DawnResourceProvider.h
@@ -65,9 +65,6 @@
                                              AccessPattern,
                                              std::string_view label);
 
-    const wgpu::BindGroupLayout& getOrCreateUniformBuffersBindGroupLayout();
-    const wgpu::BindGroupLayout& getOrCreateSingleTextureSamplerBindGroupLayout();
-
     // Find the cached bind group or create a new one based on the bound buffers and their
     // binding sizes (boundBuffersAndSizes) for these uniforms (in order):
     // - Intrinsic constants.
@@ -113,9 +110,6 @@
 
     skia_private::THashMap<uint32_t, wgpu::RenderPipeline> fBlitWithDrawPipelines;
 
-    wgpu::BindGroupLayout fUniformBuffersBindGroupLayout;
-    wgpu::BindGroupLayout fSingleTextureSamplerBindGroupLayout;
-
     wgpu::Buffer fNullBuffer;
 
     template <size_t NumEntries>
diff --git a/src/gpu/graphite/dawn/DawnSharedContext.cpp b/src/gpu/graphite/dawn/DawnSharedContext.cpp
index 5525b4a..173a66e 100644
--- a/src/gpu/graphite/dawn/DawnSharedContext.cpp
+++ b/src/gpu/graphite/dawn/DawnSharedContext.cpp
@@ -11,6 +11,7 @@
 #include "include/gpu/graphite/ContextOptions.h"
 #include "include/gpu/graphite/dawn/DawnBackendContext.h"
 #include "src/gpu/graphite/Log.h"
+#include "src/gpu/graphite/dawn/DawnGraphicsPipeline.h"
 #include "src/gpu/graphite/dawn/DawnResourceProvider.h"
 
 #include "webgpu/webgpu_cpp.h"  // NO_G3_REWRITE
@@ -69,7 +70,10 @@
         , fDevice(backendContext.fDevice)
         , fQueue(backendContext.fQueue)
         , fTick(backendContext.fTick)
-        , fNoopFragment(std::move(noopFragment)) {}
+        , fNoopFragment(std::move(noopFragment)) {
+    this->createUniformBuffersBindGroupLayout();
+    this->createSingleTextureSamplerBindGroupLayout();
+}
 
 DawnSharedContext::~DawnSharedContext() {
     // need to clear out resources before any allocator is removed
@@ -93,4 +97,76 @@
     context->checkAsyncWorkCompletion();
 };
 
+void DawnSharedContext::createUniformBuffersBindGroupLayout() {
+    const Caps* caps = this->caps();
+
+    std::array<wgpu::BindGroupLayoutEntry, 4> entries;
+    entries[0].binding = DawnGraphicsPipeline::kIntrinsicUniformBufferIndex;
+    entries[0].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
+    entries[0].buffer.type = wgpu::BufferBindingType::Uniform;
+    entries[0].buffer.hasDynamicOffset = true;
+    entries[0].buffer.minBindingSize = 0;
+
+    entries[1].binding = DawnGraphicsPipeline::kRenderStepUniformBufferIndex;
+    entries[1].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
+    entries[1].buffer.type = caps->storageBufferSupport()
+                                     ? wgpu::BufferBindingType::ReadOnlyStorage
+                                     : wgpu::BufferBindingType::Uniform;
+    entries[1].buffer.hasDynamicOffset = true;
+    entries[1].buffer.minBindingSize = 0;
+
+    entries[2].binding = DawnGraphicsPipeline::kPaintUniformBufferIndex;
+    entries[2].visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment;
+    entries[2].buffer.type = caps->storageBufferSupport()
+                                     ? wgpu::BufferBindingType::ReadOnlyStorage
+                                     : wgpu::BufferBindingType::Uniform;
+    entries[2].buffer.hasDynamicOffset = true;
+    entries[2].buffer.minBindingSize = 0;
+
+    // Gradient buffer will only be used when storage buffers are preferred, else large
+    // gradients use a texture fallback, set binding type as a uniform when not in use to
+    // satisfy any binding type restrictions for non-supported ssbo devices.
+    entries[3].binding = DawnGraphicsPipeline::kGradientBufferIndex;
+    entries[3].visibility = wgpu::ShaderStage::Fragment;
+    entries[3].buffer.type = caps->storageBufferSupport()
+                                     ? wgpu::BufferBindingType::ReadOnlyStorage
+                                     : wgpu::BufferBindingType::Uniform;
+    entries[3].buffer.hasDynamicOffset = true;
+    entries[3].buffer.minBindingSize = 0;
+
+    wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
+    if (caps->setBackendLabels()) {
+        groupLayoutDesc.label = "Uniform buffers bind group layout";
+    }
+
+    groupLayoutDesc.entryCount = entries.size();
+    groupLayoutDesc.entries = entries.data();
+    fUniformBuffersBindGroupLayout = this->device().CreateBindGroupLayout(&groupLayoutDesc);
+}
+
+void DawnSharedContext::createSingleTextureSamplerBindGroupLayout() {
+    const Caps* caps = this->caps();
+
+    std::array<wgpu::BindGroupLayoutEntry, 2> entries;
+
+    entries[0].binding = 0;
+    entries[0].visibility = wgpu::ShaderStage::Fragment;
+    entries[0].sampler.type = wgpu::SamplerBindingType::Filtering;
+
+    entries[1].binding = 1;
+    entries[1].visibility = wgpu::ShaderStage::Fragment;
+    entries[1].texture.sampleType = wgpu::TextureSampleType::Float;
+    entries[1].texture.viewDimension = wgpu::TextureViewDimension::e2D;
+    entries[1].texture.multisampled = false;
+
+    wgpu::BindGroupLayoutDescriptor groupLayoutDesc;
+    if (caps->setBackendLabels()) {
+        groupLayoutDesc.label = "Single texture + sampler bind group layout";
+    }
+
+    groupLayoutDesc.entryCount = entries.size();
+    groupLayoutDesc.entries = entries.data();
+    fSingleTextureSamplerBindGroupLayout = this->device().CreateBindGroupLayout(&groupLayoutDesc);
+}
+
 } // namespace skgpu::graphite
diff --git a/src/gpu/graphite/dawn/DawnSharedContext.h b/src/gpu/graphite/dawn/DawnSharedContext.h
index b45f66a..a94bfe2 100644
--- a/src/gpu/graphite/dawn/DawnSharedContext.h
+++ b/src/gpu/graphite/dawn/DawnSharedContext.h
@@ -43,6 +43,13 @@
 
     void deviceTick(Context*) override;
 
+    const wgpu::BindGroupLayout& getUniformBuffersBindGroupLayout() const {
+        return fUniformBuffersBindGroupLayout;
+    }
+    const wgpu::BindGroupLayout& getSingleTextureSamplerBindGroupLayout() const {
+        return fSingleTextureSamplerBindGroupLayout;
+    }
+
 private:
     DawnSharedContext(const DawnBackendContext&,
                       std::unique_ptr<const DawnCaps>,
@@ -50,6 +57,9 @@
                       SkExecutor*,
                       SkSpan<sk_sp<SkRuntimeEffect>> userDefinedKnownRuntimeEffects);
 
+    void createUniformBuffersBindGroupLayout();
+    void createSingleTextureSamplerBindGroupLayout();
+
     wgpu::Instance     fInstance;
     wgpu::Device       fDevice;
     wgpu::Queue        fQueue;
@@ -57,6 +67,9 @@
     // A noop fragment shader, it is used to workaround dawn a validation error(dawn doesn't allow
     // a pipeline with a color attachment but without a fragment shader).
     wgpu::ShaderModule fNoopFragment;
+
+    wgpu::BindGroupLayout fUniformBuffersBindGroupLayout;
+    wgpu::BindGroupLayout fSingleTextureSamplerBindGroupLayout;
 };
 
 } // namespace skgpu::graphite