From 38479dd7830ab0790b487cbdee7477e6eb6b941d Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 21 Jan 2018 01:32:20 +1000 Subject: [PATCH 1/7] RenderBase: Force a pipeline flush when drawing the XFB to the host Since we use the common pipelines here and draw vertices if a batch is currently being built by the vertex loader, we end up trampling over its pointer, as we share the buffer with the loader, and it has not been unmapped yet. Force a pipeline flush to avoid this. --- Source/Core/VideoCommon/RenderBase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 2e42ed984a8b..d37b6aa07bad 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -697,6 +697,11 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const m_last_xfb_region = xfb_rect; + // Since we use the common pipelines here and draw vertices if a batch is currently being + // built by the vertex loader, we end up trampling over its pointer, as we share the buffer + // with the loader, and it has not been unmapped yet. Force a pipeline flush to avoid this. + g_vertex_manager->Flush(); + // TODO: merge more generic parts into VideoCommon { std::lock_guard guard(m_swap_mutex); From 1adcd47dcbd80e0435d42e61dab3f00a22d1ca38 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 9 Feb 2018 20:52:25 +1000 Subject: [PATCH 2/7] Renderer: Add a base Initialize() method to match Shutdown() --- Source/Core/VideoBackends/D3D/main.cpp | 3 ++- .../Core/VideoBackends/Null/NullBackend.cpp | 2 +- Source/Core/VideoBackends/OGL/Render.cpp | 27 +++++++++++-------- Source/Core/VideoBackends/OGL/Render.h | 2 +- Source/Core/VideoBackends/OGL/main.cpp | 3 ++- Source/Core/VideoBackends/Software/SWmain.cpp | 2 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 23 +++++++++++----- Source/Core/VideoBackends/Vulkan/Renderer.h | 5 ++-- Source/Core/VideoCommon/RenderBase.cpp | 5 ++++ Source/Core/VideoCommon/RenderBase.h | 5 ++-- 10 files changed, 50 insertions(+), 27 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index 7df5358b16f1..684bc1350b0e 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -161,7 +161,8 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) D3D::InitUtils(); BBox::Init(); - return true; + + return g_renderer->Initialize(); } void VideoBackend::Shutdown() diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 147d5916ff08..d790331e3681 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -64,7 +64,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) g_framebuffer_manager = std::make_unique(); g_texture_cache = std::make_unique(); g_shader_cache = std::make_unique(); - return g_shader_cache->Initialize(); + return g_renderer->Initialize() && g_shader_cache->Initialize(); } void VideoBackend::Shutdown() diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 120774b4f7fd..8b35e59bbb0e 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -811,19 +811,11 @@ bool Renderer::IsHeadless() const return m_main_gl_context->IsHeadless(); } -void Renderer::Shutdown() +bool Renderer::Initialize() { - ::Renderer::Shutdown(); - g_framebuffer_manager.reset(); + if (!::Renderer::Initialize()) + return false; - UpdateActiveConfig(); - - s_raster_font.reset(); - m_post_processor.reset(); -} - -void Renderer::Init() -{ // Initialize the FramebufferManager g_framebuffer_manager = std::make_unique( m_target_width, m_target_height, s_MSAASamples, BoundingBox::NeedsStencilBuffer()); @@ -832,6 +824,19 @@ void Renderer::Init() m_post_processor = std::make_unique(); s_raster_font = std::make_unique(); + + return true; +} + +void Renderer::Shutdown() +{ + ::Renderer::Shutdown(); + g_framebuffer_manager.reset(); + + UpdateActiveConfig(); + + s_raster_font.reset(); + m_post_processor.reset(); } std::unique_ptr Renderer::CreateTexture(const TextureConfig& config) diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index f0cc668563a6..de051ba0d766 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -88,7 +88,7 @@ class Renderer : public ::Renderer bool IsHeadless() const override; - void Init(); + bool Initialize() override; void Shutdown() override; std::unique_ptr CreateTexture(const TextureConfig& config) override; diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 6e364113cc2f..c4ccbdcfd513 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -179,7 +179,8 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) g_texture_cache = std::make_unique(); g_sampler_cache = std::make_unique(); g_shader_cache = std::make_unique(); - static_cast(g_renderer.get())->Init(); + if (!g_renderer->Initialize()) + return false; TextureConverter::Init(); BoundingBox::Init(g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); return g_shader_cache->Initialize(); diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index a0ad3498494d..0ab16bdfa877 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -95,7 +95,7 @@ bool VideoSoftware::Initialize(const WindowSystemInfo& wsi) g_perf_query = std::make_unique(); g_texture_cache = std::make_unique(); g_shader_cache = std::make_unique(); - return g_shader_cache->Initialize(); + return g_renderer->Initialize() && g_shader_cache->Initialize(); } void VideoSoftware::Shutdown() diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index ce52b0718dbe..5e1250549ace 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -57,13 +57,7 @@ Renderer::Renderer(std::unique_ptr swap_chain) m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex; } -Renderer::~Renderer() -{ - UpdateActiveConfig(); - - DestroyShaders(); - DestroySemaphores(); -} +Renderer::~Renderer() = default; Renderer* Renderer::GetInstance() { @@ -77,6 +71,9 @@ bool Renderer::IsHeadless() const bool Renderer::Initialize() { + if (!::Renderer::Initialize()) + return false; + BindEFBToStateTracker(); if (!CreateSemaphores()) @@ -131,6 +128,18 @@ bool Renderer::Initialize() return true; } +void Renderer::Shutdown() +{ + ::Renderer::Shutdown(); + + // Submit the current command buffer, in case there's a partial frame. + StateTracker::GetInstance()->EndRenderPass(); + g_command_buffer_mgr->ExecuteCommandBuffer(false, true); + + DestroyShaders(); + DestroySemaphores(); +} + bool Renderer::CreateSemaphores() { // Create two semaphores, one that is triggered when the swapchain buffer is ready, another after diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index ba8fd889bdfd..ba27fa10c633 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -37,6 +37,9 @@ class Renderer : public ::Renderer bool IsHeadless() const override; + bool Initialize() override; + void Shutdown() override; + std::unique_ptr CreateTexture(const TextureConfig& config) override; std::unique_ptr CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; @@ -52,8 +55,6 @@ class Renderer : public ::Renderer SwapChain* GetSwapChain() const { return m_swap_chain.get(); } BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); } - bool Initialize(); - void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index d37b6aa07bad..241c74c6ec67 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -93,6 +93,11 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height) Renderer::~Renderer() = default; +bool Renderer::Initialize() +{ + return true; +} + void Renderer::Shutdown() { // First stop any framedumping, which might need to dump the last xfb frame. This process diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index d5dd761c4028..1c240c50ab72 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -79,6 +79,9 @@ class Renderer virtual bool IsHeadless() const = 0; + virtual bool Initialize(); + virtual void Shutdown(); + virtual void SetPipeline(const AbstractPipeline* pipeline) {} virtual void SetScissorRect(const MathUtil::Rectangle& rc) {} virtual void SetTexture(u32 index, const AbstractTexture* texture) {} @@ -188,8 +191,6 @@ class Renderer virtual std::unique_ptr CreateAsyncShaderCompiler(); - virtual void Shutdown(); - // Drawing utility shaders. virtual void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, u32 vertex_stride, u32 num_vertices) From 2644e920cca0fb4cb55d08b2c1920d8595140eb3 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 9 Sep 2017 16:09:24 +1000 Subject: [PATCH 3/7] Renderer: Add backbuffer format to base class --- Source/Core/VideoBackends/D3D/Render.cpp | 2 +- Source/Core/VideoBackends/Null/Render.cpp | 2 +- Source/Core/VideoBackends/OGL/Render.cpp | 3 +- .../VideoBackends/Software/SWRenderer.cpp | 3 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 43 ++++++++++++----- Source/Core/VideoBackends/Vulkan/Renderer.h | 2 + .../Core/VideoBackends/Vulkan/SwapChain.cpp | 48 +++++++++++-------- Source/Core/VideoBackends/Vulkan/SwapChain.h | 8 ++-- Source/Core/VideoCommon/RenderBase.cpp | 6 ++- Source/Core/VideoCommon/RenderBase.h | 4 +- 10 files changed, 75 insertions(+), 46 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index bfaa5763baa6..834dc893d008 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -63,7 +63,7 @@ typedef struct _Nv_Stereo_Image_Header #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e Renderer::Renderer(int backbuffer_width, int backbuffer_height) - : ::Renderer(backbuffer_width, backbuffer_height) + : ::Renderer(backbuffer_width, backbuffer_height, AbstractTextureFormat::RGBA8) { m_last_multisamples = g_ActiveConfig.iMultisamples; m_last_stereo_mode = g_ActiveConfig.stereo_mode != StereoMode::Off; diff --git a/Source/Core/VideoBackends/Null/Render.cpp b/Source/Core/VideoBackends/Null/Render.cpp index c80506c15b13..0fe6f1186e87 100644 --- a/Source/Core/VideoBackends/Null/Render.cpp +++ b/Source/Core/VideoBackends/Null/Render.cpp @@ -14,7 +14,7 @@ namespace Null { // Init functions -Renderer::Renderer() : ::Renderer(1, 1) +Renderer::Renderer() : ::Renderer(1, 1, AbstractTextureFormat::RGBA8) { UpdateActiveConfig(); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 8b35e59bbb0e..c43bb0ac8715 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -355,7 +355,8 @@ static void InitDriverInfo() // Init functions Renderer::Renderer(std::unique_ptr main_gl_context) : ::Renderer(static_cast(std::max(main_gl_context->GetBackBufferWidth(), 1u)), - static_cast(std::max(main_gl_context->GetBackBufferHeight(), 1u))), + static_cast(std::max(main_gl_context->GetBackBufferHeight(), 1u)), + AbstractTextureFormat::RGBA8), m_main_gl_context(std::move(main_gl_context)) { bool bSuccess = true; diff --git a/Source/Core/VideoBackends/Software/SWRenderer.cpp b/Source/Core/VideoBackends/Software/SWRenderer.cpp index 2c6a97027b3c..0b640227258c 100644 --- a/Source/Core/VideoBackends/Software/SWRenderer.cpp +++ b/Source/Core/VideoBackends/Software/SWRenderer.cpp @@ -25,7 +25,8 @@ #include "VideoCommon/VideoConfig.h" SWRenderer::SWRenderer(std::unique_ptr window) - : ::Renderer(static_cast(MAX_XFB_WIDTH), static_cast(MAX_XFB_HEIGHT)), + : ::Renderer(static_cast(MAX_XFB_WIDTH), static_cast(MAX_XFB_HEIGHT), + AbstractTextureFormat::RGBA8), m_window(std::move(window)) { } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 5e1250549ace..a49052d2e535 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -49,7 +49,8 @@ namespace Vulkan { Renderer::Renderer(std::unique_ptr swap_chain) : ::Renderer(swap_chain ? static_cast(swap_chain->GetWidth()) : 1, - swap_chain ? static_cast(swap_chain->GetHeight()) : 0), + swap_chain ? static_cast(swap_chain->GetHeight()) : 0, + swap_chain ? swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined), m_swap_chain(std::move(swap_chain)) { UpdateActiveConfig(); @@ -95,6 +96,23 @@ bool Renderer::Initialize() return false; } + // Swap chain render pass. + if (m_swap_chain) + { + m_swap_chain_render_pass = + g_object_cache->GetRenderPass(m_swap_chain->GetSurfaceFormat().format, VK_FORMAT_UNDEFINED, + 1, VK_ATTACHMENT_LOAD_OP_LOAD); + m_swap_chain_clear_render_pass = + g_object_cache->GetRenderPass(m_swap_chain->GetSurfaceFormat().format, VK_FORMAT_UNDEFINED, + 1, VK_ATTACHMENT_LOAD_OP_CLEAR); + if (m_swap_chain_render_pass == VK_NULL_HANDLE || + m_swap_chain_clear_render_pass == VK_NULL_HANDLE) + { + PanicAlert("Failed to create swap chain render passes."); + return false; + } + } + m_bounding_box = std::make_unique(); if (!m_bounding_box->Initialize()) { @@ -398,7 +416,7 @@ void Renderer::RenderText(const std::string& text, int left, int top, u32 color) u32 backbuffer_width = m_swap_chain->GetWidth(); u32 backbuffer_height = m_swap_chain->GetHeight(); - m_raster_font->PrintMultiLineText(m_swap_chain->GetRenderPass(), text, + m_raster_font->PrintMultiLineText(m_swap_chain_render_pass, text, left * 2.0f / static_cast(backbuffer_width) - 1, 1 - top * 2.0f / static_cast(backbuffer_height), backbuffer_width, backbuffer_height, color); @@ -816,20 +834,18 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region m_current_framebuffer_width = backbuffer->GetWidth(); m_current_framebuffer_height = backbuffer->GetHeight(); + // Draw to the backbuffer. + VkRect2D region = {{0, 0}, {backbuffer->GetWidth(), backbuffer->GetHeight()}}; + StateTracker::GetInstance()->SetRenderPass(m_swap_chain_render_pass, + m_swap_chain_clear_render_pass); + StateTracker::GetInstance()->SetFramebuffer(m_swap_chain->GetCurrentFramebuffer(), region); + // Begin render pass for rendering to the swap chain. VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - VkRenderPassBeginInfo info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - m_swap_chain->GetRenderPass(), - m_swap_chain->GetCurrentFramebuffer(), - {{0, 0}, {backbuffer->GetWidth(), backbuffer->GetHeight()}}, - 1, - &clear_value}; - vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info, - VK_SUBPASS_CONTENTS_INLINE); + StateTracker::GetInstance()->BeginClearRenderPass(region, &clear_value, 1); // Draw - BlitScreen(m_swap_chain->GetRenderPass(), GetTargetRectangle(), xfb_region, + BlitScreen(m_swap_chain_render_pass, GetTargetRectangle(), xfb_region, xfb_texture->GetRawTexIdentifier()); // Draw OSD @@ -840,7 +856,8 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region OSD::DrawMessages(); // End drawing to backbuffer - vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer()); + StateTracker::GetInstance()->EndRenderPass(); + BindEFBToStateTracker(); // Transition the backbuffer to PRESENT_SRC to ensure all commands drawing // to it have finished before present. diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index ba27fa10c633..edb7764a5d8b 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -125,6 +125,8 @@ class Renderer : public ::Renderer VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE; + VkRenderPass m_swap_chain_render_pass = VK_NULL_HANDLE; + VkRenderPass m_swap_chain_clear_render_pass = VK_NULL_HANDLE; std::unique_ptr m_swap_chain; std::unique_ptr m_bounding_box; diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index ffddfe4d07f6..3ba46b9baa2f 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -142,11 +142,8 @@ std::unique_ptr SwapChain::Create(void* display_handle, void* native_ std::unique_ptr swap_chain = std::make_unique(display_handle, native_handle, surface, vsync); - if (!swap_chain->CreateSwapChain() || !swap_chain->CreateRenderPass() || - !swap_chain->SetupSwapChainImages()) - { + if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages()) return nullptr; - } return swap_chain; } @@ -175,13 +172,27 @@ bool SwapChain::SelectSurfaceFormat() return true; } - // Use the first surface format, just use what it prefers. - // Some drivers seem to return a SRGB format here (Intel Mesa). - // This results in gamma correction when presenting to the screen, which we don't want. - // Use a linear format instead, if this is the case. - m_surface_format.format = Util::GetLinearFormat(surface_formats[0].format); - m_surface_format.colorSpace = surface_formats[0].colorSpace; - return true; + // Try to find a suitable format. + for (const VkSurfaceFormatKHR& surface_format : surface_formats) + { + // Some drivers seem to return a SRGB format here (Intel Mesa). + // This results in gamma correction when presenting to the screen, which we don't want. + // Use a linear format instead, if this is the case. + VkFormat format = Util::GetLinearFormat(surface_format.format); + if (format == VK_FORMAT_R8G8B8A8_UNORM) + m_texture_format = AbstractTextureFormat::RGBA8; + else if (format == VK_FORMAT_B8G8R8A8_UNORM) + m_texture_format = AbstractTextureFormat::BGRA8; + else + continue; + + m_surface_format.format = format; + m_surface_format.colorSpace = surface_format.colorSpace; + return true; + } + + PanicAlert("Failed to find a suitable format for swap chain buffers."); + return false; } bool SwapChain::SelectPresentMode() @@ -236,14 +247,6 @@ bool SwapChain::SelectPresentMode() return true; } -bool SwapChain::CreateRenderPass() -{ - // render pass for rendering to the swap chain - m_render_pass = g_object_cache->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, 1, - VK_ATTACHMENT_LOAD_OP_CLEAR); - return m_render_pass != VK_NULL_HANDLE; -} - bool SwapChain::CreateSwapChain() { // Look up surface properties to determine image count and dimensions @@ -367,6 +370,9 @@ bool SwapChain::SetupSwapChainImages() images.data()); ASSERT(res == VK_SUCCESS); + VkRenderPass render_pass = g_object_cache->GetRenderPass( + m_surface_format.format, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_CLEAR); + m_swap_chain_images.reserve(image_count); for (uint32_t i = 0; i < image_count; i++) { @@ -382,7 +388,7 @@ bool SwapChain::SetupSwapChainImages() VkFramebufferCreateInfo framebuffer_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0, - m_render_pass, + render_pass, 1, &view, m_width, @@ -499,7 +505,7 @@ bool SwapChain::RecreateSurface(void* native_handle) } // Finally re-create the swap chain - if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateRenderPass()) + if (!CreateSwapChain() || !SetupSwapChainImages()) return false; return true; diff --git a/Source/Core/VideoBackends/Vulkan/SwapChain.h b/Source/Core/VideoBackends/Vulkan/SwapChain.h index 8cf2776a36d0..4494d7bc57e9 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.h +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.h @@ -10,6 +10,7 @@ #include "Common/CommonTypes.h" #include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/Texture2D.h" +#include "VideoCommon/TextureConfig.h" namespace Vulkan { @@ -33,10 +34,10 @@ class SwapChain void* GetNativeHandle() const { return m_native_handle; } VkSurfaceKHR GetSurface() const { return m_surface; } VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; } + AbstractTextureFormat GetTextureFormat() const { return m_texture_format; } bool IsVSyncEnabled() const { return m_vsync_enabled; } bool IsStereoEnabled() const { return m_layers == 2; } VkSwapchainKHR GetSwapChain() const { return m_swap_chain; } - VkRenderPass GetRenderPass() const { return m_render_pass; } u32 GetWidth() const { return m_width; } u32 GetHeight() const { return m_height; } u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; } @@ -69,8 +70,6 @@ class SwapChain bool CreateSwapChain(); void DestroySwapChain(); - bool CreateRenderPass(); - bool SetupSwapChainImages(); void DestroySwapChainImages(); @@ -88,14 +87,13 @@ class SwapChain VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSurfaceFormatKHR m_surface_format = {}; VkPresentModeKHR m_present_mode = VK_PRESENT_MODE_RANGE_SIZE_KHR; + AbstractTextureFormat m_texture_format = AbstractTextureFormat::Undefined; bool m_vsync_enabled; VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE; std::vector m_swap_chain_images; u32 m_current_swap_chain_image_index = 0; - VkRenderPass m_render_pass = VK_NULL_HANDLE; - u32 m_width = 0; u32 m_height = 0; u32 m_layers = 0; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 241c74c6ec67..ba60e1636cce 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -78,8 +78,10 @@ static float AspectToWidescreen(float aspect) return aspect * ((16.0f / 9.0f) / (4.0f / 3.0f)); } -Renderer::Renderer(int backbuffer_width, int backbuffer_height) - : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height) +Renderer::Renderer(int backbuffer_width, int backbuffer_height, + AbstractTextureFormat backbuffer_format) + : m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height), + m_backbuffer_format(backbuffer_format) { UpdateActiveConfig(); UpdateDrawRectangle(); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 1c240c50ab72..9fa1beb77266 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -32,6 +32,7 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/FPSCounter.h" #include "VideoCommon/RenderState.h" +#include "VideoCommon/TextureConfig.h" #include "VideoCommon/VideoCommon.h" class AbstractFramebuffer; @@ -72,7 +73,7 @@ enum class OSDMessage : s32 class Renderer { public: - Renderer(int backbuffer_width, int backbuffer_height); + Renderer(int backbuffer_width, int backbuffer_height, AbstractTextureFormat backbuffer_format); virtual ~Renderer(); using ClearColor = std::array; @@ -230,6 +231,7 @@ class Renderer // Backbuffer (window) size and render area int m_backbuffer_width = 0; int m_backbuffer_height = 0; + AbstractTextureFormat m_backbuffer_format = AbstractTextureFormat::Undefined; TargetRectangle m_target_rectangle = {}; FPSCounter m_fps_counter; From fa8262fa4af2a6be524b1201f1e8f1db3820282a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 00:41:51 +1100 Subject: [PATCH 4/7] Vulkan: Don't panic on missing color/depth buffer in config --- Source/Core/VideoBackends/Vulkan/Util.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 4ffa5c014682..35c9bcfbafb9 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -130,6 +130,9 @@ VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format) case AbstractTextureFormat::D32F_S8: return VK_FORMAT_D32_SFLOAT_S8_UINT; + case AbstractTextureFormat::Undefined: + return VK_FORMAT_UNDEFINED; + default: PanicAlert("Unhandled texture format."); return VK_FORMAT_R8G8B8A8_UNORM; From b409a87d1a4256cdd7b5ccd3133d416ca15148f1 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 00:56:18 +1100 Subject: [PATCH 5/7] D3D: Clamp viewport to current framebuffer dimensions, not target --- Source/Core/VideoBackends/D3D/Render.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 834dc893d008..e06a5b4c6970 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -549,10 +549,12 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne { // In D3D, the viewport rectangle must fit within the render target. D3D11_VIEWPORT vp; - vp.TopLeftX = MathUtil::Clamp(x, 0.0f, static_cast(m_target_width - 1)); - vp.TopLeftY = MathUtil::Clamp(y, 0.0f, static_cast(m_target_height - 1)); - vp.Width = MathUtil::Clamp(width, 1.0f, static_cast(m_target_width) - vp.TopLeftX); - vp.Height = MathUtil::Clamp(height, 1.0f, static_cast(m_target_height) - vp.TopLeftY); + vp.TopLeftX = MathUtil::Clamp(x, 0.0f, static_cast(m_current_framebuffer_width - 1)); + vp.TopLeftY = MathUtil::Clamp(y, 0.0f, static_cast(m_current_framebuffer_height - 1)); + vp.Width = + MathUtil::Clamp(width, 1.0f, static_cast(m_current_framebuffer_width) - vp.TopLeftX); + vp.Height = + MathUtil::Clamp(height, 1.0f, static_cast(m_current_framebuffer_height) - vp.TopLeftY); vp.MinDepth = near_depth; vp.MaxDepth = far_depth; D3D::context->RSSetViewports(1, &vp); From 5ca18ff04e6dd69e09a5675db8f9474a51bdfcc0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 10 Oct 2018 19:40:47 +1000 Subject: [PATCH 6/7] Vulkan: Restore viewport/scissor state on RestoreAPIState --- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index a49052d2e535..764250cbe92b 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -857,7 +857,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region // End drawing to backbuffer StateTracker::GetInstance()->EndRenderPass(); - BindEFBToStateTracker(); // Transition the backbuffer to PRESENT_SRC to ensure all commands drawing // to it have finished before present. @@ -1047,6 +1046,8 @@ void Renderer::RestoreAPIState() static_cast(m_current_framebuffer)->TransitionForSample(); BindEFBToStateTracker(); + BPFunctions::SetViewport(); + BPFunctions::SetScissor(); // Instruct the state tracker to re-bind everything before the next draw StateTracker::GetInstance()->SetPendingRebind(); From 7afd5cc2fb7e45f2c497e5aed007a017b8461335 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 27 Nov 2018 17:16:53 +1000 Subject: [PATCH 7/7] Use main buffers for utility draws --- .../VideoBackends/D3D/GeometryShaderCache.cpp | 33 ---- .../VideoBackends/D3D/GeometryShaderCache.h | 3 +- .../VideoBackends/D3D/PixelShaderCache.cpp | 34 ---- .../Core/VideoBackends/D3D/PixelShaderCache.h | 2 - Source/Core/VideoBackends/D3D/Render.cpp | 91 ++-------- Source/Core/VideoBackends/D3D/Render.h | 13 +- .../Core/VideoBackends/D3D/VertexManager.cpp | 165 +++++++++++------ Source/Core/VideoBackends/D3D/VertexManager.h | 36 ++-- .../VideoBackends/D3D/VertexShaderCache.cpp | 31 ---- .../VideoBackends/D3D/VertexShaderCache.h | 2 - .../Core/VideoBackends/Null/VertexManager.cpp | 19 +- .../Core/VideoBackends/Null/VertexManager.h | 9 +- .../VideoBackends/OGL/ProgramShaderCache.cpp | 20 +++ .../VideoBackends/OGL/ProgramShaderCache.h | 2 + Source/Core/VideoBackends/OGL/Render.cpp | 69 +++---- Source/Core/VideoBackends/OGL/Render.h | 11 +- Source/Core/VideoBackends/OGL/StreamBuffer.h | 2 + .../Core/VideoBackends/OGL/VertexManager.cpp | 123 ++++--------- Source/Core/VideoBackends/OGL/VertexManager.h | 23 ++- .../VideoBackends/Software/SWVertexLoader.cpp | 19 +- .../VideoBackends/Software/SWVertexLoader.h | 11 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 169 ++---------------- Source/Core/VideoBackends/Vulkan/Renderer.h | 7 +- .../VideoBackends/Vulkan/StateTracker.cpp | 95 +++++++++- .../Core/VideoBackends/Vulkan/StateTracker.h | 13 +- .../VideoBackends/Vulkan/VertexManager.cpp | 87 ++++----- .../Core/VideoBackends/Vulkan/VertexManager.h | 15 +- Source/Core/VideoCommon/IndexGenerator.cpp | 8 + Source/Core/VideoCommon/IndexGenerator.h | 2 + Source/Core/VideoCommon/RenderBase.h | 14 +- Source/Core/VideoCommon/VertexManagerBase.cpp | 58 ++++-- Source/Core/VideoCommon/VertexManagerBase.h | 28 ++- 32 files changed, 533 insertions(+), 681 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index ae807bd6c2c2..baa444bf47bb 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -4,7 +4,6 @@ #include -#include "Common/Align.h" #include "Common/FileUtil.h" #include "Common/StringUtil.h" @@ -18,8 +17,6 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/GeometryShaderGen.h" -#include "VideoCommon/GeometryShaderManager.h" -#include "VideoCommon/Statistics.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -36,25 +33,6 @@ ID3D11GeometryShader* GeometryShaderCache::GetCopyGeometryShader() return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? CopyGeometryShader : nullptr; } -ID3D11Buffer* gscbuf = nullptr; - -ID3D11Buffer*& GeometryShaderCache::GetConstantBuffer() -{ - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to - // speed this up - if (GeometryShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(gscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); - D3D::context->Unmap(gscbuf, 0); - GeometryShaderManager::dirty = false; - - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(GeometryShaderConstants)); - } - return gscbuf; -} - const char clear_shader_code[] = { "struct VSOUTPUT\n" "{\n" @@ -116,15 +94,6 @@ const char copy_shader_code[] = { void GeometryShaderCache::Init() { - unsigned int gbsize = Common::AlignUp(static_cast(sizeof(GeometryShaderConstants)), - 16); // must be a multiple of 16 - D3D11_BUFFER_DESC gbdesc = CD3D11_BUFFER_DESC(gbsize, D3D11_BIND_CONSTANT_BUFFER, - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateBuffer(&gbdesc, nullptr, &gscbuf); - CHECK(hr == S_OK, "Create geometry shader constant buffer (size=%u)", gbsize); - D3D::SetDebugObjectName(gscbuf, - "geometry shader constant buffer used to emulate the GX pipeline"); - // used when drawing clear quads ClearGeometryShader = D3D::CompileAndCreateGeometryShader(clear_shader_code); CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader"); @@ -138,8 +107,6 @@ void GeometryShaderCache::Init() void GeometryShaderCache::Shutdown() { - SAFE_RELEASE(gscbuf); - SAFE_RELEASE(ClearGeometryShader); SAFE_RELEASE(CopyGeometryShader); } diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h index 28c1ee3680bb..38ffde1b51e6 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -20,7 +20,8 @@ class GeometryShaderCache static ID3D11GeometryShader* GetClearGeometryShader(); static ID3D11GeometryShader* GetCopyGeometryShader(); - static ID3D11Buffer*& GetConstantBuffer(); + static ID3D11Buffer* GetConstantBuffer(); + static void UpdateConstantBuffer(const void* data, u32 data_size); }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index e09e32d8a23a..c86086614f9e 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -4,7 +4,6 @@ #include -#include "Common/Align.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/MsgHandler.h" @@ -20,8 +19,6 @@ #include "VideoCommon/Debugger.h" #include "VideoCommon/PixelShaderGen.h" -#include "VideoCommon/PixelShaderManager.h" -#include "VideoCommon/Statistics.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -32,7 +29,6 @@ ID3D11PixelShader* s_AnaglyphProgram = nullptr; ID3D11PixelShader* s_DepthResolveProgram = nullptr; ID3D11PixelShader* s_rgba6_to_rgb8[2] = {nullptr}; ID3D11PixelShader* s_rgb8_to_rgba6[2] = {nullptr}; -ID3D11Buffer* pscbuf = nullptr; const char clear_program_code[] = {"void main(\n" "out float4 ocol0 : SV_Target,\n" @@ -277,36 +273,8 @@ ID3D11PixelShader* PixelShaderCache::GetDepthResolveProgram() return s_DepthResolveProgram; } -static void UpdateConstantBuffers() -{ - if (PixelShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(pscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &PixelShaderManager::constants, sizeof(PixelShaderConstants)); - D3D::context->Unmap(pscbuf, 0); - PixelShaderManager::dirty = false; - - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(PixelShaderConstants)); - } -} - -ID3D11Buffer* PixelShaderCache::GetConstantBuffer() -{ - UpdateConstantBuffers(); - return pscbuf; -} - void PixelShaderCache::Init() { - unsigned int cbsize = Common::AlignUp(static_cast(sizeof(PixelShaderConstants)), - 16); // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - D3D::device->CreateBuffer(&cbdesc, nullptr, &pscbuf); - CHECK(pscbuf != nullptr, "Create pixel shader constant buffer"); - D3D::SetDebugObjectName(pscbuf, "pixel shader constant buffer used to emulate the GX pipeline"); - // used when drawing clear quads s_ClearProgram = D3D::CompileAndCreatePixelShader(clear_program_code); CHECK(s_ClearProgram != nullptr, "Create clear pixel shader"); @@ -334,8 +302,6 @@ void PixelShaderCache::InvalidateMSAAShaders() void PixelShaderCache::Shutdown() { - SAFE_RELEASE(pscbuf); - SAFE_RELEASE(s_ClearProgram); SAFE_RELEASE(s_AnaglyphProgram); SAFE_RELEASE(s_DepthResolveProgram); diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.h b/Source/Core/VideoBackends/D3D/PixelShaderCache.h index 22b6b0cc0c6d..da1b3b720d46 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.h +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.h @@ -21,8 +21,6 @@ class PixelShaderCache static void Init(); static void Shutdown(); - static ID3D11Buffer* GetConstantBuffer(); - static ID3D11PixelShader* GetColorCopyProgram(bool multisampled); static ID3D11PixelShader* GetClearProgram(); static ID3D11PixelShader* GetAnaglyphProgram(); diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index e06a5b4c6970..93098f53fe7e 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -167,16 +167,6 @@ void Renderer::SetupDeviceObjects() D3D::SetDebugObjectName(m_reset_rast_state, "rasterizer state for Renderer::ResetAPIState"); m_screenshot_texture = nullptr; - - CD3D11_BUFFER_DESC vbo_desc(UTILITY_VBO_SIZE, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, - D3D11_CPU_ACCESS_WRITE); - hr = D3D::device->CreateBuffer(&vbo_desc, nullptr, &m_utility_vertex_buffer); - CHECK(SUCCEEDED(hr), "Create utility VBO"); - - CD3D11_BUFFER_DESC ubo_desc(UTILITY_UBO_SIZE, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, - D3D11_CPU_ACCESS_WRITE); - hr = D3D::device->CreateBuffer(&ubo_desc, nullptr, &m_utility_uniform_buffer); - CHECK(SUCCEEDED(hr), "Create utility UBO"); } // Kill off all device objects @@ -196,8 +186,6 @@ void Renderer::TeardownDeviceObjects() SAFE_RELEASE(m_reset_rast_state); SAFE_RELEASE(m_screenshot_texture); SAFE_RELEASE(m_3d_vision_texture); - SAFE_RELEASE(m_utility_vertex_buffer); - SAFE_RELEASE(m_utility_uniform_buffer); } void Renderer::Create3DVisionTexture(int width, int height) @@ -273,25 +261,6 @@ std::unique_ptr Renderer::CreatePipeline(const AbstractPipelin return DXPipeline::Create(config); } -void Renderer::UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size) -{ - DEBUG_ASSERT(uniforms_size > 0 && uniforms_size < UTILITY_UBO_SIZE); - D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = D3D::context->Map(m_utility_uniform_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - CHECK(SUCCEEDED(hr), "Map utility UBO"); - std::memcpy(mapped.pData, uniforms, uniforms_size); - D3D::context->Unmap(m_utility_uniform_buffer, 0); -} - -void Renderer::UpdateUtilityVertexBuffer(const void* vertices, u32 vertex_stride, u32 num_vertices) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - HRESULT hr = D3D::context->Map(m_utility_vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - CHECK(SUCCEEDED(hr), "Map utility VBO"); - std::memcpy(mapped.pData, vertices, num_vertices * vertex_stride); - D3D::context->Unmap(m_utility_vertex_buffer, 0); -} - void Renderer::SetPipeline(const AbstractPipeline* pipeline) { const DXPipeline* dx_pipeline = static_cast(pipeline); @@ -308,54 +277,6 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline) D3D::stateman->SetPixelShader(dx_pipeline->GetPixelShader()); } -void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) -{ - // Copy in uniforms. - if (uniforms_size > 0) - { - UpdateUtilityUniformBuffer(uniforms, uniforms_size); - D3D::stateman->SetVertexConstants(m_utility_uniform_buffer); - D3D::stateman->SetPixelConstants(m_utility_uniform_buffer); - D3D::stateman->SetGeometryConstants(m_utility_uniform_buffer); - } - - // If the vertices are larger than our buffer, we need to break it up into multiple draws. - const char* vertices_ptr = static_cast(vertices); - while (num_vertices > 0) - { - u32 vertices_this_draw = num_vertices; - if (vertices_ptr) - { - vertices_this_draw = std::min(vertices_this_draw, UTILITY_VBO_SIZE / vertex_stride); - DEBUG_ASSERT(vertices_this_draw > 0); - UpdateUtilityVertexBuffer(vertices_ptr, vertex_stride, vertices_this_draw); - D3D::stateman->SetVertexBuffer(m_utility_vertex_buffer, vertex_stride, 0); - } - - // Apply pending state and draw. - D3D::stateman->Apply(); - D3D::context->Draw(vertices_this_draw, 0); - vertices_ptr += vertex_stride * vertices_this_draw; - num_vertices -= vertices_this_draw; - } -} - -void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms, - u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z) -{ - D3D::stateman->SetComputeShader(static_cast(shader)->GetD3DComputeShader()); - - if (uniforms_size > 0) - { - UpdateUtilityUniformBuffer(uniforms, uniforms_size); - D3D::stateman->SetComputeConstants(m_utility_uniform_buffer); - } - - D3D::stateman->Apply(); - D3D::context->Dispatch(groups_x, groups_y, groups_z); -} - TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { TargetRectangle result; @@ -560,6 +481,18 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne D3D::context->RSSetViewports(1, &vp); } +void Renderer::Draw(u32 base_vertex, u32 num_vertices) +{ + D3D::stateman->Apply(); + D3D::context->Draw(num_vertices, base_vertex); +} + +void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) +{ + D3D::stateman->Apply(); + D3D::context->DrawIndexed(num_indices, base_index, base_vertex); +} + void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 24b02af67227..4750a0e69abd 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -50,6 +50,8 @@ class Renderer : public ::Renderer void SetInterlacingMode() override; void SetViewport(float x, float y, float width, float height, float near_depth, float far_depth) override; + void Draw(u32 base_vertex, u32 num_vertices) override; + void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; void SetFullscreen(bool enable_fullscreen) override; bool IsFullscreen() const override; @@ -73,11 +75,6 @@ class Renderer : public ::Renderer void ReinterpretPixelData(unsigned int convtype) override; - void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) override; - void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, u32 uniforms_size, - u32 groups_x, u32 groups_y, u32 groups_z) override; - private: void SetupDeviceObjects(); void TeardownDeviceObjects(); @@ -89,9 +86,6 @@ class Renderer : public ::Renderer void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height); - void UpdateUtilityUniformBuffer(const void* uniforms, u32 uniforms_size); - void UpdateUtilityVertexBuffer(const void* vertices, u32 vertex_stride, u32 num_vertices); - StateCache m_state_cache; std::array m_clear_blend_states{}; @@ -103,9 +97,6 @@ class Renderer : public ::Renderer ID3D11Texture2D* m_screenshot_texture = nullptr; D3DTexture2D* m_3d_vision_texture = nullptr; - ID3D11Buffer* m_utility_vertex_buffer = nullptr; - ID3D11Buffer* m_utility_uniform_buffer = nullptr; - u32 m_last_multisamples = 1; bool m_last_stereo_mode = false; bool m_last_fullscreen_state = false; diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 9d37aa8bf5f5..8a84ebadc38d 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -6,6 +6,7 @@ #include +#include "Common/Align.h" #include "Common/CommonTypes.h" #include "VideoBackends/D3D/BoundingBox.h" @@ -19,11 +20,14 @@ #include "VideoCommon/BoundingBox.h" #include "VideoCommon/Debugger.h" +#include "VideoCommon/GeometryShaderManager.h" #include "VideoCommon/IndexGenerator.h" #include "VideoCommon/NativeVertexFormat.h" +#include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/VertexLoaderManager.h" +#include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoConfig.h" namespace DX11 @@ -33,15 +37,34 @@ const u32 MAX_IBUFFER_SIZE = VertexManager::MAXIBUFFERSIZE * sizeof(u16) * 8; const u32 MAX_VBUFFER_SIZE = VertexManager::MAXVBUFFERSIZE; const u32 MAX_BUFFER_SIZE = MAX_IBUFFER_SIZE + MAX_VBUFFER_SIZE; +static ID3D11Buffer* AllocateConstantBuffer(u32 size) +{ + const u32 cbsize = Common::AlignUp(size, 16u); // must be a multiple of 16 + const CD3D11_BUFFER_DESC cbdesc(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, + D3D11_CPU_ACCESS_WRITE); + ID3D11Buffer* cbuf; + const HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &cbuf); + CHECK(hr == S_OK, "shader constant buffer (size=%u)", cbsize); + D3D::SetDebugObjectName(cbuf, "constant buffer used to emulate the GX pipeline"); + return cbuf; +} + +static void UpdateConstantBuffer(ID3D11Buffer* const buffer, const void* data, u32 data_size) +{ + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, data, data_size); + D3D::context->Unmap(buffer, 0); + + ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size); +} + void VertexManager::CreateDeviceObjects() { D3D11_BUFFER_DESC bufdesc = CD3D11_BUFFER_DESC(MAX_BUFFER_SIZE, D3D11_BIND_INDEX_BUFFER | D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - m_vertexDrawOffset = 0; - m_indexDrawOffset = 0; - for (int i = 0; i < MAX_BUFFER_COUNT; i++) { m_buffers[i] = nullptr; @@ -50,12 +73,18 @@ void VertexManager::CreateDeviceObjects() D3D::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager"); } - m_currentBuffer = 0; - m_bufferCursor = MAX_BUFFER_SIZE; + m_buffer_cursor = MAX_BUFFER_SIZE; + + m_vertex_constant_buffer = AllocateConstantBuffer(sizeof(VertexShaderConstants)); + m_geometry_constant_buffer = AllocateConstantBuffer(sizeof(GeometryShaderConstants)); + m_pixel_constant_buffer = AllocateConstantBuffer(sizeof(PixelShaderConstants)); } void VertexManager::DestroyDeviceObjects() { + SAFE_RELEASE(m_pixel_constant_buffer); + SAFE_RELEASE(m_geometry_constant_buffer); + SAFE_RELEASE(m_vertex_constant_buffer); for (int i = 0; i < MAX_BUFFER_COUNT; i++) { SAFE_RELEASE(m_buffers[i]); @@ -64,12 +93,12 @@ void VertexManager::DestroyDeviceObjects() VertexManager::VertexManager() { - LocalVBuffer.resize(MAXVBUFFERSIZE); + m_staging_vertex_buffer.resize(MAXVBUFFERSIZE); - m_cur_buffer_pointer = m_base_buffer_pointer = &LocalVBuffer[0]; - m_end_buffer_pointer = m_base_buffer_pointer + LocalVBuffer.size(); + m_cur_buffer_pointer = m_base_buffer_pointer = &m_staging_vertex_buffer[0]; + m_end_buffer_pointer = m_base_buffer_pointer + m_staging_vertex_buffer.size(); - LocalIBuffer.resize(MAXIBUFFERSIZE); + m_staging_index_buffer.resize(MAXIBUFFERSIZE); CreateDeviceObjects(); } @@ -79,71 +108,103 @@ VertexManager::~VertexManager() DestroyDeviceObjects(); } -void VertexManager::PrepareDrawBuffers(u32 stride) +void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) +{ + // Just use the one buffer for all three. + UpdateConstantBuffer(m_vertex_constant_buffer, uniforms, uniforms_size); + D3D::stateman->SetVertexConstants(m_vertex_constant_buffer); + D3D::stateman->SetGeometryConstants(m_vertex_constant_buffer); + D3D::stateman->SetPixelConstants(m_vertex_constant_buffer); + VertexShaderManager::dirty = true; + GeometryShaderManager::dirty = true; + PixelShaderManager::dirty = true; +} + +void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all) +{ + m_cur_buffer_pointer = m_base_buffer_pointer; + IndexGenerator::Start(m_staging_index_buffer.data()); +} + +void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) { D3D11_MAPPED_SUBRESOURCE map; - u32 vertexBufferSize = u32(m_cur_buffer_pointer - m_base_buffer_pointer); - u32 indexBufferSize = IndexGenerator::GetIndexLen() * sizeof(u16); + u32 vertexBufferSize = Common::AlignUp(num_vertices * vertex_stride, sizeof(u16)); + u32 indexBufferSize = num_indices * sizeof(u16); u32 totalBufferSize = vertexBufferSize + indexBufferSize; - u32 cursor = m_bufferCursor; - u32 padding = m_bufferCursor % stride; + u32 cursor = m_buffer_cursor; + u32 padding = vertex_stride > 0 ? (m_buffer_cursor % vertex_stride) : 0; if (padding) { - cursor += stride - padding; + cursor += vertex_stride - padding; } D3D11_MAP MapType = D3D11_MAP_WRITE_NO_OVERWRITE; if (cursor + totalBufferSize >= MAX_BUFFER_SIZE) { // Wrap around - m_currentBuffer = (m_currentBuffer + 1) % MAX_BUFFER_COUNT; + m_current_buffer = (m_current_buffer + 1) % MAX_BUFFER_COUNT; cursor = 0; MapType = D3D11_MAP_WRITE_DISCARD; } - m_vertexDrawOffset = cursor; - m_indexDrawOffset = cursor + vertexBufferSize; + *out_base_vertex = vertex_stride > 0 ? (cursor / vertex_stride) : 0; + *out_base_index = (cursor + vertexBufferSize) / sizeof(u16); - D3D::context->Map(m_buffers[m_currentBuffer], 0, MapType, 0, &map); + D3D::context->Map(m_buffers[m_current_buffer], 0, MapType, 0, &map); u8* mappedData = reinterpret_cast(map.pData); - memcpy(mappedData + m_vertexDrawOffset, m_base_buffer_pointer, vertexBufferSize); - memcpy(mappedData + m_indexDrawOffset, GetIndexBuffer(), indexBufferSize); - D3D::context->Unmap(m_buffers[m_currentBuffer], 0); + if (vertexBufferSize > 0) + std::memcpy(mappedData + cursor, m_base_buffer_pointer, vertexBufferSize); + if (indexBufferSize > 0) + std::memcpy(mappedData + cursor + vertexBufferSize, m_staging_index_buffer.data(), + indexBufferSize); + D3D::context->Unmap(m_buffers[m_current_buffer], 0); - m_bufferCursor = cursor + totalBufferSize; + m_buffer_cursor = cursor + totalBufferSize; ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize); ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize); + + D3D::stateman->SetVertexBuffer(m_buffers[m_current_buffer], vertex_stride, 0); + D3D::stateman->SetIndexBuffer(m_buffers[m_current_buffer]); } -void VertexManager::Draw(u32 stride) +void VertexManager::UploadConstants() { - u32 indices = IndexGenerator::GetIndexLen(); - - D3D::stateman->SetVertexBuffer(m_buffers[m_currentBuffer], stride, 0); - D3D::stateman->SetIndexBuffer(m_buffers[m_currentBuffer]); - - u32 baseVertex = m_vertexDrawOffset / stride; - u32 startIndex = m_indexDrawOffset / sizeof(u16); - - D3D::stateman->Apply(); - D3D::context->DrawIndexed(indices, startIndex, baseVertex); + if (VertexShaderManager::dirty) + { + UpdateConstantBuffer(m_vertex_constant_buffer, &VertexShaderManager::constants, + sizeof(VertexShaderConstants)); + VertexShaderManager::dirty = false; + } + if (GeometryShaderManager::dirty) + { + UpdateConstantBuffer(m_geometry_constant_buffer, &GeometryShaderManager::constants, + sizeof(GeometryShaderConstants)); + GeometryShaderManager::dirty = false; + } + if (PixelShaderManager::dirty) + { + UpdateConstantBuffer(m_pixel_constant_buffer, &PixelShaderManager::constants, + sizeof(PixelShaderConstants)); + PixelShaderManager::dirty = false; + } - INCSTAT(stats.thisFrame.numDrawCalls); + D3D::stateman->SetPixelConstants(m_pixel_constant_buffer, g_ActiveConfig.bEnablePixelLighting ? + m_vertex_constant_buffer : + nullptr); + D3D::stateman->SetVertexConstants(m_vertex_constant_buffer); + D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer); } -void VertexManager::vFlush() +void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) { - u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(); - PrepareDrawBuffers(stride); - - if (!m_current_pipeline_object) - return; - FramebufferManager::SetIntegerEFBRenderTarget( m_current_pipeline_config.blending_state.logicopenable); + if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active) { D3D::context->OMSetRenderTargetsAndUnorderedAccessViews( @@ -151,21 +212,7 @@ void VertexManager::vFlush() nullptr); } - g_renderer->SetPipeline(m_current_pipeline_object); - - ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); - D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), - g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); - D3D::stateman->SetVertexConstants(vertexConstants); - D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); - - Draw(stride); -} - -void VertexManager::ResetBuffer(u32 stride) -{ - m_cur_buffer_pointer = m_base_buffer_pointer; - IndexGenerator::Start(GetIndexBuffer()); + D3D::stateman->Apply(); + D3D::context->DrawIndexed(num_indices, base_index, base_vertex); } - -} // namespace +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexManager.h b/Source/Core/VideoBackends/D3D/VertexManager.h index 922f854c6b9f..a7eab78ef51f 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.h +++ b/Source/Core/VideoBackends/D3D/VertexManager.h @@ -42,32 +42,32 @@ class VertexManager : public VertexManagerBase std::unique_ptr CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; - void CreateDeviceObjects() override; - void DestroyDeviceObjects() override; + void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override; protected: - void ResetBuffer(u32 stride) override; - u16* GetIndexBuffer() { return &LocalIBuffer[0]; } + void CreateDeviceObjects() override; + void DestroyDeviceObjects() override; + void ResetBuffer(u32 vertex_stride, bool cull_all) override; + void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex, + u32* out_base_index) override; + void UploadConstants() override; + void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override; private: - void PrepareDrawBuffers(u32 stride); - void Draw(u32 stride); - // temp - void vFlush() override; - - u32 m_vertexDrawOffset; - u32 m_indexDrawOffset; - u32 m_currentBuffer; - u32 m_bufferCursor; - enum { MAX_BUFFER_COUNT = 2 }; - ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT]; + ID3D11Buffer* m_buffers[MAX_BUFFER_COUNT] = {}; + u32 m_current_buffer = 0; + u32 m_buffer_cursor = 0; + + std::vector m_staging_vertex_buffer; + std::vector m_staging_index_buffer; - std::vector LocalVBuffer; - std::vector LocalIBuffer; + ID3D11Buffer* m_vertex_constant_buffer = nullptr; + ID3D11Buffer* m_geometry_constant_buffer = nullptr; + ID3D11Buffer* m_pixel_constant_buffer = nullptr; }; -} // namespace +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 2033a38701ab..b7fc3a258203 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -4,7 +4,6 @@ #include -#include "Common/Align.h" #include "Common/CommonTypes.h" #include "Common/FileUtil.h" #include "Common/MsgHandler.h" @@ -23,7 +22,6 @@ #include "VideoCommon/UberShaderVertex.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexShaderGen.h" -#include "VideoCommon/VertexShaderManager.h" namespace DX11 { @@ -49,25 +47,6 @@ ID3D11InputLayout* VertexShaderCache::GetClearInputLayout() return ClearLayout; } -ID3D11Buffer* vscbuf = nullptr; - -ID3D11Buffer*& VertexShaderCache::GetConstantBuffer() -{ - // TODO: divide the global variables of the generated shaders into about 5 constant buffers to - // speed this up - if (VertexShaderManager::dirty) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(vscbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, &VertexShaderManager::constants, sizeof(VertexShaderConstants)); - D3D::context->Unmap(vscbuf, 0); - VertexShaderManager::dirty = false; - - ADDSTAT(stats.thisFrame.bytesUniformStreamed, sizeof(VertexShaderConstants)); - } - return vscbuf; -} - // this class will load the precompiled shaders into our cache template class VertexShaderCacheInserter : public LinearDiskCacheReader @@ -121,14 +100,6 @@ void VertexShaderCache::Init() {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; - unsigned int cbsize = Common::AlignUp(static_cast(sizeof(VertexShaderConstants)), - 16); // must be a multiple of 16 - D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(cbsize, D3D11_BIND_CONSTANT_BUFFER, - D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &vscbuf); - CHECK(hr == S_OK, "Create vertex shader constant buffer (size=%u)", cbsize); - D3D::SetDebugObjectName(vscbuf, "vertex shader constant buffer used to emulate the GX pipeline"); - D3DBlob* blob; D3D::CompileVertexShader(simple_shader_code, &blob); D3D::device->CreateInputLayout(simpleelems, 2, blob->Data(), blob->Size(), &SimpleLayout); @@ -156,8 +127,6 @@ void VertexShaderCache::Init() void VertexShaderCache::Shutdown() { - SAFE_RELEASE(vscbuf); - SAFE_RELEASE(SimpleVertexShader); SAFE_RELEASE(ClearVertexShader); diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.h b/Source/Core/VideoBackends/D3D/VertexShaderCache.h index b59d75be4743..d7f195880686 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.h +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.h @@ -23,8 +23,6 @@ class VertexShaderCache static void Init(); static void Shutdown(); - static ID3D11Buffer*& GetConstantBuffer(); - static ID3D11VertexShader* GetSimpleVertexShader(); static ID3D11VertexShader* GetClearVertexShader(); static ID3D11InputLayout* GetSimpleInputLayout(); diff --git a/Source/Core/VideoBackends/Null/VertexManager.cpp b/Source/Core/VideoBackends/Null/VertexManager.cpp index 0e121ffa0dba..872e9c36575e 100644 --- a/Source/Core/VideoBackends/Null/VertexManager.cpp +++ b/Source/Core/VideoBackends/Null/VertexManager.cpp @@ -22,6 +22,10 @@ VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_dec return std::make_unique(vtx_decl); } +void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) +{ +} + VertexManager::VertexManager() : m_local_v_buffer(MAXVBUFFERSIZE), m_local_i_buffer(MAXIBUFFERSIZE) { } @@ -30,15 +34,24 @@ VertexManager::~VertexManager() { } -void VertexManager::ResetBuffer(u32 stride) +void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all) { m_cur_buffer_pointer = m_base_buffer_pointer = m_local_v_buffer.data(); m_end_buffer_pointer = m_cur_buffer_pointer + m_local_v_buffer.size(); IndexGenerator::Start(&m_local_i_buffer[0]); } -void VertexManager::vFlush() +void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) +{ +} + +void VertexManager::UploadConstants() +{ +} + +void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) { } -} // namespace +} // namespace Null diff --git a/Source/Core/VideoBackends/Null/VertexManager.h b/Source/Core/VideoBackends/Null/VertexManager.h index 863090cab607..1d6a706ec314 100644 --- a/Source/Core/VideoBackends/Null/VertexManager.h +++ b/Source/Core/VideoBackends/Null/VertexManager.h @@ -20,11 +20,16 @@ class VertexManager : public VertexManagerBase std::unique_ptr CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; + void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override; + protected: - void ResetBuffer(u32 stride) override; + void ResetBuffer(u32 vertex_stride, bool cull_all) override; + void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex, + u32* out_base_index) override; + void UploadConstants() override; + void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override; private: - void vFlush() override; std::vector m_local_v_buffer; std::vector m_local_i_buffer; }; diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 78458aa3fe86..c8d54acd5a5a 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -259,6 +259,21 @@ void ProgramShaderCache::UploadConstants() } } +void ProgramShaderCache::UploadConstants(const void* data, u32 data_size) +{ + // allocate and copy + const u32 alloc_size = Common::AlignUp(data_size, s_ubo_align); + auto buffer = s_buffer->Map(alloc_size, s_ubo_align); + std::memcpy(buffer.first, data, data_size); + s_buffer->Unmap(alloc_size); + + // bind the same sub-buffer to all stages + for (u32 index = 1; index <= 3; index++) + glBindBufferRange(GL_UNIFORM_BUFFER, index, s_buffer->m_buffer, buffer.second, data_size); + + ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size); +} + bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode, const std::string& gcode) { @@ -539,6 +554,11 @@ void ProgramShaderCache::BindVertexFormat(const GLVertexFormat* vertex_format) s_last_VAO = new_VAO; } +bool ProgramShaderCache::IsValidVertexFormatBound() +{ + return s_last_VAO != 0 && s_last_VAO != s_attributeless_VAO; +} + void ProgramShaderCache::InvalidateVertexFormat() { s_last_VAO = 0; diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index 0096c6e5b934..b94e73316740 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -69,6 +69,7 @@ class ProgramShaderCache { public: static void BindVertexFormat(const GLVertexFormat* vertex_format); + static bool IsValidVertexFormatBound(); static void InvalidateVertexFormat(); static void InvalidateLastProgram(); @@ -83,6 +84,7 @@ class ProgramShaderCache static u32 GetUniformBufferAlignment(); static void InvalidateConstants(); static void UploadConstants(); + static void UploadConstants(const void* data, u32 data_size); static void Init(); static void Shutdown(); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index c43bb0ac8715..55de5ec0dcaa 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1184,6 +1184,27 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne glDepthRangef(near_depth, far_depth); } +void Renderer::Draw(u32 base_vertex, u32 num_vertices) +{ + glDrawArrays(static_cast(m_graphics_pipeline)->GetGLPrimitive(), base_vertex, + num_vertices); +} + +void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) +{ + if (g_ogl_config.bSupportsGLBaseVertex) + { + glDrawElementsBaseVertex(static_cast(m_graphics_pipeline)->GetGLPrimitive(), + num_indices, GL_UNSIGNED_SHORT, + static_cast(nullptr) + base_index, base_vertex); + } + else + { + glDrawElements(static_cast(m_graphics_pipeline)->GetGLPrimitive(), + num_indices, GL_UNSIGNED_SHORT, static_cast(nullptr) + base_index); + } +} + void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { @@ -1675,54 +1696,6 @@ void Renderer::SetInterlacingMode() // TODO } -void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) -{ - // Copy in uniforms. - if (uniforms_size > 0) - UploadUtilityUniforms(uniforms, uniforms_size); - - // Draw from base index if there is vertex data. - if (vertices) - { - StreamBuffer* vbuf = static_cast(g_vertex_manager.get())->GetVertexBuffer(); - auto buf = vbuf->Map(vertex_stride * num_vertices, vertex_stride); - std::memcpy(buf.first, vertices, vertex_stride * num_vertices); - vbuf->Unmap(vertex_stride * num_vertices); - glDrawArrays(m_graphics_pipeline->GetGLPrimitive(), buf.second / vertex_stride, num_vertices); - } - else - { - glDrawArrays(m_graphics_pipeline->GetGLPrimitive(), 0, num_vertices); - } -} - -void Renderer::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) -{ - DEBUG_ASSERT(uniforms_size > 0); - - auto buf = ProgramShaderCache::GetUniformBuffer()->Map( - uniforms_size, ProgramShaderCache::GetUniformBufferAlignment()); - std::memcpy(buf.first, uniforms, uniforms_size); - ProgramShaderCache::GetUniformBuffer()->Unmap(uniforms_size); - glBindBufferRange(GL_UNIFORM_BUFFER, 1, ProgramShaderCache::GetUniformBuffer()->m_buffer, - buf.second, uniforms_size); - - // This is rather horrible, but because of how the UBOs are bound, this forces it to rebind. - ProgramShaderCache::InvalidateConstants(); -} - -void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms, - u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z) -{ - glUseProgram(static_cast(shader)->GetGLComputeProgramID()); - if (uniforms_size > 0) - UploadUtilityUniforms(uniforms, uniforms_size); - - glDispatchCompute(groups_x, groups_y, groups_z); - ProgramShaderCache::InvalidateLastProgram(); -} - std::unique_ptr Renderer::CreateAsyncShaderCompiler() { return std::make_unique(); diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index de051ba0d766..2de8ff01a550 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -116,6 +116,8 @@ class Renderer : public ::Renderer void SetInterlacingMode() override; void SetViewport(float x, float y, float width, float height, float near_depth, float far_depth) override; + void Draw(u32 base_vertex, u32 num_vertices) override; + void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; void RenderText(const std::string& text, int left, int top, u32 color) override; @@ -137,18 +139,14 @@ class Renderer : public ::Renderer void ReinterpretPixelData(unsigned int convtype) override; - void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) override; - - void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, u32 uniforms_size, - u32 groups_x, u32 groups_y, u32 groups_z) override; - std::unique_ptr CreateAsyncShaderCompiler() override; // Only call methods from this on the GPU thread. GLContext* GetMainGLContext() const { return m_main_gl_context.get(); } bool IsGLES() const { return m_main_gl_context->IsGLES(); } + const OGLPipeline* GetCurrentGraphicsPipeline() const { return m_graphics_pipeline; } + private: void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc, const TargetRectangle& targetPixelRc, const void* data); @@ -165,7 +163,6 @@ class Renderer : public ::Renderer void ApplyBlendingState(const BlendingState state, bool force = false); void ApplyRasterizationState(const RasterizationState state, bool force = false); void ApplyDepthState(const DepthState state, bool force = false); - void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size); std::unique_ptr m_main_gl_context; std::array m_bound_textures{}; diff --git a/Source/Core/VideoBackends/OGL/StreamBuffer.h b/Source/Core/VideoBackends/OGL/StreamBuffer.h index 83b79bd906da..2a8efba1af18 100644 --- a/Source/Core/VideoBackends/OGL/StreamBuffer.h +++ b/Source/Core/VideoBackends/OGL/StreamBuffer.h @@ -19,6 +19,8 @@ class StreamBuffer static std::unique_ptr Create(u32 type, u32 size); virtual ~StreamBuffer(); + u32 GetCurrentOffset() const { return m_iterator; } + /* This mapping function will return a pair of: * - the pointer to the mapped buffer * - the offset into the real GPU buffer (always multiple of stride) diff --git a/Source/Core/VideoBackends/OGL/VertexManager.cpp b/Source/Core/VideoBackends/OGL/VertexManager.cpp index 00cf6b3cfa8f..3883a1359574 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.cpp +++ b/Source/Core/VideoBackends/OGL/VertexManager.cpp @@ -15,6 +15,7 @@ #include "Common/StringUtil.h" #include "VideoBackends/OGL/BoundingBox.h" +#include "VideoBackends/OGL/OGLPipeline.h" #include "VideoBackends/OGL/ProgramShaderCache.h" #include "VideoBackends/OGL/Render.h" #include "VideoBackends/OGL/StreamBuffer.h" @@ -31,11 +32,6 @@ namespace OGL const u32 MAX_IBUFFER_SIZE = 2 * 1024 * 1024; const u32 MAX_VBUFFER_SIZE = 32 * 1024 * 1024; -static std::unique_ptr s_vertexBuffer; -static std::unique_ptr s_indexBuffer; -static size_t s_baseVertex; -static size_t s_index_offset; - VertexManager::VertexManager() : m_cpu_v_buffer(MAX_VBUFFER_SIZE), m_cpu_i_buffer(MAX_IBUFFER_SIZE) { CreateDeviceObjects(); @@ -48,58 +44,45 @@ VertexManager::~VertexManager() void VertexManager::CreateDeviceObjects() { - s_vertexBuffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE); - m_vertex_buffers = s_vertexBuffer->m_buffer; - - s_indexBuffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE); - m_index_buffers = s_indexBuffer->m_buffer; + m_vertex_buffer = StreamBuffer::Create(GL_ARRAY_BUFFER, MAX_VBUFFER_SIZE); + m_index_buffer = StreamBuffer::Create(GL_ELEMENT_ARRAY_BUFFER, MAX_IBUFFER_SIZE); } void VertexManager::DestroyDeviceObjects() { - s_vertexBuffer.reset(); - s_indexBuffer.reset(); + m_vertex_buffer.reset(); + m_index_buffer.reset(); } -StreamBuffer* VertexManager::GetVertexBuffer() const +void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) { - return s_vertexBuffer.get(); -} - -OGL::StreamBuffer* VertexManager::GetIndexBuffer() const -{ - return s_indexBuffer.get(); + ProgramShaderCache::InvalidateConstants(); + ProgramShaderCache::UploadConstants(uniforms, uniforms_size); } GLuint VertexManager::GetVertexBufferHandle() const { - return m_vertex_buffers; + return m_vertex_buffer->m_buffer; } GLuint VertexManager::GetIndexBufferHandle() const { - return m_index_buffers; + return m_index_buffer->m_buffer; } -void VertexManager::PrepareDrawBuffers(u32 stride) +static void CheckBufferBinding() { - u32 vertex_data_size = IndexGenerator::GetNumVerts() * stride; - u32 index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); - // The index buffer is part of the VAO state, therefore we need to bind it first. - const GLVertexFormat* vertex_format = - static_cast(VertexLoaderManager::GetCurrentVertexFormat()); - ProgramShaderCache::BindVertexFormat(vertex_format); - s_vertexBuffer->Unmap(vertex_data_size); - s_indexBuffer->Unmap(index_data_size); - - ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); + if (!ProgramShaderCache::IsValidVertexFormatBound()) + { + ProgramShaderCache::BindVertexFormat( + static_cast(VertexLoaderManager::GetCurrentVertexFormat())); + } } -void VertexManager::ResetBuffer(u32 stride) +void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all) { - if (m_cull_all) + if (cull_all) { // This buffer isn't getting sent to the GPU. Just allocate it on the cpu. m_cur_buffer_pointer = m_base_buffer_pointer = m_cpu_v_buffer.data(); @@ -109,68 +92,41 @@ void VertexManager::ResetBuffer(u32 stride) } else { - // The index buffer is part of the VAO state, therefore we need to bind it first. - const GLVertexFormat* vertex_format = - static_cast(VertexLoaderManager::GetCurrentVertexFormat()); - ProgramShaderCache::BindVertexFormat(vertex_format); + CheckBufferBinding(); - auto buffer = s_vertexBuffer->Map(MAXVBUFFERSIZE, stride); + auto buffer = m_vertex_buffer->Map(MAXVBUFFERSIZE, vertex_stride); m_cur_buffer_pointer = m_base_buffer_pointer = buffer.first; m_end_buffer_pointer = buffer.first + MAXVBUFFERSIZE; - s_baseVertex = buffer.second / stride; - buffer = s_indexBuffer->Map(MAXIBUFFERSIZE * sizeof(u16)); + buffer = m_index_buffer->Map(MAXIBUFFERSIZE * sizeof(u16)); IndexGenerator::Start((u16*)buffer.first); - s_index_offset = buffer.second; } } -void VertexManager::Draw(u32 stride) +void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) { - u32 index_size = IndexGenerator::GetIndexLen(); - u32 max_index = IndexGenerator::GetNumVerts(); - GLenum primitive_mode = 0; + u32 vertex_data_size = num_vertices * vertex_stride; + u32 index_data_size = num_indices * sizeof(u16); - switch (m_current_primitive_type) - { - case PrimitiveType::Points: - primitive_mode = GL_POINTS; - break; - case PrimitiveType::Lines: - primitive_mode = GL_LINES; - break; - case PrimitiveType::Triangles: - primitive_mode = GL_TRIANGLES; - break; - case PrimitiveType::TriangleStrip: - primitive_mode = GL_TRIANGLE_STRIP; - break; - } + *out_base_vertex = vertex_stride > 0 ? (m_vertex_buffer->GetCurrentOffset() / vertex_stride) : 0; + *out_base_index = m_index_buffer->GetCurrentOffset() / sizeof(u16); - if (g_ogl_config.bSupportsGLBaseVertex) - { - glDrawRangeElementsBaseVertex(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, - (u8*)nullptr + s_index_offset, (GLint)s_baseVertex); - } - else - { - glDrawRangeElements(primitive_mode, 0, max_index, index_size, GL_UNSIGNED_SHORT, - (u8*)nullptr + s_index_offset); - } + CheckBufferBinding(); + m_vertex_buffer->Unmap(vertex_data_size); + m_index_buffer->Unmap(index_data_size); - INCSTAT(stats.thisFrame.numDrawCalls); + ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertex_data_size); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, index_data_size); } -void VertexManager::vFlush() +void VertexManager::UploadConstants() { - GLVertexFormat* nativeVertexFmt = (GLVertexFormat*)VertexLoaderManager::GetCurrentVertexFormat(); - u32 stride = nativeVertexFmt->GetVertexStride(); - - PrepareDrawBuffers(stride); - - // upload global constants ProgramShaderCache::UploadConstants(); +} +void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) +{ if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation()) { glEnable(GL_STENCIL_TEST); @@ -178,8 +134,8 @@ void VertexManager::vFlush() if (m_current_pipeline_object) { - g_renderer->SetPipeline(m_current_pipeline_object); - Draw(stride); + static_cast(g_renderer.get())->SetPipeline(m_current_pipeline_object); + static_cast(g_renderer.get())->DrawIndexed(base_index, num_indices, base_vertex); } if (::BoundingBox::active && !g_Config.BBoxUseFragmentShaderImplementation()) @@ -191,5 +147,4 @@ void VertexManager::vFlush() g_Config.iSaveTargetId++; ClearEFBCache(); } - -} // namespace +} // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/VertexManager.h b/Source/Core/VideoBackends/OGL/VertexManager.h index 39203c5f4c2d..388c559716d8 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.h +++ b/Source/Core/VideoBackends/OGL/VertexManager.h @@ -35,27 +35,26 @@ class VertexManager : public VertexManagerBase std::unique_ptr CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; - void CreateDeviceObjects() override; - void DestroyDeviceObjects() override; + void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override; - StreamBuffer* GetVertexBuffer() const; - StreamBuffer* GetIndexBuffer() const; GLuint GetVertexBufferHandle() const; GLuint GetIndexBufferHandle() const; protected: - void ResetBuffer(u32 stride) override; + void CreateDeviceObjects() override; + void DestroyDeviceObjects() override; + void ResetBuffer(u32 vertex_stride, bool cull_all) override; + void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex, + u32* out_base_index) override; + void UploadConstants() override; + void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override; private: - void Draw(u32 stride); - void vFlush() override; - void PrepareDrawBuffers(u32 stride); - - GLuint m_vertex_buffers; - GLuint m_index_buffers; + std::unique_ptr m_vertex_buffer; + std::unique_ptr m_index_buffer; // Alternative buffers in CPU memory for primatives we are going to discard. std::vector m_cpu_v_buffer; std::vector m_cpu_i_buffer; }; -} +} // namespace OGL diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index e62a0a234815..4a53b4041c12 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -48,14 +48,29 @@ SWVertexLoader::~SWVertexLoader() { } -void SWVertexLoader::ResetBuffer(u32 stride) +void SWVertexLoader::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) +{ +} + +void SWVertexLoader::ResetBuffer(u32 vertex_stride, bool cull_all) { m_cur_buffer_pointer = m_base_buffer_pointer = m_local_vertex_buffer.data(); m_end_buffer_pointer = m_cur_buffer_pointer + m_local_vertex_buffer.size(); IndexGenerator::Start(m_local_index_buffer.data()); } -void SWVertexLoader::vFlush() +void SWVertexLoader::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) +{ + *out_base_vertex = 0; + *out_base_index = 0; +} + +void SWVertexLoader::UploadConstants() +{ +} + +void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) { DebugUtil::OnObjectBegin(); diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.h b/Source/Core/VideoBackends/Software/SWVertexLoader.h index abb4c86b7cc0..dabbdef16814 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.h +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.h @@ -23,9 +23,14 @@ class SWVertexLoader final : public VertexManagerBase std::unique_ptr CreateNativeVertexFormat(const PortableVertexDeclaration& vdec) override; -private: - void ResetBuffer(u32 stride) override; - void vFlush() override; + void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override; + +protected: + void ResetBuffer(u32 vertex_stride, bool cull_all) override; + void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex, + u32* out_base_index) override; + void UploadConstants() override; + void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override; void SetFormat(u8 attributeIndex, u8 primitiveType); void ParseVertex(const PortableVertexDeclaration& vdec, int index); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 764250cbe92b..6bec5998820d 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -259,158 +259,6 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline) StateTracker::GetInstance()->SetPipeline(static_cast(pipeline)); } -void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) -{ - // Binding the utility pipeline layout breaks the standard layout. - StateTracker::GetInstance()->SetPendingRebind(); - - // Upload uniforms. - VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer(); - u32 uniform_buffer_offset = 0; - if (uniforms_size > 0) - std::tie(uniform_buffer, uniform_buffer_offset) = - UpdateUtilityUniformBuffer(uniforms, uniforms_size); - - // Upload vertices. - VkBuffer vertex_buffer = VK_NULL_HANDLE; - VkDeviceSize vertex_buffer_offset = 0; - if (vertices) - { - u32 vertices_size = vertex_stride * num_vertices; - StreamBuffer* vbo_buf = g_object_cache->GetUtilityShaderVertexBuffer(); - if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride)) - { - Util::ExecuteCurrentCommandsAndRestoreState(true); - if (!vbo_buf->ReserveMemory(vertices_size, vertex_stride)) - { - PanicAlert("Failed to reserve vertex buffer space for utility draw."); - return; - } - } - - vertex_buffer = vbo_buf->GetBuffer(); - vertex_buffer_offset = vbo_buf->GetCurrentOffset(); - std::memcpy(vbo_buf->GetCurrentHostPointer(), vertices, vertices_size); - vbo_buf->CommitMemory(vertices_size); - } - - // Allocate descriptor sets. - std::array dsets; - dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER)); - dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS)); - - // Flush first if failed. - if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE) - { - Util::ExecuteCurrentCommandsAndRestoreState(true); - dsets[0] = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER)); - dsets[1] = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS)); - - if (dsets[0] == VK_NULL_HANDLE || dsets[1] == VK_NULL_HANDLE) - { - PanicAlert("Failed to allocate descriptor sets in utility draw."); - return; - } - } - - // Build UBO descriptor set. - std::array dswrites; - VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)}; - dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dsets[0], 0, 0, 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr}; - dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - dsets[1], - 0, - 0, - NUM_PIXEL_SHADER_SAMPLERS, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - StateTracker::GetInstance()->GetPSSamplerBindings().data(), - nullptr, - nullptr}; - - // Build commands. - VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - StateTracker::GetInstance()->GetPipeline()->GetVkPipeline()); - if (vertex_buffer != VK_NULL_HANDLE) - vkCmdBindVertexBuffers(command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset); - - // Update and bind descriptors. - VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY); - vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast(dswrites.size()), - dswrites.data(), 0, nullptr); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, - static_cast(dsets.size()), dsets.data(), 1, &uniform_buffer_offset); - - // Ensure we're in a render pass before drawing, just in case we had to flush. - StateTracker::GetInstance()->BeginRenderPass(); - vkCmdDraw(command_buffer, num_vertices, 1, 0, 0); -} - -void Renderer::DispatchComputeShader(const AbstractShader* shader, const void* uniforms, - u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z) -{ - // Binding the utility pipeline layout breaks the standard layout. - StateTracker::GetInstance()->SetPendingRebind(); - StateTracker::GetInstance()->EndRenderPass(); - - // Upload uniforms. - VkBuffer uniform_buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer(); - u32 uniform_buffer_offset = 0; - if (uniforms_size > 0) - std::tie(uniform_buffer, uniform_buffer_offset) = - UpdateUtilityUniformBuffer(uniforms, uniforms_size); - - // Flush first if failed. - VkDescriptorSet dset = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE)); - if (dset == VK_NULL_HANDLE) - { - Util::ExecuteCurrentCommandsAndRestoreState(true); - dset = g_command_buffer_mgr->AllocateDescriptorSet( - g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_COMPUTE)); - if (dset == VK_NULL_HANDLE) - { - PanicAlert("Failed to allocate descriptor sets in utility dispatch."); - return; - } - } - - std::array dswrites; - VkDescriptorBufferInfo dsbuffer = {uniform_buffer, 0, std::max(uniforms_size, 4u)}; - dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, dset, 0, 0, 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr, &dsbuffer, nullptr}; - dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - dset, - 1, - 0, - NUM_PIXEL_SHADER_SAMPLERS, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - StateTracker::GetInstance()->GetPSSamplerBindings().data(), - nullptr, - nullptr}; - - // TODO: Texel buffers, storage images. - - // Build commands. - VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - VkPipelineLayout pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_UTILITY); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, - static_cast(shader)->GetComputePipeline()); - vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast(dswrites.size()), - dswrites.data(), 0, nullptr); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0, 1, - &dset, 1, &uniform_buffer_offset); - vkCmdDispatch(command_buffer, groups_x, groups_y, groups_z); -} - void Renderer::RenderText(const std::string& text, int left, int top, u32 color) { u32 backbuffer_width = m_swap_chain->GetWidth(); @@ -1185,6 +1033,23 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne StateTracker::GetInstance()->SetViewport(viewport); } +void Renderer::Draw(u32 base_vertex, u32 num_vertices) +{ + if (StateTracker::GetInstance()->Bind()) + return; + + vkCmdDraw(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_vertices, 1, base_vertex, 0); +} + +void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) +{ + if (!StateTracker::GetInstance()->Bind()) + return; + + vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_indices, 1, base_index, + base_vertex, 0); +} + void Renderer::RecompileShaders() { DestroyShaders(); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index edb7764a5d8b..bd7efc88caae 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -87,11 +87,8 @@ class Renderer : public ::Renderer void SetInterlacingMode() override; void SetViewport(float x, float y, float width, float height, float near_depth, float far_depth) override; - - void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) override; - void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, u32 uniforms_size, - u32 groups_x, u32 groups_y, u32 groups_z) override; + void Draw(u32 base_vertex, u32 num_vertices) override; + void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override; private: bool CreateSemaphores(); diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index f3b2752ddd7b..471a8b12f5bc 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -218,6 +218,37 @@ void StateTracker::UpdatePixelShaderConstants() PixelShaderManager::dirty = false; } +void StateTracker::UpdateConstants(const void* data, u32 data_size) +{ + if (!m_uniform_stream_buffer->ReserveMemory( + data_size, g_vulkan_context->GetUniformBufferAlignment(), true, true, false)) + { + WARN_LOG(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer"); + Util::ExecuteCurrentCommandsAndRestoreState(false); + } + + for (u32 binding = 0; binding < NUM_UBO_DESCRIPTOR_SET_BINDINGS; binding++) + { + if (m_bindings.uniform_buffer_bindings[binding].buffer != m_uniform_stream_buffer->GetBuffer()) + { + m_bindings.uniform_buffer_bindings[binding].buffer = m_uniform_stream_buffer->GetBuffer(); + m_dirty_flags |= DIRTY_FLAG_VS_UBO << binding; + } + m_bindings.uniform_buffer_offsets[binding] = + static_cast(m_uniform_stream_buffer->GetCurrentOffset()); + } + m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS; + + std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), data, data_size); + ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size); + m_uniform_stream_buffer->CommitMemory(data_size); + + // Cached data is now out-of-sync. + VertexShaderManager::dirty = true; + GeometryShaderManager::dirty = true; + PixelShaderManager::dirty = true; +} + bool StateTracker::ReserveConstantStorage() { // Since we invalidate all constants on command buffer execution, it doesn't matter if this @@ -473,16 +504,16 @@ bool StateTracker::Bind(bool rebind_all /*= false*/) { vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), 0, m_num_active_descriptor_sets, - m_descriptor_sets.data(), NUM_UBO_DESCRIPTOR_SET_BINDINGS, + m_descriptor_sets.data(), m_num_dynamic_offsets, m_bindings.uniform_buffer_offsets.data()); } else if (m_dirty_flags & DIRTY_FLAG_DYNAMIC_OFFSETS) { - vkCmdBindDescriptorSets( - command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), - DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS, 1, - &m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS], - NUM_UBO_DESCRIPTOR_SET_BINDINGS, m_bindings.uniform_buffer_offsets.data()); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + m_pipeline->GetVkPipelineLayout(), + DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS, 1, + &m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS], + m_num_dynamic_offsets, m_bindings.uniform_buffer_offsets.data()); } if (m_dirty_flags & DIRTY_FLAG_VIEWPORT || rebind_all) @@ -639,6 +670,14 @@ void StateTracker::EndClearRenderPass() } bool StateTracker::UpdateDescriptorSet() +{ + if (m_pipeline->GetUsage() == AbstractPipelineUsage::GX) + return UpdateGXDescriptorSet(); + else + return UpdateUtilityDescriptorSet(); +} + +bool StateTracker::UpdateGXDescriptorSet() { const size_t MAX_DESCRIPTOR_WRITES = NUM_UBO_DESCRIPTOR_SET_BINDINGS + // UBO 1 + // Samplers @@ -729,6 +768,50 @@ bool StateTracker::UpdateDescriptorSet() vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), num_writes, writes.data(), 0, nullptr); m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; + m_num_dynamic_offsets = NUM_UBO_DESCRIPTOR_SET_BINDINGS; + return true; +} + +bool StateTracker::UpdateUtilityDescriptorSet() +{ + // Allocate descriptor sets. + m_descriptor_sets[0] = g_command_buffer_mgr->AllocateDescriptorSet( + g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_SINGLE_UNIFORM_BUFFER)); + m_descriptor_sets[1] = g_command_buffer_mgr->AllocateDescriptorSet( + g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS)); + if (m_descriptor_sets[0] == VK_NULL_HANDLE || m_descriptor_sets[1] == VK_NULL_HANDLE) + { + return false; + } + + // Build UBO descriptor set. + std::array dswrites; + dswrites[0] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + m_descriptor_sets[0], + 0, + 0, + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + nullptr, + &m_bindings.uniform_buffer_bindings[UBO_DESCRIPTOR_SET_BINDING_VS], + nullptr}; + dswrites[1] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + m_descriptor_sets[1], + 0, + 0, + NUM_PIXEL_SHADER_SAMPLERS, + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + m_bindings.ps_samplers.data(), + nullptr, + nullptr}; + + vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast(dswrites.size()), + dswrites.data(), 0, nullptr); + m_num_active_descriptor_sets = NUM_UTILITY_DRAW_DESCRIPTOR_SETS; + m_num_dynamic_offsets = 1; + m_dirty_flags |= DIRTY_FLAG_DESCRIPTOR_SET_BINDING; return true; } diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 895e139756fa..a3d7a365aeb4 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -30,10 +30,6 @@ class StateTracker static bool CreateInstance(); static void DestroyInstance(); - const std::array& GetPSSamplerBindings() const - { - return m_bindings.ps_samplers; - } VkFramebuffer GetFramebuffer() const { return m_framebuffer; } const VKPipeline* GetPipeline() const { return m_pipeline; } void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); @@ -47,6 +43,9 @@ class StateTracker void UpdateGeometryShaderConstants(); void UpdatePixelShaderConstants(); + // Updates constants from external data, e.g. utility draws. + void UpdateConstants(const void* data, u32 data_size); + void SetTexture(size_t index, VkImageView view); void SetSampler(size_t index, VkSampler sampler); @@ -104,7 +103,8 @@ class StateTracker // Number of descriptor sets for game draws. enum { - NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1 + NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1, + NUM_UTILITY_DRAW_DESCRIPTOR_SETS = 2 }; enum DITRY_FLAG : u32 @@ -133,6 +133,8 @@ class StateTracker bool IsViewportWithinRenderArea() const; bool UpdateDescriptorSet(); + bool UpdateGXDescriptorSet(); + bool UpdateUtilityDescriptorSet(); // Allocates storage in the uniform buffer of the specified size. If this storage cannot be // allocated immediately, the current command buffer will be submitted and all stage's @@ -167,6 +169,7 @@ class StateTracker } m_bindings; size_t m_uniform_buffer_reserve_size = 0; u32 m_num_active_descriptor_sets = 0; + u32 m_num_dynamic_offsets = 0; // rasterization VkViewport m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index 4fa3a92b0930..bd0ab0b54df9 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp @@ -69,25 +69,14 @@ VertexManager::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_dec return std::make_unique(vtx_decl); } -void VertexManager::PrepareDrawBuffers(u32 stride) +void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) { - size_t vertex_data_size = IndexGenerator::GetNumVerts() * stride; - size_t index_data_size = IndexGenerator::GetIndexLen() * sizeof(u16); - - m_vertex_stream_buffer->CommitMemory(vertex_data_size); - m_index_stream_buffer->CommitMemory(index_data_size); - - ADDSTAT(stats.thisFrame.bytesVertexStreamed, static_cast(vertex_data_size)); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast(index_data_size)); - - StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0); - StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0, - VK_INDEX_TYPE_UINT16); + StateTracker::GetInstance()->UpdateConstants(uniforms, uniforms_size); } -void VertexManager::ResetBuffer(u32 stride) +void VertexManager::ResetBuffer(u32 vertex_stride, bool cull_all) { - if (m_cull_all) + if (cull_all) { // Not drawing on the gpu, so store in a heap buffer instead m_cur_buffer_pointer = m_base_buffer_pointer = m_cpu_vertex_buffer.data(); @@ -97,7 +86,8 @@ void VertexManager::ResetBuffer(u32 stride) } // Attempt to allocate from buffers - bool has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, stride); + bool has_vbuffer_allocation = + m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride); bool has_ibuffer_allocation = m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16)); if (!has_vbuffer_allocation || !has_ibuffer_allocation) @@ -108,7 +98,7 @@ void VertexManager::ResetBuffer(u32 stride) // Attempt to allocate again, this may cause a fence wait if (!has_vbuffer_allocation) - has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, stride); + has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride); if (!has_ibuffer_allocation) has_ibuffer_allocation = m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16)); @@ -123,34 +113,40 @@ void VertexManager::ResetBuffer(u32 stride) m_end_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer() + MAXVBUFFERSIZE; m_cur_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer(); IndexGenerator::Start(reinterpret_cast(m_index_stream_buffer->GetCurrentHostPointer())); - - // Update base indices - m_current_draw_base_vertex = - static_cast(m_vertex_stream_buffer->GetCurrentOffset() / stride); - m_current_draw_base_index = - static_cast(m_index_stream_buffer->GetCurrentOffset() / sizeof(u16)); } -void VertexManager::vFlush() +void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) { - const VertexFormat* vertex_format = - static_cast(VertexLoaderManager::GetCurrentVertexFormat()); - u32 vertex_stride = vertex_format->GetVertexStride(); + const u32 vertex_data_size = num_vertices * vertex_stride; + const u32 index_data_size = num_indices * sizeof(u16); + + *out_base_vertex = + vertex_stride > 0 ? + static_cast(m_vertex_stream_buffer->GetCurrentOffset() / vertex_stride) : + 0; + *out_base_index = static_cast(m_index_stream_buffer->GetCurrentOffset() / sizeof(u16)); - // Figure out the number of indices to draw - u32 index_count = IndexGenerator::GetIndexLen(); + m_vertex_stream_buffer->CommitMemory(vertex_data_size); + m_index_stream_buffer->CommitMemory(index_data_size); - // Update tracked state + ADDSTAT(stats.thisFrame.bytesVertexStreamed, static_cast(vertex_data_size)); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast(index_data_size)); + + StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0); + StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0, + VK_INDEX_TYPE_UINT16); +} + +void VertexManager::UploadConstants() +{ StateTracker::GetInstance()->UpdateVertexShaderConstants(); StateTracker::GetInstance()->UpdateGeometryShaderConstants(); StateTracker::GetInstance()->UpdatePixelShaderConstants(); +} - // Commit memory to device. - // NOTE: This must be done after constant upload, as a constant buffer overrun can cause - // the current command buffer to be executed, and we want the buffer space to be associated - // with the command buffer that has the corresponding draw. - PrepareDrawBuffers(vertex_stride); - +void VertexManager::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) +{ // Flush all EFB pokes and invalidate the peek cache. FramebufferManager::GetInstance()->InvalidatePeekCache(); FramebufferManager::GetInstance()->FlushEFBPokes(); @@ -168,19 +164,14 @@ void VertexManager::vFlush() } // Bind all pending state to the command buffer - if (m_current_pipeline_object) + if (StateTracker::GetInstance()->Bind()) { - g_renderer->SetPipeline(m_current_pipeline_object); - if (!StateTracker::GetInstance()->Bind()) - { - WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count); - return; - } - - // Execute the draw - vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), index_count, 1, - m_current_draw_base_index, m_current_draw_base_vertex, 0); - INCSTAT(stats.thisFrame.numDrawCalls); + vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_indices, 1, base_index, + base_vertex, 0); + } + else + { + WARN_LOG(VIDEO, "Skipped draw of %u indices", num_indices); } StateTracker::GetInstance()->OnDraw(); diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.h b/Source/Core/VideoBackends/Vulkan/VertexManager.h index 1f892e415142..65c31e11f423 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.h +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.h @@ -27,20 +27,19 @@ class VertexManager : public VertexManagerBase std::unique_ptr CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; -protected: - void PrepareDrawBuffers(u32 stride); - void ResetBuffer(u32 stride) override; + void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) override; -private: - void vFlush() override; +protected: + void ResetBuffer(u32 vertex_stride, bool cull_all) override; + void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, u32* out_base_vertex, + u32* out_base_index) override; + void UploadConstants() override; + void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) override; std::vector m_cpu_vertex_buffer; std::vector m_cpu_index_buffer; std::unique_ptr m_vertex_stream_buffer; std::unique_ptr m_index_stream_buffer; - - u32 m_current_draw_base_vertex = 0; - u32 m_current_draw_base_index = 0; }; } diff --git a/Source/Core/VideoCommon/IndexGenerator.cpp b/Source/Core/VideoCommon/IndexGenerator.cpp index 6cb49acebaa0..5e45cc6a5f21 100644 --- a/Source/Core/VideoCommon/IndexGenerator.cpp +++ b/Source/Core/VideoCommon/IndexGenerator.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "Common/CommonTypes.h" #include "Common/Compiler.h" @@ -56,6 +57,13 @@ void IndexGenerator::AddIndices(int primitive, u32 numVerts) base_index += numVerts; } +void IndexGenerator::AddExternalIndices(const u16* indices, u32 num_indices, u32 num_vertices) +{ + std::memcpy(index_buffer_current, indices, sizeof(u16) * num_indices); + index_buffer_current += num_indices; + base_index += num_vertices; +} + // Triangles template DOLPHIN_FORCE_INLINE u16* IndexGenerator::WriteTriangle(u16* Iptr, u32 index1, u32 index2, diff --git a/Source/Core/VideoCommon/IndexGenerator.h b/Source/Core/VideoCommon/IndexGenerator.h index 8d2a5e870060..67f16b66c18c 100644 --- a/Source/Core/VideoCommon/IndexGenerator.h +++ b/Source/Core/VideoCommon/IndexGenerator.h @@ -18,6 +18,8 @@ class IndexGenerator static void AddIndices(int primitive, u32 numVertices); + static void AddExternalIndices(const u16* indices, u32 num_indices, u32 num_vertices); + // returns numprimitives static u32 GetNumVerts() { return base_index; } static u32 GetIndexLen() { return (u32)(index_buffer_current - BASEIptr); } diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 9fa1beb77266..bea1f5ba0ae4 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -114,6 +114,10 @@ class Renderer { } + // Drawing with currently-bound pipeline state. + virtual void Draw(u32 base_vertex, u32 num_vertices) {} + virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {} + // Shader modules/objects. virtual std::unique_ptr CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) = 0; @@ -192,16 +196,6 @@ class Renderer virtual std::unique_ptr CreateAsyncShaderCompiler(); - // Drawing utility shaders. - virtual void DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, - u32 vertex_stride, u32 num_vertices) - { - } - virtual void DispatchComputeShader(const AbstractShader* shader, const void* uniforms, - u32 uniforms_size, u32 groups_x, u32 groups_y, u32 groups_z) - { - } - void ShowOSDMessage(OSDMessage message); protected: diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 8364b039c52e..0e178e4d9b23 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -27,6 +27,7 @@ #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/SamplerCommon.h" +#include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexShaderManager.h" @@ -131,7 +132,7 @@ DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count, // need to alloc new buffer if (m_is_flushed) { - g_vertex_manager->ResetBuffer(stride); + g_vertex_manager->ResetBuffer(stride, cullall); m_is_flushed = false; } @@ -209,6 +210,28 @@ std::pair VertexManagerBase::ResetFlushAspectRatioCount() return val; } +void VertexManagerBase::UploadUtilityVertices(const void* vertices, u32 vertex_stride, + u32 num_vertices, const u16* indices, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) +{ + // The GX vertex list should be flushed before any utility draws occur. + ASSERT(m_is_flushed); + + // Copy into the buffers usually used for GX drawing. + ResetBuffer(std::max(vertex_stride, 1u), false); + if (vertices) + { + const u32 copy_size = vertex_stride * num_vertices; + ASSERT((m_cur_buffer_pointer + copy_size) <= m_end_buffer_pointer); + std::memcpy(m_cur_buffer_pointer, vertices, copy_size); + m_cur_buffer_pointer += copy_size; + } + if (indices) + IndexGenerator::AddExternalIndices(indices, num_indices, num_vertices); + + CommitBuffer(num_vertices, vertex_stride, num_indices, out_base_vertex, out_base_index); +} + static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex, bool has_arbitrary_mips) { @@ -384,19 +407,35 @@ void VertexManagerBase::Flush() if (!m_cull_all) { + // Update and upload constants. Note for the Vulkan backend, this must occur before the + // vertex/index buffer is committed, otherwise the data will be associated with the + // previous command buffer, instead of the one with the draw if there is an overflow. + GeometryShaderManager::SetConstants(); + PixelShaderManager::SetConstants(); + UploadConstants(); + + // Now the vertices can be flushed to the GPU. + const u32 num_indices = IndexGenerator::GetIndexLen(); + u32 base_vertex, base_index; + CommitBuffer(IndexGenerator::GetNumVerts(), + VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride(), num_indices, + &base_vertex, &base_index); + // Update the pipeline, or compile one if needed. UpdatePipelineConfig(); UpdatePipelineObject(); + if (m_current_pipeline_object) + { + g_renderer->SetPipeline(m_current_pipeline_object); + if (PerfQueryBase::ShouldEmulate()) + g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); - // set the rest of the global constants - GeometryShaderManager::SetConstants(); - PixelShaderManager::SetConstants(); + DrawCurrentBatch(base_index, num_indices, base_vertex); + INCSTAT(stats.thisFrame.numDrawCalls); - if (PerfQueryBase::ShouldEmulate()) - g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); - g_vertex_manager->vFlush(); - if (PerfQueryBase::ShouldEmulate()) - g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); + if (PerfQueryBase::ShouldEmulate()) + g_perf_query->DisableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP); + } } GFX_DEBUGGER_PAUSE_AT(NEXT_FLUSH, true); @@ -413,7 +452,6 @@ void VertexManagerBase::Flush() void VertexManagerBase::DoState(PointerWrap& p) { p.Do(m_zslope); - g_vertex_manager->vDoState(p); } void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format) diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 88d9d9fbe0e1..cd3e4ed55249 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -69,9 +69,29 @@ class VertexManagerBase m_pipeline_config_changed = true; } + // Utility pipeline drawing (e.g. EFB copies, post-processing, UI). + virtual void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size) = 0; + void UploadUtilityVertices(const void* vertices, u32 vertex_stride, u32 num_vertices, + const u16* indices, u32 num_indices, u32* out_base_vertex, + u32* out_base_index); + protected: - virtual void vDoState(PointerWrap& p) {} - virtual void ResetBuffer(u32 stride) = 0; + // Vertex buffers/index buffer creation. + virtual void CreateDeviceObjects() {} + virtual void DestroyDeviceObjects() {} + + // Prepares the buffer for the next batch of vertices. + virtual void ResetBuffer(u32 vertex_stride, bool cull_all) = 0; + + // Commits/uploads the current batch of vertices. + virtual void CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices, + u32* out_base_vertex, u32* out_base_index) = 0; + + // Uploads uniform buffers for GX draws. + virtual void UploadConstants() = 0; + + // Issues the draw call for the current batch in the backend. + virtual void DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_vertex) = 0; u8* m_cur_buffer_pointer = nullptr; u8* m_base_buffer_pointer = nullptr; @@ -98,10 +118,6 @@ class VertexManagerBase size_t m_flush_count_4_3 = 0; size_t m_flush_count_anamorphic = 0; - virtual void vFlush() = 0; - - virtual void CreateDeviceObjects() {} - virtual void DestroyDeviceObjects() {} void UpdatePipelineConfig(); void UpdatePipelineObject(); };