CommandBufferResourceUsage: track render and compute separately.

This change is a preparation for making the compute pass track the
synchronization scope usages per dispatch instead of for the whole pass.

 - Split the tracking of render and compute passes usages.
 - Rename PassTextureUsage to TextureSubresourceUsage since is it not
   per-pass
 - Add SyncScopeResourceUsage as a subclass of PassResourceUsage to
   start modifying some of the code to work with synchronization scopes
   (even if syncscope == pass at the moment).

There are no functional changes.

Bug: dawn:632
Change-Id: Ieeb6d70a44dc1c726f26989eebcd87e63e732785
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/49883
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/Buffer.cpp b/src/dawn_native/Buffer.cpp
index e8bb23f..3ddb72b 100644
--- a/src/dawn_native/Buffer.cpp
+++ b/src/dawn_native/Buffer.cpp
@@ -133,8 +133,7 @@
           mUsage(descriptor->usage),
           mState(BufferState::Unmapped) {
         // Add readonly storage usage if the buffer has a storage usage. The validation rules in
-        // ValidatePassResourceUsage will make sure we don't use both at the same
-        // time.
+        // ValidateSyncScopeResourceUsage will make sure we don't use both at the same time.
         if (mUsage & wgpu::BufferUsage::Storage) {
             mUsage |= kReadOnlyStorageBuffer;
         }
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 97f7320..21060e4 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -470,9 +470,9 @@
     }
 
     CommandBufferResourceUsage CommandEncoder::AcquireResourceUsages() {
-        return CommandBufferResourceUsage{mEncodingContext.AcquirePassUsages(),
-                                          std::move(mTopLevelBuffers), std::move(mTopLevelTextures),
-                                          std::move(mUsedQuerySets)};
+        return CommandBufferResourceUsage{
+            mEncodingContext.AcquireRenderPassUsages(), mEncodingContext.AcquireComputePassUsages(),
+            std::move(mTopLevelBuffers), std::move(mTopLevelTextures), std::move(mUsedQuerySets)};
     }
 
     CommandIterator CommandEncoder::AcquireCommands() {
@@ -936,21 +936,21 @@
         DAWN_TRY(device->ValidateIsAlive());
 
         if (device->IsValidationEnabled()) {
-            DAWN_TRY(
-                ValidateFinish(mEncodingContext.GetIterator(), mEncodingContext.GetPassUsages()));
+            DAWN_TRY(ValidateFinish());
         }
         return device->CreateCommandBuffer(this, descriptor);
     }
 
     // Implementation of the command buffer validation that can be precomputed before submit
