[Vulkan] Untextured ImmediateDrawer, [D3D12] Small refactoring

This commit is contained in:
Triang3l 2020-09-19 18:05:54 +03:00
parent 36347ffedd
commit 229eb49b54
33 changed files with 1305 additions and 76 deletions

View File

@ -376,7 +376,7 @@ class D3D12CommandProcessor : public CommandProcessor {
CommandAllocator* command_allocator_submitted_last_ = nullptr; CommandAllocator* command_allocator_submitted_last_ = nullptr;
ID3D12GraphicsCommandList* command_list_ = nullptr; ID3D12GraphicsCommandList* command_list_ = nullptr;
ID3D12GraphicsCommandList1* command_list_1_ = nullptr; ID3D12GraphicsCommandList1* command_list_1_ = nullptr;
std::unique_ptr<DeferredCommandList> deferred_command_list_ = nullptr; std::unique_ptr<DeferredCommandList> deferred_command_list_;
// Should bindless textures and samplers be used - many times faster // Should bindless textures and samplers be used - many times faster
// UpdateBindings than bindful (that becomes a significant bottleneck with // UpdateBindings than bindful (that becomes a significant bottleneck with
@ -388,14 +388,12 @@ class D3D12CommandProcessor : public CommandProcessor {
// targets. // targets.
bool edram_rov_used_ = false; bool edram_rov_used_ = false;
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> constant_buffer_pool_ = std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> constant_buffer_pool_;
nullptr;
static constexpr uint32_t kViewBindfulHeapSize = 32768; static constexpr uint32_t kViewBindfulHeapSize = 32768;
static_assert(kViewBindfulHeapSize <= static_assert(kViewBindfulHeapSize <=
D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1); D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1);
std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool> view_bindful_heap_pool_ = std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool> view_bindful_heap_pool_;
nullptr;
// Currently bound descriptor heap - updated by RequestViewBindfulDescriptors. // Currently bound descriptor heap - updated by RequestViewBindfulDescriptors.
ID3D12DescriptorHeap* view_bindful_heap_current_; ID3D12DescriptorHeap* view_bindful_heap_current_;
// Rationale: textures have 4 KB alignment in guest memory, and there can be // 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 constexpr uint32_t kSamplerHeapSize = 2000;
static_assert(kSamplerHeapSize <= D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE); static_assert(kSamplerHeapSize <= D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE);
std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool> std::unique_ptr<ui::d3d12::D3D12DescriptorHeapPool>
sampler_bindful_heap_pool_ = nullptr; sampler_bindful_heap_pool_;
ID3D12DescriptorHeap* sampler_bindful_heap_current_; ID3D12DescriptorHeap* sampler_bindful_heap_current_;
ID3D12DescriptorHeap* sampler_bindless_heap_current_ = nullptr; ID3D12DescriptorHeap* sampler_bindless_heap_current_ = nullptr;
D3D12_CPU_DESCRIPTOR_HANDLE sampler_bindless_heap_cpu_start_; 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_vs_ = nullptr;
ID3D12RootSignature* root_signature_bindless_ds_ = nullptr; ID3D12RootSignature* root_signature_bindless_ds_ = nullptr;
std::unique_ptr<SharedMemory> shared_memory_ = nullptr; std::unique_ptr<SharedMemory> shared_memory_;
std::unique_ptr<PipelineCache> pipeline_cache_ = nullptr; std::unique_ptr<PipelineCache> pipeline_cache_;
std::unique_ptr<TextureCache> texture_cache_ = nullptr; std::unique_ptr<TextureCache> texture_cache_;
std::unique_ptr<RenderTargetCache> render_target_cache_ = nullptr; std::unique_ptr<RenderTargetCache> render_target_cache_;
std::unique_ptr<PrimitiveConverter> primitive_converter_ = nullptr; std::unique_ptr<PrimitiveConverter> primitive_converter_;
// Mip 0 contains the normal gamma ramp (256 entries), mip 1 contains the PWL // Mip 0 contains the normal gamma ramp (256 entries), mip 1 contains the PWL
// ramp (128 entries). DXGI_FORMAT_R10G10B10A2_UNORM 1D. // ramp (128 entries). DXGI_FORMAT_R10G10B10A2_UNORM 1D.

View File

@ -20,7 +20,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace d3d12 { 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/fullscreen_vs.h"
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_gamma_ps.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_gamma_ps.h"
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_ps.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/stretch_ps.h"

View File

@ -56,7 +56,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace d3d12 { 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_quad_hs.h"
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/adaptive_triangle_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" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/continuous_quad_hs.h"

View File

@ -247,7 +247,7 @@ class PipelineCache {
uint32_t resolution_scale_; uint32_t resolution_scale_;
// Reusable shader translator. // Reusable shader translator.
std::unique_ptr<DxbcShaderTranslator> shader_translator_ = nullptr; std::unique_ptr<DxbcShaderTranslator> shader_translator_;
// Command processor thread DXIL conversion/disassembly interfaces, if DXIL // Command processor thread DXIL conversion/disassembly interfaces, if DXIL
// disassembly is enabled. // disassembly is enabled.
@ -344,7 +344,7 @@ class PipelineCache {
// Manual-reset event set when the last queued pipeline state object is // 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 // created and there are no more pipeline state objects to create. This is
// triggered by the thread creating the last pipeline state object. // triggered by the thread creating the last pipeline state object.
std::unique_ptr<xe::threading::Event> creation_completion_event_ = nullptr; std::unique_ptr<xe::threading::Event> creation_completion_event_;
// Whether setting the event on completion is queued. Protected with // Whether setting the event on completion is queued. Protected with
// creation_request_lock_, notify_one creation_request_cond_ when set. // creation_request_lock_, notify_one creation_request_cond_ when set.
bool creation_completion_set_event_ = false; bool creation_completion_set_event_ = false;

View File

@ -107,7 +107,7 @@ class PrimitiveConverter {
Memory& memory_; Memory& memory_;
TraceWriter& trace_writer_; TraceWriter& trace_writer_;
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> buffer_pool_ = nullptr; std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> buffer_pool_;
// Static index buffers for emulating unsupported primitive types when drawing // Static index buffers for emulating unsupported primitive types when drawing
// without an index buffer. // without an index buffer.

View File

@ -36,7 +36,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace d3d12 { 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_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_64bpp_cs.h"
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/edram_load_color_7e3_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/edram_load_color_7e3_cs.h"

View File

@ -603,7 +603,7 @@ class RenderTargetCache {
// For traces only. // For traces only.
ID3D12Resource* edram_snapshot_download_buffer_ = nullptr; ID3D12Resource* edram_snapshot_download_buffer_ = nullptr;
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> std::unique_ptr<ui::d3d12::D3D12UploadBufferPool>
edram_snapshot_restore_pool_ = nullptr; edram_snapshot_restore_pool_;
}; };
} // namespace d3d12 } // namespace d3d12

View File

@ -212,8 +212,7 @@ class SharedMemory {
std::vector<UploadRange> upload_ranges_; std::vector<UploadRange> upload_ranges_;
void GetRangesToUpload(uint32_t request_page_first, void GetRangesToUpload(uint32_t request_page_first,
uint32_t request_page_last); uint32_t request_page_last);
std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> upload_buffer_pool_ = std::unique_ptr<ui::d3d12::D3D12UploadBufferPool> upload_buffer_pool_;
nullptr;
// GPU-written memory downloading for traces. // GPU-written memory downloading for traces.
// Start page, length in pages. // Start page, length in pages.

View File

@ -53,7 +53,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace d3d12 { 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_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_128bpb_cs.h"
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/texture_load_16bpb_2x_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/texture_load_16bpb_2x_cs.h"

View File

@ -99,7 +99,7 @@ class D3D12Context : public GraphicsContext {
// kSwapCommandAllocatorCount. // kSwapCommandAllocatorCount.
ID3D12GraphicsCommandList* swap_command_list_ = nullptr; ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr; std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_;
}; };
} // namespace d3d12 } // namespace d3d12

View File

@ -21,7 +21,7 @@ namespace xe {
namespace ui { namespace ui {
namespace d3d12 { 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_ps.h"
#include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h" #include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h"
@ -158,7 +158,7 @@ bool D3D12ImmediateDrawer::Initialize() {
} }
{ {
auto& root_parameter = 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.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
root_parameter.Constants.ShaderRegister = 0; root_parameter.Constants.ShaderRegister = 0;
root_parameter.Constants.RegisterSpace = 0; root_parameter.Constants.RegisterSpace = 0;
@ -179,7 +179,7 @@ bool D3D12ImmediateDrawer::Initialize() {
return false; return false;
} }
// Create the pipelines. // Create the pipeline states.
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {}; D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {};
pipeline_desc.pRootSignature = root_signature_; pipeline_desc.pRootSignature = root_signature_;
pipeline_desc.VS.pShaderBytecode = immediate_vs; pipeline_desc.VS.pShaderBytecode = immediate_vs;
@ -192,10 +192,13 @@ bool D3D12ImmediateDrawer::Initialize() {
pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA; pipeline_blend_desc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA; pipeline_blend_desc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
pipeline_blend_desc.BlendOp = D3D12_BLEND_OP_ADD; pipeline_blend_desc.BlendOp = D3D12_BLEND_OP_ADD;
pipeline_blend_desc.SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; // Don't change alpha (always 1).
pipeline_blend_desc.DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; 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.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.SampleMask = UINT_MAX;
pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; pipeline_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; pipeline_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
@ -295,6 +298,7 @@ bool D3D12ImmediateDrawer::Initialize() {
// Reset the current state. // Reset the current state.
current_command_list_ = nullptr; current_command_list_ = nullptr;
batch_open_ = false;
return true; return true;
} }
@ -415,6 +419,9 @@ void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
void D3D12ImmediateDrawer::Begin(int render_target_width, void D3D12ImmediateDrawer::Begin(int render_target_width,
int render_target_height) { int render_target_height) {
assert_null(current_command_list_);
assert_false(batch_open_);
auto device = context_.GetD3D12Provider().GetDevice(); auto device = context_.GetD3D12Provider().GetDevice();
// Use the compositing command list. // 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[0] = 1.0f / viewport.Width;
viewport_inv_size[1] = 1.0f / viewport.Height; viewport_inv_size[1] = 1.0f / viewport.Height;
current_command_list_->SetGraphicsRoot32BitConstants( 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_primitive_topology_ = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
current_texture_ = nullptr; current_texture_ = nullptr;
@ -493,21 +500,18 @@ void D3D12ImmediateDrawer::Begin(int render_target_width,
} }
void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) { void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
assert_false(batch_open_);
assert_not_null(current_command_list_); 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. // Bind the vertices.
D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view; D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex)); vertex_buffer_view.StrideInBytes = UINT(sizeof(ImmediateVertex));
vertex_buffer_view.SizeInBytes = 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( 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); nullptr, nullptr, &vertex_buffer_view.BufferLocation);
if (vertex_buffer_mapping == nullptr) { if (vertex_buffer_mapping == nullptr) {
XELOGE("Failed to get a buffer for {} vertices in the immediate drawer", 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; batch_has_index_buffer_ = batch.indices != nullptr;
if (batch_has_index_buffer_) { if (batch_has_index_buffer_) {
D3D12_INDEX_BUFFER_VIEW index_buffer_view; 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; index_buffer_view.Format = DXGI_FORMAT_R16_UINT;
void* index_buffer_mapping = vertex_buffer_pool_->Request( void* index_buffer_mapping = vertex_buffer_pool_->Request(
current_fence_value, index_buffer_view.SizeInBytes, sizeof(uint16_t), 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) { void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
assert_not_null(current_command_list_);
if (current_command_list_ == nullptr) {
return;
}
if (!batch_open_) { if (!batch_open_) {
// Could be an error while obtaining the vertex and index buffers. // Could be an error while obtaining the vertex and index buffers.
return; return;
@ -678,7 +677,10 @@ void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
void D3D12ImmediateDrawer::EndDrawBatch() { batch_open_ = false; } 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 d3d12
} // namespace ui } // namespace ui

View File

@ -54,7 +54,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
kRestrictTextureSamples, kRestrictTextureSamples,
kTexture, kTexture,
kSampler, kSampler,
kViewportInvSize, kViewportSizeInv,
kCount kCount
}; };
@ -75,8 +75,8 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_; D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_;
D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_; D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_;
std::unique_ptr<D3D12UploadBufferPool> vertex_buffer_pool_ = nullptr; std::unique_ptr<D3D12UploadBufferPool> vertex_buffer_pool_;
std::unique_ptr<D3D12DescriptorHeapPool> texture_descriptor_pool_ = nullptr; std::unique_ptr<D3D12DescriptorHeapPool> texture_descriptor_pool_;
uint64_t texture_descriptor_pool_heap_index_; uint64_t texture_descriptor_pool_heap_index_;
struct PendingTextureUpload { struct PendingTextureUpload {

View File

@ -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,
};

View File

@ -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

View File

@ -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,
};

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -1,4 +1,4 @@
float2 xe_viewport_inv_size : register(b0); float2 xe_viewport_size_inv : register(b0);
struct XeVertexShaderInput { struct XeVertexShaderInput {
float2 position : POSITION; float2 position : POSITION;
@ -14,10 +14,10 @@ struct XeVertexShaderOutput {
XeVertexShaderOutput main(XeVertexShaderInput input) { XeVertexShaderOutput main(XeVertexShaderInput input) {
XeVertexShaderOutput output; 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.texcoord = input.texcoord;
output.color = input.color; 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; return output;
} }

View File

@ -14,3 +14,24 @@ project("xenia-ui-vulkan")
files({ files({
"../shaders/bytecode/vulkan_spirv/*.h", "../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,
})

View File

@ -35,6 +35,8 @@ namespace vulkan {
VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window) VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window)
: GraphicsContext(provider, target_window) {} : GraphicsContext(provider, target_window) {}
VulkanContext::~VulkanContext() { Shutdown(); }
bool VulkanContext::Initialize() { bool VulkanContext::Initialize() {
context_lost_ = false; context_lost_ = false;
@ -110,7 +112,10 @@ bool VulkanContext::Initialize() {
} }
immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(*this); immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(*this);
// TODO(Triang3l): Initialize the immediate drawer. if (!immediate_drawer_->Initialize()) {
Shutdown();
return false;
}
swap_swapchain_or_surface_recreation_needed_ = true; swap_swapchain_or_surface_recreation_needed_ = true;
@ -124,6 +129,8 @@ void VulkanContext::Shutdown() {
AwaitAllSwapSubmissionsCompletion(); AwaitAllSwapSubmissionsCompletion();
immediate_drawer_.reset();
const VulkanProvider& provider = GetVulkanProvider(); const VulkanProvider& provider = GetVulkanProvider();
const VulkanProvider::InstanceFunctions& ifn = provider.ifn(); const VulkanProvider::InstanceFunctions& ifn = provider.ifn();
VkInstance instance = provider.instance(); VkInstance instance = provider.instance();

View File

@ -24,6 +24,8 @@ namespace vulkan {
class VulkanContext : public GraphicsContext { class VulkanContext : public GraphicsContext {
public: public:
~VulkanContext() override;
ImmediateDrawer* immediate_drawer() override; ImmediateDrawer* immediate_drawer() override;
bool WasLost() override; bool WasLost() override;
@ -43,6 +45,15 @@ class VulkanContext : public GraphicsContext {
return swap_submissions_[swap_submission_current_ % kSwapchainMaxImageCount] return swap_submissions_[swap_submission_current_ % kSwapchainMaxImageCount]
.command_buffer; .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: private:
friend class VulkanProvider; friend class VulkanProvider;

View File

@ -9,12 +9,22 @@
#include "xenia/ui/vulkan/vulkan_immediate_drawer.h" #include "xenia/ui/vulkan/vulkan_immediate_drawer.h"
#include <cstring>
#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_context.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe { namespace xe {
namespace ui { namespace ui {
namespace vulkan { 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 { class VulkanImmediateTexture : public ImmediateTexture {
public: public:
VulkanImmediateTexture(uint32_t width, uint32_t height) VulkanImmediateTexture(uint32_t width, uint32_t height)
@ -24,6 +34,59 @@ class VulkanImmediateTexture : public ImmediateTexture {
VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext& graphics_context) VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext& graphics_context)
: ImmediateDrawer(&graphics_context), context_(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<VulkanUploadBufferPool>(
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<ImmediateTexture> VulkanImmediateDrawer::CreateTexture( std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat, uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
const uint8_t* data) { const uint8_t* data) {
@ -35,15 +98,355 @@ void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
const uint8_t* data) {} const uint8_t* data) {}
void VulkanImmediateDrawer::Begin(int render_target_width, 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 vulkan
} // namespace ui } // namespace ui

View File

@ -10,7 +10,10 @@
#ifndef XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_ #ifndef XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_
#define XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_ #define XENIA_UI_VULKAN_VULKAN_IMMEDIATE_DRAWER_H_
#include <memory>
#include "xenia/ui/immediate_drawer.h" #include "xenia/ui/immediate_drawer.h"
#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h"
namespace xe { namespace xe {
namespace ui { namespace ui {
@ -21,6 +24,10 @@ class VulkanContext;
class VulkanImmediateDrawer : public ImmediateDrawer { class VulkanImmediateDrawer : public ImmediateDrawer {
public: public:
VulkanImmediateDrawer(VulkanContext& graphics_context); VulkanImmediateDrawer(VulkanContext& graphics_context);
~VulkanImmediateDrawer() override;
bool Initialize();
void Shutdown();
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width, std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
uint32_t height, uint32_t height,
@ -36,7 +43,29 @@ class VulkanImmediateDrawer : public ImmediateDrawer {
void End() override; void End() override;
private: private:
struct PushConstants {
struct Vertex {
float viewport_size_inv[2];
} vertex;
};
bool EnsurePipelinesCreated();
VulkanContext& context_; VulkanContext& context_;
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
std::unique_ptr<VulkanUploadBufferPool> 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 } // namespace vulkan

View File

@ -131,12 +131,16 @@ bool VulkanProvider::Initialize() {
const uint32_t api_version_target = VK_MAKE_VERSION(1, 2, 148); const uint32_t api_version_target = VK_MAKE_VERSION(1, 2, 148);
static_assert(VK_HEADER_VERSION_COMPLETE >= api_version_target, static_assert(VK_HEADER_VERSION_COMPLETE >= api_version_target,
"Vulkan header files must be up to date"); "Vulkan header files must be up to date");
uint32_t instance_api_version;
if (!lfn_.v_1_1.vkEnumerateInstanceVersion || if (!lfn_.v_1_1.vkEnumerateInstanceVersion ||
lfn_.v_1_1.vkEnumerateInstanceVersion(&api_version_) != VK_SUCCESS) { lfn_.v_1_1.vkEnumerateInstanceVersion(&instance_api_version) !=
api_version_ = VK_API_VERSION_1_0; VK_SUCCESS) {
instance_api_version = VK_API_VERSION_1_0;
} }
XELOGVK("Vulkan instance version {}.{}.{}", VK_VERSION_MAJOR(api_version_), XELOGVK("Vulkan instance version {}.{}.{}",
VK_VERSION_MINOR(api_version_), VK_VERSION_PATCH(api_version_)); VK_VERSION_MAJOR(instance_api_version),
VK_VERSION_MINOR(instance_api_version),
VK_VERSION_PATCH(instance_api_version));
// Create the instance. // Create the instance.
std::vector<const char*> instance_extensions_enabled; std::vector<const char*> instance_extensions_enabled;
@ -157,9 +161,9 @@ bool VulkanProvider::Initialize() {
// designed to use" // designed to use"
// "Vulkan 1.0 implementations were required to return // "Vulkan 1.0 implementations were required to return
// VK_ERROR_INCOMPATIBLE_DRIVER if apiVersion was larger than 1.0" // 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_target
: api_version_; : instance_api_version;
VkInstanceCreateInfo instance_create_info; VkInstanceCreateInfo instance_create_info;
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pNext = nullptr; instance_create_info.pNext = nullptr;
@ -207,6 +211,7 @@ bool VulkanProvider::Initialize() {
XE_VULKAN_LOAD_IFN(vkGetDeviceProcAddr); XE_VULKAN_LOAD_IFN(vkGetDeviceProcAddr);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceFeatures); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceFeatures);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceProperties); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceProperties);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceMemoryProperties);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceQueueFamilyProperties); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceQueueFamilyProperties);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceFormatsKHR); XE_VULKAN_LOAD_IFN(vkGetPhysicalDeviceSurfaceFormatsKHR);
@ -344,6 +349,11 @@ bool VulkanProvider::Initialize() {
continue; 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. // Get the extensions, check if swapchain is supported.
device_extension_properties.clear(); device_extension_properties.clear();
VkResult device_extensions_enumerate_result; VkResult device_extensions_enumerate_result;
@ -373,14 +383,23 @@ bool VulkanProvider::Initialize() {
continue; continue;
} }
std::memset(&device_extensions_, 0, sizeof(device_extensions_)); 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; bool device_supports_swapchain = false;
for (const VkExtensionProperties& device_extension : for (const VkExtensionProperties& device_extension :
device_extension_properties) { device_extension_properties) {
const char* device_extension_name = device_extension.extensionName; 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")) { "VK_EXT_fragment_shader_interlock")) {
device_extensions_.ext_fragment_shader_interlock = true; 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; device_supports_swapchain = true;
} }
} }
@ -388,6 +407,32 @@ bool VulkanProvider::Initialize() {
continue; 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; physical_device_ = physical_device_current;
break; break;
} }
@ -397,7 +442,6 @@ bool VulkanProvider::Initialize() {
"support"); "support");
return false; return false;
} }
ifn_.vkGetPhysicalDeviceProperties(physical_device_, &device_properties_);
XELOGVK( XELOGVK(
"Vulkan device: {} (vendor {:04X}, device {:04X}, driver {:08X}, API " "Vulkan device: {} (vendor {:04X}, device {:04X}, driver {:08X}, API "
"{}.{}.{})", "{}.{}.{})",
@ -406,7 +450,12 @@ bool VulkanProvider::Initialize() {
VK_VERSION_MAJOR(device_properties_.apiVersion), VK_VERSION_MAJOR(device_properties_.apiVersion),
VK_VERSION_MINOR(device_properties_.apiVersion), VK_VERSION_MINOR(device_properties_.apiVersion),
VK_VERSION_PATCH(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. // Create the device.
float queue_priority_high = 1.0f; float queue_priority_high = 1.0f;
@ -433,6 +482,11 @@ bool VulkanProvider::Initialize() {
if (device_extensions_.ext_fragment_shader_interlock) { if (device_extensions_.ext_fragment_shader_interlock) {
device_extensions_enabled.push_back("VK_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; VkDeviceCreateInfo device_create_info;
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pNext = nullptr; device_create_info.pNext = nullptr;
@ -462,26 +516,48 @@ bool VulkanProvider::Initialize() {
nullptr; nullptr;
XE_VULKAN_LOAD_DFN(vkAcquireNextImageKHR); XE_VULKAN_LOAD_DFN(vkAcquireNextImageKHR);
XE_VULKAN_LOAD_DFN(vkAllocateCommandBuffers); XE_VULKAN_LOAD_DFN(vkAllocateCommandBuffers);
XE_VULKAN_LOAD_DFN(vkAllocateMemory);
XE_VULKAN_LOAD_DFN(vkBeginCommandBuffer); XE_VULKAN_LOAD_DFN(vkBeginCommandBuffer);
XE_VULKAN_LOAD_DFN(vkBindBufferMemory);
XE_VULKAN_LOAD_DFN(vkCmdBeginRenderPass); 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(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(vkCreateCommandPool);
XE_VULKAN_LOAD_DFN(vkCreateFence); XE_VULKAN_LOAD_DFN(vkCreateFence);
XE_VULKAN_LOAD_DFN(vkCreateFramebuffer); XE_VULKAN_LOAD_DFN(vkCreateFramebuffer);
XE_VULKAN_LOAD_DFN(vkCreateGraphicsPipelines);
XE_VULKAN_LOAD_DFN(vkCreateImageView); XE_VULKAN_LOAD_DFN(vkCreateImageView);
XE_VULKAN_LOAD_DFN(vkCreatePipelineLayout);
XE_VULKAN_LOAD_DFN(vkCreateRenderPass); XE_VULKAN_LOAD_DFN(vkCreateRenderPass);
XE_VULKAN_LOAD_DFN(vkCreateSemaphore); XE_VULKAN_LOAD_DFN(vkCreateSemaphore);
XE_VULKAN_LOAD_DFN(vkCreateShaderModule);
XE_VULKAN_LOAD_DFN(vkCreateSwapchainKHR); XE_VULKAN_LOAD_DFN(vkCreateSwapchainKHR);
XE_VULKAN_LOAD_DFN(vkDestroyBuffer);
XE_VULKAN_LOAD_DFN(vkDestroyCommandPool); XE_VULKAN_LOAD_DFN(vkDestroyCommandPool);
XE_VULKAN_LOAD_DFN(vkDestroyFence); XE_VULKAN_LOAD_DFN(vkDestroyFence);
XE_VULKAN_LOAD_DFN(vkDestroyFramebuffer); XE_VULKAN_LOAD_DFN(vkDestroyFramebuffer);
XE_VULKAN_LOAD_DFN(vkDestroyImageView); XE_VULKAN_LOAD_DFN(vkDestroyImageView);
XE_VULKAN_LOAD_DFN(vkDestroyPipeline);
XE_VULKAN_LOAD_DFN(vkDestroyPipelineLayout);
XE_VULKAN_LOAD_DFN(vkDestroyRenderPass); XE_VULKAN_LOAD_DFN(vkDestroyRenderPass);
XE_VULKAN_LOAD_DFN(vkDestroySemaphore); XE_VULKAN_LOAD_DFN(vkDestroySemaphore);
XE_VULKAN_LOAD_DFN(vkDestroyShaderModule);
XE_VULKAN_LOAD_DFN(vkDestroySwapchainKHR); XE_VULKAN_LOAD_DFN(vkDestroySwapchainKHR);
XE_VULKAN_LOAD_DFN(vkEndCommandBuffer); 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(vkGetDeviceQueue);
XE_VULKAN_LOAD_DFN(vkGetSwapchainImagesKHR); XE_VULKAN_LOAD_DFN(vkGetSwapchainImagesKHR);
XE_VULKAN_LOAD_DFN(vkMapMemory);
XE_VULKAN_LOAD_DFN(vkResetCommandPool); XE_VULKAN_LOAD_DFN(vkResetCommandPool);
XE_VULKAN_LOAD_DFN(vkResetFences); XE_VULKAN_LOAD_DFN(vkResetFences);
XE_VULKAN_LOAD_DFN(vkQueuePresentKHR); XE_VULKAN_LOAD_DFN(vkQueuePresentKHR);

View File

@ -59,8 +59,6 @@ class VulkanProvider : public GraphicsProvider {
}; };
const LibraryFunctions& lfn() const { return lfn_; } const LibraryFunctions& lfn() const { return lfn_; }
uint32_t api_version() const { return api_version_; }
VkInstance instance() const { return instance_; } VkInstance instance() const { return instance_; }
struct InstanceFunctions { struct InstanceFunctions {
PFN_vkCreateDevice vkCreateDevice; PFN_vkCreateDevice vkCreateDevice;
@ -71,6 +69,7 @@ class VulkanProvider : public GraphicsProvider {
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures; PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties PFN_vkGetPhysicalDeviceQueueFamilyProperties
vkGetPhysicalDeviceQueueFamilyProperties; vkGetPhysicalDeviceQueueFamilyProperties;
@ -99,10 +98,21 @@ class VulkanProvider : public GraphicsProvider {
} }
struct DeviceExtensions { struct DeviceExtensions {
bool ext_fragment_shader_interlock; bool ext_fragment_shader_interlock;
// Core since 1.1.0.
bool khr_dedicated_allocation;
}; };
const DeviceExtensions& device_extensions() const { const DeviceExtensions& device_extensions() const {
return device_extensions_; 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 // FIXME(Triang3l): Allow a separate queue for present - see
// vulkan_provider.cc for details. // vulkan_provider.cc for details.
uint32_t queue_family_graphics_compute() const { uint32_t queue_family_graphics_compute() const {
@ -113,26 +123,48 @@ class VulkanProvider : public GraphicsProvider {
struct DeviceFunctions { struct DeviceFunctions {
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
PFN_vkAllocateMemory vkAllocateMemory;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer; PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
PFN_vkBindBufferMemory vkBindBufferMemory;
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
PFN_vkCmdBindPipeline vkCmdBindPipeline;
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
PFN_vkCmdDraw vkCmdDraw;
PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
PFN_vkCmdEndRenderPass vkCmdEndRenderPass; PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
PFN_vkCmdPushConstants vkCmdPushConstants;
PFN_vkCmdSetScissor vkCmdSetScissor;
PFN_vkCmdSetViewport vkCmdSetViewport;
PFN_vkCreateBuffer vkCreateBuffer;
PFN_vkCreateCommandPool vkCreateCommandPool; PFN_vkCreateCommandPool vkCreateCommandPool;
PFN_vkCreateFence vkCreateFence; PFN_vkCreateFence vkCreateFence;
PFN_vkCreateFramebuffer vkCreateFramebuffer; PFN_vkCreateFramebuffer vkCreateFramebuffer;
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
PFN_vkCreateImageView vkCreateImageView; PFN_vkCreateImageView vkCreateImageView;
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
PFN_vkCreateRenderPass vkCreateRenderPass; PFN_vkCreateRenderPass vkCreateRenderPass;
PFN_vkCreateSemaphore vkCreateSemaphore; PFN_vkCreateSemaphore vkCreateSemaphore;
PFN_vkCreateShaderModule vkCreateShaderModule;
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
PFN_vkDestroyBuffer vkDestroyBuffer;
PFN_vkDestroyCommandPool vkDestroyCommandPool; PFN_vkDestroyCommandPool vkDestroyCommandPool;
PFN_vkDestroyFence vkDestroyFence; PFN_vkDestroyFence vkDestroyFence;
PFN_vkDestroyFramebuffer vkDestroyFramebuffer; PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
PFN_vkDestroyImageView vkDestroyImageView; PFN_vkDestroyImageView vkDestroyImageView;
PFN_vkDestroyPipeline vkDestroyPipeline;
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
PFN_vkDestroyRenderPass vkDestroyRenderPass; PFN_vkDestroyRenderPass vkDestroyRenderPass;
PFN_vkDestroySemaphore vkDestroySemaphore; PFN_vkDestroySemaphore vkDestroySemaphore;
PFN_vkDestroyShaderModule vkDestroyShaderModule;
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
PFN_vkEndCommandBuffer vkEndCommandBuffer; PFN_vkEndCommandBuffer vkEndCommandBuffer;
PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
PFN_vkFreeMemory vkFreeMemory;
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
PFN_vkGetDeviceQueue vkGetDeviceQueue; PFN_vkGetDeviceQueue vkGetDeviceQueue;
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
PFN_vkMapMemory vkMapMemory;
PFN_vkResetCommandPool vkResetCommandPool; PFN_vkResetCommandPool vkResetCommandPool;
PFN_vkResetFences vkResetFences; PFN_vkResetFences vkResetFences;
PFN_vkQueuePresentKHR vkQueuePresentKHR; PFN_vkQueuePresentKHR vkQueuePresentKHR;
@ -158,8 +190,6 @@ class VulkanProvider : public GraphicsProvider {
LibraryFunctions lfn_ = {}; LibraryFunctions lfn_ = {};
uint32_t api_version_ = VK_API_VERSION_1_0;
VkInstance instance_ = VK_NULL_HANDLE; VkInstance instance_ = VK_NULL_HANDLE;
InstanceFunctions ifn_ = {}; InstanceFunctions ifn_ = {};
@ -167,6 +197,9 @@ class VulkanProvider : public GraphicsProvider {
VkPhysicalDeviceProperties device_properties_; VkPhysicalDeviceProperties device_properties_;
VkPhysicalDeviceFeatures device_features_; VkPhysicalDeviceFeatures device_features_;
DeviceExtensions device_extensions_; 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_; uint32_t queue_family_graphics_compute_;
VkDevice device_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE;

View File

@ -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 <algorithm>
#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<const VulkanPage*>(GraphicsUploadBufferPool::Request(
submission_index, size, alignment, offset));
if (!page) {
return nullptr;
}
buffer_out = page->buffer_;
offset_out = VkDeviceSize(offset);
return reinterpret_cast<uint8_t*>(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<const VulkanPage*>(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<uint8_t*>(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<const VulkanPage*>(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

View File

@ -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_

View File

@ -2,7 +2,7 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * 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. * * 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; 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<const uint32_t*>(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 util
} // namespace vulkan } // namespace vulkan
} // namespace ui } // namespace ui

View File

@ -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 <string>
#include <vector>
#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<std::string>& args);
std::unique_ptr<GraphicsProvider> 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, "");

View File

@ -689,7 +689,6 @@ class GenSpirvCommand(Command):
vulkan_bin_path = os.path.join(vulkan_sdk_path, 'bin') vulkan_bin_path = os.path.join(vulkan_sdk_path, 'bin')
glslang = os.path.join(vulkan_bin_path, 'glslangValidator') glslang = os.path.join(vulkan_bin_path, 'glslangValidator')
spirv_dis = os.path.join(vulkan_bin_path, 'spirv-dis') 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. # Ensure we have the tools.
if not os.path.exists(vulkan_sdk_path): if not os.path.exists(vulkan_sdk_path):
@ -701,9 +700,6 @@ class GenSpirvCommand(Command):
elif not has_bin(spirv_dis): elif not has_bin(spirv_dis):
print('ERROR: could not find spirv-dis') print('ERROR: could not find spirv-dis')
return 1 return 1
elif not has_bin(spirv_remap):
print('ERROR: could not find spirv-remap')
return 1
src_files = [os.path.join(root, name) src_files = [os.path.join(root, name)
for root, dirs, files in os.walk('src') 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] src_name = os.path.splitext(os.path.basename(src_file))[0]
identifier = os.path.basename(src_file).replace('.', '_') 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' spv_file = os.path.join(bin_path, identifier) + '.spv'
txt_file = os.path.join(bin_path, identifier) + '.txt' txt_file = os.path.join(bin_path, identifier) + '.txt'
h_file = os.path.join(bin_path, identifier) + '.h' h_file = os.path.join(bin_path, identifier) + '.h'