Refactor SharedTexture/BufferMemory Into SharedResourceMemory

Factors out shared code from SharedTextureMemory and SharedBufferMemory
into the new SharedResourceMemory class.

Bug: dawn:2382
Change-Id: I3be5204109c7e36c9bbe9ffdcd1bc6d3b2df84e0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/181501
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/common/RefBase.h b/src/dawn/common/RefBase.h
index 3601489..9785407 100644
--- a/src/dawn/common/RefBase.h
+++ b/src/dawn/common/RefBase.h
@@ -149,12 +149,25 @@
         return &mValue;
     }
 
+    // Cast operator.
+    template <typename Other>
+    Other Cast() && {
+        Other other;
+        CastImpl(this, &other);
+        return other;
+    }
+
   private:
     // Friend is needed so that instances of RefBase<U> can call Reference and Release on
     // RefBase<T>.
     template <typename U, typename UTraits>
     friend class RefBase;
 
+    template <typename U, typename UTraits, typename = typename std::is_convertible<U, T>::type>
+    static void CastImpl(RefBase<T, Traits>* ref, RefBase<U, UTraits>* other) {
+        other->Acquire(static_cast<U>(ref->Detach()));
+    }
+
     static void Reference(T value) {
         if (value != Traits::kNullValue) {
             Traits::Reference(value);
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index 1fa418c..d8c126c 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -354,6 +354,8 @@
     "SharedBufferMemory.h",
     "SharedFence.cpp",
     "SharedFence.h",
+    "SharedResourceMemory.cpp",
+    "SharedResourceMemory.h",
     "SharedTextureMemory.cpp",
     "SharedTextureMemory.h",
     "Subresource.cpp",
diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index e508ce2..9ce0de9 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -317,7 +317,7 @@
 // Buffer
 
 BufferBase::BufferBase(DeviceBase* device, const UnpackedPtr<BufferDescriptor>& descriptor)
-    : ApiObjectBase(device, descriptor->label),
+    : SharedResource(device, descriptor->label),
       mSize(descriptor->size),
       mUsage(AddInternalUsages(device, descriptor->usage)),
       mState(descriptor.Get<BufferHostMappedPointer>() ? BufferState::HostMappedPersistent
@@ -328,7 +328,7 @@
 BufferBase::BufferBase(DeviceBase* device,
                        const BufferDescriptor* descriptor,
                        ObjectBase::ErrorTag tag)
-    : ApiObjectBase(device, tag, descriptor->label),
+    : SharedResource(device, tag, descriptor->label),
       mSize(descriptor->size),
       mUsage(descriptor->usage),
       mState(descriptor->mappedAtCreation ? BufferState::MappedAtCreation : BufferState::Unmapped) {
@@ -444,7 +444,7 @@
     }
     // Mark the buffer as initialized since we don't want to later clear it using the GPU since that
     // would overwrite what the client wrote using the CPU.
-    SetIsDataInitialized();
+    SetInitialized(true);
 
     return {};
 }
@@ -863,14 +863,6 @@
     return !mIsDataInitialized && GetDevice()->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse);
 }
 
-bool BufferBase::IsDataInitialized() const {
-    return mIsDataInitialized;
-}
-
-void BufferBase::SetIsDataInitialized() {
-    mIsDataInitialized = true;
-}
-
 void BufferBase::MarkUsedInPendingCommands() {
     ExecutionSerial serial = GetDevice()->GetQueue()->GetPendingCommandSerial();
     DAWN_ASSERT(serial >= mLastUsageSerial);
@@ -885,6 +877,22 @@
     mState = hasAccess ? BufferState::Unmapped : BufferState::SharedMemoryNoAccess;
 }
 
+bool BufferBase::HasAccess() const {
+    return mState != BufferState::SharedMemoryNoAccess;
+}
+
+bool BufferBase::IsDestroyed() const {
+    return mState == BufferState::Destroyed;
+}
+
+void BufferBase::SetInitialized(bool initialized) {
+    mIsDataInitialized = initialized;
+}
+
+bool BufferBase::IsInitialized() const {
+    return mIsDataInitialized;
+}
+
 bool BufferBase::IsFullBufferRange(uint64_t offset, uint64_t size) const {
     return offset == 0 && size == GetSize();
 }
diff --git a/src/dawn/native/Buffer.h b/src/dawn/native/Buffer.h
index 5db99ce..3e755022 100644
--- a/src/dawn/native/Buffer.h
+++ b/src/dawn/native/Buffer.h
@@ -69,7 +69,7 @@
 static constexpr wgpu::BufferUsage kReadOnlyShaderBufferUsages =
     kShaderBufferUsages & kReadOnlyBufferUsages;
 
