mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-18 01:15:39 +00:00
Emulate store and multisample resolve on Metal
This patch implements "store and MSAA resolve" store operation on Metal drivers that don't support MTLStoreActionStoreAndMultisampleResolve with a workaround that does MSAA resolve in another render pass. Driver workaround is one type of Dawn Toggles. Dawn Toggles will include other optional optimizations and features that can be configured to use or not when we create Dawn Devices. As all Metal try bots don't need this toggle, to better test this patch on the try bots: 1. We add the support of forcing enabling a workaround when starting an Dawn end2end test so that we can test the workaround on the platforms where the workaround is disabled. 2. We add an optional parameter DeviceDescriptor to CreateDevice() so that we can custom the toggles the Dawn device should use. This patch also adds the support of querying toggle details from Instance and the names of the toggles in use from Device. These APIs are tested in the Dawn unittests added in this patch. BUG=dawn:56 TEST=dawn_end2end_tests TEST=dawn_unittests Change-Id: Iae31d2ded6057eee638b6099d3061e9d78b04d55 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6620 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
committed by
Commit Bot service account
parent
8e97b4c8a5
commit
15d4c2e63b
@@ -67,6 +67,12 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
dawn_native::DeviceDescriptor InitWorkaround(const char* forceEnabledWorkaround) {
|
||||
dawn_native::DeviceDescriptor deviceDescriptor;
|
||||
deviceDescriptor.forceEnabledToggles.push_back(forceEnabledWorkaround);
|
||||
return deviceDescriptor;
|
||||
}
|
||||
|
||||
struct MapReadUserdata {
|
||||
DawnTest* test;
|
||||
size_t slot;
|
||||
@@ -83,6 +89,12 @@ namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
DawnTestParam ForceWorkaround(const DawnTestParam& originParam, const char* workaround) {
|
||||
DawnTestParam newTestParam = originParam;
|
||||
newTestParam.forceEnabledWorkaround = workaround;
|
||||
return newTestParam;
|
||||
}
|
||||
|
||||
// Implementation of DawnTestEnvironment
|
||||
|
||||
void InitDawnEnd2EndTestEnvironment(int argc, char** argv) {
|
||||
@@ -112,10 +124,10 @@ void DawnTestEnvironment::SetUp() {
|
||||
mInstance = std::make_unique<dawn_native::Instance>();
|
||||
|
||||
static constexpr dawn_native::BackendType kAllBackends[] = {
|
||||
D3D12Backend,
|
||||
MetalBackend,
|
||||
OpenGLBackend,
|
||||
VulkanBackend,
|
||||
dawn_native::BackendType::D3D12,
|
||||
dawn_native::BackendType::Metal,
|
||||
dawn_native::BackendType::OpenGL,
|
||||
dawn_native::BackendType::Vulkan,
|
||||
};
|
||||
|
||||
// Create a test window for each backend and discover an adapter using it.
|
||||
@@ -191,19 +203,19 @@ DawnTest::~DawnTest() {
|
||||
}
|
||||
|
||||
bool DawnTest::IsD3D12() const {
|
||||
return GetParam() == D3D12Backend;
|
||||
return GetParam().backendType == dawn_native::BackendType::D3D12;
|
||||
}
|
||||
|
||||
bool DawnTest::IsMetal() const {
|
||||
return GetParam() == MetalBackend;
|
||||
return GetParam().backendType == dawn_native::BackendType::Metal;
|
||||
}
|
||||
|
||||
bool DawnTest::IsOpenGL() const {
|
||||
return GetParam() == OpenGLBackend;
|
||||
return GetParam().backendType == dawn_native::BackendType::OpenGL;
|
||||
}
|
||||
|
||||
bool DawnTest::IsVulkan() const {
|
||||
return GetParam() == VulkanBackend;
|
||||
return GetParam().backendType == dawn_native::BackendType::Vulkan;
|
||||
}
|
||||
|
||||
bool DawnTest::IsAMD() const {
|
||||
@@ -257,19 +269,20 @@ bool DawnTest::IsMacOS() const {
|
||||
void DawnTest::SetUp() {
|
||||
// Get an adapter for the backend to use, and create the device.
|
||||
dawn_native::Adapter backendAdapter;
|
||||
const dawn_native::BackendType backendType = GetParam().backendType;
|
||||
{
|
||||
dawn_native::Instance* instance = gTestEnv->GetInstance();
|
||||
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
||||
|
||||
for (const dawn_native::Adapter& adapter : adapters) {
|
||||
if (adapter.GetBackendType() == GetParam()) {
|
||||
if (adapter.GetBackendType() == backendType) {
|
||||
backendAdapter = adapter;
|
||||
// On Metal, select the last adapter so that the discrete GPU is tested on
|
||||
// multi-GPU systems.
|
||||
// TODO(cwallez@chromium.org): Replace this with command line arguments requesting
|
||||
// a specific device / vendor ID once the macOS 10.13 SDK is rolled and correct
|
||||
// PCI info collection is implemented on Metal.
|
||||
if (GetParam() != MetalBackend) {
|
||||
if (backendType != dawn_native::BackendType::Metal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -279,13 +292,22 @@ void DawnTest::SetUp() {
|
||||
}
|
||||
|
||||
mPCIInfo = backendAdapter.GetPCIInfo();
|
||||
DawnDevice backendDevice = backendAdapter.CreateDevice();
|
||||
|
||||
DawnDevice backendDevice;
|
||||
const char* forceEnabledWorkaround = GetParam().forceEnabledWorkaround;
|
||||
if (forceEnabledWorkaround != nullptr) {
|
||||
dawn_native::DeviceDescriptor deviceDescriptor = InitWorkaround(forceEnabledWorkaround);
|
||||
backendDevice = backendAdapter.CreateDevice(&deviceDescriptor);
|
||||
} else {
|
||||
backendDevice = backendAdapter.CreateDevice(nullptr);
|
||||
}
|
||||
|
||||
DawnProcTable backendProcs = dawn_native::GetProcs();
|
||||
|
||||
// Get the test window and create the device using it (esp. for OpenGL)
|
||||
GLFWwindow* testWindow = gTestEnv->GetWindowForBackend(GetParam());
|
||||
GLFWwindow* testWindow = gTestEnv->GetWindowForBackend(backendType);
|
||||
DAWN_ASSERT(testWindow != nullptr);
|
||||
mBinding.reset(utils::CreateBinding(GetParam(), testWindow, backendDevice));
|
||||
mBinding.reset(utils::CreateBinding(backendType, testWindow, backendDevice));
|
||||
DAWN_ASSERT(mBinding != nullptr);
|
||||
|
||||
// Choose whether to use the backend procs and devices directly, or set up the wire.
|
||||
@@ -586,20 +608,26 @@ namespace detail {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<dawn_native::BackendType> FilterBackends(const dawn_native::BackendType* types,
|
||||
size_t numParams) {
|
||||
std::vector<dawn_native::BackendType> backends;
|
||||
std::vector<DawnTestParam> FilterBackends(const DawnTestParam* params, size_t numParams) {
|
||||
std::vector<DawnTestParam> backends;
|
||||
|
||||
for (size_t i = 0; i < numParams; ++i) {
|
||||
if (IsBackendAvailable(types[i])) {
|
||||
backends.push_back(types[i]);
|
||||
if (IsBackendAvailable(params[i].backendType)) {
|
||||
backends.push_back(params[i]);
|
||||
}
|
||||
}
|
||||
return backends;
|
||||
}
|
||||
|
||||
std::string GetParamName(const testing::TestParamInfo<dawn_native::BackendType>& info) {
|
||||
return ParamName(info.param);
|
||||
std::string GetParamName(const testing::TestParamInfo<DawnTestParam>& info) {
|
||||
std::ostringstream ostream;
|
||||
ostream << ParamName(info.param.backendType);
|
||||
|
||||
if (info.param.forceEnabledWorkaround != nullptr) {
|
||||
ostream << "_" << info.param.forceEnabledWorkaround;
|
||||
}
|
||||
|
||||
return ostream.str();
|
||||
}
|
||||
|
||||
// Helper classes to set expectations
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "dawn_native/DawnNative.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -60,11 +61,24 @@ struct RGBA8 {
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& stream, const RGBA8& color);
|
||||
|
||||
struct DawnTestParam {
|
||||
constexpr explicit DawnTestParam(dawn_native::BackendType backendType)
|
||||
: backendType(backendType) {
|
||||
}
|
||||
|
||||
dawn_native::BackendType backendType;
|
||||
|
||||
// TODO(jiawei.shao@intel.com): support enabling and disabling multiple workarounds.
|
||||
const char* forceEnabledWorkaround = nullptr;
|
||||
};
|
||||
|
||||
// Shorthands for backend types used in the DAWN_INSTANTIATE_TEST
|
||||
static constexpr dawn_native::BackendType D3D12Backend = dawn_native::BackendType::D3D12;
|
||||
static constexpr dawn_native::BackendType MetalBackend = dawn_native::BackendType::Metal;
|
||||
static constexpr dawn_native::BackendType OpenGLBackend = dawn_native::BackendType::OpenGL;
|
||||
static constexpr dawn_native::BackendType VulkanBackend = dawn_native::BackendType::Vulkan;
|
||||
static constexpr DawnTestParam D3D12Backend(dawn_native::BackendType::D3D12);
|
||||
static constexpr DawnTestParam MetalBackend(dawn_native::BackendType::Metal);
|
||||
static constexpr DawnTestParam OpenGLBackend(dawn_native::BackendType::OpenGL);
|
||||
static constexpr DawnTestParam VulkanBackend(dawn_native::BackendType::Vulkan);
|
||||
|
||||
DawnTestParam ForceWorkaround(const DawnTestParam& originParam, const char* workaround);
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
@@ -107,7 +121,7 @@ class DawnTestEnvironment : public testing::Environment {
|
||||
std::unordered_map<dawn_native::BackendType, GLFWwindow*> mWindows;
|
||||
};
|
||||
|
||||
class DawnTest : public ::testing::TestWithParam<dawn_native::BackendType> {
|
||||
class DawnTest : public ::testing::TestWithParam<DawnTestParam> {
|
||||
public:
|
||||
DawnTest();
|
||||
~DawnTest();
|
||||
@@ -242,9 +256,8 @@ class DawnTest : public ::testing::TestWithParam<dawn_native::BackendType> {
|
||||
namespace detail {
|
||||
// Helper functions used for DAWN_INSTANTIATE_TEST
|
||||
bool IsBackendAvailable(dawn_native::BackendType type);
|
||||
std::vector<dawn_native::BackendType> FilterBackends(const dawn_native::BackendType* types,
|
||||
size_t numParams);
|
||||
std::string GetParamName(const testing::TestParamInfo<dawn_native::BackendType>& info);
|
||||
std::vector<DawnTestParam> FilterBackends(const DawnTestParam* params, size_t numParams);
|
||||
std::string GetParamName(const testing::TestParamInfo<DawnTestParam>& info);
|
||||
|
||||
// All classes used to implement the deferred expectations should inherit from this.
|
||||
class Expectation {
|
||||
|
||||
@@ -510,4 +510,9 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
|
||||
VerifyResolveTarget(kGreen, resolveTexture2, kBaseMipLevel2, kBaseArrayLayer2);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest, D3D12Backend, OpenGLBackend, MetalBackend, VulkanBackend);
|
||||
DAWN_INSTANTIATE_TEST(MultisampledRenderingTest,
|
||||
D3D12Backend,
|
||||
MetalBackend,
|
||||
OpenGLBackend,
|
||||
VulkanBackend,
|
||||
ForceWorkaround(MetalBackend, "emulate_store_and_msaa_resolve"));
|
||||
|
||||
@@ -34,7 +34,7 @@ class RingBufferTests : public testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// TODO(bryan.bernhart@intel.com): Create this device through the adapter.
|
||||
mDevice = std::make_unique<null::Device>(/*adapter*/ nullptr);
|
||||
mDevice = std::make_unique<null::Device>(/*adapter*/ nullptr, /*deviceDescriptor*/ nullptr);
|
||||
}
|
||||
|
||||
null::Device* GetDevice() const {
|
||||
|
||||
72
src/tests/unittests/validation/ToggleValidationTests.cpp
Normal file
72
src/tests/unittests/validation/ToggleValidationTests.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class ToggleValidationTest : public ValidationTest {
|
||||
};
|
||||
|
||||
// Tests querying the detail of a toggle from dawn_native::InstanceBase works correctly.
|
||||
TEST_F(ToggleValidationTest, QueryToggleInfo) {
|
||||
// Query with a valid toggle name
|
||||
{
|
||||
const char* kValidToggleName = "emulate_store_and_msaa_resolve";
|
||||
const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kValidToggleName);
|
||||
ASSERT_NE(nullptr, toggleInfo);
|
||||
ASSERT_NE(nullptr, toggleInfo->name);
|
||||
ASSERT_NE(nullptr, toggleInfo->description);
|
||||
ASSERT_NE(nullptr, toggleInfo->url);
|
||||
}
|
||||
|
||||
// Query with an invalid toggle name
|
||||
{
|
||||
const char* kInvalidToggleName = "!@#$%^&*";
|
||||
const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kInvalidToggleName);
|
||||
ASSERT_EQ(nullptr, toggleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests overriding toggles when creating a device works correctly.
|
||||
TEST_F(ToggleValidationTest, OverrideToggleUsage) {
|
||||
// Dawn unittests use null Adapters, so there should be no toggles that are enabled by default
|
||||
{
|
||||
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(device.Get());
|
||||
ASSERT_EQ(0u, toggleNames.size());
|
||||
}
|
||||
|
||||
// Create device with a valid name of a toggle
|
||||
{
|
||||
const char* kValidToggleName = "emulate_store_and_msaa_resolve";
|
||||
dawn_native::DeviceDescriptor descriptor;
|
||||
descriptor.forceEnabledToggles.push_back(kValidToggleName);
|
||||
|
||||
DawnDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
|
||||
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
|
||||
ASSERT_EQ(1u, toggleNames.size());
|
||||
ASSERT_EQ(0, strcmp(kValidToggleName, toggleNames[0]));
|
||||
}
|
||||
|
||||
// Create device with an invalid toggle name
|
||||
{
|
||||
dawn_native::DeviceDescriptor descriptor;
|
||||
descriptor.forceEnabledToggles.push_back("!@#$%^&*");
|
||||
|
||||
DawnDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
|
||||
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
|
||||
ASSERT_EQ(0u, toggleNames.size());
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
@@ -16,28 +16,26 @@
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "dawn/dawn.h"
|
||||
#include "dawn_native/DawnNative.h"
|
||||
#include "dawn_native/NullBackend.h"
|
||||
|
||||
ValidationTest::ValidationTest() {
|
||||
mInstance = std::make_unique<dawn_native::Instance>();
|
||||
mInstance->DiscoverDefaultAdapters();
|
||||
instance = std::make_unique<dawn_native::Instance>();
|
||||
instance->DiscoverDefaultAdapters();
|
||||
|
||||
std::vector<dawn_native::Adapter> adapters = mInstance->GetAdapters();
|
||||
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
||||
|
||||
// Validation tests run against the null backend, find the corresponding adapter
|
||||
bool foundNullAdapter = false;
|
||||
dawn_native::Adapter nullAdapter;
|
||||
for (auto adapter : adapters) {
|
||||
if (adapter.GetBackendType() == dawn_native::BackendType::Null) {
|
||||
nullAdapter = adapter;
|
||||
for (auto ¤tAdapter : adapters) {
|
||||
if (currentAdapter.GetBackendType() == dawn_native::BackendType::Null) {
|
||||
adapter = currentAdapter;
|
||||
foundNullAdapter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(foundNullAdapter);
|
||||
device = dawn::Device::Acquire(nullAdapter.CreateDevice());
|
||||
device = dawn::Device::Acquire(adapter.CreateDevice());
|
||||
|
||||
DawnProcTable procs = dawn_native::GetProcs();
|
||||
dawnSetProcs(&procs);
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "dawn/dawncpp.h"
|
||||
|
||||
namespace dawn_native {
|
||||
class Instance;
|
||||
}
|
||||
#include "dawn_native/DawnNative.h"
|
||||
|
||||
#define ASSERT_DEVICE_ERROR(statement) \
|
||||
StartExpectDeviceError(); \
|
||||
@@ -55,10 +52,10 @@ class ValidationTest : public testing::Test {
|
||||
|
||||
protected:
|
||||
dawn::Device device;
|
||||
dawn_native::Adapter adapter;
|
||||
std::unique_ptr<dawn_native::Instance> instance;
|
||||
|
||||
private:
|
||||
std::unique_ptr<dawn_native::Instance> mInstance;
|
||||
|
||||
static void OnDeviceError(const char* message, DawnCallbackUserdata userdata);
|
||||
std::string mDeviceErrorMessage;
|
||||
bool mExpectError = false;
|
||||
|
||||
Reference in New Issue
Block a user