[Vulkan] Remove stillborn vk project

This commit is contained in:
Triang3l 2020-08-22 23:31:52 +03:00
parent 82ca0a7eec
commit dffdf92e39
26 changed files with 2 additions and 2628 deletions

View File

@ -241,7 +241,6 @@ 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/helper/sdl")
include("src/xenia/hid")
@ -250,7 +249,6 @@ solution("xenia")
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")

View File

@ -32,7 +32,6 @@ project("xenia-app")
"xenia-debug-ui",
"xenia-gpu",
"xenia-gpu-null",
"xenia-gpu-vk",
"xenia-gpu-vulkan",
"xenia-helper-sdl",
"xenia-hid",
@ -41,7 +40,6 @@ project("xenia-app")
"xenia-kernel",
"xenia-ui",
"xenia-ui-spirv",
"xenia-ui-vk",
"xenia-ui-vulkan",
"xenia-vfs",
"xxhash",

View File

@ -30,7 +30,6 @@
// 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"
@ -48,8 +47,8 @@
#include "third_party/xbyak/xbyak/xbyak_util.h"
DEFINE_string(apu, "any", "Audio system. Use: [any, nop, sdl, xaudio2]", "APU");
DEFINE_string(gpu, "any",
"Graphics system. Use: [any, d3d12, vulkan, vk, null]", "GPU");
DEFINE_string(gpu, "any", "Graphics system. Use: [any, d3d12, vulkan, null]",
"GPU");
DEFINE_string(hid, "any", "Input system. Use: [any, nop, sdl, winkey, xinput]",
"HID");
@ -175,12 +174,7 @@ 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);
}

View File

@ -1,19 +0,0 @@
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

@ -1,56 +0,0 @@
/**
******************************************************************************
* 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;
void VulkanCommandProcessor::TracePlaybackWroteMemory(uint32_t base_ptr,
uint32_t length) {}
void VulkanCommandProcessor::RestoreEdramSnapshot(const void* snapshot) {}
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(xenos::ShaderType shader_type,
uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) {
return nullptr;
}
bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
uint32_t index_count,
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) {
return true;
}
bool VulkanCommandProcessor::IssueCopy() { return true; }
void VulkanCommandProcessor::InitializeTrace() {}
void VulkanCommandProcessor::FinalizeTrace() {}
} // namespace vk
} // namespace gpu
} // namespace xe

View File

@ -1,55 +0,0 @@
/**
******************************************************************************
* 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();
void TracePlaybackWroteMemory(uint32_t base_ptr, uint32_t length) override;
void RestoreEdramSnapshot(const void* snapshot) override;
protected:
bool SetupContext() override;
void ShutdownContext() override;
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) override;
Shader* LoadShader(xenos::ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address,
uint32_t dword_count) override;
bool IssueDraw(xenos::PrimitiveType primitive_type, uint32_t index_count,
IndexBufferInfo* index_buffer_info,
bool major_mode_explicit) override;
bool IssueCopy() override;
void InitializeTrace() override;
void FinalizeTrace() override;
};
} // namespace vk
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_VK_VULKAN_COMMAND_PROCESSOR_H_

View File

@ -1,54 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/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::string VulkanGraphicsSystem::name() const { return "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

@ -1,49 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_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::string 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

@ -1,17 +0,0 @@
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

@ -1,44 +0,0 @@
// generated from `xb genspirv`
// source: immediate.frag
const uint8_t immediate_frag[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00,
0x05, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x69,
0x6E, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F, 0x72, 0x64, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@ -1,35 +0,0 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 16
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %xe_out_color %xe_in_color %xe_in_texcoord
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %xe_out_color "xe_out_color"
OpName %xe_in_color "xe_in_color"
OpName %xe_in_texcoord "xe_in_texcoord"
OpDecorate %xe_out_color Location 0
OpDecorate %xe_in_color Location 1
OpDecorate %xe_in_texcoord Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%xe_out_color = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_v4float = OpTypePointer Input %v4float
%xe_in_color = OpVariable %_ptr_Input_v4float Input
%v2float = OpTypeVector %float 2
%_ptr_Input_v2float = OpTypePointer Input %v2float
%xe_in_texcoord = OpVariable %_ptr_Input_v2float Input
%main = OpFunction %void None %3
%5 = OpLabel
%12 = OpLoad %v4float %xe_in_color
OpStore %xe_out_color %12
OpReturn
OpFunctionEnd

View File

@ -1,126 +0,0 @@
// generated from `xb genspirv`
// source: immediate.vert
const uint8_t immediate_vert[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,
0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00,
0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x69, 0x6E,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74,
0x69, 0x6F, 0x6E, 0x00, 0x06, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x69, 0x6E, 0x74,
0x53, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6C, 0x5F, 0x43,
0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x00,
0x06, 0x00, 0x07, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x67, 0x6C, 0x5F, 0x43, 0x75, 0x6C, 0x6C, 0x44, 0x69, 0x73, 0x74, 0x61,
0x6E, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69,
0x6F, 0x6E, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00,
0x58, 0x65, 0x50, 0x75, 0x73, 0x68, 0x43, 0x6F, 0x6E, 0x73, 0x74, 0x61,
0x6E, 0x74, 0x73, 0x00, 0x06, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x76, 0x69, 0x65, 0x77, 0x70, 0x6F, 0x72, 0x74,
0x5F, 0x69, 0x6E, 0x76, 0x5F, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x00, 0x00,
0x05, 0x00, 0x07, 0x00, 0x16, 0x00, 0x00, 0x00, 0x78, 0x65, 0x5F, 0x70,
0x75, 0x73, 0x68, 0x5F, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74,
0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x6F, 0x75, 0x74, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F,
0x6F, 0x72, 0x64, 0x00, 0x05, 0x00, 0x06, 0x00, 0x28, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x74, 0x65, 0x78, 0x63, 0x6F, 0x6F,
0x72, 0x64, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x6F, 0x75, 0x74, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x78, 0x65, 0x5F, 0x69, 0x6E, 0x5F, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x12, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00,
0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x27, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00,
0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00,
0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x15, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x1E, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x2B, 0x00, 0x04, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2B, 0x00, 0x04, 0x00,
0x06, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F,
0x2B, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x3B, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00,
0x24, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x20, 0x00, 0x04, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00,
0x1D, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x10, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00,
0x41, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x16, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x85, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x05, 0x00,
0x10, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,
0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00,
0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x07, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};

View File

@ -1,86 +0,0 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 47
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %_ %xe_in_position %xe_out_texcoord %xe_in_texcoord %xe_out_color %xe_in_color
OpSource GLSL 450
OpName %main "main"
OpName %gl_PerVertex "gl_PerVertex"
OpMemberName %gl_PerVertex 0 "gl_Position"
OpMemberName %gl_PerVertex 1 "gl_PointSize"
OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
OpMemberName %gl_PerVertex 3 "gl_CullDistance"
OpName %_ ""
OpName %xe_in_position "xe_in_position"
OpName %XePushConstants "XePushConstants"
OpMemberName %XePushConstants 0 "viewport_inv_size"
OpName %xe_push_constants "xe_push_constants"
OpName %xe_out_texcoord "xe_out_texcoord"
OpName %xe_in_texcoord "xe_in_texcoord"
OpName %xe_out_color "xe_out_color"
OpName %xe_in_color "xe_in_color"
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
OpDecorate %gl_PerVertex Block
OpDecorate %xe_in_position Location 0
OpMemberDecorate %XePushConstants 0 Offset 0
OpDecorate %XePushConstants Block
OpDecorate %xe_out_texcoord Location 0
OpDecorate %xe_in_texcoord Location 1
OpDecorate %xe_out_color Location 1
OpDecorate %xe_in_color Location 2
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
%_ = OpVariable %_ptr_Output_gl_PerVertex Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%v2float = OpTypeVector %float 2
%_ptr_Input_v2float = OpTypePointer Input %v2float
%xe_in_position = OpVariable %_ptr_Input_v2float Input
%XePushConstants = OpTypeStruct %v2float
%_ptr_PushConstant_XePushConstants = OpTypePointer PushConstant %XePushConstants
%xe_push_constants = OpVariable %_ptr_PushConstant_XePushConstants PushConstant
%_ptr_PushConstant_v2float = OpTypePointer PushConstant %v2float
%float_2 = OpConstant %float 2
%float_1 = OpConstant %float 1
%float_0 = OpConstant %float 0
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_ptr_Output_v2float = OpTypePointer Output %v2float
%xe_out_texcoord = OpVariable %_ptr_Output_v2float Output
%xe_in_texcoord = OpVariable %_ptr_Input_v2float Input
%xe_out_color = OpVariable %_ptr_Output_v4float Output
%_ptr_Input_v4float = OpTypePointer Input %v4float
%xe_in_color = OpVariable %_ptr_Input_v4float Input
%46 = OpConstantComposite %v2float %float_1 %float_1
%main = OpFunction %void None %3
%5 = OpLabel
%19 = OpLoad %v2float %xe_in_position
%24 = OpAccessChain %_ptr_PushConstant_v2float %xe_push_constants %int_0
%25 = OpLoad %v2float %24
%26 = OpFMul %v2float %19 %25
%28 = OpVectorTimesScalar %v2float %26 %float_2
%31 = OpFSub %v2float %28 %46
%33 = OpCompositeExtract %float %31 0
%34 = OpCompositeExtract %float %31 1
%35 = OpCompositeConstruct %v4float %33 %34 %float_0 %float_1
%37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %37 %35
%41 = OpLoad %v2float %xe_in_texcoord
OpStore %xe_out_texcoord %41
%45 = OpLoad %v4float %xe_in_color
OpStore %xe_out_color %45
OpReturn
OpFunctionEnd

View File

@ -1,22 +0,0 @@
#version 450 core
precision highp float;
layout(location = 0) in vec2 xe_in_texcoord;
layout(location = 1) in vec4 xe_in_color;
layout(location = 0) out vec4 xe_out_color;
layout(push_constant) uniform XePushConstants {
layout(offset = 8) uint restrict_texture_samples;
} xe_push_constants;
// layout(set = 0, binding = 0) uniform sampler2D xe_immediate_texture_sampler;
void main() {
xe_out_color = xe_in_color;
/* if (xe_push_constants.restrict_texture_samples == 0u ||
xe_in_texcoord.x <= 1.0) {
xe_out_color *=
textureLod(xe_immediate_texture_sampler, xe_in_texcoord, 0.0f);
} */
}

