[Vulkan v2] Physical device, [D3D12] Small cleanup

This commit is contained in:
Triang3l 2019-08-08 00:08:20 +03:00
parent 40471dff32
commit 2334e475de
21 changed files with 835 additions and 47 deletions

View File

@ -244,12 +244,14 @@ solution("xenia")
include("src/xenia/debug/ui") include("src/xenia/debug/ui")
include("src/xenia/gpu") include("src/xenia/gpu")
include("src/xenia/gpu/null") include("src/xenia/gpu/null")
include("src/xenia/gpu/vk")
include("src/xenia/gpu/vulkan") include("src/xenia/gpu/vulkan")
include("src/xenia/hid") include("src/xenia/hid")
include("src/xenia/hid/nop") include("src/xenia/hid/nop")
include("src/xenia/kernel") include("src/xenia/kernel")
include("src/xenia/ui") include("src/xenia/ui")
include("src/xenia/ui/spirv") include("src/xenia/ui/spirv")
include("src/xenia/ui/vk")
include("src/xenia/ui/vulkan") include("src/xenia/ui/vulkan")
include("src/xenia/vfs") include("src/xenia/vfs")

View File

@ -31,12 +31,14 @@ project("xenia-app")
"xenia-debug-ui", "xenia-debug-ui",
"xenia-gpu", "xenia-gpu",
"xenia-gpu-null", "xenia-gpu-null",
"xenia-gpu-vk",
"xenia-gpu-vulkan", "xenia-gpu-vulkan",
"xenia-hid", "xenia-hid",
"xenia-hid-nop", "xenia-hid-nop",
"xenia-kernel", "xenia-kernel",
"xenia-ui", "xenia-ui",
"xenia-ui-spirv", "xenia-ui-spirv",
"xenia-ui-vk",
"xenia-ui-vulkan", "xenia-ui-vulkan",
"xenia-vfs", "xenia-vfs",
"xxhash", "xxhash",

View File

@ -29,6 +29,7 @@
// Available graphics systems: // Available graphics systems:
#include "xenia/gpu/null/null_graphics_system.h" #include "xenia/gpu/null/null_graphics_system.h"
#include "xenia/gpu/vk/vulkan_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h" #include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
#include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h"
@ -44,8 +45,8 @@
#include "third_party/xbyak/xbyak/xbyak_util.h" #include "third_party/xbyak/xbyak/xbyak_util.h"
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]", "APU"); DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]", "APU");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, d3d12, vulkan, null]", DEFINE_string(gpu, "any",
"GPU"); "Graphics system. Use: [any, d3d12, vulkan, vk, null]", "GPU");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]", DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]",
"HID"); "HID");
@ -156,7 +157,12 @@ std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
#if XE_PLATFORM_WIN32 #if XE_PLATFORM_WIN32
factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12"); factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12");
#endif // XE_PLATFORM_WIN32 #endif // XE_PLATFORM_WIN32
// Abandoned Vulkan graphics system.
factory.Add<gpu::vulkan::VulkanGraphicsSystem>("vulkan"); factory.Add<gpu::vulkan::VulkanGraphicsSystem>("vulkan");
// New Vulkan graphics system.
// TODO(Triang3l): Move this higher when it's more ready, then drop the old
// Vulkan graphics system.
factory.Add<gpu::vk::VulkanGraphicsSystem>("vk");
factory.Add<gpu::null::NullGraphicsSystem>("null"); factory.Add<gpu::null::NullGraphicsSystem>("null");
return factory.Create(cvars::gpu); return factory.Create(cvars::gpu);
} }

View File

@ -50,11 +50,12 @@ class D3D12GraphicsSystem : public GraphicsSystem {
D3D12_GPU_DESCRIPTOR_HANDLE* gamma_ramp_handle, float gamma_ramp_inv_size, D3D12_GPU_DESCRIPTOR_HANDLE* gamma_ramp_handle, float gamma_ramp_inv_size,
DeferredCommandList& command_list); DeferredCommandList& command_list);
private: protected:
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override; std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
void Swap(xe::ui::UIEvent* e) override; void Swap(xe::ui::UIEvent* e) override;
private:
ui::d3d12::D3D12Context* display_context_ = nullptr; ui::d3d12::D3D12Context* display_context_ = nullptr;
ID3D12RootSignature* stretch_root_signature_ = nullptr; ID3D12RootSignature* stretch_root_signature_ = nullptr;

