diff options
| author | Pierre Bourdon <delroth@gmail.com> | 2018-12-04 08:47:46 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-04 08:47:46 +0100 |
| commit | 59de8ea50338b39f604fde738229aaeb791cc459 (patch) | |
| tree | 17f445fc7a686cd28859e6c46fb1a32d64a56123 /Source/Core/VideoBackends/Vulkan | |
| parent | c675ef148e6872115bd46cca5b5c51826c75b373 (diff) | |
| parent | 7afd5cc2fb7e45f2c497e5aed007a017b8461335 (diff) | |
Merge pull request #7592 from stenzek/imgui-prereq
VideoBackends: Share GX vertex/index/uniform buffers with utility draws
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 236 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.h | 14 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/StateTracker.cpp | 95 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/StateTracker.h | 13 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/SwapChain.cpp | 48 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/SwapChain.h | 8 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Util.cpp | 3 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/VertexManager.cpp | 87 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/VertexManager.h | 15 |
9 files changed, 247 insertions, 272 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index ce52b0718d..6bec599882 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<SwapChain> swap_chain) : ::Renderer(swap_chain ? static_cast<int>(swap_chain->GetWidth()) : 1, - swap_chain ? static_cast<int>(swap_chain->GetHeight()) : 0), + swap_chain ? static_cast<int>(swap_chain->GetHeight()) : 0, + swap_chain ? swap_chain->GetTextureFormat() : AbstractTextureFormat::Undefined), m_swap_chain(std::move(swap_chain)) { UpdateActiveConfig(); @@ -57,13 +58,7 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain) m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex; } -Renderer::~Renderer() -{ - UpdateActiveConfig(); - - DestroyShaders(); - DestroySemaphores(); -} +Renderer::~Renderer() = default; Renderer* Renderer::GetInstance() { @@ -77,6 +72,9 @@ bool Renderer::IsHeadless() const bool Renderer::Initialize() { + if (!::Renderer::Initialize()) + return false; + BindEFBToStateTracker(); if (!CreateSemaphores()) @@ -98,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<BoundingBox>(); if (!m_bounding_box->Initialize()) { @@ -131,6 +146,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 @@ -232,164 +259,12 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline) StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(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<VkDescriptorSet, 2> 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<VkWriteDescriptorSet, 2> 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<u32>(dswrites.size()), - dswrites.data(), 0, nullptr); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, - static_cast<u32>(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<VkWriteDescriptorSet, 2> 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<const VKShader*>(shader)->GetComputePipeline()); - vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), static_cast<u32>(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(); 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<float>(backbuffer_width) - 1, 1 - top * 2.0f / static_cast<float>(backbuffer_height), backbuffer_width, backbuffer_height, color); @@ -807,20 +682,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 @@ -831,7 +704,7 @@ 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(); // Transition the backbuffer to PRESENT_SRC to ensure all commands drawing // to it have finished before present. @@ -1021,6 +894,8 @@ void Renderer::RestoreAPIState() static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample(); BindEFBToStateTracker(); + BPFunctions::SetViewport(); + BPFunctions::SetScissor(); // Instruct the state tracker to re-bind everything before the next draw StateTracker::GetInstance()->SetPendingRebind(); @@ -1158,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 ba8fd889bd..bd7efc88ca 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -37,6 +37,9 @@ public: bool IsHeadless() const override; + bool Initialize() override; + void Shutdown() override; + std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override; std::unique_ptr<AbstractStagingTexture> CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override; @@ -52,8 +55,6 @@ public: 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; @@ -86,11 +87,8 @@ public: 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(); @@ -124,6 +122,8 @@ private: 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<SwapChain> m_swap_chain; std::unique_ptr<BoundingBox> m_bounding_box; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index f3b2752ddd..471a8b12f5 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<uint32_t>(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) @@ -640,6 +671,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 1; // SSBO @@ -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<VkWriteDescriptorSet, 2> 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<uint32_t>(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 895e139756..a3d7a365ae 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -30,10 +30,6 @@ public: static bool CreateInstance(); static void DestroyInstance(); - const std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS>& 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 @@ public: 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 @@ private: // 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 @@ private: 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 @@ private: } 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/SwapChain.cpp b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp index ffddfe4d07..3ba46b9baa 100644 --- a/Source/Core/VideoBackends/Vulkan/SwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/SwapChain.cpp @@ -142,11 +142,8 @@ std::unique_ptr<SwapChain> SwapChain::Create(void* display_handle, void* native_ std::unique_ptr<SwapChain> swap_chain = std::make_unique<SwapChain>(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 8cf2776a36..4494d7bc57 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 @@ public: 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 @@ private: bool CreateSwapChain(); void DestroySwapChain(); - bool CreateRenderPass(); - bool SetupSwapChainImages(); void DestroySwapChainImages(); @@ -88,14 +87,13 @@ private: 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<SwapChainImage> 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/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 4ffa5c0146..35c9bcfbaf 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; diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index 4fa3a92b09..bd0ab0b54d 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<VertexFormat>(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<int>(vertex_data_size)); - ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast<int>(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<u16*>(m_index_stream_buffer->GetCurrentHostPointer())); - - // Update base indices - m_current_draw_base_vertex = - static_cast<u32>(m_vertex_stream_buffer->GetCurrentOffset() / stride); - m_current_draw_base_index = - static_cast<u32>(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<VertexFormat*>(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<u32>(m_vertex_stream_buffer->GetCurrentOffset() / vertex_stride) : + 0; + *out_base_index = static_cast<u32>(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<int>(vertex_data_size)); + ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast<int>(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 1f892e4151..65c31e11f4 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.h +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.h @@ -27,20 +27,19 @@ public: std::unique_ptr<NativeVertexFormat> 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<u8> m_cpu_vertex_buffer; std::vector<u16> m_cpu_index_buffer; std::unique_ptr<StreamBuffer> m_vertex_stream_buffer; std::unique_ptr<StreamBuffer> m_index_stream_buffer; - - u32 m_current_draw_base_vertex = 0; - u32 m_current_draw_base_index = 0; }; } |
