From 229eb49b54700c88b5d623e59d40b599f623533c Mon Sep 17 00:00:00 2001 From: Triang3l Date: Sat, 19 Sep 2020 18:05:54 +0300 Subject: [PATCH] [Vulkan] Untextured ImmediateDrawer, [D3D12] Small refactoring --- src/xenia/gpu/d3d12/d3d12_command_processor.h | 20 +- src/xenia/gpu/d3d12/d3d12_graphics_system.cc | 2 +- src/xenia/gpu/d3d12/pipeline_cache.cc | 2 +- src/xenia/gpu/d3d12/pipeline_cache.h | 4 +- src/xenia/gpu/d3d12/primitive_converter.h | 2 +- src/xenia/gpu/d3d12/render_target_cache.cc | 2 +- src/xenia/gpu/d3d12/render_target_cache.h | 2 +- src/xenia/gpu/d3d12/shared_memory.h | 3 +- src/xenia/gpu/d3d12/texture_cache.cc | 2 +- src/xenia/ui/d3d12/d3d12_context.h | 2 +- src/xenia/ui/d3d12/d3d12_immediate_drawer.cc | 44 +- src/xenia/ui/d3d12/d3d12_immediate_drawer.h | 6 +- .../bytecode/vulkan_spirv/immediate_frag.h | 47 ++ .../bytecode/vulkan_spirv/immediate_frag.spv | Bin 0 -> 516 bytes .../bytecode/vulkan_spirv/immediate_frag.txt | 38 ++ .../bytecode/vulkan_spirv/immediate_vert.h | 116 +++++ .../bytecode/vulkan_spirv/immediate_vert.spv | Bin 0 -> 1340 bytes .../bytecode/vulkan_spirv/immediate_vert.txt | 82 ++++ src/xenia/ui/shaders/immediate.frag | 11 + src/xenia/ui/shaders/immediate.vert | 20 + src/xenia/ui/shaders/immediate.vs.hlsl | 8 +- src/xenia/ui/vulkan/premake5.lua | 21 + src/xenia/ui/vulkan/vulkan_context.cc | 9 +- src/xenia/ui/vulkan/vulkan_context.h | 11 + .../ui/vulkan/vulkan_immediate_drawer.cc | 413 +++++++++++++++++- src/xenia/ui/vulkan/vulkan_immediate_drawer.h | 29 ++ src/xenia/ui/vulkan/vulkan_provider.cc | 96 +++- src/xenia/ui/vulkan/vulkan_provider.h | 41 +- .../ui/vulkan/vulkan_upload_buffer_pool.cc | 227 ++++++++++ .../ui/vulkan/vulkan_upload_buffer_pool.h | 67 +++ src/xenia/ui/vulkan/vulkan_util.h | 18 +- src/xenia/ui/vulkan/vulkan_window_demo.cc | 29 ++ xenia-build | 7 +- 33 files changed, 1305 insertions(+), 76 deletions(-) create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.h create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.spv create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.txt create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.h create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.spv create mode 100644 src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.txt create mode 100644 src/xenia/ui/shaders/immediate.frag create mode 100644 src/xenia/ui/shaders/immediate.vert create mode 100644 src/xenia/ui/vulkan/vulkan_upload_buffer_pool.cc create mode 100644 src/xenia/ui/vulkan/vulkan_upload_buffer_pool.h create mode 100644 src/xenia/ui/vulkan/vulkan_window_demo.cc diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.h b/src/xenia/gpu/d3d12/d3d12_command_processor.h index ba464d8e8..92e0f5c02 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.h +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.h @@ -376,7 +376,7 @@ class D3D12CommandProcessor : public CommandProcessor { CommandAllocator* command_allocator_submitted_last_ = nullptr; ID3D12GraphicsCommandList* command_list_ = nullptr; ID3D12GraphicsCommandList1* command_list_1_ = nullptr; - std::unique_ptr deferred_command_list_ = nullptr; + std::unique_ptr deferred_command_list_; // Should bindless textures and samplers be used - many times faster // UpdateBindings than bindful (that becomes a significant bottleneck with @@ -388,14 +388,12 @@ class D3D12CommandProcessor : public CommandProcessor { // targets. bool edram_rov_used_ = false; - std::unique_ptr constant_buffer_pool_ = - nullptr; + std::unique_ptr constant_buffer_pool_; static constexpr uint32_t kViewBindfulHeapSize = 32768; static_assert(kViewBindfulHeapSize <= D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1); - std::unique_ptr view_bindful_heap_pool_ = - nullptr; + std::unique_ptr view_bindful_heap_pool_; // Currently bound descriptor heap - updated by RequestViewBindfulDescriptors. ID3D12DescriptorHeap* view_bindful_heap_current_; // Rationale: textures have 4 KB alignment in guest memory, and there can be @@ -426,7 +424,7 @@ class D3D12CommandProcessor : public CommandProcessor { static constexpr uint32_t kSamplerHeapSize = 2000; static_assert(kSamplerHeapSize <= D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE); std::unique_ptr - sampler_bindful_heap_pool_ = nullptr; + sampler_bindful_heap_pool_; ID3D12DescriptorHeap* sampler_bindful_heap_current_; ID3D12DescriptorHeap* sampler_bindless_heap_current_ = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE sampler_bindless_heap_cpu_start_; @@ -452,15 +450,15 @@ class D3D12CommandProcessor : public CommandProcessor { ID3D12RootSignature* root_signature_bindless_vs_ = nullptr; ID3D12RootSignature* root_signature_bindless_ds_ = nullptr; - std::unique_ptr shared_memory_ = nullptr; + std::unique_ptr shared_memory_; - std::unique_ptr pipeline_cache_ = nullptr; + std::unique_ptr pipeline_cache_; - std::unique_ptr texture_cache_ = nullptr; + std::unique_ptr texture_cache_; - std::unique_ptr render_target_cache_ = nullptr; + std::unique_ptr render_target_cache_; - std::unique_ptr primitive_converter_ = nullptr; + std::unique_ptr primitive_converter_; // Mip 0 contains the normal gamma ramp (256 entries), mip 1 contains the PWL // ramp (128 entries). DXGI_FORMAT_R10G10B10A2_UNORM 1D. diff --git a/src/xenia/gpu/d3d12/d3d12_graphics_system.cc b/src/xenia/gpu/d3d12/d3d12_graphics_system.cc index 8eaefd15f..b8438a6fe 100644 --- a/src/xenia/gpu/d3d12/d3d12_graphics_system.cc +++ b/src/xenia/gpu/d3d12/d3d12_graphics_system.cc @@ -20,7 +20,7 @@ namespace xe { namespace gpu { namespace d3d12 { -// Generated with `xb buildhlsl`. +// Generated with `xb gendxbc`. #include "xenia/gpu/shaders/bytecode/d3d12_5_1/fullscreen_vs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_gamma_ps.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_ps.h" diff --git a/src/xenia/gpu/d3d12/pipeline_cache.cc b/src/xenia/gpu/d3d12/pipeline_cache.cc index 41bb72790..de0d43ea5 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.cc +++ b/src/xenia/gpu/d3d12/pipeline_cache.cc @@ -56,7 +56,7 @@ namespace xe { namespace gpu { namespace d3d12 { -// Generated with `xb buildhlsl`. +// Generated with `xb gendxbc`. #include "xenia/gpu/shaders/bytecode/d3d12_5_1/adaptive_quad_hs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/adaptive_triangle_hs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/continuous_quad_hs.h" diff --git a/src/xenia/gpu/d3d12/pipeline_cache.h b/src/xenia/gpu/d3d12/pipeline_cache.h index 30fd68a4e..cdc6ed5f3 100644 --- a/src/xenia/gpu/d3d12/pipeline_cache.h +++ b/src/xenia/gpu/d3d12/pipeline_cache.h @@ -247,7 +247,7 @@ class PipelineCache { uint32_t resolution_scale_; // Reusable shader translator. - std::unique_ptr shader_translator_ = nullptr; + std::unique_ptr shader_translator_; // Command processor thread DXIL conversion/disassembly interfaces, if DXIL // disassembly is enabled. @@ -344,7 +344,7 @@ class PipelineCache { // Manual-reset event set when the last queued pipeline state object is // created and there are no more pipeline state objects to create. This is // triggered by the thread creating the last pipeline state object. - std::unique_ptr creation_completion_event_ = nullptr; + std::unique_ptr creation_completion_event_; // Whether setting the event on completion is queued. Protected with // creation_request_lock_, notify_one creation_request_cond_ when set. bool creation_completion_set_event_ = false; diff --git a/src/xenia/gpu/d3d12/primitive_converter.h b/src/xenia/gpu/d3d12/primitive_converter.h index c00d29f7c..4d5c80f2d 100644 --- a/src/xenia/gpu/d3d12/primitive_converter.h +++ b/src/xenia/gpu/d3d12/primitive_converter.h @@ -107,7 +107,7 @@ class PrimitiveConverter { Memory& memory_; TraceWriter& trace_writer_; - std::unique_ptr buffer_pool_ = nullptr; + std::unique_ptr buffer_pool_; // Static index buffers for emulating unsupported primitive types when drawing // without an index buffer. diff --git a/src/xenia/gpu/d3d12/render_target_cache.cc b/src/xenia/gpu/d3d12/render_target_cache.cc index 35a0bc25d..a43ad90d3 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.cc +++ b/src/xenia/gpu/d3d12/render_target_cache.cc @@ -36,7 +36,7 @@ namespace xe { namespace gpu { namespace d3d12 { -// Generated with `xb buildhlsl`. +// Generated with `xb gendxbc`. #include "xenia/gpu/shaders/bytecode/d3d12_5_1/edram_load_color_32bpp_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/edram_load_color_64bpp_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/edram_load_color_7e3_cs.h" diff --git a/src/xenia/gpu/d3d12/render_target_cache.h b/src/xenia/gpu/d3d12/render_target_cache.h index de3846635..cf575dcdf 100644 --- a/src/xenia/gpu/d3d12/render_target_cache.h +++ b/src/xenia/gpu/d3d12/render_target_cache.h @@ -603,7 +603,7 @@ class RenderTargetCache { // For traces only. ID3D12Resource* edram_snapshot_download_buffer_ = nullptr; std::unique_ptr - edram_snapshot_restore_pool_ = nullptr; + edram_snapshot_restore_pool_; }; } // namespace d3d12 diff --git a/src/xenia/gpu/d3d12/shared_memory.h b/src/xenia/gpu/d3d12/shared_memory.h index 676803f15..86a55b2b7 100644 --- a/src/xenia/gpu/d3d12/shared_memory.h +++ b/src/xenia/gpu/d3d12/shared_memory.h @@ -212,8 +212,7 @@ class SharedMemory { std::vector upload_ranges_; void GetRangesToUpload(uint32_t request_page_first, uint32_t request_page_last); - std::unique_ptr upload_buffer_pool_ = - nullptr; + std::unique_ptr upload_buffer_pool_; // GPU-written memory downloading for traces. // Start page, length in pages. diff --git a/src/xenia/gpu/d3d12/texture_cache.cc b/src/xenia/gpu/d3d12/texture_cache.cc index 7aed8ff22..db1d30a45 100644 --- a/src/xenia/gpu/d3d12/texture_cache.cc +++ b/src/xenia/gpu/d3d12/texture_cache.cc @@ -53,7 +53,7 @@ namespace xe { namespace gpu { namespace d3d12 { -// Generated with `xb buildhlsl`. +// Generated with `xb gendxbc`. #include "xenia/gpu/shaders/bytecode/d3d12_5_1/texture_load_128bpb_2x_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/texture_load_128bpb_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/texture_load_16bpb_2x_cs.h" diff --git a/src/xenia/ui/d3d12/d3d12_context.h b/src/xenia/ui/d3d12/d3d12_context.h index c9f235b97..8ae3a0b2c 100644 --- a/src/xenia/ui/d3d12/d3d12_context.h +++ b/src/xenia/ui/d3d12/d3d12_context.h @@ -99,7 +99,7 @@ class D3D12Context : public GraphicsContext { // kSwapCommandAllocatorCount. ID3D12GraphicsCommandList* swap_command_list_ = nullptr; - std::unique_ptr immediate_drawer_ = nullptr; + std::unique_ptr immediate_drawer_; }; } // namespace d3d12 diff --git a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc index 72a4f8736..6cc1e4d56 100644 --- a/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc +++ b/src/xenia/ui/d3d12/d3d12_immediate_drawer.cc @@ -21,7 +21,7 @@ namespace xe { namespace ui { namespace d3d12 { -// Generated with `xb buildhlsl`. +// Generated with `xb gendxbc`. #include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_ps.h" #include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h" @@ -158,7 +158,7 @@ bool D3D12ImmediateDrawer::Initialize() { } { auto& root_parameter = - root_parameters[size_t(RootParameter::kViewportInvSize)]; + root_parameters[size_t(RootParameter::kViewportSizeInv)]; root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; root_parameter.Constants.ShaderRegister = 0; root_parameter.Constants.RegisterSpace = 0; @@ -179,7 +179,7 @@ bool D3D12ImmediateDrawer::Initialize() { return false; } - // Create the pipelines. + // Create the pipeline states. D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {}; pipeline_desc.pRootSignature = root_signature_; pipeline_desc.VS.pShaderBytecode = immediate_vs; @@ -192,10 +192,13 @@ bool D3D12ImmediateDrawer::Initialize() { pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA; pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA; pipeline_blend_desc.BlendOp = D3D12_BLEND_OP_ADD; - pipeline_blend_desc.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; - pipeline_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + // Don't change alpha (always 1). + pipeline_blend_desc.SrcBlendAlpha = D3D12_BLEND_ZERO; + pipeline_blend_desc.DestBlendAlpha = D3D12_BLEND_ONE; pipeline_blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD; - pipeline_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + pipeline_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_RED | + D3D12_COLOR_WRITE_ENABLE_GREEN | + D3D12_COLOR_WRITE_ENABLE_BLUE; pipeline_desc.SampleMask = UINT_MAX; pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; @@ -295,6 +298,7 @@ bool D3D12ImmediateDrawer::Initialize() { // Reset the current state. current_command_list_ = nullptr; + batch_open_ = false; return true; } @@ -415,6 +419,9 @@ void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture, void D3D12ImmediateDrawer::Begin(int render_target_width, int render_target_height) { + assert_null(current_command_list_); + assert_false(batch_open_); + auto device = context_.GetD3D12Provider().GetDevice(); // Use the compositing command list. @@ -485,7 +492,7 @@ void D3D12ImmediateDrawer::Begin(int render_target_width, 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_size, 0); + UINT(RootParameter::kViewportSizeInv), 2, viewport_inv_size, 0); current_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; current_texture_ = nullptr; @@ -493,21 +500,18 @@ void D3D12ImmediateDrawer::Begin(int render_target_width, } void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { + assert_false(batch_open_); assert_not_null(current_command_list_); - if (current_command_list_ == nullptr) { - return; - } - uint64_t current_fence_value = context_.GetSwapCurrentFenceValue(); - batch_open_ = false; + uint64_t current_fence_value = context_.GetSwapCurrentFenceValue(); // Bind the vertices. D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view; vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex)); vertex_buffer_view.SizeInBytes = - batch.vertex_count * uint32_t(sizeof(ImmediateVertex)); + UINT(sizeof(ImmediateVertex)) * batch.vertex_count; void* vertex_buffer_mapping = vertex_buffer_pool_->Request( - current_fence_value, vertex_buffer_view.SizeInBytes, sizeof(uint32_t), + current_fence_value, vertex_buffer_view.SizeInBytes, sizeof(float), nullptr, nullptr, &vertex_buffer_view.BufferLocation); if (vertex_buffer_mapping == nullptr) { XELOGE("Failed to get a buffer for {} vertices in the immediate drawer", @@ -522,7 +526,7 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { batch_has_index_buffer_ = batch.indices != nullptr; if (batch_has_index_buffer_) { D3D12_INDEX_BUFFER_VIEW index_buffer_view; - index_buffer_view.SizeInBytes = batch.index_count * sizeof(uint16_t); + index_buffer_view.SizeInBytes = UINT(sizeof(uint16_t)) * batch.index_count; index_buffer_view.Format = DXGI_FORMAT_R16_UINT; void* index_buffer_mapping = vertex_buffer_pool_->Request( current_fence_value, index_buffer_view.SizeInBytes, sizeof(uint16_t), @@ -541,11 +545,6 @@ void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { } void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) { - assert_not_null(current_command_list_); - if (current_command_list_ == nullptr) { - return; - } - if (!batch_open_) { // Could be an error while obtaining the vertex and index buffers. return; @@ -678,7 +677,10 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) { void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; } -void D3D12ImmediateDrawer::End() { current_command_list_ = nullptr; } +void D3D12ImmediateDrawer::End() { + assert_false(batch_open_); + current_command_list_ = nullptr; +} } // namespace d3d12 } // namespace ui diff --git a/src/xenia/ui/d3d12/d3d12_immediate_drawer.h b/src/xenia/ui/d3d12/d3d12_immediate_drawer.h index ce3fbcd84..b18d87909 100644 --- a/src/xenia/ui/d3d12/d3d12_immediate_drawer.h +++ b/src/xenia/ui/d3d12/d3d12_immediate_drawer.h @@ -54,7 +54,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer { kRestrictTextureSamples, kTexture, kSampler, - kViewportInvSize, + kViewportSizeInv, kCount }; @@ -75,8 +75,8 @@ class D3D12ImmediateDrawer : public ImmediateDrawer { D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_; D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_; - std::unique_ptr vertex_buffer_pool_ = nullptr; - std::unique_ptr texture_descriptor_pool_ = nullptr; + std::unique_ptr vertex_buffer_pool_; + std::unique_ptr texture_descriptor_pool_; uint64_t texture_descriptor_pool_heap_index_; struct PendingTextureUpload { diff --git a/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.h b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.h new file mode 100644 index 000000000..3fc30c576 --- /dev/null +++ b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.h @@ -0,0 +1,47 @@ +// generated from `xb genspirv` +// source: immediate.frag +const uint8_t immediate_frag[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 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, 0x01, 0x00, 0x00, 0x00, 0x36, 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, 0x66, 0x72, 0x61, 0x67, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, + 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x76, 0x61, 0x72, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x76, 0x61, 0x72, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F, + 0x6F, 0x72, 0x64, 0x00, 0x47, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x0B, 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, 0x03, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 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/shaders/bytecode/vulkan_spirv/immediate_frag.spv b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..390a723c0ecc0e557e4cbeb8657bb2f6ea76d443 GIT binary patch literal 516 zcmYk2!AiqW5Jktt)Y@uW5p*XN_r--4q3AZ7?)-of+A4w?h(-G8ZUoPHHsXWHyt((z zoj1v|tAmKW=tVb1@q11p1BvKIC*^YfIG=oMR+F3CYZZgYlTgi&zJ0RsR=vDS91?wE zNQ}_RF@#&5{H8P(p#OUcX4$u0FP@s}d9kct>xNofFYwQ*`GXU#{|?`*x68V2R#7rT zA5X~y?-!}E&XZTm=_}_Raz_#z`}A)6PWc}h^(7iN_kPB$Lmm_7=-toSoyL5-WVPb6 zUF}=M;g56E)j`dRx%u_=E;owGg8_yQ@&_n^*jH~k-AeTVfo H-FL(fq{1Ng literal 0 HcmV?d00001 diff --git a/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.txt b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.txt new file mode 100644 index 000000000..5834004d1 --- /dev/null +++ b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.txt @@ -0,0 +1,38 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 10 +; Bound: 16 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %xe_frag_color %xe_var_color %xe_var_texcoord + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %xe_frag_color "xe_frag_color" + OpName %xe_var_color "xe_var_color" + OpName %xe_var_texcoord "xe_var_texcoord" + OpDecorate %xe_frag_color RelaxedPrecision + OpDecorate %xe_frag_color Location 0 + OpDecorate %xe_var_color RelaxedPrecision + OpDecorate %xe_var_color Location 1 + OpDecorate %12 RelaxedPrecision + OpDecorate %xe_var_texcoord Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%xe_frag_color = OpVariable %_ptr_Output_v4float Output +%_ptr_Input_v4float = OpTypePointer Input %v4float +%xe_var_color = OpVariable %_ptr_Input_v4float Input + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%xe_var_texcoord = OpVariable %_ptr_Input_v2float Input + %main = OpFunction %void None %3 + %5 = OpLabel + %12 = OpLoad %v4float %xe_var_color + OpStore %xe_frag_color %12 + OpReturn + OpFunctionEnd diff --git a/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.h b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.h new file mode 100644 index 000000000..1ea709c75 --- /dev/null +++ b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.h @@ -0,0 +1,116 @@ +// generated from `xb genspirv` +// source: immediate.vert +const uint8_t immediate_vert[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00, + 0x2C, 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, 0x0B, 0x00, 0x00, 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, + 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 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, 0x76, 0x61, 0x72, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F, + 0x6F, 0x72, 0x64, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x78, 0x65, 0x5F, 0x61, 0x74, 0x74, 0x72, 0x5F, 0x74, 0x65, 0x78, 0x63, + 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x76, 0x61, 0x72, 0x5F, 0x63, + 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, 0x74, 0x74, 0x72, 0x5F, + 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, + 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, + 0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x61, + 0x74, 0x74, 0x72, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x1A, 0x00, 0x00, 0x00, + 0x58, 0x65, 0x50, 0x75, 0x73, 0x68, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61, + 0x6E, 0x74, 0x73, 0x00, 0x06, 0x00, 0x08, 0x00, 0x1A, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x65, 0x77, 0x70, 0x6F, 0x72, 0x74, + 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x5F, 0x69, 0x6E, 0x76, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x03, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x1A, 0x00, 0x00, 0x00, 0x02, 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, 0x02, 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, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0D, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x04, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2B, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, + 0x1A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x1B, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, + 0x3B, 0x00, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1D, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3F, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x23, 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, + 0x3D, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x1D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x07, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0x2A, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x03, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, +}; diff --git a/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.spv b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..ef72522c08b6a84eb82160ab7e2db18d625b5905 GIT binary patch literal 1340 zcmYk5%TE+R5XPGw_8}^W2>8UojV~m`gAxmK^Q~IS18oRSO!=y)h>`h+h%^?Km6f^_RTXEyVW%kBzTt3SU&E*uKTn zv++gg_lxtKxUOblE`%PLFWz?=3z)CxZtMJ-kH0rZAFHzQlhQY;JuqG_H!boXr&aB< zM#ZzDoLXMu?&6e;v?+G8VW`FI7ff#>^}-$yVzFm^>;l1ujjv-kao2SspEL!#LE10+ zpW_a=co%VP{=Cf{`=SQ3BE$Bu-r$H|(J$wwy@Zxqlid@SO4rq&9;0F6QsIG4UK{-D zfY}8c{so=%75(7YEA_4lQ=hj+{Gv{B;i(5^U$Ndb+0=`EFgt_WP&~88n$)`?OfEe2 zz`P5%RpB+Asg(R@0k6wOh^JrPPFp{*{V@x*@91P!_D3w3HvxzLUa*O$Hgj%DCGR61 z8vOY#;zx#^{?~c6=YdH zZpmiO52{ArycuR;7cu63;D3kSQepDoF9P>Kb}D7gUx9ll8=hG{i(?OurSM4Pp2&uq ila4hFJwKHai;vx~2YTdPY)Sc+^vFzL;{U3`E9pO88(zx* literal 0 HcmV?d00001 diff --git a/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.txt b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.txt new file mode 100644 index 000000000..fbc229b84 --- /dev/null +++ b/src/xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.txt @@ -0,0 +1,82 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 10 +; Bound: 44 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %xe_var_texcoord %xe_attr_texcoord %xe_var_color %xe_attr_color %_ %xe_attr_position + OpSource ESSL 310 + OpName %main "main" + OpName %xe_var_texcoord "xe_var_texcoord" + OpName %xe_attr_texcoord "xe_attr_texcoord" + OpName %xe_var_color "xe_var_color" + OpName %xe_attr_color "xe_attr_color" + OpName %gl_PerVertex "gl_PerVertex" + OpMemberName %gl_PerVertex 0 "gl_Position" + OpMemberName %gl_PerVertex 1 "gl_PointSize" + OpName %_ "" + OpName %xe_attr_position "xe_attr_position" + OpName %XePushConstants "XePushConstants" + OpMemberName %XePushConstants 0 "viewport_size_inv" + OpName %__0 "" + OpDecorate %xe_var_texcoord Location 0 + OpDecorate %xe_attr_texcoord Location 1 + OpDecorate %xe_var_color RelaxedPrecision + OpDecorate %xe_var_color Location 1 + OpDecorate %xe_attr_color RelaxedPrecision + OpDecorate %xe_attr_color Location 2 + OpDecorate %18 RelaxedPrecision + OpMemberDecorate %gl_PerVertex 0 BuiltIn Position + OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize + OpDecorate %gl_PerVertex Block + OpDecorate %xe_attr_position Location 0 + OpMemberDecorate %XePushConstants 0 Offset 0 + OpDecorate %XePushConstants Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 +%_ptr_Output_v2float = OpTypePointer Output %v2float +%xe_var_texcoord = OpVariable %_ptr_Output_v2float Output +%_ptr_Input_v2float = OpTypePointer Input %v2float +%xe_attr_texcoord = OpVariable %_ptr_Input_v2float Input + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%xe_var_color = OpVariable %_ptr_Output_v4float Output +%_ptr_Input_v4float = OpTypePointer Input %v4float +%xe_attr_color = OpVariable %_ptr_Input_v4float Input +%gl_PerVertex = OpTypeStruct %v4float %float +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex + %_ = OpVariable %_ptr_Output_gl_PerVertex Output + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%xe_attr_position = OpVariable %_ptr_Input_v2float Input +%XePushConstants = OpTypeStruct %v2float +%_ptr_PushConstant_XePushConstants = OpTypePointer PushConstant %XePushConstants + %__0 = 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 + %43 = OpConstantComposite %v2float %float_1 %float_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %12 = OpLoad %v2float %xe_attr_texcoord + OpStore %xe_var_texcoord %12 + %18 = OpLoad %v4float %xe_attr_color + OpStore %xe_var_color %18 + %25 = OpLoad %v2float %xe_attr_position + %30 = OpAccessChain %_ptr_PushConstant_v2float %__0 %int_0 + %31 = OpLoad %v2float %30 + %32 = OpFMul %v2float %25 %31 + %34 = OpVectorTimesScalar %v2float %32 %float_2 + %37 = OpFSub %v2float %34 %43 + %39 = OpCompositeExtract %float %37 0 + %40 = OpCompositeExtract %float %37 1 + %41 = OpCompositeConstruct %v4float %39 %40 %float_0 %float_1 + %42 = OpAccessChain %_ptr_Output_v4float %_ %int_0 + OpStore %42 %41 + OpReturn + OpFunctionEnd diff --git a/src/xenia/ui/shaders/immediate.frag b/src/xenia/ui/shaders/immediate.frag new file mode 100644 index 000000000..e1c9d63d0 --- /dev/null +++ b/src/xenia/ui/shaders/immediate.frag @@ -0,0 +1,11 @@ +#version 310 es +precision highp float; + +layout(location = 0) in vec2 xe_var_texcoord; +layout(location = 1) in lowp vec4 xe_var_color; + +layout(location = 0) out lowp vec4 xe_frag_color; + +void main() { + xe_frag_color = xe_var_color; +} diff --git a/src/xenia/ui/shaders/immediate.vert b/src/xenia/ui/shaders/immediate.vert new file mode 100644 index 000000000..15328f108 --- /dev/null +++ b/src/xenia/ui/shaders/immediate.vert @@ -0,0 +1,20 @@ +#version 310 es +precision highp float; + +layout(push_constant) uniform XePushConstants { + layout(offset = 0) vec2 viewport_size_inv; +}; + +layout(location = 0) in vec2 xe_attr_position; +layout(location = 1) in vec2 xe_attr_texcoord; +layout(location = 2) in lowp vec4 xe_attr_color; + +layout(location = 0) out vec2 xe_var_texcoord; +layout(location = 1) out lowp vec4 xe_var_color; + +void main() { + xe_var_texcoord = xe_attr_texcoord; + xe_var_color = xe_attr_color; + gl_Position = vec4(xe_attr_position * viewport_size_inv * 2.0 - 1.0, 0.0, + 1.0); +} diff --git a/src/xenia/ui/shaders/immediate.vs.hlsl b/src/xenia/ui/shaders/immediate.vs.hlsl index 7c3e22530..2391d7c3b 100644 --- a/src/xenia/ui/shaders/immediate.vs.hlsl +++ b/src/xenia/ui/shaders/immediate.vs.hlsl @@ -1,4 +1,4 @@ -float2 xe_viewport_inv_size : register(b0); +float2 xe_viewport_size_inv : register(b0); struct XeVertexShaderInput { float2 position : POSITION; @@ -14,10 +14,10 @@ struct XeVertexShaderOutput { XeVertexShaderOutput main(XeVertexShaderInput input) { XeVertexShaderOutput output; - output.position = float4( - input.position * xe_viewport_inv_size * float2(2.0, -2.0) + - float2(-1.0, 1.0), 0.0, 1.0); output.texcoord = input.texcoord; output.color = input.color; + output.position = float4( + input.position * xe_viewport_size_inv * float2(2.0, -2.0) + + float2(-1.0, 1.0), 0.0, 1.0); return output; } diff --git a/src/xenia/ui/vulkan/premake5.lua b/src/xenia/ui/vulkan/premake5.lua index e657b4af3..21a829d69 100644 --- a/src/xenia/ui/vulkan/premake5.lua +++ b/src/xenia/ui/vulkan/premake5.lua @@ -14,3 +14,24 @@ project("xenia-ui-vulkan") files({ "../shaders/bytecode/vulkan_spirv/*.h", }) + +group("demos") +project("xenia-ui-window-vulkan-demo") + uuid("97598f13-3177-454c-8e58-c59e2b6ede27") + kind("WindowedApp") + language("C++") + links({ + "fmt", + "imgui", + "xenia-base", + "xenia-ui", + "xenia-ui-vulkan", + }) + files({ + "../window_demo.cc", + "vulkan_window_demo.cc", + project_root.."/src/xenia/base/main_"..platform_suffix..".cc", + }) + resincludedirs({ + project_root, + }) diff --git a/src/xenia/ui/vulkan/vulkan_context.cc b/src/xenia/ui/vulkan/vulkan_context.cc index 28c68bcd5..2d2306045 100644 --- a/src/xenia/ui/vulkan/vulkan_context.cc +++ b/src/xenia/ui/vulkan/vulkan_context.cc @@ -35,6 +35,8 @@ namespace vulkan { VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window) : GraphicsContext(provider, target_window) {} +VulkanContext::~VulkanContext() { Shutdown(); } + bool VulkanContext::Initialize() { context_lost_ = false; @@ -110,7 +112,10 @@ bool VulkanContext::Initialize() { } immediate_drawer_ = std::make_unique(*this); - // TODO(Triang3l): Initialize the immediate drawer. + if (!immediate_drawer_->Initialize()) { + Shutdown(); + return false; + } swap_swapchain_or_surface_recreation_needed_ = true; @@ -124,6 +129,8 @@ void VulkanContext::Shutdown() { AwaitAllSwapSubmissionsCompletion(); + immediate_drawer_.reset(); + const VulkanProvider& provider = GetVulkanProvider(); const VulkanProvider::InstanceFunctions& ifn = provider.ifn(); VkInstance instance = provider.instance(); diff --git a/src/xenia/ui/vulkan/vulkan_context.h b/src/xenia/ui/vulkan/vulkan_context.h index 477d4de17..687967057 100644 --- a/src/xenia/ui/vulkan/vulkan_context.h +++ b/src/xenia/ui/vulkan/vulkan_context.h @@ -24,6 +24,8 @@ namespace vulkan { class VulkanContext : public GraphicsContext { public: + ~VulkanContext() override; + ImmediateDrawer* immediate_drawer() override; bool WasLost() override; @@ -43,6 +45,15 @@ class VulkanContext : public GraphicsContext { return swap_submissions_[swap_submission_current_ % kSwapchainMaxImageCount] .command_buffer; } + uint64_t swap_submission_current() const { return swap_submission_current_; } + uint64_t swap_submission_completed() const { + return swap_submission_completed_; + } + + const VkSurfaceFormatKHR& swap_surface_format() const { + return swap_surface_format_; + } + VkRenderPass swap_render_pass() const { return swap_render_pass_; } private: friend class VulkanProvider; diff --git a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc index abd787f12..159a13266 100644 --- a/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc +++ b/src/xenia/ui/vulkan/vulkan_immediate_drawer.cc @@ -9,12 +9,22 @@ #include "xenia/ui/vulkan/vulkan_immediate_drawer.h" +#include + +#include "xenia/base/assert.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" #include "xenia/ui/vulkan/vulkan_context.h" +#include "xenia/ui/vulkan/vulkan_util.h" namespace xe { namespace ui { namespace vulkan { +// Generated with `xb genspirv`. +#include "xenia/ui/shaders/bytecode/vulkan_spirv/immediate_frag.h" +#include "xenia/ui/shaders/bytecode/vulkan_spirv/immediate_vert.h" + class VulkanImmediateTexture : public ImmediateTexture { public: VulkanImmediateTexture(uint32_t width, uint32_t height) @@ -24,6 +34,59 @@ class VulkanImmediateTexture : public ImmediateTexture { VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext& graphics_context) : ImmediateDrawer(&graphics_context), context_(graphics_context) {} +VulkanImmediateDrawer::~VulkanImmediateDrawer() { Shutdown(); } + +bool VulkanImmediateDrawer::Initialize() { + const VulkanProvider& provider = context_.GetVulkanProvider(); + const VulkanProvider::DeviceFunctions& dfn = provider.dfn(); + VkDevice device = provider.device(); + + VkPushConstantRange push_constant_ranges[1]; + 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); + 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 (dfn.vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, + &pipeline_layout_) != VK_SUCCESS) { + XELOGE("Failed to create the immediate drawer Vulkan pipeline layout"); + Shutdown(); + return false; + } + + vertex_buffer_pool_ = std::make_unique( + provider, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + + // Reset the current state. + current_command_buffer_ = VK_NULL_HANDLE; + batch_open_ = false; + + return true; +} + +void VulkanImmediateDrawer::Shutdown() { + const VulkanProvider& provider = context_.GetVulkanProvider(); + const VulkanProvider::DeviceFunctions& dfn = provider.dfn(); + VkDevice device = provider.device(); + + util::DestroyAndNullHandle(dfn.vkDestroyPipeline, device, pipeline_line_); + util::DestroyAndNullHandle(dfn.vkDestroyPipeline, device, pipeline_triangle_); + + vertex_buffer_pool_.reset(); + + util::DestroyAndNullHandle(dfn.vkDestroyPipelineLayout, device, + pipeline_layout_); +} + std::unique_ptr VulkanImmediateDrawer::CreateTexture( uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat, const uint8_t* data) { @@ -35,15 +98,355 @@ void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture, const uint8_t* data) {} void VulkanImmediateDrawer::Begin(int render_target_width, - int render_target_height) {} + int render_target_height) { + assert_true(current_command_buffer_ == VK_NULL_HANDLE); + assert_false(batch_open_); -void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {} + if (!EnsurePipelinesCreated()) { + return; + } -void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {} + current_command_buffer_ = context_.GetSwapCommandBuffer(); -void VulkanImmediateDrawer::EndDrawBatch() {} + uint64_t submission_completed = context_.swap_submission_completed(); + vertex_buffer_pool_->Reclaim(submission_completed); -void VulkanImmediateDrawer::End() {} + const VulkanProvider::DeviceFunctions& dfn = + context_.GetVulkanProvider().dfn(); + + current_render_target_extent_.width = uint32_t(render_target_width); + current_render_target_extent_.height = uint32_t(render_target_height); + 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 = 1.0f; + dfn.vkCmdSetViewport(current_command_buffer_, 0, 1, &viewport); + PushConstants::Vertex push_constants_vertex; + push_constants_vertex.viewport_size_inv[0] = 1.0f / viewport.width; + push_constants_vertex.viewport_size_inv[1] = 1.0f / viewport.height; + dfn.vkCmdPushConstants(current_command_buffer_, pipeline_layout_, + VK_SHADER_STAGE_VERTEX_BIT, + offsetof(PushConstants, vertex), + sizeof(PushConstants::Vertex), &push_constants_vertex); + + current_pipeline_ = VK_NULL_HANDLE; +} + +void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { + assert_false(batch_open_); + if (current_command_buffer_ == VK_NULL_HANDLE) { + // No surface, or failed to create the pipelines. + return; + } + + uint64_t submission_current = context_.swap_submission_current(); + const VulkanProvider::DeviceFunctions& dfn = + context_.GetVulkanProvider().dfn(); + + // Bind the vertices. + size_t vertex_buffer_size = sizeof(ImmediateVertex) * batch.vertex_count; + VkBuffer vertex_buffer; + VkDeviceSize vertex_buffer_offset; + void* vertex_buffer_mapping = vertex_buffer_pool_->Request( + submission_current, vertex_buffer_size, sizeof(float), vertex_buffer, + vertex_buffer_offset); + if (!vertex_buffer_mapping) { + XELOGE("Failed to get a buffer for {} vertices in the immediate drawer", + batch.vertex_count); + return; + } + std::memcpy(vertex_buffer_mapping, batch.vertices, vertex_buffer_size); + dfn.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 = sizeof(uint16_t) * batch.index_count; + VkBuffer index_buffer; + VkDeviceSize index_buffer_offset; + void* index_buffer_mapping = vertex_buffer_pool_->Request( + submission_current, index_buffer_size, sizeof(uint16_t), index_buffer, + index_buffer_offset); + if (!index_buffer_mapping) { + XELOGE("Failed to get a buffer for {} indices in the immediate drawer", + batch.index_count); + return; + } + std::memcpy(index_buffer_mapping, batch.indices, index_buffer_size); + dfn.vkCmdBindIndexBuffer(current_command_buffer_, index_buffer, + index_buffer_offset, VK_INDEX_TYPE_UINT16); + } + + batch_open_ = true; +} + +void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) { + if (!batch_open_) { + // No surface, or failed to create the pipelines, or could be an error while + // obtaining the vertex and index buffers. + return; + } + + const VulkanProvider::DeviceFunctions& dfn = + context_.GetVulkanProvider().dfn(); + + // Bind the pipeline for the current primitive count. + 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) { + current_pipeline_ = pipeline; + dfn.vkCmdBindPipeline(current_command_buffer_, + VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + } + + // Set the scissor rectangle if enabled. + VkRect2D scissor; + if (draw.scissor) { + scissor.offset.x = draw.scissor_rect[0]; + scissor.offset.y = current_render_target_extent_.height - + (draw.scissor_rect[1] + draw.scissor_rect[3]); + scissor.extent.width = draw.scissor_rect[2]; + scissor.extent.height = draw.scissor_rect[3]; + } else { + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent = current_render_target_extent_; + } + dfn.vkCmdSetScissor(current_command_buffer_, 0, 1, &scissor); + + // Draw. + if (batch_has_index_buffer_) { + dfn.vkCmdDrawIndexed(current_command_buffer_, draw.count, 1, + draw.index_offset, draw.base_vertex, 0); + } else { + dfn.vkCmdDraw(current_command_buffer_, draw.count, 1, draw.base_vertex, 0); + } +} + +void VulkanImmediateDrawer::EndDrawBatch() { batch_open_ = false; } + +void VulkanImmediateDrawer::End() { + assert_false(batch_open_); + if (current_command_buffer_ == VK_NULL_HANDLE) { + // Didn't draw anything because the of some issue or surface not being + // available. + return; + } + vertex_buffer_pool_->FlushWrites(); + current_command_buffer_ = VK_NULL_HANDLE; +} + +bool VulkanImmediateDrawer::EnsurePipelinesCreated() { + VkFormat swap_surface_format = context_.swap_surface_format().format; + if (swap_surface_format == pipeline_framebuffer_format_) { + // Either created, or failed to create once (don't try to create every + // frame). + return pipeline_triangle_ != VK_NULL_HANDLE && + pipeline_line_ != VK_NULL_HANDLE; + } + VkRenderPass swap_render_pass = context_.swap_render_pass(); + if (swap_surface_format == VK_FORMAT_UNDEFINED || + swap_render_pass == VK_NULL_HANDLE) { + // Not ready yet. + return false; + } + + const VulkanProvider& provider = context_.GetVulkanProvider(); + const VulkanProvider::DeviceFunctions& dfn = provider.dfn(); + VkDevice device = provider.device(); + + // Safe to destroy the pipelines now - if the render pass was recreated, + // completion of its usage has already been awaited. + util::DestroyAndNullHandle(dfn.vkDestroyPipeline, device, pipeline_line_); + util::DestroyAndNullHandle(dfn.vkDestroyPipeline, device, pipeline_triangle_); + // If creation fails now, don't try to create every frame. + pipeline_framebuffer_format_ = swap_surface_format; + + // Triangle pipeline. + + VkPipelineShaderStageCreateInfo stages[2] = {}; + stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + stages[0].module = util::CreateShaderModule(provider, immediate_vert, + sizeof(immediate_vert)); + if (stages[0].module == VK_NULL_HANDLE) { + XELOGE("Failed to create the immediate drawer Vulkan vertex shader module"); + return false; + } + stages[0].pName = "main"; + stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stages[1].module = util::CreateShaderModule(provider, immediate_frag, + sizeof(immediate_frag)); + if (stages[1].module == VK_NULL_HANDLE) { + XELOGE( + "Failed to create the immediate drawer Vulkan fragment shader module"); + dfn.vkDestroyShaderModule(device, stages[0].module, nullptr); + return false; + } + stages[1].pName = "main"; + + VkVertexInputBindingDescription vertex_input_binding; + vertex_input_binding.binding = 0; + vertex_input_binding.stride = sizeof(ImmediateVertex); + vertex_input_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + VkVertexInputAttributeDescription vertex_input_attributes[3]; + vertex_input_attributes[0].location = 0; + vertex_input_attributes[0].binding = 0; + vertex_input_attributes[0].format = VK_FORMAT_R32G32_SFLOAT; + vertex_input_attributes[0].offset = offsetof(ImmediateVertex, x); + vertex_input_attributes[1].location = 1; + vertex_input_attributes[1].binding = 0; + vertex_input_attributes[1].format = VK_FORMAT_R32G32_SFLOAT; + vertex_input_attributes[1].offset = offsetof(ImmediateVertex, u); + vertex_input_attributes[2].location = 2; + vertex_input_attributes[2].binding = 0; + vertex_input_attributes[2].format = VK_FORMAT_R8G8B8A8_UNORM; + vertex_input_attributes[2].offset = offsetof(ImmediateVertex, color); + VkPipelineVertexInputStateCreateInfo vertex_input_state; + vertex_input_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertex_input_state.pNext = nullptr; + vertex_input_state.flags = 0; + vertex_input_state.vertexBindingDescriptionCount = 1; + vertex_input_state.pVertexBindingDescriptions = &vertex_input_binding; + vertex_input_state.vertexAttributeDescriptionCount = + uint32_t(xe::countof(vertex_input_attributes)); + vertex_input_state.pVertexAttributeDescriptions = vertex_input_attributes; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_state; + input_assembly_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + input_assembly_state.pNext = nullptr; + input_assembly_state.flags = 0; + input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + input_assembly_state.primitiveRestartEnable = VK_FALSE; + + VkPipelineViewportStateCreateInfo viewport_state; + viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = nullptr; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = nullptr; + viewport_state.scissorCount = 1; + viewport_state.pScissors = nullptr; + + VkPipelineRasterizationStateCreateInfo rasterization_state = {}; + rasterization_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_state.polygonMode = VK_POLYGON_MODE_FILL; + rasterization_state.cullMode = VK_CULL_MODE_NONE; + rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterization_state.lineWidth = 1.0f; + + VkPipelineMultisampleStateCreateInfo multisample_state = {}; + multisample_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState color_blend_attachment_state; + color_blend_attachment_state.blendEnable = VK_TRUE; + color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + color_blend_attachment_state.dstColorBlendFactor = + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; + // Don't change alpha (always 1). + color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; + color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT; + VkPipelineColorBlendStateCreateInfo color_blend_state; + color_blend_state.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_state.pNext = nullptr; + color_blend_state.flags = 0; + color_blend_state.logicOpEnable = VK_FALSE; + color_blend_state.logicOp = VK_LOGIC_OP_NO_OP; + color_blend_state.attachmentCount = 1; + color_blend_state.pAttachments = &color_blend_attachment_state; + color_blend_state.blendConstants[0] = 1.0f; + color_blend_state.blendConstants[1] = 1.0f; + color_blend_state.blendConstants[2] = 1.0f; + color_blend_state.blendConstants[3] = 1.0f; + + static const VkDynamicState dynamic_states[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + VkPipelineDynamicStateCreateInfo dynamic_state; + dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state.pNext = nullptr; + dynamic_state.flags = 0; + dynamic_state.dynamicStateCount = uint32_t(xe::countof(dynamic_states)); + dynamic_state.pDynamicStates = dynamic_states; + + 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; + pipeline_create_info.stageCount = uint32_t(xe::countof(stages)); + pipeline_create_info.pStages = stages; + pipeline_create_info.pVertexInputState = &vertex_input_state; + pipeline_create_info.pInputAssemblyState = &input_assembly_state; + pipeline_create_info.pTessellationState = nullptr; + pipeline_create_info.pViewportState = &viewport_state; + pipeline_create_info.pRasterizationState = &rasterization_state; + pipeline_create_info.pMultisampleState = &multisample_state; + pipeline_create_info.pDepthStencilState = nullptr; + pipeline_create_info.pColorBlendState = &color_blend_state; + pipeline_create_info.pDynamicState = &dynamic_state; + pipeline_create_info.layout = pipeline_layout_; + pipeline_create_info.renderPass = swap_render_pass; + pipeline_create_info.subpass = 0; + pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; + pipeline_create_info.basePipelineIndex = -1; + if (dfn.vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, + &pipeline_create_info, nullptr, + &pipeline_triangle_) != VK_SUCCESS) { + XELOGE( + "Failed to create the immediate drawer triangle list Vulkan pipeline"); + dfn.vkDestroyShaderModule(device, stages[1].module, nullptr); + dfn.vkDestroyShaderModule(device, stages[0].module, nullptr); + return false; + } + + // Line pipeline. + + input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + pipeline_create_info.flags = + (pipeline_create_info.flags & ~VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT) | + VK_PIPELINE_CREATE_DERIVATIVE_BIT; + pipeline_create_info.basePipelineHandle = pipeline_triangle_; + VkResult pipeline_line_create_result = dfn.vkCreateGraphicsPipelines( + device, VK_NULL_HANDLE, 1, &pipeline_create_info, nullptr, + &pipeline_line_); + dfn.vkDestroyShaderModule(device, stages[1].module, nullptr); + dfn.vkDestroyShaderModule(device, stages[0].module, nullptr); + if (pipeline_line_create_result != VK_SUCCESS) { + XELOGE("Failed to create the immediate drawer line list Vulkan pipeline"); + dfn.vkDestroyPipeline(device, pipeline_triangle_, nullptr); + pipeline_triangle_ = VK_NULL_HANDLE; + return false; + } + + return true; +} } // namespace vulkan } // namespace ui diff --git a/src/xenia/ui/vulkan/vulkan_immediate_drawer.h b/src/xenia/ui/vulkan/vulkan_immediate_drawer.h index 2e437ea25..eb1a4ebb4 100644 --- a/src/xenia/ui/vulkan/vulkan_immediate_drawer.h +++ b/src/xenia/ui/vulkan/vulkan_immediate_drawer.h @@ -10,7 +10,10 @@ #ifndef XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_ #define XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_ +#include + #include "xenia/ui/immediate_drawer.h" +#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h" namespace xe { namespace ui { @@ -21,6 +24,10 @@ class VulkanContext; class VulkanImmediateDrawer : public ImmediateDrawer { public: VulkanImmediateDrawer(VulkanContext& graphics_context); + ~VulkanImmediateDrawer() override; + + bool Initialize(); + void Shutdown(); std::unique_ptr CreateTexture(uint32_t width, uint32_t height, @@ -36,7 +43,29 @@ class VulkanImmediateDrawer : public ImmediateDrawer { void End() override; private: + struct PushConstants { + struct Vertex { + float viewport_size_inv[2]; + } vertex; + }; + + bool EnsurePipelinesCreated(); + VulkanContext& context_; + + VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; + + std::unique_ptr vertex_buffer_pool_; + + VkFormat pipeline_framebuffer_format_ = VK_FORMAT_UNDEFINED; + VkPipeline pipeline_triangle_ = VK_NULL_HANDLE; + VkPipeline pipeline_line_ = VK_NULL_HANDLE; + + VkCommandBuffer current_command_buffer_ = VK_NULL_HANDLE; + VkExtent2D current_render_target_extent_; + VkPipeline current_pipeline_; + bool batch_open_ = false; + bool batch_has_index_buffer_; }; } // namespace vulkan diff --git a/src/xenia/ui/vulkan/vulkan_provider.cc b/src/xenia/ui/vulkan/vulkan_provider.cc index 1a9a94921..36c3b9a2e 100644 --- a/src/xenia/ui/vulkan/vulkan_provider.cc +++ b/src/xenia/ui/vulkan/vulkan_provider.cc @@ -131,12 +131,16 @@ bool VulkanProvider::Initialize() { const uint32_t api_version_target = VK_MAKE_VERSION(1, 2, 148); static_assert(VK_HEADER_VERSION_COMPLETE >= api_version_target, "Vulkan header files must be up to date"); + uint32_t instance_api_version; if (!lfn_.v_1_1.vkEnumerateInstanceVersion || - lfn_.v_1_1.vkEnumerateInstanceVersion(&api_version_) != VK_SUCCESS) { - api_version_ = VK_API_VERSION_1_0; + lfn_.v_1_1.vkEnumerateInstanceVersion(&instance_api_version) != + VK_SUCCESS) { + instance_api_version = VK_API_VERSION_1_0; } - XELOGVK("Vulkan instance version {}.{}.{}", VK_VERSION_MAJOR(api_version_), - VK_VERSION_MINOR(api_version_), VK_VERSION_PATCH(api_version_)); + XELOGVK("Vulkan instance version {}.{}.{}", + VK_VERSION_MAJOR(instance_api_version), + VK_VERSION_MINOR(instance_api_version), + VK_VERSION_PATCH(instance_api_version)); // Create the instance. std::vector instance_extensions_enabled; @@ -157,9 +161,9 @@ bool VulkanProvider::Initialize() { // designed to use" // "Vulkan 1.0 implementations were required to return // VK_ERROR_INCOMPATIBLE_DRIVER if apiVersion was larger than 1.0" - application_info.apiVersion = api_version_ >= VK_MAKE_VERSION(1, 1, 0) + application_info.apiVersion = instance_api_version >= VK_MAKE_VERSION(1, 1, 0) ? api_version_target - : api_version_; + : instance_api_version; VkInstanceCreateInfo instance_create_info; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pNext = nullptr; @@ -207,6 +211,7 @@ bool VulkanProvider::Initialize() { XE_VULKAN_LOAD_IFN(vkGetDeviceProcAddr); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceFeatures); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceProperties); + XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceMemoryProperties); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceQueueFamilyProperties); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceFormatsKHR); @@ -344,6 +349,11 @@ bool VulkanProvider::Initialize() { continue; } + // Get device properties, will be needed to check if extensions have been + // promoted to core. + ifn_.vkGetPhysicalDeviceProperties(physical_device_current, + &device_properties_); + // Get the extensions, check if swapchain is supported. device_extension_properties.clear(); VkResult device_extensions_enumerate_result; @@ -373,14 +383,23 @@ bool VulkanProvider::Initialize() { continue; } std::memset(&device_extensions_, 0, sizeof(device_extensions_)); + if (device_properties_.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) { + device_extensions_.khr_dedicated_allocation = true; + } bool device_supports_swapchain = false; for (const VkExtensionProperties& device_extension : device_extension_properties) { const char* device_extension_name = device_extension.extensionName; - if (!std::strcmp(device_extension_name, + if (!device_extensions_.ext_fragment_shader_interlock && + !std::strcmp(device_extension_name, "VK_EXT_fragment_shader_interlock")) { device_extensions_.ext_fragment_shader_interlock = true; - } else if (!std::strcmp(device_extension_name, "VK_KHR_swapchain")) { + } else if (!device_extensions_.khr_dedicated_allocation && + !std::strcmp(device_extension_name, + "VK_KHR_dedicated_allocation")) { + device_extensions_.khr_dedicated_allocation = true; + } else if (!device_supports_swapchain && + !std::strcmp(device_extension_name, "VK_KHR_swapchain")) { device_supports_swapchain = true; } } @@ -388,6 +407,32 @@ bool VulkanProvider::Initialize() { continue; } + // Get the memory types. + VkPhysicalDeviceMemoryProperties memory_properties; + ifn_.vkGetPhysicalDeviceMemoryProperties(physical_device_current, + &memory_properties); + memory_types_device_local_ = 0; + memory_types_host_visible_ = 0; + memory_types_host_coherent_ = 0; + for (uint32_t j = 0; j < memory_properties.memoryTypeCount; ++j) { + VkMemoryPropertyFlags memory_property_flags = + memory_properties.memoryTypes[j].propertyFlags; + uint32_t memory_type_bit = uint32_t(1) << j; + if (memory_property_flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + memory_types_device_local_ |= memory_type_bit; + } + if (memory_property_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + memory_types_host_visible_ |= memory_type_bit; + } + if (memory_property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + memory_types_host_coherent_ |= memory_type_bit; + } + } + if (!memory_types_device_local_ && !memory_types_host_visible_) { + // Shouldn't happen according to the specification. + continue; + } + physical_device_ = physical_device_current; break; } @@ -397,7 +442,6 @@ bool VulkanProvider::Initialize() { "support"); return false; } - ifn_.vkGetPhysicalDeviceProperties(physical_device_, &device_properties_); XELOGVK( "Vulkan device: {} (vendor {:04X}, device {:04X}, driver {:08X}, API " "{}.{}.{})", @@ -406,7 +450,12 @@ bool VulkanProvider::Initialize() { VK_VERSION_MAJOR(device_properties_.apiVersion), VK_VERSION_MINOR(device_properties_.apiVersion), VK_VERSION_PATCH(device_properties_.apiVersion)); - // TODO(Triang3l): Report properties, features, extensions. + XELOGVK("Vulkan device extensions:"); + XELOGVK("* VK_EXT_fragment_shader_interlock: {}", + device_extensions_.ext_fragment_shader_interlock ? "yes" : "no"); + XELOGVK("* VK_KHR_dedicated_allocation: {}", + device_extensions_.khr_dedicated_allocation ? "yes" : "no"); + // TODO(Triang3l): Report properties, features. // Create the device. float queue_priority_high = 1.0f; @@ -433,6 +482,11 @@ bool VulkanProvider::Initialize() { if (device_extensions_.ext_fragment_shader_interlock) { device_extensions_enabled.push_back("VK_EXT_fragment_shader_interlock"); } + if (device_properties_.apiVersion < VK_MAKE_VERSION(1, 1, 0)) { + if (device_extensions_.khr_dedicated_allocation) { + device_extensions_enabled.push_back("VK_KHR_dedicated_allocation"); + } + } VkDeviceCreateInfo device_create_info; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.pNext = nullptr; @@ -462,26 +516,48 @@ bool VulkanProvider::Initialize() { nullptr; XE_VULKAN_LOAD_DFN(vkAcquireNextImageKHR); XE_VULKAN_LOAD_DFN(vkAllocateCommandBuffers); + XE_VULKAN_LOAD_DFN(vkAllocateMemory); XE_VULKAN_LOAD_DFN(vkBeginCommandBuffer); + XE_VULKAN_LOAD_DFN(vkBindBufferMemory); XE_VULKAN_LOAD_DFN(vkCmdBeginRenderPass); + XE_VULKAN_LOAD_DFN(vkCmdBindIndexBuffer); + XE_VULKAN_LOAD_DFN(vkCmdBindPipeline); + XE_VULKAN_LOAD_DFN(vkCmdBindVertexBuffers); + XE_VULKAN_LOAD_DFN(vkCmdDraw); + XE_VULKAN_LOAD_DFN(vkCmdDrawIndexed); XE_VULKAN_LOAD_DFN(vkCmdEndRenderPass); + XE_VULKAN_LOAD_DFN(vkCmdPushConstants); + XE_VULKAN_LOAD_DFN(vkCmdSetScissor); + XE_VULKAN_LOAD_DFN(vkCmdSetViewport); + XE_VULKAN_LOAD_DFN(vkCreateBuffer); XE_VULKAN_LOAD_DFN(vkCreateCommandPool); XE_VULKAN_LOAD_DFN(vkCreateFence); XE_VULKAN_LOAD_DFN(vkCreateFramebuffer); + XE_VULKAN_LOAD_DFN(vkCreateGraphicsPipelines); XE_VULKAN_LOAD_DFN(vkCreateImageView); + XE_VULKAN_LOAD_DFN(vkCreatePipelineLayout); XE_VULKAN_LOAD_DFN(vkCreateRenderPass); XE_VULKAN_LOAD_DFN(vkCreateSemaphore); + XE_VULKAN_LOAD_DFN(vkCreateShaderModule); XE_VULKAN_LOAD_DFN(vkCreateSwapchainKHR); + XE_VULKAN_LOAD_DFN(vkDestroyBuffer); XE_VULKAN_LOAD_DFN(vkDestroyCommandPool); XE_VULKAN_LOAD_DFN(vkDestroyFence); XE_VULKAN_LOAD_DFN(vkDestroyFramebuffer); XE_VULKAN_LOAD_DFN(vkDestroyImageView); + XE_VULKAN_LOAD_DFN(vkDestroyPipeline); + XE_VULKAN_LOAD_DFN(vkDestroyPipelineLayout); XE_VULKAN_LOAD_DFN(vkDestroyRenderPass); XE_VULKAN_LOAD_DFN(vkDestroySemaphore); + XE_VULKAN_LOAD_DFN(vkDestroyShaderModule); XE_VULKAN_LOAD_DFN(vkDestroySwapchainKHR); XE_VULKAN_LOAD_DFN(vkEndCommandBuffer); + XE_VULKAN_LOAD_DFN(vkFlushMappedMemoryRanges); + XE_VULKAN_LOAD_DFN(vkFreeMemory); + XE_VULKAN_LOAD_DFN(vkGetBufferMemoryRequirements); XE_VULKAN_LOAD_DFN(vkGetDeviceQueue); XE_VULKAN_LOAD_DFN(vkGetSwapchainImagesKHR); + XE_VULKAN_LOAD_DFN(vkMapMemory); XE_VULKAN_LOAD_DFN(vkResetCommandPool); XE_VULKAN_LOAD_DFN(vkResetFences); XE_VULKAN_LOAD_DFN(vkQueuePresentKHR); diff --git a/src/xenia/ui/vulkan/vulkan_provider.h b/src/xenia/ui/vulkan/vulkan_provider.h index da4d56b80..4e254bbe0 100644 --- a/src/xenia/ui/vulkan/vulkan_provider.h +++ b/src/xenia/ui/vulkan/vulkan_provider.h @@ -59,8 +59,6 @@ class VulkanProvider : public GraphicsProvider { }; const LibraryFunctions& lfn() const { return lfn_; } - uint32_t api_version() const { return api_version_; } - VkInstance instance() const { return instance_; } struct InstanceFunctions { PFN_vkCreateDevice vkCreateDevice; @@ -71,6 +69,7 @@ class VulkanProvider : public GraphicsProvider { PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; @@ -99,10 +98,21 @@ class VulkanProvider : public GraphicsProvider { } struct DeviceExtensions { bool ext_fragment_shader_interlock; + // Core since 1.1.0. + bool khr_dedicated_allocation; }; const DeviceExtensions& device_extensions() const { return device_extensions_; } + uint32_t memory_types_device_local() const { + return memory_types_device_local_; + } + uint32_t memory_types_host_visible() const { + return memory_types_host_visible_; + } + uint32_t memory_types_host_coherent() const { + return memory_types_host_coherent_; + } // FIXME(Triang3l): Allow a separate queue for present - see // vulkan_provider.cc for details. uint32_t queue_family_graphics_compute() const { @@ -113,26 +123,48 @@ class VulkanProvider : public GraphicsProvider { struct DeviceFunctions { PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateMemory vkAllocateMemory; PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; + PFN_vkCmdBindPipeline vkCmdBindPipeline; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; + PFN_vkCmdDraw vkCmdDraw; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed; PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkCmdPushConstants vkCmdPushConstants; + PFN_vkCmdSetScissor vkCmdSetScissor; + PFN_vkCmdSetViewport vkCmdSetViewport; + PFN_vkCreateBuffer vkCreateBuffer; PFN_vkCreateCommandPool vkCreateCommandPool; PFN_vkCreateFence vkCreateFence; PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout; PFN_vkCreateRenderPass vkCreateRenderPass; PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateShaderModule vkCreateShaderModule; PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroyBuffer vkDestroyBuffer; PFN_vkDestroyCommandPool vkDestroyCommandPool; PFN_vkDestroyFence vkDestroyFence; PFN_vkDestroyFramebuffer vkDestroyFramebuffer; PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyPipeline vkDestroyPipeline; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; PFN_vkDestroyRenderPass vkDestroyRenderPass; PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroyShaderModule vkDestroyShaderModule; PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; PFN_vkGetDeviceQueue vkGetDeviceQueue; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkMapMemory vkMapMemory; PFN_vkResetCommandPool vkResetCommandPool; PFN_vkResetFences vkResetFences; PFN_vkQueuePresentKHR vkQueuePresentKHR; @@ -158,8 +190,6 @@ class VulkanProvider : public GraphicsProvider { LibraryFunctions lfn_ = {}; - uint32_t api_version_ = VK_API_VERSION_1_0; - VkInstance instance_ = VK_NULL_HANDLE; InstanceFunctions ifn_ = {}; @@ -167,6 +197,9 @@ class VulkanProvider : public GraphicsProvider { VkPhysicalDeviceProperties device_properties_; VkPhysicalDeviceFeatures device_features_; DeviceExtensions device_extensions_; + uint32_t memory_types_device_local_; + uint32_t memory_types_host_visible_; + uint32_t memory_types_host_coherent_; uint32_t queue_family_graphics_compute_; VkDevice device_ = VK_NULL_HANDLE; diff --git a/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.cc b/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.cc new file mode 100644 index 000000000..11ef6766b --- /dev/null +++ b/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.cc @@ -0,0 +1,227 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h" + +#include + +#include "xenia/base/logging.h" +#include "xenia/base/math.h" + +namespace xe { +namespace ui { +namespace vulkan { + +VulkanUploadBufferPool::VulkanUploadBufferPool(const VulkanProvider& provider, + VkBufferUsageFlags usage, + size_t page_size) + : GraphicsUploadBufferPool(page_size), provider_(provider), usage_(usage) { + VkDeviceSize non_coherent_atom_size = + provider_.device_properties().limits.nonCoherentAtomSize; + // Memory mappings are always aligned to nonCoherentAtomSize, so for + // simplicity, round the page size to it now. On some Android implementations, + // nonCoherentAtomSize is 0, not 1. + if (non_coherent_atom_size > 1) { + page_size_ = xe::round_up(page_size_, non_coherent_atom_size); + } +} + +uint8_t* VulkanUploadBufferPool::Request(uint64_t submission_index, size_t size, + size_t alignment, VkBuffer& buffer_out, + VkDeviceSize& offset_out) { + size_t offset; + const VulkanPage* page = + static_cast(GraphicsUploadBufferPool::Request( + submission_index, size, alignment, offset)); + if (!page) { + return nullptr; + } + buffer_out = page->buffer_; + offset_out = VkDeviceSize(offset); + return reinterpret_cast(page->mapping_) + offset; +} + +uint8_t* VulkanUploadBufferPool::RequestPartial(uint64_t submission_index, + size_t size, size_t alignment, + VkBuffer& buffer_out, + VkDeviceSize& offset_out, + VkDeviceSize& size_out) { + size_t offset, size_obtained; + const VulkanPage* page = + static_cast(GraphicsUploadBufferPool::RequestPartial( + submission_index, size, alignment, offset, size_obtained)); + if (!page) { + return nullptr; + } + buffer_out = page->buffer_; + offset_out = VkDeviceSize(offset); + size_out = VkDeviceSize(size_obtained); + return reinterpret_cast(page->mapping_) + offset; +} + +GraphicsUploadBufferPool::Page* +VulkanUploadBufferPool::CreatePageImplementation() { + if (memory_type_ == kMemoryTypeUnavailable) { + // Don't try to create everything again and again if totally broken. + return nullptr; + } + + const VulkanProvider::DeviceFunctions& dfn = provider_.dfn(); + VkDevice device = provider_.device(); + + // For the first call, the page size is already aligned to nonCoherentAtomSize + // for mapping. + 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 = VkDeviceSize(page_size_); + buffer_create_info.usage = usage_; + buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + buffer_create_info.queueFamilyIndexCount = 0; + buffer_create_info.pQueueFamilyIndices = nullptr; + VkBuffer buffer; + if (dfn.vkCreateBuffer(device, &buffer_create_info, nullptr, &buffer) != + VK_SUCCESS) { + XELOGE("Failed to create a Vulkan upload buffer with {} bytes", page_size_); + return nullptr; + } + + if (memory_type_ == kMemoryTypeUnknown) { + VkMemoryRequirements memory_requirements; + dfn.vkGetBufferMemoryRequirements(device, buffer, &memory_requirements); + uint32_t memory_types_host_visible = provider_.memory_types_host_visible(); + if (!xe::bit_scan_forward( + memory_requirements.memoryTypeBits & memory_types_host_visible, + &memory_type_)) { + XELOGE( + "No host-visible memory types can store an Vulkan upload buffer with " + "{} bytes", + page_size_); + memory_type_ = kMemoryTypeUnavailable; + dfn.vkDestroyBuffer(device, buffer, nullptr); + return nullptr; + } + allocation_size_ = memory_requirements.size; + // On some Android implementations, nonCoherentAtomSize is 0, not 1. + VkDeviceSize non_coherent_atom_size = + std::max(provider_.device_properties().limits.nonCoherentAtomSize, + VkDeviceSize(1)); + VkDeviceSize allocation_size_aligned = + allocation_size_ / non_coherent_atom_size * non_coherent_atom_size; + if (allocation_size_aligned > page_size_) { + // Try to occupy all the allocation padding. If that's going to require + // even more memory for some reason, don't. + buffer_create_info.size = allocation_size_aligned; + VkBuffer buffer_expanded; + if (dfn.vkCreateBuffer(device, &buffer_create_info, nullptr, + &buffer_expanded) == VK_SUCCESS) { + VkMemoryRequirements memory_requirements_expanded; + dfn.vkGetBufferMemoryRequirements(device, buffer_expanded, + &memory_requirements_expanded); + uint32_t memory_type_expanded; + if (memory_requirements_expanded.size <= allocation_size_ && + xe::bit_scan_forward(memory_requirements_expanded.memoryTypeBits & + memory_types_host_visible, + &memory_type_expanded)) { + // page_size_ must be aligned to nonCoherentAtomSize. + page_size_ = size_t(allocation_size_aligned); + allocation_size_ = memory_requirements_expanded.size; + memory_type_ = memory_type_expanded; + dfn.vkDestroyBuffer(device, buffer, nullptr); + buffer = buffer_expanded; + } else { + dfn.vkDestroyBuffer(device, buffer_expanded, nullptr); + } + } + } + } + + VkMemoryAllocateInfo memory_allocate_info; + memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info; + if (provider_.device_extensions().khr_dedicated_allocation) { + memory_dedicated_allocate_info.sType = + VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + memory_dedicated_allocate_info.pNext = nullptr; + memory_dedicated_allocate_info.image = VK_NULL_HANDLE; + memory_dedicated_allocate_info.buffer = buffer; + memory_allocate_info.pNext = &memory_dedicated_allocate_info; + } else { + memory_allocate_info.pNext = nullptr; + } + memory_allocate_info.allocationSize = allocation_size_; + memory_allocate_info.memoryTypeIndex = memory_type_; + VkDeviceMemory memory; + if (dfn.vkAllocateMemory(device, &memory_allocate_info, nullptr, &memory) != + VK_SUCCESS) { + XELOGE("Failed to allocate {} bytes of Vulkan upload buffer memory", + allocation_size_); + dfn.vkDestroyBuffer(device, buffer, nullptr); + return nullptr; + } + + if (dfn.vkBindBufferMemory(device, buffer, memory, 0) != VK_SUCCESS) { + XELOGE("Failed to bind memory to a Vulkan upload buffer with {} bytes", + page_size_); + dfn.vkDestroyBuffer(device, buffer, nullptr); + dfn.vkFreeMemory(device, memory, nullptr); + return nullptr; + } + + void* mapping; + // page_size_ is aligned to nonCoherentAtomSize. + if (dfn.vkMapMemory(device, memory, 0, page_size_, 0, &mapping) != + VK_SUCCESS) { + XELOGE("Failed to map {} bytes of Vulkan upload buffer memory", page_size_); + dfn.vkDestroyBuffer(device, buffer, nullptr); + dfn.vkFreeMemory(device, memory, nullptr); + return nullptr; + } + + return new VulkanPage(provider_, buffer, memory, mapping); +} + +void VulkanUploadBufferPool::FlushPageWrites(Page* page, size_t offset, + size_t size) { + if (provider_.memory_types_host_coherent() & (uint32_t(1) << memory_type_)) { + return; + } + const VulkanProvider::DeviceFunctions& dfn = provider_.dfn(); + VkDevice device = provider_.device(); + VkMappedMemoryRange range; + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.pNext = nullptr; + range.memory = static_cast(page)->memory_; + range.offset = VkDeviceSize(offset); + range.size = VkDeviceSize(size); + VkDeviceSize non_coherent_atom_size = + provider_.device_properties().limits.nonCoherentAtomSize; + // On some Android implementations, nonCoherentAtomSize is 0, not 1. + if (non_coherent_atom_size > 1) { + VkDeviceSize end = + xe::round_up(range.offset + range.size, non_coherent_atom_size); + range.offset = + range.offset / non_coherent_atom_size * non_coherent_atom_size; + range.size = end - range.offset; + } + dfn.vkFlushMappedMemoryRanges(device, 1, &range); +} + +VulkanUploadBufferPool::VulkanPage::~VulkanPage() { + const VulkanProvider::DeviceFunctions& dfn = provider_.dfn(); + VkDevice device = provider_.device(); + dfn.vkDestroyBuffer(device, buffer_, nullptr); + // Unmapping is done implicitly when the memory is freed. + dfn.vkFreeMemory(device, memory_, nullptr); +} + +} // namespace vulkan +} // namespace ui +} // namespace xe diff --git a/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.h b/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.h new file mode 100644 index 000000000..309c44ff1 --- /dev/null +++ b/src/xenia/ui/vulkan/vulkan_upload_buffer_pool.h @@ -0,0 +1,67 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_UI_VULKAN_VULKAN_UPLOAD_BUFFER_POOL_H_ +#define XENIA_UI_VULKAN_VULKAN_UPLOAD_BUFFER_POOL_H_ + +#include "xenia/ui/graphics_upload_buffer_pool.h" +#include "xenia/ui/vulkan/vulkan_provider.h" + +namespace xe { +namespace ui { +namespace vulkan { + +class VulkanUploadBufferPool : public GraphicsUploadBufferPool { + public: + VulkanUploadBufferPool(const VulkanProvider& provider, + VkBufferUsageFlags usage, + size_t page_size = kDefaultPageSize); + + uint8_t* Request(uint64_t submission_index, size_t size, size_t alignment, + VkBuffer& buffer_out, VkDeviceSize& offset_out); + uint8_t* RequestPartial(uint64_t submission_index, size_t size, + size_t alignment, VkBuffer& buffer_out, + VkDeviceSize& offset_out, VkDeviceSize& size_out); + + protected: + Page* CreatePageImplementation() override; + + void FlushPageWrites(Page* page, size_t offset, size_t size) override; + + private: + struct VulkanPage : public Page { + // Takes ownership of the buffer and its memory and mapping. + VulkanPage(const VulkanProvider& provider, VkBuffer buffer, + VkDeviceMemory memory, void* mapping) + : provider_(provider), + buffer_(buffer), + memory_(memory), + mapping_(mapping) {} + ~VulkanPage() override; + const VulkanProvider& provider_; + VkBuffer buffer_; + VkDeviceMemory memory_; + void* mapping_; + }; + + const VulkanProvider& provider_; + + VkDeviceSize allocation_size_; + static constexpr uint32_t kMemoryTypeUnknown = UINT32_MAX; + static constexpr uint32_t kMemoryTypeUnavailable = kMemoryTypeUnknown - 1; + uint32_t memory_type_ = UINT32_MAX; + + VkBufferUsageFlags usage_; +}; + +} // namespace vulkan +} // namespace ui +} // namespace xe + +#endif // XENIA_UI_VULKAN_VULKAN_UPLOAD_BUFFER_POOL_H_ diff --git a/src/xenia/ui/vulkan/vulkan_util.h b/src/xenia/ui/vulkan/vulkan_util.h index c0702ba99..6239aed76 100644 --- a/src/xenia/ui/vulkan/vulkan_util.h +++ b/src/xenia/ui/vulkan/vulkan_util.h @@ -2,7 +2,7 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2019 Ben Vanik. All rights reserved. * + * Copyright 2020 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ @@ -37,6 +37,22 @@ inline bool DestroyAndNullHandle(F* destroy_function, P parent, T& handle) { return false; } +inline VkShaderModule CreateShaderModule(const VulkanProvider& provider, + const void* code, size_t code_size) { + 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 = code_size; + shader_module_create_info.pCode = reinterpret_cast(code); + VkShaderModule shader_module; + return provider.dfn().vkCreateShaderModule( + provider.device(), &shader_module_create_info, nullptr, + &shader_module) == VK_SUCCESS + ? shader_module + : nullptr; +} + } // namespace util } // namespace vulkan } // namespace ui diff --git a/src/xenia/ui/vulkan/vulkan_window_demo.cc b/src/xenia/ui/vulkan/vulkan_window_demo.cc new file mode 100644 index 000000000..12965197b --- /dev/null +++ b/src/xenia/ui/vulkan/vulkan_window_demo.cc @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include +#include + +#include "xenia/base/main.h" +#include "xenia/ui/vulkan/vulkan_provider.h" +#include "xenia/ui/window.h" + +namespace xe { +namespace ui { + +int window_demo_main(const std::vector& args); + +std::unique_ptr CreateDemoGraphicsProvider(Window* window) { + return xe::ui::vulkan::VulkanProvider::Create(window); +} + +} // namespace ui +} // namespace xe + +DEFINE_ENTRY_POINT("xenia-ui-window-vulkan-demo", xe::ui::window_demo_main, ""); diff --git a/xenia-build b/xenia-build index 25675c809..82b18b833 100755 --- a/xenia-build +++ b/xenia-build @@ -689,7 +689,6 @@ class GenSpirvCommand(Command): vulkan_bin_path = os.path.join(vulkan_sdk_path, 'bin') glslang = os.path.join(vulkan_bin_path, 'glslangValidator') spirv_dis = os.path.join(vulkan_bin_path, 'spirv-dis') - spirv_remap = os.path.join(vulkan_bin_path, 'spirv-remap') # Ensure we have the tools. if not os.path.exists(vulkan_sdk_path): @@ -701,9 +700,6 @@ class GenSpirvCommand(Command): elif not has_bin(spirv_dis): print('ERROR: could not find spirv-dis') return 1 - elif not has_bin(spirv_remap): - print('ERROR: could not find spirv-remap') - return 1 src_files = [os.path.join(root, name) for root, dirs, files in os.walk('src') @@ -717,7 +713,8 @@ class GenSpirvCommand(Command): src_name = os.path.splitext(os.path.basename(src_file))[0] identifier = os.path.basename(src_file).replace('.', '_') - bin_path = os.path.join(os.path.dirname(src_file), 'bin') + bin_path = os.path.join(os.path.dirname(src_file), + 'bytecode/vulkan_spirv') spv_file = os.path.join(bin_path, identifier) + '.spv' txt_file = os.path.join(bin_path, identifier) + '.txt' h_file = os.path.join(bin_path, identifier) + '.h'