View File

@ -0,0 +1,19 @@
project_root = "../../../.."
include(project_root.."/tools/build")
group("src")
project("xenia-gpu-vk")
uuid("66c9afbb-798a-405d-80a1-7bda473e700d")
kind("StaticLib")
language("C++")
links({
"xenia-base",
"xenia-gpu",
"xenia-ui",
"xenia-ui-vk",
"xxhash",
})
local_platform_files()
files({
"shaders/bin/*.h",
})

View File

@ -0,0 +1,46 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vk/vulkan_command_processor.h"
namespace xe {
namespace gpu {
namespace vk {
VulkanCommandProcessor::VulkanCommandProcessor(
VulkanGraphicsSystem* graphics_system, kernel::KernelState* kernel_state)
: CommandProcessor(graphics_system, kernel_state) {}
VulkanCommandProcessor::~VulkanCommandProcessor() = default;
bool VulkanCommandProcessor::SetupContext() { return true; }
void VulkanCommandProcessor::ShutdownContext() {}
void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
uint32_t frontbuffer_width,
uint32_t frontbuffer_height) {}
Shader* VulkanCommandProcessor::LoadShader(ShaderType shader_type,
uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) {
return nullptr;
}
bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info) {
return true;
}
bool VulkanCommandProcessor::IssueCopy() { return true; }
} // namespace vk
} // namespace gpu
} // namespace xe

View File

@ -0,0 +1,47 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VK_VULKAN_COMMAND_PROCESSOR_H_
#define XENIA_GPU_VK_VULKAN_COMMAND_PROCESSOR_H_
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/vk/vulkan_graphics_system.h"
#include "xenia/kernel/kernel_state.h"
namespace xe {
namespace gpu {
namespace vk {
class VulkanCommandProcessor : public CommandProcessor {
public:
explicit VulkanCommandProcessor(VulkanGraphicsSystem* graphics_system,
kernel::KernelState* kernel_state);
~VulkanCommandProcessor();
protected:
bool SetupContext() override;
void ShutdownContext() override;
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) override;
Shader* LoadShader(ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) override;
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info) override;
bool IssueCopy() override;
};
} // namespace vk
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VK_VULKAN_COMMAND_PROCESSOR_H_

View File

@ -0,0 +1,54 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vk/vulkan_graphics_system.h"
#include "xenia/gpu/vk/vulkan_command_processor.h"
namespace xe {
namespace gpu {
namespace vk {
VulkanGraphicsSystem::VulkanGraphicsSystem() {}
VulkanGraphicsSystem::~VulkanGraphicsSystem() {}
std::wstring VulkanGraphicsSystem::name() const { return L"Vulkan Prototype"; }
X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
provider_ = xe::ui::vk::VulkanProvider::Create(target_window);
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
if (result != X_STATUS_SUCCESS) {
return result;
}
if (target_window) {
display_context_ =
reinterpret_cast<xe::ui::vk::VulkanContext*>(target_window->context());
}
return X_STATUS_SUCCESS;
}
void VulkanGraphicsSystem::Shutdown() { GraphicsSystem::Shutdown(); }
std::unique_ptr<CommandProcessor>
VulkanGraphicsSystem::CreateCommandProcessor() {
return std::unique_ptr<CommandProcessor>(
new VulkanCommandProcessor(this, kernel_state_));
}
void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {}
} // namespace vk
} // namespace gpu
} // namespace xe

View File

