summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/Renderer.cpp
diff options
context:
space:
mode:
authorAnthony <Helios747@users.noreply.github.com>2018-02-23 09:18:19 -0800
committerGitHub <noreply@github.com>2018-02-23 09:18:19 -0800
commitb66f96c617c87d0edbc4a9cb84c8c8e18ead915c (patch)
tree11876004e4d5c0536a2382a9d7fd380488d47fbe /Source/Core/VideoBackends/Vulkan/Renderer.cpp
parenta62343bd4fe2ea425b8543d60922bb3d54d39ab2 (diff)
parentfec6bb4d5676de8834c90d93127c1459f46f8dcb (diff)
Merge pull request #6042 from stenzek/videocommon-pipelines
VideoCommon pipelines ("Abstract Pipeline")
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp200
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();