mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #6042 from stenzek/videocommon-pipelines
VideoCommon pipelines ("Abstract Pipeline")
This commit is contained in:
@@ -10,8 +10,6 @@
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
std::unique_ptr<cInterfaceBase> GLInterface;
|
||||
static GLuint attributelessVAO = 0;
|
||||
static GLuint attributelessVBO = 0;
|
||||
|
||||
void InitInterface()
|
||||
{
|
||||
@@ -29,7 +27,7 @@ GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string&
|
||||
const char* shader = vertexShader.c_str();
|
||||
glShaderSource(vertexShaderID, 1, &shader, nullptr);
|
||||
glCompileShader(vertexShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
GLint Result = GL_FALSE;
|
||||
char stringBuffer[1024];
|
||||
GLsizei stringBufferUsage = 0;
|
||||
@@ -56,7 +54,7 @@ GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string&
|
||||
shader = fragmentShader.c_str();
|
||||
glShaderSource(fragmentShaderID, 1, &shader, nullptr);
|
||||
glCompileShader(fragmentShaderID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &Result);
|
||||
glGetShaderInfoLog(fragmentShaderID, 1024, &stringBufferUsage, stringBuffer);
|
||||
|
||||
@@ -80,7 +78,7 @@ GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string&
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(DEBUG_GLSL)
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &Result);
|
||||
glGetProgramInfoLog(programID, 1024, &stringBufferUsage, stringBuffer);
|
||||
|
||||
@@ -102,45 +100,3 @@ GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string&
|
||||
|
||||
return programID;
|
||||
}
|
||||
|
||||
void OpenGL_CreateAttributelessVAO()
|
||||
{
|
||||
glGenVertexArrays(1, &attributelessVAO);
|
||||
_dbg_assert_msg_(VIDEO, attributelessVAO != 0,
|
||||
"Attributeless VAO should have been created successfully.")
|
||||
|
||||
// In a compatibility context, we require a valid, bound array buffer.
|
||||
glGenBuffers(1, &attributelessVBO);
|
||||
_dbg_assert_msg_(VIDEO, attributelessVBO != 0,
|
||||
"Attributeless VBO should have been created successfully.")
|
||||
|
||||
// Initialize the buffer with nothing. 16 floats is an arbitrary size that may work around
|
||||
// driver issues.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, nullptr, GL_STATIC_DRAW);
|
||||
|
||||
// We must also define vertex attribute 0.
|
||||
glBindVertexArray(attributelessVAO);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
|
||||
glEnableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
void OpenGL_BindAttributelessVAO()
|
||||
{
|
||||
_dbg_assert_msg_(VIDEO, attributelessVAO != 0,
|
||||
"Attributeless VAO should have already been created.")
|
||||
glBindVertexArray(attributelessVAO);
|
||||
}
|
||||
|
||||
void OpenGL_DeleteAttributelessVAO()
|
||||
{
|
||||
_dbg_assert_msg_(VIDEO, attributelessVAO != 0,
|
||||
"Attributeless VAO should have already been created.") if (attributelessVAO != 0)
|
||||
{
|
||||
glDeleteVertexArrays(1, &attributelessVAO);
|
||||
glDeleteBuffers(1, &attributelessVBO);
|
||||
|
||||
attributelessVAO = 0;
|
||||
attributelessVBO = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,3 @@ void InitInterface();
|
||||
|
||||
// Helpers
|
||||
GLuint OpenGL_CompileProgram(const std::string& vertexShader, const std::string& fragmentShader);
|
||||
|
||||
// Creates and deletes a VAO and VBO suitable for attributeless rendering.
|
||||
// Called by the Renderer.
|
||||
void OpenGL_CreateAttributelessVAO();
|
||||
void OpenGL_DeleteAttributelessVAO();
|
||||
|
||||
// Binds the VAO suitable for attributeless rendering.
|
||||
void OpenGL_BindAttributelessVAO();
|
||||
|
||||
// this should be removed in future, but as long as glsl is unstable, we should really read this
|
||||
// messages
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
#define DEBUG_GLSL 1
|
||||
#else
|
||||
#define DEBUG_GLSL 0
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,10 @@ set(SRCS
|
||||
D3DTexture.h
|
||||
D3DUtil.cpp
|
||||
D3DUtil.h
|
||||
DXPipeline.cpp
|
||||
DXPipeline.h
|
||||
DXShader.cpp
|
||||
DXShader.h
|
||||
DXTexture.cpp
|
||||
DXTexture.h
|
||||
FramebufferManager.cpp
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
<ClCompile Include="D3DState.cpp" />
|
||||
<ClCompile Include="D3DTexture.cpp" />
|
||||
<ClCompile Include="D3DUtil.cpp" />
|
||||
<ClCompile Include="DXPipeline.cpp" />
|
||||
<ClCompile Include="DXShader.cpp" />
|
||||
<ClCompile Include="DXTexture.cpp" />
|
||||
<ClCompile Include="FramebufferManager.cpp" />
|
||||
<ClCompile Include="GeometryShaderCache.cpp" />
|
||||
@@ -64,6 +66,8 @@
|
||||
<ClInclude Include="D3DState.h" />
|
||||
<ClInclude Include="D3DTexture.h" />
|
||||
<ClInclude Include="D3DUtil.h" />
|
||||
<ClInclude Include="DXPipeline.h" />
|
||||
<ClInclude Include="DXShader.h" />
|
||||
<ClInclude Include="DXTexture.h" />
|
||||
<ClInclude Include="FramebufferManager.h" />
|
||||
<ClInclude Include="GeometryShaderCache.h" />
|
||||
|
||||
@@ -64,6 +64,12 @@
|
||||
<ClCompile Include="DXTexture.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DXShader.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DXPipeline.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="D3DBase.h">
|
||||
@@ -118,5 +124,11 @@
|
||||
<ClInclude Include="DXTexture.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DXShader.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DXPipeline.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -511,6 +511,16 @@ const char* PixelShaderVersionString()
|
||||
return "ps_4_0";
|
||||
}
|
||||
|
||||
const char* ComputeShaderVersionString()
|
||||
{
|
||||
if (s_featlevel == D3D_FEATURE_LEVEL_11_0)
|
||||
return "cs_5_0";
|
||||
else if (s_featlevel == D3D_FEATURE_LEVEL_10_1)
|
||||
return "cs_4_1";
|
||||
else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/
|
||||
return "cs_4_0";
|
||||
}
|
||||
|
||||
D3DTexture2D* GetBackBuffer()
|
||||
{
|
||||
return s_backbuf;
|
||||
|
||||
@@ -69,6 +69,7 @@ D3DTexture2D* GetBackBuffer();
|
||||
const char* PixelShaderVersionString();
|
||||
const char* GeometryShaderVersionString();
|
||||
const char* VertexShaderVersionString();
|
||||
const char* ComputeShaderVersionString();
|
||||
bool BGRATexturesSupported();
|
||||
bool AllowTearingSupported();
|
||||
|
||||
|
||||
@@ -188,6 +188,66 @@ bool CompilePixelShader(const std::string& code, D3DBlob** blob, const D3D_SHADE
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
// bytecode->shader
|
||||
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len)
|
||||
{
|
||||
ID3D11ComputeShader* shader;
|
||||
HRESULT hr = D3D::device->CreateComputeShader(bytecode, len, nullptr, &shader);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("CreateComputeShaderFromByteCode failed at %s %d\n", __FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
// code->bytecode
|
||||
bool CompileComputeShader(const std::string& code, D3DBlob** blob, const D3D_SHADER_MACRO* pDefines)
|
||||
{
|
||||
ID3D10Blob* shaderBuffer = nullptr;
|
||||
ID3D10Blob* errorBuffer = nullptr;
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
UINT flags = D3D10_SHADER_DEBUG;
|
||||
#else
|
||||
UINT flags = D3D10_SHADER_OPTIMIZATION_LEVEL3;
|
||||
#endif
|
||||
HRESULT hr =
|
||||
PD3DCompile(code.c_str(), code.length(), nullptr, pDefines, nullptr, "main",
|
||||
D3D::ComputeShaderVersionString(), flags, 0, &shaderBuffer, &errorBuffer);
|
||||
|
||||
if (errorBuffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Compute shader compiler messages:\n%s",
|
||||
(const char*)errorBuffer->GetBufferPointer());
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_cs_%04i.txt",
|
||||
File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
File::OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile compute shader: %s\nDebug info (%s):\n%s", filename.c_str(),
|
||||
D3D::ComputeShaderVersionString(),
|
||||
reinterpret_cast<const char*>(errorBuffer->GetBufferPointer()));
|
||||
|
||||
*blob = nullptr;
|
||||
errorBuffer->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
*blob = new D3DBlob(shaderBuffer);
|
||||
shaderBuffer->Release();
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
@@ -226,6 +286,19 @@ ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code)
|
||||
{
|
||||
D3DBlob* blob = nullptr;
|
||||
CompileComputeShader(code, &blob);
|
||||
if (blob)
|
||||
{
|
||||
ID3D11ComputeShader* shader = CreateComputeShaderFromByteCode(blob);
|
||||
blob->Release();
|
||||
return shader;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace D3D
|
||||
ID3D11VertexShader* CreateVertexShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11GeometryShader* CreateGeometryShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11PixelShader* CreatePixelShaderFromByteCode(const void* bytecode, size_t len);
|
||||
ID3D11ComputeShader* CreateComputeShaderFromByteCode(const void* bytecode, size_t len);
|
||||
|
||||
// The returned bytecode buffers should be Release()d.
|
||||
bool CompileVertexShader(const std::string& code, D3DBlob** blob);
|
||||
@@ -26,12 +27,15 @@ bool CompileGeometryShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
bool CompilePixelShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
bool CompileComputeShader(const std::string& code, D3DBlob** blob,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
|
||||
// Utility functions
|
||||
ID3D11VertexShader* CompileAndCreateVertexShader(const std::string& code);
|
||||
ID3D11GeometryShader* CompileAndCreateGeometryShader(const std::string& code,
|
||||
const D3D_SHADER_MACRO* pDefines = nullptr);
|
||||
ID3D11PixelShader* CompileAndCreatePixelShader(const std::string& code);
|
||||
ID3D11ComputeShader* CompileAndCreateComputeShader(const std::string& code);
|
||||
|
||||
inline ID3D11VertexShader* CreateVertexShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
@@ -45,21 +49,29 @@ inline ID3D11PixelShader* CreatePixelShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreatePixelShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
inline ID3D11ComputeShader* CreateComputeShaderFromByteCode(D3DBlob* bytecode)
|
||||
{
|
||||
return CreateComputeShaderFromByteCode(bytecode->Data(), bytecode->Size());
|
||||
}
|
||||
|
||||
inline ID3D11VertexShader* CompileAndCreateVertexShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreateVertexShader((const char*)code->Data());
|
||||
return CompileAndCreateVertexShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
|
||||
inline ID3D11GeometryShader*
|
||||
CompileAndCreateGeometryShader(D3DBlob* code, const D3D_SHADER_MACRO* pDefines = nullptr)
|
||||
{
|
||||
return CompileAndCreateGeometryShader((const char*)code->Data(), pDefines);
|
||||
return CompileAndCreateGeometryShader(reinterpret_cast<const char*>(code->Data()), pDefines);
|
||||
}
|
||||
|
||||
inline ID3D11PixelShader* CompileAndCreatePixelShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreatePixelShader((const char*)code->Data());
|
||||
return CompileAndCreatePixelShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
inline ID3D11ComputeShader* CompileAndCreateComputeShader(D3DBlob* code)
|
||||
{
|
||||
return CompileAndCreateComputeShader(reinterpret_cast<const char*>(code->Data()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,97 +20,13 @@ namespace D3D
|
||||
{
|
||||
StateManager* stateman;
|
||||
|
||||
template <typename T>
|
||||
AutoState<T>::AutoState(const T* object) : state(object)
|
||||
{
|
||||
((IUnknown*)state)->AddRef();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AutoState<T>::AutoState(const AutoState<T>& source)
|
||||
{
|
||||
state = source.GetPtr();
|
||||
((T*)state)->AddRef();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AutoState<T>::~AutoState()
|
||||
{
|
||||
if (state)
|
||||
((T*)state)->Release();
|
||||
state = nullptr;
|
||||
}
|
||||
|
||||
StateManager::StateManager()
|
||||
: m_currentBlendState(nullptr), m_currentDepthState(nullptr), m_currentRasterizerState(nullptr),
|
||||
m_dirtyFlags(~0u), m_pending(), m_current()
|
||||
{
|
||||
}
|
||||
|
||||
void StateManager::PushBlendState(const ID3D11BlendState* state)
|
||||
{
|
||||
m_blendStates.push(AutoBlendState(state));
|
||||
}
|
||||
void StateManager::PushDepthState(const ID3D11DepthStencilState* state)
|
||||
{
|
||||
m_depthStates.push(AutoDepthStencilState(state));
|
||||
}
|
||||
void StateManager::PushRasterizerState(const ID3D11RasterizerState* state)
|
||||
{
|
||||
m_rasterizerStates.push(AutoRasterizerState(state));
|
||||
}
|
||||
void StateManager::PopBlendState()
|
||||
{
|
||||
m_blendStates.pop();
|
||||
}
|
||||
void StateManager::PopDepthState()
|
||||
{
|
||||
m_depthStates.pop();
|
||||
}
|
||||
void StateManager::PopRasterizerState()
|
||||
{
|
||||
m_rasterizerStates.pop();
|
||||
}
|
||||
StateManager::StateManager() = default;
|
||||
StateManager::~StateManager() = default;
|
||||
|
||||
void StateManager::Apply()
|
||||
{
|
||||
if (!m_blendStates.empty())
|
||||
{
|
||||
if (m_currentBlendState != m_blendStates.top().GetPtr())
|
||||
{
|
||||
m_currentBlendState = (ID3D11BlendState*)m_blendStates.top().GetPtr();
|
||||
D3D::context->OMSetBlendState(m_currentBlendState, nullptr, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Tried to apply without blend state!");
|
||||
|
||||
if (!m_depthStates.empty())
|
||||
{
|
||||
if (m_currentDepthState != m_depthStates.top().GetPtr())
|
||||
{
|
||||
m_currentDepthState = (ID3D11DepthStencilState*)m_depthStates.top().GetPtr();
|
||||
D3D::context->OMSetDepthStencilState(m_currentDepthState, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Tried to apply without depth state!");
|
||||
|
||||
if (!m_rasterizerStates.empty())
|
||||
{
|
||||
if (m_currentRasterizerState != m_rasterizerStates.top().GetPtr())
|
||||
{
|
||||
m_currentRasterizerState = (ID3D11RasterizerState*)m_rasterizerStates.top().GetPtr();
|
||||
D3D::context->RSSetState(m_currentRasterizerState);
|
||||
}
|
||||
}
|
||||
else
|
||||
ERROR_LOG(VIDEO, "Tried to apply without rasterizer state!");
|
||||
|
||||
if (!m_dirtyFlags)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int textureMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Texture0);
|
||||
int samplerMaskShift = LeastSignificantSetBit((u32)DirtyFlag_Sampler0);
|
||||
@@ -232,6 +148,22 @@ void StateManager::Apply()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dirtyFlags & DirtyFlag_BlendState)
|
||||
{
|
||||
D3D::context->OMSetBlendState(m_pending.blendState, nullptr, 0xFFFFFFFF);
|
||||
m_current.blendState = m_pending.blendState;
|
||||
}
|
||||
if (m_dirtyFlags & DirtyFlag_DepthState)
|
||||
{
|
||||
D3D::context->OMSetDepthStencilState(m_pending.depthState, 0);
|
||||
m_current.depthState = m_pending.depthState;
|
||||
}
|
||||
if (m_dirtyFlags & DirtyFlag_RasterizerState)
|
||||
{
|
||||
D3D::context->RSSetState(m_pending.rasterizerState);
|
||||
m_current.rasterizerState = m_pending.rasterizerState;
|
||||
}
|
||||
|
||||
m_dirtyFlags = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Common/BitField.h"
|
||||
@@ -14,10 +13,6 @@
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11RasterizerState;
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class StateCache
|
||||
@@ -44,37 +39,35 @@ private:
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
template <typename T>
|
||||
class AutoState
|
||||
{
|
||||
public:
|
||||
AutoState(const T* object);
|
||||
AutoState(const AutoState<T>& source);
|
||||
~AutoState();
|
||||
|
||||
const inline T* GetPtr() const { return state; }
|
||||
private:
|
||||
const T* state;
|
||||
};
|
||||
|
||||
typedef AutoState<ID3D11BlendState> AutoBlendState;
|
||||
typedef AutoState<ID3D11DepthStencilState> AutoDepthStencilState;
|
||||
typedef AutoState<ID3D11RasterizerState> AutoRasterizerState;
|
||||
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
StateManager();
|
||||
~StateManager();
|
||||
|
||||
// call any of these to change the affected states
|
||||
void PushBlendState(const ID3D11BlendState* state);
|
||||
void PushDepthState(const ID3D11DepthStencilState* state);
|
||||
void PushRasterizerState(const ID3D11RasterizerState* state);
|
||||
void SetBlendState(ID3D11BlendState* state)
|
||||
{
|
||||
if (m_current.blendState != state)
|
||||
m_dirtyFlags |= DirtyFlag_BlendState;
|
||||
|
||||
// call these after drawing
|
||||
void PopBlendState();
|
||||
void PopDepthState();
|
||||
void PopRasterizerState();
|
||||
m_pending.blendState = state;
|
||||
}
|
||||
|
||||
void SetDepthState(ID3D11DepthStencilState* state)
|
||||
{
|
||||
if (m_current.depthState != state)
|
||||
m_dirtyFlags |= DirtyFlag_DepthState;
|
||||
|
||||
m_pending.depthState = state;
|
||||
}
|
||||
|
||||
void SetRasterizerState(ID3D11RasterizerState* state)
|
||||
{
|
||||
if (m_current.rasterizerState != state)
|
||||
m_dirtyFlags |= DirtyFlag_RasterizerState;
|
||||
|
||||
m_pending.rasterizerState = state;
|
||||
}
|
||||
|
||||
void SetTexture(size_t index, ID3D11ShaderResourceView* texture)
|
||||
{
|
||||
@@ -117,6 +110,14 @@ public:
|
||||
m_pending.geometryConstants = buffer;
|
||||
}
|
||||
|
||||
void SetComputeConstants(ID3D11Buffer* buffer)
|
||||
{
|
||||
if (m_current.computeConstants != buffer)
|
||||
m_dirtyFlags |= DirtyFlag_ComputeConstants;
|
||||
|
||||
m_pending.computeConstants = buffer;
|
||||
}
|
||||
|
||||
void SetVertexBuffer(ID3D11Buffer* buffer, u32 stride, u32 offset)
|
||||
{
|
||||
if (m_current.vertexBuffer != buffer || m_current.vertexBufferStride != stride ||
|
||||
@@ -184,6 +185,14 @@ public:
|
||||
m_pending.geometryShader = shader;
|
||||
}
|
||||
|
||||
void SetComputeShader(ID3D11ComputeShader* shader)
|
||||
{
|
||||
if (m_current.computeShader != shader)
|
||||
m_dirtyFlags |= DirtyFlag_ComputeShader;
|
||||
|
||||
m_pending.computeShader = shader;
|
||||
}
|
||||
|
||||
// removes currently set texture from all slots, returns mask of previously bound slots
|
||||
u32 UnsetTexture(ID3D11ShaderResourceView* srv);
|
||||
void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv);
|
||||
@@ -193,14 +202,6 @@ public:
|
||||
void Apply();
|
||||
|
||||
private:
|
||||
std::stack<AutoBlendState> m_blendStates;
|
||||
std::stack<AutoDepthStencilState> m_depthStates;
|
||||
std::stack<AutoRasterizerState> m_rasterizerStates;
|
||||
|
||||
ID3D11BlendState* m_currentBlendState;
|
||||
ID3D11DepthStencilState* m_currentDepthState;
|
||||
ID3D11RasterizerState* m_currentRasterizerState;
|
||||
|
||||
enum DirtyFlags
|
||||
{
|
||||
DirtyFlag_Texture0 = 1 << 0,
|
||||
@@ -224,18 +225,23 @@ private:
|
||||
DirtyFlag_PixelConstants = 1 << 16,
|
||||
DirtyFlag_VertexConstants = 1 << 17,
|
||||
DirtyFlag_GeometryConstants = 1 << 18,
|
||||
DirtyFlag_ComputeConstants = 1 << 19,
|
||||
|
||||
DirtyFlag_VertexBuffer = 1 << 19,
|
||||
DirtyFlag_IndexBuffer = 1 << 20,
|
||||
DirtyFlag_VertexBuffer = 1 << 20,
|
||||
DirtyFlag_IndexBuffer = 1 << 21,
|
||||
|
||||
DirtyFlag_PixelShader = 1 << 21,
|
||||
DirtyFlag_VertexShader = 1 << 22,
|
||||
DirtyFlag_GeometryShader = 1 << 23,
|
||||
DirtyFlag_PixelShader = 1 << 22,
|
||||
DirtyFlag_VertexShader = 1 << 23,
|
||||
DirtyFlag_GeometryShader = 1 << 24,
|
||||
DirtyFlag_ComputeShader = 1 << 25,
|
||||
|
||||
DirtyFlag_InputAssembler = 1 << 24,
|
||||
DirtyFlag_InputAssembler = 1 << 26,
|
||||
DirtyFlag_BlendState = 1 << 27,
|
||||
DirtyFlag_DepthState = 1 << 28,
|
||||
DirtyFlag_RasterizerState = 1 << 29,
|
||||
};
|
||||
|
||||
u32 m_dirtyFlags;
|
||||
u32 m_dirtyFlags = ~0u;
|
||||
|
||||
struct Resources
|
||||
{
|
||||
@@ -244,6 +250,7 @@ private:
|
||||
std::array<ID3D11Buffer*, 2> pixelConstants;
|
||||
ID3D11Buffer* vertexConstants;
|
||||
ID3D11Buffer* geometryConstants;
|
||||
ID3D11Buffer* computeConstants;
|
||||
ID3D11Buffer* vertexBuffer;
|
||||
ID3D11Buffer* indexBuffer;
|
||||
u32 vertexBufferStride;
|
||||
@@ -253,10 +260,14 @@ private:
|
||||
ID3D11PixelShader* pixelShader;
|
||||
ID3D11VertexShader* vertexShader;
|
||||
ID3D11GeometryShader* geometryShader;
|
||||
ID3D11ComputeShader* computeShader;
|
||||
ID3D11BlendState* blendState;
|
||||
ID3D11DepthStencilState* depthState;
|
||||
ID3D11RasterizerState* rasterizerState;
|
||||
};
|
||||
|
||||
Resources m_pending;
|
||||
Resources m_current;
|
||||
Resources m_pending = {};
|
||||
Resources m_current = {};
|
||||
};
|
||||
|
||||
extern StateManager* stateman;
|
||||
|
||||
@@ -406,8 +406,8 @@ int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dw
|
||||
pVertices = (D3D::FONT2DVERTEX*)vbmap.pData;
|
||||
|
||||
// set general pipeline state
|
||||
D3D::stateman->PushBlendState(m_blendstate);
|
||||
D3D::stateman->PushRasterizerState(m_raststate);
|
||||
D3D::stateman->SetBlendState(m_blendstate);
|
||||
D3D::stateman->SetRasterizerState(m_raststate);
|
||||
|
||||
D3D::stateman->SetPixelShader(m_pshader);
|
||||
D3D::stateman->SetVertexShader(m_vshader);
|
||||
@@ -478,8 +478,6 @@ int CD3DFont::DrawTextScaled(float x, float y, float size, float spacing, u32 dw
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->Draw(3 * dwNumTriangles, 0);
|
||||
}
|
||||
D3D::stateman->PopBlendState();
|
||||
D3D::stateman->PopRasterizerState();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/DXPipeline.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/Render.h"
|
||||
#include "VideoBackends/D3D/VertexManager.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
DXPipeline::DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vertex_shader,
|
||||
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
|
||||
ID3D11RasterizerState* rasterizer_state,
|
||||
ID3D11DepthStencilState* depth_state, ID3D11BlendState* blend_state,
|
||||
D3D11_PRIMITIVE_TOPOLOGY primitive_topology)
|
||||
: m_input_layout(input_layout), m_vertex_shader(vertex_shader),
|
||||
m_geometry_shader(geometry_shader), m_pixel_shader(pixel_shader),
|
||||
m_rasterizer_state(rasterizer_state), m_depth_state(depth_state), m_blend_state(blend_state),
|
||||
m_primitive_topology(primitive_topology)
|
||||
{
|
||||
if (m_input_layout)
|
||||
m_input_layout->AddRef();
|
||||
if (m_vertex_shader)
|
||||
m_vertex_shader->AddRef();
|
||||
if (m_geometry_shader)
|
||||
m_geometry_shader->AddRef();
|
||||
if (m_pixel_shader)
|
||||
m_pixel_shader->AddRef();
|
||||
if (m_rasterizer_state)
|
||||
m_rasterizer_state->AddRef();
|
||||
if (m_depth_state)
|
||||
m_depth_state->AddRef();
|
||||
if (m_blend_state)
|
||||
m_blend_state->AddRef();
|
||||
}
|
||||
|
||||
DXPipeline::~DXPipeline()
|
||||
{
|
||||
if (m_input_layout)
|
||||
m_input_layout->Release();
|
||||
if (m_vertex_shader)
|
||||
m_vertex_shader->Release();
|
||||
if (m_geometry_shader)
|
||||
m_geometry_shader->Release();
|
||||
if (m_pixel_shader)
|
||||
m_pixel_shader->Release();
|
||||
if (m_rasterizer_state)
|
||||
m_rasterizer_state->Release();
|
||||
if (m_depth_state)
|
||||
m_depth_state->Release();
|
||||
if (m_blend_state)
|
||||
m_blend_state->Release();
|
||||
}
|
||||
|
||||
std::unique_ptr<DXPipeline> DXPipeline::Create(const AbstractPipelineConfig& config)
|
||||
{
|
||||
StateCache& state_cache = static_cast<Renderer*>(g_renderer.get())->GetStateCache();
|
||||
ID3D11RasterizerState* rasterizer_state = state_cache.Get(config.rasterization_state);
|
||||
ID3D11DepthStencilState* depth_state = state_cache.Get(config.depth_state);
|
||||
ID3D11BlendState* blend_state = state_cache.Get(config.blending_state);
|
||||
D3D11_PRIMITIVE_TOPOLOGY primitive_topology =
|
||||
StateCache::GetPrimitiveTopology(config.rasterization_state.primitive);
|
||||
if (!rasterizer_state || !depth_state || !blend_state)
|
||||
{
|
||||
SAFE_RELEASE(rasterizer_state);
|
||||
SAFE_RELEASE(depth_state);
|
||||
SAFE_RELEASE(blend_state);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DXShader* vertex_shader = static_cast<const DXShader*>(config.vertex_shader);
|
||||
const DXShader* geometry_shader = static_cast<const DXShader*>(config.geometry_shader);
|
||||
const DXShader* pixel_shader = static_cast<const DXShader*>(config.pixel_shader);
|
||||
_assert_(vertex_shader != nullptr && pixel_shader != nullptr);
|
||||
|
||||
ID3D11InputLayout* input_layout =
|
||||
const_cast<D3DVertexFormat*>(static_cast<const D3DVertexFormat*>(config.vertex_format))
|
||||
->GetInputLayout(vertex_shader->GetByteCode());
|
||||
|
||||
return std::make_unique<DXPipeline>(input_layout, vertex_shader->GetD3DVertexShader(),
|
||||
geometry_shader ? geometry_shader->GetD3DGeometryShader() :
|
||||
nullptr,
|
||||
pixel_shader->GetD3DPixelShader(), rasterizer_state,
|
||||
depth_state, blend_state, primitive_topology);
|
||||
}
|
||||
} // namespace DX11
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class DXPipeline final : public AbstractPipeline
|
||||
{
|
||||
public:
|
||||
DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vertex_shader,
|
||||
ID3D11GeometryShader* geometry_shader, ID3D11PixelShader* pixel_shader,
|
||||
ID3D11RasterizerState* rasterizer_state, ID3D11DepthStencilState* depth_state,
|
||||
ID3D11BlendState* blend_state, D3D11_PRIMITIVE_TOPOLOGY primitive_topology);
|
||||
~DXPipeline() override;
|
||||
|
||||
ID3D11InputLayout* GetInputLayout() const { return m_input_layout; }
|
||||
ID3D11VertexShader* GetVertexShader() const { return m_vertex_shader; }
|
||||
ID3D11GeometryShader* GetGeometryShader() const { return m_geometry_shader; }
|
||||
ID3D11PixelShader* GetPixelShader() const { return m_pixel_shader; }
|
||||
ID3D11RasterizerState* GetRasterizerState() const { return m_rasterizer_state; }
|
||||
ID3D11DepthStencilState* GetDepthState() const { return m_depth_state; }
|
||||
ID3D11BlendState* GetBlendState() const { return m_blend_state; }
|
||||
D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; }
|
||||
bool HasGeometryShader() const { return m_geometry_shader != nullptr; }
|
||||
static std::unique_ptr<DXPipeline> Create(const AbstractPipelineConfig& config);
|
||||
|
||||
private:
|
||||
ID3D11InputLayout* m_input_layout;
|
||||
ID3D11VertexShader* m_vertex_shader;
|
||||
ID3D11GeometryShader* m_geometry_shader;
|
||||
ID3D11PixelShader* m_pixel_shader;
|
||||
ID3D11RasterizerState* m_rasterizer_state;
|
||||
ID3D11DepthStencilState* m_depth_state;
|
||||
ID3D11BlendState* m_blend_state;
|
||||
D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology;
|
||||
};
|
||||
} // namespace DX11
|
||||
@@ -0,0 +1,183 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DShader.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs)
|
||||
: AbstractShader(ShaderStage::Vertex), m_bytecode(bytecode), m_shader(vs)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs)
|
||||
: AbstractShader(ShaderStage::Geometry), m_bytecode(bytecode), m_shader(gs)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps)
|
||||
: AbstractShader(ShaderStage::Pixel), m_bytecode(bytecode), m_shader(ps)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs)
|
||||
: AbstractShader(ShaderStage::Compute), m_bytecode(bytecode), m_shader(cs)
|
||||
{
|
||||
}
|
||||
|
||||
DXShader::~DXShader()
|
||||
{
|
||||
m_shader->Release();
|
||||
m_bytecode->Release();
|
||||
}
|
||||
|
||||
D3DBlob* DXShader::GetByteCode() const
|
||||
{
|
||||
return m_bytecode;
|
||||
}
|
||||
|
||||
ID3D11VertexShader* DXShader::GetD3DVertexShader() const
|
||||
{
|
||||
_dbg_assert_(VIDEO, m_stage == ShaderStage::Vertex);
|
||||
return static_cast<ID3D11VertexShader*>(m_shader);
|
||||
}
|
||||
|
||||
ID3D11GeometryShader* DXShader::GetD3DGeometryShader() const
|
||||
{
|
||||
_dbg_assert_(VIDEO, m_stage == ShaderStage::Geometry);
|
||||
return static_cast<ID3D11GeometryShader*>(m_shader);
|
||||
}
|
||||
|
||||
ID3D11PixelShader* DXShader::GetD3DPixelShader() const
|
||||
{
|
||||
_dbg_assert_(VIDEO, m_stage == ShaderStage::Pixel);
|
||||
return static_cast<ID3D11PixelShader*>(m_shader);
|
||||
}
|
||||
|
||||
ID3D11ComputeShader* DXShader::GetD3DComputeShader() const
|
||||
{
|
||||
_dbg_assert_(VIDEO, m_stage == ShaderStage::Compute);
|
||||
return static_cast<ID3D11ComputeShader*>(m_shader);
|
||||
}
|
||||
|
||||
bool DXShader::HasBinary() const
|
||||
{
|
||||
_assert_(m_bytecode);
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractShader::BinaryData DXShader::GetBinary() const
|
||||
{
|
||||
return BinaryData(m_bytecode->Data(), m_bytecode->Data() + m_bytecode->Size());
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBlob(ShaderStage stage, D3DBlob* bytecode)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
ID3D11VertexShader* vs = D3D::CreateVertexShaderFromByteCode(bytecode);
|
||||
if (vs)
|
||||
return std::make_unique<DXShader>(bytecode, vs);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
ID3D11GeometryShader* gs = D3D::CreateGeometryShaderFromByteCode(bytecode);
|
||||
if (gs)
|
||||
return std::make_unique<DXShader>(bytecode, gs);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
ID3D11PixelShader* ps = D3D::CreatePixelShaderFromByteCode(bytecode);
|
||||
if (ps)
|
||||
return std::make_unique<DXShader>(bytecode, ps);
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
ID3D11ComputeShader* cs = D3D::CreateComputeShaderFromByteCode(bytecode);
|
||||
if (cs)
|
||||
return std::make_unique<DXShader>(bytecode, cs);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length)
|
||||
{
|
||||
D3DBlob* bytecode;
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
{
|
||||
if (!D3D::CompileVertexShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Geometry:
|
||||
{
|
||||
if (!D3D::CompileGeometryShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Pixel:
|
||||
{
|
||||
if (!D3D::CompilePixelShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
|
||||
case ShaderStage::Compute:
|
||||
{
|
||||
if (!D3D::CompileComputeShader(std::string(source, length), &bytecode))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
|
||||
if (!shader)
|
||||
{
|
||||
bytecode->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
std::unique_ptr<DXShader> DXShader::CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length)
|
||||
{
|
||||
D3DBlob* bytecode = new D3DBlob(static_cast<unsigned int>(length), static_cast<const u8*>(data));
|
||||
std::unique_ptr<DXShader> shader = CreateFromBlob(stage, bytecode);
|
||||
if (!shader)
|
||||
{
|
||||
bytecode->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoBackends/D3D/D3DBlob.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
class DXShader final : public AbstractShader
|
||||
{
|
||||
public:
|
||||
// Note: vs/gs/ps/cs references are transferred.
|
||||
DXShader(D3DBlob* bytecode, ID3D11VertexShader* vs);
|
||||
DXShader(D3DBlob* bytecode, ID3D11GeometryShader* gs);
|
||||
DXShader(D3DBlob* bytecode, ID3D11PixelShader* ps);
|
||||
DXShader(D3DBlob* bytecode, ID3D11ComputeShader* cs);
|
||||
~DXShader() override;
|
||||
|
||||
D3DBlob* GetByteCode() const;
|
||||
ID3D11VertexShader* GetD3DVertexShader() const;
|
||||
ID3D11GeometryShader* GetD3DGeometryShader() const;
|
||||
ID3D11PixelShader* GetD3DPixelShader() const;
|
||||
ID3D11ComputeShader* GetD3DComputeShader() const;
|
||||
|
||||
bool HasBinary() const override;
|
||||
BinaryData GetBinary() const override;
|
||||
|
||||
// Creates a new shader object. The reference to bytecode is not transfered upon failure.
|
||||
static std::unique_ptr<DXShader> CreateFromBlob(ShaderStage stage, D3DBlob* bytecode);
|
||||
static std::unique_ptr<DXShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length);
|
||||
static std::unique_ptr<DXShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||
size_t length);
|
||||
|
||||
private:
|
||||
ID3D11DeviceChild* m_shader;
|
||||
D3DBlob* m_bytecode;
|
||||
};
|
||||
|
||||
} // namespace DX11
|
||||
@@ -119,20 +119,20 @@ D3DVertexFormat::~D3DVertexFormat()
|
||||
SAFE_RELEASE(m_layout);
|
||||
}
|
||||
|
||||
void D3DVertexFormat::SetInputLayout(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, so we don't need to recompute it if the shader
|
||||
// changes.
|
||||
HRESULT hr = DX11::D3D::device->CreateInputLayout(
|
||||
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
|
||||
if (FAILED(hr))
|
||||
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::stateman->SetInputLayout(m_layout);
|
||||
if (m_layout)
|
||||
return m_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(
|
||||
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
|
||||
if (FAILED(hr))
|
||||
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
||||
DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline");
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
} // namespace DX11
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <strsafe.h>
|
||||
#include <tuple>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MathUtil.h"
|
||||
@@ -23,6 +24,8 @@
|
||||
#include "VideoBackends/D3D/D3DBase.h"
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoBackends/D3D/D3DUtil.h"
|
||||
#include "VideoBackends/D3D/DXPipeline.h"
|
||||
#include "VideoBackends/D3D/DXShader.h"
|
||||
#include "VideoBackends/D3D/DXTexture.h"
|
||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||
@@ -41,6 +44,12 @@
|
||||
|
||||
namespace DX11
|
||||
{
|
||||
// Reserve 512KB for vertices, and 64KB for uniforms.
|
||||
// This should be sufficient for our usages, and if more is required,
|
||||
// we split it into multiple draws.
|
||||
constexpr u32 UTILITY_VBO_SIZE = 512 * 1024;
|
||||
constexpr u32 UTILITY_UBO_SIZE = 64 * 1024;
|
||||
|
||||
// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK
|
||||
typedef struct _Nv_Stereo_Image_Header
|
||||
{
|
||||
@@ -165,6 +174,16 @@ void Renderer::SetupDeviceObjects()
|
||||
D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState");
|
||||
|
||||
m_screenshot_texture = nullptr;
|
||||
|
||||
CD3D11_BUFFER_DESC vbo_desc(UTILITY_VBO_SIZE, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC,
|
||||
D3D11_CPU_ACCESS_WRITE);
|
||||
hr = D3D::device->CreateBuffer(&vbo_desc, nullptr, &m_utility_vertex_buffer);
|
||||
CHECK(SUCCEEDED(hr), "Create utility VBO");
|
||||
|
||||
CD3D11_BUFFER_DESC ubo_desc(UTILITY_UBO_SIZE, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC,
|
||||
D3D11_CPU_ACCESS_WRITE);
|
||||
hr = D3D::device->CreateBuffer(&ubo_desc, nullptr, &m_utility_uniform_buffer);
|
||||
CHECK(SUCCEEDED(hr), "Create utility UBO");
|
||||
}
|
||||
|
||||
// Kill off all device objects
|
||||
@@ -184,6 +203,8 @@ void Renderer::TeardownDeviceObjects()
|
||||
SAFE_RELEASE(m_reset_rast_state);
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
SAFE_RELEASE(m_utility_vertex_buffer);
|
||||
SAFE_RELEASE(m_utility_uniform_buffer);
|
||||
}
|
||||
|
||||
void Renderer::Create3DVisionTexture(int width, int height)
|
||||
@@ -229,6 +250,109 @@ void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||
D3D::DrawTextScaled(static_cast<float>(left), static_cast<float>(top), 20.f, 0.0f, color, text);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||
const char* source, size_t length)
|
||||
{
|
||||
return DXShader::CreateFromSource(stage, source, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||
const void* data, size_t length)
|
||||
{
|
||||
return DXShader::CreateFromBinary(stage, data, length);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||
{
|
||||
return DXPipeline::Create(config);
|
||||
}
|
||||
|
||||
void Renderer::UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size)
|
||||
{
|
||||
_dbg_assert_(VIDEO, uniforms_size > 0 && uniforms_size < UTILITY_UBO_SIZE);
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
HRESULT hr = D3D::context->Map(m_utility_uniform_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
|
||||
CHECK(SUCCEEDED(hr), "Map utility UBO");
|
||||
std::memcpy(mapped.pData, uniforms, uniforms_size);
|
||||
D3D::context->Unmap(m_utility_uniform_buffer, 0);
|
||||
}
|
||||
|
||||
void Renderer::UpdateUtilityVertexBuffer(const void* vertices, u32 vertex_stride, u32 num_vertices)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
HRESULT hr = D3D::context->Map(m_utility_vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
|
||||
CHECK(SUCCEEDED(hr), "Map utility VBO");
|
||||
std::memcpy(mapped.pData, vertices, num_vertices * vertex_stride);
|
||||
D3D::context->Unmap(m_utility_vertex_buffer, 0);
|
||||
}
|
||||
|
||||
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
||||
{
|
||||
const DXPipeline* dx_pipeline = static_cast<const DXPipeline*>(pipeline);
|
||||
|
||||
D3D::stateman->SetRasterizerState(dx_pipeline->GetRasterizerState());
|
||||
D3D::stateman->SetDepthState(dx_pipeline->GetDepthState());
|
||||
D3D::stateman->SetBlendState(dx_pipeline->GetBlendState());
|
||||
D3D::stateman->SetPrimitiveTopology(dx_pipeline->GetPrimitiveTopology());
|
||||
D3D::stateman->SetInputLayout(dx_pipeline->GetInputLayout());
|
||||
D3D::stateman->SetVertexShader(dx_pipeline->GetVertexShader());
|
||||
D3D::stateman->SetGeometryShader(dx_pipeline->GetGeometryShader());
|
||||
D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader());
|
||||
}
|
||||
|
||||
void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
|
||||
u32 vertex_stride, u32 num_vertices)
|
||||
{
|
||||
// Textures are fine, they're set directly via SetTexture.
|
||||
// Since samplers are set via gx_state, we need to fix this up here.
|
||||
for (size_t stage = 0; stage < m_gx_state.samplers.size(); stage++)
|
||||
D3D::stateman->SetSampler(stage, m_state_cache.Get(m_gx_state.samplers[stage]));
|
||||
|
||||
// Copy in uniforms.
|
||||
if (uniforms_size > 0)
|
||||
{
|
||||
UpdateUtilityUniformBuffer(uniforms, uniforms_size);
|
||||
D3D::stateman->SetVertexConstants(m_utility_uniform_buffer);
|
||||
D3D::stateman->SetPixelConstants(m_utility_uniform_buffer);
|
||||
D3D::stateman->SetGeometryConstants(m_utility_uniform_buffer);
|
||||
}
|
||||
|
||||
// If the vertices are larger than our buffer, we need to break it up into multiple draws.
|
||||
const char* vertices_ptr = static_cast<const char*>(vertices);
|
||||
while (num_vertices > 0)
|
||||
{
|
||||
u32 vertices_this_draw = num_vertices;
|
||||
if (vertices_ptr)
|
||||
{
|
||||
vertices_this_draw = std::min(vertices_this_draw, UTILITY_VBO_SIZE / vertex_stride);
|
||||
_dbg_assert_(VIDEO, vertices_this_draw > 0);
|
||||
UpdateUtilityVertexBuffer(vertices_ptr, vertex_stride, vertices_this_draw);
|
||||
D3D::stateman->SetVertexBuffer(m_utility_vertex_buffer, vertex_stride, 0);
|
||||
}
|
||||
|
||||
// Apply pending state and draw.
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->Draw(vertices_this_draw, 0);
|
||||
vertices_ptr += vertex_stride * vertices_this_draw;
|
||||
num_vertices -= vertices_this_draw;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms,
|
||||
u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||
{
|
||||
D3D::stateman->SetComputeShader(static_cast<const DXShader*>(shader)->GetD3DComputeShader());
|
||||
|
||||
if (uniforms_size > 0)
|
||||
{
|
||||
UpdateUtilityUniformBuffer(uniforms, uniforms_size);
|
||||
D3D::stateman->SetComputeConstants(m_utility_uniform_buffer);
|
||||
}
|
||||
|
||||
D3D::stateman->Apply();
|
||||
D3D::context->Dispatch(groups_x, groups_y, groups_z);
|
||||
}
|
||||
|
||||
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||
{
|
||||
TargetRectangle result;
|
||||
@@ -405,8 +529,8 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
|
||||
}
|
||||
else // if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
D3D::stateman->PushBlendState(m_clear_blend_states[3]);
|
||||
D3D::stateman->PushDepthState(m_clear_depth_states[1]);
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
|
||||
|
||||
D3D11_VIEWPORT vp =
|
||||
CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight());
|
||||
@@ -417,12 +541,6 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
|
||||
|
||||
D3D::DrawEFBPokeQuads(type, points, num_points);
|
||||
|
||||
if (type == EFBAccessType::PokeZ)
|
||||
{
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopBlendState();
|
||||
}
|
||||
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
@@ -446,21 +564,21 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||
ResetAPIState();
|
||||
|
||||
if (colorEnable && alphaEnable)
|
||||
D3D::stateman->PushBlendState(m_clear_blend_states[0]);
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[0]);
|
||||
else if (colorEnable)
|
||||
D3D::stateman->PushBlendState(m_clear_blend_states[1]);
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[1]);
|
||||
else if (alphaEnable)
|
||||
D3D::stateman->PushBlendState(m_clear_blend_states[2]);
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[2]);
|
||||
else
|
||||
D3D::stateman->PushBlendState(m_clear_blend_states[3]);
|
||||
D3D::stateman->SetBlendState(m_clear_blend_states[3]);
|
||||
|
||||
// TODO: Should we enable Z testing here?
|
||||
// if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(s_clear_depth_states[0]);
|
||||
// else
|
||||
if (zEnable)
|
||||
D3D::stateman->PushDepthState(m_clear_depth_states[1]);
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[1]);
|
||||
else /*if (!zEnable)*/
|
||||
D3D::stateman->PushDepthState(m_clear_depth_states[2]);
|
||||
D3D::stateman->SetDepthState(m_clear_depth_states[2]);
|
||||
|
||||
// Update the view port for clearing the picture
|
||||
TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc);
|
||||
@@ -474,9 +592,6 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||
u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000);
|
||||
D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f);
|
||||
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopBlendState();
|
||||
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
@@ -646,26 +761,23 @@ void Renderer::UpdateBackbufferSize()
|
||||
// ALWAYS call RestoreAPIState for each ResetAPIState call you're doing
|
||||
void Renderer::ResetAPIState()
|
||||
{
|
||||
D3D::stateman->PushBlendState(m_reset_blend_state);
|
||||
D3D::stateman->PushDepthState(m_reset_depth_state);
|
||||
D3D::stateman->PushRasterizerState(m_reset_rast_state);
|
||||
D3D::stateman->SetBlendState(m_reset_blend_state);
|
||||
D3D::stateman->SetDepthState(m_reset_depth_state);
|
||||
D3D::stateman->SetRasterizerState(m_reset_rast_state);
|
||||
}
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
// Gets us back into a more game-like state.
|
||||
D3D::stateman->PopBlendState();
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopRasterizerState();
|
||||
BPFunctions::SetViewport();
|
||||
BPFunctions::SetScissor();
|
||||
}
|
||||
|
||||
void Renderer::ApplyState()
|
||||
{
|
||||
D3D::stateman->PushBlendState(m_state_cache.Get(m_gx_state.blend));
|
||||
D3D::stateman->PushDepthState(m_state_cache.Get(m_gx_state.zmode));
|
||||
D3D::stateman->PushRasterizerState(m_state_cache.Get(m_gx_state.raster));
|
||||
D3D::stateman->SetBlendState(m_state_cache.Get(m_gx_state.blend));
|
||||
D3D::stateman->SetDepthState(m_state_cache.Get(m_gx_state.zmode));
|
||||
D3D::stateman->SetRasterizerState(m_state_cache.Get(m_gx_state.raster));
|
||||
D3D::stateman->SetPrimitiveTopology(
|
||||
StateCache::GetPrimitiveTopology(m_gx_state.raster.primitive));
|
||||
FramebufferManager::SetIntegerEFBRenderTarget(m_gx_state.blend.logicopenable);
|
||||
@@ -683,9 +795,6 @@ void Renderer::ApplyState()
|
||||
|
||||
void Renderer::RestoreState()
|
||||
{
|
||||
D3D::stateman->PopBlendState();
|
||||
D3D::stateman->PopDepthState();
|
||||
D3D::stateman->PopRasterizerState();
|
||||
}
|
||||
|
||||
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <d3d11.h>
|
||||
#include <string>
|
||||
#include "VideoBackends/D3D/D3DState.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
@@ -25,7 +26,13 @@ public:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, const char* source,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage, const void* data,
|
||||
size_t length) override;
|
||||
std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config) override;
|
||||
|
||||
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||
void SetBlendingState(const BlendingState& state) override;
|
||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||
void SetRasterizationState(const RasterizationState& state) override;
|
||||
@@ -63,6 +70,11 @@ public:
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override;
|
||||
|
||||
void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
|
||||
u32 vertex_stride, u32 num_vertices) override;
|
||||
void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, u32 uniforms_size,
|
||||
u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||
|
||||
private:
|
||||
struct GXPipelineState
|
||||
{
|
||||
@@ -82,6 +94,9 @@ private:
|
||||
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
|
||||
u32 src_width, u32 src_height, float Gamma);
|
||||
|
||||
void UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size);
|
||||
void UpdateUtilityVertexBuffer(const void* vertices, u32 vertex_stride, u32 num_vertices);
|
||||
|
||||
StateCache m_state_cache;
|
||||
GXPipelineState m_gx_state;
|
||||
|
||||
@@ -94,6 +109,9 @@ private:
|
||||
ID3D11Texture2D* m_screenshot_texture = nullptr;
|
||||
D3DTexture2D* m_3d_vision_texture = nullptr;
|
||||
|
||||
ID3D11Buffer* m_utility_vertex_buffer = nullptr;
|
||||
ID3D11Buffer* m_utility_uniform_buffer = nullptr;
|
||||
|
||||
u32 m_last_multisamples = 1;
|
||||
bool m_last_stereo_mode = false;
|
||||
bool m_last_fullscreen_state = false;
|
||||
|
||||
@@ -23,7 +23,7 @@ class D3DVertexFormat : public NativeVertexFormat
|
||||
public:
|
||||
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||
~D3DVertexFormat();
|
||||
void SetInputLayout(D3DBlob* vs_bytecode);
|
||||
ID3D11InputLayout* GetInputLayout(D3DBlob* vs_bytecode);
|
||||
|
||||
private:
|
||||
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user