@ -0,0 +1,49 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_VK_VULKAN_GRAPHICS_SYSTEM_H_
#define XENIA_GPU_VK_VULKAN_GRAPHICS_SYSTEM_H_
#include <memory>
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/graphics_system.h"
#include "xenia/ui/vk/vulkan_context.h"
namespace xe {
namespace gpu {
namespace vk {
class VulkanGraphicsSystem : public GraphicsSystem {
public:
VulkanGraphicsSystem();
~VulkanGraphicsSystem() override;
static bool IsAvailable() { return true; }
std::wstring name() const override;
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
ui::Window* target_window) override;
void Shutdown() override;
protected:
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
void Swap(xe::ui::UIEvent* e) override;
private:
ui::vk::VulkanContext* display_context_ = nullptr;
};
} // namespace vk
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VK_VULKAN_GRAPHICS_SYSTEM_H_

View File

@ -309,24 +309,12 @@ void D3D12ImmediateDrawer::Shutdown() {
texture_descriptor_pool_.reset(); texture_descriptor_pool_.reset();
vertex_buffer_pool_.reset(); vertex_buffer_pool_.reset();
if (sampler_heap_ != nullptr) { util::ReleaseAndNull(sampler_heap_);
sampler_heap_->Release();
sampler_heap_ = nullptr;
}
if (pipeline_line_ != nullptr) { util::ReleaseAndNull(pipeline_line_);
pipeline_line_->Release(); util::ReleaseAndNull(pipeline_triangle_);
pipeline_line_ = nullptr;
}
if (pipeline_triangle_ != nullptr) {
pipeline_triangle_->Release();
pipeline_triangle_ = nullptr;
}
if (root_signature_ != nullptr) { util::ReleaseAndNull(root_signature_);
root_signature_->Release();
root_signature_ = nullptr;
}
} }
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture( std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(

View File

@ -43,7 +43,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
void BeginDrawBatch(const ImmediateDrawBatch& batch) override; void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
void Draw(const ImmediateDraw& draw) override; void Draw(const ImmediateDraw& draw) override;
void EndDrawBatch() override; void EndDrawBatch() override;
void End(); void End() override;
private: private:
D3D12Context* context_ = nullptr; D3D12Context* context_ = nullptr;

View File

@ -38,18 +38,15 @@ bool D3D12Provider::IsD3D12APIAvailable() {
std::unique_ptr<D3D12Provider> D3D12Provider::Create(Window* main_window) { std::unique_ptr<D3D12Provider> D3D12Provider::Create(Window* main_window) {
std::unique_ptr<D3D12Provider> provider(new D3D12Provider(main_window)); std::unique_ptr<D3D12Provider> provider(new D3D12Provider(main_window));
InitializationResult result = provider->Initialize(); if (!provider->Initialize()) {
if (result != InitializationResult::kSucceeded) { xe::FatalError(
if (result != InitializationResult::kLibraryLoadFailed) { "Unable to initialize Direct3D 12 graphics subsystem.\n"
xe::FatalError( "\n"
"Unable to initialize Direct3D 12 graphics subsystem.\n" "Ensure that you have the latest drivers for your GPU and it supports "
"\n" "Direct3D 12 feature level 11_0.\n"
"Ensure that you have the latest drivers for your GPU and it " "\n"
"supports Direct3D 12 feature level 11_0.\n" "See https://xenia.jp/faq/ for more information and a list of "
"\n" "supported GPUs.");
"See https://xenia.jp/faq/ for more information and a list of "
"supported GPUs.");
}
return nullptr; return nullptr;
} }
return provider; return provider;
@ -83,7 +80,7 @@ D3D12Provider::~D3D12Provider() {
} }
} }
D3D12Provider::InitializationResult D3D12Provider::Initialize() { bool D3D12Provider::Initialize() {
// Load the libraries. // Load the libraries.
library_dxgi_ = LoadLibrary(L"dxgi.dll"); library_dxgi_ = LoadLibrary(L"dxgi.dll");
library_d3d12_ = LoadLibrary(L"D3D12.dll"); library_d3d12_ = LoadLibrary(L"D3D12.dll");
@ -91,7 +88,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
if (library_dxgi_ == nullptr || library_d3d12_ == nullptr || if (library_dxgi_ == nullptr || library_d3d12_ == nullptr ||
library_d3dcompiler_ == nullptr) { library_d3dcompiler_ == nullptr) {
XELOGE("Failed to load dxgi.dll, D3D12.dll and D3DCompiler_47.dll."); XELOGE("Failed to load dxgi.dll, D3D12.dll and D3DCompiler_47.dll.");
return InitializationResult::kLibraryLoadFailed; return false;
} }
bool libraries_loaded = true; bool libraries_loaded = true;
libraries_loaded &= libraries_loaded &=
@ -114,7 +111,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
libraries_loaded &= (pfn_d3d_disassemble_ = pD3DDisassemble(GetProcAddress( libraries_loaded &= (pfn_d3d_disassemble_ = pD3DDisassemble(GetProcAddress(
library_d3dcompiler_, "D3DDisassemble"))) != nullptr; library_d3dcompiler_, "D3DDisassemble"))) != nullptr;
if (!libraries_loaded) { if (!libraries_loaded) {
return InitializationResult::kLibraryLoadFailed; return false;
} }
// Enable the debug layer. // Enable the debug layer.
@ -136,7 +133,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
if (FAILED(pfn_create_dxgi_factory2_(debug ? DXGI_CREATE_FACTORY_DEBUG : 0, if (FAILED(pfn_create_dxgi_factory2_(debug ? DXGI_CREATE_FACTORY_DEBUG : 0,
IID_PPV_ARGS(&dxgi_factory)))) { IID_PPV_ARGS(&dxgi_factory)))) {
XELOGE("Failed to create a DXGI factory"); XELOGE("Failed to create a DXGI factory");
return InitializationResult::kDeviceInitializationFailed; return false;
} }
// Choose the adapter. // Choose the adapter.
@ -169,14 +166,14 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
if (adapter == nullptr) { if (adapter == nullptr) {
XELOGE("Failed to get an adapter supporting Direct3D feature level 11_0."); XELOGE("Failed to get an adapter supporting Direct3D feature level 11_0.");
dxgi_factory->Release(); dxgi_factory->Release();
return InitializationResult::kDeviceInitializationFailed; return false;
} }
DXGI_ADAPTER_DESC adapter_desc; DXGI_ADAPTER_DESC adapter_desc;
if (FAILED(adapter->GetDesc(&adapter_desc))) { if (FAILED(adapter->GetDesc(&adapter_desc))) {
XELOGE("Failed to get the DXGI adapter description."); XELOGE("Failed to get the DXGI adapter description.");
adapter->Release(); adapter->Release();
dxgi_factory->Release(); dxgi_factory->Release();
return InitializationResult::kDeviceInitializationFailed; return false;
} }
adapter_vendor_id_ = adapter_desc.VendorId; adapter_vendor_id_ = adapter_desc.VendorId;
int adapter_name_mb_size = WideCharToMultiByte( int adapter_name_mb_size = WideCharToMultiByte(
@ -199,7 +196,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
XELOGE("Failed to create a Direct3D 12 feature level 11_0 device."); XELOGE("Failed to create a Direct3D 12 feature level 11_0 device.");
adapter->Release(); adapter->Release();
dxgi_factory->Release(); dxgi_factory->Release();
return InitializationResult::kDeviceInitializationFailed; return false;
} }
adapter->Release(); adapter->Release();
@ -268,7 +265,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
// attached. // attached.
pfn_dxgi_get_debug_interface1_(0, IID_PPV_ARGS(&graphics_analysis_)); pfn_dxgi_get_debug_interface1_(0, IID_PPV_ARGS(&graphics_analysis_));
return InitializationResult::kSucceeded; return true;
} }
std::unique_ptr<GraphicsContext> D3D12Provider::CreateContext( std::unique_ptr<GraphicsContext> D3D12Provider::CreateContext(

View File

@ -97,13 +97,7 @@ class D3D12Provider : public GraphicsProvider {
private: private:
explicit D3D12Provider(Window* main_window); explicit D3D12Provider(Window* main_window);
enum InitializationResult : uint32_t { bool Initialize();
kSucceeded,
kDeviceInitializationFailed,
kLibraryLoadFailed,
};
InitializationResult Initialize();
HMODULE library_dxgi_ = nullptr; HMODULE library_dxgi_ = nullptr;
HMODULE library_d3d12_ = nullptr; HMODULE library_d3d12_ = nullptr;

View File

@ -0,0 +1,17 @@
project_root = "../../../.."
include(project_root.."/tools/build")
group("src")
project("xenia-ui-vk")
uuid("758e31de-c91b-44ce-acef-27752939d37f")
kind("StaticLib")
language("C++")
links({
"volk",
"xenia-base",
"xenia-ui",
})
local_platform_files()
files({
"shaders/bin/*.h",
})

View File

@ -0,0 +1,65 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/vk/vulkan_context.h"
#include "xenia/ui/vk/vulkan_immediate_drawer.h"
namespace xe {
namespace ui {
namespace vk {
VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window)
: GraphicsContext(provider, target_window) {}
VulkanContext::~VulkanContext() { Shutdown(); }
bool VulkanContext::Initialize() {
context_lost_ = false;
if (target_window_) {
// Initialize the immediate mode drawer if not offscreen.
immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(this);
if (!immediate_drawer_->Initialize()) {
Shutdown();
return false;
}
}
return true;
}
void VulkanContext::Shutdown() {
initialized_fully_ = false;
immediate_drawer_.reset();
}
ImmediateDrawer* VulkanContext::immediate_drawer() {
return immediate_drawer_.get();
}
bool VulkanContext::is_current() { return false; }
bool VulkanContext::MakeCurrent() { return true; }
void VulkanContext::ClearCurrent() {}
void VulkanContext::BeginSwap() {}
void VulkanContext::EndSwap() {}
std::unique_ptr<RawImage> VulkanContext::Capture() {
// TODO(Triang3l): Read back swap chain front buffer.
return nullptr;
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,63 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_CONTEXT_H_
#define XENIA_UI_VK_VULKAN_CONTEXT_H_
#include <memory>
#include "xenia/ui/graphics_context.h"
#include "xenia/ui/vk/vulkan_provider.h"
#define FINE_GRAINED_DRAW_SCOPES 1
namespace xe {
namespace ui {
namespace vk {
class VulkanImmediateDrawer;
class VulkanContext : public GraphicsContext {
public:
~VulkanContext() override;
ImmediateDrawer* immediate_drawer() override;
bool is_current() override;
bool MakeCurrent() override;
void ClearCurrent() override;
bool WasLost() override { return context_lost_; }
void BeginSwap() override;
void EndSwap() override;
std::unique_ptr<RawImage> Capture() override;
private:
friend class VulkanProvider;
explicit VulkanContext(VulkanProvider* provider, Window* target_window);
private:
bool Initialize();
void Shutdown();
bool initialized_fully_ = false;
bool context_lost_ = false;
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_ = nullptr;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_CONTEXT_H_

View File

@ -0,0 +1,68 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/vk/vulkan_immediate_drawer.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanImmediateTexture : public ImmediateTexture {
public:
VulkanImmediateTexture(uint32_t width, uint32_t height,
ImmediateTextureFilter filter, bool repeat);
~VulkanImmediateTexture() override;
};
VulkanImmediateTexture::VulkanImmediateTexture(uint32_t width, uint32_t height,
ImmediateTextureFilter filter,
bool repeat)
: ImmediateTexture(width, height) {
handle = reinterpret_cast<uintptr_t>(this);
}
VulkanImmediateTexture::~VulkanImmediateTexture() {}
VulkanImmediateDrawer::VulkanImmediateDrawer(VulkanContext* graphics_context)
: ImmediateDrawer(graphics_context), context_(graphics_context) {}
VulkanImmediateDrawer::~VulkanImmediateDrawer() { Shutdown(); }
bool VulkanImmediateDrawer::Initialize() { return true; }
void VulkanImmediateDrawer::Shutdown() {}
std::unique_ptr<ImmediateTexture> VulkanImmediateDrawer::CreateTexture(
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
const uint8_t* data) {
auto texture =
std::make_unique<VulkanImmediateTexture>(width, height, filter, repeat);
if (data != nullptr) {
UpdateTexture(texture.get(), data);
}
return std::unique_ptr<ImmediateTexture>(texture.release());
}
void VulkanImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
const uint8_t* data) {}
void VulkanImmediateDrawer::Begin(int render_target_width,
int render_target_height) {}
void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {}
void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {}
void VulkanImmediateDrawer::EndDrawBatch() {}
void VulkanImmediateDrawer::End() {}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,51 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_
#define XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_
#include <memory>
#include "xenia/ui/immediate_drawer.h"
#include "xenia/ui/vk/vulkan_context.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanImmediateDrawer : public ImmediateDrawer {
public:
VulkanImmediateDrawer(VulkanContext* graphics_context);
~VulkanImmediateDrawer() override;
bool Initialize();
void Shutdown();
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
uint32_t height,
ImmediateTextureFilter filter,
bool repeat,
const uint8_t* data) override;
void UpdateTexture(ImmediateTexture* texture, const uint8_t* data) override;
void Begin(int render_target_width, int render_target_height) override;
void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
void Draw(const ImmediateDraw& draw) override;
void EndDrawBatch() override;
void End() override;
private:
VulkanContext* context_ = nullptr;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_

View File

@ -0,0 +1,230 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/vk/vulkan_provider.h"
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/ui/vk/vulkan_context.h"
#include "xenia/ui/vk/vulkan_util.h"
DEFINE_bool(vk_validation, false, "Enable Vulkan validation layers.", "Vulkan");
DEFINE_int32(vk_device, -1,
"Index of the Vulkan physical device to use. -1 to use any "
"compatible.",
"Vulkan");
namespace xe {
namespace ui {
namespace vk {
std::unique_ptr<VulkanProvider> VulkanProvider::Create(Window* main_window) {
std::unique_ptr<VulkanProvider> provider(new VulkanProvider(main_window));
if (!provider->Initialize()) {
xe::FatalError(
"Unable to initialize Vulkan 1.1 graphics subsystem.\n"
"\n"
"Ensure you have the latest drivers for your GPU and that it supports "
"Vulkan, and install the latest Vulkan runtime from "
"https://vulkan.lunarg.com/sdk/home.\n"
"\n"
"See https://xenia.jp/faq/ for more information and a list of "
"supported GPUs.");
return nullptr;
}
return provider;
}
VulkanProvider::VulkanProvider(Window* main_window)
: GraphicsProvider(main_window) {}
VulkanProvider::~VulkanProvider() {
if (device_ != VK_NULL_HANDLE) {
vkDestroyDevice(device_, nullptr);
}
if (instance_ != VK_NULL_HANDLE) {
vkDestroyInstance(instance_, nullptr);
}
}
bool VulkanProvider::Initialize() {
if (volkInitialize() != VK_SUCCESS) {
XELOGE("Failed to initialize the Vulkan loader volk.");
return false;
}
const uint32_t api_version = VK_MAKE_VERSION(1, 1, 0);
// Create the instance.
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 = api_version;
const char* const validation_layers[] = {
"VK_LAYER_LUNARG_standard_validation",
};
const char* const instance_extensions[] = {
"VK_KHR_surface",
#if XE_PLATFORM_WIN32
"VK_KHR_win32_surface",
#endif
};
VkInstanceCreateInfo instance_create_info;
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pNext = nullptr;
instance_create_info.flags = 0;
instance_create_info.pApplicationInfo = &application_info;
if (cvars::vk_validation) {
instance_create_info.enabledLayerCount =
uint32_t(xe::countof(validation_layers));
instance_create_info.ppEnabledLayerNames = validation_layers;
} else {
instance_create_info.enabledLayerCount = 0;
instance_create_info.ppEnabledLayerNames = nullptr;
}
instance_create_info.enabledExtensionCount =
uint32_t(xe::countof(instance_extensions));
instance_create_info.ppEnabledExtensionNames = instance_extensions;
if (vkCreateInstance(&instance_create_info, nullptr, &instance_) !=
VK_SUCCESS) {
XELOGE("Failed to create a Vulkan instance.");
return false;
}
volkLoadInstance(instance_);
// Get a supported physical device.
physical_device_ = nullptr;
std::vector<VkPhysicalDevice> physical_devices;
uint32_t physical_device_count;
if (vkEnumeratePhysicalDevices(instance_, &physical_device_count, nullptr) !=
VK_SUCCESS) {
XELOGE("Failed to get Vulkan physical device count.");
return false;
}
physical_devices.resize(physical_device_count);
if (vkEnumeratePhysicalDevices(instance_, &physical_device_count,
physical_devices.data()) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan physical devices.");
return false;
}
physical_devices.resize(physical_device_count);
uint32_t physical_device_index, physical_device_index_end;
if (cvars::vk_device >= 0) {
physical_device_index = uint32_t(cvars::vk_device);
physical_device_index_end =
std::min(physical_device_index + 1, physical_device_count);
} else {
physical_device_index = 0;
physical_device_index_end = physical_device_count;
}
VkPhysicalDeviceFeatures physical_device_features;
std::vector<VkQueueFamilyProperties> queue_families;
uint32_t queue_family = UINT32_MAX;
bool sparse_residency_buffer = false;
for (; physical_device_index < physical_device_index_end;
++physical_device_index) {
VkPhysicalDevice physical_device = physical_devices[physical_device_index];
vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features);
sparse_residency_buffer = physical_device_features.sparseBinding &&
physical_device_features.sparseResidencyBuffer;
// Get a queue supporting graphics, compute and transfer, and if available,
// also sparse memory management.
queue_family = UINT32_MAX;
uint32_t queue_family_count;
vkGetPhysicalDeviceQueueFamilyProperties(physical_device,
&queue_family_count, nullptr);
queue_families.resize(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(
physical_device, &queue_family_count, queue_families.data());
const uint32_t queue_flags_required =
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
for (uint32_t i = 0; i < queue_family_count; ++i) {
const VkQueueFamilyProperties& queue_family_properties =
queue_families[i];
// Arbitrary copying done when loading textures.
if (queue_family_properties.minImageTransferGranularity.width > 1 ||
queue_family_properties.minImageTransferGranularity.height > 1 ||
queue_family_properties.minImageTransferGranularity.depth > 1) {
continue;
}
if ((queue_family_properties.queueFlags & queue_flags_required) !=
queue_flags_required) {
continue;
}
queue_family = i;
if (!sparse_residency_buffer ||
(queue_family_properties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) {
// Found a fully compatible queue family, stop searching for a family
// that support both graphics/compute/transfer and sparse binding.
break;
}
}
if (queue_family == UINT32_MAX) {
continue;
}
if (!(queue_families[queue_family].queueFlags &
VK_QUEUE_SPARSE_BINDING_BIT)) {
sparse_residency_buffer = false;
}
physical_device_ = physical_device;
break;
}
if (physical_device_ == VK_NULL_HANDLE) {
XELOGE("Failed to get a supported Vulkan physical device.");
return false;
}
supports_sparse_residency_buffer_ = sparse_residency_buffer;
supports_texture_compression_bc_ =
physical_device_features.textureCompressionBC != VK_FALSE;
// TODO(Triang3l): Check if VK_EXT_fragment_shader_interlock and
// fragmentShaderSampleInterlock are supported.
// Log physical device properties.
VkPhysicalDeviceProperties physical_device_properties;
vkGetPhysicalDeviceProperties(physical_device_, &physical_device_properties);
XELOGVK("Vulkan physical device: %s (vendor %.4X, device %.4X)",
physical_device_properties.deviceName,
physical_device_properties.vendorID,
physical_device_properties.deviceID);
XELOGVK("* Sparse buffer residency: %s",
supports_sparse_residency_buffer_ ? "yes" : "no");
XELOGVK("* BC texture compression: %s",
supports_texture_compression_bc_ ? "yes" : "no");
return true;
}
std::unique_ptr<GraphicsContext> VulkanProvider::CreateContext(
Window* target_window) {
auto new_context =
std::unique_ptr<VulkanContext>(new VulkanContext(this, target_window));
if (!new_context->Initialize()) {
return nullptr;
}
return std::unique_ptr<GraphicsContext>(new_context.release());
}
std::unique_ptr<GraphicsContext> VulkanProvider::CreateOffscreenContext() {
auto new_context =
std::unique_ptr<VulkanContext>(new VulkanContext(this, nullptr));
if (!new_context->Initialize()) {
return nullptr;
}
return std::unique_ptr<GraphicsContext>(new_context.release());
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,54 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_PROVIDER_H_
#define XENIA_UI_VK_VULKAN_PROVIDER_H_
#include <memory>
#include "third_party/volk/volk.h"
#define XELOGVK XELOGI
#include "xenia/ui/graphics_provider.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanImmediateDrawer;
class VulkanProvider : public GraphicsProvider {
public:
~VulkanProvider() override;
static std::unique_ptr<VulkanProvider> Create(Window* main_window);
std::unique_ptr<GraphicsContext> CreateContext(
Window* target_window) override;
std::unique_ptr<GraphicsContext> CreateOffscreenContext() override;
private:
explicit VulkanProvider(Window* main_window);
bool Initialize();
VkInstance instance_ = VK_NULL_HANDLE;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
bool supports_sparse_residency_buffer_ = false;
bool supports_texture_compression_bc_ = false;
VkDevice device_ = VK_NULL_HANDLE;
VkQueue graphics_queue_ = VK_NULL_HANDLE;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_PROVIDER_H_

View File

@ -0,0 +1,35 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_UTIL_H_
#define XENIA_UI_VK_VULKAN_UTIL_H_
#include "xenia/ui/vk/vulkan_provider.h"
namespace xe {
namespace ui {
namespace vk {
namespace util {
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;
}
return false;
}
} // namespace util
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_UTIL_H_