From ac2d16599c3893732ac32c907d5df500ae5f036a Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 2 Dec 2017 16:47:06 +0100 Subject: [PATCH] [d3d11] Implemented proper feature tests --- src/d3d11/d3d11_device.cpp | 68 +++++++++++++++++++++++++++- src/d3d11/d3d11_device.h | 5 +++ src/d3d11/d3d11_main.cpp | 12 ++++- src/dxgi/dxgi_device.cpp | 13 +++--- src/dxgi/dxgi_device.h | 9 ++-- src/dxgi/dxgi_swapchain.cpp | 13 ++++-- src/dxvk/dxvk_adapter.cpp | 74 ++++++++++++++++++++++++++----- src/dxvk/dxvk_adapter.h | 15 +++++-- src/dxvk/dxvk_device.cpp | 7 +-- src/dxvk/dxvk_device.h | 19 ++++++-- tests/dxvk/test_dxvk_triangle.cpp | 9 +++- 11 files changed, 208 insertions(+), 36 deletions(-) diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index 7bd3322b..9a3fd063 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -516,8 +516,74 @@ namespace dxvk { bool D3D11Device::CheckFeatureLevelSupport( + const Rc& adapter, D3D_FEATURE_LEVEL featureLevel) { - return featureLevel <= D3D_FEATURE_LEVEL_11_0; + // We currently only support 11_0 interfaces + if (featureLevel > D3D_FEATURE_LEVEL_11_0) + return false; + + // Check whether all features are supported + const VkPhysicalDeviceFeatures features + = GetDeviceFeatures(adapter, featureLevel); + + if (!adapter->checkFeatureSupport(features)) + return false; + + // TODO also check for required limits + return true; + } + + + VkPhysicalDeviceFeatures D3D11Device::GetDeviceFeatures( + const Rc& adapter, + D3D_FEATURE_LEVEL featureLevel) { + VkPhysicalDeviceFeatures supported = adapter->features(); + VkPhysicalDeviceFeatures enabled; + std::memset(&enabled, 0, sizeof(enabled)); + + if (featureLevel >= D3D_FEATURE_LEVEL_9_1) { + enabled.alphaToOne = VK_TRUE; + enabled.depthClamp = VK_TRUE; + enabled.depthBiasClamp = VK_TRUE; + enabled.depthBounds = VK_TRUE; + enabled.fillModeNonSolid = VK_TRUE; + enabled.pipelineStatisticsQuery = supported.pipelineStatisticsQuery; + enabled.samplerAnisotropy = VK_TRUE; + enabled.shaderClipDistance = VK_TRUE; + enabled.shaderCullDistance = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_9_2) { + enabled.occlusionQueryPrecise = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_9_3) { + enabled.multiViewport = VK_TRUE; + enabled.independentBlend = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_10_0) { + enabled.fullDrawIndexUint32 = VK_TRUE; + enabled.fragmentStoresAndAtomics = VK_TRUE; + enabled.geometryShader = VK_TRUE; + enabled.logicOp = supported.logicOp; + enabled.shaderImageGatherExtended = VK_TRUE; + enabled.textureCompressionBC = VK_TRUE; + enabled.vertexPipelineStoresAndAtomics = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_10_1) { + enabled.imageCubeArray = VK_TRUE; + } + + if (featureLevel >= D3D_FEATURE_LEVEL_11_0) { + enabled.shaderFloat64 = supported.shaderFloat64; + enabled.shaderInt64 = supported.shaderInt64; + enabled.tessellationShader = VK_TRUE; + enabled.variableMultisampleRate = VK_TRUE; + } + + return enabled; } } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 35320ad2..9062111b 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -221,6 +221,11 @@ namespace dxvk { } static bool CheckFeatureLevelSupport( + const Rc& adapter, + D3D_FEATURE_LEVEL featureLevel); + + static VkPhysicalDeviceFeatures GetDeviceFeatures( + const Rc& adapter, D3D_FEATURE_LEVEL featureLevel); private: diff --git a/src/d3d11/d3d11_main.cpp b/src/d3d11/d3d11_main.cpp index db10640b..92c1d169 100644 --- a/src/d3d11/d3d11_main.cpp +++ b/src/d3d11/d3d11_main.cpp @@ -4,6 +4,7 @@ #include #include "d3d11_device.h" +#include "d3d11_enums.h" extern "C" { using namespace dxvk; @@ -76,9 +77,11 @@ extern "C" { // Find the highest feature level supported by the device. // This works because the feature level array is ordered. + const Rc adapter = dxvkAdapter->GetDXVKAdapter(); + UINT flId; for (flId = 0 ; flId < FeatureLevels; flId++) { - if (D3D11Device::CheckFeatureLevelSupport(pFeatureLevels[flId])) + if (D3D11Device::CheckFeatureLevelSupport(adapter, pFeatureLevels[flId])) break; } @@ -92,6 +95,8 @@ extern "C" { try { + Logger::info(str::format("D3D11CreateDevice: Using feature level ", fl)); + // Write back the actual feature level // if the application requested it. if (pFeatureLevel != nullptr) @@ -105,7 +110,10 @@ extern "C" { if (ppDevice != nullptr) { Com dxvkDevice = nullptr; - if (FAILED(DXGICreateDevicePrivate(dxvkAdapter.ptr(), &dxvkDevice))) { + const VkPhysicalDeviceFeatures deviceFeatures + = D3D11Device::GetDeviceFeatures(adapter, fl); + + if (FAILED(DXGICreateDevicePrivate(dxvkAdapter.ptr(), &deviceFeatures, &dxvkDevice))) { Logger::err("D3D11CreateDevice: Failed to create DXGI device"); return E_FAIL; } diff --git a/src/dxgi/dxgi_device.cpp b/src/dxgi/dxgi_device.cpp index c115c100..de4a387a 100644 --- a/src/dxgi/dxgi_device.cpp +++ b/src/dxgi/dxgi_device.cpp @@ -3,9 +3,11 @@ namespace dxvk { - DxgiDevice::DxgiDevice(IDXGIAdapterPrivate* adapter) + DxgiDevice::DxgiDevice( + IDXGIAdapterPrivate* adapter, + const VkPhysicalDeviceFeatures* features) : m_adapter(adapter) { - m_device = m_adapter->GetDXVKAdapter()->createDevice(); + m_device = m_adapter->GetDXVKAdapter()->createDevice(*features); } @@ -92,10 +94,11 @@ namespace dxvk { extern "C" { DLLEXPORT HRESULT __stdcall DXGICreateDevicePrivate( - IDXGIAdapterPrivate* pAdapter, - IDXGIDevicePrivate** ppDevice) { + IDXGIAdapterPrivate* pAdapter, + const VkPhysicalDeviceFeatures* features, + IDXGIDevicePrivate** ppDevice) { try { - *ppDevice = dxvk::ref(new dxvk::DxgiDevice(pAdapter)); + *ppDevice = dxvk::ref(new dxvk::DxgiDevice(pAdapter, features)); return S_OK; } catch (const dxvk::DxvkError& e) { dxvk::Logger::err(e.message()); diff --git a/src/dxgi/dxgi_device.h b/src/dxgi/dxgi_device.h index 657265b7..6911a34e 100644 --- a/src/dxgi/dxgi_device.h +++ b/src/dxgi/dxgi_device.h @@ -13,7 +13,9 @@ namespace dxvk { public: - DxgiDevice(IDXGIAdapterPrivate* adapter); + DxgiDevice( + IDXGIAdapterPrivate* adapter, + const VkPhysicalDeviceFeatures* features); ~DxgiDevice(); HRESULT QueryInterface( @@ -65,7 +67,8 @@ namespace dxvk { extern "C" { DLLEXPORT HRESULT __stdcall DXGICreateDevicePrivate( - IDXGIAdapterPrivate* pAdapter, - IDXGIDevicePrivate** ppDevice); + IDXGIAdapterPrivate* pAdapter, + const VkPhysicalDeviceFeatures* features, + IDXGIDevicePrivate** ppDevice); } \ No newline at end of file diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index 821cfe33..43c16d44 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -319,7 +319,7 @@ namespace dxvk { DxvkImageCreateInfo imageInfo; imageInfo.type = VK_IMAGE_TYPE_2D; - imageInfo.format = VK_FORMAT_R8G8B8A8_SNORM; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT; imageInfo.extent.width = m_desc.BufferDesc.Width; imageInfo.extent.height = m_desc.BufferDesc.Height; @@ -331,9 +331,6 @@ namespace dxvk { | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageInfo.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT -// | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT -// | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT -// | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT @@ -345,6 +342,14 @@ namespace dxvk { | VK_ACCESS_SHADER_READ_BIT; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + if (dxvkDevice->features().geometryShader) + imageInfo.stages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; + + if (dxvkDevice->features().tessellationShader) { + imageInfo.stages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT + | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; + } + if (FAILED(DXGICreateImageResourcePrivate(dxgiDevice.ptr(), &imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, DXGI_USAGE_BACK_BUFFER | m_desc.BufferUsage, &resource))) diff --git a/src/dxvk/dxvk_adapter.cpp b/src/dxvk/dxvk_adapter.cpp index 9d65bf38..aa98f7b2 100644 --- a/src/dxvk/dxvk_adapter.cpp +++ b/src/dxvk/dxvk_adapter.cpp @@ -93,9 +93,70 @@ namespace dxvk { } - Rc DxvkAdapter::createDevice() { + bool DxvkAdapter::checkFeatureSupport( + const VkPhysicalDeviceFeatures& required) const { + const VkPhysicalDeviceFeatures supported = this->features(); + + return (supported.robustBufferAccess || !required.robustBufferAccess) + && (supported.fullDrawIndexUint32 || !required.fullDrawIndexUint32) + && (supported.imageCubeArray || !required.imageCubeArray) + && (supported.independentBlend || !required.independentBlend) + && (supported.geometryShader || !required.geometryShader) + && (supported.tessellationShader || !required.tessellationShader) + && (supported.sampleRateShading || !required.sampleRateShading) + && (supported.dualSrcBlend || !required.dualSrcBlend) + && (supported.logicOp || !required.logicOp) + && (supported.multiDrawIndirect || !required.multiDrawIndirect) + && (supported.drawIndirectFirstInstance || !required.drawIndirectFirstInstance) + && (supported.depthClamp || !required.depthClamp) + && (supported.depthBiasClamp || !required.depthBiasClamp) + && (supported.fillModeNonSolid || !required.fillModeNonSolid) + && (supported.depthBounds || !required.depthBounds) + && (supported.wideLines || !required.wideLines) + && (supported.largePoints || !required.largePoints) + && (supported.alphaToOne || !required.alphaToOne) + && (supported.multiViewport || !required.multiViewport) + && (supported.samplerAnisotropy || !required.samplerAnisotropy) + && (supported.textureCompressionETC2 || !required.textureCompressionETC2) + && (supported.textureCompressionASTC_LDR || !required.textureCompressionASTC_LDR) + && (supported.textureCompressionBC || !required.textureCompressionBC) + && (supported.occlusionQueryPrecise || !required.occlusionQueryPrecise) + && (supported.pipelineStatisticsQuery || !required.pipelineStatisticsQuery) + && (supported.vertexPipelineStoresAndAtomics || !required.vertexPipelineStoresAndAtomics) + && (supported.fragmentStoresAndAtomics || !required.fragmentStoresAndAtomics) + && (supported.shaderTessellationAndGeometryPointSize || !required.shaderTessellationAndGeometryPointSize) + && (supported.shaderImageGatherExtended || !required.shaderImageGatherExtended) + && (supported.shaderStorageImageExtendedFormats || !required.shaderStorageImageExtendedFormats) + && (supported.shaderStorageImageMultisample || !required.shaderStorageImageMultisample) + && (supported.shaderStorageImageReadWithoutFormat || !required.shaderStorageImageReadWithoutFormat) + && (supported.shaderStorageImageWriteWithoutFormat || !required.shaderStorageImageWriteWithoutFormat) + && (supported.shaderUniformBufferArrayDynamicIndexing || !required.shaderUniformBufferArrayDynamicIndexing) + && (supported.shaderSampledImageArrayDynamicIndexing || !required.shaderSampledImageArrayDynamicIndexing) + && (supported.shaderStorageBufferArrayDynamicIndexing || !required.shaderStorageBufferArrayDynamicIndexing) + && (supported.shaderStorageImageArrayDynamicIndexing || !required.shaderStorageImageArrayDynamicIndexing) + && (supported.shaderClipDistance || !required.shaderClipDistance) + && (supported.shaderCullDistance || !required.shaderCullDistance) + && (supported.shaderFloat64 || !required.shaderFloat64) + && (supported.shaderInt64 || !required.shaderInt64) + && (supported.shaderInt16 || !required.shaderInt16) + && (supported.shaderResourceResidency || !required.shaderResourceResidency) + && (supported.shaderResourceMinLod || !required.shaderResourceMinLod) + && (supported.sparseBinding || !required.sparseBinding) + && (supported.sparseResidencyBuffer || !required.sparseResidencyBuffer) + && (supported.sparseResidencyImage2D || !required.sparseResidencyImage2D) + && (supported.sparseResidencyImage3D || !required.sparseResidencyImage3D) + && (supported.sparseResidency2Samples || !required.sparseResidency2Samples) + && (supported.sparseResidency4Samples || !required.sparseResidency4Samples) + && (supported.sparseResidency8Samples || !required.sparseResidency8Samples) + && (supported.sparseResidency16Samples || !required.sparseResidency16Samples) + && (supported.sparseResidencyAliased || !required.sparseResidencyAliased) + && (supported.variableMultisampleRate || !required.variableMultisampleRate) + && (supported.inheritedQueries || !required.inheritedQueries); + } + + + Rc DxvkAdapter::createDevice(const VkPhysicalDeviceFeatures& enabledFeatures) { auto enabledExtensions = this->enableExtensions(); - auto enabledFeatures = this->enableFeatures(); float queuePriority = 1.0f; std::vector queueInfos; @@ -134,7 +195,7 @@ namespace dxvk { if (m_vki->vkCreateDevice(m_handle, &info, nullptr, &device) != VK_SUCCESS) throw DxvkError("DxvkDevice::createDevice: Failed to create device"); - return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device)); + return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device), enabledFeatures); } @@ -167,11 +228,4 @@ namespace dxvk { return extensionsEnabled; } - - VkPhysicalDeviceFeatures DxvkAdapter::enableFeatures() { - VkPhysicalDeviceFeatures features; - std::memset(&features, 0, sizeof(features)); - return features; - } - } \ No newline at end of file diff --git a/src/dxvk/dxvk_adapter.h b/src/dxvk/dxvk_adapter.h index b7afb0e5..acd2fc8e 100644 --- a/src/dxvk/dxvk_adapter.h +++ b/src/dxvk/dxvk_adapter.h @@ -107,13 +107,24 @@ namespace dxvk { */ uint32_t presentQueueFamily() const; + /** + * \brief Tests whether all required features are supported + * + * \param [in] features Required device features + * \returns \c true if all features are supported + */ + bool checkFeatureSupport( + const VkPhysicalDeviceFeatures& required) const; + /** * \brief Creates a DXVK device * * Creates a logical device for this adapter. + * \param [in] enabledFeatures Device features * \returns Device handle */ - Rc createDevice(); + Rc createDevice( + const VkPhysicalDeviceFeatures& enabledFeatures); /** * \brief Creates a surface @@ -136,8 +147,6 @@ namespace dxvk { vk::NameList enableExtensions(); - VkPhysicalDeviceFeatures enableFeatures(); - }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 604cb1ea..8ed28634 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -4,10 +4,12 @@ namespace dxvk { DxvkDevice::DxvkDevice( - const Rc& adapter, - const Rc& vkd) + const Rc& adapter, + const Rc& vkd, + const VkPhysicalDeviceFeatures& features) : m_adapter (adapter), m_vkd (vkd), + m_features (features), m_memory (new DxvkMemoryAllocator(adapter, vkd)), m_renderPassPool (new DxvkRenderPassPool (vkd)), m_pipelineManager (new DxvkPipelineManager(vkd)) { @@ -67,7 +69,6 @@ namespace dxvk { Rc DxvkDevice::createImage( const DxvkImageCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { - // TODO record image initialization commands return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 3b531ac3..aafe4562 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -31,8 +31,10 @@ namespace dxvk { public: DxvkDevice( - const Rc& adapter, - const Rc& vkd); + const Rc& adapter, + const Rc& vkd, + const VkPhysicalDeviceFeatures& features); + ~DxvkDevice(); /** @@ -62,6 +64,14 @@ namespace dxvk { return m_adapter; } + /** + * \brief Enabled device features + * \returns Enabled features + */ + const VkPhysicalDeviceFeatures& features() const { + return m_features; + } + /** * \brief Creates a command list * \returns The command list @@ -186,8 +196,9 @@ namespace dxvk { private: - Rc m_adapter; - Rc m_vkd; + Rc m_adapter; + Rc m_vkd; + VkPhysicalDeviceFeatures m_features; Rc m_memory; Rc m_renderPassPool; diff --git a/tests/dxvk/test_dxvk_triangle.cpp b/tests/dxvk/test_dxvk_triangle.cpp index 235dfa15..0d761398 100644 --- a/tests/dxvk/test_dxvk_triangle.cpp +++ b/tests/dxvk/test_dxvk_triangle.cpp @@ -68,7 +68,7 @@ public: TriangleApp(HINSTANCE instance, HWND window) : m_dxvkInstance (new DxvkInstance()), m_dxvkAdapter (m_dxvkInstance->enumAdapters().at(0)), - m_dxvkDevice (m_dxvkAdapter->createDevice()), + m_dxvkDevice (m_dxvkAdapter->createDevice(getDeviceFeatures())), m_dxvkSurface (m_dxvkAdapter->createSurface(instance, window)), m_dxvkSwapchain (m_dxvkDevice->createSwapchain(m_dxvkSurface, DxvkSwapchainProperties { @@ -178,6 +178,13 @@ public: m_dxvkDevice->waitForIdle(); } + + VkPhysicalDeviceFeatures getDeviceFeatures() const { + VkPhysicalDeviceFeatures features; + std::memset(&features, 0, sizeof(features)); + return features; + } + private: Rc m_dxvkInstance;