From adf41b9bbd23e58b10e8b3c6e1cd88a53af309b0 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 13 Oct 2022 19:56:57 +1000 Subject: [PATCH] D3D12HostDisplay: Implement post processing --- src/core/cdrom.cpp | 18 +- src/frontend-common/d3d12_host_display.cpp | 336 ++++++++++++++++++--- src/frontend-common/d3d12_host_display.h | 31 +- 3 files changed, 315 insertions(+), 70 deletions(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 1baf5cb20..44b7c1290 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -213,21 +213,11 @@ void CDROM::SoftReset(TickCount ticks_late) if (HasMedia()) { - const TickCount toc_read_ticks = GetTicksForTOCRead(); const TickCount speed_change_ticks = was_double_speed ? GetTicksForSpeedChange() : 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; - - if (was_double_speed) - { - 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); - } + const TickCount total_ticks = std::max(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, + seek_ticks); if (m_current_lba != 0) { @@ -1351,7 +1341,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Init: { - Log_DebugPrintf("CDROM reset command"); + Log_DebugPrintf("CDROM init command"); if (m_command_second_response == Command::Init) { diff --git a/src/frontend-common/d3d12_host_display.cpp b/src/frontend-common/d3d12_host_display.cpp index 3df04a459..d1d4935eb 100644 --- a/src/frontend-common/d3d12_host_display.cpp +++ b/src/frontend-common/d3d12_host_display.cpp @@ -2,6 +2,7 @@ #include "common/assert.h" #include "common/d3d11/shader_compiler.h" #include "common/d3d12/context.h" +#include "common/d3d12/shader_cache.h" #include "common/d3d12/util.h" #include "common/log.h" #include "common/string_util.h" @@ -15,6 +16,8 @@ #include Log_SetChannel(D3D12HostDisplay); +static constexpr const std::array s_clear_color = {0.0f, 0.0f, 0.0f, 1.0f}; + D3D12HostDisplay::D3D12HostDisplay() = default; D3D12HostDisplay::~D3D12HostDisplay() @@ -501,13 +504,30 @@ HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList() bool D3D12HostDisplay::CreateResources() { 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_SAMPLER, 0, 1, D3D12_SHADER_VISIBILITY_ALL); m_display_root_signature = rsbuilder.Create(); if (!m_display_root_signature) 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; gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); 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); - if (!m_display_uniform_buffer.Create(DISPLAY_UNIFORM_BUFFER_SIZE)) - return false; - return true; } void D3D12HostDisplay::DestroyResources() { - // m_post_processing_chain.ClearStages(); - // m_post_processing_input_texture.Destroy(); - // m_post_processing_stages.clear(); + m_post_processing_cbuffer.Destroy(false); + m_post_processing_chain.ClearStages(); + 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_display_uniform_buffer.Destroy(false); g_d3d12_context->GetSamplerHeapManager().Free(&m_linear_sampler); g_d3d12_context->GetSamplerHeapManager().Free(&m_point_sampler); m_software_cursor_pipeline.Reset(); @@ -596,16 +615,11 @@ bool D3D12HostDisplay::Render(bool skip_present) return false; } - static constexpr std::array clear_color = {}; 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(m_swap_chain_buffers.size())); ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList(); - swap_chain_buf.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); - cmdlist->ClearRenderTargetView(swap_chain_buf.GetRTVOrDSVDescriptor(), clear_color.data(), 0, nullptr); - cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr); - - RenderDisplay(cmdlist); + RenderDisplay(cmdlist, &swap_chain_buf); if (ImGui::GetCurrentContext()) RenderImGui(cmdlist); @@ -637,18 +651,28 @@ bool D3D12HostDisplay::RenderScreenshot(u32 width, u32 height, std::vector* return false; } - static constexpr std::array clear_color = {}; ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList(); - render_texture.TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); - cmdlist->ClearRenderTargetView(render_texture.GetRTVOrDSVDescriptor(), clear_color.data(), 0, nullptr); - cmdlist->OMSetRenderTargets(1, &render_texture.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr); + const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height); - if (HasDisplayTexture()) + if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) { - const auto [left, top, draw_width, draw_height] = CalculateDrawRect(width, height, 0); - RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast(m_display_texture), - m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, IsUsingLinearFiltering()); + ApplyPostProcessingChain(cmdlist, &render_texture, left, top, width, height, + static_cast(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); + cmdlist->ClearRenderTargetView(render_texture.GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr); + cmdlist->OMSetRenderTargets(1, &render_texture.GetRTVOrDSVDescriptor().cpu_handle, FALSE, nullptr); + + if (HasDisplayTexture()) + { + RenderDisplay(cmdlist, left, top, draw_width, draw_height, static_cast(m_display_texture), + m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); + } } cmdlist->OMSetRenderTargets(0, nullptr, FALSE, nullptr); @@ -682,21 +706,25 @@ void D3D12HostDisplay::RenderImGui(ID3D12GraphicsCommandList* cmdlist) 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()); - // if (!m_post_processing_chain.IsEmpty()) - // { - // ApplyPostProcessingChain(m_swap_chain_rtv.Get(), left, top, width, height, m_display_texture_handle, - // m_display_texture_width, m_display_texture_height, m_display_texture_view_x, - // m_display_texture_view_y, m_display_texture_view_width, - // m_display_texture_view_height); - // return; - // } + if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) + { + ApplyPostProcessingChain(cmdlist, swap_chain_buf, left, top, width, height, + static_cast(m_display_texture), m_display_texture_view_x, + m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, + GetWindowWidth(), GetWindowHeight()); + 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(m_display_texture), 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(texture_view_y) + position_adjust) / static_cast(texture->GetHeight()), (static_cast(texture_view_width) - size_adjust) / static_cast(texture->GetWidth()), (static_cast(texture_view_height) - size_adjust) / static_cast(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->SetPipelineState(m_display_pipeline.Get()); - cmdlist->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); + cmdlist->SetGraphicsRoot32BitConstants(0, static_cast(std::size(uniforms)), uniforms, 0); cmdlist->SetGraphicsRootDescriptorTable(1, texture->GetSRVDescriptor()); 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) { 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->SetGraphicsRootConstantBufferView(0, m_display_uniform_buffer.GetGPUPointer() + ubo_offset); + cmdlist->SetGraphicsRoot32BitConstants(0, static_cast(std::size(uniforms)), uniforms, 0); cmdlist->SetGraphicsRootDescriptorTable(1, static_cast(texture_handle)->GetRTVOrDSVDescriptor()); cmdlist->SetGraphicsRootDescriptorTable(2, m_linear_sampler); @@ -846,7 +862,227 @@ HostDisplay::AdapterAndModeList D3D12HostDisplay::GetAdapterAndModeList(IDXGIFac 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) { - return false; + 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 vs_blob(shader_cache.GetVertexShader(vs)); + ComPtr 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; + } + D3D12::SetObjectName(m_post_processing_input_texture.GetResource(), "Post Processing Input Texture"); + } + + const u32 target_count = (static_cast(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(m_post_processing_stages.size()) - 1u; + for (u32 i = 0; i < static_cast(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(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(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; + } + } } diff --git a/src/frontend-common/d3d12_host_display.h b/src/frontend-common/d3d12_host_display.h index 833d3d70f..4b1f2d13b 100644 --- a/src/frontend-common/d3d12_host_display.h +++ b/src/frontend-common/d3d12_host_display.h @@ -1,12 +1,13 @@ #pragma once -#pragma once #include "common/d3d12/descriptor_heap_manager.h" #include "common/d3d12/staging_texture.h" #include "common/d3d12/stream_buffer.h" #include "common/d3d12/texture.h" +#include "common/timer.h" #include "common/window_info.h" #include "common/windows_headers.h" #include "core/host_display.h" +#include "postprocessing_chain.h" #include #include #include @@ -73,10 +74,15 @@ public: static AdapterAndModeList StaticGetAdapterAndModeList(); protected: - enum : u32 + struct PostProcessingStage { - DISPLAY_UNIFORM_BUFFER_SIZE = 65536, - TEXTURE_STREAMING_BUFFER_SIZE = 4 * 1024 * 1024 + PostProcessingStage() = default; + PostProcessingStage(PostProcessingStage&& move); + ~PostProcessingStage(); + + ComPtr pipeline; + D3D12::Texture output_texture; + u32 uniforms_size = 0; }; static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); @@ -92,7 +98,7 @@ protected: bool CreateSwapChainRTV(); void DestroySwapChainRTVs(); - void RenderDisplay(ID3D12GraphicsCommandList* cmdlist); + void RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Texture* swap_chain_buf); void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist); void RenderImGui(ID3D12GraphicsCommandList* cmdlist); @@ -102,6 +108,12 @@ protected: void RenderSoftwareCursor(ID3D12GraphicsCommandList* cmdlist, s32 left, s32 top, s32 width, s32 height, 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 m_dxgi_factory; ComPtr m_swap_chain; std::vector m_swap_chain_buffers; @@ -114,9 +126,16 @@ protected: D3D12::DescriptorHandle m_linear_sampler; D3D12::Texture m_display_pixels_texture; - D3D12::StreamBuffer m_display_uniform_buffer; D3D12::StagingTexture m_readback_staging_texture; + ComPtr m_post_processing_root_signature; + ComPtr 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 m_post_processing_stages; + Common::Timer m_post_processing_timer; + bool m_allow_tearing_supported = false; bool m_using_allow_tearing = false; bool m_vsync = true;