Add SubresourceStorage::Fill(const T&)

This will be used to change the values in the subresource storage after
creation efficiently. Also adds tests.

Bug: 41497359
Change-Id: I575afb5f00a7c2d0c49a2a8cb10a7d03e01e4d27
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173462
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/SubresourceStorage.h b/src/dawn/native/SubresourceStorage.h
index 34ad25c..3dccfc5 100644
--- a/src/dawn/native/SubresourceStorage.h
+++ b/src/dawn/native/SubresourceStorage.h
@@ -129,12 +129,16 @@
     SubresourceStorage(Aspect aspects,
                        uint32_t arrayLayerCount,
                        uint32_t mipLevelCount,
-                       T initialValue = {});
+                       const T& initialValue = {});
 
     // Returns the data for a single subresource. Note that the reference returned might be the
     // same for multiple subresources.
     const T& Get(Aspect aspect, uint32_t arrayLayer, uint32_t mipLevel) const;
 
+    // Fill the storage with a single value for all subresources, resulting in a fully
+    // compressed storage.
+    void Fill(const T& value);
+
     // Given an iterateFunc that's a function or function-like object that can be called with
     // arguments of type (const SubresourceRange& range, const T& data) and returns either void or
     // MaybeError, calls it with aggregate ranges if possible, such that each subresource is part of
@@ -247,17 +251,22 @@
 SubresourceStorage<T>::SubresourceStorage(Aspect aspects,
                                           uint32_t arrayLayerCount,
                                           uint32_t mipLevelCount,
-                                          T initialValue)
+                                          const T& initialValue)
     : mAspects(aspects), mMipLevelCount(mipLevelCount), mArrayLayerCount(arrayLayerCount) {
     DAWN_ASSERT(arrayLayerCount <= std::numeric_limits<decltype(mArrayLayerCount)>::max());
     DAWN_ASSERT(mipLevelCount <= std::numeric_limits<decltype(mMipLevelCount)>::max());
 
-    uint32_t aspectCount = GetAspectCount(aspects);
+    Fill(initialValue);
+}
+
+template <typename T>
+void SubresourceStorage<T>::Fill(const T& value) {
+    uint32_t aspectCount = GetAspectCount(mAspects);
     DAWN_ASSERT(aspectCount <= kMaxAspects);
 
     for (uint32_t aspectIndex = 0; aspectIndex < aspectCount; aspectIndex++) {
         mAspectCompressed[aspectIndex] = true;
-        DataInline(aspectIndex) = initialValue;
+        DataInline(aspectIndex) = value;
     }
 }
 
diff --git a/src/dawn/tests/unittests/SubresourceStorageTests.cpp b/src/dawn/tests/unittests/SubresourceStorageTests.cpp
index c1f6bb0..eeaa82a 100644
--- a/src/dawn/tests/unittests/SubresourceStorageTests.cpp
+++ b/src/dawn/tests/unittests/SubresourceStorageTests.cpp
@@ -25,6 +25,7 @@
 // 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 <algorithm>
 #include <memory>
 #include <string>
 #include <vector>
@@ -46,12 +47,14 @@
     FakeStorage(Aspect aspects,
                 uint32_t arrayLayerCount,
                 uint32_t mipLevelCount,
-                T initialValue = {})
+                const T& initialValue = {})
         : mAspects(aspects),
           mArrayLayerCount(arrayLayerCount),
           mMipLevelCount(mipLevelCount),
           mData(GetAspectCount(aspects) * arrayLayerCount * mipLevelCount, initialValue) {}
 
+    void Fill(const T& value) { std::fill(mData.begin(), mData.end(), value); }
+
     template <typename F>
     void Update(const SubresourceRange& range, F&& updateFunc) {
         for (Aspect aspect : IterateEnumMask(range.aspects)) {
@@ -710,6 +713,44 @@
     EXPECT_EQ(3, s.Get(Aspect::Color, 0, 1));
 }
 
+// Check that fill after creation overwrites whatever was passed as initial value.
+TEST(SubresourceStorageTest, FillAfterInitialization) {
+    const uint32_t kLayers = 2;
+    const uint32_t kLevels = 2;
+    SubresourceStorage<int> s(Aspect::Color, kLayers, kLevels, 3);
+    FakeStorage<int> f(Aspect::Color, kLayers, kLevels, 3);
+
+    s.Fill(42);
+    f.Fill(42);
+
+    f.CheckSameAs(s);
+    CheckAspectCompressed(s, Aspect::Color, true);
+}
+
+// Check that fill after some modification overwrites everything and recompresses.
+TEST(SubresourceStorageTest, FillAfterModificationRecompresses) {
+    const uint32_t kLayers = 2;
+    const uint32_t kLevels = 2;
+    SubresourceStorage<int> s(Aspect::Depth | Aspect::Stencil, kLayers, kLevels, 3);
+    FakeStorage<int> f(Aspect::Depth | Aspect::Stencil, kLayers, kLevels, 3);
+
+    // Cause decompression by writing to a single subresource.
+    {
+        SubresourceRange range = SubresourceRange::MakeSingle(Aspect::Stencil, 1, 1);
+        CallUpdateOnBoth(&s, &f, range, [](const SubresourceRange&, int* data) { *data = 0xCAFE; });
+    }
+    CheckAspectCompressed(s, Aspect::Depth, true);
+    CheckAspectCompressed(s, Aspect::Stencil, false);
+
+    // Fill with 42, aspects should be recompressed entirely.
+    s.Fill(42);
+    f.Fill(42);
+
+    f.CheckSameAs(s);
+    CheckAspectCompressed(s, Aspect::Depth, true);
+    CheckAspectCompressed(s, Aspect::Stencil, true);
+}
+
 // Bugs found while testing:
 //  - mLayersCompressed not initialized to true.
 //  - DecompressLayer setting Compressed to true instead of false.