-class BufferBase : public ApiObjectBase {
+class BufferBase : public SharedResource {
   public:
     enum class BufferState {
         Unmapped,
@@ -101,12 +101,14 @@
 
     bool IsFullBufferRange(uint64_t offset, uint64_t size) const;
     bool NeedsInitialization() const;
-    bool IsDataInitialized() const;
-    void SetIsDataInitialized();
     void MarkUsedInPendingCommands();
 
-    // SetHasAccess determines Dawn's ability to access SharedBufferMemory.
-    void SetHasAccess(bool hasAccess);
+    // SharedResource impl.
+    void SetHasAccess(bool hasAccess) override;
+    bool HasAccess() const override;
+    bool IsDestroyed() const override;
+    void SetInitialized(bool initialized) override;
+    bool IsInitialized() const override;
 
     virtual void* GetMappedPointer() = 0;
     void* GetMappedRange(size_t offset, size_t size, bool writable = true);
@@ -144,9 +146,6 @@
 
     ExecutionSerial mLastUsageSerial = ExecutionSerial(0);
 
-    // The shared buffer memory state the buffer was created from. May be null.
-    Ref<SharedBufferMemoryContents> mSharedBufferMemoryContents;
-
   private:
     std::function<void()> PrepareMappingCallback(MapRequestID mapID,
                                                  WGPUBufferMapAsyncStatus status);
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 57b6d75..6058500 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -213,6 +213,8 @@
     "SharedBufferMemory.h"
     "SharedFence.cpp"
     "SharedFence.h"
+    "SharedResourceMemory.cpp"
+    "SharedResourceMemory.h"
     "SharedTextureMemory.cpp"
     "SharedTextureMemory.h"
     "Subresource.cpp"
diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp
index cd33fac..be9bc74 100644
--- a/src/dawn/native/CommandEncoder.cpp
+++ b/src/dawn/native/CommandEncoder.cpp
@@ -855,9 +855,9 @@
 
     // In the internal shader to convert timestamps to nanoseconds, we can ensure no uninitialized
     // data will be read and the full buffer range will be filled with valid data.
-    if (!destination->IsDataInitialized() &&
+    if (!destination->IsInitialized() &&
         destination->IsFullBufferRange(firstQuery, sizeof(uint64_t) * queryCount)) {
-        destination->SetIsDataInitialized();
+        destination->SetInitialized(true);
     }
 
     return EncodeConvertTimestampsToNanoseconds(encoder, destination, availabilityBuffer.Get(),
diff --git a/src/dawn/native/ScratchBuffer.cpp b/src/dawn/native/ScratchBuffer.cpp
index 8589a97..4fb1f22 100644
--- a/src/dawn/native/ScratchBuffer.cpp
+++ b/src/dawn/native/ScratchBuffer.cpp
@@ -46,7 +46,7 @@
         descriptor.size = capacity;
         descriptor.usage = mUsage;
         DAWN_TRY_ASSIGN(mBuffer, mDevice->CreateBuffer(&descriptor));
-        mBuffer->SetIsDataInitialized();
+        mBuffer->SetInitialized(true);
     }
     return {};
 }
diff --git a/src/dawn/native/SharedBufferMemory.cpp b/src/dawn/native/SharedBufferMemory.cpp
index 384e290..cc9bded 100644
--- a/src/dawn/native/SharedBufferMemory.cpp
+++ b/src/dawn/native/SharedBufferMemory.cpp
@@ -60,13 +60,13 @@
 SharedBufferMemoryBase::SharedBufferMemoryBase(DeviceBase* device,
                                                const SharedBufferMemoryDescriptor* descriptor,
                                                ObjectBase::ErrorTag tag)
-    : ApiObjectBase(device, tag, descriptor->label),
+    : SharedResourceMemory(device, tag, descriptor->label),
       mProperties{nullptr, wgpu::BufferUsage::None, 0} {}
 
 SharedBufferMemoryBase::SharedBufferMemoryBase(DeviceBase* device,
                                                const char* label,
                                                const SharedBufferMemoryProperties& properties)
-    : ApiObjectBase(device, label), mProperties(properties) {
+    : SharedResourceMemory(device, label), mProperties(properties) {
     GetObjectTrackingList()->Track(this);
 }
 
@@ -74,13 +74,6 @@
     return ObjectType::SharedBufferMemory;
 }
 
-void SharedBufferMemoryBase::DestroyImpl() {}
-
-void SharedBufferMemoryBase::Initialize() {
-    DAWN_ASSERT(!IsError());
-    mContents = CreateContents();
-}
-
 void SharedBufferMemoryBase::APIGetProperties(SharedBufferMemoryProperties* properties) const {
     properties->usage = mProperties.usage;
     properties->size = mProperties.size;
@@ -137,35 +130,6 @@
     return buffer;
 }
 
-Ref<SharedBufferMemoryContents> SharedBufferMemoryBase::CreateContents() {
-    return AcquireRef(new SharedBufferMemoryContents(GetWeakRef(this)));
-}
-
-SharedBufferMemoryContents* SharedBufferMemoryBase::GetContents() const {
-    return mContents.Get();
-}
-
-bool SharedBufferMemoryBase::APIBeginAccess(BufferBase* buffer,
-                                            const BeginAccessDescriptor* descriptor) {
-    return false;
-}
-
-bool SharedBufferMemoryBase::APIEndAccess(BufferBase* buffer, EndAccessState* state) {
-    return false;
-}
-
-bool SharedBufferMemoryBase::APIIsDeviceLost() {
-    return GetDevice()->IsLost();
-}
-
-SharedBufferMemoryContents::SharedBufferMemoryContents(
-    WeakRef<SharedBufferMemoryBase> sharedBufferMemory)
-    : mSharedBufferMemory(std::move(sharedBufferMemory)) {}
-
-const WeakRef<SharedBufferMemoryBase>& SharedBufferMemoryContents::GetSharedBufferMemory() const {
-    return mSharedBufferMemory;
-}
-
 void APISharedBufferMemoryEndAccessStateFreeMembers(WGPUSharedBufferMemoryEndAccessState cState) {
     auto* state = reinterpret_cast<SharedBufferMemoryBase::EndAccessState*>(&cState);
     for (size_t i = 0; i < state->fenceCount; ++i) {
diff --git a/src/dawn/native/SharedBufferMemory.h b/src/dawn/native/SharedBufferMemory.h
index fac946e..64c1731 100644
--- a/src/dawn/native/SharedBufferMemory.h
+++ b/src/dawn/native/SharedBufferMemory.h
@@ -34,44 +34,29 @@
 #include "dawn/native/Forward.h"
 #include "dawn/native/ObjectBase.h"
 #include "dawn/native/SharedFence.h"
+#include "dawn/native/SharedResourceMemory.h"
 #include "dawn/native/dawn_platform.h"
 
 namespace dawn::native {
 
-class SharedBufferMemoryContents;
 struct SharedBufferMemoryDescriptor;
 struct SharedBufferMemoryBeginAccessDescriptor;
 struct SharedBufferMemoryEndAccessState;
 struct SharedBufferMemoryProperties;
 struct BufferDescriptor;
 
-class SharedBufferMemoryBase : public ApiObjectBase, public WeakRefSupport<SharedBufferMemoryBase> {
+class SharedBufferMemoryBase : public SharedResourceMemory {
   public:
     using BeginAccessDescriptor = SharedBufferMemoryBeginAccessDescriptor;
     using EndAccessState = SharedBufferMemoryEndAccessState;
-
     static SharedBufferMemoryBase* MakeError(DeviceBase* device,
                                              const SharedBufferMemoryDescriptor* descriptor);
 
-    void Initialize();
-
     void APIGetProperties(SharedBufferMemoryProperties* properties) const;
     BufferBase* APICreateBuffer(const BufferDescriptor* descriptor);
-    // Returns true if access was acquired. If it returns true, then APIEndAccess must
-    // be called to release access. Other errors may occur even if `true` is returned.
-    // Use an error scope to catch them.
-    bool APIBeginAccess(BufferBase* buffer, const BeginAccessDescriptor* descriptor);
-    // Returns true if access was released.
-    bool APIEndAccess(BufferBase* buffer, EndAccessState* state);
-    // Returns true iff the device passed to this object on creation is now lost.
-    // TODO(crbug.com/1506468): Eliminate this API once Chromium has been
-    // transitioned away from using it in favor of observing device lost events.
-    bool APIIsDeviceLost();
 
     ObjectType GetType() const override;
 
-    SharedBufferMemoryContents* GetContents() const;
-
   protected:
     SharedBufferMemoryBase(DeviceBase* device,
                            const char* label,
@@ -80,29 +65,13 @@
                            const SharedBufferMemoryDescriptor* descriptor,
                            ObjectBase::ErrorTag tag);
 
-    void DestroyImpl() override;
-
     SharedBufferMemoryProperties mProperties;
 
   private:
-    virtual Ref<SharedBufferMemoryContents> CreateContents();
-
     ResultOrError<Ref<BufferBase>> CreateBuffer(const BufferDescriptor* rawDescriptor);
 
     virtual ResultOrError<Ref<BufferBase>> CreateBufferImpl(
         const UnpackedPtr<BufferDescriptor>& descriptor) = 0;
-
-    Ref<SharedBufferMemoryContents> mContents;
-};
-
-class SharedBufferMemoryContents : public RefCounted {
-  public:
-    explicit SharedBufferMemoryContents(WeakRef<SharedBufferMemoryBase> sharedBufferMemory);
-
-    const WeakRef<SharedBufferMemoryBase>& GetSharedBufferMemory() const;
-
-  private:
-    WeakRef<SharedBufferMemoryBase> mSharedBufferMemory;
 };
 
 }  // namespace dawn::native
diff --git a/src/dawn/native/SharedResourceMemory.cpp b/src/dawn/native/SharedResourceMemory.cpp
new file mode 100644
index 0000000..ade989b
--- /dev/null
+++ b/src/dawn/native/SharedResourceMemory.cpp
@@ -0,0 +1,314 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "dawn/native/SharedResourceMemory.h"
+
+#include <utility>
+
+#include "dawn/native/Buffer.h"
+#include "dawn/native/ChainUtils.h"
+#include "dawn/native/Device.h"
+#include "dawn/native/Queue.h"
+#include "dawn/native/Texture.h"
+
+namespace dawn::native {
+
+SharedResource::~SharedResource() = default;
+
+SharedResourceMemoryContents* SharedResource::GetSharedResourceMemoryContents() const {
+    return mSharedResourceMemoryContents.Get();
+}
+
+SharedResourceMemory::SharedResourceMemory(DeviceBase* device,
+                                           ObjectBase::ErrorTag tag,
+                                           const char* label)
+    : ApiObjectBase(device, tag, label),
+      mContents(new SharedResourceMemoryContents(GetWeakRef(this))) {}
+
+SharedResourceMemory::~SharedResourceMemory() = default;
+
+void SharedResourceMemory::DestroyImpl() {}
+
+bool SharedResourceMemory::HasWriteAccess() const {
+    return mHasWriteAccess;
+}
+
+bool SharedResourceMemory::HasExclusiveReadAccess() const {
+    return mHasExclusiveReadAccess;
+}
+
+int SharedResourceMemory::GetReadAccessCount() const {
+    return mReadAccessCount;
+}
+
+void SharedResourceMemory::Initialize() {
+    DAWN_ASSERT(!IsError());
+    mContents = CreateContents();
+}
+
+Ref<SharedResourceMemoryContents> SharedResourceMemory::CreateContents() {
+    return AcquireRef(new SharedResourceMemoryContents(GetWeakRef(this)));
+}
+
+SharedResourceMemoryContents* SharedResourceMemory::GetContents() const {
+    return mContents.Get();
+}
+
+MaybeError SharedResourceMemory::ValidateResourceCreatedFromSelf(SharedResource* resource) {
+    auto* contents = resource->GetSharedResourceMemoryContents();
+    DAWN_INVALID_IF(contents == nullptr, "%s was not created from %s.", resource, this);
+
+    auto* sharedResourceMemory =
+        resource->GetSharedResourceMemoryContents()->GetSharedResourceMemory().Promote().Get();
+    DAWN_INVALID_IF(sharedResourceMemory != this, "%s created from %s cannot be used with %s.",
+                    resource, sharedResourceMemory, this);
+    return {};
+}
+
+bool SharedResourceMemory::APIBeginAccess(
+    TextureBase* texture,
+    const SharedTextureMemoryBeginAccessDescriptor* descriptor) {
+    return !GetDevice()->ConsumedError(BeginAccess(texture, descriptor),
+                                       "calling %s.BeginAccess(%s).", this, texture);
+}
+
+bool SharedResourceMemory::APIBeginAccess(
+    BufferBase* buffer,
+    const SharedBufferMemoryBeginAccessDescriptor* descriptor) {
+    return !GetDevice()->ConsumedError(BeginAccess(buffer, descriptor),
+                                       "calling %s.BeginAccess(%s).", this, buffer);
+}
+
+template <typename Resource, typename BeginAccessDescriptor>
+MaybeError SharedResourceMemory::BeginAccess(Resource* resource,
+                                             const BeginAccessDescriptor* rawDescriptor) {
+    DAWN_TRY(GetDevice()->ValidateIsAlive());
+    DAWN_TRY(GetDevice()->ValidateObject(resource));
+
+    UnpackedPtr<BeginAccessDescriptor> descriptor;
+    DAWN_TRY_ASSIGN(descriptor, ValidateAndUnpack(rawDescriptor));
+
+    for (size_t i = 0; i < descriptor->fenceCount; ++i) {
+        DAWN_TRY(GetDevice()->ValidateObject(descriptor->fences[i]));
+    }
+
+    DAWN_TRY(ValidateResourceCreatedFromSelf(resource));
+
+    DAWN_INVALID_IF(resource->IsDestroyed(), "%s has been destroyed.", resource);
+    DAWN_INVALID_IF(resource->HasAccess(), "%s is already used to access %s.", resource, this);
+
+    if constexpr (std::is_same_v<Resource, TextureBase>) {
+        DAWN_INVALID_IF(resource->GetFormat().IsMultiPlanar() && !descriptor->initialized,
+                        "%s with multiplanar format (%s) must be initialized.", resource,
+                        resource->GetFormat().format);
+    }
+    DAWN_INVALID_IF(mHasWriteAccess, "%s is currently accessed for writing.", this);
+    DAWN_INVALID_IF(mHasExclusiveReadAccess, "%s is currently accessed for exclusive reading.",
+                    this);
+
+    if constexpr (std::is_same_v<Resource, TextureBase>) {
+        if (static_cast<TextureBase*>(resource)->IsReadOnly()) {
+            if (descriptor->concurrentRead) {
+                DAWN_INVALID_IF(!descriptor->initialized, "Concurrent reading an uninitialized %s.",
+                                resource);
+                ++mReadAccessCount;
+            } else {
+                DAWN_INVALID_IF(
+                    mReadAccessCount != 0,
+                    "Exclusive read access used while %s is currently accessed for reading.", this);
+                mHasExclusiveReadAccess = true;
+            }
+        } else {
+            DAWN_INVALID_IF(descriptor->concurrentRead, "Concurrent reading read-write %s.",
+                            resource);
+            DAWN_INVALID_IF(mReadAccessCount != 0,
+                            "Read-Write access used while %s is currently accessed for reading.",
+                            this);
+            mHasWriteAccess = true;
+        }
+    }
+
+    DAWN_TRY(BeginAccessImpl(resource, descriptor));
+
+    for (size_t i = 0; i < descriptor->fenceCount; ++i) {
+        mContents->mPendingFences->push_back(
+            {descriptor->fences[i], descriptor->signaledValues[i]});
+    }
+
+    DAWN_ASSERT(!resource->IsError());
+    resource->SetHasAccess(true);
+    resource->SetInitialized(descriptor->initialized);
+    return {};
+}
+
+bool SharedResourceMemory::APIEndAccess(TextureBase* texture,
+                                        SharedTextureMemoryEndAccessState* state) {
+    bool didEnd = false;
+    DAWN_UNUSED(GetDevice()->ConsumedError(EndAccess(texture, state, &didEnd),
+                                           "calling %s.EndAccess(%s).", this, texture));
+    return didEnd;
+}
+
+bool SharedResourceMemory::APIEndAccess(BufferBase* buffer,
+                                        SharedBufferMemoryEndAccessState* state) {
+    bool didEnd = false;
+    DAWN_UNUSED(GetDevice()->ConsumedError(EndAccess(buffer, state, &didEnd),
+                                           "calling %s.EndAccess(%s).", this, buffer));
+    return didEnd;
+}
+
+MaybeError SharedResourceMemory::BeginAccessImpl(
+    TextureBase* texture,
+    const UnpackedPtr<SharedTextureMemoryBeginAccessDescriptor>& descriptor) {
+    DAWN_UNREACHABLE();
+}
+
+MaybeError SharedResourceMemory::BeginAccessImpl(
+    BufferBase* buffer,
+    const UnpackedPtr<SharedBufferMemoryBeginAccessDescriptor>& descriptor) {
+    DAWN_UNREACHABLE();
+}
+
+ResultOrError<FenceAndSignalValue> SharedResourceMemory::EndAccessImpl(
+    TextureBase* texture,
+    UnpackedPtr<SharedTextureMemoryEndAccessState>& state) {
+    DAWN_UNREACHABLE();
+}
+
+ResultOrError<FenceAndSignalValue> SharedResourceMemory::EndAccessImpl(
+    BufferBase* buffer,
+    UnpackedPtr<SharedBufferMemoryEndAccessState>& state) {
+    DAWN_UNREACHABLE();
+}
+
+bool SharedResourceMemory::APIIsDeviceLost() const {
+    return GetDevice()->IsLost();
+}
+
+template <typename Resource, typename EndAccessState>
+MaybeError SharedResourceMemory::EndAccess(Resource* resource,
+                                           EndAccessState* state,
+                                           bool* didEnd) {
+    DAWN_TRY(GetDevice()->ValidateObject(resource));
+    DAWN_TRY(ValidateResourceCreatedFromSelf(resource));
+
+    DAWN_INVALID_IF(!resource->HasAccess(), "%s is not currently being accessed.", resource);
+    if constexpr (std::is_same_v<Resource, TextureBase>) {
+        if (static_cast<TextureBase*>(resource)->IsReadOnly()) {
+            DAWN_ASSERT(!mHasWriteAccess);
+            if (mHasExclusiveReadAccess) {
+                DAWN_ASSERT(mReadAccessCount == 0);
+                mHasExclusiveReadAccess = false;
+            } else {
+                DAWN_ASSERT(!mHasExclusiveReadAccess);
+                --mReadAccessCount;
+            }
+        } else {
+            DAWN_ASSERT(mHasWriteAccess);
+            DAWN_ASSERT(!mHasExclusiveReadAccess);
+            DAWN_ASSERT(mReadAccessCount == 0);
+            mHasWriteAccess = false;
+        }
+    }
+
+    PendingFenceList fenceList;
+    mContents->AcquirePendingFences(&fenceList);
+
+    DAWN_ASSERT(!resource->IsError());
+    resource->SetHasAccess(false);
+
+    *didEnd = true;
+
+    // Call the error-generating part of the EndAccess implementation. This is separated out because
+    // writing the output state must happen regardless of whether or not EndAccessInternal
+    // succeeds.
+    MaybeError err;
+    {
+        ResultOrError<FenceAndSignalValue> result = EndAccessInternal(resource, state);
+        if (result.IsSuccess()) {
+            fenceList->push_back(result.AcquireSuccess());
+        } else {
+            err = result.AcquireError();
+        }
+    }
+
+    // Copy the fences to the output state.
+    if (size_t fenceCount = fenceList->size()) {
+        auto* fences = new SharedFenceBase*[fenceCount];
+        uint64_t* signaledValues = new uint64_t[fenceCount];
+        for (size_t i = 0; i < fenceCount; ++i) {
+            fences[i] = ReturnToAPI(std::move(fenceList[i].object));
+            signaledValues[i] = fenceList[i].signaledValue;
+        }
+
+        state->fenceCount = fenceCount;
+        state->fences = fences;
+        state->signaledValues = signaledValues;
+    } else {
+        state->fenceCount = 0;
+        state->fences = nullptr;
+        state->signaledValues = nullptr;
+    }
+    state->initialized = resource->IsInitialized();
+    return err;
+}
+
+template <typename Resource, typename EndAccessState>
+ResultOrError<FenceAndSignalValue> SharedResourceMemory::EndAccessInternal(
+    Resource* resource,
+    EndAccessState* rawState) {
+    UnpackedPtr<EndAccessState> state;
+    DAWN_TRY_ASSIGN(state, ValidateAndUnpack(rawState));
+    // Ensure that commands are submitted before exporting fences with the last usage serial.
+    DAWN_TRY(GetDevice()->GetQueue()->EnsureCommandsFlushed(mContents->GetLastUsageSerial()));
+    return EndAccessImpl(resource, state);
+}
+
+// SharedResourceMemoryContents
+
+SharedResourceMemoryContents::SharedResourceMemoryContents(
+    WeakRef<SharedResourceMemory> sharedResourceMemory)
+    : mSharedResourceMemory(std::move(sharedResourceMemory)) {}
+
+const WeakRef<SharedResourceMemory>& SharedResourceMemoryContents::GetSharedResourceMemory() const {
+    return mSharedResourceMemory;
+}
+
+void SharedResourceMemoryContents::AcquirePendingFences(PendingFenceList* fences) {
+    *fences = mPendingFences;
+    mPendingFences->clear();
+}
+
+void SharedResourceMemoryContents::SetLastUsageSerial(ExecutionSerial lastUsageSerial) {
+    mLastUsageSerial = lastUsageSerial;
+}
+
+ExecutionSerial SharedResourceMemoryContents::GetLastUsageSerial() const {
+    return mLastUsageSerial;
+}
+
+}  // namespace dawn::native
diff --git a/src/dawn/native/SharedResourceMemory.h b/src/dawn/native/SharedResourceMemory.h
new file mode 100644
index 0000000..a587dbe
--- /dev/null
+++ b/src/dawn/native/SharedResourceMemory.h
@@ -0,0 +1,172 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_NATIVE_SHAREDRESOURCEMEMORY_H_
+#define SRC_DAWN_NATIVE_SHAREDRESOURCEMEMORY_H_
+
+#include "dawn/common/StackContainer.h"
+#include "dawn/common/WeakRef.h"
+#include "dawn/common/WeakRefSupport.h"
+#include "dawn/native/Error.h"
+#include "dawn/native/Forward.h"
+#include "dawn/native/IntegerTypes.h"
+#include "dawn/native/ObjectBase.h"
+#include "dawn/native/SharedFence.h"
+#include "dawn/native/dawn_platform.h"
+
+namespace dawn::native {
+
+class SharedResourceMemoryContents;
+
+class SharedResource : public ApiObjectBase {
+  public:
+    using ApiObjectBase::ApiObjectBase;
+    ~SharedResource() override;
+
+    SharedResourceMemoryContents* GetSharedResourceMemoryContents() const;
+
+    virtual void SetHasAccess(bool hasAccess) = 0;
+    virtual bool HasAccess() const = 0;
+    virtual bool IsDestroyed() const = 0;
+    virtual void SetInitialized(bool initialized) = 0;
+    virtual bool IsInitialized() const = 0;
+
+  protected:
+    // The shared contents the resource was created from. May be null.
+    Ref<SharedResourceMemoryContents> mSharedResourceMemoryContents;
+};
+
+class SharedResourceMemory : public ApiObjectBase, public WeakRefSupport<SharedResourceMemory> {
+  public:
+    using PendingFenceList = StackVector<FenceAndSignalValue, 1>;
+
+    ~SharedResourceMemory() override;
+    void Initialize();
+    void DestroyImpl() override;
+
+    // Returns true if access was acquired. If it returns true, then APIEndAccess must
+    // be called to release access. Other errors may occur even if `true` is returned.
+    // Use an error scope to catch them.
+    bool APIBeginAccess(TextureBase* texture,
+                        const SharedTextureMemoryBeginAccessDescriptor* descriptor);
+    // Returns true if access was released.
+    bool APIEndAccess(TextureBase* texture, SharedTextureMemoryEndAccessState* state);
+
+    // Returns true if access was acquired. If it returns true, then APIEndAccess must
+    // be called to release access. Other errors may occur even if `true` is returned.
+    // Use an error scope to catch them.
+    bool APIBeginAccess(BufferBase* buffer,
+                        const SharedBufferMemoryBeginAccessDescriptor* descriptor);
+    // Returns true if access was released.
+    bool APIEndAccess(BufferBase* buffer, SharedBufferMemoryEndAccessState* state);
+
+    // Returns true iff the device passed to this object on creation is now lost.
+    // TODO(crbug.com/1506468): Eliminate this API once Chromium has been
+    // transitioned away from using it in favor of observing device lost events.
+    bool APIIsDeviceLost() const;
+
+    SharedResourceMemoryContents* GetContents() const;
+
+    // Validate that the resource was created from this SharedResourceMemory.
+    MaybeError ValidateResourceCreatedFromSelf(SharedResource* resource);
+
+  protected:
+    SharedResourceMemory(DeviceBase* device, ObjectBase::ErrorTag, const char* label);
+    using ApiObjectBase::ApiObjectBase;
+
+    bool HasWriteAccess() const;
+    bool HasExclusiveReadAccess() const;
+    int GetReadAccessCount() const;
+
+  private:
+    virtual Ref<SharedResourceMemoryContents> CreateContents();
+
+    template <typename Resource, typename BeginAccessDescriptor>
+    MaybeError BeginAccess(Resource* resource, const BeginAccessDescriptor* rawDescriptor);
+
+    template <typename Resource, typename EndAccessState>
+    MaybeError EndAccess(Resource* resource, EndAccessState* state, bool* didEnd);
+
+    template <typename Resource, typename EndAccessState>
+    ResultOrError<FenceAndSignalValue> EndAccessInternal(Resource* resource,
+                                                         EndAccessState* rawState);
+
+    // BeginAccessImpl validates the operation is valid on the backend, and performs any
+    // backend specific operations. It does NOT need to acquire begin fences; that is done in the
+    // frontend in BeginAccess.
+    virtual MaybeError BeginAccessImpl(
+        TextureBase* texture,
+        const UnpackedPtr<SharedTextureMemoryBeginAccessDescriptor>& descriptor);
+    virtual MaybeError BeginAccessImpl(
+        BufferBase* buffer,
+        const UnpackedPtr<SharedBufferMemoryBeginAccessDescriptor>& descriptor);
+    // EndAccessImpl validates the operation is valid on the backend, and returns the end fence.
+    // It should also write out any backend specific state in chained out structs of EndAccessState.
+    virtual ResultOrError<FenceAndSignalValue> EndAccessImpl(
+        TextureBase* texture,
+        UnpackedPtr<SharedTextureMemoryEndAccessState>& state);
+    virtual ResultOrError<FenceAndSignalValue> EndAccessImpl(
+        BufferBase* buffer,
+        UnpackedPtr<SharedBufferMemoryEndAccessState>& state);
+
+    bool mHasWriteAccess = false;
+    bool mHasExclusiveReadAccess = false;
+    int mReadAccessCount = 0;
+    Ref<SharedResourceMemoryContents> mContents;
+};
+
+// SharedResourceMemoryContents is a separate object because it needs to live as long as
+// the SharedResourceMemory or any resources created from the SharedResourceMemory. This
+// allows state and objects needed by the resource to persist after the
+// SharedResourceMemory itself has been dropped.
+class SharedResourceMemoryContents : public RefCounted {
+  public:
+    using PendingFenceList = SharedResourceMemory::PendingFenceList;
+
+    explicit SharedResourceMemoryContents(WeakRef<SharedResourceMemory> sharedResourceMemory);
+
+    void AcquirePendingFences(PendingFenceList* fences);
+
+    // Set the last usage serial. This indicates when the SharedFence exported
+    // from APIEndAccess will complete.
+    void SetLastUsageSerial(ExecutionSerial lastUsageSerial);
+    ExecutionSerial GetLastUsageSerial() const;
+
+    const WeakRef<SharedResourceMemory>& GetSharedResourceMemory() const;
+
+  private:
+    friend class SharedResourceMemory;
+
+    PendingFenceList mPendingFences;
+    ExecutionSerial mLastUsageSerial{0};
+
+    WeakRef<SharedResourceMemory> mSharedResourceMemory;
+};
+
+}  // namespace dawn::native
+
+#endif  // SRC_DAWN_NATIVE_SHAREDRESOURCEMEMORY_H_
diff --git a/src/dawn/native/SharedTextureMemory.cpp b/src/dawn/native/SharedTextureMemory.cpp
index 90e1098..01f84e1 100644
--- a/src/dawn/native/SharedTextureMemory.cpp
+++ b/src/dawn/native/SharedTextureMemory.cpp
@@ -44,7 +44,7 @@
     ErrorSharedTextureMemory(DeviceBase* device, const SharedTextureMemoryDescriptor* descriptor)
         : SharedTextureMemoryBase(device, descriptor, ObjectBase::kError) {}
 
-    Ref<SharedTextureMemoryContents> CreateContents() override { DAWN_UNREACHABLE(); }
+    Ref<SharedResourceMemoryContents> CreateContents() override { DAWN_UNREACHABLE(); }
     ResultOrError<Ref<TextureBase>> CreateTextureImpl(
         const UnpackedPtr<TextureDescriptor>& descriptor) override {
         DAWN_UNREACHABLE();
@@ -57,6 +57,7 @@
                                                      UnpackedPtr<EndAccessState>& state) override {
         DAWN_UNREACHABLE();
     }
+    void DestroyImpl() override {}
 };
 
 }  // namespace
@@ -71,19 +72,18 @@
 SharedTextureMemoryBase::SharedTextureMemoryBase(DeviceBase* device,
                                                  const SharedTextureMemoryDescriptor* descriptor,
                                                  ObjectBase::ErrorTag tag)
-    : ApiObjectBase(device, tag, descriptor->label),
+    : SharedResourceMemory(device, tag, descriptor->label),
       mProperties{
           nullptr,
           wgpu::TextureUsage::None,
           {0, 0, 0},
           wgpu::TextureFormat::Undefined,
-      },
-      mContents(new SharedTextureMemoryContents(GetWeakRef(this))) {}
+      } {}
 
 SharedTextureMemoryBase::SharedTextureMemoryBase(DeviceBase* device,
                                                  const char* label,
                                                  const SharedTextureMemoryProperties& properties)
-    : ApiObjectBase(device, label), mProperties(properties) {
+    : SharedResourceMemory(device, label), mProperties(properties) {
     // Reify properties to ensure we don't expose capabilities not supported by the device.
     const Format& internalFormat = device->GetValidInternalFormat(mProperties.format);
     if (!internalFormat.supportsStorageUsage || internalFormat.IsMultiPlanar()) {
@@ -105,25 +105,6 @@
     return ObjectType::SharedTextureMemory;
 }
 
-void SharedTextureMemoryBase::DestroyImpl() {}
-
-bool SharedTextureMemoryBase::HasWriteAccess() const {
-    return mHasWriteAccess;
-}
-
-bool SharedTextureMemoryBase::HasExclusiveReadAccess() const {
-    return mHasExclusiveReadAccess;
-}
-
-int SharedTextureMemoryBase::GetReadAccessCount() const {
-    return mReadAccessCount;
-}
-
-void SharedTextureMemoryBase::Initialize() {
-    DAWN_ASSERT(!IsError());
-    mContents = CreateContents();
-}
-
 void SharedTextureMemoryBase::APIGetProperties(SharedTextureMemoryProperties* properties) const {
     properties->usage = mProperties.usage;
     properties->size = mProperties.size;
@@ -157,10 +138,6 @@
     return ReturnToAPI(std::move(result));
 }
 
-Ref<SharedTextureMemoryContents> SharedTextureMemoryBase::CreateContents() {
-    return AcquireRef(new SharedTextureMemoryContents(GetWeakRef(this)));
-}
-
 ResultOrError<Ref<TextureBase>> SharedTextureMemoryBase::CreateTexture(
     const TextureDescriptor* rawDescriptor) {
     DAWN_TRY(GetDevice()->ValidateIsAlive());
@@ -205,198 +182,6 @@
     return texture;
 }
 
-SharedTextureMemoryContents* SharedTextureMemoryBase::GetContents() const {
-    return mContents.Get();
-}
-
-MaybeError SharedTextureMemoryBase::ValidateTextureCreatedFromSelf(TextureBase* texture) {
-    auto* contents = texture->GetSharedTextureMemoryContents();
-    DAWN_INVALID_IF(contents == nullptr, "%s was not created from %s.", texture, this);
-
-    auto* sharedTextureMemory =
-        texture->GetSharedTextureMemoryContents()->GetSharedTextureMemory().Promote().Get();
-    DAWN_INVALID_IF(sharedTextureMemory != this, "%s created from %s cannot be used with %s.",
-                    texture, sharedTextureMemory, this);
-    return {};
-}
-
-bool SharedTextureMemoryBase::APIBeginAccess(TextureBase* texture,
-                                             const BeginAccessDescriptor* descriptor) {
-    if (GetDevice()->ConsumedError(BeginAccess(texture, descriptor), "calling %s.BeginAccess(%s).",
-                                   this, texture)) {
-        return false;
-    }
-    return true;
-}
-
-bool SharedTextureMemoryBase::APIIsDeviceLost() {
-    return GetDevice()->IsLost();
-}
-
-MaybeError SharedTextureMemoryBase::BeginAccess(TextureBase* texture,
-                                                const BeginAccessDescriptor* rawDescriptor) {
-    DAWN_TRY(GetDevice()->ValidateIsAlive());
-    DAWN_TRY(GetDevice()->ValidateObject(texture));
-
-    UnpackedPtr<BeginAccessDescriptor> descriptor;
-    DAWN_TRY_ASSIGN(descriptor, ValidateAndUnpack(rawDescriptor));
-
-    for (size_t i = 0; i < descriptor->fenceCount; ++i) {
-        DAWN_TRY(GetDevice()->ValidateObject(descriptor->fences[i]));
-    }
-
-    DAWN_TRY(ValidateTextureCreatedFromSelf(texture));
-
-    DAWN_INVALID_IF(texture->GetFormat().IsMultiPlanar() && !descriptor->initialized,
-                    "%s with multiplanar format (%s) must be initialized.", texture,
-                    texture->GetFormat().format);
-
-    DAWN_INVALID_IF(texture->IsDestroyed(), "%s has been destroyed.", texture);
-    DAWN_INVALID_IF(texture->HasAccess(), "%s is already used to access %s.", texture, this);
-
-    DAWN_INVALID_IF(mHasWriteAccess, "%s is currently accessed for writing.", this);
-    DAWN_INVALID_IF(mHasExclusiveReadAccess, "%s is currently accessed for exclusive reading.",
-                    this);
-
-    if (texture->IsReadOnly()) {
-        if (descriptor->concurrentRead) {
-            DAWN_INVALID_IF(!descriptor->initialized, "Concurrent reading an uninitialized %s.",
-                            texture);
-            ++mReadAccessCount;
-        } else {
-            DAWN_INVALID_IF(
-                mReadAccessCount != 0,
-                "Exclusive read access used while %s is currently accessed for reading.", this);
-            mHasExclusiveReadAccess = true;
-        }
-    } else {
-        DAWN_INVALID_IF(descriptor->concurrentRead, "Concurrent reading read-write %s.", texture);
-        DAWN_INVALID_IF(mReadAccessCount != 0,
-                        "Read-Write access used while %s is currently accessed for reading.", this);
-        mHasWriteAccess = true;
-    }
-
-    DAWN_TRY(BeginAccessImpl(texture, descriptor));
-
-    for (size_t i = 0; i < descriptor->fenceCount; ++i) {
-        mContents->mPendingFences->push_back(
-            {descriptor->fences[i], descriptor->signaledValues[i]});
-    }
-
-    DAWN_ASSERT(!texture->IsError());
-    texture->SetHasAccess(true);
-    texture->SetIsSubresourceContentInitialized(descriptor->initialized,
-                                                texture->GetAllSubresources());
-    return {};
-}
-
-bool SharedTextureMemoryBase::APIEndAccess(TextureBase* texture, EndAccessState* state) {
-    bool didEnd = false;
-    DAWN_UNUSED(GetDevice()->ConsumedError(EndAccess(texture, state, &didEnd),
-                                           "calling %s.EndAccess(%s).", this, texture));
-    return didEnd;
-}
-
-MaybeError SharedTextureMemoryBase::EndAccess(TextureBase* texture,
-                                              EndAccessState* state,
-                                              bool* didEnd) {
-    DAWN_TRY(GetDevice()->ValidateObject(texture));
-    DAWN_TRY(ValidateTextureCreatedFromSelf(texture));
-
-    DAWN_INVALID_IF(!texture->HasAccess(), "%s is not currently being accessed.", texture);
-
-    if (texture->IsReadOnly()) {
-        DAWN_ASSERT(!mHasWriteAccess);
-        if (mHasExclusiveReadAccess) {
-            DAWN_ASSERT(mReadAccessCount == 0);
-            mHasExclusiveReadAccess = false;
-        } else {
-            DAWN_ASSERT(!mHasExclusiveReadAccess);
-            --mReadAccessCount;
-        }
-    } else {
-        DAWN_ASSERT(mHasWriteAccess);
-        DAWN_ASSERT(!mHasExclusiveReadAccess);
-        DAWN_ASSERT(mReadAccessCount == 0);
-        mHasWriteAccess = false;
-    }
-
-    PendingFenceList fenceList;
-    mContents->AcquirePendingFences(&fenceList);
-
-    DAWN_ASSERT(!texture->IsError());
-    texture->SetHasAccess(false);
-
-    *didEnd = true;
-
-    // Call the error-generating part of the EndAccess implementation. This is separated out because
-    // writing the output state must happen regardless of whether or not EndAccessInternal
-    // succeeds.
-    MaybeError err;
-    {
-        ResultOrError<FenceAndSignalValue> result = EndAccessInternal(texture, state);
-        if (result.IsSuccess()) {
-            fenceList->push_back(result.AcquireSuccess());
-        } else {
-            err = result.AcquireError();
-        }
-    }
-
-    // Copy the fences to the output state.
-    if (size_t fenceCount = fenceList->size()) {
-        auto* fences = new SharedFenceBase*[fenceCount];
-        uint64_t* signaledValues = new uint64_t[fenceCount];
-        for (size_t i = 0; i < fenceCount; ++i) {
-            fences[i] = ReturnToAPI(std::move(fenceList[i].object));
-            signaledValues[i] = fenceList[i].signaledValue;
-        }
-
-        state->fenceCount = fenceCount;
-        state->fences = fences;
-        state->signaledValues = signaledValues;
-    } else {
-        state->fenceCount = 0;
-        state->fences = nullptr;
-        state->signaledValues = nullptr;
-    }
-    state->initialized = texture->IsSubresourceContentInitialized(texture->GetAllSubresources());
-    return err;
-}
-
-ResultOrError<FenceAndSignalValue> SharedTextureMemoryBase::EndAccessInternal(
-    TextureBase* texture,
-    EndAccessState* rawState) {
-    UnpackedPtr<EndAccessState> state;
-    DAWN_TRY_ASSIGN(state, ValidateAndUnpack(rawState));
-    // Ensure that commands are submitted before exporting fences with the last usage serial.
-    DAWN_TRY(GetDevice()->GetQueue()->EnsureCommandsFlushed(mContents->GetLastUsageSerial()));
-    return EndAccessImpl(texture, state);
-}
-
-// SharedTextureMemoryContents
-
-SharedTextureMemoryContents::SharedTextureMemoryContents(
-    WeakRef<SharedTextureMemoryBase> sharedTextureMemory)
-    : mSharedTextureMemory(std::move(sharedTextureMemory)) {}
-
-const WeakRef<SharedTextureMemoryBase>& SharedTextureMemoryContents::GetSharedTextureMemory()
-    const {
-    return mSharedTextureMemory;
-}
-
-void SharedTextureMemoryContents::AcquirePendingFences(PendingFenceList* fences) {
-    *fences = mPendingFences;
-    mPendingFences->clear();
-}
-
-void SharedTextureMemoryContents::SetLastUsageSerial(ExecutionSerial lastUsageSerial) {
-    mLastUsageSerial = lastUsageSerial;
-}
-
-ExecutionSerial SharedTextureMemoryContents::GetLastUsageSerial() const {
-    return mLastUsageSerial;
-}
-
 void APISharedTextureMemoryEndAccessStateFreeMembers(WGPUSharedTextureMemoryEndAccessState cState) {
     auto* state = reinterpret_cast<SharedTextureMemoryBase::EndAccessState*>(&cState);
     for (size_t i = 0; i < state->fenceCount; ++i) {
diff --git a/src/dawn/native/SharedTextureMemory.h b/src/dawn/native/SharedTextureMemory.h
index be34418..7751b34 100644
--- a/src/dawn/native/SharedTextureMemory.h
+++ b/src/dawn/native/SharedTextureMemory.h
@@ -36,49 +36,31 @@
 #include "dawn/native/IntegerTypes.h"
 #include "dawn/native/ObjectBase.h"
 #include "dawn/native/SharedFence.h"
+#include "dawn/native/SharedResourceMemory.h"
 #include "dawn/native/dawn_platform.h"
 
 namespace dawn::native {
 
-class SharedTextureMemoryContents;
+class SharedResourceMemoryContents;
 struct SharedTextureMemoryDescriptor;
 struct SharedTextureMemoryBeginAccessDescriptor;
 struct SharedTextureMemoryEndAccessState;
 struct SharedTextureMemoryProperties;
 struct TextureDescriptor;
 
-class SharedTextureMemoryBase : public ApiObjectBase,
-                                public WeakRefSupport<SharedTextureMemoryBase> {
+class SharedTextureMemoryBase : public SharedResourceMemory {
   public:
     using BeginAccessDescriptor = SharedTextureMemoryBeginAccessDescriptor;
     using EndAccessState = SharedTextureMemoryEndAccessState;
-    using PendingFenceList = StackVector<FenceAndSignalValue, 1>;
 
     static Ref<SharedTextureMemoryBase> MakeError(DeviceBase* device,
                                                   const SharedTextureMemoryDescriptor* descriptor);
 
-    void Initialize();
-
     void APIGetProperties(SharedTextureMemoryProperties* properties) const;
     TextureBase* APICreateTexture(const TextureDescriptor* descriptor);
-    // Returns true if access was acquired. If it returns true, then APIEndAccess must
-    // be called to release access. Other errors may occur even if `true` is returned.
-    // Use an error scope to catch them.
-    bool APIBeginAccess(TextureBase* texture, const BeginAccessDescriptor* descriptor);
-    // Returns true if access was released.
-    bool APIEndAccess(TextureBase* texture, EndAccessState* state);
-    // Returns true iff the device passed to this object on creation is now lost.
-    // TODO(crbug.com/1506468): Eliminate this API once Chromium has been
-    // transitioned away from using it in favor of observing device lost events.
-    bool APIIsDeviceLost();
 
     ObjectType GetType() const override;
 
-    SharedTextureMemoryContents* GetContents() const;
-
-    // Validate that the texture was created from this SharedTextureMemory.
-    MaybeError ValidateTextureCreatedFromSelf(TextureBase* texture);
-
   protected:
     SharedTextureMemoryBase(DeviceBase* device,
                             const char* label,
@@ -87,68 +69,13 @@
                             const SharedTextureMemoryDescriptor* descriptor,
                             ObjectBase::ErrorTag tag);
 
-    void DestroyImpl() override;
-
-    bool HasWriteAccess() const;
-    bool HasExclusiveReadAccess() const;
-    int GetReadAccessCount() const;
-
   private:
-    virtual Ref<SharedTextureMemoryContents> CreateContents();
-
     ResultOrError<Ref<TextureBase>> CreateTexture(const TextureDescriptor* rawDescriptor);
-    MaybeError BeginAccess(TextureBase* texture, const BeginAccessDescriptor* rawDescriptor);
-    MaybeError EndAccess(TextureBase* texture, EndAccessState* state, bool* didEnd);
-    ResultOrError<FenceAndSignalValue> EndAccessInternal(TextureBase* texture,
-                                                         EndAccessState* rawState);
 
     virtual ResultOrError<Ref<TextureBase>> CreateTextureImpl(
         const UnpackedPtr<TextureDescriptor>& descriptor) = 0;
 
-    // BeginAccessImpl validates the operation is valid on the backend, and performs any
-    // backend specific operations. It does NOT need to acquire begin fences; that is done in the
-    // frontend in BeginAccess.
-    virtual MaybeError BeginAccessImpl(TextureBase* texture,
-                                       const UnpackedPtr<BeginAccessDescriptor>& descriptor) = 0;
-    // EndAccessImpl validates the operation is valid on the backend, and returns the end fence.
-    // It should also write out any backend specific state in chained out structs of EndAccessState.
-    virtual ResultOrError<FenceAndSignalValue> EndAccessImpl(
-        TextureBase* texture,
-        UnpackedPtr<EndAccessState>& state) = 0;
-
     SharedTextureMemoryProperties mProperties;
-    bool mHasWriteAccess = false;
-    bool mHasExclusiveReadAccess = false;
-    int mReadAccessCount = 0;
-    Ref<SharedTextureMemoryContents> mContents;
-};
-
-// SharedTextureMemoryContents is a separate object because it needs to live as long as
-// the SharedTextureMemory or any textures created from the SharedTextureMemory. This
-// allows state and objects needed by the texture to persist after the
-// SharedTextureMemory itself has been dropped.
-class SharedTextureMemoryContents : public RefCounted {
-  public:
-    using PendingFenceList = SharedTextureMemoryBase::PendingFenceList;
-
-    explicit SharedTextureMemoryContents(WeakRef<SharedTextureMemoryBase> sharedTextureMemory);
-
-    void AcquirePendingFences(PendingFenceList* fences);
-
-    // Set the last usage serial. This indicates when the SharedFence exported
-    // from APIEndAccess will complete.
-    void SetLastUsageSerial(ExecutionSerial lastUsageSerial);
-    ExecutionSerial GetLastUsageSerial() const;
-
-    const WeakRef<SharedTextureMemoryBase>& GetSharedTextureMemory() const;
-
-  private:
-    friend class SharedTextureMemoryBase;
-
-    PendingFenceList mPendingFences;
-    ExecutionSerial mLastUsageSerial{0};
-
-    WeakRef<SharedTextureMemoryBase> mSharedTextureMemory;
 };
 
 }  // namespace dawn::native
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 1dbb297..b15bbe8 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -725,7 +725,7 @@
 TextureBase::TextureState::TextureState() : hasAccess(true), destroyed(false) {}
 
 TextureBase::TextureBase(DeviceBase* device, const UnpackedPtr<TextureDescriptor>& descriptor)
-    : ApiObjectBase(device, descriptor->label),
+    : SharedResource(device, descriptor->label),
       mDimension(descriptor->dimension),
       mCompatibilityTextureBindingViewDimension(
           ResolveDefaultCompatiblityTextureBindingViewDimension(device, descriptor)),
@@ -787,7 +787,7 @@
 TextureBase::TextureBase(DeviceBase* device,
                          const TextureDescriptor* descriptor,
                          ObjectBase::ErrorTag tag)
-    : ApiObjectBase(device, tag, descriptor->label),
+    : SharedResource(device, tag, descriptor->label),
       mDimension(descriptor->dimension),
       mCompatibilityTextureBindingViewDimension(
           ResolveDefaultCompatiblityTextureBindingViewDimension(device, Unpack(descriptor))),
@@ -973,6 +973,14 @@
     return mState.destroyed;
 }
 
+bool TextureBase::IsInitialized() const {
+    return IsSubresourceContentInitialized(GetAllSubresources());
+}
+
+void TextureBase::SetInitialized(bool initialized) {
+    SetIsSubresourceContentInitialized(initialized, GetAllSubresources());
+}
+
 void TextureBase::SetHasAccess(bool hasAccess) {
     DAWN_ASSERT(!IsError());
     mState.hasAccess = hasAccess;
@@ -1029,8 +1037,11 @@
     if (DAWN_UNLIKELY(mState.destroyed || !mState.hasAccess)) {
         DAWN_INVALID_IF(mState.destroyed, "Destroyed texture %s used in a submit.", this);
         if (DAWN_UNLIKELY(!mState.hasAccess)) {
-            if (mSharedTextureMemoryContents != nullptr) {
-                auto memory = mSharedTextureMemoryContents->GetSharedTextureMemory().Promote();
+            if (mSharedResourceMemoryContents != nullptr) {
+                Ref<SharedTextureMemoryBase> memory =
+                    mSharedResourceMemoryContents->GetSharedResourceMemory()
+                        .Promote()
+                        .Cast<Ref<SharedTextureMemoryBase>>();
                 if (memory != nullptr) {
                     return DAWN_VALIDATION_ERROR("%s used in a submit without current access to %s",
                                                  this, memory.Get());
@@ -1164,10 +1175,6 @@
     return (GetUsage() & wgpu::TextureUsage::TextureBinding) != 0;
 }
 
-SharedTextureMemoryContents* TextureBase::GetSharedTextureMemoryContents() const {
-    return mSharedTextureMemoryContents.Get();
-}
-
 void TextureBase::APIDestroy() {
     Destroy();
 }
diff --git a/src/dawn/native/Texture.h b/src/dawn/native/Texture.h
index 4ca39f6..3180200 100644
--- a/src/dawn/native/Texture.h
+++ b/src/dawn/native/Texture.h
@@ -78,7 +78,7 @@
     wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture |
     wgpu::TextureUsage::StorageBinding | kWriteOnlyStorageTexture;
 
-class TextureBase : public ApiObjectBase {
+class TextureBase : public SharedResource {
   public:
     enum class ClearValue { Zero, NonZero };
 
@@ -112,9 +112,14 @@
     wgpu::TextureUsage GetUsage() const;
     wgpu::TextureUsage GetInternalUsage() const;
 
-    bool IsDestroyed() const;
-    void SetHasAccess(bool hasAccess);
-    bool HasAccess() const;
+    // SharedResource implementation
+    void SetHasAccess(bool hasAccess) override;
+    bool HasAccess() const override;
+    bool IsDestroyed() const override;
+    bool IsInitialized() const override;
+    void SetInitialized(bool initialized) override;
+
+    bool IsReadOnly() const;
     uint32_t GetSubresourceIndex(uint32_t mipLevel, uint32_t arraySlice, Aspect aspect) const;
     bool IsSubresourceContentInitialized(const SubresourceRange& range) const;
     void SetIsSubresourceContentInitialized(bool isInitialized, const SubresourceRange& range);
@@ -122,7 +127,6 @@
     MaybeError ValidateCanUseInSubmitNow() const;
 
     bool IsMultisampledTexture() const;
-    bool IsReadOnly() const;
 
     // Returns true if the size covers the whole subresource.
     bool CoversFullSubresource(uint32_t mipLevel, Aspect aspect, const Extent3D& size) const;
@@ -149,8 +153,6 @@
 
     bool IsImplicitMSAARenderTextureViewSupported() const;
 
-    SharedTextureMemoryContents* GetSharedTextureMemoryContents() const;
-
     // Dawn API
     TextureViewBase* APICreateView(const TextureViewDescriptor* descriptor = nullptr);
     TextureViewBase* APICreateErrorView(const TextureViewDescriptor* descriptor = nullptr);
@@ -171,9 +173,6 @@
     void DestroyImpl() override;
     void AddInternalUsage(wgpu::TextureUsage usage);
 
-    // The shared texture memory state the texture was created from. May be null.
-    Ref<SharedTextureMemoryContents> mSharedTextureMemoryContents;
-
   private:
     struct TextureState {
         TextureState();
diff --git a/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp b/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
index d83751f..16e49df 100644
--- a/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
+++ b/src/dawn/native/d3d/SharedTextureMemoryD3D.cpp
@@ -79,7 +79,7 @@
 
     return FenceAndSignalValue{
         std::move(sharedFence),
-        static_cast<uint64_t>(texture->GetSharedTextureMemoryContents()->GetLastUsageSerial())};
+        static_cast<uint64_t>(texture->GetSharedResourceMemoryContents()->GetLastUsageSerial())};
 }
 
 }  // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d11/BufferD3D11.cpp b/src/dawn/native/d3d11/BufferD3D11.cpp
index a571a37..f8b2395 100644
--- a/src/dawn/native/d3d11/BufferD3D11.cpp
+++ b/src/dawn/native/d3d11/BufferD3D11.cpp
@@ -381,7 +381,7 @@
     }
 
     if (IsFullBufferRange(offset, size)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return {};
     }
 
@@ -397,7 +397,7 @@
     }
 
     if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
     } else {
         DAWN_TRY(InitializeToZero(commandContext));
     }
@@ -409,7 +409,7 @@
     DAWN_ASSERT(NeedsInitialization());
 
     DAWN_TRY(ClearInternal(commandContext, uint8_t(0u)));
-    SetIsDataInitialized();
+    SetInitialized(true);
     GetDevice()->IncrementLazyClearCountForTesting();
 
     return {};
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index 0ead78c..62107d1 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -267,7 +267,7 @@
     Ref<Texture> texture = AcquireRef(new Texture(device, descriptor, Kind::Normal));
     DAWN_TRY(
         texture->InitializeAsExternalTexture(memory->GetD3DResource(), memory->GetKeyedMutex()));
-    texture->mSharedTextureMemoryContents = memory->GetContents();
+    texture->mSharedResourceMemoryContents = memory->GetContents();
     return texture;
 }
 
@@ -502,7 +502,7 @@
 
 MaybeError Texture::SynchronizeTextureBeforeUse(
     const ScopedCommandRecordingContext* commandContext) {
-    if (auto* contents = GetSharedTextureMemoryContents()) {
+    if (auto* contents = GetSharedResourceMemoryContents()) {
         SharedTextureMemoryBase::PendingFenceList fences;
         contents->AcquirePendingFences(&fences);
         contents->SetLastUsageSerial(GetDevice()->GetQueue()->GetPendingCommandSerial());
diff --git a/src/dawn/native/d3d12/BufferD3D12.cpp b/src/dawn/native/d3d12/BufferD3D12.cpp
index fc1ad9b..a8075ba 100644
--- a/src/dawn/native/d3d12/BufferD3D12.cpp
+++ b/src/dawn/native/d3d12/BufferD3D12.cpp
@@ -138,7 +138,7 @@
     Device* device = ToBackend(memory->GetDevice());
     Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor));
     DAWN_TRY(buffer->InitializeAsExternalBuffer(memory->GetD3DResource(), descriptor));
-    buffer->mSharedBufferMemoryContents = memory->GetContents();
+    buffer->mSharedResourceMemoryContents = memory->GetContents();
     return buffer;
 }
 
@@ -299,7 +299,7 @@
     SetLabelImpl();
 
     // Assume the data is initialized since an external pointer was provided.
-    SetIsDataInitialized();
+    SetInitialized(true);
     return {};
 }
 
@@ -571,7 +571,7 @@
     }
 
     if (IsFullBufferRange(offset, size)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return {false};
     }
 
@@ -586,7 +586,7 @@
     }
 
     if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
     } else {
         DAWN_TRY(InitializeToZero(commandContext));
     }
@@ -605,7 +605,7 @@
     // TODO(crbug.com/dawn/484): skip initializing the buffer when it is created on a heap
     // that has already been zero initialized.
     DAWN_TRY(ClearBuffer(commandContext, uint8_t(0u)));
-    SetIsDataInitialized();
+    SetInitialized(true);
     GetDevice()->IncrementLazyClearCountForTesting();
 
     return {};
diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp
index 977b13b..e91368f 100644
--- a/src/dawn/native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -300,7 +300,7 @@
     // the allocation of the staging buffer causes various end2end tests that monitor heap usage
     // to fail if it's done during device creation. Perhaps ClearUnorderedAccessView*() can be
     // used to avoid that.
-    if (!mZeroBuffer->IsDataInitialized()) {
+    if (!mZeroBuffer->IsInitialized()) {
         DynamicUploader* uploader = GetDynamicUploader();
         UploadHandle uploadHandle;
         DAWN_TRY_ASSIGN(uploadHandle,
@@ -313,7 +313,7 @@
                                       uploadHandle.startOffset, mZeroBuffer.Get(), 0,
                                       kZeroBufferSize);
 
-        mZeroBuffer->SetIsDataInitialized();
+        mZeroBuffer->SetInitialized(true);
     }
 
     Buffer* dstBuffer = ToBackend(destination);
diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp
index ff0f67a..8267cd8 100644
--- a/src/dawn/native/d3d12/TextureD3D12.cpp
+++ b/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -237,7 +237,7 @@
     Ref<Texture> texture = AcquireRef(new Texture(device, descriptor));
     DAWN_TRY(texture->InitializeAsExternalTexture(memory->GetD3DResource(), memory->GetKeyedMutex(),
                                                   {}, false));
-    texture->mSharedTextureMemoryContents = memory->GetContents();
+    texture->mSharedResourceMemoryContents = memory->GetContents();
     return texture;
 }
 
@@ -438,7 +438,7 @@
     // Perform the wait only on the first call.
     std::vector<FenceAndSignalValue> waitFences = std::move(mWaitFences);
 
-    if (SharedTextureMemoryContents* contents = GetSharedTextureMemoryContents()) {
+    if (SharedResourceMemoryContents* contents = GetSharedResourceMemoryContents()) {
         SharedTextureMemoryBase::PendingFenceList fences;
         contents->AcquirePendingFences(&fences);
         waitFences.insert(waitFences.end(), std::make_move_iterator(fences->begin()),
@@ -577,7 +577,7 @@
         }
     }
 
-    if (mSharedTextureMemoryContents) {
+    if (mSharedResourceMemoryContents) {
         // SharedTextureMemory supports concurrent reads of the underlying D3D12
         // texture via multiple TextureD3D12 instances created from a single
         // SharedTextureMemory instance. Concurrent read access requires that the
diff --git a/src/dawn/native/metal/BufferMTL.mm b/src/dawn/native/metal/BufferMTL.mm
index d9d0eb4..2403e90 100644
--- a/src/dawn/native/metal/BufferMTL.mm
+++ b/src/dawn/native/metal/BufferMTL.mm
@@ -176,7 +176,7 @@
     }
 
     // Data is assumed to be initialized since it is externally allocated.
-    SetIsDataInitialized();
+    SetInitialized(true);
     SetLabelImpl();
     return {};
 }
@@ -245,7 +245,7 @@
     }
 
     if (IsFullBufferRange(offset, size)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -260,7 +260,7 @@
     }
 
     if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -273,7 +273,7 @@
 
     ClearBuffer(commandContext, uint8_t(0u));
 
-    SetIsDataInitialized();
+    SetInitialized(true);
     GetDevice()->IncrementLazyClearCountForTesting();
 }
 
diff --git a/src/dawn/native/metal/SharedTextureMemoryMTL.mm b/src/dawn/native/metal/SharedTextureMemoryMTL.mm
index e9c291a..c0c08ba 100644
--- a/src/dawn/native/metal/SharedTextureMemoryMTL.mm
+++ b/src/dawn/native/metal/SharedTextureMemoryMTL.mm
@@ -209,7 +209,8 @@
 
         return FenceAndSignalValue{
             std::move(fence),
-            static_cast<uint64_t>(texture->GetSharedTextureMemoryContents()->GetLastUsageSerial())};
+            static_cast<uint64_t>(
+                texture->GetSharedResourceMemoryContents()->GetLastUsageSerial())};
     }
     DAWN_UNREACHABLE();
 }
