// Copyright 2020 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 <algorithm> #include <memory> #include <string> #include <vector> #include "dawn/common/Log.h" #include "dawn/native/SubresourceStorage.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace dawn::native { HasSubstr; // A fake class that replicates the behavior of SubresourceStorage but without any compression // and is used to compare the results of operations on SubresourceStorage against the "ground // truth" of FakeStorage. template <typename T> struct FakeStorage { … }; // Track a set of ranges that have been seen and can assert that in aggregate they make exactly // a single range (and that each subresource was seen only once). struct RangeTracker { … }; template <typename T> void FakeStorage<T>::CheckSameAs(const SubresourceStorage<T>& real) { … } template <typename T> void CheckAspectCompressed(const SubresourceStorage<T>& s, Aspect aspect, bool expected) { … } template <typename T> void CheckLayerCompressed(const SubresourceStorage<T>& s, Aspect aspect, uint32_t layer, bool expected) { … } struct SmallData { … }; bool operator==(const SmallData& a, const SmallData& b) { … } // Tests that the MaybeError version of Iterate returns the first error that it encounters. TEST(SubresourceStorageTest, IterateMaybeError) { … } // Test that the default value is correctly set. TEST(SubresourceStorageTest, DefaultValue) { … } // The tests for Update() all follow the same pattern of setting up a real and a fake storage // then performing one or multiple Update()s on them and checking: // - They have the same content. // - The Update() range was correct. // - The aspects and layers have the expected "compressed" status. // Calls Update both on the read storage and the fake storage but intercepts the call to // updateFunc done by the real storage to check their ranges argument aggregate to exactly the // update range. template <typename T, typename F> void CallUpdateOnBoth(SubresourceStorage<T>* s, FakeStorage<T>* f, const SubresourceRange& range, F&& updateFunc) { … } // Test updating a single subresource on a single-aspect storage. TEST(SubresourceStorageTest, SingleSubresourceUpdateSingleAspect) { … } // Test updating a single subresource on a multi-aspect storage. TEST(SubresourceStorageTest, SingleSubresourceUpdateMultiAspect) { … } // Test updating as a stipple pattern on one of two aspects then updating it completely. TEST(SubresourceStorageTest, UpdateStipple) { … } // Test updating as a crossing band pattern: // - The first band is full layers [2, 3] on both aspects // - The second band is full mips [5, 6] on one aspect. // Then updating completely. TEST(SubresourceStorageTest, UpdateTwoBand) { … } // Test updating with extremal subresources // - Then half of the array layers in full. // - Then updating completely. TEST(SubresourceStorageTest, UpdateExtremas) { … } // A regression test for an issue found while reworking the implementation where // RecompressAspect didn't correctly check that each each layer was compressed but only that // their 0th value was the same. TEST(SubresourceStorageTest, UpdateLevel0sHappenToMatch) { … } // The tests for Merge() all follow the same as the Update() tests except that they use Update() // to set up the test storages. // Similar to CallUpdateOnBoth but for Merge template <typename T, typename U, typename F> void CallMergeOnBoth(SubresourceStorage<T>* s, FakeStorage<T>* f, const SubresourceStorage<U>& other, F&& mergeFunc) { … } // Test merging two fully compressed single-aspect resources. TEST(SubresourceStorageTest, MergeFullWithFullSingleAspect) { … } // Test merging two fully compressed multi-aspect resources. TEST(SubresourceStorageTest, MergeFullWithFullMultiAspect) { … } // Test merging a fully compressed resource in a resource with the "cross band" pattern. // - The first band is full layers [2, 3] on both aspects // - The second band is full mips [5, 6] on one aspect. // This provides coverage of using a single piece of data from `other` to update all of `s` TEST(SubresourceStorageTest, MergeFullInTwoBand) { … } // Test the reverse, mergign two-bands in a full resource. This provides coverage for // decompressing aspects / and partilly layers to match the compression of `other` TEST(SubresourceStorageTest, MergeTwoBandInFull) { … } // Test merging storage with a layer band in a stipple patterned storage. This provide coverage // for the code path that uses the same layer data for other multiple times. TEST(SubresourceStorageTest, MergeLayerBandInStipple) { … } // Regression test for a missing check that layer 0 is compressed when recompressing. TEST(SubresourceStorageTest, Layer0NotCompressedBlocksAspectRecompression) { … } // Regression test for aspect decompression not copying to layer 0 TEST(SubresourceStorageTest, AspectDecompressionUpdatesLayer0) { … } // Check that fill after creation overwrites whatever was passed as initial value. TEST(SubresourceStorageTest, FillAfterInitialization) { … } // Check that fill after some modification overwrites everything and recompresses. TEST(SubresourceStorageTest, FillAfterModificationRecompresses) { … } // Bugs found while testing: // - mLayersCompressed not initialized to true. // - DecompressLayer setting Compressed to true instead of false. // - Get() checking for !compressed instead of compressed for the early exit. // - DAWN_ASSERT in RecompressLayers was inverted. // - Two != being converted to == during a rework. // - (with DAWN_ASSERT) that RecompressAspect didn't check that aspect 0 was compressed. // - Missing decompression of layer 0 after introducing mInlineAspectData. } // namespace dawn::native