From a43b6ee9dbca48085f2cf794fb89006c216e8a96 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 2 Aug 2023 21:40:53 +1000 Subject: [PATCH] Postfx --- src/core/gpu/d3d11_device.cpp | 342 ++++-------------- src/core/gpu/d3d11_device.h | 14 +- src/core/gpu/d3d12_gpu_device.cpp | 29 +- src/core/gpu/d3d12_gpu_device.h | 28 -- src/core/gpu/gpu_device.cpp | 148 ++++---- src/core/gpu/gpu_device.h | 39 +- src/core/gpu/opengl_gpu_device.cpp | 26 +- src/core/gpu/opengl_gpu_device.h | 21 -- src/core/gpu/postprocessing_chain.cpp | 122 ++++++- src/core/gpu/postprocessing_chain.h | 29 +- src/core/gpu/postprocessing_shader.cpp | 83 ++++- src/core/gpu/postprocessing_shader.h | 41 ++- src/core/gpu/postprocessing_shadergen.cpp | 8 +- src/core/gpu/postprocessing_shadergen.h | 5 - src/core/gpu/vulkan_gpu_device.cpp | 30 +- src/core/gpu/vulkan_gpu_device.h | 27 -- src/core/gpu_hw.cpp | 112 +++--- src/core/gpu_hw.h | 11 +- .../postprocessingchainconfigwidget.cpp | 4 +- .../postprocessingchainconfigwidget.h | 4 +- .../postprocessingsettingswidget.cpp | 2 +- .../postprocessingshaderconfigwidget.cpp | 6 +- .../postprocessingshaderconfigwidget.h | 6 +- src/frontend-common/fullscreen_ui.cpp | 20 +- 24 files changed, 528 insertions(+), 629 deletions(-) diff --git a/src/core/gpu/d3d11_device.cpp b/src/core/gpu/d3d11_device.cpp index dde18fb8b..0a80ac504 100644 --- a/src/core/gpu/d3d11_device.cpp +++ b/src/core/gpu/d3d11_device.cpp @@ -38,6 +38,12 @@ static void SetD3DDebugObjectName(ID3D11DeviceChild* obj, const std::string_view { // WKPDID_D3DDebugObjectName static constexpr GUID guid = {0x429b8c22, 0x9188, 0x4b0c, 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00}; + + UINT existing_data_size; + HRESULT hr = obj->GetPrivateData(guid, &existing_data_size, nullptr); + if (SUCCEEDED(hr) && existing_data_size > 0) + return; + const std::wstring wname = StringUtil::UTF8StringToWideString(name); obj->SetPrivateData(guid, static_cast(wname.length()) * 2u, wname.c_str()); } @@ -163,21 +169,6 @@ RenderAPI D3D11Device::GetRenderAPI() const return RenderAPI::D3D11; } -void* D3D11Device::GetDevice() const -{ - return m_device.Get(); -} - -void* D3D11Device::GetContext() const -{ - return m_context.Get(); -} - -bool D3D11Device::HasDevice() const -{ - return static_cast(m_device); -} - bool D3D11Device::HasSurface() const { return static_cast(m_swap_chain); @@ -396,11 +387,12 @@ bool D3D11Device::CreateDevice(const WindowInfo& wi, bool vsync) static constexpr std::array requested_feature_levels = { {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}}; + ComPtr device; + ComPtr context; hr = D3D11CreateDevice(dxgi_adapter.Get(), dxgi_adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, create_flags, requested_feature_levels.data(), static_cast(requested_feature_levels.size()), - D3D11_SDK_VERSION, m_device.GetAddressOf(), nullptr, m_context.GetAddressOf()); - + D3D11_SDK_VERSION, device.GetAddressOf(), nullptr, context.GetAddressOf()); // we re-grab these later, see below dxgi_adapter.Reset(); temp_dxgi_factory.Reset(); @@ -410,6 +402,11 @@ bool D3D11Device::CreateDevice(const WindowInfo& wi, bool vsync) Log_ErrorPrintf("Failed to create D3D device: 0x%08X", hr); return false; } + else if (FAILED(hr = device.As(&m_device)) || FAILED(hr = context.As(&m_context))) + { + Log_ErrorPrintf("Failed to get D3D11.1 device: 0x%08X", hr); + return false; + } if (g_settings.gpu_use_debug_device && IsDebuggerPresent()) { @@ -603,20 +600,22 @@ bool D3D11Device::CreateSwapChainRTV() return false; } - D3D11_TEXTURE2D_DESC backbuffer_desc; - backbuffer->GetDesc(&backbuffer_desc); - - CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D, backbuffer_desc.Format, 0, 0, - backbuffer_desc.ArraySize); - hr = m_device->CreateRenderTargetView(backbuffer.Get(), &rtv_desc, m_swap_chain_rtv.GetAddressOf()); - if (FAILED(hr)) + m_swap_chain_texture = std::make_unique(); + if (!m_swap_chain_texture->Adopt(m_device.Get(), std::move(backbuffer))) { - Log_ErrorPrintf("CreateRenderTargetView for swap chain failed: 0x%08X", hr); + m_swap_chain_texture.reset(); return false; } - m_window_info.surface_width = backbuffer_desc.Width; - m_window_info.surface_height = backbuffer_desc.Height; + if (!(m_swap_chain_framebuffer = std::unique_ptr( + static_cast(CreateFramebuffer(m_swap_chain_texture.get()).release())))) + { + m_swap_chain_texture.reset(); + return false; + } + + m_window_info.surface_width = m_swap_chain_texture->GetWidth(); + m_window_info.surface_height = m_swap_chain_texture->GetHeight(); Log_InfoPrintf("Swap chain buffer size: %ux%u", m_window_info.surface_width, m_window_info.surface_height); if (m_window_info.type == WindowInfo::Type::Win32) @@ -652,7 +651,8 @@ void D3D11Device::DestroySurface() if (IsFullscreen()) SetFullscreen(false, 0, 0, 0.0f); - m_swap_chain_rtv.Reset(); + m_swap_chain_framebuffer.reset(); + m_swap_chain_texture.reset(); m_swap_chain.Reset(); } @@ -676,7 +676,8 @@ void D3D11Device::ResizeWindow(s32 new_window_width, s32 new_window_height) if (!m_swap_chain) return; - m_swap_chain_rtv.Reset(); + m_swap_chain_framebuffer.reset(); + m_swap_chain_texture.reset(); HRESULT hr = m_swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, m_using_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); @@ -745,7 +746,8 @@ bool D3D11Device::SetFullscreen(bool fullscreen, u32 width, u32 height, float re return true; } - m_swap_chain_rtv.Reset(); + m_swap_chain_framebuffer.reset(); + m_swap_chain_texture.reset(); m_swap_chain.Reset(); if (!CreateSwapChain(&closest_mode)) @@ -764,7 +766,7 @@ bool D3D11Device::CreateBuffers() { if (!m_vertex_buffer.Create(m_device.Get(), D3D11_BIND_VERTEX_BUFFER, VERTEX_BUFFER_SIZE) || !m_index_buffer.Create(m_device.Get(), D3D11_BIND_INDEX_BUFFER, INDEX_BUFFER_SIZE) || - !m_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, MAX_UNIFORM_BUFFER_SIZE)) + !m_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, UNIFORM_BUFFER_SIZE)) { Log_ErrorPrintf("Failed to create vertex/index/uniform buffers."); return false; @@ -795,11 +797,19 @@ bool D3D11Device::Render(bool skip_present) if (m_vsync_enabled && m_gpu_timing_enabled) PopTimestampQuery(); - m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), s_clear_color.data()); - m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr); - m_current_framebuffer = nullptr; + ClearRenderTarget(m_swap_chain_texture.get(), 0); - RenderDisplay(); + if (HasDisplayTexture()) + { + const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight()); + GL_SCOPE("RenderDisplay: %dx%d at %d,%d", left, top, width, height); + RenderDisplay(m_swap_chain_framebuffer.get(), left, top, width, height, m_display_texture, m_display_texture_view_x, + m_display_texture_view_y, m_display_texture_view_width, m_display_texture_view_height, + IsUsingLinearFiltering()); + } + + SetFramebuffer(m_swap_chain_framebuffer.get()); + SetViewportAndScissor(0, 0, m_swap_chain_framebuffer->GetWidth(), m_swap_chain_framebuffer->GetHeight()); RenderImGui(); @@ -816,6 +826,8 @@ bool D3D11Device::Render(bool skip_present) if (m_gpu_timing_enabled) KickTimestampQuery(); + m_current_framebuffer = nullptr; + return true; } @@ -1032,9 +1044,9 @@ D3D11Framebuffer::~D3D11Framebuffer() = default; void D3D11Framebuffer::SetDebugName(const std::string_view& name) { if (m_rtv) - SetD3DDebugObjectName(m_rtv.Get(), name); + SetD3DDebugObjectName(m_rtv.Get(), fmt::format("{} RTV", name)); if (m_dsv) - SetD3DDebugObjectName(m_dsv.Get(), name); + SetD3DDebugObjectName(m_dsv.Get(), fmt::format("{} DSV", name)); } void D3D11Framebuffer::CommitClear(ID3D11DeviceContext* context) @@ -1633,7 +1645,7 @@ std::unique_ptr D3D11Device::CreatePipeline(const GPUPipeline::Grap return std::unique_ptr( new D3D11Pipeline(std::move(rs), std::move(ds), std::move(bs), std::move(il), static_cast(config.vertex_shader)->GetVertexShader(), - static_cast(config.pixel_shader)->GetPixelShader(), + static_cast(config.fragment_shader)->GetPixelShader(), primitives[static_cast(config.primitive)])); } @@ -2070,29 +2082,33 @@ void D3D11Device::UnmapIndexBuffer(u32 used_index_count) void D3D11Device::PushUniformBuffer(const void* data, u32 data_size) { - Assert(data_size <= MAX_UNIFORM_BUFFER_SIZE); - - const auto res = m_uniform_buffer.Map(m_context.Get(), MAX_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE); + const u32 used_space = Common::AlignUpPow2(data_size, UNIFORM_BUFFER_ALIGNMENT); + const auto res = m_uniform_buffer.Map(m_context.Get(), UNIFORM_BUFFER_ALIGNMENT, used_space); std::memcpy(res.pointer, data, data_size); m_uniform_buffer.Unmap(m_context.Get(), data_size); - m_context->VSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray()); - m_context->PSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray()); + const UINT first_constant = (res.index_aligned * UNIFORM_BUFFER_ALIGNMENT) / 16u; + const UINT num_constants = (used_space * UNIFORM_BUFFER_ALIGNMENT) / 16u; + m_context->VSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants); + m_context->PSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants); } void* D3D11Device::MapUniformBuffer(u32 size) { - Assert(size <= MAX_UNIFORM_BUFFER_SIZE); - - const auto res = m_uniform_buffer.Map(m_context.Get(), MAX_UNIFORM_BUFFER_SIZE, MAX_UNIFORM_BUFFER_SIZE); + const u32 used_space = Common::AlignUpPow2(size, UNIFORM_BUFFER_ALIGNMENT); + const auto res = m_uniform_buffer.Map(m_context.Get(), UNIFORM_BUFFER_ALIGNMENT, used_space); return res.pointer; } void D3D11Device::UnmapUniformBuffer(u32 size) { - m_uniform_buffer.Unmap(m_context.Get(), size); - m_context->VSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray()); - m_context->PSSetConstantBuffers(0, 1, m_uniform_buffer.GetD3DBufferArray()); + const u32 used_space = Common::AlignUpPow2(size, UNIFORM_BUFFER_ALIGNMENT); + const UINT first_constant = m_uniform_buffer.GetPosition() / 16u; + const UINT num_constants = used_space / 16u; + + m_uniform_buffer.Unmap(m_context.Get(), used_space); + m_context->VSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants); + m_context->PSSetConstantBuffers1(0, 1, m_uniform_buffer.GetD3DBufferArray(), &first_constant, &num_constants); } void D3D11Device::SetFramebuffer(GPUFramebuffer* fb) @@ -2186,231 +2202,3 @@ void D3D11Device::DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) PreDrawCheck(); m_context->DrawIndexed(index_count, base_index, base_vertex); } - -#if 0 - struct PostProcessingStage - { - ComPtr vertex_shader; - ComPtr pixel_shader; - D3D11Texture output_texture; - u32 uniforms_size; - }; - - bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); - void ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, s32 final_width, - s32 final_height, D3D11Texture* texture, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, u32 target_width, u32 target_height); - FrontendCommon::PostProcessingChain m_post_processing_chain; - D3D11Texture m_post_processing_input_texture; - std::vector m_post_processing_stages; - Common::Timer m_post_processing_timer; - - bool D3D11Device::SetPostProcessingChain(const std::string_view& config) -{ - if (config.empty()) - { - m_post_processing_input_texture.Destroy(); - 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(); - - D3D11::ShaderCache shader_cache; - shader_cache.Open(EmuFolders::Cache, m_device->GetFeatureLevel(), SHADER_CACHE_VERSION, - g_settings.gpu_use_debug_device); - - FrontendCommon::PostProcessingShaderGen shadergen(RenderAPI::D3D11, true); - u32 max_ubo_size = 0; - - 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); - - PostProcessingStage stage; - stage.uniforms_size = shader.GetUniformsSize(); - stage.vertex_shader = shader_cache.GetVertexShader(m_device.Get(), vs); - stage.pixel_shader = shader_cache.GetPixelShader(m_device.Get(), ps); - if (!stage.vertex_shader || !stage.pixel_shader) - { - Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling."); - m_post_processing_stages.clear(); - m_post_processing_chain.ClearStages(); - return false; - } - - max_ubo_size = std::max(max_ubo_size, stage.uniforms_size); - m_post_processing_stages.push_back(std::move(stage)); - } - - if (m_push_uniform_buffer.GetSize() < max_ubo_size && - !m_push_uniform_buffer.Create(m_device.Get(), D3D11_BIND_CONSTANT_BUFFER, max_ubo_size)) - { - Log_ErrorPrintf("Failed to allocate %u byte constant buffer for postprocessing", max_ubo_size); - m_post_processing_stages.clear(); - m_post_processing_chain.ClearStages(); - return false; - } - - m_post_processing_timer.Reset(); - return true; -} - -bool D3D11Device::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height) -{ - DebugAssert(!m_post_processing_stages.empty()); - - const GPUTexture::Type type = GPUTexture::Type::RenderTarget; - const GPUTexture::Format format = GPUTexture::Format::RGBA8; - - if (m_post_processing_input_texture.GetWidth() != target_width || - m_post_processing_input_texture.GetHeight() != target_height) - { - if (!m_post_processing_input_texture.Create(m_device.Get(), target_width, target_height, 1, 1, 1, type, format)) - return false; - } - - 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(m_device.Get(), target_width, target_height, 1, 1, 1, type, format)) - return false; - } - } - - return true; -} - -void D3D11Device::ApplyPostProcessingChain(ID3D11RenderTargetView* final_target, s32 final_left, s32 final_top, - s32 final_width, s32 final_height, D3D11Texture* 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)) - { - RenderDisplay(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_context->ClearRenderTargetView(m_post_processing_input_texture.GetD3DRTV(), s_clear_color.data()); - m_context->OMSetRenderTargets(1, m_post_processing_input_texture.GetD3DRTVArray(), nullptr); - RenderDisplay(final_left, final_top, final_width, final_height, texture, texture_view_x, texture_view_y, - texture_view_width, texture_view_height, IsUsingLinearFiltering()); - - 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]; - ID3D11RenderTargetView* rtv = (i == final_stage) ? final_target : pps.output_texture.GetD3DRTV(); - m_context->ClearRenderTargetView(rtv, s_clear_color.data()); - m_context->OMSetRenderTargets(1, &rtv, nullptr); - - m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - m_context->VSSetShader(pps.vertex_shader.Get(), nullptr, 0); - m_context->PSSetShader(pps.pixel_shader.Get(), nullptr, 0); - m_context->PSSetShaderResources(0, 1, texture->GetD3DSRVArray()); - m_context->PSSetSamplers(0, 1, m_border_sampler.GetAddressOf()); - - const auto map = m_push_uniform_buffer.Map(m_context.Get(), m_push_uniform_buffer.GetSize(), pps.uniforms_size); - m_post_processing_chain.GetShaderStage(i).FillUniformBuffer( - map.pointer, 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_push_uniform_buffer.Unmap(m_context.Get(), pps.uniforms_size); - m_context->VSSetConstantBuffers(0, 1, m_push_uniform_buffer.GetD3DBufferArray()); - m_context->PSSetConstantBuffers(0, 1, m_push_uniform_buffer.GetD3DBufferArray()); - - m_context->Draw(3, 0); - - if (i != final_stage) - texture = &pps.output_texture; - } - - ID3D11ShaderResourceView* null_srv = nullptr; - m_context->PSSetShaderResources(0, 1, &null_srv); -} -void D3D11Device::RenderDisplay() -{ - const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight()); - - if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) - { - ApplyPostProcessingChain(m_swap_chain_rtv.Get(), 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; - } - - m_context->ClearRenderTargetView(m_swap_chain_rtv.Get(), s_clear_color.data()); - m_context->OMSetRenderTargets(1, m_swap_chain_rtv.GetAddressOf(), nullptr); - - if (!HasDisplayTexture()) - return; - - RenderDisplay(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, - IsUsingLinearFiltering()); -} -bool D3D11Device::RenderScreenshot(u32 width, u32 height, const Common::Rectangle& draw_rect, - std::vector* out_pixels, u32* out_stride, GPUTexture::Format* out_format) -{ - static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; - - D3D11Texture render_texture; - if (!render_texture.Create(m_device.Get(), width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat)) - return false; - - static constexpr std::array clear_color = {}; - m_context->ClearRenderTargetView(render_texture.GetD3DRTV(), clear_color.data()); - m_context->OMSetRenderTargets(1, render_texture.GetD3DRTVArray(), nullptr); - - if (HasDisplayTexture()) - { - if (!m_post_processing_chain.IsEmpty()) - { - ApplyPostProcessingChain(render_texture.GetD3DRTV(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(), - draw_rect.GetHeight(), 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 - { - RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(), - 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()); - } - } - - m_context->OMSetRenderTargets(0, nullptr, nullptr); - - const u32 stride = GPUTexture::GetPixelSize(hdformat) * width; - out_pixels->resize(width * height); - if (!DownloadTexture(&render_texture, 0, 0, width, height, out_pixels->data(), stride)) - return false; - - *out_stride = stride; - *out_format = hdformat; - return true; -} - -#endif diff --git a/src/core/gpu/d3d11_device.h b/src/core/gpu/d3d11_device.h index f5f331c79..a15570a21 100644 --- a/src/core/gpu/d3d11_device.h +++ b/src/core/gpu/d3d11_device.h @@ -264,10 +264,7 @@ public: ~D3D11Device(); RenderAPI GetRenderAPI() const override; - void* GetDevice() const override; - void* GetContext() const override; - bool HasDevice() const override; bool HasSurface() const override; bool CreateDevice(const WindowInfo& wi, bool vsync) override; @@ -353,10 +350,10 @@ private: using InputLayoutMap = std::unordered_map, GPUPipeline::InputLayoutHash>; - // Currently we don't stream uniforms, instead just re-map the buffer every time and let the driver take care of it. - static constexpr u32 MAX_UNIFORM_BUFFER_SIZE = 64; static constexpr u32 VERTEX_BUFFER_SIZE = 8 * 1024 * 1024; static constexpr u32 INDEX_BUFFER_SIZE = 4 * 1024 * 1024; + static constexpr u32 UNIFORM_BUFFER_SIZE = 2 * 1024 * 1024; + static constexpr u32 UNIFORM_BUFFER_ALIGNMENT = 256; static constexpr u8 NUM_TIMESTAMP_QUERIES = 3; static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); @@ -384,13 +381,14 @@ private: void PopTimestampQuery(); void KickTimestampQuery(); - ComPtr m_device; - ComPtr m_context; + ComPtr m_device; + ComPtr m_context; ComPtr m_annotation; ComPtr m_dxgi_factory; ComPtr m_swap_chain; - ComPtr m_swap_chain_rtv; + std::unique_ptr m_swap_chain_texture; + std::unique_ptr m_swap_chain_framebuffer; RasterizationStateMap m_rasterization_states; DepthStateMap m_depth_states; diff --git a/src/core/gpu/d3d12_gpu_device.cpp b/src/core/gpu/d3d12_gpu_device.cpp index 26a0e7b9c..b97b52edc 100644 --- a/src/core/gpu/d3d12_gpu_device.cpp +++ b/src/core/gpu/d3d12_gpu_device.cpp @@ -37,21 +37,6 @@ RenderAPI D3D12GPUDevice::GetRenderAPI() const return RenderAPI::D3D12; } -void* D3D12GPUDevice::GetDevice() const -{ - return g_d3d12_context->GetDevice(); -} - -void* D3D12GPUDevice::GetContext() const -{ - return g_d3d12_context.get(); -} - -bool D3D12GPUDevice::HasDevice() const -{ - return static_cast(g_d3d12_context); -} - bool D3D12GPUDevice::HasSurface() const { return static_cast(m_swap_chain); @@ -472,6 +457,7 @@ bool D3D12GPUDevice::CreateResources() if (!m_display_root_signature) return false; +#if 0 rsbuilder.SetInputAssemblerFlag(); rsbuilder.Add32BitConstants(0, FrontendCommon::PostProcessingShader::PUSH_CONSTANT_SIZE_THRESHOLD / sizeof(u32), D3D12_SHADER_VISIBILITY_ALL); @@ -488,6 +474,7 @@ bool D3D12GPUDevice::CreateResources() m_post_processing_cb_root_signature = rsbuilder.Create(); if (!m_post_processing_cb_root_signature) return false; +#endif D3D12::GraphicsPipelineBuilder gpbuilder; gpbuilder.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); @@ -546,12 +533,14 @@ void D3D12GPUDevice::DestroyResources() { GPUDevice::DestroyResources(); +#if 0 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(); +#endif m_readback_staging_texture.Destroy(false); g_d3d12_context->GetSamplerHeapManager().Free(&m_border_sampler); @@ -638,6 +627,7 @@ void D3D12GPUDevice::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Te { const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight()); +#if 0 if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) { ApplyPostProcessingChain(cmdlist, swap_chain_buf, left, top, width, height, @@ -646,6 +636,7 @@ void D3D12GPUDevice::RenderDisplay(ID3D12GraphicsCommandList* cmdlist, D3D12::Te GetWindowWidth(), GetWindowHeight()); return; } +#endif swap_chain_buf->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); cmdlist->ClearRenderTargetView(swap_chain_buf->GetRTVOrDSVDescriptor(), s_clear_color.data(), 0, nullptr); @@ -787,6 +778,7 @@ GPUDevice::AdapterAndModeList D3D12GPUDevice::GetAdapterAndModeList(IDXGIFactory return adapter_info; } +#if 0 D3D12GPUDevice::PostProcessingStage::PostProcessingStage(PostProcessingStage&& move) : pipeline(std::move(move.pipeline)), output_texture(std::move(move.output_texture)), uniforms_size(move.uniforms_size) @@ -798,9 +790,11 @@ D3D12GPUDevice::PostProcessingStage::~PostProcessingStage() { output_texture.Destroy(true); } +#endif bool D3D12GPUDevice::SetPostProcessingChain(const std::string_view& config) { +#if 0 g_d3d12_context->ExecuteCommandList(true); if (config.empty()) @@ -882,8 +876,12 @@ bool D3D12GPUDevice::SetPostProcessingChain(const std::string_view& config) m_post_processing_timer.Reset(); return true; +#else + return false; +#endif } +#if 0 bool D3D12GPUDevice::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height) { DebugAssert(!m_post_processing_stages.empty()); @@ -1011,3 +1009,4 @@ void D3D12GPUDevice::ApplyPostProcessingChain(ID3D12GraphicsCommandList* cmdlist } } } +#endif \ No newline at end of file diff --git a/src/core/gpu/d3d12_gpu_device.h b/src/core/gpu/d3d12_gpu_device.h index 505b578d1..63975a4f7 100644 --- a/src/core/gpu/d3d12_gpu_device.h +++ b/src/core/gpu/d3d12_gpu_device.h @@ -29,10 +29,7 @@ public: ~D3D12GPUDevice(); RenderAPI GetRenderAPI() const override; - void* GetDevice() const override; - void* GetContext() const override; - bool HasDevice() const override; bool HasSurface() const override; bool CreateDevice(const WindowInfo& wi, bool vsync) override; @@ -70,17 +67,6 @@ public: static AdapterAndModeList StaticGetAdapterAndModeList(); protected: - struct PostProcessingStage - { - PostProcessingStage() = default; - PostProcessingStage(PostProcessingStage&& move); - ~PostProcessingStage(); - - ComPtr pipeline; - D3D12::Texture output_texture; - u32 uniforms_size = 0; - }; - static AdapterAndModeList GetAdapterAndModeList(IDXGIFactory* dxgi_factory); virtual bool CreateResources() override; @@ -100,12 +86,6 @@ 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; @@ -121,14 +101,6 @@ protected: D3D12::Texture m_display_pixels_texture; 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; }; diff --git a/src/core/gpu/gpu_device.cpp b/src/core/gpu/gpu_device.cpp index 5349a2338..6af332313 100644 --- a/src/core/gpu/gpu_device.cpp +++ b/src/core/gpu/gpu_device.cpp @@ -4,6 +4,8 @@ #include "gpu_device.h" #include "../settings.h" #include "../shadergen.h" +#include "postprocessing_chain.h" + #include "common/align.h" #include "common/assert.h" #include "common/file_system.h" @@ -12,15 +14,18 @@ #include "common/path.h" #include "common/string_util.h" #include "common/timer.h" + #include "imgui.h" #include "stb_image.h" #include "stb_image_resize.h" #include "stb_image_write.h" + #include #include #include #include #include + Log_SetChannel(GPUDevice); // FIXME @@ -43,6 +48,28 @@ GPUSampler::GPUSampler() = default; GPUSampler::~GPUSampler() = default; +GPUSampler::Config GPUSampler::GetNearestConfig() +{ + Config config = {}; + config.address_u = GPUSampler::AddressMode::ClampToEdge; + config.address_v = GPUSampler::AddressMode::ClampToEdge; + config.address_w = GPUSampler::AddressMode::ClampToEdge; + config.min_filter = GPUSampler::Filter::Nearest; + config.mag_filter = GPUSampler::Filter::Nearest; + return config; +} + +GPUSampler::Config GPUSampler::GetLinearConfig() +{ + Config config = {}; + config.address_u = GPUSampler::AddressMode::ClampToEdge; + config.address_v = GPUSampler::AddressMode::ClampToEdge; + config.address_w = GPUSampler::AddressMode::ClampToEdge; + config.min_filter = GPUSampler::Filter::Linear; + config.mag_filter = GPUSampler::Filter::Linear; + return config; +} + GPUShader::GPUShader(GPUShaderStage stage) : m_stage(stage) { } @@ -188,32 +215,16 @@ bool GPUDevice::SetupDevice() bool GPUDevice::CreateResources() { - GPUSampler::Config spconfig = {}; - spconfig.address_u = GPUSampler::AddressMode::ClampToEdge; - spconfig.address_v = GPUSampler::AddressMode::ClampToEdge; - spconfig.address_w = GPUSampler::AddressMode::ClampToEdge; - spconfig.min_filter = GPUSampler::Filter::Nearest; - spconfig.mag_filter = GPUSampler::Filter::Nearest; - if (!(m_point_sampler = CreateSampler(spconfig))) + if (!(m_nearest_sampler = CreateSampler(GPUSampler::GetNearestConfig()))) return false; - spconfig.min_filter = GPUSampler::Filter::Linear; - spconfig.mag_filter = GPUSampler::Filter::Linear; - if (!(m_linear_sampler = CreateSampler(spconfig))) + if (!(m_linear_sampler = CreateSampler(GPUSampler::GetLinearConfig()))) return false; - spconfig.mag_filter = GPUSampler::Filter::Nearest; - spconfig.mag_filter = GPUSampler::Filter::Nearest; - spconfig.address_u = GPUSampler::AddressMode::ClampToBorder; - spconfig.address_v = GPUSampler::AddressMode::ClampToBorder; - spconfig.border_color = 0xFF000000u; - if (!(m_border_sampler = CreateSampler(spconfig))) - return false; - - ShaderGen shadergen(GetRenderAPI(), /*FIXME DSB*/ true); + ShaderGen shadergen(GetRenderAPI(), m_features.dual_source_blend); GPUPipeline::GraphicsConfig plconfig; - plconfig.layout = GPUPipeline::Layout::SingleTexture; + plconfig.layout = GPUPipeline::Layout::SingleTexturePushConstants; plconfig.primitive = GPUPipeline::Primitive::Triangles; plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState(); plconfig.depth = GPUPipeline::DepthState::GetNoTestsState(); @@ -235,13 +246,13 @@ bool GPUDevice::CreateResources() GL_OBJECT_NAME(cursor_fs, "Cursor Fragment Shader"); plconfig.vertex_shader = display_vs.get(); - plconfig.pixel_shader = display_fs.get(); + plconfig.fragment_shader = display_fs.get(); if (!(m_display_pipeline = CreatePipeline(plconfig))) return false; GL_OBJECT_NAME(m_display_pipeline, "Display Pipeline"); plconfig.blend = GPUPipeline::BlendState::GetAlphaBlendingState(); - plconfig.pixel_shader = cursor_fs.get(); + plconfig.fragment_shader = cursor_fs.get(); if (!(m_cursor_pipeline = CreatePipeline(plconfig))) return false; GL_OBJECT_NAME(m_cursor_pipeline, "Cursor Pipeline"); @@ -262,7 +273,7 @@ bool GPUDevice::CreateResources() plconfig.input_layout.vertex_attributes = imgui_attributes; plconfig.input_layout.vertex_stride = sizeof(ImDrawVert); plconfig.vertex_shader = imgui_vs.get(); - plconfig.pixel_shader = imgui_fs.get(); + plconfig.fragment_shader = imgui_fs.get(); m_imgui_pipeline = CreatePipeline(plconfig); if (!m_imgui_pipeline) @@ -287,14 +298,33 @@ void GPUDevice::DestroyResources() m_imgui_pipeline.reset(); m_linear_sampler.reset(); - m_point_sampler.reset(); + m_nearest_sampler.reset(); m_shader_cache.Close(); } bool GPUDevice::SetPostProcessingChain(const std::string_view& config) { - return false; + static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; // TODO FIXME m_window_info.surface_format + + m_post_processing_chain.reset(); + + if (config.empty()) + return true; + + m_post_processing_chain = std::make_unique(); + if (!m_post_processing_chain->CreateFromString(config) || !m_post_processing_chain->CompilePipelines(hdformat)) + { + m_post_processing_chain.reset(); + return false; + } + else if (m_post_processing_chain->IsEmpty()) + { + m_post_processing_chain.reset(); + return true; + } + + return true; } std::string GPUDevice::GetShaderCacheBaseName(const std::string_view& type, bool debug) const @@ -862,26 +892,10 @@ bool GPUDevice::RenderScreenshot(u32 width, u32 height, const Common::Rectangle< return false; ClearRenderTarget(render_texture.get(), 0); - SetFramebuffer(render_fb.get()); - if (HasDisplayTexture()) - { -#if 0 - if (!m_post_processing_chain.IsEmpty()) - { - ApplyPostProcessingChain(render_texture.GetD3DRTV(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(), - draw_rect.GetHeight(), 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 -#endif - { - RenderDisplay(draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(), m_display_texture, - m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, - m_display_texture_view_height, IsUsingLinearFiltering()); - } - } + RenderDisplay(render_fb.get(), draw_rect.left, draw_rect.top, draw_rect.GetWidth(), draw_rect.GetHeight(), + m_display_texture, m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width, + m_display_texture_view_height, IsUsingLinearFiltering()); SetFramebuffer(nullptr); @@ -895,35 +909,27 @@ bool GPUDevice::RenderScreenshot(u32 width, u32 height, const Common::Rectangle< return true; } -void GPUDevice::RenderDisplay() +void GPUDevice::RenderDisplay(GPUFramebuffer* target, s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, + bool linear_filter) { - const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight()); - - GL_SCOPE("RenderDisplay: %dx%d at %d,%d", left, top, width, height); - -#if 0 - if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) + static constexpr GPUTexture::Format hdformat = GPUTexture::Format::RGBA8; // TODO FIXME m_window_info.surface_format + const u32 target_width = target ? target->GetWidth() : m_window_info.surface_width; + const u32 target_height = target ? target->GetHeight() : m_window_info.surface_height; + const bool postfx = + (m_post_processing_chain && m_post_processing_chain->CheckTargets(hdformat, target_width, target_height)); + if (postfx) { - ApplyPostProcessingChain(m_swap_chain_rtv.Get(), 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; + ClearRenderTarget(m_post_processing_chain->GetInputTexture(), 0); + SetFramebuffer(m_post_processing_chain->GetInputFramebuffer()); + } + else + { + SetFramebuffer(target); } -#endif - if (!HasDisplayTexture()) - return; - - RenderDisplay(left, top, width, height, m_display_texture, m_display_texture_view_x, m_display_texture_view_y, - m_display_texture_view_width, m_display_texture_view_height, IsUsingLinearFiltering()); -} - -void GPUDevice::RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter) -{ SetPipeline(m_display_pipeline.get()); - SetTextureSampler(0, texture, linear_filter ? m_linear_sampler.get() : m_point_sampler.get()); + SetTextureSampler(0, texture, linear_filter ? m_linear_sampler.get() : m_nearest_sampler.get()); const bool linear = IsUsingLinearFiltering(); const float position_adjust = linear ? 0.5f : 0.0f; @@ -937,6 +943,12 @@ void GPUDevice::RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTextu SetViewportAndScissor(left, top, width, height); Draw(3, 0); + + if (postfx) + { + m_post_processing_chain->Apply(target, left, top, width, height, texture_view_width, texture_view_height, + target_width, target_height); + } } void GPUDevice::RenderSoftwareCursor() diff --git a/src/core/gpu/gpu_device.h b/src/core/gpu/gpu_device.h index 9bd2fde5d..310aa7f7a 100644 --- a/src/core/gpu/gpu_device.h +++ b/src/core/gpu/gpu_device.h @@ -89,6 +89,9 @@ public: virtual ~GPUSampler(); virtual void SetDebugName(const std::string_view& name) = 0; + + static Config GetNearestConfig(); + static Config GetLinearConfig(); }; enum class GPUShaderStage : u8 @@ -119,11 +122,11 @@ class GPUPipeline public: enum class Layout : u8 { - // 128 byte UBO via push constants, 1 texture. - SingleTexture, - // 1 streamed UBO, 1 texture in PS. - HWBatch, + SingleTextureUBO, + + // 128 byte UBO via push constants, 1 texture. + SingleTexturePushConstants, MaxCount }; @@ -254,6 +257,7 @@ public: MaxCount }; + // TODO: purge this? union RasterizationState { BitField cull_mode; @@ -326,7 +330,7 @@ public: BlendState blend; const GPUShader* vertex_shader; - const GPUShader* pixel_shader; + const GPUShader* fragment_shader; GPUTexture::Format color_format; GPUTexture::Format depth_format; @@ -369,6 +373,9 @@ protected: u32 m_current_position; }; +// TODO: remove +class PostProcessingChain; + class GPUDevice { public: @@ -412,7 +419,7 @@ public: ALWAYS_INLINE float GetWindowScale() const { return m_window_info.surface_scale; } ALWAYS_INLINE GPUSampler* GetLinearSampler() const { return m_linear_sampler.get(); } - ALWAYS_INLINE GPUSampler* GetPointSampler() const { return m_point_sampler.get(); } + ALWAYS_INLINE GPUSampler* GetNearestSampler() const { return m_nearest_sampler.get(); } // Position is relative to the top-left corner of the window. ALWAYS_INLINE s32 GetMousePositionX() const { return m_mouse_position_x; } @@ -430,22 +437,21 @@ public: ALWAYS_INLINE bool IsGPUTimingEnabled() const { return m_gpu_timing_enabled; } virtual RenderAPI GetRenderAPI() const = 0; - virtual void* GetDevice() const = 0; - virtual void* GetContext() const = 0; - - virtual bool HasDevice() const = 0; - virtual bool HasSurface() const = 0; virtual bool CreateDevice(const WindowInfo& wi, bool vsync) = 0; virtual bool SetupDevice(); virtual bool MakeCurrent() = 0; virtual bool DoneCurrent() = 0; + + virtual bool HasSurface() const = 0; virtual void DestroySurface() = 0; virtual bool ChangeWindow(const WindowInfo& wi) = 0; + virtual bool SupportsFullscreen() const = 0; virtual bool IsFullscreen() = 0; virtual bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) = 0; virtual AdapterAndModeList GetAdapterAndModeList() = 0; + virtual bool CreateResources(); virtual void DestroyResources(); @@ -605,11 +611,11 @@ protected: void RenderImGui(); - void RenderDisplay(); void RenderSoftwareCursor(); - void RenderDisplay(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, s32 texture_view_x, - s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter); + void RenderDisplay(GPUFramebuffer* target, s32 left, s32 top, s32 width, s32 height, GPUTexture* texture, + s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, + bool linear_filter); void RenderSoftwareCursor(s32 left, s32 top, s32 width, s32 height, GPUTexture* texture); Features m_features = {}; @@ -620,9 +626,8 @@ protected: GPUShaderCache m_shader_cache; - std::unique_ptr m_point_sampler; + std::unique_ptr m_nearest_sampler; std::unique_ptr m_linear_sampler; - std::unique_ptr m_border_sampler; u64 m_last_frame_displayed_time = 0; @@ -655,6 +660,8 @@ protected: bool m_display_changed = false; bool m_gpu_timing_enabled = false; bool m_vsync_enabled = false; + + std::unique_ptr m_post_processing_chain; }; /// Returns a pointer to the current host display abstraction. Assumes AcquireHostDisplay() has been called. diff --git a/src/core/gpu/opengl_gpu_device.cpp b/src/core/gpu/opengl_gpu_device.cpp index 8a44ad8b9..d2af29ae1 100644 --- a/src/core/gpu/opengl_gpu_device.cpp +++ b/src/core/gpu/opengl_gpu_device.cpp @@ -37,16 +37,6 @@ RenderAPI OpenGLGPUDevice::GetRenderAPI() const return m_gl_context->IsGLES() ? RenderAPI::OpenGLES : RenderAPI::OpenGL; } -void* OpenGLGPUDevice::GetDevice() const -{ - return nullptr; -} - -void* OpenGLGPUDevice::GetContext() const -{ - return m_gl_context.get(); -} - std::unique_ptr OpenGLGPUDevice::CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, GPUTexture::Type type, GPUTexture::Format format, const void* data, u32 data_stride, @@ -273,11 +263,6 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen } } -bool OpenGLGPUDevice::HasDevice() const -{ - return static_cast(m_gl_context); -} - bool OpenGLGPUDevice::HasSurface() const { return m_window_info.type != WindowInfo::Type::Surfaceless; @@ -623,10 +608,12 @@ void OpenGLGPUDevice::DestroyResources() { GPUDevice::DestroyResources(); +#if 0 m_post_processing_chain.ClearStages(); m_post_processing_input_texture.Destroy(); m_post_processing_ubo.reset(); m_post_processing_stages.clear(); +#endif if (m_display_vao != 0) { @@ -695,6 +682,7 @@ void OpenGLGPUDevice::RenderDisplay() { const auto [left, top, width, height] = CalculateDrawRect(GetWindowWidth(), GetWindowHeight()); +#if 0 if (HasDisplayTexture() && !m_post_processing_chain.IsEmpty()) { ApplyPostProcessingChain(0, left, GetWindowHeight() - top - height, width, height, @@ -703,6 +691,7 @@ void OpenGLGPUDevice::RenderDisplay() GetWindowWidth(), GetWindowHeight()); return; } +#endif glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); @@ -817,6 +806,7 @@ void OpenGLGPUDevice::RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 bool OpenGLGPUDevice::SetPostProcessingChain(const std::string_view& config) { +#if 0 if (config.empty()) { m_post_processing_input_texture.Destroy(); @@ -882,8 +872,12 @@ bool OpenGLGPUDevice::SetPostProcessingChain(const std::string_view& config) m_post_processing_timer.Reset(); return true; +#else + return false; +#endif } +#if 0 bool OpenGLGPUDevice::CheckPostProcessingRenderTargets(u32 target_width, u32 target_height) { DebugAssert(!m_post_processing_stages.empty()); @@ -973,7 +967,7 @@ void OpenGLGPUDevice::ApplyPostProcessingChain(GLuint final_target, s32 final_le glBindSampler(0, 0); m_post_processing_ubo->Unbind(); } - +#endif void OpenGLGPUDevice::CreateTimestampQueries() { const bool gles = m_gl_context->IsGLES(); diff --git a/src/core/gpu/opengl_gpu_device.h b/src/core/gpu/opengl_gpu_device.h index 74706494d..20fa693ea 100644 --- a/src/core/gpu/opengl_gpu_device.h +++ b/src/core/gpu/opengl_gpu_device.h @@ -20,10 +20,7 @@ public: ~OpenGLGPUDevice(); RenderAPI GetRenderAPI() const override; - void* GetDevice() const override; - void* GetContext() const override; - bool HasDevice() const override; bool HasSurface() const override; bool CreateDevice(const WindowInfo& wi, bool vsync) override; @@ -82,18 +79,6 @@ protected: s32 texture_view_y, s32 texture_view_width, s32 texture_view_height, bool linear_filter); void RenderSoftwareCursor(s32 left, s32 bottom, s32 width, s32 height, GPUTexture* texture_handle); - struct PostProcessingStage - { - GL::Program program; - GL::Texture output_texture; - u32 uniforms_size; - }; - - bool CheckPostProcessingRenderTargets(u32 target_width, u32 target_height); - void ApplyPostProcessingChain(GLuint final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, - GL::Texture* texture, s32 texture_view_x, s32 texture_view_y, s32 texture_view_width, - s32 texture_view_height, u32 target_width, u32 target_height); - void CreateTimestampQueries(); void DestroyTimestampQueries(); void PopTimestampQuery(); @@ -113,12 +98,6 @@ protected: std::vector m_texture_repack_buffer; u32 m_texture_stream_buffer_offset = 0; - FrontendCommon::PostProcessingChain m_post_processing_chain; - GL::Texture m_post_processing_input_texture; - std::unique_ptr m_post_processing_ubo; - std::vector m_post_processing_stages; - Common::Timer m_post_processing_timer; - std::array m_timestamp_queries = {}; float m_accumulated_gpu_time = 0.0f; u8 m_read_timestamp_query = 0; diff --git a/src/core/gpu/postprocessing_chain.cpp b/src/core/gpu/postprocessing_chain.cpp index ddd8858af..2cd7044c6 100644 --- a/src/core/gpu/postprocessing_chain.cpp +++ b/src/core/gpu/postprocessing_chain.cpp @@ -1,19 +1,21 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "postprocessing_chain.h" +#include "../host.h" +#include "../settings.h" +#include "gpu_device.h" + #include "common/assert.h" #include "common/file_system.h" #include "common/log.h" -#include "common/string.h" #include "common/path.h" -#include "core/host.h" -#include "core/settings.h" +#include "common/string.h" + #include "fmt/format.h" #include -Log_SetChannel(PostProcessingChain); -namespace FrontendCommon { +Log_SetChannel(PostProcessingChain); static bool TryLoadingShader(PostProcessingShader* shader, const std::string_view& shader_name) { @@ -24,7 +26,8 @@ static bool TryLoadingShader(PostProcessingShader* shader, const std::string_vie return true; } - std::optional resource_str(Host::ReadResourceFileToString(fmt::format("shaders" FS_OSPATH_SEPARATOR_STR "{}.glsl", shader_name).c_str())); + std::optional resource_str( + Host::ReadResourceFileToString(fmt::format("shaders" FS_OSPATH_SEPARATOR_STR "{}.glsl", shader_name).c_str())); if (resource_str.has_value() && shader->LoadFromString(std::string(shader_name), std::move(resource_str.value()))) return true; @@ -115,6 +118,20 @@ bool PostProcessingChain::CreateFromString(const std::string_view& chain_config) return true; } +bool PostProcessingChain::CompilePipelines(GPUTexture::Format target_format) +{ + for (PostProcessingShader& stage : m_shaders) + { + if (!stage.CompilePipeline(target_format)) + { + Log_ErrorPrintf("Failed to compile one or more post-processing shaders, disabling."); + return false; + } + } + + return true; +} + std::vector PostProcessingChain::GetAvailableShaderNames() { std::vector names; @@ -182,4 +199,93 @@ void PostProcessingChain::ClearStages() m_shaders.clear(); } -} // namespace FrontendCommon \ No newline at end of file +bool PostProcessingChain::CheckTargets(GPUTexture::Format format, u32 target_width, u32 target_height) +{ + if (!m_input_texture || m_input_texture->GetFormat() != format || m_input_texture->GetWidth() != target_width || + m_input_texture->GetHeight() != target_height) + { + m_input_framebuffer.reset(); + m_input_texture.reset(); + + if (!(m_input_texture = g_host_display->CreateTexture(target_width, target_height, 1, 1, 1, + GPUTexture::Type::RenderTarget, format))) + { + return false; + } + + if (!(m_input_framebuffer = g_host_display->CreateFramebuffer(m_input_texture.get()))) + { + m_input_texture.reset(); + return false; + } + } + + const PostProcessingShader& final_stage = m_shaders.back(); + for (PostProcessingShader& shader : m_shaders) + { + if (&shader == &final_stage) + continue; + + if (!shader.ResizeOutput(format, target_width, target_height)) + return false; + } + + if (!m_border_sampler) + { + GPUSampler::Config config = GPUSampler::GetNearestConfig(); + config.address_u = GPUSampler::AddressMode::ClampToBorder; + config.address_v = GPUSampler::AddressMode::ClampToBorder; + config.border_color = 0xFF000000u; + if (!(m_border_sampler = g_host_display->CreateSampler(config))) + return false; + } + + return true; +} + +void PostProcessingChain::Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width, + s32 final_height, s32 orig_width, s32 orig_height, u32 target_width, u32 target_height) +{ + const u32 window_width = final_target ? final_target->GetWidth() : g_host_display->GetWindowWidth(); + const u32 window_height = final_target ? final_target->GetHeight() : g_host_display->GetWindowHeight(); + + GL_PUSH("PostProcessingChain Apply"); + + g_host_display->SetViewportAndScissor(final_left, final_top, final_width, final_height); + + GPUTexture* input = m_input_texture.get(); + input->MakeReadyForSampling(); + + const PostProcessingShader& final_stage = m_shaders.back(); + for (PostProcessingShader& stage : m_shaders) + { + const bool is_final = (&stage == &final_stage); + + GL_SCOPE("PostProcessingShader %s", stage.GetName().c_str()); + + // Assumes final stage has been cleared already. + if (!is_final) + g_host_display->ClearRenderTarget(stage.GetOutputTexture(), 0); + + g_host_display->SetFramebuffer(is_final ? final_target : stage.GetOutputFramebuffer()); + + g_host_display->SetPipeline(stage.GetPipeline()); + g_host_display->SetTextureSampler(0, input, m_border_sampler.get()); + + const u32 uniforms_size = stage.GetUniformsSize(); + void* uniforms = g_host_display->MapUniformBuffer(uniforms_size); + stage.FillUniformBuffer(uniforms, input->GetWidth(), input->GetHeight(), final_left, final_top, final_width, + final_height, window_width, window_height, orig_width, orig_height, + static_cast(m_timer.GetTimeSeconds())); + g_host_display->UnmapUniformBuffer(uniforms_size); + g_host_display->Draw(3, 0); + + if (!is_final) + { + input = stage.GetOutputTexture(); + input->MakeReadyForSampling(); + } + } + + GL_POP(); +} diff --git a/src/core/gpu/postprocessing_chain.h b/src/core/gpu/postprocessing_chain.h index f9b2de53c..235207643 100644 --- a/src/core/gpu/postprocessing_chain.h +++ b/src/core/gpu/postprocessing_chain.h @@ -1,12 +1,19 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once +#include "gpu_device.h" #include "postprocessing_shader.h" + +#include "common/timer.h" + +#include #include #include -namespace FrontendCommon { +class GPUSampler; +class GPUFramebuffer; +class GPUTexture; class PostProcessingChain { @@ -14,10 +21,14 @@ public: PostProcessingChain(); ~PostProcessingChain(); + static std::vector GetAvailableShaderNames(); + ALWAYS_INLINE bool IsEmpty() const { return m_shaders.empty(); } ALWAYS_INLINE u32 GetStageCount() const { return static_cast(m_shaders.size()); } ALWAYS_INLINE const PostProcessingShader& GetShaderStage(u32 i) const { return m_shaders[i]; } ALWAYS_INLINE PostProcessingShader& GetShaderStage(u32 i) { return m_shaders[i]; } + ALWAYS_INLINE GPUTexture* GetInputTexture() const { return m_input_texture.get(); } + ALWAYS_INLINE GPUFramebuffer* GetInputFramebuffer() const { return m_input_framebuffer.get(); } void AddShader(PostProcessingShader shader); bool AddStage(const std::string_view& name); @@ -29,11 +40,19 @@ public: std::string GetConfigString() const; bool CreateFromString(const std::string_view& chain_config); + bool CompilePipelines(GPUTexture::Format target_format); - static std::vector GetAvailableShaderNames(); + bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height); + + void Apply(GPUFramebuffer* final_target, s32 final_left, s32 final_top, s32 final_width, s32 final_height, + s32 orig_width, s32 orig_height, u32 target_width, u32 target_height); private: std::vector m_shaders; -}; -} // namespace FrontendCommon + std::unique_ptr m_border_sampler; + std::unique_ptr m_input_texture; + std::unique_ptr m_input_framebuffer; + + Common::Timer m_timer; +}; diff --git a/src/core/gpu/postprocessing_shader.cpp b/src/core/gpu/postprocessing_shader.cpp index da3b09f13..90af19705 100644 --- a/src/core/gpu/postprocessing_shader.cpp +++ b/src/core/gpu/postprocessing_shader.cpp @@ -2,18 +2,19 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "postprocessing_shader.h" +#include "postprocessing_shadergen.h" + #include "common/file_system.h" #include "common/log.h" #include "common/string_util.h" -#include "core/shadergen.h" + #include #include #include + Log_SetChannel(PostProcessingShader); -namespace FrontendCommon { - -void ParseKeyValue(const std::string_view& line, std::string_view* key, std::string_view* value) +static void ParseKeyValue(const std::string_view& line, std::string_view* key, std::string_view* value) { size_t key_start = 0; while (key_start < line.size() && std::isspace(line[key_start])) @@ -49,7 +50,7 @@ void ParseKeyValue(const std::string_view& line, std::string_view* key, std::str } template -u32 ParseVector(const std::string_view& line, PostProcessingShader::Option::ValueVector* values) +static u32 ParseVector(const std::string_view& line, PostProcessingShader::Option::ValueVector* values) { u32 index = 0; size_t start = 0; @@ -141,7 +142,7 @@ const PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const return nullptr; } -FrontendCommon::PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name) +PostProcessingShader::Option* PostProcessingShader::GetOptionByName(const std::string_view& name) { for (Option& option : m_options) { @@ -238,11 +239,6 @@ void PostProcessingShader::SetConfigString(const std::string_view& str) } } -bool PostProcessingShader::UsePushConstants() const -{ - return GetUniformsSize() <= PUSH_CONSTANT_SIZE_THRESHOLD; -} - u32 PostProcessingShader::GetUniformsSize() const { // lazy packing. todo improve. @@ -293,7 +289,66 @@ void PostProcessingShader::FillUniformBuffer(void* buffer, u32 texture_width, s3 } } -FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy) +bool PostProcessingShader::CompilePipeline(GPUTexture::Format target_format) +{ + if (m_pipeline) + m_pipeline.reset(); + + PostProcessingShaderGen shadergen(g_host_display->GetRenderAPI(), g_host_display->GetFeatures().dual_source_blend); + + std::unique_ptr vs = + g_host_display->CreateShader(GPUShaderStage::Vertex, shadergen.GeneratePostProcessingVertexShader(*this)); + std::unique_ptr fs = + g_host_display->CreateShader(GPUShaderStage::Fragment, shadergen.GeneratePostProcessingFragmentShader(*this)); + if (!vs || !fs) + return false; + + GPUPipeline::GraphicsConfig plconfig; + plconfig.layout = GPUPipeline::Layout::SingleTextureUBO; + plconfig.primitive = GPUPipeline::Primitive::Triangles; + plconfig.color_format = target_format; + plconfig.depth_format = GPUTexture::Format::Unknown; + plconfig.rasterization = GPUPipeline::RasterizationState::GetNoCullState(); + plconfig.depth = GPUPipeline::DepthState::GetNoTestsState(); + plconfig.blend = GPUPipeline::BlendState::GetNoBlendingState(); + plconfig.samples = 1; + plconfig.per_sample_shading = false; + plconfig.vertex_shader = vs.get(); + plconfig.fragment_shader = fs.get(); + + if (!(m_pipeline = g_host_display->CreatePipeline(plconfig))) + return false; + + return true; +} + +bool PostProcessingShader::ResizeOutput(GPUTexture::Format format, u32 width, u32 height) +{ + if (m_output_texture && m_output_texture->GetFormat() == format && m_output_texture->GetWidth() == width && + m_output_texture->GetHeight() == height) + { + return true; + } + + m_output_framebuffer.reset(); + m_output_texture.reset(); + + if (!(m_output_texture = + g_host_display->CreateTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, format))) + { + return false; + } + + if (!(m_output_framebuffer = g_host_display->CreateFramebuffer(m_output_texture.get()))) + { + m_output_texture.reset(); + return false; + } + + return true; +} + +PostProcessingShader& PostProcessingShader::operator=(const PostProcessingShader& copy) { m_name = copy.m_name; m_code = copy.m_code; @@ -301,7 +356,7 @@ FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(const Post return *this; } -FrontendCommon::PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move) +PostProcessingShader& PostProcessingShader::operator=(PostProcessingShader& move) { m_name = std::move(move.m_name); m_code = std::move(move.m_code); @@ -434,5 +489,3 @@ void PostProcessingShader::LoadOptions() m_options.push_back(std::move(current_option)); } } - -} // namespace FrontendCommon diff --git a/src/core/gpu/postprocessing_shader.h b/src/core/gpu/postprocessing_shader.h index bf8a27cac..dc2a70bb1 100644 --- a/src/core/gpu/postprocessing_shader.h +++ b/src/core/gpu/postprocessing_shader.h @@ -1,24 +1,29 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once + #include "common/rectangle.h" #include "core/types.h" +#include "gpu_device.h" + #include #include #include #include -namespace FrontendCommon { +class GPUPipeline; +class GPUTexture; + +class PostProcessingChain; +class PostProcessingShaderGen; class PostProcessingShader { -public: - enum : u32 - { - PUSH_CONSTANT_SIZE_THRESHOLD = 128 - }; + friend PostProcessingChain; + friend PostProcessingShaderGen; +public: struct Option { enum : u32 @@ -82,11 +87,7 @@ public: bool LoadFromFile(std::string name, const char* filename); bool LoadFromString(std::string name, std::string code); - bool UsePushConstants() const; - u32 GetUniformsSize() const; - void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, - s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height, - s32 original_width, s32 original_height, float time) const; + bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height); private: struct CommonUniforms @@ -105,9 +106,21 @@ private: void LoadOptions(); + ALWAYS_INLINE GPUPipeline* GetPipeline() const { return m_pipeline.get(); } + ALWAYS_INLINE GPUTexture* GetOutputTexture() const { return m_output_texture.get(); } + ALWAYS_INLINE GPUFramebuffer* GetOutputFramebuffer() const { return m_output_framebuffer.get(); } + + u32 GetUniformsSize() const; + void FillUniformBuffer(void* buffer, u32 texture_width, s32 texture_height, s32 texture_view_x, s32 texture_view_y, + s32 texture_view_width, s32 texture_view_height, u32 window_width, u32 window_height, + s32 original_width, s32 original_height, float time) const; + bool CompilePipeline(GPUTexture::Format target_format); + std::string m_name; std::string m_code; std::vector