Merge branch 'master' of https://github.com/xenia-project/xenia into canary_new

This commit is contained in:
Gliniak 2020-08-29 14:44:51 +02:00
commit a79054ffb1
49 changed files with 942 additions and 3442 deletions

3
.gitmodules vendored
View File

@ -61,3 +61,6 @@
[submodule "third_party/disruptorplus"]
path = third_party/disruptorplus
url = https://github.com/xenia-project/disruptorplus.git
[submodule "third_party/DirectXShaderCompiler"]
path = third_party/DirectXShaderCompiler
url = https://github.com/microsoft/DirectXShaderCompiler.git

View File

@ -241,7 +241,6 @@ solution("xenia")
include("src/xenia/debug/ui")
include("src/xenia/gpu")
include("src/xenia/gpu/null")
include("src/xenia/gpu/vk")
include("src/xenia/gpu/vulkan")
include("src/xenia/helper/sdl")
include("src/xenia/hid")
@ -250,7 +249,6 @@ solution("xenia")
include("src/xenia/kernel")
include("src/xenia/ui")
include("src/xenia/ui/spirv")
include("src/xenia/ui/vk")
include("src/xenia/ui/vulkan")
include("src/xenia/vfs")

View File

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

View File

@ -31,7 +31,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"
@ -49,8 +48,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");
@ -73,6 +72,10 @@ DEFINE_bool(mount_scratch, false, "Enable scratch mount", "Storage");
DEFINE_transient_path(target, "",
"Specifies the target .xex or .iso to execute.",
"General");
DEFINE_transient_bool(portable, false,
"Specifies if Xenia should run in portable mode.",
"General");
DECLARE_bool(debug);
DEFINE_bool(discord, true, "Enable Discord rich presence", "General");
@ -171,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);
}
@ -215,7 +213,8 @@ int xenia_main(const std::vector<std::string>& args) {
std::filesystem::path storage_root = cvars::storage_root;
if (storage_root.empty()) {
storage_root = xe::filesystem::GetExecutableFolder();
if (!std::filesystem::exists(storage_root / "portable.txt")) {
if (!cvars::portable &&
!std::filesystem::exists(storage_root / "portable.txt")) {
storage_root = xe::filesystem::GetUserFolder();
#if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_LINUX)
storage_root = storage_root / "Xenia";

View File

@ -298,6 +298,9 @@ T* define_cmdvar(const char* name, T* default_value, const char* description) {
DEFINE_CVar(name, default_value, description, category, false, \
std::filesystem::path)
#define DEFINE_transient_bool(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, true, bool)
#define DEFINE_transient_string(name, default_value, description, category) \
DEFINE_CVar(name, default_value, description, category, true, std::string)

View File

@ -62,21 +62,73 @@ void D3D12Shader::SetTexturesAndSamplers(
}
}
bool D3D12Shader::DisassembleDxbc(const ui::d3d12::D3D12Provider* provider) {
if (!host_disassembly_.empty()) {
return true;
void D3D12Shader::DisassembleDxbc(const ui::d3d12::D3D12Provider& provider,
bool disassemble_dxbc,
IDxbcConverter* dxbc_converter,
IDxcUtils* dxc_utils,
IDxcCompiler* dxc_compiler) {
bool is_first_disassembly = true;
if (disassemble_dxbc) {
ID3DBlob* dxbc_disassembly;
if (SUCCEEDED(provider.Disassemble(translated_binary().data(),
translated_binary().size(),
D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING |
D3D_DISASM_ENABLE_INSTRUCTION_OFFSET,
nullptr, &dxbc_disassembly))) {
assert_true(is_first_disassembly);
is_first_disassembly = false;
host_disassembly_.append(
reinterpret_cast<const char*>(dxbc_disassembly->GetBufferPointer()));
dxbc_disassembly->Release();
} else {
XELOGE("Failed to disassemble DXBC shader {:016X}", ucode_data_hash());
}
}
ID3DBlob* blob;
if (FAILED(provider->Disassemble(translated_binary().data(),
translated_binary().size(),
D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING |
D3D_DISASM_ENABLE_INSTRUCTION_OFFSET,
nullptr, &blob))) {
return false;
if (dxbc_converter && dxc_utils && dxc_compiler) {
void* dxil;
UINT32 dxil_size;
if (SUCCEEDED(dxbc_converter->Convert(
translated_binary().data(), UINT32(translated_binary().size()),
nullptr, &dxil, &dxil_size, nullptr)) &&
dxil != nullptr) {
IDxcBlobEncoding* dxil_blob;
if (SUCCEEDED(dxc_utils->CreateBlobFromPinned(dxil, dxil_size, DXC_CP_ACP,
&dxil_blob))) {
IDxcBlobEncoding* dxil_disassembly;
bool dxil_disassembled =
SUCCEEDED(dxc_compiler->Disassemble(dxil_blob, &dxil_disassembly));
dxil_blob->Release();
CoTaskMemFree(dxil);
if (dxil_disassembled) {
IDxcBlobUtf8* dxil_disassembly_utf8;
bool dxil_disassembly_got_utf8 = SUCCEEDED(dxc_utils->GetBlobAsUtf8(
dxil_disassembly, &dxil_disassembly_utf8));
dxil_disassembly->Release();
if (dxil_disassembly_got_utf8) {
if (!is_first_disassembly) {
host_disassembly_.append("\n\n");
}
is_first_disassembly = false;
host_disassembly_.append(reinterpret_cast<const char*>(
dxil_disassembly_utf8->GetStringPointer()));
dxil_disassembly_utf8->Release();
} else {
XELOGE("Failed to get DXIL shader {:016X} disassembly as UTF-8",
ucode_data_hash());
}
} else {
XELOGE("Failed to disassemble DXIL shader {:016X}",
ucode_data_hash());
}
} else {
XELOGE("Failed to create a blob with DXIL shader {:016X}",
ucode_data_hash());
CoTaskMemFree(dxil);
}
} else {
XELOGE("Failed to convert shader {:016X} to DXIL", ucode_data_hash());
}
}
host_disassembly_ = reinterpret_cast<const char*>(blob->GetBufferPointer());
blob->Release();
return true;
}
} // namespace d3d12

View File

@ -43,7 +43,11 @@ class D3D12Shader : public Shader {
return forced_early_z_shader_;
}
bool DisassembleDxbc(const ui::d3d12::D3D12Provider* provider);
void DisassembleDxbc(const ui::d3d12::D3D12Provider& provider,
bool disassemble_dxbc,
IDxbcConverter* dxbc_converter = nullptr,
IDxcUtils* dxc_utils = nullptr,
IDxcCompiler* dxc_compiler = nullptr);
static constexpr uint32_t kMaxTextureBindingIndexBits =
DxbcShaderTranslator::kMaxTextureBindingIndexBits;

View File

@ -31,9 +31,16 @@
#include "xenia/base/string.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/ui/d3d12/d3d12_util.h"
DEFINE_bool(d3d12_dxbc_disasm, false,
"Disassemble DXBC shaders after generation.", "D3D12");
DEFINE_bool(
d3d12_dxbc_disasm_dxilconv, false,
"Disassemble DXBC shaders after conversion to DXIL, if DXIL shaders are "
"supported by the OS, and DirectX Shader Compiler DLLs available at "
"https://github.com/microsoft/DirectXShaderCompiler/releases are present.",
"D3D12");
DEFINE_int32(
d3d12_pipeline_creation_threads, -1,
"Number of threads used for graphics pipeline state object creation. -1 to "
@ -85,6 +92,33 @@ PipelineCache::PipelineCache(D3D12CommandProcessor* command_processor,
PipelineCache::~PipelineCache() { Shutdown(); }
bool PipelineCache::Initialize() {
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
// Initialize the command processor thread DXIL objects.
dxbc_converter_ = nullptr;
dxc_utils_ = nullptr;
dxc_compiler_ = nullptr;
if (cvars::d3d12_dxbc_disasm_dxilconv) {
if (FAILED(provider->DxbcConverterCreateInstance(
CLSID_DxbcConverter, IID_PPV_ARGS(&dxbc_converter_)))) {
XELOGE(
"Failed to create DxbcConverter, converted DXIL disassembly for "
"debugging will be unavailable");
}
if (FAILED(provider->DxcCreateInstance(CLSID_DxcUtils,
IID_PPV_ARGS(&dxc_utils_)))) {
XELOGE(
"Failed to create DxcUtils, converted DXIL disassembly for debugging "
"will be unavailable");
}
if (FAILED(provider->DxcCreateInstance(CLSID_DxcCompiler,
IID_PPV_ARGS(&dxc_compiler_)))) {
XELOGE(
"Failed to create DxcCompiler, converted DXIL disassembly for "
"debugging will be unavailable");
}
}
uint32_t logical_processor_count = xe::threading::logical_processor_count();
if (!logical_processor_count) {
// Pick some reasonable amount if couldn't determine the number of cores.
@ -134,6 +168,10 @@ void PipelineCache::Shutdown() {
creation_threads_.clear();
}
creation_completion_event_.reset();
ui::d3d12::util::ReleaseAndNull(dxc_compiler_);
ui::d3d12::util::ReleaseAndNull(dxc_utils_);
ui::d3d12::util::ReleaseAndNull(dxbc_converter_);
}
void PipelineCache::ClearCache(bool shutting_down) {
@ -273,6 +311,19 @@ void PipelineCache::InitializeShaderStorage(
DxbcShaderTranslator translator(
provider->GetAdapterVendorID(), bindless_resources_used_,
edram_rov_used_, provider->GetGraphicsAnalysis() != nullptr);
// If needed and possible, create objects needed for DXIL conversion and
// disassembly on this thread.
IDxbcConverter* dxbc_converter = nullptr;
IDxcUtils* dxc_utils = nullptr;
IDxcCompiler* dxc_compiler = nullptr;
if (cvars::d3d12_dxbc_disasm_dxilconv && dxbc_converter_ && dxc_utils_ &&
dxc_compiler_) {
provider->DxbcConverterCreateInstance(CLSID_DxbcConverter,
IID_PPV_ARGS(&dxbc_converter));
provider->DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(&dxc_utils));
provider->DxcCreateInstance(CLSID_DxcCompiler,
IID_PPV_ARGS(&dxc_compiler));
}
for (;;) {
std::pair<ShaderStoredHeader, D3D12Shader*> shader_to_translate;
for (;;) {
@ -292,7 +343,8 @@ void PipelineCache::InitializeShaderStorage(
assert_not_null(shader_to_translate.second);
if (!TranslateShader(
translator, shader_to_translate.second,
shader_to_translate.first.sq_program_cntl,
shader_to_translate.first.sq_program_cntl, dxbc_converter,
dxc_utils, dxc_compiler,
shader_to_translate.first.host_vertex_shader_type)) {
std::lock_guard<std::mutex> lock(shaders_failed_to_translate_mutex);
shaders_failed_to_translate.push_back(shader_to_translate.second);
@ -302,6 +354,15 @@ void PipelineCache::InitializeShaderStorage(
--shader_translation_threads_busy;
}
}
if (dxc_compiler) {
dxc_compiler->Release();
}
if (dxc_utils) {
dxc_utils->Release();
}
if (dxbc_converter) {
dxbc_converter->Release();
}
};
std::vector<std::unique_ptr<xe::threading::Thread>>
shader_translation_threads;
@ -825,6 +886,7 @@ bool PipelineCache::EnsureShadersTranslated(
if (!vertex_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, vertex_shader, sq_program_cntl,
dxbc_converter_, dxc_utils_, dxc_compiler_,
host_vertex_shader_type)) {
XELOGE("Failed to translate the vertex shader!");
return false;
@ -842,7 +904,8 @@ bool PipelineCache::EnsureShadersTranslated(
}
if (pixel_shader != nullptr && !pixel_shader->is_translated()) {
if (!TranslateShader(*shader_translator_, pixel_shader, sq_program_cntl)) {
if (!TranslateShader(*shader_translator_, pixel_shader, sq_program_cntl,
dxbc_converter_, dxc_utils_, dxc_compiler_)) {
XELOGE("Failed to translate the pixel shader!");
return false;
}
@ -953,7 +1016,8 @@ bool PipelineCache::ConfigurePipeline(
bool PipelineCache::TranslateShader(
DxbcShaderTranslator& translator, D3D12Shader* shader,
reg::SQ_PROGRAM_CNTL cntl,
reg::SQ_PROGRAM_CNTL cntl, IDxbcConverter* dxbc_converter,
IDxcUtils* dxc_utils, IDxcCompiler* dxc_compiler,
Shader::HostVertexShaderType host_vertex_shader_type) {
// Perform translation.
// If this fails the shader will be marked as invalid and ignored later.
@ -1134,12 +1198,12 @@ bool PipelineCache::TranslateShader(
}
// Disassemble the shader for dumping.
if (cvars::d3d12_dxbc_disasm) {
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
if (!shader->DisassembleDxbc(provider)) {
XELOGE("Failed to disassemble DXBC shader {:016X}",
shader->ucode_data_hash());
}
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
if (cvars::d3d12_dxbc_disasm_dxilconv) {
shader->DisassembleDxbc(*provider, cvars::d3d12_dxbc_disasm, dxbc_converter,
dxc_utils, dxc_compiler);
} else {
shader->DisassembleDxbc(*provider, cvars::d3d12_dxbc_disasm);
}
// Dump shader files if desired.

View File

@ -224,6 +224,9 @@ class PipelineCache {
// Can be called from multiple threads.
bool TranslateShader(DxbcShaderTranslator& translator, D3D12Shader* shader,
reg::SQ_PROGRAM_CNTL cntl,
IDxbcConverter* dxbc_converter = nullptr,
IDxcUtils* dxc_utils = nullptr,
IDxcCompiler* dxc_compiler = nullptr,
Shader::HostVertexShaderType host_vertex_shader_type =
Shader::HostVertexShaderType::kVertex);
@ -245,6 +248,13 @@ class PipelineCache {
// Reusable shader translator.
std::unique_ptr<DxbcShaderTranslator> shader_translator_ = nullptr;
// Command processor thread DXIL conversion/disassembly interfaces, if DXIL
// disassembly is enabled.
IDxbcConverter* dxbc_converter_ = nullptr;
IDxcUtils* dxc_utils_ = nullptr;
IDxcCompiler* dxc_compiler_ = nullptr;
// All loaded shaders mapped by their guest hash key.
std::unordered_map<uint64_t, D3D12Shader*, xe::hash::IdentityHasher<uint64_t>>
shader_map_;

View File

@ -1133,7 +1133,7 @@ bool RenderTargetCache::Resolve(const Memory& memory,
copy_dest_resident = texture_cache.EnsureScaledResolveBufferResident(
resolve_info.copy_dest_base, resolve_info.copy_dest_length);
} else {
copy_dest_resident = shared_memory.EnsureTilesResident(
copy_dest_resident = shared_memory.RequestRange(
resolve_info.copy_dest_base, resolve_info.copy_dest_length);
}
if (copy_dest_resident) {
@ -1225,6 +1225,8 @@ bool RenderTargetCache::Resolve(const Memory& memory,
written_length_out = resolve_info.copy_dest_length;
copied = true;
}
} else {
XELOGE("Failed to obtain the resolve destination memory region");
}
}
} else {

View File

@ -85,10 +85,6 @@ class SharedMemory {
// Unregisters previously registered watched memory range.
void UnwatchMemoryRange(WatchHandle handle);
// Ensures the buffer tiles backing the range are resident, but doesn't upload
// anything.
bool EnsureTilesResident(uint32_t start, uint32_t length);
// Checks if the range has been updated, uploads new data if needed and
// ensures the buffer tiles backing the range are resident. May transition the
// tiled buffer to copy destination - call this before UseForReading or
@ -106,7 +102,10 @@ class SharedMemory {
// Marks the range as containing GPU-generated data (such as resolves),
// triggering modification callbacks, making it valid (so pages are not
// copied from the main memory until they're modified by the CPU) and
// protecting it.
// protecting it. Before writing anything from the GPU side, RequestRange must
// be called, to make sure, if the GPU writes don't overwrite *everything* in
// the pages they touch, the CPU data is properly loaded to the unmodified
// regions in those pages.
void RangeWrittenByGPU(uint32_t start, uint32_t length);
// Makes the buffer usable for vertices, indices and texture untiling.
@ -185,6 +184,10 @@ class SharedMemory {
// Total buffer page count.
uint32_t page_count_;
// Ensures the buffer tiles backing the range are resident, but doesn't upload
// anything.
bool EnsureTilesResident(uint32_t start, uint32_t length);
// Non-shader-visible buffer descriptor heap for faster binding (via copying
// rather than creation).
enum class BufferDescriptorIndex : uint32_t {

View File

@ -1878,7 +1878,7 @@ void TextureCache::LogTextureAction(const Texture* texture,
const char* action) {
XELOGGPU(
"{} {} {}{}x{}x{} {} {} texture with {} {}packed mip level{}, "
"base at 0x{:08X} (size {}), mips at 0x{:08X} (size {})",
"base at 0x{:08X} (size 0x{:08X}), mips at 0x{:08X} (size 0x{:08X})",
action, texture->key.tiled ? "tiled" : "linear",
texture->key.scaled_resolve ? "2x-scaled " : "", texture->key.width,
texture->key.height, texture->key.depth,

View File

@ -48,7 +48,7 @@ int32_t FloatToD3D11Fixed16p8(float f32) {
}
// n <= -2^(i-1) -> -2^(i-1) . 0
if (f32 <= -32768.0f) {
return -32768 << 8;
return -32768 * 256;
}
uint32_t f32_bits = *reinterpret_cast<const uint32_t*>(&f32);
// Copy float32 mantissa bits [22:0] into corresponding bits [22:0] of a
@ -380,8 +380,7 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
dest_width, dest_height, dest_depth);
}
copy_dest_length = texture_util::GetGuestMipSliceStorageSize(
dest_width, dest_height, dest_depth, false, dest_format, nullptr,
false);
dest_width, dest_height, dest_depth, true, dest_format, nullptr, false);
} else {
XELOGE("Tried to resolve to format {}, which is not a ColorFormat",
dest_format_info.name);

View File

@ -868,17 +868,6 @@ void DxbcShaderTranslator::StartPixelShader() {
}
void DxbcShaderTranslator::StartTranslation() {
// Allocate labels and registers for subroutines.
label_rov_depth_stencil_sample_ = UINT32_MAX;
uint32_t label_index = 0;
system_temps_subroutine_count_ = 0;
if (IsDxbcPixelShader() && edram_rov_used_) {
label_rov_depth_stencil_sample_ = label_index++;
system_temps_subroutine_count_ =
std::max((uint32_t)2, system_temps_subroutine_count_);
}
system_temps_subroutine_ = PushSystemTemp(0, system_temps_subroutine_count_);
// Allocate global system temporary registers that may also be used in the
// epilogue.
if (IsDxbcVertexOrDomainShader()) {
@ -1198,14 +1187,6 @@ void DxbcShaderTranslator::CompleteShaderCode() {
// Return from `main`.
DxbcOpRet();
// Write subroutines - can only do this immediately after `ret`. They still
// need the global system temps, and can't allocate their own temps (since
// they may be called from anywhere and don't know anything about the caller's
// register allocation).
if (label_rov_depth_stencil_sample_ != UINT32_MAX) {
CompleteShaderCode_ROV_DepthStencilSampleSubroutine();
}
if (IsDxbcVertexOrDomainShader()) {
// Release system_temp_position_ and
// system_temp_point_size_edge_flag_kill_vertex_.
@ -1226,9 +1207,6 @@ void DxbcShaderTranslator::CompleteShaderCode() {
PopSystemTemp();
}
}
// Release system_temps_subroutine_.
PopSystemTemp(system_temps_subroutine_count_);
}
std::vector<uint8_t> DxbcShaderTranslator::CompleteTranslation() {

View File

@ -2265,21 +2265,6 @@ class DxbcShaderTranslator : public ShaderTranslator {
void CompletePixelShader_WriteToROV();
void CompletePixelShader();
// Writes a function that does early (or both early and late, when not
// separating) depth/stencil testing for one sample (ROV only).
// Input:
// - system_temps_subroutine_[0].x - depth converted to 24 bits in bits 0:23.
// - system_temp_rov_params_.y - depth sample EDRAM address.
// Output:
// - system_temps_subroutine_[0].x - resulting packed depth/stencil.
// - system_temps_subroutine_[0].y - test result, bit 0 if test FAILED (so
// coverage can be updated with XOR), and if depth/stencil is early, also
// bit 4 if the pixel shader still needs to be done to check for
// kills/alphatest/AtoC before writing the new stencil.
// Local temps:
// - system_temps_subroutine_[0].zw.
// - system_temps_subroutine_[1].xy.
void CompleteShaderCode_ROV_DepthStencilSampleSubroutine();
void CompleteShaderCode();
// Writes the original instruction disassembly in the output DXBC if enabled,
@ -2505,22 +2490,12 @@ class DxbcShaderTranslator : public ShaderTranslator {
// Whether the faceness has been used in the pixel shader.
bool in_front_face_used_;
// Subroutine labels. D3D10_SB_OPCODE_LABEL is not counted as an instruction
// in STAT.
uint32_t label_rov_depth_stencil_sample_;
// Number of currently allocated Xenia internal r# registers.
uint32_t system_temp_count_current_;
// Total maximum number of temporary registers ever used during this
// translation (for the declaration).
uint32_t system_temp_count_max_;
// Registers for the needed count of non-main-subroutine-local variables.
// This includes arguments.
uint32_t system_temps_subroutine_;
// Number of registers allocated for subroutines other than main.
uint32_t system_temps_subroutine_count_;
// Position in vertex shaders (because viewport and W transformations can be
// applied in the end of the shader).
uint32_t system_temp_position_;

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -112,8 +112,7 @@ X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) {
ObjectTableEntry& entry = table_[slot];
entry.object = object;
entry.handle_ref_count = 1;
handle = slot << 2;
handle = XObject::kHandleBase + (slot << 2);
object->handles().push_back(handle);
// Retain so long as the object is in the table.
@ -251,7 +250,7 @@ ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
auto global_lock = global_critical_region_.Acquire();
// Lower 2 bits are ignored.
uint32_t slot = handle >> 2;
uint32_t slot = GetHandleSlot(handle);
if (slot <= table_capacity_) {
return &table_[slot];
}
@ -279,7 +278,7 @@ XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) {
}
// Lower 2 bits are ignored.
uint32_t slot = handle >> 2;
uint32_t slot = GetHandleSlot(handle);
// Verify slot.
if (slot < table_capacity_) {
@ -390,7 +389,7 @@ bool ObjectTable::Restore(ByteStream* stream) {
}
X_STATUS ObjectTable::RestoreHandle(X_HANDLE handle, XObject* object) {
uint32_t slot = handle >> 2;
uint32_t slot = GetHandleSlot(handle);
assert_true(table_capacity_ >= slot);
if (table_capacity_ >= slot) {

View File

@ -92,6 +92,9 @@ class ObjectTable {
std::vector<object_ref<XObject>>* results);
X_HANDLE TranslateHandle(X_HANDLE handle);
static constexpr uint32_t GetHandleSlot(X_HANDLE handle) {
return (handle - XObject::kHandleBase) >> 2;
}
X_STATUS FindFreeSlot(uint32_t* out_slot);
bool Resize(uint32_t new_capacity);

View File

@ -493,6 +493,8 @@ DECLARE_XAM_EXPORT1(XamContentDelete, kContent, kImplemented);
dword_result_t XamContentDeleteInternal(lpvoid_t content_data_ptr,
lpunknown_t overlapped_ptr) {
// INFO: Analysis of xam.xex shows that "internal" functions are wrappers with
// 0xFE as user_index
return XamContentDelete(0xFE, content_data_ptr, overlapped_ptr);
}
DECLARE_XAM_EXPORT1(XamContentDeleteInternal, kContent, kImplemented);

View File

@ -9,6 +9,7 @@
#include <cstring>
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/kernel/kernel_state.h"
@ -291,12 +292,18 @@ dword_result_t NtQueryVirtualMemory(
memory_basic_information_ptr->allocation_protect =
ToXdkProtectFlags(alloc_info.allocation_protect);
memory_basic_information_ptr->region_size = alloc_info.region_size;
uint32_t x_state = 0;
if (alloc_info.state & kMemoryAllocationReserve) {
x_state |= X_MEM_RESERVE;
}
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information
// State: ... This member can be one of the following values: MEM_COMMIT,
// MEM_FREE, MEM_RESERVE.
// State queried by Beautiful Katamari before displaying the loading screen.
uint32_t x_state;
if (alloc_info.state & kMemoryAllocationCommit) {
x_state |= X_MEM_COMMIT;
assert_not_zero(alloc_info.state & kMemoryAllocationReserve);
x_state = X_MEM_COMMIT;
} else if (alloc_info.state & kMemoryAllocationReserve) {
x_state = X_MEM_RESERVE;
} else {
x_state = X_MEM_FREE;
}
memory_basic_information_ptr->state = x_state;
memory_basic_information_ptr->protect = ToXdkProtectFlags(alloc_info.protect);

View File

@ -109,6 +109,13 @@ struct X_OBJECT_TYPE {
class XObject {
public:
// Burnout Paradise needs proper handle value for certain calculations
// It gets handle value from TLS (without base handle value is 0x88)
// and substract 0xF8000088. Without base we're receiving wrong address
// Instead of receiving address that starts with 0x82... we're receiving
// one with 0x8A... which causes crash
static constexpr uint32_t kHandleBase = 0xF8000000;
enum Type {
kTypeUndefined,
kTypeEnumerator,

View File

@ -20,6 +20,9 @@
#include <dxgi1_4.h>
#include <dxgidebug.h>
#include "third_party/DirectXShaderCompiler/include/dxc/dxcapi.h"
#include "third_party/DirectXShaderCompiler/projects/dxilconv/include/DxbcConverter.h"
#define XELOGD3D XELOGI
#endif // XENIA_UI_D3D12_D3D12_API_H_

View File

@ -78,6 +78,12 @@ D3D12Provider::~D3D12Provider() {
dxgi_factory_->Release();
}
if (library_dxcompiler_ != nullptr) {
FreeLibrary(library_dxcompiler_);
}
if (library_dxilconv_ != nullptr) {
FreeLibrary(library_dxilconv_);
}
if (library_d3dcompiler_ != nullptr) {
FreeLibrary(library_d3dcompiler_);
}
@ -109,13 +115,11 @@ bool D3D12Provider::EnableIncreaseBasePriorityPrivilege() {
}
bool D3D12Provider::Initialize() {
// Load the libraries.
// Load the core libraries.
library_dxgi_ = LoadLibraryW(L"dxgi.dll");
library_d3d12_ = LoadLibraryW(L"D3D12.dll");
library_d3dcompiler_ = LoadLibraryW(L"D3DCompiler_47.dll");
if (library_dxgi_ == nullptr || library_d3d12_ == nullptr ||
library_d3dcompiler_ == nullptr) {
XELOGE("Failed to load dxgi.dll, D3D12.dll or D3DCompiler_47.dll.");
if (library_dxgi_ == nullptr || library_d3d12_ == nullptr) {
XELOGE("Failed to load dxgi.dll or D3D12.dll");
return false;
}
bool libraries_loaded = true;
@ -136,12 +140,65 @@ bool D3D12Provider::Initialize() {
(pfn_d3d12_serialize_root_signature_ = PFN_D3D12_SERIALIZE_ROOT_SIGNATURE(
GetProcAddress(library_d3d12_, "D3D12SerializeRootSignature"))) !=
nullptr;
libraries_loaded &= (pfn_d3d_disassemble_ = pD3DDisassemble(GetProcAddress(
library_d3dcompiler_, "D3DDisassemble"))) != nullptr;
if (!libraries_loaded) {
XELOGE("Failed to get DXGI or Direct3D 12 functions");
return false;
}
// Load optional D3DCompiler_47.dll.
pfn_d3d_disassemble_ = nullptr;
library_d3dcompiler_ = LoadLibraryW(L"D3DCompiler_47.dll");
if (library_d3dcompiler_) {
pfn_d3d_disassemble_ =
pD3DDisassemble(GetProcAddress(library_d3dcompiler_, "D3DDisassemble"));
if (pfn_d3d_disassemble_ == nullptr) {
XELOGW(
"Failed to get D3DDisassemble from D3DCompiler_47.dll, DXBC "
"disassembly for debugging will be unavailable");
}
} else {
XELOGW(
"Failed to load D3DCompiler_47.dll, DXBC disassembly for debugging "
"will be unavailable");
}
// Load optional dxilconv.dll.
pfn_dxilconv_dxc_create_instance_ = nullptr;
library_dxilconv_ = LoadLibraryW(L"dxilconv.dll");
if (library_dxilconv_) {
pfn_dxilconv_dxc_create_instance_ = DxcCreateInstanceProc(
GetProcAddress(library_dxilconv_, "DxcCreateInstance"));
if (pfn_dxilconv_dxc_create_instance_ == nullptr) {
XELOGW(
"Failed to get DxcCreateInstance from dxilconv.dll, converted DXIL "
"disassembly for debugging will be unavailable");
}
} else {
XELOGW(
"Failed to load dxilconv.dll, converted DXIL disassembly for debugging "
"will be unavailable - DXIL may be unsupported by your OS version");
}
// Load optional dxcompiler.dll.
pfn_dxcompiler_dxc_create_instance_ = nullptr;
library_dxcompiler_ = LoadLibraryW(L"dxcompiler.dll");
if (library_dxcompiler_) {
pfn_dxcompiler_dxc_create_instance_ = DxcCreateInstanceProc(
GetProcAddress(library_dxcompiler_, "DxcCreateInstance"));
if (pfn_dxcompiler_dxc_create_instance_ == nullptr) {
XELOGW(
"Failed to get DxcCreateInstance from dxcompiler.dll, converted DXIL "
"disassembly for debugging will be unavailable");
}
} else {
XELOGW(
"Failed to load dxcompiler.dll, converted DXIL disassembly for "
"debugging will be unavailable - if needed, download the DirectX "
"Shader Compiler from "
"https://github.com/microsoft/DirectXShaderCompiler/releases and place "
"the DLL in the Xenia directory");
}
// Configure the DXGI debug info queue.
if (cvars::d3d12_break_on_error) {
IDXGIInfoQueue* dxgi_info_queue;
@ -205,13 +262,13 @@ bool D3D12Provider::Initialize() {
++adapter_index;
}
if (adapter == nullptr) {
XELOGE("Failed to get an adapter supporting Direct3D feature level 11_0.");
XELOGE("Failed to get an adapter supporting Direct3D feature level 11_0");
dxgi_factory->Release();
return false;
}
DXGI_ADAPTER_DESC adapter_desc;
if (FAILED(adapter->GetDesc(&adapter_desc))) {
XELOGE("Failed to get the DXGI adapter description.");
XELOGE("Failed to get the DXGI adapter description");
adapter->Release();
dxgi_factory->Release();
return false;
@ -234,7 +291,7 @@ bool D3D12Provider::Initialize() {
ID3D12Device* device;
if (FAILED(pfn_d3d12_create_device_(adapter, D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&device)))) {
XELOGE("Failed to create a Direct3D 12 feature level 11_0 device.");
XELOGE("Failed to create a Direct3D 12 feature level 11_0 device");
adapter->Release();
dxgi_factory->Release();
return false;

View File

@ -96,9 +96,27 @@ class D3D12Provider : public GraphicsProvider {
inline HRESULT Disassemble(const void* src_data, size_t src_data_size,
UINT flags, const char* comments,
ID3DBlob** disassembly_out) const {
if (!pfn_d3d_disassemble_) {
return E_NOINTERFACE;
}
return pfn_d3d_disassemble_(src_data, src_data_size, flags, comments,
disassembly_out);
}
inline HRESULT DxbcConverterCreateInstance(const CLSID& rclsid,
const IID& riid,
void** ppv) const {
if (!pfn_dxilconv_dxc_create_instance_) {
return E_NOINTERFACE;
}
return pfn_dxilconv_dxc_create_instance_(rclsid, riid, ppv);
}
inline HRESULT DxcCreateInstance(const CLSID& rclsid, const IID& riid,
void** ppv) const {
if (!pfn_dxcompiler_dxc_create_instance_) {
return E_NOINTERFACE;
}
return pfn_dxcompiler_dxc_create_instance_(rclsid, riid, ppv);
}
private:
explicit D3D12Provider(Window* main_window);
@ -106,21 +124,28 @@ class D3D12Provider : public GraphicsProvider {
static bool EnableIncreaseBasePriorityPrivilege();
bool Initialize();
HMODULE library_dxgi_ = nullptr;
HMODULE library_d3d12_ = nullptr;
HMODULE library_d3dcompiler_ = nullptr;
typedef HRESULT(WINAPI* PFNCreateDXGIFactory2)(UINT Flags, REFIID riid,
_COM_Outptr_ void** ppFactory);
typedef HRESULT(WINAPI* PFNDXGIGetDebugInterface1)(
UINT Flags, REFIID riid, _COM_Outptr_ void** pDebug);
HMODULE library_dxgi_ = nullptr;
PFNCreateDXGIFactory2 pfn_create_dxgi_factory2_;
PFNDXGIGetDebugInterface1 pfn_dxgi_get_debug_interface1_;
HMODULE library_d3d12_ = nullptr;
PFN_D3D12_GET_DEBUG_INTERFACE pfn_d3d12_get_debug_interface_;
PFN_D3D12_CREATE_DEVICE pfn_d3d12_create_device_;
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfn_d3d12_serialize_root_signature_;
pD3DDisassemble pfn_d3d_disassemble_;
HMODULE library_d3dcompiler_ = nullptr;
pD3DDisassemble pfn_d3d_disassemble_ = nullptr;
HMODULE library_dxilconv_ = nullptr;
DxcCreateInstanceProc pfn_dxilconv_dxc_create_instance_ = nullptr;
HMODULE library_dxcompiler_ = nullptr;
DxcCreateInstanceProc pfn_dxcompiler_dxc_create_instance_ = nullptr;
IDXGIFactory2* dxgi_factory_ = nullptr;
IDXGraphicsAnalysis* graphics_analysis_ = nullptr;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,118 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_CONTEXT_H_
#define XENIA_UI_VK_VULKAN_CONTEXT_H_
#include <memory>
#include <vector>
#include "xenia/ui/graphics_context.h"
#include "xenia/ui/vk/vulkan_immediate_drawer.h"
#include "xenia/ui/vk/vulkan_provider.h"
#define FINE_GRAINED_DRAW_SCOPES 1
namespace xe {
namespace ui {
namespace vk {
class VulkanContext : public GraphicsContext {
public:
~VulkanContext() override;
ImmediateDrawer* immediate_drawer() override;
bool is_current() override;
bool MakeCurrent() override;
void ClearCurrent() override;
bool WasLost() override { return context_lost_; }
void BeginSwap() override;
void EndSwap() override;
std::unique_ptr<RawImage> Capture() override;
VulkanProvider* GetVulkanProvider() const {
return static_cast<VulkanProvider*>(provider_);
}
// The count of copies of transient objects (like command buffers, dynamic
// descriptor pools) that must be kept when rendering with this context.
static constexpr uint32_t kQueuedFrames = 3;
// The current absolute frame number.
uint64_t GetCurrentFrame() { return current_frame_; }
// The last completed frame - it's fine to destroy objects used in it.
uint64_t GetLastCompletedFrame() { return last_completed_frame_; }
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
void AwaitAllFramesCompletion();
const VkSurfaceFormatKHR& GetSurfaceFormat() const { return surface_format_; }
VkRenderPass GetPresentRenderPass() const { return present_render_pass_; }
VkCommandBuffer GetPresentCommandBuffer() const {
return present_command_buffers_[current_queue_frame_];
}
private:
friend class VulkanProvider;
explicit VulkanContext(VulkanProvider* provider, Window* target_window);
private:
bool Initialize();
void Shutdown();
void DestroySwapchainImages();
bool initialized_fully_ = false;
bool context_lost_ = false;
uint64_t current_frame_ = 1;
uint64_t last_completed_frame_ = 0;
uint32_t current_queue_frame_ = 1;
VkFence fences_[kQueuedFrames] = {};
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
uint32_t surface_min_image_count_ = 3;
VkSurfaceFormatKHR surface_format_ = {VK_FORMAT_R8G8B8A8_UNORM,
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
VkSurfaceTransformFlagBitsKHR surface_transform_ =
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
VkCompositeAlphaFlagBitsKHR surface_composite_alpha_ =
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkPresentModeKHR surface_present_mode_ = VK_PRESENT_MODE_FIFO_KHR;
VkSemaphore semaphore_present_complete_ = VK_NULL_HANDLE;
VkSemaphore semaphore_draw_complete_ = VK_NULL_HANDLE;
VkRenderPass present_render_pass_ = VK_NULL_HANDLE;
VkCommandPool present_command_pool_ = VK_NULL_HANDLE;
VkCommandBuffer present_command_buffers_[kQueuedFrames] = {};
std::unique_ptr<VulkanImmediateDrawer> immediate_drawer_ = nullptr;
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
VkExtent2D swapchain_extent_ = {};
struct SwapchainImage {
VkImage image;
VkImageView image_view;
VkFramebuffer framebuffer;
};
std::vector<SwapchainImage> swapchain_images_;
uint32_t swapchain_acquired_image_index_ = 0;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_CONTEXT_H_

View File

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

View File

@ -1,74 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_
#define XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_
#include <memory>
#include "xenia/ui/immediate_drawer.h"
#include "xenia/ui/vk/transient_objects.h"
namespace xe {
namespace ui {
namespace vk {
class VulkanContext;
class VulkanImmediateDrawer : public ImmediateDrawer {
public:
VulkanImmediateDrawer(VulkanContext* graphics_context);
~VulkanImmediateDrawer() override;
bool Initialize();
void Shutdown();
std::unique_ptr<ImmediateTexture> CreateTexture(uint32_t width,
uint32_t height,
ImmediateTextureFilter filter,
bool repeat,
const uint8_t* data) override;
void UpdateTexture(ImmediateTexture* texture, const uint8_t* data) override;
void Begin(int render_target_width, int render_target_height) override;
void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
void Draw(const ImmediateDraw& draw) override;
void EndDrawBatch() override;
void End() override;
private:
VulkanContext* context_ = nullptr;
struct PushConstants {
struct {
float viewport_inv_size[2];
} vertex;
struct {
uint32_t restrict_texture_samples;
} fragment;
};
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
VkPipeline pipeline_triangle_ = VK_NULL_HANDLE;
VkPipeline pipeline_line_ = VK_NULL_HANDLE;
std::unique_ptr<UploadBufferChain> vertex_buffer_chain_ = nullptr;
VkCommandBuffer current_command_buffer_ = VK_NULL_HANDLE;
VkExtent2D current_render_target_extent_;
bool batch_open_ = false;
bool batch_has_index_buffer_;
VkPipeline current_pipeline_ = VK_NULL_HANDLE;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_IMMEDIATE_DRAWER_H_

View File

@ -1,306 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/vk/vulkan_provider.h"
#include <cstring>
#include <vector>
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/platform.h"
#include "xenia/ui/vk/vulkan_context.h"
#include "xenia/ui/vk/vulkan_util.h"
DEFINE_bool(vk_validation, false, "Enable Vulkan validation layers.", "Vulkan");
DEFINE_int32(vk_device, -1,
"Index of the Vulkan physical device to use. -1 to use any "
"compatible.",
"Vulkan");
namespace xe {
namespace ui {
namespace vk {
std::unique_ptr<VulkanProvider> VulkanProvider::Create(Window* main_window) {
std::unique_ptr<VulkanProvider> provider(new VulkanProvider(main_window));
if (!provider->Initialize()) {
xe::FatalError(
"Unable to initialize Vulkan 1.1 graphics subsystem.\n"
"\n"
"Ensure you have the latest drivers for your GPU and that it supports "
"Vulkan, and install the latest Vulkan runtime from "
"https://vulkan.lunarg.com/sdk/home.\n"
"\n"
"See https://xenia.jp/faq/ for more information and a list of "
"supported GPUs.");
return nullptr;
}
return provider;
}
VulkanProvider::VulkanProvider(Window* main_window)
: GraphicsProvider(main_window) {}
VulkanProvider::~VulkanProvider() {
if (device_ != VK_NULL_HANDLE) {
vkDestroyDevice(device_, nullptr);
}
if (instance_ != VK_NULL_HANDLE) {
vkDestroyInstance(instance_, nullptr);
}
}
uint32_t VulkanProvider::FindMemoryType(
uint32_t memory_type_bits_requirement,
VkMemoryPropertyFlags required_properties) const {
uint32_t memory_index;
while (xe::bit_scan_forward(memory_type_bits_requirement, &memory_index)) {
memory_type_bits_requirement &= ~(uint32_t(1) << memory_index);
VkMemoryPropertyFlags properties =
physical_device_memory_properties_.memoryTypes[memory_index]
.propertyFlags;
if ((properties & required_properties) == required_properties) {
return memory_index;
}
}
return UINT32_MAX;
}
bool VulkanProvider::Initialize() {
if (volkInitialize() != VK_SUCCESS) {
XELOGE("Failed to initialize the Vulkan loader volk");
return false;
}
const uint32_t api_version = VK_MAKE_VERSION(1, 1, 0);
// Create the instance.
VkApplicationInfo application_info;
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.pNext = nullptr;
application_info.pApplicationName = "Xenia";
application_info.applicationVersion = 1;
application_info.pEngineName = "Xenia";
application_info.engineVersion = 1;
application_info.apiVersion = api_version;
const char* const validation_layers[] = {
"VK_LAYER_LUNARG_standard_validation",
};
const char* const instance_extensions[] = {
"VK_KHR_surface",
#if XE_PLATFORM_WIN32
"VK_KHR_win32_surface",
#endif
};
VkInstanceCreateInfo instance_create_info;
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pNext = nullptr;
instance_create_info.flags = 0;
instance_create_info.pApplicationInfo = &application_info;
if (cvars::vk_validation) {
instance_create_info.enabledLayerCount =
uint32_t(xe::countof(validation_layers));
instance_create_info.ppEnabledLayerNames = validation_layers;
} else {
instance_create_info.enabledLayerCount = 0;
instance_create_info.ppEnabledLayerNames = nullptr;
}
instance_create_info.enabledExtensionCount =
uint32_t(xe::countof(instance_extensions));
instance_create_info.ppEnabledExtensionNames = instance_extensions;
if (vkCreateInstance(&instance_create_info, nullptr, &instance_) !=
VK_SUCCESS) {
XELOGE("Failed to create a Vulkan instance");
return false;
}
volkLoadInstance(instance_);
// Get a supported physical device.
physical_device_ = nullptr;
uint32_t physical_device_count;
if (vkEnumeratePhysicalDevices(instance_, &physical_device_count, nullptr) !=
VK_SUCCESS) {
XELOGE("Failed to get Vulkan physical device count");
return false;
}
std::vector<VkPhysicalDevice> physical_devices;
physical_devices.resize(physical_device_count);
if (vkEnumeratePhysicalDevices(instance_, &physical_device_count,
physical_devices.data()) != VK_SUCCESS) {
XELOGE("Failed to get Vulkan physical devices");
return false;
}
uint32_t physical_device_index, physical_device_index_end;
if (cvars::vk_device >= 0) {
physical_device_index = uint32_t(cvars::vk_device);
physical_device_index_end =
std::min(physical_device_index + 1, physical_device_count);
} else {
physical_device_index = 0;
physical_device_index_end = physical_device_count;
}
std::vector<VkExtensionProperties> physical_device_extensions;
std::vector<VkQueueFamilyProperties> queue_families;
bool sparse_residency_buffer = false;
for (; physical_device_index < physical_device_index_end;
++physical_device_index) {
VkPhysicalDevice physical_device = physical_devices[physical_device_index];
vkGetPhysicalDeviceProperties(physical_device,
&physical_device_properties_);
if (physical_device_properties_.apiVersion < api_version) {
continue;
}
vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features_);
if (!physical_device_features_.geometryShader) {
continue;
}
uint32_t physical_device_extension_count;
if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
&physical_device_extension_count,
nullptr) != VK_SUCCESS) {
continue;
}
physical_device_extensions.resize(physical_device_extension_count);
if (vkEnumerateDeviceExtensionProperties(
physical_device, nullptr, &physical_device_extension_count,
physical_device_extensions.data()) != VK_SUCCESS) {
continue;
}
bool supports_swapchain = false;
for (uint32_t i = 0; i < physical_device_extension_count; ++i) {
const char* extension_name = physical_device_extensions[i].extensionName;
if (!std::strcmp(extension_name, "VK_KHR_swapchain")) {
supports_swapchain = true;
break;
}
}
if (!supports_swapchain) {
continue;
}
sparse_residency_buffer = physical_device_features_.sparseBinding &&
physical_device_features_.sparseResidencyBuffer;
// Get a queue supporting graphics and compute, and if available, also
// sparse memory management.
graphics_queue_family_ = UINT32_MAX;
uint32_t queue_family_count;
vkGetPhysicalDeviceQueueFamilyProperties(physical_device,
&queue_family_count, nullptr);
queue_families.resize(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(
physical_device, &queue_family_count, queue_families.data());
const uint32_t queue_flags_required =
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
for (uint32_t i = 0; i < queue_family_count; ++i) {
const VkQueueFamilyProperties& queue_family_properties =
queue_families[i];
// Arbitrary copying done when loading textures.
if (queue_family_properties.minImageTransferGranularity.width > 1 ||
queue_family_properties.minImageTransferGranularity.height > 1 ||
queue_family_properties.minImageTransferGranularity.depth > 1) {
continue;
}
if ((queue_family_properties.queueFlags & queue_flags_required) !=
queue_flags_required) {
continue;
}
graphics_queue_family_ = i;
if (!sparse_residency_buffer ||
(queue_family_properties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)) {
// Found a fully compatible queue family, stop searching for a family
// that support both graphics/compute/transfer and sparse binding.
break;
}
}
if (graphics_queue_family_ == UINT32_MAX) {
continue;
}
if (!(queue_families[graphics_queue_family_].queueFlags &
VK_QUEUE_SPARSE_BINDING_BIT)) {
sparse_residency_buffer = false;
}
physical_device_ = physical_device;
break;
}
if (physical_device_ == VK_NULL_HANDLE) {
XELOGE("Failed to get a supported Vulkan physical device");
return false;
}
// TODO(Triang3l): Check if VK_EXT_fragment_shader_interlock and
// fragmentShaderSampleInterlock are supported.
// Get the needed info about the physical device.
vkGetPhysicalDeviceMemoryProperties(physical_device_,
&physical_device_memory_properties_);
// Log physical device properties.
XELOGVK("Vulkan physical device: {} (vendor {:04X}, device {:04X})",
physical_device_properties_.deviceName,
physical_device_properties_.vendorID,
physical_device_properties_.deviceID);
// Create a logical device and a queue.
float queue_priority = 1.0f;
VkDeviceQueueCreateInfo queue_create_info;
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info.pNext = nullptr;
queue_create_info.flags = 0;
queue_create_info.queueFamilyIndex = graphics_queue_family_;
queue_create_info.queueCount = 1;
queue_create_info.pQueuePriorities = &queue_priority;
const char* const device_extensions[] = {
"VK_KHR_swapchain",
};
// TODO(Triang3l): Add VK_EXT_fragment_shader_interlock if supported.
VkDeviceCreateInfo device_create_info;
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pNext = nullptr;
device_create_info.flags = 0;
device_create_info.queueCreateInfoCount = 1;
device_create_info.pQueueCreateInfos = &queue_create_info;
device_create_info.enabledLayerCount = 0;
device_create_info.ppEnabledLayerNames = nullptr;
device_create_info.enabledExtensionCount =
uint32_t(xe::countof(device_extensions));
device_create_info.ppEnabledExtensionNames = device_extensions;
device_create_info.pEnabledFeatures = nullptr;
if (vkCreateDevice(physical_device_, &device_create_info, nullptr,
&device_) != VK_SUCCESS) {
XELOGE("Failed to create a Vulkan device");
return false;
}
volkLoadDevice(device_);
vkGetDeviceQueue(device_, graphics_queue_family_, 0, &graphics_queue_);
return true;
}
std::unique_ptr<GraphicsContext> VulkanProvider::CreateContext(
Window* target_window) {
auto new_context =
std::unique_ptr<VulkanContext>(new VulkanContext(this, target_window));
if (!new_context->Initialize()) {
return nullptr;
}
return std::unique_ptr<GraphicsContext>(new_context.release());
}
std::unique_ptr<GraphicsContext> VulkanProvider::CreateOffscreenContext() {
auto new_context =
std::unique_ptr<VulkanContext>(new VulkanContext(this, nullptr));
if (!new_context->Initialize()) {
return nullptr;
}
return std::unique_ptr<GraphicsContext>(new_context.release());
}
} // namespace vk
} // namespace ui
} // namespace xe

View File

@ -1,87 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_PROVIDER_H_
#define XENIA_UI_VK_VULKAN_PROVIDER_H_
#include <cstdint>
#include <memory>
#include "xenia/base/platform.h"
#include "xenia/ui/graphics_provider.h"
#if XE_PLATFORM_WIN32
#ifndef VK_USE_PLATFORM_WIN32_KHR
#define VK_USE_PLATFORM_WIN32_KHR 1
#endif
#elif XE_PLATFORM_LINUX
#include "xenia/ui/window_gtk.h"
#if defined(GDK_WINDOWING_X11) && !defined(VK_USE_PLATFORM_XCB_KHR)
#define VK_USE_PLATFORM_XCB_KHR 1
#endif
#endif
#include "third_party/volk/volk.h"
#define XELOGVK XELOGI
namespace xe {
namespace ui {
namespace vk {
class VulkanImmediateDrawer;
class VulkanProvider : public GraphicsProvider {
public:
~VulkanProvider() override;
static std::unique_ptr<VulkanProvider> Create(Window* main_window);
std::unique_ptr<GraphicsContext> CreateContext(
Window* target_window) override;
std::unique_ptr<GraphicsContext> CreateOffscreenContext() override;
VkInstance GetInstance() const { return instance_; }
VkPhysicalDevice GetPhysicalDevice() const { return physical_device_; }
const VkPhysicalDeviceProperties& GetPhysicalDeviceProperties() const {
return physical_device_properties_;
}
const VkPhysicalDeviceFeatures& GetPhysicalDeviceFeatures() const {
return physical_device_features_;
}
const VkPhysicalDeviceMemoryProperties& GetPhysicalDeviceMemoryProperties()
const {
return physical_device_memory_properties_;
}
VkDevice GetDevice() const { return device_; }
uint32_t GetGraphicsQueueFamily() const { return graphics_queue_family_; }
VkQueue GetGraphicsQueue() const { return graphics_queue_; }
uint32_t FindMemoryType(uint32_t memory_type_bits_requirement,
VkMemoryPropertyFlags required_properties) const;
private:
explicit VulkanProvider(Window* main_window);
bool Initialize();
VkInstance instance_ = VK_NULL_HANDLE;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
VkPhysicalDeviceProperties physical_device_properties_;
VkPhysicalDeviceFeatures physical_device_features_;
VkPhysicalDeviceMemoryProperties physical_device_memory_properties_;
VkDevice device_ = VK_NULL_HANDLE;
uint32_t graphics_queue_family_ = UINT32_MAX;
VkQueue graphics_queue_ = VK_NULL_HANDLE;
};
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_PROVIDER_H_

View File

@ -1,45 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2019 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VK_VULKAN_UTIL_H_
#define XENIA_UI_VK_VULKAN_UTIL_H_
#include "xenia/ui/vk/vulkan_provider.h"
namespace xe {
namespace ui {
namespace vk {
namespace util {
template <typename F, typename T>
inline bool DestroyAndNullHandle(F* destroy_function, T& handle) {
if (handle != VK_NULL_HANDLE) {
destroy_function(handle, nullptr);
handle = VK_NULL_HANDLE;
return true;
}
return false;
}
template <typename F, typename P, typename T>
inline bool DestroyAndNullHandle(F* destroy_function, P parent, T& handle) {
if (handle != VK_NULL_HANDLE) {
destroy_function(parent, handle, nullptr);
handle = VK_NULL_HANDLE;
return true;
}
return false;
}
} // namespace util
} // namespace vk
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VK_VULKAN_UTIL_H_

View File

@ -119,31 +119,35 @@ typedef uint32_t X_HRESULT;
#define X_E_NO_SUCH_USER X_HRESULT_FROM_WIN32(X_ERROR_NO_SUCH_USER)
// MEM_*, used by NtAllocateVirtualMemory
#define X_MEM_COMMIT 0x00001000
#define X_MEM_RESERVE 0x00002000
#define X_MEM_DECOMMIT 0x00004000
#define X_MEM_RELEASE 0x00008000
#define X_MEM_FREE 0x00010000
#define X_MEM_PRIVATE 0x00020000
#define X_MEM_RESET 0x00080000
#define X_MEM_TOP_DOWN 0x00100000
#define X_MEM_NOZERO 0x00800000
#define X_MEM_LARGE_PAGES 0x20000000
#define X_MEM_HEAP 0x40000000
#define X_MEM_16MB_PAGES 0x80000000 // from Valve SDK
enum X_MEM : uint32_t {
X_MEM_COMMIT = 0x00001000,
X_MEM_RESERVE = 0x00002000,
X_MEM_DECOMMIT = 0x00004000,
X_MEM_RELEASE = 0x00008000,
X_MEM_FREE = 0x00010000,
X_MEM_PRIVATE = 0x00020000,
X_MEM_RESET = 0x00080000,
X_MEM_TOP_DOWN = 0x00100000,
X_MEM_NOZERO = 0x00800000,
X_MEM_LARGE_PAGES = 0x20000000,
X_MEM_HEAP = 0x40000000,
X_MEM_16MB_PAGES = 0x80000000 // from Valve SDK
};
// PAGE_*, used by NtAllocateVirtualMemory
#define X_PAGE_NOACCESS 0x00000001
#define X_PAGE_READONLY 0x00000002
#define X_PAGE_READWRITE 0x00000004
#define X_PAGE_WRITECOPY 0x00000008
#define X_PAGE_EXECUTE 0x00000010
#define X_PAGE_EXECUTE_READ 0x00000020
#define X_PAGE_EXECUTE_READWRITE 0x00000040
#define X_PAGE_EXECUTE_WRITECOPY 0x00000080
#define X_PAGE_GUARD 0x00000100
#define X_PAGE_NOCACHE 0x00000200
#define X_PAGE_WRITECOMBINE 0x00000400
enum X_PAGE : uint32_t {
X_PAGE_NOACCESS = 0x00000001,
X_PAGE_READONLY = 0x00000002,
X_PAGE_READWRITE = 0x00000004,
X_PAGE_WRITECOPY = 0x00000008,
X_PAGE_EXECUTE = 0x00000010,
X_PAGE_EXECUTE_READ = 0x00000020,
X_PAGE_EXECUTE_READWRITE = 0x00000040,
X_PAGE_EXECUTE_WRITECOPY = 0x00000080,
X_PAGE_GUARD = 0x00000100,
X_PAGE_NOCACHE = 0x00000200,
X_PAGE_WRITECOMBINE = 0x00000400
};
// Sockets/networking.
#define X_INVALID_SOCKET (uint32_t)(~0)

1
third_party/DirectXShaderCompiler vendored Submodule

@ -0,0 +1 @@
Subproject commit 6b6f40200bea5ed99367513f53f6a28e52fd3d0e