// Copyright 2017 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_TESTS_DAWNTEST_H_ #define SRC_DAWN_TESTS_DAWNTEST_H_ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <webgpu/webgpu_cpp.h> #include <atomic> #include <memory> #include <queue> #include <string> #include <unordered_map> #include <utility> #include <vector> #include "dawn/common/Log.h" #include "dawn/common/Mutex.h" #include "dawn/common/Platform.h" #include "dawn/common/Preprocessor.h" #include "dawn/dawn_proc_table.h" #include "dawn/native/DawnNative.h" #include "dawn/platform/DawnPlatform.h" #include "dawn/tests/AdapterTestConfig.h" #include "dawn/tests/MockCallback.h" #include "dawn/tests/ParamGenerator.h" #include "dawn/tests/ToggleParser.h" #include "dawn/utils/TestUtils.h" #include "dawn/utils/TextureUtils.h" #include "dawn/webgpu_cpp_print.h" #include "partition_alloc/pointers/raw_ptr.h" // Getting data back from Dawn is done in an async manners so all expectations are "deferred" // until the end of the test. Also expectations use a copy to a MapRead buffer to get the data // so resources should have the CopySrc allowed usage bit if you want to add expectations on // them. // AddBufferExpectation is defined in DawnTestBase as protected function. This ensures the macro can // only be used in derivd class of DawnTestBase. Use "this" pointer to ensure the macro works with // CRTP. #define EXPECT_BUFFER(buffer, offset, size, expectation) … #define EXPECT_BUFFER_U8_EQ(expected, buffer, offset) … #define EXPECT_BUFFER_U8_RANGE_EQ(expected, buffer, offset, count) … #define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) … #define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) … #define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) … #define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) … #define EXPECT_BUFFER_U64_EQ(expected, buffer, offset) … #define EXPECT_BUFFER_U64_RANGE_EQ(expected, buffer, offset, count) … #define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) … #define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) … // Test a pixel of the mip level 0 of a 2D texture. #define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) … #define EXPECT_PIXEL_FLOAT_EQ(expected, texture, x, y) … #define EXPECT_PIXEL_FLOAT16_EQ(expected, texture, x, y) … #define EXPECT_PIXEL_RGBA8_BETWEEN(color0, color1, texture, x, y) … #define EXPECT_TEXTURE_EQ(...) … #define EXPECT_TEXTURE_FLOAT16_EQ(...) … // Matcher for C++ types to verify that their internal C-handles are identical. MATCHER_P(CHandleIs, cType, "") { … } #define ASSERT_DEVICE_ERROR_MSG_ON(device, statement, matcher) … #define ASSERT_DEVICE_ERROR_MSG(statement, matcher) … #define ASSERT_DEVICE_ERROR_ON(device, statement) … #define ASSERT_DEVICE_ERROR(statement) … struct GLFWwindow; void InitDawnEnd2EndTestEnvironment(int argc, char** argv); namespace dawn { namespace utils { class PlatformDebugLogger; class TerribleCommandBuffer; class WireHelper; } // namespace utils namespace detail { class Expectation; class CustomTextureExpectation; template <typename T> class ExpectConstant; template <typename T, typename U = T> class ExpectEq; template <typename T> class ExpectBetweenColors; } // namespace detail namespace wire { class CommandHandler; class WireClient; class WireServer; } // namespace wire class DawnTestEnvironment : public testing::Environment { … }; class DawnTestBase { … }; #define DAWN_SKIP_TEST_IF_BASE(condition, type, reason) … // Skip a test which requires a feature or a toggle to be present / not present or some WIP // features. #define DAWN_TEST_UNSUPPORTED_IF(condition) … // Skip a test when the test failing on a specific HW / backend / OS combination. We can disable // this macro with the command line parameter "--run-suppressed-tests". #define DAWN_SUPPRESS_TEST_IF(condition) … #define EXPECT_DEPRECATION_WARNINGS(statement, n) … #define EXPECT_DEPRECATION_WARNING(statement) … template <typename Params = AdapterTestParam> class DawnTestWithParams : public DawnTestBase, public ::testing::TestWithParam<Params> { … }; template <typename Params> DawnTestWithParams<Params>::DawnTestWithParams() : … { … } DawnTest; // Instantiate the test once for each backend provided after the first argument. Use it like this: // DAWN_INSTANTIATE_TEST(MyTestFixture, MetalBackend, OpenGLBackend) #define DAWN_INSTANTIATE_TEST(testName, ...) … #define DAWN_INSTANTIATE_PREFIXED_TEST_P(prefix, testName, ...) … // Instantiate the test once for each backend provided in the first param list. // The test will be parameterized over the following param lists. // Use it like this: // DAWN_INSTANTIATE_TEST_P(MyTestFixture, {MetalBackend(), OpenGLBackend()}, {A, B}, {1, 2}) // MyTestFixture must extend DawnTestWithParams<Param> where Param is a struct that extends // AdapterTestParam, and whose constructor looks like: // Param(AdapterTestParam, ABorC, 12or3, ..., otherParams... ) // You must also teach GTest how to print this struct. // https://github.com/google/googletest/blob/main/docs/advanced.md#teaching-googletest-how-to-print-your-values // Macro DAWN_TEST_PARAM_STRUCT can help generate this struct. #define DAWN_INSTANTIATE_TEST_P(testName, ...) … // Basically same as DAWN_INSTANTIATE_TEST_P, except that each backend is provided in the // 'backends' param list. #define DAWN_INSTANTIATE_TEST_B(testName, backends, ...) … // Usage: DAWN_TEST_PARAM_STRUCT(Foo, TypeA, TypeB, ...) // Generate a test param struct called Foo which extends AdapterTestParam and generated // struct _Dawn_Foo. _Dawn_Foo has members of types TypeA, TypeB, etc. which are named mTypeA, // mTypeB, etc. in the order they are placed in the macro argument list. Struct Foo should be // constructed with an AdapterTestParam as the first argument, followed by a list of values // to initialize the base _Dawn_Foo struct. // It is recommended to use alias declarations so that stringified types are more readable. // Example: // using MyParam = unsigned int; // DAWN_TEST_PARAM_STRUCT(FooParams, MyParam); #define DAWN_TEST_PARAM_STRUCT(StructName, ...) … namespace detail { // Helper functions used for DAWN_INSTANTIATE_TEST std::vector<AdapterTestParam> GetAvailableAdapterTestParamsForBackends( const BackendTestConfig* params, size_t numParams); // All classes used to implement the deferred expectations should inherit from this. class Expectation { … }; template <typename T> class ExpectConstant : public Expectation { … }; extern template class ExpectConstant<float>; // Expectation that checks the data is equal to some expected values. // T - expected value Type // U - actual value Type (defaults = T) // This is expanded for float16 mostly where T=float, U=uint16_t template <typename T, typename U> class ExpectEq : public Expectation { … }; extern template class ExpectEq<uint8_t>; extern template class ExpectEq<int16_t>; extern template class ExpectEq<uint32_t>; extern template class ExpectEq<uint64_t>; extern template class ExpectEq<int32_t>; extern template class ExpectEq<utils::RGBA8>; extern template class ExpectEq<float>; extern template class ExpectEq<float, uint16_t>; template <typename T> class ExpectBetweenColors : public Expectation { … }; // A color is considered between color0 and color1 when all channel values are within range of // each counterparts. It doesn't matter which value is higher or lower. Essentially color = // lerp(color0, color1, t) where t is [0,1]. But I don't want to be too strict here. extern template class ExpectBetweenColors<utils::RGBA8>; class CustomTextureExpectation : public Expectation { … }; } // namespace detail template <typename Param, typename... Params> auto MakeParamGenerator(std::vector<BackendTestConfig>&& first, std::initializer_list<Params>&&... params) { … } template <typename Param, typename... Params> auto MakeParamGenerator(std::vector<BackendTestConfig>&& first, std::vector<Params>&&... params) { … } } // namespace dawn #endif // SRC_DAWN_TESTS_DAWNTEST_H_