diff --git a/src/dawn/native/metal/TextureMTL.mm b/src/dawn/native/metal/TextureMTL.mm
index 0b1cec6..1538de0 100644
--- a/src/dawn/native/metal/TextureMTL.mm
+++ b/src/dawn/native/metal/TextureMTL.mm
@@ -321,7 +321,7 @@
     Device* device = ToBackend(memory->GetDevice());
     Ref<Texture> texture = AcquireRef(new Texture(device, descriptor));
     DAWN_TRY(texture->InitializeFromSharedTextureMemory(memory, descriptor));
-    texture->mSharedTextureMemoryContents = memory->GetContents();
+    texture->mSharedResourceMemoryContents = memory->GetContents();
     return texture;
 }
 
@@ -414,7 +414,7 @@
 void Texture::SynchronizeTextureBeforeUse(CommandRecordingContext* commandContext) {
     if (@available(macOS 10.14, iOS 12.0, *)) {
         SharedTextureMemoryBase::PendingFenceList fences;
-        SharedTextureMemoryContents* contents = GetSharedTextureMemoryContents();
+        SharedResourceMemoryContents* contents = GetSharedResourceMemoryContents();
         if (contents != nullptr) {
             contents->AcquirePendingFences(&fences);
             contents->SetLastUsageSerial(GetDevice()->GetQueue()->GetPendingCommandSerial());
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index eeb8a16..db54784 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -270,7 +270,7 @@
                                                uint64_t destinationOffset,
                                                uint64_t size) {
     if (IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
-        destination->SetIsDataInitialized();
+        destination->SetInitialized(true);
     }
 
     auto operation = std::make_unique<CopyFromStagingToBufferOperation>();
diff --git a/src/dawn/native/opengl/BufferGL.cpp b/src/dawn/native/opengl/BufferGL.cpp
index d19f011..6c8eacb 100644
--- a/src/dawn/native/opengl/BufferGL.cpp
+++ b/src/dawn/native/opengl/BufferGL.cpp
@@ -80,7 +80,7 @@
                bool shouldLazyClear)
     : Buffer(device, descriptor) {
     if (!shouldLazyClear) {
-        SetIsDataInitialized();
+        SetInitialized(true);
     }
 }
 
@@ -105,7 +105,7 @@
     }
 
     if (IsFullBufferRange(offset, size)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -119,7 +119,7 @@
     }
 
     if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -140,7 +140,7 @@
     device->IncrementLazyClearCountForTesting();
 
     TrackUsage();
-    SetIsDataInitialized();
+    SetInitialized(true);
 }
 
 bool Buffer::IsCPUWritableAtCreation() const {
diff --git a/src/dawn/native/vulkan/BufferVk.cpp b/src/dawn/native/vulkan/BufferVk.cpp
index d0ac815..65fdeb9 100644
--- a/src/dawn/native/vulkan/BufferVk.cpp
+++ b/src/dawn/native/vulkan/BufferVk.cpp
@@ -362,7 +362,7 @@
     SetLabelImpl();
 
     // Assume the data is initialized since an external pointer was provided.
-    SetIsDataInitialized();
+    SetInitialized(true);
     return {};
 }
 
