Refactor graphics #1

This commit is contained in:
nmzik committed 2026-07-19 00:54:31 +02:00
1 parent 7905f2d12f
commit cbc11d2eaf
71 files changed
+2051 -3399

No files matched your search

-8
View File
@@ -85,14 +85,6 @@ bool SpirvDebugPrintfEnabled() {
return g_config->spirv_debug_printf_enabled; return g_config->spirv_debug_printf_enabled;
} }
bool PipelineDumpEnabled() {
return g_config->pipeline_dump_enabled;
}
std::filesystem::path GetPipelineDumpFolder() {
return g_config->pipeline_dump_folder;
}
bool RenderDocEnabled() { bool RenderDocEnabled() {
return g_config->renderdoc_enabled; return g_config->renderdoc_enabled;
} }
-5
View File
@@ -34,8 +34,6 @@ struct ConfigOptions {
std::filesystem::path printf_output_file = "_kyty.txt"; std::filesystem::path printf_output_file = "_kyty.txt";
ProfilerDirection profiler_direction = ProfilerDirection::None; ProfilerDirection profiler_direction = ProfilerDirection::None;
bool spirv_debug_printf_enabled = false; bool spirv_debug_printf_enabled = false;
bool pipeline_dump_enabled = false;
std::filesystem::path pipeline_dump_folder = "_Pipelines";
bool renderdoc_enabled = false; bool renderdoc_enabled = false;
bool ngg_rectlist_draw_enabled = true; bool ngg_rectlist_draw_enabled = true;
}; };
@@ -64,9 +62,6 @@ ProfilerDirection GetProfilerDirection();
bool SpirvDebugPrintfEnabled(); bool SpirvDebugPrintfEnabled();
bool PipelineDumpEnabled();
std::filesystem::path GetPipelineDumpFolder();
bool RenderDocEnabled(); bool RenderDocEnabled();
bool NggRectlistDrawEnabled(); bool NggRectlistDrawEnabled();
@@ -2,19 +2,14 @@
namespace Libs::Graphics { namespace Libs::Graphics {
hw_ctx_parser_func_t g_hw_ctx_func[Pm4::CX_NUM] = {};
hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM] = {}; hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM] = {};
hw_sh_parser_func_t g_hw_sh_func[Pm4::SH_NUM] = {};
hw_sh_indirect_func_t g_hw_sh_indirect_func[Pm4::SH_NUM] = {}; hw_sh_indirect_func_t g_hw_sh_indirect_func[Pm4::SH_NUM] = {};
hw_uc_parser_func_t g_hw_uc_func[Pm4::UC_NUM] = {};
hw_uc_indirect_func_t g_hw_uc_indirect_func[Pm4::UC_NUM] = {}; hw_uc_indirect_func_t g_hw_uc_indirect_func[Pm4::UC_NUM] = {};
cp_op_parser_func_t g_cp_op_func[256] = {};
cp_op_parser_func_t g_cp_op_custom_func[Pm4::R_NUM] = {};
void GraphicsInitJmpTables() { namespace {
for (auto& func: g_hw_ctx_func) {
func = nullptr; constexpr auto MakeContextDispatchTable() {
} std::array<hw_ctx_parser_func_t, Pm4::CX_NUM> g_hw_ctx_func {};
g_hw_ctx_func[Pm4::DB_RENDER_CONTROL] = HwCtxSetRenderControl; g_hw_ctx_func[Pm4::DB_RENDER_CONTROL] = HwCtxSetRenderControl;
g_hw_ctx_func[Pm4::DB_COUNT_CONTROL] = HwCtxSetDepthMetadataRegisters; g_hw_ctx_func[Pm4::DB_COUNT_CONTROL] = HwCtxSetDepthMetadataRegisters;
@@ -107,9 +102,11 @@ void GraphicsInitJmpTables() {
} }
} }
for (auto& func: g_hw_sh_func) { return g_hw_ctx_func;
func = nullptr; }
}
constexpr auto MakeShaderDispatchTable() {
std::array<hw_sh_parser_func_t, Pm4::SH_NUM> g_hw_sh_func {};
for (uint32_t slot = 0; slot < 32; slot++) { for (uint32_t slot = 0; slot < 32; slot++) {
g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_PS_0 + slot * 1] = HwShSetPsUserSgpr; g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_PS_0 + slot * 1] = HwShSetPsUserSgpr;
@@ -174,9 +171,11 @@ void GraphicsInitJmpTables() {
g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_HI_HS] = HwShIgnoreRegisters; g_hw_sh_func[Pm4::SPI_SHADER_USER_DATA_ADDR_HI_HS] = HwShIgnoreRegisters;
g_hw_sh_func[Pm4::SPI_SHADER_REQ_CTRL_LSHS] = HwShIgnoreRegisters; g_hw_sh_func[Pm4::SPI_SHADER_REQ_CTRL_LSHS] = HwShIgnoreRegisters;
for (auto& func: g_hw_uc_func) { return g_hw_sh_func;
func = nullptr; }
}
constexpr auto MakeUconfigDispatchTable() {
std::array<hw_uc_parser_func_t, Pm4::UC_NUM> g_hw_uc_func {};
g_hw_uc_func[Pm4::VGT_PRIMITIVE_TYPE] = HwUcSetPrimitiveType; g_hw_uc_func[Pm4::VGT_PRIMITIVE_TYPE] = HwUcSetPrimitiveType;
g_hw_uc_func[Pm4::VGT_INDEX_TYPE] = HwUcSetIndexType; g_hw_uc_func[Pm4::VGT_INDEX_TYPE] = HwUcSetIndexType;
@@ -191,9 +190,11 @@ void GraphicsInitJmpTables() {
g_hw_uc_func[Pm4::GDS_OA_COUNTER] = HwUcSetGdsOaRegisters; g_hw_uc_func[Pm4::GDS_OA_COUNTER] = HwUcSetGdsOaRegisters;
g_hw_uc_func[Pm4::GDS_OA_ADDRESS] = HwUcSetGdsOaRegisters; g_hw_uc_func[Pm4::GDS_OA_ADDRESS] = HwUcSetGdsOaRegisters;
for (auto& func: g_cp_op_func) { return g_hw_uc_func;
func = nullptr; }
}
constexpr auto MakeOpcodeDispatchTable() {
std::array<cp_op_parser_func_t, 256> g_cp_op_func {};
g_cp_op_func[Pm4::IT_NOP] = CpOpNop; g_cp_op_func[Pm4::IT_NOP] = CpOpNop;
g_cp_op_func[Pm4::IT_SET_BASE] = CpOpSetBase; g_cp_op_func[Pm4::IT_SET_BASE] = CpOpSetBase;
@@ -238,9 +239,11 @@ void GraphicsInitJmpTables() {
g_cp_op_func[Pm4::IT_WAIT_ON_DE_COUNTER_DIFF] = CpOpWaitOnDeCounterDiff; g_cp_op_func[Pm4::IT_WAIT_ON_DE_COUNTER_DIFF] = CpOpWaitOnDeCounterDiff;
g_cp_op_func[Pm4::IT_GET_LOD_STATS] = CpOpGetLodStats; g_cp_op_func[Pm4::IT_GET_LOD_STATS] = CpOpGetLodStats;
for (auto& func: g_cp_op_custom_func) { return g_cp_op_func;
func = nullptr; }
}
constexpr auto MakeCustomOpcodeDispatchTable() {
std::array<cp_op_parser_func_t, Pm4::R_NUM> g_cp_op_custom_func {};
g_cp_op_custom_func[Pm4::R_DISPATCH_RESET] = CpOpDispatchReset; g_cp_op_custom_func[Pm4::R_DISPATCH_RESET] = CpOpDispatchReset;
g_cp_op_custom_func[Pm4::R_WAIT_MEM_32] = CpOpWaitRegMem32; g_cp_op_custom_func[Pm4::R_WAIT_MEM_32] = CpOpWaitRegMem32;
@@ -252,6 +255,22 @@ void GraphicsInitJmpTables() {
g_cp_op_custom_func[Pm4::R_FLIP] = CpOpFlip; g_cp_op_custom_func[Pm4::R_FLIP] = CpOpFlip;
g_cp_op_custom_func[Pm4::R_RELEASE_MEM] = CpOpReleaseMem; g_cp_op_custom_func[Pm4::R_RELEASE_MEM] = CpOpReleaseMem;
return g_cp_op_custom_func;
}
} // namespace
constinit const std::array<hw_ctx_parser_func_t, Pm4::CX_NUM> g_hw_ctx_func =
MakeContextDispatchTable();
constinit const std::array<hw_sh_parser_func_t, Pm4::SH_NUM> g_hw_sh_func =
MakeShaderDispatchTable();
constinit const std::array<hw_uc_parser_func_t, Pm4::UC_NUM> g_hw_uc_func =
MakeUconfigDispatchTable();
constinit const std::array<cp_op_parser_func_t, 256> g_cp_op_func = MakeOpcodeDispatchTable();
constinit const std::array<cp_op_parser_func_t, Pm4::R_NUM> g_cp_op_custom_func =
MakeCustomOpcodeDispatchTable();
void GraphicsInitJmpTables() {
GraphicsInitJmpTablesCxIndirect(); GraphicsInitJmpTablesCxIndirect();
GraphicsInitJmpTablesShIndirect(); GraphicsInitJmpTablesShIndirect();
GraphicsInitJmpTablesUcIndirect(); GraphicsInitJmpTablesUcIndirect();
@@ -3,6 +3,7 @@
#include "graphics/guest_gpu/pm4.h" #include "graphics/guest_gpu/pm4.h"
#include <array>
#include <cstdint> #include <cstdint>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -21,14 +22,14 @@ using hw_ctx_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
using hw_uc_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); using hw_uc_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
using hw_sh_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); using hw_sh_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t);
extern hw_ctx_parser_func_t g_hw_ctx_func[Pm4::CX_NUM]; extern const std::array<hw_ctx_parser_func_t, Pm4::CX_NUM> g_hw_ctx_func;
extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM]; extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM];
extern hw_sh_parser_func_t g_hw_sh_func[Pm4::SH_NUM]; extern const std::array<hw_sh_parser_func_t, Pm4::SH_NUM> g_hw_sh_func;
extern hw_sh_indirect_func_t g_hw_sh_indirect_func[Pm4::SH_NUM]; extern hw_sh_indirect_func_t g_hw_sh_indirect_func[Pm4::SH_NUM];
extern hw_uc_parser_func_t g_hw_uc_func[Pm4::UC_NUM]; extern const std::array<hw_uc_parser_func_t, Pm4::UC_NUM> g_hw_uc_func;
extern hw_uc_indirect_func_t g_hw_uc_indirect_func[Pm4::UC_NUM]; extern hw_uc_indirect_func_t g_hw_uc_indirect_func[Pm4::UC_NUM];
extern cp_op_parser_func_t g_cp_op_func[256]; extern const std::array<cp_op_parser_func_t, 256> g_cp_op_func;
extern cp_op_parser_func_t g_cp_op_custom_func[Pm4::R_NUM]; extern const std::array<cp_op_parser_func_t, Pm4::R_NUM> g_cp_op_custom_func;
void GraphicsInitJmpTables(); void GraphicsInitJmpTables();
void GraphicsInitJmpTablesCxIndirect(); void GraphicsInitJmpTablesCxIndirect();
+70 -85
View File
@@ -7,82 +7,76 @@
namespace Libs::Graphics::Prospero { namespace Libs::Graphics::Prospero {
namespace { namespace {
struct FormatInfo {
uint32_t format;
uint32_t bytes_per_element;
uint32_t block_compressed_bytes_per_block;
uint32_t render_target_bytes_per_element;
bool supported_sampled_texture_format;
bool unsigned_integer_texture_format;
};
constexpr FormatInfo kFormatInfo[] = { constexpr FormatInfo kFormatInfo[] = {
{GpuEnumValue(BufferFormat::k8UNorm), vk::Format::eR8Unorm, 1, 0, 1, true, false}, {GpuEnumValue(BufferFormat::k8UNorm), 1, 0, 1, true, false},
{GpuEnumValue(BufferFormat::k8SNorm), vk::Format::eUndefined, 0, 0, 1, false, false}, {GpuEnumValue(BufferFormat::k8SNorm), 0, 0, 1, false, false},
{GpuEnumValue(BufferFormat::k8UInt), vk::Format::eR8Uint, 1, 0, 1, true, true}, {GpuEnumValue(BufferFormat::k8UInt), 1, 0, 1, true, true},
{GpuEnumValue(BufferFormat::k16UNorm), vk::Format::eR16Unorm, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::k16UNorm), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k16SNorm), vk::Format::eR16Snorm, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::k16SNorm), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k16UInt), vk::Format::eR16Uint, 2, 0, 2, true, true}, {GpuEnumValue(BufferFormat::k16UInt), 2, 0, 2, true, true},
{GpuEnumValue(BufferFormat::k16SInt), vk::Format::eR16Sint, 2, 0, 2, false, false}, {GpuEnumValue(BufferFormat::k16SInt), 2, 0, 2, false, false},
{GpuEnumValue(BufferFormat::k16Float), vk::Format::eR16Sfloat, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::k16Float), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k8_8UNorm), vk::Format::eR8G8Unorm, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::k8_8UNorm), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k8_8SNorm), vk::Format::eR8G8Snorm, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::k8_8SNorm), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k8_8UInt), vk::Format::eR8G8Uint, 2, 0, 2, true, true}, {GpuEnumValue(BufferFormat::k8_8UInt), 2, 0, 2, true, true},
{GpuEnumValue(BufferFormat::k8_8SInt), vk::Format::eR8G8Sint, 2, 0, 2, false, false}, {GpuEnumValue(BufferFormat::k8_8SInt), 2, 0, 2, false, false},
{GpuEnumValue(BufferFormat::k32UInt), vk::Format::eR32Uint, 4, 0, 4, true, true}, {GpuEnumValue(BufferFormat::k32UInt), 4, 0, 4, true, true},
{GpuEnumValue(BufferFormat::k32SInt), vk::Format::eR32Sint, 4, 0, 4, false, false}, {GpuEnumValue(BufferFormat::k32SInt), 4, 0, 4, false, false},
{GpuEnumValue(BufferFormat::k32Float), vk::Format::eR32Sfloat, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k32Float), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k16_16UNorm), vk::Format::eR16G16Unorm, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k16_16UNorm), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k16_16SNorm), vk::Format::eR16G16Snorm, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k16_16SNorm), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k16_16UInt), vk::Format::eR16G16Uint, 4, 0, 4, true, true}, {GpuEnumValue(BufferFormat::k16_16UInt), 4, 0, 4, true, true},
{GpuEnumValue(BufferFormat::k16_16SInt), vk::Format::eR16G16Sint, 4, 0, 4, false, false}, {GpuEnumValue(BufferFormat::k16_16SInt), 4, 0, 4, false, false},
{GpuEnumValue(BufferFormat::k16_16Float), vk::Format::eR16G16Sfloat, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k16_16Float), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k11_11_10Float), vk::Format::eB10G11R11UfloatPack32, 4, 0, 4, true, {GpuEnumValue(BufferFormat::k11_11_10Float), 4, 0, 4, true, false},
false}, {GpuEnumValue(BufferFormat::k10_10_10_2UNorm), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k10_10_10_2UNorm), vk::Format::eA2B10G10R10UnormPack32, 4, 0, 4, {GpuEnumValue(BufferFormat::k8_8_8_8UNorm), 4, 0, 4, true, false},
true, false}, {GpuEnumValue(BufferFormat::k8_8_8_8SNorm), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k8_8_8_8UNorm), vk::Format::eR8G8B8A8Unorm, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k8_8_8_8UInt), 4, 0, 4, true, true},
{GpuEnumValue(BufferFormat::k8_8_8_8SNorm), vk::Format::eR8G8B8A8Snorm, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::k8_8_8_8SInt), 4, 0, 4, false, false},
{GpuEnumValue(BufferFormat::k8_8_8_8UInt), vk::Format::eR8G8B8A8Uint, 4, 0, 4, true, true}, {GpuEnumValue(BufferFormat::k32_32UInt), 8, 0, 8, true, true},
{GpuEnumValue(BufferFormat::k8_8_8_8SInt), vk::Format::eR8G8B8A8Sint, 4, 0, 4, false, false}, {GpuEnumValue(BufferFormat::k32_32SInt), 8, 0, 8, false, false},
{GpuEnumValue(BufferFormat::k32_32UInt), vk::Format::eR32G32Uint, 8, 0, 8, true, true}, {GpuEnumValue(BufferFormat::k32_32Float), 8, 0, 8, true, false},
{GpuEnumValue(BufferFormat::k32_32SInt), vk::Format::eR32G32Sint, 8, 0, 8, false, false}, {GpuEnumValue(BufferFormat::k16_16_16_16UNorm), 8, 0, 8, true, false},
{GpuEnumValue(BufferFormat::k32_32Float), vk::Format::eR32G32Sfloat, 8, 0, 8, true, false}, {GpuEnumValue(BufferFormat::k16_16_16_16SNorm), 8, 0, 8, true, false},
{GpuEnumValue(BufferFormat::k16_16_16_16UNorm), vk::Format::eR16G16B16A16Unorm, 8, 0, 8, true, {GpuEnumValue(BufferFormat::k16_16_16_16UInt), 8, 0, 8, true, true},
false}, {GpuEnumValue(BufferFormat::k16_16_16_16SInt), 8, 0, 8, false, false},
{GpuEnumValue(BufferFormat::k16_16_16_16SNorm), vk::Format::eR16G16B16A16Snorm, 8, 0, 8, true, {GpuEnumValue(BufferFormat::k16_16_16_16Float), 8, 0, 8, true, false},
false}, {GpuEnumValue(BufferFormat::k32_32_32UInt), 12, 0, 12, true, true},
{GpuEnumValue(BufferFormat::k16_16_16_16UInt), vk::Format::eR16G16B16A16Uint, 8, 0, 8, true, {GpuEnumValue(BufferFormat::k32_32_32SInt), 12, 0, 12, false, false},
true}, {GpuEnumValue(BufferFormat::k32_32_32Float), 12, 0, 12, true, false},
{GpuEnumValue(BufferFormat::k16_16_16_16SInt), vk::Format::eR16G16B16A16Sint, 8, 0, 8, false, {GpuEnumValue(BufferFormat::k32_32_32_32UInt), 16, 0, 16, true, true},
false}, {GpuEnumValue(BufferFormat::k32_32_32_32SInt), 16, 0, 16, false, false},
{GpuEnumValue(BufferFormat::k16_16_16_16Float), vk::Format::eR16G16B16A16Sfloat, 8, 0, 8, true, {GpuEnumValue(BufferFormat::k32_32_32_32Float), 16, 0, 16, true, false},
false}, {GpuEnumValue(BufferFormat::k8_8_8_8Srgb), 4, 0, 4, true, false},
{GpuEnumValue(BufferFormat::k32_32_32UInt), vk::Format::eR32G32B32Uint, 12, 0, 12, true, true}, {GpuEnumValue(BufferFormat::k9_9_9_5Float), 4, 0, 0, true, false},
{GpuEnumValue(BufferFormat::k32_32_32SInt), vk::Format::eR32G32B32Sint, 12, 0, 12, false, {GpuEnumValue(BufferFormat::k5_6_5UNorm), 2, 0, 2, true, false},
false}, {GpuEnumValue(BufferFormat::k5_5_5_1UNorm), 2, 0, 2, true, false},
{GpuEnumValue(BufferFormat::k32_32_32Float), vk::Format::eR32G32B32Sfloat, 12, 0, 12, true, {GpuEnumValue(BufferFormat::k4_4_4_4UNorm), 2, 0, 2, true, false},
false}, {GpuEnumValue(BufferFormat::kFmask8_S4_F4), 1, 0, 1, true, false},
{GpuEnumValue(BufferFormat::k32_32_32_32UInt), vk::Format::eR32G32B32A32Uint, 16, 0, 16, true, {GpuEnumValue(BufferFormat::kBc1UNorm), 0, 8, 0, true, false},
true}, {GpuEnumValue(BufferFormat::kBc1Srgb), 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::k32_32_32_32SInt), vk::Format::eR32G32B32A32Sint, 16, 0, 16, false, {GpuEnumValue(BufferFormat::kBc2UNorm), 0, 16, 0, true, false},
false}, {GpuEnumValue(BufferFormat::kBc2Srgb), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::k32_32_32_32Float), vk::Format::eR32G32B32A32Sfloat, 16, 0, 16, {GpuEnumValue(BufferFormat::kBc3UNorm), 0, 16, 0, true, false},
true, false}, {GpuEnumValue(BufferFormat::kBc3Srgb), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::k8_8_8_8Srgb), vk::Format::eR8G8B8A8Srgb, 4, 0, 4, true, false}, {GpuEnumValue(BufferFormat::kBc4UNorm), 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::k9_9_9_5Float), vk::Format::eE5B9G9R9UfloatPack32, 4, 0, 0, true, {GpuEnumValue(BufferFormat::kBc4SNorm), 0, 8, 0, true, false},
false}, {GpuEnumValue(BufferFormat::kBc5UNorm), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::k5_6_5UNorm), vk::Format::eB5G6R5UnormPack16, 2, 0, 2, true, false}, {GpuEnumValue(BufferFormat::kBc5SNorm), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::k5_5_5_1UNorm), vk::Format::eR5G5B5A1UnormPack16, 2, 0, 2, true, {GpuEnumValue(BufferFormat::kBc6UFloat), 0, 16, 0, true, false},
false}, {GpuEnumValue(BufferFormat::kBc6SFloat), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::k4_4_4_4UNorm), vk::Format::eR4G4B4A4UnormPack16, 2, 0, 2, true, {GpuEnumValue(BufferFormat::kBc7UNorm), 0, 16, 0, true, false},
false}, {GpuEnumValue(BufferFormat::kBc7Srgb), 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kFmask8_S4_F4), vk::Format::eR32Sfloat, 1, 0, 1, true, false},
{GpuEnumValue(BufferFormat::kBc1UNorm), vk::Format::eBc1RgbaUnormBlock, 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::kBc1Srgb), vk::Format::eBc1RgbaSrgbBlock, 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::kBc2UNorm), vk::Format::eBc2UnormBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc2Srgb), vk::Format::eBc2SrgbBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc3UNorm), vk::Format::eBc3UnormBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc3Srgb), vk::Format::eBc3SrgbBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc4UNorm), vk::Format::eBc4UnormBlock, 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::kBc4SNorm), vk::Format::eBc4SnormBlock, 0, 8, 0, true, false},
{GpuEnumValue(BufferFormat::kBc5UNorm), vk::Format::eBc5UnormBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc5SNorm), vk::Format::eBc5SnormBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc6UFloat), vk::Format::eBc6HUfloatBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc6SFloat), vk::Format::eBc6HSfloatBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc7UNorm), vk::Format::eBc7UnormBlock, 0, 16, 0, true, false},
{GpuEnumValue(BufferFormat::kBc7Srgb), vk::Format::eBc7SrgbBlock, 0, 16, 0, true, false},
}; };
constexpr auto MakeFormatInfoLookup() { constexpr auto MakeFormatInfoLookup() {
@@ -96,20 +90,11 @@ constexpr auto MakeFormatInfoLookup() {
constexpr auto kFormatInfoLookup = MakeFormatInfoLookup(); constexpr auto kFormatInfoLookup = MakeFormatInfoLookup();
} // namespace
std::span<const FormatInfo> Formats() {
return kFormatInfo;
}
const FormatInfo* FindFormatInfo(uint32_t format) { const FormatInfo* FindFormatInfo(uint32_t format) {
return format < kFormatInfoLookup.size() ? kFormatInfoLookup[format] : nullptr; return format < kFormatInfoLookup.size() ? kFormatInfoLookup[format] : nullptr;
} }
vk::Format SurfaceFormat(uint32_t format) { } // namespace
const auto* info = FindFormatInfo(format);
return info != nullptr ? info->vk_format : vk::Format::eUndefined;
}
uint32_t NumBytesPerElement(uint32_t format) { uint32_t NumBytesPerElement(uint32_t format) {
const auto* info = FindFormatInfo(format); const auto* info = FindFormatInfo(format);
+6 -22
View File
@@ -2,31 +2,15 @@
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GUEST_GPU_GPU_FORMAT_H_ #define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GUEST_GPU_GPU_FORMAT_H_
#include "common/common.h" #include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <span>
namespace Libs::Graphics::Prospero { namespace Libs::Graphics::Prospero {
struct FormatInfo { uint32_t NumBytesPerElement(uint32_t format);
uint32_t format = 0; uint32_t BlockCompressedBytesPerBlock(uint32_t format);
vk::Format vk_format = vk::Format::eUndefined; uint32_t RenderTargetBytesPerElement(uint32_t format);
uint32_t bytes_per_element = 0; bool IsSupportedTextureFormat(uint32_t format);
uint32_t block_compressed_bytes_per_block = 0; bool IsUintTextureFormat(uint32_t format);
uint32_t render_target_bytes_per_element = 0; bool IsFmaskTextureFormat(uint32_t format);
bool supported_sampled_texture_format = false;
bool unsigned_integer_texture_format = false;
};
std::span<const FormatInfo> Formats();
const FormatInfo* FindFormatInfo(uint32_t format);
vk::Format SurfaceFormat(uint32_t format);
uint32_t NumBytesPerElement(uint32_t format);
uint32_t BlockCompressedBytesPerBlock(uint32_t format);
uint32_t RenderTargetBytesPerElement(uint32_t format);
bool IsSupportedTextureFormat(uint32_t format);
bool IsUintTextureFormat(uint32_t format);
bool IsFmaskTextureFormat(uint32_t format);
} // namespace Libs::Graphics::Prospero } // namespace Libs::Graphics::Prospero
+6 -10
View File
@@ -626,8 +626,8 @@ struct GeUserVgprEn {
class Context { class Context {
public: public:
Context() = default; Context() = default;
virtual ~Context() = default; ~Context() = default;
KYTY_CLASS_DEFAULT_COPY(Context); KYTY_CLASS_DEFAULT_COPY(Context);
@@ -723,10 +723,6 @@ public:
return m_depth_render_target.size; return m_depth_render_target.size;
} }
void SetViewportZ(uint32_t viewport_id, float zmin, float zmax) {
m_screen_viewport.viewports[viewport_id].zmin = zmin;
m_screen_viewport.viewports[viewport_id].zmax = zmax;
}
void SetViewportZMin(uint32_t viewport_id, float zmin) { void SetViewportZMin(uint32_t viewport_id, float zmin) {
m_screen_viewport.viewports[viewport_id].zmin = zmin; m_screen_viewport.viewports[viewport_id].zmin = zmin;
} }
@@ -942,8 +938,8 @@ private:
class UserConfig { class UserConfig {
public: public:
UserConfig() = default; UserConfig() = default;
virtual ~UserConfig() = default; ~UserConfig() = default;
KYTY_CLASS_DEFAULT_COPY(UserConfig); KYTY_CLASS_DEFAULT_COPY(UserConfig);
@@ -980,8 +976,8 @@ private:
class Shader { class Shader {
public: public:
Shader() = default; Shader() = default;
virtual ~Shader() = default; ~Shader() = default;
KYTY_CLASS_DEFAULT_COPY(Shader); KYTY_CLASS_DEFAULT_COPY(Shader);
+124 -107
View File
@@ -3,97 +3,104 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/file.h" #include "common/file.h"
#include <array>
namespace Libs::Graphics::Pm4 { namespace Libs::Graphics::Pm4 {
static const char* g_names[256] = {}; namespace {
static const char* g_r_names[Pm4::R_NUM] = {};
static bool g_names_initialized = false;
static void InitNames() { enum class PacketType : uint32_t { Type0, Type1, Type2, Type3 };
if (!g_names_initialized) {
for (auto& n: g_names) {
n = "<unknown>";
}
for (auto& n: g_r_names) { constexpr auto MakeRegisterNames() {
n = "<unknown>"; std::array<const char*, R_NUM> names {};
} for (auto& name: names) {
name = "<unknown>";
g_r_names[R_ZERO] = "R_ZERO";
g_r_names[R_DRAW_RESET] = "R_DRAW_RESET";
g_r_names[R_WAIT_FLIP_DONE] = "R_WAIT_FLIP_DONE";
g_r_names[R_DISPATCH_RESET] = "R_DISPATCH_RESET";
g_r_names[R_WAIT_MEM_32] = "R_WAIT_MEM_32";
g_r_names[R_PUSH_MARKER] = "R_PUSH_MARKER";
g_r_names[R_POP_MARKER] = "R_POP_MARKER";
g_r_names[R_ACQUIRE_MEM] = "R_ACQUIRE_MEM";
g_r_names[R_WRITE_DATA] = "R_WRITE_DATA";
g_r_names[R_WAIT_MEM_64] = "R_WAIT_MEM_64";
g_r_names[R_FLIP] = "R_FLIP";
g_r_names[R_RELEASE_MEM] = "R_RELEASE_MEM";
g_r_names[R_DMA_DATA] = "R_DMA_DATA";
g_names[IT_NOP] = "IT_NOP";
g_names[IT_SET_BASE] = "IT_SET_BASE";
g_names[IT_CLEAR_STATE] = "IT_CLEAR_STATE";
g_names[IT_INDEX_BUFFER_SIZE] = "IT_INDEX_BUFFER_SIZE";
g_names[IT_DISPATCH_DIRECT] = "IT_DISPATCH_DIRECT";
g_names[IT_DISPATCH_INDIRECT] = "IT_DISPATCH_INDIRECT";
g_names[IT_SET_PREDICATION] = "IT_SET_PREDICATION";
g_names[IT_COND_EXEC] = "IT_COND_EXEC";
g_names[IT_DRAW_INDIRECT] = "IT_DRAW_INDIRECT";
g_names[IT_DRAW_INDEX_INDIRECT] = "IT_DRAW_INDEX_INDIRECT";
g_names[IT_INDEX_BASE] = "IT_INDEX_BASE";
g_names[IT_DRAW_INDEX_2] = "IT_DRAW_INDEX_2";
g_names[IT_CONTEXT_CONTROL] = "IT_CONTEXT_CONTROL";
g_names[IT_INDEX_TYPE] = "IT_INDEX_TYPE";
g_names[IT_DRAW_INDIRECT_MULTI] = "IT_DRAW_INDIRECT_MULTI";
g_names[IT_DRAW_INDEX_AUTO] = "IT_DRAW_INDEX_AUTO";
g_names[IT_NUM_INSTANCES] = "IT_NUM_INSTANCES";
g_names[IT_INDIRECT_BUFFER_CNST] = "IT_INDIRECT_BUFFER_CNST";
g_names[IT_DRAW_INDEX_OFFSET_2] = "IT_DRAW_INDEX_OFFSET_2";
g_names[IT_WRITE_DATA] = "IT_WRITE_DATA";
g_names[IT_MEM_SEMAPHORE] = "IT_MEM_SEMAPHORE";
g_names[IT_DRAW_INDEX_INDIRECT_MULTI] = "IT_DRAW_INDEX_INDIRECT_MULTI";
g_names[IT_INDIRECT_BUFFER] = "IT_INDIRECT_BUFFER";
g_names[IT_COPY_DATA] = "IT_COPY_DATA";
g_names[IT_CP_DMA] = "IT_CP_DMA";
g_names[IT_PFP_SYNC_ME] = "IT_PFP_SYNC_ME";
g_names[IT_SURFACE_SYNC] = "IT_SURFACE_SYNC";
g_names[IT_EVENT_WRITE] = "IT_EVENT_WRITE";
g_names[IT_EVENT_WRITE_EOP] = "IT_EVENT_WRITE_EOP";
g_names[IT_EVENT_WRITE_EOS] = "IT_EVENT_WRITE_EOS";
g_names[IT_RELEASE_MEM] = "IT_RELEASE_MEM";
g_names[IT_DMA_DATA] = "IT_DMA_DATA";
g_names[IT_ACQUIRE_MEM] = "IT_ACQUIRE_MEM";
g_names[IT_REWIND] = "IT_REWIND";
g_names[IT_SET_SH_REG_INDIRECT] = "IT_SET_SH_REG_INDIRECT";
g_names[IT_SET_UCONFIG_REG_INDIRECT] = "IT_SET_UCONFIG_REG_INDIRECT";
g_names[IT_SET_CONFIG_REG] = "IT_SET_CONFIG_REG";
g_names[IT_SET_CONTEXT_REG] = "IT_SET_CONTEXT_REG";
g_names[IT_SET_SH_REG] = "IT_SET_SH_REG";
g_names[IT_SET_QUEUE_REG] = "IT_SET_QUEUE_REG";
g_names[IT_SET_UCONFIG_REG] = "IT_SET_UCONFIG_REG";
g_names[IT_SET_UCONFIG_REG_INDEX] = "IT_SET_UCONFIG_REG_INDEX";
g_names[IT_WRITE_CONST_RAM] = "IT_WRITE_CONST_RAM";
g_names[IT_DUMP_CONST_RAM] = "IT_DUMP_CONST_RAM";
g_names[IT_INCREMENT_CE_COUNTER] = "IT_INCREMENT_CE_COUNTER";
g_names[IT_INCREMENT_DE_COUNTER] = "IT_INCREMENT_DE_COUNTER";
g_names[IT_WAIT_ON_CE_COUNTER] = "IT_WAIT_ON_CE_COUNTER";
g_names[IT_WAIT_ON_DE_COUNTER_DIFF] = "IT_WAIT_ON_DE_COUNTER_DIFF";
g_names[IT_DISPATCH_DRAW_PREAMBLE] = "IT_DISPATCH_DRAW_PREAMBLE";
g_names[IT_DISPATCH_DRAW] = "IT_DISPATCH_DRAW";
g_names[IT_GET_LOD_STATS] = "IT_GET_LOD_STATS";
g_names[IT_SET_CONTEXT_REG_INDIRECT] = "IT_SET_CONTEXT_REG_INDIRECT";
g_names_initialized = true;
} }
names[R_ZERO] = "R_ZERO";
names[R_DRAW_RESET] = "R_DRAW_RESET";
names[R_WAIT_FLIP_DONE] = "R_WAIT_FLIP_DONE";
names[R_DISPATCH_RESET] = "R_DISPATCH_RESET";
names[R_WAIT_MEM_32] = "R_WAIT_MEM_32";
names[R_PUSH_MARKER] = "R_PUSH_MARKER";
names[R_POP_MARKER] = "R_POP_MARKER";
names[R_ACQUIRE_MEM] = "R_ACQUIRE_MEM";
names[R_WRITE_DATA] = "R_WRITE_DATA";
names[R_WAIT_MEM_64] = "R_WAIT_MEM_64";
names[R_FLIP] = "R_FLIP";
names[R_RELEASE_MEM] = "R_RELEASE_MEM";
names[R_DMA_DATA] = "R_DMA_DATA";
return names;
} }
constexpr auto MakeOpcodeNames() {
std::array<const char*, 256> names {};
for (auto& name: names) {
name = "<unknown>";
}
names[IT_NOP] = "IT_NOP";
names[IT_SET_BASE] = "IT_SET_BASE";
names[IT_CLEAR_STATE] = "IT_CLEAR_STATE";
names[IT_INDEX_BUFFER_SIZE] = "IT_INDEX_BUFFER_SIZE";
names[IT_DISPATCH_DIRECT] = "IT_DISPATCH_DIRECT";
names[IT_DISPATCH_INDIRECT] = "IT_DISPATCH_INDIRECT";
names[IT_SET_PREDICATION] = "IT_SET_PREDICATION";
names[IT_COND_EXEC] = "IT_COND_EXEC";
names[IT_DRAW_INDIRECT] = "IT_DRAW_INDIRECT";
names[IT_DRAW_INDEX_INDIRECT] = "IT_DRAW_INDEX_INDIRECT";
names[IT_INDEX_BASE] = "IT_INDEX_BASE";
names[IT_DRAW_INDEX_2] = "IT_DRAW_INDEX_2";
names[IT_CONTEXT_CONTROL] = "IT_CONTEXT_CONTROL";
names[IT_INDEX_TYPE] = "IT_INDEX_TYPE";
names[IT_DRAW_INDIRECT_MULTI] = "IT_DRAW_INDIRECT_MULTI";
names[IT_DRAW_INDEX_AUTO] = "IT_DRAW_INDEX_AUTO";
names[IT_NUM_INSTANCES] = "IT_NUM_INSTANCES";
names[IT_INDIRECT_BUFFER_CNST] = "IT_INDIRECT_BUFFER_CNST";
names[IT_DRAW_INDEX_OFFSET_2] = "IT_DRAW_INDEX_OFFSET_2";
names[IT_WRITE_DATA] = "IT_WRITE_DATA";
names[IT_MEM_SEMAPHORE] = "IT_MEM_SEMAPHORE";
names[IT_DRAW_INDEX_INDIRECT_MULTI] = "IT_DRAW_INDEX_INDIRECT_MULTI";
names[IT_INDIRECT_BUFFER] = "IT_INDIRECT_BUFFER";
names[IT_COPY_DATA] = "IT_COPY_DATA";
names[IT_CP_DMA] = "IT_CP_DMA";
names[IT_PFP_SYNC_ME] = "IT_PFP_SYNC_ME";
names[IT_SURFACE_SYNC] = "IT_SURFACE_SYNC";
names[IT_EVENT_WRITE] = "IT_EVENT_WRITE";
names[IT_EVENT_WRITE_EOP] = "IT_EVENT_WRITE_EOP";
names[IT_EVENT_WRITE_EOS] = "IT_EVENT_WRITE_EOS";
names[IT_RELEASE_MEM] = "IT_RELEASE_MEM";
names[IT_DMA_DATA] = "IT_DMA_DATA";
names[IT_ACQUIRE_MEM] = "IT_ACQUIRE_MEM";
names[IT_REWIND] = "IT_REWIND";
names[IT_SET_SH_REG_INDIRECT] = "IT_SET_SH_REG_INDIRECT";
names[IT_SET_UCONFIG_REG_INDIRECT] = "IT_SET_UCONFIG_REG_INDIRECT";
names[IT_SET_CONFIG_REG] = "IT_SET_CONFIG_REG";
names[IT_SET_CONTEXT_REG] = "IT_SET_CONTEXT_REG";
names[IT_SET_SH_REG] = "IT_SET_SH_REG";
names[IT_SET_QUEUE_REG] = "IT_SET_QUEUE_REG";
names[IT_SET_UCONFIG_REG] = "IT_SET_UCONFIG_REG";
names[IT_SET_UCONFIG_REG_INDEX] = "IT_SET_UCONFIG_REG_INDEX";
names[IT_WRITE_CONST_RAM] = "IT_WRITE_CONST_RAM";
names[IT_DUMP_CONST_RAM] = "IT_DUMP_CONST_RAM";
names[IT_INCREMENT_CE_COUNTER] = "IT_INCREMENT_CE_COUNTER";
names[IT_INCREMENT_DE_COUNTER] = "IT_INCREMENT_DE_COUNTER";
names[IT_WAIT_ON_CE_COUNTER] = "IT_WAIT_ON_CE_COUNTER";
names[IT_WAIT_ON_DE_COUNTER_DIFF] = "IT_WAIT_ON_DE_COUNTER_DIFF";
names[IT_DISPATCH_DRAW_PREAMBLE] = "IT_DISPATCH_DRAW_PREAMBLE";
names[IT_DISPATCH_DRAW] = "IT_DISPATCH_DRAW";
names[IT_GET_LOD_STATS] = "IT_GET_LOD_STATS";
names[IT_SET_CONTEXT_REG_INDIRECT] = "IT_SET_CONTEXT_REG_INDIRECT";
return names;
}
constexpr auto g_register_names = MakeRegisterNames();
constexpr auto g_opcode_names = MakeOpcodeNames();
} // namespace
void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t start_dw, void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t start_dw,
uint32_t num_dw) { uint32_t num_dw) {
InitNames();
// db_dump(); // db_dump();
file->Printf("----- Buffer --- dwords: 0x%05" PRIx32 ", offset : %u, addr: %016" PRIx64 file->Printf("----- Buffer --- dwords: 0x%05" PRIx32 ", offset : %u, addr: %016" PRIx64
@@ -112,36 +119,46 @@ void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t star
uint32_t len = 0; uint32_t len = 0;
if ((cmd_id & 0xC0000000u) == 0xC0000000u) { const auto packet_type = static_cast<PacketType>(cmd_id >> 30u);
const bool sh_gx = (cmd_id & 0x2u) == 0; switch (packet_type) {
const uint8_t op = ((cmd_id >> 8u) & 0xffu); case PacketType::Type3: {
const auto r = KYTY_PM4_R(cmd_id); const bool sh_gx = (cmd_id & 0x2u) == 0;
len = ((cmd_id >> 16u) & 0x3fffu) + 1; const uint8_t op = ((cmd_id >> 8u) & 0xffu);
const auto r = KYTY_PM4_R(cmd_id);
len = ((cmd_id >> 16u) & 0x3fffu) + 1;
file->Printf("%s %s(OP:0x%02" PRIx8 ") SH:%s CNT:%u\n", g_names[op], EXIT_NOT_IMPLEMENTED(len >= dw);
(op == IT_NOP ? g_r_names[r] : ""), op, sh_gx ? "GX" : "CX", len);
for (uint32_t i = 0; i < len; i++) { file->Printf("%s %s(OP:0x%02" PRIx8 ") SH:%s CNT:%u\n", g_opcode_names[op],
file->Printf(" | 0x%08" PRIx32 " | \n", cmd[i]); (op == IT_NOP ? g_register_names[r] : ""), op, sh_gx ? "GX" : "CX",
} len);
if ((op == IT_SET_CONTEXT_REG_INDIRECT || op == IT_SET_SH_REG_INDIRECT || for (uint32_t i = 0; i < len; i++) {
op == IT_SET_UCONFIG_REG_INDIRECT) && file->Printf(" | 0x%08" PRIx32 " | \n", cmd[i]);
len == 4) {
auto* indirect_buffer =
reinterpret_cast<uint32_t*>((static_cast<uint64_t>(cmd[0]) & 0xfffffffcu) |
(static_cast<uint64_t>(cmd[1]) << 32u));
const uint32_t indirect_num_regs = cmd[3] & 0x3fffu;
for (uint32_t i = 0; indirect_buffer != nullptr && i < indirect_num_regs;
i++, indirect_buffer += 2) {
file->Printf(" | | offset = 0x%08" PRIx32
", value = 0x%08" PRIx32 "\n",
indirect_buffer[0], indirect_buffer[1]);
} }
if ((op == IT_SET_CONTEXT_REG_INDIRECT || op == IT_SET_SH_REG_INDIRECT ||
op == IT_SET_UCONFIG_REG_INDIRECT) &&
len == 4) {
auto* indirect_buffer =
reinterpret_cast<uint32_t*>((static_cast<uint64_t>(cmd[0]) & 0xfffffffcu) |
(static_cast<uint64_t>(cmd[1]) << 32u));
const uint32_t indirect_num_regs = cmd[3] & 0x3fffu;
for (uint32_t i = 0; indirect_buffer != nullptr && i < indirect_num_regs;
i++, indirect_buffer += 2) {
file->Printf(" | | offset = 0x%08" PRIx32
", value = 0x%08" PRIx32 "\n",
indirect_buffer[0], indirect_buffer[1]);
}
}
break;
} }
} else { case PacketType::Type0:
file->Printf("?????\n"); case PacketType::Type1:
case PacketType::Type2:
file->Printf("<unsupported TYPE%u packet>\n", static_cast<uint32_t>(packet_type));
break;
} }
cmd += len; cmd += len;
+71 -361
View File
@@ -1392,81 +1392,82 @@ static const Standard64KB128Tables& GetStandard64KB128Tables() {
return tables; return tables;
} }
void TileConvertTiledToLinearStandard64KB32(void* dst, const void* src, uint32_t width, template <typename T, uint32_t BlockWidth, uint32_t BlockHeight, uint32_t CopyBatch,
uint32_t height, uint32_t pitch, uint64_t size, bool ExactSurfaceRequiresFullWidth, typename Tables>
uint64_t src_size, uint32_t src_x, uint32_t src_y) { static void ConvertTiledToLinearStandard64KBElements(void* dst, const void* src, uint32_t width,
KYTY_PROFILER_FUNCTION(); uint32_t height, uint32_t pitch, uint64_t size,
uint64_t src_size, uint32_t src_x,
uint32_t src_y, const Tables& tables) {
static_assert(BlockWidth * BlockHeight * sizeof(T) == 64u * 1024u);
static_assert(CopyBatch != 0 && BlockWidth % CopyBatch == 0);
EXIT_IF(dst == nullptr || src == nullptr); EXIT_IF(dst == nullptr || src == nullptr);
EXIT_NOT_IMPLEMENTED(pitch == 0); EXIT_NOT_IMPLEMENTED(pitch == 0);
const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size));
EXIT_NOT_IMPLEMENTED(width > pitch); EXIT_NOT_IMPLEMENTED(width > pitch);
EXIT_NOT_IMPLEMENTED(tail_block && (src_x + width > 128u || src_y + height > 128u)); EXIT_NOT_IMPLEMENTED(tail_block &&
(src_x + width > BlockWidth || src_y + height > BlockHeight));
auto* dst32 = static_cast<uint32_t*>(dst); auto* dst_elements = static_cast<T*>(dst);
const auto* src32 = static_cast<const uint32_t*>(src); const auto* src_elements = static_cast<const T*>(src);
const auto element_count = size / sizeof(T);
const auto& tables = GetStandard64KB32Tables(); const auto src_element_count = (src_size != 0 ? src_size : size) / sizeof(T);
const auto size_words = size >> 2u;
const auto src_size_words = (src_size != 0 ? src_size : size) >> 2u;
const auto blocks_per_row = const auto blocks_per_row =
(tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch, 128u) >> 7u)); tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch, BlockWidth) / BlockWidth);
const auto dst_words = static_cast<uint64_t>(pitch) * height; const auto dst_element_count = static_cast<uint64_t>(pitch) * height;
const bool exact_surface = const bool exact_surface = !tail_block && (!ExactSurfaceRequiresFullWidth || width == pitch) &&
(!tail_block && width == pitch && (size & 3u) == 0 && size_words == dst_words); size % sizeof(T) == 0 && element_count == dst_element_count;
const auto* x_words = tables.x_words.data(); const auto* x_elements = tables.x_words.data();
const auto* y_words = tables.y_words.data(); const auto* y_elements = tables.y_words.data();
if (!exact_surface) { if (!exact_surface) {
std::memset(dst32, 0, static_cast<size_t>(size)); std::memset(dst_elements, 0, static_cast<size_t>(size));
} }
for (uint32_t block_y = 0; block_y < height; block_y += 128u) { constexpr uint64_t ElementsPerBlock = BlockWidth * BlockHeight;
const uint32_t block_height = std::min(128u, height - block_y); for (uint32_t block_y = 0; block_y < height; block_y += BlockHeight) {
const uint32_t copy_height = std::min(BlockHeight, height - block_y);
for (uint32_t block_x = 0; block_x < width; block_x += 128u) { for (uint32_t block_x = 0; block_x < width; block_x += BlockWidth) {
const uint32_t block_width = std::min(128u, width - block_x); const uint32_t copy_width = std::min(BlockWidth, width - block_x);
const uint64_t block_base = const uint64_t block_base =
(tail_block tail_block ? 0u
? 0u : ((static_cast<uint64_t>(block_y / BlockHeight) * blocks_per_row) +
: (((static_cast<uint64_t>(block_y) >> 7u) * blocks_per_row) + (block_x >> 7u)) block_x / BlockWidth) *
<< 14u); ElementsPerBlock;
const bool full_block = const bool full_block = !tail_block && copy_width == BlockWidth &&
(!tail_block && block_width == 128u && block_height == 128u && copy_height == BlockHeight &&
block_base + 16384u <= src_size_words && block_base + ElementsPerBlock <= src_element_count &&
(static_cast<uint64_t>(block_y + 127u) * pitch) + block_x + 127u < size_words); static_cast<uint64_t>(block_y + BlockHeight - 1u) * pitch +
block_x + BlockWidth - 1u <
element_count;
if (full_block) { if (full_block) {
for (uint32_t local_y = 0; local_y < 128u; local_y++) { for (uint32_t local_y = 0; local_y < BlockHeight; local_y++) {
const uint64_t dst_row = const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x; static_cast<uint64_t>(block_y + local_y) * pitch + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y]; const uint64_t src_row = block_base + y_elements[src_y + local_y];
for (uint32_t local_x = 0; local_x < 128u; local_x += 4u) { for (uint32_t local_x = 0; local_x < BlockWidth; local_x += CopyBatch) {
dst32[dst_row + local_x + 0u] = for (uint32_t i = 0; i < CopyBatch; i++) {
src32[src_row + x_words[src_x + local_x + 0u]]; dst_elements[dst_row + local_x + i] =
dst32[dst_row + local_x + 1u] = src_elements[src_row + x_elements[src_x + local_x + i]];
src32[src_row + x_words[src_x + local_x + 1u]]; }
dst32[dst_row + local_x + 2u] =
src32[src_row + x_words[src_x + local_x + 2u]];
dst32[dst_row + local_x + 3u] =
src32[src_row + x_words[src_x + local_x + 3u]];
} }
} }
continue; continue;
} }
for (uint32_t local_y = 0; local_y < block_height; local_y++) { for (uint32_t local_y = 0; local_y < copy_height; local_y++) {
const uint64_t dst_row = const uint64_t dst_row = static_cast<uint64_t>(block_y + local_y) * pitch + block_x;
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x; const uint64_t src_row = block_base + y_elements[src_y + local_y];
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < block_width; local_x++) { for (uint32_t local_x = 0; local_x < copy_width; local_x++) {
const uint64_t dst_index = dst_row + local_x; const uint64_t dst_index = dst_row + local_x;
const uint64_t src_index = src_row + x_words[src_x + local_x]; const uint64_t src_index = src_row + x_elements[src_x + local_x];
if (src_index < src_size_words && dst_index < size_words) { if (src_index < src_element_count && dst_index < element_count) {
dst32[dst_index] = src32[src_index]; dst_elements[dst_index] = src_elements[src_index];
} }
} }
} }
@@ -1474,6 +1475,15 @@ void TileConvertTiledToLinearStandard64KB32(void* dst, const void* src, uint32_t
} }
} }
void TileConvertTiledToLinearStandard64KB32(void* dst, const void* src, uint32_t width,
uint32_t height, uint32_t pitch, uint64_t size,
uint64_t src_size, uint32_t src_x, uint32_t src_y) {
KYTY_PROFILER_FUNCTION();
ConvertTiledToLinearStandard64KBElements<uint32_t, 128u, 128u, 4u, true>(
dst, src, width, height, pitch, size, src_size, src_x, src_y, GetStandard64KB32Tables());
}
void TileConvertLinearToTiledStandard64KB32(void* dst, const void* src, uint32_t width, void TileConvertLinearToTiledStandard64KB32(void* dst, const void* src, uint32_t width,
uint32_t height, uint32_t pitch, uint64_t size) { uint32_t height, uint32_t pitch, uint64_t size) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
@@ -1540,81 +1550,8 @@ void TileConvertTiledToLinearStandard64KB16(void* dst, const void* src, uint32_t
uint64_t src_size, uint32_t src_x, uint32_t src_y) { uint64_t src_size, uint32_t src_x, uint32_t src_y) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(dst == nullptr || src == nullptr); ConvertTiledToLinearStandard64KBElements<uint16_t, 256u, 128u, 4u, true>(
EXIT_NOT_IMPLEMENTED(pitch == 0); dst, src, width, height, pitch, size, src_size, src_x, src_y, GetStandard64KB16Tables());
const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size));
EXIT_NOT_IMPLEMENTED(width > pitch);
EXIT_NOT_IMPLEMENTED(tail_block && (src_x + width > 256u || src_y + height > 128u));
auto* dst16 = static_cast<uint16_t*>(dst);
const auto* src16 = static_cast<const uint16_t*>(src);
const auto& tables = GetStandard64KB16Tables();
const auto size_words = size >> 1u;
const auto src_size_words = (src_size != 0 ? src_size : size) >> 1u;
const auto blocks_per_row =
(tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch, 256u) >> 8u));
const auto dst_words = static_cast<uint64_t>(pitch) * height;
const bool exact_surface =
(!tail_block && width == pitch && (size & 1u) == 0 && size_words == dst_words);
const auto* x_words = tables.x_words.data();
const auto* y_words = tables.y_words.data();
if (!exact_surface) {
std::memset(dst16, 0, static_cast<size_t>(size));
}
for (uint32_t block_y = 0; block_y < height; block_y += 128u) {
const uint32_t block_height = std::min(128u, height - block_y);
for (uint32_t block_x = 0; block_x < width; block_x += 256u) {
const uint32_t block_width = std::min(256u, width - block_x);
const uint64_t block_base =
(tail_block
? 0u
: (((static_cast<uint64_t>(block_y) >> 7u) * blocks_per_row) + (block_x >> 8u))
<< 15u);
const bool full_block =
(!tail_block && block_width == 256u && block_height == 128u &&
block_base + 32768u <= src_size_words &&
(static_cast<uint64_t>(block_y + 127u) * pitch) + block_x + 255u < size_words);
if (full_block) {
for (uint32_t local_y = 0; local_y < 128u; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < 256u; local_x += 4u) {
dst16[dst_row + local_x + 0u] =
src16[src_row + x_words[src_x + local_x + 0u]];
dst16[dst_row + local_x + 1u] =
src16[src_row + x_words[src_x + local_x + 1u]];
dst16[dst_row + local_x + 2u] =
src16[src_row + x_words[src_x + local_x + 2u]];
dst16[dst_row + local_x + 3u] =
src16[src_row + x_words[src_x + local_x + 3u]];
}
}
continue;
}
for (uint32_t local_y = 0; local_y < block_height; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < block_width; local_x++) {
const uint64_t dst_index = dst_row + local_x;
const uint64_t src_index = src_row + x_words[src_x + local_x];
if (src_index < src_size_words && dst_index < size_words) {
dst16[dst_index] = src16[src_index];
}
}
}
}
}
} }
static void TileConvertTiledToLinearStandard64KB8Elements( static void TileConvertTiledToLinearStandard64KB8Elements(
@@ -1622,82 +1559,9 @@ static void TileConvertTiledToLinearStandard64KB8Elements(
uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) { uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(dst == nullptr || src == nullptr); ConvertTiledToLinearStandard64KBElements<uint8_t, 256u, 256u, 4u, false>(
EXIT_NOT_IMPLEMENTED(pitch_elements == 0); dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y,
const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); GetStandard64KB8Tables());
EXIT_NOT_IMPLEMENTED(width_elements > pitch_elements);
EXIT_NOT_IMPLEMENTED(tail_block &&
(src_x + width_elements > 256u || src_y + height_elements > 256u));
auto* dst8 = static_cast<uint8_t*>(dst);
const auto* src8 = static_cast<const uint8_t*>(src);
const auto& tables = GetStandard64KB8Tables();
const auto size_words = size;
const auto src_size_words = (src_size != 0 ? src_size : size);
const auto blocks_per_row =
(tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch_elements, 256u) >> 8u));
const auto dst_words = static_cast<uint64_t>(pitch_elements) * height_elements;
const bool exact_surface = (!tail_block && size_words == dst_words);
const auto* x_words = tables.x_words.data();
const auto* y_words = tables.y_words.data();
if (!exact_surface) {
std::memset(dst8, 0, static_cast<size_t>(size));
}
for (uint32_t block_y = 0; block_y < height_elements; block_y += 256u) {
const uint32_t block_height = std::min(256u, height_elements - block_y);
for (uint32_t block_x = 0; block_x < width_elements; block_x += 256u) {
const uint32_t block_width = std::min(256u, width_elements - block_x);
const uint64_t block_base =
(tail_block
? 0u
: (((static_cast<uint64_t>(block_y) >> 8u) * blocks_per_row) + (block_x >> 8u))
<< 16u);
const bool full_block =
(!tail_block && block_width == 256u && block_height == 256u &&
block_base + 65536u <= src_size_words &&
(static_cast<uint64_t>(block_y + 255u) * pitch_elements) + block_x + 255u <
size_words);
if (full_block) {
for (uint32_t local_y = 0; local_y < 256u; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < 256u; local_x += 4u) {
dst8[dst_row + local_x + 0u] =
src8[src_row + x_words[src_x + local_x + 0u]];
dst8[dst_row + local_x + 1u] =
src8[src_row + x_words[src_x + local_x + 1u]];
dst8[dst_row + local_x + 2u] =
src8[src_row + x_words[src_x + local_x + 2u]];
dst8[dst_row + local_x + 3u] =
src8[src_row + x_words[src_x + local_x + 3u]];
}
}
continue;
}
for (uint32_t local_y = 0; local_y < block_height; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < block_width; local_x++) {
const uint64_t dst_index = dst_row + local_x;
const uint64_t src_index = src_row + x_words[src_x + local_x];
if (src_index < src_size_words && dst_index < size_words) {
dst8[dst_index] = src8[src_index];
}
}
}
}
}
} }
static void TileConvertTiledToLinearStandard64KB64Elements( static void TileConvertTiledToLinearStandard64KB64Elements(
@@ -1705,90 +1569,9 @@ static void TileConvertTiledToLinearStandard64KB64Elements(
uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) { uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(dst == nullptr || src == nullptr); ConvertTiledToLinearStandard64KBElements<uint64_t, 128u, 64u, 8u, false>(
EXIT_NOT_IMPLEMENTED(pitch_elements == 0); dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y,
const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); GetStandard64KB64Tables());
EXIT_NOT_IMPLEMENTED(width_elements > pitch_elements);
EXIT_NOT_IMPLEMENTED(tail_block &&
(src_x + width_elements > 128u || src_y + height_elements > 64u));
auto* dst64 = static_cast<uint64_t*>(dst);
const auto* src64 = static_cast<const uint64_t*>(src);
const auto& tables = GetStandard64KB64Tables();
const auto size_words = size >> 3u;
const auto src_size_words = (src_size != 0 ? src_size : size) >> 3u;
const auto blocks_per_row =
(tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch_elements, 128u) >> 7u));
const auto dst_words = static_cast<uint64_t>(pitch_elements) * height_elements;
const bool exact_surface = (!tail_block && (size & 7u) == 0 && size_words == dst_words);
const auto* x_words = tables.x_words.data();
const auto* y_words = tables.y_words.data();
if (!exact_surface) {
std::memset(dst64, 0, static_cast<size_t>(size));
}
for (uint32_t block_y = 0; block_y < height_elements; block_y += 64u) {
const uint32_t block_height = std::min(64u, height_elements - block_y);
for (uint32_t block_x = 0; block_x < width_elements; block_x += 128u) {
const uint32_t block_width = std::min(128u, width_elements - block_x);
const uint64_t block_base =
(tail_block
? 0u
: (((static_cast<uint64_t>(block_y) >> 6u) * blocks_per_row) + (block_x >> 7u))
<< 13u);
const bool full_block =
(!tail_block && block_width == 128u && block_height == 64u &&
block_base + 8192u <= src_size_words &&
(static_cast<uint64_t>(block_y + 63u) * pitch_elements) + block_x + 127u <
size_words);
if (full_block) {
for (uint32_t local_y = 0; local_y < 64u; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < 128u; local_x += 8u) {
dst64[dst_row + local_x + 0u] =
src64[src_row + x_words[src_x + local_x + 0u]];
dst64[dst_row + local_x + 1u] =
src64[src_row + x_words[src_x + local_x + 1u]];
dst64[dst_row + local_x + 2u] =
src64[src_row + x_words[src_x + local_x + 2u]];
dst64[dst_row + local_x + 3u] =
src64[src_row + x_words[src_x + local_x + 3u]];
dst64[dst_row + local_x + 4u] =
src64[src_row + x_words[src_x + local_x + 4u]];
dst64[dst_row + local_x + 5u] =
src64[src_row + x_words[src_x + local_x + 5u]];
dst64[dst_row + local_x + 6u] =
src64[src_row + x_words[src_x + local_x + 6u]];
dst64[dst_row + local_x + 7u] =
src64[src_row + x_words[src_x + local_x + 7u]];
}
}
continue;
}
for (uint32_t local_y = 0; local_y < block_height; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < block_width; local_x++) {
const uint64_t dst_index = dst_row + local_x;
const uint64_t src_index = src_row + x_words[src_x + local_x];
if (src_index < src_size_words && dst_index < size_words) {
dst64[dst_index] = src64[src_index];
}
}
}
}
}
} }
static void TileConvertLinearToTiledStandard64KB64Elements( static void TileConvertLinearToTiledStandard64KB64Elements(
@@ -1822,82 +1605,9 @@ static void TileConvertTiledToLinearStandard64KB128Elements(
uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) { uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(dst == nullptr || src == nullptr); ConvertTiledToLinearStandard64KBElements<Uint128, 64u, 64u, 4u, false>(
EXIT_NOT_IMPLEMENTED(pitch_elements == 0); dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y,
const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); GetStandard64KB128Tables());
EXIT_NOT_IMPLEMENTED(width_elements > pitch_elements);
EXIT_NOT_IMPLEMENTED(tail_block &&
(src_x + width_elements > 64u || src_y + height_elements > 64u));
auto* dst128 = static_cast<Uint128*>(dst);
const auto* src128 = static_cast<const Uint128*>(src);
const auto& tables = GetStandard64KB128Tables();
const auto size_words = size >> 4u;
const auto src_size_words = (src_size != 0 ? src_size : size) >> 4u;
const auto blocks_per_row =
(tail_block ? 1u : static_cast<uint64_t>(AlignUp(pitch_elements, 64u) >> 6u));
const auto dst_words = static_cast<uint64_t>(pitch_elements) * height_elements;
const bool exact_surface = (!tail_block && (size & 15u) == 0 && size_words == dst_words);
const auto* x_words = tables.x_words.data();
const auto* y_words = tables.y_words.data();
if (!exact_surface) {
std::memset(dst128, 0, static_cast<size_t>(size));
}
for (uint32_t block_y = 0; block_y < height_elements; block_y += 64u) {
const uint32_t block_height = std::min(64u, height_elements - block_y);
for (uint32_t block_x = 0; block_x < width_elements; block_x += 64u) {
const uint32_t block_width = std::min(64u, width_elements - block_x);
const uint64_t block_base =
(tail_block
? 0u
: (((static_cast<uint64_t>(block_y) >> 6u) * blocks_per_row) + (block_x >> 6u))
<< 12u);
const bool full_block =
(!tail_block && block_width == 64u && block_height == 64u &&
block_base + 4096u <= src_size_words &&
(static_cast<uint64_t>(block_y + 63u) * pitch_elements) + block_x + 63u <
size_words);
if (full_block) {
for (uint32_t local_y = 0; local_y < 64u; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < 64u; local_x += 4u) {
dst128[dst_row + local_x + 0u] =
src128[src_row + x_words[src_x + local_x + 0u]];
dst128[dst_row + local_x + 1u] =
src128[src_row + x_words[src_x + local_x + 1u]];
dst128[dst_row + local_x + 2u] =
src128[src_row + x_words[src_x + local_x + 2u]];
dst128[dst_row + local_x + 3u] =
src128[src_row + x_words[src_x + local_x + 3u]];
}
}
continue;
}
for (uint32_t local_y = 0; local_y < block_height; local_y++) {
const uint64_t dst_row =
(static_cast<uint64_t>(block_y + local_y) * pitch_elements) + block_x;
const uint64_t src_row = block_base + y_words[src_y + local_y];
for (uint32_t local_x = 0; local_x < block_width; local_x++) {
const uint64_t dst_index = dst_row + local_x;
const uint64_t src_index = src_row + x_words[src_x + local_x];
if (src_index < src_size_words && dst_index < size_words) {
dst128[dst_index] = src128[src_index];
}
}
}
}
}
} }
void TileConvertTiledToLinearStandard64KB(void* dst, const void* src, uint32_t format, void TileConvertTiledToLinearStandard64KB(void* dst, const void* src, uint32_t format,
+4 -2
View File
@@ -7,6 +7,7 @@
#include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export #include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export
#include "graphics/host_gpu/vulkanInstance.h" #include "graphics/host_gpu/vulkanInstance.h"
#include <array>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
@@ -42,8 +43,9 @@ struct VulkanCommandPool {
}; };
struct GraphicContext: public VulkanInstance { struct GraphicContext: public VulkanInstance {
uint32_t screen_width = 0; uint32_t screen_width = 0;
uint32_t screen_height = 0; uint32_t screen_height = 0;
std::array<Common::Mutex, QUEUES_NUM> queue_mutexes;
}; };
struct VulkanMemory { struct VulkanMemory {
+13 -4
View File
@@ -4,6 +4,7 @@
#include "common/threads.h" #include "common/threads.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
@@ -270,7 +271,7 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
submission.completion = std::make_shared<LabelEvent>(); submission.completion = std::make_shared<LabelEvent>();
submission.completion->device = label->device; submission.completion->device = label->device;
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr); EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr);
@@ -279,14 +280,22 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) {
create_info.pNext = nullptr; create_info.pNext = nullptr;
create_info.flags = {}; create_info.flags = {};
label->device.createEvent(&create_info, nullptr, &submission.completion->event); const auto create_result =
EXIT_NOT_IMPLEMENTED(submission.completion->event == nullptr); label->device.createEvent(&create_info, nullptr, &submission.completion->event);
if (create_result != vk::Result::eSuccess || submission.completion->event == nullptr) {
EXIT("failed to create label event: %s (%d)\n", VulkanToString(create_result).c_str(),
static_cast<int>(create_result));
}
buffer->RetainResourceUntilFence(submission.completion); buffer->RetainResourceUntilFence(submission.completion);
// Labels can be reused before an earlier end-of-pipe event has been // Labels can be reused before an earlier end-of-pipe event has been
// observed by the polling thread. Capture a separate Vulkan event and // observed by the polling thread. Capture a separate Vulkan event and
// callback snapshot for each set so older writes are not lost. // callback snapshot for each set so older writes are not lost.
label->device.resetEvent(submission.completion->event); const auto reset_result = label->device.resetEvent(submission.completion->event);
if (reset_result != vk::Result::eSuccess) {
EXIT("failed to reset label event: %s (%d)\n", VulkanToString(reset_result).c_str(),
static_cast<int>(reset_result));
}
vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe); vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe);
label->submissions.push_back(submission); label->submissions.push_back(submission);
+178 -172
View File
@@ -5,8 +5,9 @@
#include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/gpu_format.h" #include "graphics/guest_gpu/gpu_format.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
@@ -14,6 +15,127 @@
#include <cstring> #include <cstring>
namespace Libs::Graphics { namespace Libs::Graphics {
namespace {
struct RenderTargetFormatMapping {
Prospero::ChannelLayout layout;
Prospero::ChannelType type;
Prospero::ChannelOrder order;
RenderTargetFormatInfo info;
};
constexpr RenderTargetFormatMapping kRenderTargetFormats[] = {
{Prospero::ChannelLayout::k8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8Unorm, 2}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Unorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Snorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR8G8B8A8Srgb, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Unorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Snorm, 4}},
{Prospero::ChannelLayout::k8_8_8_8,
Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kAlt,
{vk::Format::eB8G8R8A8Srgb, 4}},
{Prospero::ChannelLayout::k5_5_5_1,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR5G5B5A1UnormPack16, 2}},
{Prospero::ChannelLayout::k4_4_4_4,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kReversed,
{vk::Format::eB4G4R4A4UnormPack16, 2}},
{Prospero::ChannelLayout::k10_10_10_2,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eA2B10G10R10UnormPack32, 4}},
{Prospero::ChannelLayout::k10_10_10_2,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt,
{vk::Format::eA2R10G10B10UnormPack32, 4}},
{Prospero::ChannelLayout::k11_11_10,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eB10G11R11UfloatPack32, 4}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Unorm, 2}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Uint, 2}},
{Prospero::ChannelLayout::k16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16Sfloat, 2}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Unorm, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Snorm, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Uint, 4}},
{Prospero::ChannelLayout::k16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16Sfloat, 4}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16B16A16Unorm, 8}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR16G16B16A16Sfloat, 8}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kAlt,
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingBgra}},
{Prospero::ChannelLayout::k16_16_16_16,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kReversed,
{vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingAbgr}},
{Prospero::ChannelLayout::k32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32Sfloat, 4}},
{Prospero::ChannelLayout::k32_32,
Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32Uint, 8}},
{Prospero::ChannelLayout::k32_32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32Sfloat, 8}},
{Prospero::ChannelLayout::k32_32_32_32,
Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard,
{vk::Format::eR32G32B32A32Sfloat, 16}},
};
} // namespace
// TODO: cleanup! // TODO: cleanup!
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_t raw_type, RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_t raw_type,
@@ -21,132 +143,25 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_
const auto layout = static_cast<Prospero::ChannelLayout>(raw_layout); const auto layout = static_cast<Prospero::ChannelLayout>(raw_layout);
const auto type = static_cast<Prospero::ChannelType>(raw_type); const auto type = static_cast<Prospero::ChannelType>(raw_type);
const auto order = static_cast<Prospero::ChannelOrder>(raw_order); const auto order = static_cast<Prospero::ChannelOrder>(raw_order);
const auto is = [=](Prospero::ChannelLayout l, Prospero::ChannelType t,
Prospero::ChannelOrder o) {
return layout == l && type == t && order == o;
};
if (layout == Prospero::ChannelLayout::k8 && type == Prospero::ChannelType::kUNorm && if (layout == Prospero::ChannelLayout::k8 && type == Prospero::ChannelType::kUNorm &&
raw_order <= Prospero::GpuEnumValue(Prospero::ChannelOrder::kAltReversed)) { raw_order <= Prospero::GpuEnumValue(Prospero::ChannelOrder::kAltReversed)) {
return {vk::Format::eR8Unorm, 1}; return {vk::Format::eR8Unorm, 1};
} }
if (is(Prospero::ChannelLayout::k8_8, Prospero::ChannelType::kUNorm, for (const auto& mapping: kRenderTargetFormats) {
Prospero::ChannelOrder::kStandard)) { if (mapping.layout == layout && mapping.type == type && mapping.order == order) {
return {vk::Format::eR8G8Unorm, 2}; return mapping.info;
} }
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Unorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Snorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR8G8B8A8Srgb, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Unorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Snorm, 4};
}
if (is(Prospero::ChannelLayout::k8_8_8_8, Prospero::ChannelType::kSrgb,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eB8G8R8A8Srgb, 4};
}
if (is(Prospero::ChannelLayout::k5_5_5_1, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR5G5B5A1UnormPack16, 2};
}
if (is(Prospero::ChannelLayout::k4_4_4_4, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kReversed)) {
return {vk::Format::eB4G4R4A4UnormPack16, 2};
}
if (is(Prospero::ChannelLayout::k10_10_10_2, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eA2B10G10R10UnormPack32, 4};
}
if (is(Prospero::ChannelLayout::k10_10_10_2, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eA2R10G10B10UnormPack32, 4};
}
if (is(Prospero::ChannelLayout::k11_11_10, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eB10G11R11UfloatPack32, 4};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Unorm, 2};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Uint, 2};
}
if (is(Prospero::ChannelLayout::k16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16Sfloat, 2};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Unorm, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kSNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Snorm, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Uint, 4};
}
if (is(Prospero::ChannelLayout::k16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16Sfloat, 4};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kUNorm,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16B16A16Unorm, 8};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR16G16B16A16Sfloat, 8};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kAlt)) {
return {vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingBgra};
}
if (is(Prospero::ChannelLayout::k16_16_16_16, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kReversed)) {
return {vk::Format::eR16G16B16A16Sfloat, 8, Prospero::ColorMappingAbgr};
}
if (is(Prospero::ChannelLayout::k32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32Sfloat, 4};
}
if (is(Prospero::ChannelLayout::k32_32, Prospero::ChannelType::kUInt,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32Uint, 8};
}
if (is(Prospero::ChannelLayout::k32_32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32Sfloat, 8};
}
if (is(Prospero::ChannelLayout::k32_32_32_32, Prospero::ChannelType::kFloat,
Prospero::ChannelOrder::kStandard)) {
return {vk::Format::eR32G32B32A32Sfloat, 16};
} }
EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n", raw_layout, EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n", raw_layout,
raw_type, raw_order); raw_type, raw_order);
} }
static uint64_t TextureUploadLevelSrcOffset(const TileSizeOffset& level_size) { static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset); return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset);
} }
static uint64_t TextureUploadLevelSrcSize(const TileSizeOffset& level_size) { static uint64_t GetLevelSrcSize(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_size : level_size.size); return (level_size.src_size != 0 ? level_size.src_size : level_size.size);
} }
@@ -156,11 +171,11 @@ uint64_t TextureUploadSliceSourceOffset(const TextureUploadLayout& layout, uint3
if (level >= 16 || layout.level_sizes[level].size == 0) { if (level >= 16 || layout.level_sizes[level].size == 0) {
EXIT("invalid texture upload slice source, level=%u slice=%u\n", level, slice); EXIT("invalid texture upload slice source, level=%u slice=%u\n", level, slice);
} }
const auto level_offset = TextureUploadLevelSrcOffset(layout.level_sizes[level]); const auto level_offset = GetLevelSrcOffset(layout.level_sizes[level]);
const auto slice_stride = const auto slice_stride =
source_slice_layout == TextureUploadSliceLayout::MipChainPerSlice source_slice_layout == TextureUploadSliceLayout::MipChainPerSlice
? (layout.source_slice_stride != 0 ? layout.source_slice_stride : layout.slice_stride) ? (layout.source_slice_stride != 0 ? layout.source_slice_stride : layout.slice_stride)
: TextureUploadLevelSrcSize(layout.level_sizes[level]); : GetLevelSrcSize(layout.level_sizes[level]);
if (slice_stride != 0 && slice > (UINT64_MAX - level_offset) / slice_stride) { if (slice_stride != 0 && slice > (UINT64_MAX - level_offset) / slice_stride) {
EXIT("texture upload slice source offset overflow, level=%u slice=%u\n", level, slice); EXIT("texture upload slice source offset overflow, level=%u slice=%u\n", level, slice);
} }
@@ -178,7 +193,7 @@ uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout,
} }
for (uint32_t level = 0; level < levels; level++) { for (uint32_t level = 0; level < levels; level++) {
const auto src_size = TextureUploadLevelSrcSize(layout.level_sizes[level]); const auto src_size = GetLevelSrcSize(layout.level_sizes[level]);
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
size = std::max<uint64_t>( size = std::max<uint64_t>(
size, size,
@@ -191,7 +206,7 @@ uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout,
void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer, void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
uint64_t src_buffer_offset, uint64_t copy_size, uint64_t src_buffer_offset, uint64_t copy_size,
UtilScratchBuffer* dst) { Transfer::ScratchBuffer* dst) {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(src_buffer == nullptr); EXIT_IF(src_buffer == nullptr);
EXIT_IF(dst == nullptr); EXIT_IF(dst == nullptr);
@@ -223,7 +238,7 @@ void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCoherent |
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, (src_buffer_offset + available + 3u) & ~uint64_t {3}, &readback); VulkanCreateBuffer(ctx, (src_buffer_offset + available + 3u) & ~uint64_t {3}, &readback);
UtilCopyBuffer(src_buffer, &readback, src_buffer_offset + available); Transfer::CopyBuffer(src_buffer, &readback, src_buffer_offset + available);
void* data = nullptr; void* data = nullptr;
VulkanMapMemory(ctx, &readback.memory, &data); VulkanMapMemory(ctx, &readback.memory, &data);
@@ -349,8 +364,8 @@ vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage) {
return vk_usage; return vk_usage;
} }
vk::Format TextureGetFormat(uint32_t fmt, [[maybe_unused]] TextureFormatUsage usage) { vk::Format TextureGetFormat(uint32_t fmt) {
const auto vk_format = Prospero::SurfaceFormat(fmt); const auto vk_format = VulkanFormat(fmt);
if (vk_format != vk::Format::eUndefined) { if (vk_format != vk::Format::eUndefined) {
return vk_format; return vk_format;
} }
@@ -435,14 +450,15 @@ static bool CalcStandard4kbVolumeMipLayout(uint32_t format, uint32_t pitch, uint
uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth, uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth,
uint64_t levels) { uint64_t levels) {
return (depth > 1 && levels > 1 && UtilIsBcFormat(format) ? AlignUpU32(mip_height, 4u) return (depth > 1 && levels > 1 && Transfer::IsBlockCompressedFormat(format)
: mip_height); ? AlignUpU32(mip_height, 4u)
: mip_height);
} }
uint32_t TextureCalcStackedImageHeight(vk::Format format, uint32_t height, uint32_t depth, uint32_t TextureCalcStackedImageHeight(vk::Format format, uint32_t height, uint32_t depth,
uint64_t levels) { uint64_t levels) {
auto image_height = height * depth; auto image_height = height * depth;
if (depth <= 1 || levels <= 1 || !UtilIsBcFormat(format)) { if (depth <= 1 || levels <= 1 || !Transfer::IsBlockCompressedFormat(format)) {
return image_height; return image_height;
} }
@@ -468,7 +484,7 @@ uint32_t TextureCalcMipmapAtlasImageHeight(vk::Format format, uint32_t width, ui
uint32_t mip_height = height; uint32_t mip_height = height;
for (uint32_t level = 0; level < levels; level++) { for (uint32_t level = 0; level < levels; level++) {
const auto mipmap_offset = UtilCalcMipmapOffset(level, width, height); const auto mipmap_offset = Transfer::MipmapAtlasOffset(level, width, height);
const auto mip_bottom = const auto mip_bottom =
static_cast<uint32_t>(mipmap_offset.second) + static_cast<uint32_t>(mipmap_offset.second) +
TextureGetAtlasSliceYStride(format, mip_height, depth, levels) * depth; TextureGetAtlasSliceYStride(format, mip_height, depth, levels) * depth;
@@ -502,20 +518,20 @@ bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer
layer_count % 6u == 0; layer_count % 6u == 0;
} }
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, VulkanMemory* mem, vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj,
const TextureImageCreateParams& params) { const TextureImageCreateParams& params) {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(vk_obj == nullptr); EXIT_IF(vk_obj == nullptr);
EXIT_IF(mem == nullptr);
EXIT_IF(params.owner == nullptr); EXIT_IF(params.owner == nullptr);
const bool array_texture = TextureIsLayeredTexture(params.type); const bool array_texture = TextureIsLayeredTexture(params.type);
const bool volume_texture = TextureIs3DTexture(params.type); const bool volume_texture = TextureIs3DTexture(params.type);
auto pixel_format = TextureGetFormat(params.fmt, params.format_usage); auto pixel_format = TextureGetFormat(params.fmt);
EXIT_NOT_IMPLEMENTED(pixel_format == vk::Format::eUndefined); EXIT_NOT_IMPLEMENTED(pixel_format == vk::Format::eUndefined);
EXIT_NOT_IMPLEMENTED(params.width == 0); EXIT_NOT_IMPLEMENTED(params.width == 0);
EXIT_NOT_IMPLEMENTED(params.height == 0); EXIT_NOT_IMPLEMENTED(params.height == 0);
EXIT_NOT_IMPLEMENTED(params.depth == 0);
EXIT_NOT_IMPLEMENTED(params.levels == 0 || params.levels > 16); EXIT_NOT_IMPLEMENTED(params.levels == 0 || params.levels > 16);
uint32_t image_height = 0; uint32_t image_height = 0;
@@ -618,15 +634,11 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj
vk_obj->image = nullptr; vk_obj->image = nullptr;
vk_obj->layout = image_info.initialLayout; vk_obj->layout = image_info.initialLayout;
UtilResetImageViews(vk_obj); vk_obj->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
mem->property = vk::MemoryPropertyFlagBits::eDeviceLocal; bool created = VulkanCreateImage(ctx, image_info, vk_obj);
bool created = VulkanCreateImage(ctx, &image_info, vk_obj, mem);
EXIT_NOT_IMPLEMENTED(!created); EXIT_NOT_IMPLEMENTED(!created);
vk_obj->memory = *mem;
return components; return components;
} }
@@ -672,17 +684,19 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
create_info.viewType = vk::ImageViewType::e2DArray; create_info.viewType = vk::ImageViewType::e2DArray;
} }
ctx->device.createImageView(&create_info, nullptr, auto create_view = [&](int index) {
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT]); const auto result =
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT] == nullptr); ctx->device.createImageView(&create_info, nullptr, &vk_obj->image_view[index]);
if (result != vk::Result::eSuccess || vk_obj->image_view[index] == nullptr) {
EXIT("failed to create texture image view: result=%d format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(create_info.format), index);
}
};
create_view(VulkanImage::VIEW_DEFAULT);
if (!volume_texture || depth >= 1) { create_info.viewType = vk::ImageViewType::e2DArray;
create_info.viewType = vk::ImageViewType::e2DArray; create_info.subresourceRange.layerCount = volume_texture ? volume_slices : layer_count;
create_info.subresourceRange.layerCount = (volume_texture ? volume_slices : layer_count); create_view(VulkanImage::VIEW_DEFAULT_ARRAY);
ctx->device.createImageView(&create_info, nullptr,
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT_ARRAY]);
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT_ARRAY] == nullptr);
}
} }
static uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels, static uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels,
@@ -847,7 +861,7 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
EXIT_NOT_IMPLEMENTED(layout.level_sizes[i].size == 0); EXIT_NOT_IMPLEMENTED(layout.level_sizes[i].size == 0);
const auto mipmap_offset = UtilCalcMipmapOffset(i, width, height); const auto mipmap_offset = Transfer::MipmapAtlasOffset(i, width, height);
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -861,7 +875,7 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
regions[region_index].height = mip_height; regions[region_index].height = mip_height;
regions[region_index].copy_height = regions[region_index].copy_height =
(!array_texture && !volume_texture && depth > 1 && levels > 1 && (!array_texture && !volume_texture && depth > 1 && levels > 1 &&
UtilIsBcFormat(image_format) Transfer::IsBlockCompressedFormat(image_format)
? TextureGetAtlasSliceYStride(image_format, mip_height, depth, levels) ? TextureGetAtlasSliceYStride(image_format, mip_height, depth, levels)
: 0); : 0);
regions[region_index].dst_layer = (array_texture ? z : 0); regions[region_index].dst_layer = (array_texture ? z : 0);
@@ -911,14 +925,6 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
return regions; return regions;
} }
static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset);
}
static uint64_t GetLevelSrcSize(const TileSizeOffset& level_size) {
return (level_size.src_size != 0 ? level_size.src_size : level_size.size);
}
static uint64_t GetSliceSrcStride(const TextureUploadLayout& layout, uint32_t level, static uint64_t GetSliceSrcStride(const TextureUploadLayout& layout, uint32_t level,
TextureUploadSliceLayout source_slice_layout) { TextureUploadSliceLayout source_slice_layout) {
return ( return (
@@ -954,13 +960,13 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj,
", upload_size=%" PRIu64 " regions=%zu\n", ", upload_size=%" PRIu64 " regions=%zu\n",
owner, kIdentityFmaskPattern, upload_size, upload_regions.size()); owner, kIdentityFmaskPattern, upload_size, upload_regions.size());
UtilScratchBuffer temp_buf(upload_size); Transfer::ScratchBuffer temp_buf(upload_size);
auto* words = static_cast<uint32_t*>(temp_buf.Data()); auto* words = static_cast<uint32_t*>(temp_buf.Data());
for (uint64_t i = 0; i < upload_size / sizeof(uint32_t); i++) { for (uint64_t i = 0; i < upload_size / sizeof(uint32_t); i++) {
words[i] = kIdentityFmaskPattern; words[i] = kIdentityFmaskPattern;
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), upload_size, upload_regions, dst_layout);
} }
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data, void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
@@ -974,13 +980,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
" extent=%" PRIu64 "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n", " extent=%" PRIu64 "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n",
owner, layout.tile, size, width, height, depth, layout.pitch, levels); owner, layout.tile, size, width, height, depth, layout.pitch, levels);
} else if (static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear) { } else if (static_cast<Prospero::TileMode>(layout.tile) == Prospero::TileMode::kLinear) {
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
} else if (layout.fmt_tiled_render_target) { } else if (layout.fmt_tiled_render_target) {
LOGF("%s: detiling typed render-target texture: fmt=%u tile=%u size=%" PRIu64 LOGF("%s: detiling typed render-target texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels); static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -995,7 +1001,7 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y); layout.level_sizes[i].x, layout.level_sizes[i].y);
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_depth) { } else if (layout.fmt_tiled_depth) {
if (Prospero::IsFmaskTextureFormat(static_cast<uint32_t>(fmt))) { if (Prospero::IsFmaskTextureFormat(static_cast<uint32_t>(fmt))) {
UploadFmaskIdentity(ctx, vk_obj, regions, dst_layout, owner); UploadFmaskIdentity(ctx, vk_obj, regions, dst_layout, owner);
@@ -1004,13 +1010,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
const uint32_t bytes_per_element = const uint32_t bytes_per_element =
Prospero::RenderTargetBytesPerElement(static_cast<uint32_t>(fmt)); Prospero::RenderTargetBytesPerElement(static_cast<uint32_t>(fmt));
if (bytes_per_element == 1) { if (bytes_per_element == 1) {
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
} else { } else {
LOGF("%s: detiling typed depth texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 LOGF("%s: detiling typed depth texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64
"x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels); static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -1025,10 +1031,10 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].size); layout.level_sizes[i].size);
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} }
} else if (layout.fmt_tiled_standard256b) { } else if (layout.fmt_tiled_standard256b) {
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -1042,13 +1048,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].size, layout.level_sizes[i].size); layout.level_sizes[i].size, layout.level_sizes[i].size);
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard4kb && layout.volume_texture) { } else if (layout.fmt_tiled_standard4kb && layout.volume_texture) {
LOGF("%s: detiling typed Standard4KB 3D texture: fmt=%u tile=%u size=%" PRIu64 LOGF("%s: detiling typed Standard4KB 3D texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch, levels); static_cast<uint64_t>(depth), layout.pitch, levels);
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
if (levels == 1) { if (levels == 1) {
TileConvertTiledToLinearStandard4KB3D( TileConvertTiledToLinearStandard4KB3D(
temp_buf.Data(), src_data, static_cast<uint32_t>(fmt), static_cast<uint32_t>(width), temp_buf.Data(), src_data, static_cast<uint32_t>(fmt), static_cast<uint32_t>(width),
@@ -1099,13 +1105,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
} }
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard4kb) { } else if (layout.fmt_tiled_standard4kb) {
LOGF("%s: detiling typed Standard4KB texture: fmt=%u tile=%u size=%" PRIu64 LOGF("%s: detiling typed Standard4KB texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n", " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch); static_cast<uint64_t>(depth), layout.pitch);
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -1120,13 +1126,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y); layout.level_sizes[i].x, layout.level_sizes[i].y);
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.fmt_tiled_standard64kb) { } else if (layout.fmt_tiled_standard64kb) {
LOGF("%s: detiling typed Standard64KB texture: fmt=%u tile=%u size=%" PRIu64 LOGF("%s: detiling typed Standard64KB texture: fmt=%u tile=%u size=%" PRIu64
" extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n", " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height,
static_cast<uint64_t>(depth), layout.pitch); static_cast<uint64_t>(depth), layout.pitch);
UtilScratchBuffer temp_buf(size); Transfer::ScratchBuffer temp_buf(size);
for (uint32_t i = 0; i < levels; i++) { for (uint32_t i = 0; i < levels; i++) {
for (uint32_t z = 0; z < depth; z++) { for (uint32_t z = 0; z < depth; z++) {
const auto region_index = i * depth + z; const auto region_index = i * depth + z;
@@ -1141,14 +1147,14 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi
layout.level_sizes[i].x, layout.level_sizes[i].y); layout.level_sizes[i].x, layout.level_sizes[i].y);
} }
} }
UtilFillImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, temp_buf.Data(), size, regions, dst_layout);
} else if (layout.tile != 0) { } else if (layout.tile != 0) {
EXIT("%s: typed tiled upload still unsupported after sizing, using linear fallback: fmt=%u " EXIT("%s: typed tiled upload still unsupported after sizing, using linear fallback: fmt=%u "
"tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " pitch=%u levels=%" PRIu64 "tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " pitch=%u levels=%" PRIu64
"\n", "\n",
owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, layout.pitch, owner, static_cast<uint32_t>(fmt), layout.tile, size, width, height, layout.pitch,
levels); levels);
UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout); Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout);
} }
} }
@@ -5,7 +5,7 @@
#include "common/common.h" #include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/tile.h" #include "graphics/guest_gpu/tile.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include <vector> #include <vector>
@@ -14,7 +14,6 @@ namespace Libs::Graphics {
struct GraphicContext; struct GraphicContext;
struct VulkanImage; struct VulkanImage;
struct VulkanMemory;
enum class TextureFormatUsage : uint32_t { enum class TextureFormatUsage : uint32_t {
None = 0, None = 0,
@@ -93,7 +92,7 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo
bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components); bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components);
vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage); vk::ImageUsageFlags TextureGetUsage(TextureFormatUsage usage);
vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage); vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage);
vk::Format TextureGetFormat(uint32_t fmt, TextureFormatUsage usage); vk::Format TextureGetFormat(uint32_t fmt);
RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t layout, uint32_t type, uint32_t order); RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t layout, uint32_t type, uint32_t order);
uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth, uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth,
uint64_t levels); uint64_t levels);
@@ -105,7 +104,7 @@ bool TextureIs3DTexture(uint64_t type);
bool TextureIsCubeTexture(uint64_t type); bool TextureIsCubeTexture(uint64_t type);
bool TextureIsLayeredTexture(uint64_t type); bool TextureIsLayeredTexture(uint64_t type);
bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count); bool TextureCanCreateCubeView(uint64_t type, uint32_t base_array, uint32_t layer_count);
vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, VulkanMemory* mem, vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* image,
const TextureImageCreateParams& params); const TextureImageCreateParams& params);
void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj,
vk::ComponentMapping components, uint64_t type, uint32_t base_array, vk::ComponentMapping components, uint64_t type, uint32_t base_array,
@@ -128,7 +127,8 @@ std::vector<BufferImageCopy> TextureBuildUploadRegions(
uint32_t depth, uint64_t levels, bool array_texture, bool volume_texture, uint32_t depth, uint64_t levels, bool array_texture, bool volume_texture,
TextureUploadDestination destination, TextureUploadSliceLayout slice_layout); TextureUploadDestination destination, TextureUploadSliceLayout slice_layout);
void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer, void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer,
uint64_t src_buffer_offset, uint64_t copy_size, UtilScratchBuffer* dst); uint64_t src_buffer_offset, uint64_t copy_size,
Transfer::ScratchBuffer* dst);
void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data, void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const void* src_data,
uint64_t size, const std::vector<BufferImageCopy>& regions, uint64_t size, const std::vector<BufferImageCopy>& regions,
const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width,
+24 -45
View File
@@ -9,7 +9,7 @@
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/resourceMutex.h" #include "graphics/host_gpu/renderer/resourceMutex.h"
#include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "kernel/memory.h" #include "kernel/memory.h"
@@ -21,6 +21,7 @@
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <thread> #include <thread>
#include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -498,7 +499,7 @@ struct BufferCache::ReadbackWorker {
" count=%u bytes=%u\n", " count=%u bytes=%u\n",
page, range_count, data_offset); page, range_count, data_offset);
} }
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; auto vk_buffer = command->Handle();
command->Begin(); command->Begin();
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags {}, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags {},
@@ -562,7 +563,7 @@ BufferCache::~BufferCache() {
} }
} }
if (!m_buffers.empty()) { if (!m_buffers.empty()) {
VulkanDeviceWaitIdle(m_buffers.begin()->second->ctx); Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx);
} }
m_buffers.clear(); m_buffers.clear();
} }
@@ -628,8 +629,8 @@ void BufferCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes); const auto ranges = m_gpu_modified_ranges.Intersections(address, bytes);
for (const auto& range: ranges) { for (const auto& range: ranges) {
std::vector<uint8_t> data(range.size); std::vector<uint8_t> data(range.size);
UtilDownloadBuffer(cached->ctx, cached->buffer.get(), range.address - begin, Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(),
data.data(), range.size); range.address - begin, data.data(), range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size; downloaded += range.size;
} }
@@ -781,10 +782,10 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: uploads) { for (const auto& [upload_vaddr, upload_size]: uploads) {
UtilUploadBuffer(ctx, StagingBufferType::Vertex, old.buffer.get(), Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
upload_vaddr - old.vaddr, old.buffer.get(), upload_vaddr - old.vaddr,
reinterpret_cast<const void*>(upload_vaddr), reinterpret_cast<const void*>(upload_vaddr),
upload_size); upload_size);
} }
}); });
} }
@@ -801,7 +802,7 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
VulkanCreateBuffer(ctx, cached->size, cached->buffer.get()); VulkanCreateBuffer(ctx, cached->size, cached->buffer.get());
if (!overlaps.empty()) { if (!overlaps.empty()) {
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; auto vk_buffer = command->Handle();
std::vector<vk::BufferMemoryBarrier> before; std::vector<vk::BufferMemoryBarrier> before;
before.reserve(overlaps.size() + 1); before.reserve(overlaps.size() + 1);
for (const auto& overlap: overlaps) { for (const auto& overlap: overlaps) {
@@ -866,9 +867,9 @@ std::pair<VulkanBuffer*, uint64_t> BufferCache::ObtainBuffer(CommandBuffer* com
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [upload_vaddr, upload_size]: ranges) { for (const auto& [upload_vaddr, upload_size]: ranges) {
UtilUploadBuffer(ctx, StagingBufferType::Vertex, cached.buffer.get(), Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex,
upload_vaddr - cached.vaddr, cached.buffer.get(), upload_vaddr - cached.vaddr,
reinterpret_cast<const void*>(upload_vaddr), upload_size); reinterpret_cast<const void*>(upload_vaddr), upload_size);
} }
}); });
if (is_written) { if (is_written) {
@@ -963,7 +964,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
for (const auto& range: dirty_ranges) { for (const auto& range: dirty_ranges) {
auto& owner = find_owner(range.address, range.size); auto& owner = find_owner(range.address, range.size);
if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) { if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) {
VulkanDeviceWaitIdle(owner.ctx); Transfer::WaitForGraphicsIdle(owner.ctx);
waited.push_back(owner.ctx); waited.push_back(owner.ctx);
} }
} }
@@ -985,8 +986,8 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
auto& owner = find_owner(range.address, range.size); auto& owner = find_owner(range.address, range.size);
const auto buffer_offset = range.address - owner.vaddr; const auto buffer_offset = range.address - owner.vaddr;
std::vector<uint8_t> data(range.size); std::vector<uint8_t> data(range.size);
UtilDownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, data.data(), Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset,
range.size); data.data(), range.size);
Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size());
downloaded += range.size; downloaded += range.size;
} }
@@ -1020,9 +1021,9 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
}, },
[&]() noexcept { [&]() noexcept {
for (const auto& [address, bytes]: uploads) { for (const auto& [address, bytes]: uploads) {
UtilUploadBuffer(cached.ctx, StagingBufferType::Vertex, cached.buffer.get(), Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex,
address - cached.vaddr, reinterpret_cast<const void*>(address), cached.buffer.get(), address - cached.vaddr,
bytes); reinterpret_cast<const void*>(address), bytes);
} }
}); });
if (uploads.empty()) { if (uploads.empty()) {
@@ -1065,16 +1066,11 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui
} }
vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) { vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) {
if (command == nullptr || command->IsInvalid() || command->GetPool() == nullptr || if (command == nullptr) {
command->GetIndex() >= command->GetPool()->buffers_count) {
EXIT("BufferCache: invalid DMA command buffer, command=%p\n", EXIT("BufferCache: invalid DMA command buffer, command=%p\n",
static_cast<const void*>(command)); static_cast<const void*>(command));
} }
const auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; return command->Handle();
if (vk_buffer == nullptr) {
EXIT("BufferCache: DMA command buffer handle is null, index=%u\n", command->GetIndex());
}
return vk_buffer;
} }
} // namespace } // namespace
@@ -1308,27 +1304,10 @@ void BufferCache::SetTextureCache(TextureCache& texture_cache) {
m_texture_cache = &texture_cache; m_texture_cache = &texture_cache;
} }
// TODO: add LRU cache void BufferCache::ResetNullBuffer() {
void BufferCache::RegisterForDelete(VulkanBuffer* buffer) { KYTY_PROFILER_BLOCK("BufferCache::ResetNullBuffer");
FaultSafeCacheLock lock(this, m_mutex);
m_delete_later.push_back(buffer);
}
void BufferCache::DeleteAll(GraphicContext* ctx) {
KYTY_PROFILER_BLOCK("BufferCache::DeleteAll");
FaultSafeCacheLock lock(this, m_mutex); FaultSafeCacheLock lock(this, m_mutex);
for (auto* buffer: m_delete_later) {
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->buffer == nullptr);
EXIT_IF(ctx == nullptr);
VulkanDeleteBuffer(ctx, buffer);
delete buffer;
}
m_delete_later.clear();
m_null_buffer.reset(); m_null_buffer.reset();
} }
+4 -6
View File
@@ -10,7 +10,6 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -75,16 +74,15 @@ public:
void ValidateGpuAccess(uint64_t vaddr, uint64_t size, bool is_read, bool is_written) const; void ValidateGpuAccess(uint64_t vaddr, uint64_t size, bool is_read, bool is_written) const;
void SetTextureCache(TextureCache& texture_cache); void SetTextureCache(TextureCache& texture_cache);
void RegisterForDelete(VulkanBuffer* buffer); void ResetNullBuffer();
void DeleteAll(GraphicContext* ctx);
private: private:
struct CachedBuffer; struct CachedBuffer;
struct ReadbackWorker; struct ReadbackWorker;
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::vector<VulkanBuffer*> m_delete_later; std::shared_ptr<VulkanBuffer> m_null_buffer;
std::shared_ptr<VulkanBuffer> m_null_buffer; // TODO: add LRU cache
std::map<uint64_t, std::unique_ptr<CachedBuffer>> m_buffers; std::map<uint64_t, std::unique_ptr<CachedBuffer>> m_buffers;
std::unique_ptr<ReadbackWorker> m_readback; std::unique_ptr<ReadbackWorker> m_readback;
RangeSet m_gpu_modified_ranges; RangeSet m_gpu_modified_ranges;
@@ -1,11 +1,8 @@
#include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "graphics/host_gpu/renderer/colorRenderTarget.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/common.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/guest_gpu/hardwareContext.h" #include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/guest_gpu/tile.h" #include "graphics/guest_gpu/tile.h"
@@ -16,264 +13,17 @@
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/displayBuffer.h" #include "graphics/presentation/displayBuffer.h"
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
#include <cmath>
#include <cstdarg>
#include <cstdio>
#include <limits>
namespace Libs::Graphics { namespace Libs::Graphics {
static std::atomic<uint32_t> g_render_color_log_count = 0; static std::atomic<uint32_t> g_render_color_log_count = 0;
static float ColorClearUnorm(uint32_t value, uint32_t bits) {
return static_cast<float>(value) / static_cast<float>((1u << bits) - 1u);
}
static float ColorClearSnorm(uint32_t value, uint32_t bits) {
const uint32_t mask = (1u << bits) - 1u;
const uint32_t sign_bit = 1u << (bits - 1u);
value &= mask;
auto signed_value = static_cast<int32_t>(value);
if ((value & sign_bit) != 0) {
signed_value = static_cast<int32_t>(value | ~mask);
}
const auto denominator = static_cast<float>((1u << (bits - 1u)) - 1u);
return std::max(-1.0f, static_cast<float>(signed_value) / denominator);
}
static float ColorClearF16(uint32_t value) {
const uint32_t sign = (value >> 15u) & 0x1u;
const uint32_t exponent = (value >> 10u) & 0x1fu;
const uint32_t mantissa = value & 0x3ffu;
const float sign_mul = (sign != 0 ? -1.0f : 1.0f);
if (exponent == 0) {
if (mantissa == 0) {
return sign_mul * 0.0f;
}
return sign_mul * std::ldexp(static_cast<float>(mantissa), -24);
}
if (exponent == 0x1fu) {
return mantissa == 0 ? sign_mul * std::numeric_limits<float>::infinity()
: std::numeric_limits<float>::quiet_NaN();
}
return sign_mul *
std::ldexp(static_cast<float>(0x400u | mantissa), static_cast<int>(exponent) - 25);
}
[[maybe_unused]] static vk::ClearColorValue ColorClearValue(const HW::RenderTarget& rt) {
const uint32_t c0 = rt.clear_word0.word0;
const uint32_t c1 = rt.clear_word1.word1;
vk::ClearColorValue color {};
switch (static_cast<Prospero::ChannelType>(rt.info.channel_type)) {
case Prospero::ChannelType::kUNorm:
case Prospero::ChannelType::kSrgb:
// SRGB clear words are still encoded as normalized component values.
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
case Prospero::ChannelLayout::k8:
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k8_8:
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
color.float32[1] = ColorClearUnorm((c0 >> 8u) & 0xffu, 8);
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k8_8_8_8:
color.float32[0] = ColorClearUnorm(c0 & 0xffu, 8);
color.float32[1] = ColorClearUnorm((c0 >> 8u) & 0xffu, 8);
color.float32[2] = ColorClearUnorm((c0 >> 16u) & 0xffu, 8);
color.float32[3] = ColorClearUnorm((c0 >> 24u) & 0xffu, 8);
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.float32[0], color.float32[2]);
}
break;
case Prospero::ChannelLayout::k11_11_10:
color.float32[0] = 0.0f;
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k10_10_10_2:
color.float32[0] = ColorClearUnorm(c0 & 0x3ffu, 10);
color.float32[1] = ColorClearUnorm((c0 >> 10u) & 0x3ffu, 10);
color.float32[2] = ColorClearUnorm((c0 >> 20u) & 0x3ffu, 10);
color.float32[3] = ColorClearUnorm((c0 >> 30u) & 0x3u, 2);
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.float32[0], color.float32[2]);
}
break;
case Prospero::ChannelLayout::k16_16:
color.float32[0] = 0.0f;
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k32_32_32_32:
color.float32[0] = 0.0f;
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
default:
EXIT("%s\n unsupported color clear format\n",
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
}
break;
case Prospero::ChannelType::kSNorm:
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
case Prospero::ChannelLayout::k16_16:
color.float32[0] = ColorClearSnorm(c0 & 0xffffu, 16);
color.float32[1] = ColorClearSnorm((c0 >> 16u) & 0xffffu, 16);
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k8_8_8_8:
color.float32[0] = ColorClearSnorm(c0 & 0xffu, 8);
color.float32[1] = ColorClearSnorm((c0 >> 8u) & 0xffu, 8);
color.float32[2] = ColorClearSnorm((c0 >> 16u) & 0xffu, 8);
color.float32[3] = ColorClearSnorm((c0 >> 24u) & 0xffu, 8);
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.float32[0], color.float32[2]);
}
break;
default:
EXIT("%s\n unsupported snorm color clear format\n",
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
}
break;
case Prospero::ChannelType::kFloat:
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
case Prospero::ChannelLayout::k16:
color.float32[0] = ColorClearF16(c0 & 0xffffu);
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k16_16:
color.float32[0] = ColorClearF16(c0 & 0xffffu);
color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu);
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
case Prospero::ChannelLayout::k16_16_16_16:
color.float32[0] = ColorClearF16(c0 & 0xffffu);
color.float32[1] = ColorClearF16((c0 >> 16u) & 0xffffu);
color.float32[2] = ColorClearF16(c1 & 0xffffu);
color.float32[3] = ColorClearF16((c1 >> 16u) & 0xffffu);
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.float32[0], color.float32[2]);
}
break;
case Prospero::ChannelLayout::k32:
case Prospero::ChannelLayout::k11_11_10:
case Prospero::ChannelLayout::k32_32_32_32:
color.float32[0] = 0.0f;
color.float32[1] = 0.0f;
color.float32[2] = 0.0f;
color.float32[3] = 1.0f;
break;
default:
EXIT("%s\n unsupported float color clear format\n",
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
}
break;
case Prospero::ChannelType::kUInt:
case Prospero::ChannelType::kSInt:
switch (static_cast<Prospero::ChannelLayout>(rt.info.format)) {
case Prospero::ChannelLayout::k8:
color.uint32[0] = c0;
color.uint32[1] = 0;
color.uint32[2] = 0;
color.uint32[3] = 1;
break;
case Prospero::ChannelLayout::k16:
color.uint32[0] = c0 & 0xffffu;
color.uint32[1] = 0;
color.uint32[2] = 0;
color.uint32[3] = 1;
break;
case Prospero::ChannelLayout::k16_16:
color.uint32[0] = c0 & 0xffffu;
color.uint32[1] = (c0 >> 16u) & 0xffffu;
color.uint32[2] = 0;
color.uint32[3] = 1;
break;
case Prospero::ChannelLayout::k8_8_8_8:
color.uint32[0] = c0 & 0xffu;
color.uint32[1] = (c0 >> 8u) & 0xffu;
color.uint32[2] = (c0 >> 16u) & 0xffu;
color.uint32[3] = c0 >> 24u;
if (rt.info.channel_order ==
Prospero::GpuEnumValue(Prospero::ChannelOrder::kAlt)) {
std::swap(color.uint32[0], color.uint32[2]);
}
break;
case Prospero::ChannelLayout::k32_32:
color.uint32[0] = c0;
color.uint32[1] = c1;
color.uint32[2] = 0;
color.uint32[3] = 1;
break;
default:
EXIT("%s\n unsupported integer color clear format\n",
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
}
break;
default:
EXIT("%s\n unsupported color clear number type\n",
Common::Concat(rt_print("RenderTarget", rt), "").c_str());
}
EXIT_NOT_IMPLEMENTED(
c1 != 0 &&
!(rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kFloat) &&
rt.info.format == Prospero::GpuEnumValue(Prospero::ChannelLayout::k16_16_16_16)) &&
!((rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kUInt) ||
rt.info.channel_type == Prospero::GpuEnumValue(Prospero::ChannelType::kSInt)) &&
rt.info.format == Prospero::GpuEnumValue(Prospero::ChannelLayout::k32_32)));
return color;
}
static uint32_t RenderGetColorBpp(uint32_t dfmt) {
switch (static_cast<Prospero::ChannelLayout>(dfmt)) {
case Prospero::ChannelLayout::k8: return 8;
case Prospero::ChannelLayout::k16:
case Prospero::ChannelLayout::k8_8: return 16;
case Prospero::ChannelLayout::k32:
case Prospero::ChannelLayout::k16_16:
case Prospero::ChannelLayout::k11_11_10:
case Prospero::ChannelLayout::k10_10_10_2:
case Prospero::ChannelLayout::k8_8_8_8: return 32;
case Prospero::ChannelLayout::k32_32:
case Prospero::ChannelLayout::k16_16_16_16: return 64;
case Prospero::ChannelLayout::k32_32_32_32: return 128;
case Prospero::ChannelLayout::k5_5_5_1:
case Prospero::ChannelLayout::k4_4_4_4: return 16;
default: EXIT("unsupported render-target channel layout: %u\n", dfmt);
}
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderColorInfo* r, uint32_t render_target_slice_offset, RenderColorInfo* r, uint32_t render_target_slice_offset,
@@ -369,6 +119,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
// CB_COLOR_CONTROL describes the color-buffer operation / ROP3 logic op. // CB_COLOR_CONTROL describes the color-buffer operation / ROP3 logic op.
// ROP3 Copy is the normal color write path, not a render-target clear. // ROP3 Copy is the normal color write path, not a render-target clear.
// SRGB clear words are still encoded as normalized component values.
// Fast color clears are metadata driven and must be handled explicitly when // Fast color clears are metadata driven and must be handled explicitly when
// that metadata path is implemented; render-pass load must preserve contents. // that metadata path is implemented; render-pass load must preserve contents.
r->color_clear_enable = false; r->color_clear_enable = false;
@@ -394,9 +145,11 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
EXIT("linear mipmapped render targets are unsupported\n"); EXIT("linear mipmapped render targets are unsupported\n");
} }
width = rt.attrib2.width + 1; width = rt.attrib2.width + 1;
height = rt.attrib2.height + 1; height = rt.attrib2.height + 1;
const auto bytes_per_element = RenderGetColorBpp(rt.info.format) / 8u; const auto target_format =
TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type, rt.info.channel_order);
const auto bytes_per_element = target_format.bytes_per_element;
if (bytes_per_element == 0) { if (bytes_per_element == 0) {
EXIT("render-target format has no valid element size\n"); EXIT("render-target format has no valid element size\n");
} }
@@ -497,18 +250,15 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
} }
if (render_to_texture) { if (render_to_texture) {
const auto rt_format = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
rt.info.channel_order);
(void)reuse_existing_render_texture; (void)reuse_existing_render_texture;
RenderTargetInfo target {}; RenderTargetInfo target {};
target.address = rt.base.addr; target.address = rt.base.addr;
target.size = backing_size; target.size = backing_size;
target.format = rt_format.format; target.format = target_format.format;
target.width = width; target.width = width;
target.height = height; target.height = height;
target.pitch = pitch; target.pitch = pitch;
target.bytes_per_element = rt_format.bytes_per_element; target.bytes_per_element = target_format.bytes_per_element;
target.tile_mode = rt.attrib3.tile_mode; target.tile_mode = rt.attrib3.tile_mode;
target.levels = levels; target.levels = levels;
target.layers = view.image_layers; target.layers = view.image_layers;
@@ -525,7 +275,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
r->extent = view_extent; r->extent = view_extent;
r->base_mip_level = rt.view.current_mip_level; r->base_mip_level = rt.view.current_mip_level;
r->buffer_size = backing_size; r->buffer_size = backing_size;
r->export_mapping = rt_format.export_mapping; r->export_mapping = target_format.export_mapping;
} else { } else {
const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format); const auto layout = static_cast<Prospero::ChannelLayout>(rt.info.format);
const auto type = static_cast<Prospero::ChannelType>(rt.info.channel_type); const auto type = static_cast<Prospero::ChannelType>(rt.info.channel_type);
@@ -562,9 +312,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H
r->extent = video_image.image->extent; r->extent = video_image.image->extent;
r->base_mip_level = 0; r->base_mip_level = 0;
r->buffer_size = video_image.size; r->buffer_size = video_image.size;
r->export_mapping = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type, r->export_mapping = target_format.export_mapping;
rt.info.channel_order)
.export_mapping;
} }
} }
+103 -186
View File
@@ -10,19 +10,35 @@
#include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/descriptorCache.h" #include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/imageView.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/window.h" #include "graphics/presentation/window.h"
#include <algorithm> #include <algorithm>
#include <array>
#include <atomic> #include <atomic>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
namespace Libs::Graphics { namespace Libs::Graphics {
static std::atomic<uint64_t> g_command_buffer_submit_seq = 0; static std::atomic<uint64_t> g_command_buffer_submit_seq = 0;
static void RequireValidQueueId(int queue_id) {
EXIT_IF(queue_id < 0 || queue_id >= GraphicContext::QUEUES_NUM);
}
static void ResetNativeCommandBuffer(vk::CommandBuffer buffer) {
EXIT_IF(buffer == nullptr);
const auto result = buffer.reset(vk::CommandBufferResetFlagBits::eReleaseResources);
if (result != vk::Result::eSuccess) {
EXIT("failed to reset Vulkan command buffer: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result));
}
}
class CommandPool { class CommandPool {
public: public:
CommandPool() = default; CommandPool() = default;
@@ -34,18 +50,19 @@ public:
KYTY_CLASS_NO_COPY(CommandPool); KYTY_CLASS_NO_COPY(CommandPool);
VulkanCommandPool* GetPool(int id) { VulkanCommandPool* GetPool(int queue_id) {
if (m_pool[id] == nullptr) { RequireValidQueueId(queue_id);
Create(id); if (m_pools[queue_id] == nullptr) {
Create(queue_id);
} }
return m_pool[id]; return m_pools[queue_id];
} }
void DeleteAll(); void DeleteAll();
private: private:
void Create(int id); void Create(int queue_id);
VulkanCommandPool* m_pool[GraphicContext::QUEUES_NUM] = {}; std::array<VulkanCommandPool*, GraphicContext::QUEUES_NUM> m_pools {};
}; };
RenderContext* g_render_ctx = nullptr; RenderContext* g_render_ctx = nullptr;
@@ -90,28 +107,28 @@ void GraphicsRenderCreateContext() {
g_render_ctx->SetGraphicCtx(WindowGetGraphicContext()); g_render_ctx->SetGraphicCtx(WindowGetGraphicContext());
} }
void CommandPool::Create(int id) { void CommandPool::Create(int queue_id) {
auto* ctx = g_render_ctx->GetGraphicCtx(); RequireValidQueueId(queue_id);
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(id < 0 || id >= GraphicContext::QUEUES_NUM); auto* ctx = g_render_ctx->GetGraphicCtx();
auto*& pool = m_pool[id]; auto*& pool = m_pools[queue_id];
EXIT_IF(pool != nullptr); EXIT_IF(pool != nullptr);
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(ctx->device == nullptr);
EXIT_IF(ctx->queues[id].family == static_cast<uint32_t>(-1)); EXIT_IF(ctx->queues[queue_id].family == static_cast<uint32_t>(-1));
pool = new VulkanCommandPool; pool = new VulkanCommandPool;
vk::CommandPoolCreateInfo pool_info {}; vk::CommandPoolCreateInfo pool_info {};
pool_info.sType = vk::StructureType::eCommandPoolCreateInfo; pool_info.sType = vk::StructureType::eCommandPoolCreateInfo;
pool_info.pNext = nullptr; pool_info.pNext = nullptr;
pool_info.queueFamilyIndex = ctx->queues[id].family; pool_info.queueFamilyIndex = ctx->queues[queue_id].family;
pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer; pool_info.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool); const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr);
EXIT_NOT_IMPLEMENTED(pool->pool == nullptr);
pool->buffers_count = 8; pool->buffers_count = 8;
pool->buffers = std::make_unique<vk::CommandBuffer[]>(pool->buffers_count); pool->buffers = std::make_unique<vk::CommandBuffer[]>(pool->buffers_count);
@@ -162,7 +179,7 @@ void CommandPool::Create(int id) {
void CommandPool::DeleteAll() { void CommandPool::DeleteAll() {
auto* ctx = g_render_ctx->GetGraphicCtx(); auto* ctx = g_render_ctx->GetGraphicCtx();
for (auto& pool: m_pool) { for (auto& pool: m_pools) {
if (pool != nullptr) { if (pool != nullptr) {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(ctx->device == nullptr);
@@ -194,6 +211,14 @@ bool CommandBuffer::IsInvalid() const {
return true; return true;
} }
vk::CommandBuffer CommandBuffer::Handle() const {
EXIT_IF(IsInvalid());
const auto handle = m_pool->buffers[m_index];
EXIT_IF(handle == nullptr);
return handle;
}
void CommandBuffer::Allocate() { void CommandBuffer::Allocate() {
EXIT_IF(!IsInvalid()); EXIT_IF(!IsInvalid());
@@ -204,7 +229,7 @@ void CommandBuffer::Allocate() {
for (uint32_t i = 0; i < m_pool->buffers_count; i++) { for (uint32_t i = 0; i < m_pool->buffers_count; i++) {
if (!m_pool->busy[i]) { if (!m_pool->busy[i]) {
m_pool->busy[i] = true; m_pool->busy[i] = true;
m_pool->buffers[i].reset(vk::CommandBufferResetFlagBits::eReleaseResources); ResetNativeCommandBuffer(m_pool->buffers[i]);
m_index = i; m_index = i;
break; break;
} }
@@ -223,9 +248,8 @@ void CommandBuffer::Free() {
m_host_stream.Release(); m_host_stream.Release();
m_pool->busy[m_index] = false; m_pool->busy[m_index] = false;
m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources); ResetNativeCommandBuffer(m_pool->buffers[m_index]);
RecycleDescriptorsAfterFence(); ReleaseResourcesAfterFence();
m_fence_resources.ReleaseAfterFence();
m_index = static_cast<uint32_t>(-1); m_index = static_cast<uint32_t>(-1);
EXIT_NOT_IMPLEMENTED(!IsInvalid()); EXIT_NOT_IMPLEMENTED(!IsInvalid());
@@ -258,9 +282,7 @@ void CommandBuffer::RecycleDescriptorsAfterFence() {
} }
void CommandBuffer::Begin() const { void CommandBuffer::Begin() const {
EXIT_IF(IsInvalid()); auto buffer = Handle();
auto buffer = m_pool->buffers[m_index];
vk::CommandBufferBeginInfo begin_info {}; vk::CommandBufferBeginInfo begin_info {};
begin_info.sType = vk::StructureType::eCommandBufferBeginInfo; begin_info.sType = vk::StructureType::eCommandBufferBeginInfo;
@@ -274,9 +296,7 @@ void CommandBuffer::Begin() const {
} }
void CommandBuffer::End() const { void CommandBuffer::End() const {
EXIT_IF(IsInvalid()); auto buffer = Handle();
auto buffer = m_pool->buffers[m_index];
auto result = buffer.end(); auto result = buffer.end();
@@ -295,159 +315,48 @@ void CommandBuffer::SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0,
} }
void CommandBuffer::Execute() { void CommandBuffer::Execute() {
EXIT_IF(IsInvalid()); Submit(nullptr, {}, nullptr);
EXIT_IF(m_execute);
auto buffer = m_pool->buffers[m_index];
auto fence = m_pool->fences[m_index];
vk::SubmitInfo submit_info {};
submit_info.sType = vk::StructureType::eSubmitInfo;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
auto result = g_render_ctx->GetGraphicCtx()->device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
if (queue.mutex != nullptr) {
queue.mutex->Lock();
}
if (Config::GraphicsDebugDumpEnabled()) {
LOGF("vkQueueSubmit begin: queue=%d index=%u debug_op=%u debug_submit=%" PRIu64
" args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
m_queue, m_index, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1,
m_debug_arg2, m_debug_arg3, m_debug_arg4);
}
result = queue.vk_queue.submit(1, &submit_info, fence);
if (queue.mutex != nullptr) {
queue.mutex->Unlock();
}
m_execute = true;
m_fence_waited = false;
m_submit_seq = g_command_buffer_submit_seq.fetch_add(1, std::memory_order_relaxed) + 1;
if (result != vk::Result::eSuccess) {
LOGF("vkQueueSubmit failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
VulkanToString(result).c_str(), static_cast<int>(result), m_queue, m_index,
m_submit_seq, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2,
m_debug_arg3, m_debug_arg4);
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
} }
void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore signal_semaphore) { void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore signal_semaphore) {
EXIT_IF(IsInvalid()); Submit(nullptr, {}, ResolveSignalSemaphore(signal_semaphore));
EXIT_IF(m_execute);
auto buffer = m_pool->buffers[m_index];
auto fence = m_pool->fences[m_index];
if (signal_semaphore == nullptr) {
signal_semaphore = m_pool->semaphores[m_index];
}
vk::SubmitInfo submit_info {};
submit_info.sType = vk::StructureType::eSubmitInfo;
submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &signal_semaphore;
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
auto result = g_render_ctx->GetGraphicCtx()->device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result));
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
if (queue.mutex != nullptr) {
queue.mutex->Lock();
}
if (Config::GraphicsDebugDumpEnabled()) {
LOGF("vkQueueSubmit begin: queue=%d index=%u signal_semaphore=%p debug_op=%u"
" debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
m_queue, m_index, static_cast<void*>(signal_semaphore), m_debug_op, m_debug_submit_id,
m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3, m_debug_arg4);
}
result = queue.vk_queue.submit(1, &submit_info, fence);
if (queue.mutex != nullptr) {
queue.mutex->Unlock();
}
m_execute = true;
m_fence_waited = false;
m_submit_seq = g_command_buffer_submit_seq.fetch_add(1, std::memory_order_relaxed) + 1;
if (result != vk::Result::eSuccess) {
LOGF("vkQueueSubmit failed: %s (%d), queue=%d index=%u submit_seq=%" PRIu64
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
VulkanToString(result).c_str(), static_cast<int>(result), m_queue, m_index,
m_submit_seq, m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2,
m_debug_arg3, m_debug_arg4);
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
} }
void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore, void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore,
vk::PipelineStageFlags wait_stage, vk::PipelineStageFlags wait_stage,
vk::Semaphore signal_semaphore) { vk::Semaphore signal_semaphore) {
EXIT_IF(wait_semaphore == nullptr);
Submit(wait_semaphore, wait_stage, ResolveSignalSemaphore(signal_semaphore));
}
void CommandBuffer::Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags wait_stage,
vk::Semaphore signal_semaphore) {
RequireValidQueueId(m_queue);
EXIT_IF(IsInvalid()); EXIT_IF(IsInvalid());
EXIT_IF(m_execute); EXIT_IF(m_execute);
EXIT_IF(wait_semaphore == nullptr);
auto buffer = m_pool->buffers[m_index]; const bool has_wait = wait_semaphore != nullptr;
auto fence = m_pool->fences[m_index]; const bool has_signal = signal_semaphore != nullptr;
auto buffer = Handle();
if (signal_semaphore == nullptr) { auto fence = m_pool->fences[m_index];
signal_semaphore = m_pool->semaphores[m_index];
}
vk::SubmitInfo submit_info {}; vk::SubmitInfo submit_info {};
submit_info.sType = vk::StructureType::eSubmitInfo; submit_info.sType = vk::StructureType::eSubmitInfo;
submit_info.pNext = nullptr; submit_info.pNext = nullptr;
submit_info.waitSemaphoreCount = 1; submit_info.waitSemaphoreCount = has_wait ? 1u : 0u;
submit_info.pWaitSemaphores = &wait_semaphore; submit_info.pWaitSemaphores = has_wait ? &wait_semaphore : nullptr;
submit_info.pWaitDstStageMask = &wait_stage; submit_info.pWaitDstStageMask = has_wait ? &wait_stage : nullptr;
submit_info.commandBufferCount = 1; submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &buffer; submit_info.pCommandBuffers = &buffer;
submit_info.signalSemaphoreCount = 1; submit_info.signalSemaphoreCount = has_signal ? 1u : 0u;
submit_info.pSignalSemaphores = &signal_semaphore; submit_info.pSignalSemaphores = has_signal ? &signal_semaphore : nullptr;
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM); auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
const auto& queue = ctx->queues[m_queue];
const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue]; auto result = ctx->device.resetFences(1, &fence);
auto result = g_render_ctx->GetGraphicCtx()->device.resetFences(1, &fence);
if (result != vk::Result::eSuccess) { if (result != vk::Result::eSuccess) {
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(), LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
static_cast<int>(result)); static_cast<int>(result));
@@ -486,20 +395,16 @@ void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore,
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
} }
vk::Semaphore CommandBuffer::ResolveSignalSemaphore(vk::Semaphore semaphore) const {
if (semaphore != nullptr) {
return semaphore;
}
EXIT_IF(IsInvalid());
return m_pool->semaphores[m_index];
}
void CommandBuffer::WaitForFence() { void CommandBuffer::WaitForFence() {
const bool was_executed = m_execute; FinalizeFence(false);
WaitForFenceOnly();
if (was_executed) {
m_execute = false;
m_fence_waited = false;
RecycleDescriptorsAfterFence();
m_fence_resources.ReleaseAfterFence();
}
for (auto* buffer: m_delete_after_fence) {
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
delete buffer;
}
m_delete_after_fence.clear();
} }
void CommandBuffer::WaitForFenceOnly() { void CommandBuffer::WaitForFenceOnly() {
@@ -521,19 +426,35 @@ void CommandBuffer::WaitForFenceOnly() {
} }
void CommandBuffer::WaitForFenceAndReset() { void CommandBuffer::WaitForFenceAndReset() {
FinalizeFence(true);
}
void CommandBuffer::FinalizeFence(bool reset_recording) {
const bool was_executed = m_execute; const bool was_executed = m_execute;
WaitForFenceOnly(); WaitForFenceOnly();
if (was_executed) { if (was_executed) {
m_execute = false; m_execute = false;
m_fence_waited = false; m_fence_waited = false;
m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources); if (reset_recording) {
m_recording_generation++; ResetNativeCommandBuffer(m_pool->buffers[m_index]);
m_recording_generation++;
}
}
if (reset_recording) {
m_host_stream.Reset();
} }
m_host_stream.Reset();
if (was_executed) { if (was_executed) {
RecycleDescriptorsAfterFence(); ReleaseResourcesAfterFence();
m_fence_resources.ReleaseAfterFence();
} }
DeleteBuffersAfterFence();
}
void CommandBuffer::ReleaseResourcesAfterFence() {
RecycleDescriptorsAfterFence();
m_fence_resources.ReleaseAfterFence();
}
void CommandBuffer::DeleteBuffersAfterFence() {
for (auto* buffer: m_delete_after_fence) { for (auto* buffer: m_delete_after_fence) {
VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer); VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer);
delete buffer; delete buffer;
@@ -543,9 +464,7 @@ void CommandBuffer::WaitForFenceAndReset() {
void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors,
uint32_t requested_color_count, RenderDepthInfo* depth) const { uint32_t requested_color_count, RenderDepthInfo* depth) const {
EXIT_IF(IsInvalid()); auto buffer = Handle();
auto buffer = m_pool->buffers[m_index];
EXIT_IF(framebuffer == nullptr); EXIT_IF(framebuffer == nullptr);
EXIT_IF(colors == nullptr); EXIT_IF(colors == nullptr);
@@ -643,7 +562,7 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = depth->vulkan_buffer->image; image_memory_barrier.image = depth->vulkan_buffer->image;
image_memory_barrier.subresourceRange.aspectMask = image_memory_barrier.subresourceRange.aspectMask =
DepthStencilAspectMask(depth->vulkan_buffer->format); ImageViewOps::DepthAspectMask(depth->vulkan_buffer->format);
image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = 1; image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.baseArrayLayer = 0;
@@ -665,9 +584,7 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI
} }
void CommandBuffer::EndRenderPass() const { void CommandBuffer::EndRenderPass() const {
EXIT_IF(IsInvalid()); auto buffer = Handle();
auto buffer = m_pool->buffers[m_index];
buffer.endRenderPass(); buffer.endRenderPass();
} }
@@ -16,7 +16,7 @@
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/displayBuffer.h" #include "graphics/presentation/displayBuffer.h"
@@ -102,15 +102,10 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi
} // namespace } // namespace
void DescriptorCache::Init() {
m_initialized = true;
}
vk::DescriptorSetLayout vk::DescriptorSetLayout
DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage,
const ShaderRecompiler::IR::Program& program) { const ShaderRecompiler::IR::Program& program) {
EXIT_IF(gctx == nullptr); EXIT_IF(gctx == nullptr);
Init();
const auto key = LayoutKey(stage, program); const auto key = LayoutKey(stage, program);
if (const auto found = m_descriptor_set_layouts.find(key); if (const auto found = m_descriptor_set_layouts.find(key);
found != m_descriptor_set_layouts.end()) { found != m_descriptor_set_layouts.end()) {
@@ -132,8 +127,8 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag
info.bindingCount = static_cast<uint32_t>(bindings.size()); info.bindingCount = static_cast<uint32_t>(bindings.size());
info.pBindings = bindings.data(); info.pBindings = bindings.data();
vk::DescriptorSetLayout layout = nullptr; vk::DescriptorSetLayout layout = nullptr;
gctx->device.createDescriptorSetLayout(&info, nullptr, &layout); const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout);
EXIT_NOT_IMPLEMENTED(layout == nullptr); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr);
m_descriptor_set_layouts.emplace(key, layout); m_descriptor_set_layouts.emplace(key, layout);
return layout; return layout;
} }
@@ -157,8 +152,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) {
info.maxSets = MaxSets; info.maxSets = MaxSets;
const auto pool_id = static_cast<int>(m_pools.size()); const auto pool_id = static_cast<int>(m_pools.size());
auto& pool = m_pools.emplace_back(); auto& pool = m_pools.emplace_back();
gctx->device.createDescriptorPool(&info, nullptr, &pool.pool); const auto result = gctx->device.createDescriptorPool(&info, nullptr, &pool.pool);
EXIT_NOT_IMPLEMENTED(pool.pool == nullptr); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr);
pool.next_free_pool = m_first_free_pool; pool.next_free_pool = m_first_free_pool;
m_first_free_pool = pool_id; m_first_free_pool = pool_id;
} }
@@ -198,7 +193,6 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage
} }
return new VulkanDescriptorSet {sets.back(), layout, pool_id}; return new VulkanDescriptorSet {sets.back(), layout, pool_id};
} }
pool.free = false;
m_first_free_pool = pool.next_free_pool; m_first_free_pool = pool.next_free_pool;
break; break;
} }
@@ -22,10 +22,6 @@ struct Program;
class CommandBuffer; class CommandBuffer;
struct ShaderStageRuntime; struct ShaderStageRuntime;
struct VulkanDescriptor {
vk::DescriptorSet descriptor_set = nullptr;
};
struct VulkanDescriptorSet { struct VulkanDescriptorSet {
vk::DescriptorSet set = nullptr; vk::DescriptorSet set = nullptr;
vk::DescriptorSetLayout layout = nullptr; vk::DescriptorSetLayout layout = nullptr;
@@ -38,12 +34,6 @@ struct BufferView {
vk::DeviceSize range = VK_WHOLE_SIZE; vk::DeviceSize range = VK_WHOLE_SIZE;
}; };
struct ShaderAddressWriteRange {
VulkanBuffer* buffer = nullptr;
uint64_t address = 0;
uint64_t size = 0;
};
class DescriptorCache { class DescriptorCache {
public: public:
enum class Stage { Unknown, Vertex, Pixel, Compute }; enum class Stage { Unknown, Vertex, Pixel, Compute };
@@ -74,7 +64,7 @@ public:
}; };
DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; } ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(DescriptorCache); KYTY_CLASS_NO_COPY(DescriptorCache);
vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage, vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage,
@@ -87,10 +77,8 @@ private:
struct Pool { struct Pool {
vk::DescriptorPool pool = nullptr; vk::DescriptorPool pool = nullptr;
int next_free_pool = -1; int next_free_pool = -1;
bool free = true;
}; };
void Init();
void CreatePool(GraphicContext* gctx); void CreatePool(GraphicContext* gctx);
VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program); VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program);
vk::DescriptorSetLayout vk::DescriptorSetLayout
@@ -103,17 +91,12 @@ private:
std::unordered_map<vk::DescriptorSetLayout, std::vector<VulkanDescriptorSet*>> std::unordered_map<vk::DescriptorSetLayout, std::vector<VulkanDescriptorSet*>>
m_free_sets_by_layout; m_free_sets_by_layout;
std::map<std::vector<uint32_t>, vk::DescriptorSetLayout> m_descriptor_set_layouts; std::map<std::vector<uint32_t>, vk::DescriptorSetLayout> m_descriptor_set_layouts;
bool m_initialized = false;
}; };
const char* storage_usage_name(ShaderStorageUsage usage); void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format); vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
vk::PipelineBindPoint pipeline_bind_point, DescriptorCache::Stage stage);
vk::PipelineLayout layout,
const ShaderStageRuntime& runtime,
vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+24 -56
View File
@@ -23,7 +23,7 @@
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/renderTargetBarriers.h" #include "graphics/host_gpu/renderer/renderTargetBarriers.h"
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h" #include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/displayBuffer.h" #include "graphics/presentation/displayBuffer.h"
@@ -34,9 +34,9 @@
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
#include <cstring>
#include <fmt/format.h> #include <fmt/format.h>
#include <limits> #include <limits>
#include <span>
#ifdef min #ifdef min
#undef min #undef min
@@ -71,14 +71,6 @@ static const char* VulkanImageTypeName(VulkanImageType type) {
} }
} }
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format) {
auto ret = static_cast<vk::ImageAspectFlags>(vk::ImageAspectFlagBits::eDepth);
if (format == vk::Format::eD24UnormS8Uint || format == vk::Format::eD32SfloatS8Uint) {
ret |= vk::ImageAspectFlagBits::eStencil;
}
return ret;
}
static int SampledArrayViewIndex(const VulkanImage* image, int view_index) { static int SampledArrayViewIndex(const VulkanImage* image, int view_index) {
EXIT_IF(image == nullptr); EXIT_IF(image == nullptr);
@@ -126,25 +118,10 @@ static VulkanImage* GetDummyStorageTexture(TextureVariant variant) {
TextureVariantIs3D(variant)); TextureVariantIs3D(variant));
} }
static ShaderBufferResource static void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source,
NativeBufferDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) { std::span<uint32_t> destination) {
ShaderBufferResource result; EXIT_IF(source.dword_count != destination.size());
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields); std::copy_n(source.dwords.begin(), destination.size(), destination.begin());
return result;
}
static ShaderTextureResource
NativeTextureDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) {
ShaderTextureResource result;
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
return result;
}
static ShaderSamplerResource
NativeSamplerDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) {
ShaderSamplerResource result;
std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
return result;
} }
static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer, static BufferView NativeStorageBuffer(uint64_t submit_id, CommandBuffer* command_buffer,
@@ -505,10 +482,11 @@ static DescriptorCache::TextureBinding
NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer, NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
const ShaderRecompiler::IR::ImageResource& resource, const ShaderRecompiler::IR::ImageResource& resource,
const ShaderRecompiler::IR::DescriptorValue& value) { const ShaderRecompiler::IR::DescriptorValue& value) {
auto descriptor = NativeTextureDescriptor(value); ShaderTextureResource descriptor;
const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage || CopyNativeDescriptor(value, descriptor.fields);
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage ||
const auto variant = NativeTextureVariant(resource); resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
const auto variant = NativeTextureVariant(resource);
if (storage) { if (storage) {
ValidateStorageImageResource(resource); ValidateStorageImageResource(resource);
} }
@@ -542,8 +520,7 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n", EXIT("sampled image numeric class mismatch: kind=%u format=%u addr=0x%016" PRIx64 "\n",
static_cast<uint32_t>(resource.kind), format, address); static_cast<uint32_t>(resource.kind), format, address);
} }
const auto view_format = TextureGetFormat(format, storage ? TextureFormatUsage::Storage const auto view_format = TextureGetFormat(format);
: TextureFormatUsage::Sampled);
const auto type = static_cast<Prospero::ImageType>(descriptor.Type()); const auto type = static_cast<Prospero::ImageType>(descriptor.Type());
const auto target_view = const auto target_view =
ResolveTargetTextureView(resource, type, descriptor.BaseArray5(), depth); ResolveTargetTextureView(resource, type, descriptor.BaseArray5(), depth);
@@ -754,7 +731,8 @@ NativeTexture(uint64_t submit_id, CommandBuffer* command_buffer,
static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, uint32_t index, static vk::Sampler NativeSampler(const ShaderRecompiler::IR::Program& program, uint32_t index,
const ShaderRecompiler::IR::DescriptorValue& value) { const ShaderRecompiler::IR::DescriptorValue& value) {
auto descriptor = NativeSamplerDescriptor(value); ShaderSamplerResource descriptor;
CopyNativeDescriptor(value, descriptor.fields);
const bool depth_compare = std::any_of(program.info.sampled_pairs.begin(), const bool depth_compare = std::any_of(program.info.sampled_pairs.begin(),
program.info.sampled_pairs.end(), [&](const auto& pair) { program.info.sampled_pairs.end(), [&](const auto& pair) {
return pair.sampler == index && return pair.sampler == index &&
@@ -776,12 +754,10 @@ static BufferView NativeUpload(CommandBuffer* command_buffer, std::span<const ui
return result; return result;
} }
std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer,
vk::PipelineBindPoint pipeline_bind_point, vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout,
vk::PipelineLayout layout, const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage,
const ShaderStageRuntime& runtime, DescriptorCache::Stage stage) {
vk::ShaderStageFlags vk_stage,
DescriptorCache::Stage stage) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer == nullptr || !runtime); EXIT_IF(buffer == nullptr || !runtime);
const auto& program = *runtime.program; const auto& program = *runtime.program;
@@ -790,15 +766,16 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) { if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) {
EXIT("invalid native shader runtime snapshot: %s\n", error.c_str()); EXIT("invalid native shader runtime snapshot: %s\n", error.c_str());
} }
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
const auto shader_stages = ShaderPipelineStages(vk_stage); const auto shader_stages = ShaderPipelineStages(vk_stage);
DescriptorCache::NativeDescriptors descriptors; DescriptorCache::NativeDescriptors descriptors;
descriptors.buffers.reserve(program.info.buffers.size()); descriptors.buffers.reserve(program.info.buffers.size());
for (uint32_t i = 0; i < program.info.buffers.size(); i++) { for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
ShaderBufferResource descriptor;
CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields);
descriptors.buffers.push_back( descriptors.buffers.push_back(
NativeStorageBuffer(submit_id, buffer, NativeBufferDescriptor(snapshot.buffers[i]), NativeStorageBuffer(submit_id, buffer, descriptor, program.info.buffers[i]));
program.info.buffers[i]));
} }
descriptors.images.reserve(program.info.images.size()); descriptors.images.reserve(program.info.images.size());
for (uint32_t i = 0; i < program.info.images.size(); i++) { for (uint32_t i = 0; i < program.info.images.size(); i++) {
@@ -816,17 +793,9 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
descriptors.samplers.push_back(NativeSampler(program, i, snapshot.samplers[i])); descriptors.samplers.push_back(NativeSampler(program, i, snapshot.samplers[i]));
} }
descriptors.addresses.reserve(program.info.addresses.size()); descriptors.addresses.reserve(program.info.addresses.size());
std::vector<ShaderAddressWriteRange> address_writes;
for (uint32_t i = 0; i < program.info.addresses.size(); i++) { for (uint32_t i = 0; i < program.info.addresses.size(); i++) {
auto view = NativeAddressBuffer(submit_id, buffer, program.info.addresses[i], descriptors.addresses.push_back(NativeAddressBuffer(
snapshot.addresses[i]); submit_id, buffer, program.info.addresses[i], snapshot.addresses[i]));
descriptors.addresses.push_back(view);
if (program.info.addresses[i].written && snapshot.addresses[i].binding_base != 0) {
EXIT_IF(view.buffer == nullptr || view.offset != 0 || view.range == VK_WHOLE_SIZE ||
view.range == 0);
address_writes.push_back({view.buffer, snapshot.addresses[i].binding_base,
static_cast<uint64_t>(view.range)});
}
} }
if (ShaderRecompiler::IR::FindBinding( if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) !=
@@ -893,7 +862,6 @@ std::vector<ShaderAddressWriteRange> BindDescriptors(uint64_t submit_id, Command
vk_buffer.pushConstants(layout, vk_stage, program.bindings.push_constant_offset, vk_buffer.pushConstants(layout, vk_stage, program.bindings.push_constant_offset,
program.bindings.push_constant_size, user_data.data()); program.bindings.push_constant_size, user_data.data());
} }
return address_writes;
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -1,16 +1,29 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_ #ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_DESCRIPTORS_H_
#include "common/assert.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/shader/recompiler/ShaderIR.h" #include "graphics/shader/recompiler/ShaderIR.h"
#include "graphics/shader/shaderBindings.h" #include "graphics/shader/shaderBindings.h"
#include <cstdint> #include <cstdint>
#include <cstring>
#include <type_traits>
namespace Libs::Graphics { namespace Libs::Graphics {
struct VulkanImage; struct VulkanImage;
template <typename T>
[[nodiscard]] T DecodeNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& value) {
static_assert(std::is_trivially_copyable_v<T>);
static_assert(sizeof(T) % sizeof(uint32_t) == 0);
T result {};
EXIT_IF(value.dword_count < sizeof(result) / sizeof(uint32_t));
std::memcpy(&result, value.dwords.data(), sizeof(result));
return result;
}
struct TargetTextureViewInfo { struct TargetTextureViewInfo {
vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM); vk::ImageViewType type = static_cast<vk::ImageViewType>(VK_IMAGE_VIEW_TYPE_MAX_ENUM);
uint32_t base_layer = 0; uint32_t base_layer = 0;
@@ -2,7 +2,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "graphics/host_gpu/renderer/image.h" #include "graphics/host_gpu/renderer/image.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -20,11 +20,11 @@ DummyTextureCache::~DummyTextureCache() {
return; return;
} }
VulkanDeviceWaitIdle(m_ctx); Transfer::WaitForGraphicsIdle(m_ctx);
const auto destroy = [this](auto& slots) { const auto destroy = [this](auto& slots) {
for (auto& slot: slots) { for (auto& slot: slots) {
if (slot.image != nullptr) { if (slot.image != nullptr) {
ImageOps::Destroy(m_ctx, slot.image, &slot.memory); ImageOps::Destroy(m_ctx, slot.image);
slot.image = nullptr; slot.image = nullptr;
} }
} }
@@ -49,8 +49,8 @@ VulkanImage* DummyTextureCache::Get(GraphicContext* ctx, Usage usage, bool uint_
auto& slots = usage == Usage::Storage ? m_storage : m_sampled; auto& slots = usage == Usage::Storage ? m_storage : m_sampled;
auto& slot = slots[DummyTextureIndex(uint_format, image_3d)]; auto& slot = slots[DummyTextureIndex(uint_format, image_3d)];
if (slot.image == nullptr) { if (slot.image == nullptr) {
slot.image = ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, slot.image =
usage == Usage::Storage, &slot.memory); ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage);
} }
return slot.image; return slot.image;
} }
@@ -24,7 +24,6 @@ public:
private: private:
struct Slot { struct Slot {
GpuTextureVulkanImage* image = nullptr; GpuTextureVulkanImage* image = nullptr;
VulkanMemory memory {};
}; };
Common::Mutex m_mutex; Common::Mutex m_mutex;
@@ -6,7 +6,6 @@
#include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "graphics/host_gpu/renderer/colorRenderTarget.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include <algorithm> #include <algorithm>
@@ -108,6 +107,19 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
} }
} }
if (!with_depth && color_count == 0) {
LOGF("Framebuffer: warning: no color or depth attachment\n");
return nullptr;
}
EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height));
if (first_color == nullptr) {
first_color_extent = depth->vulkan_buffer->extent;
}
auto* framebuffer = new VulkanFramebuffer; auto* framebuffer = new VulkanFramebuffer;
framebuffer->render_pass = nullptr; framebuffer->render_pass = nullptr;
framebuffer->framebuffer = nullptr; framebuffer->framebuffer = nullptr;
@@ -120,23 +132,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors,
EXIT_IF(gctx == nullptr); EXIT_IF(gctx == nullptr);
if (!with_depth && color_count == 0) {
LOGF("Framebuffer: warning: no color or depth attachment\n");
return nullptr;
}
EXIT_NOT_IMPLEMENTED(!with_depth && color_count == 0);
EXIT_NOT_IMPLEMENTED(with_depth && first_color != nullptr &&
(first_color_extent.width != depth->vulkan_buffer->extent.width ||
first_color_extent.height != depth->vulkan_buffer->extent.height));
if (first_color == nullptr) {
first_color =
CreateDummyBuffer(vk::Format::eB8G8R8A8Srgb, depth->vulkan_buffer->extent.width,
depth->vulkan_buffer->extent.height);
first_color_extent = first_color->extent;
}
vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {}; vk::AttachmentDescription attachments[RENDER_COLOR_ATTACHMENTS_MAX + 1] = {};
for (uint32_t i = 0; i < color_count; i++) { for (uint32_t i = 0; i < color_count; i++) {
attachments[i].flags = {}; attachments[i].flags = {};
@@ -355,81 +350,4 @@ void FramebufferCache::FreeFramebufferByDepth(DepthStencilVulkanImage* image) {
} }
} }
VideoOutVulkanImage* FramebufferCache::CreateDummyBuffer(vk::Format format, uint32_t width,
uint32_t height) {
for (auto* b: m_dummy_buffers) {
if (b->extent.width == width && b->extent.height == height && b->format == format) {
return b;
}
}
auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(ctx == nullptr);
auto* vk_obj = new VideoOutVulkanImage;
vk_obj->extent.width = width;
vk_obj->extent.height = height;
vk_obj->format = format;
vk_obj->image = nullptr;
vk_obj->layout = vk::ImageLayout::eUndefined;
UtilResetImageViews(vk_obj);
vk::ImageCreateInfo image_info {};
image_info.sType = vk::StructureType::eImageCreateInfo;
image_info.pNext = nullptr;
image_info.flags = {};
image_info.imageType = vk::ImageType::e2D;
image_info.extent.width = vk_obj->extent.width;
image_info.extent.height = vk_obj->extent.height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = vk_obj->format;
image_info.tiling = vk::ImageTiling::eOptimal;
image_info.initialLayout = vk_obj->layout;
image_info.usage = vk::ImageUsageFlagBits::eColorAttachment;
image_info.sharingMode = vk::SharingMode::eExclusive;
image_info.samples = vk::SampleCountFlagBits::e1;
VulkanMemory mem;
mem.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
bool created = VulkanCreateImage(ctx, &image_info, vk_obj, &mem);
EXIT_NOT_IMPLEMENTED(!created);
vk_obj->memory = mem;
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = nullptr;
create_info.flags = {};
create_info.image = vk_obj->image;
create_info.viewType = vk::ImageViewType::e2D;
create_info.format = vk_obj->format;
create_info.components.r = vk::ComponentSwizzle::eIdentity;
create_info.components.g = vk::ComponentSwizzle::eIdentity;
create_info.components.b = vk::ComponentSwizzle::eIdentity;
create_info.components.a = vk::ComponentSwizzle::eIdentity;
create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
create_info.subresourceRange.baseArrayLayer = 0;
create_info.subresourceRange.baseMipLevel = 0;
create_info.subresourceRange.layerCount = 1;
create_info.subresourceRange.levelCount = 1;
ctx->device.createImageView(&create_info, nullptr,
&vk_obj->image_view[VulkanImage::VIEW_DEFAULT]);
EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT] == nullptr);
UtilSetImageLayoutOptimal(vk_obj);
m_dummy_buffers.push_back(vk_obj);
return vk_obj;
}
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -50,7 +50,7 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co
class FramebufferCache { class FramebufferCache {
public: public:
FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; } ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FramebufferCache); KYTY_CLASS_NO_COPY(FramebufferCache);
VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count, VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count,
@@ -59,8 +59,6 @@ public:
void FreeFramebufferByDepth(DepthStencilVulkanImage* image); void FreeFramebufferByDepth(DepthStencilVulkanImage* image);
private: private:
VideoOutVulkanImage* CreateDummyBuffer(vk::Format format, uint32_t width, uint32_t height);
struct Framebuffer { struct Framebuffer {
VulkanFramebuffer* framebuffer = nullptr; VulkanFramebuffer* framebuffer = nullptr;
uint64_t image_id[RENDER_COLOR_ATTACHMENTS_MAX] = {}; uint64_t image_id[RENDER_COLOR_ATTACHMENTS_MAX] = {};
@@ -74,9 +72,8 @@ private:
bool depth_read_only = false; bool depth_read_only = false;
}; };
Common::Mutex m_mutex; Common::Mutex m_mutex;
std::vector<Framebuffer> m_framebuffers; std::vector<Framebuffer> m_framebuffers;
std::vector<VideoOutVulkanImage*> m_dummy_buffers;
}; };
} // namespace Libs::Graphics } // namespace Libs::Graphics
+1 -1
View File
@@ -1,7 +1,7 @@
#include "graphics/host_gpu/renderer/gdsBuffer.h" #include "graphics/host_gpu/renderer/gdsBuffer.h"
#include "common/assert.h" #include "common/assert.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
namespace Libs::Graphics { namespace Libs::Graphics {
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Libs::Graphics {
class GdsBuffer { class GdsBuffer {
public: public:
GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; } ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(GdsBuffer); KYTY_CLASS_NO_COPY(GdsBuffer);
void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value); void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value);
+85 -114
View File
@@ -10,7 +10,8 @@
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/imageView.h" #include "graphics/host_gpu/renderer/imageView.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h"
#include "graphics/shader/shader.h" #include "graphics/shader/shader.h"
#include <algorithm> #include <algorithm>
@@ -40,7 +41,7 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) {
params.image_layout = TextureUploadDestination::MipLevels; params.image_layout = TextureUploadDestination::MipLevels;
params.allow_cube_view = !storage; params.allow_cube_view = !storage;
params.compatible_format_views = params.compatible_format_views =
storage && (IsRgba8SrgbViewFormat(TextureGetFormat(info.format, params.format_usage)) || storage && (IsRgba8SrgbViewFormat(TextureGetFormat(info.format)) ||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) || info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)); info.format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float));
params.owner = storage ? "StorageTextureCache" : "TextureCache"; params.owner = storage ? "StorageTextureCache" : "TextureCache";
@@ -140,13 +141,13 @@ uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element) {
} }
GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage, GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, bool storage,
VulkanMemory* memory, vk::ComponentMapping* components) { vk::ComponentMapping* components) {
if (components == nullptr) { if (components == nullptr) {
EXIT("TextureCache: invalid texture component output\n"); EXIT("TextureCache: invalid texture component output\n");
} }
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage) auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage; : new TextureVulkanImage;
*components = TextureCreateImage(ctx, image, memory, MakeImageParams(info, storage)); *components = TextureCreateImage(ctx, image, MakeImageParams(info, storage));
return image; return image;
} }
@@ -172,7 +173,7 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size); base_layer, layer_count, info.layers, image != nullptr ? image->layers : 0, info.size);
} }
if (refresh) { if (refresh) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
const auto slice_size = info.size / info.layers; const auto slice_size = info.size / info.layers;
const auto upload_size = slice_size * layer_count; const auto upload_size = slice_size * layer_count;
@@ -204,16 +205,16 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima
return; return;
} }
if (info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && if (info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
UtilBufferIsTiled(info.address, slice_size)) { Transfer::GuestBufferIsTiled(info.address, slice_size)) {
UtilScratchBuffer scratch(slice_size); Transfer::ScratchBuffer scratch(slice_size);
TileConvertTiledToLinearRenderTarget( TileConvertTiledToLinearRenderTarget(
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height, scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
info.pitch, info.bytes_per_element, slice_size); info.pitch, info.bytes_per_element, slice_size);
UtilFillImage(ctx, image, scratch.Data(), slice_size, info.pitch, Transfer::UploadImage(ctx, image, scratch.Data(), slice_size, info.pitch,
vk::ImageLayout::eGeneral); vk::ImageLayout::eGeneral);
} else { } else {
UtilFillImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size, Transfer::UploadImage(ctx, image, reinterpret_cast<const void*>(info.address), slice_size,
info.pitch, vk::ImageLayout::eGeneral); info.pitch, vk::ImageLayout::eGeneral);
} }
} }
@@ -222,8 +223,7 @@ void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh); UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh);
} }
RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info, RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) {
VulkanMemory* memory) {
auto* image = new RenderTextureVulkanImage; auto* image = new RenderTextureVulkanImage;
image->extent.width = info.width; image->extent.width = info.width;
image->extent.height = info.height; image->extent.height = info.height;
@@ -231,33 +231,30 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa
image->mip_levels = info.levels; image->mip_levels = info.levels;
image->layers = info.layers; image->layers = info.layers;
image->layout = vk::ImageLayout::eUndefined; image->layout = vk::ImageLayout::eUndefined;
UtilResetImageViews(image);
vk::ImageCreateInfo create {}; vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo; create.sType = vk::StructureType::eImageCreateInfo;
create.flags = RenderTargetCreateFlags(info.format); create.flags = RenderTargetCreateFlags(info.format);
create.imageType = vk::ImageType::e2D; create.imageType = vk::ImageType::e2D;
create.extent = {info.width, info.height, 1}; create.extent = {info.width, info.height, 1};
create.mipLevels = info.levels; create.mipLevels = info.levels;
create.arrayLayers = info.layers; create.arrayLayers = info.layers;
create.format = info.format; create.format = info.format;
create.tiling = vk::ImageTiling::eOptimal; create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined; create.initialLayout = vk::ImageLayout::eUndefined;
create.usage = RenderTargetUsage(ctx, info.format, create.flags); create.usage = RenderTargetUsage(ctx, info.format, create.flags);
create.sharingMode = vk::SharingMode::eExclusive; create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1; create.samples = vk::SampleCountFlagBits::e1;
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, &create, image, memory)) { if (!VulkanCreateImage(ctx, create, image)) {
EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64 EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
image->memory = *memory;
ImageViewOps::CreateRenderTargetViews(ctx, image); ImageViewOps::CreateRenderTargetViews(ctx, image);
return image; return image;
} }
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) {
VulkanMemory* memory) {
vk::ImageCreateInfo create {}; vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo; create.sType = vk::StructureType::eImageCreateInfo;
create.imageType = vk::ImageType::e2D; create.imageType = vk::ImageType::e2D;
@@ -278,22 +275,20 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
static_cast<int>(info.format), static_cast<int>(info.format),
static_cast<vk::ImageUsageFlags::MaskType>(create.usage)); static_cast<vk::ImageUsageFlags::MaskType>(create.usage));
} }
auto* image = new DepthStencilVulkanImage; auto* image = new DepthStencilVulkanImage;
image->extent.width = info.width; image->extent.width = info.width;
image->extent.height = info.height; image->extent.height = info.height;
image->guest_pitch = info.pitch; image->guest_pitch = info.pitch;
image->layers = info.layers; image->layers = info.layers;
image->format = info.format; image->format = info.format;
image->layout = vk::ImageLayout::eUndefined; image->layout = vk::ImageLayout::eUndefined;
image->compressed = false; image->compressed = false;
UtilResetImageViews(image); image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; if (!VulkanCreateImage(ctx, create, image)) {
if (!VulkanCreateImage(ctx, &create, image, memory)) {
EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64 EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
image->memory = *memory;
ImageViewOps::CreateDepthViews(ctx, image); ImageViewOps::CreateDepthViews(ctx, image);
return image; return image;
} }
@@ -334,34 +329,31 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
(void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {}); (void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {});
} }
VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info, VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) {
VulkanMemory* memory) {
auto* image = new VideoOutVulkanImage; auto* image = new VideoOutVulkanImage;
image->extent.width = info.width; image->extent.width = info.width;
image->extent.height = info.height; image->extent.height = info.height;
image->format = info.format; image->format = info.format;
image->layout = vk::ImageLayout::eUndefined; image->layout = vk::ImageLayout::eUndefined;
UtilResetImageViews(image);
vk::ImageCreateInfo create {}; vk::ImageCreateInfo create {};
create.sType = vk::StructureType::eImageCreateInfo; create.sType = vk::StructureType::eImageCreateInfo;
create.imageType = vk::ImageType::e2D; create.imageType = vk::ImageType::e2D;
create.extent = {info.width, info.height, 1}; create.extent = {info.width, info.height, 1};
create.mipLevels = 1; create.mipLevels = 1;
create.arrayLayers = 1; create.arrayLayers = 1;
create.format = info.format; create.format = info.format;
create.tiling = vk::ImageTiling::eOptimal; create.tiling = vk::ImageTiling::eOptimal;
create.initialLayout = vk::ImageLayout::eUndefined; create.initialLayout = vk::ImageLayout::eUndefined;
create.flags = RenderTargetCreateFlags(info.format); create.flags = RenderTargetCreateFlags(info.format);
create.usage = RenderTargetUsage(ctx, info.format, create.flags); create.usage = RenderTargetUsage(ctx, info.format, create.flags);
create.sharingMode = vk::SharingMode::eExclusive; create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1; create.samples = vk::SampleCountFlagBits::e1;
memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
if (!VulkanCreateImage(ctx, &create, image, memory)) { if (!VulkanCreateImage(ctx, create, image)) {
EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64 EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64
" extent=%ux%u format=%d\n", " extent=%ux%u format=%d\n",
info.address, info.width, info.height, static_cast<int>(info.format)); info.address, info.width, info.height, static_cast<int>(info.format));
} }
image->memory = *memory;
ImageViewOps::CreateVideoOutViews(ctx, image); ImageViewOps::CreateVideoOutViews(ctx, image);
return image; return image;
} }
@@ -374,10 +366,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
info.address, info.metadata_address, info.dcc_control); info.address, info.metadata_address, info.dcc_control);
} }
if (refresh) { if (refresh) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
image->layout = vk::ImageLayout::eUndefined; image->layout = vk::ImageLayout::eUndefined;
UtilScratchBuffer scratch(info.size); Transfer::ScratchBuffer scratch(info.size);
TileConvertTiledToLinearRenderTarget( TileConvertTiledToLinearRenderTarget(
scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height, scratch.Data(), reinterpret_cast<const void*>(info.address), info.width, info.height,
info.pitch, info.bytes_per_element, info.size); info.pitch, info.bytes_per_element, info.size);
@@ -387,16 +379,12 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video
std::swap(pixels[i], pixels[i + 2]); std::swap(pixels[i], pixels[i + 2]);
} }
} }
UtilFillImage(ctx, image, scratch.Data(), info.size, info.pitch, vk::ImageLayout::eGeneral); Transfer::UploadImage(ctx, image, scratch.Data(), info.size, info.pitch,
vk::ImageLayout::eGeneral);
} }
GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d, GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, bool image_3d,
bool storage, VulkanMemory* memory) { bool storage) {
if (memory == nullptr || memory->allocation != nullptr) {
EXIT("TextureCache: invalid dummy texture memory slot, slot=%p allocation=%p storage=%d\n",
static_cast<const void*>(memory),
memory == nullptr ? nullptr : static_cast<const void*>(memory->allocation), storage);
}
auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage) auto* image = storage ? static_cast<GpuTextureVulkanImage*>(new StorageTextureVulkanImage)
: new TextureVulkanImage; : new TextureVulkanImage;
auto usage = storage ? TextureFormatUsage::Storage : TextureFormatUsage::Sampled; auto usage = storage ? TextureFormatUsage::Storage : TextureFormatUsage::Sampled;
@@ -404,69 +392,52 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture"; auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture";
auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner); auto params = MakeDummyTextureParams(uint_format, image_3d, usage, owner);
auto components = TextureCreateImage(ctx, image, memory, params); auto components = TextureCreateImage(ctx, image, params);
static constexpr uint32_t zero = 0; static constexpr uint32_t zero = 0;
UtilFillImage(ctx, image, &zero, sizeof(zero), 1, layout); Transfer::UploadImage(ctx, image, &zero, sizeof(zero), 1, layout);
TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level, TextureCreateImageViews(ctx, image, components, params.type, 0, params.base_level,
params.levels, params.depth, params.allow_cube_view, params.view_usage); params.levels, params.depth, params.allow_cube_view, params.view_usage);
return image; return image;
} }
void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory) { void Destroy(GraphicContext* ctx, VulkanImage* image) {
KYTY_PROFILER_BLOCK("TextureCache::DeleteGpuTexture"); KYTY_PROFILER_BLOCK("TextureCache::DeleteImage");
EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr);
EXIT_IF(ctx == nullptr); switch (image->type) {
EXIT_IF(image == nullptr); case VulkanImageType::RenderTexture:
case VulkanImageType::VideoOut:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
break;
case VulkanImageType::DepthStencil:
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(
static_cast<DepthStencilVulkanImage*>(image));
break;
case VulkanImageType::Texture:
case VulkanImageType::StorageTexture: break;
case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n");
}
ImageViewOps::DestroyViews(ctx, image); ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image, memory); VulkanDeleteImage(ctx, image);
switch (image->type) { switch (image->type) {
case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break; case VulkanImageType::Texture: delete static_cast<TextureVulkanImage*>(image); break;
case VulkanImageType::StorageTexture: case VulkanImageType::StorageTexture:
delete static_cast<StorageTextureVulkanImage*>(image); delete static_cast<StorageTextureVulkanImage*>(image);
break; break;
default: EXIT("unsupported gpu texture image type: %d\n", static_cast<int>(image->type)); case VulkanImageType::RenderTexture:
delete static_cast<RenderTextureVulkanImage*>(image);
break;
case VulkanImageType::DepthStencil:
delete static_cast<DepthStencilVulkanImage*>(image);
break;
case VulkanImageType::VideoOut: delete static_cast<VideoOutVulkanImage*>(image); break;
case VulkanImageType::Unknown: EXIT("cannot delete an untyped Vulkan image\n");
} }
} }
void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_BLOCK("TextureCache::DeleteRenderTexture");
EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr);
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image, memory);
delete image;
}
void Destroy(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_BLOCK("TextureCache::DeleteDepthStencil");
EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr);
g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth(image);
ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image, memory);
delete image;
}
void Destroy(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_BLOCK("TextureCache::DeleteVideoOut");
EXIT_IF(ctx == nullptr);
EXIT_IF(image == nullptr);
g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image);
ImageViewOps::DestroyViews(ctx, image);
VulkanDeleteImage(ctx, image, memory);
delete image;
}
} // namespace ImageOps } // namespace ImageOps
} // namespace Libs::Graphics } // namespace Libs::Graphics
+10 -16
View File
@@ -15,7 +15,7 @@ struct GpuTextureVulkanImage;
struct GraphicContext; struct GraphicContext;
struct RenderTextureVulkanImage; struct RenderTextureVulkanImage;
struct VideoOutVulkanImage; struct VideoOutVulkanImage;
struct VulkanMemory; struct VulkanImage;
struct Image final: ImageInfo { struct Image final: ImageInfo {
Image& operator=(const ImageInfo& value) { Image& operator=(const ImageInfo& value) {
@@ -101,37 +101,31 @@ private:
namespace ImageOps { namespace ImageOps {
[[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, [[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info,
bool storage, VulkanMemory* memory, bool storage, vk::ComponentMapping* components);
vk::ComponentMapping* components);
void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
bool storage, vk::ComponentMapping components); bool storage, vk::ComponentMapping components);
[[nodiscard]] RenderTextureVulkanImage* [[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx,
CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info, VulkanMemory* memory); const RenderTargetInfo& info);
[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element); [[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element);
void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image, void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image,
const RenderTargetInfo& info, uint32_t base_layer, const RenderTargetInfo& info, uint32_t base_layer,
uint32_t layer_count, bool refresh); uint32_t layer_count, bool refresh);
void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image,
const RenderTargetInfo& info, bool refresh); const RenderTargetInfo& info, bool refresh);
[[nodiscard]] DepthStencilVulkanImage* [[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx,
CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, VulkanMemory* memory); const DepthTargetInfo& info);
void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info, [[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info);
VulkanMemory* memory);
void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info, void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info,
bool refresh); bool refresh);
[[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, [[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format,
bool image_3d, bool storage, bool image_3d, bool storage);
VulkanMemory* memory);
void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory); void Destroy(GraphicContext* ctx, VulkanImage* image);
void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory);
void Destroy(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* memory);
void Destroy(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* memory);
} // namespace ImageOps } // namespace ImageOps
+59 -16
View File
@@ -3,7 +3,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/utils.h"
#include <mutex> #include <mutex>
@@ -11,28 +10,72 @@ namespace Libs::Graphics {
namespace { namespace {
void CreateView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer, uint32_t base_mip_level,
uint32_t layer_count, uint32_t level_count,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}) {
if (ctx == nullptr || image == nullptr || view_index < 0 ||
view_index >= VulkanImage::VIEW_MAX || image->image == nullptr ||
image->image_view[view_index] != nullptr) {
EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n",
static_cast<const void*>(image), view_index,
image != nullptr && view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image->image_view[view_index] != nullptr);
}
vk::ImageViewUsageCreateInfo usage_info {};
usage_info.sType = vk::StructureType::eImageViewUsageCreateInfo;
usage_info.usage = view_usage;
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = view_usage ? &usage_info : nullptr;
create_info.image = image->image;
create_info.viewType = view_type;
create_info.format = view_format != vk::Format::eUndefined ? view_format : image->format;
create_info.components = components;
create_info.subresourceRange.aspectMask = aspect_mask;
create_info.subresourceRange.baseArrayLayer = base_array_layer;
create_info.subresourceRange.baseMipLevel = base_mip_level;
create_info.subresourceRange.layerCount = layer_count;
create_info.subresourceRange.levelCount = level_count;
const auto result =
ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]);
if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) {
EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(image->format),
static_cast<int>(create_info.format), view_index);
}
}
void CreateRenderTargetView(GraphicContext* ctx, VulkanImage* image, int index, void CreateRenderTargetView(GraphicContext* ctx, VulkanImage* image, int index,
vk::ComponentSwizzle r, vk::ComponentSwizzle g, vk::ComponentSwizzle b, vk::ComponentSwizzle r, vk::ComponentSwizzle g, vk::ComponentSwizzle b,
vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D, vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D,
vk::Format view_format = vk::Format::eUndefined, vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) { vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) {
const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u; const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u;
UtilCreateImageView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, CreateView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0,
0, layer_count, level_count == 0 ? image->mip_levels : level_count, layer_count, level_count == 0 ? image->mip_levels : level_count, view_format,
view_format, view_usage); view_usage);
} }
} // namespace } // namespace
namespace ImageViewOps { namespace ImageViewOps {
vk::ImageAspectFlags DepthAspectMask(vk::Format format) noexcept { vk::ImageAspectFlags DepthAspectMask(vk::Format format) {
auto aspects = vk::ImageAspectFlags {vk::ImageAspectFlagBits::eDepth}; switch (format) {
if (format == vk::Format::eD16UnormS8Uint || format == vk::Format::eD24UnormS8Uint || case vk::Format::eD16Unorm:
format == vk::Format::eD32SfloatS8Uint) { case vk::Format::eD32Sfloat: return vk::ImageAspectFlagBits::eDepth;
aspects |= vk::ImageAspectFlagBits::eStencil; case vk::Format::eD16UnormS8Uint:
case vk::Format::eD24UnormS8Uint:
case vk::Format::eD32SfloatS8Uint:
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
default: EXIT("unsupported depth/stencil image format: %d\n", static_cast<int>(format));
} }
return aspects;
} }
bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) { bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) {
@@ -68,11 +111,11 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag
} }
void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) { void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) {
UtilCreateImageView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D,
DepthAspectMask(image->format), DepthAspectMask(image->format),
{vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity},
0, 0, 1, 1); 0, 0, 1, 1);
} }
void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) {
@@ -338,7 +381,7 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext*
static_cast<const void*>(image), info.type, info.depth, info.base_level, info.levels, static_cast<const void*>(image), info.type, info.depth, info.base_level, info.levels,
info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array); info.view_levels, image != nullptr ? image->mip_levels : 0, info.base_array);
} }
const auto view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled); const auto view_format = TextureGetFormat(info.format);
if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) && if (view_format != image->format && !IsRgba8SrgbReinterpretation(image->format, view_format) &&
!IsR32UintFloatReinterpretation(image->format, view_format)) { !IsR32UintFloatReinterpretation(image->format, view_format)) {
EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d"
+1 -1
View File
@@ -215,7 +215,7 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource
namespace ImageViewOps { namespace ImageViewOps {
[[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format) noexcept; [[nodiscard]] vk::ImageAspectFlags DepthAspectMask(vk::Format format);
[[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format); [[nodiscard]] bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format);
void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image); void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image);
-11
View File
@@ -1,11 +0,0 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
#include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/gdsBuffer.h"
#include "graphics/host_gpu/renderer/pipelineCache.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/samplerCache.h"
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_INTERNAL_H_
@@ -1,22 +1,16 @@
#include "graphics/host_gpu/renderer/pipelineCache.h" #include "graphics/host_gpu/renderer/pipelineCache.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/emulatorConfig.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/stringUtils.h"
#include "graphics/guest_gpu/graphicsRun.h"
#include "graphics/guest_gpu/hardwareContext.h" #include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "graphics/host_gpu/renderer/colorRenderTarget.h"
#include "graphics/host_gpu/renderer/debug.h" #include "graphics/host_gpu/renderer/debug.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h"
#include <atomic> #include <atomic>
#include <cstring> #include <cstring>
#include <fmt/format.h>
#include <span> #include <span>
#include <utility> #include <utility>
@@ -44,26 +38,6 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other)
return std::memcmp(this, &other, sizeof(*this)) == 0; return std::memcmp(this, &other, sizeof(*this)) == 0;
} }
void PipelineCache::DeletePipelineInternal(Pipeline* p) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(p == nullptr);
EXIT_IF(p->pipeline == nullptr);
EXIT_IF(p->pipeline_layout == nullptr);
DumpPipeline("delete", *p);
auto* gctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(gctx == nullptr);
VulkanDeviceWaitIdle(gctx);
gctx->device.destroyPipeline(p->pipeline, nullptr);
gctx->device.destroyPipelineLayout(p->pipeline_layout, nullptr);
p->pipeline = nullptr;
p->pipeline_layout = nullptr;
}
PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline( PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count,
RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx, RenderDepthInfo* depth, ShaderVertexInputInfo* vs_input_info, HW::Context* ctx,
@@ -188,7 +162,6 @@ PipelineCache::GraphicsPipeline* PipelineCache::CreateGraphicsPipeline(
auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached)); auto [iter, inserted] = m_graphics_pipelines.emplace(std::move(key), std::move(cached));
EXIT_IF(!inserted); EXIT_IF(!inserted);
DumpPipeline("create", *iter->second);
return iter->second.get(); return iter->second.get();
} }
@@ -231,69 +204,4 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info,
return iter->second.get(); return iter->second.get();
} }
void PipelineCache::DeletePipeline(Pipeline* pipeline) {
Common::LockGuard lock(m_mutex);
EXIT_IF(pipeline == nullptr);
for (auto iter = m_graphics_pipelines.begin(); iter != m_graphics_pipelines.end(); iter++) {
if (iter->second.get() == pipeline) {
DeletePipelineInternal(iter->second.get());
m_graphics_pipelines.erase(iter);
return;
}
}
for (auto iter = m_compute_pipelines.begin(); iter != m_compute_pipelines.end(); iter++) {
if (iter->second.get() == pipeline) {
DeletePipelineInternal(iter->second.get());
m_compute_pipelines.erase(iter);
return;
}
}
EXIT_IF(true);
}
void PipelineCache::DeleteAllPipelines() {
Common::LockGuard lock(m_mutex);
for (auto& item: m_graphics_pipelines) {
DeletePipelineInternal(item.second.get());
}
m_graphics_pipelines.clear();
for (auto& item: m_compute_pipelines) {
DeletePipelineInternal(item.second.get());
}
m_compute_pipelines.clear();
}
void PipelineCache::DumpToFile(Common::File* f, const Pipeline& p) {}
void PipelineCache::DumpPipeline(const char* action, const Pipeline& p) {
EXIT_IF(action == nullptr);
static std::atomic_int dump_id = 0;
if (!Config::PipelineDumpEnabled()) {
return;
}
Common::File f;
const auto file_name =
Config::GetPipelineDumpFolder() /
fmt::format("{:04d}_{:04d}_pipeline_{}.log", GraphicsRunGetFrameNum(), dump_id++, action);
Common::File::CreateDirectories(file_name.parent_path());
f.Create(file_name);
if (f.IsInvalid()) {
auto file_name_text = Common::PathToString(file_name);
LOGF_COLOR(Log::Color::BrightRed, "Can't create file: %s\n", file_name_text.c_str());
return;
}
DumpToFile(&f, p);
f.Close();
}
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -4,7 +4,6 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/common.h" #include "common/common.h"
#include "common/file.h"
#include "common/threads.h" #include "common/threads.h"
#include "graphics/host_gpu/renderer/renderTarget.h" #include "graphics/host_gpu/renderer/renderTarget.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
@@ -15,7 +14,6 @@
#include <span> #include <span>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -86,7 +84,7 @@ static_assert(sizeof(PipelineStaticParameters) ==
class PipelineCache { class PipelineCache {
public: public:
PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~PipelineCache() { KYTY_NOT_IMPLEMENTED; } ~PipelineCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(PipelineCache); KYTY_CLASS_NO_COPY(PipelineCache);
struct Pipeline { struct Pipeline {
@@ -112,8 +110,6 @@ public:
ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info, ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info,
const HW::ComputeShaderInfo* cs_regs, const HW::ComputeShaderInfo* cs_regs,
std::span<const uint32_t> cs_spirv); std::span<const uint32_t> cs_spirv);
void DeletePipeline(Pipeline* pipeline);
void DeleteAllPipelines();
private: private:
struct GraphicsPipelineKey { struct GraphicsPipelineKey {
@@ -178,10 +174,6 @@ private:
} }
}; };
void DeletePipelineInternal(Pipeline* p);
void DumpToFile(Common::File* f, const Pipeline& p);
void DumpPipeline(const char* action, const Pipeline& p);
std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>, std::unordered_map<GraphicsPipelineKey, std::unique_ptr<GraphicsPipeline>,
GraphicsPipelineKeyHash> GraphicsPipelineKeyHash>
m_graphics_pipelines; m_graphics_pipelines;
+11 -6
View File
@@ -69,7 +69,7 @@ private:
class CommandBuffer { class CommandBuffer {
public: public:
explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); } explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); }
virtual ~CommandBuffer() { Free(); } ~CommandBuffer() { Free(); }
KYTY_CLASS_NO_COPY(CommandBuffer); KYTY_CLASS_NO_COPY(CommandBuffer);
@@ -95,16 +95,21 @@ public:
void RetainResourceUntilFence(std::shared_ptr<void> resource); void RetainResourceUntilFence(std::shared_ptr<void> resource);
void RecycleDescriptorAfterFence(VulkanDescriptorSet* set); void RecycleDescriptorAfterFence(VulkanDescriptorSet* set);
[[nodiscard]] uint32_t GetIndex() const { return m_index; } [[nodiscard]] vk::CommandBuffer Handle() const;
[[nodiscard]] int GetQueue() const { return m_queue; } [[nodiscard]] int GetQueue() const { return m_queue; }
VulkanCommandPool* GetPool() { return m_pool; } [[nodiscard]] bool IsExecute() const { return m_execute; }
[[nodiscard]] bool IsExecute() const { return m_execute; }
[[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; } [[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; }
private: private:
friend class BufferCache; friend class BufferCache;
void RecycleDescriptorsAfterFence(); void Submit(vk::Semaphore wait_semaphore, vk::PipelineStageFlags wait_stage,
vk::Semaphore signal_semaphore);
[[nodiscard]] vk::Semaphore ResolveSignalSemaphore(vk::Semaphore semaphore) const;
void FinalizeFence(bool reset_recording);
void ReleaseResourcesAfterFence();
void DeleteBuffersAfterFence();
void RecycleDescriptorsAfterFence();
VulkanCommandPool* m_pool = nullptr; VulkanCommandPool* m_pool = nullptr;
uint32_t m_index = static_cast<uint32_t>(-1); uint32_t m_index = static_cast<uint32_t>(-1);
@@ -14,15 +14,15 @@
#include "graphics/host_gpu/objects/label.h" #include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h"
#include "graphics/host_gpu/renderer/descriptorCache.h" #include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/host_gpu/renderer/descriptors.h"
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/imageInfo.h" #include "graphics/host_gpu/renderer/imageInfo.h"
#include "graphics/host_gpu/renderer/pipelineCache.h" #include "graphics/host_gpu/renderer/pipelineCache.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/renderInternal.h"
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h" #include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
#include "graphics/host_gpu/renderer/shaderSubgroup.h" #include "graphics/host_gpu/renderer/shaderSubgroup.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/shader/recompiler/ResourceMaterialization.h"
#include "graphics/shader/recompiler/ShaderIR.h" #include "graphics/shader/recompiler/ShaderIR.h"
@@ -528,15 +528,15 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
for (;;) { for (;;) {
const auto recording_generation = buffer->GetRecordingGeneration(); const auto recording_generation = buffer->GetRecordingGeneration();
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline( auto* pipeline = g_render_ctx->GetPipelineCache()->CreateComputePipeline(
&input_info, &sh_ctx->GetCs(), cs_shader); &input_info, &sh_ctx->GetCs(), cs_shader);
vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline); vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline);
const auto address_writes = BindDescriptors( BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute,
submit_id, buffer, vk::PipelineBindPoint::eCompute, pipeline->pipeline_layout, pipeline->pipeline_layout, input_info.stage,
input_info.stage, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
if (buffer->GetRecordingGeneration() != recording_generation) { if (buffer->GetRecordingGeneration() != recording_generation) {
continue; continue;
} }
@@ -544,7 +544,6 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
vk_buffer.dispatch(thread_group_x, thread_group_y, thread_group_z); vk_buffer.dispatch(thread_group_x, thread_group_y, thread_group_z);
bool has_storage_writes = HasShaderBufferWrites(input_info.stage); bool has_storage_writes = HasShaderBufferWrites(input_info.stage);
has_storage_writes = MarkShaderAddressWrites(address_writes) || has_storage_writes;
has_storage_writes = has_storage_writes =
std::any_of( std::any_of(
program.info.images.begin(), program.info.images.end(), program.info.images.begin(), program.info.images.end(),
@@ -19,8 +19,6 @@ void RenderContext::SetGraphicCtx(GraphicContext* ctx) {
} }
GraphicContext* RenderContext::GetGraphicCtx() { GraphicContext* RenderContext::GetGraphicCtx() {
EXIT_IF(g_render_ctx == nullptr);
{ {
Common::LockGuard lock(m_graphic_ctx_mutex); Common::LockGuard lock(m_graphic_ctx_mutex);
if (m_graphic_ctx != nullptr) { if (m_graphic_ctx != nullptr) {
@@ -24,7 +24,7 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800;
class RenderContext { class RenderContext {
public: public:
RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~RenderContext() { KYTY_NOT_IMPLEMENTED; } ~RenderContext() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(RenderContext); KYTY_CLASS_NO_COPY(RenderContext);
void SetGraphicCtx(GraphicContext* ctx); void SetGraphicCtx(GraphicContext* ctx);
+34 -82
View File
@@ -22,11 +22,9 @@
#include "graphics/host_gpu/renderer/pipelineCache.h" #include "graphics/host_gpu/renderer/pipelineCache.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/renderInternal.h"
#include "graphics/host_gpu/renderer/renderVertex.h"
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h" #include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
#include "graphics/host_gpu/renderer/shaderSubgroup.h" #include "graphics/host_gpu/renderer/shaderSubgroup.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/shader/recompiler/ResourceMaterialization.h"
#include "graphics/shader/recompiler/ShaderIR.h" #include "graphics/shader/recompiler/ShaderIR.h"
@@ -47,6 +45,25 @@
namespace Libs::Graphics { namespace Libs::Graphics {
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info) {
if (index_offset != 0 || !vs_input_info.fetch_embedded) {
return static_cast<int32_t>(index_offset);
}
EXIT_IF(!vs_input_info.stage);
const auto& program = *vs_input_info.stage.program;
const auto& resources = *vs_input_info.stage.resources;
if (program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
const auto index =
static_cast<uint32_t>(program.info.vertex_offset_sgpr) - program.user_data_base;
if (index < resources.user_data.size()) {
return static_cast<int32_t>(resources.user_data[index]);
}
}
return 0;
}
static std::atomic<uint32_t> g_draw_state_log_count = 0; static std::atomic<uint32_t> g_draw_state_log_count = 0;
static std::atomic<uint32_t> g_draw_input_log_count = 0; static std::atomic<uint32_t> g_draw_input_log_count = 0;
static std::atomic<uint32_t> g_mrt_state_log_count = 0; static std::atomic<uint32_t> g_mrt_state_log_count = 0;
@@ -288,66 +305,6 @@ static void LogDrawInputState(const RenderColorInfo& color,
} }
} }
[[maybe_unused]] static void LogDrawTextureState(const char* draw_name,
const RenderColorInfo& color,
const ShaderPixelInputInfo& ps_input_info) {
static std::atomic<uint32_t> log_count {0};
const auto log_id = log_count.fetch_add(1, std::memory_order_relaxed);
if (log_id >= 256) {
return;
}
const auto& ps_program = *ps_input_info.stage.program;
const auto& ps_resources = *ps_input_info.stage.resources;
const auto sampled_images = std::count_if(
ps_program.info.images.begin(), ps_program.info.images.end(), [](const auto& image) {
return image.kind == ShaderRecompiler::IR::ResourceKind::Image ||
image.kind == ShaderRecompiler::IR::ResourceKind::ImageUint;
});
LOGF("DrawTextureState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
" textures=%zu sampled=%zu storage=%zu samplers=%zu\n",
log_id, GraphicsRunGetFrameNum(), draw_name, RenderColorTypeName(color.type),
color.base_addr, ps_program.info.images.size(), sampled_images,
ps_program.info.images.size() - sampled_images, ps_program.info.samplers.size());
for (uint32_t i = 0; i < ps_program.info.images.size(); i++) {
const auto& image = ps_program.info.images[i];
const auto r = DecodeNativeDescriptor<ShaderTextureResource>(ps_resources.images[i]);
LOGF("DrawTextureState[%u]: tex[%u] source=%u usage=%s sampled=%s "
"addr=0x%010" PRIx64 " type=%u fmt=%u extent=%ux%u depth=%u levels=%u base_level=%u "
"tile=%u swizzle=0x%03" PRIx32 " fields=%08" PRIx32 " %08" PRIx32 " %08" PRIx32
" %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n",
log_id, i, image.source, image.written ? "read-write" : "read-only",
(image.kind == ShaderRecompiler::IR::ResourceKind::Image ||
image.kind == ShaderRecompiler::IR::ResourceKind::ImageUint)
? "true"
: "false",
r.Base40(), static_cast<uint32_t>(r.Type()), static_cast<uint32_t>(r.Format()),
static_cast<uint32_t>(r.Width5()) + 1u, static_cast<uint32_t>(r.Height5()) + 1u,
static_cast<uint32_t>(r.Depth()) + 1u,
std::max<uint32_t>(static_cast<uint32_t>(r.LastLevel()),
static_cast<uint32_t>(r.MaxMip())) +
1u,
static_cast<uint32_t>(r.BaseLevel()), static_cast<uint32_t>(r.TileMode()),
r.DstSelXYZW(), r.fields[0], r.fields[1], r.fields[2], r.fields[3], r.fields[4],
r.fields[5], r.fields[6], r.fields[7]);
}
for (uint32_t i = 0; i < ps_program.info.samplers.size(); i++) {
const auto& sampler = ps_program.info.samplers[i];
const auto r = DecodeNativeDescriptor<ShaderSamplerResource>(ps_resources.samplers[i]);
LOGF("DrawTextureState[%u]: samp[%u] source=%u clamp=%u/%u/%u filter=%u/%u/%u "
"mip=%u lod=%u-%u"
" bias=%d fields=%08" PRIx32 " %08" PRIx32 " %08" PRIx32 " %08" PRIx32 "\n",
log_id, i, sampler.source, static_cast<uint32_t>(r.ClampX()),
static_cast<uint32_t>(r.ClampY()), static_cast<uint32_t>(r.ClampZ()),
static_cast<uint32_t>(r.XyMagFilter()), static_cast<uint32_t>(r.XyMinFilter()),
static_cast<uint32_t>(r.ZFilter()), static_cast<uint32_t>(r.MipFilter()),
static_cast<uint32_t>(r.MinLod()), static_cast<uint32_t>(r.MaxLod()),
static_cast<int32_t>(r.LodBias()), r.fields[0], r.fields[1], r.fields[2], r.fields[3]);
}
}
static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer, static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer,
uint32_t attachment_count, uint32_t attachment_count,
const vk::Bool32* p_color_write_enables) { const vk::Bool32* p_color_write_enables) {
@@ -730,7 +687,7 @@ static bool PrepareDrawRenderState(uint64_t submit_id, CommandBuffer* buffer, HW
EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr); EXIT_NOT_IMPLEMENTED(state->framebuffer == nullptr);
EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr); EXIT_NOT_IMPLEMENTED(state->framebuffer->render_pass == nullptr);
state->vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; state->vk_buffer = buffer->Handle();
return true; return true;
} }
@@ -851,8 +808,10 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D
return; return;
} }
LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg, if (state.ps_active) {
state.ps_input_info, draw.index_count, draw.flags); LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg,
state.ps_input_info, draw.index_count, draw.flags);
}
LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size, LogDrawInputState(state.color_info[0], state.vs_input_info, index_type_and_size,
draw.index_count, index_addr); draw.index_count, index_addr);
// LogDrawTextureState(draw.name, state.color_info[0], state.ps_input_info); // LogDrawTextureState(draw.name, state.color_info[0], state.ps_input_info);
@@ -965,21 +924,18 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x200u); SetDrawDebugPhase(buffer, submit_id, draw, 0x200u);
} }
const auto vs_address_writes = BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, pipeline->pipeline_layout, state->vs_input_info.stage,
pipeline->pipeline_layout, state->vs_input_info.stage, vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex);
std::vector<ShaderAddressWriteRange> ps_address_writes;
if (state->ps_active) { if (state->ps_active) {
LogDrawPhase(draw.name, "BindDescriptorsPS"); LogDrawPhase(draw.name, "BindDescriptorsPS");
if (set_auto_debug) { if (set_auto_debug) {
SetDrawDebugPhase(buffer, submit_id, draw, 0x300u); SetDrawDebugPhase(buffer, submit_id, draw, 0x300u);
} }
ps_address_writes = BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics,
BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, pipeline->pipeline_layout, state->ps_input_info.stage,
pipeline->pipeline_layout, state->ps_input_info.stage, vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel);
} }
if (buffer->GetRecordingGeneration() != recording_generation) { if (buffer->GetRecordingGeneration() != recording_generation) {
continue; continue;
@@ -1008,15 +964,11 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C
} }
buffer->EndRenderPass(); buffer->EndRenderPass();
vk::PipelineStageFlags shader_write_stages = {}; vk::PipelineStageFlags shader_write_stages = {};
const bool vs_wrote_buffers = HasShaderBufferWrites(state->vs_input_info.stage); if (HasShaderBufferWrites(state->vs_input_info.stage)) {
const bool vs_wrote_addresses = MarkShaderAddressWrites(vs_address_writes);
if (vs_wrote_buffers || vs_wrote_addresses) {
shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader; shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader;
} }
if (state->ps_active) { if (state->ps_active) {
const bool ps_wrote_buffers = HasShaderBufferWrites(state->ps_input_info.stage); if (HasShaderBufferWrites(state->ps_input_info.stage)) {
const bool ps_wrote_addresses = MarkShaderAddressWrites(ps_address_writes);
if (ps_wrote_buffers || ps_wrote_addresses) {
shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader; shader_write_stages |= vk::PipelineStageFlagBits::eFragmentShader;
} }
} }
@@ -1328,7 +1280,7 @@ static bool ResolveColorTargets(uint64_t submit_id, CommandBuffer* buffer, const
const std::array regions {MakeColorResolveCopy(src, dst, width, height)}; const std::array regions {MakeColorResolveCopy(src, dst, width, height)};
MarkRenderTargetGpuWritten(dst); MarkRenderTargetGpuWritten(dst);
UtilImageToImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout); Transfer::CopyImage(buffer, regions, dst.vulkan_buffer, dst.vulkan_buffer->layout);
return true; return true;
} }
@@ -10,6 +10,7 @@ namespace Libs::Graphics {
struct ImageImageCopy; struct ImageImageCopy;
struct RenderColorInfo; struct RenderColorInfo;
struct ShaderVertexInputInfo;
#pragma pack(push, 1) #pragma pack(push, 1)
@@ -43,6 +44,8 @@ static_assert(sizeof(PipelineDynamicParameters) ==
[[nodiscard]] ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, [[nodiscard]] ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src,
const RenderColorInfo& dst, uint32_t width, const RenderColorInfo& dst, uint32_t width,
uint32_t height); uint32_t height);
[[nodiscard]] int32_t ResolveVertexOffset(uint32_t index_offset,
const ShaderVertexInputInfo& vs_input_info);
} // namespace Libs::Graphics } // namespace Libs::Graphics
@@ -1,21 +0,0 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
#include "common/assert.h"
#include "graphics/shader/recompiler/ShaderIR.h"
#include <cstring>
namespace Libs::Graphics {
template <typename T>
T DecodeNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& value) {
T result {};
EXIT_IF(value.dword_count < sizeof(result) / sizeof(uint32_t));
std::memcpy(&result, value.dwords.data(), sizeof(result));
return result;
}
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERINTERNAL_H_
@@ -11,11 +11,11 @@
#include "graphics/guest_gpu/tile.h" #include "graphics/guest_gpu/tile.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/imageView.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/displayBuffer.h" #include "graphics/presentation/displayBuffer.h"
@@ -34,7 +34,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) {
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(g_render_ctx->GetMutex());
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
VulkanMemoryBarrier mem_barrier {}; VulkanMemoryBarrier mem_barrier {};
mem_barrier.sType = vk::StructureType::eMemoryBarrier; mem_barrier.sType = vk::StructureType::eMemoryBarrier;
@@ -121,8 +121,6 @@ void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* i
} }
} }
vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format);
void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image, void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage* image,
vk::ImageLayout new_layout) { vk::ImageLayout new_layout) {
EXIT_IF(image == nullptr); EXIT_IF(image == nullptr);
@@ -144,9 +142,9 @@ void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanI
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image->image; barrier.image = image->image;
barrier.subresourceRange = {DepthStencilAspectMask(image->format), 0, VK_REMAINING_MIP_LEVELS, barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0,
0, image->layers}; VK_REMAINING_MIP_LEVELS, 0, image->layers};
const auto stages = static_cast<vk::PipelineStageFlags>( const auto stages = static_cast<vk::PipelineStageFlags>(
vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader |
vk::PipelineStageFlagBits::eTransfer); vk::PipelineStageFlagBits::eTransfer);
vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1,
@@ -182,9 +180,10 @@ void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage*
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = image->image; image_memory_barrier.image = image->image;
image_memory_barrier.subresourceRange.aspectMask = DepthStencilAspectMask(image->format); image_memory_barrier.subresourceRange.aspectMask =
image_memory_barrier.subresourceRange.baseMipLevel = 0; ImageViewOps::DepthAspectMask(image->format);
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseMipLevel = 0;
image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.baseArrayLayer = 0;
image_memory_barrier.subresourceRange.layerCount = image->layers; image_memory_barrier.subresourceRange.layerCount = image->layers;
@@ -205,7 +204,7 @@ void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(g_render_ctx->GetMutex());
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size); auto* native = g_render_ctx->GetTextureCache()->FindRenderTargetByRange(buffer, vaddr, size);
if (native == nullptr) { if (native == nullptr) {
@@ -220,7 +219,7 @@ void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, ui
Common::LockGuard lock(g_render_ctx->GetMutex()); Common::LockGuard lock(g_render_ctx->GetMutex());
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size); auto* native = g_render_ctx->GetTextureCache()->FindDepthTargetByRange(buffer, vaddr, size);
if (native == nullptr) { if (native == nullptr) {
EXIT("depth-target barrier range has no cached image\n"); EXIT("depth-target barrier range has no cached image\n");
@@ -1,29 +0,0 @@
#include "graphics/host_gpu/renderer/renderVertex.h"
#include "common/assert.h"
#include "graphics/shader/recompiler/ResourceMaterialization.h"
#include "graphics/shader/recompiler/ShaderIR.h"
#include "graphics/shader/shader.h"
namespace Libs::Graphics {
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info) {
if (index_offset != 0 || !vs_input_info.fetch_embedded) {
return static_cast<int32_t>(index_offset);
}
EXIT_IF(!vs_input_info.stage);
const auto& program = *vs_input_info.stage.program;
const auto& resources = *vs_input_info.stage.resources;
if (program.info.vertex_offset_sgpr >= static_cast<int32_t>(program.user_data_base)) {
const auto index =
static_cast<uint32_t>(program.info.vertex_offset_sgpr) - program.user_data_base;
if (index < resources.user_data.size()) {
return static_cast<int32_t>(resources.user_data[index]);
}
}
return 0;
}
} // namespace Libs::Graphics
@@ -1,14 +0,0 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
#include <cstdint>
namespace Libs::Graphics {
struct ShaderVertexInputInfo;
int32_t ResolveVertexOffset(uint32_t index_offset, const ShaderVertexInputInfo& vs_input_info);
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_
@@ -143,8 +143,9 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) {
} }
vk::Sampler vk_sampler = nullptr; vk::Sampler vk_sampler = nullptr;
g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler); const auto result =
EXIT_NOT_IMPLEMENTED(vk_sampler == nullptr); g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler);
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || vk_sampler == nullptr);
m_samplers.emplace(key, vk_sampler); m_samplers.emplace(key, vk_sampler);
return vk_sampler; return vk_sampler;
@@ -17,7 +17,7 @@ namespace Libs::Graphics {
class SamplerCache { class SamplerCache {
public: public:
SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~SamplerCache() { KYTY_NOT_IMPLEMENTED; } ~SamplerCache() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(SamplerCache); KYTY_CLASS_NO_COPY(SamplerCache);
vk::Sampler GetSampler(const ShaderSamplerResource& r); vk::Sampler GetSampler(const ShaderSamplerResource& r);
@@ -1,7 +1,6 @@
#include "graphics/host_gpu/renderer/shaderResourceBarrier.h" #include "graphics/host_gpu/renderer/shaderResourceBarrier.h"
#include "common/assert.h" #include "common/assert.h"
#include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/shader/shader.h" #include "graphics/shader/shader.h"
#include "graphics/shader/shaderBindings.h" #include "graphics/shader/shaderBindings.h"
@@ -108,13 +107,6 @@ CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program,
return writes; return writes;
} }
bool MarkShaderAddressWrites(const std::vector<ShaderAddressWriteRange>& writes) {
if (!writes.empty()) {
EXIT("shader address writes are unsupported\n");
}
return false;
}
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) { bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
EXIT_IF(!runtime); EXIT_IF(!runtime);
return !CollectShaderBufferWrites(*runtime.program, *runtime.resources).empty(); return !CollectShaderBufferWrites(*runtime.program, *runtime.resources).empty();
@@ -8,7 +8,6 @@
namespace Libs::Graphics { namespace Libs::Graphics {
struct ShaderAddressWriteRange;
struct ShaderStageRuntime; struct ShaderStageRuntime;
struct ShaderBufferWriteRange { struct ShaderBufferWriteRange {
@@ -26,7 +25,6 @@ vk::BufferMemoryBarrier MakeGdsDependency(const VulkanBuffer& buffer);
std::vector<ShaderBufferWriteRange> std::vector<ShaderBufferWriteRange>
CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program, CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program,
const ShaderRecompiler::IR::ResourceSnapshot& resources); const ShaderRecompiler::IR::ResourceSnapshot& resources);
bool MarkShaderAddressWrites(const std::vector<ShaderAddressWriteRange>& writes);
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime); bool HasShaderBufferWrites(const ShaderStageRuntime& runtime);
void ShaderWriteBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages); void ShaderWriteBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages);
@@ -4,7 +4,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include <atomic> #include <atomic>
+170 -174
View File
@@ -14,7 +14,9 @@
#include "kernel/pthread.h" #include "kernel/pthread.h"
#include "libs/errno.h" #include "libs/errno.h"
#include <array>
#include <limits> #include <limits>
#include <optional>
namespace Libs::Graphics::Sync { namespace Libs::Graphics::Sync {
@@ -71,6 +73,104 @@ static bool CompleteDisplayBufferFlip(const uint64_t* args) {
return true; return true;
} }
enum class EndOfPipeCompletion { None, Interrupt, Flip, FlipAndInterrupt };
struct EndOfPipeSignal {
CommandBuffer* buffer = nullptr;
uint64_t submit_id = 0;
CommandBufferDebugOp debug_operation = CommandBufferDebugOp::Unknown;
std::array<uint32_t, 4> debug_args = {};
uint64_t debug_data = 0;
std::optional<uint64_t> destination;
EndOfPipeCompletion completion = EndOfPipeCompletion::None;
uint64_t completion_data = 0;
};
enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 };
enum class EndOfPipeWriteAction { Write, WriteBack, Interrupt, InterruptWriteBack };
static bool TriggerEopEventCallback(const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
EXIT_IF(args == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
}
static bool TriggerDefaultEopEventCallback(const uint64_t* /*args*/) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(0);
return true;
}
static void ValidateEndOfPipeSignal(const EndOfPipeSignal& signal) {
EXIT_IF(g_render_ctx == nullptr);
if (signal.destination.has_value()) {
EXIT_IF(*signal.destination == 0);
}
EXIT_IF(signal.buffer == nullptr);
(void)signal.buffer->Handle();
}
static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) {
ValidateEndOfPipeSignal(signal);
signal.buffer->SetDebugInfo(static_cast<uint32_t>(signal.debug_operation), signal.submit_id,
signal.debug_args[0], signal.debug_args[1], signal.debug_args[2],
signal.debug_args[3], signal.debug_data);
const uint64_t args[LABEL_ARGS_MAX] = {signal.completion_data};
switch (signal.completion) {
case EndOfPipeCompletion::None: return;
case EndOfPipeCompletion::Interrupt:
SubmitLabel(signal.buffer, nullptr, TriggerEopEventCallback, args);
return;
case EndOfPipeCompletion::Flip:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, nullptr, args);
return;
case EndOfPipeCompletion::FlipAndInterrupt:
SubmitLabel(signal.buffer, CompleteDisplayBufferFlip, TriggerDefaultEopEventCallback,
args);
return;
}
}
static CommandBufferDebugOp DebugOperation(EndOfPipeWriteAction action) {
switch (action) {
case EndOfPipeWriteAction::Write: return CommandBufferDebugOp::EopWrite;
case EndOfPipeWriteAction::WriteBack:
case EndOfPipeWriteAction::InterruptWriteBack: return CommandBufferDebugOp::EopWriteBack;
case EndOfPipeWriteAction::Interrupt: return CommandBufferDebugOp::EopInterrupt;
}
EXIT("unsupported end-of-pipe write action\n");
return CommandBufferDebugOp::Unknown;
}
static bool TriggersInterrupt(EndOfPipeWriteAction action) {
return action == EndOfPipeWriteAction::Interrupt ||
action == EndOfPipeWriteAction::InterruptWriteBack;
}
static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer* buffer, uint64_t destination,
uint64_t value, EndOfPipeWriteSize size,
EndOfPipeWriteAction action, uint32_t context_id = 0) {
const auto width = static_cast<uint32_t>(size);
const auto value_low = static_cast<uint32_t>(value);
const auto value_high = static_cast<uint32_t>(value >> 32u);
const bool interrupt = TriggersInterrupt(action);
EndOfPipeSignal signal {
.buffer = buffer,
.submit_id = submit_id,
.debug_operation = DebugOperation(action),
.debug_args = interrupt ? std::array {width, context_id, value_low, value_high}
: std::array {width, value_low, value_high, 0u},
.debug_data = destination,
.destination = destination,
.completion = interrupt ? EndOfPipeCompletion::Interrupt : EndOfPipeCompletion::None,
.completion_data = context_id != 0 ? context_id : value,
};
RecordEndOfPipeSignal(signal);
}
void TriggerAgcUserInterrupt() { void TriggerAgcUserInterrupt() {
auto tsc = LibKernel::KernelReadTsc(); auto tsc = LibKernel::KernelReadTsc();
auto result = LibKernel::EventQueue::KernelTriggerUserEventForAll(AGC_USER_INTERRUPT_EVENT, auto result = LibKernel::EventQueue::KernelTriggerUserEventForAll(AGC_USER_INTERRUPT_EVENT,
@@ -85,47 +185,33 @@ void TriggerEopEvent(uint32_t context_id) {
void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
uint32_t value) { uint32_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 4, value,
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
} }
void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
uint32_t dw_offset, uint32_t dw_num) { uint32_t dw_offset, uint32_t dw_num) {
EXIT_IF(g_render_ctx == nullptr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
EXIT_IF(dst_gpu_addr == nullptr); RecordEndOfPipeSignal({
EXIT_IF(buffer == nullptr); .buffer = buffer,
EXIT_IF(buffer->IsInvalid()); .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWrite,
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, .debug_args = {dw_offset, dw_num, 0, 0},
dw_offset, dw_num, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr)); .debug_data = destination,
.destination = destination,
});
} }
void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
uint64_t value) { uint64_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 8,
static_cast<uint32_t>(value), static_cast<uint32_t>(value >> 32u), 0,
reinterpret_cast<uint64_t>(dst_gpu_addr));
} }
void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr,
uint64_t value) { uint64_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 8, 0, 0,
0, reinterpret_cast<uint64_t>(dst_gpu_addr));
LOGF_COLOR(Log::Color::BrightGreen, LOGF_COLOR(Log::Color::BrightGreen,
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n", "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
@@ -134,13 +220,8 @@ void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uin
void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer* buffer,
uint64_t* dst_gpu_addr, uint64_t value) { uint64_t* dst_gpu_addr, uint64_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), 0,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8, 0,
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
LOGF_COLOR(Log::Color::BrightGreen, LOGF_COLOR(Log::Color::BrightGreen,
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n", "EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
@@ -149,115 +230,42 @@ void WriteAtEndOfPipeClockCounterWithWriteBack(uint64_t submit_id, CommandBuffer
void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
uint64_t* dst_gpu_addr, uint64_t value) { uint64_t* dst_gpu_addr, uint64_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8,
static_cast<uint32_t>(value), static_cast<uint32_t>(value >> 32u), 0,
reinterpret_cast<uint64_t>(dst_gpu_addr));
} }
void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
uint32_t* dst_gpu_addr, uint32_t value) { uint32_t* dst_gpu_addr, uint32_t value) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 4,
value, 0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
} }
void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer,
uint64_t* dst_gpu_addr, uint64_t value, uint64_t* dst_gpu_addr, uint64_t value,
uint32_t context_id) { uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::InterruptWriteBack,
EXIT_IF(buffer == nullptr); context_id);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8,
context_id, static_cast<uint32_t>(value),
static_cast<uint32_t>(value >> 32u),
reinterpret_cast<uint64_t>(dst_gpu_addr));
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
SubmitLabel(
buffer, nullptr,
[](const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
},
args);
} }
void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer,
uint32_t* dst_gpu_addr, uint32_t value, uint32_t* dst_gpu_addr, uint32_t value,
uint32_t context_id) { uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::InterruptWriteBack,
EXIT_IF(buffer == nullptr); context_id);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 4,
context_id, value, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
SubmitLabel(
buffer, nullptr,
[](const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
},
args);
} }
void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer,
uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopInterrupt), submit_id, 8,
context_id, static_cast<uint32_t>(value),
static_cast<uint32_t>(value >> 32u),
reinterpret_cast<uint64_t>(dst_gpu_addr));
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
SubmitLabel(
buffer, nullptr,
[](const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
},
args);
} }
void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer, void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer,
uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast<uint64_t>(dst_gpu_addr), value,
EXIT_IF(dst_gpu_addr == nullptr); EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id);
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopInterrupt), submit_id, 4,
context_id, value, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
uint64_t args[LABEL_ARGS_MAX] = {context_id != 0 ? context_id : value};
SubmitLabel(
buffer, nullptr,
[](const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
},
args);
} }
uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode, uint64_t PrepareDisplayBufferFlip(CommandBuffer* buffer, int handle, int index, int flip_mode,
@@ -283,69 +291,56 @@ void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuf
uint32_t* dst_gpu_addr, uint32_t value, uint32_t* dst_gpu_addr, uint32_t value,
int handle, int index, int flip_mode, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) { int64_t flip_arg, uint64_t request_id) {
EXIT_IF(g_render_ctx == nullptr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
EXIT_IF(dst_gpu_addr == nullptr); RecordEndOfPipeSignal({
EXIT_IF(buffer == nullptr); .buffer = buffer,
EXIT_IF(buffer->IsInvalid()); .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBackFlip), submit_id, .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
static_cast<uint32_t>(handle), static_cast<uint32_t>(index), static_cast<uint32_t>(flip_mode), value},
static_cast<uint32_t>(flip_mode), value, static_cast<uint64_t>(flip_arg)); .debug_data = static_cast<uint64_t>(flip_arg),
const uint64_t args[LABEL_ARGS_MAX] = {request_id}; .destination = destination,
SubmitLabel( .completion = EndOfPipeCompletion::FlipAndInterrupt,
buffer, CompleteDisplayBufferFlip, .completion_data = request_id,
[](const uint64_t* /*args*/) { });
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(0);
return true;
},
args);
} }
void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr,
uint32_t value, int handle, int index, int flip_mode, uint32_t value, int handle, int index, int flip_mode,
int64_t flip_arg, uint64_t request_id) { int64_t flip_arg, uint64_t request_id) {
EXIT_IF(g_render_ctx == nullptr); const auto destination = reinterpret_cast<uint64_t>(dst_gpu_addr);
EXIT_IF(dst_gpu_addr == nullptr); RecordEndOfPipeSignal({
EXIT_IF(buffer == nullptr); .buffer = buffer,
EXIT_IF(buffer->IsInvalid()); .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopFlip,
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopFlip), submit_id, .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
static_cast<uint32_t>(handle), static_cast<uint32_t>(index), static_cast<uint32_t>(flip_mode), value},
static_cast<uint32_t>(flip_mode), value, static_cast<uint64_t>(flip_arg)); .debug_data = static_cast<uint64_t>(flip_arg),
const uint64_t args[LABEL_ARGS_MAX] = {request_id}; .destination = destination,
SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args); .completion = EndOfPipeCompletion::Flip,
.completion_data = request_id,
});
} }
void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index, void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index,
int flip_mode, int64_t flip_arg, uint64_t request_id) { int flip_mode, int64_t flip_arg, uint64_t request_id) {
EXIT_IF(g_render_ctx == nullptr); RecordEndOfPipeSignal({
EXIT_IF(buffer == nullptr); .buffer = buffer,
EXIT_IF(buffer->IsInvalid()); .submit_id = submit_id,
.debug_operation = CommandBufferDebugOp::EopOnlyFlip,
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopOnlyFlip), submit_id, .debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
static_cast<uint32_t>(handle), static_cast<uint32_t>(index), static_cast<uint32_t>(flip_mode), 0},
static_cast<uint32_t>(flip_mode), 0, static_cast<uint64_t>(flip_arg)); .debug_data = static_cast<uint64_t>(flip_arg),
.completion = EndOfPipeCompletion::Flip,
const uint64_t args[LABEL_ARGS_MAX] = {request_id}; .completion_data = request_id,
SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args); });
} }
void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) { void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) {
EXIT_IF(g_render_ctx == nullptr); ValidateEndOfPipeSignal({.buffer = buffer});
EXIT_IF(buffer == nullptr);
EXIT_IF(buffer->IsInvalid());
uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)}; uint64_t args[LABEL_ARGS_MAX] = {static_cast<uint64_t>(context_id)};
SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args);
SubmitLabel(
buffer, nullptr,
[](const uint64_t* args) {
EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->TriggerEopEvent(static_cast<uint32_t>(args[0]));
return true;
},
args);
} }
static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) { static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
@@ -398,7 +393,8 @@ int AddEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) {
int result = LibKernel::EventQueue::KernelAddEvent(eq, event); int result = LibKernel::EventQueue::KernelAddEvent(eq, event);
if (id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP) { if (result == 0 &&
(id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) {
g_render_ctx->AddEopEq(eq, id); g_render_ctx->AddEopEq(eq, id);
} }
@@ -422,7 +418,7 @@ void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) {
void DeleteBuffers() { void DeleteBuffers() {
EXIT_IF(g_render_ctx == nullptr); EXIT_IF(g_render_ctx == nullptr);
g_render_ctx->GetBufferCache()->DeleteAll(g_render_ctx->GetGraphicCtx()); g_render_ctx->GetBufferCache()->ResetNullBuffer();
} }
} // namespace Libs::Graphics::Sync } // namespace Libs::Graphics::Sync
+50 -64
View File
@@ -18,7 +18,8 @@
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/renderTargetBarriers.h" #include "graphics/host_gpu/renderer/renderTargetBarriers.h"
#include "graphics/host_gpu/renderer/resourceMutex.h" #include "graphics/host_gpu/renderer/resourceMutex.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include "kernel/memory.h" #include "kernel/memory.h"
#include <algorithm> #include <algorithm>
@@ -104,9 +105,8 @@ struct TextureCache::CachedImage {
RenderTargetInfo target; RenderTargetInfo target;
DepthTargetInfo depth; DepthTargetInfo depth;
VideoOutInfo video_out; VideoOutInfo video_out;
GraphicContext* ctx = nullptr; GraphicContext* ctx = nullptr;
VulkanImage* image = nullptr; VulkanImage* image = nullptr;
VulkanMemory memory;
bool gpu_modified = false; bool gpu_modified = false;
bool buffer_modified = false; bool buffer_modified = false;
bool stencil_initialized = false; bool stencil_initialized = false;
@@ -119,21 +119,7 @@ struct TextureCache::CachedImage {
static_cast<const void*>(ctx), static_cast<const void*>(image), static_cast<const void*>(ctx), static_cast<const void*>(image),
static_cast<uint32_t>(kind), registered); static_cast<uint32_t>(kind), registered);
} }
switch (kind) { ImageOps::Destroy(ctx, image);
case Kind::Texture:
case Kind::StorageTexture:
ImageOps::Destroy(ctx, static_cast<GpuTextureVulkanImage*>(image), &memory);
break;
case Kind::RenderTarget:
ImageOps::Destroy(ctx, static_cast<RenderTextureVulkanImage*>(image), &memory);
break;
case Kind::DepthTarget:
ImageOps::Destroy(ctx, static_cast<DepthStencilVulkanImage*>(image), &memory);
break;
case Kind::VideoOut:
ImageOps::Destroy(ctx, static_cast<VideoOutVulkanImage*>(image), &memory);
break;
}
image = nullptr; image = nullptr;
} }
@@ -465,10 +451,10 @@ struct TextureCache::ReadbackWorker {
download.resize(info.size); download.resize(info.size);
std::fill(download.begin(), download.end(), 0); std::fill(download.begin(), download.end(), 0);
const auto regions = const auto regions =
MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width, Transfer::MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width,
info.height, vk::ImageAspectFlagBits::eDepth); info.height, vk::ImageAspectFlagBits::eDepth);
UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image, Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image,
cached.image->layout); cached.image->layout);
guest.resize(info.size); guest.resize(info.size);
cache.m_tiler.TileImage(guest.data(), download.data(), info); cache.m_tiler.TileImage(guest.data(), download.data(), info);
Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size); Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size);
@@ -478,11 +464,11 @@ struct TextureCache::ReadbackWorker {
[[nodiscard]] ReadbackRange DownloadColorImage(CachedImage& cached) { [[nodiscard]] ReadbackRange DownloadColorImage(CachedImage& cached) {
const bool storage = cached.kind == CachedImage::Kind::StorageTexture; const bool storage = cached.kind == CachedImage::Kind::StorageTexture;
const bool target = cached.kind == CachedImage::Kind::RenderTarget; const bool target = cached.kind == CachedImage::Kind::RenderTarget;
const auto info = storage ? MakeColorImageTransferInfo( const auto info =
cached.info, Prospero::SurfaceFormat(cached.info.format), storage ? MakeColorImageTransferInfo(cached.info, VulkanFormat(cached.info.format),
Prospero::NumBytesPerElement(cached.info.format)) Prospero::NumBytesPerElement(cached.info.format))
: MakeColorImageTransferInfo(cached.target); : MakeColorImageTransferInfo(cached.target);
const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear); const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
const bool tiled_target = target && IsTiledRenderTarget(cached.target); const bool tiled_target = target && IsTiledRenderTarget(cached.target);
const bool tiled_storage = const bool tiled_storage =
storage && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget); storage && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
@@ -520,10 +506,10 @@ struct TextureCache::ReadbackWorker {
} }
download.resize(info.size); download.resize(info.size);
std::fill(download.begin(), download.end(), 0); std::fill(download.begin(), download.end(), 0);
const auto regions = const auto regions = Transfer::MakeLayeredImageBufferCopies(layers, slice_size, info.pitch,
MakeLayeredImageBufferCopies(layers, slice_size, info.pitch, info.width, info.height); info.width, info.height);
UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image, Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image,
cached.image->layout); cached.image->layout);
if (tiled_target || tiled_storage) { if (tiled_target || tiled_storage) {
guest.resize(info.size); guest.resize(info.size);
const RenderTargetInfo layout = const RenderTargetInfo layout =
@@ -959,7 +945,7 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn
} }
RequireRetirementIsolation(retire, "sampled target", requested.address, requested.size); RequireRetirementIsolation(retire, "sampled target", requested.address, requested.size);
if (wait_idle) { if (wait_idle) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
for (auto* cached: retire) { for (auto* cached: retire) {
if (!cached->gpu_modified) { if (!cached->gpu_modified) {
@@ -1080,7 +1066,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag
if (selected == nullptr) { if (selected == nullptr) {
return; return;
} }
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
const auto transfer = m_readback->DownloadDepthTarget(*selected, false); const auto transfer = m_readback->DownloadDepthTarget(*selected, false);
m_memory_tracker.ForEachDownloadRange<true>(transfer.address, transfer.size, m_memory_tracker.ForEachDownloadRange<true>(transfer.address, transfer.size,
[](uint64_t, uint64_t) noexcept {}); [](uint64_t, uint64_t) noexcept {});
@@ -1091,7 +1077,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag
TextureCache::~TextureCache() { TextureCache::~TextureCache() {
m_readback.reset(); m_readback.reset();
if (!m_images.empty()) { if (!m_images.empty()) {
VulkanDeviceWaitIdle(m_images.front()->ctx); Transfer::WaitForGraphicsIdle(m_images.front()->ctx);
} }
for (const auto& image: m_images) { for (const auto& image: m_images) {
UnregisterImageLocked(*image, false); UnregisterImageLocked(*image, false);
@@ -1136,7 +1122,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c
info.address, info.size, metadata_read); info.address, info.size, metadata_read);
} }
std::shared_ptr<CachedImage> storage_match; std::shared_ptr<CachedImage> storage_match;
const auto requested_view_format = TextureGetFormat(info.format, TextureFormatUsage::Sampled); const auto requested_view_format = TextureGetFormat(info.format);
for (auto& cached: m_images) { for (auto& cached: m_images) {
if (cached->kind != CachedImage::Kind::StorageTexture) { if (cached->kind != CachedImage::Kind::StorageTexture) {
continue; continue;
@@ -1266,7 +1252,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c
cached->info = info; cached->info = info;
cached->ctx = ctx; cached->ctx = ctx;
vk::ComponentMapping components {}; vk::ComponentMapping components {};
cached->image = ImageOps::CreateTexture(ctx, info, false, &cached->memory, &components); cached->image = ImageOps::CreateTexture(ctx, info, false, &components);
m_memory_tracker.ForEachUploadRange( m_memory_tracker.ForEachUploadRange(
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
[&]() noexcept { [&]() noexcept {
@@ -1402,7 +1388,7 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com
cached->info = info; cached->info = info;
cached->ctx = ctx; cached->ctx = ctx;
vk::ComponentMapping components {}; vk::ComponentMapping components {};
cached->image = ImageOps::CreateTexture(ctx, info, true, &cached->memory, &components); cached->image = ImageOps::CreateTexture(ctx, info, true, &components);
m_memory_tracker.ForEachUploadRange( m_memory_tracker.ForEachUploadRange(
info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, info.address, info.size, true, [](uint64_t, uint64_t) noexcept {},
[&]() noexcept { [&]() noexcept {
@@ -1610,7 +1596,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
cached->kind = CachedImage::Kind::RenderTarget; cached->kind = CachedImage::Kind::RenderTarget;
cached->target = info; cached->target = info;
cached->ctx = ctx; cached->ctx = ctx;
cached->image = ImageOps::CreateRenderTarget(ctx, info, &cached->memory); cached->image = ImageOps::CreateRenderTarget(ctx, info);
const bool preserve_native = native_image_source != nullptr; const bool preserve_native = native_image_source != nullptr;
if (preserve_native) { if (preserve_native) {
command->RetainResourceUntilFence(native_image_source); command->RetainResourceUntilFence(native_image_source);
@@ -1636,7 +1622,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer*
regions.reserve(static_cast<size_t>(native_image_source->image->layers) * regions.reserve(static_cast<size_t>(native_image_source->image->layers) *
native_image_source->image->mip_levels); native_image_source->image->mip_levels);
AppendLayerCopies(regions, native_image_source->image, vk::ImageAspectFlagBits::eColor); AppendLayerCopies(regions, native_image_source->image, vk::ImageAspectFlagBits::eColor);
UtilImageToImage(command, regions, cached->image, RENDER_COLOR_IMAGE_LAYOUT); Transfer::CopyImage(command, regions, cached->image, RENDER_COLOR_IMAGE_LAYOUT);
} else { } else {
m_memory_tracker.ForEachUploadRange( m_memory_tracker.ForEachUploadRange(
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
@@ -1885,7 +1871,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
cached->depth = info; cached->depth = info;
cached->ctx = ctx; cached->ctx = ctx;
cached->stencil_initialized = !has_stencil; cached->stencil_initialized = !has_stencil;
cached->image = ImageOps::CreateDepthTarget(ctx, info, &cached->memory); cached->image = ImageOps::CreateDepthTarget(ctx, info);
if (discarded_depth_source != nullptr) { if (discarded_depth_source != nullptr) {
command->RetainResourceUntilFence(discarded_depth_source); command->RetainResourceUntilFence(discarded_depth_source);
} }
@@ -1939,13 +1925,13 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
AppendLayerCopies(regions, native_depth_source->image, AppendLayerCopies(regions, native_depth_source->image,
vk::ImageAspectFlagBits::eStencil); vk::ImageAspectFlagBits::eStencil);
} }
UtilImageToImage(command, regions, cached->image, Transfer::CopyImage(command, regions, cached->image,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
cached->gpu_modified = true; cached->gpu_modified = true;
} else { } else {
if (sampled_depth_source != nullptr && if (sampled_depth_source != nullptr &&
(sampled_depth_source->image->type != VulkanImageType::Texture || (sampled_depth_source->image->type != VulkanImageType::Texture ||
sampled_depth_source->image->format != Prospero::SurfaceFormat(info.guest_format) || sampled_depth_source->image->format != VulkanFormat(info.guest_format) ||
sampled_depth_source->image->extent.width != info.width || sampled_depth_source->image->extent.width != info.width ||
sampled_depth_source->image->extent.height != info.height)) { sampled_depth_source->image->extent.height != info.height)) {
EXIT("TextureCache: sampled-depth native source is inconsistent\n"); EXIT("TextureCache: sampled-depth native source is inconsistent\n");
@@ -1967,11 +1953,11 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
break; break;
case DepthTransitionSource::Native: case DepthTransitionSource::Native:
command->RetainResourceUntilFence(sampled_depth_source); command->RetainResourceUntilFence(sampled_depth_source);
UtilCopyImageWithBuffer(command, ctx, sampled_depth_source->image, Transfer::CopyImageViaBuffer(
vk::ImageAspectFlagBits::eColor, cached->image, command, ctx, sampled_depth_source->image,
vk::ImageAspectFlagBits::eDepth, vk::ImageAspectFlagBits::eColor, cached->image,
info.bytes_per_element, vk::ImageAspectFlagBits::eDepth, info.bytes_per_element,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
break; break;
} }
}); });
@@ -2036,7 +2022,7 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx,
cached->kind = CachedImage::Kind::VideoOut; cached->kind = CachedImage::Kind::VideoOut;
cached->video_out = info; cached->video_out = info;
cached->ctx = ctx; cached->ctx = ctx;
cached->image = ImageOps::CreateVideoOut(ctx, info, &cached->memory); cached->image = ImageOps::CreateVideoOut(ctx, info);
if (info.compression == VideoOutCompression::Uncompressed) { if (info.compression == VideoOutCompression::Uncompressed) {
m_memory_tracker.ForEachUploadRange( m_memory_tracker.ForEachUploadRange(
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
@@ -2147,7 +2133,7 @@ void TextureCache::UnregisterVideoOutSurfaces(const std::vector<VideoOutVulkanIm
cached->Address(), cached->Size()); cached->Address(), cached->Size());
} }
} }
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
for (auto* cached: selected) { for (auto* cached: selected) {
if (cached->gpu_modified) { if (cached->gpu_modified) {
m_memory_tracker.UnmarkRegionAsGpuModified(cached->Address(), cached->Size()); m_memory_tracker.UnmarkRegionAsGpuModified(cached->Address(), cached->Size());
@@ -2269,7 +2255,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr,
image_cpu_modified); image_cpu_modified);
} }
auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; auto vk_buffer = command->Handle();
if (aspect == ClearAspect::Color) { if (aspect == ClearAspect::Color) {
vk::ClearColorValue clear {}; vk::ClearColorValue clear {};
if (!DecodePackedColorClear(match->image->format, packed_clear, &clear)) { if (!DecodePackedColorClear(match->image->format, packed_clear, &clear)) {
@@ -2438,7 +2424,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
const auto& info = cached.info; const auto& info = cached.info;
target.address = info.address; target.address = info.address;
target.size = info.size; target.size = info.size;
target.format = Prospero::SurfaceFormat(info.format); target.format = VulkanFormat(info.format);
target.width = info.width; target.width = info.width;
target.height = info.height; target.height = info.height;
target.pitch = info.pitch; target.pitch = info.pitch;
@@ -2513,7 +2499,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
// This is the CPU Tiler backend for the image-to-buffer synchronization seam. // This is the CPU Tiler backend for the image-to-buffer synchronization seam.
// The vectors and Vulkan staging allocation retain capacity; a future PS5 GPU tiler can replace // The vectors and Vulkan staging allocation retain capacity; a future PS5 GPU tiler can replace
// this block without changing alias classification or ownership transitions. // this block without changing alias classification or ownership transitions.
VulkanDeviceWaitIdle(cached.ctx); Transfer::WaitForGraphicsIdle(cached.ctx);
m_buffer_transition_linear.resize(target.size); m_buffer_transition_linear.resize(target.size);
std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0); std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0);
std::vector<ImageBufferCopy> regions; std::vector<ImageBufferCopy> regions;
@@ -2533,11 +2519,11 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint
upload.dst_y, upload.dst_z, upload.aspect}); upload.dst_y, upload.dst_z, upload.aspect});
} }
} else { } else {
regions = MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch, regions = Transfer::MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch,
target.width, target.height); target.width, target.height);
} }
UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), target.size, regions, Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), target.size, regions,
cached.image, cached.image->layout); cached.image, cached.image->layout);
if (storage) { if (storage) {
m_buffer_transition_guest.resize(target.size); m_buffer_transition_guest.resize(target.size);
m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(), m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(),
@@ -2599,13 +2585,13 @@ void TextureCache::SynchronizeDepthImageToBufferLocked(CachedImage& cached, uint
info.layers, static_cast<int>(info.format), info.guest_format, info.bytes_per_element, info.layers, static_cast<int>(info.format), info.guest_format, info.bytes_per_element,
has_stencil, has_htile, cached.gpu_modified, cached.buffer_modified); has_stencil, has_htile, cached.gpu_modified, cached.buffer_modified);
} }
VulkanDeviceWaitIdle(cached.ctx); Transfer::WaitForGraphicsIdle(cached.ctx);
m_buffer_transition_linear.resize(info.size); m_buffer_transition_linear.resize(info.size);
std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0); std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0);
const auto regions = MakeLayeredImageBufferCopies(1, info.size, info.pitch, info.width, const auto regions = Transfer::MakeLayeredImageBufferCopies(
info.height, vk::ImageAspectFlagBits::eDepth); 1, info.size, info.pitch, info.width, info.height, vk::ImageAspectFlagBits::eDepth);
UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), info.size, regions, cached.image, Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), info.size, regions,
cached.image->layout); cached.image, cached.image->layout);
m_buffer_transition_guest.resize(info.size); m_buffer_transition_guest.resize(info.size);
m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(), info); m_tiler.TileImage(m_buffer_transition_guest.data(), m_buffer_transition_linear.data(), info);
Libs::LibKernel::Memory::WriteBacking(info.address, m_buffer_transition_guest.data(), Libs::LibKernel::Memory::WriteBacking(info.address, m_buffer_transition_guest.data(),
@@ -3169,7 +3155,7 @@ void TextureCache::UnmapMemory(uint64_t vaddr, uint64_t size) {
} }
} }
if (wait_ctx != nullptr) { if (wait_ctx != nullptr) {
VulkanDeviceWaitIdle(wait_ctx); Transfer::WaitForGraphicsIdle(wait_ctx);
} }
for (auto& cached: m_images) { for (auto& cached: m_images) {
if (!cached->OverlapsRange(vaddr, size, false) || !cached->gpu_modified) { if (!cached->OverlapsRange(vaddr, size, false) || !cached->gpu_modified) {
+17 -17
View File
@@ -7,7 +7,8 @@
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/objects/textureCommon.h"
#include "graphics/host_gpu/renderer/image.h" #include "graphics/host_gpu/renderer/image.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <vector> #include <vector>
@@ -26,7 +27,7 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage*
" host_slice=0x%016" PRIx64 " layers=%u\n", " host_slice=0x%016" PRIx64 " layers=%u\n",
slice_size, host_slice_size, info.layers); slice_size, host_slice_size, info.layers);
} }
UtilScratchBuffer host_linear(host_upload_size); Transfer::ScratchBuffer host_linear(host_upload_size);
std::vector<uint16_t> guest_linear(slice_size / sizeof(uint16_t)); std::vector<uint16_t> guest_linear(slice_size / sizeof(uint16_t));
std::vector<BufferImageCopy> regions; std::vector<BufferImageCopy> regions;
regions.reserve(info.layers); regions.reserve(info.layers);
@@ -48,14 +49,14 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage*
region.aspect = vk::ImageAspectFlagBits::eDepth; region.aspect = vk::ImageAspectFlagBits::eDepth;
regions.push_back(region); regions.push_back(region);
} }
UtilFillImage(ctx, image, host_linear.Data(), host_upload_size, regions, Transfer::UploadImage(ctx, image, host_linear.Data(), host_upload_size, regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const { const BufferImageCopySource& source, bool refresh, bool storage) const {
if (refresh) { if (refresh) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
const bool array_texture = TextureIsLayeredTexture(info.type); const bool array_texture = TextureIsLayeredTexture(info.type);
const bool volume_texture = TextureIs3DTexture(info.type); const bool volume_texture = TextureIs3DTexture(info.type);
@@ -77,7 +78,7 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source, const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const { bool refresh, uint32_t base_layer) const {
if (refresh) { if (refresh) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) { if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
switch (info.format) { switch (info.format) {
@@ -93,7 +94,7 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
} }
} }
const auto slice_size = info.size / info.layers; const auto slice_size = info.size / info.layers;
UtilScratchBuffer linear(info.size); Transfer::ScratchBuffer linear(info.size);
std::vector<BufferImageCopy> regions; std::vector<BufferImageCopy> regions;
regions.reserve(info.layers); regions.reserve(info.layers);
for (uint32_t layer = 0; layer < info.layers; layer++) { for (uint32_t layer = 0; layer < info.layers; layer++) {
@@ -110,8 +111,8 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
region.aspect = vk::ImageAspectFlagBits::eDepth; region.aspect = vk::ImageAspectFlagBits::eDepth;
regions.push_back(region); regions.push_back(region);
} }
UtilFillImage(ctx, image, linear.Data(), info.size, regions, Transfer::UploadImage(ctx, image, linear.Data(), info.size, regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
@@ -121,10 +122,10 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const auto stencil_pitch = TileGetTexturePitch( const auto stencil_pitch = TileGetTexturePitch(
stencil_format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth)); stencil_format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
if (refresh) { if (refresh) {
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
} }
const auto slice_size = info.stencil_size / info.layers; const auto slice_size = info.stencil_size / info.layers;
UtilScratchBuffer linear(info.stencil_size); Transfer::ScratchBuffer linear(info.stencil_size);
std::vector<BufferImageCopy> regions; std::vector<BufferImageCopy> regions;
regions.reserve(info.layers); regions.reserve(info.layers);
for (uint32_t layer = 0; layer < info.layers; layer++) { for (uint32_t layer = 0; layer < info.layers; layer++) {
@@ -141,8 +142,8 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
region.aspect = vk::ImageAspectFlagBits::eStencil; region.aspect = vk::ImageAspectFlagBits::eStencil;
regions.push_back(region); regions.push_back(region);
} }
UtilFillImage(ctx, image, linear.Data(), info.stencil_size, regions, Transfer::UploadImage(ctx, image, linear.Data(), info.stencil_size, regions,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) const { void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) const {
@@ -185,10 +186,9 @@ void Tiler::TileImage(void* dst, const void* src, const ImageInfo& info) const {
auto layout = TextureCalcUploadLayout(info.format, info.width, info.height, info.levels, auto layout = TextureCalcUploadLayout(info.format, info.width, info.height, info.levels,
info.depth, info.pitch, info.tile, info.size, true, false, info.depth, info.pitch, info.tile, info.size, true, false,
false, "StorageTextureReadback"); false, "StorageTextureReadback");
auto regions = TextureBuildUploadRegions(layout, Prospero::SurfaceFormat(info.format), auto regions = TextureBuildUploadRegions(
info.width, info.height, info.depth, info.levels, layout, VulkanFormat(info.format), info.width, info.height, info.depth, info.levels, false,
false, false, TextureUploadDestination::MipLevels, false, TextureUploadDestination::MipLevels, TextureUploadSliceLayout::MipChainPerSlice);
TextureUploadSliceLayout::MipChainPerSlice);
std::memset(dst, 0, info.size); std::memset(dst, 0, info.size);
for (uint32_t level = 0; level < info.levels; level++) { for (uint32_t level = 0; level < info.levels; level++) {
const auto& level_size = layout.level_sizes[level]; const auto& level_size = layout.level_sizes[level];
@@ -1,10 +1,11 @@
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/threads.h" #include "common/threads.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/imageView.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
@@ -16,7 +17,7 @@
#include <span> #include <span>
#include <vector> #include <vector>
namespace Libs::Graphics { namespace Libs::Graphics::Transfer {
static Common::Mutex g_scratch_buffer_mutex; static Common::Mutex g_scratch_buffer_mutex;
static std::unique_ptr<uint8_t[]> g_scratch_buffer; static std::unique_ptr<uint8_t[]> g_scratch_buffer;
@@ -43,7 +44,7 @@ std::vector<ImageBufferCopy> MakeLayeredImageBufferCopies(uint32_t layers, uint6
return regions; return regions;
} }
UtilScratchBuffer::UtilScratchBuffer(uint64_t size) { ScratchBuffer::ScratchBuffer(uint64_t size) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
g_scratch_buffer_mutex.Lock(); g_scratch_buffer_mutex.Lock();
@@ -56,11 +57,11 @@ UtilScratchBuffer::UtilScratchBuffer(uint64_t size) {
m_data = g_scratch_buffer.get(); m_data = g_scratch_buffer.get();
} }
UtilScratchBuffer::~UtilScratchBuffer() { ScratchBuffer::~ScratchBuffer() {
g_scratch_buffer_mutex.Unlock(); g_scratch_buffer_mutex.Unlock();
} }
bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size) { bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size) {
if ((size & 0x7u) == 0) { if ((size & 0x7u) == 0) {
if (size == 0) { if (size == 0) {
return false; return false;
@@ -80,7 +81,7 @@ bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size) {
return true; return true;
} }
void VulkanDeviceWaitIdle(GraphicContext* ctx) { void WaitForGraphicsIdle(GraphicContext* ctx) {
Common::Mutex* locked[GraphicContext::QUEUES_NUM] {}; Common::Mutex* locked[GraphicContext::QUEUES_NUM] {};
int locked_num = 0; int locked_num = 0;
@@ -117,64 +118,17 @@ void VulkanDeviceWaitIdle(GraphicContext* ctx) {
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
} }
void UtilResetImageViews(VulkanImage* image) {
for (auto& view: image->image_view) {
view = nullptr;
}
}
void UtilCreateImageView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer,
uint32_t base_mip_level, uint32_t layer_count, uint32_t level_count,
vk::Format view_format, vk::ImageUsageFlags view_usage) {
if (view_index < 0 || view_index >= VulkanImage::VIEW_MAX || image->image == nullptr ||
image->image_view[view_index] != nullptr) {
EXIT("invalid image-view creation target: image=%p index=%d current_view=%d\n",
static_cast<const void*>(image), view_index,
view_index >= 0 && view_index < VulkanImage::VIEW_MAX &&
image->image_view[view_index] != nullptr);
}
vk::ImageViewUsageCreateInfo usage_info {};
usage_info.sType = vk::StructureType::eImageViewUsageCreateInfo;
usage_info.pNext = nullptr;
usage_info.usage = view_usage;
vk::ImageViewCreateInfo create_info {};
create_info.sType = vk::StructureType::eImageViewCreateInfo;
create_info.pNext = (view_usage ? &usage_info : nullptr);
create_info.flags = {};
create_info.image = image->image;
create_info.viewType = view_type;
create_info.format = (view_format != vk::Format::eUndefined ? view_format : image->format);
create_info.components = components;
create_info.subresourceRange.aspectMask = aspect_mask;
create_info.subresourceRange.baseArrayLayer = base_array_layer;
create_info.subresourceRange.baseMipLevel = base_mip_level;
create_info.subresourceRange.layerCount = layer_count;
create_info.subresourceRange.levelCount = level_count;
const auto result =
ctx->device.createImageView(&create_info, nullptr, &image->image_view[view_index]);
if (result != vk::Result::eSuccess || image->image_view[view_index] == nullptr) {
EXIT("failed to create image view: result=%d image_format=%d view_format=%d index=%d\n",
static_cast<int>(result), static_cast<int>(image->format),
static_cast<int>(create_info.format), view_index);
}
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask, uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout); vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout);
template <typename Recorder> template <typename Recorder>
static void ExecuteImmediateUtilCommands(const Recorder& recorder) { static void ExecuteImmediateCommands(const Recorder& recorder) {
// Keep synchronous utility submission behind one boundary so adopting a central scheduler does // Keep synchronous utility submission behind one boundary so adopting a central scheduler does
// not touch every caller. // not touch every caller.
CommandBuffer command(GraphicContext::QUEUE_UTIL); CommandBuffer command(GraphicContext::QUEUE_UTIL);
command.Begin(); command.Begin();
recorder(&command, command.GetPool()->buffers[command.GetIndex()]); recorder(&command, command.Handle());
command.End(); command.End();
command.Execute(); command.Execute();
command.WaitForFence(); command.WaitForFence();
@@ -220,18 +174,6 @@ static void SetBufferMemoryBarrier(vk::CommandBuffer command, vk::Buffer buffer,
0, nullptr); 0, nullptr);
} }
[[nodiscard]] static vk::ImageAspectFlags GetDepthStencilAspects(vk::Format format) {
switch (format) {
case vk::Format::eD16Unorm:
case vk::Format::eD32Sfloat: return vk::ImageAspectFlagBits::eDepth;
case vk::Format::eD16UnormS8Uint:
case vk::Format::eD24UnormS8Uint:
case vk::Format::eD32SfloatS8Uint:
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
default: EXIT("unsupported depth/stencil image format: %d\n", static_cast<int>(format));
}
}
[[nodiscard]] static vk::ImageAspectFlags GetTransferAspects(const VulkanImage& image, [[nodiscard]] static vk::ImageAspectFlags GetTransferAspects(const VulkanImage& image,
vk::ImageAspectFlags copy_aspect) { vk::ImageAspectFlags copy_aspect) {
if (copy_aspect == vk::ImageAspectFlagBits::eColor) { if (copy_aspect == vk::ImageAspectFlagBits::eColor) {
@@ -239,7 +181,7 @@ static void SetBufferMemoryBarrier(vk::CommandBuffer command, vk::Buffer buffer,
} }
if (copy_aspect == vk::ImageAspectFlagBits::eDepth || if (copy_aspect == vk::ImageAspectFlagBits::eDepth ||
copy_aspect == vk::ImageAspectFlagBits::eStencil) { copy_aspect == vk::ImageAspectFlagBits::eStencil) {
const auto aspects = GetDepthStencilAspects(image.format); const auto aspects = ImageViewOps::DepthAspectMask(image.format);
if (!(copy_aspect & aspects)) { if (!(copy_aspect & aspects)) {
EXIT("image transfer aspect is unavailable: format=%d copy=0x%x available=0x%x\n", EXIT("image transfer aspect is unavailable: format=%d copy=0x%x available=0x%x\n",
static_cast<int>(image.format), static_cast<int>(image.format),
@@ -257,7 +199,7 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu
std::span<const vk::BufferImageCopy> regions, std::span<const vk::BufferImageCopy> regions,
vk::ImageAspectFlags transition_aspects, vk::ImageAspectFlags transition_aspects,
vk::ImageLayout initial_layout, vk::ImageLayout final_layout) { vk::ImageLayout initial_layout, vk::ImageLayout final_layout) {
auto vk_command = command.GetPool()->buffers[command.GetIndex()]; auto vk_command = command.Handle();
SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, VK_WHOLE_SIZE, SetBufferMemoryBarrier(vk_command, src_buffer.buffer, 0, VK_WHOLE_SIZE,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -301,7 +243,7 @@ ConvertImageBufferCopies(std::span<const ImageBufferCopy> regions) {
static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image,
VulkanBuffer& dst_buffer, std::span<const ImageBufferCopy> regions, VulkanBuffer& dst_buffer, std::span<const ImageBufferCopy> regions,
vk::ImageLayout final_layout) { vk::ImageLayout final_layout) {
auto vk_command = command.GetPool()->buffers[command.GetIndex()]; auto vk_command = command.Handle();
vk::ImageAspectFlags aspects = {}; vk::ImageAspectFlags aspects = {};
for (const auto& region: regions) { for (const auto& region: regions) {
aspects |= GetTransferAspects(src_image, region.aspect); aspects |= GetTransferAspects(src_image, region.aspect);
@@ -399,7 +341,7 @@ public:
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect); RecordImageToBuffer(*command, *src_image, m_buffer, dst_pitch, src_layout, aspect);
}); });
@@ -411,7 +353,7 @@ public:
vk::ImageLayout src_layout) { vk::ImageLayout src_layout) {
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst); EnsureBuffer(ctx, size, vk::BufferUsageFlagBits::eTransferDst);
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout); RecordImageToBuffer(*command, *src_image, m_buffer, regions, src_layout);
}); });
std::memcpy(dst_data, m_mapped_data, size); std::memcpy(dst_data, m_mapped_data, size);
@@ -435,9 +377,9 @@ private:
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc); CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc);
if constexpr (WaitIdle) { if constexpr (WaitIdle) {
VulkanDeviceWaitIdle(ctx); WaitForGraphicsIdle(ctx);
} }
ExecuteImmediateUtilCommands(recorder); ExecuteImmediateCommands(recorder);
} }
void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size, void CopyFromHost(GraphicContext* ctx, const void* src_data, uint64_t size,
@@ -476,10 +418,7 @@ static ReusableStagingBuffer g_texture_staging_buffer;
static ReusableStagingBuffer g_vertex_staging_buffer; static ReusableStagingBuffer g_vertex_staging_buffer;
static ReusableStagingBuffer g_readback_staging_buffer; static ReusableStagingBuffer g_readback_staging_buffer;
static Common::Mutex g_compressed_image_copy_mutex; bool IsBlockCompressedFormat(vk::Format format) {
static VulkanBuffer g_compressed_image_copy_buffer;
bool UtilIsBcFormat(vk::Format format) {
return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock || return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock ||
format == vk::Format::eBc1RgbaUnormBlock || format == vk::Format::eBc1RgbaSrgbBlock || format == vk::Format::eBc1RgbaUnormBlock || format == vk::Format::eBc1RgbaSrgbBlock ||
format == vk::Format::eBc2UnormBlock || format == vk::Format::eBc2SrgbBlock || format == vk::Format::eBc2UnormBlock || format == vk::Format::eBc2SrgbBlock ||
@@ -490,7 +429,7 @@ bool UtilIsBcFormat(vk::Format format) {
format == vk::Format::eBc7UnormBlock || format == vk::Format::eBc7SrgbBlock; format == vk::Format::eBc7UnormBlock || format == vk::Format::eBc7SrgbBlock;
} }
uint32_t UtilGetBcBlockSize(vk::Format format) { uint32_t BlockCompressedBytesPerBlock(vk::Format format) {
switch (format) { switch (format) {
case vk::Format::eBc1RgbUnormBlock: case vk::Format::eBc1RgbUnormBlock:
case vk::Format::eBc1RgbSrgbBlock: case vk::Format::eBc1RgbSrgbBlock:
@@ -522,24 +461,6 @@ static uint32_t GetFormatTexelSize(vk::Format format) {
} }
} }
static VulkanBuffer* GetCompressedImageCopyBuffer(GraphicContext* ctx, uint64_t size) {
EXIT_IF(size == 0);
constexpr uint64_t buffer_size = 64ull * 1024ull * 1024ull;
EXIT_NOT_IMPLEMENTED(size > buffer_size);
Common::LockGuard lock(g_compressed_image_copy_mutex);
if (g_compressed_image_copy_buffer.buffer == nullptr) {
g_compressed_image_copy_buffer.usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
g_compressed_image_copy_buffer.memory.property = {};
VulkanCreateBuffer(ctx, buffer_size, &g_compressed_image_copy_buffer);
}
return &g_compressed_image_copy_buffer;
}
static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) { static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) {
switch (type) { switch (type) {
case StagingBufferType::Texture: return &g_texture_staging_buffer; case StagingBufferType::Texture: return &g_texture_staging_buffer;
@@ -551,6 +472,13 @@ static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) {
return nullptr; return nullptr;
} }
void ReleaseCachedResources(GraphicContext* ctx) {
EXIT_IF(ctx == nullptr);
g_texture_staging_buffer.Release(ctx);
g_vertex_staging_buffer.Release(ctx);
g_readback_staging_buffer.Release(ctx);
}
static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level,
uint32_t levels, vk::ImageAspectFlags aspect_mask, uint32_t levels, vk::ImageAspectFlags aspect_mask,
vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) { vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout) {
@@ -662,28 +590,35 @@ static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uin
dst_image->layout = new_image_layout; dst_image->layout = new_image_layout;
} }
static bool CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r, static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r,
VulkanImage* dst_image) { const VulkanImage& dst_image) {
if (r.src_aspect != vk::ImageAspectFlagBits::eColor || if (r.src_aspect != vk::ImageAspectFlagBits::eColor ||
r.dst_aspect != vk::ImageAspectFlagBits::eColor || !UtilIsBcFormat(dst_image->format)) { r.dst_aspect != vk::ImageAspectFlagBits::eColor ||
return false; !IsBlockCompressedFormat(dst_image.format)) {
return 0;
} }
auto src_texel_size = GetFormatTexelSize(r.src_image->format); auto src_texel_size = GetFormatTexelSize(r.src_image->format);
auto dst_block_size = UtilGetBcBlockSize(dst_image->format); auto dst_block_size = BlockCompressedBytesPerBlock(dst_image.format);
if (src_texel_size == 0 || src_texel_size != dst_block_size) { if (src_texel_size == 0 || src_texel_size != dst_block_size) {
return false; return 0;
} }
auto block_width = (r.width + 3u) / 4u; auto block_width = (r.width + 3u) / 4u;
auto block_height = (r.height + 3u) / 4u; auto block_height = (r.height + 3u) / 4u;
if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) { if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) {
return false; return 0;
} }
return static_cast<uint64_t>(block_width) * block_height * dst_block_size;
}
auto* ctx = WindowGetGraphicContext(); static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r,
auto* copy_buffer = GetCompressedImageCopyBuffer(ctx, static_cast<uint64_t>(block_width) * VulkanImage* dst_image, VulkanBuffer* copy_buffer) {
block_height * dst_block_size); const auto copy_size = CompressedImageCopyBufferSize(r, *dst_image);
EXIT_IF(copy_size == 0 || copy_buffer == nullptr || copy_buffer->buffer_size < copy_size);
const auto block_width = (r.width + 3u) / 4u;
const auto block_height = (r.height + 3u) / 4u;
const auto src_region = const auto src_region =
MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer, MakeBufferImageCopy(0, 0, vk::ImageAspectFlagBits::eColor, r.src_level, r.src_layer,
@@ -713,13 +648,11 @@ static bool CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const I
SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor, SetImageLayout(vk_buffer, r.src_image, r.src_level, 1, vk::ImageAspectFlagBits::eColor,
vk::ImageLayout::eTransferSrcOptimal, src_layout); vk::ImageLayout::eTransferSrcOptimal, src_layout);
return true;
} }
void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions, void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) { VulkanImage* dst_image, vk::ImageLayout dst_layout) {
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
bool same_image_copy = false; bool same_image_copy = false;
vk::ImageAspectFlags dst_transition_aspects = {}; vk::ImageAspectFlags dst_transition_aspects = {};
@@ -777,15 +710,28 @@ void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> reg
SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects,
dst_image->layout, vk::ImageLayout::eTransferDstOptimal); dst_image->layout, vk::ImageLayout::eTransferDstOptimal);
uint64_t compressed_copy_size = 0;
for (const auto& r: regions) {
compressed_copy_size =
std::max(compressed_copy_size, CompressedImageCopyBufferSize(r, *dst_image));
}
VulkanBuffer* compressed_copy_buffer = nullptr;
if (compressed_copy_size != 0) {
compressed_copy_buffer = new VulkanBuffer;
compressed_copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
compressed_copy_buffer->memory.property = {};
VulkanCreateBuffer(WindowGetGraphicContext(), compressed_copy_size, compressed_copy_buffer);
buffer->DeleteAfterFence(compressed_copy_buffer);
}
for (const auto& r: regions) { for (const auto& r: regions) {
vk::ImageCopy region; vk::ImageCopy region;
auto src_layout = r.src_image->layout; auto src_layout = r.src_image->layout;
if (r.src_aspect == vk::ImageAspectFlagBits::eColor && if (CompressedImageCopyBufferSize(r, *dst_image) != 0) {
r.dst_aspect == vk::ImageAspectFlagBits::eColor && CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer);
CopyBlockImageToCompressedImage(vk_buffer, r, dst_image)) {
continue; continue;
} }
@@ -817,10 +763,10 @@ void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> reg
vk::ImageLayout::eTransferDstOptimal, dst_layout); vk::ImageLayout::eTransferDstOptimal, dst_layout);
} }
void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image, void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image, vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element, vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout) { vk::ImageLayout dst_layout) {
if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) || if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) ||
(bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 || (bytes_per_element != 2 && bytes_per_element != 4) || src_image->layers != 1 ||
dst_image->layers != 1 || src_image->mip_levels != 1 || dst_image->mip_levels != 1 || dst_image->layers != 1 || src_image->mip_levels != 1 || dst_image->mip_levels != 1 ||
@@ -849,7 +795,7 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
// recording the recreate copy; commands already recorded on this buffer remain ordered by the // recording the recreate copy; commands already recorded on this buffer remain ordered by the
// barriers below. The preservation policy stays isolated here so a future scheduler can replace // barriers below. The preservation policy stays isolated here so a future scheduler can replace
// this synchronization without changing texture-cache ownership logic. // this synchronization without changing texture-cache ownership logic.
VulkanDeviceWaitIdle(ctx); WaitForGraphicsIdle(ctx);
auto* copy_buffer = new VulkanBuffer; auto* copy_buffer = new VulkanBuffer;
copy_buffer->usage = copy_buffer->usage =
vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
@@ -857,7 +803,7 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer); VulkanCreateBuffer(ctx, copy_buffer_size, copy_buffer);
buffer->DeleteAfterFence(copy_buffer); buffer->DeleteAfterFence(copy_buffer);
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
const auto src_layout = src_image->layout; const auto src_layout = src_image->layout;
const auto final_layout = dst_layout; const auto final_layout = dst_layout;
SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout, SetImageLayout(vk_buffer, src_image, 0, 1, src_aspect, src_layout,
@@ -894,9 +840,9 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI
final_layout); final_layout);
} }
void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image, void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain) { VulkanSwapchain* dst_swapchain) {
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; auto vk_buffer = buffer->Handle();
if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) { if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) {
EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n", EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n",
static_cast<const void*>(src_image), static_cast<const void*>(src_image),
@@ -939,9 +885,8 @@ void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image,
vk::Filter::eLinear); vk::Filter::eLinear);
} }
void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image, void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) {
const vk::ClearColorValue& color) { auto vk_buffer = buffer->Handle();
auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()];
SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout, SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout,
vk::ImageLayout::eTransferDstOptimal); vk::ImageLayout::eTransferDstOptimal);
const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}; const vk::ImageSubresourceRange range {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
@@ -951,105 +896,8 @@ void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal); vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eTransferSrcOptimal);
} }
void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer) { void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
KYTY_PROFILER_FUNCTION(); uint32_t src_pitch, vk::ImageLayout dst_layout) {
EXIT_IF(buffer->buffer != nullptr);
vk::BufferCreateInfo buffer_info {};
buffer_info.sType = vk::StructureType::eBufferCreateInfo;
buffer_info.size = size;
buffer_info.usage = buffer->usage;
buffer_info.sharingMode = vk::SharingMode::eExclusive;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags =
static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property);
vk::Buffer::CType native_buffer = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateBuffer(
gctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info),
&alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info));
buffer->buffer = native_buffer;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(gctx);
}
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
gctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size;
VulkanTrackAllocation(&buffer->memory);
}
void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(buffer->memory.allocation == nullptr);
VulkanUntrackAllocation(&buffer->memory);
vmaDestroyBuffer(gctx->allocator, buffer->buffer, buffer->memory.allocation);
buffer->buffer = nullptr;
buffer->memory.memory = nullptr;
buffer->memory.allocation = nullptr;
buffer->memory.allocation_info = {};
buffer->memory.offset = 0;
}
bool VulkanCreateImage(GraphicContext* gctx, const vk::ImageCreateInfo* image_info,
VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(image->image != nullptr);
EXIT_IF(memory->allocation != nullptr);
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory->property);
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage(
gctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(*image_info),
&alloc_info, &native_image, &memory->allocation, &memory->allocation_info));
image->image = native_image;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(gctx);
return false;
}
gctx->device.getImageMemoryRequirements(image->image, &memory->requirements);
memory->type = memory->allocation_info.memoryType;
memory->memory = memory->allocation_info.deviceMemory;
memory->offset = memory->allocation_info.offset;
memory->unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(memory);
return true;
}
void VulkanDeleteImage(GraphicContext* gctx, VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(memory->allocation == nullptr);
VulkanUntrackAllocation(memory);
vmaDestroyImage(gctx->allocator, image->image, memory->allocation);
image->image = nullptr;
memory->memory = nullptr;
memory->allocation = nullptr;
memory->allocation_info = {};
memory->offset = 0;
}
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0); EXIT_IF(size == 0);
@@ -1059,9 +907,9 @@ void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_
vk::ImageLayout::eUndefined, dst_layout); vk::ImageLayout::eUndefined, dst_layout);
} }
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout, VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect) { vk::ImageAspectFlags aspect) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0); EXIT_IF(size == 0);
@@ -1070,67 +918,49 @@ void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t
->DownloadFromImage(ctx, dst_data, size, dst_pitch, src_image, src_layout, aspect); ->DownloadFromImage(ctx, dst_data, size, dst_pitch, src_image, src_layout, aspect);
} }
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image, std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout) { vk::ImageLayout src_layout) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(size == 0 || regions.empty()); EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::ReadBack) GetStagingBuffer(StagingBufferType::ReadBack)
->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout); ->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout);
} }
void UtilSetImageLayoutOptimal(VulkanImage* image) { void UploadImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
SetImageLayout(vk_command, image, 0, VK_REMAINING_MIP_LEVELS,
vk::ImageAspectFlagBits::eColor, image->layout, vk::ImageLayout::eGeneral);
});
}
void UtilFillImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout) {
EXIT_IF(size == 0 || regions.empty()); EXIT_IF(size == 0 || regions.empty());
GetStagingBuffer(StagingBufferType::Texture) GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, regions, dst_layout); ->UploadToImage(ctx, image, src_data, size, regions, dst_layout);
} }
void UtilFillImage(GraphicContext* ctx, std::span<const ImageImageCopy> regions, void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout) { VulkanImage* dst_image, vk::ImageLayout dst_layout) {
ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) { ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) {
UtilImageToImage(command, regions, dst_image, dst_layout); CopyImage(command, regions, dst_image, dst_layout);
}); });
} }
void UtilFillImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data, void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) { uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
GetStagingBuffer(StagingBufferType::Texture) GetStagingBuffer(StagingBufferType::Texture)
->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout, ->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout,
vk::ImageLayout::eDepthStencilAttachmentOptimal); vk::ImageLayout::eDepthStencilAttachmentOptimal);
} }
void UtilUploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size) { uint64_t dst_offset, const void* src_data, uint64_t size) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset); EXIT_IF(dst_offset > dst_buffer->buffer_size || size > dst_buffer->buffer_size - dst_offset);
GetStagingBuffer(type)->UploadToBuffer(ctx, dst_buffer, src_data, size, dst_offset); GetStagingBuffer(type)->UploadToBuffer(ctx, dst_buffer, src_data, size, dst_offset);
} }
void UtilReleaseCachedResources(GraphicContext* ctx) { void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) {
EXIT_IF(ctx == nullptr);
g_texture_staging_buffer.Release(ctx);
g_vertex_staging_buffer.Release(ctx);
g_readback_staging_buffer.Release(ctx);
Common::LockGuard lock(g_compressed_image_copy_mutex);
if (g_compressed_image_copy_buffer.buffer != nullptr) {
VulkanDeleteBuffer(ctx, &g_compressed_image_copy_buffer);
}
}
void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size) {
EXIT_IF(size == 0 || size > src_buffer->buffer_size || size > dst_buffer->buffer_size); EXIT_IF(size == 0 || size > src_buffer->buffer_size || size > dst_buffer->buffer_size);
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size, SetBufferMemoryBarrier(vk_command, src_buffer->buffer, 0, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -1149,8 +979,8 @@ void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t
}); });
} }
void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset, void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size) { void* dst_data, uint64_t size) {
EXIT_IF(size == 0); EXIT_IF(size == 0);
EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset); EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset);
const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family; const auto family = ctx->queues[GraphicContext::QUEUE_UTIL].family;
@@ -1176,7 +1006,7 @@ void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t
vk::MemoryPropertyFlagBits::eHostCached; vk::MemoryPropertyFlagBits::eHostCached;
VulkanCreateBuffer(ctx, size, &readback); VulkanCreateBuffer(ctx, size, &readback);
ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { ExecuteImmediateCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) {
SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size, SetBufferMemoryBarrier(vk_command, src_buffer->buffer, src_offset, size,
vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands,
@@ -1196,4 +1026,4 @@ void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t
VulkanDeleteBuffer(ctx, &readback); VulkanDeleteBuffer(ctx, &readback);
} }
} // namespace Libs::Graphics } // namespace Libs::Graphics::Transfer
+148
View File
@@ -0,0 +1,148 @@
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
#include "common/abi.h"
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <span>
#include <utility>
#include <vector>
namespace Libs::Graphics {
class CommandBuffer;
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct DepthStencilVulkanImage;
struct VulkanSwapchain;
struct BufferImageCopy {
uint32_t offset;
uint32_t pitch;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t dst_layer = 0;
int dst_x;
int dst_y;
int dst_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageBufferCopy {
uint32_t offset;
uint32_t pitch;
uint32_t src_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t src_layer = 0;
int src_x;
int src_y;
int src_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageImageCopy {
VulkanImage* src_image;
uint32_t src_level;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t src_layer = 0;
uint32_t dst_layer = 0;
vk::ImageAspectFlags src_aspect = vk::ImageAspectFlagBits::eColor;
vk::ImageAspectFlags dst_aspect = vk::ImageAspectFlagBits::eColor;
int src_x;
int src_y;
int src_z = 0;
int dst_x;
int dst_y;
int dst_z = 0;
};
namespace Transfer {
[[nodiscard]] std::vector<ImageBufferCopy>
MakeLayeredImageBufferCopies(uint32_t layers, uint64_t slice_size, uint32_t pitch, uint32_t width,
uint32_t height,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
enum class StagingBufferType { Texture, Vertex, ReadBack };
class ScratchBuffer {
public:
explicit ScratchBuffer(uint64_t size);
~ScratchBuffer();
KYTY_CLASS_NO_COPY(ScratchBuffer);
[[nodiscard]] void* Data() const { return m_data; }
private:
void* m_data = nullptr;
};
void CopyImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void CopyImageViaBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout);
void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, VulkanSwapchain* dst_swapchain);
void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout);
void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void CopyImageImmediate(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout);
void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size);
void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size);
void ReleaseCachedResources(GraphicContext* ctx);
bool GuestBufferIsTiled(uint64_t vaddr, uint64_t size);
bool IsBlockCompressedFormat(vk::Format format);
uint32_t BlockCompressedBytesPerBlock(vk::Format format);
void WaitForGraphicsIdle(GraphicContext* ctx);
inline std::pair<int, int> MipmapAtlasOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width;
uint32_t mip_height = height;
int mip_x = 0;
int mip_y = 0;
for (uint32_t i = 0; i < 16; i++) {
if (i == lod) {
return {mip_x, mip_y};
}
bool odd = ((i & 1u) != 0);
mip_x += static_cast<int>(odd ? mip_width : 0);
mip_y += static_cast<int>(odd ? 0 : mip_height);
mip_width >>= (mip_width > 1 ? 1u : 0u);
mip_height >>= (mip_height > 1 ? 1u : 0u);
}
return {mip_x, mip_y};
}
} // namespace Transfer
} // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_TRANSFER_H_
-160
View File
@@ -1,160 +0,0 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_
#include "common/abi.h"
#include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
#include <span>
#include <utility>
#include <vector>
namespace Libs::Graphics {
class CommandBuffer;
struct GraphicContext;
struct VulkanBuffer;
struct VulkanImage;
struct VulkanMemory;
struct DepthStencilVulkanImage;
struct VulkanSwapchain;
struct BufferImageCopy {
uint32_t offset;
uint32_t pitch;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t dst_layer = 0;
int dst_x;
int dst_y;
int dst_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageBufferCopy {
uint32_t offset;
uint32_t pitch;
uint32_t src_level;
uint32_t width;
uint32_t height;
uint32_t copy_height = 0;
uint32_t src_layer = 0;
int src_x;
int src_y;
int src_z = 0;
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor;
};
struct ImageImageCopy {
VulkanImage* src_image;
uint32_t src_level;
uint32_t dst_level;
uint32_t width;
uint32_t height;
uint32_t src_layer = 0;
uint32_t dst_layer = 0;
vk::ImageAspectFlags src_aspect = vk::ImageAspectFlagBits::eColor;
vk::ImageAspectFlags dst_aspect = vk::ImageAspectFlagBits::eColor;
int src_x;
int src_y;
int src_z = 0;
int dst_x;
int dst_y;
int dst_z = 0;
};
[[nodiscard]] std::vector<ImageBufferCopy>
MakeLayeredImageBufferCopies(uint32_t layers, uint64_t slice_size, uint32_t pitch, uint32_t width,
uint32_t height,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
enum class StagingBufferType { Texture, Vertex, ReadBack };
class UtilScratchBuffer {
public:
explicit UtilScratchBuffer(uint64_t size);
~UtilScratchBuffer();
KYTY_CLASS_NO_COPY(UtilScratchBuffer);
[[nodiscard]] void* Data() const { return m_data; }
private:
void* m_data = nullptr;
};
void UtilImageToImage(CommandBuffer* buffer, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanImage* src_image,
vk::ImageAspectFlags src_aspect, VulkanImage* dst_image,
vk::ImageAspectFlags dst_aspect, uint32_t bytes_per_element,
vk::ImageLayout dst_layout);
void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image,
VulkanSwapchain* dst_swapchain);
void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image,
const vk::ClearColorValue& color);
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
uint32_t src_pitch, vk::ImageLayout dst_layout);
void UtilFillImage(GraphicContext* ctx, DepthStencilVulkanImage* dst_image, const void* src_data,
uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect);
void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size,
std::span<const BufferImageCopy> regions, vk::ImageLayout dst_layout);
void UtilFillImage(GraphicContext* ctx, std::span<const ImageImageCopy> regions,
VulkanImage* dst_image, vk::ImageLayout dst_layout);
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch,
VulkanImage* src_image, vk::ImageLayout src_layout,
vk::ImageAspectFlags aspect = vk::ImageAspectFlagBits::eColor);
void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size,
std::span<const ImageBufferCopy> regions, VulkanImage* src_image,
vk::ImageLayout src_layout);
void UtilUploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer,
uint64_t dst_offset, const void* src_data, uint64_t size);
void UtilReleaseCachedResources(GraphicContext* ctx);
void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t size);
void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset,
void* dst_data, uint64_t size);
bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size);
void UtilSetImageLayoutOptimal(VulkanImage* image);
void UtilResetImageViews(VulkanImage* image);
void UtilCreateImageView(GraphicContext* ctx, VulkanImage* image, int view_index,
vk::ImageViewType view_type, vk::ImageAspectFlags aspect_mask,
vk::ComponentMapping components, uint32_t base_array_layer,
uint32_t base_mip_level, uint32_t layer_count, uint32_t level_count,
vk::Format view_format = vk::Format::eUndefined,
vk::ImageUsageFlags view_usage = {});
bool UtilIsBcFormat(vk::Format format);
uint32_t UtilGetBcBlockSize(vk::Format format);
void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer);
void VulkanDeleteBuffer(GraphicContext* gctx, VulkanBuffer* buffer);
bool VulkanCreateImage(GraphicContext* gctx, const vk::ImageCreateInfo* image_info,
VulkanImage* image, VulkanMemory* memory);
void VulkanDeleteImage(GraphicContext* gctx, VulkanImage* image, VulkanMemory* memory);
void VulkanDeviceWaitIdle(GraphicContext* ctx);
inline std::pair<int, int> UtilCalcMipmapOffset(uint32_t lod, uint32_t width, uint32_t height) {
uint32_t mip_width = width;
uint32_t mip_height = height;
int mip_x = 0;
int mip_y = 0;
for (uint32_t i = 0; i < 16; i++) {
if (i == lod) {
return {mip_x, mip_y};
}
bool odd = ((i & 1u) != 0);
mip_x += static_cast<int>(odd ? mip_width : 0);
mip_y += static_cast<int>(odd ? 0 : mip_height);
mip_width >>= (mip_width > 1 ? 1u : 0u);
mip_height >>= (mip_height > 1 ? 1u : 0u);
}
return {mip_x, mip_y};
}
} // namespace Libs::Graphics
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_UTILS_H_ */
+82 -65
View File
@@ -17,15 +17,11 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/profiler.h" #include "common/profiler.h"
#include "common/stringUtils.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include <atomic> #include <atomic>
#include <cinttypes> #include <cinttypes>
#include <fmt/format.h>
#include <string>
#include <vector>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -117,57 +113,96 @@ void VulkanLogMemoryBudget(GraphicContext* ctx) {
} }
} }
bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* memory) { void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || memory->memory != nullptr || EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
memory->allocation != nullptr || ctx->allocator == nullptr || buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0);
memory->requirements.size == 0);
const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); vk::BufferCreateInfo buffer_info {};
uint32_t index = 0; buffer_info.sType = vk::StructureType::eBufferCreateInfo;
for (; index < properties.memoryTypeCount; index++) { buffer_info.size = size;
if ((memory->requirements.memoryTypeBits & (uint32_t {1} << index)) != 0 && buffer_info.usage = buffer->usage;
(properties.memoryTypes[index].propertyFlags & memory->property) == memory->property) { buffer_info.sharingMode = vk::SharingMode::eExclusive;
break;
}
}
VmaAllocationCreateInfo info {}; VmaAllocationCreateInfo alloc_info {};
info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory->property); alloc_info.requiredFlags =
memory->unique_id = VulkanNextMemoryUniqueId(); static_cast<vk::MemoryPropertyFlags::MaskType>(buffer->memory.property);
const auto result = static_cast<vk::Result>(vmaAllocateMemory(
ctx->allocator,
static_cast<const vk::MemoryRequirements::NativeType*>(memory->requirements), &info,
&memory->allocation, &memory->allocation_info));
if (result == vk::Result::eSuccess) {
memory->type = memory->allocation_info.memoryType;
memory->memory = memory->allocation_info.deviceMemory;
memory->offset = memory->allocation_info.offset;
VulkanTrackAllocation(memory);
return true;
}
VulkanLogMemoryBudget(ctx); vk::Buffer::CType native_buffer = VK_NULL_HANDLE;
std::vector<std::string> stats; const auto result = static_cast<vk::Result>(vmaCreateBuffer(
for (uint32_t i = 0; i < properties.memoryTypeCount; i++) { ctx->allocator, static_cast<const vk::BufferCreateInfo::NativeType*>(buffer_info),
stats.push_back(fmt::format("{}, {}, {}", i, g_memory_stats.count[i].load(), &alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info));
g_memory_stats.allocated[i].load())); buffer->buffer = native_buffer;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
} }
EXIT("size = %" PRIu64 ", index = %u, error: %s:%s\n", memory->requirements.size, index, EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
VulkanToString(result).c_str(), Common::Concat(stats, '\n').c_str());
return false; ctx->device.getBufferMemoryRequirements(buffer->buffer, &buffer->memory.requirements);
buffer->memory.type = buffer->memory.allocation_info.memoryType;
buffer->memory.memory = buffer->memory.allocation_info.deviceMemory;
buffer->memory.offset = buffer->memory.allocation_info.offset;
buffer->memory.unique_id = VulkanNextMemoryUniqueId();
buffer->buffer_size = size;
VulkanTrackAllocation(&buffer->memory);
} }
void VulkanFree(GraphicContext* ctx, VulkanMemory* memory) { void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr || EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr ||
memory->allocation == nullptr); buffer->buffer == nullptr || buffer->memory.allocation == nullptr);
vmaFreeMemory(ctx->allocator, memory->allocation);
VulkanUntrackAllocation(memory); VulkanUntrackAllocation(&buffer->memory);
memory->memory = nullptr; vmaDestroyBuffer(ctx->allocator, buffer->buffer, buffer->memory.allocation);
memory->allocation = nullptr; buffer->buffer = nullptr;
memory->allocation_info = {}; buffer->memory.memory = nullptr;
memory->offset = 0; buffer->memory.allocation = nullptr;
buffer->memory.allocation_info = {};
buffer->memory.offset = 0;
}
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image != nullptr || image->memory.allocation != nullptr);
auto& memory = image->memory;
VmaAllocationCreateInfo alloc_info {};
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
vk::Image::CType native_image = VK_NULL_HANDLE;
const auto result = static_cast<vk::Result>(vmaCreateImage(
ctx->allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
&alloc_info, &native_image, &memory.allocation, &memory.allocation_info));
image->image = native_image;
if (result != vk::Result::eSuccess) {
VulkanLogMemoryBudget(ctx);
return false;
}
ctx->device.getImageMemoryRequirements(image->image, &memory.requirements);
memory.type = memory.allocation_info.memoryType;
memory.memory = memory.allocation_info.deviceMemory;
memory.offset = memory.allocation_info.offset;
memory.unique_id = VulkanNextMemoryUniqueId();
VulkanTrackAllocation(&memory);
return true;
}
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || image == nullptr ||
image->image == nullptr || image->memory.allocation == nullptr);
auto& memory = image->memory;
VulkanUntrackAllocation(&memory);
vmaDestroyImage(ctx->allocator, image->image, memory.allocation);
image->image = nullptr;
memory.memory = nullptr;
memory.allocation = nullptr;
memory.allocation_info = {};
memory.offset = 0;
} }
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) { void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data) {
@@ -185,22 +220,4 @@ void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) {
vmaUnmapMemory(ctx->allocator, memory->allocation); vmaUnmapMemory(ctx->allocator, memory->allocation);
} }
void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || image == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
EXIT_NOT_IMPLEMENTED(
static_cast<vk::Result>(vmaBindImageMemory(ctx->allocator, memory->allocation,
image->image)) != vk::Result::eSuccess);
}
void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* memory) {
KYTY_PROFILER_FUNCTION();
EXIT_IF(ctx == nullptr || buffer == nullptr || memory == nullptr || ctx->allocator == nullptr ||
memory->allocation == nullptr);
EXIT_NOT_IMPLEMENTED(
static_cast<vk::Result>(vmaBindBufferMemory(ctx->allocator, memory->allocation,
buffer->buffer)) != vk::Result::eSuccess);
}
} // namespace Libs::Graphics } // namespace Libs::Graphics
+6 -4
View File
@@ -2,6 +2,7 @@
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_
#include "common/common.h" #include "common/common.h"
#include "graphics/host_gpu/vulkanCommon.h"
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -16,12 +17,13 @@ uint64_t VulkanNextMemoryUniqueId();
void VulkanTrackAllocation(const VulkanMemory* memory); void VulkanTrackAllocation(const VulkanMemory* memory);
void VulkanUntrackAllocation(const VulkanMemory* memory); void VulkanUntrackAllocation(const VulkanMemory* memory);
void VulkanLogMemoryBudget(GraphicContext* ctx); void VulkanLogMemoryBudget(GraphicContext* ctx);
bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* memory); void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer);
void VulkanFree(GraphicContext* ctx, VulkanMemory* memory); void VulkanDeleteBuffer(GraphicContext* ctx, VulkanBuffer* buffer);
bool VulkanCreateImage(GraphicContext* ctx, const vk::ImageCreateInfo& image_info,
VulkanImage* image);
void VulkanDeleteImage(GraphicContext* ctx, VulkanImage* image);
void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data); void VulkanMapMemory(GraphicContext* ctx, VulkanMemory* memory, void** data);
void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory); void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory);
void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* memory);
void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* memory);
} // namespace Libs::Graphics } // namespace Libs::Graphics
+99
View File
@@ -1,8 +1,95 @@
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "common/assert.h"
#include "graphics/guest_gpu/gpu_defs.h"
#include <array>
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
namespace Libs::Graphics { namespace Libs::Graphics {
namespace {
struct FormatMapping {
Prospero::BufferFormat guest;
vk::Format host;
};
constexpr FormatMapping kFormatMappings[] = {
{Prospero::BufferFormat::k8UNorm, vk::Format::eR8Unorm},
{Prospero::BufferFormat::k8UInt, vk::Format::eR8Uint},
{Prospero::BufferFormat::k16UNorm, vk::Format::eR16Unorm},
{Prospero::BufferFormat::k16SNorm, vk::Format::eR16Snorm},
{Prospero::BufferFormat::k16UInt, vk::Format::eR16Uint},
{Prospero::BufferFormat::k16SInt, vk::Format::eR16Sint},
{Prospero::BufferFormat::k16Float, vk::Format::eR16Sfloat},
{Prospero::BufferFormat::k8_8UNorm, vk::Format::eR8G8Unorm},
{Prospero::BufferFormat::k8_8SNorm, vk::Format::eR8G8Snorm},
{Prospero::BufferFormat::k8_8UInt, vk::Format::eR8G8Uint},
{Prospero::BufferFormat::k8_8SInt, vk::Format::eR8G8Sint},
{Prospero::BufferFormat::k32UInt, vk::Format::eR32Uint},
{Prospero::BufferFormat::k32SInt, vk::Format::eR32Sint},
{Prospero::BufferFormat::k32Float, vk::Format::eR32Sfloat},
{Prospero::BufferFormat::k16_16UNorm, vk::Format::eR16G16Unorm},
{Prospero::BufferFormat::k16_16SNorm, vk::Format::eR16G16Snorm},
{Prospero::BufferFormat::k16_16UInt, vk::Format::eR16G16Uint},
{Prospero::BufferFormat::k16_16SInt, vk::Format::eR16G16Sint},
{Prospero::BufferFormat::k16_16Float, vk::Format::eR16G16Sfloat},
{Prospero::BufferFormat::k11_11_10Float, vk::Format::eB10G11R11UfloatPack32},
{Prospero::BufferFormat::k10_10_10_2UNorm, vk::Format::eA2B10G10R10UnormPack32},
{Prospero::BufferFormat::k8_8_8_8UNorm, vk::Format::eR8G8B8A8Unorm},
{Prospero::BufferFormat::k8_8_8_8SNorm, vk::Format::eR8G8B8A8Snorm},
{Prospero::BufferFormat::k8_8_8_8UInt, vk::Format::eR8G8B8A8Uint},
{Prospero::BufferFormat::k8_8_8_8SInt, vk::Format::eR8G8B8A8Sint},
{Prospero::BufferFormat::k32_32UInt, vk::Format::eR32G32Uint},
{Prospero::BufferFormat::k32_32SInt, vk::Format::eR32G32Sint},
{Prospero::BufferFormat::k32_32Float, vk::Format::eR32G32Sfloat},
{Prospero::BufferFormat::k16_16_16_16UNorm, vk::Format::eR16G16B16A16Unorm},
{Prospero::BufferFormat::k16_16_16_16SNorm, vk::Format::eR16G16B16A16Snorm},
{Prospero::BufferFormat::k16_16_16_16UInt, vk::Format::eR16G16B16A16Uint},
{Prospero::BufferFormat::k16_16_16_16SInt, vk::Format::eR16G16B16A16Sint},
{Prospero::BufferFormat::k16_16_16_16Float, vk::Format::eR16G16B16A16Sfloat},
{Prospero::BufferFormat::k32_32_32UInt, vk::Format::eR32G32B32Uint},
{Prospero::BufferFormat::k32_32_32SInt, vk::Format::eR32G32B32Sint},
{Prospero::BufferFormat::k32_32_32Float, vk::Format::eR32G32B32Sfloat},
{Prospero::BufferFormat::k32_32_32_32UInt, vk::Format::eR32G32B32A32Uint},
{Prospero::BufferFormat::k32_32_32_32SInt, vk::Format::eR32G32B32A32Sint},
{Prospero::BufferFormat::k32_32_32_32Float, vk::Format::eR32G32B32A32Sfloat},
{Prospero::BufferFormat::k8_8_8_8Srgb, vk::Format::eR8G8B8A8Srgb},
{Prospero::BufferFormat::k9_9_9_5Float, vk::Format::eE5B9G9R9UfloatPack32},
{Prospero::BufferFormat::k5_6_5UNorm, vk::Format::eB5G6R5UnormPack16},
{Prospero::BufferFormat::k5_5_5_1UNorm, vk::Format::eR5G5B5A1UnormPack16},
{Prospero::BufferFormat::k4_4_4_4UNorm, vk::Format::eR4G4B4A4UnormPack16},
{Prospero::BufferFormat::kFmask8_S4_F4, vk::Format::eR32Sfloat},
{Prospero::BufferFormat::kBc1UNorm, vk::Format::eBc1RgbaUnormBlock},
{Prospero::BufferFormat::kBc1Srgb, vk::Format::eBc1RgbaSrgbBlock},
{Prospero::BufferFormat::kBc2UNorm, vk::Format::eBc2UnormBlock},
{Prospero::BufferFormat::kBc2Srgb, vk::Format::eBc2SrgbBlock},
{Prospero::BufferFormat::kBc3UNorm, vk::Format::eBc3UnormBlock},
{Prospero::BufferFormat::kBc3Srgb, vk::Format::eBc3SrgbBlock},
{Prospero::BufferFormat::kBc4UNorm, vk::Format::eBc4UnormBlock},
{Prospero::BufferFormat::kBc4SNorm, vk::Format::eBc4SnormBlock},
{Prospero::BufferFormat::kBc5UNorm, vk::Format::eBc5UnormBlock},
{Prospero::BufferFormat::kBc5SNorm, vk::Format::eBc5SnormBlock},
{Prospero::BufferFormat::kBc6UFloat, vk::Format::eBc6HUfloatBlock},
{Prospero::BufferFormat::kBc6SFloat, vk::Format::eBc6HSfloatBlock},
{Prospero::BufferFormat::kBc7UNorm, vk::Format::eBc7UnormBlock},
{Prospero::BufferFormat::kBc7Srgb, vk::Format::eBc7SrgbBlock},
};
constexpr auto MakeFormatLookup() {
constexpr auto kMaxFormat = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc7Srgb);
std::array<vk::Format, kMaxFormat + 1> lookup {};
lookup.fill(vk::Format::eUndefined);
for (const auto& mapping: kFormatMappings) {
lookup[Prospero::GpuEnumValue(mapping.guest)] = mapping.host;
}
return lookup;
}
constexpr auto kFormatLookup = MakeFormatLookup();
} // namespace
std::string VulkanToString(vk::Result value) { std::string VulkanToString(vk::Result value) {
return vk::to_string(value); return vk::to_string(value);
@@ -20,4 +107,16 @@ std::string VulkanToString(vk::QueueFlags value) {
return vk::to_string(value); return vk::to_string(value);
} }
vk::Format VulkanFormat(uint32_t guest_format) {
return guest_format < kFormatLookup.size() ? kFormatLookup[guest_format]
: vk::Format::eUndefined;
}
void RequireVulkanSuccess(vk::Result result, const char* operation) {
if (result != vk::Result::eSuccess) {
EXIT("%s failed: %s (%d)\n", operation, VulkanToString(result).c_str(),
static_cast<int>(result));
}
}
} // namespace Libs::Graphics } // namespace Libs::Graphics
+25
View File
@@ -10,7 +10,9 @@
#define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#include <cstdint>
#include <string> #include <string>
#include <vector>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_hash.hpp> #include <vulkan/vulkan_hash.hpp>
@@ -27,6 +29,29 @@ std::string VulkanToString(vk::Result value);
std::string VulkanToString(vk::Format value); std::string VulkanToString(vk::Format value);
std::string VulkanToString(vk::ImageLayout value); std::string VulkanToString(vk::ImageLayout value);
std::string VulkanToString(vk::QueueFlags value); std::string VulkanToString(vk::QueueFlags value);
vk::Format VulkanFormat(uint32_t guest_format);
void RequireVulkanSuccess(vk::Result result, const char* operation);
template <typename T, typename Enumerator>
[[nodiscard]] std::vector<T> EnumerateVulkan(const char* operation, Enumerator&& enumerate) {
for (;;) {
uint32_t count = 0;
RequireVulkanSuccess(enumerate(&count, nullptr), operation);
if (count == 0) {
return {};
}
std::vector<T> values(count);
const auto result = enumerate(&count, values.data());
if (result == vk::Result::eSuccess) {
values.resize(count);
return values;
}
if (result != vk::Result::eIncomplete) {
RequireVulkanSuccess(result, operation);
}
}
}
} // namespace Libs::Graphics } // namespace Libs::Graphics
+255 -504
View File
@@ -57,6 +57,15 @@ constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED = 0;
constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_COMPRESSED = 1; constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_COMPRESSED = 1;
constexpr uint64_t VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8; constexpr uint64_t VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;
enum class VideoOutEventKind : uintptr_t {
Flip = VIDEO_OUT_EVENT_FLIP,
Vblank = VIDEO_OUT_EVENT_VBLANK,
PreVblankStart = VIDEO_OUT_EVENT_PRE_VBLANK_START,
OutputMode = VIDEO_OUT_EVENT_SET_MODE,
};
enum class FlipRequestSource { Cpu, GpuEop };
struct VideoOutBufferAttribute2 { struct VideoOutBufferAttribute2 {
uint32_t reserved0; uint32_t reserved0;
uint32_t tiling_mode; uint32_t tiling_mode;
@@ -160,10 +169,10 @@ struct VideoOutConfig {
class FlipQueue { class FlipQueue {
public: public:
FlipQueue() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } FlipQueue() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~FlipQueue() { KYTY_NOT_IMPLEMENTED; } ~FlipQueue() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(FlipQueue); KYTY_CLASS_NO_COPY(FlipQueue);
bool Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, bool gpu_eop, bool Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id); uint64_t* request_id);
void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer); void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer);
uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer); uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer);
@@ -183,7 +192,7 @@ private:
int index; int index;
int64_t flip_arg; int64_t flip_arg;
uint64_t submit_ptc; uint64_t submit_ptc;
bool gpu_eop; FlipRequestSource source;
RequestState state; RequestState state;
Graphics::PreparedFrame* frame; Graphics::PreparedFrame* frame;
}; };
@@ -203,7 +212,7 @@ public:
static constexpr int VIDEO_OUT_NUM_MAX = 2; static constexpr int VIDEO_OUT_NUM_MAX = 2;
VideoOutContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } VideoOutContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); }
virtual ~VideoOutContext() { KYTY_NOT_IMPLEMENTED; } ~VideoOutContext() { KYTY_NOT_IMPLEMENTED; }
KYTY_CLASS_NO_COPY(VideoOutContext); KYTY_CLASS_NO_COPY(VideoOutContext);
@@ -240,6 +249,167 @@ private:
static VideoOutContext* g_video_out_context = nullptr; static VideoOutContext* g_video_out_context = nullptr;
using VideoOutEventQueues = std::vector<EventQueue::KernelEqueue>;
static uintptr_t VideoOutEventId(VideoOutEventKind kind) {
return static_cast<uintptr_t>(kind);
}
static VideoOutEventKind GetVideoOutEventKind(uintptr_t event_id) {
switch (event_id) {
case VIDEO_OUT_EVENT_FLIP: return VideoOutEventKind::Flip;
case VIDEO_OUT_EVENT_VBLANK: return VideoOutEventKind::Vblank;
case VIDEO_OUT_EVENT_PRE_VBLANK_START: return VideoOutEventKind::PreVblankStart;
case VIDEO_OUT_EVENT_SET_MODE: return VideoOutEventKind::OutputMode;
default: EXIT("unsupported video-out event id=%" PRIuPTR "\n", event_id);
}
return VideoOutEventKind::Flip;
}
static VideoOutEventQueues& VideoOutEventQueuesFor(VideoOutConfig& video_out,
VideoOutEventKind kind) {
switch (kind) {
case VideoOutEventKind::Flip: return video_out.flip_eqs;
case VideoOutEventKind::Vblank: return video_out.vblank_eqs;
case VideoOutEventKind::PreVblankStart: return video_out.pre_vblank_eqs;
case VideoOutEventKind::OutputMode: return video_out.output_mode_eqs;
}
EXIT("unsupported video-out event kind\n");
return video_out.flip_eqs;
}
static intptr_t MakeVideoOutEventData(intptr_t current_data, void* trigger_data) {
const uint64_t old_data = static_cast<uint64_t>(current_data);
uint64_t counter = (old_data >> 12u) & 0xfu;
if (counter != 0xfu) {
counter++;
}
const uint64_t time = LibKernel::KernelReadTsc() & 0xfffu;
const uint64_t payload = static_cast<uint64_t>(reinterpret_cast<intptr_t>(trigger_data));
return static_cast<intptr_t>(time | (counter << 12u) |
((payload & 0x0000ffffffffffffULL) << 16u));
}
static void ResetVideoOutEvent(EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
event->triggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
static void TriggerVideoOutEvent(EventQueue::KernelEqueueEvent* event, void* trigger_data) {
EXIT_IF(event == nullptr);
auto triggered_event = event->event;
triggered_event.fflags =
triggered_event.fflags < 0xfu ? triggered_event.fflags + 1u : triggered_event.fflags;
triggered_event.data = MakeVideoOutEventData(triggered_event.data, trigger_data);
if (event->triggered) {
event->pending_events.push_back(triggered_event);
return;
}
event->event = triggered_event;
event->triggered = true;
}
static void RemoveVideoOutEventQueue(EventQueue::KernelEqueue eq,
EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(event->filter.data == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.filter != EventQueue::KERNEL_EVFILT_VIDEO_OUT);
auto* video_out = static_cast<VideoOutConfig*>(event->filter.data);
auto& queues = VideoOutEventQueuesFor(*video_out, GetVideoOutEventKind(event->event.ident));
Common::LockGuard lock(video_out->mutex);
EXIT_IF(queues.empty());
const auto entry = std::find(queues.begin(), queues.end(), eq);
EXIT_NOT_IMPLEMENTED(entry == queues.end());
*entry = nullptr;
}
static void TriggerVideoOutEventsLocked(const VideoOutEventQueues& queues, VideoOutEventKind kind,
void* trigger_data) {
for (auto eq: queues) {
if (eq == nullptr) {
continue;
}
const auto result = EventQueue::KernelTriggerEvent(
eq, VideoOutEventId(kind), EventQueue::KERNEL_EVFILT_VIDEO_OUT, trigger_data);
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
static void DeleteVideoOutEventsLocked(VideoOutEventQueues& queues, VideoOutEventKind kind) {
for (auto eq: queues) {
if (eq == nullptr) {
continue;
}
const auto result = EventQueue::KernelDeleteEvent(eq, VideoOutEventId(kind),
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
EXIT_NOT_IMPLEMENTED(result != OK);
}
queues.clear();
}
static int RegisterVideoOutEvent(int handle, EventQueue::KernelEqueue eq, VideoOutEventKind kind,
void* udata) {
EXIT_IF(g_video_out_context == nullptr);
auto* video_out = g_video_out_context->Get(handle);
if (video_out == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
Common::LockGuard lock(video_out->mutex);
if (kind == VideoOutEventKind::OutputMode) {
LOGF("\t eq = 0x%016" PRIx64 "\n"
"\t handle = %d\n"
"\t udata = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(eq), handle, reinterpret_cast<uint64_t>(udata));
}
if (eq == nullptr) {
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
auto& queues = VideoOutEventQueuesFor(*video_out, kind);
const bool add_queue = std::find(queues.begin(), queues.end(), eq) == queues.end();
const bool initially_triggered = kind == VideoOutEventKind::OutputMode;
void* const initial_trigger_data =
initially_triggered ? reinterpret_cast<void*>(video_out->output_mode) : nullptr;
EventQueue::KernelEqueueEvent event {};
event.triggered = initially_triggered;
event.event.ident = VideoOutEventId(kind);
event.event.filter = EventQueue::KERNEL_EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = initially_triggered ? 1u : 0u;
event.event.data = initially_triggered ? MakeVideoOutEventData(0, initial_trigger_data) : 0;
event.filter.delete_event_func = RemoveVideoOutEventQueue;
event.filter.reset_func = ResetVideoOutEvent;
event.filter.trigger_func = TriggerVideoOutEvent;
event.filter.data = video_out;
const int result = EventQueue::KernelAddEvent(eq, event);
if (result == OK && add_queue) {
queues.push_back(eq);
}
return result;
}
static int DeleteVideoOutEvent(int handle, EventQueue::KernelEqueue eq, VideoOutEventKind kind) {
EXIT_IF(g_video_out_context == nullptr);
if (g_video_out_context->Get(handle) == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (eq == nullptr) {
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
return EventQueue::KernelDeleteEvent(eq, VideoOutEventId(kind),
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
}
static void WaitForNextVblank() { static void WaitForNextVblank() {
static uint64_t next_vblank_ticks = 0; static uint64_t next_vblank_ticks = 0;
@@ -286,6 +456,38 @@ static bool IsSpecialBufferIndex(int index) {
return index == VIDEO_OUT_BUFFER_INDEX_BLANK || index == VIDEO_OUT_BUFFER_INDEX_BLACK; return index == VIDEO_OUT_BUFFER_INDEX_BLANK || index == VIDEO_OUT_BUFFER_INDEX_BLACK;
} }
static bool IsValidFlipMode(int mode) {
return mode >= VIDEO_OUT_FLIP_MODE_VSYNC && mode <= VIDEO_OUT_FLIP_MODE_VSYNC_MULTI;
}
static int ReserveFlipRequest(int handle, int index, int flip_mode, int64_t flip_arg,
FlipRequestSource source, uint64_t* request_id) {
EXIT_IF(g_video_out_context == nullptr || request_id == nullptr);
auto* video_out = g_video_out_context->Get(handle);
if (video_out == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (!IsValidFlipMode(flip_mode)) {
return VIDEO_OUT_ERROR_INVALID_VALUE;
}
if (!IsValidBufferIndex(index)) {
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
Common::LockGuard lock(video_out->mutex);
if (video_out->closing ||
(!IsSpecialBufferIndex(index) &&
(video_out->unregistering[index] || video_out->buffers[index].buffer_vulkan == nullptr))) {
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
if (!g_video_out_context->GetFlipQueue().Reserve(video_out, index, flip_arg, source,
request_id)) {
return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
}
return OK;
}
static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& attribute, static Graphics::VideoOutInfo MakeVideoOutInfo(const VideoOutBufferAttribute2& attribute,
uint64_t address, uint64_t metadata_address, uint64_t address, uint64_t metadata_address,
Graphics::VideoOutCompression compression) { Graphics::VideoOutCompression compression) {
@@ -396,54 +598,27 @@ void VideoOutContext::Close(int handle) {
EXIT_NOT_IMPLEMENTED(handle >= VIDEO_OUT_NUM_MAX); EXIT_NOT_IMPLEMENTED(handle >= VIDEO_OUT_NUM_MAX);
EXIT_NOT_IMPLEMENTED(!m_video_out_ctx[handle].opened); EXIT_NOT_IMPLEMENTED(!m_video_out_ctx[handle].opened);
m_video_out_ctx[handle].opened = false; auto& config = m_video_out_ctx[handle];
config.opened = false;
m_video_out_ctx[handle].mutex.Lock(); config.mutex.Lock();
if (m_video_out_ctx[handle].closing) { if (config.closing) {
EXIT("video-out handle is already closing\n"); EXIT("video-out handle is already closing\n");
} }
m_video_out_ctx[handle].closing = true; config.closing = true;
if (m_flip_queue.HasPending(&m_video_out_ctx[handle], VIDEO_OUT_BUFFER_INDEX_BLACK, if (m_flip_queue.HasPending(&config, VIDEO_OUT_BUFFER_INDEX_BLACK,
VIDEO_OUT_BUFFER_NUM_MAX - VIDEO_OUT_BUFFER_INDEX_BLACK)) { VIDEO_OUT_BUFFER_NUM_MAX - VIDEO_OUT_BUFFER_INDEX_BLACK)) {
EXIT("cannot close video-out handle with pending flips\n"); EXIT("cannot close video-out handle with pending flips\n");
} }
for (auto& flip_eq: m_video_out_ctx[handle].flip_eqs) { DeleteVideoOutEventsLocked(config.flip_eqs, VideoOutEventKind::Flip);
if (flip_eq != nullptr) { DeleteVideoOutEventsLocked(config.pre_vblank_eqs, VideoOutEventKind::PreVblankStart);
auto result = EventQueue::KernelDeleteEvent(flip_eq, VIDEO_OUT_EVENT_FLIP, DeleteVideoOutEventsLocked(config.vblank_eqs, VideoOutEventKind::Vblank);
EventQueue::KERNEL_EVFILT_VIDEO_OUT); DeleteVideoOutEventsLocked(config.output_mode_eqs, VideoOutEventKind::OutputMode);
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
m_video_out_ctx[handle].flip_eqs.clear();
for (auto& vblank_eq: m_video_out_ctx[handle].pre_vblank_eqs) {
if (vblank_eq != nullptr) {
auto result = EventQueue::KernelDeleteEvent(vblank_eq, VIDEO_OUT_EVENT_PRE_VBLANK_START,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
m_video_out_ctx[handle].pre_vblank_eqs.clear();
for (auto& vblank_eq: m_video_out_ctx[handle].vblank_eqs) {
if (vblank_eq != nullptr) {
auto result = EventQueue::KernelDeleteEvent(vblank_eq, VIDEO_OUT_EVENT_VBLANK,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
m_video_out_ctx[handle].vblank_eqs.clear();
for (auto& output_mode_eq: m_video_out_ctx[handle].output_mode_eqs) {
if (output_mode_eq != nullptr) {
auto result = EventQueue::KernelDeleteEvent(output_mode_eq, VIDEO_OUT_EVENT_SET_MODE,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
m_video_out_ctx[handle].output_mode_eqs.clear();
m_video_out_ctx[handle].flip_rate = 0; config.flip_rate = 0;
std::vector<Graphics::VideoOutVulkanImage*> images; std::vector<Graphics::VideoOutVulkanImage*> images;
for (const auto& buffer: m_video_out_ctx[handle].buffers) { for (const auto& buffer: config.buffers) {
if ((buffer.buffer == nullptr) != (buffer.buffer_vulkan == nullptr) || if ((buffer.buffer == nullptr) != (buffer.buffer_vulkan == nullptr) ||
(buffer.buffer_vulkan != nullptr && (buffer.buffer_vulkan != nullptr &&
(buffer.buffer_size == 0 || buffer.buffer_pitch == 0))) { (buffer.buffer_size == 0 || buffer.buffer_pitch == 0))) {
@@ -459,21 +634,17 @@ void VideoOutContext::Close(int handle) {
} }
Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images); Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images);
} }
for (auto& buffer: m_video_out_ctx[handle].buffers) { for (auto& buffer: config.buffers) {
buffer.buffer = nullptr; buffer = VideoOutBufferInfo {};
buffer.buffer_vulkan = nullptr;
buffer.buffer_size = 0;
buffer.buffer_pitch = 0;
buffer.set_id = 0;
} }
m_video_out_ctx[handle].buffers_sets.clear(); config.buffers_sets.clear();
for (bool unregistering: m_video_out_ctx[handle].unregistering) { for (bool unregistering: config.unregistering) {
if (unregistering) { if (unregistering) {
EXIT("video-out close raced with buffer unregistration\n"); EXIT("video-out close raced with buffer unregistration\n");
} }
} }
m_video_out_ctx[handle].mutex.Unlock(); config.mutex.Unlock();
} }
VideoOutConfig* VideoOutContext::Get(int handle) { VideoOutConfig* VideoOutContext::Get(int handle) {
@@ -503,15 +674,8 @@ void VideoOutContext::VblankBegin() {
ctx.pre_vblank_status.reserved = LibKernel::KernelReadTsc(); ctx.pre_vblank_status.reserved = LibKernel::KernelReadTsc();
ctx.pre_vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter(); ctx.pre_vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter();
for (auto& vblank_eq: ctx.pre_vblank_eqs) { TriggerVideoOutEventsLocked(ctx.pre_vblank_eqs, VideoOutEventKind::PreVblankStart,
if (vblank_eq != nullptr) { reinterpret_cast<void*>(ctx.pre_vblank_status.count));
auto result = EventQueue::KernelTriggerEvent(
vblank_eq, VIDEO_OUT_EVENT_PRE_VBLANK_START,
EventQueue::KERNEL_EVFILT_VIDEO_OUT,
reinterpret_cast<void*>(ctx.pre_vblank_status.count));
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
ctx.mutex.Unlock(); ctx.mutex.Unlock();
} }
} }
@@ -529,14 +693,8 @@ void VideoOutContext::VblankEnd() {
ctx.vblank_status.reserved = LibKernel::KernelReadTsc(); ctx.vblank_status.reserved = LibKernel::KernelReadTsc();
ctx.vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter(); ctx.vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter();
for (auto& vblank_eq: ctx.vblank_eqs) { TriggerVideoOutEventsLocked(ctx.vblank_eqs, VideoOutEventKind::Vblank,
if (vblank_eq != nullptr) { reinterpret_cast<void*>(ctx.vblank_status.count));
auto result = EventQueue::KernelTriggerEvent(
vblank_eq, VIDEO_OUT_EVENT_VBLANK, EventQueue::KERNEL_EVFILT_VIDEO_OUT,
reinterpret_cast<void*>(ctx.vblank_status.count));
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
ctx.mutex.Unlock(); ctx.mutex.Unlock();
} }
} }
@@ -574,7 +732,7 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer,
return ret; return ret;
} }
bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, bool gpu_eop, bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, FlipRequestSource source,
uint64_t* request_id) { uint64_t* request_id) {
EXIT_IF(cfg == nullptr || request_id == nullptr); EXIT_IF(cfg == nullptr || request_id == nullptr);
Common::LockGuard lock(m_mutex); Common::LockGuard lock(m_mutex);
@@ -582,7 +740,7 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, bool g
if (m_requests.size() + m_cpu_requests.size() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) { if (m_requests.size() + m_cpu_requests.size() >= VIDEO_OUT_FLIP_QUEUE_CAPACITY) {
return false; return false;
} }
auto& pending = gpu_eop ? m_requests : m_cpu_requests; auto& pending = source == FlipRequestSource::GpuEop ? m_requests : m_cpu_requests;
Request r {}; Request r {};
r.id = m_next_request_id++; r.id = m_next_request_id++;
@@ -590,7 +748,7 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, bool g
r.index = index; r.index = index;
r.flip_arg = flip_arg; r.flip_arg = flip_arg;
r.submit_ptc = LibKernel::KernelGetProcessTimeCounter(); r.submit_ptc = LibKernel::KernelGetProcessTimeCounter();
r.gpu_eop = gpu_eop; r.source = source;
r.state = RequestState::Reserved; r.state = RequestState::Reserved;
pending.push_back(r); pending.push_back(r);
@@ -598,7 +756,7 @@ bool FlipQueue::Reserve(VideoOutConfig* cfg, int index, int64_t flip_arg, bool g
cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size()); cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size());
cfg->flip_status.submitProcessTimeCounter = r.submit_ptc; cfg->flip_status.submitProcessTimeCounter = r.submit_ptc;
if (gpu_eop) { if (source == FlipRequestSource::GpuEop) {
cfg->flip_status.gcQueueNum++; cfg->flip_status.gcQueueNum++;
} }
@@ -782,7 +940,7 @@ bool FlipQueue::Flip(uint32_t micros) {
r.cfg->flip_status.flipArg = r.flip_arg; r.cfg->flip_status.flipArg = r.flip_arg;
r.cfg->flip_status.currentBuffer = r.index; r.cfg->flip_status.currentBuffer = r.index;
r.cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size()); r.cfg->flip_status.flipPendingNum = static_cast<int>(m_requests.size() + m_cpu_requests.size());
if (r.gpu_eop && r.cfg->flip_status.gcQueueNum > 0) { if (r.source == FlipRequestSource::GpuEop && r.cfg->flip_status.gcQueueNum > 0) {
r.cfg->flip_status.gcQueueNum--; r.cfg->flip_status.gcQueueNum--;
} }
@@ -792,14 +950,8 @@ bool FlipQueue::Flip(uint32_t micros) {
m_mutex.Unlock(); m_mutex.Unlock();
r.cfg->mutex.Lock(); r.cfg->mutex.Lock();
for (auto& flip_eq: r.cfg->flip_eqs) { TriggerVideoOutEventsLocked(r.cfg->flip_eqs, VideoOutEventKind::Flip,
if (flip_eq != nullptr) { reinterpret_cast<void*>(r.flip_arg));
auto result = EventQueue::KernelTriggerEvent(flip_eq, VIDEO_OUT_EVENT_FLIP,
EventQueue::KERNEL_EVFILT_VIDEO_OUT,
reinterpret_cast<void*>(r.flip_arg));
EXIT_NOT_IMPLEMENTED(result != OK);
}
}
r.cfg->mutex.Unlock(); r.cfg->mutex.Unlock();
if (Config::GraphicsDebugDumpEnabled() && if (Config::GraphicsDebugDumpEnabled() &&
@@ -926,398 +1078,42 @@ KYTY_SYSV_ABI int VideoOutSetFlipRate(int handle, int rate) {
return OK; return OK;
} }
static void FlipEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
event->triggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
static void FlipEventDeleteFunc(EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(event->filter.data == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.ident != VIDEO_OUT_EVENT_FLIP);
EXIT_NOT_IMPLEMENTED(event->event.filter != EventQueue::KERNEL_EVFILT_VIDEO_OUT);
if (event->filter.data != nullptr) {
auto* video_out = static_cast<VideoOutConfig*>(event->filter.data);
video_out->mutex.Lock();
EXIT_IF(video_out->flip_eqs.empty());
auto it = std::find(video_out->flip_eqs.begin(), video_out->flip_eqs.end(), eq);
EXIT_NOT_IMPLEMENTED(it == video_out->flip_eqs.end());
*it = nullptr;
video_out->mutex.Unlock();
}
}
static intptr_t MakeVideoOutEventData(intptr_t current_data, void* trigger_data) {
const uint64_t old_data = static_cast<uint64_t>(current_data);
uint64_t counter = (old_data >> 12u) & 0xfu;
if (counter != 0xfu) {
counter++;
}
const uint64_t time = LibKernel::KernelReadTsc() & 0xfffu;
const uint64_t payload = static_cast<uint64_t>(reinterpret_cast<intptr_t>(trigger_data));
return static_cast<intptr_t>(time | (counter << 12u) |
((payload & 0x0000ffffffffffffULL) << 16u));
}
static void FlipEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event,
void* trigger_data) {
EXIT_IF(event == nullptr);
auto triggered_event = event->event;
triggered_event.fflags =
((triggered_event.fflags < 0xfu) ? triggered_event.fflags + 1u : triggered_event.fflags);
triggered_event.data = MakeVideoOutEventData(triggered_event.data, trigger_data);
if (event->triggered) {
event->pending_events.push_back(triggered_event);
} else {
event->event = triggered_event;
event->triggered = true;
}
}
static void VblankEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
event->triggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
static void VblankEventDeleteFunc(EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(event->filter.data == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.ident != VIDEO_OUT_EVENT_VBLANK);
EXIT_NOT_IMPLEMENTED(event->event.filter != EventQueue::KERNEL_EVFILT_VIDEO_OUT);
if (event->filter.data != nullptr) {
auto* video_out = static_cast<VideoOutConfig*>(event->filter.data);
video_out->mutex.Lock();
EXIT_IF(video_out->vblank_eqs.empty());
auto it = std::find(video_out->vblank_eqs.begin(), video_out->vblank_eqs.end(), eq);
EXIT_NOT_IMPLEMENTED(it == video_out->vblank_eqs.end());
*it = nullptr;
video_out->mutex.Unlock();
}
}
static void PreVblankEventDeleteFunc(EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(event->filter.data == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.ident != VIDEO_OUT_EVENT_PRE_VBLANK_START);
EXIT_NOT_IMPLEMENTED(event->event.filter != EventQueue::KERNEL_EVFILT_VIDEO_OUT);
if (event->filter.data != nullptr) {
auto* video_out = static_cast<VideoOutConfig*>(event->filter.data);
video_out->mutex.Lock();
EXIT_IF(video_out->pre_vblank_eqs.empty());
auto it = std::find(video_out->pre_vblank_eqs.begin(), video_out->pre_vblank_eqs.end(), eq);
EXIT_NOT_IMPLEMENTED(it == video_out->pre_vblank_eqs.end());
*it = nullptr;
video_out->mutex.Unlock();
}
}
static void VblankEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event,
void* trigger_data) {
EXIT_IF(event == nullptr);
auto triggered_event = event->event;
triggered_event.fflags =
((triggered_event.fflags < 0xfu) ? triggered_event.fflags + 1u : triggered_event.fflags);
triggered_event.data = MakeVideoOutEventData(triggered_event.data, trigger_data);
if (event->triggered) {
event->pending_events.push_back(triggered_event);
} else {
event->event = triggered_event;
event->triggered = true;
}
}
static void OutputModeEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
event->triggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
static void OutputModeEventDeleteFunc(EventQueue::KernelEqueue eq,
LibKernel::EventQueue::KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
EXIT_IF(event->filter.data == nullptr);
EXIT_NOT_IMPLEMENTED(event->event.ident != VIDEO_OUT_EVENT_SET_MODE);
EXIT_NOT_IMPLEMENTED(event->event.filter != EventQueue::KERNEL_EVFILT_VIDEO_OUT);
if (event->filter.data != nullptr) {
auto* video_out = static_cast<VideoOutConfig*>(event->filter.data);
video_out->mutex.Lock();
EXIT_IF(video_out->output_mode_eqs.empty());
auto it =
std::find(video_out->output_mode_eqs.begin(), video_out->output_mode_eqs.end(), eq);
EXIT_NOT_IMPLEMENTED(it == video_out->output_mode_eqs.end());
*it = nullptr;
video_out->mutex.Unlock();
}
}
static void OutputModeEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event,
void* trigger_data) {
EXIT_IF(event == nullptr);
auto triggered_event = event->event;
triggered_event.fflags =
((triggered_event.fflags < 0xfu) ? triggered_event.fflags + 1u : triggered_event.fflags);
triggered_event.data = MakeVideoOutEventData(triggered_event.data, trigger_data);
if (event->triggered) {
event->pending_events.push_back(triggered_event);
} else {
event->event = triggered_event;
event->triggered = true;
}
}
KYTY_SYSV_ABI int VideoOutDeleteFlipEvent(EventQueue::KernelEqueue eq, int handle) { KYTY_SYSV_ABI int VideoOutDeleteFlipEvent(EventQueue::KernelEqueue eq, int handle) {
PRINT_NAME(); PRINT_NAME();
return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::Flip);
EXIT_IF(g_video_out_context == nullptr);
[[maybe_unused]] auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (eq == nullptr) {
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
return EventQueue::KernelDeleteEvent(eq, VIDEO_OUT_EVENT_FLIP,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
} }
KYTY_SYSV_ABI int VideoOutAddFlipEvent(EventQueue::KernelEqueue eq, int handle, void* udata) { KYTY_SYSV_ABI int VideoOutAddFlipEvent(EventQueue::KernelEqueue eq, int handle, void* udata) {
PRINT_NAME(); PRINT_NAME();
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::Flip, udata);
EXIT_IF(g_video_out_context == nullptr);
auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
ctx->mutex.Lock();
if (eq == nullptr) {
ctx->mutex.Unlock();
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
bool add_eq =
(std::find(ctx->flip_eqs.begin(), ctx->flip_eqs.end(), eq) == ctx->flip_eqs.end());
EventQueue::KernelEqueueEvent event;
event.triggered = false;
event.event.ident = VIDEO_OUT_EVENT_FLIP;
event.event.filter = EventQueue::KERNEL_EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = 0;
event.event.data = 0;
event.filter.delete_event_func = FlipEventDeleteFunc;
event.filter.reset_func = FlipEventResetFunc;
event.filter.trigger_func = FlipEventTriggerFunc;
event.filter.data = ctx;
int result = EventQueue::KernelAddEvent(eq, event);
if (add_eq) {
ctx->flip_eqs.push_back(eq);
}
ctx->mutex.Unlock();
return result;
} }
KYTY_SYSV_ABI int VideoOutDeleteVblankEvent(EventQueue::KernelEqueue eq, int handle) { KYTY_SYSV_ABI int VideoOutDeleteVblankEvent(EventQueue::KernelEqueue eq, int handle) {
PRINT_NAME(); PRINT_NAME();
return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::Vblank);
EXIT_IF(g_video_out_context == nullptr);
[[maybe_unused]] auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (eq == nullptr) {
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
return EventQueue::KernelDeleteEvent(eq, VIDEO_OUT_EVENT_VBLANK,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
} }
KYTY_SYSV_ABI int VideoOutDeletePreVblankStartEvent(EventQueue::KernelEqueue eq, int handle) { KYTY_SYSV_ABI int VideoOutDeletePreVblankStartEvent(EventQueue::KernelEqueue eq, int handle) {
PRINT_NAME(); PRINT_NAME();
return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::PreVblankStart);
EXIT_IF(g_video_out_context == nullptr);
[[maybe_unused]] auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (eq == nullptr) {
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
return EventQueue::KernelDeleteEvent(eq, VIDEO_OUT_EVENT_PRE_VBLANK_START,
EventQueue::KERNEL_EVFILT_VIDEO_OUT);
} }
KYTY_SYSV_ABI int VideoOutAddVblankEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, KYTY_SYSV_ABI int VideoOutAddVblankEvent(LibKernel::EventQueue::KernelEqueue eq, int handle,
void* udata) { void* udata) {
PRINT_NAME(); PRINT_NAME();
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::Vblank, udata);
EXIT_IF(g_video_out_context == nullptr);
auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
ctx->mutex.Lock();
if (eq == nullptr) {
ctx->mutex.Unlock();
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
bool add_eq =
(std::find(ctx->vblank_eqs.begin(), ctx->vblank_eqs.end(), eq) == ctx->vblank_eqs.end());
EventQueue::KernelEqueueEvent event;
event.triggered = false;
event.event.ident = VIDEO_OUT_EVENT_VBLANK;
event.event.filter = EventQueue::KERNEL_EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = 0;
event.event.data = 0;
event.filter.delete_event_func = VblankEventDeleteFunc;
event.filter.reset_func = VblankEventResetFunc;
event.filter.trigger_func = VblankEventTriggerFunc;
event.filter.data = ctx;
int result = EventQueue::KernelAddEvent(eq, event);
if (add_eq) {
ctx->vblank_eqs.push_back(eq);
}
ctx->mutex.Unlock();
return result;
} }
KYTY_SYSV_ABI int VideoOutAddPreVblankStartEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, KYTY_SYSV_ABI int VideoOutAddPreVblankStartEvent(LibKernel::EventQueue::KernelEqueue eq, int handle,
void* udata) { void* udata) {
PRINT_NAME(); PRINT_NAME();
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::PreVblankStart, udata);
EXIT_IF(g_video_out_context == nullptr);
auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
ctx->mutex.Lock();
if (eq == nullptr) {
ctx->mutex.Unlock();
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
bool add_eq = (std::find(ctx->pre_vblank_eqs.begin(), ctx->pre_vblank_eqs.end(), eq) ==
ctx->pre_vblank_eqs.end());
EventQueue::KernelEqueueEvent event;
event.triggered = false;
event.event.ident = VIDEO_OUT_EVENT_PRE_VBLANK_START;
event.event.filter = EventQueue::KERNEL_EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = 0;
event.event.data = 0;
event.filter.delete_event_func = PreVblankEventDeleteFunc;
event.filter.reset_func = VblankEventResetFunc;
event.filter.trigger_func = VblankEventTriggerFunc;
event.filter.data = ctx;
int result = EventQueue::KernelAddEvent(eq, event);
if (add_eq) {
ctx->pre_vblank_eqs.push_back(eq);
}
ctx->mutex.Unlock();
return result;
} }
KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue eq, int handle,
void* udata) { void* udata) {
PRINT_NAME(); PRINT_NAME();
return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::OutputMode, udata);
EXIT_IF(g_video_out_context == nullptr);
auto* ctx = g_video_out_context->Get(handle);
if (ctx == nullptr) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
ctx->mutex.Lock();
LOGF("\t eq = 0x%016" PRIx64 "\n"
"\t handle = %d\n"
"\t udata = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(eq), handle, reinterpret_cast<uint64_t>(udata));
if (eq == nullptr) {
ctx->mutex.Unlock();
return VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
}
bool add_eq = (std::find(ctx->output_mode_eqs.begin(), ctx->output_mode_eqs.end(), eq) ==
ctx->output_mode_eqs.end());
EventQueue::KernelEqueueEvent event;
event.triggered = true;
event.event.ident = VIDEO_OUT_EVENT_SET_MODE;
event.event.filter = EventQueue::KERNEL_EVFILT_VIDEO_OUT;
event.event.udata = udata;
event.event.fflags = 1;
event.event.data = MakeVideoOutEventData(0, reinterpret_cast<void*>(ctx->output_mode));
event.filter.delete_event_func = OutputModeEventDeleteFunc;
event.filter.reset_func = OutputModeEventResetFunc;
event.filter.trigger_func = OutputModeEventTriggerFunc;
event.filter.data = ctx;
int result = EventQueue::KernelAddEvent(eq, event);
if (add_eq) {
ctx->output_mode_eqs.push_back(eq);
}
ctx->mutex.Unlock();
return result;
} }
static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_index, static int RegisterBuffersInternal(VideoOutConfig* ctx, int set_id, int start_index,
@@ -1428,8 +1224,8 @@ KYTY_SYSV_ABI int VideoOutRegisterBuffers2(int handle, int set_index, int buffer
for (int i = 0; i < buffer_num; i++) { for (int i = 0; i < buffer_num; i++) {
LOGF("\t buffers[%d]: data=%p metadata=%p\n", i, buffers[i].data, buffers[i].metadata); LOGF("\t buffers[%d]: data=%p metadata=%p\n", i, buffers[i].data, buffers[i].metadata);
if (buffers[i].reserved[0] != nullptr || buffers[i].reserved[1] != nullptr) { if (buffers[i].reserved[0] != nullptr || buffers[i].reserved[1] != nullptr) {
LOGF("\t buffers[%d]: ignoring reserved fields {%p, %p}\n", i, LOGF("\t buffers[%d]: ignoring reserved fields {%p, %p}\n", i, buffers[i].reserved[0],
buffers[i].reserved[0], buffers[i].reserved[1]); buffers[i].reserved[1]);
} }
const auto data_address = reinterpret_cast<uint64_t>(buffers[i].data); const auto data_address = reinterpret_cast<uint64_t>(buffers[i].data);
const auto metadata_address = reinterpret_cast<uint64_t>(buffers[i].metadata); const auto metadata_address = reinterpret_cast<uint64_t>(buffers[i].metadata);
@@ -1543,33 +1339,14 @@ namespace Libs::VideoOut {
KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64_t flip_arg) { KYTY_SYSV_ABI int VideoOutSubmitFlip(int handle, int index, int flip_mode, int64_t flip_arg) {
PRINT_NAME(); PRINT_NAME();
EXIT_IF(g_video_out_context == nullptr); uint64_t request_id = 0;
const int result =
auto* ctx = g_video_out_context->Get(handle); ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, &request_id);
if (ctx == nullptr) { if (result == VIDEO_OUT_ERROR_INVALID_VALUE) {
return VIDEO_OUT_ERROR_INVALID_HANDLE;
}
if (flip_mode < VIDEO_OUT_FLIP_MODE_VSYNC || flip_mode > VIDEO_OUT_FLIP_MODE_VSYNC_MULTI) {
LOGF("\t unsupported flip_mode = %d\n", flip_mode); LOGF("\t unsupported flip_mode = %d\n", flip_mode);
return VIDEO_OUT_ERROR_INVALID_VALUE;
} }
if (result != OK) {
if (!IsValidBufferIndex(index)) { return result;
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
uint64_t request_id = 0;
{
Common::LockGuard lock(ctx->mutex);
const bool special = IsSpecialBufferIndex(index);
if (ctx->closing || (!special && (ctx->unregistering[index] ||
ctx->buffers[index].buffer_vulkan == nullptr))) {
return VIDEO_OUT_ERROR_INVALID_INDEX;
}
if (!g_video_out_context->GetFlipQueue().Reserve(ctx, index, flip_arg, false,
&request_id)) {
return VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
}
} }
Graphics::GraphicsRunSubmitFlipPreparation(); Graphics::GraphicsRunSubmitFlipPreparation();
@@ -1585,30 +1362,10 @@ int DisplayBufferSubmitFlipFromGpu(Graphics::CommandBuffer* buffer, int handle,
EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr || EXIT_IF(VideoOut::g_video_out_context == nullptr || Graphics::g_render_ctx == nullptr ||
buffer == nullptr || request_id == nullptr); buffer == nullptr || request_id == nullptr);
auto* ctx = VideoOut::g_video_out_context->Get(handle); const int result = VideoOut::ReserveFlipRequest(
if (ctx == nullptr) { handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id);
return VideoOut::VIDEO_OUT_ERROR_INVALID_HANDLE; if (result != OK) {
} return result;
if (flip_mode < VideoOut::VIDEO_OUT_FLIP_MODE_VSYNC ||
flip_mode > VideoOut::VIDEO_OUT_FLIP_MODE_VSYNC_MULTI) {
return VideoOut::VIDEO_OUT_ERROR_INVALID_VALUE;
}
if (!VideoOut::IsValidBufferIndex(index)) {
return VideoOut::VIDEO_OUT_ERROR_INVALID_INDEX;
}
{
Common::LockGuard lock(ctx->mutex);
const bool special = VideoOut::IsSpecialBufferIndex(index);
if (ctx->closing || (!special && (ctx->unregistering[index] ||
ctx->buffers[index].buffer_vulkan == nullptr))) {
return VideoOut::VIDEO_OUT_ERROR_INVALID_INDEX;
}
if (!VideoOut::g_video_out_context->GetFlipQueue().Reserve(ctx, index, flip_arg, true,
request_id)) {
return VideoOut::VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
}
} }
VideoOut::g_video_out_context->GetFlipQueue().Prepare(*request_id, buffer); VideoOut::g_video_out_context->GetFlipQueue().Prepare(*request_id, buffer);
@@ -1901,14 +1658,8 @@ KYTY_SYSV_ABI int VideoOutConfigureOutput(int handle, uint64_t mode,
ctx->mutex.Lock(); ctx->mutex.Lock();
ctx->output_mode = mode; ctx->output_mode = mode;
for (auto& output_mode_eq: ctx->output_mode_eqs) { TriggerVideoOutEventsLocked(ctx->output_mode_eqs, VideoOutEventKind::OutputMode,
if (output_mode_eq != nullptr) { reinterpret_cast<void*>(ctx->output_mode));
auto trigger_result = EventQueue::KernelTriggerEvent(
output_mode_eq, VIDEO_OUT_EVENT_SET_MODE, EventQueue::KERNEL_EVFILT_VIDEO_OUT,
reinterpret_cast<void*>(ctx->output_mode));
EXIT_NOT_IMPLEMENTED(trigger_result != OK);
}
}
ctx->mutex.Unlock(); ctx->mutex.Unlock();
return OK; return OK;
+23 -14
View File
@@ -29,7 +29,7 @@
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/renderDoc.h" #include "graphics/presentation/renderDoc.h"
@@ -155,7 +155,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
} }
if (dst.image != nullptr) { if (dst.image != nullptr) {
EXIT_IF(!dst.view_cache.views.empty()); EXIT_IF(!dst.view_cache.views.empty());
VulkanDeleteImage(ctx, &dst, &dst.memory); VulkanDeleteImage(ctx, &dst);
dst.memory = {}; dst.memory = {};
} }
@@ -178,7 +178,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk
create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
create.sharingMode = vk::SharingMode::eExclusive; create.sharingMode = vk::SharingMode::eExclusive;
create.samples = vk::SampleCountFlagBits::e1; create.samples = vk::SampleCountFlagBits::e1;
if (!VulkanCreateImage(ctx, &create, &dst, &dst.memory)) { if (!VulkanCreateImage(ctx, create, &dst)) {
EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n", EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n",
dst.extent.width, dst.extent.height, static_cast<int>(dst.format)); dst.extent.width, dst.extent.height, static_cast<int>(dst.format));
} }
@@ -248,13 +248,19 @@ VulkanSwapchain::~VulkanSwapchain() = default;
vk::SwapchainKHR swapchain = nullptr; vk::SwapchainKHR swapchain = nullptr;
device.createSwapchainKHR(&create_info, nullptr, &swapchain); RequireVulkanSuccess(device.createSwapchainKHR(&create_info, nullptr, &swapchain),
"vkCreateSwapchainKHR");
EXIT_IF(swapchain == nullptr);
device.getSwapchainImagesKHR(swapchain, swapchain_images_count, nullptr); auto images = EnumerateVulkan<vk::Image>(
EXIT_NOT_IMPLEMENTED(*swapchain_images_count == 0); "vkGetSwapchainImagesKHR", [&](uint32_t* count, vk::Image* values) {
return device.getSwapchainImagesKHR(swapchain, count, values);
});
EXIT_NOT_IMPLEMENTED(images.empty());
*swapchain_images = std::make_unique<vk::Image[]>(*swapchain_images_count); *swapchain_images_count = static_cast<uint32_t>(images.size());
device.getSwapchainImagesKHR(swapchain, swapchain_images_count, swapchain_images->get()); *swapchain_images = std::make_unique<vk::Image[]>(images.size());
std::copy(images.begin(), images.end(), swapchain_images->get());
*swapchain_image_views = std::make_unique<vk::ImageView[]>(*swapchain_images_count); *swapchain_image_views = std::make_unique<vk::ImageView[]>(*swapchain_images_count);
for (uint32_t i = 0; i < *swapchain_images_count; i++) { for (uint32_t i = 0; i < *swapchain_images_count; i++) {
@@ -275,7 +281,10 @@ VulkanSwapchain::~VulkanSwapchain() = default;
create_info.subresourceRange.layerCount = 1; create_info.subresourceRange.layerCount = 1;
create_info.subresourceRange.levelCount = 1; create_info.subresourceRange.levelCount = 1;
device.createImageView(&create_info, nullptr, &((*swapchain_image_views)[i])); RequireVulkanSuccess(
device.createImageView(&create_info, nullptr, &((*swapchain_image_views)[i])),
"vkCreateImageView");
EXIT_IF((*swapchain_image_views)[i] == nullptr);
} }
return swapchain; return swapchain;
@@ -330,7 +339,7 @@ static void VulkanDeleteSwapchain(GraphicContext* ctx, VulkanSwapchain* s) {
} }
auto swapchain_owner = std::unique_ptr<VulkanSwapchain>(s); auto swapchain_owner = std::unique_ptr<VulkanSwapchain>(s);
VulkanDeviceWaitIdle(ctx); Transfer::WaitForGraphicsIdle(ctx);
if (s->image_acquired_semaphores != nullptr) { if (s->image_acquired_semaphores != nullptr) {
for (uint32_t i = 0; i < s->swapchain_images_count; i++) { for (uint32_t i = 0; i < s->swapchain_images_count; i++) {
@@ -406,7 +415,7 @@ PreparedFrame* WindowPrepareFrame(CommandBuffer* buffer, VideoOutVulkanImage* im
ConfigurePreparedFrame(frame, image->extent, image->format); ConfigurePreparedFrame(frame, image->extent, image->format);
const std::array copies {ImageImageCopy { const std::array copies {ImageImageCopy {
.src_image = image, .width = image->extent.width, .height = image->extent.height}}; .src_image = image, .width = image->extent.width, .height = image->extent.height}};
UtilImageToImage(buffer, copies, &frame->image, vk::ImageLayout::eTransferSrcOptimal); Transfer::CopyImage(buffer, copies, &frame->image, vk::ImageLayout::eTransferSrcOptimal);
return frame; return frame;
} }
@@ -421,7 +430,7 @@ PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, ui
ConfigurePreparedFrame(frame, {width, height}, format); ConfigurePreparedFrame(frame, {width, height}, format);
vk::ClearColorValue clear {}; vk::ClearColorValue clear {};
clear.float32[3] = opaque ? 1.0f : 0.0f; clear.float32[3] = opaque ? 1.0f : 0.0f;
UtilClearColorImage(buffer, &frame->image, clear); Transfer::ClearColorImage(buffer, &frame->image, clear);
return frame; return frame;
} }
@@ -475,11 +484,11 @@ void WindowPresentFrame(PreparedFrame* frame) {
frame->present_commands->WaitForFenceAndReset(); frame->present_commands->WaitForFenceAndReset();
auto& buffer = *frame->present_commands; auto& buffer = *frame->present_commands;
auto vk_buffer = buffer.GetPool()->buffers[buffer.GetIndex()]; auto vk_buffer = buffer.Handle();
buffer.Begin(); buffer.Begin();
UtilBlitPreparedImage(&buffer, &frame->image, swapchain); Transfer::BlitToSwapchain(&buffer, &frame->image, swapchain);
vk::ImageMemoryBarrier pre_present_barrier {}; vk::ImageMemoryBarrier pre_present_barrier {};
pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier; pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier;
+81 -112
View File
@@ -28,7 +28,7 @@
#include "common/timer.h" #include "common/timer.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/renderDoc.h" #include "graphics/presentation/renderDoc.h"
@@ -81,36 +81,34 @@ static bool HasLayer(const std::vector<vk::LayerProperties>& layers, const char*
void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface,
SurfaceCapabilities* r) { SurfaceCapabilities* r) {
physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities); RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities),
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
uint32_t formats_count = 0; r->formats = EnumerateVulkan<vk::SurfaceFormatKHR>( // @suppress("Ambiguous problem")
physical_device.getSurfaceFormatsKHR(surface, &formats_count, nullptr); "vkGetPhysicalDeviceSurfaceFormatsKHR", [&](uint32_t* count, vk::SurfaceFormatKHR* values) {
return physical_device.getSurfaceFormatsKHR(surface, count, values);
});
EXIT_NOT_IMPLEMENTED(r->formats.empty());
EXIT_NOT_IMPLEMENTED(formats_count == 0); r->present_modes = EnumerateVulkan<vk::PresentModeKHR>( // @suppress("Ambiguous problem")
"vkGetPhysicalDeviceSurfacePresentModesKHR",
[&](uint32_t* count, vk::PresentModeKHR* values) {
return physical_device.getSurfacePresentModesKHR(surface, count, values);
});
EXIT_NOT_IMPLEMENTED(r->present_modes.empty());
r->formats = std::vector<vk::SurfaceFormatKHR>(formats_count); // @suppress("Ambiguous problem") r->format_srgb_bgra32 = false;
physical_device.getSurfaceFormatsKHR(surface, &formats_count, r->formats.data()); r->format_unorm_bgra32 = false;
uint32_t present_modes_count = 0;
physical_device.getSurfacePresentModesKHR(surface, &present_modes_count, nullptr);
EXIT_NOT_IMPLEMENTED(present_modes_count == 0);
r->present_modes =
std::vector<vk::PresentModeKHR>(present_modes_count); // @suppress("Ambiguous problem")
physical_device.getSurfacePresentModesKHR(surface, &present_modes_count,
r->present_modes.data());
r->format_srgb_bgra32 = false;
for (const auto& f: r->formats) { for (const auto& f: r->formats) {
if (f.format == vk::Format::eB8G8R8A8Srgb && if (f.format == vk::Format::eB8G8R8A8Srgb &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
r->format_srgb_bgra32 = true; r->format_srgb_bgra32 = true;
break;
} }
if (f.format == vk::Format::eB8G8R8A8Unorm && if (f.format == vk::Format::eB8G8R8A8Unorm &&
f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
r->format_unorm_bgra32 = true; r->format_unorm_bgra32 = true;
}
if (r->format_srgb_bgra32 && r->format_unorm_bgra32) {
break; break;
} }
} }
@@ -131,7 +129,6 @@ struct QueueInfo {
uint32_t index = 0; uint32_t index = 0;
bool graphics = false; bool graphics = false;
bool compute = false; bool compute = false;
bool transfer = false;
bool present = false; bool present = false;
}; };
@@ -141,7 +138,6 @@ struct VulkanQueues {
std::vector<QueueInfo> available; std::vector<QueueInfo> available;
std::vector<QueueInfo> graphics; std::vector<QueueInfo> graphics;
std::vector<QueueInfo> compute; std::vector<QueueInfo> compute;
std::vector<QueueInfo> transfer;
std::vector<QueueInfo> present; std::vector<QueueInfo> present;
}; };
@@ -163,10 +159,6 @@ static void VulkanDumpQueues(const VulkanQueues& qs) {
for (const auto& q: qs.compute) { for (const auto& q: qs.compute) {
LOGF("\t\t family = %u, index = %u\n", q.family, q.index); LOGF("\t\t family = %u, index = %u\n", q.family, q.index);
} }
LOGF("\t transfer:\n");
for (const auto& q: qs.transfer) {
LOGF("\t\t family = %u, index = %u\n", q.family, q.index);
}
LOGF("\t present:\n"); LOGF("\t present:\n");
for (const auto& q: qs.present) { for (const auto& q: qs.present) {
LOGF("\t\t family = %u, index = %u\n", q.family, q.index); LOGF("\t\t family = %u, index = %u\n", q.family, q.index);
@@ -175,7 +167,7 @@ static void VulkanDumpQueues(const VulkanQueues& qs) {
static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR surface, static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR surface,
uint32_t graphics_num, uint32_t compute_num, uint32_t graphics_num, uint32_t compute_num,
uint32_t transfer_num, uint32_t present_num) { uint32_t present_num) {
EXIT_IF(device == nullptr); EXIT_IF(device == nullptr);
EXIT_IF(surface == nullptr); EXIT_IF(surface == nullptr);
@@ -191,7 +183,8 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s
uint32_t family = 0; uint32_t family = 0;
for (auto& f: queue_families) { for (auto& f: queue_families) {
vk::Bool32 presentation_supported = VK_FALSE; vk::Bool32 presentation_supported = VK_FALSE;
device.getSurfaceSupportKHR(family, surface, &presentation_supported); RequireVulkanSuccess(device.getSurfaceSupportKHR(family, surface, &presentation_supported),
"vkGetPhysicalDeviceSurfaceSupportKHR");
LOGF("\tqueue family: %s [count = %u], [present = %s]\n", LOGF("\tqueue family: %s [count = %u], [present = %s]\n",
VulkanToString(f.queueFlags).c_str(), f.queueCount, VulkanToString(f.queueFlags).c_str(), f.queueCount,
@@ -203,7 +196,6 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s
info.index = i; info.index = i;
info.graphics = static_cast<bool>(f.queueFlags & vk::QueueFlagBits::eGraphics); info.graphics = static_cast<bool>(f.queueFlags & vk::QueueFlagBits::eGraphics);
info.compute = static_cast<bool>(f.queueFlags & vk::QueueFlagBits::eCompute); info.compute = static_cast<bool>(f.queueFlags & vk::QueueFlagBits::eCompute);
info.transfer = static_cast<bool>(f.queueFlags & vk::QueueFlagBits::eTransfer);
info.present = (presentation_supported == VK_TRUE); info.present = (presentation_supported == VK_TRUE);
qs.available.push_back(info); qs.available.push_back(info);
@@ -244,7 +236,6 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s
} }
} }
select_queues(transfer_num, [](const auto& q) { return q.transfer; }, qs.transfer);
select_queues(present_num, [](const auto& q) { return q.present; }, qs.present); select_queues(present_num, [](const auto& q) { return q.present; }, qs.present);
return qs; return qs;
@@ -261,16 +252,15 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
EXIT_IF(out_device == nullptr); EXIT_IF(out_device == nullptr);
EXIT_IF(out_queues == nullptr); EXIT_IF(out_queues == nullptr);
uint32_t devices_count = 0; auto devices = EnumerateVulkan<vk::PhysicalDevice>(
instance.enumeratePhysicalDevices(&devices_count, nullptr); "vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) {
return instance.enumeratePhysicalDevices(count, values);
});
EXIT_NOT_IMPLEMENTED(devices.empty());
EXIT_NOT_IMPLEMENTED(devices_count == 0); vk::PhysicalDevice best_device = nullptr;
VulkanQueues best_queues;
std::vector<vk::PhysicalDevice> devices(devices_count); SurfaceCapabilities best_capabilities;
instance.enumeratePhysicalDevices(&devices_count, devices.data());
vk::PhysicalDevice best_device = nullptr;
VulkanQueues best_queues;
for (const auto& device: devices) { for (const auto& device: devices) {
bool skip_device = false; bool skip_device = false;
@@ -313,15 +303,14 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
device.getFeatures2(&device_features2); device.getFeatures2(&device_features2);
auto qs = VulkanFindQueues( auto qs =
device, surface, GraphicContext::QUEUE_GFX_NUM, GraphicContext::QUEUE_COMPUTE_NUM, VulkanFindQueues(device, surface, GraphicContext::QUEUE_GFX_NUM,
GraphicContext::QUEUE_UTIL_NUM, GraphicContext::QUEUE_PRESENT_NUM); GraphicContext::QUEUE_COMPUTE_NUM, GraphicContext::QUEUE_PRESENT_NUM);
VulkanDumpQueues(qs); VulkanDumpQueues(qs);
if (qs.graphics.size() != GraphicContext::QUEUE_GFX_NUM || if (qs.graphics.size() != GraphicContext::QUEUE_GFX_NUM ||
!(qs.compute.size() >= 1 && qs.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM) || !(qs.compute.size() >= 1 && qs.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM) ||
qs.transfer.size() != GraphicContext::QUEUE_UTIL_NUM ||
qs.present.size() != GraphicContext::QUEUE_PRESENT_NUM) { qs.present.size() != GraphicContext::QUEUE_PRESENT_NUM) {
LOGF("Not enough queues\n"); LOGF("Not enough queues\n");
skip_device = true; skip_device = true;
@@ -387,14 +376,12 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
} }
if (!skip_device) { if (!skip_device) {
uint32_t extensions_count = 0; auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
device.enumerateDeviceExtensionProperties(nullptr, &extensions_count, nullptr); "vkEnumerateDeviceExtensionProperties",
[&](uint32_t* count, vk::ExtensionProperties* values) {
EXIT_NOT_IMPLEMENTED(extensions_count == 0); return device.enumerateDeviceExtensionProperties(nullptr, count, values);
});
std::vector<vk::ExtensionProperties> available_extensions(extensions_count); EXIT_NOT_IMPLEMENTED(available_extensions.empty());
device.enumerateDeviceExtensionProperties(nullptr, &extensions_count,
available_extensions.data());
for (const char* ext: device_extensions) { for (const char* ext: device_extensions) {
if (!HasExtension(available_extensions, ext)) { if (!HasExtension(available_extensions, ext)) {
@@ -411,10 +398,11 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
} }
} }
SurfaceCapabilities candidate_capabilities;
if (!skip_device) { if (!skip_device) {
VulkanGetSurfaceCapabilities(device, surface, out_capabilities); VulkanGetSurfaceCapabilities(device, surface, &candidate_capabilities);
if (!(out_capabilities->capabilities.supportedUsageFlags & if (!(candidate_capabilities.capabilities.supportedUsageFlags &
vk::ImageUsageFlagBits::eTransferDst)) { vk::ImageUsageFlagBits::eTransferDst)) {
LOGF("Surface cannot be destination of blit\n"); LOGF("Surface cannot be destination of blit\n");
skip_device = true; skip_device = true;
@@ -510,13 +498,17 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
if (best_device == nullptr || if (best_device == nullptr ||
device_properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { device_properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
best_device = device; best_device = device;
best_queues = qs; best_queues = qs;
best_capabilities = std::move(candidate_capabilities);
} }
} }
*out_device = best_device; *out_device = best_device;
*out_queues = best_queues; *out_queues = best_queues;
if (best_device != nullptr) {
*out_capabilities = std::move(best_capabilities);
}
} }
static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, GraphicContext* ctx) { static void VulkanInitSubgroupSizeControl(vk::PhysicalDevice physical_device, GraphicContext* ctx) {
@@ -700,9 +692,7 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
EXIT_IF(window == nullptr); EXIT_IF(window == nullptr);
EXIT_IF(r == nullptr); EXIT_IF(r == nullptr);
uint32_t required_extensions_count = 0; uint32_t required_extensions_count = 0;
uint32_t available_extensions_count = 0;
uint32_t available_layers_count = 0;
auto sdl_result = SDL_Vulkan_GetInstanceExtensions(window, &required_extensions_count, nullptr); auto sdl_result = SDL_Vulkan_GetInstanceExtensions(window, &required_extensions_count, nullptr);
@@ -721,17 +711,12 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
EXIT_NOT_IMPLEMENTED(required_extensions_count == 0); EXIT_NOT_IMPLEMENTED(required_extensions_count == 0);
EXIT_NOT_IMPLEMENTED(required_extensions_count != r->required_extensions.size()); EXIT_NOT_IMPLEMENTED(required_extensions_count != r->required_extensions.size());
vk::enumerateInstanceExtensionProperties(nullptr, &available_extensions_count, nullptr); r->available_extensions =
EnumerateVulkan<vk::ExtensionProperties>( // @suppress("Ambiguous problem")
r->available_extensions = std::vector<vk::ExtensionProperties>( "vkEnumerateInstanceExtensionProperties",
available_extensions_count); // @suppress("Ambiguous problem") [](uint32_t* count, vk::ExtensionProperties* values) {
std::memset(r->available_extensions.data(), 0, return vk::enumerateInstanceExtensionProperties(nullptr, count, values);
sizeof(vk::ExtensionProperties) * r->available_extensions.size()); });
vk::enumerateInstanceExtensionProperties(nullptr, &available_extensions_count,
r->available_extensions.data());
EXIT_NOT_IMPLEMENTED(available_extensions_count != r->available_extensions.size());
r->enable_validation_layers = Config::VulkanValidationEnabled(); r->enable_validation_layers = Config::VulkanValidationEnabled();
@@ -750,15 +735,10 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
ext.specVersion); ext.specVersion);
} }
vk::enumerateInstanceLayerProperties(&available_layers_count, nullptr); r->available_layers = EnumerateVulkan<vk::LayerProperties>( // @suppress("Ambiguous problem")
"vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) {
r->available_layers = return vk::enumerateInstanceLayerProperties(count, values);
std::vector<vk::LayerProperties>(available_layers_count); // @suppress("Ambiguous problem") });
std::memset(r->available_layers.data(), 0,
sizeof(vk::LayerProperties) * r->available_layers.size());
vk::enumerateInstanceLayerProperties(&available_layers_count, r->available_layers.data());
EXIT_NOT_IMPLEMENTED(available_layers_count != r->available_layers.size());
for (const auto& l: r->available_layers) { for (const auto& l: r->available_layers) {
LOGF("Vulkan available layer: %s, specVersion = %u, implVersion = %u, %s\n", LOGF("Vulkan available layer: %s, specVersion = %u, implVersion = %u, %s\n",
@@ -778,14 +758,12 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) {
} }
if (r->enable_validation_layers) { if (r->enable_validation_layers) {
vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
&available_extensions_count, nullptr); "vkEnumerateInstanceExtensionProperties",
[](uint32_t* count, vk::ExtensionProperties* values) {
std::vector<vk::ExtensionProperties> available_extensions(available_extensions_count); return vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation",
count, values);
vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", });
&available_extensions_count,
available_extensions.data());
for (const auto& ext: available_extensions) { for (const auto& ext: available_extensions) {
LOGF("VK_LAYER_KHRONOS_validation available extension: %s, version = %u\n", LOGF("VK_LAYER_KHRONOS_validation available extension: %s, version = %u\n",
@@ -881,37 +859,31 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(ctx->device == nullptr);
EXIT_IF(queues.graphics.size() != 1); EXIT_IF(queues.graphics.size() != 1);
EXIT_IF(queues.transfer.size() != 1);
EXIT_IF(queues.present.size() != 1); EXIT_IF(queues.present.size() != 1);
EXIT_IF(!(queues.compute.size() >= 1 && EXIT_IF(!(queues.compute.size() >= 1 &&
queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM)); queues.compute.size() <= GraphicContext::QUEUE_COMPUTE_NUM));
auto get_queue = [ctx](int id, const QueueInfo& info, bool with_mutex = false) { auto get_queue = [ctx](int id, const QueueInfo& info) {
ctx->queues[id].family = info.family; ctx->queues[id].family = info.family;
ctx->queues[id].index = info.index; ctx->queues[id].index = info.index;
EXIT_IF(ctx->queues[id].vk_queue != nullptr); EXIT_IF(ctx->queues[id].vk_queue != nullptr);
ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index, ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index,
&ctx->queues[id].vk_queue); &ctx->queues[id].vk_queue);
EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr); EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr);
if (with_mutex) {
ctx->queues[id].mutex = new Common::Mutex;
}
}; };
get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0], true); get_queue(GraphicContext::QUEUE_GFX, queues.graphics[0]);
ctx->queues[GraphicContext::QUEUE_UTIL].family = ctx->queues[GraphicContext::QUEUE_GFX].family; ctx->queues[GraphicContext::QUEUE_UTIL].family = ctx->queues[GraphicContext::QUEUE_GFX].family;
ctx->queues[GraphicContext::QUEUE_UTIL].index = ctx->queues[GraphicContext::QUEUE_GFX].index; ctx->queues[GraphicContext::QUEUE_UTIL].index = ctx->queues[GraphicContext::QUEUE_GFX].index;
ctx->queues[GraphicContext::QUEUE_UTIL].vk_queue = ctx->queues[GraphicContext::QUEUE_UTIL].vk_queue =
ctx->queues[GraphicContext::QUEUE_GFX].vk_queue; ctx->queues[GraphicContext::QUEUE_GFX].vk_queue;
ctx->queues[GraphicContext::QUEUE_UTIL].mutex = ctx->queues[GraphicContext::QUEUE_GFX].mutex;
LOGF("Vulkan queue: using graphics queue for utility submissions to preserve resource " LOGF("Vulkan queue: using graphics queue for utility submissions to preserve resource "
"ordering\n"); "ordering\n");
get_queue(GraphicContext::QUEUE_PRESENT, queues.present[0], true); get_queue(GraphicContext::QUEUE_PRESENT, queues.present[0]);
for (int id = 0; id < GraphicContext::QUEUE_COMPUTE_NUM; id++) { for (int id = 0; id < GraphicContext::QUEUE_COMPUTE_NUM; id++) {
bool with_mutex = (GraphicContext::QUEUE_COMPUTE_NUM == queues.compute.size());
get_queue(GraphicContext::QUEUE_COMPUTE_START + id, get_queue(GraphicContext::QUEUE_COMPUTE_START + id,
queues.compute[id % queues.compute.size()], with_mutex); queues.compute[id % queues.compute.size()]);
} }
for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) { for (int id = 0; id < GraphicContext::QUEUES_NUM; id++) {
@@ -919,10 +891,7 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
if (queue.vk_queue == nullptr) { if (queue.vk_queue == nullptr) {
continue; continue;
} }
EXIT_IF(queue.mutex != nullptr);
if (queue.mutex == nullptr) {
queue.mutex = new Common::Mutex;
}
for (int other_id = 0; other_id < id; other_id++) { for (int other_id = 0; other_id < id; other_id++) {
auto& other = ctx->queues[other_id]; auto& other = ctx->queues[other_id];
@@ -930,14 +899,15 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
continue; continue;
} }
if (other.mutex == nullptr && queue.mutex != nullptr) { EXIT_IF(other.mutex == nullptr);
other.mutex = queue.mutex; queue.mutex = other.mutex;
} else {
queue.mutex = other.mutex;
}
LOGF("Vulkan queue: sharing mutex for queue ids %d and %d\n", other_id, id); LOGF("Vulkan queue: sharing mutex for queue ids %d and %d\n", other_id, id);
break; break;
} }
if (queue.mutex == nullptr) {
queue.mutex = &ctx->queue_mutexes[id];
}
} }
} }
@@ -1096,13 +1066,12 @@ void VulkanCreate(WindowContext* ctx) {
LOGF("Select device: %s\n", device_properties.deviceName.data()); LOGF("Select device: %s\n", device_properties.deviceName.data());
{ {
uint32_t extensions_count = 0; auto available_extensions = EnumerateVulkan<vk::ExtensionProperties>(
ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( "vkEnumerateDeviceExtensionProperties",
nullptr, &extensions_count, nullptr); [&](uint32_t* count, vk::ExtensionProperties* values) {
return ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties(
std::vector<vk::ExtensionProperties> available_extensions(extensions_count); nullptr, count, values);
ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( });
nullptr, &extensions_count, available_extensions.data());
if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) { if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) {
device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
+1 -1
View File
@@ -30,7 +30,7 @@
#include "common/timer.h" #include "common/timer.h"
#include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vma.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/presentation/renderDoc.h" #include "graphics/presentation/renderDoc.h"
@@ -224,20 +224,6 @@ constexpr uint32_t GetFormatComponentCount(Prospero::BufferFormat format) {
return GetFormatInfo(format).component_count; return GetFormatInfo(format).component_count;
} }
constexpr uint32_t GetFormatByteSize(Prospero::BufferFormat format) {
return GetFormatInfo(format).byte_size;
}
constexpr uint32_t GetFormatComponentBits(Prospero::BufferFormat format, uint32_t component) {
const auto info = GetFormatInfo(format);
return component < info.component_count ? info.component_bits[component] : 0u;
}
constexpr uint32_t GetFormatComponentBitOffset(Prospero::BufferFormat format, uint32_t component) {
const auto info = GetFormatInfo(format);
return component < info.component_count ? info.component_bit_offset[component] : 0u;
}
constexpr uint32_t GetFormatComponentByteOffset(Prospero::BufferFormat format, uint32_t component) { constexpr uint32_t GetFormatComponentByteOffset(Prospero::BufferFormat format, uint32_t component) {
const auto info = GetFormatInfo(format); const auto info = GetFormatInfo(format);
if (component >= info.component_count) { if (component >= info.component_count) {
@@ -1,8 +1,9 @@
#include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/shader/recompiler/ResourceMaterialization.h"
#include "graphics/guest_gpu/gpu_format.h" #include "graphics/guest_gpu/gpu_format.h"
#include "graphics/shader/recompiler/BufferFormat.h" #include "graphics/shader/shaderBindings.h"
#include <algorithm>
#include <fmt/format.h> #include <fmt/format.h>
namespace Libs::Graphics::ShaderRecompiler::IR { namespace Libs::Graphics::ShaderRecompiler::IR {
@@ -36,16 +37,12 @@ uint32_t DescriptorImageSwizzle(const DescriptorValue& descriptor) {
return descriptor.dwords[3] & 0xfffu; return descriptor.dwords[3] & 0xfffu;
} }
uint32_t DescriptorPackedStride(const DescriptorValue& descriptor) { bool DecodeBufferDescriptor(const DescriptorValue& descriptor, ShaderBufferResource& result) {
const auto stride = (descriptor.dwords[1] >> 16u) & 0x3fffu; if (descriptor.dword_count != std::size(result.fields)) {
const auto swizzle = (descriptor.dwords[1] >> 31u) & 1u; return false;
const auto index_stride = (descriptor.dwords[3] >> 21u) & 3u; }
const auto add_tid = (descriptor.dwords[3] >> 23u) & 1u; std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields);
return stride | (swizzle << 14u) | (index_stride << 16u) | (add_tid << 20u); return true;
}
uint32_t DescriptorBufferFormat(const DescriptorValue& descriptor) {
return (descriptor.dwords[3] >> 12u) & 0x7fu;
} }
uint64_t AddressSpecialization(const AddressResource& resource, uint64_t AddressSpecialization(const AddressResource& resource,
@@ -130,10 +127,16 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh
return false; return false;
} }
for (uint32_t i = 0; i < program.info.buffers.size(); i++) { for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
const auto& buffer = program.info.buffers[i]; const auto& buffer = program.info.buffers[i];
const auto& descriptor = snapshot.buffers[i]; ShaderBufferResource descriptor;
if (buffer.packed_stride != DescriptorPackedStride(descriptor) || if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) {
buffer.descriptor_format != DescriptorBufferFormat(descriptor)) { if (error != nullptr) {
*error = fmt::format("buffer descriptor {} has invalid width", i);
}
return false;
}
if (buffer.packed_stride != descriptor.PackedStride() ||
buffer.descriptor_format != descriptor.Format()) {
if (error != nullptr) { if (error != nullptr) {
*error = fmt::format("buffer descriptor {} no longer matches specialization", i); *error = fmt::format("buffer descriptor {} no longer matches specialization", i);
} }
@@ -297,8 +300,15 @@ bool SpecializeResources(Program* program, const ResourceSnapshot& snapshot, std
auto next = program->info; auto next = program->info;
for (uint32_t i = 0; i < next.buffers.size(); i++) { for (uint32_t i = 0; i < next.buffers.size(); i++) {
next.buffers[i].packed_stride = DescriptorPackedStride(snapshot.buffers[i]); ShaderBufferResource descriptor;
next.buffers[i].descriptor_format = DescriptorBufferFormat(snapshot.buffers[i]); if (!DecodeBufferDescriptor(snapshot.buffers[i], descriptor)) {
if (error != nullptr) {
*error = fmt::format("buffer descriptor {} has invalid width", i);
}
return false;
}
next.buffers[i].packed_stride = descriptor.PackedStride();
next.buffers[i].descriptor_format = descriptor.Format();
} }
for (uint32_t i = 0; i < next.addresses.size(); i++) { for (uint32_t i = 0; i < next.addresses.size(); i++) {
next.addresses[i].specialized_base = next.addresses[i].specialized_base =
-5
View File
@@ -205,11 +205,6 @@ static void ExitShaderRecompilerFailure(const char* label, uint64_t shader_hash,
reason != nullptr ? reason : ""); reason != nullptr ? reason : "");
} }
bool ShaderBindingResearchGuardEnabled() {
return Config::GraphicsDebugDumpEnabled() ||
Config::GetShaderLogDirection() != Config::ShaderLogDirection::Silent;
}
static const ShaderBinaryInfo* GetBinaryInfo(const uint32_t* code) { static const ShaderBinaryInfo* GetBinaryInfo(const uint32_t* code) {
EXIT_IF(code == nullptr); EXIT_IF(code == nullptr);
-1
View File
@@ -242,7 +242,6 @@ bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegis
std::vector<uint32_t>* spirv); std::vector<uint32_t>* spirv);
bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh,
ShaderComputeInputInfo* input_info, std::vector<uint32_t>* spirv); ShaderComputeInputInfo* input_info, std::vector<uint32_t>* spirv);
bool ShaderBindingResearchGuardEnabled();
bool ShaderAddressValid(uint64_t addr); bool ShaderAddressValid(uint64_t addr);
} // namespace Libs::Graphics } // namespace Libs::Graphics
-10
View File
@@ -52,7 +52,6 @@ struct ShaderBufferResource {
[[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; } [[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; }
[[nodiscard]] bool AddTid() const { return ((fields[3] >> 23u) & 0x1u) == 1; } [[nodiscard]] bool AddTid() const { return ((fields[3] >> 23u) & 0x1u) == 1; }
[[nodiscard]] uint8_t IndexStride() const { return (fields[3] >> 21u) & 0x3u; } [[nodiscard]] uint8_t IndexStride() const { return (fields[3] >> 21u) & 0x3u; }
[[nodiscard]] uint32_t IndexStrideRecords() const { return 8u << IndexStride(); }
[[nodiscard]] uint32_t PackedStride() const { [[nodiscard]] uint32_t PackedStride() const {
return Stride() | (static_cast<uint32_t>(SwizzleEnabled()) << 14u) | return Stride() | (static_cast<uint32_t>(SwizzleEnabled()) << 14u) |
(static_cast<uint32_t>(IndexStride()) << 16u) | (static_cast<uint32_t>(IndexStride()) << 16u) |
@@ -70,13 +69,6 @@ struct ShaderBufferResource {
struct ShaderTextureResource { struct ShaderTextureResource {
uint32_t fields[8] = {0}; uint32_t fields[8] = {0};
void UpdateAddress40(uint64_t gpu_addr) {
auto lo = static_cast<uint32_t>(gpu_addr & 0xffffffffu);
auto hi = static_cast<uint32_t>(gpu_addr >> 32u);
fields[0] = lo;
fields[1] = (fields[1] & 0xffffff00u) | (hi & 0x000000ffu);
}
[[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; } [[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; }
[[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; } [[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; }
[[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; } [[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; }
@@ -126,8 +118,6 @@ struct ShaderTextureResource {
struct ShaderSamplerResource { struct ShaderSamplerResource {
uint32_t fields[4] = {0}; uint32_t fields[4] = {0};
void UpdateIndex(uint32_t index) { fields[0] = index; }
[[nodiscard]] uint8_t ClampX() const { return (fields[0] >> 0u) & 0x7u; } [[nodiscard]] uint8_t ClampX() const { return (fields[0] >> 0u) & 0x7u; }
[[nodiscard]] uint8_t ClampY() const { return (fields[0] >> 3u) & 0x7u; } [[nodiscard]] uint8_t ClampY() const { return (fields[0] >> 3u) & 0x7u; }
[[nodiscard]] uint8_t ClampZ() const { return (fields[0] >> 6u) & 0x7u; } [[nodiscard]] uint8_t ClampZ() const { return (fields[0] >> 6u) & 0x7u; }
-9
View File
@@ -57,8 +57,6 @@ static void PrintUsage() {
::printf(" --printf-output-file <path> Guest printf output file.\n"); ::printf(" --printf-output-file <path> Guest printf output file.\n");
::printf(" --profiler-direction <value> None or Network.\n"); ::printf(" --profiler-direction <value> None or Network.\n");
::printf(" --spirv-debug-printf <true|false> Enable SPIR-V debug printf.\n"); ::printf(" --spirv-debug-printf <true|false> Enable SPIR-V debug printf.\n");
::printf(" --pipeline-dump <true|false> Enable pipeline dumps.\n");
::printf(" --pipeline-dump-folder <path> Pipeline dump folder.\n");
::printf(" --ngg-rectlist-draw <true|false> Draw rect-list auto draws using the NGG " ::printf(" --ngg-rectlist-draw <true|false> Draw rect-list auto draws using the NGG "
"4-vertex path.\n"); "4-vertex path.\n");
::printf(" --rd Enable RenderDoc capture.\n"); ::printf(" --rd Enable RenderDoc capture.\n");
@@ -207,13 +205,6 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str()); ::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
return false; return false;
} }
} else if (arg == "--pipeline-dump") {
if (!ParseBool(value, options.config.pipeline_dump_enabled)) {
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
return false;
}
} else if (arg == "--pipeline-dump-folder") {
options.config.pipeline_dump_folder = value;
} else if (arg == "--ngg-rectlist-draw") { } else if (arg == "--ngg-rectlist-draw") {
if (!ParseBool(value, options.config.ngg_rectlist_draw_enabled)) { if (!ParseBool(value, options.config.ngg_rectlist_draw_enabled)) {
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str()); ::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
+5 -6
View File
@@ -20,12 +20,11 @@
#include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/renderDraw.h" #include "graphics/host_gpu/renderer/renderDraw.h"
#include "graphics/host_gpu/renderer/renderTarget.h" #include "graphics/host_gpu/renderer/renderTarget.h"
#include "graphics/host_gpu/renderer/renderVertex.h"
#include "graphics/host_gpu/renderer/resourceMutex.h" #include "graphics/host_gpu/renderer/resourceMutex.h"
#include "graphics/host_gpu/renderer/sync.h" #include "graphics/host_gpu/renderer/sync.h"
#include "graphics/host_gpu/renderer/textureCache.h" #include "graphics/host_gpu/renderer/textureCache.h"
#include "graphics/host_gpu/renderer/tiler.h" #include "graphics/host_gpu/renderer/tiler.h"
#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/transfer.h"
#include "graphics/host_gpu/vulkanCommon.h" #include "graphics/host_gpu/vulkanCommon.h"
#include "graphics/shader/recompiler/BindingLayout.h" #include "graphics/shader/recompiler/BindingLayout.h"
#include "graphics/shader/recompiler/ShaderDecoder.h" #include "graphics/shader/recompiler/ShaderDecoder.h"
@@ -2481,10 +2480,10 @@ private:
void Destroy() { void Destroy() {
if (m_device != nullptr) { if (m_device != nullptr) {
m_device.waitIdle(); RequireVulkanSuccess(m_device.waitIdle(), "vkDeviceWaitIdle");
if (m_runtime_context.allocator != nullptr) { if (m_runtime_context.allocator != nullptr) {
GraphicsRenderReleaseThreadCommandPools(); GraphicsRenderReleaseThreadCommandPools();
UtilReleaseCachedResources(&m_runtime_context); Transfer::ReleaseCachedResources(&m_runtime_context);
vmaDestroyAllocator(m_runtime_context.allocator); vmaDestroyAllocator(m_runtime_context.allocator);
m_runtime_context.allocator = nullptr; m_runtime_context.allocator = nullptr;
} }
@@ -10664,8 +10663,8 @@ void CheckRenderTargetTileRoundTrip() {
"layered render-target conversion crossed array slices"); "layered render-target conversion crossed array slices");
} }
} }
const auto regions = const auto regions = Transfer::MakeLayeredImageBufferCopies(
MakeLayeredImageBufferCopies(layers, storage.size, pitch, width, height); layers, storage.size, pitch, width, height);
Require("RenderTargetTileRoundTrip", "layered regions", Require("RenderTargetTileRoundTrip", "layered regions",
regions.size() == layers && regions[0].offset == 0 && regions.size() == layers && regions[0].offset == 0 &&
regions[1].offset == storage.size && regions[1].offset == storage.size &&