mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-21 11:37:14 +01:00
VideoBackends: Add AbstractShader and AbstractPipeline classes
This commit is contained in:
parent
31111ef143
commit
fec6bb4d56
@ -13,6 +13,10 @@ set(SRCS
|
|||||||
D3DTexture.h
|
D3DTexture.h
|
||||||
D3DUtil.cpp
|
D3DUtil.cpp
|
||||||
D3DUtil.h
|
D3DUtil.h
|
||||||
|
DXPipeline.cpp
|
||||||
|
DXPipeline.h
|
||||||
|
DXShader.cpp
|
||||||
|
DXShader.h
|
||||||
DXTexture.cpp
|
DXTexture.cpp
|
||||||
DXTexture.h
|
DXTexture.h
|
||||||
FramebufferManager.cpp
|
FramebufferManager.cpp
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
<ClCompile Include="D3DState.cpp" />
|
<ClCompile Include="D3DState.cpp" />
|
||||||
<ClCompile Include="D3DTexture.cpp" />
|
<ClCompile Include="D3DTexture.cpp" />
|
||||||
<ClCompile Include="D3DUtil.cpp" />
|
<ClCompile Include="D3DUtil.cpp" />
|
||||||
|
<ClCompile Include="DXPipeline.cpp" />
|
||||||
|
<ClCompile Include="DXShader.cpp" />
|
||||||
<ClCompile Include="DXTexture.cpp" />
|
<ClCompile Include="DXTexture.cpp" />
|
||||||
<ClCompile Include="FramebufferManager.cpp" />
|
<ClCompile Include="FramebufferManager.cpp" />
|
||||||
<ClCompile Include="GeometryShaderCache.cpp" />
|
<ClCompile Include="GeometryShaderCache.cpp" />
|
||||||
@ -64,6 +66,8 @@
|
|||||||
<ClInclude Include="D3DState.h" />
|
<ClInclude Include="D3DState.h" />
|
||||||
<ClInclude Include="D3DTexture.h" />
|
<ClInclude Include="D3DTexture.h" />
|
||||||
<ClInclude Include="D3DUtil.h" />
|
<ClInclude Include="D3DUtil.h" />
|
||||||
|
<ClInclude Include="DXPipeline.h" />
|
||||||
|
<ClInclude Include="DXShader.h" />
|
||||||
<ClInclude Include="DXTexture.h" />
|
<ClInclude Include="DXTexture.h" />
|
||||||
<ClInclude Include="FramebufferManager.h" />
|
<ClInclude Include="FramebufferManager.h" />
|
||||||
<ClInclude Include="GeometryShaderCache.h" />
|
<ClInclude Include="GeometryShaderCache.h" />
|
||||||
|
@ -64,6 +64,12 @@
|
|||||||
<ClCompile Include="DXTexture.cpp">
|
<ClCompile Include="DXTexture.cpp">
|
||||||
<Filter>Render</Filter>
|
<Filter>Render</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="DXShader.cpp">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="DXPipeline.cpp">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="D3DBase.h">
|
<ClInclude Include="D3DBase.h">
|
||||||
@ -118,5 +124,11 @@
|
|||||||
<ClInclude Include="DXTexture.h">
|
<ClInclude Include="DXTexture.h">
|
||||||
<Filter>Render</Filter>
|
<Filter>Render</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="DXShader.h">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DXPipeline.h">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
96
Source/Core/VideoBackends/D3D/DXPipeline.cpp
Normal file
96
Source/Core/VideoBackends/D3D/DXPipeline.cpp
Normal file
@ -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
|
43
Source/Core/VideoBackends/D3D/DXPipeline.h
Normal file
43
Source/Core/VideoBackends/D3D/DXPipeline.h
Normal file
@ -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
|
183
Source/Core/VideoBackends/D3D/DXShader.cpp
Normal file
183
Source/Core/VideoBackends/D3D/DXShader.cpp
Normal file
@ -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
|
48
Source/Core/VideoBackends/D3D/DXShader.h
Normal file
48
Source/Core/VideoBackends/D3D/DXShader.h
Normal file
@ -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);
|
SAFE_RELEASE(m_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3DVertexFormat::SetInputLayout(D3DBlob* vs_bytecode)
|
ID3D11InputLayout* D3DVertexFormat::GetInputLayout(D3DBlob* vs_bytecode)
|
||||||
{
|
{
|
||||||
if (!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
|
// CreateInputLayout requires a shader input, but it only looks at the
|
||||||
// changes.
|
// signature of the shader, so we don't need to recompute it if the shader
|
||||||
HRESULT hr = DX11::D3D::device->CreateInputLayout(
|
// changes.
|
||||||
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
|
HRESULT hr = DX11::D3D::device->CreateInputLayout(
|
||||||
if (FAILED(hr))
|
m_elems.data(), m_num_elems, vs_bytecode->Data(), vs_bytecode->Size(), &m_layout);
|
||||||
PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__);
|
if (FAILED(hr))
|
||||||
DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline");
|
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);
|
return m_layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace DX11
|
} // namespace DX11
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
@ -23,6 +24,8 @@
|
|||||||
#include "VideoBackends/D3D/D3DBase.h"
|
#include "VideoBackends/D3D/D3DBase.h"
|
||||||
#include "VideoBackends/D3D/D3DState.h"
|
#include "VideoBackends/D3D/D3DState.h"
|
||||||
#include "VideoBackends/D3D/D3DUtil.h"
|
#include "VideoBackends/D3D/D3DUtil.h"
|
||||||
|
#include "VideoBackends/D3D/DXPipeline.h"
|
||||||
|
#include "VideoBackends/D3D/DXShader.h"
|
||||||
#include "VideoBackends/D3D/DXTexture.h"
|
#include "VideoBackends/D3D/DXTexture.h"
|
||||||
#include "VideoBackends/D3D/FramebufferManager.h"
|
#include "VideoBackends/D3D/FramebufferManager.h"
|
||||||
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
#include "VideoBackends/D3D/GeometryShaderCache.h"
|
||||||
@ -41,6 +44,12 @@
|
|||||||
|
|
||||||
namespace DX11
|
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
|
// Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK
|
||||||
typedef struct _Nv_Stereo_Image_Header
|
typedef struct _Nv_Stereo_Image_Header
|
||||||
{
|
{
|
||||||
@ -165,6 +174,16 @@ void Renderer::SetupDeviceObjects()
|
|||||||
D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState");
|
D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState");
|
||||||
|
|
||||||
m_screenshot_texture = nullptr;
|
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
|
// Kill off all device objects
|
||||||
@ -184,6 +203,8 @@ void Renderer::TeardownDeviceObjects()
|
|||||||
SAFE_RELEASE(m_reset_rast_state);
|
SAFE_RELEASE(m_reset_rast_state);
|
||||||
SAFE_RELEASE(m_screenshot_texture);
|
SAFE_RELEASE(m_screenshot_texture);
|
||||||
SAFE_RELEASE(m_3d_vision_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)
|
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);
|
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 Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||||
{
|
{
|
||||||
TargetRectangle result;
|
TargetRectangle result;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <d3d11.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "VideoBackends/D3D/D3DState.h"
|
#include "VideoBackends/D3D/D3DState.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
@ -25,7 +26,13 @@ public:
|
|||||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
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 SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
@ -63,6 +70,11 @@ public:
|
|||||||
|
|
||||||
void ReinterpretPixelData(unsigned int convtype) override;
|
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:
|
private:
|
||||||
struct GXPipelineState
|
struct GXPipelineState
|
||||||
{
|
{
|
||||||
@ -82,6 +94,9 @@ private:
|
|||||||
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
|
void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture,
|
||||||
u32 src_width, u32 src_height, float Gamma);
|
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;
|
StateCache m_state_cache;
|
||||||
GXPipelineState m_gx_state;
|
GXPipelineState m_gx_state;
|
||||||
|
|
||||||
@ -94,6 +109,9 @@ private:
|
|||||||
ID3D11Texture2D* m_screenshot_texture = nullptr;
|
ID3D11Texture2D* m_screenshot_texture = nullptr;
|
||||||
D3DTexture2D* m_3d_vision_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;
|
u32 m_last_multisamples = 1;
|
||||||
bool m_last_stereo_mode = false;
|
bool m_last_stereo_mode = false;
|
||||||
bool m_last_fullscreen_state = false;
|
bool m_last_fullscreen_state = false;
|
||||||
|
@ -23,7 +23,7 @@ class D3DVertexFormat : public NativeVertexFormat
|
|||||||
public:
|
public:
|
||||||
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
D3DVertexFormat(const PortableVertexDeclaration& vtx_decl);
|
||||||
~D3DVertexFormat();
|
~D3DVertexFormat();
|
||||||
void SetInputLayout(D3DBlob* vs_bytecode);
|
ID3D11InputLayout* GetInputLayout(D3DBlob* vs_bytecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
std::array<D3D11_INPUT_ELEMENT_DESC, 32> m_elems{};
|
||||||
|
@ -260,7 +260,7 @@ bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format)
|
|||||||
if (!last_entry->shader)
|
if (!last_entry->shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vertex_format->SetInputLayout(last_entry->bytecode);
|
D3D::stateman->SetInputLayout(vertex_format->GetInputLayout(last_entry->bytecode));
|
||||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ bool VertexShaderCache::SetShader(D3DVertexFormat* vertex_format)
|
|||||||
if (!last_entry->shader)
|
if (!last_entry->shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
vertex_format->SetInputLayout(last_entry->bytecode);
|
D3D::stateman->SetInputLayout(vertex_format->GetInputLayout(last_entry->bytecode));
|
||||||
D3D::stateman->SetVertexShader(last_entry->shader);
|
D3D::stateman->SetVertexShader(last_entry->shader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format)
|
|||||||
if (!last_uber_entry->shader)
|
if (!last_uber_entry->shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uber_vertex_format->SetInputLayout(last_uber_entry->bytecode);
|
D3D::stateman->SetInputLayout(uber_vertex_format->GetInputLayout(last_uber_entry->bytecode));
|
||||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -340,7 +340,7 @@ bool VertexShaderCache::SetUberShader(D3DVertexFormat* vertex_format)
|
|||||||
if (!last_uber_entry->shader)
|
if (!last_uber_entry->shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uber_vertex_format->SetInputLayout(last_uber_entry->bytecode);
|
D3D::stateman->SetInputLayout(uber_vertex_format->GetInputLayout(last_uber_entry->bytecode));
|
||||||
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
D3D::stateman->SetVertexShader(last_uber_entry->shader);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "VideoBackends/Null/NullTexture.h"
|
#include "VideoBackends/Null/NullTexture.h"
|
||||||
#include "VideoBackends/Null/Render.h"
|
#include "VideoBackends/Null/Render.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
|
#include "VideoCommon/AbstractShader.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
namespace Null
|
namespace Null
|
||||||
@ -33,6 +35,40 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
|||||||
return std::make_unique<NullStagingTexture>(type, config);
|
return std::make_unique<NullStagingTexture>(type, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NullShader final : public AbstractShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NullShader(ShaderStage stage) : AbstractShader(stage) {}
|
||||||
|
~NullShader() = default;
|
||||||
|
|
||||||
|
bool HasBinary() const override { return false; }
|
||||||
|
BinaryData GetBinary() const override { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
|
const char* source, size_t length)
|
||||||
|
{
|
||||||
|
return std::make_unique<NullShader>(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
const void* data, size_t length)
|
||||||
|
{
|
||||||
|
return std::make_unique<NullShader>(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NullPipeline final : public AbstractPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NullPipeline() : AbstractPipeline() {}
|
||||||
|
~NullPipeline() override = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
return std::make_unique<NullPipeline>();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||||
{
|
{
|
||||||
NOTICE_LOG(VIDEO, "RenderText: %s", text.c_str());
|
NOTICE_LOG(VIDEO, "RenderText: %s", text.c_str());
|
||||||
|
@ -18,6 +18,12 @@ public:
|
|||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
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 RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
||||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; }
|
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override { return 0; }
|
||||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
||||||
|
@ -3,6 +3,8 @@ set(SRCS
|
|||||||
FramebufferManager.cpp
|
FramebufferManager.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
NativeVertexFormat.cpp
|
NativeVertexFormat.cpp
|
||||||
|
OGLPipeline.cpp
|
||||||
|
OGLShader.cpp
|
||||||
OGLTexture.cpp
|
OGLTexture.cpp
|
||||||
PerfQuery.cpp
|
PerfQuery.cpp
|
||||||
PostProcessing.cpp
|
PostProcessing.cpp
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="OGLPipeline.cpp" />
|
||||||
|
<ClCompile Include="OGLShader.cpp" />
|
||||||
<ClCompile Include="OGLTexture.cpp" />
|
<ClCompile Include="OGLTexture.cpp" />
|
||||||
<ClCompile Include="BoundingBox.cpp" />
|
<ClCompile Include="BoundingBox.cpp" />
|
||||||
<ClCompile Include="FramebufferManager.cpp" />
|
<ClCompile Include="FramebufferManager.cpp" />
|
||||||
@ -53,6 +55,8 @@
|
|||||||
<ClCompile Include="VertexManager.cpp" />
|
<ClCompile Include="VertexManager.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="OGLPipeline.h" />
|
||||||
|
<ClInclude Include="OGLShader.h" />
|
||||||
<ClInclude Include="OGLTexture.h" />
|
<ClInclude Include="OGLTexture.h" />
|
||||||
<ClInclude Include="BoundingBox.h" />
|
<ClInclude Include="BoundingBox.h" />
|
||||||
<ClInclude Include="FramebufferManager.h" />
|
<ClInclude Include="FramebufferManager.h" />
|
||||||
|
@ -56,6 +56,12 @@
|
|||||||
<ClCompile Include="OGLTexture.cpp">
|
<ClCompile Include="OGLTexture.cpp">
|
||||||
<Filter>Render</Filter>
|
<Filter>Render</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="OGLShader.cpp">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="OGLPipeline.cpp">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="VertexManager.h">
|
<ClInclude Include="VertexManager.h">
|
||||||
@ -99,6 +105,12 @@
|
|||||||
<ClInclude Include="OGLTexture.h">
|
<ClInclude Include="OGLTexture.h">
|
||||||
<Filter>Render</Filter>
|
<Filter>Render</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="OGLShader.h">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="OGLPipeline.h">
|
||||||
|
<Filter>Render</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
62
Source/Core/VideoBackends/OGL/OGLPipeline.cpp
Normal file
62
Source/Core/VideoBackends/OGL/OGLPipeline.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
|
||||||
|
#include "VideoBackends/OGL/OGLPipeline.h"
|
||||||
|
#include "VideoBackends/OGL/OGLShader.h"
|
||||||
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||||
|
#include "VideoBackends/OGL/Render.h"
|
||||||
|
#include "VideoBackends/OGL/VertexManager.h"
|
||||||
|
|
||||||
|
namespace OGL
|
||||||
|
{
|
||||||
|
static GLenum MapToGLPrimitive(PrimitiveType primitive_type)
|
||||||
|
{
|
||||||
|
switch (primitive_type)
|
||||||
|
{
|
||||||
|
case PrimitiveType::Points:
|
||||||
|
return GL_POINTS;
|
||||||
|
case PrimitiveType::Lines:
|
||||||
|
return GL_LINES;
|
||||||
|
case PrimitiveType::Triangles:
|
||||||
|
return GL_TRIANGLES;
|
||||||
|
case PrimitiveType::TriangleStrip:
|
||||||
|
return GL_TRIANGLE_STRIP;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OGLPipeline::OGLPipeline(const GLVertexFormat* vertex_format,
|
||||||
|
const RasterizationState& rasterization_state,
|
||||||
|
const DepthState& depth_state, const BlendingState& blending_state,
|
||||||
|
const PipelineProgram* program, GLuint gl_primitive)
|
||||||
|
: m_vertex_format(vertex_format), m_rasterization_state(rasterization_state),
|
||||||
|
m_depth_state(depth_state), m_blending_state(blending_state), m_program(program),
|
||||||
|
m_gl_primitive(gl_primitive)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLPipeline::~OGLPipeline()
|
||||||
|
{
|
||||||
|
// We don't want to destroy the shaders.
|
||||||
|
ProgramShaderCache::ReleasePipelineProgram(m_program);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<OGLPipeline> OGLPipeline::Create(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
const PipelineProgram* program =
|
||||||
|
ProgramShaderCache::GetPipelineProgram(static_cast<const OGLShader*>(config.vertex_shader),
|
||||||
|
static_cast<const OGLShader*>(config.geometry_shader),
|
||||||
|
static_cast<const OGLShader*>(config.pixel_shader));
|
||||||
|
if (!program)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const GLVertexFormat* vertex_format = static_cast<const GLVertexFormat*>(config.vertex_format);
|
||||||
|
GLenum gl_primitive = MapToGLPrimitive(config.rasterization_state.primitive);
|
||||||
|
return std::make_unique<OGLPipeline>(vertex_format, config.rasterization_state,
|
||||||
|
config.depth_state, config.blending_state, program,
|
||||||
|
gl_primitive);
|
||||||
|
}
|
||||||
|
} // namespace OGL
|
43
Source/Core/VideoBackends/OGL/OGLPipeline.h
Normal file
43
Source/Core/VideoBackends/OGL/OGLPipeline.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Common/GL/GLUtil.h"
|
||||||
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||||
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
|
|
||||||
|
namespace OGL
|
||||||
|
{
|
||||||
|
class OGLPipeline final : public AbstractPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OGLPipeline(const GLVertexFormat* vertex_format,
|
||||||
|
const RasterizationState& rasterization_state, const DepthState& depth_state,
|
||||||
|
const BlendingState& blending_state, const PipelineProgram* program,
|
||||||
|
GLenum gl_primitive);
|
||||||
|
~OGLPipeline() override;
|
||||||
|
|
||||||
|
const GLVertexFormat* GetVertexFormat() const { return m_vertex_format; }
|
||||||
|
const RasterizationState& GetRasterizationState() const { return m_rasterization_state; }
|
||||||
|
const DepthState& GetDepthState() const { return m_depth_state; }
|
||||||
|
const BlendingState& GetBlendingState() const { return m_blending_state; }
|
||||||
|
const PipelineProgram* GetProgram() const { return m_program; }
|
||||||
|
bool HasVertexInput() const { return m_vertex_format != nullptr; }
|
||||||
|
GLenum GetGLPrimitive() const { return m_gl_primitive; }
|
||||||
|
static std::unique_ptr<OGLPipeline> Create(const AbstractPipelineConfig& config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const GLVertexFormat* m_vertex_format;
|
||||||
|
RasterizationState m_rasterization_state;
|
||||||
|
DepthState m_depth_state;
|
||||||
|
BlendingState m_blending_state;
|
||||||
|
const PipelineProgram* m_program;
|
||||||
|
GLenum m_gl_primitive;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OGL
|
77
Source/Core/VideoBackends/OGL/OGLShader.cpp
Normal file
77
Source/Core/VideoBackends/OGL/OGLShader.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "VideoBackends/OGL/OGLShader.h"
|
||||||
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||||
|
|
||||||
|
namespace OGL
|
||||||
|
{
|
||||||
|
static GLenum GetGLShaderTypeForStage(ShaderStage stage)
|
||||||
|
{
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
|
case ShaderStage::Vertex:
|
||||||
|
return GL_VERTEX_SHADER;
|
||||||
|
case ShaderStage::Geometry:
|
||||||
|
return GL_GEOMETRY_SHADER;
|
||||||
|
case ShaderStage::Pixel:
|
||||||
|
return GL_FRAGMENT_SHADER;
|
||||||
|
case ShaderStage::Compute:
|
||||||
|
return GL_COMPUTE_SHADER;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLShader::OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id)
|
||||||
|
: AbstractShader(stage), m_type(gl_type), m_id(shader_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLShader::OGLShader(GLuint compute_program_id)
|
||||||
|
: AbstractShader(ShaderStage::Compute), m_type(GL_COMPUTE_SHADER), m_id(compute_program_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLShader::~OGLShader()
|
||||||
|
{
|
||||||
|
if (m_stage != ShaderStage::Compute)
|
||||||
|
glDeleteShader(m_id);
|
||||||
|
else
|
||||||
|
glDeleteProgram(m_compute_program_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OGLShader::HasBinary() const
|
||||||
|
{
|
||||||
|
// NOTE: GL shaders do not have binaries, programs do.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractShader::BinaryData OGLShader::GetBinary() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<OGLShader> OGLShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (stage != ShaderStage::Compute)
|
||||||
|
{
|
||||||
|
GLenum shader_type = GetGLShaderTypeForStage(stage);
|
||||||
|
GLuint shader_id =
|
||||||
|
ProgramShaderCache::CompileSingleShader(shader_type, std::string(source, length));
|
||||||
|
if (!shader_id)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return std::make_unique<OGLShader>(stage, shader_type, shader_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute shaders.
|
||||||
|
SHADER prog;
|
||||||
|
if (!ProgramShaderCache::CompileComputeShader(prog, std::string(source, length)))
|
||||||
|
return nullptr;
|
||||||
|
return std::make_unique<OGLShader>(prog.glprogid);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace OGL
|
38
Source/Core/VideoBackends/OGL/OGLShader.h
Normal file
38
Source/Core/VideoBackends/OGL/OGLShader.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/GL/GLUtil.h"
|
||||||
|
#include "VideoCommon/AbstractShader.h"
|
||||||
|
|
||||||
|
namespace OGL
|
||||||
|
{
|
||||||
|
class OGLShader final : public AbstractShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit OGLShader(ShaderStage stage, GLenum gl_type, GLuint shader_id);
|
||||||
|
explicit OGLShader(GLuint compute_program_id);
|
||||||
|
~OGLShader() override;
|
||||||
|
|
||||||
|
GLenum GetGLShaderType() const { return m_type; }
|
||||||
|
GLuint GetGLShaderID() const { return m_id; }
|
||||||
|
GLuint GetGLComputeProgramID() const { return m_compute_program_id; }
|
||||||
|
bool HasBinary() const override;
|
||||||
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
|
static std::unique_ptr<OGLShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLenum m_type;
|
||||||
|
GLuint m_id;
|
||||||
|
GLuint m_compute_program_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OGL
|
@ -9,6 +9,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common/Align.h"
|
#include "Common/Align.h"
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/GL/GLInterfaceBase.h"
|
#include "Common/GL/GLInterfaceBase.h"
|
||||||
@ -20,6 +21,7 @@
|
|||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
|
|
||||||
|
#include "VideoBackends/OGL/OGLShader.h"
|
||||||
#include "VideoBackends/OGL/Render.h"
|
#include "VideoBackends/OGL/Render.h"
|
||||||
#include "VideoBackends/OGL/StreamBuffer.h"
|
#include "VideoBackends/OGL/StreamBuffer.h"
|
||||||
#include "VideoBackends/OGL/VertexManager.h"
|
#include "VideoBackends/OGL/VertexManager.h"
|
||||||
@ -57,6 +59,7 @@ static LinearDiskCache<UBERSHADERUID, u8> s_uber_program_disk_cache;
|
|||||||
static GLuint CurrentProgram = 0;
|
static GLuint CurrentProgram = 0;
|
||||||
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
|
ProgramShaderCache::PCache ProgramShaderCache::pshaders;
|
||||||
ProgramShaderCache::UberPCache ProgramShaderCache::ubershaders;
|
ProgramShaderCache::UberPCache ProgramShaderCache::ubershaders;
|
||||||
|
ProgramShaderCache::PipelineProgramMap ProgramShaderCache::pipelineprograms;
|
||||||
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
|
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_entry;
|
||||||
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_uber_entry;
|
ProgramShaderCache::PCacheEntry* ProgramShaderCache::last_uber_entry;
|
||||||
SHADERUID ProgramShaderCache::last_uid;
|
SHADERUID ProgramShaderCache::last_uid;
|
||||||
@ -188,6 +191,47 @@ void SHADER::DestroyShaders()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PipelineProgramKey::operator!=(const PipelineProgramKey& rhs) const
|
||||||
|
{
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PipelineProgramKey::operator==(const PipelineProgramKey& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(vertex_shader, geometry_shader, pixel_shader) ==
|
||||||
|
std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PipelineProgramKey::operator<(const PipelineProgramKey& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(vertex_shader, geometry_shader, pixel_shader) <
|
||||||
|
std::tie(rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t PipelineProgramKeyHash::operator()(const PipelineProgramKey& key) const
|
||||||
|
{
|
||||||
|
// We would really want std::hash_combine for this..
|
||||||
|
std::hash<const void*> hasher;
|
||||||
|
return hasher(key.vertex_shader) + hasher(key.geometry_shader) + hasher(key.pixel_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamBuffer* ProgramShaderCache::GetUniformBuffer()
|
||||||
|
{
|
||||||
|
return s_buffer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ProgramShaderCache::GetUniformBufferAlignment()
|
||||||
|
{
|
||||||
|
return s_ubo_align;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::InvalidateConstants()
|
||||||
|
{
|
||||||
|
VertexShaderManager::dirty = true;
|
||||||
|
GeometryShaderManager::dirty = true;
|
||||||
|
PixelShaderManager::dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::UploadConstants()
|
void ProgramShaderCache::UploadConstants()
|
||||||
{
|
{
|
||||||
if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty)
|
if (PixelShaderManager::dirty || VertexShaderManager::dirty || GeometryShaderManager::dirty)
|
||||||
@ -697,6 +741,10 @@ void ProgramShaderCache::Shutdown()
|
|||||||
s_attributeless_VBO = 0;
|
s_attributeless_VBO = 0;
|
||||||
s_attributeless_VAO = 0;
|
s_attributeless_VAO = 0;
|
||||||
s_last_VAO = 0;
|
s_last_VAO = 0;
|
||||||
|
|
||||||
|
// All pipeline programs should have been released.
|
||||||
|
_dbg_assert_(VIDEO, pipelineprograms.empty());
|
||||||
|
pipelineprograms.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::CreateAttributelessVAO()
|
void ProgramShaderCache::CreateAttributelessVAO()
|
||||||
@ -732,6 +780,11 @@ void ProgramShaderCache::InvalidateVertexFormat()
|
|||||||
s_last_VAO = 0;
|
s_last_VAO = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::InvalidateLastProgram()
|
||||||
|
{
|
||||||
|
CurrentProgram = 0;
|
||||||
|
}
|
||||||
|
|
||||||
GLuint ProgramShaderCache::CreateProgramFromBinary(const u8* value, u32 value_size)
|
GLuint ProgramShaderCache::CreateProgramFromBinary(const u8* value, u32 value_size)
|
||||||
{
|
{
|
||||||
const u8* binary = value + sizeof(GLenum);
|
const u8* binary = value + sizeof(GLenum);
|
||||||
@ -860,6 +913,58 @@ void ProgramShaderCache::DestroyShaders()
|
|||||||
ubershaders.clear();
|
ubershaders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PipelineProgram* ProgramShaderCache::GetPipelineProgram(const OGLShader* vertex_shader,
|
||||||
|
const OGLShader* geometry_shader,
|
||||||
|
const OGLShader* pixel_shader)
|
||||||
|
{
|
||||||
|
PipelineProgramKey key = {vertex_shader, geometry_shader, pixel_shader};
|
||||||
|
auto iter = pipelineprograms.find(key);
|
||||||
|
if (iter != pipelineprograms.end())
|
||||||
|
{
|
||||||
|
iter->second->reference_count++;
|
||||||
|
return iter->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PipelineProgram> prog = std::make_unique<PipelineProgram>();
|
||||||
|
prog->key = key;
|
||||||
|
|
||||||
|
// Attach shaders.
|
||||||
|
_assert_(vertex_shader && vertex_shader->GetStage() == ShaderStage::Vertex);
|
||||||
|
_assert_(pixel_shader && pixel_shader->GetStage() == ShaderStage::Pixel);
|
||||||
|
prog->shader.glprogid = glCreateProgram();
|
||||||
|
glAttachShader(prog->shader.glprogid, vertex_shader->GetGLShaderID());
|
||||||
|
glAttachShader(prog->shader.glprogid, pixel_shader->GetGLShaderID());
|
||||||
|
if (geometry_shader)
|
||||||
|
{
|
||||||
|
_assert_(geometry_shader->GetStage() == ShaderStage::Geometry);
|
||||||
|
glAttachShader(prog->shader.glprogid, geometry_shader->GetGLShaderID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link program.
|
||||||
|
prog->shader.SetProgramBindings(false);
|
||||||
|
glLinkProgram(prog->shader.glprogid);
|
||||||
|
if (!ProgramShaderCache::CheckProgramLinkResult(prog->shader.glprogid, {}, {}, {}))
|
||||||
|
{
|
||||||
|
prog->shader.Destroy();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ip = pipelineprograms.emplace(key, std::move(prog));
|
||||||
|
return ip.first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramShaderCache::ReleasePipelineProgram(const PipelineProgram* prog)
|
||||||
|
{
|
||||||
|
auto iter = pipelineprograms.find(prog->key);
|
||||||
|
_assert_(iter != pipelineprograms.end() && prog == iter->second.get());
|
||||||
|
|
||||||
|
if (--iter->second->reference_count == 0)
|
||||||
|
{
|
||||||
|
iter->second->shader.Destroy();
|
||||||
|
pipelineprograms.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ProgramShaderCache::CreateHeader()
|
void ProgramShaderCache::CreateHeader()
|
||||||
{
|
{
|
||||||
GlslVersion v = g_ogl_config.eSupportedGLSLVersion;
|
GlslVersion v = g_ogl_config.eSupportedGLSLVersion;
|
||||||
@ -1368,5 +1473,4 @@ void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, PrimitiveType
|
|||||||
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||||
glDeleteSync(sync);
|
glDeleteSync(sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OGL
|
} // namespace OGL
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "Common/GL/GLUtil.h"
|
#include "Common/GL/GLUtil.h"
|
||||||
#include "Common/LinearDiskCache.h"
|
#include "Common/LinearDiskCache.h"
|
||||||
@ -21,7 +23,9 @@ class cInterfaceBase;
|
|||||||
|
|
||||||
namespace OGL
|
namespace OGL
|
||||||
{
|
{
|
||||||
|
class OGLShader;
|
||||||
class GLVertexFormat;
|
class GLVertexFormat;
|
||||||
|
class StreamBuffer;
|
||||||
|
|
||||||
class SHADERUID
|
class SHADERUID
|
||||||
{
|
{
|
||||||
@ -81,6 +85,29 @@ struct SHADER
|
|||||||
void DestroyShaders();
|
void DestroyShaders();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PipelineProgramKey
|
||||||
|
{
|
||||||
|
const OGLShader* vertex_shader;
|
||||||
|
const OGLShader* geometry_shader;
|
||||||
|
const OGLShader* pixel_shader;
|
||||||
|
|
||||||
|
bool operator==(const PipelineProgramKey& rhs) const;
|
||||||
|
bool operator!=(const PipelineProgramKey& rhs) const;
|
||||||
|
bool operator<(const PipelineProgramKey& rhs) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineProgramKeyHash
|
||||||
|
{
|
||||||
|
std::size_t operator()(const PipelineProgramKey& key) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineProgram
|
||||||
|
{
|
||||||
|
PipelineProgramKey key;
|
||||||
|
SHADER shader;
|
||||||
|
std::atomic_size_t reference_count{1};
|
||||||
|
};
|
||||||
|
|
||||||
class ProgramShaderCache
|
class ProgramShaderCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -98,6 +125,7 @@ public:
|
|||||||
static SHADER* SetUberShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format);
|
static SHADER* SetUberShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format);
|
||||||
static void BindVertexFormat(const GLVertexFormat* vertex_format);
|
static void BindVertexFormat(const GLVertexFormat* vertex_format);
|
||||||
static void InvalidateVertexFormat();
|
static void InvalidateVertexFormat();
|
||||||
|
static void InvalidateLastProgram();
|
||||||
|
|
||||||
static bool CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode,
|
static bool CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode,
|
||||||
const std::string& gcode = "");
|
const std::string& gcode = "");
|
||||||
@ -106,6 +134,9 @@ public:
|
|||||||
static bool CheckShaderCompileResult(GLuint id, GLenum type, const std::string& code);
|
static bool CheckShaderCompileResult(GLuint id, GLenum type, const std::string& code);
|
||||||
static bool CheckProgramLinkResult(GLuint id, const std::string& vcode, const std::string& pcode,
|
static bool CheckProgramLinkResult(GLuint id, const std::string& vcode, const std::string& pcode,
|
||||||
const std::string& gcode);
|
const std::string& gcode);
|
||||||
|
static StreamBuffer* GetUniformBuffer();
|
||||||
|
static u32 GetUniformBufferAlignment();
|
||||||
|
static void InvalidateConstants();
|
||||||
static void UploadConstants();
|
static void UploadConstants();
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
@ -115,6 +146,11 @@ public:
|
|||||||
static void RetrieveAsyncShaders();
|
static void RetrieveAsyncShaders();
|
||||||
static void PrecompileUberShaders();
|
static void PrecompileUberShaders();
|
||||||
|
|
||||||
|
static const PipelineProgram* GetPipelineProgram(const OGLShader* vertex_shader,
|
||||||
|
const OGLShader* geometry_shader,
|
||||||
|
const OGLShader* pixel_shader);
|
||||||
|
static void ReleasePipelineProgram(const PipelineProgram* prog);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename UIDType>
|
template <typename UIDType>
|
||||||
class ProgramShaderCacheInserter : public LinearDiskCacheReader<UIDType, u8>
|
class ProgramShaderCacheInserter : public LinearDiskCacheReader<UIDType, u8>
|
||||||
@ -189,6 +225,9 @@ private:
|
|||||||
|
|
||||||
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
typedef std::map<SHADERUID, PCacheEntry> PCache;
|
||||||
typedef std::map<UBERSHADERUID, PCacheEntry> UberPCache;
|
typedef std::map<UBERSHADERUID, PCacheEntry> UberPCache;
|
||||||
|
typedef std::unordered_map<PipelineProgramKey, std::unique_ptr<PipelineProgram>,
|
||||||
|
PipelineProgramKeyHash>
|
||||||
|
PipelineProgramMap;
|
||||||
|
|
||||||
static void CreateAttributelessVAO();
|
static void CreateAttributelessVAO();
|
||||||
static GLuint CreateProgramFromBinary(const u8* value, u32 value_size);
|
static GLuint CreateProgramFromBinary(const u8* value, u32 value_size);
|
||||||
@ -202,6 +241,7 @@ private:
|
|||||||
|
|
||||||
static PCache pshaders;
|
static PCache pshaders;
|
||||||
static UberPCache ubershaders;
|
static UberPCache ubershaders;
|
||||||
|
static PipelineProgramMap pipelineprograms;
|
||||||
static PCacheEntry* last_entry;
|
static PCacheEntry* last_entry;
|
||||||
static PCacheEntry* last_uber_entry;
|
static PCacheEntry* last_uber_entry;
|
||||||
static SHADERUID last_uid;
|
static SHADERUID last_uid;
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/Atomic.h"
|
#include "Common/Atomic.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/GL/GLInterfaceBase.h"
|
#include "Common/GL/GLInterfaceBase.h"
|
||||||
@ -27,11 +28,14 @@
|
|||||||
|
|
||||||
#include "VideoBackends/OGL/BoundingBox.h"
|
#include "VideoBackends/OGL/BoundingBox.h"
|
||||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||||
|
#include "VideoBackends/OGL/OGLPipeline.h"
|
||||||
|
#include "VideoBackends/OGL/OGLShader.h"
|
||||||
#include "VideoBackends/OGL/OGLTexture.h"
|
#include "VideoBackends/OGL/OGLTexture.h"
|
||||||
#include "VideoBackends/OGL/PostProcessing.h"
|
#include "VideoBackends/OGL/PostProcessing.h"
|
||||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||||
#include "VideoBackends/OGL/RasterFont.h"
|
#include "VideoBackends/OGL/RasterFont.h"
|
||||||
#include "VideoBackends/OGL/SamplerCache.h"
|
#include "VideoBackends/OGL/SamplerCache.h"
|
||||||
|
#include "VideoBackends/OGL/StreamBuffer.h"
|
||||||
#include "VideoBackends/OGL/TextureCache.h"
|
#include "VideoBackends/OGL/TextureCache.h"
|
||||||
#include "VideoBackends/OGL/VertexManager.h"
|
#include "VideoBackends/OGL/VertexManager.h"
|
||||||
|
|
||||||
@ -847,6 +851,23 @@ void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
|||||||
m_backbuffer_width, m_backbuffer_height, color);
|
m_backbuffer_width, m_backbuffer_height, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
|
const char* source, size_t length)
|
||||||
|
{
|
||||||
|
return OGLShader::CreateFromSource(stage, source, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
const void* data, size_t length)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
return OGLPipeline::Create(config);
|
||||||
|
}
|
||||||
|
|
||||||
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
|
||||||
{
|
{
|
||||||
TargetRectangle result;
|
TargetRectangle result;
|
||||||
@ -1217,7 +1238,7 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetBlendingState(const BlendingState& state)
|
void Renderer::ApplyBlendingState(const BlendingState& state)
|
||||||
{
|
{
|
||||||
bool useDualSource =
|
bool useDualSource =
|
||||||
state.usedualsrc && g_ActiveConfig.backend_info.bSupportsDualSourceBlend &&
|
state.usedualsrc && g_ActiveConfig.backend_info.bSupportsDualSourceBlend &&
|
||||||
@ -1491,7 +1512,7 @@ void Renderer::RestoreAPIState()
|
|||||||
BPFunctions::SetBlendMode();
|
BPFunctions::SetBlendMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetRasterizationState(const RasterizationState& state)
|
void Renderer::ApplyRasterizationState(const RasterizationState& state)
|
||||||
{
|
{
|
||||||
// none, ccw, cw, ccw
|
// none, ccw, cw, ccw
|
||||||
if (state.cullmode != GenMode::CULL_NONE)
|
if (state.cullmode != GenMode::CULL_NONE)
|
||||||
@ -1506,7 +1527,7 @@ void Renderer::SetRasterizationState(const RasterizationState& state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::SetDepthState(const DepthState& state)
|
void Renderer::ApplyDepthState(const DepthState& state)
|
||||||
{
|
{
|
||||||
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
|
const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
|
||||||
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
|
GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS};
|
||||||
@ -1527,6 +1548,33 @@ void Renderer::SetDepthState(const DepthState& state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::SetRasterizationState(const RasterizationState& state)
|
||||||
|
{
|
||||||
|
ApplyRasterizationState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::SetDepthState(const DepthState& state)
|
||||||
|
{
|
||||||
|
ApplyDepthState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::SetBlendingState(const BlendingState& state)
|
||||||
|
{
|
||||||
|
ApplyBlendingState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
||||||
|
{
|
||||||
|
// Not all shader changes currently go through SetPipeline, so we can't
|
||||||
|
// test if the pipeline hasn't changed and skip these applications. Yet.
|
||||||
|
m_graphics_pipeline = static_cast<const OGLPipeline*>(pipeline);
|
||||||
|
ApplyRasterizationState(m_graphics_pipeline->GetRasterizationState());
|
||||||
|
ApplyDepthState(m_graphics_pipeline->GetDepthState());
|
||||||
|
ApplyBlendingState(m_graphics_pipeline->GetBlendingState());
|
||||||
|
ProgramShaderCache::BindVertexFormat(m_graphics_pipeline->GetVertexFormat());
|
||||||
|
m_graphics_pipeline->GetProgram()->shader.Bind();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
|
void Renderer::SetTexture(u32 index, const AbstractTexture* texture)
|
||||||
{
|
{
|
||||||
if (m_bound_textures[index] == texture)
|
if (m_bound_textures[index] == texture)
|
||||||
@ -1559,4 +1607,52 @@ void Renderer::SetInterlacingMode()
|
|||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
|
||||||
|
u32 vertex_stride, u32 num_vertices)
|
||||||
|
{
|
||||||
|
// Copy in uniforms.
|
||||||
|
if (uniforms_size > 0)
|
||||||
|
UploadUtilityUniforms(uniforms, uniforms_size);
|
||||||
|
|
||||||
|
// Draw from base index if there is vertex data.
|
||||||
|
if (vertices)
|
||||||
|
{
|
||||||
|
StreamBuffer* vbuf = static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBuffer();
|
||||||
|
auto buf = vbuf->Map(vertex_stride * num_vertices, vertex_stride);
|
||||||
|
std::memcpy(buf.first, vertices, vertex_stride * num_vertices);
|
||||||
|
vbuf->Unmap(vertex_stride * num_vertices);
|
||||||
|
glDrawArrays(m_graphics_pipeline->GetGLPrimitive(), buf.second / vertex_stride, num_vertices);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glDrawArrays(m_graphics_pipeline->GetGLPrimitive(), 0, num_vertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size)
|
||||||
|
{
|
||||||
|
_dbg_assert_(VIDEO, uniforms_size > 0);
|
||||||
|
|
||||||
|
auto buf = ProgramShaderCache::GetUniformBuffer()->Map(
|
||||||
|
uniforms_size, ProgramShaderCache::GetUniformBufferAlignment());
|
||||||
|
std::memcpy(buf.first, uniforms, uniforms_size);
|
||||||
|
ProgramShaderCache::GetUniformBuffer()->Unmap(uniforms_size);
|
||||||
|
glBindBufferRange(GL_UNIFORM_BUFFER, 1, ProgramShaderCache::GetUniformBuffer()->m_buffer,
|
||||||
|
buf.second, uniforms_size);
|
||||||
|
|
||||||
|
// This is rather horrible, but because of how the UBOs are bound, this forces it to rebind.
|
||||||
|
ProgramShaderCache::InvalidateConstants();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms,
|
||||||
|
u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||||
|
{
|
||||||
|
glUseProgram(static_cast<const OGLShader*>(shader)->GetGLComputeProgramID());
|
||||||
|
if (uniforms_size > 0)
|
||||||
|
UploadUtilityUniforms(uniforms, uniforms_size);
|
||||||
|
|
||||||
|
glDispatchCompute(groups_x, groups_y, groups_z);
|
||||||
|
ProgramShaderCache::InvalidateLastProgram();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ struct XFBSourceBase;
|
|||||||
|
|
||||||
namespace OGL
|
namespace OGL
|
||||||
{
|
{
|
||||||
|
class OGLPipeline;
|
||||||
void ClearEFBCache();
|
void ClearEFBCache();
|
||||||
|
|
||||||
enum GlslVersion
|
enum GlslVersion
|
||||||
@ -89,7 +90,13 @@ public:
|
|||||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
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 SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
@ -121,6 +128,12 @@ public:
|
|||||||
|
|
||||||
void ReinterpretPixelData(unsigned int convtype) override;
|
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:
|
private:
|
||||||
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
|
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
|
||||||
const TargetRectangle& targetPixelRc, const void* data);
|
const TargetRectangle& targetPixelRc, const void* data);
|
||||||
@ -134,6 +147,12 @@ private:
|
|||||||
void CheckForSurfaceChange();
|
void CheckForSurfaceChange();
|
||||||
void CheckForSurfaceResize();
|
void CheckForSurfaceResize();
|
||||||
|
|
||||||
|
void ApplyBlendingState(const BlendingState& state);
|
||||||
|
void ApplyRasterizationState(const RasterizationState& state);
|
||||||
|
void ApplyDepthState(const DepthState& state);
|
||||||
|
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);
|
||||||
|
|
||||||
std::array<const AbstractTexture*, 8> m_bound_textures{};
|
std::array<const AbstractTexture*, 8> m_bound_textures{};
|
||||||
|
const OGLPipeline* m_graphics_pipeline = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,16 @@ void VertexManager::DestroyDeviceObjects()
|
|||||||
s_indexBuffer.reset();
|
s_indexBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StreamBuffer* VertexManager::GetVertexBuffer() const
|
||||||
|
{
|
||||||
|
return s_vertexBuffer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
OGL::StreamBuffer* VertexManager::GetIndexBuffer() const
|
||||||
|
{
|
||||||
|
return s_indexBuffer.get();
|
||||||
|
}
|
||||||
|
|
||||||
GLuint VertexManager::GetVertexBufferHandle() const
|
GLuint VertexManager::GetVertexBufferHandle() const
|
||||||
{
|
{
|
||||||
return m_vertex_buffers;
|
return m_vertex_buffers;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
namespace OGL
|
namespace OGL
|
||||||
{
|
{
|
||||||
|
class StreamBuffer;
|
||||||
class GLVertexFormat : public NativeVertexFormat
|
class GLVertexFormat : public NativeVertexFormat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -37,6 +38,8 @@ public:
|
|||||||
void CreateDeviceObjects() override;
|
void CreateDeviceObjects() override;
|
||||||
void DestroyDeviceObjects() override;
|
void DestroyDeviceObjects() override;
|
||||||
|
|
||||||
|
StreamBuffer* GetVertexBuffer() const;
|
||||||
|
StreamBuffer* GetIndexBuffer() const;
|
||||||
GLuint GetVertexBufferHandle() const;
|
GLuint GetVertexBufferHandle() const;
|
||||||
GLuint GetIndexBufferHandle() const;
|
GLuint GetIndexBufferHandle() const;
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include "VideoBackends/Software/SWOGLWindow.h"
|
#include "VideoBackends/Software/SWOGLWindow.h"
|
||||||
#include "VideoBackends/Software/SWTexture.h"
|
#include "VideoBackends/Software/SWTexture.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
|
#include "VideoCommon/AbstractShader.h"
|
||||||
#include "VideoCommon/BoundingBox.h"
|
#include "VideoCommon/BoundingBox.h"
|
||||||
#include "VideoCommon/OnScreenDisplay.h"
|
#include "VideoCommon/OnScreenDisplay.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
@ -42,6 +44,40 @@ void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 colo
|
|||||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SWShader final : public AbstractShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SWShader(ShaderStage stage) : AbstractShader(stage) {}
|
||||||
|
~SWShader() = default;
|
||||||
|
|
||||||
|
bool HasBinary() const override { return false; }
|
||||||
|
BinaryData GetBinary() const override { return {}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
SWRenderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length)
|
||||||
|
{
|
||||||
|
return std::make_unique<SWShader>(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> SWRenderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
const void* data, size_t length)
|
||||||
|
{
|
||||||
|
return std::make_unique<SWShader>(stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SWPipeline final : public AbstractPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SWPipeline() : AbstractPipeline() {}
|
||||||
|
~SWPipeline() override = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractPipeline> SWRenderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
return std::make_unique<SWPipeline>();
|
||||||
|
}
|
||||||
|
|
||||||
// Called on the GPU thread
|
// Called on the GPU thread
|
||||||
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region, u64 ticks,
|
||||||
float Gamma)
|
float Gamma)
|
||||||
|
@ -17,6 +17,12 @@ public:
|
|||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
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 RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
||||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
||||||
|
@ -19,6 +19,8 @@ set(SRCS
|
|||||||
Util.cpp
|
Util.cpp
|
||||||
VertexFormat.cpp
|
VertexFormat.cpp
|
||||||
VertexManager.cpp
|
VertexManager.cpp
|
||||||
|
VKPipeline.cpp
|
||||||
|
VKShader.cpp
|
||||||
VKTexture.cpp
|
VKTexture.cpp
|
||||||
VulkanContext.cpp
|
VulkanContext.cpp
|
||||||
VulkanLoader.cpp
|
VulkanLoader.cpp
|
||||||
|
@ -26,7 +26,8 @@ enum STAGING_BUFFER_TYPE
|
|||||||
// Descriptor set layouts
|
// Descriptor set layouts
|
||||||
enum DESCRIPTOR_SET_LAYOUT
|
enum DESCRIPTOR_SET_LAYOUT
|
||||||
{
|
{
|
||||||
DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS,
|
DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER,
|
||||||
|
DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS,
|
||||||
DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS,
|
DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS,
|
||||||
DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS,
|
DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS,
|
||||||
DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS,
|
DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS,
|
||||||
@ -69,6 +70,7 @@ enum PIPELINE_LAYOUT
|
|||||||
PIPELINE_LAYOUT_BBOX,
|
PIPELINE_LAYOUT_BBOX,
|
||||||
PIPELINE_LAYOUT_PUSH_CONSTANT,
|
PIPELINE_LAYOUT_PUSH_CONSTANT,
|
||||||
PIPELINE_LAYOUT_TEXTURE_CONVERSION,
|
PIPELINE_LAYOUT_TEXTURE_CONVERSION,
|
||||||
|
PIPELINE_LAYOUT_UTILITY,
|
||||||
PIPELINE_LAYOUT_COMPUTE,
|
PIPELINE_LAYOUT_COMPUTE,
|
||||||
NUM_PIPELINE_LAYOUTS
|
NUM_PIPELINE_LAYOUTS
|
||||||
};
|
};
|
||||||
@ -128,7 +130,7 @@ constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10;
|
|||||||
union MultisamplingState
|
union MultisamplingState
|
||||||
{
|
{
|
||||||
BitField<0, 5, u32> samples; // 1-16
|
BitField<0, 5, u32> samples; // 1-16
|
||||||
BitField<0, 1, u32> per_sample_shading; // SSAA
|
BitField<5, 1, u32> per_sample_shading; // SSAA
|
||||||
u32 hex;
|
u32 hex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +106,10 @@ void ObjectCache::DestroySamplers()
|
|||||||
|
|
||||||
bool ObjectCache::CreateDescriptorSetLayouts()
|
bool ObjectCache::CreateDescriptorSetLayouts()
|
||||||
{
|
{
|
||||||
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
static const VkDescriptorSetLayoutBinding single_ubo_set_bindings[] = {
|
||||||
|
0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT};
|
||||||
|
static const VkDescriptorSetLayoutBinding per_stage_ubo_set_bindings[] = {
|
||||||
{UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
{UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||||
VK_SHADER_STAGE_FRAGMENT_BIT},
|
VK_SHADER_STAGE_FRAGMENT_BIT},
|
||||||
{UBO_DESCRIPTOR_SET_BINDING_VS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
{UBO_DESCRIPTOR_SET_BINDING_VS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1,
|
||||||
@ -138,7 +141,9 @@ bool ObjectCache::CreateDescriptorSetLayouts()
|
|||||||
|
|
||||||
static const VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = {
|
static const VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = {
|
||||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
static_cast<u32>(ArraySize(ubo_set_bindings)), ubo_set_bindings},
|
static_cast<u32>(ArraySize(single_ubo_set_bindings)), single_ubo_set_bindings},
|
||||||
|
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
|
static_cast<u32>(ArraySize(per_stage_ubo_set_bindings)), per_stage_ubo_set_bindings},
|
||||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
static_cast<u32>(ArraySize(sampler_set_bindings)), sampler_set_bindings},
|
static_cast<u32>(ArraySize(sampler_set_bindings)), sampler_set_bindings},
|
||||||
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
@ -177,16 +182,19 @@ bool ObjectCache::CreatePipelineLayouts()
|
|||||||
|
|
||||||
// Descriptor sets for each pipeline layout
|
// Descriptor sets for each pipeline layout
|
||||||
VkDescriptorSetLayout standard_sets[] = {
|
VkDescriptorSetLayout standard_sets[] = {
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
||||||
VkDescriptorSetLayout bbox_sets[] = {
|
VkDescriptorSetLayout bbox_sets[] = {
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS]};
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS]};
|
||||||
VkDescriptorSetLayout texture_conversion_sets[] = {
|
VkDescriptorSetLayout texture_conversion_sets[] = {
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS],
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS],
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS],
|
||||||
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS]};
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_TEXEL_BUFFERS]};
|
||||||
|
VkDescriptorSetLayout utility_sets[] = {
|
||||||
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER],
|
||||||
|
m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]};
|
||||||
VkDescriptorSetLayout compute_sets[] = {m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_COMPUTE]};
|
VkDescriptorSetLayout compute_sets[] = {m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_COMPUTE]};
|
||||||
VkPushConstantRange push_constant_range = {
|
VkPushConstantRange push_constant_range = {
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, PUSH_CONSTANT_BUFFER_SIZE};
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, PUSH_CONSTANT_BUFFER_SIZE};
|
||||||
@ -212,6 +220,10 @@ bool ObjectCache::CreatePipelineLayouts()
|
|||||||
static_cast<u32>(ArraySize(texture_conversion_sets)), texture_conversion_sets, 1,
|
static_cast<u32>(ArraySize(texture_conversion_sets)), texture_conversion_sets, 1,
|
||||||
&push_constant_range},
|
&push_constant_range},
|
||||||
|
|
||||||
|
// Texture Conversion
|
||||||
|
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
|
static_cast<u32>(ArraySize(utility_sets)), utility_sets, 0, nullptr},
|
||||||
|
|
||||||
// Compute
|
// Compute
|
||||||
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0,
|
||||||
static_cast<u32>(ArraySize(compute_sets)), compute_sets, 1, &compute_push_constant_range}};
|
static_cast<u32>(ArraySize(compute_sets)), compute_sets, 1, &compute_push_constant_range}};
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@ -23,9 +24,12 @@
|
|||||||
#include "VideoBackends/Vulkan/RasterFont.h"
|
#include "VideoBackends/Vulkan/RasterFont.h"
|
||||||
#include "VideoBackends/Vulkan/Renderer.h"
|
#include "VideoBackends/Vulkan/Renderer.h"
|
||||||
#include "VideoBackends/Vulkan/StateTracker.h"
|
#include "VideoBackends/Vulkan/StateTracker.h"
|
||||||
|
#include "VideoBackends/Vulkan/StreamBuffer.h"
|
||||||
#include "VideoBackends/Vulkan/SwapChain.h"
|
#include "VideoBackends/Vulkan/SwapChain.h"
|
||||||
#include "VideoBackends/Vulkan/TextureCache.h"
|
#include "VideoBackends/Vulkan/TextureCache.h"
|
||||||
#include "VideoBackends/Vulkan/Util.h"
|
#include "VideoBackends/Vulkan/Util.h"
|
||||||
|
#include "VideoBackends/Vulkan/VKPipeline.h"
|
||||||
|
#include "VideoBackends/Vulkan/VKShader.h"
|
||||||
#include "VideoBackends/Vulkan/VKTexture.h"
|
#include "VideoBackends/Vulkan/VKTexture.h"
|
||||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
|
|
||||||
@ -171,6 +175,202 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe
|
|||||||
return VKStagingTexture::Create(type, config);
|
return VKStagingTexture::Create(type, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage,
|
||||||
|
const char* source, size_t length)
|
||||||
|
{
|
||||||
|
return VKShader::CreateFromSource(stage, source, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage,
|
||||||
|
const void* data, size_t length)
|
||||||
|
{
|
||||||
|
return VKShader::CreateFromBinary(stage, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
return VKPipeline::Create(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* uniforms,
|
||||||
|
u32 uniforms_size)
|
||||||
|
{
|
||||||
|
StreamBuffer* ubo_buf = g_object_cache->GetUtilityShaderUniformBuffer();
|
||||||
|
if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment()))
|
||||||
|
{
|
||||||
|
Util::ExecuteCurrentCommandsAndRestoreState(false, true);
|
||||||
|
if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment()))
|
||||||
|
{
|
||||||
|
PanicAlert("Failed to reserve uniform buffer space for utility draw.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBuffer ubo = ubo_buf->GetBuffer();
|
||||||
|
u32 ubo_offset = static_cast<u32>(ubo_buf->GetCurrentOffset());
|
||||||
|
std::memcpy(ubo_buf->GetCurrentHostPointer(), uniforms, uniforms_size);
|
||||||
|
ubo_buf->CommitMemory(uniforms_size);
|
||||||
|
|
||||||
|
return std::tie(ubo, ubo_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::SetPipeline(const AbstractPipeline* pipeline)
|
||||||
|
{
|
||||||
|
m_graphics_pipeline = static_cast<const VKPipeline*>(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
|
||||||
|
u32 vertex_stride, u32 num_vertices)
|
||||||
|
{
|
||||||
|
// Binding the utility pipeline layout breaks the standard layout.
|
||||||
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
|
|
||||||
|
// Upload uniforms.
|
||||||
|
VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
|
||||||
|
u32 uniform_buffer_offset = 0;
|
||||||
|
if (uniforms_size > 0)
|
||||||
|
std::tie(uniform_buffer, uniform_buffer_offset) =
|
||||||
|
UpdateUtilityUniformBuffer(uniforms, uniforms_size);
|
||||||
|
|
||||||
|
// Upload vertices.
|
||||||
|
VkBuffer vertex_buffer = VK_NULL_HANDLE;
|
||||||
|
VkDeviceSize vertex_buffer_offset = 0;
|
||||||
|
if (vertices)
|
||||||
|
{
|
||||||
|
u32 vertices_size = vertex_stride * num_vertices;
|
||||||
|
StreamBuffer* vbo_buf = g_object_cache->GetUtilityShaderVertexBuffer();
|
||||||
|
if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride))
|
||||||
|
{
|
||||||
|
Util::ExecuteCurrentCommandsAndRestoreState(true);
|
||||||
|
if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride))
|
||||||
|
{
|
||||||
|
PanicAlert("Failed to reserve vertex buffer space for utility draw.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex_buffer = vbo_buf->GetBuffer();
|
||||||
|
vertex_buffer_offset = vbo_buf->GetCurrentOffset();
|
||||||
|
std::memcpy(vbo_buf->GetCurrentHostPointer(), vertices, vertices_size);
|
||||||
|
vbo_buf->CommitMemory(vertices_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate descriptor sets.
|
||||||
|
std::array<VkDescriptorSet, 2> dsets;
|
||||||
|
dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER));
|
||||||
|
dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS));
|
||||||
|
|
||||||
|
// Flush first if failed.
|
||||||
|
if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
Util::ExecuteCurrentCommandsAndRestoreState(true);
|
||||||
|
dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER));
|
||||||
|
dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS));
|
||||||
|
|
||||||
|
if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
PanicAlert("Failed to allocate descriptor sets in utility draw.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build UBO descriptor set.
|
||||||
|
std::array<VkWriteDescriptorSet, 2> dswrites;
|
||||||
|
VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)};
|
||||||
|
dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dsets[0], 0, 0, 1,
|
||||||
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr};
|
||||||
|
dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
nullptr,
|
||||||
|
dsets[1],
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NUM_PIXEL_SHADER_SAMPLERS,
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
StateTracker::GetInstance()->GetPSSamplerBindings().data(),
|
||||||
|
nullptr,
|
||||||
|
nullptr};
|
||||||
|
|
||||||
|
// Build commands.
|
||||||
|
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
||||||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
m_graphics_pipeline->GetPipeline());
|
||||||
|
if (vertex_buffer != VK_NULL_HANDLE)
|
||||||
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset);
|
||||||
|
|
||||||
|
// Update and bind descriptors.
|
||||||
|
VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
|
||||||
|
vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<u32>(dswrites.size()),
|
||||||
|
dswrites.data(), 0, nullptr);
|
||||||
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0,
|
||||||
|
static_cast<u32>(dsets.size()), dsets.data(), 1, &uniform_buffer_offset);
|
||||||
|
|
||||||
|
// Ensure we're in a render pass before drawing, just in case we had to flush.
|
||||||
|
StateTracker::GetInstance()->BeginRenderPass();
|
||||||
|
vkCmdDraw(command_buffer, num_vertices, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms,
|
||||||
|
u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||||
|
{
|
||||||
|
// Binding the utility pipeline layout breaks the standard layout.
|
||||||
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
|
StateTracker::GetInstance()->EndRenderPass();
|
||||||
|
|
||||||
|
// Upload uniforms.
|
||||||
|
VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
|
||||||
|
u32 uniform_buffer_offset = 0;
|
||||||
|
if (uniforms_size > 0)
|
||||||
|
std::tie(uniform_buffer, uniform_buffer_offset) =
|
||||||
|
UpdateUtilityUniformBuffer(uniforms, uniforms_size);
|
||||||
|
|
||||||
|
// Flush first if failed.
|
||||||
|
VkDescriptorSet dset = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE));
|
||||||
|
if (dset == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
Util::ExecuteCurrentCommandsAndRestoreState(true);
|
||||||
|
dset = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE));
|
||||||
|
if (dset == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
PanicAlert("Failed to allocate descriptor sets in utility dispatch.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkWriteDescriptorSet, 2> dswrites;
|
||||||
|
VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)};
|
||||||
|
dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dset, 0, 0, 1,
|
||||||
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr};
|
||||||
|
dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
nullptr,
|
||||||
|
dset,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
NUM_PIXEL_SHADER_SAMPLERS,
|
||||||
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
StateTracker::GetInstance()->GetPSSamplerBindings().data(),
|
||||||
|
nullptr,
|
||||||
|
nullptr};
|
||||||
|
|
||||||
|
// TODO: Texel buffers, storage images.
|
||||||
|
|
||||||
|
// Build commands.
|
||||||
|
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
||||||
|
VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
|
||||||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
|
static_cast<const VKShader*>(shader)->GetComputePipeline());
|
||||||
|
vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<u32>(dswrites.size()),
|
||||||
|
dswrites.data(), 0, nullptr);
|
||||||
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1,
|
||||||
|
&dset, 1, &uniform_buffer_offset);
|
||||||
|
vkCmdDispatch(command_buffer, groups_x, groups_y, groups_z);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||||
{
|
{
|
||||||
u32 backbuffer_width = m_swap_chain->GetWidth();
|
u32 backbuffer_width = m_swap_chain->GetWidth();
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoBackends/Vulkan/Constants.h"
|
#include "VideoBackends/Vulkan/Constants.h"
|
||||||
@ -22,6 +23,7 @@ class SwapChain;
|
|||||||
class StagingTexture2D;
|
class StagingTexture2D;
|
||||||
class Texture2D;
|
class Texture2D;
|
||||||
class RasterFont;
|
class RasterFont;
|
||||||
|
class VKPipeline;
|
||||||
class VKTexture;
|
class VKTexture;
|
||||||
|
|
||||||
class Renderer : public ::Renderer
|
class Renderer : public ::Renderer
|
||||||
@ -36,6 +38,12 @@ public:
|
|||||||
std::unique_ptr<AbstractStagingTexture>
|
std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
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;
|
||||||
|
|
||||||
SwapChain* GetSwapChain() const { return m_swap_chain.get(); }
|
SwapChain* GetSwapChain() const { return m_swap_chain.get(); }
|
||||||
BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); }
|
BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); }
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
@ -59,6 +67,7 @@ public:
|
|||||||
void ResetAPIState() override;
|
void ResetAPIState() override;
|
||||||
void RestoreAPIState() override;
|
void RestoreAPIState() override;
|
||||||
|
|
||||||
|
void SetPipeline(const AbstractPipeline* pipeline) override;
|
||||||
void SetBlendingState(const BlendingState& state) override;
|
void SetBlendingState(const BlendingState& state) override;
|
||||||
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
void SetScissorRect(const MathUtil::Rectangle<int>& rc) override;
|
||||||
void SetRasterizationState(const RasterizationState& state) override;
|
void SetRasterizationState(const RasterizationState& state) override;
|
||||||
@ -70,6 +79,11 @@ public:
|
|||||||
void SetViewport(float x, float y, float width, float height, float near_depth,
|
void SetViewport(float x, float y, float width, float height, float near_depth,
|
||||||
float far_depth) override;
|
float far_depth) 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:
|
private:
|
||||||
bool CreateSemaphores();
|
bool CreateSemaphores();
|
||||||
void DestroySemaphores();
|
void DestroySemaphores();
|
||||||
@ -97,6 +111,8 @@ private:
|
|||||||
void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect,
|
void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect,
|
||||||
const TargetRectangle& src_rect, const Texture2D* src_tex);
|
const TargetRectangle& src_rect, const Texture2D* src_tex);
|
||||||
|
|
||||||
|
std::tuple<VkBuffer, u32> UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size);
|
||||||
|
|
||||||
VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE;
|
VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE;
|
||||||
VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE;
|
VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE;
|
||||||
|
|
||||||
@ -109,5 +125,6 @@ private:
|
|||||||
|
|
||||||
// Shaders used for clear/blit.
|
// Shaders used for clear/blit.
|
||||||
VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE;
|
VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE;
|
||||||
|
const VKPipeline* m_graphics_pipeline = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1043,7 +1043,7 @@ bool StateTracker::UpdateDescriptorSet()
|
|||||||
m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS] == VK_NULL_HANDLE)
|
m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS] == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayout layout =
|
VkDescriptorSetLayout layout =
|
||||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS);
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS);
|
||||||
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(layout);
|
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(layout);
|
||||||
if (set == VK_NULL_HANDLE)
|
if (set == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,6 +41,10 @@ public:
|
|||||||
}
|
}
|
||||||
const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; }
|
const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; }
|
||||||
const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; }
|
const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; }
|
||||||
|
const std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS>& GetPSSamplerBindings() const
|
||||||
|
{
|
||||||
|
return m_bindings.ps_samplers;
|
||||||
|
}
|
||||||
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset);
|
||||||
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type);
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ void UtilityShaderDraw::BindDescriptors()
|
|||||||
if (m_vs_uniform_buffer.buffer != VK_NULL_HANDLE || m_ps_uniform_buffer.buffer != VK_NULL_HANDLE)
|
if (m_vs_uniform_buffer.buffer != VK_NULL_HANDLE || m_ps_uniform_buffer.buffer != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(
|
VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(
|
||||||
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS));
|
g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS));
|
||||||
if (set == VK_NULL_HANDLE)
|
if (set == VK_NULL_HANDLE)
|
||||||
PanicAlert("Failed to allocate descriptor set for utility draw");
|
PanicAlert("Failed to allocate descriptor set for utility draw");
|
||||||
|
|
||||||
@ -595,7 +595,7 @@ void UtilityShaderDraw::BindDescriptors()
|
|||||||
&dummy_uniform_buffer,
|
&dummy_uniform_buffer,
|
||||||
nullptr};
|
nullptr};
|
||||||
|
|
||||||
bind_descriptor_sets[DESCRIPTOR_SET_LAYOUT_UNIFORM_BUFFERS] = set;
|
bind_descriptor_sets[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS] = set;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PS samplers
|
// PS samplers
|
||||||
|
73
Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
Normal file
73
Source/Core/VideoBackends/Vulkan/VKPipeline.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
|
|
||||||
|
#include "VideoBackends/Vulkan/ObjectCache.h"
|
||||||
|
#include "VideoBackends/Vulkan/Util.h"
|
||||||
|
#include "VideoBackends/Vulkan/VKPipeline.h"
|
||||||
|
#include "VideoBackends/Vulkan/VKShader.h"
|
||||||
|
#include "VideoBackends/Vulkan/VertexFormat.h"
|
||||||
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
|
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
VKPipeline::VKPipeline(VkPipeline pipeline) : m_pipeline(pipeline)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VKPipeline::~VKPipeline()
|
||||||
|
{
|
||||||
|
vkDestroyPipeline(g_vulkan_context->GetDevice(), m_pipeline, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VKPipeline> VKPipeline::Create(const AbstractPipelineConfig& config)
|
||||||
|
{
|
||||||
|
_dbg_assert_(VIDEO, config.vertex_shader && config.pixel_shader);
|
||||||
|
|
||||||
|
// Get render pass for config.
|
||||||
|
VkRenderPass render_pass = g_object_cache->GetRenderPass(
|
||||||
|
Util::GetVkFormatForHostTextureFormat(config.framebuffer_state.color_texture_format),
|
||||||
|
VK_FORMAT_UNDEFINED, config.framebuffer_state.samples, VK_ATTACHMENT_LOAD_OP_LOAD);
|
||||||
|
|
||||||
|
// Get pipeline layout.
|
||||||
|
VkPipelineLayout pipeline_layout;
|
||||||
|
switch (config.usage)
|
||||||
|
{
|
||||||
|
case AbstractPipelineUsage::GX:
|
||||||
|
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD);
|
||||||
|
break;
|
||||||
|
case AbstractPipelineUsage::Utility:
|
||||||
|
pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PanicAlert("Unknown pipeline layout.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Move ShaderCache stuff to here.
|
||||||
|
PipelineInfo pinfo;
|
||||||
|
pinfo.vertex_format = static_cast<const VertexFormat*>(config.vertex_format);
|
||||||
|
pinfo.pipeline_layout = pipeline_layout;
|
||||||
|
pinfo.vs = static_cast<const VKShader*>(config.vertex_shader)->GetShaderModule();
|
||||||
|
pinfo.ps = static_cast<const VKShader*>(config.pixel_shader)->GetShaderModule();
|
||||||
|
pinfo.gs = config.geometry_shader ?
|
||||||
|
static_cast<const VKShader*>(config.geometry_shader)->GetShaderModule() :
|
||||||
|
VK_NULL_HANDLE;
|
||||||
|
pinfo.render_pass = render_pass;
|
||||||
|
pinfo.rasterization_state.hex = config.rasterization_state.hex;
|
||||||
|
pinfo.depth_state.hex = config.depth_state.hex;
|
||||||
|
pinfo.blend_state.hex = config.blending_state.hex;
|
||||||
|
pinfo.multisampling_state.hex = 0;
|
||||||
|
pinfo.multisampling_state.samples = config.framebuffer_state.samples;
|
||||||
|
pinfo.multisampling_state.per_sample_shading = config.framebuffer_state.per_sample_shading;
|
||||||
|
|
||||||
|
VkPipeline pipeline = g_shader_cache->CreatePipeline(pinfo);
|
||||||
|
if (pipeline == VK_NULL_HANDLE)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return std::make_unique<VKPipeline>(pipeline);
|
||||||
|
}
|
||||||
|
} // namespace Vulkan
|
27
Source/Core/VideoBackends/Vulkan/VKPipeline.h
Normal file
27
Source/Core/VideoBackends/Vulkan/VKPipeline.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||||
|
#include "VideoCommon/AbstractPipeline.h"
|
||||||
|
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
class VKPipeline final : public AbstractPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit VKPipeline(VkPipeline pipeline);
|
||||||
|
~VKPipeline() override;
|
||||||
|
|
||||||
|
VkPipeline GetPipeline() const { return m_pipeline; }
|
||||||
|
static std::unique_ptr<VKPipeline> Create(const AbstractPipelineConfig& config);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPipeline m_pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
124
Source/Core/VideoBackends/Vulkan/VKShader.cpp
Normal file
124
Source/Core/VideoBackends/Vulkan/VKShader.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
|
|
||||||
|
#include "VideoBackends/Vulkan/ShaderCompiler.h"
|
||||||
|
#include "VideoBackends/Vulkan/Util.h"
|
||||||
|
#include "VideoBackends/Vulkan/VKShader.h"
|
||||||
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
|
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
VKShader::VKShader(ShaderStage stage, std::vector<u32> spv, VkShaderModule mod)
|
||||||
|
: AbstractShader(stage), m_spv(std::move(spv)), m_module(mod),
|
||||||
|
m_compute_pipeline(VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VKShader::VKShader(std::vector<u32> spv, VkPipeline compute_pipeline)
|
||||||
|
: AbstractShader(ShaderStage::Compute), m_spv(std::move(spv)), m_module(VK_NULL_HANDLE),
|
||||||
|
m_compute_pipeline(compute_pipeline)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VKShader::~VKShader()
|
||||||
|
{
|
||||||
|
if (m_stage != ShaderStage::Compute)
|
||||||
|
vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_module, nullptr);
|
||||||
|
else
|
||||||
|
vkDestroyPipeline(g_vulkan_context->GetDevice(), m_compute_pipeline, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VKShader::HasBinary() const
|
||||||
|
{
|
||||||
|
_assert_(!m_spv.empty());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractShader::BinaryData VKShader::GetBinary() const
|
||||||
|
{
|
||||||
|
BinaryData ret(sizeof(u32) * m_spv.size());
|
||||||
|
std::memcpy(ret.data(), m_spv.data(), sizeof(u32) * m_spv.size());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<VKShader> CreateShaderObject(ShaderStage stage,
|
||||||
|
ShaderCompiler::SPIRVCodeVector spv)
|
||||||
|
{
|
||||||
|
VkShaderModule mod = Util::CreateShaderModule(spv.data(), spv.size());
|
||||||
|
if (mod == VK_NULL_HANDLE)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// If it's a graphics shader, we defer pipeline creation.
|
||||||
|
if (stage != ShaderStage::Compute)
|
||||||
|
return std::make_unique<VKShader>(stage, std::move(spv), mod);
|
||||||
|
|
||||||
|
// If it's a compute shader, we create the pipeline straight away.
|
||||||
|
ComputePipelineInfo pinfo;
|
||||||
|
pinfo.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_COMPUTE);
|
||||||
|
pinfo.cs = mod;
|
||||||
|
VkPipeline pipeline = g_shader_cache->CreateComputePipeline(pinfo);
|
||||||
|
if (pipeline == VK_NULL_HANDLE)
|
||||||
|
{
|
||||||
|
vkDestroyShaderModule(g_vulkan_context->GetDevice(), mod, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shader module is no longer needed, now it is compiled to a pipeline.
|
||||||
|
return std::make_unique<VKShader>(std::move(spv), pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VKShader> VKShader::CreateFromSource(ShaderStage stage, const char* source,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
ShaderCompiler::SPIRVCodeVector spv;
|
||||||
|
bool result;
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
|
case ShaderStage::Vertex:
|
||||||
|
result = ShaderCompiler::CompileVertexShader(&spv, source, length);
|
||||||
|
break;
|
||||||
|
case ShaderStage::Geometry:
|
||||||
|
result = ShaderCompiler::CompileGeometryShader(&spv, source, length);
|
||||||
|
break;
|
||||||
|
case ShaderStage::Pixel:
|
||||||
|
result = ShaderCompiler::CompileFragmentShader(&spv, source, length);
|
||||||
|
break;
|
||||||
|
case ShaderStage::Compute:
|
||||||
|
result = ShaderCompiler::CompileComputeShader(&spv, source, length);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return CreateShaderObject(stage, std::move(spv));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<VKShader> VKShader::CreateFromBinary(ShaderStage stage, const void* data,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
ShaderCompiler::SPIRVCodeVector spv;
|
||||||
|
const size_t size_in_words = sizeof(length) / sizeof(ShaderCompiler::SPIRVCodeType);
|
||||||
|
if (size_in_words > 0)
|
||||||
|
{
|
||||||
|
spv.resize(length / size_in_words);
|
||||||
|
std::memcpy(spv.data(), data, size_in_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-aligned code sizes, unlikely (unless using VK_NV_glsl).
|
||||||
|
if ((length % sizeof(ShaderCompiler::SPIRVCodeType)) != 0)
|
||||||
|
{
|
||||||
|
spv.resize(size_in_words + 1);
|
||||||
|
std::memcpy(&spv[size_in_words], data, (length % sizeof(ShaderCompiler::SPIRVCodeType)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateShaderObject(stage, std::move(spv));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
40
Source/Core/VideoBackends/Vulkan/VKShader.h
Normal file
40
Source/Core/VideoBackends/Vulkan/VKShader.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||||
|
#include "VideoCommon/AbstractShader.h"
|
||||||
|
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
|
class VKShader final : public AbstractShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VKShader(ShaderStage stage, std::vector<u32> spv, VkShaderModule mod);
|
||||||
|
VKShader(std::vector<u32> spv, VkPipeline compute_pipeline);
|
||||||
|
~VKShader() override;
|
||||||
|
|
||||||
|
VkShaderModule GetShaderModule() const { return m_module; }
|
||||||
|
VkPipeline GetComputePipeline() const { return m_compute_pipeline; }
|
||||||
|
bool HasBinary() const override;
|
||||||
|
BinaryData GetBinary() const override;
|
||||||
|
|
||||||
|
static std::unique_ptr<VKShader> CreateFromSource(ShaderStage stage, const char* source,
|
||||||
|
size_t length);
|
||||||
|
static std::unique_ptr<VKShader> CreateFromBinary(ShaderStage stage, const void* data,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<u32> m_spv;
|
||||||
|
VkShaderModule m_module;
|
||||||
|
VkPipeline m_compute_pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
@ -57,6 +57,8 @@
|
|||||||
<ClCompile Include="Texture2D.cpp" />
|
<ClCompile Include="Texture2D.cpp" />
|
||||||
<ClCompile Include="TextureCache.cpp" />
|
<ClCompile Include="TextureCache.cpp" />
|
||||||
<ClCompile Include="VertexManager.cpp" />
|
<ClCompile Include="VertexManager.cpp" />
|
||||||
|
<ClCompile Include="VKPipeline.cpp" />
|
||||||
|
<ClCompile Include="VKShader.cpp" />
|
||||||
<ClCompile Include="VKTexture.cpp" />
|
<ClCompile Include="VKTexture.cpp" />
|
||||||
<ClCompile Include="VulkanContext.cpp" />
|
<ClCompile Include="VulkanContext.cpp" />
|
||||||
<ClCompile Include="VulkanLoader.cpp" />
|
<ClCompile Include="VulkanLoader.cpp" />
|
||||||
@ -84,6 +86,8 @@
|
|||||||
<ClInclude Include="TextureCache.h" />
|
<ClInclude Include="TextureCache.h" />
|
||||||
<ClInclude Include="VertexManager.h" />
|
<ClInclude Include="VertexManager.h" />
|
||||||
<ClInclude Include="VideoBackend.h" />
|
<ClInclude Include="VideoBackend.h" />
|
||||||
|
<ClInclude Include="VKPipeline.h" />
|
||||||
|
<ClInclude Include="VKShader.h" />
|
||||||
<ClInclude Include="VKTexture.h" />
|
<ClInclude Include="VKTexture.h" />
|
||||||
<ClInclude Include="VulkanContext.h" />
|
<ClInclude Include="VulkanContext.h" />
|
||||||
<ClInclude Include="VulkanLoader.h" />
|
<ClInclude Include="VulkanLoader.h" />
|
||||||
|
95
Source/Core/VideoCommon/AbstractPipeline.h
Normal file
95
Source/Core/VideoCommon/AbstractPipeline.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoCommon/RenderState.h"
|
||||||
|
#include "VideoCommon/TextureConfig.h"
|
||||||
|
|
||||||
|
class AbstractShader;
|
||||||
|
class NativeVertexFormat;
|
||||||
|
|
||||||
|
// We use three pipeline usages:
|
||||||
|
// - GX
|
||||||
|
// - Per-stage UBO (VS/GS/PS, VS constants accessible from PS)
|
||||||
|
// - 8 combined image samplers (accessible from PS)
|
||||||
|
// - 1 SSBO, accessible from PS if bounding box is enabled
|
||||||
|
// - Utility
|
||||||
|
// - Single UBO, accessible from all stages [set=0, binding=1]
|
||||||
|
// - 8 combined image samplers (accessible from PS) [set=1, binding=0-7]
|
||||||
|
// - 1 texel buffer, accessible from PS [set=2, binding=0]
|
||||||
|
// - Compute
|
||||||
|
// - 1 uniform buffer [set=0, binding=1]
|
||||||
|
// - 8 combined image samplers [set=1, binding=0-7]
|
||||||
|
// - 1 texel buffer [set=2, binding=0]
|
||||||
|
// - 1 storage image [set=3, binding=0]
|
||||||
|
enum class AbstractPipelineUsage
|
||||||
|
{
|
||||||
|
GX,
|
||||||
|
Utility
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbstractPipelineConfig
|
||||||
|
{
|
||||||
|
const NativeVertexFormat* vertex_format;
|
||||||
|
const AbstractShader* vertex_shader;
|
||||||
|
const AbstractShader* geometry_shader;
|
||||||
|
const AbstractShader* pixel_shader;
|
||||||
|
RasterizationState rasterization_state;
|
||||||
|
DepthState depth_state;
|
||||||
|
BlendingState blending_state;
|
||||||
|
|
||||||
|
union FramebufferState
|
||||||
|
{
|
||||||
|
BitField<0, 8, AbstractTextureFormat> color_texture_format;
|
||||||
|
BitField<8, 8, AbstractTextureFormat> depth_texture_format;
|
||||||
|
BitField<16, 8, u32> samples;
|
||||||
|
BitField<24, 1, u32> per_sample_shading;
|
||||||
|
|
||||||
|
bool operator==(const FramebufferState& rhs) const { return hex == rhs.hex; }
|
||||||
|
bool operator!=(const FramebufferState& rhs) const { return hex != rhs.hex; }
|
||||||
|
FramebufferState& operator=(const FramebufferState& rhs)
|
||||||
|
{
|
||||||
|
hex = rhs.hex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 hex;
|
||||||
|
} framebuffer_state;
|
||||||
|
|
||||||
|
AbstractPipelineUsage usage;
|
||||||
|
|
||||||
|
bool operator==(const AbstractPipelineConfig& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(vertex_format, vertex_shader, geometry_shader, pixel_shader,
|
||||||
|
rasterization_state.hex, depth_state.hex, blending_state.hex,
|
||||||
|
framebuffer_state.hex, usage) ==
|
||||||
|
std::tie(rhs.vertex_format, rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader,
|
||||||
|
rhs.rasterization_state.hex, rhs.depth_state.hex, rhs.blending_state.hex,
|
||||||
|
rhs.framebuffer_state.hex, rhs.usage);
|
||||||
|
}
|
||||||
|
bool operator!=(const AbstractPipelineConfig& rhs) const { return !operator==(rhs); }
|
||||||
|
bool operator<(const AbstractPipelineConfig& rhs) const
|
||||||
|
{
|
||||||
|
return std::tie(vertex_format, vertex_shader, geometry_shader, pixel_shader,
|
||||||
|
rasterization_state.hex, depth_state.hex, blending_state.hex,
|
||||||
|
framebuffer_state.hex, usage) <
|
||||||
|
std::tie(rhs.vertex_format, rhs.vertex_shader, rhs.geometry_shader, rhs.pixel_shader,
|
||||||
|
rhs.rasterization_state.hex, rhs.depth_state.hex, rhs.blending_state.hex,
|
||||||
|
rhs.framebuffer_state.hex, rhs.usage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbstractPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractPipeline() = default;
|
||||||
|
virtual ~AbstractPipeline() = default;
|
||||||
|
};
|
34
Source/Core/VideoCommon/AbstractShader.h
Normal file
34
Source/Core/VideoCommon/AbstractShader.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
enum class ShaderStage
|
||||||
|
{
|
||||||
|
Vertex,
|
||||||
|
Geometry,
|
||||||
|
Pixel,
|
||||||
|
Compute
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbstractShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AbstractShader(ShaderStage stage) : m_stage(stage) {}
|
||||||
|
virtual ~AbstractShader() = default;
|
||||||
|
|
||||||
|
ShaderStage GetStage() const { return m_stage; }
|
||||||
|
using BinaryData = std::vector<u8>;
|
||||||
|
virtual bool HasBinary() const = 0;
|
||||||
|
virtual BinaryData GetBinary() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ShaderStage m_stage;
|
||||||
|
};
|
@ -33,10 +33,15 @@
|
|||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
|
|
||||||
class AbstractRawTexture;
|
class AbstractRawTexture;
|
||||||
|
class AbstractPipeline;
|
||||||
|
class AbstractShader;
|
||||||
class AbstractTexture;
|
class AbstractTexture;
|
||||||
class AbstractStagingTexture;
|
class AbstractStagingTexture;
|
||||||
class PostProcessingShaderImplementation;
|
class PostProcessingShaderImplementation;
|
||||||
struct TextureConfig;
|
struct TextureConfig;
|
||||||
|
struct ComputePipelineConfig;
|
||||||
|
struct AbstractPipelineConfig;
|
||||||
|
enum class ShaderStage;
|
||||||
enum class EFBAccessType;
|
enum class EFBAccessType;
|
||||||
enum class StagingTextureType;
|
enum class StagingTextureType;
|
||||||
|
|
||||||
@ -69,6 +74,7 @@ public:
|
|||||||
PP_EFB_COPY_CLOCKS
|
PP_EFB_COPY_CLOCKS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual void SetPipeline(const AbstractPipeline* pipeline) {}
|
||||||
virtual void SetBlendingState(const BlendingState& state) {}
|
virtual void SetBlendingState(const BlendingState& state) {}
|
||||||
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
|
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
|
||||||
virtual void SetRasterizationState(const RasterizationState& state) {}
|
virtual void SetRasterizationState(const RasterizationState& state) {}
|
||||||
@ -91,6 +97,14 @@ public:
|
|||||||
virtual std::unique_ptr<AbstractStagingTexture>
|
virtual std::unique_ptr<AbstractStagingTexture>
|
||||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
|
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
|
||||||
|
|
||||||
|
// Shader modules/objects.
|
||||||
|
virtual std::unique_ptr<AbstractShader>
|
||||||
|
CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) = 0;
|
||||||
|
virtual std::unique_ptr<AbstractShader>
|
||||||
|
CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) = 0;
|
||||||
|
virtual std::unique_ptr<AbstractPipeline>
|
||||||
|
CreatePipeline(const AbstractPipelineConfig& config) = 0;
|
||||||
|
|
||||||
// Ideal internal resolution - multiple of the native EFB resolution
|
// Ideal internal resolution - multiple of the native EFB resolution
|
||||||
int GetTargetWidth() const { return m_target_width; }
|
int GetTargetWidth() const { return m_target_width; }
|
||||||
int GetTargetHeight() const { return m_target_height; }
|
int GetTargetHeight() const { return m_target_height; }
|
||||||
@ -160,6 +174,16 @@ public:
|
|||||||
|
|
||||||
virtual void Shutdown();
|
virtual void Shutdown();
|
||||||
|
|
||||||
|
// Drawing utility shaders.
|
||||||
|
virtual void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices,
|
||||||
|
u32 vertex_stride, u32 num_vertices)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual void DispatchComputeShader(const AbstractShader* shader, const void* uniforms,
|
||||||
|
u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||||
bool CalculateTargetSize();
|
bool CalculateTargetSize();
|
||||||
|
@ -99,6 +99,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AbstractStagingTexture.h" />
|
<ClInclude Include="AbstractStagingTexture.h" />
|
||||||
|
<ClInclude Include="AbstractPipeline.h" />
|
||||||
|
<ClInclude Include="AbstractShader.h" />
|
||||||
<ClInclude Include="AbstractTexture.h" />
|
<ClInclude Include="AbstractTexture.h" />
|
||||||
<ClInclude Include="AsyncRequests.h" />
|
<ClInclude Include="AsyncRequests.h" />
|
||||||
<ClInclude Include="AsyncShaderCompiler.h" />
|
<ClInclude Include="AsyncShaderCompiler.h" />
|
||||||
|
@ -374,8 +374,14 @@
|
|||||||
<ClInclude Include="AbstractStagingTexture.h">
|
<ClInclude Include="AbstractStagingTexture.h">
|
||||||
<Filter>Base</Filter>
|
<Filter>Base</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="AbstractShader.h">
|
||||||
|
<Filter>Base</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="AbstractPipeline.h">
|
||||||
|
<Filter>Base</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user