Shader/pipeline abstraction
This commit is contained in:
parent
9b967e3751
commit
dbf31ff75d
|
@ -37,6 +37,8 @@
|
|||
<ClCompile Include="gpu\d3d11\shader_compiler.cpp" />
|
||||
<ClCompile Include="gpu\d3d11\stream_buffer.cpp" />
|
||||
<ClCompile Include="gpu\d3d11_device.cpp" />
|
||||
<ClCompile Include="gpu\d3d11_pipeline.cpp" />
|
||||
<ClCompile Include="gpu\d3d11_shader.cpp" />
|
||||
<ClCompile Include="gpu\d3d11_texture.cpp" />
|
||||
<ClCompile Include="gpu\d3d12\context.cpp" />
|
||||
<ClCompile Include="gpu\d3d12\descriptor_heap_manager.cpp" />
|
||||
|
@ -161,6 +163,8 @@
|
|||
<ClInclude Include="gpu\d3d11\shader_compiler.h" />
|
||||
<ClInclude Include="gpu\d3d11\stream_buffer.h" />
|
||||
<ClInclude Include="gpu\d3d11_device.h" />
|
||||
<ClInclude Include="gpu\d3d11_pipeline.h" />
|
||||
<ClInclude Include="gpu\d3d11_shader.h" />
|
||||
<ClInclude Include="gpu\d3d_shaders.h" />
|
||||
<ClInclude Include="gpu\d3d11_texture.h" />
|
||||
<ClInclude Include="gpu\d3d12\context.h" />
|
||||
|
@ -197,6 +201,8 @@
|
|||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu\gpu_device.h" />
|
||||
<ClInclude Include="gpu\gpu_pipeline.h" />
|
||||
<ClInclude Include="gpu\gpu_shader.h" />
|
||||
<ClInclude Include="gpu\gpu_texture.h" />
|
||||
<ClInclude Include="gpu\imgui_impl_dx12.h" />
|
||||
<ClInclude Include="gpu\imgui_impl_opengl3.h" />
|
||||
|
|
|
@ -188,6 +188,12 @@
|
|||
<ClCompile Include="gpu\d3d11_texture.cpp">
|
||||
<Filter>gpu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gpu\d3d11_shader.cpp">
|
||||
<Filter>gpu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gpu\d3d11_pipeline.cpp">
|
||||
<Filter>gpu</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="types.h" />
|
||||
|
@ -395,6 +401,18 @@
|
|||
<ClInclude Include="gpu\d3d_shaders.h">
|
||||
<Filter>gpu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu\gpu_pipeline.h">
|
||||
<Filter>gpu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu\gpu_shader.h">
|
||||
<Filter>gpu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu\d3d11_shader.h">
|
||||
<Filter>gpu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu\d3d11_pipeline.h">
|
||||
<Filter>gpu</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="gpu">
|
||||
|
|
|
@ -8,15 +8,20 @@
|
|||
#include "d3d11/stream_buffer.h"
|
||||
#include "d3d11_texture.h"
|
||||
#include "gpu_device.h"
|
||||
#include "gpu_pipeline.h"
|
||||
#include "postprocessing_chain.h"
|
||||
#include <d3d11.h>
|
||||
#include <dxgi.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <wrl/client.h>
|
||||
|
||||
class D3D11Pipeline;
|
||||
class D3D11Shader;
|
||||
|
||||
class D3D11Device final : public GPUDevice
|
||||
{
|
||||
public:
|
||||
|
@ -65,6 +70,11 @@ public:
|
|||
void ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32 dst_layer, u32 dst_level, GPUTexture* src,
|
||||
u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width, u32 height) override;
|
||||
|
||||
std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data) override;
|
||||
std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
||||
std::vector<u8>* out_binary = nullptr) override;
|
||||
std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config) override;
|
||||
|
||||
bool GetHostRefreshRate(float* refresh_rate) override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
|
@ -78,7 +88,12 @@ public:
|
|||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
protected:
|
||||
private:
|
||||
using RasterizationStateMap = std::unordered_map<u8, ComPtr<ID3D11RasterizerState>>;
|
||||
using DepthStateMap = std::unordered_map<u8, ComPtr<ID3D11DepthStencilState>>;
|
||||
using BlendStateMap = std::unordered_map<u32, ComPtr<ID3D11BlendState>>;
|
||||
using InputLayoutMap = std::unordered_map<GPUPipeline::InputLayout, ComPtr<ID3D11InputLayout>, GPUPipeline::InputLayoutHash>;
|
||||
|
||||
static constexpr u32 DISPLAY_UNIFORM_BUFFER_SIZE = 64;
|
||||
static constexpr u32 IMGUI_VERTEX_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||
static constexpr u32 IMGUI_INDEX_BUFFER_SIZE = 2 * 1024 * 1024;
|
||||
|
@ -98,6 +113,11 @@ protected:
|
|||
bool CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode);
|
||||
bool CreateSwapChainRTV();
|
||||
|
||||
ComPtr<ID3D11RasterizerState> GetRasterizationState(const GPUPipeline::RasterizationState& rs);
|
||||
ComPtr<ID3D11DepthStencilState> GetDepthState(const GPUPipeline::DepthState& ds);
|
||||
ComPtr<ID3D11BlendState> GetBlendState(const GPUPipeline::BlendState& bs);
|
||||
ComPtr<ID3D11InputLayout> GetInputLayout(const GPUPipeline::InputLayout& il, const D3D11Shader* vs);
|
||||
|
||||
void RenderDisplay();
|
||||
void RenderSoftwareCursor();
|
||||
void RenderImGui();
|
||||
|
@ -142,6 +162,11 @@ protected:
|
|||
ComPtr<ID3D11SamplerState> m_linear_sampler;
|
||||
ComPtr<ID3D11SamplerState> m_border_sampler;
|
||||
|
||||
RasterizationStateMap m_rasterization_states;
|
||||
DepthStateMap m_depth_states;
|
||||
BlendStateMap m_blend_states;
|
||||
InputLayoutMap m_input_layouts;
|
||||
|
||||
D3D11::StreamBuffer m_display_uniform_buffer;
|
||||
ComPtr<ID3D11Texture2D> m_readback_staging_texture;
|
||||
DXGI_FORMAT m_readback_staging_texture_format = DXGI_FORMAT_UNKNOWN;
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "d3d11_pipeline.h"
|
||||
#include "d3d11_device.h"
|
||||
#include "d3d11_shader.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
|
||||
#include <array>
|
||||
#include <malloc.h>
|
||||
|
||||
Log_SetChannel(D3D11Device);
|
||||
|
||||
D3D11Pipeline::D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds,
|
||||
ComPtr<ID3D11BlendState> bs, ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs,
|
||||
ComPtr<ID3D11PixelShader> ps, D3D11_PRIMITIVE_TOPOLOGY topology)
|
||||
: m_rs(std::move(rs)), m_ds(std::move(ds)), m_bs(std::move(bs)), m_il(std::move(il)), m_vs(std::move(vs)),
|
||||
m_ps(std::move(ps)), m_topology(topology)
|
||||
{
|
||||
}
|
||||
|
||||
D3D11Pipeline::~D3D11Pipeline() = default;
|
||||
|
||||
void D3D11Pipeline::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
UnreachableCode();
|
||||
}
|
||||
|
||||
void D3D11Pipeline::Bind(ID3D11DeviceContext* context)
|
||||
{
|
||||
context->IASetInputLayout(GetInputLayout());
|
||||
context->IASetPrimitiveTopology(GetPrimitiveTopology());
|
||||
context->RSSetState(GetRasterizerState());
|
||||
context->OMSetDepthStencilState(GetDepthStencilState(), 0);
|
||||
context->OMSetBlendState(GetBlendState(), nullptr, 0xFFFFFFFFu);
|
||||
context->VSSetShader(GetVertexShader(), nullptr, 0);
|
||||
context->PSSetShader(GetPixelShader(), nullptr, 0);
|
||||
}
|
||||
|
||||
D3D11Device::ComPtr<ID3D11RasterizerState> D3D11Device::GetRasterizationState(const GPUPipeline::RasterizationState& rs)
|
||||
{
|
||||
ComPtr<ID3D11RasterizerState> drs;
|
||||
|
||||
const auto it = m_rasterization_states.find(rs.key);
|
||||
if (it != m_rasterization_states.end())
|
||||
{
|
||||
drs = it->second;
|
||||
return drs;
|
||||
}
|
||||
|
||||
static constexpr std::array<D3D11_CULL_MODE, static_cast<u32>(GPUPipeline::CullMode::MaxCount)> cull_mapping = {{
|
||||
D3D11_CULL_NONE, // None
|
||||
D3D11_CULL_FRONT, // Front
|
||||
D3D11_CULL_BACK, // Back
|
||||
}};
|
||||
|
||||
D3D11_RASTERIZER_DESC desc = {};
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.CullMode = cull_mapping[static_cast<u8>(rs.cull_mode.GetValue())];
|
||||
desc.ScissorEnable = TRUE;
|
||||
// desc.MultisampleEnable ???
|
||||
|
||||
HRESULT hr = m_device->CreateRasterizerState(&desc, drs.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
Log_ErrorPrintf("Failed to create depth state with %08X", hr);
|
||||
|
||||
m_rasterization_states.emplace(rs.key, drs);
|
||||
return drs;
|
||||
}
|
||||
|
||||
D3D11Device::ComPtr<ID3D11DepthStencilState> D3D11Device::GetDepthState(const GPUPipeline::DepthState& ds)
|
||||
{
|
||||
ComPtr<ID3D11DepthStencilState> dds;
|
||||
|
||||
const auto it = m_depth_states.find(ds.key);
|
||||
if (it != m_depth_states.end())
|
||||
{
|
||||
dds = it->second;
|
||||
return dds;
|
||||
}
|
||||
|
||||
static constexpr std::array<D3D11_COMPARISON_FUNC, static_cast<u32>(GPUPipeline::DepthFunc::MaxCount)> func_mapping =
|
||||
{{
|
||||
D3D11_COMPARISON_NEVER, // Never
|
||||
D3D11_COMPARISON_ALWAYS, // Always
|
||||
D3D11_COMPARISON_LESS, // Less
|
||||
D3D11_COMPARISON_LESS_EQUAL, // LessEqual
|
||||
D3D11_COMPARISON_GREATER, // Greater
|
||||
D3D11_COMPARISON_GREATER_EQUAL, // GreaterEqual
|
||||
D3D11_COMPARISON_EQUAL, // Equal
|
||||
}};
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC desc = {};
|
||||
desc.DepthEnable = ds.depth_test != GPUPipeline::DepthFunc::Never;
|
||||
desc.DepthFunc = func_mapping[static_cast<u8>(ds.depth_test.GetValue())];
|
||||
desc.DepthWriteMask = ds.depth_write ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
|
||||
HRESULT hr = m_device->CreateDepthStencilState(&desc, dds.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
Log_ErrorPrintf("Failed to create depth state with %08X", hr);
|
||||
|
||||
m_depth_states.emplace(ds.key, dds);
|
||||
return dds;
|
||||
}
|
||||
|
||||
D3D11Device::ComPtr<ID3D11BlendState> D3D11Device::GetBlendState(const GPUPipeline::BlendState& bs)
|
||||
{
|
||||
ComPtr<ID3D11BlendState> dbs;
|
||||
|
||||
const auto it = m_blend_states.find(bs.key);
|
||||
if (it != m_blend_states.end())
|
||||
{
|
||||
dbs = it->second;
|
||||
return dbs;
|
||||
}
|
||||
|
||||
static constexpr std::array<D3D11_BLEND, static_cast<u32>(GPUPipeline::BlendFunc::MaxCount)> blend_mapping = {{
|
||||
D3D11_BLEND_ZERO, // Zero
|
||||
D3D11_BLEND_ONE, // One
|
||||
D3D11_BLEND_SRC_COLOR, // SrcColor
|
||||
D3D11_BLEND_INV_SRC_COLOR, // InvSrcColor
|
||||
D3D11_BLEND_DEST_COLOR, // DstColor
|
||||
D3D11_BLEND_INV_DEST_COLOR, // InvDstColor
|
||||
D3D11_BLEND_SRC_ALPHA, // SrcAlpha
|
||||
D3D11_BLEND_INV_SRC_ALPHA, // InvSrcAlpha
|
||||
D3D11_BLEND_SRC1_ALPHA, // SrcAlpha1
|
||||
D3D11_BLEND_INV_SRC1_ALPHA, // InvSrcAlpha1
|
||||
D3D11_BLEND_DEST_ALPHA, // DstAlpha
|
||||
D3D11_BLEND_INV_DEST_ALPHA, // InvDstAlpha
|
||||
}};
|
||||
|
||||
static constexpr std::array<D3D11_BLEND_OP, static_cast<u32>(GPUPipeline::BlendOp::MaxCount)> op_mapping = {{
|
||||
D3D11_BLEND_OP_ADD, // Add
|
||||
D3D11_BLEND_OP_SUBTRACT, // Subtract
|
||||
D3D11_BLEND_OP_REV_SUBTRACT, // ReverseSubtract
|
||||
D3D11_BLEND_OP_MIN, // Min
|
||||
D3D11_BLEND_OP_MAX, // Max
|
||||
}};
|
||||
|
||||
D3D11_BLEND_DESC blend_desc = {};
|
||||
D3D11_RENDER_TARGET_BLEND_DESC& tgt_desc = blend_desc.RenderTarget[0];
|
||||
tgt_desc.BlendEnable = bs.enable;
|
||||
tgt_desc.RenderTargetWriteMask = bs.write_mask;
|
||||
if (bs.enable)
|
||||
{
|
||||
tgt_desc.SrcBlend = blend_mapping[static_cast<u8>(bs.src_blend.GetValue())];
|
||||
tgt_desc.DestBlend = blend_mapping[static_cast<u8>(bs.dst_blend.GetValue())];
|
||||
tgt_desc.BlendOp = op_mapping[static_cast<u8>(bs.blend_op.GetValue())];
|
||||
tgt_desc.SrcBlendAlpha = blend_mapping[static_cast<u8>(bs.src_alpha_blend.GetValue())];
|
||||
tgt_desc.DestBlendAlpha = blend_mapping[static_cast<u8>(bs.dst_alpha_blend.GetValue())];
|
||||
tgt_desc.BlendOpAlpha = op_mapping[static_cast<u8>(bs.alpha_blend_op.GetValue())];
|
||||
}
|
||||
|
||||
HRESULT hr = m_device->CreateBlendState(&blend_desc, dbs.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
Log_ErrorPrintf("Failed to create blend state with %08X", hr);
|
||||
|
||||
m_blend_states.emplace(bs.key, dbs);
|
||||
return dbs;
|
||||
}
|
||||
|
||||
D3D11Device::ComPtr<ID3D11InputLayout> D3D11Device::GetInputLayout(const GPUPipeline::InputLayout& il,
|
||||
const D3D11Shader* vs)
|
||||
{
|
||||
ComPtr<ID3D11InputLayout> dil;
|
||||
const auto it = m_input_layouts.find(il);
|
||||
if (it != m_input_layouts.end())
|
||||
{
|
||||
dil = it->second;
|
||||
return dil;
|
||||
}
|
||||
|
||||
static constexpr std::array<const char*, static_cast<u32>(GPUPipeline::VertexAttribute::Semantic::MaxCount)>
|
||||
semantics = {{
|
||||
"POSITION", // Position
|
||||
"TEXCOORD", // Texcoord
|
||||
"COLOR", // Color
|
||||
}};
|
||||
|
||||
static constexpr u32 MAX_COMPONENTS = 4;
|
||||
static constexpr const DXGI_FORMAT
|
||||
format_mapping[static_cast<u8>(GPUPipeline::VertexAttribute::Type::MaxCount)][MAX_COMPONENTS] = {
|
||||
{DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT}, // Float
|
||||
{DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UINT}, // UInt8
|
||||
{DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_SINT}, // SInt8
|
||||
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM}, // UNorm8
|
||||
{DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UINT}, // UInt16
|
||||
{DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_SINT}, // SInt16
|
||||
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16G16B16A16_UNORM}, // UNorm16
|
||||
{DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_UINT}, // UInt32
|
||||
{DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32G32B32A32_SINT}, // SInt32
|
||||
};
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC* elems =
|
||||
static_cast<D3D11_INPUT_ELEMENT_DESC*>(alloca(sizeof(D3D11_INPUT_ELEMENT_DESC) * il.vertex_attributes.size()));
|
||||
for (size_t i = 0; i < il.vertex_attributes.size(); i++)
|
||||
{
|
||||
const GPUPipeline::VertexAttribute& va = il.vertex_attributes[i];
|
||||
Assert(va.components > 0 && va.components < MAX_COMPONENTS);
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC& elem = elems[i];
|
||||
elem.SemanticName = semantics[static_cast<u8>(va.semantic.GetValue())];
|
||||
elem.SemanticIndex = va.semantic_index;
|
||||
elem.Format = format_mapping[static_cast<u8>(va.type.GetValue())][va.components - 1];
|
||||
elem.InputSlot = 0;
|
||||
elem.AlignedByteOffset = va.offset;
|
||||
elem.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
elem.InstanceDataStepRate = 0;
|
||||
}
|
||||
|
||||
HRESULT hr = m_device->CreateInputLayout(elems, static_cast<UINT>(il.vertex_attributes.size()),
|
||||
vs->GetBytecode().data(), vs->GetBytecode().size(), dil.GetAddressOf());
|
||||
if (FAILED(hr))
|
||||
Log_ErrorPrintf("Failed to create input layout with %08X", hr);
|
||||
|
||||
m_input_layouts.emplace(il, dil);
|
||||
return dil;
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUPipeline> D3D11Device::CreatePipeline(const GPUPipeline::GraphicsConfig& config)
|
||||
{
|
||||
ComPtr<ID3D11RasterizerState> rs = GetRasterizationState(config.rasterization);
|
||||
ComPtr<ID3D11DepthStencilState> ds = GetDepthState(config.depth);
|
||||
ComPtr<ID3D11BlendState> bs = GetBlendState(config.blend);
|
||||
|
||||
static constexpr std::array<D3D11_PRIMITIVE_TOPOLOGY, static_cast<u32>(GPUPipeline::Primitive::MaxCount)> primitives =
|
||||
{{
|
||||
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, // Points
|
||||
D3D11_PRIMITIVE_TOPOLOGY_LINELIST, // Lines
|
||||
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // Triangles
|
||||
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, // TriangleStrips
|
||||
}};
|
||||
|
||||
return std::unique_ptr<GPUPipeline>(
|
||||
new D3D11Pipeline(std::move(rs), std::move(ds), std::move(bs), nullptr,
|
||||
static_cast<const D3D11Shader*>(config.vertex_shader)->GetD3DVertexShader(),
|
||||
static_cast<const D3D11Shader*>(config.pixel_shader)->GetD3DPixelShader(),
|
||||
primitives[static_cast<u8>(config.primitive)]));
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_pipeline.h"
|
||||
|
||||
#include "common/windows_headers.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "gsl/span"
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
class D3D11Pipeline final : public GPUPipeline
|
||||
{
|
||||
friend D3D11Device;
|
||||
|
||||
template<typename T>
|
||||
using ComPtr = Microsoft::WRL::ComPtr<T>;
|
||||
|
||||
public:
|
||||
~D3D11Pipeline() override;
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
ALWAYS_INLINE ID3D11RasterizerState* GetRasterizerState() const { return m_rs.Get(); }
|
||||
ALWAYS_INLINE ID3D11DepthStencilState* GetDepthStencilState() const { return m_ds.Get(); }
|
||||
ALWAYS_INLINE ID3D11BlendState* GetBlendState() const { return m_bs.Get(); }
|
||||
ALWAYS_INLINE ID3D11InputLayout* GetInputLayout() const { return m_il.Get(); }
|
||||
ALWAYS_INLINE ID3D11VertexShader* GetVertexShader() const { return m_vs.Get(); }
|
||||
ALWAYS_INLINE ID3D11PixelShader* GetPixelShader() const { return m_ps.Get(); }
|
||||
ALWAYS_INLINE D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_topology; }
|
||||
|
||||
void Bind(ID3D11DeviceContext* context);
|
||||
|
||||
private:
|
||||
D3D11Pipeline(ComPtr<ID3D11RasterizerState> rs, ComPtr<ID3D11DepthStencilState> ds, ComPtr<ID3D11BlendState> bs,
|
||||
ComPtr<ID3D11InputLayout> il, ComPtr<ID3D11VertexShader> vs, ComPtr<ID3D11PixelShader> ps,
|
||||
D3D11_PRIMITIVE_TOPOLOGY topology);
|
||||
|
||||
ComPtr<ID3D11RasterizerState> m_rs;
|
||||
ComPtr<ID3D11DepthStencilState> m_ds;
|
||||
ComPtr<ID3D11BlendState> m_bs;
|
||||
ComPtr<ID3D11InputLayout> m_il;
|
||||
ComPtr<ID3D11VertexShader> m_vs;
|
||||
ComPtr<ID3D11PixelShader> m_ps;
|
||||
D3D11_PRIMITIVE_TOPOLOGY m_topology;
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "d3d11_shader.h"
|
||||
#include "d3d11/shader_compiler.h"
|
||||
#include "d3d11_device.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
D3D11Shader::D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader)
|
||||
: GPUShader(stage), m_shader(std::move(shader))
|
||||
{
|
||||
}
|
||||
|
||||
D3D11Shader::~D3D11Shader() = default;
|
||||
|
||||
ID3D11VertexShader* D3D11Shader::GetD3DVertexShader() const
|
||||
{
|
||||
DebugAssert(m_stage == Stage::Vertex);
|
||||
return static_cast<ID3D11VertexShader*>(m_shader.Get());
|
||||
}
|
||||
|
||||
ID3D11PixelShader* D3D11Shader::GetD3DPixelShader() const
|
||||
{
|
||||
DebugAssert(m_stage == Stage::Pixel);
|
||||
return static_cast<ID3D11PixelShader*>(m_shader.Get());
|
||||
}
|
||||
|
||||
ID3D11ComputeShader* D3D11Shader::GetD3DComputeShader() const
|
||||
{
|
||||
DebugAssert(m_stage == Stage::Compute);
|
||||
return static_cast<ID3D11ComputeShader*>(m_shader.Get());
|
||||
}
|
||||
|
||||
void D3D11Shader::SetDebugName(const std::string_view& name)
|
||||
{
|
||||
Panic("Implement me");
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data)
|
||||
{
|
||||
ComPtr<ID3D11DeviceChild> shader;
|
||||
std::vector<u8> bytecode;
|
||||
switch (stage)
|
||||
{
|
||||
case GPUShader::Stage::Vertex:
|
||||
shader = D3D11::ShaderCompiler::CreateVertexShader(D3D11Device::GetD3DDevice(), data.data(), data.size());
|
||||
bytecode.resize(data.size());
|
||||
std::memcpy(bytecode.data(), data.data(), data.size());
|
||||
break;
|
||||
|
||||
case GPUShader::Stage::Pixel:
|
||||
shader = D3D11::ShaderCompiler::CreatePixelShader(D3D11Device::GetD3DDevice(), data.data(), data.size());
|
||||
break;
|
||||
|
||||
case GPUShader::Stage::Compute:
|
||||
shader = D3D11::ShaderCompiler::CreateComputeShader(D3D11Device::GetD3DDevice(), data.data(), data.size());
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!shader)
|
||||
return {};
|
||||
|
||||
return std::unique_ptr<GPUShader>(new D3D11Shader(stage, std::move(shader), std::move(bytecode)));
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
||||
std::vector<u8>* out_binary /* = nullptr */)
|
||||
{
|
||||
// TODO: This shouldn't be dependent on build type.
|
||||
#ifdef _DEBUG
|
||||
constexpr bool debug = true;
|
||||
#else
|
||||
constexpr bool debug = false;
|
||||
#endif
|
||||
|
||||
ComPtr<ID3DBlob> blob;
|
||||
switch (stage)
|
||||
{
|
||||
case GPUShader::Stage::Vertex:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(),
|
||||
source, debug);
|
||||
break;
|
||||
|
||||
case GPUShader::Stage::Pixel:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_device->GetFeatureLevel(),
|
||||
source, debug);
|
||||
break;
|
||||
|
||||
case GPUShader::Stage::Compute:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Compute, m_device->GetFeatureLevel(),
|
||||
source, debug);
|
||||
break;
|
||||
|
||||
default:
|
||||
UnreachableCode();
|
||||
break;
|
||||
}
|
||||
|
||||
if (out_binary)
|
||||
{
|
||||
const size_t size = blob->GetBufferSize();
|
||||
out_binary->resize(size);
|
||||
std::memcpy(out_binary->data(), blob->GetBufferPointer(), size);
|
||||
}
|
||||
|
||||
return CreateShaderFromBinary(
|
||||
stage, gsl::span<const u8>(static_cast<const u8*>(blob->GetBufferPointer()), blob->GetBufferSize()));
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader.h"
|
||||
|
||||
#include "common/windows_headers.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#include "gsl/span"
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
class D3D11Shader final : public GPUShader
|
||||
{
|
||||
friend D3D11Device;
|
||||
|
||||
public:
|
||||
~D3D11Shader() override;
|
||||
|
||||
ID3D11VertexShader* GetD3DVertexShader() const;
|
||||
ID3D11PixelShader* GetD3DPixelShader() const;
|
||||
ID3D11ComputeShader* GetD3DComputeShader() const;
|
||||
|
||||
ALWAYS_INLINE const std::vector<u8>& GetBytecode() const { return m_bytecode; }
|
||||
|
||||
void SetDebugName(const std::string_view& name) override;
|
||||
|
||||
private:
|
||||
D3D11Shader(Stage stage, Microsoft::WRL::ComPtr<ID3D11DeviceChild> shader, std::vector<u8> bytecode);
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11DeviceChild> m_shader;
|
||||
std::vector<u8> m_bytecode; // only for VS
|
||||
};
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/align.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/hash_combine.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/timer.h"
|
||||
|
@ -22,6 +23,75 @@ Log_SetChannel(GPUDevice);
|
|||
|
||||
std::unique_ptr<GPUDevice> g_host_display;
|
||||
|
||||
size_t GPUPipeline::InputLayoutHash::operator()(const InputLayout& il) const
|
||||
{
|
||||
std::size_t h = 0;
|
||||
hash_combine(h, il.vertex_attributes.size(), il.vertex_stride);
|
||||
|
||||
for (const VertexAttribute& va : il.vertex_attributes)
|
||||
hash_combine(h, va.key);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
bool GPUPipeline::InputLayout::operator==(const InputLayout& rhs) const
|
||||
{
|
||||
return (vertex_stride == rhs.vertex_stride && vertex_attributes.size() == rhs.vertex_attributes.size() &&
|
||||
std::memcmp(vertex_attributes.data(), rhs.vertex_attributes.data(),
|
||||
sizeof(VertexAttribute) * rhs.vertex_attributes.size()) == 0);
|
||||
}
|
||||
|
||||
bool GPUPipeline::InputLayout::operator!=(const InputLayout& rhs) const
|
||||
{
|
||||
return (vertex_stride != rhs.vertex_stride ||
|
||||
vertex_attributes.size() != rhs.vertex_attributes.size() &&
|
||||
std::memcmp(vertex_attributes.data(), rhs.vertex_attributes.data(),
|
||||
sizeof(VertexAttribute) * rhs.vertex_attributes.size()) != 0);
|
||||
}
|
||||
|
||||
GPUPipeline::RasterizationState GPUPipeline::RasterizationState::GetNoCullState()
|
||||
{
|
||||
RasterizationState ret = {};
|
||||
ret.cull_mode = CullMode::None;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GPUPipeline::DepthState GPUPipeline::DepthState::GetNoTestsState()
|
||||
{
|
||||
DepthState ret = {};
|
||||
ret.depth_test = DepthFunc::Always;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GPUPipeline::DepthState GPUPipeline::DepthState::GetAlwaysWriteState()
|
||||
{
|
||||
DepthState ret = {};
|
||||
ret.depth_test = DepthFunc::Always;
|
||||
ret.depth_write = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GPUPipeline::BlendState GPUPipeline::BlendState::GetNoBlendingState()
|
||||
{
|
||||
BlendState ret = {};
|
||||
ret.write_mask = 0xf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GPUPipeline::BlendState GPUPipeline::BlendState::GetAlphaBlendingState()
|
||||
{
|
||||
BlendState ret = {};
|
||||
ret.enable = true;
|
||||
ret.src_blend = BlendFunc::SrcAlpha;
|
||||
ret.dst_blend = BlendFunc::InvSrcAlpha;
|
||||
ret.blend_op = BlendOp::Add;
|
||||
ret.src_alpha_blend = BlendFunc::One;
|
||||
ret.dst_alpha_blend = BlendFunc::Zero;
|
||||
ret.alpha_blend_op = BlendOp::Add;
|
||||
ret.write_mask = 0xf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
GPUDevice::~GPUDevice() = default;
|
||||
|
||||
RenderAPI GPUDevice::GetPreferredAPI()
|
||||
|
@ -54,6 +124,28 @@ void GPUDevice::ResolveTextureRegion(GPUTexture* dst, u32 dst_x, u32 dst_y, u32
|
|||
UnreachableCode();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> GPUDevice::CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data)
|
||||
{
|
||||
// TODO: REMOVE ME
|
||||
UnreachableCode();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUShader> GPUDevice::CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
||||
std::vector<u8>* out_binary /* = nullptr */)
|
||||
{
|
||||
// TODO: REMOVE ME
|
||||
UnreachableCode();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<GPUPipeline> GPUDevice::CreatePipeline(const GPUPipeline::GraphicsConfig& config)
|
||||
{
|
||||
// TODO: REMOVE ME
|
||||
UnreachableCode();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool GPUDevice::ParseFullscreenMode(const std::string_view& mode, u32* width, u32* height, float* refresh_rate)
|
||||
{
|
||||
if (!mode.empty())
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "gpu_pipeline.h"
|
||||
#include "gpu_shader.h"
|
||||
#include "gpu_texture.h"
|
||||
|
||||
#include "common/rectangle.h"
|
||||
#include "common/types.h"
|
||||
#include "common/window_info.h"
|
||||
#include "gpu_texture.h"
|
||||
|
||||
#include "gsl/span"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -101,6 +107,12 @@ public:
|
|||
GPUTexture* src, u32 src_x, u32 src_y, u32 src_layer, u32 src_level, u32 width,
|
||||
u32 height);
|
||||
|
||||
/// Shader abstraction.
|
||||
virtual std::unique_ptr<GPUShader> CreateShaderFromBinary(GPUShader::Stage stage, gsl::span<const u8> data);
|
||||
virtual std::unique_ptr<GPUShader> CreateShaderFromSource(GPUShader::Stage stage, const std::string_view& source,
|
||||
std::vector<u8>* out_binary = nullptr);
|
||||
virtual std::unique_ptr<GPUPipeline> CreatePipeline(const GPUPipeline::GraphicsConfig& config);
|
||||
|
||||
/// Returns false if the window was completely occluded.
|
||||
virtual bool Render(bool skip_present) = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_texture.h"
|
||||
|
||||
#include "common/bitfield.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include "gsl/span"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
class GPUShader;
|
||||
|
||||
class GPUPipeline
|
||||
{
|
||||
public:
|
||||
enum class Layout : u8
|
||||
{
|
||||
// 128 byte UBO via push constants, 1 texture.
|
||||
SingleTexture,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class Primitive : u8
|
||||
{
|
||||
Points,
|
||||
Lines,
|
||||
Triangles,
|
||||
TriangleStrips,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
union VertexAttribute
|
||||
{
|
||||
enum class Semantic : u8
|
||||
{
|
||||
Position,
|
||||
Texcoord,
|
||||
Color,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class Type : u8
|
||||
{
|
||||
Float,
|
||||
UInt8,
|
||||
SInt8,
|
||||
UNorm8,
|
||||
UInt16,
|
||||
SInt16,
|
||||
UNorm16,
|
||||
UInt32,
|
||||
SInt32,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
BitField<u32, Semantic, 0, 3> semantic;
|
||||
BitField<u32, u8, 4, 8> semantic_index;
|
||||
BitField<u32, Type, 12, 4> type;
|
||||
BitField<u32, u8, 16, 2> components;
|
||||
BitField<u32, u8, 18, 8> offset;
|
||||
u32 key;
|
||||
};
|
||||
|
||||
struct InputLayout
|
||||
{
|
||||
gsl::span<const VertexAttribute> vertex_attributes;
|
||||
u32 vertex_stride;
|
||||
|
||||
bool operator==(const InputLayout& rhs) const;
|
||||
bool operator!=(const InputLayout& rhs) const;
|
||||
};
|
||||
|
||||
struct InputLayoutHash
|
||||
{
|
||||
size_t operator()(const InputLayout& il) const;
|
||||
};
|
||||
|
||||
enum class CullMode : u8
|
||||
{
|
||||
None,
|
||||
Front,
|
||||
Back,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class DepthFunc : u8
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
Less,
|
||||
LessEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Equal,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class BlendFunc : u8
|
||||
{
|
||||
Zero,
|
||||
One,
|
||||
SrcColor,
|
||||
InvSrcColor,
|
||||
DstColor,
|
||||
InvDstColor,
|
||||
SrcAlpha,
|
||||
InvSrcAlpha,
|
||||
SrcAlpha1,
|
||||
InvSrcAlpha1,
|
||||
DstAlpha,
|
||||
InvDstAlpha,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
enum class BlendOp : u8
|
||||
{
|
||||
Add,
|
||||
Subtract,
|
||||
ReverseSubtract,
|
||||
Min,
|
||||
Max,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
union RasterizationState
|
||||
{
|
||||
BitField<u8, CullMode, 0, 2> cull_mode;
|
||||
u8 key;
|
||||
|
||||
static RasterizationState GetNoCullState();
|
||||
};
|
||||
|
||||
struct DepthState
|
||||
{
|
||||
BitField<u8, DepthFunc, 0, 3> depth_test;
|
||||
BitField<u8, bool, 4, 1> depth_write;
|
||||
u8 key;
|
||||
|
||||
static DepthState GetNoTestsState();
|
||||
static DepthState GetAlwaysWriteState();
|
||||
};
|
||||
|
||||
struct BlendState
|
||||
{
|
||||
BitField<u32, bool, 0, 1> enable;
|
||||
BitField<u32, BlendFunc, 1, 4> src_blend;
|
||||
BitField<u32, BlendFunc, 5, 4> src_alpha_blend;
|
||||
BitField<u32, BlendFunc, 9, 4> dst_blend;
|
||||
BitField<u32, BlendFunc, 13, 4> dst_alpha_blend;
|
||||
BitField<u32, BlendOp, 17, 3> blend_op;
|
||||
BitField<u32, BlendOp, 20, 3> alpha_blend_op;
|
||||
BitField<u32, bool, 24, 1> write_r;
|
||||
BitField<u32, bool, 25, 1> write_g;
|
||||
BitField<u32, bool, 26, 1> write_b;
|
||||
BitField<u32, bool, 27, 1> write_a;
|
||||
BitField<u32, u8, 24, 4> write_mask;
|
||||
u32 key;
|
||||
|
||||
static BlendState GetNoBlendingState();
|
||||
static BlendState GetAlphaBlendingState();
|
||||
};
|
||||
|
||||
struct GraphicsConfig
|
||||
{
|
||||
Layout layout;
|
||||
|
||||
Primitive primitive;
|
||||
InputLayout input_layout;
|
||||
|
||||
RasterizationState rasterization;
|
||||
DepthState depth;
|
||||
BlendState blend;
|
||||
|
||||
const GPUShader* vertex_shader;
|
||||
const GPUShader* pixel_shader;
|
||||
|
||||
GPUTexture::Format color_format;
|
||||
GPUTexture::Format depth_format;
|
||||
u32 samples;
|
||||
bool per_sample_shading;
|
||||
};
|
||||
|
||||
GPUPipeline() = default;
|
||||
virtual ~GPUPipeline() = default;
|
||||
|
||||
virtual void SetDebugName(const std::string_view& name) = 0;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
class GPUShader
|
||||
{
|
||||
public:
|
||||
enum class Stage
|
||||
{
|
||||
Vertex,
|
||||
Pixel,
|
||||
Compute
|
||||
};
|
||||
|
||||
GPUShader(Stage stage) : m_stage(stage) {}
|
||||
virtual ~GPUShader() = default;
|
||||
|
||||
ALWAYS_INLINE Stage GetStage() const { return m_stage; }
|
||||
|
||||
virtual void SetDebugName(const std::string_view& name) = 0;
|
||||
|
||||
protected:
|
||||
Stage m_stage;
|
||||
};
|
Loading…
Reference in New Issue