mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-23 20:22:08 +00:00
But keep a namespace alias to avoid breaking project that depend on the previous namespace name while they get updated. Some TraceEvent.h macro were using "platform" as an argument name so that was renamed to "platformObj" to avoid conflicting with ::platform:: Bug: dawn:824 Change-Id: Iaf14853f02b0d9fcf866ce87788f87a3fdf8f364 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/75541 Auto-Submit: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
799 lines
36 KiB
C++
799 lines
36 KiB
C++
// 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 "utils/TextureUtils.h"
|
|
|
|
#include <dawn_platform/DawnPlatform.h>
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
// 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<uint8_t>(expected))
|
|
|
|
#define EXPECT_BUFFER_U8_RANGE_EQ(expected, buffer, offset, count) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint8_t) * (count), \
|
|
new ::detail::ExpectEq<uint8_t>(expected, count))
|
|
|
|
#define EXPECT_BUFFER_U16_EQ(expected, buffer, offset) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint16_t), new ::detail::ExpectEq<uint16_t>(expected))
|
|
|
|
#define EXPECT_BUFFER_U16_RANGE_EQ(expected, buffer, offset, count) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint16_t) * (count), \
|
|
new ::detail::ExpectEq<uint16_t>(expected, count))
|
|
|
|
#define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint32_t), new ::detail::ExpectEq<uint32_t>(expected))
|
|
|
|
#define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint32_t) * (count), \
|
|
new ::detail::ExpectEq<uint32_t>(expected, count))
|
|
|
|
#define EXPECT_BUFFER_U64_EQ(expected, buffer, offset) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint64_t), new ::detail::ExpectEq<uint64_t>(expected))
|
|
|
|
#define EXPECT_BUFFER_U64_RANGE_EQ(expected, buffer, offset, count) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(uint64_t) * (count), \
|
|
new ::detail::ExpectEq<uint64_t>(expected, count))
|
|
|
|
#define EXPECT_BUFFER_FLOAT_EQ(expected, buffer, offset) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(float), new ::detail::ExpectEq<float>(expected))
|
|
|
|
#define EXPECT_BUFFER_FLOAT_RANGE_EQ(expected, buffer, offset, count) \
|
|
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
|
new ::detail::ExpectEq<float>(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<float, uint16_t>(__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 EXPECT_TEXTURE_FLOAT16_EQ(...) \
|
|
AddTextureExpectation<float, uint16_t>(__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<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
wgpu::BackendType backendType;
|
|
|
|
std::vector<const char*> forceEnabledWorkarounds;
|
|
std::vector<const char*> 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<const char*> forceEnabledWorkarounds;
|
|
std::vector<const char*> forceDisabledWorkarounds;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const AdapterTestParam& param);
|
|
|
|
BackendTestConfig D3D12Backend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
BackendTestConfig MetalBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
BackendTestConfig NullBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
BackendTestConfig OpenGLBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
BackendTestConfig OpenGLESBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
BackendTestConfig VulkanBackend(std::initializer_list<const char*> forceEnabledWorkarounds = {},
|
|
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
|
|
|
struct GLFWwindow;
|
|
|
|
namespace utils {
|
|
class PlatformDebugLogger;
|
|
class TerribleCommandBuffer;
|
|
class WireHelper;
|
|
} // namespace utils
|
|
|
|
namespace detail {
|
|
class Expectation;
|
|
class CustomTextureExpectation;
|
|
|
|
template <typename T, typename U = T>
|
|
class ExpectEq;
|
|
template <typename T>
|
|
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<AdapterTestParam> 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<std::string>& GetEnabledToggles() const;
|
|
const std::vector<std::string>& GetDisabledToggles() const;
|
|
|
|
bool RunSuppressedTests() const;
|
|
|
|
protected:
|
|
std::unique_ptr<dawn_native::Instance> mInstance;
|
|
|
|
private:
|
|
void ParseArgs(int argc, char** argv);
|
|
std::unique_ptr<dawn_native::Instance> 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<dawn_native::DeviceType> mDevicePreferences;
|
|
std::vector<TestAdapterProperties> mAdapterProperties;
|
|
|
|
std::unique_ptr<utils::PlatformDebugLogger> 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<std::string> 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<dawn::platform::Platform> CreateTestPlatform();
|
|
|
|
struct PrintToStringParamName {
|
|
PrintToStringParamName(const char* test);
|
|
std::string SanitizeParamName(std::string paramName, size_t index) const;
|
|
|
|
template <class ParamType>
|
|
std::string operator()(const ::testing::TestParamInfo<ParamType>& 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 <typename T, typename U = T>
|
|
std::ostringstream& AddTextureExpectation(const char* file,
|
|
int line,
|
|
const T* expectedData,
|
|
const wgpu::Texture& texture,
|
|
wgpu::Origin3D origin,
|
|
wgpu::Extent3D extent,
|
|
wgpu::TextureFormat format,
|
|
T tolerance = 0,
|
|
uint32_t level = 0,
|
|
wgpu::TextureAspect aspect = wgpu::TextureAspect::All,
|
|
uint32_t bytesPerRow = 0) {
|
|
uint32_t texelBlockSize = utils::GetTexelBlockSizeInBytes(format);
|
|
uint32_t texelComponentCount = utils::GetWGSLRenderableColorTextureComponentCount(format);
|
|
|
|
return AddTextureExpectationImpl(
|
|
file, line,
|
|
new detail::ExpectEq<T, U>(
|
|
expectedData,
|
|
texelComponentCount * extent.width * extent.height * extent.depthOrArrayLayers,
|
|
tolerance),
|
|
texture, origin, extent, level, aspect, texelBlockSize, bytesPerRow);
|
|
}
|
|
|
|
template <typename T, typename U = T>
|
|
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<T, U>(expectedData,
|
|
extent.width * extent.height * extent.depthOrArrayLayers),
|
|
texture, origin, extent, level, aspect, sizeof(U), bytesPerRow);
|
|
}
|
|
|
|
template <typename T, typename U = T>
|
|
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<T, U>(expectedData),
|
|
texture, origin, {1, 1}, level, aspect, sizeof(U),
|
|
bytesPerRow);
|
|
}
|
|
|
|
template <typename E,
|
|
typename = typename std::enable_if<
|
|
std::is_base_of<detail::CustomTextureExpectation, E>::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 <typename T>
|
|
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<T>(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<float> 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<float> 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<wgpu::FeatureName>& 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<wgpu::FeatureName> 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<utils::WireHelper> 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<std::string> 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<ReadbackSlot> 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<detail::Expectation> 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<std::ostringstream> message;
|
|
};
|
|
std::vector<DeferredExpectation> mDeferredExpectations;
|
|
|
|
// Assuming the data is mapped, checks all expectations
|
|
void ResolveExpectations();
|
|
|
|
dawn_native::Adapter mBackendAdapter;
|
|
|
|
std::unique_ptr<dawn::platform::Platform> 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 <typename Params = AdapterTestParam>
|
|
class DawnTestWithParams : public DawnTestBase, public ::testing::TestWithParam<Params> {
|
|
protected:
|
|
DawnTestWithParams();
|
|
~DawnTestWithParams() override = default;
|
|
|
|
void SetUp() override {
|
|
DawnTestBase::SetUp();
|
|
}
|
|
|
|
void TearDown() override {
|
|
DawnTestBase::TearDown();
|
|
}
|
|
};
|
|
|
|
template <typename Params>
|
|
DawnTestWithParams<Params>::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<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/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<testName::ParamType>(__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 <typename... Args> \
|
|
StructName(const AdapterTestParam& param, Args&&... args) \
|
|
: AdapterTestParam(param), \
|
|
DAWN_PP_CONCATENATE(_Dawn_, StructName){std::forward<Args>(args)...} { \
|
|
} \
|
|
}; \
|
|
std::ostream& operator<<(std::ostream& o, const StructName& param) { \
|
|
o << static_cast<const AdapterTestParam&>(param); \
|
|
o << "; " << static_cast<const DAWN_PP_CONCATENATE(_Dawn_, StructName)&>(param); \
|
|
return o; \
|
|
} \
|
|
static_assert(true, "require semicolon")
|
|
|
|
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 {
|
|
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 <typename T, typename U>
|
|
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<T> mExpected;
|
|
T mTolerance;
|
|
};
|
|
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<RGBA8>;
|
|
extern template class ExpectEq<float>;
|
|
extern template class ExpectEq<float, uint16_t>;
|
|
|
|
template <typename T>
|
|
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<T> mLowerColorChannels;
|
|
std::vector<T> mHigherColorChannels;
|
|
|
|
// used for printing error
|
|
std::vector<T> mValues0;
|
|
std::vector<T> 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<RGBA8>;
|
|
|
|
class CustomTextureExpectation : public Expectation {
|
|
public:
|
|
virtual ~CustomTextureExpectation() = default;
|
|
virtual uint32_t DataSize() = 0;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
#endif // TESTS_DAWNTEST_H_
|