diff options
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 236 |
1 files changed, 64 insertions, 172 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(); |
