[Vulkan] Remove stillborn vk project
This commit is contained in:
parent
82ca0a7eec
commit
dffdf92e39
|
@ -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")
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
})
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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",
|
||||
})
|
|
@ -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,
|
||||
};
|
Binary file not shown.
|
@ -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
|
|
@ -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,
|
||||
};
|
Binary file not shown.
|
@ -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
|
|
@ -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);
|
||||
} */
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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_
|
Loading…
Reference in New Issue