summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/Util.cpp
diff options
context:
space:
mode:
authorMat M <mathew1800@gmail.com>2016-09-30 19:15:50 -0400
committerGitHub <noreply@github.com>2016-09-30 19:15:50 -0400
commit46b9383280a623753686ab6df6c479e784e416ae (patch)
tree9ffb2cbdba6d39a29d6fed9df4db03166755a20d /Source/Core/VideoBackends/Vulkan/Util.cpp
parentf3cdc6433cba253fa4485cd7e27025c31410ed0c (diff)
parenta8194cff3ca8f9b85a779da6b8214b58ba3fa7d0 (diff)
Merge pull request #3935 from stenzek/vulkan-pr
Vulkan Backend
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Util.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Util.cpp755
1 files changed, 755 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp
new file mode 100644
index 0000000000..5048466aa2
--- /dev/null
+++ b/Source/Core/VideoBackends/Vulkan/Util.cpp
@@ -0,0 +1,755 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "Common/Assert.h"
+#include "Common/CommonFuncs.h"
+#include "Common/MathUtil.h"
+
+#include "VideoBackends/Vulkan/CommandBufferManager.h"
+#include "VideoBackends/Vulkan/ObjectCache.h"
+#include "VideoBackends/Vulkan/Renderer.h"
+#include "VideoBackends/Vulkan/ShaderCompiler.h"
+#include "VideoBackends/Vulkan/StateTracker.h"
+#include "VideoBackends/Vulkan/StreamBuffer.h"
+#include "VideoBackends/Vulkan/Util.h"
+#include "VideoBackends/Vulkan/VulkanContext.h"
+
+namespace Vulkan
+{
+namespace Util
+{
+size_t AlignValue(size_t value, size_t alignment)
+{
+ // Have to use mod rather than masking bits in case alignment is not a power of two.
+ size_t offset = value % alignment;
+ if (offset != 0)
+ value += (alignment - offset);
+ return value;
+}
+
+size_t AlignBufferOffset(size_t offset, size_t alignment)
+{
+ // Assume an offset of zero is already aligned to a value larger than alignment.
+ if (offset == 0)
+ return 0;
+
+ return AlignValue(offset, alignment);
+}
+
+u32 MakeRGBA8Color(float r, float g, float b, float a)
+{
+ return (static_cast<u32>(MathUtil::Clamp(static_cast<int>(r * 255.0f), 0, 255)) << 0) |
+ (static_cast<u32>(MathUtil::Clamp(static_cast<int>(g * 255.0f), 0, 255)) << 8) |
+ (static_cast<u32>(MathUtil::Clamp(static_cast<int>(b * 255.0f), 0, 255)) << 16) |
+ (static_cast<u32>(MathUtil::Clamp(static_cast<int>(a * 255.0f), 0, 255)) << 24);
+}
+
+bool IsDepthFormat(VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_D16_UNORM:
+ case VK_FORMAT_D16_UNORM_S8_UINT:
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ case VK_FORMAT_D32_SFLOAT:
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+VkFormat GetLinearFormat(VkFormat format)
+{
+ switch (format)
+ {
+ case VK_FORMAT_R8_SRGB:
+ return VK_FORMAT_R8_UNORM;
+ case VK_FORMAT_R8G8_SRGB:
+ return VK_FORMAT_R8G8_UNORM;
+ case VK_FORMAT_R8G8B8_SRGB:
+ return VK_FORMAT_R8G8B8_UNORM;
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ return VK_FORMAT_R8G8B8A8_UNORM;
+ case VK_FORMAT_B8G8R8_SRGB:
+ return VK_FORMAT_B8G8R8_UNORM;
+ case VK_FORMAT_B8G8R8A8_SRGB:
+ return VK_FORMAT_B8G8R8A8_UNORM;
+ default:
+ return format;
+ }
+}
+
+u32 GetTexelSize(VkFormat format)
+{
+ // Only contains pixel formats we use.
+ switch (format)
+ {
+ case VK_FORMAT_R32_SFLOAT:
+ return 4;
+
+ case VK_FORMAT_D32_SFLOAT:
+ return 4;
+
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ return 4;
+
+ case VK_FORMAT_B8G8R8A8_UNORM:
+ return 4;
+
+ default:
+ PanicAlert("Unhandled pixel format");
+ return 1;
+ }
+}
+
+VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
+{
+ switch (factor)
+ {
+ case VK_BLEND_FACTOR_SRC_COLOR:
+ return VK_BLEND_FACTOR_SRC_ALPHA;
+ case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
+ return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ case VK_BLEND_FACTOR_DST_COLOR:
+ return VK_BLEND_FACTOR_DST_ALPHA;
+ case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
+ return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
+ default:
+ return factor;
+ }
+}
+
+RasterizationState GetNoCullRasterizationState()
+{
+ RasterizationState state = {};
+ state.cull_mode = VK_CULL_MODE_NONE;
+ state.samples = VK_SAMPLE_COUNT_1_BIT;
+ state.per_sample_shading = VK_FALSE;
+ state.depth_clamp = VK_FALSE;
+ return state;
+}
+
+DepthStencilState GetNoDepthTestingDepthStencilState()
+{
+ DepthStencilState state = {};
+ state.test_enable = VK_FALSE;
+ state.write_enable = VK_FALSE;
+ state.compare_op = VK_COMPARE_OP_ALWAYS;
+ return state;
+}
+
+BlendState GetNoBlendingBlendState()
+{
+ BlendState state = {};
+ state.blend_enable = VK_FALSE;
+ state.blend_op = VK_BLEND_OP_ADD;
+ state.src_blend = VK_BLEND_FACTOR_ONE;
+ state.dst_blend = VK_BLEND_FACTOR_ZERO;
+ state.alpha_blend_op = VK_BLEND_OP_ADD;
+ state.src_alpha_blend = VK_BLEND_FACTOR_ONE;
+ state.dst_alpha_blend = VK_BLEND_FACTOR_ZERO;
+ state.logic_op_enable = VK_FALSE;
+ state.logic_op = VK_LOGIC_OP_CLEAR;
+ state.write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+ return state;
+}
+
+void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
+ float min_depth /*= 0.0f*/, float max_depth /*= 1.0f*/)
+{
+ VkViewport viewport = {static_cast<float>(x),
+ static_cast<float>(y),
+ static_cast<float>(width),
+ static_cast<float>(height),
+ min_depth,
+ max_depth};
+
+ VkRect2D scissor = {{x, y}, {static_cast<uint32_t>(width), static_cast<uint32_t>(height)}};
+
+ vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+ vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+}
+
+void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer,
+ VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask,
+ VkDeviceSize offset, VkDeviceSize size,
+ VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask)
+{
+ VkBufferMemoryBarrier buffer_info = {
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
+ nullptr, // const void* pNext
+ src_access_mask, // VkAccessFlags srcAccessMask
+ dst_access_mask, // VkAccessFlags dstAccessMask
+ VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
+ VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
+ buffer, // VkBuffer buffer
+ offset, // VkDeviceSize offset
+ size // VkDeviceSize size
+ };
+
+ vkCmdPipelineBarrier(command_buffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 1,
+ &buffer_info, 0, nullptr);
+}
+
+void ExecuteCurrentCommandsAndRestoreState(StateTracker* state_tracker, bool execute_off_thread,
+ bool wait_for_completion)
+{
+ state_tracker->EndRenderPass();
+ g_command_buffer_mgr->ExecuteCommandBuffer(execute_off_thread, wait_for_completion);
+ state_tracker->InvalidateDescriptorSets();
+ state_tracker->SetPendingRebind();
+}
+
+VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count)
+{
+ VkShaderModuleCreateInfo info = {};
+ info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ info.codeSize = spv_word_count * sizeof(u32);
+ info.pCode = spv;
+
+ VkShaderModule module;
+ VkResult res = vkCreateShaderModule(g_vulkan_context->GetDevice(), &info, nullptr, &module);
+ if (res != VK_SUCCESS)
+ {
+ LOG_VULKAN_ERROR(res, "vkCreateShaderModule failed: ");
+ return VK_NULL_HANDLE;
+ }
+
+ return module;
+}
+
+VkShaderModule CompileAndCreateVertexShader(const std::string& source_code, bool prepend_header)
+{
+ ShaderCompiler::SPIRVCodeVector code;
+ if (!ShaderCompiler::CompileVertexShader(&code, source_code.c_str(), source_code.length(),
+ prepend_header))
+ {
+ return VK_NULL_HANDLE;
+ }
+
+ return CreateShaderModule(code.data(), code.size());
+}
+
+VkShaderModule CompileAndCreateGeometryShader(const std::string& source_code, bool prepend_header)
+{
+ ShaderCompiler::SPIRVCodeVector code;
+ if (!ShaderCompiler::CompileGeometryShader(&code, source_code.c_str(), source_code.length(),
+ prepend_header))
+ {
+ return VK_NULL_HANDLE;
+ }
+
+ return CreateShaderModule(code.data(), code.size());
+}
+
+VkShaderModule CompileAndCreateFragmentShader(const std::string& source_code, bool prepend_header)
+{
+ ShaderCompiler::SPIRVCodeVector code;
+ if (!ShaderCompiler::CompileFragmentShader(&code, source_code.c_str(), source_code.length(),
+ prepend_header))
+ {
+ return VK_NULL_HANDLE;
+ }
+
+ return CreateShaderModule(code.data(), code.size());
+}
+
+} // namespace Util
+
+template <>
+DeferredResourceDestruction
+DeferredResourceDestruction::Wrapper<VkCommandPool>(VkCommandPool object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.command_pool = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyCommandPool(device, obj.command_pool, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction
+DeferredResourceDestruction::Wrapper<VkDeviceMemory>(VkDeviceMemory object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.device_memory = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkFreeMemory(device, obj.device_memory, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkBuffer>(VkBuffer object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.buffer = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyBuffer(device, obj.buffer, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkBufferView>(VkBufferView object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.buffer_view = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyBufferView(device, obj.buffer_view, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkImage>(VkImage object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.image = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyImage(device, obj.image, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkImageView>(VkImageView object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.image_view = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyImageView(device, obj.image_view, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkRenderPass>(VkRenderPass object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.render_pass = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyRenderPass(device, obj.render_pass, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction
+DeferredResourceDestruction::Wrapper<VkFramebuffer>(VkFramebuffer object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.framebuffer = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyFramebuffer(device, obj.framebuffer, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction
+DeferredResourceDestruction::Wrapper<VkShaderModule>(VkShaderModule object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.shader_module = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyShaderModule(device, obj.shader_module, nullptr);
+ };
+ return ret;
+}
+
+template <>
+DeferredResourceDestruction DeferredResourceDestruction::Wrapper<VkPipeline>(VkPipeline object)
+{
+ DeferredResourceDestruction ret;
+ ret.object.pipeline = object;
+ ret.destroy_callback = [](VkDevice device, const Object& obj) {
+ vkDestroyPipeline(device, obj.pipeline, nullptr);
+ };
+ return ret;
+}
+
+UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer,
+ VkPipelineLayout pipeline_layout, VkRenderPass render_pass,
+ VkShaderModule vertex_shader, VkShaderModule geometry_shader,
+ VkShaderModule pixel_shader)
+ : m_command_buffer(command_buffer)
+{
+ // Populate minimal pipeline state
+ m_pipeline_info.vertex_format = g_object_cache->GetUtilityShaderVertexFormat();
+ m_pipeline_info.pipeline_layout = pipeline_layout;
+ m_pipeline_info.render_pass = render_pass;
+ m_pipeline_info.vs = vertex_shader;
+ m_pipeline_info.gs = geometry_shader;
+ m_pipeline_info.ps = pixel_shader;
+ m_pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits;
+ m_pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits;
+ m_pipeline_info.blend_state.bits = Util::GetNoBlendingBlendState().bits;
+ m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+}
+
+UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(VkPrimitiveTopology topology, size_t count)
+{
+ m_pipeline_info.primitive_topology = topology;
+
+ if (!g_object_cache->GetUtilityShaderVertexBuffer()->ReserveMemory(
+ sizeof(UtilityShaderVertex) * count, sizeof(UtilityShaderVertex), true, true, true))
+ PanicAlert("Failed to allocate space for vertices in backend shader");
+
+ m_vertex_buffer = g_object_cache->GetUtilityShaderVertexBuffer()->GetBuffer();
+ m_vertex_buffer_offset = g_object_cache->GetUtilityShaderVertexBuffer()->GetCurrentOffset();
+
+ return reinterpret_cast<UtilityShaderVertex*>(
+ g_object_cache->GetUtilityShaderVertexBuffer()->GetCurrentHostPointer());
+}
+
+void UtilityShaderDraw::CommitVertices(size_t count)
+{
+ g_object_cache->GetUtilityShaderVertexBuffer()->CommitMemory(sizeof(UtilityShaderVertex) * count);
+ m_vertex_count = static_cast<uint32_t>(count);
+}
+
+void UtilityShaderDraw::UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices,
+ size_t count)
+{
+ UtilityShaderVertex* upload_vertices = ReserveVertices(topology, count);
+ memcpy(upload_vertices, vertices, sizeof(UtilityShaderVertex) * count);
+ CommitVertices(count);
+}
+
+u8* UtilityShaderDraw::AllocateVSUniforms(size_t size)
+{
+ if (!g_object_cache->GetUtilityShaderUniformBuffer()->ReserveMemory(
+ size, g_vulkan_context->GetUniformBufferAlignment(), true, true, true))
+ PanicAlert("Failed to allocate util uniforms");
+
+ return g_object_cache->GetUtilityShaderUniformBuffer()->GetCurrentHostPointer();
+}
+
+void UtilityShaderDraw::CommitVSUniforms(size_t size)
+{
+ m_vs_uniform_buffer.buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
+ m_vs_uniform_buffer.offset = 0;
+ m_vs_uniform_buffer.range = size;
+ m_ubo_offsets[UBO_DESCRIPTOR_SET_BINDING_VS] =
+ static_cast<uint32_t>(g_object_cache->GetUtilityShaderUniformBuffer()->GetCurrentOffset());
+
+ g_object_cache->GetUtilityShaderUniformBuffer()->CommitMemory(size);
+}
+
+u8* UtilityShaderDraw::AllocatePSUniforms(size_t size)
+{
+ if (!g_object_cache->GetUtilityShaderUniformBuffer()->ReserveMemory(
+ size, g_vulkan_context->GetUniformBufferAlignment(), true, true, true))
+ PanicAlert("Failed to allocate util uniforms");
+
+ return g_object_cache->GetUtilityShaderUniformBuffer()->GetCurrentHostPointer();
+}
+
+void UtilityShaderDraw::CommitPSUniforms(size_t size)
+{
+ m_ps_uniform_buffer.buffer = g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer();
+ m_ps_uniform_buffer.offset = 0;
+ m_ps_uniform_buffer.range = size;
+ m_ubo_offsets[UBO_DESCRIPTOR_SET_BINDING_PS] =
+ static_cast<uint32_t>(g_object_cache->GetUtilityShaderUniformBuffer()->GetCurrentOffset());
+
+ g_object_cache->GetUtilityShaderUniformBuffer()->CommitMemory(size);
+}
+
+void UtilityShaderDraw::SetPushConstants(const void* data, size_t data_size)
+{
+ _assert_(static_cast<u32>(data_size) < PUSH_CONSTANT_BUFFER_SIZE);
+
+ vkCmdPushConstants(m_command_buffer, m_pipeline_info.pipeline_layout,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0,
+ static_cast<u32>(data_size), data);
+}
+
+void UtilityShaderDraw::SetPSSampler(size_t index, VkImageView view, VkSampler sampler)
+{
+ m_ps_samplers[index].sampler = sampler;
+ m_ps_samplers[index].imageView = view;
+ m_ps_samplers[index].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+}
+
+void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state)
+{
+ m_pipeline_info.rasterization_state.bits = state.bits;
+}
+
+void UtilityShaderDraw::SetDepthStencilState(const DepthStencilState& state)
+{
+ m_pipeline_info.depth_stencil_state.bits = state.bits;
+}
+
+void UtilityShaderDraw::SetBlendState(const BlendState& state)
+{
+ m_pipeline_info.blend_state.bits = state.bits;
+}
+
+void UtilityShaderDraw::BeginRenderPass(VkFramebuffer framebuffer, const VkRect2D& region,
+ const VkClearValue* clear_value)
+{
+ VkRenderPassBeginInfo begin_info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ nullptr,
+ m_pipeline_info.render_pass,
+ framebuffer,
+ region,
+ clear_value ? 1u : 0u,
+ clear_value};
+
+ vkCmdBeginRenderPass(m_command_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE);
+}
+
+void UtilityShaderDraw::EndRenderPass()
+{
+ vkCmdEndRenderPass(m_command_buffer);
+}
+
+void UtilityShaderDraw::Draw()
+{
+ BindVertexBuffer();
+ BindDescriptors();
+ if (!BindPipeline())
+ return;
+
+ vkCmdDraw(m_command_buffer, m_vertex_count, 1, 0, 0);
+}
+
+void UtilityShaderDraw::DrawQuad(int x, int y, int width, int height, float z)
+{
+ UtilityShaderVertex vertices[4];
+ vertices[0].SetPosition(-1.0f, 1.0f, z);
+ vertices[0].SetTextureCoordinates(0.0f, 1.0f);
+ vertices[0].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[1].SetPosition(1.0f, 1.0f, z);
+ vertices[1].SetTextureCoordinates(1.0f, 1.0f);
+ vertices[1].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[2].SetPosition(-1.0f, -1.0f, z);
+ vertices[2].SetTextureCoordinates(0.0f, 0.0f);
+ vertices[2].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[3].SetPosition(1.0f, -1.0f, z);
+ vertices[3].SetTextureCoordinates(1.0f, 0.0f);
+ vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
+ UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
+ Draw();
+}
+
+void UtilityShaderDraw::DrawQuad(int dst_x, int dst_y, int dst_width, int dst_height, int src_x,
+ int src_y, int src_layer, int src_width, int src_height,
+ int src_full_width, int src_full_height, float z)
+{
+ float u0 = float(src_x) / float(src_full_width);
+ float v0 = float(src_y) / float(src_full_height);
+ float u1 = float(src_x + src_width) / float(src_full_width);
+ float v1 = float(src_y + src_height) / float(src_full_height);
+ float w = static_cast<float>(src_layer);
+
+ UtilityShaderVertex vertices[4];
+ vertices[0].SetPosition(-1.0f, 1.0f, z);
+ vertices[0].SetTextureCoordinates(u0, v1, w);
+ vertices[0].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[1].SetPosition(1.0f, 1.0f, z);
+ vertices[1].SetTextureCoordinates(u1, v1, w);
+ vertices[1].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[2].SetPosition(-1.0f, -1.0f, z);
+ vertices[2].SetTextureCoordinates(u0, v0, w);
+ vertices[2].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+ vertices[3].SetPosition(1.0f, -1.0f, z);
+ vertices[3].SetTextureCoordinates(u1, v0, w);
+ vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
+
+ Util::SetViewportAndScissor(m_command_buffer, dst_x, dst_y, dst_width, dst_height);
+ UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
+ Draw();
+}
+
+void UtilityShaderDraw::DrawColoredQuad(int x, int y, int width, int height, float r, float g,
+ float b, float a, float z)
+{
+ return DrawColoredQuad(x, y, width, height, Util::MakeRGBA8Color(r, g, b, a), z);
+}
+
+void UtilityShaderDraw::DrawColoredQuad(int x, int y, int width, int height, u32 color, float z)
+{
+ UtilityShaderVertex vertices[4];
+ vertices[0].SetPosition(-1.0f, 1.0f, z);
+ vertices[0].SetTextureCoordinates(0.0f, 1.0f);
+ vertices[0].SetColor(color);
+ vertices[1].SetPosition(1.0f, 1.0f, z);
+ vertices[1].SetTextureCoordinates(1.0f, 1.0f);
+ vertices[1].SetColor(color);
+ vertices[2].SetPosition(-1.0f, -1.0f, z);
+ vertices[2].SetTextureCoordinates(0.0f, 0.0f);
+ vertices[2].SetColor(color);
+ vertices[3].SetPosition(1.0f, -1.0f, z);
+ vertices[3].SetTextureCoordinates(1.0f, 0.0f);
+ vertices[3].SetColor(color);
+
+ Util::SetViewportAndScissor(m_command_buffer, x, y, width, height);
+ UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices));
+ Draw();
+}
+
+void UtilityShaderDraw::SetViewportAndScissor(int x, int y, int width, int height)
+{
+ Util::SetViewportAndScissor(m_command_buffer, x, y, width, height, 0.0f, 1.0f);
+}
+
+void UtilityShaderDraw::DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology,
+ u32 vertex_count)
+{
+ m_pipeline_info.vertex_format = nullptr;
+ m_pipeline_info.primitive_topology = primitive_topology;
+
+ BindDescriptors();
+ if (!BindPipeline())
+ return;
+
+ vkCmdDraw(m_command_buffer, vertex_count, 1, 0, 0);
+}
+
+void UtilityShaderDraw::BindVertexBuffer()
+{
+ vkCmdBindVertexBuffers(m_command_buffer, 0, 1, &m_vertex_buffer, &m_vertex_buffer_offset);
+}
+
+void UtilityShaderDraw::BindDescriptors()
+{
+ // TODO: This method is a mess, clean it up
+ std::array<VkDescriptorSet, NUM_DESCRIPTOR_SETS> bind_descriptor_sets = {};
+ std::array<VkWriteDescriptorSet, NUM_UBO_DESCRIPTOR_SET_BINDINGS + NUM_PIXEL_SHADER_SAMPLERS>
+ set_writes = {};
+ uint32_t num_set_writes = 0;
+
+ VkDescriptorBufferInfo dummy_uniform_buffer = {
+ g_object_cache->GetUtilityShaderUniformBuffer()->GetBuffer(), 0, 1};
+
+ // uniform buffers
+ if (m_vs_uniform_buffer.buffer != VK_NULL_HANDLE || m_ps_uniform_buffer.buffer != VK_NULL_HANDLE)
+ {
+ VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(
+ g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_UNIFORM_BUFFERS));
+ if (set == VK_NULL_HANDLE)
+ PanicAlert("Failed to allocate descriptor set for utility draw");
+
+ set_writes[num_set_writes++] = {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, set, UBO_DESCRIPTOR_SET_BINDING_VS, 0, 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr,
+ (m_vs_uniform_buffer.buffer != VK_NULL_HANDLE) ? &m_vs_uniform_buffer :
+ &dummy_uniform_buffer,
+ nullptr};
+
+ set_writes[num_set_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ nullptr,
+ set,
+ UBO_DESCRIPTOR_SET_BINDING_GS,
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ nullptr,
+ &dummy_uniform_buffer,
+ nullptr};
+
+ set_writes[num_set_writes++] = {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, set, UBO_DESCRIPTOR_SET_BINDING_PS, 0, 1,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, nullptr,
+ (m_ps_uniform_buffer.buffer != VK_NULL_HANDLE) ? &m_ps_uniform_buffer :
+ &dummy_uniform_buffer,
+ nullptr};
+
+ bind_descriptor_sets[DESCRIPTOR_SET_UNIFORM_BUFFERS] = set;
+ }
+
+ // PS samplers
+ size_t first_active_sampler;
+ for (first_active_sampler = 0; first_active_sampler < NUM_PIXEL_SHADER_SAMPLERS;
+ first_active_sampler++)
+ {
+ if (m_ps_samplers[first_active_sampler].imageView != VK_NULL_HANDLE &&
+ m_ps_samplers[first_active_sampler].sampler != VK_NULL_HANDLE)
+ {
+ break;
+ }
+ }
+
+ // Check if we have any at all, skip the binding process entirely if we don't
+ if (first_active_sampler != NUM_PIXEL_SHADER_SAMPLERS)
+ {
+ // Allocate a new descriptor set
+ VkDescriptorSet set = g_command_buffer_mgr->AllocateDescriptorSet(
+ g_object_cache->GetDescriptorSetLayout(DESCRIPTOR_SET_PIXEL_SHADER_SAMPLERS));
+ if (set == VK_NULL_HANDLE)
+ PanicAlert("Failed to allocate descriptor set for utility draw");
+
+ for (size_t i = 0; i < NUM_PIXEL_SHADER_SAMPLERS; i++)
+ {
+ const VkDescriptorImageInfo& info = m_ps_samplers[i];
+ if (info.imageView != VK_NULL_HANDLE && info.sampler != VK_NULL_HANDLE)
+ {
+ set_writes[num_set_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ nullptr,
+ set,
+ static_cast<uint32_t>(i),
+ 0,
+ 1,
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ &info,
+ nullptr,
+ nullptr};
+ }
+ }
+
+ bind_descriptor_sets[DESCRIPTOR_SET_PIXEL_SHADER_SAMPLERS] = set;
+ }
+
+ vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), num_set_writes, set_writes.data(), 0,
+ nullptr);
+
+ // Bind only the sets we updated
+ if (bind_descriptor_sets[0] != VK_NULL_HANDLE && bind_descriptor_sets[1] == VK_NULL_HANDLE)
+ {
+ // UBO only
+ vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ m_pipeline_info.pipeline_layout, DESCRIPTOR_SET_UNIFORM_BUFFERS, 1,
+ &bind_descriptor_sets[0], NUM_UBO_DESCRIPTOR_SET_BINDINGS,
+ m_ubo_offsets.data());
+ }
+ else if (bind_descriptor_sets[0] == VK_NULL_HANDLE && bind_descriptor_sets[1] != VK_NULL_HANDLE)
+ {
+ // Samplers only
+ vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ m_pipeline_info.pipeline_layout, DESCRIPTOR_SET_PIXEL_SHADER_SAMPLERS,
+ 1, &bind_descriptor_sets[1], 0, nullptr);
+ }
+ else if (bind_descriptor_sets[0] != VK_NULL_HANDLE && bind_descriptor_sets[1] != VK_NULL_HANDLE)
+ {
+ // Both
+ vkCmdBindDescriptorSets(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+ m_pipeline_info.pipeline_layout, DESCRIPTOR_SET_UNIFORM_BUFFERS, 2,
+ bind_descriptor_sets.data(), NUM_UBO_DESCRIPTOR_SET_BINDINGS,
+ m_ubo_offsets.data());
+ }
+}
+
+bool UtilityShaderDraw::BindPipeline()
+{
+ VkPipeline pipeline = g_object_cache->GetPipeline(m_pipeline_info);
+ if (pipeline == VK_NULL_HANDLE)
+ {
+ PanicAlert("Failed to get pipeline for backend shader draw");
+ return false;
+ }
+
+ vkCmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
+ return true;
+}
+
+} // namespace Vulkan