[Vulkan v2] Physical device, [D3D12] Small cleanup
This commit is contained in:
parent
40471dff32
commit
2334e475de
|
@ -244,12 +244,14 @@ solution("xenia")
|
|||
include("src/xenia/debug/ui")
|
||||
include("src/xenia/gpu")
|
||||
include("src/xenia/gpu/null")
|
||||
include("src/xenia/gpu/vk")
|
||||
include("src/xenia/gpu/vulkan")
|
||||
include("src/xenia/hid")
|
||||
include("src/xenia/hid/nop")
|
||||
include("src/xenia/kernel")
|
||||
include("src/xenia/ui")
|
||||
include("src/xenia/ui/spirv")
|
||||
include("src/xenia/ui/vk")
|
||||
include("src/xenia/ui/vulkan")
|
||||
include("src/xenia/vfs")
|
||||
|
||||
|
|
|
@ -31,12 +31,14 @@ project("xenia-app")
|
|||
"xenia-debug-ui",
|
||||
"xenia-gpu",
|
||||
"xenia-gpu-null",
|
||||
"xenia-gpu-vk",
|
||||
"xenia-gpu-vulkan",
|
||||
"xenia-hid",
|
||||
"xenia-hid-nop",
|
||||
"xenia-kernel",
|
||||
"xenia-ui",
|
||||
"xenia-ui-spirv",
|
||||
"xenia-ui-vk",
|
||||
"xenia-ui-vulkan",
|
||||
"xenia-vfs",
|
||||
"xxhash",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
// Available graphics systems:
|
||||
#include "xenia/gpu/null/null_graphics_system.h"
|
||||
#include "xenia/gpu/vk/vulkan_graphics_system.h"
|
||||
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||
#if XE_PLATFORM_WIN32
|
||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||
|
@ -44,8 +45,8 @@
|
|||
#include "third_party/xbyak/xbyak/xbyak_util.h"
|
||||
|
||||
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, xaudio2]", "APU");
|
||||
DEFINE_string(gpu, "any", "Graphics system. Use: [any, d3d12, vulkan, null]",
|
||||
"GPU");
|
||||
DEFINE_string(gpu, "any",
|
||||
"Graphics system. Use: [any, d3d12, vulkan, vk, null]", "GPU");
|
||||
DEFINE_string(hid, "any", "Input system. Use: [any, nop, winkey, xinput]",
|
||||
"HID");
|
||||
|
||||
|
@ -156,7 +157,12 @@ std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
|
|||
#if XE_PLATFORM_WIN32
|
||||
factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12");
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
// Abandoned Vulkan graphics system.
|
||||
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");
|
||||
return factory.Create(cvars::gpu);
|
||||
}
|
||||
|
|
|
@ -50,11 +50,12 @@ class D3D12GraphicsSystem : public GraphicsSystem {
|
|||
D3D12_GPU_DESCRIPTOR_HANDLE* gamma_ramp_handle, float gamma_ramp_inv_size,
|
||||
DeferredCommandList& command_list);
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
|
||||
|
||||
void Swap(xe::ui::UIEvent* e) override;
|
||||
|
||||
private:
|
||||
ui::d3d12::D3D12Context* display_context_ = nullptr;
|
||||
|
||||
ID3D12RootSignature* stretch_root_signature_ = nullptr;
|
||||
|
|
|
@ -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",
|
||||
})
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -309,24 +309,12 @@ void D3D12ImmediateDrawer::Shutdown() {
|
|||
texture_descriptor_pool_.reset();
|
||||
vertex_buffer_pool_.reset();
|
||||
|
||||
if (sampler_heap_ != nullptr) {
|
||||
sampler_heap_->Release();
|
||||
sampler_heap_ = nullptr;
|
||||
}
|
||||
util::ReleaseAndNull(sampler_heap_);
|
||||
|
||||
if (pipeline_line_ != nullptr) {
|
||||
pipeline_line_->Release();
|
||||
pipeline_line_ = nullptr;
|
||||
}
|
||||
if (pipeline_triangle_ != nullptr) {
|
||||
pipeline_triangle_->Release();
|
||||
pipeline_triangle_ = nullptr;
|
||||
}
|
||||
util::ReleaseAndNull(pipeline_line_);
|
||||
util::ReleaseAndNull(pipeline_triangle_);
|
||||
|
||||
if (root_signature_ != nullptr) {
|
||||
root_signature_->Release();
|
||||
root_signature_ = nullptr;
|
||||
}
|
||||
util::ReleaseAndNull(root_signature_);
|
||||
}
|
||||
|
||||
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
||||
|
|
|
@ -43,7 +43,7 @@ class D3D12ImmediateDrawer : public ImmediateDrawer {
|
|||
void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
|
||||
void Draw(const ImmediateDraw& draw) override;
|
||||
void EndDrawBatch() override;
|
||||
void End();
|
||||
void End() override;
|
||||
|
||||
private:
|
||||
D3D12Context* context_ = nullptr;
|
||||
|
|
|
@ -38,18 +38,15 @@ bool D3D12Provider::IsD3D12APIAvailable() {
|
|||
|
||||
std::unique_ptr<D3D12Provider> D3D12Provider::Create(Window* main_window) {
|
||||
std::unique_ptr<D3D12Provider> provider(new D3D12Provider(main_window));
|
||||
InitializationResult result = provider->Initialize();
|
||||
if (result != InitializationResult::kSucceeded) {
|
||||
if (result != InitializationResult::kLibraryLoadFailed) {
|
||||
xe::FatalError(
|
||||
"Unable to initialize Direct3D 12 graphics subsystem.\n"
|
||||
"\n"
|
||||
"Ensure that you have the latest drivers for your GPU and it "
|
||||
"supports Direct3D 12 feature level 11_0.\n"
|
||||
"\n"
|
||||
"See https://xenia.jp/faq/ for more information and a list of "
|
||||
"supported GPUs.");
|
||||
}
|
||||
if (!provider->Initialize()) {
|
||||
xe::FatalError(
|
||||
"Unable to initialize Direct3D 12 graphics subsystem.\n"
|
||||
"\n"
|
||||
"Ensure that you have the latest drivers for your GPU and it supports "
|
||||
"Direct3D 12 feature level 11_0.\n"
|
||||
"\n"
|
||||
"See https://xenia.jp/faq/ for more information and a list of "
|
||||
"supported GPUs.");
|
||||
return nullptr;
|
||||
}
|
||||
return provider;
|
||||
|
@ -83,7 +80,7 @@ D3D12Provider::~D3D12Provider() {
|
|||
}
|
||||
}
|
||||
|
||||
D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
||||
bool D3D12Provider::Initialize() {
|
||||
// Load the libraries.
|
||||
library_dxgi_ = LoadLibrary(L"dxgi.dll");
|
||||
library_d3d12_ = LoadLibrary(L"D3D12.dll");
|
||||
|
@ -91,7 +88,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
|||
if (library_dxgi_ == nullptr || library_d3d12_ == nullptr ||
|
||||
library_d3dcompiler_ == nullptr) {
|
||||
XELOGE("Failed to load dxgi.dll, D3D12.dll and D3DCompiler_47.dll.");
|
||||
return InitializationResult::kLibraryLoadFailed;
|
||||
return false;
|
||||
}
|
||||
bool libraries_loaded = true;
|
||||
libraries_loaded &=
|
||||
|
@ -114,7 +111,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
|||
libraries_loaded &= (pfn_d3d_disassemble_ = pD3DDisassemble(GetProcAddress(
|
||||
library_d3dcompiler_, "D3DDisassemble"))) != nullptr;
|
||||
if (!libraries_loaded) {
|
||||
return InitializationResult::kLibraryLoadFailed;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable the debug layer.
|
||||
|
@ -136,7 +133,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
|||
if (FAILED(pfn_create_dxgi_factory2_(debug ? DXGI_CREATE_FACTORY_DEBUG : 0,
|
||||
IID_PPV_ARGS(&dxgi_factory)))) {
|
||||
XELOGE("Failed to create a DXGI factory");
|
||||
return InitializationResult::kDeviceInitializationFailed;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Choose the adapter.
|
||||
|
@ -169,14 +166,14 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
|||
if (adapter == nullptr) {
|
||||
XELOGE("Failed to get an adapter supporting Direct3D feature level 11_0.");
|
||||
dxgi_factory->Release();
|
||||
return InitializationResult::kDeviceInitializationFailed;
|
||||
return false;
|
||||
}
|
||||
DXGI_ADAPTER_DESC adapter_desc;
|
||||
if (FAILED(adapter->GetDesc(&adapter_desc))) {
|
||||
XELOGE("Failed to get the DXGI adapter description.");
|
||||
adapter->Release();
|
||||
dxgi_factory->Release();
|
||||
return InitializationResult::kDeviceInitializationFailed;
|
||||
return false;
|
||||
}
|
||||
adapter_vendor_id_ = adapter_desc.VendorId;
|
||||
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.");
|
||||
adapter->Release();
|
||||
dxgi_factory->Release();
|
||||
return InitializationResult::kDeviceInitializationFailed;
|
||||
return false;
|
||||
}
|
||||
adapter->Release();
|
||||
|
||||
|
@ -268,7 +265,7 @@ D3D12Provider::InitializationResult D3D12Provider::Initialize() {
|
|||
// attached.
|
||||
pfn_dxgi_get_debug_interface1_(0, IID_PPV_ARGS(&graphics_analysis_));
|
||||
|
||||
return InitializationResult::kSucceeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<GraphicsContext> D3D12Provider::CreateContext(
|
||||
|
|
|
@ -97,13 +97,7 @@ class D3D12Provider : public GraphicsProvider {
|
|||
private:
|
||||
explicit D3D12Provider(Window* main_window);
|
||||
|
||||
enum InitializationResult : uint32_t {
|
||||
kSucceeded,
|
||||
kDeviceInitializationFailed,
|
||||
kLibraryLoadFailed,
|
||||
};
|
||||
|
||||
InitializationResult Initialize();
|
||||
bool Initialize();
|
||||
|
||||
HMODULE library_dxgi_ = nullptr;
|
||||
HMODULE library_d3d12_ = nullptr;
|
||||
|
|
|
@ -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",
|
||||
})
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
Loading…
Reference in New Issue