-    MaybeError CommandEncoder::ValidateFinish(CommandIterator* commands,
-                                              const PerPassUsages& perPassUsages) const {
+    MaybeError CommandEncoder::ValidateFinish() const {
         TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "CommandEncoder::ValidateFinish");
         DAWN_TRY(GetDevice()->ValidateObject(this));
 
-        for (const PassResourceUsage& passUsage : perPassUsages) {
-            DAWN_TRY(ValidatePassResourceUsage(passUsage));
+        for (const PassResourceUsage& passUsage : mEncodingContext.GetRenderPassUsages()) {
+            DAWN_TRY(ValidateSyncScopeResourceUsage(passUsage));
         }
+        // TODO(dawn:632): The synchronization scopes of compute passes should be validated here
+        // once they are tracked per-dispatch.
 
         if (mDebugGroupStackSize != 0) {
             return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
diff --git a/src/dawn_native/CommandEncoder.h b/src/dawn_native/CommandEncoder.h
index a8bf6a0..13678f1 100644
--- a/src/dawn_native/CommandEncoder.h
+++ b/src/dawn_native/CommandEncoder.h
@@ -73,8 +73,7 @@
         ResultOrError<Ref<CommandBufferBase>> FinishInternal(
             const CommandBufferDescriptor* descriptor);
 
-        MaybeError ValidateFinish(CommandIterator* commands,
-                                  const PerPassUsages& perPassUsages) const;
+        MaybeError ValidateFinish() const;
 
         EncodingContext mEncodingContext;
         std::set<BufferBase*> mTopLevelBuffers;
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 1e2fc38..05e3a9e 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -28,20 +28,10 @@
 
 namespace dawn_native {
 
-    // Performs the per-pass usage validation checks
-    // This will eventually need to differentiate between render and compute passes.
-    // It will be valid to use a buffer both as uniform and storage in the same compute pass.
-    // TODO(yunchao.he@intel.com): add read/write usage tracking for compute
-    MaybeError ValidatePassResourceUsage(const PassResourceUsage& pass) {
-        // TODO(cwallez@chromium.org): Remove this special casing once the PassResourceUsage is a
-        // SyncScopeResourceUsage.
-        if (pass.passType != PassType::Render) {
-            return {};
-        }
-
+    // Performs validation of the "synchronization scope" rules of WebGPU.
+    MaybeError ValidateSyncScopeResourceUsage(const SyncScopeResourceUsage& scope) {
         // Buffers can only be used as single-write or multiple read.
-        for (size_t i = 0; i < pass.buffers.size(); ++i) {
-            wgpu::BufferUsage usage = pass.bufferUsages[i];
+        for (wgpu::BufferUsage usage : scope.bufferUsages) {
             bool readOnly = IsSubset(usage, kReadOnlyBufferUsages);
             bool singleUse = wgpu::HasZeroOrOneBits(usage);
 
@@ -53,7 +43,7 @@
 
         // Check that every single subresource is used as either a single-write usage or a
         // combination of readonly usages.
-        for (const PassTextureUsage& textureUsage : pass.textureUsages) {
+        for (const TextureSubresourceUsage& textureUsage : scope.textureUsages) {
             MaybeError error = {};
             textureUsage.Iterate([&](const SubresourceRange&, const wgpu::TextureUsage& usage) {
                 bool readOnly = IsSubset(usage, kReadOnlyTextureUsages);
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index 9c8a42f..7b5fce2 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -24,10 +24,10 @@
 namespace dawn_native {
 
     class QuerySetBase;
-    struct PassResourceUsage;
+    struct SyncScopeResourceUsage;
     struct TexelBlockInfo;
 
-    MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
+    MaybeError ValidateSyncScopeResourceUsage(const SyncScopeResourceUsage& usage);
 
     MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
 
diff --git a/src/dawn_native/ComputePassEncoder.cpp b/src/dawn_native/ComputePassEncoder.cpp
index 04bb8ff..666235e 100644
--- a/src/dawn_native/ComputePassEncoder.cpp
+++ b/src/dawn_native/ComputePassEncoder.cpp
@@ -55,7 +55,8 @@
 
                 return {};
             })) {
-            mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
+            mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage(),
+                                       PassType::Compute);
         }
     }
 
diff --git a/src/dawn_native/EncodingContext.cpp b/src/dawn_native/EncodingContext.cpp
index 39b5d4c..acdecd7 100644
--- a/src/dawn_native/EncodingContext.cpp
+++ b/src/dawn_native/EncodingContext.cpp
@@ -76,25 +76,43 @@
         mCurrentEncoder = passEncoder;
     }
 
-    void EncodingContext::ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsage) {
+    void EncodingContext::ExitPass(const ObjectBase* passEncoder,
+                                   PassResourceUsage passUsage,
+                                   PassType type) {
         // Assert we're not at the top level.
         ASSERT(mCurrentEncoder != mTopLevelEncoder);
         // Assert the pass encoder is current.
         ASSERT(mCurrentEncoder == passEncoder);
 
         mCurrentEncoder = mTopLevelEncoder;
-        mPassUsages.push_back(std::move(passUsage));
+
+        if (type == PassType::Render) {
+            mRenderPassUsages.push_back(std::move(passUsage));
+        } else {
+            mComputePassUsages.push_back(std::move(passUsage));
+        }
     }
 
-    const PerPassUsages& EncodingContext::GetPassUsages() const {
-        ASSERT(!mWerePassUsagesAcquired);
-        return mPassUsages;
+    const RenderPassUsages& EncodingContext::GetRenderPassUsages() const {
+        ASSERT(!mWereRenderPassUsagesAcquired);
+        return mRenderPassUsages;
     }
 
-    PerPassUsages EncodingContext::AcquirePassUsages() {
-        ASSERT(!mWerePassUsagesAcquired);
-        mWerePassUsagesAcquired = true;
-        return std::move(mPassUsages);
+    RenderPassUsages EncodingContext::AcquireRenderPassUsages() {
+        ASSERT(!mWereRenderPassUsagesAcquired);
+        mWereRenderPassUsagesAcquired = true;
+        return std::move(mRenderPassUsages);
+    }
+
+    const ComputePassUsages& EncodingContext::GetComputePassUsages() const {
+        ASSERT(!mWereComputePassUsagesAcquired);
+        return mComputePassUsages;
+    }
+
+    ComputePassUsages EncodingContext::AcquireComputePassUsages() {
+        ASSERT(!mWereComputePassUsagesAcquired);
+        mWereComputePassUsagesAcquired = true;
+        return std::move(mComputePassUsages);
     }
 
     MaybeError EncodingContext::Finish() {
diff --git a/src/dawn_native/EncodingContext.h b/src/dawn_native/EncodingContext.h
index e74819a..f181e57 100644
--- a/src/dawn_native/EncodingContext.h
+++ b/src/dawn_native/EncodingContext.h
@@ -79,11 +79,13 @@
 
         // Functions to set current encoder state
         void EnterPass(const ObjectBase* passEncoder);
-        void ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsages);
+        void ExitPass(const ObjectBase* passEncoder, PassResourceUsage passUsages, PassType type);
         MaybeError Finish();
 
-        const PerPassUsages& GetPassUsages() const;
-        PerPassUsages AcquirePassUsages();
+        const RenderPassUsages& GetRenderPassUsages() const;
+        const ComputePassUsages& GetComputePassUsages() const;
+        RenderPassUsages AcquireRenderPassUsages();
+        ComputePassUsages AcquireComputePassUsages();
 
       private:
         bool IsFinished() const;
@@ -101,8 +103,10 @@
         // CommandEncoder::Begin/EndPass.
         const ObjectBase* mCurrentEncoder;
 
-        PerPassUsages mPassUsages;
-        bool mWerePassUsagesAcquired = false;
+        RenderPassUsages mRenderPassUsages;
+        bool mWereRenderPassUsagesAcquired = false;
+        ComputePassUsages mComputePassUsages;
+        bool mWereComputePassUsagesAcquired = false;
 
         CommandAllocator mAllocator;
         CommandIterator mIterator;
diff --git a/src/dawn_native/PassResourceUsage.h b/src/dawn_native/PassResourceUsage.h
index 772f8c2..0f64346 100644
--- a/src/dawn_native/PassResourceUsage.h
+++ b/src/dawn_native/PassResourceUsage.h
@@ -30,27 +30,31 @@
     enum class PassType { Render, Compute };
 
     // The texture usage inside passes must be tracked per-subresource.
-    using PassTextureUsage = SubresourceStorage<wgpu::TextureUsage>;
+    using TextureSubresourceUsage = SubresourceStorage<wgpu::TextureUsage>;
 
-    // Which resources are used by pass and how they are used. The command buffer validation
-    // pre-computes this information so that backends with explicit barriers don't have to
-    // re-compute it.
-    struct PassResourceUsage {
-        PassType passType;
+    // Which resources are used by a synchronization scope and how they are used. The command
+    // buffer validation pre-computes this information so that backends with explicit barriers
+    // don't have to re-compute it.
+    struct SyncScopeResourceUsage {
         std::vector<BufferBase*> buffers;
         std::vector<wgpu::BufferUsage> bufferUsages;
 
         std::vector<TextureBase*> textures;
-        std::vector<PassTextureUsage> textureUsages;
+        std::vector<TextureSubresourceUsage> textureUsages;
+    };
 
+    // Additional data tracked per-pass.
+    struct PassResourceUsage : public SyncScopeResourceUsage {
         std::vector<QuerySetBase*> querySets;
         std::vector<std::vector<bool>> queryAvailabilities;
     };
 
-    using PerPassUsages = std::vector<PassResourceUsage>;
+    using RenderPassUsages = std::vector<PassResourceUsage>;
+    using ComputePassUsages = std::vector<PassResourceUsage>;
 
     struct CommandBufferResourceUsage {
-        PerPassUsages perPass;
+        RenderPassUsages renderPasses;
+        ComputePassUsages computePasses;
         std::set<BufferBase*> topLevelBuffers;
         std::set<TextureBase*> topLevelTextures;
         std::set<QuerySetBase*> usedQuerySets;
diff --git a/src/dawn_native/PassResourceUsageTracker.cpp b/src/dawn_native/PassResourceUsageTracker.cpp
index 81d72ed..806d40b 100644
--- a/src/dawn_native/PassResourceUsageTracker.cpp
+++ b/src/dawn_native/PassResourceUsageTracker.cpp
@@ -37,13 +37,13 @@
         TextureBase* texture = view->GetTexture();
         const SubresourceRange& range = view->GetSubresourceRange();
 
-        // Get or create a new PassTextureUsage for that texture (initially filled with
+        // Get or create a new TextureSubresourceUsage for that texture (initially filled with
         // wgpu::TextureUsage::None)
         auto it = mTextureUsages.emplace(
             std::piecewise_construct, std::forward_as_tuple(texture),
             std::forward_as_tuple(texture->GetFormat().aspects, texture->GetArrayLayers(),
                                   texture->GetNumMipLevels(), wgpu::TextureUsage::None));
-        PassTextureUsage& textureUsage = it.first->second;
+        TextureSubresourceUsage& textureUsage = it.first->second;
 
         textureUsage.Update(range,
                             [usage](const SubresourceRange&, wgpu::TextureUsage* storedUsage) {
@@ -52,14 +52,14 @@
     }
 
     void PassResourceUsageTracker::AddTextureUsage(TextureBase* texture,
-                                                   const PassTextureUsage& textureUsage) {
-        // Get or create a new PassTextureUsage for that texture (initially filled with
+                                                   const TextureSubresourceUsage& textureUsage) {
+        // Get or create a new TextureSubresourceUsage for that texture (initially filled with
         // wgpu::TextureUsage::None)
         auto it = mTextureUsages.emplace(
             std::piecewise_construct, std::forward_as_tuple(texture),
             std::forward_as_tuple(texture->GetFormat().aspects, texture->GetArrayLayers(),
                                   texture->GetNumMipLevels(), wgpu::TextureUsage::None));
-        PassTextureUsage* passTextureUsage = &it.first->second;
+        TextureSubresourceUsage* passTextureUsage = &it.first->second;
 
         passTextureUsage->Merge(
             textureUsage, [](const SubresourceRange&, wgpu::TextureUsage* storedUsage,
@@ -86,7 +86,6 @@
     // Returns the per-pass usage for use by backends for APIs with explicit barriers.
     PassResourceUsage PassResourceUsageTracker::AcquireResourceUsage() {
         PassResourceUsage result;
-        result.passType = mPassType;
         result.buffers.reserve(mBufferUsages.size());
         result.bufferUsages.reserve(mBufferUsages.size());
         result.textures.reserve(mTextureUsages.size());
diff --git a/src/dawn_native/PassResourceUsageTracker.h b/src/dawn_native/PassResourceUsageTracker.h
index cd54f8c..d56d724 100644
--- a/src/dawn_native/PassResourceUsageTracker.h
+++ b/src/dawn_native/PassResourceUsageTracker.h
@@ -38,7 +38,7 @@
         PassResourceUsageTracker(PassType passType);
         void BufferUsedAs(BufferBase* buffer, wgpu::BufferUsage usage);
         void TextureViewUsedAs(TextureViewBase* texture, wgpu::TextureUsage usage);
-        void AddTextureUsage(TextureBase* texture, const PassTextureUsage& textureUsage);
+        void AddTextureUsage(TextureBase* texture, const TextureSubresourceUsage& textureUsage);
         void TrackQueryAvailability(QuerySetBase* querySet, uint32_t queryIndex);
         const QueryAvailabilityMap& GetQueryAvailabilityMap() const;
 
@@ -48,7 +48,7 @@
       private:
         PassType mPassType;
         std::map<BufferBase*, wgpu::BufferUsage> mBufferUsages;
-        std::map<TextureBase*, PassTextureUsage> mTextureUsages;
+        std::map<TextureBase*, TextureSubresourceUsage> mTextureUsages;
         // Dedicated to track the availability of the queries used on render pass. The same query
         // cannot be written twice in same render pass, so each render pass also need to have its
         // own query availability map for validation.
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index c113c1e..c555d99 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -37,6 +37,18 @@
 
     namespace {
 
+        MaybeError ValidateSyncScopeUsedInSubmit(const SyncScopeResourceUsage& scope) {
+            for (const BufferBase* buffer : scope.buffers) {
+                DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
+            }
+
+            for (const TextureBase* texture : scope.textures) {
+                DAWN_TRY(texture->ValidateCanUseInSubmitNow());
+            }
+
+            return {};
+        }
+
         void CopyTextureData(uint8_t* dstPointer,
                              const uint8_t* srcPointer,
                              uint32_t depth,
@@ -410,13 +422,11 @@
 
             const CommandBufferResourceUsage& usages = commands[i]->GetResourceUsages();
 
-            for (const PassResourceUsage& passUsages : usages.perPass) {
-                for (const BufferBase* buffer : passUsages.buffers) {
-                    DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
-                }
-                for (const TextureBase* texture : passUsages.textures) {
-                    DAWN_TRY(texture->ValidateCanUseInSubmitNow());
-                }
+            for (const SyncScopeResourceUsage& scope : usages.renderPasses) {
+                DAWN_TRY(ValidateSyncScopeUsedInSubmit(scope));
+            }
+            for (const SyncScopeResourceUsage& scope : usages.computePasses) {
+                DAWN_TRY(ValidateSyncScopeUsedInSubmit(scope));
             }
 
             for (const BufferBase* buffer : usages.topLevelBuffers) {
diff --git a/src/dawn_native/RenderBundleEncoder.cpp b/src/dawn_native/RenderBundleEncoder.cpp
index 45647a4..8afcd32 100644
--- a/src/dawn_native/RenderBundleEncoder.cpp
+++ b/src/dawn_native/RenderBundleEncoder.cpp
@@ -137,7 +137,7 @@
                                                    const PassResourceUsage& usages) const {
         TRACE_EVENT0(GetDevice()->GetPlatform(), Validation, "RenderBundleEncoder::ValidateFinish");
         DAWN_TRY(GetDevice()->ValidateObject(this));
-        DAWN_TRY(ValidatePassResourceUsage(usages));
+        DAWN_TRY(ValidateSyncScopeResourceUsage(usages));
         return {};
     }
 
diff --git a/src/dawn_native/RenderPassEncoder.cpp b/src/dawn_native/RenderPassEncoder.cpp
index 1ab9023..c5c52e4 100644
--- a/src/dawn_native/RenderPassEncoder.cpp
+++ b/src/dawn_native/RenderPassEncoder.cpp
@@ -101,7 +101,8 @@
                 allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
                 return {};
             })) {
-            mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
+            mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage(),
+                                       PassType::Render);
         }
     }
 
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 2e6eafb..f0ea858 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -441,7 +441,7 @@
         mIsSubresourceContentInitializedAtIndex = std::vector<bool>(subresourceCount, false);
 
         // Add readonly storage usage if the texture has a storage usage. The validation rules in
-        // ValidatePassResourceUsage will make sure we don't use both at the same time.
+        // ValidateSyncScopeResourceUsage will make sure we don't use both at the same time.
         if (mUsage & wgpu::TextureUsage::Storage) {
             mUsage |= kReadOnlyStorageTexture;
         }
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 9e575a6..9d7f96d 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -682,8 +682,8 @@
             }
         };
 
-        const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
-        uint32_t nextPassNumber = 0;
+        size_t nextComputePassNumber = 0;
+        size_t nextRenderPassNumber = 0;
 
         Command type;
         while (mCommands.NextCommandId(&type)) {
@@ -691,12 +691,12 @@
                 case Command::BeginComputePass: {
                     mCommands.NextCommand<BeginComputePassCmd>();
 
-                    PrepareResourcesForComputePass(commandContext,
-                                                   passResourceUsages[nextPassNumber]);
+                    PrepareResourcesForComputePass(
+                        commandContext, GetResourceUsages().computePasses[nextComputePassNumber]);
                     bindingTracker.SetInComputePass(true);
                     DAWN_TRY(RecordComputePass(commandContext, &bindingTracker));
 
-                    nextPassNumber++;
+                    nextComputePassNumber++;
                     break;
                 }
 
@@ -705,14 +705,14 @@
                         mCommands.NextCommand<BeginRenderPassCmd>();
 
                     const bool passHasUAV = PrepareResourcesForRenderPass(
-                        commandContext, passResourceUsages[nextPassNumber]);
+                        commandContext, GetResourceUsages().renderPasses[nextRenderPassNumber]);
                     bindingTracker.SetInComputePass(false);
 
                     LazyClearRenderPassAttachments(beginRenderPassCmd);
                     DAWN_TRY(RecordRenderPass(commandContext, &bindingTracker, beginRenderPassCmd,
                                               passHasUAV));
 
-                    nextPassNumber++;
+                    nextRenderPassNumber++;
                     break;
                 }
 
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 6274801..11d9048 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -776,7 +776,7 @@
     void Texture::TrackUsageAndGetResourceBarrierForPass(
         CommandRecordingContext* commandContext,
         std::vector<D3D12_RESOURCE_BARRIER>* barriers,
-        const PassTextureUsage& textureUsages) {
+        const TextureSubresourceUsage& textureUsages) {
         if (mResourceAllocation.GetInfo().mMethod != AllocationMethod::kExternal) {
             // Track the underlying heap to ensure residency.
             Heap* heap = ToBackend(mResourceAllocation.GetResourceHeap());
diff --git a/src/dawn_native/d3d12/TextureD3D12.h b/src/dawn_native/d3d12/TextureD3D12.h
index 528dd21..c7a652d 100644
--- a/src/dawn_native/d3d12/TextureD3D12.h
+++ b/src/dawn_native/d3d12/TextureD3D12.h
@@ -64,7 +64,7 @@
 
         void TrackUsageAndGetResourceBarrierForPass(CommandRecordingContext* commandContext,
                                                     std::vector<D3D12_RESOURCE_BARRIER>* barrier,
-                                                    const PassTextureUsage& textureUsages);
+                                                    const TextureSubresourceUsage& textureUsages);
         void TransitionUsageAndGetResourceBarrier(CommandRecordingContext* commandContext,
                                                   std::vector<D3D12_RESOURCE_BARRIER>* barrier,
                                                   wgpu::TextureUsage usage,
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index f93737d..0793f97 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -551,25 +551,25 @@
     }
 
     MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext) {
-        const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
-        size_t nextPassNumber = 0;
+        size_t nextComputePassNumber = 0;
+        size_t nextRenderPassNumber = 0;
 
-        auto LazyClearForPass = [](const PassResourceUsage& usages,
+        auto LazyClearForPass = [](const SyncScopeResourceUsage& scope,
                                    CommandRecordingContext* commandContext) {
-            for (size_t i = 0; i < usages.textures.size(); ++i) {
-                Texture* texture = ToBackend(usages.textures[i]);
+            for (size_t i = 0; i < scope.textures.size(); ++i) {
+                Texture* texture = ToBackend(scope.textures[i]);
 
                 // Clear subresources that are not render attachments. Render attachments will be
                 // cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
                 // subresource has not been initialized before the render pass.
-                usages.textureUsages[i].Iterate(
+                scope.textureUsages[i].Iterate(
                     [&](const SubresourceRange& range, wgpu::TextureUsage usage) {
                         if (usage & ~wgpu::TextureUsage::RenderAttachment) {
                             texture->EnsureSubresourceContentInitialized(range);
                         }
                     });
             }
-            for (BufferBase* bufferBase : usages.buffers) {
+            for (BufferBase* bufferBase : scope.buffers) {
                 ToBackend(bufferBase)->EnsureDataInitialized(commandContext);
             }
         };
@@ -580,19 +580,21 @@
                 case Command::BeginComputePass: {
                     mCommands.NextCommand<BeginComputePassCmd>();
 
-                    LazyClearForPass(passResourceUsages[nextPassNumber], commandContext);
+                    LazyClearForPass(GetResourceUsages().computePasses[nextComputePassNumber],
+                                     commandContext);
                     commandContext->EndBlit();
 
                     DAWN_TRY(EncodeComputePass(commandContext));
 
-                    nextPassNumber++;
+                    nextComputePassNumber++;
                     break;
                 }
 
                 case Command::BeginRenderPass: {
                     BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
 
-                    LazyClearForPass(passResourceUsages[nextPassNumber], commandContext);
+                    LazyClearForPass(GetResourceUsages().renderPasses[nextRenderPassNumber],
+                                     commandContext);
                     commandContext->EndBlit();
 
                     LazyClearRenderPassAttachments(cmd);
@@ -600,7 +602,7 @@
                     DAWN_TRY(EncodeRenderPass(commandContext, descriptor.Get(), cmd->width,
                                               cmd->height));
 
-                    nextPassNumber++;
+                    nextRenderPassNumber++;
                     break;
                 }
 
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index afb15a2..54687a0 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -536,14 +536,14 @@
     MaybeError CommandBuffer::Execute() {
         const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
 
-        auto TransitionForPass = [](const PassResourceUsage& usages) {
-            for (size_t i = 0; i < usages.textures.size(); i++) {
-                Texture* texture = ToBackend(usages.textures[i]);
+        auto LazyClearForPass = [](const SyncScopeResourceUsage& scope) {
+            for (size_t i = 0; i < scope.textures.size(); i++) {
+                Texture* texture = ToBackend(scope.textures[i]);
 
                 // Clear subresources that are not render attachments. Render attachments will be
                 // cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
                 // subresource has not been initialized before the render pass.
-                usages.textureUsages[i].Iterate(
+                scope.textureUsages[i].Iterate(
                     [&](const SubresourceRange& range, wgpu::TextureUsage usage) {
                         if (usage & ~wgpu::TextureUsage::RenderAttachment) {
                             texture->EnsureSubresourceContentInitialized(range);
@@ -551,34 +551,33 @@
                     });
             }
 
-            for (BufferBase* bufferBase : usages.buffers) {
+            for (BufferBase* bufferBase : scope.buffers) {
                 ToBackend(bufferBase)->EnsureDataInitialized();
             }
         };
 
-        const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
-        uint32_t nextPassNumber = 0;
+        size_t nextComputePassNumber = 0;
+        size_t nextRenderPassNumber = 0;
 
         Command type;
         while (mCommands.NextCommandId(&type)) {
             switch (type) {
                 case Command::BeginComputePass: {
                     mCommands.NextCommand<BeginComputePassCmd>();
-                    TransitionForPass(passResourceUsages[nextPassNumber]);
+                    LazyClearForPass(GetResourceUsages().computePasses[nextComputePassNumber]);
                     DAWN_TRY(ExecuteComputePass());
 
-                    nextPassNumber++;
+                    nextComputePassNumber++;
                     break;
                 }
 
                 case Command::BeginRenderPass: {
                     auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
-                    TransitionForPass(passResourceUsages[nextPassNumber]);
-
+                    LazyClearForPass(GetResourceUsages().renderPasses[nextRenderPassNumber]);
                     LazyClearRenderPassAttachments(cmd);
                     DAWN_TRY(ExecuteRenderPass(cmd));
 
-                    nextPassNumber++;
+                    nextRenderPassNumber++;
                     break;
                 }
 
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index d154026..c014c85 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -596,8 +596,8 @@
             }
         };
 
-        const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
-        size_t nextPassNumber = 0;
+        size_t nextComputePassNumber = 0;
+        size_t nextRenderPassNumber = 0;
 
         Command type;
         while (mCommands.NextCommandId(&type)) {
@@ -774,24 +774,26 @@
                 case Command::BeginRenderPass: {
                     BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
 
-                    PrepareResourcesForRenderPass(device, recordingContext,
-                                                  passResourceUsages[nextPassNumber]);
+                    PrepareResourcesForRenderPass(
+                        device, recordingContext,
+                        GetResourceUsages().renderPasses[nextRenderPassNumber]);
 
                     LazyClearRenderPassAttachments(cmd);
                     DAWN_TRY(RecordRenderPass(recordingContext, cmd));
 
-                    nextPassNumber++;
+                    nextRenderPassNumber++;
                     break;
                 }
 
                 case Command::BeginComputePass: {
                     mCommands.NextCommand<BeginComputePassCmd>();
 
-                    PrepareResourcesForComputePass(device, recordingContext,
-                                                   passResourceUsages[nextPassNumber]);
+                    PrepareResourcesForComputePass(
+                        device, recordingContext,
+                        GetResourceUsages().computePasses[nextComputePassNumber]);
                     DAWN_TRY(RecordComputePass(recordingContext));
 
-                    nextPassNumber++;
+                    nextComputePassNumber++;
                     break;
                 }
 
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 59e753f..90f85f3 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -863,7 +863,7 @@
     }
 
     void Texture::TransitionUsageForPass(CommandRecordingContext* recordingContext,
-                                         const PassTextureUsage& textureUsages,
+                                         const TextureSubresourceUsage& textureUsages,
                                          std::vector<VkImageMemoryBarrier>* imageBarriers,
                                          VkPipelineStageFlags* srcStages,
                                          VkPipelineStageFlags* dstStages) {
diff --git a/src/dawn_native/vulkan/TextureVk.h b/src/dawn_native/vulkan/TextureVk.h
index 013a3b6..908e468 100644
--- a/src/dawn_native/vulkan/TextureVk.h
+++ b/src/dawn_native/vulkan/TextureVk.h
@@ -78,7 +78,7 @@
                                                   VkPipelineStageFlags* srcStages,
                                                   VkPipelineStageFlags* dstStages);
         void TransitionUsageForPass(CommandRecordingContext* recordingContext,
-                                    const PassTextureUsage& textureUsages,
+                                    const TextureSubresourceUsage& textureUsages,
                                     std::vector<VkImageMemoryBarrier>* imageBarriers,
                                     VkPipelineStageFlags* srcStages,
                                     VkPipelineStageFlags* dstStages);