D3D12HostDisplay: Implement post processing
This commit is contained in:
parent
cc3fadba14
commit
adf41b9bbd
|
@ -213,21 +213,11 @@ void CDROM::SoftReset(TickCount ticks_late)
|
||||||
|
|
||||||
if (HasMedia())
|
if (HasMedia())
|
||||||
{
|
{
|
||||||
const TickCount toc_read_ticks = GetTicksForTOCRead();
|
|
||||||
const TickCount speed_change_ticks = was_double_speed ? GetTicksForSpeedChange() : 0;
|
const TickCount speed_change_ticks = was_double_speed ? GetTicksForSpeedChange() : 0;
|
||||||
const TickCount seek_ticks = (m_current_lba != 0) ? GetTicksForSeek(0) : 0;
|
const TickCount seek_ticks = (m_current_lba != 0) ? GetTicksForSeek(0) : 0;
|
||||||
const TickCount total_ticks = toc_read_ticks + speed_change_ticks + seek_ticks - ticks_late;
|
const TickCount total_ticks = std::max<TickCount>(speed_change_ticks + seek_ticks, INIT_TICKS) - ticks_late;
|
||||||
|
Log_DevPrintf("CDROM init total disc ticks = %d (speed change = %d, seek = %d)", total_ticks, speed_change_ticks,
|
||||||
if (was_double_speed)
|
seek_ticks);
|
||||||
{
|
|
||||||
Log_DevPrintf("CDROM was double speed on reset, switching to single speed in %d ticks, reading TOC in %d ticks, "
|
|
||||||
"seeking in %d ticks",
|
|
||||||
speed_change_ticks, toc_read_ticks, seek_ticks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log_DevPrintf("CDROM reading TOC on reset in %d ticks and seeking in %d ticks", toc_read_ticks, seek_ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_current_lba != 0)
|
if (m_current_lba != 0)
|
||||||
{
|
{
|
||||||
|
@ -1351,7 +1341,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late)
|
||||||
|
|
||||||
case Command::Init:
|
case Command::Init:
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("CDROM reset command");
|
Log_DebugPrintf("CDROM init command");
|
||||||
|
|
||||||
if (m_command_second_response == Command::Init)
|
if (m_command_second_response == Command::Init)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/d3d11/shader_compiler.h"
|
#include "common/d3d11/shader_compiler.h"
|
||||||
#include "common/d3d12/context.h"
|
#include "common/d3d12/context.h"
|
||||||
|
#include "common/d3d12/shader_cache.h"
|
||||||
#include "common/d3d12/util.h"
|
#include "common/d3d12/util.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
@ -15,6 +16,8 @@
|
||||||
#include <dxgi1_5.h>
|
#include <dxgi1_5.h>
|
||||||
Log_SetChannel(D3D12HostDisplay);
|
Log_SetChannel(D3D12HostDisplay);
|
||||||
|
|
||||||
|
static constexpr const std::array<float, 4> s_clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
D3D12HostDisplay::D3D12HostDisplay() = default;
|
D3D12HostDisplay::D3D12HostDisplay() = default;
|
||||||
|
|
||||||
D3D12HostDisplay::~D3D12HostDisplay()
|
D3D12HostDisplay::~D3D12HostDisplay()
|
||||||
|
@ -501,13 +504,30 @@ HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList()
|
||||||
bool D3D12HostDisplay::CreateResources()
|
bool D3D12HostDisplay::CreateResources()
|
||||||
{
|
{
|
||||||
D3D12::RootSignatureBuilder rsbuilder;
|
D3D12::RootSignatureBuilder rsbuilder;
|
||||||
rsbuilder.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
rsbuilder.Add32BitConstants(0, 4, D3D12_SHADER_VISIBILITY_VERTEX);
|
||||||
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_ALL);
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_ALL);
|
||||||
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_ALL);
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_ALL);
|
||||||
m_display_root_signature = rsbuilder.Create();
|
m_display_root_signature = rsbuilder.Create();
|
||||||
if (!m_display_root_signature)
|
if (!m_display_root_signature)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
rsbuilder.SetInputAssemblerFlag();
|
||||||
|
rsbuilder.Add32BitConstants(0, FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD / sizeof(u32),
|
||||||
|
D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
m_post_processing_root_signature = rsbuilder.Create();
|
||||||
|
if (!m_post_processing_root_signature)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rsbuilder.SetInputAssemblerFlag();
|
||||||
|
rsbuilder.AddCBVParameter(0, D3D12_SHADER_VISIBILITY_ALL);
|
||||||
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
rsbuilder.AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_PIXEL);
|
||||||
|
m_post_processing_cb_root_signature = rsbuilder.Create();
|
||||||
|
if (!m_post_processing_cb_root_signature)
|
||||||
|
return false;
|
||||||
|
|
||||||
D3D12::GraphicsPipelineBuilder gpbuilder;
|
D3D12::GraphicsPipelineBuilder gpbuilder;
|
||||||
gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
|
gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
|
||||||
gpbuilder.SetRootSignature(m_display_root_signature.Get());
|
gpbuilder.SetRootSignature(m_display_root_signature.Get());
|
||||||
|
@ -545,20 +565,19 @@ bool D3D12HostDisplay::CreateResources()
|
||||||
|
|
||||||
g_d3d12_context->GetDevice()->CreateSampler(&desc, m_linear_sampler.cpu_handle);
|
g_d3d12_context->GetDevice()->CreateSampler(&desc, m_linear_sampler.cpu_handle);
|
||||||
|
|
||||||
if (!m_display_uniform_buffer.Create(DISPLAY_UNIFORM_BUFFER_SIZE))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12HostDisplay::DestroyResources()
|
void D3D12HostDisplay::DestroyResources()
|
||||||
{
|
{
|
||||||
// m_post_processing_chain.ClearStages();
|
m_post_processing_cbuffer.Destroy(false);
|
||||||
// m_post_processing_input_texture.Destroy();
|
m_post_processing_chain.ClearStages();
|
||||||
// m_post_processing_stages.clear();
|
m_post_processing_input_texture.Destroy();
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
m_post_processing_cb_root_signature.Reset();
|
||||||
|
m_post_processing_root_signature.Reset();
|
||||||
|
|
||||||
m_readback_staging_texture.Destroy(false);
|
m_readback_staging_texture.Destroy(false);
|
||||||
m_display_uniform_buffer.Destroy(false);
|
|
||||||
g_d3d12_context->GetSamplerHeapManager().Free(&m_linear_sampler);
|
g_d3d12_context->GetSamplerHeapManager().Free(&m_linear_sampler);
|
||||||
g_d3d12_context->GetSamplerHeapManager().Free(&m_point_sampler);
|
g_d3d12_context->GetSamplerHeapManager().Free(&m_point_sampler);
|
||||||
m_software_cursor_pipeline.Reset();
|
m_software_cursor_pipeline.Reset();
|
||||||
|
@ -596,16 +615,11 @@ bool D3D12HostDisplay::Render(bool skip_present)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<float, 4> clear_color = {};
|
|
||||||
D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer];
|
D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer];
|
||||||
m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast<u32>(m_swap_chain_buffers.size()));
|
m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast<u32>(m_swap_chain_buffers.size()));
|
||||||
|
|
||||||
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
||||||
swap_chain_buf.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
RenderDisplay(cmdlist, &swap_chain_buf);
|
||||||
cmdlist->ClearRenderTargetView(swap_chain_buf.GetRTVOrDSVDescriptor(), clear_color.data(), 0, nullptr);
|
|
||||||
cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
|
||||||
|
|
||||||
RenderDisplay(cmdlist);
|
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
if (ImGui::GetCurrentContext())
|
||||||
RenderImGui(cmdlist);
|
RenderImGui(cmdlist);
|
||||||
|
@ -637,19 +651,29 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector<u32>*
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<float, 4> clear_color = {};
|
|
||||||
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
||||||
|
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height);
|
||||||
|
|
||||||
|
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
|
||||||
|
{
|
||||||
|
ApplyPostProcessingChain(cmdlist, &render_texture, left, top, width, height,
|
||||||
|
static_cast<D3D12::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||||
|
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||||
|
width, height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
render_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
render_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
cmdlist->ClearRenderTargetView(render_texture.GetRTVOrDSVDescriptor(), clear_color.data(), 0, nullptr);
|
cmdlist->ClearRenderTargetView(render_texture.GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr);
|
||||||
cmdlist->OMSetRenderTargets(1, &render_texture.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
cmdlist->OMSetRenderTargets(1, &render_texture.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
||||||
|
|
||||||
if (HasDisplayTexture())
|
if (HasDisplayTexture())
|
||||||
{
|
{
|
||||||
const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0);
|
|
||||||
RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast<D3D12::Texture*>(m_display_texture),
|
RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast<D3D12::Texture*>(m_display_texture),
|
||||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||||
m_display_texture_view_height, IsUsingLinearFiltering());
|
m_display_texture_view_height, IsUsingLinearFiltering());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
|
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr);
|
||||||
|
|
||||||
|
@ -682,21 +706,25 @@ void D3D12HostDisplay::RenderImGui(ID3D12GraphicsCommandList* cmdlist)
|
||||||
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData());
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist)
|
void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* swap_chain_buf)
|
||||||
{
|
{
|
||||||
if (!HasDisplayTexture())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
|
const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight());
|
||||||
|
|
||||||
// if (!m_post_processing_chain.IsEmpty())
|
if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty())
|
||||||
// {
|
{
|
||||||
// ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, m_display_texture_handle,
|
ApplyPostProcessingChain(cmdlist, swap_chain_buf, left, top, width, height,
|
||||||
// m_display_texture_width, m_display_texture_height, m_display_texture_view_x,
|
static_cast<D3D12::Texture*>(m_display_texture), m_display_texture_view_x,
|
||||||
// m_display_texture_view_y, m_display_texture_view_width,
|
m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height,
|
||||||
// m_display_texture_view_height);
|
GetWindowWidth(), GetWindowHeight());
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
swap_chain_buf->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
|
cmdlist->ClearRenderTargetView(swap_chain_buf->GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr);
|
||||||
|
cmdlist->OMSetRenderTargets(1, &swap_chain_buf->GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
||||||
|
|
||||||
|
if (!HasDisplayTexture())
|
||||||
|
return;
|
||||||
|
|
||||||
RenderDisplay(cmdlist, left, top, width, height, static_cast<D3D12::Texture*>(m_display_texture),
|
RenderDisplay(cmdlist, left, top, width, height, static_cast<D3D12::Texture*>(m_display_texture),
|
||||||
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
|
||||||
|
@ -714,16 +742,10 @@ void D3D12HostDisplay::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, s32 lef
|
||||||
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
|
(static_cast<float>(texture_view_y) + position_adjust) / static_cast<float>(texture->GetHeight()),
|
||||||
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
(static_cast<float>(texture_view_width) - size_adjust) / static_cast<float>(texture->GetWidth()),
|
||||||
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
|
(static_cast<float>(texture_view_height) - size_adjust) / static_cast<float>(texture->GetHeight())};
|
||||||
if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
|
|
||||||
Panic("Failed to reserve UBO space");
|
|
||||||
|
|
||||||
const u32 ubo_offset = m_display_uniform_buffer.GetCurrentOffset();
|
|
||||||
std::memcpy(m_display_uniform_buffer.GetCurrentHostPointer(), uniforms, sizeof(uniforms));
|
|
||||||
m_display_uniform_buffer.CommitMemory(sizeof(uniforms));
|
|
||||||
|
|
||||||
cmdlist->SetGraphicsRootSignature(m_display_root_signature.Get());
|
cmdlist->SetGraphicsRootSignature(m_display_root_signature.Get());
|
||||||
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
||||||
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
|
cmdlist->SetGraphicsRoot32BitConstants(0, static_cast<UINT>(std::size(uniforms)), uniforms, 0);
|
||||||
cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor());
|
cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor());
|
||||||
cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler);
|
cmdlist->SetGraphicsRootDescriptorTable(2, linear_filter ? m_linear_sampler : m_point_sampler);
|
||||||
|
|
||||||
|
@ -746,15 +768,9 @@ void D3D12HostDisplay::RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist,
|
||||||
s32 height, GPUTexture* texture_handle)
|
s32 height, GPUTexture* texture_handle)
|
||||||
{
|
{
|
||||||
const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f};
|
const float uniforms[4] = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||||
if (!m_display_uniform_buffer.ReserveMemory(sizeof(uniforms), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
|
|
||||||
Panic("Failed to reserve UBO space");
|
|
||||||
|
|
||||||
const u32 ubo_offset = m_display_uniform_buffer.GetCurrentOffset();
|
|
||||||
std::memcpy(m_display_uniform_buffer.GetCurrentHostPointer(), uniforms, sizeof(uniforms));
|
|
||||||
m_display_uniform_buffer.CommitMemory(sizeof(uniforms));
|
|
||||||
|
|
||||||
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
cmdlist->SetPipelineState(m_display_pipeline.Get());
|
||||||
cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset);
|
cmdlist->SetGraphicsRoot32BitConstants(0, static_cast<UINT>(std::size(uniforms)), uniforms, 0);
|
||||||
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12::Texture*>(texture_handle)->GetRTVOrDSVDescriptor());
|
cmdlist->SetGraphicsRootDescriptorTable(1, static_cast<D3D12::Texture*>(texture_handle)->GetRTVOrDSVDescriptor());
|
||||||
cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler);
|
cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler);
|
||||||
|
|
||||||
|
@ -846,7 +862,227 @@ HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFac
|
||||||
return adapter_info;
|
return adapter_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12HostDisplay::PostProcessingStage::PostProcessingStage(PostProcessingStage&& move)
|
||||||
|
: pipeline(std::move(move.pipeline)), output_texture(std::move(move.output_texture)),
|
||||||
|
uniforms_size(move.uniforms_size)
|
||||||
|
{
|
||||||
|
move.uniforms_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12HostDisplay::PostProcessingStage::~PostProcessingStage()
|
||||||
|
{
|
||||||
|
output_texture.Destroy(true);
|
||||||
|
}
|
||||||
|
|
||||||
bool D3D12HostDisplay::SetPostProcessingChain(const std::string_view& config)
|
bool D3D12HostDisplay::SetPostProcessingChain(const std::string_view& config)
|
||||||
|
{
|
||||||
|
g_d3d12_context->ExecuteCommandList(true);
|
||||||
|
|
||||||
|
if (config.empty())
|
||||||
|
{
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
m_post_processing_chain.ClearStages();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_post_processing_chain.CreateFromString(config))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
|
||||||
|
D3D12::ShaderCache shader_cache;
|
||||||
|
shader_cache.Open(EmuFolders::Cache, g_d3d12_context->GetFeatureLevel(), g_settings.gpu_use_debug_device);
|
||||||
|
|
||||||
|
FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::D3D12, false);
|
||||||
|
bool only_use_push_constants = true;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_post_processing_chain.GetStageCount(); i++)
|
||||||
|
{
|
||||||
|
const FrontendCommon::PostProcessingShader& shader = m_post_processing_chain.GetShaderStage(i);
|
||||||
|
const std::string vs = shadergen.GeneratePostProcessingVertexShader(shader);
|
||||||
|
const std::string ps = shadergen.GeneratePostProcessingFragmentShader(shader);
|
||||||
|
const bool use_push_constants = shader.UsePushConstants();
|
||||||
|
only_use_push_constants &= use_push_constants;
|
||||||
|
|
||||||
|
PostProcessingStage stage;
|
||||||
|
stage.uniforms_size = shader.GetUniformsSize();
|
||||||
|
|
||||||
|
ComPtr<ID3DBlob> vs_blob(shader_cache.GetVertexShader(vs));
|
||||||
|
ComPtr<ID3DBlob> ps_blob(shader_cache.GetPixelShader(ps));
|
||||||
|
if (!vs_blob || !ps_blob)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling.");
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
m_post_processing_chain.ClearStages();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::GraphicsPipelineBuilder gpbuilder;
|
||||||
|
gpbuilder.SetVertexShader(vs_blob.Get());
|
||||||
|
gpbuilder.SetPixelShader(ps_blob.Get());
|
||||||
|
gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
|
||||||
|
gpbuilder.SetNoCullRasterizationState();
|
||||||
|
gpbuilder.SetNoDepthTestState();
|
||||||
|
gpbuilder.SetNoBlendingState();
|
||||||
|
gpbuilder.SetRootSignature(use_push_constants ? m_post_processing_root_signature.Get() :
|
||||||
|
m_post_processing_cb_root_signature.Get());
|
||||||
|
gpbuilder.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||||
|
|
||||||
|
stage.pipeline = gpbuilder.Create(g_d3d12_context->GetDevice(), shader_cache);
|
||||||
|
if (!stage.pipeline)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to compile one or more post-processing pipelines, disabling.");
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
m_post_processing_chain.ClearStages();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
D3D12::SetObjectNameFormatted(stage.pipeline.Get(), "%s Pipeline", shader.GetName().c_str());
|
||||||
|
|
||||||
|
m_post_processing_stages.push_back(std::move(stage));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u32 UBO_SIZE = 1 * 1024 * 1024;
|
||||||
|
if (!only_use_push_constants && m_post_processing_cbuffer.GetSize() < UBO_SIZE)
|
||||||
|
{
|
||||||
|
if (!m_post_processing_cbuffer.Create(UBO_SIZE))
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to allocate %u byte constant buffer for postprocessing", UBO_SIZE);
|
||||||
|
m_post_processing_stages.clear();
|
||||||
|
m_post_processing_chain.ClearStages();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::SetObjectName(m_post_processing_cbuffer.GetBuffer(), "Post Processing Uniform Buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_post_processing_timer.Reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool D3D12HostDisplay::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height)
|
||||||
|
{
|
||||||
|
DebugAssert(!m_post_processing_stages.empty());
|
||||||
|
|
||||||
|
const DXGI_FORMAT tex_format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
const DXGI_FORMAT srv_format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
const DXGI_FORMAT rtv_format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
|
if (m_post_processing_input_texture.GetWidth() != target_width ||
|
||||||
|
m_post_processing_input_texture.GetHeight() != target_height)
|
||||||
|
{
|
||||||
|
if (!m_post_processing_input_texture.Create(target_width, target_height, 1, 1, 1, tex_format, srv_format,
|
||||||
|
rtv_format, DXGI_FORMAT_UNKNOWN,
|
||||||
|
D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
D3D12::SetObjectName(m_post_processing_input_texture.GetResource(), "Post Processing Input Texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 target_count = (static_cast<u32>(m_post_processing_stages.size()) - 1);
|
||||||
|
for (u32 i = 0; i < target_count; i++)
|
||||||
|
{
|
||||||
|
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||||
|
if (pps.output_texture.GetWidth() != target_width || pps.output_texture.GetHeight() != target_height)
|
||||||
|
{
|
||||||
|
if (!pps.output_texture.Create(target_width, target_height, 1, 1, 1, tex_format, srv_format, rtv_format,
|
||||||
|
DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
D3D12::SetObjectNameFormatted(pps.output_texture.GetResource(), "Post Processing Output Texture %u", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12HostDisplay::ApplyPostProcessingChain(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* final_target,
|
||||||
|
s32 final_left, s32 final_top, s32 final_width, s32 final_height,
|
||||||
|
D3D12::Texture* texture, s32 texture_view_x, s32 texture_view_y,
|
||||||
|
s32 texture_view_width, s32 texture_view_height, u32 target_width,
|
||||||
|
u32 target_height)
|
||||||
|
{
|
||||||
|
if (!CheckPostProcessingRenderTargets(target_width, target_height))
|
||||||
|
{
|
||||||
|
final_target->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
|
cmdlist->ClearRenderTargetView(final_target->GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr);
|
||||||
|
cmdlist->OMSetRenderTargets(1, &final_target->GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
||||||
|
|
||||||
|
RenderDisplay(cmdlist, final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||||
|
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// downsample/upsample - use same viewport for remainder
|
||||||
|
m_post_processing_input_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
|
cmdlist->ClearRenderTargetView(m_post_processing_input_texture.GetRTVOrDSVDescriptor(), s_clear_color.data(), 0,
|
||||||
|
nullptr);
|
||||||
|
cmdlist->OMSetRenderTargets(1, &m_post_processing_input_texture.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
||||||
|
RenderDisplay(cmdlist, final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y,
|
||||||
|
texture_view_width, texture_view_height, IsUsingLinearFiltering());
|
||||||
|
m_post_processing_input_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||||
|
|
||||||
|
const s32 orig_texture_width = texture_view_width;
|
||||||
|
const s32 orig_texture_height = texture_view_height;
|
||||||
|
texture = &m_post_processing_input_texture;
|
||||||
|
texture_view_x = final_left;
|
||||||
|
texture_view_y = final_top;
|
||||||
|
texture_view_width = final_width;
|
||||||
|
texture_view_height = final_height;
|
||||||
|
|
||||||
|
const u32 final_stage = static_cast<u32>(m_post_processing_stages.size()) - 1u;
|
||||||
|
for (u32 i = 0; i < static_cast<u32>(m_post_processing_stages.size()); i++)
|
||||||
|
{
|
||||||
|
PostProcessingStage& pps = m_post_processing_stages[i];
|
||||||
|
|
||||||
|
const bool use_push_constants = m_post_processing_chain.GetShaderStage(i).UsePushConstants();
|
||||||
|
if (use_push_constants)
|
||||||
|
{
|
||||||
|
u8 buffer[FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD];
|
||||||
|
Assert(pps.uniforms_size <= sizeof(buffer));
|
||||||
|
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||||
|
buffer, texture->GetWidth(), texture->GetHeight(), texture_view_x, texture_view_y, texture_view_width,
|
||||||
|
texture_view_height, GetWindowWidth(), GetWindowHeight(), orig_texture_width, orig_texture_height,
|
||||||
|
static_cast<float>(m_post_processing_timer.GetTimeSeconds()));
|
||||||
|
|
||||||
|
cmdlist->SetGraphicsRootSignature(m_post_processing_root_signature.Get());
|
||||||
|
cmdlist->SetGraphicsRoot32BitConstants(0, sizeof(buffer) / sizeof(u32), buffer, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_post_processing_cbuffer.ReserveMemory(pps.uniforms_size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT))
|
||||||
|
{
|
||||||
|
Panic("Failed to reserve space in post-processing UBO");
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 offset = m_post_processing_cbuffer.GetCurrentOffset();
|
||||||
|
m_post_processing_chain.GetShaderStage(i).FillUniformBuffer(
|
||||||
|
m_post_processing_cbuffer.GetCurrentHostPointer(), texture->GetWidth(), texture->GetHeight(), texture_view_x,
|
||||||
|
texture_view_y, texture_view_width, texture_view_height, GetWindowWidth(), GetWindowHeight(),
|
||||||
|
orig_texture_width, orig_texture_height, static_cast<float>(m_post_processing_timer.GetTimeSeconds()));
|
||||||
|
m_post_processing_cbuffer.CommitMemory(pps.uniforms_size);
|
||||||
|
|
||||||
|
cmdlist->SetGraphicsRootSignature(m_post_processing_cb_root_signature.Get());
|
||||||
|
cmdlist->SetGraphicsRootConstantBufferView(0, m_post_processing_cbuffer.GetGPUPointer() + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12::Texture* rt = (i != final_stage) ? &pps.output_texture : final_target;
|
||||||
|
rt->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||||
|
cmdlist->ClearRenderTargetView(rt->GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr);
|
||||||
|
cmdlist->OMSetRenderTargets(1, &rt->GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr);
|
||||||
|
|
||||||
|
cmdlist->SetPipelineState(pps.pipeline.Get());
|
||||||
|
cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor());
|
||||||
|
cmdlist->SetGraphicsRootDescriptorTable(2, m_point_sampler);
|
||||||
|
|
||||||
|
cmdlist->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||||
|
cmdlist->DrawInstanced(3, 1, 0, 0);
|
||||||
|
|
||||||
|
if (i != final_stage)
|
||||||
|
{
|
||||||
|
pps.output_texture.TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||||
|
texture = &pps.output_texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#pragma once
|
|
||||||
#include "common/d3d12/descriptor_heap_manager.h"
|
#include "common/d3d12/descriptor_heap_manager.h"
|
||||||
#include "common/d3d12/staging_texture.h"
|
#include "common/d3d12/staging_texture.h"
|
||||||
#include "common/d3d12/stream_buffer.h"
|
#include "common/d3d12/stream_buffer.h"
|
||||||
#include "common/d3d12/texture.h"
|
#include "common/d3d12/texture.h"
|
||||||
|
#include "common/timer.h"
|
||||||
#include "common/window_info.h"
|
#include "common/window_info.h"
|
||||||
#include "common/windows_headers.h"
|
#include "common/windows_headers.h"
|
||||||
#include "core/host_display.h"
|
#include "core/host_display.h"
|
||||||
|
#include "postprocessing_chain.h"
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
#include <dxgi.h>
|
#include <dxgi.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -73,10 +74,15 @@ public:
|
||||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : u32
|
struct PostProcessingStage
|
||||||
{
|
{
|
||||||
DISPLAY_UNIFORM_BUFFER_SIZE = 65536,
|
PostProcessingStage() = default;
|
||||||
TEXTURE_STREAMING_BUFFER_SIZE = 4 * 1024 * 1024
|
PostProcessingStage(PostProcessingStage&& move);
|
||||||
|
~PostProcessingStage();
|
||||||
|
|
||||||
|
ComPtr<ID3D12PipelineState> pipeline;
|
||||||
|
D3D12::Texture output_texture;
|
||||||
|
u32 uniforms_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
|
static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory);
|
||||||
|
@ -92,7 +98,7 @@ protected:
|
||||||
bool CreateSwapChainRTV();
|
bool CreateSwapChainRTV();
|
||||||
void DestroySwapChainRTVs();
|
void DestroySwapChainRTVs();
|
||||||
|
|
||||||
void RenderDisplay(ID3D12GraphicsCommandList* cmdlist);
|
void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* swap_chain_buf);
|
||||||
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist);
|
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist);
|
||||||
void RenderImGui(ID3D12GraphicsCommandList* cmdlist);
|
void RenderImGui(ID3D12GraphicsCommandList* cmdlist);
|
||||||
|
|
||||||
|
@ -102,6 +108,12 @@ protected:
|
||||||
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height,
|
||||||
GPUTexture* texture_handle);
|
GPUTexture* texture_handle);
|
||||||
|
|
||||||
|
bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height);
|
||||||
|
void ApplyPostProcessingChain(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* final_target, s32 final_left,
|
||||||
|
s32 final_top, s32 final_width, s32 final_height, D3D12::Texture* texture,
|
||||||
|
s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height,
|
||||||
|
u32 target_width, u32 target_height);
|
||||||
|
|
||||||
ComPtr<IDXGIFactory> m_dxgi_factory;
|
ComPtr<IDXGIFactory> m_dxgi_factory;
|
||||||
ComPtr<IDXGISwapChain> m_swap_chain;
|
ComPtr<IDXGISwapChain> m_swap_chain;
|
||||||
std::vector<D3D12::Texture> m_swap_chain_buffers;
|
std::vector<D3D12::Texture> m_swap_chain_buffers;
|
||||||
|
@ -114,9 +126,16 @@ protected:
|
||||||
D3D12::DescriptorHandle m_linear_sampler;
|
D3D12::DescriptorHandle m_linear_sampler;
|
||||||
|
|
||||||
D3D12::Texture m_display_pixels_texture;
|
D3D12::Texture m_display_pixels_texture;
|
||||||
D3D12::StreamBuffer m_display_uniform_buffer;
|
|
||||||
D3D12::StagingTexture m_readback_staging_texture;
|
D3D12::StagingTexture m_readback_staging_texture;
|
||||||
|
|
||||||
|
ComPtr<ID3D12RootSignature> m_post_processing_root_signature;
|
||||||
|
ComPtr<ID3D12RootSignature> m_post_processing_cb_root_signature;
|
||||||
|
FrontendCommon::PostProcessingChain m_post_processing_chain;
|
||||||
|
D3D12::StreamBuffer m_post_processing_cbuffer;
|
||||||
|
D3D12::Texture m_post_processing_input_texture;
|
||||||
|
std::vector<PostProcessingStage> m_post_processing_stages;
|
||||||
|
Common::Timer m_post_processing_timer;
|
||||||
|
|
||||||
bool m_allow_tearing_supported = false;
|
bool m_allow_tearing_supported = false;
|
||||||
bool m_using_allow_tearing = false;
|
bool m_using_allow_tearing = false;
|
||||||
bool m_vsync = true;
|
bool m_vsync = true;
|
||||||
|
|
Loading…
Reference in New Issue