From e9802a9f3ba89ea52fde7747dcd5090e5061ee27 Mon Sep 17 00:00:00 2001 From: gibbed Date: Mon, 26 Aug 2019 12:19:00 -0500 Subject: [PATCH 1/3] [x64] Further simplification / fix buffer overrun in code cache. - [x64] Further simplify padding of code / unwind reservation in code cache. - [x64] Fix accidental buffer overrun caused by previous simplification. --- src/xenia/cpu/backend/x64/x64_code_cache.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/xenia/cpu/backend/x64/x64_code_cache.cc b/src/xenia/cpu/backend/x64/x64_code_cache.cc index 3dbe05f89..021d51c62 100644 --- a/src/xenia/cpu/backend/x64/x64_code_cache.cc +++ b/src/xenia/cpu/backend/x64/x64_code_cache.cc @@ -138,7 +138,6 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code, // unwind table requires entries AND code to be sorted in order. size_t low_mark; size_t high_mark; - size_t code_offset; uint8_t* code_address; UnwindReservation unwind_reservation; { @@ -148,10 +147,11 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code, // Reserve code. // Always move the code to land on 16b alignment. - code_offset = generated_code_offset_; - code_address = generated_code_base_ + code_offset; + code_address = generated_code_base_ + generated_code_offset_; generated_code_offset_ += xe::round_up(func_info.code_size.total, 16); + auto tail_address = generated_code_base_ + generated_code_offset_; + // Reserve unwind info. // We go on the high size of the unwind info as we don't know how big we // need it, and a few extra bytes of padding isn't the worst thing. @@ -159,6 +159,8 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code, RequestUnwindReservation(generated_code_base_ + generated_code_offset_); generated_code_offset_ += xe::round_up(unwind_reservation.data_size, 16); + auto end_address = generated_code_base_ + generated_code_offset_; + high_mark = generated_code_offset_; // Store in map. It is maintained in sorted order of host PC dependent on @@ -191,8 +193,8 @@ void* X64CodeCache::PlaceGuestCode(uint32_t guest_address, void* machine_code, std::memcpy(code_address, machine_code, func_info.code_size.total); // Fill unused slots with 0xCC - std::memset(code_address + func_info.code_size.total, 0xCC, - generated_code_offset_ - code_offset); + std::memset(tail_address, 0xCC, + static_cast(end_address - tail_address)); // Notify subclasses of placed code. PlaceCode(guest_address, machine_code, func_info, code_address, From b3382f3de1a93f89c3decfafb78b0a70ccb67123 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Mon, 26 Aug 2019 22:57:14 +0300 Subject: [PATCH 2/3] [Vulkan v2] Upload buffer chain, immediate drawer without textures --- src/xenia/ui/d3d12/d3d12_immediate_drawer.cc | 26 +- src/xenia/ui/d3d12/shaders/immediate.ps.hlsl | 5 +- src/xenia/ui/vk/shaders/immediate.frag | 22 ++ src/xenia/ui/vk/shaders/immediate.vert | 21 ++ src/xenia/ui/vk/transient_objects.cc | 211 +++++++++++ src/xenia/ui/vk/transient_objects.h | 72 ++++ src/xenia/ui/vk/vulkan_context.cc | 9 +- src/xenia/ui/vk/vulkan_context.h | 1 + src/xenia/ui/vk/vulkan_immediate_drawer.cc | 375 ++++++++++++++++++- src/xenia/ui/vk/vulkan_immediate_drawer.h | 22 ++ src/xenia/ui/vk/vulkan_provider.cc | 33 +- src/xenia/ui/vk/vulkan_provider.h | 12 + 12 files changed, 778 insertions(+), 31 deletions(-) create mode 100644 src/xenia/ui/vk/shaders/immediate.frag create mode 100644 src/xenia/ui/vk/shaders/immediate.vert create mode 100644 src/xenia/ui/vk/transient_objects.cc create mode 100644 src/xenia/ui/vk/transient_objects.h diff --git a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc index ccaffd1c2..6d6823796 100644 --- a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc +++ b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc @@ -203,13 +203,14 @@ bool D3D12ImmediateDrawer::Initialize() { D3D12_INPUT_ELEMENT_DESC pipeline_input_elements[3] = {}; pipeline_input_elements[0].SemanticName = "POSITION"; pipeline_input_elements[0].Format = DXGI_FORMAT_R32G32_FLOAT; - pipeline_input_elements[0].AlignedByteOffset = 0; + pipeline_input_elements[0].AlignedByteOffset = offsetof(ImmediateVertex, x); pipeline_input_elements[1].SemanticName = "TEXCOORD"; pipeline_input_elements[1].Format = DXGI_FORMAT_R32G32_FLOAT; - pipeline_input_elements[1].AlignedByteOffset = 8; + pipeline_input_elements[1].AlignedByteOffset = offsetof(ImmediateVertex, u); pipeline_input_elements[2].SemanticName = "COLOR"; pipeline_input_elements[2].Format = DXGI_FORMAT_R8G8B8A8_UNORM; - pipeline_input_elements[2].AlignedByteOffset = 16; + pipeline_input_elements[2].AlignedByteOffset = + offsetof(ImmediateVertex, color); pipeline_desc.InputLayout.pInputElementDescs = pipeline_input_elements; pipeline_desc.InputLayout.NumElements = UINT(xe::countof(pipeline_input_elements)); @@ -475,11 +476,15 @@ void D3D12ImmediateDrawer::Begin(int render_target_width, current_command_list_->RSSetViewports(1, &viewport); current_command_list_->SetGraphicsRootSignature(root_signature_); - float viewport_inv_scale[2]; - viewport_inv_scale[0] = 1.0f / viewport.Width; - viewport_inv_scale[1] = 1.0f / viewport.Height; + float viewport_inv_size[2]; + viewport_inv_size[0] = 1.0f / viewport.Width; + viewport_inv_size[1] = 1.0f / viewport.Height; current_command_list_->SetGraphicsRoot32BitConstants( - UINT(RootParameter::kViewportInvSize), 2, viewport_inv_scale, 0); + UINT(RootParameter::kViewportInvSize), 2, viewport_inv_size, 0); + + current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + current_texture_ = nullptr; + current_sampler_index_ = SamplerIndex::kInvalid; } void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { @@ -514,8 +519,8 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { index_buffer_view.SizeInBytes = batch.index_count * sizeof(uint16_t); index_buffer_view.Format = DXGI_FORMAT_R16_UINT; void* index_buffer_mapping = vertex_buffer_pool_->RequestFull( - index_buffer_view.SizeInBytes, nullptr, nullptr, - &index_buffer_view.BufferLocation); + xe::align(index_buffer_view.SizeInBytes, UINT(sizeof(uint32_t))), + nullptr, nullptr, &index_buffer_view.BufferLocation); if (index_buffer_mapping == nullptr) { XELOGE("Failed to get a buffer for %u indices in the immediate drawer", batch.index_count); @@ -527,9 +532,6 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { } batch_open_ = true; - current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; - current_texture_ = nullptr; - current_sampler_index_ = SamplerIndex::kInvalid; } void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) { diff --git a/src/xenia/ui/d3d12/shaders/immediate.ps.hlsl b/src/xenia/ui/d3d12/shaders/immediate.ps.hlsl index 3d9c8de51..4c31b812b 100644 --- a/src/xenia/ui/d3d12/shaders/immediate.ps.hlsl +++ b/src/xenia/ui/d3d12/shaders/immediate.ps.hlsl @@ -9,8 +9,9 @@ struct XePixelShaderInput { float4 main(XePixelShaderInput input) : SV_Target { float4 output = input.color; - if (!xe_restrict_texture_samples || input.texcoord.x <= 1.0) { - output *= xe_immediate_texture.Sample(xe_immediate_sampler, input.texcoord); + if (!xe_restrict_texture_samples || input.texcoord.x <= 1.0f) { + output *= xe_immediate_texture.SampleLevel(xe_immediate_sampler, + input.texcoord, 0.0f); } return output; } diff --git a/src/xenia/ui/vk/shaders/immediate.frag b/src/xenia/ui/vk/shaders/immediate.frag new file mode 100644 index 000000000..e1b0b2c40 --- /dev/null +++ b/src/xenia/ui/vk/shaders/immediate.frag @@ -0,0 +1,22 @@ +#version 450 core +precision highp float; + +layout(location = 0) in vec2 xe_in_texcoord; +layout(location = 1) in vec4 xe_in_color; + +layout(location = 0) out vec4 xe_out_color; + +layout(push_constant) uniform XePushConstants { + layout(offset = 8) uint restrict_texture_samples; +} xe_push_constants; + +// layout(set = 0, binding = 0) uniform sampler2D xe_immediate_texture_sampler; + +void main() { + xe_out_color = xe_in_color; + /* if (xe_push_constants.restrict_texture_samples == 0u || + xe_in_texcoord.x <= 1.0) { + xe_out_color *= + textureLod(xe_immediate_texture_sampler, xe_in_texcoord, 0.0f); + } */ +} diff --git a/src/xenia/ui/vk/shaders/immediate.vert b/src/xenia/ui/vk/shaders/immediate.vert new file mode 100644 index 000000000..49eaa0efe --- /dev/null +++ b/src/xenia/ui/vk/shaders/immediate.vert @@ -0,0 +1,21 @@ +#version 450 core +precision highp float; + +layout(location = 0) in vec2 xe_in_position; +layout(location = 1) in vec2 xe_in_texcoord; +layout(location = 2) in vec4 xe_in_color; + +layout(location = 0) out vec2 xe_out_texcoord; +layout(location = 1) out vec4 xe_out_color; + +layout(push_constant) uniform XePushConstants { + layout(offset = 0) vec2 viewport_inv_size; +} xe_push_constants; + +void main() { + gl_Position = vec4( + xe_in_position * xe_push_constants.viewport_inv_size * 2.0 - 1.0, 0.0, + 1.0); + xe_out_texcoord = xe_in_texcoord; + xe_out_color = xe_in_color; +} diff --git a/src/xenia/ui/vk/transient_objects.cc b/src/xenia/ui/vk/transient_objects.cc new file mode 100644 index 000000000..ffa74e70c --- /dev/null +++ b/src/xenia/ui/vk/transient_objects.cc @@ -0,0 +1,211 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2019 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/vk/transient_objects.h" + +#include + +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/ui/vk/vulkan_context.h" + +namespace xe { +namespace ui { +namespace vk { + +UploadBufferChain::UploadBufferChain(VulkanContext* context, + VkDeviceSize frame_page_size, + VkBufferUsageFlags usage_flags) + : context_(context), + frame_page_size_(frame_page_size), + usage_flags_(usage_flags) {} + +UploadBufferChain::~UploadBufferChain() { + // Allow mid-frame destruction in cases like device loss. + EndFrame(); + ClearCache(); +} + +void UploadBufferChain::ClearCache() { + assert_true(current_frame_buffer_ == 0 && current_frame_buffer_bytes_ == 0); + auto device = context_->GetVulkanProvider()->GetDevice(); + for (UploadBuffer& upload_buffer : upload_buffers_) { + vkDestroyBuffer(device, upload_buffer.buffer, nullptr); + vkUnmapMemory(device, upload_buffer.memory); + vkFreeMemory(device, upload_buffer.memory, nullptr); + } +} + +void UploadBufferChain::EndFrame() { + EndPage(); + current_frame_buffer_ = 0; + buffer_creation_failed_ = false; +} + +void UploadBufferChain::EndPage() { + if (current_frame_buffer_bytes_ == 0) { + return; + } + if (!memory_host_coherent_) { + auto device = context_->GetVulkanProvider()->GetDevice(); + VkMappedMemoryRange flush_range; + flush_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + flush_range.pNext = nullptr; + flush_range.memory = upload_buffers_[current_frame_buffer_].memory; + flush_range.offset = frame_page_size_ * context_->GetCurrentQueueFrame(); + flush_range.size = current_frame_buffer_bytes_; + vkFlushMappedMemoryRanges(device, 1, &flush_range); + } + ++current_frame_buffer_; + current_frame_buffer_bytes_ = 0; +} + +bool UploadBufferChain::EnsureCurrentBufferAllocated() { + if (current_frame_buffer_ < upload_buffers_.size()) { + return true; + } + assert_true(current_frame_buffer_ == upload_buffers_.size()); + assert_true(current_frame_buffer_bytes_ == 0); + if (buffer_creation_failed_) { + return false; + } + + UploadBuffer upload_buffer; + + auto provider = context_->GetVulkanProvider(); + auto device = provider->GetDevice(); + + VkBufferCreateInfo buffer_create_info; + buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_create_info.pNext = nullptr; + buffer_create_info.flags = 0; + buffer_create_info.size = frame_page_size_ * VulkanContext::kQueuedFrames; + buffer_create_info.usage = usage_flags_; + buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_create_info.queueFamilyIndexCount = 0; + buffer_create_info.pQueueFamilyIndices = nullptr; + if (vkCreateBuffer(device, &buffer_create_info, nullptr, + &upload_buffer.buffer) != VK_SUCCESS) { + XELOGE( + "Failed to create a Vulkan upload buffer with %ull x %u bytes and " + "0x%.8X usage", + buffer_create_info.size, VulkanContext::kQueuedFrames, usage_flags_); + buffer_creation_failed_ = true; + return false; + } + + if (memory_type_ == UINT32_MAX) { + // Page memory requirements not known yet. + VkMemoryRequirements buffer_memory_requirements; + vkGetBufferMemoryRequirements(device, upload_buffer.buffer, + &buffer_memory_requirements); + memory_type_ = + provider->FindMemoryType(buffer_memory_requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + if (memory_type_ == UINT32_MAX) { + XELOGE( + "Failed to find a memory type for an upload buffer with %ull bytes " + "and 0x%.8X usage", + buffer_memory_requirements.size, usage_flags_); + vkDestroyBuffer(device, upload_buffer.buffer, nullptr); + buffer_creation_failed_ = true; + return false; + } + const VkPhysicalDeviceMemoryProperties& device_memory_properties = + provider->GetPhysicalDeviceMemoryProperties(); + memory_host_coherent_ = + (device_memory_properties.memoryTypes[memory_type_].propertyFlags & + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; + memory_page_size_ = buffer_memory_requirements.size; + } + + VkMemoryAllocateInfo memory_allocate_info; + memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_allocate_info.pNext = nullptr; + memory_allocate_info.allocationSize = memory_page_size_; + memory_allocate_info.memoryTypeIndex = memory_type_; + if (vkAllocateMemory(device, &memory_allocate_info, nullptr, + &upload_buffer.memory) != VK_SUCCESS) { + XELOGE("Failed to allocate %ull for a Vulkan upload buffer", + memory_page_size_); + vkDestroyBuffer(device, upload_buffer.buffer, nullptr); + buffer_creation_failed_ = true; + return false; + } + + if (vkBindBufferMemory(device, upload_buffer.buffer, upload_buffer.memory, + 0) != VK_SUCCESS) { + XELOGE("Failed to bind a %ull-byte memory object to a Vulkan upload buffer", + memory_page_size_); + vkDestroyBuffer(device, upload_buffer.buffer, nullptr); + vkFreeMemory(device, upload_buffer.memory, nullptr); + buffer_creation_failed_ = true; + return false; + } + + if (vkMapMemory(device, upload_buffer.memory, 0, memory_page_size_, 0, + &upload_buffer.mapping) != VK_SUCCESS) { + XELOGE("Failed to map a %ull-byte memory object of a Vulkan upload buffer", + memory_page_size_); + vkDestroyBuffer(device, upload_buffer.buffer, nullptr); + vkFreeMemory(device, upload_buffer.memory, nullptr); + buffer_creation_failed_ = true; + return false; + } + + upload_buffers_.push_back(upload_buffer); + + return true; +} + +uint8_t* UploadBufferChain::RequestFull(VkDeviceSize size, VkBuffer& buffer_out, + VkDeviceSize& offset_out) { + assert_true(size <= frame_page_size_); + if (size > frame_page_size_) { + return nullptr; + } + if (frame_page_size_ - current_frame_buffer_bytes_ < size) { + EndPage(); + } + if (!EnsureCurrentBufferAllocated()) { + return nullptr; + } + VkDeviceSize offset = current_frame_buffer_bytes_ + + context_->GetCurrentQueueFrame() * frame_page_size_; + current_frame_buffer_bytes_ += size; + UploadBuffer& upload_buffer = upload_buffers_[current_frame_buffer_]; + buffer_out = upload_buffer.buffer; + offset_out = offset; + return reinterpret_cast(upload_buffer.mapping) + offset; +} + +uint8_t* UploadBufferChain::RequestPartial(VkDeviceSize size, + VkBuffer& buffer_out, + VkDeviceSize& offset_out, + VkDeviceSize& size_out) { + if (current_frame_buffer_bytes_ >= frame_page_size_) { + EndPage(); + } + if (!EnsureCurrentBufferAllocated()) { + return nullptr; + } + size = std::min(size, frame_page_size_ - current_frame_buffer_bytes_); + size_out = size; + VkDeviceSize offset = current_frame_buffer_bytes_ + + context_->GetCurrentQueueFrame() * frame_page_size_; + current_frame_buffer_bytes_ += size; + UploadBuffer& upload_buffer = upload_buffers_[current_frame_buffer_]; + buffer_out = upload_buffer.buffer; + offset_out = offset; + return reinterpret_cast(upload_buffer.mapping) + offset; +} + +} // namespace vk +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/vk/transient_objects.h b/src/xenia/ui/vk/transient_objects.h new file mode 100644 index 000000000..d58e5a57e --- /dev/null +++ b/src/xenia/ui/vk/transient_objects.h @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2019 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_VK_TRANSIENT_OBJECTS_H_ +#define XENIA_UI_VK_TRANSIENT_OBJECTS_H_ + +#include + +#include "xenia/ui/vk/vulkan_provider.h" + +namespace xe { +namespace ui { +namespace vk { + +class VulkanContext; + +class UploadBufferChain { + public: + UploadBufferChain(VulkanContext* context, VkDeviceSize frame_page_size, + VkBufferUsageFlags usage_flags); + ~UploadBufferChain(); + + void EndFrame(); + void ClearCache(); + + // Request to write data in a single piece, creating a new page if the current + // one doesn't have enough free space. + uint8_t* RequestFull(VkDeviceSize size, VkBuffer& buffer_out, + VkDeviceSize& offset_out); + // Request to write data in multiple parts, filling the buffer entirely. + uint8_t* RequestPartial(VkDeviceSize size, VkBuffer& buffer_out, + VkDeviceSize& offset_out, VkDeviceSize& size_out); + + private: + VulkanContext* context_; + VkBufferUsageFlags usage_flags_; + VkDeviceSize frame_page_size_; + + void EndPage(); + bool EnsureCurrentBufferAllocated(); + + VkDeviceSize memory_page_size_ = 0; + uint32_t memory_type_ = UINT32_MAX; + bool memory_host_coherent_ = false; + + struct UploadBuffer { + // frame_page_size_ * VulkanContext::kQueuedFrames bytes. + // Single allocation for VulkanContext::kQueuedFrames pages so there are + // less different memory objects. + VkDeviceMemory memory; + void* mapping; + VkBuffer buffer; + }; + std::vector upload_buffers_; + + size_t current_frame_buffer_ = 0; + VkDeviceSize current_frame_buffer_bytes_ = 0; + + bool buffer_creation_failed_ = false; +}; + +} // namespace vk +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_VK_TRANSIENT_OBJECTS_H_ diff --git a/src/xenia/ui/vk/vulkan_context.cc b/src/xenia/ui/vk/vulkan_context.cc index 12f99f8c6..2426ecc54 100644 --- a/src/xenia/ui/vk/vulkan_context.cc +++ b/src/xenia/ui/vk/vulkan_context.cc @@ -321,6 +321,7 @@ bool VulkanContext::Initialize() { swapchain_ = VK_NULL_HANDLE; } + initialized_fully_ = true; return true; } @@ -608,9 +609,11 @@ void VulkanContext::EndSwap() { VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = nullptr; - submit_info.pWaitDstStageMask = nullptr; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphore_present_complete_; + VkPipelineStageFlags present_complete_wait_dst_stage_mask = + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submit_info.pWaitDstStageMask = &present_complete_wait_dst_stage_mask; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &command_buffer; submit_info.signalSemaphoreCount = 1; diff --git a/src/xenia/ui/vk/vulkan_context.h b/src/xenia/ui/vk/vulkan_context.h index e454159de..a4310bd77 100644 --- a/src/xenia/ui/vk/vulkan_context.h +++ b/src/xenia/ui/vk/vulkan_context.h @@ -56,6 +56,7 @@ class VulkanContext : public GraphicsContext { const VkSurfaceFormatKHR& GetSurfaceFormat() const { return surface_format_; } + VkRenderPass GetPresentRenderPass() const { return present_render_pass_; } VkCommandBuffer GetPresentCommandBuffer() const { return present_command_buffers_[current_queue_frame_]; } diff --git a/src/xenia/ui/vk/vulkan_immediate_drawer.cc b/src/xenia/ui/vk/vulkan_immediate_drawer.cc index 15cd80e84..ecbbd8387 100644 --- a/src/xenia/ui/vk/vulkan_immediate_drawer.cc +++ b/src/xenia/ui/vk/vulkan_immediate_drawer.cc @@ -9,12 +9,20 @@ #include "xenia/ui/vk/vulkan_immediate_drawer.h" +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/ui/vk/vulkan_context.h" +#include "xenia/ui/vk/vulkan_util.h" namespace xe { namespace ui { namespace vk { +// Generated with `xb genspirv`. +#include "xenia/ui/vk/shaders/bin/immediate_frag.h" +#include "xenia/ui/vk/shaders/bin/immediate_vert.h" + class VulkanImmediateTexture : public ImmediateTexture { public: VulkanImmediateTexture(uint32_t width, uint32_t height, @@ -36,16 +44,235 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context) VulkanImmediateDrawer::~VulkanImmediateDrawer() { Shutdown(); } -bool VulkanImmediateDrawer::Initialize() { return true; } +bool VulkanImmediateDrawer::Initialize() { + auto device = context_->GetVulkanProvider()->GetDevice(); -void VulkanImmediateDrawer::Shutdown() {} + // Create the pipeline layout. + // TODO(Triang3l): Texture descriptor set layout. + VkPushConstantRange push_constant_ranges[2]; + push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + push_constant_ranges[0].offset = offsetof(PushConstants, vertex); + push_constant_ranges[0].size = sizeof(PushConstants::vertex); + push_constant_ranges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + push_constant_ranges[1].offset = offsetof(PushConstants, fragment); + push_constant_ranges[1].size = sizeof(PushConstants::fragment); + VkPipelineLayoutCreateInfo pipeline_layout_create_info; + pipeline_layout_create_info.sType = + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_create_info.pNext = nullptr; + pipeline_layout_create_info.flags = 0; + pipeline_layout_create_info.setLayoutCount = 0; + pipeline_layout_create_info.pSetLayouts = nullptr; + pipeline_layout_create_info.pushConstantRangeCount = + uint32_t(xe::countof(push_constant_ranges)); + pipeline_layout_create_info.pPushConstantRanges = push_constant_ranges; + if (vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, + &pipeline_layout_) != VK_SUCCESS) { + XELOGE("Failed to create the Vulkan immediate drawer pipeline layout"); + return false; + } + + // Load the shaders. + VkShaderModuleCreateInfo shader_module_create_info; + shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_module_create_info.pNext = nullptr; + shader_module_create_info.flags = 0; + shader_module_create_info.codeSize = sizeof(immediate_vert); + shader_module_create_info.pCode = + reinterpret_cast(immediate_vert); + VkShaderModule shader_module_vertex; + if (vkCreateShaderModule(device, &shader_module_create_info, nullptr, + &shader_module_vertex) != VK_SUCCESS) { + XELOGE("Failed to create the Vulkan immediate drawer vertex shader module"); + return false; + } + shader_module_create_info.codeSize = sizeof(immediate_frag); + shader_module_create_info.pCode = + reinterpret_cast(immediate_frag); + VkShaderModule shader_module_fragment; + if (vkCreateShaderModule(device, &shader_module_create_info, nullptr, + &shader_module_fragment) != VK_SUCCESS) { + XELOGE( + "Failed to create the Vulkan immediate drawer fragment shader module"); + vkDestroyShaderModule(device, shader_module_vertex, nullptr); + return false; + } + + // Create the pipelines for triangles and lines. + VkGraphicsPipelineCreateInfo pipeline_create_info; + pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_create_info.pNext = nullptr; + pipeline_create_info.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; + VkPipelineShaderStageCreateInfo pipeline_stages[2]; + pipeline_stages[0].sType = pipeline_stages[1].sType = + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipeline_stages[0].pNext = pipeline_stages[1].pNext = nullptr; + pipeline_stages[0].flags = pipeline_stages[1].flags = 0; + pipeline_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + pipeline_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + pipeline_stages[0].module = shader_module_vertex; + pipeline_stages[1].module = shader_module_fragment; + pipeline_stages[0].pName = pipeline_stages[1].pName = "main"; + pipeline_stages[0].pSpecializationInfo = nullptr; + pipeline_stages[1].pSpecializationInfo = nullptr; + pipeline_create_info.stageCount = uint32_t(xe::countof(pipeline_stages)); + pipeline_create_info.pStages = pipeline_stages; + VkPipelineVertexInputStateCreateInfo pipeline_vertex_input; + pipeline_vertex_input.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + pipeline_vertex_input.pNext = nullptr; + pipeline_vertex_input.flags = 0; + VkVertexInputBindingDescription pipeline_vertex_bindings[1]; + pipeline_vertex_bindings[0].binding = 0; + pipeline_vertex_bindings[0].stride = sizeof(ImmediateVertex); + pipeline_vertex_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + pipeline_vertex_input.vertexBindingDescriptionCount = + uint32_t(xe::countof(pipeline_vertex_bindings)); + pipeline_vertex_input.pVertexBindingDescriptions = pipeline_vertex_bindings; + VkVertexInputAttributeDescription pipeline_vertex_attributes[3]; + pipeline_vertex_attributes[0].location = 0; + pipeline_vertex_attributes[0].binding = 0; + pipeline_vertex_attributes[0].format = VK_FORMAT_R32G32_SFLOAT; + pipeline_vertex_attributes[0].offset = offsetof(ImmediateVertex, x); + pipeline_vertex_attributes[1].location = 1; + pipeline_vertex_attributes[1].binding = 0; + pipeline_vertex_attributes[1].format = VK_FORMAT_R32G32_SFLOAT; + pipeline_vertex_attributes[1].offset = offsetof(ImmediateVertex, u); + pipeline_vertex_attributes[2].location = 2; + pipeline_vertex_attributes[2].binding = 0; + pipeline_vertex_attributes[2].format = VK_FORMAT_R8G8B8A8_UNORM; + pipeline_vertex_attributes[2].offset = offsetof(ImmediateVertex, color); + pipeline_vertex_input.vertexAttributeDescriptionCount = + uint32_t(xe::countof(pipeline_vertex_attributes)); + pipeline_vertex_input.pVertexAttributeDescriptions = + pipeline_vertex_attributes; + pipeline_create_info.pVertexInputState = &pipeline_vertex_input; + VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly; + pipeline_input_assembly.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + pipeline_input_assembly.pNext = nullptr; + pipeline_input_assembly.flags = 0; + pipeline_input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly; + pipeline_create_info.pTessellationState = nullptr; + VkPipelineViewportStateCreateInfo pipeline_viewport; + pipeline_viewport.sType = + VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + pipeline_viewport.pNext = nullptr; + pipeline_viewport.flags = 0; + pipeline_viewport.viewportCount = 1; + pipeline_viewport.pViewports = nullptr; + pipeline_viewport.scissorCount = 1; + pipeline_viewport.pScissors = nullptr; + pipeline_create_info.pViewportState = &pipeline_viewport; + VkPipelineRasterizationStateCreateInfo pipeline_rasterization = {}; + pipeline_rasterization.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + pipeline_rasterization.polygonMode = VK_POLYGON_MODE_FILL; + pipeline_rasterization.cullMode = VK_CULL_MODE_BACK_BIT; + pipeline_rasterization.frontFace = VK_FRONT_FACE_CLOCKWISE; + pipeline_rasterization.lineWidth = 1.0f; + pipeline_create_info.pRasterizationState = &pipeline_rasterization; + VkPipelineMultisampleStateCreateInfo pipeline_multisample = {}; + pipeline_multisample.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + pipeline_multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + pipeline_create_info.pMultisampleState = &pipeline_multisample; + pipeline_create_info.pDepthStencilState = nullptr; + VkPipelineColorBlendStateCreateInfo pipeline_color_blend; + pipeline_color_blend.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + pipeline_color_blend.pNext = nullptr; + pipeline_color_blend.flags = 0; + pipeline_color_blend.logicOpEnable = VK_FALSE; + pipeline_color_blend.logicOp = VK_LOGIC_OP_NO_OP; + VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment = {}; + pipeline_color_blend_attachment.blendEnable = VK_TRUE; + pipeline_color_blend_attachment.srcColorBlendFactor = + VK_BLEND_FACTOR_SRC_ALPHA; + pipeline_color_blend_attachment.dstColorBlendFactor = + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + pipeline_color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; + pipeline_color_blend_attachment.srcAlphaBlendFactor = + VK_BLEND_FACTOR_SRC_ALPHA; + pipeline_color_blend_attachment.dstAlphaBlendFactor = + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + pipeline_color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; + pipeline_color_blend_attachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + pipeline_color_blend.attachmentCount = 1; + pipeline_color_blend.pAttachments = &pipeline_color_blend_attachment; + pipeline_create_info.pColorBlendState = &pipeline_color_blend; + static const VkDynamicState pipeline_dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + VkPipelineDynamicStateCreateInfo pipeline_dynamic_state; + pipeline_dynamic_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + pipeline_dynamic_state.pNext = nullptr; + pipeline_dynamic_state.flags = 0; + pipeline_dynamic_state.dynamicStateCount = + uint32_t(xe::countof(pipeline_dynamic_states)); + pipeline_dynamic_state.pDynamicStates = pipeline_dynamic_states; + pipeline_create_info.pDynamicState = &pipeline_dynamic_state; + pipeline_create_info.layout = pipeline_layout_; + pipeline_create_info.renderPass = context_->GetPresentRenderPass(); + pipeline_create_info.subpass = 0; + pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_create_info.basePipelineIndex = -1; + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, + &pipeline_create_info, nullptr, + &pipeline_triangle_) != VK_SUCCESS) { + XELOGE("Failed to create the Vulkan immediate drawer triangle pipeline"); + vkDestroyShaderModule(device, shader_module_fragment, nullptr); + vkDestroyShaderModule(device, shader_module_vertex, nullptr); + return false; + } + pipeline_create_info.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT; + pipeline_input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + pipeline_create_info.basePipelineHandle = pipeline_triangle_; + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, + &pipeline_create_info, nullptr, + &pipeline_line_) != VK_SUCCESS) { + XELOGE("Failed to create the Vulkan immediate drawer triangle pipeline"); + vkDestroyShaderModule(device, shader_module_fragment, nullptr); + vkDestroyShaderModule(device, shader_module_vertex, nullptr); + return false; + } + + vkDestroyShaderModule(device, shader_module_fragment, nullptr); + vkDestroyShaderModule(device, shader_module_vertex, nullptr); + + // Create transient resource pools for draws. + vertex_buffer_chain_ = std::make_unique( + context_, 2 * 1024 * 2014, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + + // Reset the current state. + current_command_buffer_ = VK_NULL_HANDLE; + + return true; +} + +void VulkanImmediateDrawer::Shutdown() { + auto device = context_->GetVulkanProvider()->GetDevice(); + + vertex_buffer_chain_.reset(); + + util::DestroyAndNullHandle(vkDestroyPipeline, device, pipeline_line_); + util::DestroyAndNullHandle(vkDestroyPipeline, device, pipeline_triangle_); + + util::DestroyAndNullHandle(vkDestroyPipelineLayout, device, pipeline_layout_); +} std::unique_ptr VulkanImmediateDrawer::CreateTexture( uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat, const uint8_t* data) { auto texture = std::make_unique(width, height, filter, repeat); - if (data != nullptr) { + if (data) { UpdateTexture(texture.get(), data); } return std::unique_ptr(texture.release()); @@ -55,15 +282,147 @@ void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture, const uint8_t* data) {} void VulkanImmediateDrawer::Begin(int render_target_width, - int render_target_height) {} + int render_target_height) { + current_command_buffer_ = context_->GetPresentCommandBuffer(); -void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {} + current_render_target_extent_.width = render_target_width; + current_render_target_extent_.height = render_target_height; -void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {} + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = float(render_target_width); + viewport.height = float(render_target_height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 0.0f; + vkCmdSetViewport(current_command_buffer_, 0, 1, &viewport); -void VulkanImmediateDrawer::EndDrawBatch() {} + float viewport_inv_size[2]; + viewport_inv_size[0] = 1.0f / viewport.width; + viewport_inv_size[1] = 1.0f / viewport.height; + vkCmdPushConstants(current_command_buffer_, pipeline_layout_, + VK_SHADER_STAGE_VERTEX_BIT, + offsetof(PushConstants, vertex.viewport_inv_size), + sizeof(viewport_inv_size), viewport_inv_size); -void VulkanImmediateDrawer::End() {} + current_pipeline_ = VK_NULL_HANDLE; +} + +void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { + assert_true(current_command_buffer_ != VK_NULL_HANDLE); + if (current_command_buffer_ == VK_NULL_HANDLE) { + return; + } + + batch_open_ = false; + + // Bind the vertices. + size_t vertex_buffer_size = batch.vertex_count * sizeof(ImmediateVertex); + VkBuffer vertex_buffer; + VkDeviceSize vertex_buffer_offset; + void* vertex_buffer_mapping = vertex_buffer_chain_->RequestFull( + vertex_buffer_size, vertex_buffer, vertex_buffer_offset); + if (!vertex_buffer_mapping) { + XELOGE( + "Failed to get a Vulkan buffer for %u vertices in the immediate drawer", + batch.vertex_count); + return; + } + std::memcpy(vertex_buffer_mapping, batch.vertices, vertex_buffer_size); + vkCmdBindVertexBuffers(current_command_buffer_, 0, 1, &vertex_buffer, + &vertex_buffer_offset); + + // Bind the indices. + batch_has_index_buffer_ = batch.indices != nullptr; + if (batch_has_index_buffer_) { + size_t index_buffer_size = batch.index_count * sizeof(uint16_t); + VkBuffer index_buffer; + VkDeviceSize index_buffer_offset; + void* index_buffer_mapping = vertex_buffer_chain_->RequestFull( + xe::align(index_buffer_size, VkDeviceSize(sizeof(uint32_t))), + index_buffer, index_buffer_offset); + if (!index_buffer_mapping) { + XELOGE( + "Failed to get a Vulkan buffer for %u indices in the immediate " + "drawer", + batch.index_count); + return; + } + std::memcpy(index_buffer_mapping, batch.indices, index_buffer_size); + vkCmdBindIndexBuffer(current_command_buffer_, index_buffer, + index_buffer_offset, VK_INDEX_TYPE_UINT16); + } + + batch_open_ = true; +} + +void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) { + assert_true(current_command_buffer_ != VK_NULL_HANDLE); + if (current_command_buffer_ == VK_NULL_HANDLE) { + return; + } + + if (!batch_open_) { + // Could be an error while obtaining the vertex and index buffers. + return; + } + + // TODO(Triang3l): Bind the texture. + + // Set whether texture coordinates need to be restricted. + uint32_t restrict_texture_samples = draw.restrict_texture_samples ? 1 : 0; + vkCmdPushConstants(current_command_buffer_, pipeline_layout_, + VK_SHADER_STAGE_FRAGMENT_BIT, + offsetof(PushConstants, fragment.restrict_texture_samples), + sizeof(uint32_t), &restrict_texture_samples); + + // Bind the pipeline for the primitive type. + VkPipeline pipeline; + switch (draw.primitive_type) { + case ImmediatePrimitiveType::kLines: + pipeline = pipeline_line_; + break; + case ImmediatePrimitiveType::kTriangles: + pipeline = pipeline_triangle_; + break; + default: + assert_unhandled_case(draw.primitive_type); + return; + } + if (current_pipeline_ != pipeline) { + vkCmdBindPipeline(current_command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, + pipeline); + current_pipeline_ = pipeline; + } + + // Set the scissor rectangle if enabled. + VkRect2D scissor; + if (draw.scissor) { + scissor.offset.x = draw.scissor_rect[0]; + scissor.offset.y = draw.scissor_rect[1]; + scissor.extent.width = draw.scissor_rect[2]; + scissor.extent.height = draw.scissor_rect[3]; + } else { + scissor.offset.x = scissor.offset.y = 0; + scissor.extent = current_render_target_extent_; + } + vkCmdSetScissor(current_command_buffer_, 0, 1, &scissor); + + // Draw. + if (batch_has_index_buffer_) { + vkCmdDrawIndexed(current_command_buffer_, draw.count, 1, draw.index_offset, + draw.base_vertex, 0); + } else { + vkCmdDraw(current_command_buffer_, draw.count, 1, draw.base_vertex, 0); + } +} + +void VulkanImmediateDrawer::EndDrawBatch() { batch_open_ = false; } + +void VulkanImmediateDrawer::End() { + vertex_buffer_chain_->EndFrame(); + current_command_buffer_ = VK_NULL_HANDLE; +} } // namespace vk } // namespace ui diff --git a/src/xenia/ui/vk/vulkan_immediate_drawer.h b/src/xenia/ui/vk/vulkan_immediate_drawer.h index c42f6a7ba..85a77e393 100644 --- a/src/xenia/ui/vk/vulkan_immediate_drawer.h +++ b/src/xenia/ui/vk/vulkan_immediate_drawer.h @@ -13,6 +13,7 @@ #include #include "xenia/ui/immediate_drawer.h" +#include "xenia/ui/vk/transient_objects.h" namespace xe { namespace ui { @@ -43,6 +44,27 @@ class VulkanImmediateDrawer : public ImmediateDrawer { private: VulkanContext* context_ = nullptr; + + struct PushConstants { + struct { + float viewport_inv_size[2]; + } vertex; + struct { + uint32_t restrict_texture_samples; + } fragment; + }; + VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + + VkPipeline pipeline_triangle_ = VK_NULL_HANDLE; + VkPipeline pipeline_line_ = VK_NULL_HANDLE; + + std::unique_ptr vertex_buffer_chain_ = nullptr; + + VkCommandBuffer current_command_buffer_ = VK_NULL_HANDLE; + VkExtent2D current_render_target_extent_; + bool batch_open_ = false; + bool batch_has_index_buffer_; + VkPipeline current_pipeline_ = VK_NULL_HANDLE; }; } // namespace vk diff --git a/src/xenia/ui/vk/vulkan_provider.cc b/src/xenia/ui/vk/vulkan_provider.cc index 503857d10..5d370c7a9 100644 --- a/src/xenia/ui/vk/vulkan_provider.cc +++ b/src/xenia/ui/vk/vulkan_provider.cc @@ -14,6 +14,7 @@ #include "xenia/base/cvar.h" #include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/base/platform.h" #include "xenia/ui/vk/vulkan_context.h" #include "xenia/ui/vk/vulkan_util.h" @@ -57,6 +58,22 @@ VulkanProvider::~VulkanProvider() { } } +uint32_t VulkanProvider::FindMemoryType( + uint32_t memory_type_bits_requirement, + VkMemoryPropertyFlags required_properties) const { + uint32_t memory_index; + while (xe::bit_scan_forward(memory_type_bits_requirement, &memory_index)) { + memory_type_bits_requirement &= ~(uint32_t(1) << memory_index); + VkMemoryPropertyFlags properties = + physical_device_memory_properties_.memoryTypes[memory_index] + .propertyFlags; + if ((properties & required_properties) == required_properties) { + return memory_index; + } + } + return UINT32_MAX; +} + bool VulkanProvider::Initialize() { if (volkInitialize() != VK_SUCCESS) { XELOGE("Failed to initialize the Vulkan loader volk"); @@ -130,15 +147,15 @@ bool VulkanProvider::Initialize() { physical_device_index = 0; physical_device_index_end = physical_device_count; } - VkPhysicalDeviceProperties physical_device_properties; std::vector physical_device_extensions; std::vector queue_families; bool sparse_residency_buffer = false; for (; physical_device_index < physical_device_index_end; ++physical_device_index) { VkPhysicalDevice physical_device = physical_devices[physical_device_index]; - vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); - if (physical_device_properties.apiVersion < api_version) { + vkGetPhysicalDeviceProperties(physical_device, + &physical_device_properties_); + if (physical_device_properties_.apiVersion < api_version) { continue; } vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features_); @@ -219,11 +236,15 @@ bool VulkanProvider::Initialize() { // TODO(Triang3l): Check if VK_EXT_fragment_shader_interlock and // fragmentShaderSampleInterlock are supported. + // Get the needed info about the physical device. + vkGetPhysicalDeviceMemoryProperties(physical_device_, + &physical_device_memory_properties_); + // Log physical device properties. XELOGVK("Vulkan physical device: %s (vendor %.4X, device %.4X)", - physical_device_properties.deviceName, - physical_device_properties.vendorID, - physical_device_properties.deviceID); + physical_device_properties_.deviceName, + physical_device_properties_.vendorID, + physical_device_properties_.deviceID); // Create a logical device and a queue. float queue_priority = 1.0f; diff --git a/src/xenia/ui/vk/vulkan_provider.h b/src/xenia/ui/vk/vulkan_provider.h index 950c784fc..a1bff5c11 100644 --- a/src/xenia/ui/vk/vulkan_provider.h +++ b/src/xenia/ui/vk/vulkan_provider.h @@ -48,13 +48,23 @@ class VulkanProvider : public GraphicsProvider { VkInstance GetInstance() const { return instance_; } VkPhysicalDevice GetPhysicalDevice() const { return physical_device_; } + const VkPhysicalDeviceProperties& GetPhysicalDeviceProperties() const { + return physical_device_properties_; + } const VkPhysicalDeviceFeatures& GetPhysicalDeviceFeatures() const { return physical_device_features_; } + const VkPhysicalDeviceMemoryProperties& GetPhysicalDeviceMemoryProperties() + const { + return physical_device_memory_properties_; + } VkDevice GetDevice() const { return device_; } uint32_t GetGraphicsQueueFamily() const { return graphics_queue_family_; } VkQueue GetGraphicsQueue() const { return graphics_queue_; } + uint32_t FindMemoryType(uint32_t memory_type_bits_requirement, + VkMemoryPropertyFlags required_properties) const; + private: explicit VulkanProvider(Window* main_window); @@ -62,7 +72,9 @@ class VulkanProvider : public GraphicsProvider { VkInstance instance_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; + VkPhysicalDeviceProperties physical_device_properties_; VkPhysicalDeviceFeatures physical_device_features_; + VkPhysicalDeviceMemoryProperties physical_device_memory_properties_; VkDevice device_ = VK_NULL_HANDLE; uint32_t graphics_queue_family_ = UINT32_MAX; VkQueue graphics_queue_ = VK_NULL_HANDLE; From b01f6cd7ea173488834d0b2d5bfe07e11f62610c Mon Sep 17 00:00:00 2001 From: Triang3l Date: Mon, 26 Aug 2019 23:43:05 +0300 Subject: [PATCH 3/3] [Vulkan v2] Add immediate shader SPIR-V code --- src/xenia/ui/vk/shaders/bin/immediate_frag.h | 44 ++++++ .../ui/vk/shaders/bin/immediate_frag.spv | Bin 0 -> 476 bytes .../ui/vk/shaders/bin/immediate_frag.txt | 35 +++++ src/xenia/ui/vk/shaders/bin/immediate_vert.h | 126 ++++++++++++++++++ .../ui/vk/shaders/bin/immediate_vert.spv | Bin 0 -> 1460 bytes .../ui/vk/shaders/bin/immediate_vert.txt | 86 ++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_frag.h create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_frag.spv create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_frag.txt create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_vert.h create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_vert.spv create mode 100644 src/xenia/ui/vk/shaders/bin/immediate_vert.txt diff --git a/src/xenia/ui/vk/shaders/bin/immediate_frag.h b/src/xenia/ui/vk/shaders/bin/immediate_frag.h new file mode 100644 index 000000000..1b78ab75c --- /dev/null +++ b/src/xenia/ui/vk/shaders/bin/immediate_frag.h @@ -0,0 +1,44 @@ +// generated from `xb genspirv` +// source: immediate.frag +const uint8_t immediate_frag[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69, + 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, + 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, +}; diff --git a/src/xenia/ui/vk/shaders/bin/immediate_frag.spv b/src/xenia/ui/vk/shaders/bin/immediate_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..8a4c6e437bc7c277fcdf554cb119eaf76eeef100 GIT binary patch literal 476 zcmYk1!AgQr5QQiIelsmKg4&7FURr1fQQJ1|dH@M^A(R*N4}89!s!h=MT@}1AckVee zbLQNl_HYq#7WHUEH}>ZyYA_KkSo7QTeLCD$i{WVeXh%B=Q?7NGJLheDeXQ2Ng!CG6=;$u8%1%USxaX7lu!HbDBytOdVXA832k-gDJ*H&1D^z$c1o z^c>`f^&!sx06TZA-{M9;gX}Ew`;K=Vu20<4uWzwl``it(zn6bLV0X${Z<5`0tc&#^ ur`|PLJ@?w*CR>wNPpn6|C;o1qyFKpsg(=A|uzh{;=c44~Fe|XHNtPt{B@ZNzB)gKfel6)gDjF%{d`_ghsC1ks!?gOGR!w>) zDAw`V_{utKva%36Yvbw9@>$UwWZzTbf{(l8+sm`@hpcW6i%~lDF#*0wo=<&|`lELa z{V>B>nq);X4%b@#y7({Ya8iHWD+}s2wW2!)o^zU|-^OLtDDyO_T~m?zU6oJu#!5^^ z(@b|4yOOV*G>Il3m1T8g?_z(hhbe7&cIx9tWnNZ-;v>6f7w_ng;@k`Ip6&$By|H`8 zz_Byp*iYcF;drlsJlMny#IU2TghPDTLC;Y(9xlW)XNV`C`M~x&6K1aSnC}Km{<8kj zo9cm{uvcZxNXL>jY)AP0#=Gcia*t5B|63 z)@8%9pP!!FkPS~ypTx1hO$j_FaCc?HF~?BTF<(zYEWTL6JoLy;wj_Kb^!P?ofr$_O bK9tQK@v&bpKI%S}urqw@7W_{)zm)t3bZl~{ literal 0 HcmV?d00001 diff --git a/src/xenia/ui/vk/shaders/bin/immediate_vert.txt b/src/xenia/ui/vk/shaders/bin/immediate_vert.txt new file mode 100644 index 000000000..90c5364e3 --- /dev/null +++ b/src/xenia/ui/vk/shaders/bin/immediate_vert.txt @@ -0,0 +1,86 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 6 +; Bound: 47 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %_ %xe_in_position %xe_out_texcoord %xe_in_texcoord %xe_out_color %xe_in_color + OpSource GLSL 450 + OpName %main "main" + OpName %gl_PerVertex "gl_PerVertex" + OpMemberName %gl_PerVertex 0 "gl_Position" + OpMemberName %gl_PerVertex 1 "gl_PointSize" + OpMemberName %gl_PerVertex 2 "gl_ClipDistance" + OpMemberName %gl_PerVertex 3 "gl_CullDistance" + OpName %_ "" + OpName %xe_in_position "xe_in_position" + OpName %XePushConstants "XePushConstants" + OpMemberName %XePushConstants 0 "viewport_inv_size" + OpName %xe_push_constants "xe_push_constants" + OpName %xe_out_texcoord "xe_out_texcoord" + OpName %xe_in_texcoord "xe_in_texcoord" + OpName %xe_out_color "xe_out_color" + OpName %xe_in_color "xe_in_color" + OpMemberDecorate %gl_PerVertex 0 BuiltIn Position + OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize + OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance + OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance + OpDecorate %gl_PerVertex Block + OpDecorate %xe_in_position Location 0 + OpMemberDecorate %XePushConstants 0 Offset 0 + OpDecorate %XePushConstants Block + OpDecorate %xe_out_texcoord Location 0 + OpDecorate %xe_in_texcoord Location 1 + OpDecorate %xe_out_color Location 1 + OpDecorate %xe_in_color Location 2 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex + %_ = OpVariable %_ptr_Output_gl_PerVertex Output + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%xe_in_position = OpVariable %_ptr_Input_v2float Input +%XePushConstants = OpTypeStruct %v2float +%_ptr_PushConstant_XePushConstants = OpTypePointer PushConstant %XePushConstants +%xe_push_constants = OpVariable %_ptr_PushConstant_XePushConstants PushConstant +%_ptr_PushConstant_v2float = OpTypePointer PushConstant %v2float + %float_2 = OpConstant %float 2 + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output_v2float = OpTypePointer Output %v2float +%xe_out_texcoord = OpVariable %_ptr_Output_v2float Output +%xe_in_texcoord = OpVariable %_ptr_Input_v2float Input +%xe_out_color = OpVariable %_ptr_Output_v4float Output +%_ptr_Input_v4float = OpTypePointer Input %v4float +%xe_in_color = OpVariable %_ptr_Input_v4float Input + %46 = OpConstantComposite %v2float %float_1 %float_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %19 = OpLoad %v2float %xe_in_position + %24 = OpAccessChain %_ptr_PushConstant_v2float %xe_push_constants %int_0 + %25 = OpLoad %v2float %24 + %26 = OpFMul %v2float %19 %25 + %28 = OpVectorTimesScalar %v2float %26 %float_2 + %31 = OpFSub %v2float %28 %46 + %33 = OpCompositeExtract %float %31 0 + %34 = OpCompositeExtract %float %31 1 + %35 = OpCompositeConstruct %v4float %33 %34 %float_0 %float_1 + %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0 + OpStore %37 %35 + %41 = OpLoad %v2float %xe_in_texcoord + OpStore %xe_out_texcoord %41 + %45 = OpLoad %v4float %xe_in_color + OpStore %xe_out_color %45 + OpReturn + OpFunctionEnd