@@ -599,7 +599,7 @@
     }
 
     if (IsFullBufferRange(offset, size)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -614,7 +614,7 @@
     }
 
     if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
-        SetIsDataInitialized();
+        SetInitialized(true);
         return false;
     }
 
@@ -668,7 +668,7 @@
 
     ClearBuffer(recordingContext, 0u);
     GetDevice()->IncrementLazyClearCountForTesting();
-    SetIsDataInitialized();
+    SetInitialized(true);
 }
 
 void Buffer::ClearBuffer(CommandRecordingContext* recordingContext,
diff --git a/src/dawn/native/vulkan/QueueVk.cpp b/src/dawn/native/vulkan/QueueVk.cpp
index 9e4b0cf..820b93d 100644
--- a/src/dawn/native/vulkan/QueueVk.cpp
+++ b/src/dawn/native/vulkan/QueueVk.cpp
@@ -364,7 +364,7 @@
         mRecordingContext.waitSemaphores.insert(mRecordingContext.waitSemaphores.end(),
                                                 waitRequirements.begin(), waitRequirements.end());
 
-        SharedTextureMemoryContents* contents = texture->GetSharedTextureMemoryContents();
+        SharedResourceMemoryContents* contents = texture->GetSharedResourceMemoryContents();
         if (contents != nullptr) {
             SharedTextureMemoryBase::PendingFenceList fences;
             contents->AcquirePendingFences(&fences);
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index 90ba5ec..3b331f2 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -783,7 +783,7 @@
     const UnpackedPtr<TextureDescriptor>& textureDescriptor) {
     Ref<Texture> texture =
         AcquireRef(new Texture(ToBackend(memory->GetDevice()), textureDescriptor));
-    texture->mSharedTextureMemoryContents = memory->GetContents();
+    texture->mSharedResourceMemoryContents = memory->GetContents();
     texture->mSharedTextureMemoryObjects = {memory->GetVkImage(), memory->GetVkDeviceMemory()};
     texture->mHandle = texture->mSharedTextureMemoryObjects.vkImage->Get();
     texture->mExternalAllocation = texture->mSharedTextureMemoryObjects.vkDeviceMemory->Get();
@@ -1081,7 +1081,7 @@
 
 void Texture::SetPendingAcquire(VkImageLayout pendingAcquireOldLayout,
                                 VkImageLayout pendingAcquireNewLayout) {
-    DAWN_ASSERT(GetSharedTextureMemoryContents() != nullptr);
+    DAWN_ASSERT(GetSharedResourceMemoryContents() != nullptr);
     mExternalState = ExternalState::PendingAcquire;
     mLastExternalState = ExternalState::PendingAcquire;
 
@@ -1190,7 +1190,7 @@
     // to skip the deallocation of the (absence of) VkDeviceMemory.
     device->GetResourceMemoryAllocator()->Deallocate(&mMemoryAllocation);
 
-    if (mExternalAllocation != VK_NULL_HANDLE && GetSharedTextureMemoryContents() == nullptr) {
+    if (mExternalAllocation != VK_NULL_HANDLE && GetSharedResourceMemoryContents() == nullptr) {
         device->GetFencedDeleter()->DeleteWhenUnused(mExternalAllocation);
     }