D3D: Make NativeVertexFormat thread safe

This commit is contained in:
Stenzek 2018-02-25 00:23:24 +10:00
parent 40845e6b8f
commit 1ddc4c5568
2 changed files with 23 additions and 9 deletions

View File

@ -13,6 +13,8 @@
namespace DX11 namespace DX11
{ {
std::mutex s_input_layout_lock;
std::unique_ptr<NativeVertexFormat> std::unique_ptr<NativeVertexFormat>
VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
{ {
@ -116,23 +118,34 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& _vtx_decl)
D3DVertexFormat::~D3DVertexFormat() D3DVertexFormat::~D3DVertexFormat()
{ {
SAFE_RELEASE(m_layout); ID3D11InputLayout* layout = m_layout.load();
SAFE_RELEASE(layout);
} }
ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode) ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
{ {
if (m_layout) // CreateInputLayout requires a shader input, but it only looks at the signature of the shader,
return m_layout; // so we don't need to recompute it if the shader changes.
ID3D11InputLayout* layout = m_layout.load();
if (layout)
return layout;
// CreateInputLayout requires a shader input, but it only looks at the
// signature of the shader, so we don't need to recompute it if the shader
// changes.
HRESULT hr = DX11::D3D::device->CreateInputLayout( HRESULT hr = DX11::D3D::device->CreateInputLayout(
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout); m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &layout);
if (FAILED(hr)) if (FAILED(hr))
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline"); DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline");
return m_layout;
// This method can be called from multiple threads, so ensure that only one thread sets the
// cached input layout pointer. If another thread beats this thread, use the existing layout.
ID3D11InputLayout* expected = nullptr;
if (!m_layout.compare_exchange_strong(expected, layout))
{
SAFE_RELEASE(layout);
layout = expected;
}
return layout;
} }
} // namespace DX11 } // namespace DX11

View File

@ -7,6 +7,7 @@
#include <d3d11.h> #include <d3d11.h>
#include <array> #include <array>
#include <atomic>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -29,7 +30,7 @@ private:
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{}; std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
UINT m_num_elems = 0; UINT m_num_elems = 0;
ID3D11InputLayout* m_layout = nullptr; std::atomic<ID3D11InputLayout*> m_layout{nullptr};
}; };
class VertexManager : public VertexManagerBase class VertexManager : public VertexManagerBase