diff options
| author | Mat M <mathew1800@gmail.com> | 2016-09-30 19:15:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-09-30 19:15:50 -0400 |
| commit | 46b9383280a623753686ab6df6c479e784e416ae (patch) | |
| tree | 9ffb2cbdba6d39a29d6fed9df4db03166755a20d /Source/Core/VideoBackends/Vulkan/Util.cpp | |
| parent | f3cdc6433cba253fa4485cd7e27025c31410ed0c (diff) | |
| parent | a8194cff3ca8f9b85a779da6b8214b58ba3fa7d0 (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.cpp | 755 |
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 |