View File

@ -1,21 +0,0 @@
#version 450 core
precision highp float;
layout(location = 0) in vec2 xe_in_position;
layout(location = 1) in vec2 xe_in_texcoord;
layout(location = 2) in vec4 xe_in_color;
layout(location = 0) out vec2 xe_out_texcoord;
layout(location = 1) out vec4 xe_out_color;
layout(push_constant) uniform XePushConstants {
layout(offset = 0) vec2 viewport_inv_size;
} xe_push_constants;
void main() {
gl_Position = vec4(
xe_in_position * xe_push_constants.viewport_inv_size * 2.0 - 1.0, 0.0,
1.0);
xe_out_texcoord = xe_in_texcoord;
xe_out_color = xe_in_color;
}

View File

@ -1,212 +0,0 @@
/**
******************************************************************************
* 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/transient_objects.h"
#include <algorithm>
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/ui/vk/vulkan_context.h"
namespace xe {
namespace ui {
namespace vk {
UploadBufferChain::UploadBufferChain(VulkanContext* context,
VkDeviceSize frame_page_size,
VkBufferUsageFlags usage_flags)
: context_(context),
frame_page_size_(frame_page_size),
usage_flags_(usage_flags) {}
UploadBufferChain::~UploadBufferChain() {
// Allow mid-frame destruction in cases like device loss.
EndFrame();
ClearCache();
}
void UploadBufferChain::ClearCache() {
assert_true(current_frame_buffer_ == 0 && current_frame_buffer_bytes_ == 0);
auto device = context_->GetVulkanProvider()->GetDevice();
for (UploadBuffer& upload_buffer : upload_buffers_) {
vkDestroyBuffer(device, upload_buffer.buffer, nullptr);
vkUnmapMemory(device, upload_buffer.memory);
vkFreeMemory(device, upload_buffer.memory, nullptr);
}
}
void UploadBufferChain::EndFrame() {
EndPage();
current_frame_buffer_ = 0;
buffer_creation_failed_ = false;
}
void UploadBufferChain::EndPage() {
if (current_frame_buffer_bytes_ == 0) {
return;
}
if (!memory_host_coherent_) {
auto device = context_->GetVulkanProvider()->GetDevice();
VkMappedMemoryRange flush_range;
flush_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
flush_range.pNext = nullptr;
flush_range.memory = upload_buffers_[current_frame_buffer_].memory;
flush_range.offset = frame_page_size_ * context_->GetCurrentQueueFrame();
flush_range.size = current_frame_buffer_bytes_;
vkFlushMappedMemoryRanges(device, 1, &flush_range);
}
++current_frame_buffer_;
current_frame_buffer_bytes_ = 0;
}
bool UploadBufferChain::EnsureCurrentBufferAllocated() {
if (current_frame_buffer_ < upload_buffers_.size()) {
return true;
}
assert_true(current_frame_buffer_ == upload_buffers_.size());
assert_true(current_frame_buffer_bytes_ == 0);
if (buffer_creation_failed_) {
return false;
}
UploadBuffer upload_buffer;
auto provider = context_->GetVulkanProvider();
auto device = provider->GetDevice();
VkBufferCreateInfo buffer_create_info;
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
buffer_create_info.pNext = nullptr;
buffer_create_info.flags = 0;
buffer_create_info.size = frame_page_size_ * VulkanContext::kQueuedFrames;
buffer_create_info.usage = usage_flags_;
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buffer_create_info.queueFamilyIndexCount = 0;
buffer_create_info.pQueueFamilyIndices = nullptr;
if (vkCreateBuffer(device, &buffer_create_info, nullptr,
&upload_buffer.buffer) != VK_SUCCESS) {
XELOGE(
"Failed to create a Vulkan upload buffer with {} x {} bytes and "
"0x{:08X} usage",
buffer_create_info.size, VulkanContext::kQueuedFrames,
static_cast<uint32_t>(usage_flags_));
buffer_creation_failed_ = true;
return false;
}
if (memory_type_ == UINT32_MAX) {
// Page memory requirements not known yet.
VkMemoryRequirements buffer_memory_requirements;
vkGetBufferMemoryRequirements(device, upload_buffer.buffer,
&buffer_memory_requirements);
memory_type_ =
provider->FindMemoryType(buffer_memory_requirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
if (memory_type_ == UINT32_MAX) {
XELOGE(
"Failed to find a memory type for an upload buffer with {} bytes "
"and 0x{:08X} usage",
buffer_memory_requirements.size, usage_flags_);
vkDestroyBuffer(device, upload_buffer.buffer, nullptr);
buffer_creation_failed_ = true;
return false;
}
const VkPhysicalDeviceMemoryProperties& device_memory_properties =
provider->GetPhysicalDeviceMemoryProperties();
memory_host_coherent_ =
(device_memory_properties.memoryTypes[memory_type_].propertyFlags &
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
memory_page_size_ = buffer_memory_requirements.size;
}
VkMemoryAllocateInfo memory_allocate_info;
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memory_allocate_info.pNext = nullptr;
memory_allocate_info.allocationSize = memory_page_size_;
memory_allocate_info.memoryTypeIndex = memory_type_;
if (vkAllocateMemory(device, &memory_allocate_info, nullptr,
&upload_buffer.memory) != VK_SUCCESS) {
XELOGE("Failed to allocate {} for a Vulkan upload buffer",
memory_page_size_);
vkDestroyBuffer(device, upload_buffer.buffer, nullptr);
buffer_creation_failed_ = true;
return false;
}
if (vkBindBufferMemory(device, upload_buffer.buffer, upload_buffer.memory,
0) != VK_SUCCESS) {
XELOGE("Failed to bind a {}-byte memory object to a Vulkan upload buffer",
memory_page_size_);
vkDestroyBuffer(device, upload_buffer.buffer, nullptr);
vkFreeMemory(device, upload_buffer.memory, nullptr);
buffer_creation_failed_ = true;
return false;
}
if (vkMapMemory(device, upload_buffer.memory, 0, memory_page_size_, 0,
&upload_buffer.mapping) != VK_SUCCESS) {
XELOGE("Failed to map a {}-byte memory object of a Vulkan upload buffer",
memory_page_size_);
vkDestroyBuffer(device, upload_buffer.buffer, nullptr);
vkFreeMemory(device, upload_buffer.memory, nullptr);
buffer_creation_failed_ = true;
return false;
}
upload_buffers_.push_back(upload_buffer);
return true;
}
uint8_t* UploadBufferChain::RequestFull(VkDeviceSize size, VkBuffer& buffer_out,
VkDeviceSize& offset_out) {
assert_true(size <= frame_page_size_);
if (size > frame_page_size_) {
return nullptr;
}
if (frame_page_size_ - current_frame_buffer_bytes_ < size) {
EndPage();
}
if (!EnsureCurrentBufferAllocated()) {
return nullptr;
}
VkDeviceSize offset = current_frame_buffer_bytes_ +
context_->GetCurrentQueueFrame() * frame_page_size_;
current_frame_buffer_bytes_ += size;
UploadBuffer& upload_buffer = upload_buffers_[current_frame_buffer_];
buffer_out = upload_buffer.buffer;
offset_out = offset;
return reinterpret_cast<uint8_t*>(upload_buffer.mapping) + offset;
}
uint8_t* UploadBufferChain::RequestPartial(VkDeviceSize size,
VkBuffer& buffer_out,
VkDeviceSize& offset_out,
VkDeviceSize& size_out) {
if (current_frame_buffer_bytes_ >= frame_page_size_) {
EndPage();
}
if (!EnsureCurrentBufferAllocated()) {
return nullptr;
}
size = std::min(size, frame_page_size_ - current_frame_buffer_bytes_);
size_out = size;
VkDeviceSize offset = current_frame_buffer_bytes_ +
context_->GetCurrentQueueFrame() * frame_page_size_;
current_frame_buffer_bytes_ += size;
UploadBuffer& upload_buffer = upload_buffers_[current_frame_buffer_];
buffer_out = upload_buffer.buffer;
offset_out = offset;
return reinterpret_cast<uint8_t*>(upload_buffer.mapping) + offset;
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -1,72 +0,0 @@
/**
******************************************************************************
* 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_TRANSIENT_OBJECTS_H_
#define XENIA_UI_VK_TRANSIENT_OBJECTS_H_
#include <vector>
#include "xenia/ui/vk/vulkan_provider.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanContext;
class UploadBufferChain {
public:
UploadBufferChain(VulkanContext* context, VkDeviceSize frame_page_size,
VkBufferUsageFlags usage_flags);
~UploadBufferChain();
void EndFrame();
void ClearCache();
// Request to write data in a single piece, creating a new page if the current
// one doesn't have enough free space.
uint8_t* RequestFull(VkDeviceSize size, VkBuffer& buffer_out,
VkDeviceSize& offset_out);
// Request to write data in multiple parts, filling the buffer entirely.
uint8_t* RequestPartial(VkDeviceSize size, VkBuffer& buffer_out,
VkDeviceSize& offset_out, VkDeviceSize& size_out);
private:
VulkanContext* context_;
VkBufferUsageFlags usage_flags_;
VkDeviceSize frame_page_size_;
void EndPage();
bool EnsureCurrentBufferAllocated();
VkDeviceSize memory_page_size_ = 0;
uint32_t memory_type_ = UINT32_MAX;
bool memory_host_coherent_ = false;
struct UploadBuffer {
// frame_page_size_ * VulkanContext::kQueuedFrames bytes.
// Single allocation for VulkanContext::kQueuedFrames pages so there are
// less different memory objects.
VkDeviceMemory memory;
void* mapping;
VkBuffer buffer;
};
std::vector<UploadBuffer> upload_buffers_;
size_t current_frame_buffer_ = 0;
VkDeviceSize current_frame_buffer_bytes_ = 0;
bool buffer_creation_failed_ = false;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_TRANSIENT_OBJECTS_H_

View File

@ -1,689 +0,0 @@
/**
******************************************************************************
* 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 <cstdlib>
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/platform.h"
#include "xenia/ui/vk/vulkan_immediate_drawer.h"
#include "xenia/ui/vk/vulkan_util.h"
#include "xenia/ui/window.h"
DEFINE_bool(vk_random_clear_color, false,
"Randomize presentation framebuffer clear color.", "Vulkan");
namespace xe {
namespace ui {
namespace vk {
VulkanContext::VulkanContext(VulkanProvider* provider, Window* target_window)
: GraphicsContext(provider, target_window) {}
VulkanContext::~VulkanContext() { Shutdown(); }
bool VulkanContext::Initialize() {
auto provider = GetVulkanProvider();
auto instance = provider->GetInstance();
auto physical_device = provider->GetPhysicalDevice();
auto device = provider->GetDevice();
auto graphics_queue_family = provider->GetGraphicsQueueFamily();
context_lost_ = false;
current_frame_ = 1;
// No frames have been completed yet.
last_completed_frame_ = 0;
// Keep in sync with the modulo because why not.
current_queue_frame_ = 1;
// Create fences for synchronization of reuse and destruction of transient
// objects (like command buffers) and for global shutdown.
VkFenceCreateInfo fence_create_info;
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_create_info.pNext = nullptr;
fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
if (vkCreateFence(device, &fence_create_info, nullptr, &fences_[i]) !=
VK_SUCCESS) {
XELOGE("Failed to create a Vulkan fence");
Shutdown();
return false;
}
}
if (target_window_) {
// Create the surface.
VkResult surface_create_result;
#if XE_PLATFORM_WIN32
VkWin32SurfaceCreateInfoKHR surface_create_info;
surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surface_create_info.pNext = nullptr;
surface_create_info.flags = 0;
surface_create_info.hinstance =
static_cast<HINSTANCE>(target_window_->native_platform_handle());
surface_create_info.hwnd =
static_cast<HWND>(target_window_->native_handle());
surface_create_result = vkCreateWin32SurfaceKHR(
instance, &surface_create_info, nullptr, &surface_);
#elif XE_PLATFORM_LINUX
#ifdef GDK_WINDOWING_X11
VkXcbSurfaceCreateInfoKHR surface_create_info;
surface_create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
surface_create_info.pNext = nullptr;
surface_create_info.flags = 0;
surface_create_info.connection = static_cast<xcb_connection_t*>(
target_window_->native_platform_handle());
surface_create_info.window = gdk_x11_window_get_xid(gtk_widget_get_window(
static_cast<GtkWidget*>(target_window_->native_handle())));
surface_create_result = vkCreateXcbSurfaceKHR(
instance, &surface_create_info, nullptr, &surface_);
#else
#error No Vulkan surface creation for the GDK backend implemented yet.
#endif
#else
#error No Vulkan surface creation for the platform implemented yet.
#endif
if (surface_create_result != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan surface");
Shutdown();
return false;
}
// Check if the graphics queue can present to the surface.
// FIXME(Triang3l): Separate present queue not supported - would require
// deferring VkDevice creation because vkCreateDevice needs all used queues.
VkBool32 surface_supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, graphics_queue_family,
surface_, &surface_supported);
if (!surface_supported) {
XELOGE(
"Surface not supported by the graphics queue of the Vulkan physical "
"device");
Shutdown();
return false;
}
// Choose the number of swapchain images and the alpha compositing mode.
VkSurfaceCapabilitiesKHR surface_capabilities;
if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
physical_device, surface_, &surface_capabilities) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan surface capabilities");
Shutdown();
return false;
}
surface_min_image_count_ =
std::max(uint32_t(3), surface_capabilities.minImageCount);
if (surface_capabilities.maxImageCount) {
surface_min_image_count_ = std::min(surface_min_image_count_,
surface_capabilities.maxImageCount);
}
surface_transform_ = surface_capabilities.currentTransform;
if (surface_capabilities.supportedCompositeAlpha &
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
surface_composite_alpha_ = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
} else if (surface_capabilities.supportedCompositeAlpha &
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
surface_composite_alpha_ = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
} else {
surface_composite_alpha_ = VkCompositeAlphaFlagBitsKHR(
uint32_t(1) << xe::tzcnt(
surface_capabilities.supportedCompositeAlpha));
}
// Get the preferred surface format.
uint32_t surface_format_count;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface_,
&surface_format_count,
nullptr) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan surface format count");
Shutdown();
return false;
}
std::vector<VkSurfaceFormatKHR> surface_formats;
surface_formats.resize(surface_format_count);
if (vkGetPhysicalDeviceSurfaceFormatsKHR(
physical_device, surface_, &surface_format_count,
surface_formats.data()) != VK_SUCCESS ||
!surface_format_count) {
XELOGE("Failed to get Vulkan surface formats");
Shutdown();
return false;
}
// Prefer RGB8.
surface_format_ = surface_formats[0];
for (uint32_t i = 0; i < surface_format_count; ++i) {
const VkSurfaceFormatKHR& surface_format = surface_formats[i];
if (surface_format.format == VK_FORMAT_UNDEFINED) {
surface_format_.format = VK_FORMAT_R8G8B8A8_UNORM;
surface_format_.colorSpace = surface_format.colorSpace;
break;
}
if (surface_format.format == VK_FORMAT_R8G8B8A8_UNORM ||
surface_format.format == VK_FORMAT_B8G8R8A8_UNORM) {
surface_format_ = surface_format;
break;
}
}
// Prefer non-vsyncing presentation modes (better without tearing), or fall
// back to FIFO.
surface_present_mode_ = VK_PRESENT_MODE_FIFO_KHR;
uint32_t present_mode_count;
if (vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface_,
&present_mode_count,
nullptr) == VK_SUCCESS) {
std::vector<VkPresentModeKHR> present_modes;
present_modes.resize(present_mode_count);
if (vkGetPhysicalDeviceSurfacePresentModesKHR(
physical_device, surface_, &present_mode_count,
present_modes.data()) == VK_SUCCESS) {
for (uint32_t i = 0; i < present_mode_count; ++i) {
VkPresentModeKHR present_mode = present_modes[i];
if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR ||
present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
surface_present_mode_ = present_mode;
if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
break;
}
}
}
}
}
// Create presentation semaphores.
VkSemaphoreCreateInfo semaphore_create_info;
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphore_create_info.pNext = nullptr;
semaphore_create_info.flags = 0;
if (vkCreateSemaphore(device, &semaphore_create_info, nullptr,
&semaphore_present_complete_) != VK_SUCCESS) {
XELOGE(
"Failed to create a Vulkan semaphone for awaiting swapchain image "
"acquisition");
Shutdown();
return false;
}
if (vkCreateSemaphore(device, &semaphore_create_info, nullptr,
&semaphore_draw_complete_) != VK_SUCCESS) {
XELOGE(
"Failed to create a Vulkan semaphone for awaiting drawing before "
"presentation");
Shutdown();
return false;
}
// Create the render pass for drawing to the presentation image.
VkAttachmentDescription render_pass_attachment;
render_pass_attachment.flags = 0;
render_pass_attachment.format = surface_format_.format;
render_pass_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
render_pass_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
render_pass_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
render_pass_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
render_pass_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
render_pass_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
render_pass_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference render_pass_attachment_reference;
render_pass_attachment_reference.attachment = 0;
render_pass_attachment_reference.layout =
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription render_pass_subpass = {};
render_pass_subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
render_pass_subpass.colorAttachmentCount = 1;
render_pass_subpass.pColorAttachments = &render_pass_attachment_reference;
VkSubpassDependency render_pass_dependencies[2];
render_pass_dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
render_pass_dependencies[0].dstSubpass = 0;
render_pass_dependencies[0].srcStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[0].dstStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
render_pass_dependencies[0].dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
render_pass_dependencies[1].srcSubpass = 0;
render_pass_dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
render_pass_dependencies[1].srcStageMask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
render_pass_dependencies[1].dstStageMask =
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
render_pass_dependencies[1].srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
render_pass_dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
render_pass_dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo render_pass_create_info;
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_create_info.pNext = nullptr;
render_pass_create_info.flags = 0;
render_pass_create_info.attachmentCount = 1;
render_pass_create_info.pAttachments = &render_pass_attachment;
render_pass_create_info.subpassCount = 1;
render_pass_create_info.pSubpasses = &render_pass_subpass;
render_pass_create_info.dependencyCount =
uint32_t(xe::countof(render_pass_dependencies));
render_pass_create_info.pDependencies = render_pass_dependencies;
if (vkCreateRenderPass(device, &render_pass_create_info, nullptr,
&present_render_pass_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan render pass");
Shutdown();
return false;
}
// Create the command buffers for drawing to the presentation image.
VkCommandPoolCreateInfo command_pool_create_info;
command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
command_pool_create_info.pNext = nullptr;
command_pool_create_info.flags =
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
command_pool_create_info.queueFamilyIndex = graphics_queue_family;
if (vkCreateCommandPool(device, &command_pool_create_info, nullptr,
&present_command_pool_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan command pool");
Shutdown();
return false;
}
VkCommandBufferAllocateInfo command_buffer_allocate_info;
command_buffer_allocate_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocate_info.pNext = nullptr;
command_buffer_allocate_info.commandPool = present_command_pool_;
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_allocate_info.commandBufferCount =
uint32_t(xe::countof(present_command_buffers_));
if (vkAllocateCommandBuffers(device, &command_buffer_allocate_info,
present_command_buffers_) != VK_SUCCESS) {
XELOGE("Failed to create the presentation Vulkan command buffers");
Shutdown();
return false;
}
// Initialize the immediate mode drawer if not offscreen.
immediate_drawer_ = std::make_unique<VulkanImmediateDrawer>(this);
if (!immediate_drawer_->Initialize()) {
Shutdown();
return false;
}
swapchain_ = VK_NULL_HANDLE;
}
initialized_fully_ = true;
return true;
}
void VulkanContext::Shutdown() {
auto provider = GetVulkanProvider();
auto instance = provider->GetInstance();
auto device = provider->GetDevice();
if (initialized_fully_ && !context_lost_) {
AwaitAllFramesCompletion();
}
initialized_fully_ = false;
if (target_window_) {
DestroySwapchainImages();
util::DestroyAndNullHandle(vkDestroySwapchainKHR, device, swapchain_);
immediate_drawer_.reset();
util::DestroyAndNullHandle(vkDestroyCommandPool, device,
present_command_pool_);
util::DestroyAndNullHandle(vkDestroyRenderPass, device,
present_render_pass_);
util::DestroyAndNullHandle(vkDestroySemaphore, device,
semaphore_draw_complete_);
util::DestroyAndNullHandle(vkDestroySemaphore, device,
semaphore_present_complete_);
util::DestroyAndNullHandle(vkDestroySurfaceKHR, instance, surface_);
}
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
util::DestroyAndNullHandle(vkDestroyFence, device, fences_[i]);
}
}
void VulkanContext::DestroySwapchainImages() {
auto device = GetVulkanProvider()->GetDevice();
for (auto& image : swapchain_images_) {
vkDestroyFramebuffer(device, image.framebuffer, nullptr);
vkDestroyImageView(device, image.image_view, nullptr);
}
swapchain_images_.clear();
}
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() {
if (context_lost_) {
return;
}
auto provider = GetVulkanProvider();
auto device = provider->GetDevice();
// Await the availability of transient objects for the new frame.
// The frame number is incremented in EndSwap so it can be treated the same
// way both when inside a frame and when outside of it (it's tied to actual
// submissions).
if (vkWaitForFences(device, 1, &fences_[current_queue_frame_], VK_TRUE,
UINT64_MAX) != VK_SUCCESS) {
XELOGE("Failed to wait for the Vulkan fence the next frame");
context_lost_ = true;
return;
}
// Update the completed frame if didn't explicitly await all queued frames.
if (last_completed_frame_ + kQueuedFrames < current_frame_) {
last_completed_frame_ = current_frame_ - kQueuedFrames;
}
if (target_window_) {
VkExtent2D target_window_extent = {
uint32_t(target_window_->scaled_width()),
uint32_t(target_window_->scaled_height())};
// On certain platforms (like Windows), swapchain size must match the window
// size.
VkSurfaceTransformFlagBitsKHR current_transform = surface_transform_;
VkSurfaceCapabilitiesKHR surface_capabilities;
if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
provider->GetPhysicalDevice(), surface_, &surface_capabilities) ==
VK_SUCCESS) {
current_transform = surface_capabilities.currentTransform;
}
bool create_swapchain =
swapchain_ == VK_NULL_HANDLE ||
swapchain_extent_.width != target_window_extent.width ||
swapchain_extent_.height != target_window_extent.height ||
surface_transform_ != current_transform;
if (!create_swapchain) {
// Try to acquire the image for the existing swapchain or check if out of
// date.
VkResult acquire_result = vkAcquireNextImageKHR(
device, swapchain_, UINT64_MAX, semaphore_present_complete_,
VK_NULL_HANDLE, &swapchain_acquired_image_index_);
if (acquire_result == VK_ERROR_OUT_OF_DATE_KHR) {
create_swapchain = true;
} else if (acquire_result != VK_SUCCESS &&
acquire_result != VK_SUBOPTIMAL_KHR) {
// Checking for resizing externally. For proper suboptimal handling,
// either the swapchain needs to be recreated in the next frame, or the
// semaphore must be awaited right now (since suboptimal is a successful
// result). Assume all other errors are fatal.
XELOGE("Failed to acquire a Vulkan swapchain image");
context_lost_ = true;
return;
}
}
if (create_swapchain) {
if (swapchain_ != VK_NULL_HANDLE) {
AwaitAllFramesCompletion();
if (context_lost_) {
return;
}
}
DestroySwapchainImages();
// Destroying the old swapchain after creating the new one because
// swapchain creation needs the old one.
VkSwapchainKHR swapchain;
VkSwapchainCreateInfoKHR swapchain_create_info;
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchain_create_info.pNext = nullptr;
swapchain_create_info.flags = 0;
swapchain_create_info.surface = surface_;
swapchain_create_info.minImageCount = surface_min_image_count_;
swapchain_create_info.imageFormat = surface_format_.format;
swapchain_create_info.imageColorSpace = surface_format_.colorSpace;
swapchain_create_info.imageExtent = target_window_extent;
swapchain_create_info.imageArrayLayers = 1;
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchain_create_info.queueFamilyIndexCount = 0;
swapchain_create_info.pQueueFamilyIndices = nullptr;
swapchain_create_info.preTransform = current_transform;
swapchain_create_info.compositeAlpha = surface_composite_alpha_;
swapchain_create_info.presentMode = surface_present_mode_;
swapchain_create_info.clipped = VK_TRUE;
swapchain_create_info.oldSwapchain = swapchain_;
if (vkCreateSwapchainKHR(device, &swapchain_create_info, nullptr,
&swapchain) != VK_SUCCESS) {
XELOGE("Failed to create a {}x{} Vulkan swap chain",
target_window_extent.width, target_window_extent.height);
context_lost_ = true;
return;
}
if (swapchain_ != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(device, swapchain_, nullptr);
}
swapchain_ = swapchain;
swapchain_extent_ = target_window_extent;
surface_transform_ = current_transform;
uint32_t swapchain_image_count;
if (vkGetSwapchainImagesKHR(device, swapchain_, &swapchain_image_count,
nullptr) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan swapchain image count");
context_lost_ = true;
return;
}
std::vector<VkImage> swapchain_images;
swapchain_images.resize(swapchain_image_count);
if (vkGetSwapchainImagesKHR(device, swapchain_, &swapchain_image_count,
swapchain_images.data()) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan swapchain images");
context_lost_ = true;
return;
}
swapchain_images_.reserve(swapchain_image_count);
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
image_view_create_info.pNext = nullptr;
image_view_create_info.flags = 0;
image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
image_view_create_info.format = surface_format_.format;
image_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
image_view_create_info.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_COLOR_BIT;
image_view_create_info.subresourceRange.baseMipLevel = 0;
image_view_create_info.subresourceRange.levelCount = 1;
image_view_create_info.subresourceRange.baseArrayLayer = 0;
image_view_create_info.subresourceRange.layerCount = 1;
VkFramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_create_info.pNext = nullptr;
framebuffer_create_info.flags = 0;
framebuffer_create_info.renderPass = present_render_pass_;
framebuffer_create_info.attachmentCount = 1;
framebuffer_create_info.width = swapchain_extent_.width;
framebuffer_create_info.height = swapchain_extent_.height;
framebuffer_create_info.layers = 1;
for (uint32_t i = 0; i < swapchain_image_count; ++i) {
SwapchainImage swapchain_image;
swapchain_image.image = swapchain_images[i];
image_view_create_info.image = swapchain_image.image;
if (vkCreateImageView(device, &image_view_create_info, nullptr,
&swapchain_image.image_view) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan swapchain image view");
context_lost_ = true;
return;
}
framebuffer_create_info.pAttachments = &swapchain_image.image_view;
if (vkCreateFramebuffer(device, &framebuffer_create_info, nullptr,
&swapchain_image.framebuffer) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan swapchain framebuffer");
vkDestroyImageView(device, swapchain_image.image_view, nullptr);
context_lost_ = true;
return;
}
// Add now so it's complete if DestroySwapchainImages is called.
swapchain_images_.push_back(swapchain_image);
}
VkResult acquire_result = vkAcquireNextImageKHR(
device, swapchain_, UINT64_MAX, semaphore_present_complete_,
VK_NULL_HANDLE, &swapchain_acquired_image_index_);
if (acquire_result != VK_SUCCESS && acquire_result != VK_SUBOPTIMAL_KHR) {
XELOGE("Failed to acquire a Vulkan swapchain image");
context_lost_ = true;
return;
}
}
// Begin drawing to the present image.
VkCommandBuffer command_buffer = GetPresentCommandBuffer();
VkCommandBufferBeginInfo command_buffer_begin_info;
command_buffer_begin_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.pNext = nullptr;
command_buffer_begin_info.flags =
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
command_buffer_begin_info.pInheritanceInfo = nullptr;
vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
// TODO(Triang3l): Handle vkBeginCommandBuffer failure.
VkClearValue clear_value;
if (cvars::vk_random_clear_color) {
clear_value.color.float32[0] =
rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
clear_value.color.float32[1] = 1.0f;
clear_value.color.float32[2] = 0.0f;
} else {
clear_value.color.float32[0] = 238.0f / 255.0f;
clear_value.color.float32[1] = 238.0f / 255.0f;
clear_value.color.float32[2] = 238.0f / 255.0f;
}
clear_value.color.float32[3] = 1.0f;
VkRenderPassBeginInfo render_pass_begin_info;
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_begin_info.pNext = nullptr;
render_pass_begin_info.renderPass = present_render_pass_;
render_pass_begin_info.framebuffer =
swapchain_images_[swapchain_acquired_image_index_].framebuffer;
render_pass_begin_info.renderArea.offset.x = 0;
render_pass_begin_info.renderArea.offset.y = 0;
render_pass_begin_info.renderArea.extent = swapchain_extent_;
render_pass_begin_info.clearValueCount = 1;
render_pass_begin_info.pClearValues = &clear_value;
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
VK_SUBPASS_CONTENTS_INLINE);
}
}
void VulkanContext::EndSwap() {
if (context_lost_) {
return;
}
auto provider = GetVulkanProvider();
auto queue = provider->GetGraphicsQueue();
if (target_window_ != nullptr) {
// Present.
VkCommandBuffer command_buffer = GetPresentCommandBuffer();
vkCmdEndRenderPass(command_buffer);
vkEndCommandBuffer(command_buffer);
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &semaphore_present_complete_;
VkPipelineStageFlags present_complete_wait_dst_stage_mask =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.pWaitDstStageMask = &present_complete_wait_dst_stage_mask;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &semaphore_draw_complete_;
if (vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
XELOGE("Failed to submit the presentation command buffer");
context_lost_ = true;
return;
}
VkPresentInfoKHR present_info;
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = nullptr;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &semaphore_draw_complete_;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain_;
present_info.pImageIndices = &swapchain_acquired_image_index_;
present_info.pResults = nullptr;
VkResult present_result = vkQueuePresentKHR(queue, &present_info);
if (present_result != VK_SUCCESS && present_result != VK_SUBOPTIMAL_KHR &&
present_result != VK_ERROR_OUT_OF_DATE_KHR) {
// VK_ERROR_OUT_OF_DATE_KHR will be handled in the next BeginSwap. In case
// of it, the semaphore will be unsignaled anyway:
// https://github.com/KhronosGroup/Vulkan-Docs/issues/572
XELOGE("Failed to present the image");
context_lost_ = true;
return;
}
}
// Go to the next transient object frame.
VkFence fence = fences_[current_queue_frame_];
vkResetFences(provider->GetDevice(), 1, &fence);
if (vkQueueSubmit(queue, 0, nullptr, fences_[current_queue_frame_]) !=
VK_SUCCESS) {
XELOGE("Failed to signal a Vulkan frame fence");
context_lost_ = true;
return;
}
++current_queue_frame_;
if (current_queue_frame_ >= kQueuedFrames) {
current_queue_frame_ -= kQueuedFrames;
}
++current_frame_;
}
std::unique_ptr<RawImage> VulkanContext::Capture() {
// TODO(Triang3l): Read back swapchain front buffer.
return nullptr;
}
void VulkanContext::AwaitAllFramesCompletion() {
// Await the last frame since previous frames must be completed before it.
if (context_lost_) {
return;
}
auto device = GetVulkanProvider()->GetDevice();
uint32_t await_frame = current_queue_frame_ + (kQueuedFrames - 1);
if (await_frame >= kQueuedFrames) {
await_frame -= kQueuedFrames;
}
if (vkWaitForFences(device, 1, &fences_[await_frame], VK_TRUE, UINT64_MAX) !=
VK_SUCCESS) {
XELOGE("Failed to wait for the Vulkan fence the last frame");
context_lost_ = true;
return;
}
last_completed_frame_ = current_frame_ - 1;
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -1,118 +0,0 @@
/**
******************************************************************************
* 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 <vector>
#include "xenia/ui/graphics_context.h"
#include "xenia/ui/vk/vulkan_immediate_drawer.h"
#include "xenia/ui/vk/vulkan_provider.h"
#define FINE_GRAINED_DRAW_SCOPES 1
namespace xe {
namespace ui {
namespace vk {
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;
VulkanProvider* GetVulkanProvider() const {
return static_cast<VulkanProvider*>(provider_);
}
// The count of copies of transient objects (like command buffers, dynamic
// descriptor pools) that must be kept when rendering with this context.
static constexpr uint32_t kQueuedFrames = 3;
// The current absolute frame number.
uint64_t GetCurrentFrame() { return current_frame_; }
// The last completed frame - it's fine to destroy objects used in it.
uint64_t GetLastCompletedFrame() { return last_completed_frame_; }
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
void AwaitAllFramesCompletion();
const VkSurfaceFormatKHR& GetSurfaceFormat() const { return surface_format_; }
VkRenderPass GetPresentRenderPass() const { return present_render_pass_; }
VkCommandBuffer GetPresentCommandBuffer() const {
return present_command_buffers_[current_queue_frame_];
}
private:
friend class VulkanProvider;
explicit VulkanContext(VulkanProvider* provider, Window* target_window);
private:
bool Initialize();
void Shutdown();
void DestroySwapchainImages();
bool initialized_fully_ = false;
bool context_lost_ = false;
uint64_t current_frame_ = 1;
uint64_t last_completed_frame_ = 0;
uint32_t current_queue_frame_ = 1;
VkFence fences_[kQueuedFrames] = {};
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
uint32_t surface_min_image_count_ = 3;
VkSurfaceFormatKHR surface_format_ = {VK_FORMAT_R8G8B8A8_UNORM,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
VkSurfaceTransformFlagBitsKHR surface_transform_ =
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
VkCompositeAlphaFlagBitsKHR surface_composite_alpha_ =
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkPresentModeKHR surface_present_mode_ = VK_PRESENT_MODE_FIFO_KHR;
VkSemaphore semaphore_present_complete_ = VK_NULL_HANDLE;
VkSemaphore semaphore_draw_complete_ = VK_NULL_HANDLE;
VkRenderPass present_render_pass_ = VK_NULL_HANDLE;
VkCommandPool present_command_pool_ = VK_NULL_HANDLE;
VkCommandBuffer present_command_buffers_[kQueuedFrames] = {};
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_ = nullptr;
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
VkExtent2D swapchain_extent_ = {};
struct SwapchainImage {
VkImage image;
VkImageView image_view;
VkFramebuffer framebuffer;
};
std::vector<SwapchainImage> swapchain_images_;
uint32_t swapchain_acquired_image_index_ = 0;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_CONTEXT_H_

View File

@ -1,429 +0,0 @@
/**
******************************************************************************
* 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"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/ui/vk/vulkan_context.h"
#include "xenia/ui/vk/vulkan_util.h"
namespace xe {
namespace ui {
namespace vk {
// Generated with `xb genspirv`.
#include "xenia/ui/vk/shaders/bin/immediate_frag.h"
#include "xenia/ui/vk/shaders/bin/immediate_vert.h"
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() {
auto device = context_->GetVulkanProvider()->GetDevice();
// Create the pipeline layout.
// TODO(Triang3l): Texture descriptor set layout.
VkPushConstantRange push_constant_ranges[2];
push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
push_constant_ranges[0].offset = offsetof(PushConstants, vertex);
push_constant_ranges[0].size = sizeof(PushConstants::vertex);
push_constant_ranges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
push_constant_ranges[1].offset = offsetof(PushConstants, fragment);
push_constant_ranges[1].size = sizeof(PushConstants::fragment);
VkPipelineLayoutCreateInfo pipeline_layout_create_info;
pipeline_layout_create_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.pNext = nullptr;
pipeline_layout_create_info.flags = 0;
pipeline_layout_create_info.setLayoutCount = 0;
pipeline_layout_create_info.pSetLayouts = nullptr;
pipeline_layout_create_info.pushConstantRangeCount =
uint32_t(xe::countof(push_constant_ranges));
pipeline_layout_create_info.pPushConstantRanges = push_constant_ranges;
if (vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr,
&pipeline_layout_) != VK_SUCCESS) {
XELOGE("Failed to create the Vulkan immediate drawer pipeline layout");
return false;
}
// Load the shaders.
VkShaderModuleCreateInfo shader_module_create_info;
shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_create_info.pNext = nullptr;
shader_module_create_info.flags = 0;
shader_module_create_info.codeSize = sizeof(immediate_vert);
shader_module_create_info.pCode =
reinterpret_cast<const uint32_t*>(immediate_vert);
VkShaderModule shader_module_vertex;
if (vkCreateShaderModule(device, &shader_module_create_info, nullptr,
&shader_module_vertex) != VK_SUCCESS) {
XELOGE("Failed to create the Vulkan immediate drawer vertex shader module");
return false;
}
shader_module_create_info.codeSize = sizeof(immediate_frag);
shader_module_create_info.pCode =
reinterpret_cast<const uint32_t*>(immediate_frag);
VkShaderModule shader_module_fragment;
if (vkCreateShaderModule(device, &shader_module_create_info, nullptr,
&shader_module_fragment) != VK_SUCCESS) {
XELOGE(
"Failed to create the Vulkan immediate drawer fragment shader module");
vkDestroyShaderModule(device, shader_module_vertex, nullptr);
return false;
}
// Create the pipelines for triangles and lines.
VkGraphicsPipelineCreateInfo pipeline_create_info;
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_create_info.pNext = nullptr;
pipeline_create_info.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
VkPipelineShaderStageCreateInfo pipeline_stages[2];
pipeline_stages[0].sType = pipeline_stages[1].sType =
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
pipeline_stages[0].pNext = pipeline_stages[1].pNext = nullptr;
pipeline_stages[0].flags = pipeline_stages[1].flags = 0;
pipeline_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
pipeline_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
pipeline_stages[0].module = shader_module_vertex;
pipeline_stages[1].module = shader_module_fragment;
pipeline_stages[0].pName = pipeline_stages[1].pName = "main";
pipeline_stages[0].pSpecializationInfo = nullptr;
pipeline_stages[1].pSpecializationInfo = nullptr;
pipeline_create_info.stageCount = uint32_t(xe::countof(pipeline_stages));
pipeline_create_info.pStages = pipeline_stages;
VkPipelineVertexInputStateCreateInfo pipeline_vertex_input;
pipeline_vertex_input.sType =
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
pipeline_vertex_input.pNext = nullptr;
pipeline_vertex_input.flags = 0;
VkVertexInputBindingDescription pipeline_vertex_bindings[1];
pipeline_vertex_bindings[0].binding = 0;
pipeline_vertex_bindings[0].stride = sizeof(ImmediateVertex);
pipeline_vertex_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
pipeline_vertex_input.vertexBindingDescriptionCount =
uint32_t(xe::countof(pipeline_vertex_bindings));
pipeline_vertex_input.pVertexBindingDescriptions = pipeline_vertex_bindings;
VkVertexInputAttributeDescription pipeline_vertex_attributes[3];
pipeline_vertex_attributes[0].location = 0;
pipeline_vertex_attributes[0].binding = 0;
pipeline_vertex_attributes[0].format = VK_FORMAT_R32G32_SFLOAT;
pipeline_vertex_attributes[0].offset = offsetof(ImmediateVertex, x);
pipeline_vertex_attributes[1].location = 1;
pipeline_vertex_attributes[1].binding = 0;
pipeline_vertex_attributes[1].format = VK_FORMAT_R32G32_SFLOAT;
pipeline_vertex_attributes[1].offset = offsetof(ImmediateVertex, u);
pipeline_vertex_attributes[2].location = 2;
pipeline_vertex_attributes[2].binding = 0;
pipeline_vertex_attributes[2].format = VK_FORMAT_R8G8B8A8_UNORM;
pipeline_vertex_attributes[2].offset = offsetof(ImmediateVertex, color);
pipeline_vertex_input.vertexAttributeDescriptionCount =
uint32_t(xe::countof(pipeline_vertex_attributes));
pipeline_vertex_input.pVertexAttributeDescriptions =
pipeline_vertex_attributes;
pipeline_create_info.pVertexInputState = &pipeline_vertex_input;
VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly;
pipeline_input_assembly.sType =
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
pipeline_input_assembly.pNext = nullptr;
pipeline_input_assembly.flags = 0;
pipeline_input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly;
pipeline_create_info.pTessellationState = nullptr;
VkPipelineViewportStateCreateInfo pipeline_viewport;
pipeline_viewport.sType =
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
pipeline_viewport.pNext = nullptr;
pipeline_viewport.flags = 0;
pipeline_viewport.viewportCount = 1;
pipeline_viewport.pViewports = nullptr;
pipeline_viewport.scissorCount = 1;
pipeline_viewport.pScissors = nullptr;
pipeline_create_info.pViewportState = &pipeline_viewport;
VkPipelineRasterizationStateCreateInfo pipeline_rasterization = {};
pipeline_rasterization.sType =
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
pipeline_rasterization.polygonMode = VK_POLYGON_MODE_FILL;
pipeline_rasterization.cullMode = VK_CULL_MODE_BACK_BIT;
pipeline_rasterization.frontFace = VK_FRONT_FACE_CLOCKWISE;
pipeline_rasterization.lineWidth = 1.0f;
pipeline_create_info.pRasterizationState = &pipeline_rasterization;
VkPipelineMultisampleStateCreateInfo pipeline_multisample = {};
pipeline_multisample.sType =
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
pipeline_multisample.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
pipeline_create_info.pMultisampleState = &pipeline_multisample;
pipeline_create_info.pDepthStencilState = nullptr;
VkPipelineColorBlendStateCreateInfo pipeline_color_blend;
pipeline_color_blend.sType =
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
pipeline_color_blend.pNext = nullptr;
pipeline_color_blend.flags = 0;
pipeline_color_blend.logicOpEnable = VK_FALSE;
pipeline_color_blend.logicOp = VK_LOGIC_OP_NO_OP;
VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment = {};
pipeline_color_blend_attachment.blendEnable = VK_TRUE;
pipeline_color_blend_attachment.srcColorBlendFactor =
VK_BLEND_FACTOR_SRC_ALPHA;
pipeline_color_blend_attachment.dstColorBlendFactor =
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
pipeline_color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
pipeline_color_blend_attachment.srcAlphaBlendFactor =
VK_BLEND_FACTOR_SRC_ALPHA;
pipeline_color_blend_attachment.dstAlphaBlendFactor =
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
pipeline_color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
pipeline_color_blend_attachment.colorWriteMask =
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
pipeline_color_blend.attachmentCount = 1;
pipeline_color_blend.pAttachments = &pipeline_color_blend_attachment;
pipeline_create_info.pColorBlendState = &pipeline_color_blend;
static const VkDynamicState pipeline_dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
VkPipelineDynamicStateCreateInfo pipeline_dynamic_state;
pipeline_dynamic_state.sType =
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
pipeline_dynamic_state.pNext = nullptr;
pipeline_dynamic_state.flags = 0;
pipeline_dynamic_state.dynamicStateCount =
uint32_t(xe::countof(pipeline_dynamic_states));
pipeline_dynamic_state.pDynamicStates = pipeline_dynamic_states;
pipeline_create_info.pDynamicState = &pipeline_dynamic_state;
pipeline_create_info.layout = pipeline_layout_;
pipeline_create_info.renderPass = context_->GetPresentRenderPass();
pipeline_create_info.subpass = 0;
pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
pipeline_create_info.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1,
&pipeline_create_info, nullptr,
&pipeline_triangle_) != VK_SUCCESS) {
XELOGE("Failed to create the Vulkan immediate drawer triangle pipeline");
vkDestroyShaderModule(device, shader_module_fragment, nullptr);
vkDestroyShaderModule(device, shader_module_vertex, nullptr);
return false;
}
pipeline_create_info.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT;
pipeline_input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
pipeline_create_info.basePipelineHandle = pipeline_triangle_;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1,
&pipeline_create_info, nullptr,
&pipeline_line_) != VK_SUCCESS) {
XELOGE("Failed to create the Vulkan immediate drawer triangle pipeline");
vkDestroyShaderModule(device, shader_module_fragment, nullptr);
vkDestroyShaderModule(device, shader_module_vertex, nullptr);
return false;
}
vkDestroyShaderModule(device, shader_module_fragment, nullptr);
vkDestroyShaderModule(device, shader_module_vertex, nullptr);
// Create transient resource pools for draws.
vertex_buffer_chain_ = std::make_unique<UploadBufferChain>(
context_, 2 * 1024 * 2014,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
// Reset the current state.
current_command_buffer_ = VK_NULL_HANDLE;
return true;
}
void VulkanImmediateDrawer::Shutdown() {
auto device = context_->GetVulkanProvider()->GetDevice();
vertex_buffer_chain_.reset();
util::DestroyAndNullHandle(vkDestroyPipeline, device, pipeline_line_);
util::DestroyAndNullHandle(vkDestroyPipeline, device, pipeline_triangle_);
util::DestroyAndNullHandle(vkDestroyPipelineLayout, device, pipeline_layout_);
}
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) {
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) {
current_command_buffer_ = context_->GetPresentCommandBuffer();
current_render_target_extent_.width = render_target_width;
current_render_target_extent_.height = render_target_height;
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = float(render_target_width);
viewport.height = float(render_target_height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 0.0f;
vkCmdSetViewport(current_command_buffer_, 0, 1, &viewport);
float viewport_inv_size[2];
viewport_inv_size[0] = 1.0f / viewport.width;
viewport_inv_size[1] = 1.0f / viewport.height;
vkCmdPushConstants(current_command_buffer_, pipeline_layout_,
VK_SHADER_STAGE_VERTEX_BIT,
offsetof(PushConstants, vertex.viewport_inv_size),
sizeof(viewport_inv_size), viewport_inv_size);
current_pipeline_ = VK_NULL_HANDLE;
}
void VulkanImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
assert_true(current_command_buffer_ != VK_NULL_HANDLE);
if (current_command_buffer_ == VK_NULL_HANDLE) {
return;
}
batch_open_ = false;
// Bind the vertices.
size_t vertex_buffer_size = batch.vertex_count * sizeof(ImmediateVertex);
VkBuffer vertex_buffer;
VkDeviceSize vertex_buffer_offset;
void* vertex_buffer_mapping = vertex_buffer_chain_->RequestFull(
vertex_buffer_size, vertex_buffer, vertex_buffer_offset);
if (!vertex_buffer_mapping) {
XELOGE(
"Failed to get a Vulkan buffer for {} vertices in the immediate drawer",
batch.vertex_count);
return;
}
std::memcpy(vertex_buffer_mapping, batch.vertices, vertex_buffer_size);
vkCmdBindVertexBuffers(current_command_buffer_, 0, 1, &vertex_buffer,
&vertex_buffer_offset);
// Bind the indices.
batch_has_index_buffer_ = batch.indices != nullptr;
if (batch_has_index_buffer_) {
size_t index_buffer_size = batch.index_count * sizeof(uint16_t);
VkBuffer index_buffer;
VkDeviceSize index_buffer_offset;
void* index_buffer_mapping = vertex_buffer_chain_->RequestFull(
xe::align(index_buffer_size, VkDeviceSize(sizeof(uint32_t))),
index_buffer, index_buffer_offset);
if (!index_buffer_mapping) {
XELOGE(
"Failed to get a Vulkan buffer for {} indices in the immediate "
"drawer",
batch.index_count);
return;
}
std::memcpy(index_buffer_mapping, batch.indices, index_buffer_size);
vkCmdBindIndexBuffer(current_command_buffer_, index_buffer,
index_buffer_offset, VK_INDEX_TYPE_UINT16);
}
batch_open_ = true;
}
void VulkanImmediateDrawer::Draw(const ImmediateDraw& draw) {
assert_true(current_command_buffer_ != VK_NULL_HANDLE);
if (current_command_buffer_ == VK_NULL_HANDLE) {
return;
}
if (!batch_open_) {
// Could be an error while obtaining the vertex and index buffers.
return;
}
// TODO(Triang3l): Bind the texture.
// Set whether texture coordinates need to be restricted.
uint32_t restrict_texture_samples = draw.restrict_texture_samples ? 1 : 0;
vkCmdPushConstants(current_command_buffer_, pipeline_layout_,
VK_SHADER_STAGE_FRAGMENT_BIT,
offsetof(PushConstants, fragment.restrict_texture_samples),
sizeof(uint32_t), &restrict_texture_samples);
// Bind the pipeline for the primitive type.
VkPipeline pipeline;
switch (draw.primitive_type) {
case ImmediatePrimitiveType::kLines:
pipeline = pipeline_line_;
break;
case ImmediatePrimitiveType::kTriangles:
pipeline = pipeline_triangle_;
break;
default:
assert_unhandled_case(draw.primitive_type);
return;
}
if (current_pipeline_ != pipeline) {
vkCmdBindPipeline(current_command_buffer_, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline);
current_pipeline_ = pipeline;
}
// Set the scissor rectangle if enabled.
VkRect2D scissor;
if (draw.scissor) {
scissor.offset.x = draw.scissor_rect[0];
scissor.offset.y = draw.scissor_rect[1];
scissor.extent.width = draw.scissor_rect[2];
scissor.extent.height = draw.scissor_rect[3];
} else {
scissor.offset.x = scissor.offset.y = 0;
scissor.extent = current_render_target_extent_;
}
vkCmdSetScissor(current_command_buffer_, 0, 1, &scissor);
// Draw.
if (batch_has_index_buffer_) {
vkCmdDrawIndexed(current_command_buffer_, draw.count, 1, draw.index_offset,
draw.base_vertex, 0);
} else {
vkCmdDraw(current_command_buffer_, draw.count, 1, draw.base_vertex, 0);
}
}
void VulkanImmediateDrawer::EndDrawBatch() { batch_open_ = false; }
void VulkanImmediateDrawer::End() {
vertex_buffer_chain_->EndFrame();
current_command_buffer_ = VK_NULL_HANDLE;
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -1,74 +0,0 @@
/**
******************************************************************************
* 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/transient_objects.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanContext;
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;
struct PushConstants {
struct {
float viewport_inv_size[2];
} vertex;
struct {
uint32_t restrict_texture_samples;
} fragment;
};
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
VkPipeline pipeline_triangle_ = VK_NULL_HANDLE;
VkPipeline pipeline_line_ = VK_NULL_HANDLE;
std::unique_ptr<UploadBufferChain> vertex_buffer_chain_ = nullptr;
VkCommandBuffer current_command_buffer_ = VK_NULL_HANDLE;
VkExtent2D current_render_target_extent_;
bool batch_open_ = false;
bool batch_has_index_buffer_;
VkPipeline current_pipeline_ = VK_NULL_HANDLE;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_

View File

@ -1,306 +0,0 @@
/**
******************************************************************************
* 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 <cstring>
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/platform.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);
}
}
uint32_t VulkanProvider::FindMemoryType(
uint32_t memory_type_bits_requirement,
VkMemoryPropertyFlags required_properties) const {
uint32_t memory_index;
while (xe::bit_scan_forward(memory_type_bits_requirement, &memory_index)) {
memory_type_bits_requirement &= ~(uint32_t(1) << memory_index);
VkMemoryPropertyFlags properties =
physical_device_memory_properties_.memoryTypes[memory_index]
.propertyFlags;
if ((properties & required_properties) == required_properties) {
return memory_index;
}
}
return UINT32_MAX;
}
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;
uint32_t physical_device_count;
if (vkEnumeratePhysicalDevices(instance_, &physical_device_count, nullptr) !=
VK_SUCCESS) {
XELOGE("Failed to get Vulkan physical device count");
return false;
}
std::vector<VkPhysicalDevice> physical_devices;
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;
}
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;
}
std::vector<VkExtensionProperties> physical_device_extensions;
std::vector<VkQueueFamilyProperties> queue_families;
bool sparse_residency_buffer = false;
for (; physical_device_index < physical_device_index_end;
++physical_device_index) {
VkPhysicalDevice physical_device = physical_devices[physical_device_index];
vkGetPhysicalDeviceProperties(physical_device,
&physical_device_properties_);
if (physical_device_properties_.apiVersion < api_version) {
continue;
}
vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features_);
if (!physical_device_features_.geometryShader) {
continue;
}
uint32_t physical_device_extension_count;
if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
&physical_device_extension_count,
nullptr) != VK_SUCCESS) {
continue;
}
physical_device_extensions.resize(physical_device_extension_count);
if (vkEnumerateDeviceExtensionProperties(
physical_device, nullptr, &physical_device_extension_count,
physical_device_extensions.data()) != VK_SUCCESS) {
continue;
}
bool supports_swapchain = false;
for (uint32_t i = 0; i < physical_device_extension_count; ++i) {
const char* extension_name = physical_device_extensions[i].extensionName;
if (!std::strcmp(extension_name, "VK_KHR_swapchain")) {
supports_swapchain = true;
break;
}
}
if (!supports_swapchain) {
continue;
}
sparse_residency_buffer = physical_device_features_.sparseBinding &&
physical_device_features_.sparseResidencyBuffer;
// Get a queue supporting graphics and compute, and if available, also
// sparse memory management.
graphics_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;
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;
}
graphics_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 (graphics_queue_family_ == UINT32_MAX) {
continue;
}
if (!(queue_families[graphics_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;
}
// TODO(Triang3l): Check if VK_EXT_fragment_shader_interlock and
// fragmentShaderSampleInterlock are supported.
// Get the needed info about the physical device.
vkGetPhysicalDeviceMemoryProperties(physical_device_,
&physical_device_memory_properties_);
// Log physical device properties.
XELOGVK("Vulkan physical device: {} (vendor {:04X}, device {:04X})",
physical_device_properties_.deviceName,
physical_device_properties_.vendorID,
physical_device_properties_.deviceID);
// Create a logical device and a queue.
float queue_priority = 1.0f;
VkDeviceQueueCreateInfo queue_create_info;
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info.pNext = nullptr;
queue_create_info.flags = 0;
queue_create_info.queueFamilyIndex = graphics_queue_family_;
queue_create_info.queueCount = 1;
queue_create_info.pQueuePriorities = &queue_priority;
const char* const device_extensions[] = {
"VK_KHR_swapchain",
};
// TODO(Triang3l): Add VK_EXT_fragment_shader_interlock if supported.
VkDeviceCreateInfo device_create_info;
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pNext = nullptr;
device_create_info.flags = 0;
device_create_info.queueCreateInfoCount = 1;
device_create_info.pQueueCreateInfos = &queue_create_info;
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = nullptr;
device_create_info.enabledExtensionCount =
uint32_t(xe::countof(device_extensions));
device_create_info.ppEnabledExtensionNames = device_extensions;
device_create_info.pEnabledFeatures = nullptr;
if (vkCreateDevice(physical_device_, &device_create_info, nullptr,
&device_) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan device");
return false;
}
volkLoadDevice(device_);
vkGetDeviceQueue(device_, graphics_queue_family_, 0, &graphics_queue_);
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

@ -1,87 +0,0 @@
/**
******************************************************************************
* 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 <cstdint>
#include <memory>
#include "xenia/base/platform.h"
#include "xenia/ui/graphics_provider.h"
#if XE_PLATFORM_WIN32
#ifndef VK_USE_PLATFORM_WIN32_KHR
#define VK_USE_PLATFORM_WIN32_KHR 1
#endif
#elif XE_PLATFORM_LINUX
#include "xenia/ui/window_gtk.h"
#if defined(GDK_WINDOWING_X11) && !defined(VK_USE_PLATFORM_XCB_KHR)
#define VK_USE_PLATFORM_XCB_KHR 1
#endif
#endif
#include "third_party/volk/volk.h"
#define XELOGVK XELOGI
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;
VkInstance GetInstance() const { return instance_; }
VkPhysicalDevice GetPhysicalDevice() const { return physical_device_; }
const VkPhysicalDeviceProperties& GetPhysicalDeviceProperties() const {
return physical_device_properties_;
}
const VkPhysicalDeviceFeatures& GetPhysicalDeviceFeatures() const {
return physical_device_features_;
}
const VkPhysicalDeviceMemoryProperties& GetPhysicalDeviceMemoryProperties()
const {
return physical_device_memory_properties_;
}
VkDevice GetDevice() const { return device_; }
uint32_t GetGraphicsQueueFamily() const { return graphics_queue_family_; }
VkQueue GetGraphicsQueue() const { return graphics_queue_; }
uint32_t FindMemoryType(uint32_t memory_type_bits_requirement,
VkMemoryPropertyFlags required_properties) const;
private:
explicit VulkanProvider(Window* main_window);
bool Initialize();
VkInstance instance_ = VK_NULL_HANDLE;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceProperties physical_device_properties_;
VkPhysicalDeviceFeatures physical_device_features_;
VkPhysicalDeviceMemoryProperties physical_device_memory_properties_;
VkDevice device_ = VK_NULL_HANDLE;
uint32_t graphics_queue_family_ = UINT32_MAX;
VkQueue graphics_queue_ = VK_NULL_HANDLE;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_PROVIDER_H_

View File

@ -1,45 +0,0 @@
/**
******************************************************************************
* 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;
}
template <typename F, typename P, typename T>
inline bool DestroyAndNullHandle(F* destroy_function, P parent, T& handle) {
if (handle != VK_NULL_HANDLE) {
destroy_function(parent, 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_