// Copyright 2017 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef TESTS_DAWNTEST_H_ #define TESTS_DAWNTEST_H_ #include "common/Log.h" #include "common/Platform.h" #include "common/Preprocessor.h" #include "dawn/dawn_proc_table.h" #include "dawn/webgpu_cpp.h" #include "dawn/webgpu_cpp_print.h" #include "dawn_native/DawnNative.h" #include "tests/ParamGenerator.h" #include "tests/ToggleParser.h" #include "utils/ScopedAutoreleasePool.h" #include #include #include #include #include #include // 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) \ this->AddBufferExpectation(__FILE__, __LINE__, buffer, offset, size, expectation) #define EXPECT_BUFFER_U8_EQ(expected, buffer, offset) \ EXPECT_BUFFER(buffer, offset, sizeof(uint8_t), new ::detail::ExpectEq(expected)) #define EXPECT_BUFFER_U8_RANGE_EQ(expected, buffer, offset, count) \ EXPECT_BUFFER(buffer, offset, sizeof(uint8_t) * (count), \ new ::detail::ExpectEq(expected, count)) #define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) \ EXPECT_BUFFER(buffer, offset, sizeof(uint16_t), new ::detail::ExpectEq(expected)) #define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) \ EXPECT_BUFFER(buffer, offset, sizeof(uint16_t) * (count), \ new ::detail::ExpectEq(expected, count)) #define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \ EXPECT_BUFFER(buffer, offset, sizeof(uint32_t), new ::detail::ExpectEq(expected)) #define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \ EXPECT_BUFFER(buffer, offset, sizeof(uint32_t) * (count), \ new ::detail::ExpectEq(expected, count)) #define EXPECT_BUFFER_U64_EQ(expected, buffer, offset) \ EXPECT_BUFFER(buffer, offset, sizeof(uint64_t), new ::detail::ExpectEq(expected)) #define EXPECT_BUFFER_U64_RANGE_EQ(expected, buffer, offset, count) \ EXPECT_BUFFER(buffer, offset, sizeof(uint64_t) * (count), \ new ::detail::ExpectEq(expected, count)) #define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) \ EXPECT_BUFFER(buffer, offset, sizeof(float), new ::detail::ExpectEq(expected)) #define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) \ EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \ new ::detail::ExpectEq(expected, count)) // Test a pixel of the mip level 0 of a 2D texture. #define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \ AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y}) #define EXPECT_PIXEL_FLOAT_EQ(expected, texture, x, y) \ AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y}) #define EXPECT_PIXEL_FLOAT16_EQ(expected, texture, x, y) \ AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y}) #define EXPECT_PIXEL_RGBA8_BETWEEN(color0, color1, texture, x, y) \ AddTextureBetweenColorsExpectation(__FILE__, __LINE__, color0, color1, texture, x, y) #define EXPECT_TEXTURE_EQ(...) AddTextureExpectation(__FILE__, __LINE__, __VA_ARGS__) #define ASSERT_DEVICE_ERROR_MSG(statement, matcher) \ StartExpectDeviceError(matcher); \ statement; \ FlushWire(); \ if (!EndExpectDeviceError()) { \ FAIL() << "Expected device error in:\n " << #statement; \ } \ do { \ } while (0) #define ASSERT_DEVICE_ERROR(statement) ASSERT_DEVICE_ERROR_MSG(statement, testing::_) struct RGBA8 { constexpr RGBA8() : RGBA8(0, 0, 0, 0) { } constexpr RGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) { } bool operator==(const RGBA8& other) const; bool operator!=(const RGBA8& other) const; bool operator<=(const RGBA8& other) const; bool operator>=(const RGBA8& other) const; uint8_t r, g, b, a; static const RGBA8 kZero; static const RGBA8 kBlack; static const RGBA8 kRed; static const RGBA8 kGreen; static const RGBA8 kBlue; static const RGBA8 kYellow; static const RGBA8 kWhite; }; std::ostream& operator<<(std::ostream& stream, const RGBA8& color); struct BackendTestConfig { BackendTestConfig(wgpu::BackendType backendType, std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); wgpu::BackendType backendType; std::vector forceEnabledWorkarounds; std::vector forceDisabledWorkarounds; }; struct TestAdapterProperties : wgpu::AdapterProperties { TestAdapterProperties(const wgpu::AdapterProperties& properties, bool selected); std::string adapterName; bool selected; private: // This may be temporary, so it is copied into |adapterName| and made private. using wgpu::AdapterProperties::name; }; struct AdapterTestParam { AdapterTestParam(const BackendTestConfig& config, const TestAdapterProperties& adapterProperties); TestAdapterProperties adapterProperties; std::vector forceEnabledWorkarounds; std::vector forceDisabledWorkarounds; }; std::ostream& operator<<(std::ostream& os, const AdapterTestParam& param); BackendTestConfig D3D12Backend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); BackendTestConfig MetalBackend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); BackendTestConfig NullBackend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); BackendTestConfig OpenGLBackend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); BackendTestConfig OpenGLESBackend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); BackendTestConfig VulkanBackend(std::initializer_list forceEnabledWorkarounds = {}, std::initializer_list forceDisabledWorkarounds = {}); struct GLFWwindow; namespace utils { class PlatformDebugLogger; class TerribleCommandBuffer; class WireHelper; } // namespace utils namespace detail { class Expectation; class CustomTextureExpectation; template class ExpectEq; template class ExpectBetweenColors; } // namespace detail namespace dawn_wire { class CommandHandler; class WireClient; class WireServer; } // namespace dawn_wire void InitDawnEnd2EndTestEnvironment(int argc, char** argv); class DawnTestEnvironment : public testing::Environment { public: DawnTestEnvironment(int argc, char** argv); ~DawnTestEnvironment() override; static void SetEnvironment(DawnTestEnvironment* env); std::vector GetAvailableAdapterTestParamsForBackends( const BackendTestConfig* params, size_t numParams); void SetUp() override; void TearDown() override; bool UsesWire() const; dawn_native::BackendValidationLevel GetBackendValidationLevel() const; dawn_native::Instance* GetInstance() const; bool HasVendorIdFilter() const; uint32_t GetVendorIdFilter() const; bool HasBackendTypeFilter() const; wgpu::BackendType GetBackendTypeFilter() const; const char* GetWireTraceDir() const; GLFWwindow* GetOpenGLWindow() const; GLFWwindow* GetOpenGLESWindow() const; const std::vector& GetEnabledToggles() const; const std::vector& GetDisabledToggles() const; bool RunSuppressedTests() const; protected: std::unique_ptr mInstance; private: void ParseArgs(int argc, char** argv); std::unique_ptr CreateInstanceAndDiscoverAdapters(); void SelectPreferredAdapterProperties(const dawn_native::Instance* instance); void PrintTestConfigurationAndAdapterInfo(dawn_native::Instance* instance) const; bool mUseWire = false; dawn_native::BackendValidationLevel mBackendValidationLevel = dawn_native::BackendValidationLevel::Disabled; bool mBeginCaptureOnStartup = false; bool mHasVendorIdFilter = false; uint32_t mVendorIdFilter = 0; bool mHasBackendTypeFilter = false; wgpu::BackendType mBackendTypeFilter; std::string mWireTraceDir; bool mRunSuppressedTests = false; ToggleParser mToggleParser; std::vector mDevicePreferences; std::vector mAdapterProperties; std::unique_ptr mPlatformDebugLogger; GLFWwindow* mOpenGLWindow; GLFWwindow* mOpenGLESWindow; }; class DawnTestBase { friend class DawnPerfTestBase; public: DawnTestBase(const AdapterTestParam& param); virtual ~DawnTestBase(); void SetUp(); void TearDown(); bool IsD3D12() const; bool IsMetal() const; bool IsNull() const; bool IsOpenGL() const; bool IsOpenGLES() const; bool IsVulkan() const; bool IsAMD() const; bool IsARM() const; bool IsImgTec() const; bool IsIntel() const; bool IsNvidia() const; bool IsQualcomm() const; bool IsSwiftshader() const; bool IsANGLE() const; bool IsWARP() const; bool IsWindows() const; bool IsLinux() const; bool IsMacOS(int32_t majorVersion = -1, int32_t minorVersion = -1) const; bool UsesWire() const; bool IsBackendValidationEnabled() const; bool RunSuppressedTests() const; bool IsDXC() const; bool IsAsan() const; bool HasToggleEnabled(const char* workaround) const; void StartExpectDeviceError(testing::Matcher errorMatcher = testing::_); bool EndExpectDeviceError(); void ExpectDeviceDestruction(); bool HasVendorIdFilter() const; uint32_t GetVendorIdFilter() const; bool HasBackendTypeFilter() const; wgpu::BackendType GetBackendTypeFilter() const; wgpu::Instance GetInstance() const; dawn_native::Adapter GetAdapter() const; virtual std::unique_ptr CreateTestPlatform(); struct PrintToStringParamName { PrintToStringParamName(const char* test); std::string SanitizeParamName(std::string paramName, size_t index) const; template std::string operator()(const ::testing::TestParamInfo& info) const { return SanitizeParamName(::testing::PrintToStringParamName()(info), info.index); } std::string mTest; }; protected: wgpu::Device device; wgpu::Queue queue; DawnProcTable backendProcs = {}; WGPUDevice backendDevice = nullptr; size_t mLastWarningCount = 0; // Helper methods to implement the EXPECT_ macros std::ostringstream& AddBufferExpectation(const char* file, int line, const wgpu::Buffer& buffer, uint64_t offset, uint64_t size, detail::Expectation* expectation); // T - expected value Type // U - actual value Type (defaults = T) template std::ostringstream& AddTextureExpectation(const char* file, int line, const T* expectedData, const wgpu::Texture& texture, wgpu::Origin3D origin, wgpu::Extent3D extent, uint32_t level = 0, wgpu::TextureAspect aspect = wgpu::TextureAspect::All, uint32_t bytesPerRow = 0) { return AddTextureExpectationImpl( file, line, new detail::ExpectEq(expectedData, extent.width * extent.height * extent.depthOrArrayLayers), texture, origin, extent, level, aspect, sizeof(U), bytesPerRow); } template std::ostringstream& AddTextureExpectation(const char* file, int line, const T& expectedData, const wgpu::Texture& texture, wgpu::Origin3D origin, uint32_t level = 0, wgpu::TextureAspect aspect = wgpu::TextureAspect::All, uint32_t bytesPerRow = 0) { return AddTextureExpectationImpl(file, line, new detail::ExpectEq(expectedData), texture, origin, {1, 1}, level, aspect, sizeof(U), bytesPerRow); } template ::value>::type> std::ostringstream& AddTextureExpectation(const char* file, int line, E* expectation, const wgpu::Texture& texture, wgpu::Origin3D origin, wgpu::Extent3D extent, uint32_t level = 0, wgpu::TextureAspect aspect = wgpu::TextureAspect::All, uint32_t bytesPerRow = 0) { return AddTextureExpectationImpl(file, line, expectation, texture, origin, extent, level, aspect, expectation->DataSize(), bytesPerRow); } template std::ostringstream& AddTextureBetweenColorsExpectation( const char* file, int line, const T& color0, const T& color1, const wgpu::Texture& texture, uint32_t x, uint32_t y, uint32_t level = 0, wgpu::TextureAspect aspect = wgpu::TextureAspect::All, uint32_t bytesPerRow = 0) { return AddTextureExpectationImpl( file, line, new detail::ExpectBetweenColors(color0, color1), texture, {x, y}, {1, 1}, level, aspect, sizeof(T), bytesPerRow); } std::ostringstream& ExpectSampledFloatData(wgpu::Texture texture, uint32_t width, uint32_t height, uint32_t componentCount, uint32_t arrayLayer, uint32_t mipLevel, detail::Expectation* expectation); std::ostringstream& ExpectMultisampledFloatData(wgpu::Texture texture, uint32_t width, uint32_t height, uint32_t componentCount, uint32_t sampleCount, uint32_t arrayLayer, uint32_t mipLevel, detail::Expectation* expectation); std::ostringstream& ExpectSampledDepthData(wgpu::Texture depthTexture, uint32_t width, uint32_t height, uint32_t arrayLayer, uint32_t mipLevel, detail::Expectation* expectation); // Check depth by uploading expected data to a sampled texture, writing it out as a depth // attachment, and then using the "equals" depth test to check the contents are the same. // Check stencil by rendering a full screen quad and using the "equals" stencil test with // a stencil reference value. Note that checking stencil checks that the entire stencil // buffer is equal to the expected stencil value. std::ostringstream& ExpectAttachmentDepthStencilTestData(wgpu::Texture texture, wgpu::TextureFormat format, uint32_t width, uint32_t height, uint32_t arrayLayer, uint32_t mipLevel, std::vector expectedDepth, uint8_t* expectedStencil); std::ostringstream& ExpectAttachmentDepthTestData(wgpu::Texture texture, wgpu::TextureFormat format, uint32_t width, uint32_t height, uint32_t arrayLayer, uint32_t mipLevel, std::vector expectedDepth) { return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer, mipLevel, std::move(expectedDepth), nullptr); } std::ostringstream& ExpectAttachmentStencilTestData(wgpu::Texture texture, wgpu::TextureFormat format, uint32_t width, uint32_t height, uint32_t arrayLayer, uint32_t mipLevel, uint8_t expectedStencil) { return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer, mipLevel, {}, &expectedStencil); } void WaitABit(); void FlushWire(); void WaitForAllOperations(); bool SupportsFeatures(const std::vector& features); // Called in SetUp() to get the features required to be enabled in the tests. The tests must // check if the required features are supported by the adapter in this function and guarantee // the returned features are all supported by the adapter. The tests may provide different // code path to handle the situation when not all features are supported. virtual std::vector GetRequiredFeatures(); virtual wgpu::RequiredLimits GetRequiredLimits(const wgpu::SupportedLimits&); const wgpu::AdapterProperties& GetAdapterProperties() const; // TODO(crbug.com/dawn/689): Use limits returned from the wire // This is implemented here because tests need to always query // the |backendDevice| since limits are not implemented in the wire. wgpu::SupportedLimits GetSupportedLimits(); private: utils::ScopedAutoreleasePool mObjCAutoreleasePool; AdapterTestParam mParam; std::unique_ptr mWireHelper; // Tracking for validation errors static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata); static void OnDeviceLost(WGPUDeviceLostReason reason, const char* message, void* userdata); bool mExpectError = false; bool mError = false; testing::Matcher mErrorMatcher; bool mExpectDestruction = false; std::ostringstream& AddTextureExpectationImpl(const char* file, int line, detail::Expectation* expectation, const wgpu::Texture& texture, wgpu::Origin3D origin, wgpu::Extent3D extent, uint32_t level, wgpu::TextureAspect aspect, uint32_t dataSize, uint32_t bytesPerRow); std::ostringstream& ExpectSampledFloatDataImpl(wgpu::TextureView textureView, const char* wgslTextureType, uint32_t width, uint32_t height, uint32_t componentCount, uint32_t sampleCount, detail::Expectation* expectation); // MapRead buffers used to get data for the expectations struct ReadbackSlot { wgpu::Buffer buffer; uint64_t bufferSize; const void* mappedData = nullptr; }; std::vector mReadbackSlots; // Maps all the buffers and fill ReadbackSlot::mappedData void MapSlotsSynchronously(); static void SlotMapCallback(WGPUBufferMapAsyncStatus status, void* userdata); size_t mNumPendingMapOperations = 0; // Reserve space where the data for an expectation can be copied struct ReadbackReservation { wgpu::Buffer buffer; size_t slot; uint64_t offset; }; ReadbackReservation ReserveReadback(uint64_t readbackSize); struct DeferredExpectation { const char* file; int line; size_t readbackSlot; uint64_t readbackOffset; uint64_t size; uint32_t rowBytes; uint32_t bytesPerRow; std::unique_ptr expectation; // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316 // Use unique_ptr because of missing move/copy constructors on std::basic_ostringstream std::unique_ptr message; }; std::vector mDeferredExpectations; // Assuming the data is mapped, checks all expectations void ResolveExpectations(); dawn_native::Adapter mBackendAdapter; std::unique_ptr mTestPlatform; }; #define DAWN_SKIP_TEST_IF_BASE(condition, type, reason) \ do { \ if (condition) { \ dawn::InfoLog() << "Test " type ": " #reason; \ GTEST_SKIP(); \ return; \ } \ } while (0) // 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) \ DAWN_SKIP_TEST_IF_BASE(condition, "unsupported", 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) \ DAWN_SKIP_TEST_IF_BASE(!RunSuppressedTests() && condition, "suppressed", condition) #define EXPECT_DEPRECATION_WARNINGS(statement, n) \ do { \ if (UsesWire()) { \ statement; \ } else { \ size_t warningsBefore = \ dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \ statement; \ size_t warningsAfter = \ dawn_native::GetDeprecationWarningCountForTesting(device.Get()); \ EXPECT_EQ(mLastWarningCount, warningsBefore); \ if (!HasToggleEnabled("skip_validation")) { \ EXPECT_EQ(warningsAfter, warningsBefore + n); \ } \ mLastWarningCount = warningsAfter; \ } \ } while (0) #define EXPECT_DEPRECATION_WARNING(statement) EXPECT_DEPRECATION_WARNINGS(statement, 1) template class DawnTestWithParams : public DawnTestBase, public ::testing::TestWithParam { protected: DawnTestWithParams(); ~DawnTestWithParams() override = default; void SetUp() override { DawnTestBase::SetUp(); } void TearDown() override { DawnTestBase::TearDown(); } }; template DawnTestWithParams::DawnTestWithParams() : DawnTestBase(this->GetParam()) { } using DawnTest = DawnTestWithParams<>; // 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, ...) \ const decltype(DAWN_PP_GET_HEAD(__VA_ARGS__)) testName##params[] = {__VA_ARGS__}; \ INSTANTIATE_TEST_SUITE_P( \ , testName, \ testing::ValuesIn(::detail::GetAvailableAdapterTestParamsForBackends( \ testName##params, sizeof(testName##params) / sizeof(testName##params[0]))), \ DawnTestBase::PrintToStringParamName(#testName)); \ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(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, C}, {1, 2, 3}) // MyTestFixture must extend DawnTestWithParams 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/master/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, ...) \ INSTANTIATE_TEST_SUITE_P( \ , testName, ::testing::ValuesIn(MakeParamGenerator(__VA_ARGS__)), \ DawnTestBase::PrintToStringParamName(#testName)); \ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName) // Implementation for DAWN_TEST_PARAM_STRUCT to declare/print struct fields. #define DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD(Type) Type DAWN_PP_CONCATENATE(m, Type); #define DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD(Type) \ o << "; " << #Type << "=" << param.DAWN_PP_CONCATENATE(m, Type); // 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, ...) \ struct DAWN_PP_CONCATENATE(_Dawn_, StructName) { \ DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD, \ __VA_ARGS__)) \ }; \ std::ostream& operator<<(std::ostream& o, \ const DAWN_PP_CONCATENATE(_Dawn_, StructName) & param) { \ DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD, \ __VA_ARGS__)) \ return o; \ } \ struct StructName : AdapterTestParam, DAWN_PP_CONCATENATE(_Dawn_, StructName) { \ template \ StructName(const AdapterTestParam& param, Args&&... args) \ : AdapterTestParam(param), \ DAWN_PP_CONCATENATE(_Dawn_, StructName){std::forward(args)...} { \ } \ }; \ std::ostream& operator<<(std::ostream& o, const StructName& param) { \ o << static_cast(param); \ o << "; " << static_cast(param); \ return o; \ } \ static_assert(true, "require semicolon") namespace detail { // Helper functions used for DAWN_INSTANTIATE_TEST std::vector GetAvailableAdapterTestParamsForBackends( const BackendTestConfig* params, size_t numParams); // All classes used to implement the deferred expectations should inherit from this. class Expectation { public: virtual ~Expectation() = default; // Will be called with the buffer or texture data the expectation should check. virtual testing::AssertionResult Check(const void* data, size_t size) = 0; }; // 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 class ExpectEq : public Expectation { public: ExpectEq(T singleValue, T tolerance = {}); ExpectEq(const T* values, const unsigned int count, T tolerance = {}); testing::AssertionResult Check(const void* data, size_t size) override; private: std::vector mExpected; T mTolerance; }; extern template class ExpectEq; extern template class ExpectEq; extern template class ExpectEq; extern template class ExpectEq; extern template class ExpectEq; extern template class ExpectEq; extern template class ExpectEq; template class ExpectBetweenColors : public Expectation { public: // Inclusive for now ExpectBetweenColors(T value0, T value1); testing::AssertionResult Check(const void* data, size_t size) override; private: std::vector mLowerColorChannels; std::vector mHigherColorChannels; // used for printing error std::vector mValues0; std::vector mValues1; }; // 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; class CustomTextureExpectation : public Expectation { public: virtual ~CustomTextureExpectation() = default; virtual uint32_t DataSize() = 0; }; } // namespace detail #endif // TESTS_DAWNTEST_H_