Merge branch 'master' into linux_windowing
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <d3d12.h>
|
||||
#include <d3d12sdklayers.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <dcomp.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <dxgidebug.h>
|
||||
// For Microsoft::WRL::ComPtr.
|
||||
|
||||
@@ -32,10 +32,10 @@ bool D3D12Context::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& provider = GetD3D12Provider();
|
||||
auto dxgi_factory = provider.GetDXGIFactory();
|
||||
auto device = provider.GetDevice();
|
||||
auto direct_queue = provider.GetDirectQueue();
|
||||
const D3D12Provider& provider = GetD3D12Provider();
|
||||
IDXGIFactory2* dxgi_factory = provider.GetDXGIFactory();
|
||||
ID3D12Device* device = provider.GetDevice();
|
||||
ID3D12CommandQueue* direct_queue = provider.GetDirectQueue();
|
||||
|
||||
swap_fence_current_value_ = 1;
|
||||
swap_fence_completed_value_ = 0;
|
||||
@@ -70,11 +70,10 @@ bool D3D12Context::Initialize() {
|
||||
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
|
||||
swap_chain_desc.Flags = 0;
|
||||
IDXGISwapChain1* swap_chain_1;
|
||||
if (FAILED(dxgi_factory->CreateSwapChainForHwnd(
|
||||
provider.GetDirectQueue(),
|
||||
reinterpret_cast<HWND>(target_window_->native_handle()),
|
||||
&swap_chain_desc, nullptr, nullptr, &swap_chain_1))) {
|
||||
XELOGE("Failed to create a DXGI swap chain");
|
||||
if (FAILED(dxgi_factory->CreateSwapChainForComposition(
|
||||
provider.GetDirectQueue(), &swap_chain_desc, nullptr,
|
||||
&swap_chain_1))) {
|
||||
XELOGE("Failed to create a DXGI swap chain for composition");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
@@ -117,9 +116,9 @@ bool D3D12Context::Initialize() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
swap_command_allocators_[0], nullptr,
|
||||
IID_PPV_ARGS(&swap_command_list_)))) {
|
||||
if (FAILED(device->CreateCommandList(
|
||||
0, D3D12_COMMAND_LIST_TYPE_DIRECT, swap_command_allocators_[0].Get(),
|
||||
nullptr, IID_PPV_ARGS(&swap_command_list_)))) {
|
||||
XELOGE("Failed to create the composition graphics command list");
|
||||
Shutdown();
|
||||
return false;
|
||||
@@ -127,6 +126,45 @@ bool D3D12Context::Initialize() {
|
||||
// Initially in open state, wait until BeginSwap.
|
||||
swap_command_list_->Close();
|
||||
|
||||
// Associate the swap chain with the window via DirectComposition.
|
||||
if (FAILED(provider.CreateDCompositionDevice(nullptr,
|
||||
IID_PPV_ARGS(&dcomp_device_)))) {
|
||||
XELOGE("Failed to create a DirectComposition device");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dcomp_device_->CreateTargetForHwnd(
|
||||
reinterpret_cast<HWND>(target_window_->native_handle()), TRUE,
|
||||
&dcomp_target_))) {
|
||||
XELOGE("Failed to create a DirectComposition target for the window");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dcomp_device_->CreateVisual(&dcomp_visual_))) {
|
||||
XELOGE("Failed to create a DirectComposition visual");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dcomp_visual_->SetContent(swap_chain_.Get()))) {
|
||||
XELOGE(
|
||||
"Failed to set the content of the DirectComposition visual to the swap "
|
||||
"chain");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dcomp_target_->SetRoot(dcomp_visual_.Get()))) {
|
||||
XELOGE(
|
||||
"Failed to set the root of the DirectComposition target to the swap "
|
||||
"chain visual");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
if (FAILED(dcomp_device_->Commit())) {
|
||||
XELOGE("Failed to commit DirectComposition commands");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the immediate mode drawer if not offscreen.
|
||||
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(*this);
|
||||
if (!immediate_drawer_->Initialize()) {
|
||||
@@ -151,14 +189,14 @@ bool D3D12Context::InitializeSwapChainBuffers() {
|
||||
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
|
||||
|
||||
// Create RTV descriptors for the swap chain buffers.
|
||||
auto device = GetD3D12Provider().GetDevice();
|
||||
ID3D12Device* device = GetD3D12Provider().GetDevice();
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
|
||||
rtv_desc.Format = kSwapChainFormat;
|
||||
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||
rtv_desc.Texture2D.MipSlice = 0;
|
||||
rtv_desc.Texture2D.PlaneSlice = 0;
|
||||
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
|
||||
device->CreateRenderTargetView(swap_chain_buffers_[i], &rtv_desc,
|
||||
device->CreateRenderTargetView(swap_chain_buffers_[i].Get(), &rtv_desc,
|
||||
GetSwapChainBufferRTV(i));
|
||||
}
|
||||
|
||||
@@ -179,34 +217,23 @@ void D3D12Context::Shutdown() {
|
||||
|
||||
immediate_drawer_.reset();
|
||||
|
||||
util::ReleaseAndNull(swap_command_list_);
|
||||
dcomp_visual_.Reset();
|
||||
dcomp_target_.Reset();
|
||||
dcomp_device_.Reset();
|
||||
|
||||
swap_command_list_.Reset();
|
||||
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
|
||||
auto& swap_command_allocator = swap_command_allocators_[i];
|
||||
if (!swap_command_allocator) {
|
||||
break;
|
||||
}
|
||||
swap_command_allocator->Release();
|
||||
swap_command_allocator = nullptr;
|
||||
swap_command_allocators_[i].Reset();
|
||||
}
|
||||
|
||||
if (swap_chain_) {
|
||||
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
|
||||
auto& swap_chain_buffer = swap_chain_buffers_[i];
|
||||
if (!swap_chain_buffer) {
|
||||
break;
|
||||
}
|
||||
swap_chain_buffer->Release();
|
||||
swap_chain_buffer = nullptr;
|
||||
}
|
||||
|
||||
util::ReleaseAndNull(swap_chain_rtv_heap_);
|
||||
|
||||
swap_chain_->Release();
|
||||
swap_chain_ = nullptr;
|
||||
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
|
||||
swap_chain_buffers_[i].Reset();
|
||||
}
|
||||
swap_chain_rtv_heap_.Reset();
|
||||
swap_chain_.Reset();
|
||||
|
||||
// First release the fence since it may reference the event.
|
||||
util::ReleaseAndNull(swap_fence_);
|
||||
swap_fence_.Reset();
|
||||
if (swap_fence_completion_event_) {
|
||||
CloseHandle(swap_fence_completion_event_);
|
||||
swap_fence_completion_event_ = nullptr;
|
||||
@@ -243,8 +270,7 @@ bool D3D12Context::BeginSwap() {
|
||||
}
|
||||
// All buffer references must be released before resizing.
|
||||
for (uint32_t i = 0; i < kSwapChainBufferCount; ++i) {
|
||||
swap_chain_buffers_[i]->Release();
|
||||
swap_chain_buffers_[i] = nullptr;
|
||||
swap_chain_buffers_[i].Reset();
|
||||
}
|
||||
if (FAILED(swap_chain_->ResizeBuffers(
|
||||
kSwapChainBufferCount, target_window_width, target_window_height,
|
||||
@@ -276,7 +302,8 @@ bool D3D12Context::BeginSwap() {
|
||||
uint32_t command_allocator_index =
|
||||
uint32_t((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1)) %
|
||||
kSwapCommandAllocatorCount);
|
||||
auto command_allocator = swap_command_allocators_[command_allocator_index];
|
||||
ID3D12CommandAllocator* command_allocator =
|
||||
swap_command_allocators_[command_allocator_index].Get();
|
||||
command_allocator->Reset();
|
||||
swap_command_list_->Reset(command_allocator, nullptr);
|
||||
|
||||
@@ -285,7 +312,7 @@ bool D3D12Context::BeginSwap() {
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource =
|
||||
swap_chain_buffers_[swap_chain_back_buffer_index_];
|
||||
swap_chain_buffers_[swap_chain_back_buffer_index_].Get();
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
@@ -305,14 +332,14 @@ void D3D12Context::EndSwap() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto direct_queue = GetD3D12Provider().GetDirectQueue();
|
||||
ID3D12CommandQueue* direct_queue = GetD3D12Provider().GetDirectQueue();
|
||||
|
||||
// Switch the back buffer to presentation state.
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource =
|
||||
swap_chain_buffers_[swap_chain_back_buffer_index_];
|
||||
swap_chain_buffers_[swap_chain_back_buffer_index_].Get();
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
@@ -320,7 +347,7 @@ void D3D12Context::EndSwap() {
|
||||
|
||||
// Submit the command list.
|
||||
swap_command_list_->Close();
|
||||
ID3D12CommandList* execute_command_lists[] = {swap_command_list_};
|
||||
ID3D12CommandList* execute_command_lists[] = {swap_command_list_.Get()};
|
||||
direct_queue->ExecuteCommandLists(1, execute_command_lists);
|
||||
|
||||
// Present and check if the context was lost.
|
||||
@@ -330,7 +357,7 @@ void D3D12Context::EndSwap() {
|
||||
}
|
||||
|
||||
// Signal the fence to wait for frame resources to become free again.
|
||||
direct_queue->Signal(swap_fence_, swap_fence_current_value_++);
|
||||
direct_queue->Signal(swap_fence_.Get(), swap_fence_current_value_++);
|
||||
|
||||
// Get the back buffer index for the next frame.
|
||||
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
|
||||
|
||||
@@ -40,7 +40,7 @@ class D3D12Context : public GraphicsContext {
|
||||
// The format used by DWM.
|
||||
static constexpr DXGI_FORMAT kSwapChainFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
ID3D12Resource* GetSwapChainBuffer(uint32_t buffer_index) const {
|
||||
return swap_chain_buffers_[buffer_index];
|
||||
return swap_chain_buffers_[buffer_index].Get();
|
||||
}
|
||||
uint32_t GetSwapChainBackBufferIndex() const {
|
||||
return swap_chain_back_buffer_index_;
|
||||
@@ -62,7 +62,7 @@ class D3D12Context : public GraphicsContext {
|
||||
return swap_fence_completed_value_;
|
||||
}
|
||||
ID3D12GraphicsCommandList* GetSwapCommandList() const {
|
||||
return swap_command_list_;
|
||||
return swap_command_list_.Get();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -77,25 +77,30 @@ class D3D12Context : public GraphicsContext {
|
||||
bool context_lost_ = false;
|
||||
|
||||
static constexpr uint32_t kSwapChainBufferCount = 3;
|
||||
IDXGISwapChain3* swap_chain_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<IDXGISwapChain3> swap_chain_;
|
||||
uint32_t swap_chain_width_ = 0, swap_chain_height_ = 0;
|
||||
ID3D12Resource* swap_chain_buffers_[kSwapChainBufferCount] = {};
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource>
|
||||
swap_chain_buffers_[kSwapChainBufferCount];
|
||||
uint32_t swap_chain_back_buffer_index_ = 0;
|
||||
ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> swap_chain_rtv_heap_;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE swap_chain_rtv_heap_start_;
|
||||
|
||||
uint64_t swap_fence_current_value_ = 1;
|
||||
uint64_t swap_fence_completed_value_ = 0;
|
||||
HANDLE swap_fence_completion_event_ = nullptr;
|
||||
ID3D12Fence* swap_fence_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<ID3D12Fence> swap_fence_;
|
||||
|
||||
static constexpr uint32_t kSwapCommandAllocatorCount = 3;
|
||||
ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] =
|
||||
{};
|
||||
Microsoft::WRL::ComPtr<ID3D12CommandAllocator>
|
||||
swap_command_allocators_[kSwapCommandAllocatorCount];
|
||||
// Current command allocator is:
|
||||
// ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) %
|
||||
// kSwapCommandAllocatorCount.
|
||||
ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
|
||||
Microsoft::WRL::ComPtr<ID3D12GraphicsCommandList> swap_command_list_;
|
||||
|
||||
Microsoft::WRL::ComPtr<IDCompositionDevice> dcomp_device_;
|
||||
Microsoft::WRL::ComPtr<IDCompositionTarget> dcomp_target_;
|
||||
Microsoft::WRL::ComPtr<IDCompositionVisual> dcomp_visual_;
|
||||
|
||||
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_;
|
||||
};
|
||||
|
||||
@@ -24,9 +24,11 @@ namespace xe {
|
||||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
// Generated with `xb buildhlsl`.
|
||||
#include "xenia/ui/d3d12/shaders/dxbc/immediate_ps.h"
|
||||
#include "xenia/ui/d3d12/shaders/dxbc/immediate_vs.h"
|
||||
// Generated with `xb buildshaders`.
|
||||
namespace shaders {
|
||||
#include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_ps.h"
|
||||
#include "xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h"
|
||||
} // namespace shaders
|
||||
|
||||
D3D12ImmediateDrawer::D3D12ImmediateTexture::D3D12ImmediateTexture(
|
||||
uint32_t width, uint32_t height, ID3D12Resource* resource,
|
||||
@@ -121,10 +123,10 @@ bool D3D12ImmediateDrawer::Initialize() {
|
||||
// Create the pipelines.
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc = {};
|
||||
pipeline_desc.pRootSignature = root_signature_;
|
||||
pipeline_desc.VS.pShaderBytecode = immediate_vs;
|
||||
pipeline_desc.VS.BytecodeLength = sizeof(immediate_vs);
|
||||
pipeline_desc.PS.pShaderBytecode = immediate_ps;
|
||||
pipeline_desc.PS.BytecodeLength = sizeof(immediate_ps);
|
||||
pipeline_desc.VS.pShaderBytecode = shaders::immediate_vs;
|
||||
pipeline_desc.VS.BytecodeLength = sizeof(shaders::immediate_vs);
|
||||
pipeline_desc.PS.pShaderBytecode = shaders::immediate_ps;
|
||||
pipeline_desc.PS.BytecodeLength = sizeof(shaders::immediate_ps);
|
||||
D3D12_RENDER_TARGET_BLEND_DESC& pipeline_blend_desc =
|
||||
pipeline_desc.BlendState.RenderTarget[0];
|
||||
pipeline_blend_desc.BlendEnable = TRUE;
|
||||
|
||||
@@ -89,6 +89,9 @@ D3D12Provider::~D3D12Provider() {
|
||||
if (library_d3dcompiler_ != nullptr) {
|
||||
FreeLibrary(library_d3dcompiler_);
|
||||
}
|
||||
if (library_dcomp_ != nullptr) {
|
||||
FreeLibrary(library_dcomp_);
|
||||
}
|
||||
if (library_d3d12_ != nullptr) {
|
||||
FreeLibrary(library_d3d12_);
|
||||
}
|
||||
@@ -120,8 +123,9 @@ bool D3D12Provider::Initialize() {
|
||||
// Load the core libraries.
|
||||
library_dxgi_ = LoadLibraryW(L"dxgi.dll");
|
||||
library_d3d12_ = LoadLibraryW(L"D3D12.dll");
|
||||
if (library_dxgi_ == nullptr || library_d3d12_ == nullptr) {
|
||||
XELOGE("Failed to load dxgi.dll or D3D12.dll");
|
||||
library_dcomp_ = LoadLibraryW(L"dcomp.dll");
|
||||
if (!library_dxgi_ || !library_d3d12_ || !library_dcomp_) {
|
||||
XELOGE("Failed to load dxgi.dll, D3D12.dll or dcomp.dll");
|
||||
return false;
|
||||
}
|
||||
bool libraries_loaded = true;
|
||||
@@ -142,8 +146,12 @@ bool D3D12Provider::Initialize() {
|
||||
(pfn_d3d12_serialize_root_signature_ = PFN_D3D12_SERIALIZE_ROOT_SIGNATURE(
|
||||
GetProcAddress(library_d3d12_, "D3D12SerializeRootSignature"))) !=
|
||||
nullptr;
|
||||
libraries_loaded &=
|
||||
(pfn_dcomposition_create_device_ = PFNDCompositionCreateDevice(
|
||||
GetProcAddress(library_dcomp_, "DCompositionCreateDevice"))) !=
|
||||
nullptr;
|
||||
if (!libraries_loaded) {
|
||||
XELOGE("Failed to get DXGI or Direct3D 12 functions");
|
||||
XELOGE("Failed to get DXGI, Direct3D 12 or DirectComposition functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,12 +162,12 @@ bool D3D12Provider::Initialize() {
|
||||
pfn_d3d_disassemble_ =
|
||||
pD3DDisassemble(GetProcAddress(library_d3dcompiler_, "D3DDisassemble"));
|
||||
if (pfn_d3d_disassemble_ == nullptr) {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to get D3DDisassemble from D3DCompiler_47.dll, DXBC "
|
||||
"disassembly for debugging will be unavailable");
|
||||
}
|
||||
} else {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to load D3DCompiler_47.dll, DXBC disassembly for debugging "
|
||||
"will be unavailable");
|
||||
}
|
||||
@@ -171,12 +179,12 @@ bool D3D12Provider::Initialize() {
|
||||
pfn_dxilconv_dxc_create_instance_ = DxcCreateInstanceProc(
|
||||
GetProcAddress(library_dxilconv_, "DxcCreateInstance"));
|
||||
if (pfn_dxilconv_dxc_create_instance_ == nullptr) {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to get DxcCreateInstance from dxilconv.dll, converted DXIL "
|
||||
"disassembly for debugging will be unavailable");
|
||||
}
|
||||
} else {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to load dxilconv.dll, converted DXIL disassembly for debugging "
|
||||
"will be unavailable - DXIL may be unsupported by your OS version");
|
||||
}
|
||||
@@ -188,12 +196,12 @@ bool D3D12Provider::Initialize() {
|
||||
pfn_dxcompiler_dxc_create_instance_ = DxcCreateInstanceProc(
|
||||
GetProcAddress(library_dxcompiler_, "DxcCreateInstance"));
|
||||
if (pfn_dxcompiler_dxc_create_instance_ == nullptr) {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to get DxcCreateInstance from dxcompiler.dll, converted DXIL "
|
||||
"disassembly for debugging will be unavailable");
|
||||
}
|
||||
} else {
|
||||
XELOGW(
|
||||
XELOGD(
|
||||
"Failed to load dxcompiler.dll, converted DXIL disassembly for "
|
||||
"debugging will be unavailable - if needed, download the DirectX "
|
||||
"Shader Compiler from "
|
||||
@@ -359,7 +367,7 @@ bool D3D12Provider::Initialize() {
|
||||
if (cvars::d3d12_queue_priority >= 2) {
|
||||
queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME;
|
||||
if (!EnableIncreaseBasePriorityPrivilege()) {
|
||||
XELOGD3D(
|
||||
XELOGW(
|
||||
"Failed to enable SeIncreaseBasePriorityPrivilege for global "
|
||||
"realtime Direct3D 12 command queue priority, falling back to high "
|
||||
"priority, try launching Xenia as administrator");
|
||||
@@ -377,7 +385,7 @@ bool D3D12Provider::Initialize() {
|
||||
IID_PPV_ARGS(&direct_queue)))) {
|
||||
bool queue_created = false;
|
||||
if (queue_desc.Priority == D3D12_COMMAND_QUEUE_PRIORITY_GLOBAL_REALTIME) {
|
||||
XELOGD3D(
|
||||
XELOGW(
|
||||
"Failed to create a Direct3D 12 direct command queue with global "
|
||||
"realtime priority, falling back to high priority, try launching "
|
||||
"Xenia as administrator");
|
||||
|
||||
@@ -110,7 +110,7 @@ class D3D12Provider : public GraphicsProvider {
|
||||
return virtual_address_bits_per_resource_;
|
||||
}
|
||||
|
||||
// Proxies for Direct3D 12 functions since they are loaded dynamically.
|
||||
// Proxies for DirectX functions since they are loaded dynamically.
|
||||
HRESULT SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc,
|
||||
D3D_ROOT_SIGNATURE_VERSION version,
|
||||
ID3DBlob** blob_out,
|
||||
@@ -118,6 +118,11 @@ class D3D12Provider : public GraphicsProvider {
|
||||
return pfn_d3d12_serialize_root_signature_(desc, version, blob_out,
|
||||
error_blob_out);
|
||||
}
|
||||
HRESULT CreateDCompositionDevice(IDXGIDevice* dxgi_device, const IID& iid,
|
||||
void** dcomposition_device_out) const {
|
||||
return pfn_dcomposition_create_device_(dxgi_device, iid,
|
||||
dcomposition_device_out);
|
||||
}
|
||||
HRESULT Disassemble(const void* src_data, size_t src_data_size, UINT flags,
|
||||
const char* comments, ID3DBlob** disassembly_out) const {
|
||||
if (!pfn_d3d_disassemble_) {
|
||||
@@ -151,6 +156,9 @@ class D3D12Provider : public GraphicsProvider {
|
||||
_COM_Outptr_ void** ppFactory);
|
||||
typedef HRESULT(WINAPI* PFNDXGIGetDebugInterface1)(
|
||||
UINT Flags, REFIID riid, _COM_Outptr_ void** pDebug);
|
||||
typedef HRESULT(WINAPI* PFNDCompositionCreateDevice)(
|
||||
_In_opt_ IDXGIDevice* dxgiDevice, _In_ REFIID iid,
|
||||
_Outptr_ void** dcompositionDevice);
|
||||
|
||||
HMODULE library_dxgi_ = nullptr;
|
||||
PFNCreateDXGIFactory2 pfn_create_dxgi_factory2_;
|
||||
@@ -161,6 +169,9 @@ class D3D12Provider : public GraphicsProvider {
|
||||
PFN_D3D12_CREATE_DEVICE pfn_d3d12_create_device_;
|
||||
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfn_d3d12_serialize_root_signature_;
|
||||
|
||||
HMODULE library_dcomp_ = nullptr;
|
||||
PFNDCompositionCreateDevice pfn_dcomposition_create_device_;
|
||||
|
||||
HMODULE library_d3dcompiler_ = nullptr;
|
||||
pD3DDisassemble pfn_d3d_disassemble_ = nullptr;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ project("xenia-ui-d3d12")
|
||||
})
|
||||
local_platform_files()
|
||||
files({
|
||||
"shaders/bin/*.h",
|
||||
"../shaders/bytecode/d3d12_5_1/*.h",
|
||||
})
|
||||
|
||||
group("demos")
|
||||
|
||||
Binary file not shown.
@@ -1,68 +0,0 @@
|
||||
// generated from `xb buildhlsl`
|
||||
// source: immediate.ps.hlsl
|
||||
const uint8_t immediate_ps[] = {
|
||||
0x44, 0x58, 0x42, 0x43, 0xDA, 0xC8, 0x6C, 0xC4, 0x3A, 0x1C, 0x46, 0xE2,
|
||||
0x62, 0x89, 0x59, 0xC7, 0xDA, 0x3A, 0x9B, 0xAC, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||
0x1C, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x9C, 0x01, 0x00, 0x00,
|
||||
0x64, 0x02, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0xE0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0xFF, 0xFF, 0x00, 0x05, 0x00, 0x00,
|
||||
0xB6, 0x00, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x8C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69,
|
||||
0x6D, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5F, 0x73, 0x61, 0x6D,
|
||||
0x70, 0x6C, 0x65, 0x72, 0x00, 0x78, 0x65, 0x5F, 0x69, 0x6D, 0x6D, 0x65,
|
||||
0x64, 0x69, 0x61, 0x74, 0x65, 0x5F, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72,
|
||||
0x65, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20,
|
||||
0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53, 0x68, 0x61,
|
||||
0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C, 0x65, 0x72,
|
||||
0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0xAB, 0xAB, 0x49, 0x53, 0x47, 0x4E,
|
||||
0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00,
|
||||
0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
|
||||
0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0xAB, 0xAB, 0xAB,
|
||||
0x4F, 0x53, 0x47, 0x4E, 0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5F, 0x54, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x00, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x51, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x6A, 0x08, 0x00, 0x01,
|
||||
0x5A, 0x00, 0x00, 0x06, 0x46, 0x6E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x18, 0x00, 0x07, 0x46, 0x7E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
|
||||
0x48, 0x00, 0x00, 0x0D, 0xF2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x46, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x7E, 0x20, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0xF2, 0x20, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x46, 0x0E, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x46, 0x1E, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01,
|
||||
0x53, 0x54, 0x41, 0x54, 0x94, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
|
||||
//
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim ID HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
// xe_immediate_sampler sampler NA NA S0 s0 1
|
||||
// xe_immediate_texture texture float4 2d T0 t0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
// Input signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// TEXCOORD 0 xy 0 NONE float xy
|
||||
// TEXCOORD 1 xyzw 1 NONE float xyzw
|
||||
//
|
||||
//
|
||||
// Output signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// SV_Target 0 xyzw 0 TARGET float xyzw
|
||||
//
|
||||
ps_5_1
|
||||
dcl_globalFlags refactoringAllowed
|
||||
dcl_sampler S0[0:0], mode_default, space=0
|
||||
dcl_resource_texture2d (float,float,float,float) T0[0:0], space=0
|
||||
dcl_input_ps linear v0.xy
|
||||
dcl_input_ps linear v1.xyzw
|
||||
dcl_output o0.xyzw
|
||||
dcl_temps 1
|
||||
sample_l r0.xyzw, v0.xyxx, T0[0].xyzw, S0[0], l(0.000000)
|
||||
mul o0.xyzw, r0.xyzw, v1.xyzw
|
||||
ret
|
||||
// Approximately 3 instruction slots used
|
||||
Binary file not shown.
@@ -1,91 +0,0 @@
|
||||
// generated from `xb buildhlsl`
|
||||
// source: immediate.vs.hlsl
|
||||
const uint8_t immediate_vs[] = {
|
||||
0x44, 0x58, 0x42, 0x43, 0x72, 0x14, 0x64, 0xA2, 0xD5, 0x3D, 0x4B, 0x94,
|
||||
0xC5, 0xDD, 0x32, 0xBA, 0xB5, 0xC9, 0x90, 0x20, 0x01, 0x00, 0x00, 0x00,
|
||||
0x10, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
||||
0x64, 0x01, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00,
|
||||
0x74, 0x03, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x28, 0x01, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x3C, 0x00, 0x00, 0x00, 0x01, 0x05, 0xFE, 0xFF, 0x00, 0x05, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x13, 0x13, 0x44, 0x25, 0x3C, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x58, 0x65, 0x49, 0x6D, 0x6D, 0x65, 0x64, 0x69,
|
||||
0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6F, 0x6E,
|
||||
0x73, 0x74, 0x61, 0x6E, 0x74, 0x73, 0x00, 0xAB, 0x64, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x78, 0x65, 0x5F, 0x76, 0x69, 0x65, 0x77, 0x70, 0x6F, 0x72, 0x74, 0x5F,
|
||||
0x73, 0x69, 0x7A, 0x65, 0x5F, 0x69, 0x6E, 0x76, 0x00, 0x66, 0x6C, 0x6F,
|
||||
0x61, 0x74, 0x32, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xD5, 0x00, 0x00, 0x00, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
|
||||
0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4C, 0x53, 0x4C, 0x20, 0x53,
|
||||
0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x69, 0x6C,
|
||||
0x65, 0x72, 0x20, 0x31, 0x30, 0x2E, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4E,
|
||||
0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00,
|
||||
0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00,
|
||||
0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
|
||||
0x50, 0x4F, 0x53, 0x49, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x54, 0x45, 0x58,
|
||||
0x43, 0x4F, 0x4F, 0x52, 0x44, 0x00, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00,
|
||||
0x4F, 0x53, 0x47, 0x4E, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x03, 0x0C, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4F, 0x4F, 0x52, 0x44,
|
||||
0x00, 0x53, 0x56, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E,
|
||||
0x00, 0xAB, 0xAB, 0xAB, 0x53, 0x48, 0x45, 0x58, 0x28, 0x01, 0x00, 0x00,
|
||||
0x51, 0x00, 0x01, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x6A, 0x08, 0x00, 0x01,
|
||||
0x59, 0x00, 0x00, 0x07, 0x46, 0x8E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x03, 0xF2, 0x10, 0x10, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xF2, 0x20, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xF2, 0x20, 0x10, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02,
|
||||
0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x09, 0x32, 0x00, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x46, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0F, 0x32, 0x20, 0x10, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xF2, 0x20, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x46, 0x1E, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x36, 0x00, 0x00, 0x08, 0xC2, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x36, 0x00, 0x00, 0x05,
|
||||
0x32, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54,
|
||||
0x94, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
|
||||
//
|
||||
//
|
||||
// Buffer Definitions:
|
||||
//
|
||||
// cbuffer XeImmediateVertexConstants
|
||||
// {
|
||||
//
|
||||
// float2 xe_viewport_size_inv; // Offset: 0 Size: 8
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim ID HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
// XeImmediateVertexConstants cbuffer NA NA CB0 cb0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
// Input signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// POSITION 0 xy 0 NONE float xy
|
||||
// TEXCOORD 0 xy 1 NONE float xy
|
||||
// COLOR 0 xyzw 2 NONE float xyzw
|
||||
//
|
||||
//
|
||||
// Output signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// TEXCOORD 0 xy 0 NONE float xy
|
||||
// TEXCOORD 1 xyzw 1 NONE float xyzw
|
||||
// SV_Position 0 xyzw 2 POS float xyzw
|
||||
//
|
||||
vs_5_1
|
||||
dcl_globalFlags refactoringAllowed
|
||||
dcl_constantbuffer CB0[0:0][1], immediateIndexed, space=0
|
||||
dcl_input v0.xy
|
||||
dcl_input v1.xy
|
||||
dcl_input v2.xyzw
|
||||
dcl_output o0.xy
|
||||
dcl_output o1.xyzw
|
||||
dcl_output_siv o2.xyzw, position
|
||||
dcl_temps 1
|
||||
mul r0.xy, v0.xyxx, CB0[0][0].xyxx
|
||||
mad o2.xy, r0.xyxx, l(2.000000, -2.000000, 0.000000, 0.000000), l(-1.000000, 1.000000, 0.000000, 0.000000)
|
||||
mov o1.xyzw, v2.xyzw
|
||||
mov o2.zw, l(0,0,0,1.000000)
|
||||
mov o0.xy, v1.xyxx
|
||||
ret
|
||||
// Approximately 6 instruction slots used
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "third_party/imgui/imgui.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -107,23 +108,23 @@ void ImGuiDrawer::Initialize() {
|
||||
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f);
|
||||
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
||||
|
||||
io.KeyMap[ImGuiKey_Tab] = 0x09; // VK_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = 0x25;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = 0x27;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = 0x26;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = 0x28;
|
||||
io.KeyMap[ImGuiKey_Home] = 0x24;
|
||||
io.KeyMap[ImGuiKey_End] = 0x23;
|
||||
io.KeyMap[ImGuiKey_Delete] = 0x2E;
|
||||
io.KeyMap[ImGuiKey_Backspace] = 0x08;
|
||||
io.KeyMap[ImGuiKey_Enter] = 0x0D;
|
||||
io.KeyMap[ImGuiKey_Escape] = 0x1B;
|
||||
io.KeyMap[ImGuiKey_A] = 'A';
|
||||
io.KeyMap[ImGuiKey_C] = 'C';
|
||||
io.KeyMap[ImGuiKey_V] = 'V';
|
||||
io.KeyMap[ImGuiKey_X] = 'X';
|
||||
io.KeyMap[ImGuiKey_Y] = 'Y';
|
||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||
io.KeyMap[ImGuiKey_Tab] = int(ui::VirtualKey::kTab);
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = int(ui::VirtualKey::kLeft);
|
||||
io.KeyMap[ImGuiKey_RightArrow] = int(ui::VirtualKey::kRight);
|
||||
io.KeyMap[ImGuiKey_UpArrow] = int(ui::VirtualKey::kUp);
|
||||
io.KeyMap[ImGuiKey_DownArrow] = int(ui::VirtualKey::kDown);
|
||||
io.KeyMap[ImGuiKey_Home] = int(ui::VirtualKey::kHome);
|
||||
io.KeyMap[ImGuiKey_End] = int(ui::VirtualKey::kEnd);
|
||||
io.KeyMap[ImGuiKey_Delete] = int(ui::VirtualKey::kDelete);
|
||||
io.KeyMap[ImGuiKey_Backspace] = int(ui::VirtualKey::kBack);
|
||||
io.KeyMap[ImGuiKey_Enter] = int(ui::VirtualKey::kReturn);
|
||||
io.KeyMap[ImGuiKey_Escape] = int(ui::VirtualKey::kEscape);
|
||||
io.KeyMap[ImGuiKey_A] = int(ui::VirtualKey::kA);
|
||||
io.KeyMap[ImGuiKey_C] = int(ui::VirtualKey::kC);
|
||||
io.KeyMap[ImGuiKey_V] = int(ui::VirtualKey::kV);
|
||||
io.KeyMap[ImGuiKey_X] = int(ui::VirtualKey::kX);
|
||||
io.KeyMap[ImGuiKey_Y] = int(ui::VirtualKey::kY);
|
||||
io.KeyMap[ImGuiKey_Z] = int(ui::VirtualKey::kZ);
|
||||
}
|
||||
|
||||
void ImGuiDrawer::SetupFont() {
|
||||
@@ -228,36 +229,16 @@ void ImGuiDrawer::RenderDrawLists() {
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiDrawer::OnKeyDown(KeyEvent* e) {
|
||||
auto& io = GetIO();
|
||||
io.KeysDown[e->key_code()] = true;
|
||||
switch (e->key_code()) {
|
||||
case 16: {
|
||||
io.KeyShift = true;
|
||||
} break;
|
||||
case 17: {
|
||||
io.KeyCtrl = true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
void ImGuiDrawer::OnKeyDown(KeyEvent* e) { OnKey(e, true); }
|
||||
|
||||
void ImGuiDrawer::OnKeyUp(KeyEvent* e) {
|
||||
auto& io = GetIO();
|
||||
io.KeysDown[e->key_code()] = false;
|
||||
switch (e->key_code()) {
|
||||
case 16: {
|
||||
io.KeyShift = false;
|
||||
} break;
|
||||
case 17: {
|
||||
io.KeyCtrl = false;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
void ImGuiDrawer::OnKeyUp(KeyEvent* e) { OnKey(e, false); }
|
||||
|
||||
void ImGuiDrawer::OnKeyChar(KeyEvent* e) {
|
||||
auto& io = GetIO();
|
||||
if (e->key_code() > 0 && e->key_code() < 0x10000) {
|
||||
io.AddInputCharacter(e->key_code());
|
||||
// TODO(Triang3l): Accept the Unicode character.
|
||||
unsigned int character = static_cast<unsigned int>(e->virtual_key());
|
||||
if (character > 0 && character < 0x10000) {
|
||||
io.AddInputCharacter(character);
|
||||
e->set_handled(true);
|
||||
}
|
||||
}
|
||||
@@ -327,5 +308,30 @@ void ImGuiDrawer::OnMouseWheel(MouseEvent* e) {
|
||||
io.MouseWheel += float(e->dy() / 120.0f);
|
||||
}
|
||||
|
||||
void ImGuiDrawer::OnKey(KeyEvent* e, bool is_down) {
|
||||
auto& io = GetIO();
|
||||
VirtualKey virtual_key = e->virtual_key();
|
||||
if (size_t(virtual_key) < xe::countof(io.KeysDown)) {
|
||||
io.KeysDown[size_t(virtual_key)] = is_down;
|
||||
}
|
||||
switch (virtual_key) {
|
||||
case VirtualKey::kShift:
|
||||
io.KeyShift = is_down;
|
||||
break;
|
||||
case VirtualKey::kControl:
|
||||
io.KeyCtrl = is_down;
|
||||
break;
|
||||
case VirtualKey::kMenu:
|
||||
// FIXME(Triang3l): Doesn't work in xenia-ui-window-demo.
|
||||
io.KeyAlt = is_down;
|
||||
break;
|
||||
case VirtualKey::kLWin:
|
||||
io.KeySuper = is_down;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
@@ -57,6 +57,9 @@ class ImGuiDrawer : public WindowListener {
|
||||
|
||||
ImGuiContext* internal_state_ = nullptr;
|
||||
std::unique_ptr<ImmediateTexture> font_texture_;
|
||||
|
||||
private:
|
||||
void OnKey(KeyEvent* e, bool is_down);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
1
src/xenia/ui/shaders/bytecode/.clang-format
generated
Normal file
1
src/xenia/ui/shaders/bytecode/.clang-format
generated
Normal file
@@ -0,0 +1 @@
|
||||
DisableFormat: true
|
||||
173
src/xenia/ui/shaders/bytecode/d3d12_5_1/immediate_ps.h
generated
Normal file
173
src/xenia/ui/shaders/bytecode/d3d12_5_1/immediate_ps.h
generated
Normal file
@@ -0,0 +1,173 @@
|
||||
#if 0
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
|
||||
//
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim ID HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
// xe_immediate_sampler sampler NA NA S0 s0 1
|
||||
// xe_immediate_texture texture float4 2d T0 t0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
// Input signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// TEXCOORD 0 xy 0 NONE float xy
|
||||
// TEXCOORD 1 xyzw 1 NONE float xyzw
|
||||
//
|
||||
//
|
||||
// Output signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// SV_Target 0 xyzw 0 TARGET float xyzw
|
||||
//
|
||||
ps_5_1
|
||||
dcl_globalFlags refactoringAllowed
|
||||
dcl_sampler S0[0:0], mode_default, space=0
|
||||
dcl_resource_texture2d (float,float,float,float) T0[0:0], space=0
|
||||
dcl_input_ps linear v0.xy
|
||||
dcl_input_ps linear v1.xyzw
|
||||
dcl_output o0.xyzw
|
||||
dcl_temps 1
|
||||
sample_l r0.xyzw, v0.xyxx, T0[0].xyzw, S0[0], l(0.000000)
|
||||
mul o0.xyzw, r0.xyzw, v1.xyzw
|
||||
ret
|
||||
// Approximately 3 instruction slots used
|
||||
#endif
|
||||
|
||||
const BYTE immediate_ps[] =
|
||||
{
|
||||
68, 88, 66, 67, 204, 46,
|
||||
131, 39, 62, 129, 239, 95,
|
||||
188, 170, 211, 224, 226, 155,
|
||||
212, 68, 1, 0, 0, 0,
|
||||
0, 3, 0, 0, 5, 0,
|
||||
0, 0, 52, 0, 0, 0,
|
||||
28, 1, 0, 0, 104, 1,
|
||||
0, 0, 156, 1, 0, 0,
|
||||
100, 2, 0, 0, 82, 68,
|
||||
69, 70, 224, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 2, 0, 0, 0,
|
||||
60, 0, 0, 0, 1, 5,
|
||||
255, 255, 0, 5, 4, 0,
|
||||
182, 0, 0, 0, 19, 19,
|
||||
68, 37, 60, 0, 0, 0,
|
||||
24, 0, 0, 0, 40, 0,
|
||||
0, 0, 40, 0, 0, 0,
|
||||
36, 0, 0, 0, 12, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
140, 0, 0, 0, 3, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 161, 0,
|
||||
0, 0, 2, 0, 0, 0,
|
||||
5, 0, 0, 0, 4, 0,
|
||||
0, 0, 255, 255, 255, 255,
|
||||
0, 0, 0, 0, 1, 0,
|
||||
0, 0, 12, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 120, 101, 95, 105,
|
||||
109, 109, 101, 100, 105, 97,
|
||||
116, 101, 95, 115, 97, 109,
|
||||
112, 108, 101, 114, 0, 120,
|
||||
101, 95, 105, 109, 109, 101,
|
||||
100, 105, 97, 116, 101, 95,
|
||||
116, 101, 120, 116, 117, 114,
|
||||
101, 0, 77, 105, 99, 114,
|
||||
111, 115, 111, 102, 116, 32,
|
||||
40, 82, 41, 32, 72, 76,
|
||||
83, 76, 32, 83, 104, 97,
|
||||
100, 101, 114, 32, 67, 111,
|
||||
109, 112, 105, 108, 101, 114,
|
||||
32, 49, 48, 46, 49, 0,
|
||||
171, 171, 73, 83, 71, 78,
|
||||
68, 0, 0, 0, 2, 0,
|
||||
0, 0, 8, 0, 0, 0,
|
||||
56, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 0, 0,
|
||||
0, 0, 3, 3, 0, 0,
|
||||
56, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 1, 0,
|
||||
0, 0, 15, 15, 0, 0,
|
||||
84, 69, 88, 67, 79, 79,
|
||||
82, 68, 0, 171, 171, 171,
|
||||
79, 83, 71, 78, 44, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
8, 0, 0, 0, 32, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
15, 0, 0, 0, 83, 86,
|
||||
95, 84, 97, 114, 103, 101,
|
||||
116, 0, 171, 171, 83, 72,
|
||||
69, 88, 192, 0, 0, 0,
|
||||
81, 0, 0, 0, 48, 0,
|
||||
0, 0, 106, 8, 0, 1,
|
||||
90, 0, 0, 6, 70, 110,
|
||||
48, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
88, 24, 0, 7, 70, 126,
|
||||
48, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 85, 85, 0, 0,
|
||||
0, 0, 0, 0, 98, 16,
|
||||
0, 3, 50, 16, 16, 0,
|
||||
0, 0, 0, 0, 98, 16,
|
||||
0, 3, 242, 16, 16, 0,
|
||||
1, 0, 0, 0, 101, 0,
|
||||
0, 3, 242, 32, 16, 0,
|
||||
0, 0, 0, 0, 104, 0,
|
||||
0, 2, 1, 0, 0, 0,
|
||||
72, 0, 0, 13, 242, 0,
|
||||
16, 0, 0, 0, 0, 0,
|
||||
70, 16, 16, 0, 0, 0,
|
||||
0, 0, 70, 126, 32, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 96, 32, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 64, 0, 0,
|
||||
0, 0, 0, 0, 56, 0,
|
||||
0, 7, 242, 32, 16, 0,
|
||||
0, 0, 0, 0, 70, 14,
|
||||
16, 0, 0, 0, 0, 0,
|
||||
70, 30, 16, 0, 1, 0,
|
||||
0, 0, 62, 0, 0, 1,
|
||||
83, 84, 65, 84, 148, 0,
|
||||
0, 0, 3, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
0, 0, 3, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0
|
||||
};
|
||||
236
src/xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h
generated
Normal file
236
src/xenia/ui/shaders/bytecode/d3d12_5_1/immediate_vs.h
generated
Normal file
@@ -0,0 +1,236 @@
|
||||
#if 0
|
||||
//
|
||||
// Generated by Microsoft (R) HLSL Shader Compiler 10.1
|
||||
//
|
||||
//
|
||||
// Buffer Definitions:
|
||||
//
|
||||
// cbuffer XeImmediateVertexConstants
|
||||
// {
|
||||
//
|
||||
// float2 xe_viewport_size_inv; // Offset: 0 Size: 8
|
||||
//
|
||||
// }
|
||||
//
|
||||
//
|
||||
// Resource Bindings:
|
||||
//
|
||||
// Name Type Format Dim ID HLSL Bind Count
|
||||
// ------------------------------ ---------- ------- ----------- ------- -------------- ------
|
||||
// XeImmediateVertexConstants cbuffer NA NA CB0 cb0 1
|
||||
//
|
||||
//
|
||||
//
|
||||
// Input signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// POSITION 0 xy 0 NONE float xy
|
||||
// TEXCOORD 0 xy 1 NONE float xy
|
||||
// COLOR 0 xyzw 2 NONE float xyzw
|
||||
//
|
||||
//
|
||||
// Output signature:
|
||||
//
|
||||
// Name Index Mask Register SysValue Format Used
|
||||
// -------------------- ----- ------ -------- -------- ------- ------
|
||||
// TEXCOORD 0 xy 0 NONE float xy
|
||||
// TEXCOORD 1 xyzw 1 NONE float xyzw
|
||||
// SV_Position 0 xyzw 2 POS float xyzw
|
||||
//
|
||||
vs_5_1
|
||||
dcl_globalFlags refactoringAllowed
|
||||
dcl_constantbuffer CB0[0:0][1], immediateIndexed, space=0
|
||||
dcl_input v0.xy
|
||||
dcl_input v1.xy
|
||||
dcl_input v2.xyzw
|
||||
dcl_output o0.xy
|
||||
dcl_output o1.xyzw
|
||||
dcl_output_siv o2.xyzw, position
|
||||
dcl_temps 1
|
||||
mul r0.xy, v0.xyxx, CB0[0][0].xyxx
|
||||
mad o2.xy, r0.xyxx, l(2.000000, -2.000000, 0.000000, 0.000000), l(-1.000000, 1.000000, 0.000000, 0.000000)
|
||||
mov o1.xyzw, v2.xyzw
|
||||
mov o2.zw, l(0,0,0,1.000000)
|
||||
mov o0.xy, v1.xyxx
|
||||
ret
|
||||
// Approximately 6 instruction slots used
|
||||
#endif
|
||||
|
||||
const BYTE immediate_vs[] =
|
||||
{
|
||||
68, 88, 66, 67, 88, 56,
|
||||
35, 17, 155, 211, 230, 48,
|
||||
9, 16, 27, 220, 163, 42,
|
||||
194, 218, 1, 0, 0, 0,
|
||||
16, 4, 0, 0, 5, 0,
|
||||
0, 0, 52, 0, 0, 0,
|
||||
100, 1, 0, 0, 212, 1,
|
||||
0, 0, 68, 2, 0, 0,
|
||||
116, 3, 0, 0, 82, 68,
|
||||
69, 70, 40, 1, 0, 0,
|
||||
1, 0, 0, 0, 128, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
60, 0, 0, 0, 1, 5,
|
||||
254, 255, 0, 5, 4, 0,
|
||||
0, 1, 0, 0, 19, 19,
|
||||
68, 37, 60, 0, 0, 0,
|
||||
24, 0, 0, 0, 40, 0,
|
||||
0, 0, 40, 0, 0, 0,
|
||||
36, 0, 0, 0, 12, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
100, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 88, 101,
|
||||
73, 109, 109, 101, 100, 105,
|
||||
97, 116, 101, 86, 101, 114,
|
||||
116, 101, 120, 67, 111, 110,
|
||||
115, 116, 97, 110, 116, 115,
|
||||
0, 171, 100, 0, 0, 0,
|
||||
1, 0, 0, 0, 152, 0,
|
||||
0, 0, 16, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 192, 0, 0, 0,
|
||||
0, 0, 0, 0, 8, 0,
|
||||
0, 0, 2, 0, 0, 0,
|
||||
220, 0, 0, 0, 0, 0,
|
||||
0, 0, 255, 255, 255, 255,
|
||||
0, 0, 0, 0, 255, 255,
|
||||
255, 255, 0, 0, 0, 0,
|
||||
120, 101, 95, 118, 105, 101,
|
||||
119, 112, 111, 114, 116, 95,
|
||||
115, 105, 122, 101, 95, 105,
|
||||
110, 118, 0, 102, 108, 111,
|
||||
97, 116, 50, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
213, 0, 0, 0, 77, 105,
|
||||
99, 114, 111, 115, 111, 102,
|
||||
116, 32, 40, 82, 41, 32,
|
||||
72, 76, 83, 76, 32, 83,
|
||||
104, 97, 100, 101, 114, 32,
|
||||
67, 111, 109, 112, 105, 108,
|
||||
101, 114, 32, 49, 48, 46,
|
||||
49, 0, 73, 83, 71, 78,
|
||||
104, 0, 0, 0, 3, 0,
|
||||
0, 0, 8, 0, 0, 0,
|
||||
80, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 0, 0,
|
||||
0, 0, 3, 3, 0, 0,
|
||||
89, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 1, 0,
|
||||
0, 0, 3, 3, 0, 0,
|
||||
98, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 0, 0, 0, 2, 0,
|
||||
0, 0, 15, 15, 0, 0,
|
||||
80, 79, 83, 73, 84, 73,
|
||||
79, 78, 0, 84, 69, 88,
|
||||
67, 79, 79, 82, 68, 0,
|
||||
67, 79, 76, 79, 82, 0,
|
||||
79, 83, 71, 78, 104, 0,
|
||||
0, 0, 3, 0, 0, 0,
|
||||
8, 0, 0, 0, 80, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
3, 12, 0, 0, 80, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 3, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
15, 0, 0, 0, 89, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 3, 0,
|
||||
0, 0, 2, 0, 0, 0,
|
||||
15, 0, 0, 0, 84, 69,
|
||||
88, 67, 79, 79, 82, 68,
|
||||
0, 83, 86, 95, 80, 111,
|
||||
115, 105, 116, 105, 111, 110,
|
||||
0, 171, 171, 171, 83, 72,
|
||||
69, 88, 40, 1, 0, 0,
|
||||
81, 0, 1, 0, 74, 0,
|
||||
0, 0, 106, 8, 0, 1,
|
||||
89, 0, 0, 7, 70, 142,
|
||||
48, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 95, 0,
|
||||
0, 3, 50, 16, 16, 0,
|
||||
0, 0, 0, 0, 95, 0,
|
||||
0, 3, 50, 16, 16, 0,
|
||||
1, 0, 0, 0, 95, 0,
|
||||
0, 3, 242, 16, 16, 0,
|
||||
2, 0, 0, 0, 101, 0,
|
||||
0, 3, 50, 32, 16, 0,
|
||||
0, 0, 0, 0, 101, 0,
|
||||
0, 3, 242, 32, 16, 0,
|
||||
1, 0, 0, 0, 103, 0,
|
||||
0, 4, 242, 32, 16, 0,
|
||||
2, 0, 0, 0, 1, 0,
|
||||
0, 0, 104, 0, 0, 2,
|
||||
1, 0, 0, 0, 56, 0,
|
||||
0, 9, 50, 0, 16, 0,
|
||||
0, 0, 0, 0, 70, 16,
|
||||
16, 0, 0, 0, 0, 0,
|
||||
70, 128, 48, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 50, 0,
|
||||
0, 15, 50, 32, 16, 0,
|
||||
2, 0, 0, 0, 70, 0,
|
||||
16, 0, 0, 0, 0, 0,
|
||||
2, 64, 0, 0, 0, 0,
|
||||
0, 64, 0, 0, 0, 192,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 2, 64, 0, 0,
|
||||
0, 0, 128, 191, 0, 0,
|
||||
128, 63, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 54, 0,
|
||||
0, 5, 242, 32, 16, 0,
|
||||
1, 0, 0, 0, 70, 30,
|
||||
16, 0, 2, 0, 0, 0,
|
||||
54, 0, 0, 8, 194, 32,
|
||||
16, 0, 2, 0, 0, 0,
|
||||
2, 64, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
128, 63, 54, 0, 0, 5,
|
||||
50, 32, 16, 0, 0, 0,
|
||||
0, 0, 70, 16, 16, 0,
|
||||
1, 0, 0, 0, 62, 0,
|
||||
0, 1, 83, 84, 65, 84,
|
||||
148, 0, 0, 0, 6, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 6, 0,
|
||||
0, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0
|
||||
};
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
@@ -42,11 +44,12 @@ class FileDropEvent : public UIEvent {
|
||||
|
||||
class KeyEvent : public UIEvent {
|
||||
public:
|
||||
KeyEvent(Window* target, int key_code, int repeat_count, bool prev_state,
|
||||
bool modifier_shift_pressed, bool modifier_ctrl_pressed,
|
||||
bool modifier_alt_pressed, bool modifier_super_pressed)
|
||||
KeyEvent(Window* target, VirtualKey virtual_key, int repeat_count,
|
||||
bool prev_state, bool modifier_shift_pressed,
|
||||
bool modifier_ctrl_pressed, bool modifier_alt_pressed,
|
||||
bool modifier_super_pressed)
|
||||
: UIEvent(target),
|
||||
key_code_(key_code),
|
||||
virtual_key_(virtual_key),
|
||||
repeat_count_(repeat_count),
|
||||
prev_state_(prev_state),
|
||||
modifier_shift_pressed_(modifier_shift_pressed),
|
||||
@@ -58,7 +61,7 @@ class KeyEvent : public UIEvent {
|
||||
bool is_handled() const { return handled_; }
|
||||
void set_handled(bool value) { handled_ = value; }
|
||||
|
||||
int key_code() const { return key_code_; }
|
||||
VirtualKey virtual_key() const { return virtual_key_; }
|
||||
|
||||
int repeat_count() const { return repeat_count_; }
|
||||
bool prev_state() const { return prev_state_; }
|
||||
@@ -70,7 +73,7 @@ class KeyEvent : public UIEvent {
|
||||
|
||||
private:
|
||||
bool handled_ = false;
|
||||
int key_code_ = 0;
|
||||
VirtualKey virtual_key_ = VirtualKey::kNone;
|
||||
|
||||
int repeat_count_ = 0;
|
||||
bool prev_state_ = false; // Key previously down(true) or up(false)
|
||||
|
||||
362
src/xenia/ui/virtual_key.h
Normal file
362
src/xenia/ui/virtual_key.h
Normal file
@@ -0,0 +1,362 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2021 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_VIRTUAL_KEY_H_
|
||||
#define XENIA_UI_VIRTUAL_KEY_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
// Windows and Xbox 360 / XInput virtual key enumeration.
|
||||
// This is what platform-specific keys should be translated to, for both HID
|
||||
// keystroke emulation and Xenia-internal UI events. On Windows, the translation
|
||||
// is a simple cast.
|
||||
// This is uint16_t as it's WPARAM (which was 16-bit back in Win16 days, where
|
||||
// virtual key codes were added), and XINPUT_KEYSTROKE stores the virtual key as
|
||||
// a WORD. In some cases (see kPacket), bits above 16 may be used as well, but
|
||||
// VK_ on Windows are defined up to 0xFF (0xFE not counting the reserved 0xFF)
|
||||
// as of Windows SDK 10.0.19041.0, and XInput virtual key codes are 16-bit.
|
||||
// Base virtual key codes as of _WIN32_WINNT 0x0500 (Windows 2000, which the
|
||||
// Xbox 360's kernel is based on), virtual key codes added later are marked
|
||||
// explicitly as such.
|
||||
enum class VirtualKey : uint16_t {
|
||||
// Not a valid key - MapVirtualKey returns zero when there is no translation.
|
||||
kNone,
|
||||
|
||||
kLButton = 0x01,
|
||||
kRButton = 0x02,
|
||||
kCancel = 0x03, // Control-break.
|
||||
kMButton = 0x04, // Not contiguous with kLButton and kRButton.
|
||||
|
||||
kXButton1 = 0x05, // Not contiguous with kLButton and kRButton.
|
||||
kXButton2 = 0x06, // Not contiguous with kLButton and kRButton.
|
||||
|
||||
kBack = 0x08, // Backspace.
|
||||
kTab = 0x09,
|
||||
|
||||
kClear = 0x0C,
|
||||
kReturn = 0x0D, // Enter.
|
||||
|
||||
kShift = 0x10,
|
||||
kControl = 0x11, // Ctrl.
|
||||
kMenu = 0x12, // Alt.
|
||||
kPause = 0x13,
|
||||
kCapital = 0x14, // Caps Lock.
|
||||
|
||||
kKana = 0x15,
|
||||
kHangeul = 0x15, // Old name.
|
||||
kHangul = 0x15,
|
||||
kImeOn = 0x16,
|
||||
kJunja = 0x17,
|
||||
kFinal = 0x18,
|
||||
kHanja = 0x19,
|
||||
kKanji = 0x19,
|
||||
kImeOff = 0x1A,
|
||||
|
||||
kEscape = 0x1B,
|
||||
|
||||
kConvert = 0x1C,
|
||||
kNonConvert = 0x1D,
|
||||
kAccept = 0x1E,
|
||||
kModeChange = 0x1F,
|
||||
|
||||
kSpace = 0x20,
|
||||
kPrior = 0x21, // Page Up.
|
||||
kNext = 0x22, // Page Down.
|
||||
kEnd = 0x23,
|
||||
kHome = 0x24,
|
||||
kLeft = 0x25,
|
||||
kUp = 0x26,
|
||||
kRight = 0x27,
|
||||
kDown = 0x28,
|
||||
kSelect = 0x29,
|
||||
kPrint = 0x2A,
|
||||
kExecute = 0x2B,
|
||||
kSnapshot = 0x2C,
|
||||
kInsert = 0x2D,
|
||||
kDelete = 0x2E,
|
||||
kHelp = 0x2F,
|
||||
|
||||
// Same as ASCII '0' - '9'.
|
||||
k0 = 0x30,
|
||||
k1 = 0x31,
|
||||
k2 = 0x32,
|
||||
k3 = 0x33,
|
||||
k4 = 0x34,
|
||||
k5 = 0x35,
|
||||
k6 = 0x36,
|
||||
k7 = 0x37,
|
||||
k8 = 0x38,
|
||||
k9 = 0x39,
|
||||
|
||||
// Same as ASCII 'A' - 'Z'.
|
||||
kA = 0x41,
|
||||
kB = 0x42,
|
||||
kC = 0x43,
|
||||
kD = 0x44,
|
||||
kE = 0x45,
|
||||
kF = 0x46,
|
||||
kG = 0x47,
|
||||
kH = 0x48,
|
||||
kI = 0x49,
|
||||
kJ = 0x4A,
|
||||
kK = 0x4B,
|
||||
kL = 0x4C,
|
||||
kM = 0x4D,
|
||||
kN = 0x4E,
|
||||
kO = 0x4F,
|
||||
kP = 0x50,
|
||||
kQ = 0x51,
|
||||
kR = 0x52,
|
||||
kS = 0x53,
|
||||
kT = 0x54,
|
||||
kU = 0x55,
|
||||
kV = 0x56,
|
||||
kW = 0x57,
|
||||
kX = 0x58,
|
||||
kY = 0x59,
|
||||
kZ = 0x5A,
|
||||
|
||||
kLWin = 0x5B,
|
||||
kRWin = 0x5C,
|
||||
kApps = 0x5D,
|
||||
|
||||
kSleep = 0x5F,
|
||||
|
||||
kNumpad0 = 0x60,
|
||||
kNumpad1 = 0x61,
|
||||
kNumpad2 = 0x62,
|
||||
kNumpad3 = 0x63,
|
||||
kNumpad4 = 0x64,
|
||||
kNumpad5 = 0x65,
|
||||
kNumpad6 = 0x66,
|
||||
kNumpad7 = 0x67,
|
||||
kNumpad8 = 0x68,
|
||||
kNumpad9 = 0x69,
|
||||
kMultiply = 0x6A,
|
||||
kAdd = 0x6B,
|
||||
kSeparator = 0x6C,
|
||||
kSubtract = 0x6D,
|
||||
kDecimal = 0x6E,
|
||||
kDivide = 0x6F,
|
||||
kF1 = 0x70,
|
||||
kF2 = 0x71,
|
||||
kF3 = 0x72,
|
||||
kF4 = 0x73,
|
||||
kF5 = 0x74,
|
||||
kF6 = 0x75,
|
||||
kF7 = 0x76,
|
||||
kF8 = 0x77,
|
||||
kF9 = 0x78,
|
||||
kF10 = 0x79,
|
||||
kF11 = 0x7A,
|
||||
kF12 = 0x7B,
|
||||
kF13 = 0x7C,
|
||||
kF14 = 0x7D,
|
||||
kF15 = 0x7E,
|
||||
kF16 = 0x7F,
|
||||
kF17 = 0x80,
|
||||
kF18 = 0x81,
|
||||
kF19 = 0x82,
|
||||
kF20 = 0x83,
|
||||
kF21 = 0x84,
|
||||
kF22 = 0x85,
|
||||
kF23 = 0x86,
|
||||
kF24 = 0x87,
|
||||
|
||||
// VK_NAVIGATION_* added in _WIN32_WINNT 0x0604, but marked as reserved in
|
||||
// WinUser.h and not documented on MSDN.
|
||||
kNavigationView = 0x88,
|
||||
kNavigationMenu = 0x89,
|
||||
kNavigationUp = 0x8A,
|
||||
kNavigationDown = 0x8B,
|
||||
kNavigationLeft = 0x8C,
|
||||
kNavigationRight = 0x8D,
|
||||
kNavigationAccept = 0x8E,
|
||||
kNavigationCancel = 0x8F,
|
||||
|
||||
kNumLock = 0x90,
|
||||
kScroll = 0x91,
|
||||
|
||||
// NEC PC-9800 keyboard.
|
||||
kOemNecEqual = 0x92, // '=' key on the numpad.
|
||||
|
||||
// Fujitsu/OASYS keyboard.
|
||||
kOemFjJisho = 0x92, // 'Dictionary' key.
|
||||
kOemFjMasshou = 0x93, // 'Unregister word' key.
|
||||
kOemFjTouroku = 0x94, // 'Register word' key.
|
||||
kOemFjLOya = 0x95, // 'Left OYAYUBI' key.
|
||||
kOemFjROya = 0x96, // 'Right OYAYUBI' key.
|
||||
|
||||
// Left and right Alt, Ctrl and Shift virtual keys.
|
||||
// On Windows (from WinUser.h):
|
||||
// "Used only as parameters to GetAsyncKeyState() and GetKeyState().
|
||||
// No other API or message will distinguish left and right keys in this way."
|
||||
kLShift = 0xA0,
|
||||
kRShift = 0xA1,
|
||||
kLControl = 0xA2,
|
||||
kRControl = 0xA3,
|
||||
kLMenu = 0xA4,
|
||||
kRMenu = 0xA5,
|
||||
|
||||
kBrowserBack = 0xA6,
|
||||
kBrowserForward = 0xA7,
|
||||
kBrowserRefresh = 0xA8,
|
||||
kBrowserStop = 0xA9,
|
||||
kBrowserSearch = 0xAA,
|
||||
kBrowserFavorites = 0xAB,
|
||||
kBrowserHome = 0xAC,
|
||||
|
||||
kVolumeMute = 0xAD,
|
||||
kVolumeDown = 0xAE,
|
||||
kVolumeUp = 0xAF,
|
||||
kMediaNextTrack = 0xB0,
|
||||
kMediaPrevTrack = 0xB1,
|
||||
kMediaStop = 0xB2,
|
||||
kMediaPlayPause = 0xB3,
|
||||
kLaunchMail = 0xB4,
|
||||
kLaunchMediaSelect = 0xB5,
|
||||
kLaunchApp1 = 0xB6,
|
||||
kLaunchApp2 = 0xB7,
|
||||
|
||||
kOem1 = 0xBA, // ';:' for the US.
|
||||
kOemPlus = 0xBB, // '+' for any country.
|
||||
kOemComma = 0xBC, // ',' for any country.
|
||||
kOemMinus = 0xBD, // '-' for any country.
|
||||
kOemPeriod = 0xBE, // '.' for any country.
|
||||
kOem2 = 0xBF, // '/?' for the US.
|
||||
kOem3 = 0xC0, // '`~' for the US.
|
||||
|
||||
// VK_GAMEPAD_* (since _WIN32_WINNT 0x0604) virtual key codes are marked as
|
||||
// reserved in WinUser.h and are mostly not documented on MSDN (with the
|
||||
// exception of the Xbox Device Portal Remote Input REST API in the "UWP on
|
||||
// Xbox One" section).
|
||||
// Xenia uses VK_PAD_* (kXInputPad*) for HID emulation internally instead
|
||||
// because XInput is the API used for the Xbox 360 controller.
|
||||
// To avoid confusion between VK_GAMEPAD_* and VK_PAD_*, here they are
|
||||
// prefixed with kXboxOne and kXInput respectively.
|
||||
kXboxOneGamepadA = 0xC3,
|
||||
kXboxOneGamepadB = 0xC4,
|
||||
kXboxOneGamepadX = 0xC5,
|
||||
kXboxOneGamepadY = 0xC6,
|
||||
kXboxOneGamepadRightShoulder = 0xC7,
|
||||
kXboxOneGamepadLeftShoulder = 0xC8,
|
||||
kXboxOneGamepadLeftTrigger = 0xC9,
|
||||
kXboxOneGamepadRightTrigger = 0xCA,
|
||||
kXboxOneGamepadDpadUp = 0xCB,
|
||||
kXboxOneGamepadDpadDown = 0xCC,
|
||||
kXboxOneGamepadDpadLeft = 0xCD,
|
||||
kXboxOneGamepadDpadRight = 0xCE,
|
||||
kXboxOneGamepadMenu = 0xCF,
|
||||
kXboxOneGamepadView = 0xD0,
|
||||
kXboxOneGamepadLeftThumbstickButton = 0xD1,
|
||||
kXboxOneGamepadRightThumbstickButton = 0xD2,
|
||||
kXboxOneGamepadLeftThumbstickUp = 0xD3,
|
||||
kXboxOneGamepadLeftThumbstickDown = 0xD4,
|
||||
kXboxOneGamepadLeftThumbstickRight = 0xD5,
|
||||
kXboxOneGamepadLeftThumbstickLeft = 0xD6,
|
||||
kXboxOneGamepadRightThumbstickUp = 0xD7,
|
||||
kXboxOneGamepadRightThumbstickDown = 0xD8,
|
||||
kXboxOneGamepadRightThumbstickRight = 0xD9,
|
||||
kXboxOneGamepadRightThumbstickLeft = 0xDA,
|
||||
|
||||
kOem4 = 0xDB, // '[{' for the US.
|
||||
kOem5 = 0xDC, // '\|' for the US.
|
||||
kOem6 = 0xDD, // ']}' for the US.
|
||||
kOem7 = 0xDE, // ''"' for the US.
|
||||
kOem8 = 0xDF,
|
||||
|
||||
kOemAx = 0xE1, // 'AX' key on the Japanese AX keyboard.
|
||||
kOem102 = 0xE2, // "<>" or "\|" on the RT 102-key keyboard.
|
||||
kIcoHelp = 0xE3, // Help key on the Olivetti keyboard (ICO).
|
||||
kIco00 = 0xE4, // 00 key on the ICO.
|
||||
|
||||
kProcessKey = 0xE5,
|
||||
|
||||
kIcoClear = 0xE6,
|
||||
|
||||
// From MSDN:
|
||||
// "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET
|
||||
// key is the low word of a 32-bit Virtual Key value used for non-keyboard
|
||||
// input methods."
|
||||
kPacket = 0xE7,
|
||||
|
||||
// Nokia/Ericsson.
|
||||
kOemReset = 0xE9,
|
||||
kOemJump = 0xEA,
|
||||
kOemPa1 = 0xEB,
|
||||
kOemPa2 = 0xEC,
|
||||
kOemPa3 = 0xED,
|
||||
kOemWsCtrl = 0xEE,
|
||||
kOemCuSel = 0xEF,
|
||||
kOemAttn = 0xF0,
|
||||
kOemFinish = 0xF1,
|
||||
kOemCopy = 0xF2,
|
||||
kOemAuto = 0xF3,
|
||||
kOemEnlW = 0xF4,
|
||||
kOemBackTab = 0xF5,
|
||||
|
||||
kAttn = 0xF6,
|
||||
kCrSel = 0xF7,
|
||||
kExSel = 0xF8,
|
||||
kErEof = 0xF9,
|
||||
kPlay = 0xFA,
|
||||
kZoom = 0xFB,
|
||||
kNoName = 0xFC,
|
||||
kPa1 = 0xFD,
|
||||
kOemClear = 0xFE,
|
||||
|
||||
// VK_PAD_* from XInput.h for XInputGetKeystroke. kXInput prefix added to
|
||||
// distinguish from VK_GAMEPAD_*, added much later for the Xbox One
|
||||
// controller.
|
||||
|
||||
kXInputPadA = 0x5800,
|
||||
kXInputPadB = 0x5801,
|
||||
kXInputPadX = 0x5802,
|
||||
kXInputPadY = 0x5803,
|
||||
// RShoulder before LShoulder, not a typo.
|
||||
kXInputPadRShoulder = 0x5804,
|
||||
kXInputPadLShoulder = 0x5805,
|
||||
kXInputPadLTrigger = 0x5806,
|
||||
kXInputPadRTrigger = 0x5807,
|
||||
|
||||
kXInputPadDpadUp = 0x5810,
|
||||
kXInputPadDpadDown = 0x5811,
|
||||
kXInputPadDpadLeft = 0x5812,
|
||||
kXInputPadDpadRight = 0x5813,
|
||||
kXInputPadStart = 0x5814,
|
||||
kXInputPadBack = 0x5815,
|
||||
kXInputPadLThumbPress = 0x5816,
|
||||
kXInputPadRThumbPress = 0x5817,
|
||||
|
||||
kXInputPadLThumbUp = 0x5820,
|
||||
kXInputPadLThumbDown = 0x5821,
|
||||
kXInputPadLThumbRight = 0x5822,
|
||||
kXInputPadLThumbLeft = 0x5823,
|
||||
kXInputPadLThumbUpLeft = 0x5824,
|
||||
kXInputPadLThumbUpRight = 0x5825,
|
||||
kXInputPadLThumbDownRight = 0x5826,
|
||||
kXInputPadLThumbDownLeft = 0x5827,
|
||||
|
||||
kXInputPadRThumbUp = 0x5830,
|
||||
kXInputPadRThumbDown = 0x5831,
|
||||
kXInputPadRThumbRight = 0x5832,
|
||||
kXInputPadRThumbLeft = 0x5833,
|
||||
kXInputPadRThumbUpLeft = 0x5834,
|
||||
kXInputPadRThumbUpRight = 0x5835,
|
||||
kXInputPadRThumbDownRight = 0x5836,
|
||||
kXInputPadRThumbDownLeft = 0x5837,
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_VIRTUAL_KEY_H_
|
||||
@@ -26,6 +26,7 @@ Blitter::~Blitter() { Shutdown(); }
|
||||
VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
device_ = device;
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
// Shaders
|
||||
@@ -34,8 +35,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
shader_create_info.codeSize = sizeof(blit_vert);
|
||||
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_vert);
|
||||
status = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_vertex_);
|
||||
status = dfn.vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_vertex_);
|
||||
CheckResult(status, "vkCreateShaderModule");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -46,8 +47,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
|
||||
shader_create_info.codeSize = sizeof(blit_color_frag);
|
||||
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_color_frag);
|
||||
status = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_color_);
|
||||
status = dfn.vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_color_);
|
||||
CheckResult(status, "vkCreateShaderModule");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -58,8 +59,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
|
||||
shader_create_info.codeSize = sizeof(blit_depth_frag);
|
||||
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_depth_frag);
|
||||
status = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_depth_);
|
||||
status = dfn.vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||
&blit_depth_);
|
||||
CheckResult(status, "vkCreateShaderModule");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -83,8 +84,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
texture_binding.pImmutableSamplers = nullptr;
|
||||
texture_set_layout_info.pBindings = &texture_binding;
|
||||
status = vkCreateDescriptorSetLayout(*device_, &texture_set_layout_info,
|
||||
nullptr, &descriptor_set_layout_);
|
||||
status = dfn.vkCreateDescriptorSetLayout(*device_, &texture_set_layout_info,
|
||||
nullptr, &descriptor_set_layout_);
|
||||
CheckResult(status, "vkCreateDescriptorSetLayout");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -119,8 +120,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
pipeline_layout_info.pushConstantRangeCount =
|
||||
static_cast<uint32_t>(xe::countof(push_constant_ranges));
|
||||
pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
|
||||
status = vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr,
|
||||
&pipeline_layout_);
|
||||
status = dfn.vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr,
|
||||
&pipeline_layout_);
|
||||
CheckResult(status, "vkCreatePipelineLayout");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -147,8 +148,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
|
||||
VK_FALSE,
|
||||
};
|
||||
status =
|
||||
vkCreateSampler(*device_, &sampler_create_info, nullptr, &samp_nearest_);
|
||||
status = dfn.vkCreateSampler(*device_, &sampler_create_info, nullptr,
|
||||
&samp_nearest_);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -157,8 +158,8 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
sampler_create_info.minFilter = VK_FILTER_LINEAR;
|
||||
sampler_create_info.magFilter = VK_FILTER_LINEAR;
|
||||
sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
status =
|
||||
vkCreateSampler(*device_, &sampler_create_info, nullptr, &samp_linear_);
|
||||
status = dfn.vkCreateSampler(*device_, &sampler_create_info, nullptr,
|
||||
&samp_linear_);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -168,49 +169,50 @@ VkResult Blitter::Initialize(VulkanDevice* device) {
|
||||
}
|
||||
|
||||
void Blitter::Shutdown() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
if (samp_nearest_) {
|
||||
vkDestroySampler(*device_, samp_nearest_, nullptr);
|
||||
dfn.vkDestroySampler(*device_, samp_nearest_, nullptr);
|
||||
samp_nearest_ = nullptr;
|
||||
}
|
||||
if (samp_linear_) {
|
||||
vkDestroySampler(*device_, samp_linear_, nullptr);
|
||||
dfn.vkDestroySampler(*device_, samp_linear_, nullptr);
|
||||
samp_linear_ = nullptr;
|
||||
}
|
||||
if (blit_vertex_) {
|
||||
vkDestroyShaderModule(*device_, blit_vertex_, nullptr);
|
||||
dfn.vkDestroyShaderModule(*device_, blit_vertex_, nullptr);
|
||||
blit_vertex_ = nullptr;
|
||||
}
|
||||
if (blit_color_) {
|
||||
vkDestroyShaderModule(*device_, blit_color_, nullptr);
|
||||
dfn.vkDestroyShaderModule(*device_, blit_color_, nullptr);
|
||||
blit_color_ = nullptr;
|
||||
}
|
||||
if (blit_depth_) {
|
||||
vkDestroyShaderModule(*device_, blit_depth_, nullptr);
|
||||
dfn.vkDestroyShaderModule(*device_, blit_depth_, nullptr);
|
||||
blit_depth_ = nullptr;
|
||||
}
|
||||
if (pipeline_color_) {
|
||||
vkDestroyPipeline(*device_, pipeline_color_, nullptr);
|
||||
dfn.vkDestroyPipeline(*device_, pipeline_color_, nullptr);
|
||||
pipeline_color_ = nullptr;
|
||||
}
|
||||
if (pipeline_depth_) {
|
||||
vkDestroyPipeline(*device_, pipeline_depth_, nullptr);
|
||||
dfn.vkDestroyPipeline(*device_, pipeline_depth_, nullptr);
|
||||
pipeline_depth_ = nullptr;
|
||||
}
|
||||
if (pipeline_layout_) {
|
||||
vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr);
|
||||
dfn.vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr);
|
||||
pipeline_layout_ = nullptr;
|
||||
}
|
||||
if (descriptor_set_layout_) {
|
||||
vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr);
|
||||
dfn.vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr);
|
||||
descriptor_set_layout_ = nullptr;
|
||||
}
|
||||
for (auto& pipeline : pipelines_) {
|
||||
vkDestroyPipeline(*device_, pipeline.second, nullptr);
|
||||
dfn.vkDestroyPipeline(*device_, pipeline.second, nullptr);
|
||||
}
|
||||
pipelines_.clear();
|
||||
|
||||
for (auto& pass : render_passes_) {
|
||||
vkDestroyRenderPass(*device_, pass.second, nullptr);
|
||||
dfn.vkDestroyRenderPass(*device_, pass.second, nullptr);
|
||||
}
|
||||
render_passes_.clear();
|
||||
}
|
||||
@@ -230,6 +232,8 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence,
|
||||
VkFramebuffer dst_framebuffer, VkViewport viewport,
|
||||
VkRect2D scissor, VkFilter filter,
|
||||
bool color_or_depth, bool swap_channels) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
// Do we need a full draw, or can we cheap out with a blit command?
|
||||
bool full_draw = swap_channels || true;
|
||||
if (full_draw) {
|
||||
@@ -249,18 +253,18 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
vkCmdBeginRenderPass(command_buffer, &render_pass_info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
dfn.vkCmdBeginRenderPass(command_buffer, &render_pass_info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
dfn.vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||
dfn.vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
|
||||
// Acquire a pipeline.
|
||||
auto pipeline =
|
||||
GetPipeline(render_pass, color_or_depth ? blit_color_ : blit_depth_,
|
||||
color_or_depth);
|
||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline);
|
||||
dfn.vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline);
|
||||
|
||||
// Acquire and update a descriptor set for this image.
|
||||
auto set = descriptor_pool_->AcquireEntry(descriptor_set_layout_);
|
||||
@@ -287,10 +291,10 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence,
|
||||
write.pImageInfo = ℑ
|
||||
write.pBufferInfo = nullptr;
|
||||
write.pTexelBufferView = nullptr;
|
||||
vkUpdateDescriptorSets(*device_, 1, &write, 0, nullptr);
|
||||
dfn.vkUpdateDescriptorSets(*device_, 1, &write, 0, nullptr);
|
||||
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline_layout_, 0, 1, &set, 0, nullptr);
|
||||
dfn.vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline_layout_, 0, 1, &set, 0, nullptr);
|
||||
|
||||
VtxPushConstants vtx_constants = {
|
||||
{
|
||||
@@ -306,9 +310,9 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence,
|
||||
float(dst_rect.extent.height) / dst_extents.height,
|
||||
},
|
||||
};
|
||||
vkCmdPushConstants(command_buffer, pipeline_layout_,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(VtxPushConstants),
|
||||
&vtx_constants);
|
||||
dfn.vkCmdPushConstants(command_buffer, pipeline_layout_,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0,
|
||||
sizeof(VtxPushConstants), &vtx_constants);
|
||||
|
||||
PixPushConstants pix_constants = {
|
||||
0,
|
||||
@@ -316,12 +320,12 @@ void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkFence fence,
|
||||
0,
|
||||
swap_channels ? 1 : 0,
|
||||
};
|
||||
vkCmdPushConstants(command_buffer, pipeline_layout_,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(VtxPushConstants),
|
||||
sizeof(PixPushConstants), &pix_constants);
|
||||
dfn.vkCmdPushConstants(
|
||||
command_buffer, pipeline_layout_, VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
sizeof(VtxPushConstants), sizeof(PixPushConstants), &pix_constants);
|
||||
|
||||
vkCmdDraw(command_buffer, 4, 1, 0, 0);
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
dfn.vkCmdDraw(command_buffer, 4, 1, 0, 0);
|
||||
dfn.vkCmdEndRenderPass(command_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,8 +425,9 @@ VkRenderPass Blitter::CreateRenderPass(VkFormat output_format,
|
||||
nullptr,
|
||||
};
|
||||
VkRenderPass renderpass = nullptr;
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult result =
|
||||
vkCreateRenderPass(*device_, &renderpass_info, nullptr, &renderpass);
|
||||
dfn.vkCreateRenderPass(*device_, &renderpass_info, nullptr, &renderpass);
|
||||
CheckResult(result, "vkCreateRenderPass");
|
||||
|
||||
return renderpass;
|
||||
@@ -431,6 +436,7 @@ VkRenderPass Blitter::CreateRenderPass(VkFormat output_format,
|
||||
VkPipeline Blitter::CreatePipeline(VkRenderPass render_pass,
|
||||
VkShaderModule frag_shader,
|
||||
bool color_or_depth) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
// Pipeline
|
||||
@@ -576,8 +582,8 @@ VkPipeline Blitter::CreatePipeline(VkRenderPass render_pass,
|
||||
pipeline_info.basePipelineIndex = -1;
|
||||
|
||||
VkPipeline pipeline = nullptr;
|
||||
result = vkCreateGraphicsPipelines(*device_, nullptr, 1, &pipeline_info,
|
||||
nullptr, &pipeline);
|
||||
result = dfn.vkCreateGraphicsPipelines(*device_, nullptr, 1, &pipeline_info,
|
||||
nullptr, &pipeline);
|
||||
CheckResult(result, "vkCreateGraphicsPipelines");
|
||||
|
||||
return pipeline;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace vulkan {
|
||||
CircularBuffer::CircularBuffer(VulkanDevice* device, VkBufferUsageFlags usage,
|
||||
VkDeviceSize capacity, VkDeviceSize alignment)
|
||||
: device_(device), capacity_(capacity) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
// Create our internal buffer.
|
||||
@@ -34,14 +35,14 @@ CircularBuffer::CircularBuffer(VulkanDevice* device, VkBufferUsageFlags usage,
|
||||
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
buffer_info.queueFamilyIndexCount = 0;
|
||||
buffer_info.pQueueFamilyIndices = nullptr;
|
||||
status = vkCreateBuffer(*device_, &buffer_info, nullptr, &gpu_buffer_);
|
||||
status = dfn.vkCreateBuffer(*device_, &buffer_info, nullptr, &gpu_buffer_);
|
||||
CheckResult(status, "vkCreateBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
assert_always();
|
||||
}
|
||||
|
||||
VkMemoryRequirements reqs;
|
||||
vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
|
||||
dfn.vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
|
||||
alignment_ = xe::round_up(alignment, reqs.alignment);
|
||||
}
|
||||
CircularBuffer::~CircularBuffer() { Shutdown(); }
|
||||
@@ -52,10 +53,12 @@ VkResult CircularBuffer::Initialize(VkDeviceMemory memory,
|
||||
gpu_memory_ = memory;
|
||||
gpu_base_ = offset;
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
// Bind the buffer to its backing memory.
|
||||
status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
|
||||
status =
|
||||
dfn.vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
|
||||
CheckResult(status, "vkBindBufferMemory");
|
||||
if (status != VK_SUCCESS) {
|
||||
XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
|
||||
@@ -64,8 +67,8 @@ VkResult CircularBuffer::Initialize(VkDeviceMemory memory,
|
||||
}
|
||||
|
||||
// Map the memory so we can access it.
|
||||
status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
|
||||
reinterpret_cast<void**>(&host_base_));
|
||||
status = dfn.vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
|
||||
reinterpret_cast<void**>(&host_base_));
|
||||
CheckResult(status, "vkMapMemory");
|
||||
if (status != VK_SUCCESS) {
|
||||
XELOGE("CircularBuffer::Initialize - Failed to map memory!");
|
||||
@@ -77,10 +80,11 @@ VkResult CircularBuffer::Initialize(VkDeviceMemory memory,
|
||||
}
|
||||
|
||||
VkResult CircularBuffer::Initialize() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status = VK_SUCCESS;
|
||||
|
||||
VkMemoryRequirements reqs;
|
||||
vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
|
||||
dfn.vkGetBufferMemoryRequirements(*device_, gpu_buffer_, &reqs);
|
||||
|
||||
// Allocate memory from the device to back the buffer.
|
||||
owns_gpu_memory_ = true;
|
||||
@@ -95,7 +99,8 @@ VkResult CircularBuffer::Initialize() {
|
||||
gpu_base_ = 0;
|
||||
|
||||
// Bind the buffer to its backing memory.
|
||||
status = vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
|
||||
status =
|
||||
dfn.vkBindBufferMemory(*device_, gpu_buffer_, gpu_memory_, gpu_base_);
|
||||
CheckResult(status, "vkBindBufferMemory");
|
||||
if (status != VK_SUCCESS) {
|
||||
XELOGE("CircularBuffer::Initialize - Failed to bind memory!");
|
||||
@@ -104,8 +109,8 @@ VkResult CircularBuffer::Initialize() {
|
||||
}
|
||||
|
||||
// Map the memory so we can access it.
|
||||
status = vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
|
||||
reinterpret_cast<void**>(&host_base_));
|
||||
status = dfn.vkMapMemory(*device_, gpu_memory_, gpu_base_, capacity_, 0,
|
||||
reinterpret_cast<void**>(&host_base_));
|
||||
CheckResult(status, "vkMapMemory");
|
||||
if (status != VK_SUCCESS) {
|
||||
XELOGE("CircularBuffer::Initialize - Failed to map memory!");
|
||||
@@ -118,22 +123,24 @@ VkResult CircularBuffer::Initialize() {
|
||||
|
||||
void CircularBuffer::Shutdown() {
|
||||
Clear();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
if (host_base_) {
|
||||
vkUnmapMemory(*device_, gpu_memory_);
|
||||
dfn.vkUnmapMemory(*device_, gpu_memory_);
|
||||
host_base_ = nullptr;
|
||||
}
|
||||
if (gpu_buffer_) {
|
||||
vkDestroyBuffer(*device_, gpu_buffer_, nullptr);
|
||||
dfn.vkDestroyBuffer(*device_, gpu_buffer_, nullptr);
|
||||
gpu_buffer_ = nullptr;
|
||||
}
|
||||
if (gpu_memory_ && owns_gpu_memory_) {
|
||||
vkFreeMemory(*device_, gpu_memory_, nullptr);
|
||||
dfn.vkFreeMemory(*device_, gpu_memory_, nullptr);
|
||||
gpu_memory_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CircularBuffer::GetBufferMemoryRequirements(VkMemoryRequirements* reqs) {
|
||||
vkGetBufferMemoryRequirements(*device_, gpu_buffer_, reqs);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
dfn.vkGetBufferMemoryRequirements(*device_, gpu_buffer_, reqs);
|
||||
}
|
||||
|
||||
bool CircularBuffer::CanAcquire(VkDeviceSize length) {
|
||||
@@ -224,23 +231,25 @@ CircularBuffer::Allocation* CircularBuffer::Acquire(VkDeviceSize length,
|
||||
}
|
||||
|
||||
void CircularBuffer::Flush(Allocation* allocation) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkMappedMemoryRange range;
|
||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
range.pNext = nullptr;
|
||||
range.memory = gpu_memory_;
|
||||
range.offset = gpu_base_ + allocation->offset;
|
||||
range.size = allocation->length;
|
||||
vkFlushMappedMemoryRanges(*device_, 1, &range);
|
||||
dfn.vkFlushMappedMemoryRanges(*device_, 1, &range);
|
||||
}
|
||||
|
||||
void CircularBuffer::Flush(VkDeviceSize offset, VkDeviceSize length) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkMappedMemoryRange range;
|
||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
range.pNext = nullptr;
|
||||
range.memory = gpu_memory_;
|
||||
range.offset = gpu_base_ + offset;
|
||||
range.size = length;
|
||||
vkFlushMappedMemoryRanges(*device_, 1, &range);
|
||||
dfn.vkFlushMappedMemoryRanges(*device_, 1, &range);
|
||||
}
|
||||
|
||||
void CircularBuffer::Clear() {
|
||||
@@ -249,12 +258,14 @@ void CircularBuffer::Clear() {
|
||||
}
|
||||
|
||||
void CircularBuffer::Scavenge() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
// Stash the last signalled fence
|
||||
VkFence fence = nullptr;
|
||||
while (!allocations_.empty()) {
|
||||
Allocation& alloc = allocations_.front();
|
||||
if (fence != alloc.fence &&
|
||||
vkGetFenceStatus(*device_, alloc.fence) != VK_SUCCESS) {
|
||||
dfn.vkGetFenceStatus(*device_, alloc.fence) != VK_SUCCESS) {
|
||||
// Don't bother freeing following allocations to ensure proper ordering.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ namespace vulkan {
|
||||
|
||||
using xe::ui::vulkan::CheckResult;
|
||||
|
||||
CommandBufferPool::CommandBufferPool(VkDevice device,
|
||||
CommandBufferPool::CommandBufferPool(const VulkanDevice& device,
|
||||
uint32_t queue_family_index)
|
||||
: BaseFencedPool(device) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
|
||||
// Create the pool used for allocating buffers.
|
||||
// They are marked as transient (short-lived) and cycled frequently.
|
||||
VkCommandPoolCreateInfo cmd_pool_info;
|
||||
@@ -31,7 +33,7 @@ CommandBufferPool::CommandBufferPool(VkDevice device,
|
||||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
cmd_pool_info.queueFamilyIndex = queue_family_index;
|
||||
auto err =
|
||||
vkCreateCommandPool(device_, &cmd_pool_info, nullptr, &command_pool_);
|
||||
dfn.vkCreateCommandPool(device_, &cmd_pool_info, nullptr, &command_pool_);
|
||||
CheckResult(err, "vkCreateCommandPool");
|
||||
|
||||
// Allocate a bunch of command buffers to start.
|
||||
@@ -43,8 +45,8 @@ CommandBufferPool::CommandBufferPool(VkDevice device,
|
||||
command_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
command_buffer_info.commandBufferCount = kDefaultCount;
|
||||
VkCommandBuffer command_buffers[kDefaultCount];
|
||||
err =
|
||||
vkAllocateCommandBuffers(device_, &command_buffer_info, command_buffers);
|
||||
err = dfn.vkAllocateCommandBuffers(device_, &command_buffer_info,
|
||||
command_buffers);
|
||||
CheckResult(err, "vkCreateCommandBuffer");
|
||||
for (size_t i = 0; i < xe::countof(command_buffers); ++i) {
|
||||
PushEntry(command_buffers[i], nullptr);
|
||||
@@ -53,7 +55,8 @@ CommandBufferPool::CommandBufferPool(VkDevice device,
|
||||
|
||||
CommandBufferPool::~CommandBufferPool() {
|
||||
FreeAllEntries();
|
||||
vkDestroyCommandPool(device_, command_pool_, nullptr);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
dfn.vkDestroyCommandPool(device_, command_pool_, nullptr);
|
||||
command_pool_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -67,17 +70,19 @@ VkCommandBuffer CommandBufferPool::AllocateEntry(void* data) {
|
||||
VkCommandBufferLevel(reinterpret_cast<uintptr_t>(data));
|
||||
command_buffer_info.commandBufferCount = 1;
|
||||
VkCommandBuffer command_buffer;
|
||||
auto err =
|
||||
vkAllocateCommandBuffers(device_, &command_buffer_info, &command_buffer);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
auto err = dfn.vkAllocateCommandBuffers(device_, &command_buffer_info,
|
||||
&command_buffer);
|
||||
CheckResult(err, "vkCreateCommandBuffer");
|
||||
return command_buffer;
|
||||
}
|
||||
|
||||
void CommandBufferPool::FreeEntry(VkCommandBuffer handle) {
|
||||
vkFreeCommandBuffers(device_, command_pool_, 1, &handle);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
dfn.vkFreeCommandBuffers(device_, command_pool_, 1, &handle);
|
||||
}
|
||||
|
||||
DescriptorPool::DescriptorPool(VkDevice device, uint32_t max_count,
|
||||
DescriptorPool::DescriptorPool(const VulkanDevice& device, uint32_t max_count,
|
||||
std::vector<VkDescriptorPoolSize> pool_sizes)
|
||||
: BaseFencedPool(device) {
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_info;
|
||||
@@ -88,13 +93,15 @@ DescriptorPool::DescriptorPool(VkDevice device, uint32_t max_count,
|
||||
descriptor_pool_info.maxSets = max_count;
|
||||
descriptor_pool_info.poolSizeCount = uint32_t(pool_sizes.size());
|
||||
descriptor_pool_info.pPoolSizes = pool_sizes.data();
|
||||
auto err = vkCreateDescriptorPool(device, &descriptor_pool_info, nullptr,
|
||||
&descriptor_pool_);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
auto err = dfn.vkCreateDescriptorPool(device, &descriptor_pool_info, nullptr,
|
||||
&descriptor_pool_);
|
||||
CheckResult(err, "vkCreateDescriptorPool");
|
||||
}
|
||||
DescriptorPool::~DescriptorPool() {
|
||||
FreeAllEntries();
|
||||
vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
dfn.vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr);
|
||||
descriptor_pool_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -108,15 +115,17 @@ VkDescriptorSet DescriptorPool::AllocateEntry(void* data) {
|
||||
set_alloc_info.descriptorPool = descriptor_pool_;
|
||||
set_alloc_info.descriptorSetCount = 1;
|
||||
set_alloc_info.pSetLayouts = &layout;
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
auto err =
|
||||
vkAllocateDescriptorSets(device_, &set_alloc_info, &descriptor_set);
|
||||
dfn.vkAllocateDescriptorSets(device_, &set_alloc_info, &descriptor_set);
|
||||
CheckResult(err, "vkAllocateDescriptorSets");
|
||||
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
void DescriptorPool::FreeEntry(VkDescriptorSet handle) {
|
||||
vkFreeDescriptorSets(device_, descriptor_pool_, 1, &handle);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
dfn.vkFreeDescriptorSets(device_, descriptor_pool_, 1, &handle);
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/ui/vulkan/vulkan.h"
|
||||
#include "xenia/ui/vulkan/vulkan_device.h"
|
||||
#include "xenia/ui/vulkan/vulkan_util.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -28,7 +29,7 @@ namespace vulkan {
|
||||
template <typename T, typename HANDLE>
|
||||
class BaseFencedPool {
|
||||
public:
|
||||
BaseFencedPool(VkDevice device) : device_(device) {}
|
||||
BaseFencedPool(const VulkanDevice& device) : device_(device) {}
|
||||
|
||||
virtual ~BaseFencedPool() {
|
||||
// TODO(benvanik): wait on fence until done.
|
||||
@@ -47,11 +48,12 @@ class BaseFencedPool {
|
||||
// Checks all pending batches for completion and scavenges their entries.
|
||||
// This should be called as frequently as reasonable.
|
||||
void Scavenge() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
while (pending_batch_list_head_) {
|
||||
auto batch = pending_batch_list_head_;
|
||||
assert_not_null(batch->fence);
|
||||
|
||||
VkResult status = vkGetFenceStatus(device_, batch->fence);
|
||||
VkResult status = dfn.vkGetFenceStatus(device_, batch->fence);
|
||||
if (status == VK_SUCCESS || status == VK_ERROR_DEVICE_LOST) {
|
||||
// Batch has completed. Reclaim.
|
||||
pending_batch_list_head_ = batch->next;
|
||||
@@ -80,6 +82,7 @@ class BaseFencedPool {
|
||||
VkFence BeginBatch(VkFence fence = nullptr) {
|
||||
assert_null(open_batch_);
|
||||
Batch* batch = nullptr;
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
if (free_batch_list_head_) {
|
||||
// Reuse a batch.
|
||||
batch = free_batch_list_head_;
|
||||
@@ -88,10 +91,10 @@ class BaseFencedPool {
|
||||
|
||||
if (batch->flags & kBatchOwnsFence && !fence) {
|
||||
// Reset owned fence.
|
||||
vkResetFences(device_, 1, &batch->fence);
|
||||
dfn.vkResetFences(device_, 1, &batch->fence);
|
||||
} else if ((batch->flags & kBatchOwnsFence) && fence) {
|
||||
// Transfer owned -> external
|
||||
vkDestroyFence(device_, batch->fence, nullptr);
|
||||
dfn.vkDestroyFence(device_, batch->fence, nullptr);
|
||||
batch->fence = fence;
|
||||
batch->flags &= ~kBatchOwnsFence;
|
||||
} else if (!(batch->flags & kBatchOwnsFence) && !fence) {
|
||||
@@ -100,7 +103,8 @@ class BaseFencedPool {
|
||||
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
VkResult res = vkCreateFence(device_, &info, nullptr, &batch->fence);
|
||||
VkResult res =
|
||||
dfn.vkCreateFence(device_, &info, nullptr, &batch->fence);
|
||||
if (res != VK_SUCCESS) {
|
||||
assert_always();
|
||||
}
|
||||
@@ -121,7 +125,8 @@ class BaseFencedPool {
|
||||
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
VkResult res = vkCreateFence(device_, &info, nullptr, &batch->fence);
|
||||
VkResult res =
|
||||
dfn.vkCreateFence(device_, &info, nullptr, &batch->fence);
|
||||
if (res != VK_SUCCESS) {
|
||||
assert_always();
|
||||
}
|
||||
@@ -239,13 +244,14 @@ class BaseFencedPool {
|
||||
}
|
||||
|
||||
void FreeAllEntries() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
// Run down free lists.
|
||||
while (free_batch_list_head_) {
|
||||
auto batch = free_batch_list_head_;
|
||||
free_batch_list_head_ = batch->next;
|
||||
|
||||
if (batch->flags & kBatchOwnsFence) {
|
||||
vkDestroyFence(device_, batch->fence, nullptr);
|
||||
dfn.vkDestroyFence(device_, batch->fence, nullptr);
|
||||
batch->fence = nullptr;
|
||||
}
|
||||
delete batch;
|
||||
@@ -258,7 +264,7 @@ class BaseFencedPool {
|
||||
}
|
||||
}
|
||||
|
||||
VkDevice device_ = nullptr;
|
||||
const VulkanDevice& device_;
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
@@ -288,7 +294,7 @@ class CommandBufferPool
|
||||
public:
|
||||
typedef BaseFencedPool<CommandBufferPool, VkCommandBuffer> Base;
|
||||
|
||||
CommandBufferPool(VkDevice device, uint32_t queue_family_index);
|
||||
CommandBufferPool(const VulkanDevice& device, uint32_t queue_family_index);
|
||||
~CommandBufferPool() override;
|
||||
|
||||
VkCommandBuffer AcquireEntry(
|
||||
@@ -308,7 +314,7 @@ class DescriptorPool : public BaseFencedPool<DescriptorPool, VkDescriptorSet> {
|
||||
public:
|
||||
typedef BaseFencedPool<DescriptorPool, VkDescriptorSet> Base;
|
||||
|
||||
DescriptorPool(VkDevice device, uint32_t max_count,
|
||||
DescriptorPool(const VulkanDevice& device, uint32_t max_count,
|
||||
std::vector<VkDescriptorPoolSize> pool_sizes);
|
||||
~DescriptorPool() override;
|
||||
|
||||
|
||||
83
src/xenia/ui/vulkan/functions/device_1_0.inc
Normal file
83
src/xenia/ui/vulkan/functions/device_1_0.inc
Normal file
@@ -0,0 +1,83 @@
|
||||
// Vulkan 1.0 core device functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkAllocateCommandBuffers)
|
||||
XE_UI_VULKAN_FUNCTION(vkAllocateDescriptorSets)
|
||||
XE_UI_VULKAN_FUNCTION(vkAllocateMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkBeginCommandBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBeginRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindDescriptorSets)
|
||||
XE_UI_VULKAN_FUNCTION(vkBindBufferMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkBindImageMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindIndexBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindPipeline)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBindVertexBuffers)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdBlitImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdClearColorImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdClearDepthStencilImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyBufferToImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyImageToBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDraw)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDrawIndexed)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdEndRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdExecuteCommands)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdFillBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdPipelineBarrier)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdPushConstants)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdResolveImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetBlendConstants)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetDepthBias)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetDepthBounds)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetLineWidth)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetScissor)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetStencilCompareMask)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetStencilReference)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetStencilWriteMask)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetViewport)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateCommandPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDescriptorPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDescriptorSetLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateFence)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateFramebuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateGraphicsPipelines)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateImageView)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreatePipelineCache)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreatePipelineLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateSampler)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateSemaphore)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateShaderModule)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyCommandPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyDescriptorPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyDescriptorSetLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyFence)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyFramebuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyImageView)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipeline)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipelineCache)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyPipelineLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyRenderPass)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySampler)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySemaphore)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyShaderModule)
|
||||
XE_UI_VULKAN_FUNCTION(vkEndCommandBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkFlushMappedMemoryRanges)
|
||||
XE_UI_VULKAN_FUNCTION(vkFreeCommandBuffers)
|
||||
XE_UI_VULKAN_FUNCTION(vkFreeDescriptorSets)
|
||||
XE_UI_VULKAN_FUNCTION(vkFreeMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetDeviceQueue)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetBufferMemoryRequirements)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetFenceStatus)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetImageMemoryRequirements)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetImageSubresourceLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPipelineCacheData)
|
||||
XE_UI_VULKAN_FUNCTION(vkMapMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkQueueSubmit)
|
||||
XE_UI_VULKAN_FUNCTION(vkQueueWaitIdle)
|
||||
XE_UI_VULKAN_FUNCTION(vkResetCommandBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkResetFences)
|
||||
XE_UI_VULKAN_FUNCTION(vkUnmapMemory)
|
||||
XE_UI_VULKAN_FUNCTION(vkUpdateDescriptorSets)
|
||||
XE_UI_VULKAN_FUNCTION(vkWaitForFences)
|
||||
2
src/xenia/ui/vulkan/functions/device_amd_shader_info.inc
Normal file
2
src/xenia/ui/vulkan/functions/device_amd_shader_info.inc
Normal file
@@ -0,0 +1,2 @@
|
||||
// VK_AMD_shader_info functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkGetShaderInfoAMD)
|
||||
@@ -0,0 +1,5 @@
|
||||
// VK_EXT_debug_marker functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkDebugMarkerSetObjectNameEXT)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDebugMarkerBeginEXT)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDebugMarkerEndEXT)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDebugMarkerInsertEXT)
|
||||
6
src/xenia/ui/vulkan/functions/device_khr_swapchain.inc
Normal file
6
src/xenia/ui/vulkan/functions/device_khr_swapchain.inc
Normal file
@@ -0,0 +1,6 @@
|
||||
// VK_KHR_swapchain functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkAcquireNextImageKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateSwapchainKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySwapchainKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetSwapchainImagesKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkQueuePresentKHR)
|
||||
13
src/xenia/ui/vulkan/functions/instance_1_0.inc
Normal file
13
src/xenia/ui/vulkan/functions/instance_1_0.inc
Normal file
@@ -0,0 +1,13 @@
|
||||
// Vulkan 1.0 core instance functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDevice)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyDevice)
|
||||
XE_UI_VULKAN_FUNCTION(vkEnumerateDeviceExtensionProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkEnumerateDeviceLayerProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkEnumeratePhysicalDevices)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetDeviceProcAddr)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceFeatures)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceFormatProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceImageFormatProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)
|
||||
@@ -0,0 +1,3 @@
|
||||
// VK_EXT_debug_report functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDebugReportCallbackEXT)
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroyDebugReportCallbackEXT)
|
||||
@@ -0,0 +1,2 @@
|
||||
// VK_KHR_android_surface functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateAndroidSurfaceKHR)
|
||||
6
src/xenia/ui/vulkan/functions/instance_khr_surface.inc
Normal file
6
src/xenia/ui/vulkan/functions/instance_khr_surface.inc
Normal file
@@ -0,0 +1,6 @@
|
||||
// VK_KHR_surface functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkDestroySurfaceKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR)
|
||||
@@ -0,0 +1,2 @@
|
||||
// VK_KHR_win32_surface functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateWin32SurfaceKHR)
|
||||
@@ -0,0 +1,2 @@
|
||||
// VK_KHR_xcb_surface functions used in Xenia.
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateXcbSurfaceKHR)
|
||||
@@ -18,6 +18,7 @@ project("xenia-ui-vulkan")
|
||||
project_root.."/third_party/vulkan/",
|
||||
})
|
||||
local_platform_files()
|
||||
local_platform_files("functions")
|
||||
files({
|
||||
"shaders/bin/*.h",
|
||||
})
|
||||
@@ -31,7 +32,6 @@ project("xenia-ui-window-vulkan-demo")
|
||||
links({
|
||||
"fmt",
|
||||
"imgui",
|
||||
"volk",
|
||||
"xenia-base",
|
||||
"xenia-ui",
|
||||
"xenia-ui-spirv",
|
||||
|
||||
@@ -10,20 +10,30 @@
|
||||
#ifndef XENIA_UI_VULKAN_VULKAN_H_
|
||||
#define XENIA_UI_VULKAN_VULKAN_H_
|
||||
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/platform.h"
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
#elif XE_PLATFORM_LINUX
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#ifndef VK_USE_PLATFORM_ANDROID_KHR
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR 1
|
||||
#endif
|
||||
#elif XE_PLATFORM_GNU_LINUX
|
||||
#ifndef VK_USE_PLATFORM_XCB_KHR
|
||||
#define VK_USE_PLATFORM_XCB_KHR 1
|
||||
#else
|
||||
#error Platform not yet supported.
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
#endif
|
||||
#elif XE_PLATFORM_WIN32
|
||||
// Must be included before vulkan.h with VK_USE_PLATFORM_WIN32_KHR because it
|
||||
// includes Windows.h too.
|
||||
#include "xenia/base/platform_win.h"
|
||||
#ifndef VK_USE_PLATFORM_WIN32_KHR
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// We use a loader with its own function prototypes.
|
||||
#include "third_party/volk/volk.h"
|
||||
#ifndef VK_NO_PROTOTYPES
|
||||
#define VK_NO_PROTOTYPES 1
|
||||
#endif
|
||||
#include "third_party/vulkan/vulkan.h"
|
||||
#include "xenia/base/cvar.h"
|
||||
|
||||
#define XELOGVK XELOGI
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "xenia/ui/vulkan/vulkan_util.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
#if XE_PLATFORM_LINUX
|
||||
#if XE_PLATFORM_GNU_LINUX
|
||||
#include "xenia/ui/window_gtk.h"
|
||||
|
||||
#include <X11/Xlib-xcb.h>
|
||||
@@ -41,10 +41,11 @@ VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window)
|
||||
VulkanContext::~VulkanContext() {
|
||||
VkResult status;
|
||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||
auto device = provider->device();
|
||||
VulkanDevice* device = provider->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
{
|
||||
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||
status = vkQueueWaitIdle(device->primary_queue());
|
||||
status = dfn.vkQueueWaitIdle(device->primary_queue());
|
||||
}
|
||||
immediate_drawer_.reset();
|
||||
swap_chain_.reset();
|
||||
@@ -52,6 +53,8 @@ VulkanContext::~VulkanContext() {
|
||||
|
||||
bool VulkanContext::Initialize() {
|
||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||
VulkanInstance* instance = provider->instance();
|
||||
const VulkanInstance::InstanceFunctions& ifn = instance->ifn();
|
||||
|
||||
if (target_window_) {
|
||||
// Create swap chain used to present to the window.
|
||||
@@ -65,10 +68,10 @@ bool VulkanContext::Initialize() {
|
||||
create_info.hinstance =
|
||||
static_cast<HINSTANCE>(target_window_->native_platform_handle());
|
||||
create_info.hwnd = static_cast<HWND>(target_window_->native_handle());
|
||||
status = vkCreateWin32SurfaceKHR(*provider->instance(), &create_info,
|
||||
nullptr, &surface);
|
||||
status = ifn.vkCreateWin32SurfaceKHR(*provider->instance(), &create_info,
|
||||
nullptr, &surface);
|
||||
CheckResult(status, "vkCreateWin32SurfaceKHR");
|
||||
#elif XE_PLATFORM_LINUX
|
||||
#elif XE_PLATFORM_GNU_LINUX
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GtkWidget* window_handle =
|
||||
dynamic_cast<GTKWindow*>(target_window_)->native_window_handle();
|
||||
@@ -81,8 +84,8 @@ bool VulkanContext::Initialize() {
|
||||
create_info.connection = static_cast<xcb_connection_t*>(
|
||||
target_window_->native_platform_handle());
|
||||
create_info.window = static_cast<xcb_window_t>(window);
|
||||
status = vkCreateXcbSurfaceKHR(*provider->instance(), &create_info, nullptr,
|
||||
&surface);
|
||||
status = ifn.vkCreateXcbSurfaceKHR(*provider->instance(), &create_info,
|
||||
nullptr, &surface);
|
||||
CheckResult(status, "vkCreateXcbSurfaceKHR");
|
||||
#else
|
||||
#error Unsupported GDK Backend on Linux.
|
||||
@@ -95,8 +98,8 @@ bool VulkanContext::Initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap_chain_ = std::make_unique<VulkanSwapChain>(provider->instance(),
|
||||
provider->device());
|
||||
swap_chain_ =
|
||||
std::make_unique<VulkanSwapChain>(instance, provider->device());
|
||||
if (swap_chain_->Initialize(surface) != VK_SUCCESS) {
|
||||
XELOGE("Unable to initialize swap chain");
|
||||
return false;
|
||||
@@ -139,7 +142,8 @@ void VulkanContext::ClearCurrent() {}
|
||||
bool VulkanContext::BeginSwap() {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||
auto device = provider->device();
|
||||
VulkanDevice* device = provider->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
VkResult status;
|
||||
|
||||
@@ -164,15 +168,16 @@ bool VulkanContext::BeginSwap() {
|
||||
|
||||
// TODO(benvanik): use a fence instead? May not be possible with target image.
|
||||
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||
status = vkQueueWaitIdle(device->primary_queue());
|
||||
status = dfn.vkQueueWaitIdle(device->primary_queue());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanContext::EndSwap() {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
auto provider = static_cast<VulkanProvider*>(provider_);
|
||||
auto device = provider->device();
|
||||
auto provider = static_cast<const VulkanProvider*>(provider_);
|
||||
VulkanDevice* device = provider->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
VkResult status;
|
||||
|
||||
@@ -188,7 +193,7 @@ void VulkanContext::EndSwap() {
|
||||
// Wait until the queue is idle.
|
||||
// TODO(benvanik): is this required?
|
||||
std::lock_guard<std::mutex> queue_lock(device->primary_queue_mutex());
|
||||
status = vkQueueWaitIdle(device->primary_queue());
|
||||
status = dfn.vkQueueWaitIdle(device->primary_queue());
|
||||
}
|
||||
|
||||
std::unique_ptr<RawImage> VulkanContext::Capture() {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cinttypes>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
@@ -68,7 +69,8 @@ VulkanDevice::VulkanDevice(VulkanInstance* instance) : instance_(instance) {
|
||||
|
||||
VulkanDevice::~VulkanDevice() {
|
||||
if (handle) {
|
||||
vkDestroyDevice(handle, nullptr);
|
||||
const VulkanInstance::InstanceFunctions& ifn = instance_->ifn();
|
||||
ifn.vkDestroyDevice(handle, nullptr);
|
||||
handle = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -91,9 +93,11 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const VulkanInstance::InstanceFunctions& ifn = instance_->ifn();
|
||||
|
||||
// Query supported features so we can make sure we have what we need.
|
||||
VkPhysicalDeviceFeatures supported_features;
|
||||
vkGetPhysicalDeviceFeatures(device_info.handle, &supported_features);
|
||||
ifn.vkGetPhysicalDeviceFeatures(device_info.handle, &supported_features);
|
||||
VkPhysicalDeviceFeatures enabled_features = {0};
|
||||
bool any_features_missing = false;
|
||||
#define ENABLE_AND_EXPECT(name) \
|
||||
@@ -189,7 +193,8 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||
create_info.ppEnabledExtensionNames = enabled_extensions_.data();
|
||||
create_info.pEnabledFeatures = &enabled_features;
|
||||
|
||||
auto err = vkCreateDevice(device_info.handle, &create_info, nullptr, &handle);
|
||||
auto err =
|
||||
ifn.vkCreateDevice(device_info.handle, &create_info, nullptr, &handle);
|
||||
switch (err) {
|
||||
case VK_SUCCESS:
|
||||
// Ok!
|
||||
@@ -211,30 +216,34 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set flags so we can track enabled extensions easily.
|
||||
for (auto& ext : enabled_extensions_) {
|
||||
if (!std::strcmp(ext, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
|
||||
debug_marker_ena_ = true;
|
||||
pfn_vkDebugMarkerSetObjectNameEXT_ =
|
||||
(PFN_vkDebugMarkerSetObjectNameEXT)vkGetDeviceProcAddr(
|
||||
*this, "vkDebugMarkerSetObjectNameEXT");
|
||||
pfn_vkCmdDebugMarkerBeginEXT_ =
|
||||
(PFN_vkCmdDebugMarkerBeginEXT)vkGetDeviceProcAddr(
|
||||
*this, "vkCmdDebugMarkerBeginEXT");
|
||||
pfn_vkCmdDebugMarkerEndEXT_ =
|
||||
(PFN_vkCmdDebugMarkerEndEXT)vkGetDeviceProcAddr(
|
||||
*this, "vkCmdDebugMarkerEndEXT");
|
||||
pfn_vkCmdDebugMarkerInsertEXT_ =
|
||||
(PFN_vkCmdDebugMarkerInsertEXT)vkGetDeviceProcAddr(
|
||||
*this, "vkCmdDebugMarkerInsertEXT");
|
||||
}
|
||||
// Get device functions.
|
||||
std::memset(&dfn_, 0, sizeof(dfn_));
|
||||
bool device_functions_loaded = true;
|
||||
debug_marker_ena_ = false;
|
||||
#define XE_UI_VULKAN_FUNCTION(name) \
|
||||
device_functions_loaded &= \
|
||||
(dfn_.name = PFN_##name(ifn.vkGetDeviceProcAddr(handle, #name))) != \
|
||||
nullptr;
|
||||
#include "xenia/ui/vulkan/functions/device_1_0.inc"
|
||||
#include "xenia/ui/vulkan/functions/device_khr_swapchain.inc"
|
||||
if (HasEnabledExtension(VK_AMD_SHADER_INFO_EXTENSION_NAME)) {
|
||||
#include "xenia/ui/vulkan/functions/device_amd_shader_info.inc"
|
||||
}
|
||||
debug_marker_ena_ = HasEnabledExtension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||
if (debug_marker_ena_) {
|
||||
#include "xenia/ui/vulkan/functions/device_ext_debug_marker.inc"
|
||||
}
|
||||
#undef XE_UI_VULKAN_FUNCTION
|
||||
if (!device_functions_loaded) {
|
||||
XELOGE("Failed to get Vulkan device function pointers");
|
||||
return false;
|
||||
}
|
||||
|
||||
device_info_ = std::move(device_info);
|
||||
queue_family_index_ = ideal_queue_family_index;
|
||||
|
||||
// Get the primary queue used for most submissions/etc.
|
||||
vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);
|
||||
dfn_.vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);
|
||||
if (!primary_queue_) {
|
||||
XELOGE("vkGetDeviceQueue returned nullptr!");
|
||||
return false;
|
||||
@@ -253,7 +262,7 @@ bool VulkanDevice::Initialize(DeviceInfo device_info) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(handle, i, j, &queue);
|
||||
dfn_.vkGetDeviceQueue(handle, i, j, &queue);
|
||||
if (queue) {
|
||||
free_queues_[i].push_back(queue);
|
||||
}
|
||||
@@ -292,8 +301,8 @@ void VulkanDevice::ReleaseQueue(VkQueue queue, uint32_t queue_family_index) {
|
||||
|
||||
void VulkanDevice::DbgSetObjectName(uint64_t object,
|
||||
VkDebugReportObjectTypeEXT object_type,
|
||||
std::string name) {
|
||||
if (!debug_marker_ena_ || pfn_vkDebugMarkerSetObjectNameEXT_ == nullptr) {
|
||||
const std::string& name) const {
|
||||
if (!debug_marker_ena_) {
|
||||
// Extension disabled.
|
||||
return;
|
||||
}
|
||||
@@ -304,13 +313,13 @@ void VulkanDevice::DbgSetObjectName(uint64_t object,
|
||||
info.objectType = object_type;
|
||||
info.object = object;
|
||||
info.pObjectName = name.c_str();
|
||||
pfn_vkDebugMarkerSetObjectNameEXT_(*this, &info);
|
||||
dfn_.vkDebugMarkerSetObjectNameEXT(*this, &info);
|
||||
}
|
||||
|
||||
void VulkanDevice::DbgMarkerBegin(VkCommandBuffer command_buffer,
|
||||
std::string name, float r, float g, float b,
|
||||
float a) {
|
||||
if (!debug_marker_ena_ || pfn_vkCmdDebugMarkerBeginEXT_ == nullptr) {
|
||||
float a) const {
|
||||
if (!debug_marker_ena_) {
|
||||
// Extension disabled.
|
||||
return;
|
||||
}
|
||||
@@ -323,22 +332,22 @@ void VulkanDevice::DbgMarkerBegin(VkCommandBuffer command_buffer,
|
||||
info.color[1] = g;
|
||||
info.color[2] = b;
|
||||
info.color[3] = a;
|
||||
pfn_vkCmdDebugMarkerBeginEXT_(command_buffer, &info);
|
||||
dfn_.vkCmdDebugMarkerBeginEXT(command_buffer, &info);
|
||||
}
|
||||
|
||||
void VulkanDevice::DbgMarkerEnd(VkCommandBuffer command_buffer) {
|
||||
if (!debug_marker_ena_ || pfn_vkCmdDebugMarkerEndEXT_ == nullptr) {
|
||||
void VulkanDevice::DbgMarkerEnd(VkCommandBuffer command_buffer) const {
|
||||
if (!debug_marker_ena_) {
|
||||
// Extension disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
pfn_vkCmdDebugMarkerEndEXT_(command_buffer);
|
||||
dfn_.vkCmdDebugMarkerEndEXT(command_buffer);
|
||||
}
|
||||
|
||||
void VulkanDevice::DbgMarkerInsert(VkCommandBuffer command_buffer,
|
||||
std::string name, float r, float g, float b,
|
||||
float a) {
|
||||
if (!debug_marker_ena_ || pfn_vkCmdDebugMarkerInsertEXT_ == nullptr) {
|
||||
float a) const {
|
||||
if (!debug_marker_ena_) {
|
||||
// Extension disabled.
|
||||
return;
|
||||
}
|
||||
@@ -351,7 +360,7 @@ void VulkanDevice::DbgMarkerInsert(VkCommandBuffer command_buffer,
|
||||
info.color[1] = g;
|
||||
info.color[2] = g;
|
||||
info.color[3] = b;
|
||||
pfn_vkCmdDebugMarkerInsertEXT_(command_buffer, &info);
|
||||
dfn_.vkCmdDebugMarkerInsertEXT(command_buffer, &info);
|
||||
}
|
||||
|
||||
bool VulkanDevice::is_renderdoc_attached() const {
|
||||
@@ -379,7 +388,8 @@ void VulkanDevice::EndRenderDocFrameCapture() {
|
||||
}
|
||||
|
||||
VkDeviceMemory VulkanDevice::AllocateMemory(
|
||||
const VkMemoryRequirements& requirements, VkFlags required_properties) {
|
||||
const VkMemoryRequirements& requirements,
|
||||
VkFlags required_properties) const {
|
||||
// Search memory types to find one matching our requirements and our
|
||||
// properties.
|
||||
uint32_t type_index = UINT_MAX;
|
||||
@@ -407,7 +417,7 @@ VkDeviceMemory VulkanDevice::AllocateMemory(
|
||||
memory_info.allocationSize = requirements.size;
|
||||
memory_info.memoryTypeIndex = type_index;
|
||||
VkDeviceMemory memory = nullptr;
|
||||
auto err = vkAllocateMemory(handle, &memory_info, nullptr, &memory);
|
||||
auto err = dfn_.vkAllocateMemory(handle, &memory_info, nullptr, &memory);
|
||||
CheckResult(err, "vkAllocateMemory");
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -32,11 +32,23 @@ class VulkanDevice {
|
||||
VulkanDevice(VulkanInstance* instance);
|
||||
~VulkanDevice();
|
||||
|
||||
VulkanInstance* instance() const { return instance_; }
|
||||
|
||||
VkDevice handle = nullptr;
|
||||
|
||||
operator VkDevice() const { return handle; }
|
||||
operator VkPhysicalDevice() const { return device_info_.handle; }
|
||||
|
||||
struct DeviceFunctions {
|
||||
#define XE_UI_VULKAN_FUNCTION(name) PFN_##name name;
|
||||
#include "xenia/ui/vulkan/functions/device_1_0.inc"
|
||||
#include "xenia/ui/vulkan/functions/device_amd_shader_info.inc"
|
||||
#include "xenia/ui/vulkan/functions/device_ext_debug_marker.inc"
|
||||
#include "xenia/ui/vulkan/functions/device_khr_swapchain.inc"
|
||||
#undef XE_UI_VULKAN_FUNCTION
|
||||
};
|
||||
const DeviceFunctions& dfn() const { return dfn_; }
|
||||
|
||||
// Declares a layer to verify and enable upon initialization.
|
||||
// Must be called before Initialize.
|
||||
void DeclareRequiredLayer(std::string name, uint32_t min_version,
|
||||
@@ -78,16 +90,16 @@ class VulkanDevice {
|
||||
void ReleaseQueue(VkQueue queue, uint32_t queue_family_index);
|
||||
|
||||
void DbgSetObjectName(uint64_t object, VkDebugReportObjectTypeEXT object_type,
|
||||
std::string name);
|
||||
const std::string& name) const;
|
||||
|
||||
void DbgMarkerBegin(VkCommandBuffer command_buffer, std::string name,
|
||||
float r = 0.0f, float g = 0.0f, float b = 0.0f,
|
||||
float a = 0.0f);
|
||||
void DbgMarkerEnd(VkCommandBuffer command_buffer);
|
||||
float a = 0.0f) const;
|
||||
void DbgMarkerEnd(VkCommandBuffer command_buffer) const;
|
||||
|
||||
void DbgMarkerInsert(VkCommandBuffer command_buffer, std::string name,
|
||||
float r = 0.0f, float g = 0.0f, float b = 0.0f,
|
||||
float a = 0.0f);
|
||||
float a = 0.0f) const;
|
||||
|
||||
// True if RenderDoc is attached and available for use.
|
||||
bool is_renderdoc_attached() const;
|
||||
@@ -101,7 +113,7 @@ class VulkanDevice {
|
||||
// Allocates memory of the given size matching the required properties.
|
||||
VkDeviceMemory AllocateMemory(
|
||||
const VkMemoryRequirements& requirements,
|
||||
VkFlags required_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
VkFlags required_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) const;
|
||||
|
||||
private:
|
||||
VulkanInstance* instance_ = nullptr;
|
||||
@@ -110,6 +122,8 @@ class VulkanDevice {
|
||||
std::vector<Requirement> required_extensions_;
|
||||
std::vector<const char*> enabled_extensions_;
|
||||
|
||||
DeviceFunctions dfn_ = {};
|
||||
|
||||
bool debug_marker_ena_ = false;
|
||||
PFN_vkDebugMarkerSetObjectNameEXT pfn_vkDebugMarkerSetObjectNameEXT_ =
|
||||
nullptr;
|
||||
|
||||
@@ -29,9 +29,11 @@ constexpr uint32_t kCircularBufferCapacity = 2 * 1024 * 1024;
|
||||
|
||||
class LightweightCircularBuffer {
|
||||
public:
|
||||
LightweightCircularBuffer(VulkanDevice* device) : device_(*device) {
|
||||
LightweightCircularBuffer(const VulkanDevice* device) : device_(*device) {
|
||||
buffer_capacity_ = xe::round_up(kCircularBufferCapacity, 4096);
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
// Index buffer.
|
||||
VkBufferCreateInfo index_buffer_info;
|
||||
index_buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
@@ -42,8 +44,8 @@ class LightweightCircularBuffer {
|
||||
index_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
index_buffer_info.queueFamilyIndexCount = 0;
|
||||
index_buffer_info.pQueueFamilyIndices = nullptr;
|
||||
auto status =
|
||||
vkCreateBuffer(device_, &index_buffer_info, nullptr, &index_buffer_);
|
||||
auto status = dfn.vkCreateBuffer(device_, &index_buffer_info, nullptr,
|
||||
&index_buffer_);
|
||||
CheckResult(status, "vkCreateBuffer");
|
||||
|
||||
// Vertex buffer.
|
||||
@@ -56,34 +58,37 @@ class LightweightCircularBuffer {
|
||||
vertex_buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
vertex_buffer_info.queueFamilyIndexCount = 0;
|
||||
vertex_buffer_info.pQueueFamilyIndices = nullptr;
|
||||
status =
|
||||
vkCreateBuffer(*device, &vertex_buffer_info, nullptr, &vertex_buffer_);
|
||||
status = dfn.vkCreateBuffer(*device, &vertex_buffer_info, nullptr,
|
||||
&vertex_buffer_);
|
||||
CheckResult(status, "vkCreateBuffer");
|
||||
|
||||
// Allocate underlying buffer.
|
||||
// We alias it for both vertices and indices.
|
||||
VkMemoryRequirements buffer_requirements;
|
||||
vkGetBufferMemoryRequirements(device_, index_buffer_, &buffer_requirements);
|
||||
dfn.vkGetBufferMemoryRequirements(device_, index_buffer_,
|
||||
&buffer_requirements);
|
||||
buffer_memory_ = device->AllocateMemory(
|
||||
buffer_requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
vkBindBufferMemory(*device, index_buffer_, buffer_memory_, 0);
|
||||
vkBindBufferMemory(*device, vertex_buffer_, buffer_memory_, 0);
|
||||
dfn.vkBindBufferMemory(*device, index_buffer_, buffer_memory_, 0);
|
||||
dfn.vkBindBufferMemory(*device, vertex_buffer_, buffer_memory_, 0);
|
||||
|
||||
// Persistent mapping.
|
||||
status = vkMapMemory(device_, buffer_memory_, 0, VK_WHOLE_SIZE, 0,
|
||||
&buffer_data_);
|
||||
status = dfn.vkMapMemory(device_, buffer_memory_, 0, VK_WHOLE_SIZE, 0,
|
||||
&buffer_data_);
|
||||
CheckResult(status, "vkMapMemory");
|
||||
}
|
||||
|
||||
~LightweightCircularBuffer() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
|
||||
if (buffer_memory_) {
|
||||
vkUnmapMemory(device_, buffer_memory_);
|
||||
dfn.vkUnmapMemory(device_, buffer_memory_);
|
||||
buffer_memory_ = nullptr;
|
||||
}
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyBuffer, device_, index_buffer_, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyBuffer, device_, vertex_buffer_, nullptr);
|
||||
VK_SAFE_DESTROY(vkFreeMemory, device_, buffer_memory_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyBuffer, device_, index_buffer_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyBuffer, device_, vertex_buffer_);
|
||||
DestroyAndNullHandle(dfn.vkFreeMemory, device_, buffer_memory_);
|
||||
}
|
||||
|
||||
VkBuffer vertex_buffer() const { return vertex_buffer_; }
|
||||
@@ -118,18 +123,19 @@ class LightweightCircularBuffer {
|
||||
|
||||
// Flush memory.
|
||||
// TODO(benvanik): do only in large batches? can barrier it.
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_.dfn();
|
||||
VkMappedMemoryRange dirty_range;
|
||||
dirty_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
dirty_range.pNext = nullptr;
|
||||
dirty_range.memory = buffer_memory_;
|
||||
dirty_range.offset = offset;
|
||||
dirty_range.size = source_length;
|
||||
vkFlushMappedMemoryRanges(device_, 1, &dirty_range);
|
||||
dfn.vkFlushMappedMemoryRanges(device_, 1, &dirty_range);
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice device_ = nullptr;
|
||||
const VulkanDevice& device_;
|
||||
|
||||
VkBuffer index_buffer_ = nullptr;
|
||||
VkBuffer vertex_buffer_ = nullptr;
|
||||
@@ -153,6 +159,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
VkResult Initialize(VkDescriptorSetLayout descriptor_set_layout,
|
||||
VkImageView image_view) {
|
||||
image_view_ = image_view;
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
// Create descriptor set used just for this texture.
|
||||
@@ -163,8 +170,8 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
set_alloc_info.descriptorPool = descriptor_pool_;
|
||||
set_alloc_info.descriptorSetCount = 1;
|
||||
set_alloc_info.pSetLayouts = &descriptor_set_layout;
|
||||
status =
|
||||
vkAllocateDescriptorSets(*device_, &set_alloc_info, &descriptor_set_);
|
||||
status = dfn.vkAllocateDescriptorSets(*device_, &set_alloc_info,
|
||||
&descriptor_set_);
|
||||
CheckResult(status, "vkAllocateDescriptorSets");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -184,12 +191,13 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
descriptor_write.descriptorCount = 1;
|
||||
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptor_write.pImageInfo = &texture_info;
|
||||
vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
||||
dfn.vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult Initialize(VkDescriptorSetLayout descriptor_set_layout) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
// Create image object.
|
||||
@@ -209,7 +217,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
image_info.queueFamilyIndexCount = 0;
|
||||
image_info.pQueueFamilyIndices = nullptr;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
||||
status = vkCreateImage(*device_, &image_info, nullptr, &image_);
|
||||
status = dfn.vkCreateImage(*device_, &image_info, nullptr, &image_);
|
||||
CheckResult(status, "vkCreateImage");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -217,7 +225,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
|
||||
// Allocate memory for the image.
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetImageMemoryRequirements(*device_, image_, &memory_requirements);
|
||||
dfn.vkGetImageMemoryRequirements(*device_, image_, &memory_requirements);
|
||||
device_memory_ = device_->AllocateMemory(
|
||||
memory_requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
||||
if (!device_memory_) {
|
||||
@@ -225,7 +233,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
}
|
||||
|
||||
// Bind memory and the image together.
|
||||
status = vkBindImageMemory(*device_, image_, device_memory_, 0);
|
||||
status = dfn.vkBindImageMemory(*device_, image_, device_memory_, 0);
|
||||
CheckResult(status, "vkBindImageMemory");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -246,7 +254,7 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
VK_COMPONENT_SWIZZLE_A,
|
||||
};
|
||||
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||
status = vkCreateImageView(*device_, &view_info, nullptr, &image_view_);
|
||||
status = dfn.vkCreateImageView(*device_, &view_info, nullptr, &image_view_);
|
||||
CheckResult(status, "vkCreateImageView");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -260,8 +268,8 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
set_alloc_info.descriptorPool = descriptor_pool_;
|
||||
set_alloc_info.descriptorSetCount = 1;
|
||||
set_alloc_info.pSetLayouts = &descriptor_set_layout;
|
||||
status =
|
||||
vkAllocateDescriptorSets(*device_, &set_alloc_info, &descriptor_set_);
|
||||
status = dfn.vkAllocateDescriptorSets(*device_, &set_alloc_info,
|
||||
&descriptor_set_);
|
||||
CheckResult(status, "vkAllocateDescriptorSets");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -281,44 +289,48 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
descriptor_write.descriptorCount = 1;
|
||||
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptor_write.pImageInfo = &texture_info;
|
||||
vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
||||
dfn.vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
if (descriptor_set_) {
|
||||
vkFreeDescriptorSets(*device_, descriptor_pool_, 1, &descriptor_set_);
|
||||
dfn.vkFreeDescriptorSets(*device_, descriptor_pool_, 1, &descriptor_set_);
|
||||
descriptor_set_ = nullptr;
|
||||
}
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyImageView, *device_, image_view_, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyImage, *device_, image_, nullptr);
|
||||
VK_SAFE_DESTROY(vkFreeMemory, *device_, device_memory_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyImageView, *device_, image_view_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyImage, *device_, image_);
|
||||
DestroyAndNullHandle(dfn.vkFreeMemory, *device_, device_memory_);
|
||||
}
|
||||
|
||||
VkResult Upload(const uint8_t* src_data) {
|
||||
// TODO(benvanik): assert not in use? textures aren't dynamic right now.
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
// Get device image layout.
|
||||
VkImageSubresource subresource;
|
||||
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresource.mipLevel = 0;
|
||||
subresource.arrayLayer = 0;
|
||||
VkSubresourceLayout layout;
|
||||
vkGetImageSubresourceLayout(*device_, image_, &subresource, &layout);
|
||||
dfn.vkGetImageSubresourceLayout(*device_, image_, &subresource, &layout);
|
||||
|
||||
// Map memory for upload.
|
||||
uint8_t* gpu_data = nullptr;
|
||||
auto status = vkMapMemory(*device_, device_memory_, 0, layout.size, 0,
|
||||
reinterpret_cast<void**>(&gpu_data));
|
||||
auto status = dfn.vkMapMemory(*device_, device_memory_, 0, layout.size, 0,
|
||||
reinterpret_cast<void**>(&gpu_data));
|
||||
CheckResult(status, "vkMapMemory");
|
||||
|
||||
if (status == VK_SUCCESS) {
|
||||
// Copy the entire texture, hoping its layout matches what we expect.
|
||||
std::memcpy(gpu_data + layout.offset, src_data, layout.size);
|
||||
|
||||
vkUnmapMemory(*device_, device_memory_);
|
||||
dfn.vkUnmapMemory(*device_, device_memory_);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -328,6 +340,8 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
// the command buffer WILL be queued and executed by the device.
|
||||
void TransitionLayout(VkCommandBuffer command_buffer,
|
||||
VkImageLayout new_layout) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
VkImageMemoryBarrier image_barrier;
|
||||
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_barrier.pNext = nullptr;
|
||||
@@ -342,16 +356,16 @@ class VulkanImmediateTexture : public ImmediateTexture {
|
||||
image_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_layout_ = new_layout;
|
||||
|
||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &image_barrier);
|
||||
dfn.vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr,
|
||||
0, nullptr, 1, &image_barrier);
|
||||
}
|
||||
|
||||
VkDescriptorSet descriptor_set() const { return descriptor_set_; }
|
||||
VkImageLayout layout() const { return image_layout_; }
|
||||
|
||||
private:
|
||||
ui::vulkan::VulkanDevice* device_ = nullptr;
|
||||
VulkanDevice* device_ = nullptr;
|
||||
VkDescriptorPool descriptor_pool_ = nullptr;
|
||||
VkSampler sampler_ = nullptr; // Not owned.
|
||||
VkImage image_ = nullptr;
|
||||
@@ -367,7 +381,8 @@ VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
|
||||
VulkanImmediateDrawer::~VulkanImmediateDrawer() { Shutdown(); }
|
||||
|
||||
VkResult VulkanImmediateDrawer::Initialize() {
|
||||
auto device = context_->device();
|
||||
const VulkanDevice* device = context_->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
// NEAREST + CLAMP
|
||||
VkSamplerCreateInfo sampler_info;
|
||||
@@ -389,8 +404,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
sampler_info.maxLod = 0.0f;
|
||||
sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
sampler_info.unnormalizedCoordinates = VK_FALSE;
|
||||
auto status = vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.nearest_clamp);
|
||||
auto status = dfn.vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.nearest_clamp);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -400,8 +415,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
status = vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.nearest_repeat);
|
||||
status = dfn.vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.nearest_repeat);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -413,8 +428,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
status =
|
||||
vkCreateSampler(*device, &sampler_info, nullptr, &samplers_.linear_clamp);
|
||||
status = dfn.vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.linear_clamp);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -424,8 +439,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
status = vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.linear_repeat);
|
||||
status = dfn.vkCreateSampler(*device, &sampler_info, nullptr,
|
||||
&samplers_.linear_repeat);
|
||||
CheckResult(status, "vkCreateSampler");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -447,8 +462,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
texture_binding.pImmutableSamplers = nullptr;
|
||||
texture_set_layout_info.pBindings = &texture_binding;
|
||||
status = vkCreateDescriptorSetLayout(*device, &texture_set_layout_info,
|
||||
nullptr, &texture_set_layout_);
|
||||
status = dfn.vkCreateDescriptorSetLayout(*device, &texture_set_layout_info,
|
||||
nullptr, &texture_set_layout_);
|
||||
CheckResult(status, "vkCreateDescriptorSetLayout");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -468,8 +483,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
pool_sizes[0].descriptorCount = 128;
|
||||
descriptor_pool_info.poolSizeCount = 1;
|
||||
descriptor_pool_info.pPoolSizes = pool_sizes;
|
||||
status = vkCreateDescriptorPool(*device, &descriptor_pool_info, nullptr,
|
||||
&descriptor_pool_);
|
||||
status = dfn.vkCreateDescriptorPool(*device, &descriptor_pool_info, nullptr,
|
||||
&descriptor_pool_);
|
||||
CheckResult(status, "vkCreateDescriptorPool");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -495,8 +510,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
pipeline_layout_info.pushConstantRangeCount =
|
||||
static_cast<uint32_t>(xe::countof(push_constant_ranges));
|
||||
pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
|
||||
status = vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr,
|
||||
&pipeline_layout_);
|
||||
status = dfn.vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr,
|
||||
&pipeline_layout_);
|
||||
CheckResult(status, "vkCreatePipelineLayout");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -510,8 +525,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
vertex_shader_info.codeSize = sizeof(immediate_vert);
|
||||
vertex_shader_info.pCode = reinterpret_cast<const uint32_t*>(immediate_vert);
|
||||
VkShaderModule vertex_shader;
|
||||
status = vkCreateShaderModule(*device, &vertex_shader_info, nullptr,
|
||||
&vertex_shader);
|
||||
status = dfn.vkCreateShaderModule(*device, &vertex_shader_info, nullptr,
|
||||
&vertex_shader);
|
||||
CheckResult(status, "vkCreateShaderModule");
|
||||
VkShaderModuleCreateInfo fragment_shader_info;
|
||||
fragment_shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
@@ -521,8 +536,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
fragment_shader_info.pCode =
|
||||
reinterpret_cast<const uint32_t*>(immediate_frag);
|
||||
VkShaderModule fragment_shader;
|
||||
status = vkCreateShaderModule(*device, &fragment_shader_info, nullptr,
|
||||
&fragment_shader);
|
||||
status = dfn.vkCreateShaderModule(*device, &fragment_shader_info, nullptr,
|
||||
&fragment_shader);
|
||||
CheckResult(status, "vkCreateShaderModule");
|
||||
|
||||
// Pipeline used when rendering triangles.
|
||||
@@ -667,8 +682,8 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
pipeline_info.basePipelineHandle = nullptr;
|
||||
pipeline_info.basePipelineIndex = -1;
|
||||
if (status == VK_SUCCESS) {
|
||||
status = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
|
||||
nullptr, &triangle_pipeline_);
|
||||
status = dfn.vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
|
||||
nullptr, &triangle_pipeline_);
|
||||
CheckResult(status, "vkCreateGraphicsPipelines");
|
||||
}
|
||||
|
||||
@@ -678,13 +693,13 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
pipeline_info.basePipelineHandle = triangle_pipeline_;
|
||||
pipeline_info.basePipelineIndex = -1;
|
||||
if (status == VK_SUCCESS) {
|
||||
status = vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
|
||||
nullptr, &line_pipeline_);
|
||||
status = dfn.vkCreateGraphicsPipelines(*device, nullptr, 1, &pipeline_info,
|
||||
nullptr, &line_pipeline_);
|
||||
CheckResult(status, "vkCreateGraphicsPipelines");
|
||||
}
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyShaderModule, *device, vertex_shader, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyShaderModule, *device, fragment_shader, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyShaderModule, *device, vertex_shader);
|
||||
DestroyAndNullHandle(dfn.vkDestroyShaderModule, *device, fragment_shader);
|
||||
|
||||
// Allocate the buffer we'll use for our vertex and index data.
|
||||
circular_buffer_ = std::make_unique<LightweightCircularBuffer>(device);
|
||||
@@ -693,22 +708,23 @@ VkResult VulkanImmediateDrawer::Initialize() {
|
||||
}
|
||||
|
||||
void VulkanImmediateDrawer::Shutdown() {
|
||||
auto device = context_->device();
|
||||
const VulkanDevice* device = context_->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
circular_buffer_.reset();
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyPipeline, *device, line_pipeline_, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyPipeline, *device, triangle_pipeline_, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyPipelineLayout, *device, pipeline_layout_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyPipeline, *device, line_pipeline_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyPipeline, *device, triangle_pipeline_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyPipelineLayout, *device, pipeline_layout_);
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyDescriptorPool, *device, descriptor_pool_, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyDescriptorSetLayout, *device, texture_set_layout_,
|
||||
nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyDescriptorPool, *device, descriptor_pool_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout, *device,
|
||||
texture_set_layout_);
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.nearest_clamp, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.nearest_repeat, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.linear_clamp, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroySampler, *device, samplers_.linear_repeat, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroySampler, *device, samplers_.nearest_clamp);
|
||||
DestroyAndNullHandle(dfn.vkDestroySampler, *device, samplers_.nearest_repeat);
|
||||
DestroyAndNullHandle(dfn.vkDestroySampler, *device, samplers_.linear_clamp);
|
||||
DestroyAndNullHandle(dfn.vkDestroySampler, *device, samplers_.linear_repeat);
|
||||
}
|
||||
|
||||
std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
|
||||
@@ -751,7 +767,8 @@ std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::WrapTexture(
|
||||
|
||||
void VulkanImmediateDrawer::Begin(int render_target_width,
|
||||
int render_target_height) {
|
||||
auto device = context_->device();
|
||||
const VulkanDevice* device = context_->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
auto swap_chain = context_->swap_chain();
|
||||
assert_null(current_cmd_buffer_);
|
||||
current_cmd_buffer_ = swap_chain->render_cmd_buffer();
|
||||
@@ -766,7 +783,7 @@ void VulkanImmediateDrawer::Begin(int render_target_width,
|
||||
viewport.height = static_cast<float>(render_target_height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(current_cmd_buffer_, 0, 1, &viewport);
|
||||
dfn.vkCmdSetViewport(current_cmd_buffer_, 0, 1, &viewport);
|
||||
|
||||
// Update projection matrix.
|
||||
const float ortho_projection[4][4] = {
|
||||
@@ -775,13 +792,14 @@ void VulkanImmediateDrawer::Begin(int render_target_width,
|
||||
{0.0f, 0.0f, -1.0f, 0.0f},
|
||||
{-1.0f, 1.0f, 0.0f, 1.0f},
|
||||
};
|
||||
vkCmdPushConstants(current_cmd_buffer_, pipeline_layout_,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 16,
|
||||
ortho_projection);
|
||||
dfn.vkCmdPushConstants(current_cmd_buffer_, pipeline_layout_,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 16,
|
||||
ortho_projection);
|
||||
}
|
||||
|
||||
void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||
auto device = context_->device();
|
||||
const VulkanDevice* device = context_->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
// Upload vertices.
|
||||
VkDeviceSize vertices_offset = circular_buffer_->Emplace(
|
||||
@@ -791,8 +809,8 @@ void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||
return;
|
||||
}
|
||||
auto vertex_buffer = circular_buffer_->vertex_buffer();
|
||||
vkCmdBindVertexBuffers(current_cmd_buffer_, 0, 1, &vertex_buffer,
|
||||
&vertices_offset);
|
||||
dfn.vkCmdBindVertexBuffers(current_cmd_buffer_, 0, 1, &vertex_buffer,
|
||||
&vertices_offset);
|
||||
|
||||
// Upload indices.
|
||||
if (batch.indices) {
|
||||
@@ -802,22 +820,27 @@ void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||
// TODO(benvanik): die?
|
||||
return;
|
||||
}
|
||||
vkCmdBindIndexBuffer(current_cmd_buffer_, circular_buffer_->index_buffer(),
|
||||
indices_offset, VK_INDEX_TYPE_UINT16);
|
||||
dfn.vkCmdBindIndexBuffer(current_cmd_buffer_,
|
||||
circular_buffer_->index_buffer(), indices_offset,
|
||||
VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
|
||||
batch_has_index_buffer_ = !!batch.indices;
|
||||
}
|
||||
|
||||
void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||
const VulkanDevice* device = context_->device();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device->dfn();
|
||||
|
||||
switch (draw.primitive_type) {
|
||||
case ImmediatePrimitiveType::kLines:
|
||||
vkCmdBindPipeline(current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
line_pipeline_);
|
||||
dfn.vkCmdBindPipeline(current_cmd_buffer_,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, line_pipeline_);
|
||||
break;
|
||||
case ImmediatePrimitiveType::kTriangles:
|
||||
vkCmdBindPipeline(current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
triangle_pipeline_);
|
||||
dfn.vkCmdBindPipeline(current_cmd_buffer_,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
triangle_pipeline_);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -833,18 +856,18 @@ void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||
XELOGW("Failed to acquire texture descriptor set for immediate drawer!");
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(current_cmd_buffer_,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_,
|
||||
0, 1, &texture_set, 0, nullptr);
|
||||
dfn.vkCmdBindDescriptorSets(
|
||||
current_cmd_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_,
|
||||
0, 1, &texture_set, 0, nullptr);
|
||||
}
|
||||
|
||||
// Use push constants for our per-draw changes.
|
||||
// Here, the restrict_texture_samples uniform (was used before September 26,
|
||||
// 2020, now deleted).
|
||||
int restrict_texture_samples = 0;
|
||||
vkCmdPushConstants(current_cmd_buffer_, pipeline_layout_,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 16,
|
||||
sizeof(int), &restrict_texture_samples);
|
||||
dfn.vkCmdPushConstants(current_cmd_buffer_, pipeline_layout_,
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 16,
|
||||
sizeof(int), &restrict_texture_samples);
|
||||
|
||||
// Scissor, if enabled.
|
||||
// Scissor can be disabled by making it the full screen.
|
||||
@@ -861,14 +884,14 @@ void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||
scissor.extent.width = current_render_target_width_;
|
||||
scissor.extent.height = current_render_target_height_;
|
||||
}
|
||||
vkCmdSetScissor(current_cmd_buffer_, 0, 1, &scissor);
|
||||
dfn.vkCmdSetScissor(current_cmd_buffer_, 0, 1, &scissor);
|
||||
|
||||
// Issue draw.
|
||||
if (batch_has_index_buffer_) {
|
||||
vkCmdDrawIndexed(current_cmd_buffer_, draw.count, 1, draw.index_offset,
|
||||
draw.base_vertex, 0);
|
||||
dfn.vkCmdDrawIndexed(current_cmd_buffer_, draw.count, 1, draw.index_offset,
|
||||
draw.base_vertex, 0);
|
||||
} else {
|
||||
vkCmdDraw(current_cmd_buffer_, draw.count, 1, draw.base_vertex, 0);
|
||||
dfn.vkCmdDraw(current_cmd_buffer_, draw.count, 1, draw.base_vertex, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,15 +10,16 @@
|
||||
#include "xenia/ui/vulkan/vulkan_instance.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/renderdoc/renderdoc_app.h"
|
||||
#include "third_party/volk/volk.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/ui/vulkan/vulkan.h"
|
||||
#include "xenia/ui/vulkan/vulkan_immediate_drawer.h"
|
||||
@@ -26,6 +27,12 @@
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
#if XE_PLATFORM_LINUX
|
||||
#include <dlfcn.h>
|
||||
#elif XE_PLATFORM_WIN32
|
||||
#include "xenia/base/platform_win.h"
|
||||
#endif
|
||||
|
||||
#if XE_PLATFORM_GNU_LINUX
|
||||
#include "xenia/ui/window_gtk.h"
|
||||
#endif
|
||||
|
||||
@@ -64,21 +71,6 @@ VulkanInstance::VulkanInstance() {
|
||||
|
||||
DeclareRequiredExtension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
||||
Version::Make(0, 0, 0), true);
|
||||
DeclareRequiredExtension(VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
Version::Make(0, 0, 0), true);
|
||||
#if XE_PLATFORM_WIN32
|
||||
DeclareRequiredExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
|
||||
Version::Make(0, 0, 0), true);
|
||||
#elif XE_PLATFORM_LINUX
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
DeclareRequiredExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
|
||||
Version::Make(0, 0, 0), true);
|
||||
#else
|
||||
#error No Vulkan surface extension for the GDK backend defined yet.
|
||||
#endif
|
||||
#else
|
||||
#error No Vulkan surface extension for the platform defined yet.
|
||||
#endif
|
||||
}
|
||||
|
||||
VulkanInstance::~VulkanInstance() { DestroyInstance(); }
|
||||
@@ -86,8 +78,61 @@ VulkanInstance::~VulkanInstance() { DestroyInstance(); }
|
||||
bool VulkanInstance::Initialize() {
|
||||
auto version = Version::Parse(VK_API_VERSION);
|
||||
XELOGVK("Initializing Vulkan {}...", version.pretty_string);
|
||||
if (volkInitialize() != VK_SUCCESS) {
|
||||
XELOGE("volkInitialize() failed!");
|
||||
|
||||
// Load the library.
|
||||
bool library_functions_loaded = true;
|
||||
#if XE_PLATFORM_LINUX
|
||||
#if XE_PLATFORM_ANDROID
|
||||
const char* libvulkan_name = "libvulkan.so";
|
||||
#else
|
||||
const char* libvulkan_name = "libvulkan.so.1";
|
||||
#endif
|
||||
// http://developer.download.nvidia.com/mobile/shield/assets/Vulkan/UsingtheVulkanAPI.pdf
|
||||
library_ = dlopen(libvulkan_name, RTLD_NOW | RTLD_LOCAL);
|
||||
if (!library_) {
|
||||
XELOGE("Failed to load {}", libvulkan_name);
|
||||
return false;
|
||||
}
|
||||
#define XE_VULKAN_LOAD_MODULE_LFN(name) \
|
||||
library_functions_loaded &= \
|
||||
(lfn_.name = PFN_##name(dlsym(library_, #name))) != nullptr;
|
||||
#elif XE_PLATFORM_WIN32
|
||||
library_ = LoadLibraryA("vulkan-1.dll");
|
||||
if (!library_) {
|
||||
XELOGE("Failed to load vulkan-1.dll");
|
||||
return false;
|
||||
}
|
||||
#define XE_VULKAN_LOAD_MODULE_LFN(name) \
|
||||
library_functions_loaded &= \
|
||||
(lfn_.name = PFN_##name(GetProcAddress(library_, #name))) != nullptr;
|
||||
#else
|
||||
#error No Vulkan library loading provided for the target platform.
|
||||
#endif
|
||||
XE_VULKAN_LOAD_MODULE_LFN(vkGetInstanceProcAddr);
|
||||
XE_VULKAN_LOAD_MODULE_LFN(vkDestroyInstance);
|
||||
#undef XE_VULKAN_LOAD_MODULE_LFN
|
||||
if (!library_functions_loaded) {
|
||||
XELOGE("Failed to get Vulkan library function pointers");
|
||||
return false;
|
||||
}
|
||||
library_functions_loaded &=
|
||||
(lfn_.vkCreateInstance = PFN_vkCreateInstance(lfn_.vkGetInstanceProcAddr(
|
||||
VK_NULL_HANDLE, "vkCreateInstance"))) != nullptr;
|
||||
library_functions_loaded &=
|
||||
(lfn_.vkEnumerateInstanceExtensionProperties =
|
||||
PFN_vkEnumerateInstanceExtensionProperties(
|
||||
lfn_.vkGetInstanceProcAddr(
|
||||
VK_NULL_HANDLE,
|
||||
"vkEnumerateInstanceExtensionProperties"))) != nullptr;
|
||||
library_functions_loaded &=
|
||||
(lfn_.vkEnumerateInstanceLayerProperties =
|
||||
PFN_vkEnumerateInstanceLayerProperties(lfn_.vkGetInstanceProcAddr(
|
||||
VK_NULL_HANDLE, "vkEnumerateInstanceLayerProperties"))) !=
|
||||
nullptr;
|
||||
if (!library_functions_loaded) {
|
||||
XELOGE(
|
||||
"Failed to get Vulkan library function pointers via "
|
||||
"vkGetInstanceProcAddr");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -164,11 +209,11 @@ bool VulkanInstance::QueryGlobals() {
|
||||
std::vector<VkLayerProperties> global_layer_properties;
|
||||
VkResult err;
|
||||
do {
|
||||
err = vkEnumerateInstanceLayerProperties(&count, nullptr);
|
||||
err = lfn_.vkEnumerateInstanceLayerProperties(&count, nullptr);
|
||||
CheckResult(err, "vkEnumerateInstanceLayerProperties");
|
||||
global_layer_properties.resize(count);
|
||||
err = vkEnumerateInstanceLayerProperties(&count,
|
||||
global_layer_properties.data());
|
||||
err = lfn_.vkEnumerateInstanceLayerProperties(
|
||||
&count, global_layer_properties.data());
|
||||
} while (err == VK_INCOMPLETE);
|
||||
CheckResult(err, "vkEnumerateInstanceLayerProperties");
|
||||
global_layers_.resize(count);
|
||||
@@ -178,11 +223,11 @@ bool VulkanInstance::QueryGlobals() {
|
||||
|
||||
// Get all extensions available for the layer.
|
||||
do {
|
||||
err = vkEnumerateInstanceExtensionProperties(
|
||||
err = lfn_.vkEnumerateInstanceExtensionProperties(
|
||||
global_layer.properties.layerName, &count, nullptr);
|
||||
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
||||
global_layer.extensions.resize(count);
|
||||
err = vkEnumerateInstanceExtensionProperties(
|
||||
err = lfn_.vkEnumerateInstanceExtensionProperties(
|
||||
global_layer.properties.layerName, &count,
|
||||
global_layer.extensions.data());
|
||||
} while (err == VK_INCOMPLETE);
|
||||
@@ -205,11 +250,11 @@ bool VulkanInstance::QueryGlobals() {
|
||||
|
||||
// Scan global extensions.
|
||||
do {
|
||||
err = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
||||
err = lfn_.vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
||||
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
||||
global_extensions_.resize(count);
|
||||
err = vkEnumerateInstanceExtensionProperties(nullptr, &count,
|
||||
global_extensions_.data());
|
||||
err = lfn_.vkEnumerateInstanceExtensionProperties(
|
||||
nullptr, &count, global_extensions_.data());
|
||||
} while (err == VK_INCOMPLETE);
|
||||
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
||||
XELOGVK("Found {} global extensions:", global_extensions_.size());
|
||||
@@ -218,6 +263,136 @@ bool VulkanInstance::QueryGlobals() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanInstance::CreateInstance() {
|
||||
XELOGVK("Verifying layers and extensions...");
|
||||
|
||||
// Gather list of enabled layer names.
|
||||
auto layers_result = CheckRequirements(required_layers_, global_layers_);
|
||||
auto& enabled_layers = layers_result.second;
|
||||
|
||||
// Gather list of enabled extension names.
|
||||
auto extensions_result =
|
||||
CheckRequirements(required_extensions_, global_extensions_);
|
||||
auto& enabled_extensions = extensions_result.second;
|
||||
|
||||
// We wait until both extensions and layers are checked before failing out so
|
||||
// that the user gets a complete list of what they have/don't.
|
||||
if (!extensions_result.first || !layers_result.first) {
|
||||
XELOGE("Layer and extension verification failed; aborting initialization");
|
||||
return false;
|
||||
}
|
||||
|
||||
XELOGVK("Initializing application instance...");
|
||||
|
||||
// TODO(benvanik): use GetEntryInfo?
|
||||
VkApplicationInfo application_info;
|
||||
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
application_info.pNext = nullptr;
|
||||
application_info.pApplicationName = "xenia";
|
||||
application_info.applicationVersion = 1;
|
||||
application_info.pEngineName = "xenia";
|
||||
application_info.engineVersion = 1;
|
||||
application_info.apiVersion = VK_API_VERSION;
|
||||
|
||||
VkInstanceCreateInfo instance_info;
|
||||
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
instance_info.pNext = nullptr;
|
||||
instance_info.flags = 0;
|
||||
instance_info.pApplicationInfo = &application_info;
|
||||
instance_info.enabledLayerCount =
|
||||
static_cast<uint32_t>(enabled_layers.size());
|
||||
instance_info.ppEnabledLayerNames = enabled_layers.data();
|
||||
instance_info.enabledExtensionCount =
|
||||
static_cast<uint32_t>(enabled_extensions.size());
|
||||
instance_info.ppEnabledExtensionNames = enabled_extensions.data();
|
||||
|
||||
auto err = lfn_.vkCreateInstance(&instance_info, nullptr, &handle);
|
||||
if (err != VK_SUCCESS) {
|
||||
XELOGE("vkCreateInstance returned {}", to_string(err));
|
||||
}
|
||||
switch (err) {
|
||||
case VK_SUCCESS:
|
||||
// Ok!
|
||||
break;
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
XELOGE("Instance initialization failed; generic");
|
||||
return false;
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||
XELOGE(
|
||||
"Instance initialization failed; cannot find a compatible Vulkan "
|
||||
"installable client driver (ICD)");
|
||||
return false;
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
XELOGE("Instance initialization failed; requested extension not present");
|
||||
return false;
|
||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||
XELOGE("Instance initialization failed; requested layer not present");
|
||||
return false;
|
||||
default:
|
||||
XELOGE("Instance initialization failed; unknown: {}", to_string(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if extensions are enabled.
|
||||
dbg_report_ena_ = false;
|
||||
for (const char* enabled_extension : enabled_extensions) {
|
||||
if (!dbg_report_ena_ &&
|
||||
!std::strcmp(enabled_extension, VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) {
|
||||
dbg_report_ena_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get instance functions.
|
||||
std::memset(&ifn_, 0, sizeof(ifn_));
|
||||
bool instance_functions_loaded = true;
|
||||
#define XE_UI_VULKAN_FUNCTION(name) \
|
||||
instance_functions_loaded &= \
|
||||
(ifn_.name = PFN_##name(lfn_.vkGetInstanceProcAddr(handle, #name))) != \
|
||||
nullptr;
|
||||
#include "xenia/ui/vulkan/functions/instance_1_0.inc"
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_surface.inc"
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_android_surface.inc"
|
||||
#elif XE_PLATFORM_GNU_LINUX
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_xcb_surface.inc"
|
||||
#elif XE_PLATFORM_WIN32
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_win32_surface.inc"
|
||||
#endif
|
||||
if (dbg_report_ena_) {
|
||||
#include "xenia/ui/vulkan/functions/instance_ext_debug_report.inc"
|
||||
}
|
||||
#undef XE_VULKAN_LOAD_IFN
|
||||
if (!instance_functions_loaded) {
|
||||
XELOGE("Failed to get Vulkan instance function pointers");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable debug validation, if needed.
|
||||
EnableDebugValidation();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanInstance::DestroyInstance() {
|
||||
if (handle) {
|
||||
DisableDebugValidation();
|
||||
lfn_.vkDestroyInstance(handle, nullptr);
|
||||
handle = nullptr;
|
||||
}
|
||||
|
||||
#if XE_PLATFORM_LINUX
|
||||
if (library_) {
|
||||
dlclose(library_);
|
||||
library_ = nullptr;
|
||||
}
|
||||
#elif XE_PLATFORM_WIN32
|
||||
if (library_) {
|
||||
FreeLibrary(library_);
|
||||
library_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VkBool32 VKAPI_PTR DebugMessageCallback(VkDebugReportFlagsEXT flags,
|
||||
VkDebugReportObjectTypeEXT objectType,
|
||||
uint64_t object, size_t location,
|
||||
@@ -255,116 +430,14 @@ VkBool32 VKAPI_PTR DebugMessageCallback(VkDebugReportFlagsEXT flags,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VulkanInstance::CreateInstance() {
|
||||
XELOGVK("Verifying layers and extensions...");
|
||||
|
||||
// Gather list of enabled layer names.
|
||||
auto layers_result = CheckRequirements(required_layers_, global_layers_);
|
||||
auto& enabled_layers = layers_result.second;
|
||||
|
||||
// Gather list of enabled extension names.
|
||||
auto extensions_result =
|
||||
CheckRequirements(required_extensions_, global_extensions_);
|
||||
auto& enabled_extensions = extensions_result.second;
|
||||
|
||||
// We wait until both extensions and layers are checked before failing out so
|
||||
// that the user gets a complete list of what they have/don't.
|
||||
if (!extensions_result.first || !layers_result.first) {
|
||||
XELOGE("Layer and extension verification failed; aborting initialization");
|
||||
return false;
|
||||
}
|
||||
|
||||
XELOGVK("Initializing application instance...");
|
||||
|
||||
VkDebugReportCallbackCreateInfoEXT debug_info;
|
||||
debug_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
||||
debug_info.pNext = nullptr;
|
||||
// TODO(benvanik): flags to set these.
|
||||
debug_info.flags =
|
||||
VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
|
||||
VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
|
||||
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
|
||||
debug_info.pfnCallback = &DebugMessageCallback;
|
||||
debug_info.pUserData = this;
|
||||
|
||||
// TODO(benvanik): use GetEntryInfo?
|
||||
VkApplicationInfo application_info;
|
||||
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
application_info.pNext = &debug_info;
|
||||
application_info.pApplicationName = "xenia";
|
||||
application_info.applicationVersion = 1;
|
||||
application_info.pEngineName = "xenia";
|
||||
application_info.engineVersion = 1;
|
||||
application_info.apiVersion = VK_API_VERSION;
|
||||
|
||||
VkInstanceCreateInfo instance_info;
|
||||
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
instance_info.pNext = nullptr;
|
||||
instance_info.flags = 0;
|
||||
instance_info.pApplicationInfo = &application_info;
|
||||
instance_info.enabledLayerCount =
|
||||
static_cast<uint32_t>(enabled_layers.size());
|
||||
instance_info.ppEnabledLayerNames = enabled_layers.data();
|
||||
instance_info.enabledExtensionCount =
|
||||
static_cast<uint32_t>(enabled_extensions.size());
|
||||
instance_info.ppEnabledExtensionNames = enabled_extensions.data();
|
||||
|
||||
auto err = vkCreateInstance(&instance_info, nullptr, &handle);
|
||||
if (err != VK_SUCCESS) {
|
||||
XELOGE("vkCreateInstance returned {}", to_string(err));
|
||||
}
|
||||
switch (err) {
|
||||
case VK_SUCCESS:
|
||||
// Ok!
|
||||
break;
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
XELOGE("Instance initialization failed; generic");
|
||||
return false;
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||
XELOGE(
|
||||
"Instance initialization failed; cannot find a compatible Vulkan "
|
||||
"installable client driver (ICD)");
|
||||
return false;
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
XELOGE("Instance initialization failed; requested extension not present");
|
||||
return false;
|
||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||
XELOGE("Instance initialization failed; requested layer not present");
|
||||
return false;
|
||||
default:
|
||||
XELOGE("Instance initialization failed; unknown: {}", to_string(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load Vulkan entry points and extensions.
|
||||
volkLoadInstance(handle);
|
||||
|
||||
// Enable debug validation, if needed.
|
||||
EnableDebugValidation();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanInstance::DestroyInstance() {
|
||||
if (!handle) {
|
||||
return;
|
||||
}
|
||||
DisableDebugValidation();
|
||||
vkDestroyInstance(handle, nullptr);
|
||||
handle = nullptr;
|
||||
}
|
||||
|
||||
void VulkanInstance::EnableDebugValidation() {
|
||||
if (dbg_report_callback_) {
|
||||
DisableDebugValidation();
|
||||
}
|
||||
auto vk_create_debug_report_callback_ext =
|
||||
reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
|
||||
vkGetInstanceProcAddr(handle, "vkCreateDebugReportCallbackEXT"));
|
||||
if (!vk_create_debug_report_callback_ext) {
|
||||
if (!dbg_report_ena_) {
|
||||
XELOGVK("Debug validation layer not installed; ignoring");
|
||||
return;
|
||||
}
|
||||
if (dbg_report_callback_) {
|
||||
DisableDebugValidation();
|
||||
}
|
||||
VkDebugReportCallbackCreateInfoEXT create_info;
|
||||
create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
||||
create_info.pNext = nullptr;
|
||||
@@ -375,7 +448,7 @@ void VulkanInstance::EnableDebugValidation() {
|
||||
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
|
||||
create_info.pfnCallback = &DebugMessageCallback;
|
||||
create_info.pUserData = this;
|
||||
auto status = vk_create_debug_report_callback_ext(
|
||||
auto status = ifn_.vkCreateDebugReportCallbackEXT(
|
||||
handle, &create_info, nullptr, &dbg_report_callback_);
|
||||
if (status == VK_SUCCESS) {
|
||||
XELOGVK("Debug validation layer enabled");
|
||||
@@ -386,16 +459,10 @@ void VulkanInstance::EnableDebugValidation() {
|
||||
}
|
||||
|
||||
void VulkanInstance::DisableDebugValidation() {
|
||||
if (!dbg_report_callback_) {
|
||||
if (!dbg_report_ena_ || !dbg_report_callback_) {
|
||||
return;
|
||||
}
|
||||
auto vk_destroy_debug_report_callback_ext =
|
||||
reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
|
||||
vkGetInstanceProcAddr(handle, "vkDestroyDebugReportCallbackEXT"));
|
||||
if (!vk_destroy_debug_report_callback_ext) {
|
||||
return;
|
||||
}
|
||||
vk_destroy_debug_report_callback_ext(handle, dbg_report_callback_, nullptr);
|
||||
ifn_.vkDestroyDebugReportCallbackEXT(handle, dbg_report_callback_, nullptr);
|
||||
dbg_report_callback_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -403,11 +470,11 @@ bool VulkanInstance::QueryDevices() {
|
||||
// Get handles to all devices.
|
||||
uint32_t count = 0;
|
||||
std::vector<VkPhysicalDevice> device_handles;
|
||||
auto err = vkEnumeratePhysicalDevices(handle, &count, nullptr);
|
||||
auto err = ifn_.vkEnumeratePhysicalDevices(handle, &count, nullptr);
|
||||
CheckResult(err, "vkEnumeratePhysicalDevices");
|
||||
|
||||
device_handles.resize(count);
|
||||
err = vkEnumeratePhysicalDevices(handle, &count, device_handles.data());
|
||||
err = ifn_.vkEnumeratePhysicalDevices(handle, &count, device_handles.data());
|
||||
CheckResult(err, "vkEnumeratePhysicalDevices");
|
||||
|
||||
// Query device info.
|
||||
@@ -417,33 +484,34 @@ bool VulkanInstance::QueryDevices() {
|
||||
device_info.handle = device_handle;
|
||||
|
||||
// Query general attributes.
|
||||
vkGetPhysicalDeviceProperties(device_handle, &device_info.properties);
|
||||
vkGetPhysicalDeviceFeatures(device_handle, &device_info.features);
|
||||
vkGetPhysicalDeviceMemoryProperties(device_handle,
|
||||
&device_info.memory_properties);
|
||||
ifn_.vkGetPhysicalDeviceProperties(device_handle, &device_info.properties);
|
||||
ifn_.vkGetPhysicalDeviceFeatures(device_handle, &device_info.features);
|
||||
ifn_.vkGetPhysicalDeviceMemoryProperties(device_handle,
|
||||
&device_info.memory_properties);
|
||||
|
||||
// Gather queue family properties.
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device_handle, &count, nullptr);
|
||||
ifn_.vkGetPhysicalDeviceQueueFamilyProperties(device_handle, &count,
|
||||
nullptr);
|
||||
device_info.queue_family_properties.resize(count);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
ifn_.vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
device_handle, &count, device_info.queue_family_properties.data());
|
||||
|
||||
// Gather layers.
|
||||
std::vector<VkLayerProperties> layer_properties;
|
||||
err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr);
|
||||
err = ifn_.vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr);
|
||||
CheckResult(err, "vkEnumerateDeviceLayerProperties");
|
||||
layer_properties.resize(count);
|
||||
err = vkEnumerateDeviceLayerProperties(device_handle, &count,
|
||||
layer_properties.data());
|
||||
err = ifn_.vkEnumerateDeviceLayerProperties(device_handle, &count,
|
||||
layer_properties.data());
|
||||
CheckResult(err, "vkEnumerateDeviceLayerProperties");
|
||||
for (size_t j = 0; j < layer_properties.size(); ++j) {
|
||||
LayerInfo layer_info;
|
||||
layer_info.properties = layer_properties[j];
|
||||
err = vkEnumerateDeviceExtensionProperties(
|
||||
err = ifn_.vkEnumerateDeviceExtensionProperties(
|
||||
device_handle, layer_info.properties.layerName, &count, nullptr);
|
||||
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
||||
layer_info.extensions.resize(count);
|
||||
err = vkEnumerateDeviceExtensionProperties(
|
||||
err = ifn_.vkEnumerateDeviceExtensionProperties(
|
||||
device_handle, layer_info.properties.layerName, &count,
|
||||
layer_info.extensions.data());
|
||||
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
||||
@@ -451,12 +519,12 @@ bool VulkanInstance::QueryDevices() {
|
||||
}
|
||||
|
||||
// Gather extensions.
|
||||
err = vkEnumerateDeviceExtensionProperties(device_handle, nullptr, &count,
|
||||
nullptr);
|
||||
err = ifn_.vkEnumerateDeviceExtensionProperties(device_handle, nullptr,
|
||||
&count, nullptr);
|
||||
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
||||
device_info.extensions.resize(count);
|
||||
err = vkEnumerateDeviceExtensionProperties(device_handle, nullptr, &count,
|
||||
device_info.extensions.data());
|
||||
err = ifn_.vkEnumerateDeviceExtensionProperties(
|
||||
device_handle, nullptr, &count, device_info.extensions.data());
|
||||
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
||||
|
||||
available_devices_.push_back(std::move(device_info));
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/ui/vulkan/vulkan.h"
|
||||
#include "xenia/ui/vulkan/vulkan_util.h"
|
||||
#include "xenia/ui/window.h"
|
||||
@@ -28,10 +29,38 @@ class VulkanInstance {
|
||||
VulkanInstance();
|
||||
~VulkanInstance();
|
||||
|
||||
struct LibraryFunctions {
|
||||
// From the module.
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
PFN_vkDestroyInstance vkDestroyInstance;
|
||||
// From vkGetInstanceProcAddr.
|
||||
PFN_vkCreateInstance vkCreateInstance;
|
||||
PFN_vkEnumerateInstanceExtensionProperties
|
||||
vkEnumerateInstanceExtensionProperties;
|
||||
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
|
||||
};
|
||||
const LibraryFunctions& lfn() const { return lfn_; }
|
||||
|
||||
VkInstance handle = nullptr;
|
||||
|
||||
operator VkInstance() const { return handle; }
|
||||
|
||||
struct InstanceFunctions {
|
||||
#define XE_UI_VULKAN_FUNCTION(name) PFN_##name name;
|
||||
#include "xenia/ui/vulkan/functions/instance_1_0.inc"
|
||||
#include "xenia/ui/vulkan/functions/instance_ext_debug_report.inc"
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_surface.inc"
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_android_surface.inc"
|
||||
#elif XE_PLATFORM_GNU_LINUX
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_xcb_surface.inc"
|
||||
#elif XE_PLATFORM_WIN32
|
||||
#include "xenia/ui/vulkan/functions/instance_khr_win32_surface.inc"
|
||||
#endif
|
||||
#undef XE_UI_VULKAN_FUNCTION
|
||||
};
|
||||
const InstanceFunctions& ifn() const { return ifn_; }
|
||||
|
||||
// Declares a layer to verify and enable upon initialization.
|
||||
// Must be called before Initialize.
|
||||
void DeclareRequiredLayer(std::string name, uint32_t min_version,
|
||||
@@ -85,13 +114,24 @@ class VulkanInstance {
|
||||
const char* indent);
|
||||
void DumpDeviceInfo(const DeviceInfo& device_info);
|
||||
|
||||
#if XE_PLATFORM_LINUX
|
||||
void* library_ = nullptr;
|
||||
#elif XE_PLATFORM_WIN32
|
||||
HMODULE library_ = nullptr;
|
||||
#endif
|
||||
|
||||
LibraryFunctions lfn_ = {};
|
||||
|
||||
std::vector<Requirement> required_layers_;
|
||||
std::vector<Requirement> required_extensions_;
|
||||
|
||||
InstanceFunctions ifn_ = {};
|
||||
|
||||
std::vector<LayerInfo> global_layers_;
|
||||
std::vector<VkExtensionProperties> global_extensions_;
|
||||
std::vector<DeviceInfo> available_devices_;
|
||||
|
||||
bool dbg_report_ena_ = false;
|
||||
VkDebugReportCallbackEXT dbg_report_callback_ = nullptr;
|
||||
|
||||
void* renderdoc_api_ = nullptr;
|
||||
|
||||
@@ -10,31 +10,35 @@
|
||||
#ifndef XENIA_UI_VULKAN_VULKAN_MEM_ALLOC_H_
|
||||
#define XENIA_UI_VULKAN_VULKAN_MEM_ALLOC_H_
|
||||
|
||||
#include "third_party/volk/volk.h"
|
||||
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#include "third_party/vulkan/vk_mem_alloc.h"
|
||||
|
||||
#include "xenia/ui/vulkan/vulkan_device.h"
|
||||
#include "xenia/ui/vulkan/vulkan_instance.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
inline void FillVMAVulkanFunctions(VmaVulkanFunctions* vma_funcs) {
|
||||
vma_funcs->vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
|
||||
inline void FillVMAVulkanFunctions(VmaVulkanFunctions* vma_funcs,
|
||||
const VulkanDevice& device) {
|
||||
const VulkanInstance::InstanceFunctions& ifn = device.instance()->ifn();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device.dfn();
|
||||
vma_funcs->vkGetPhysicalDeviceProperties = ifn.vkGetPhysicalDeviceProperties;
|
||||
vma_funcs->vkGetPhysicalDeviceMemoryProperties =
|
||||
vkGetPhysicalDeviceMemoryProperties;
|
||||
vma_funcs->vkAllocateMemory = vkAllocateMemory;
|
||||
vma_funcs->vkFreeMemory = vkFreeMemory;
|
||||
vma_funcs->vkMapMemory = vkMapMemory;
|
||||
vma_funcs->vkUnmapMemory = vkUnmapMemory;
|
||||
vma_funcs->vkBindBufferMemory = vkBindBufferMemory;
|
||||
vma_funcs->vkBindImageMemory = vkBindImageMemory;
|
||||
vma_funcs->vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
|
||||
vma_funcs->vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
|
||||
vma_funcs->vkCreateBuffer = vkCreateBuffer;
|
||||
vma_funcs->vkDestroyBuffer = vkDestroyBuffer;
|
||||
vma_funcs->vkCreateImage = vkCreateImage;
|
||||
vma_funcs->vkDestroyImage = vkDestroyImage;
|
||||
ifn.vkGetPhysicalDeviceMemoryProperties;
|
||||
vma_funcs->vkAllocateMemory = dfn.vkAllocateMemory;
|
||||
vma_funcs->vkFreeMemory = dfn.vkFreeMemory;
|
||||
vma_funcs->vkMapMemory = dfn.vkMapMemory;
|
||||
vma_funcs->vkUnmapMemory = dfn.vkUnmapMemory;
|
||||
vma_funcs->vkBindBufferMemory = dfn.vkBindBufferMemory;
|
||||
vma_funcs->vkBindImageMemory = dfn.vkBindImageMemory;
|
||||
vma_funcs->vkGetBufferMemoryRequirements = dfn.vkGetBufferMemoryRequirements;
|
||||
vma_funcs->vkGetImageMemoryRequirements = dfn.vkGetImageMemoryRequirements;
|
||||
vma_funcs->vkCreateBuffer = dfn.vkCreateBuffer;
|
||||
vma_funcs->vkDestroyBuffer = dfn.vkDestroyBuffer;
|
||||
vma_funcs->vkCreateImage = dfn.vkCreateImage;
|
||||
vma_funcs->vkDestroyImage = dfn.vkDestroyImage;
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
|
||||
@@ -52,14 +52,16 @@ bool VulkanProvider::Initialize() {
|
||||
instance_ = std::make_unique<VulkanInstance>();
|
||||
|
||||
// Always enable the swapchain.
|
||||
instance_->DeclareRequiredExtension(VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
#if XE_PLATFORM_GNU_LINUX || XE_PLATFORM_WIN32
|
||||
instance_->DeclareRequiredExtension("VK_KHR_surface", Version::Make(0, 0, 0),
|
||||
false);
|
||||
#if XE_PLATFORM_GNU_LINUX
|
||||
instance_->DeclareRequiredExtension("VK_KHR_xcb_surface",
|
||||
Version::Make(0, 0, 0), false);
|
||||
#if XE_PLATFORM_WIN32
|
||||
instance_->DeclareRequiredExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
|
||||
Version::Make(0, 0, 0), false);
|
||||
#elif XE_PLATFORM_LINUX
|
||||
instance_->DeclareRequiredExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
|
||||
#elif XE_PLATFORM_WIN32
|
||||
instance_->DeclareRequiredExtension("VK_KHR_win32_surface",
|
||||
Version::Make(0, 0, 0), false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Attempt initialization and device query.
|
||||
|
||||
@@ -35,6 +35,8 @@ VulkanSwapChain::~VulkanSwapChain() { Shutdown(); }
|
||||
|
||||
VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
surface_ = surface;
|
||||
const VulkanInstance::InstanceFunctions& ifn = instance_->ifn();
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
// Find a queue family that supports presentation.
|
||||
@@ -49,8 +51,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = vkGetPhysicalDeviceSurfaceSupportKHR(*device_, i, surface,
|
||||
&surface_supported);
|
||||
status = ifn.vkGetPhysicalDeviceSurfaceSupportKHR(*device_, i, surface,
|
||||
&surface_supported);
|
||||
if (status == VK_SUCCESS && surface_supported == VK_TRUE) {
|
||||
queue_family_index = i;
|
||||
break;
|
||||
@@ -80,13 +82,13 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
|
||||
// Query supported target formats.
|
||||
uint32_t count = 0;
|
||||
status =
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count, nullptr);
|
||||
status = ifn.vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count,
|
||||
nullptr);
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||
std::vector<VkSurfaceFormatKHR> surface_formats;
|
||||
surface_formats.resize(count);
|
||||
status = vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count,
|
||||
surface_formats.data());
|
||||
status = ifn.vkGetPhysicalDeviceSurfaceFormatsKHR(*device_, surface_, &count,
|
||||
surface_formats.data());
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -107,8 +109,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
|
||||
// Query surface min/max/caps.
|
||||
VkSurfaceCapabilitiesKHR surface_caps;
|
||||
status = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*device_, surface_,
|
||||
&surface_caps);
|
||||
status = ifn.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(*device_, surface_,
|
||||
&surface_caps);
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -116,16 +118,16 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
|
||||
// Query surface properties so we can configure ourselves within bounds.
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
status = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
||||
nullptr);
|
||||
status = ifn.vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_,
|
||||
&count, nullptr);
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
present_modes.resize(count);
|
||||
status = vkGetPhysicalDeviceSurfacePresentModesKHR(*device_, surface_, &count,
|
||||
present_modes.data());
|
||||
status = ifn.vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
*device_, surface_, &count, present_modes.data());
|
||||
CheckResult(status, "vkGetPhysicalDeviceSurfacePresentModesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -210,7 +212,7 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
XELOGVK(" imageSharingMode = {}", to_string(create_info.imageSharingMode));
|
||||
XELOGVK(" queueFamilyCount = {}", create_info.queueFamilyIndexCount);
|
||||
|
||||
status = vkCreateSwapchainKHR(*device_, &create_info, nullptr, &handle);
|
||||
status = dfn.vkCreateSwapchainKHR(*device_, &create_info, nullptr, &handle);
|
||||
if (status != VK_SUCCESS) {
|
||||
XELOGE("Failed to create swapchain: {}", to_string(status));
|
||||
return status;
|
||||
@@ -223,7 +225,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
cmd_pool_info.pNext = nullptr;
|
||||
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
cmd_pool_info.queueFamilyIndex = presentation_queue_family_;
|
||||
status = vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_);
|
||||
status =
|
||||
dfn.vkCreateCommandPool(*device_, &cmd_pool_info, nullptr, &cmd_pool_);
|
||||
CheckResult(status, "vkCreateCommandPool");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -236,7 +239,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
cmd_buffer_info.commandPool = cmd_pool_;
|
||||
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmd_buffer_info.commandBufferCount = 2;
|
||||
status = vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &cmd_buffer_);
|
||||
status =
|
||||
dfn.vkAllocateCommandBuffers(*device_, &cmd_buffer_info, &cmd_buffer_);
|
||||
CheckResult(status, "vkCreateCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -247,7 +251,7 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
|
||||
cmd_buffer_info.commandBufferCount = 2;
|
||||
status =
|
||||
vkAllocateCommandBuffers(*device_, &cmd_buffer_info, command_buffers);
|
||||
dfn.vkAllocateCommandBuffers(*device_, &cmd_buffer_info, command_buffers);
|
||||
CheckResult(status, "vkCreateCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -296,8 +300,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
render_pass_info.pSubpasses = &render_subpass;
|
||||
render_pass_info.dependencyCount = 0;
|
||||
render_pass_info.pDependencies = nullptr;
|
||||
status =
|
||||
vkCreateRenderPass(*device_, &render_pass_info, nullptr, &render_pass_);
|
||||
status = dfn.vkCreateRenderPass(*device_, &render_pass_info, nullptr,
|
||||
&render_pass_);
|
||||
CheckResult(status, "vkCreateRenderPass");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -308,16 +312,16 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
semaphore_info.pNext = nullptr;
|
||||
semaphore_info.flags = 0;
|
||||
status = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||
&image_available_semaphore_);
|
||||
status = dfn.vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||
&image_available_semaphore_);
|
||||
CheckResult(status, "vkCreateSemaphore");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Create another semaphore used to synchronize writes to the swap image.
|
||||
status = vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||
&image_usage_semaphore_);
|
||||
status = dfn.vkCreateSemaphore(*device_, &semaphore_info, nullptr,
|
||||
&image_usage_semaphore_);
|
||||
CheckResult(status, "vkCreateSemaphore");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -327,16 +331,16 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
// Note that this may differ from our requested amount.
|
||||
uint32_t actual_image_count = 0;
|
||||
std::vector<VkImage> images;
|
||||
status =
|
||||
vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count, nullptr);
|
||||
status = dfn.vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count,
|
||||
nullptr);
|
||||
CheckResult(status, "vkGetSwapchainImagesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
images.resize(actual_image_count);
|
||||
status = vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count,
|
||||
images.data());
|
||||
status = dfn.vkGetSwapchainImagesKHR(*device_, handle, &actual_image_count,
|
||||
images.data());
|
||||
CheckResult(status, "vkGetSwapchainImagesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -360,8 +364,8 @@ VkResult VulkanSwapChain::Initialize(VkSurfaceKHR surface) {
|
||||
nullptr,
|
||||
VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
status = vkCreateFence(*device_, &fence_create_info, nullptr,
|
||||
&synchronization_fence_);
|
||||
status = dfn.vkCreateFence(*device_, &fence_create_info, nullptr,
|
||||
&synchronization_fence_);
|
||||
CheckResult(status, "vkGetSwapchainImagesKHR");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -376,6 +380,7 @@ VkResult VulkanSwapChain::InitializeBuffer(Buffer* buffer,
|
||||
DestroyBuffer(buffer);
|
||||
buffer->image = target_image;
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
// Create an image view for the presentation image.
|
||||
@@ -396,8 +401,8 @@ VkResult VulkanSwapChain::InitializeBuffer(Buffer* buffer,
|
||||
image_view_info.subresourceRange.levelCount = 1;
|
||||
image_view_info.subresourceRange.baseArrayLayer = 0;
|
||||
image_view_info.subresourceRange.layerCount = 1;
|
||||
status = vkCreateImageView(*device_, &image_view_info, nullptr,
|
||||
&buffer->image_view);
|
||||
status = dfn.vkCreateImageView(*device_, &image_view_info, nullptr,
|
||||
&buffer->image_view);
|
||||
CheckResult(status, "vkCreateImageView");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -416,8 +421,8 @@ VkResult VulkanSwapChain::InitializeBuffer(Buffer* buffer,
|
||||
framebuffer_info.width = surface_width_;
|
||||
framebuffer_info.height = surface_height_;
|
||||
framebuffer_info.layers = 1;
|
||||
status = vkCreateFramebuffer(*device_, &framebuffer_info, nullptr,
|
||||
&buffer->framebuffer);
|
||||
status = dfn.vkCreateFramebuffer(*device_, &framebuffer_info, nullptr,
|
||||
&buffer->framebuffer);
|
||||
CheckResult(status, "vkCreateFramebuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -427,12 +432,13 @@ VkResult VulkanSwapChain::InitializeBuffer(Buffer* buffer,
|
||||
}
|
||||
|
||||
void VulkanSwapChain::DestroyBuffer(Buffer* buffer) {
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
if (buffer->framebuffer) {
|
||||
vkDestroyFramebuffer(*device_, buffer->framebuffer, nullptr);
|
||||
dfn.vkDestroyFramebuffer(*device_, buffer->framebuffer, nullptr);
|
||||
buffer->framebuffer = nullptr;
|
||||
}
|
||||
if (buffer->image_view) {
|
||||
vkDestroyImageView(*device_, buffer->image_view, nullptr);
|
||||
dfn.vkDestroyImageView(*device_, buffer->image_view, nullptr);
|
||||
buffer->image_view = nullptr;
|
||||
}
|
||||
// Image is taken care of by the presentation engine.
|
||||
@@ -458,19 +464,21 @@ void VulkanSwapChain::Shutdown() {
|
||||
}
|
||||
buffers_.clear();
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroySemaphore, *device_, image_available_semaphore_,
|
||||
nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroyRenderPass, *device_, render_pass_, nullptr);
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
|
||||
DestroyAndNullHandle(dfn.vkDestroySemaphore, *device_,
|
||||
image_available_semaphore_);
|
||||
DestroyAndNullHandle(dfn.vkDestroyRenderPass, *device_, render_pass_);
|
||||
|
||||
if (copy_cmd_buffer_) {
|
||||
vkFreeCommandBuffers(*device_, cmd_pool_, 1, ©_cmd_buffer_);
|
||||
dfn.vkFreeCommandBuffers(*device_, cmd_pool_, 1, ©_cmd_buffer_);
|
||||
copy_cmd_buffer_ = nullptr;
|
||||
}
|
||||
if (render_cmd_buffer_) {
|
||||
vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_);
|
||||
dfn.vkFreeCommandBuffers(*device_, cmd_pool_, 1, &render_cmd_buffer_);
|
||||
render_cmd_buffer_ = nullptr;
|
||||
}
|
||||
VK_SAFE_DESTROY(vkDestroyCommandPool, *device_, cmd_pool_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyCommandPool, *device_, cmd_pool_);
|
||||
|
||||
if (presentation_queue_) {
|
||||
if (!presentation_queue_mutex_) {
|
||||
@@ -482,33 +490,36 @@ void VulkanSwapChain::Shutdown() {
|
||||
presentation_queue_family_ = -1;
|
||||
}
|
||||
|
||||
VK_SAFE_DESTROY(vkDestroyFence, *device_, synchronization_fence_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroyFence, *device_, synchronization_fence_);
|
||||
|
||||
// images_ doesn't need to be cleaned up as the swapchain does it implicitly.
|
||||
VK_SAFE_DESTROY(vkDestroySwapchainKHR, *device_, handle, nullptr);
|
||||
VK_SAFE_DESTROY(vkDestroySurfaceKHR, *instance_, surface_, nullptr);
|
||||
DestroyAndNullHandle(dfn.vkDestroySwapchainKHR, *device_, handle);
|
||||
const VulkanInstance::InstanceFunctions& ifn = instance_->ifn();
|
||||
DestroyAndNullHandle(ifn.vkDestroySurfaceKHR, *instance_, surface_);
|
||||
}
|
||||
|
||||
VkResult VulkanSwapChain::Begin() {
|
||||
wait_semaphores_.clear();
|
||||
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
// Wait for the last swap to finish.
|
||||
status = vkWaitForFences(*device_, 1, &synchronization_fence_, VK_TRUE, -1);
|
||||
status =
|
||||
dfn.vkWaitForFences(*device_, 1, &synchronization_fence_, VK_TRUE, -1);
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = vkResetFences(*device_, 1, &synchronization_fence_);
|
||||
status = dfn.vkResetFences(*device_, 1, &synchronization_fence_);
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get the index of the next available swapchain image.
|
||||
status =
|
||||
vkAcquireNextImageKHR(*device_, handle, 0, image_available_semaphore_,
|
||||
nullptr, ¤t_buffer_index_);
|
||||
dfn.vkAcquireNextImageKHR(*device_, handle, 0, image_available_semaphore_,
|
||||
nullptr, ¤t_buffer_index_);
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
@@ -531,7 +542,8 @@ VkResult VulkanSwapChain::Begin() {
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->lock();
|
||||
}
|
||||
status = vkQueueSubmit(presentation_queue_, 1, &wait_submit_info, nullptr);
|
||||
status =
|
||||
dfn.vkQueueSubmit(presentation_queue_, 1, &wait_submit_info, nullptr);
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->unlock();
|
||||
}
|
||||
@@ -540,8 +552,8 @@ VkResult VulkanSwapChain::Begin() {
|
||||
}
|
||||
|
||||
// Reset all command buffers.
|
||||
vkResetCommandBuffer(render_cmd_buffer_, 0);
|
||||
vkResetCommandBuffer(copy_cmd_buffer_, 0);
|
||||
dfn.vkResetCommandBuffer(render_cmd_buffer_, 0);
|
||||
dfn.vkResetCommandBuffer(copy_cmd_buffer_, 0);
|
||||
auto& current_buffer = buffers_[current_buffer_index_];
|
||||
|
||||
// Build the command buffer that will execute all queued rendering buffers.
|
||||
@@ -561,7 +573,7 @@ VkResult VulkanSwapChain::Begin() {
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
|
||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
begin_info.pInheritanceInfo = &inherit_info;
|
||||
status = vkBeginCommandBuffer(render_cmd_buffer_, &begin_info);
|
||||
status = dfn.vkBeginCommandBuffer(render_cmd_buffer_, &begin_info);
|
||||
CheckResult(status, "vkBeginCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -569,7 +581,7 @@ VkResult VulkanSwapChain::Begin() {
|
||||
|
||||
// Start recording the copy command buffer as well.
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
status = vkBeginCommandBuffer(copy_cmd_buffer_, &begin_info);
|
||||
status = dfn.vkBeginCommandBuffer(copy_cmd_buffer_, &begin_info);
|
||||
CheckResult(status, "vkBeginCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -588,31 +600,32 @@ VkResult VulkanSwapChain::Begin() {
|
||||
clear_color.float32[1] = 1.0f;
|
||||
clear_color.float32[2] = 0.0f;
|
||||
}
|
||||
vkCmdClearColorImage(copy_cmd_buffer_, current_buffer.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1,
|
||||
&clear_range);
|
||||
dfn.vkCmdClearColorImage(copy_cmd_buffer_, current_buffer.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color,
|
||||
1, &clear_range);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult VulkanSwapChain::End() {
|
||||
auto& current_buffer = buffers_[current_buffer_index_];
|
||||
const VulkanDevice::DeviceFunctions& dfn = device_->dfn();
|
||||
VkResult status;
|
||||
|
||||
status = vkEndCommandBuffer(render_cmd_buffer_);
|
||||
status = dfn.vkEndCommandBuffer(render_cmd_buffer_);
|
||||
CheckResult(status, "vkEndCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = vkEndCommandBuffer(copy_cmd_buffer_);
|
||||
status = dfn.vkEndCommandBuffer(copy_cmd_buffer_);
|
||||
CheckResult(status, "vkEndCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Build primary command buffer.
|
||||
status = vkResetCommandBuffer(cmd_buffer_, 0);
|
||||
status = dfn.vkResetCommandBuffer(cmd_buffer_, 0);
|
||||
CheckResult(status, "vkResetCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -623,7 +636,7 @@ VkResult VulkanSwapChain::End() {
|
||||
begin_info.pNext = nullptr;
|
||||
begin_info.flags = 0;
|
||||
begin_info.pInheritanceInfo = nullptr;
|
||||
status = vkBeginCommandBuffer(cmd_buffer_, &begin_info);
|
||||
status = dfn.vkBeginCommandBuffer(cmd_buffer_, &begin_info);
|
||||
CheckResult(status, "vkBeginCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -642,14 +655,14 @@ VkResult VulkanSwapChain::End() {
|
||||
pre_image_copy_barrier.image = current_buffer.image;
|
||||
pre_image_copy_barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
|
||||
1};
|
||||
vkCmdPipelineBarrier(cmd_buffer_, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &pre_image_copy_barrier);
|
||||
dfn.vkCmdPipelineBarrier(cmd_buffer_, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &pre_image_copy_barrier);
|
||||
|
||||
current_buffer.image_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
|
||||
// Execute copy commands
|
||||
vkCmdExecuteCommands(cmd_buffer_, 1, ©_cmd_buffer_);
|
||||
dfn.vkCmdExecuteCommands(cmd_buffer_, 1, ©_cmd_buffer_);
|
||||
|
||||
// Transition the image to a color attachment target for drawing.
|
||||
VkImageMemoryBarrier pre_image_memory_barrier;
|
||||
@@ -669,9 +682,9 @@ VkResult VulkanSwapChain::End() {
|
||||
pre_image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
pre_image_memory_barrier.oldLayout = current_buffer.image_layout;
|
||||
pre_image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
vkCmdPipelineBarrier(cmd_buffer_, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0,
|
||||
nullptr, 0, nullptr, 1, &pre_image_memory_barrier);
|
||||
dfn.vkCmdPipelineBarrier(cmd_buffer_, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0,
|
||||
nullptr, 0, nullptr, 1, &pre_image_memory_barrier);
|
||||
|
||||
current_buffer.image_layout = pre_image_memory_barrier.newLayout;
|
||||
|
||||
@@ -687,14 +700,14 @@ VkResult VulkanSwapChain::End() {
|
||||
render_pass_begin_info.renderArea.extent.height = surface_height_;
|
||||
render_pass_begin_info.clearValueCount = 0;
|
||||
render_pass_begin_info.pClearValues = nullptr;
|
||||
vkCmdBeginRenderPass(cmd_buffer_, &render_pass_begin_info,
|
||||
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
|
||||
dfn.vkCmdBeginRenderPass(cmd_buffer_, &render_pass_begin_info,
|
||||
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
|
||||
|
||||
// Render commands.
|
||||
vkCmdExecuteCommands(cmd_buffer_, 1, &render_cmd_buffer_);
|
||||
dfn.vkCmdExecuteCommands(cmd_buffer_, 1, &render_cmd_buffer_);
|
||||
|
||||
// End render pass.
|
||||
vkCmdEndRenderPass(cmd_buffer_);
|
||||
dfn.vkCmdEndRenderPass(cmd_buffer_);
|
||||
|
||||
// Transition the image to a format the presentation engine can source from.
|
||||
// FIXME: Do we need more synchronization here between the copy buffer?
|
||||
@@ -715,14 +728,14 @@ VkResult VulkanSwapChain::End() {
|
||||
post_image_memory_barrier.subresourceRange.levelCount = 1;
|
||||
post_image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
||||
post_image_memory_barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(cmd_buffer_,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &post_image_memory_barrier);
|
||||
dfn.vkCmdPipelineBarrier(cmd_buffer_,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||
nullptr, 1, &post_image_memory_barrier);
|
||||
|
||||
current_buffer.image_layout = post_image_memory_barrier.newLayout;
|
||||
|
||||
status = vkEndCommandBuffer(cmd_buffer_);
|
||||
status = dfn.vkEndCommandBuffer(cmd_buffer_);
|
||||
CheckResult(status, "vkEndCommandBuffer");
|
||||
if (status != VK_SUCCESS) {
|
||||
return status;
|
||||
@@ -752,8 +765,8 @@ VkResult VulkanSwapChain::End() {
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->lock();
|
||||
}
|
||||
status = vkQueueSubmit(presentation_queue_, 1, &render_submit_info,
|
||||
synchronization_fence_);
|
||||
status = dfn.vkQueueSubmit(presentation_queue_, 1, &render_submit_info,
|
||||
synchronization_fence_);
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->unlock();
|
||||
}
|
||||
@@ -777,7 +790,7 @@ VkResult VulkanSwapChain::End() {
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->lock();
|
||||
}
|
||||
status = vkQueuePresentKHR(presentation_queue_, &present_info);
|
||||
status = dfn.vkQueuePresentKHR(presentation_queue_, &present_info);
|
||||
if (presentation_queue_mutex_) {
|
||||
presentation_queue_mutex_->unlock();
|
||||
}
|
||||
|
||||
@@ -26,39 +26,37 @@ namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
#define VK_SAFE_DESTROY(fn, dev, obj, alloc) \
|
||||
\
|
||||
do { \
|
||||
if (obj) { \
|
||||
fn(dev, obj, alloc); \
|
||||
obj = nullptr; \
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
class Fence {
|
||||
public:
|
||||
Fence(VkDevice device) : device_(device) {
|
||||
VkFenceCreateInfo fence_info;
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.pNext = nullptr;
|
||||
fence_info.flags = 0;
|
||||
vkCreateFence(device, &fence_info, nullptr, &fence_);
|
||||
template <typename F, typename T>
|
||||
inline bool DestroyAndNullHandle(F* destroy_function, T& handle) {
|
||||
if (handle != VK_NULL_HANDLE) {
|
||||
destroy_function(handle, nullptr);
|
||||
handle = VK_NULL_HANDLE;
|
||||
return true;
|
||||
}
|
||||
~Fence() {
|
||||
vkDestroyFence(device_, fence_, nullptr);
|
||||
fence_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
inline bool DestroyAndNullHandle(F* destroy_function, VkInstance parent,
|
||||
T& handle) {
|
||||
if (handle != VK_NULL_HANDLE) {
|
||||
destroy_function(parent, handle, nullptr);
|
||||
handle = VK_NULL_HANDLE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult status() const { return vkGetFenceStatus(device_, fence_); }
|
||||
|
||||
VkFence fence() const { return fence_; }
|
||||
operator VkFence() const { return fence_; }
|
||||
|
||||
private:
|
||||
VkDevice device_;
|
||||
VkFence fence_ = nullptr;
|
||||
};
|
||||
template <typename F, typename T>
|
||||
inline bool DestroyAndNullHandle(F* destroy_function, VkDevice parent,
|
||||
T& handle) {
|
||||
if (handle != VK_NULL_HANDLE) {
|
||||
destroy_function(parent, handle, nullptr);
|
||||
handle = VK_NULL_HANDLE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Version {
|
||||
uint32_t major;
|
||||
|
||||
@@ -259,20 +259,21 @@ void Window::OnLostFocus(UIEvent* e) {
|
||||
|
||||
void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) {
|
||||
if (!is_char) {
|
||||
switch (e->key_code()) {
|
||||
case 16:
|
||||
switch (e->virtual_key()) {
|
||||
case VirtualKey::kShift:
|
||||
modifier_shift_pressed_ = is_down;
|
||||
break;
|
||||
case 17:
|
||||
case VirtualKey::kControl:
|
||||
modifier_cntrl_pressed_ = is_down;
|
||||
break;
|
||||
// case xx:
|
||||
// // alt ??
|
||||
// modifier_alt_pressed_ = is_down;
|
||||
// break;
|
||||
case 91:
|
||||
case VirtualKey::kMenu:
|
||||
modifier_alt_pressed_ = is_down;
|
||||
break;
|
||||
case VirtualKey::kLWin:
|
||||
modifier_super_pressed_ = is_down;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "xenia/base/delegate.h"
|
||||
#include "xenia/base/platform.h"
|
||||
#include "xenia/ui/graphics_context.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
#include "xenia/ui/menu_item.h"
|
||||
@@ -172,9 +173,16 @@ class Window {
|
||||
Loop* loop_ = nullptr;
|
||||
std::unique_ptr<MenuItem> main_menu_;
|
||||
std::string title_;
|
||||
#ifdef XE_PLATFORM_GNU_LINUX
|
||||
// GTK must have a default value here that isn't 0
|
||||
// TODO(Triang3l): Cleanup and unify this. May need to get the first resize
|
||||
// message on various platforms.
|
||||
int32_t width_ = 1280;
|
||||
int32_t height_ = 720;
|
||||
#else
|
||||
int32_t width_ = 0;
|
||||
int32_t height_ = 0;
|
||||
#endif
|
||||
bool has_focus_ = true;
|
||||
bool is_cursor_visible_ = true;
|
||||
bool is_imgui_input_enabled_ = false;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "xenia/ui/graphics_provider.h"
|
||||
#include "xenia/ui/imgui_dialog.h"
|
||||
#include "xenia/ui/imgui_drawer.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -92,10 +93,12 @@ int window_demo_main(const std::vector<std::string>& args) {
|
||||
loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); });
|
||||
|
||||
window->on_key_down.AddListener([](xe::ui::KeyEvent* e) {
|
||||
switch (e->key_code()) {
|
||||
case 0x72: { // F3
|
||||
switch (e->virtual_key()) {
|
||||
case VirtualKey::kF3:
|
||||
Profiler::ToggleDisplay();
|
||||
} break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform_linux.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
#include "xenia/ui/window_gtk.h"
|
||||
|
||||
namespace xe {
|
||||
@@ -31,7 +32,9 @@ GTKWindow::GTKWindow(Loop* loop, const std::string& title)
|
||||
GTKWindow::~GTKWindow() {
|
||||
OnDestroy();
|
||||
if (window_) {
|
||||
if (GTK_IS_WIDGET(window_)) gtk_widget_destroy(window_);
|
||||
if (GTK_IS_WIDGET(window_)) {
|
||||
gtk_widget_destroy(window_);
|
||||
}
|
||||
window_ = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -406,9 +409,10 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) {
|
||||
bool alt_pressed = modifiers & GDK_META_MASK;
|
||||
bool super_pressed = modifiers & GDK_SUPER_MASK;
|
||||
uint32_t key_char = gdk_keyval_to_unicode(event->keyval);
|
||||
auto e =
|
||||
KeyEvent(this, event->hardware_keycode, 1, event->type == GDK_KEY_RELEASE,
|
||||
shift_pressed, ctrl_pressed, alt_pressed, super_pressed);
|
||||
// TODO(Triang3l): event->hardware_keycode to VirtualKey translation.
|
||||
auto e = KeyEvent(this, VirtualKey(event->hardware_keycode), 1,
|
||||
event->type == GDK_KEY_RELEASE, shift_pressed, ctrl_pressed,
|
||||
alt_pressed, super_pressed);
|
||||
switch (event->type) {
|
||||
case GDK_KEY_PRESS:
|
||||
OnKeyDown(&e);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "xenia/base/filesystem.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/platform_win.h"
|
||||
#include "xenia/ui/virtual_key.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
@@ -446,7 +447,7 @@ void Win32Window::Close() {
|
||||
closing_ = true;
|
||||
OnClose();
|
||||
DestroyWindow(hwnd_);
|
||||
hwnd_ = 0;
|
||||
hwnd_ = nullptr;
|
||||
}
|
||||
|
||||
void Win32Window::OnMainMenuChange() {
|
||||
@@ -707,7 +708,7 @@ bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
|
||||
bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
auto e = KeyEvent(
|
||||
this, static_cast<int>(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
|
||||
this, VirtualKey(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
|
||||
!!(GetKeyState(VK_SHIFT) & 0x80), !!(GetKeyState(VK_CONTROL) & 0x80),
|
||||
!!(GetKeyState(VK_MENU) & 0x80), !!(GetKeyState(VK_LWIN) & 0x80));
|
||||
switch (message) {
|
||||
|
||||
Reference in New Issue
Block a user