diff options
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 7b65884075..e4a7401c54 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include <algorithm> #include <cstddef> #include <cstdio> #include <limits> @@ -23,9 +24,12 @@ #include "VideoBackends/Vulkan/RasterFont.h" #include "VideoBackends/Vulkan/Renderer.h" #include "VideoBackends/Vulkan/StateTracker.h" +#include "VideoBackends/Vulkan/StreamBuffer.h" #include "VideoBackends/Vulkan/SwapChain.h" #include "VideoBackends/Vulkan/TextureCache.h" #include "VideoBackends/Vulkan/Util.h" +#include "VideoBackends/Vulkan/VKPipeline.h" +#include "VideoBackends/Vulkan/VKShader.h" #include "VideoBackends/Vulkan/VKTexture.h" #include "VideoBackends/Vulkan/VulkanContext.h" @@ -171,6 +175,202 @@ std::unique_ptr<AbstractStagingTexture> Renderer::CreateStagingTexture(StagingTe return VKStagingTexture::Create(type, config); } +std::unique_ptr<AbstractShader> Renderer::CreateShaderFromSource(ShaderStage stage, + const char* source, size_t length) +{ + return VKShader::CreateFromSource(stage, source, length); +} + +std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage stage, + const void* data, size_t length) +{ + return VKShader::CreateFromBinary(stage, data, length); +} + +std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config) +{ + return VKPipeline::Create(config); +} + +std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* uniforms, + u32 uniforms_size) +{ + StreamBuffer* ubo_buf = g_object_cache->GetUtilityShaderUniformBuffer(); + if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment())) + { + Util::ExecuteCurrentCommandsAndRestoreState(false, true); + if (!ubo_buf->ReserveMemory(uniforms_size, g_vulkan_context->GetUniformBufferAlignment())) + { + PanicAlert("Failed to reserve uniform buffer space for utility draw."); + return {}; + } + } + + VkBuffer ubo = ubo_buf->GetBuffer(); + u32 ubo_offset = static_cast<u32>(ubo_buf->GetCurrentOffset()); + std::memcpy(ubo_buf->GetCurrentHostPointer(), uniforms, uniforms_size); + ubo_buf->CommitMemory(uniforms_size); + + return std::tie(ubo, ubo_offset); +} + +void Renderer::SetPipeline(const AbstractPipeline* pipeline) +{ + m_graphics_pipeline = 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, + m_graphics_pipeline->GetPipeline()); + 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(); |
