From c7e113186465ec52bef8104ec4b5f1d9beff494a Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 6 Dec 2017 13:16:54 +0100 Subject: [PATCH] [d3d11] Implemented rasterizer state creation --- src/d3d11/d3d11_context.cpp | 27 +++++----- src/d3d11/d3d11_device.cpp | 22 +++++++- src/d3d11/d3d11_device.h | 3 ++ src/d3d11/d3d11_state.cpp | 101 +++++++++-------------------------- src/d3d11/d3d11_state.h | 71 +++++++++++++++--------- src/d3d11/d3d11_state_rs.cpp | 87 ++++++++++++++++++++++++++++++ src/d3d11/d3d11_state_rs.h | 45 ++++++++++++++++ src/d3d11/meson.build | 1 + src/util/com/com_pointer.h | 6 +++ 9 files changed, 247 insertions(+), 116 deletions(-) create mode 100644 src/d3d11/d3d11_state_rs.cpp create mode 100644 src/d3d11/d3d11_state_rs.h diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 0323e9d8..9140ed24 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -995,19 +995,22 @@ namespace dxvk { void D3D11DeviceContext::RSSetState(ID3D11RasterizerState* pRasterizerState) { auto rasterizerState = static_cast(pRasterizerState); - m_state.rs.state = rasterizerState; - // Use default state if the rasterizer - // state is not explicitly defined. - m_context->setRasterizerState( - rasterizerState != nullptr - ? rasterizerState->GetDXVKStateObject() - : m_defaultRsState); - - // In D3D11, the rasterizer state defines - // whether the scissor test is enabled, so - // we have to update the scissor rectangles. - this->ApplyViewportState(); + if (m_state.rs.state != rasterizerState) { + m_state.rs.state = rasterizerState; + + // Use default state if the rasterizer + // state is not explicitly defined. + m_context->setRasterizerState( + rasterizerState != nullptr + ? rasterizerState->GetDXVKStateObject() + : m_defaultRsState); + + // In D3D11, the rasterizer state defines + // whether the scissor test is enabled, so + // we have to update the scissor rectangles. + this->ApplyViewportState(); + } } diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index f7430ea4..5c1fe054 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -365,8 +365,26 @@ namespace dxvk { HRESULT D3D11Device::CreateRasterizerState( const D3D11_RASTERIZER_DESC* pRasterizerDesc, ID3D11RasterizerState** ppRasterizerState) { - Logger::err("D3D11Device::CreateRasterizerState: Not implemented"); - return E_NOTIMPL; + D3D11_RASTERIZER_DESC desc; + + if (pRasterizerDesc != nullptr) { + desc = *pRasterizerDesc; + } else { + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = D3D11_CULL_BACK; + desc.FrontCounterClockwise = FALSE; + desc.DepthBias = 0; + desc.SlopeScaledDepthBias = 0.0f; + desc.DepthBiasClamp = 0.0f; + desc.DepthClipEnable = TRUE; + desc.ScissorEnable = FALSE; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + } + + if (ppRasterizerState != nullptr) + *ppRasterizerState = m_rsStateObjects.Create(this, desc); + return S_OK; } diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 63ada07d..c179b31c 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -4,6 +4,7 @@ #include #include "d3d11_interfaces.h" +#include "d3d11_state.h" #include "../util/com/com_private_data.h" @@ -242,6 +243,8 @@ namespace dxvk { Com m_context; + D3D11StateObjectSet m_rsStateObjects; + }; } diff --git a/src/d3d11/d3d11_state.cpp b/src/d3d11/d3d11_state.cpp index 717cacc4..1925df79 100644 --- a/src/d3d11/d3d11_state.cpp +++ b/src/d3d11/d3d11_state.cpp @@ -1,87 +1,34 @@ -#include "d3d11_device.h" #include "d3d11_state.h" namespace dxvk { - D3D11RasterizerState::D3D11RasterizerState( - D3D11Device* device, - const D3D11_RASTERIZER_DESC& desc) - : m_device(device), m_desc(desc) { - - // Polygon mode. Determines whether the rasterizer fills - // a polygon or renders lines connecting the vertices. - VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL; - - switch (desc.FillMode) { - case D3D11_FILL_WIREFRAME: polygonMode = VK_POLYGON_MODE_LINE; break; - case D3D11_FILL_SOLID: polygonMode = VK_POLYGON_MODE_FILL; break; - - default: - Logger::err(str::format( - "D3D11RasterizerState: Unsupported fill mode: ", - desc.FillMode)); - } - - // Face culling properties. The rasterizer may discard - // polygons that are facing towards or away from the - // viewer, depending on the options below. - VkCullModeFlags cullMode = 0; - - switch (desc.CullMode) { - case D3D11_CULL_NONE: cullMode = 0; break; - case D3D11_CULL_FRONT: cullMode = VK_CULL_MODE_FRONT_BIT; break; - case D3D11_CULL_BACK: cullMode = VK_CULL_MODE_BACK_BIT; break; - - default: - Logger::err(str::format( - "D3D11RasterizerState: Unsupported cull mode: ", - desc.CullMode)); - } - - VkFrontFace frontFace = desc.FrontCounterClockwise - ? VK_FRONT_FACE_COUNTER_CLOCKWISE - : VK_FRONT_FACE_CLOCKWISE; - - // TODO implement depth bias - if (desc.DepthBias != 0) - Logger::err("D3D11RasterizerState: Depth bias not supported"); - - // TODO implement depth clipping - if (desc.DepthClipEnable) - Logger::err("D3D11RasterizerState: Depth clip not supported"); - - if (desc.AntialiasedLineEnable) - Logger::err("D3D11RasterizerState: Antialiased lines not supported"); - - m_state = new DxvkRasterizerState( - VK_FALSE, VK_FALSE, - polygonMode, cullMode, frontFace, - VK_FALSE, 0.0f, 0.0f, 0.0f, 1.0f); + size_t D3D11StateDescHash::operator () (const D3D11_RASTERIZER_DESC& desc) const { + DxvkHashState hash; + hash.add(desc.FillMode); + hash.add(desc.CullMode); + hash.add(desc.FrontCounterClockwise); + hash.add(desc.DepthBias); + hash.add(desc.SlopeScaledDepthBias); + hash.add(desc.DepthBiasClamp); + hash.add(desc.DepthClipEnable); + hash.add(desc.ScissorEnable); + hash.add(desc.MultisampleEnable); + hash.add(desc.AntialiasedLineEnable); + return hash; } - D3D11RasterizerState::~D3D11RasterizerState() { - - } - - - HRESULT D3D11RasterizerState::QueryInterface(REFIID riid, void** ppvObject) { - COM_QUERY_IFACE(riid, ppvObject, IUnknown); - COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); - COM_QUERY_IFACE(riid, ppvObject, ID3D11RasterizerState); - - Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query"); - return E_NOINTERFACE; - } - - - void D3D11RasterizerState::GetDevice(ID3D11Device** ppDevice) { - *ppDevice = m_device.ref(); - } - - - void D3D11RasterizerState::GetDesc(D3D11_RASTERIZER_DESC* pDesc) { - *pDesc = m_desc; + bool D3D11StateDescEqual::operator () (const D3D11_RASTERIZER_DESC& a, const D3D11_RASTERIZER_DESC& b) const { + return a.FillMode == b.FillMode + && a.CullMode == b.CullMode + && a.FrontCounterClockwise == b.FrontCounterClockwise + && a.DepthBias == b.DepthBias + && a.SlopeScaledDepthBias == b.SlopeScaledDepthBias + && a.DepthBiasClamp == b.DepthBiasClamp + && a.DepthClipEnable == b.DepthClipEnable + && a.ScissorEnable == b.ScissorEnable + && a.MultisampleEnable == b.MultisampleEnable + && a.AntialiasedLineEnable == b.AntialiasedLineEnable; } } \ No newline at end of file diff --git a/src/d3d11/d3d11_state.h b/src/d3d11/d3d11_state.h index d21cb8b5..e9f6a098 100644 --- a/src/d3d11/d3d11_state.h +++ b/src/d3d11/d3d11_state.h @@ -1,42 +1,63 @@ #pragma once -#include +#include -#include "d3d11_device_child.h" +#include "d3d11_state_rs.h" namespace dxvk { class D3D11Device; - class D3D11RasterizerState : public D3D11DeviceChild { - + struct D3D11StateDescHash { + size_t operator () (const D3D11_RASTERIZER_DESC& desc) const; + }; + + + struct D3D11StateDescEqual { + bool operator () (const D3D11_RASTERIZER_DESC& a, const D3D11_RASTERIZER_DESC& b) const; + }; + + + /** + * \brief Unique state object set + * + * When creating state objects, D3D11 first checks if + * an object with the same description already exists + * and returns it if that is the case. This class + * implements that behaviour. + */ + template + class D3D11StateObjectSet { + using DescType = typename T::DescType; public: - D3D11RasterizerState( - D3D11Device* device, - const D3D11_RASTERIZER_DESC& desc); - ~D3D11RasterizerState(); - - HRESULT QueryInterface( - REFIID riid, - void** ppvObject) final; - - void GetDevice( - ID3D11Device **ppDevice) final; - - void GetDesc( - D3D11_RASTERIZER_DESC* pDesc) final; - - Rc GetDXVKStateObject() { - return m_state; + /** + * \brief Retrieves a state object + * + * Returns an object with the same description or + * creates a new one if no such object exists. + * \param [in] device The calling D3D11 device + * \param [in] desc State object description + * \returns Pointer to the state object + */ + T* Create(D3D11Device* device, const DescType& desc) { + std::lock_guard lock(m_mutex); + + auto pair = m_objects.find(desc); + + if (pair != m_objects.end()) + return pair->second.ptr(); + + Com result = new T(device, desc); + m_objects.insert({ desc, result }); + return result.ptr(); } private: - Com m_device; - - D3D11_RASTERIZER_DESC m_desc; - Rc m_state; + std::mutex m_mutex; + std::unordered_map, + D3D11StateDescHash, D3D11StateDescEqual> m_objects; }; diff --git a/src/d3d11/d3d11_state_rs.cpp b/src/d3d11/d3d11_state_rs.cpp new file mode 100644 index 00000000..41acafbc --- /dev/null +++ b/src/d3d11/d3d11_state_rs.cpp @@ -0,0 +1,87 @@ +#include "d3d11_device.h" +#include "d3d11_state_rs.h" + +namespace dxvk { + + D3D11RasterizerState::D3D11RasterizerState( + D3D11Device* device, + const D3D11_RASTERIZER_DESC& desc) + : m_device(device), m_desc(desc) { + + // Polygon mode. Determines whether the rasterizer fills + // a polygon or renders lines connecting the vertices. + VkPolygonMode polygonMode = VK_POLYGON_MODE_FILL; + + switch (desc.FillMode) { + case D3D11_FILL_WIREFRAME: polygonMode = VK_POLYGON_MODE_LINE; break; + case D3D11_FILL_SOLID: polygonMode = VK_POLYGON_MODE_FILL; break; + + default: + Logger::err(str::format( + "D3D11RasterizerState: Unsupported fill mode: ", + desc.FillMode)); + } + + // Face culling properties. The rasterizer may discard + // polygons that are facing towards or away from the + // viewer, depending on the options below. + VkCullModeFlags cullMode = 0; + + switch (desc.CullMode) { + case D3D11_CULL_NONE: cullMode = 0; break; + case D3D11_CULL_FRONT: cullMode = VK_CULL_MODE_FRONT_BIT; break; + case D3D11_CULL_BACK: cullMode = VK_CULL_MODE_BACK_BIT; break; + + default: + Logger::err(str::format( + "D3D11RasterizerState: Unsupported cull mode: ", + desc.CullMode)); + } + + VkFrontFace frontFace = desc.FrontCounterClockwise + ? VK_FRONT_FACE_COUNTER_CLOCKWISE + : VK_FRONT_FACE_CLOCKWISE; + + // TODO implement depth bias + if (desc.DepthBias != 0) + Logger::err("D3D11RasterizerState: Depth bias not supported"); + + // TODO implement depth clamp + if (!desc.DepthClipEnable) + Logger::err("D3D11RasterizerState: Depth clip not supported"); + + if (desc.AntialiasedLineEnable) + Logger::err("D3D11RasterizerState: Antialiased lines not supported"); + + m_state = new DxvkRasterizerState( + VK_FALSE, VK_FALSE, + polygonMode, cullMode, frontFace, + VK_FALSE, 0.0f, 0.0f, 0.0f, 1.0f); + } + + + D3D11RasterizerState::~D3D11RasterizerState() { + + } + + + HRESULT D3D11RasterizerState::QueryInterface(REFIID riid, void** ppvObject) { + COM_QUERY_IFACE(riid, ppvObject, IUnknown); + COM_QUERY_IFACE(riid, ppvObject, ID3D11DeviceChild); + COM_QUERY_IFACE(riid, ppvObject, ID3D11RasterizerState); + + Logger::warn("D3D11RasterizerState::QueryInterface: Unknown interface query"); + return E_NOINTERFACE; + } + + + void D3D11RasterizerState::GetDevice(ID3D11Device** ppDevice) { + *ppDevice = m_device.ref(); + } + + + void D3D11RasterizerState::GetDesc(D3D11_RASTERIZER_DESC* pDesc) { + *pDesc = m_desc; + } + +} \ No newline at end of file diff --git a/src/d3d11/d3d11_state_rs.h b/src/d3d11/d3d11_state_rs.h new file mode 100644 index 00000000..a0a11804 --- /dev/null +++ b/src/d3d11/d3d11_state_rs.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#include "d3d11_device_child.h" + +namespace dxvk { + + class D3D11Device; + + class D3D11RasterizerState : public D3D11DeviceChild { + + public: + + using DescType = D3D11_RASTERIZER_DESC; + + D3D11RasterizerState( + D3D11Device* device, + const D3D11_RASTERIZER_DESC& desc); + ~D3D11RasterizerState(); + + HRESULT QueryInterface( + REFIID riid, + void** ppvObject) final; + + void GetDevice( + ID3D11Device **ppDevice) final; + + void GetDesc( + D3D11_RASTERIZER_DESC* pDesc) final; + + Rc GetDXVKStateObject() { + return m_state; + } + + private: + + Com m_device; + + D3D11_RASTERIZER_DESC m_desc; + Rc m_state; + + }; + +} diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 674f3f80..7b964405 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -6,6 +6,7 @@ d3d11_src = [ 'd3d11_main.cpp', 'd3d11_present.cpp', 'd3d11_state.cpp', + 'd3d11_state_rs.cpp', 'd3d11_texture.cpp', 'd3d11_view.cpp', ] diff --git a/src/util/com/com_pointer.h b/src/util/com/com_pointer.h index 2fb8242a..e6fe99bc 100644 --- a/src/util/com/com_pointer.h +++ b/src/util/com/com_pointer.h @@ -63,6 +63,12 @@ namespace dxvk { T** operator & () { return &m_ptr; } T* const* operator & () const { return &m_ptr; } + bool operator == (const Com& other) const { return m_ptr == other.m_ptr; } + bool operator != (const Com& other) const { return m_ptr != other.m_ptr; } + + bool operator == (const T* other) const { return m_ptr == other; } + bool operator != (const T* other) const { return m_ptr != other; } + bool operator == (std::nullptr_t) const { return m_ptr == nullptr; } bool operator != (std::nullptr_t) const { return m_ptr != nullptr; }