diff --git a/src/common/emulatorConfig.cpp b/src/common/emulatorConfig.cpp index 06d5cdb35..418cfda4e 100644 --- a/src/common/emulatorConfig.cpp +++ b/src/common/emulatorConfig.cpp @@ -85,14 +85,6 @@ bool SpirvDebugPrintfEnabled() { 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() { return g_config->renderdoc_enabled; } diff --git a/src/common/emulatorConfig.h b/src/common/emulatorConfig.h index 82f614147..f2426366e 100644 --- a/src/common/emulatorConfig.h +++ b/src/common/emulatorConfig.h @@ -34,8 +34,6 @@ struct ConfigOptions { std::filesystem::path printf_output_file = "_kyty.txt"; ProfilerDirection profiler_direction = ProfilerDirection::None; bool spirv_debug_printf_enabled = false; - bool pipeline_dump_enabled = false; - std::filesystem::path pipeline_dump_folder = "_Pipelines"; bool renderdoc_enabled = false; bool ngg_rectlist_draw_enabled = true; }; @@ -64,9 +62,6 @@ ProfilerDirection GetProfilerDirection(); bool SpirvDebugPrintfEnabled(); -bool PipelineDumpEnabled(); -std::filesystem::path GetPipelineDumpFolder(); - bool RenderDocEnabled(); bool NggRectlistDrawEnabled(); diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp index 8cb888452..9a7a91bf9 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp @@ -2,19 +2,14 @@ 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_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_uc_parser_func_t g_hw_uc_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() { - for (auto& func: g_hw_ctx_func) { - func = nullptr; - } +namespace { + +constexpr auto MakeContextDispatchTable() { + std::array g_hw_ctx_func {}; g_hw_ctx_func[Pm4::DB_RENDER_CONTROL] = HwCtxSetRenderControl; g_hw_ctx_func[Pm4::DB_COUNT_CONTROL] = HwCtxSetDepthMetadataRegisters; @@ -107,9 +102,11 @@ void GraphicsInitJmpTables() { } } - for (auto& func: g_hw_sh_func) { - func = nullptr; - } + return g_hw_ctx_func; +} + +constexpr auto MakeShaderDispatchTable() { + std::array g_hw_sh_func {}; for (uint32_t slot = 0; slot < 32; slot++) { 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_REQ_CTRL_LSHS] = HwShIgnoreRegisters; - for (auto& func: g_hw_uc_func) { - func = nullptr; - } + return g_hw_sh_func; +} + +constexpr auto MakeUconfigDispatchTable() { + std::array g_hw_uc_func {}; g_hw_uc_func[Pm4::VGT_PRIMITIVE_TYPE] = HwUcSetPrimitiveType; 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_ADDRESS] = HwUcSetGdsOaRegisters; - for (auto& func: g_cp_op_func) { - func = nullptr; - } + return g_hw_uc_func; +} + +constexpr auto MakeOpcodeDispatchTable() { + std::array g_cp_op_func {}; g_cp_op_func[Pm4::IT_NOP] = CpOpNop; 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_GET_LOD_STATS] = CpOpGetLodStats; - for (auto& func: g_cp_op_custom_func) { - func = nullptr; - } + return g_cp_op_func; +} + +constexpr auto MakeCustomOpcodeDispatchTable() { + std::array g_cp_op_custom_func {}; g_cp_op_custom_func[Pm4::R_DISPATCH_RESET] = CpOpDispatchReset; 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_RELEASE_MEM] = CpOpReleaseMem; + return g_cp_op_custom_func; +} + +} // namespace + +constinit const std::array g_hw_ctx_func = + MakeContextDispatchTable(); +constinit const std::array g_hw_sh_func = + MakeShaderDispatchTable(); +constinit const std::array g_hw_uc_func = + MakeUconfigDispatchTable(); +constinit const std::array g_cp_op_func = MakeOpcodeDispatchTable(); +constinit const std::array g_cp_op_custom_func = + MakeCustomOpcodeDispatchTable(); + +void GraphicsInitJmpTables() { GraphicsInitJmpTablesCxIndirect(); GraphicsInitJmpTablesShIndirect(); GraphicsInitJmpTablesUcIndirect(); diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h index 120edcd97..e601a34fa 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h @@ -3,6 +3,7 @@ #include "graphics/guest_gpu/pm4.h" +#include #include 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_sh_indirect_func_t = void (*)(CommandProcessor*, uint32_t, uint32_t); -extern hw_ctx_parser_func_t g_hw_ctx_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 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 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 cp_op_parser_func_t g_cp_op_custom_func[Pm4::R_NUM]; +extern const std::array g_hw_ctx_func; +extern hw_ctx_indirect_func_t g_hw_ctx_indirect_func[Pm4::CX_NUM]; +extern const std::array g_hw_sh_func; +extern hw_sh_indirect_func_t g_hw_sh_indirect_func[Pm4::SH_NUM]; +extern const std::array g_hw_uc_func; +extern hw_uc_indirect_func_t g_hw_uc_indirect_func[Pm4::UC_NUM]; +extern const std::array g_cp_op_func; +extern const std::array g_cp_op_custom_func; void GraphicsInitJmpTables(); void GraphicsInitJmpTablesCxIndirect(); diff --git a/src/graphics/guest_gpu/gpu_format.cpp b/src/graphics/guest_gpu/gpu_format.cpp index 786dc6deb..566af8d0b 100644 --- a/src/graphics/guest_gpu/gpu_format.cpp +++ b/src/graphics/guest_gpu/gpu_format.cpp @@ -7,82 +7,76 @@ namespace Libs::Graphics::Prospero { 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[] = { - {GpuEnumValue(BufferFormat::k8UNorm), vk::Format::eR8Unorm, 1, 0, 1, true, false}, - {GpuEnumValue(BufferFormat::k8SNorm), vk::Format::eUndefined, 0, 0, 1, false, false}, - {GpuEnumValue(BufferFormat::k8UInt), vk::Format::eR8Uint, 1, 0, 1, true, true}, - {GpuEnumValue(BufferFormat::k16UNorm), vk::Format::eR16Unorm, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k16SNorm), vk::Format::eR16Snorm, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k16UInt), vk::Format::eR16Uint, 2, 0, 2, true, true}, - {GpuEnumValue(BufferFormat::k16SInt), vk::Format::eR16Sint, 2, 0, 2, false, false}, - {GpuEnumValue(BufferFormat::k16Float), vk::Format::eR16Sfloat, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k8_8UNorm), vk::Format::eR8G8Unorm, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k8_8SNorm), vk::Format::eR8G8Snorm, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k8_8UInt), vk::Format::eR8G8Uint, 2, 0, 2, true, true}, - {GpuEnumValue(BufferFormat::k8_8SInt), vk::Format::eR8G8Sint, 2, 0, 2, false, false}, - {GpuEnumValue(BufferFormat::k32UInt), vk::Format::eR32Uint, 4, 0, 4, true, true}, - {GpuEnumValue(BufferFormat::k32SInt), vk::Format::eR32Sint, 4, 0, 4, false, false}, - {GpuEnumValue(BufferFormat::k32Float), vk::Format::eR32Sfloat, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k16_16UNorm), vk::Format::eR16G16Unorm, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k16_16SNorm), vk::Format::eR16G16Snorm, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k16_16UInt), vk::Format::eR16G16Uint, 4, 0, 4, true, true}, - {GpuEnumValue(BufferFormat::k16_16SInt), vk::Format::eR16G16Sint, 4, 0, 4, false, false}, - {GpuEnumValue(BufferFormat::k16_16Float), vk::Format::eR16G16Sfloat, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k11_11_10Float), vk::Format::eB10G11R11UfloatPack32, 4, 0, 4, true, - false}, - {GpuEnumValue(BufferFormat::k10_10_10_2UNorm), vk::Format::eA2B10G10R10UnormPack32, 4, 0, 4, - true, false}, - {GpuEnumValue(BufferFormat::k8_8_8_8UNorm), vk::Format::eR8G8B8A8Unorm, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k8_8_8_8SNorm), vk::Format::eR8G8B8A8Snorm, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k8_8_8_8UInt), vk::Format::eR8G8B8A8Uint, 4, 0, 4, true, true}, - {GpuEnumValue(BufferFormat::k8_8_8_8SInt), vk::Format::eR8G8B8A8Sint, 4, 0, 4, false, false}, - {GpuEnumValue(BufferFormat::k32_32UInt), vk::Format::eR32G32Uint, 8, 0, 8, true, true}, - {GpuEnumValue(BufferFormat::k32_32SInt), vk::Format::eR32G32Sint, 8, 0, 8, false, false}, - {GpuEnumValue(BufferFormat::k32_32Float), vk::Format::eR32G32Sfloat, 8, 0, 8, true, false}, - {GpuEnumValue(BufferFormat::k16_16_16_16UNorm), vk::Format::eR16G16B16A16Unorm, 8, 0, 8, true, - false}, - {GpuEnumValue(BufferFormat::k16_16_16_16SNorm), vk::Format::eR16G16B16A16Snorm, 8, 0, 8, true, - false}, - {GpuEnumValue(BufferFormat::k16_16_16_16UInt), vk::Format::eR16G16B16A16Uint, 8, 0, 8, true, - true}, - {GpuEnumValue(BufferFormat::k16_16_16_16SInt), vk::Format::eR16G16B16A16Sint, 8, 0, 8, false, - false}, - {GpuEnumValue(BufferFormat::k16_16_16_16Float), vk::Format::eR16G16B16A16Sfloat, 8, 0, 8, true, - false}, - {GpuEnumValue(BufferFormat::k32_32_32UInt), vk::Format::eR32G32B32Uint, 12, 0, 12, true, true}, - {GpuEnumValue(BufferFormat::k32_32_32SInt), vk::Format::eR32G32B32Sint, 12, 0, 12, false, - false}, - {GpuEnumValue(BufferFormat::k32_32_32Float), vk::Format::eR32G32B32Sfloat, 12, 0, 12, true, - false}, - {GpuEnumValue(BufferFormat::k32_32_32_32UInt), vk::Format::eR32G32B32A32Uint, 16, 0, 16, true, - true}, - {GpuEnumValue(BufferFormat::k32_32_32_32SInt), vk::Format::eR32G32B32A32Sint, 16, 0, 16, false, - false}, - {GpuEnumValue(BufferFormat::k32_32_32_32Float), vk::Format::eR32G32B32A32Sfloat, 16, 0, 16, - true, false}, - {GpuEnumValue(BufferFormat::k8_8_8_8Srgb), vk::Format::eR8G8B8A8Srgb, 4, 0, 4, true, false}, - {GpuEnumValue(BufferFormat::k9_9_9_5Float), vk::Format::eE5B9G9R9UfloatPack32, 4, 0, 0, true, - false}, - {GpuEnumValue(BufferFormat::k5_6_5UNorm), vk::Format::eB5G6R5UnormPack16, 2, 0, 2, true, false}, - {GpuEnumValue(BufferFormat::k5_5_5_1UNorm), vk::Format::eR5G5B5A1UnormPack16, 2, 0, 2, true, - false}, - {GpuEnumValue(BufferFormat::k4_4_4_4UNorm), vk::Format::eR4G4B4A4UnormPack16, 2, 0, 2, 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}, + {GpuEnumValue(BufferFormat::k8UNorm), 1, 0, 1, true, false}, + {GpuEnumValue(BufferFormat::k8SNorm), 0, 0, 1, false, false}, + {GpuEnumValue(BufferFormat::k8UInt), 1, 0, 1, true, true}, + {GpuEnumValue(BufferFormat::k16UNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k16SNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k16UInt), 2, 0, 2, true, true}, + {GpuEnumValue(BufferFormat::k16SInt), 2, 0, 2, false, false}, + {GpuEnumValue(BufferFormat::k16Float), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k8_8UNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k8_8SNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k8_8UInt), 2, 0, 2, true, true}, + {GpuEnumValue(BufferFormat::k8_8SInt), 2, 0, 2, false, false}, + {GpuEnumValue(BufferFormat::k32UInt), 4, 0, 4, true, true}, + {GpuEnumValue(BufferFormat::k32SInt), 4, 0, 4, false, false}, + {GpuEnumValue(BufferFormat::k32Float), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k16_16UNorm), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k16_16SNorm), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k16_16UInt), 4, 0, 4, true, true}, + {GpuEnumValue(BufferFormat::k16_16SInt), 4, 0, 4, false, false}, + {GpuEnumValue(BufferFormat::k16_16Float), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k11_11_10Float), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k10_10_10_2UNorm), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k8_8_8_8UNorm), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k8_8_8_8SNorm), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k8_8_8_8UInt), 4, 0, 4, true, true}, + {GpuEnumValue(BufferFormat::k8_8_8_8SInt), 4, 0, 4, false, false}, + {GpuEnumValue(BufferFormat::k32_32UInt), 8, 0, 8, true, true}, + {GpuEnumValue(BufferFormat::k32_32SInt), 8, 0, 8, false, false}, + {GpuEnumValue(BufferFormat::k32_32Float), 8, 0, 8, true, false}, + {GpuEnumValue(BufferFormat::k16_16_16_16UNorm), 8, 0, 8, true, false}, + {GpuEnumValue(BufferFormat::k16_16_16_16SNorm), 8, 0, 8, true, false}, + {GpuEnumValue(BufferFormat::k16_16_16_16UInt), 8, 0, 8, true, true}, + {GpuEnumValue(BufferFormat::k16_16_16_16SInt), 8, 0, 8, false, false}, + {GpuEnumValue(BufferFormat::k16_16_16_16Float), 8, 0, 8, true, false}, + {GpuEnumValue(BufferFormat::k32_32_32UInt), 12, 0, 12, true, true}, + {GpuEnumValue(BufferFormat::k32_32_32SInt), 12, 0, 12, false, false}, + {GpuEnumValue(BufferFormat::k32_32_32Float), 12, 0, 12, true, false}, + {GpuEnumValue(BufferFormat::k32_32_32_32UInt), 16, 0, 16, true, true}, + {GpuEnumValue(BufferFormat::k32_32_32_32SInt), 16, 0, 16, false, false}, + {GpuEnumValue(BufferFormat::k32_32_32_32Float), 16, 0, 16, true, false}, + {GpuEnumValue(BufferFormat::k8_8_8_8Srgb), 4, 0, 4, true, false}, + {GpuEnumValue(BufferFormat::k9_9_9_5Float), 4, 0, 0, true, false}, + {GpuEnumValue(BufferFormat::k5_6_5UNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k5_5_5_1UNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::k4_4_4_4UNorm), 2, 0, 2, true, false}, + {GpuEnumValue(BufferFormat::kFmask8_S4_F4), 1, 0, 1, true, false}, + {GpuEnumValue(BufferFormat::kBc1UNorm), 0, 8, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc1Srgb), 0, 8, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc2UNorm), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc2Srgb), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc3UNorm), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc3Srgb), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc4UNorm), 0, 8, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc4SNorm), 0, 8, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc5UNorm), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc5SNorm), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc6UFloat), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc6SFloat), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc7UNorm), 0, 16, 0, true, false}, + {GpuEnumValue(BufferFormat::kBc7Srgb), 0, 16, 0, true, false}, }; constexpr auto MakeFormatInfoLookup() { @@ -96,20 +90,11 @@ constexpr auto MakeFormatInfoLookup() { constexpr auto kFormatInfoLookup = MakeFormatInfoLookup(); -} // namespace - -std::span Formats() { - return kFormatInfo; -} - const FormatInfo* FindFormatInfo(uint32_t format) { return format < kFormatInfoLookup.size() ? kFormatInfoLookup[format] : nullptr; } -vk::Format SurfaceFormat(uint32_t format) { - const auto* info = FindFormatInfo(format); - return info != nullptr ? info->vk_format : vk::Format::eUndefined; -} +} // namespace uint32_t NumBytesPerElement(uint32_t format) { const auto* info = FindFormatInfo(format); diff --git a/src/graphics/guest_gpu/gpu_format.h b/src/graphics/guest_gpu/gpu_format.h index a096c254b..208c19b3f 100644 --- a/src/graphics/guest_gpu/gpu_format.h +++ b/src/graphics/guest_gpu/gpu_format.h @@ -2,31 +2,15 @@ #define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GUEST_GPU_GPU_FORMAT_H_ #include "common/common.h" -#include "graphics/host_gpu/vulkanCommon.h" - -#include namespace Libs::Graphics::Prospero { -struct FormatInfo { - uint32_t format = 0; - vk::Format vk_format = vk::Format::eUndefined; - uint32_t bytes_per_element = 0; - uint32_t block_compressed_bytes_per_block = 0; - uint32_t render_target_bytes_per_element = 0; - bool supported_sampled_texture_format = false; - bool unsigned_integer_texture_format = false; -}; - -std::span 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); +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 diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index 6d8d1f0bb..ad8307e67 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -626,8 +626,8 @@ struct GeUserVgprEn { class Context { public: - Context() = default; - virtual ~Context() = default; + Context() = default; + ~Context() = default; KYTY_CLASS_DEFAULT_COPY(Context); @@ -723,10 +723,6 @@ public: 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) { m_screen_viewport.viewports[viewport_id].zmin = zmin; } @@ -942,8 +938,8 @@ private: class UserConfig { public: - UserConfig() = default; - virtual ~UserConfig() = default; + UserConfig() = default; + ~UserConfig() = default; KYTY_CLASS_DEFAULT_COPY(UserConfig); @@ -980,8 +976,8 @@ private: class Shader { public: - Shader() = default; - virtual ~Shader() = default; + Shader() = default; + ~Shader() = default; KYTY_CLASS_DEFAULT_COPY(Shader); diff --git a/src/graphics/guest_gpu/pm4.cpp b/src/graphics/guest_gpu/pm4.cpp index 592ac409c..854e88e7a 100644 --- a/src/graphics/guest_gpu/pm4.cpp +++ b/src/graphics/guest_gpu/pm4.cpp @@ -3,97 +3,104 @@ #include "common/assert.h" #include "common/file.h" +#include + namespace Libs::Graphics::Pm4 { -static const char* g_names[256] = {}; -static const char* g_r_names[Pm4::R_NUM] = {}; -static bool g_names_initialized = false; +namespace { -static void InitNames() { - if (!g_names_initialized) { - for (auto& n: g_names) { - n = ""; - } +enum class PacketType : uint32_t { Type0, Type1, Type2, Type3 }; - for (auto& n: g_r_names) { - n = ""; - } - - 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; +constexpr auto MakeRegisterNames() { + std::array names {}; + for (auto& name: names) { + name = ""; } + + 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 names {}; + for (auto& name: names) { + name = ""; + } + + 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, uint32_t num_dw) { - InitNames(); - // db_dump(); 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; - if ((cmd_id & 0xC0000000u) == 0xC0000000u) { - const bool sh_gx = (cmd_id & 0x2u) == 0; - const uint8_t op = ((cmd_id >> 8u) & 0xffu); - const auto r = KYTY_PM4_R(cmd_id); - len = ((cmd_id >> 16u) & 0x3fffu) + 1; + const auto packet_type = static_cast(cmd_id >> 30u); + switch (packet_type) { + case PacketType::Type3: { + const bool sh_gx = (cmd_id & 0x2u) == 0; + 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], - (op == IT_NOP ? g_r_names[r] : ""), op, sh_gx ? "GX" : "CX", len); + EXIT_NOT_IMPLEMENTED(len >= dw); - for (uint32_t i = 0; i < len; i++) { - file->Printf(" | 0x%08" PRIx32 " | \n", cmd[i]); - } + file->Printf("%s %s(OP:0x%02" PRIx8 ") SH:%s CNT:%u\n", g_opcode_names[op], + (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 || - op == IT_SET_UCONFIG_REG_INDIRECT) && - len == 4) { - auto* indirect_buffer = - reinterpret_cast((static_cast(cmd[0]) & 0xfffffffcu) | - (static_cast(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]); + for (uint32_t i = 0; i < len; i++) { + file->Printf(" | 0x%08" PRIx32 " | \n", cmd[i]); } + + 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((static_cast(cmd[0]) & 0xfffffffcu) | + (static_cast(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 { - file->Printf("?????\n"); + case PacketType::Type0: + case PacketType::Type1: + case PacketType::Type2: + file->Printf("\n", static_cast(packet_type)); + break; } cmd += len; diff --git a/src/graphics/guest_gpu/tile.cpp b/src/graphics/guest_gpu/tile.cpp index 2576b8838..6499fba65 100644 --- a/src/graphics/guest_gpu/tile.cpp +++ b/src/graphics/guest_gpu/tile.cpp @@ -1392,81 +1392,82 @@ static const Standard64KB128Tables& GetStandard64KB128Tables() { return tables; } -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(); +template +static void ConvertTiledToLinearStandard64KBElements(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, 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_NOT_IMPLEMENTED(pitch == 0); 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 > 128u || src_y + height > 128u)); + EXIT_NOT_IMPLEMENTED(tail_block && + (src_x + width > BlockWidth || src_y + height > BlockHeight)); - auto* dst32 = static_cast(dst); - const auto* src32 = static_cast(src); - - const auto& tables = GetStandard64KB32Tables(); - const auto size_words = size >> 2u; - const auto src_size_words = (src_size != 0 ? src_size : size) >> 2u; + auto* dst_elements = static_cast(dst); + const auto* src_elements = static_cast(src); + const auto element_count = size / sizeof(T); + const auto src_element_count = (src_size != 0 ? src_size : size) / sizeof(T); const auto blocks_per_row = - (tail_block ? 1u : static_cast(AlignUp(pitch, 128u) >> 7u)); - const auto dst_words = static_cast(pitch) * height; - const bool exact_surface = - (!tail_block && width == pitch && (size & 3u) == 0 && size_words == dst_words); - const auto* x_words = tables.x_words.data(); - const auto* y_words = tables.y_words.data(); + tail_block ? 1u : static_cast(AlignUp(pitch, BlockWidth) / BlockWidth); + const auto dst_element_count = static_cast(pitch) * height; + const bool exact_surface = !tail_block && (!ExactSurfaceRequiresFullWidth || width == pitch) && + size % sizeof(T) == 0 && element_count == dst_element_count; + const auto* x_elements = tables.x_words.data(); + const auto* y_elements = tables.y_words.data(); if (!exact_surface) { - std::memset(dst32, 0, static_cast(size)); + std::memset(dst_elements, 0, static_cast(size)); } - for (uint32_t block_y = 0; block_y < height; block_y += 128u) { - const uint32_t block_height = std::min(128u, height - block_y); + constexpr uint64_t ElementsPerBlock = BlockWidth * BlockHeight; + 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) { - const uint32_t block_width = std::min(128u, width - block_x); + for (uint32_t block_x = 0; block_x < width; block_x += BlockWidth) { + const uint32_t copy_width = std::min(BlockWidth, width - block_x); const uint64_t block_base = - (tail_block - ? 0u - : (((static_cast(block_y) >> 7u) * blocks_per_row) + (block_x >> 7u)) - << 14u); - const bool full_block = - (!tail_block && block_width == 128u && block_height == 128u && - block_base + 16384u <= src_size_words && - (static_cast(block_y + 127u) * pitch) + block_x + 127u < size_words); + tail_block ? 0u + : ((static_cast(block_y / BlockHeight) * blocks_per_row) + + block_x / BlockWidth) * + ElementsPerBlock; + const bool full_block = !tail_block && copy_width == BlockWidth && + copy_height == BlockHeight && + block_base + ElementsPerBlock <= src_element_count && + static_cast(block_y + BlockHeight - 1u) * pitch + + block_x + BlockWidth - 1u < + element_count; 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 = - (static_cast(block_y + local_y) * pitch) + block_x; - const uint64_t src_row = block_base + y_words[src_y + local_y]; + static_cast(block_y + local_y) * pitch + block_x; + 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) { - dst32[dst_row + local_x + 0u] = - src32[src_row + x_words[src_x + local_x + 0u]]; - dst32[dst_row + local_x + 1u] = - 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]]; + for (uint32_t local_x = 0; local_x < BlockWidth; local_x += CopyBatch) { + for (uint32_t i = 0; i < CopyBatch; i++) { + dst_elements[dst_row + local_x + i] = + src_elements[src_row + x_elements[src_x + local_x + i]]; + } } } continue; } - for (uint32_t local_y = 0; local_y < block_height; local_y++) { - const uint64_t dst_row = - (static_cast(block_y + local_y) * pitch) + block_x; - const uint64_t src_row = block_base + y_words[src_y + local_y]; + for (uint32_t local_y = 0; local_y < copy_height; local_y++) { + const uint64_t dst_row = static_cast(block_y + local_y) * pitch + block_x; + const uint64_t src_row = block_base + y_elements[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 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) { - dst32[dst_index] = src32[src_index]; + if (src_index < src_element_count && dst_index < element_count) { + 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( + dst, src, width, height, pitch, size, src_size, src_x, src_y, GetStandard64KB32Tables()); +} + void TileConvertLinearToTiledStandard64KB32(void* dst, const void* src, uint32_t width, uint32_t height, uint32_t pitch, uint64_t size) { 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) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(dst == nullptr || src == nullptr); - EXIT_NOT_IMPLEMENTED(pitch == 0); - 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(dst); - const auto* src16 = static_cast(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(AlignUp(pitch, 256u) >> 8u)); - const auto dst_words = static_cast(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)); - } - - 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(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(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(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(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]; - } - } - } - } - } + ConvertTiledToLinearStandard64KBElements( + dst, src, width, height, pitch, size, src_size, src_x, src_y, GetStandard64KB16Tables()); } 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) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(dst == nullptr || src == nullptr); - EXIT_NOT_IMPLEMENTED(pitch_elements == 0); - const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); - 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(dst); - const auto* src8 = static_cast(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(AlignUp(pitch_elements, 256u) >> 8u)); - const auto dst_words = static_cast(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)); - } - - 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(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(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(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(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]; - } - } - } - } - } + ConvertTiledToLinearStandard64KBElements( + dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y, + GetStandard64KB8Tables()); } 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) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(dst == nullptr || src == nullptr); - EXIT_NOT_IMPLEMENTED(pitch_elements == 0); - const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); - 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(dst); - const auto* src64 = static_cast(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(AlignUp(pitch_elements, 128u) >> 7u)); - const auto dst_words = static_cast(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)); - } - - 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(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(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(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(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]; - } - } - } - } - } + ConvertTiledToLinearStandard64KBElements( + dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y, + GetStandard64KB64Tables()); } 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) { KYTY_PROFILER_FUNCTION(); - EXIT_IF(dst == nullptr || src == nullptr); - EXIT_NOT_IMPLEMENTED(pitch_elements == 0); - const bool tail_block = (src_size != 0 && (src_x != 0 || src_y != 0 || size < src_size)); - 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(dst); - const auto* src128 = static_cast(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(AlignUp(pitch_elements, 64u) >> 6u)); - const auto dst_words = static_cast(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)); - } - - 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(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(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(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(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]; - } - } - } - } - } + ConvertTiledToLinearStandard64KBElements( + dst, src, width_elements, height_elements, pitch_elements, size, src_size, src_x, src_y, + GetStandard64KB128Tables()); } void TileConvertTiledToLinearStandard64KB(void* dst, const void* src, uint32_t format, diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index 61bf62610..bde77d295 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -7,6 +7,7 @@ #include "graphics/host_gpu/vulkanCommon.h" // IWYU pragma: export #include "graphics/host_gpu/vulkanInstance.h" +#include #include #include #include @@ -42,8 +43,9 @@ struct VulkanCommandPool { }; struct GraphicContext: public VulkanInstance { - uint32_t screen_width = 0; - uint32_t screen_height = 0; + uint32_t screen_width = 0; + uint32_t screen_height = 0; + std::array queue_mutexes; }; struct VulkanMemory { diff --git a/src/graphics/host_gpu/objects/label.cpp b/src/graphics/host_gpu/objects/label.cpp index 98454c4d3..2d6bc6247 100644 --- a/src/graphics/host_gpu/objects/label.cpp +++ b/src/graphics/host_gpu/objects/label.cpp @@ -4,6 +4,7 @@ #include "common/threads.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/renderer/render.h" +#include "graphics/host_gpu/vulkanCommon.h" #include #include @@ -270,7 +271,7 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) { submission.completion = std::make_shared(); submission.completion->device = label->device; - auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + auto vk_buffer = buffer->Handle(); EXIT_NOT_IMPLEMENTED(vk_buffer == nullptr); @@ -279,14 +280,22 @@ void LabelManager::Set(CommandBuffer* buffer, Label* label) { create_info.pNext = nullptr; create_info.flags = {}; - label->device.createEvent(&create_info, nullptr, &submission.completion->event); - EXIT_NOT_IMPLEMENTED(submission.completion->event == nullptr); + const auto create_result = + 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(create_result)); + } buffer->RetainResourceUntilFence(submission.completion); // Labels can be reused before an earlier end-of-pipe event has been // observed by the polling thread. Capture a separate Vulkan event and // 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(reset_result)); + } vk_buffer.setEvent(submission.completion->event, vk::PipelineStageFlagBits::eBottomOfPipe); label->submissions.push_back(submission); diff --git a/src/graphics/host_gpu/objects/textureCommon.cpp b/src/graphics/host_gpu/objects/textureCommon.cpp index ab4242758..efc477613 100644 --- a/src/graphics/host_gpu/objects/textureCommon.cpp +++ b/src/graphics/host_gpu/objects/textureCommon.cpp @@ -5,8 +5,9 @@ #include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/gpu_format.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/vulkanCommon.h" #include #include @@ -14,6 +15,127 @@ #include 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! 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(raw_layout); const auto type = static_cast(raw_type); const auto order = static_cast(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 && raw_order <= Prospero::GpuEnumValue(Prospero::ChannelOrder::kAltReversed)) { return {vk::Format::eR8Unorm, 1}; } - if (is(Prospero::ChannelLayout::k8_8, Prospero::ChannelType::kUNorm, - Prospero::ChannelOrder::kStandard)) { - return {vk::Format::eR8G8Unorm, 2}; - } - 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}; + for (const auto& mapping: kRenderTargetFormats) { + if (mapping.layout == layout && mapping.type == type && mapping.order == order) { + return mapping.info; + } } EXIT("unsupported render-target format combination: layout=%u type=%u order=%u\n", raw_layout, 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); } -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); } @@ -156,11 +171,11 @@ uint64_t TextureUploadSliceSourceOffset(const TextureUploadLayout& layout, uint3 if (level >= 16 || layout.level_sizes[level].size == 0) { 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 = source_slice_layout == TextureUploadSliceLayout::MipChainPerSlice ? (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) { 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++) { - 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++) { size = std::max( size, @@ -191,7 +206,7 @@ uint64_t TextureCalcUploadSize(const TextureUploadLayout& layout, void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_buffer_offset, uint64_t copy_size, - UtilScratchBuffer* dst) { + Transfer::ScratchBuffer* dst) { EXIT_IF(ctx == nullptr); EXIT_IF(src_buffer == nullptr); EXIT_IF(dst == nullptr); @@ -223,7 +238,7 @@ void TextureCopyBufferBytes(GraphicContext* ctx, VulkanBuffer* src_buffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; 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; VulkanMapMemory(ctx, &readback.memory, &data); @@ -349,8 +364,8 @@ vk::ImageUsageFlags TextureGetViewUsage(TextureFormatUsage usage) { return vk_usage; } -vk::Format TextureGetFormat(uint32_t fmt, [[maybe_unused]] TextureFormatUsage usage) { - const auto vk_format = Prospero::SurfaceFormat(fmt); +vk::Format TextureGetFormat(uint32_t fmt) { + const auto vk_format = VulkanFormat(fmt); if (vk_format != vk::Format::eUndefined) { 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, uint64_t levels) { - return (depth > 1 && levels > 1 && UtilIsBcFormat(format) ? AlignUpU32(mip_height, 4u) - : mip_height); + return (depth > 1 && levels > 1 && Transfer::IsBlockCompressedFormat(format) + ? AlignUpU32(mip_height, 4u) + : mip_height); } uint32_t TextureCalcStackedImageHeight(vk::Format format, uint32_t height, uint32_t depth, uint64_t levels) { auto image_height = height * depth; - if (depth <= 1 || levels <= 1 || !UtilIsBcFormat(format)) { + if (depth <= 1 || levels <= 1 || !Transfer::IsBlockCompressedFormat(format)) { return image_height; } @@ -468,7 +484,7 @@ uint32_t TextureCalcMipmapAtlasImageHeight(vk::Format format, uint32_t width, ui uint32_t mip_height = height; 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 = static_cast(mipmap_offset.second) + 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; } -vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, VulkanMemory* mem, +vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj, const TextureImageCreateParams& params) { EXIT_IF(ctx == nullptr); EXIT_IF(vk_obj == nullptr); - EXIT_IF(mem == nullptr); EXIT_IF(params.owner == nullptr); const bool array_texture = TextureIsLayeredTexture(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(params.width == 0); EXIT_NOT_IMPLEMENTED(params.height == 0); + EXIT_NOT_IMPLEMENTED(params.depth == 0); EXIT_NOT_IMPLEMENTED(params.levels == 0 || params.levels > 16); uint32_t image_height = 0; @@ -618,15 +634,11 @@ vk::ComponentMapping TextureCreateImage(GraphicContext* ctx, VulkanImage* vk_obj vk_obj->image = nullptr; 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, mem); + bool created = VulkanCreateImage(ctx, image_info, vk_obj); EXIT_NOT_IMPLEMENTED(!created); - vk_obj->memory = *mem; - return components; } @@ -672,17 +684,19 @@ void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, create_info.viewType = vk::ImageViewType::e2DArray; } - ctx->device.createImageView(&create_info, nullptr, - &vk_obj->image_view[VulkanImage::VIEW_DEFAULT]); - EXIT_NOT_IMPLEMENTED(vk_obj->image_view[VulkanImage::VIEW_DEFAULT] == nullptr); + auto create_view = [&](int index) { + const auto result = + 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(result), static_cast(create_info.format), index); + } + }; + create_view(VulkanImage::VIEW_DEFAULT); - if (!volume_texture || depth >= 1) { - create_info.viewType = vk::ImageViewType::e2DArray; - create_info.subresourceRange.layerCount = (volume_texture ? volume_slices : layer_count); - 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); - } + create_info.viewType = vk::ImageViewType::e2DArray; + create_info.subresourceRange.layerCount = volume_texture ? volume_slices : layer_count; + create_view(VulkanImage::VIEW_DEFAULT_ARRAY); } static uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels, @@ -847,7 +861,7 @@ std::vector TextureBuildUploadRegions( for (uint32_t i = 0; i < levels; i++) { 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++) { const auto region_index = i * depth + z; @@ -861,7 +875,7 @@ std::vector TextureBuildUploadRegions( regions[region_index].height = mip_height; regions[region_index].copy_height = (!array_texture && !volume_texture && depth > 1 && levels > 1 && - UtilIsBcFormat(image_format) + Transfer::IsBlockCompressedFormat(image_format) ? TextureGetAtlasSliceYStride(image_format, mip_height, depth, levels) : 0); regions[region_index].dst_layer = (array_texture ? z : 0); @@ -911,14 +925,6 @@ std::vector TextureBuildUploadRegions( 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, TextureUploadSliceLayout source_slice_layout) { return ( @@ -954,13 +960,13 @@ static void UploadFmaskIdentity(GraphicContext* ctx, VulkanImage* vk_obj, ", upload_size=%" PRIu64 " regions=%zu\n", owner, kIdentityFmaskPattern, upload_size, upload_regions.size()); - UtilScratchBuffer temp_buf(upload_size); - auto* words = static_cast(temp_buf.Data()); + Transfer::ScratchBuffer temp_buf(upload_size); + auto* words = static_cast(temp_buf.Data()); for (uint64_t i = 0; i < upload_size / sizeof(uint32_t); i++) { 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, @@ -974,13 +980,13 @@ void TextureUploadGuestImage(GraphicContext* ctx, VulkanImage* vk_obj, const voi " extent=%" PRIu64 "x%" PRIu64 " depth=%u pitch=%u levels=%" PRIu64 "\n", owner, layout.tile, size, width, height, depth, layout.pitch, levels); } else if (static_cast(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) { LOGF("%s: detiling typed render-target texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", owner, static_cast(fmt), layout.tile, size, width, height, static_cast(depth), layout.pitch, levels); - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); for (uint32_t i = 0; i < levels; i++) { for (uint32_t z = 0; z < 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); } } - 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) { if (Prospero::IsFmaskTextureFormat(static_cast(fmt))) { 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 = Prospero::RenderTargetBytesPerElement(static_cast(fmt)); 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 { LOGF("%s: detiling typed depth texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", owner, static_cast(fmt), layout.tile, size, width, height, static_cast(depth), layout.pitch, levels); - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); for (uint32_t i = 0; i < levels; i++) { for (uint32_t z = 0; z < 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); } } - 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) { - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); for (uint32_t i = 0; i < levels; i++) { for (uint32_t z = 0; z < 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); } } - 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) { LOGF("%s: detiling typed Standard4KB 3D texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u levels=%" PRIu64 "\n", owner, static_cast(fmt), layout.tile, size, width, height, static_cast(depth), layout.pitch, levels); - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); if (levels == 1) { TileConvertTiledToLinearStandard4KB3D( temp_buf.Data(), src_data, static_cast(fmt), static_cast(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) { LOGF("%s: detiling typed Standard4KB texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n", owner, static_cast(fmt), layout.tile, size, width, height, static_cast(depth), layout.pitch); - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); for (uint32_t i = 0; i < levels; i++) { for (uint32_t z = 0; z < 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); } } - 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) { LOGF("%s: detiling typed Standard64KB texture: fmt=%u tile=%u size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " depth=%" PRIu64 " pitch=%u\n", owner, static_cast(fmt), layout.tile, size, width, height, static_cast(depth), layout.pitch); - UtilScratchBuffer temp_buf(size); + Transfer::ScratchBuffer temp_buf(size); for (uint32_t i = 0; i < levels; i++) { for (uint32_t z = 0; z < 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); } } - 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) { 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 "\n", owner, static_cast(fmt), layout.tile, size, width, height, layout.pitch, levels); - UtilFillImage(ctx, vk_obj, src_data, size, regions, dst_layout); + Transfer::UploadImage(ctx, vk_obj, src_data, size, regions, dst_layout); } } diff --git a/src/graphics/host_gpu/objects/textureCommon.h b/src/graphics/host_gpu/objects/textureCommon.h index 7842cd14a..38e3d68ac 100644 --- a/src/graphics/host_gpu/objects/textureCommon.h +++ b/src/graphics/host_gpu/objects/textureCommon.h @@ -5,7 +5,7 @@ #include "common/common.h" #include "graphics/guest_gpu/gpu_defs.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 @@ -14,7 +14,6 @@ namespace Libs::Graphics { struct GraphicContext; struct VulkanImage; -struct VulkanMemory; enum class TextureFormatUsage : uint32_t { None = 0, @@ -93,7 +92,7 @@ bool TextureCheckFormat(GraphicContext* ctx, vk::ImageCreateInfo bool TextureCheckStorageSwizzle(vk::ImageCreateInfo* image_info, vk::ComponentMapping* components); vk::ImageUsageFlags TextureGetUsage(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); uint32_t TextureGetAtlasSliceYStride(vk::Format format, uint32_t mip_height, uint32_t depth, uint64_t levels); @@ -105,7 +104,7 @@ bool TextureIs3DTexture(uint64_t type); bool TextureIsCubeTexture(uint64_t type); bool TextureIsLayeredTexture(uint64_t type); 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); void TextureCreateImageViews(GraphicContext* ctx, VulkanImage* vk_obj, vk::ComponentMapping components, uint64_t type, uint32_t base_array, @@ -128,7 +127,8 @@ std::vector TextureBuildUploadRegions( uint32_t depth, uint64_t levels, bool array_texture, bool volume_texture, TextureUploadDestination destination, TextureUploadSliceLayout slice_layout); 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, uint64_t size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t fmt, uint64_t width, diff --git a/src/graphics/host_gpu/renderer/bufferCache.cpp b/src/graphics/host_gpu/renderer/bufferCache.cpp index f749f398d..fa06f76ce 100644 --- a/src/graphics/host_gpu/renderer/bufferCache.cpp +++ b/src/graphics/host_gpu/renderer/bufferCache.cpp @@ -9,7 +9,7 @@ #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/resourceMutex.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 "kernel/memory.h" @@ -21,6 +21,7 @@ #include #include #include +#include namespace Libs::Graphics { @@ -498,7 +499,7 @@ struct BufferCache::ReadbackWorker { " count=%u bytes=%u\n", page, range_count, data_offset); } - auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; + auto vk_buffer = command->Handle(); command->Begin(); vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlags {}, @@ -562,7 +563,7 @@ BufferCache::~BufferCache() { } } if (!m_buffers.empty()) { - VulkanDeviceWaitIdle(m_buffers.begin()->second->ctx); + Transfer::WaitForGraphicsIdle(m_buffers.begin()->second->ctx); } 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); for (const auto& range: ranges) { std::vector data(range.size); - UtilDownloadBuffer(cached->ctx, cached->buffer.get(), range.address - begin, - data.data(), range.size); + Transfer::DownloadBuffer(cached->ctx, cached->buffer.get(), + range.address - begin, data.data(), range.size); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); downloaded += range.size; } @@ -781,10 +782,10 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com }, [&]() noexcept { for (const auto& [upload_vaddr, upload_size]: uploads) { - UtilUploadBuffer(ctx, StagingBufferType::Vertex, old.buffer.get(), - upload_vaddr - old.vaddr, - reinterpret_cast(upload_vaddr), - upload_size); + Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, + old.buffer.get(), upload_vaddr - old.vaddr, + reinterpret_cast(upload_vaddr), + upload_size); } }); } @@ -801,7 +802,7 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com cached->buffer->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; VulkanCreateBuffer(ctx, cached->size, cached->buffer.get()); if (!overlaps.empty()) { - auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; + auto vk_buffer = command->Handle(); std::vector before; before.reserve(overlaps.size() + 1); for (const auto& overlap: overlaps) { @@ -866,9 +867,9 @@ std::pair BufferCache::ObtainBuffer(CommandBuffer* com }, [&]() noexcept { for (const auto& [upload_vaddr, upload_size]: ranges) { - UtilUploadBuffer(ctx, StagingBufferType::Vertex, cached.buffer.get(), - upload_vaddr - cached.vaddr, - reinterpret_cast(upload_vaddr), upload_size); + Transfer::UploadBuffer(ctx, Transfer::StagingBufferType::Vertex, + cached.buffer.get(), upload_vaddr - cached.vaddr, + reinterpret_cast(upload_vaddr), upload_size); } }); if (is_written) { @@ -963,7 +964,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t for (const auto& range: dirty_ranges) { auto& owner = find_owner(range.address, range.size); if (std::find(waited.begin(), waited.end(), owner.ctx) == waited.end()) { - VulkanDeviceWaitIdle(owner.ctx); + Transfer::WaitForGraphicsIdle(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); const auto buffer_offset = range.address - owner.vaddr; std::vector data(range.size); - UtilDownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, data.data(), - range.size); + Transfer::DownloadBuffer(owner.ctx, owner.buffer.get(), buffer_offset, + data.data(), range.size); Libs::LibKernel::Memory::WriteBacking(range.address, data.data(), data.size()); downloaded += range.size; } @@ -1020,9 +1021,9 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t }, [&]() noexcept { for (const auto& [address, bytes]: uploads) { - UtilUploadBuffer(cached.ctx, StagingBufferType::Vertex, cached.buffer.get(), - address - cached.vaddr, reinterpret_cast(address), - bytes); + Transfer::UploadBuffer(cached.ctx, Transfer::StagingBufferType::Vertex, + cached.buffer.get(), address - cached.vaddr, + reinterpret_cast(address), bytes); } }); if (uploads.empty()) { @@ -1065,16 +1066,11 @@ vk::BufferMemoryBarrier MakeDmaBarrier(VulkanBuffer* buffer, uint64_t offset, ui } vk::CommandBuffer GetDmaCommandBuffer(CommandBuffer* command) { - if (command == nullptr || command->IsInvalid() || command->GetPool() == nullptr || - command->GetIndex() >= command->GetPool()->buffers_count) { + if (command == nullptr) { EXIT("BufferCache: invalid DMA command buffer, command=%p\n", static_cast(command)); } - const auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; - if (vk_buffer == nullptr) { - EXIT("BufferCache: DMA command buffer handle is null, index=%u\n", command->GetIndex()); - } - return vk_buffer; + return command->Handle(); } } // namespace @@ -1308,27 +1304,10 @@ void BufferCache::SetTextureCache(TextureCache& texture_cache) { m_texture_cache = &texture_cache; } -// TODO: add LRU cache -void BufferCache::RegisterForDelete(VulkanBuffer* buffer) { - FaultSafeCacheLock lock(this, m_mutex); - - m_delete_later.push_back(buffer); -} - -void BufferCache::DeleteAll(GraphicContext* ctx) { - KYTY_PROFILER_BLOCK("BufferCache::DeleteAll"); +void BufferCache::ResetNullBuffer() { + KYTY_PROFILER_BLOCK("BufferCache::ResetNullBuffer"); 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(); } diff --git a/src/graphics/host_gpu/renderer/bufferCache.h b/src/graphics/host_gpu/renderer/bufferCache.h index 8ce33c9e0..a53c65345 100644 --- a/src/graphics/host_gpu/renderer/bufferCache.h +++ b/src/graphics/host_gpu/renderer/bufferCache.h @@ -10,7 +10,6 @@ #include #include #include -#include namespace Libs::Graphics { @@ -75,16 +74,15 @@ public: void ValidateGpuAccess(uint64_t vaddr, uint64_t size, bool is_read, bool is_written) const; void SetTextureCache(TextureCache& texture_cache); - void RegisterForDelete(VulkanBuffer* buffer); - void DeleteAll(GraphicContext* ctx); + void ResetNullBuffer(); private: struct CachedBuffer; struct ReadbackWorker; - Common::Mutex m_mutex; - std::vector m_delete_later; - std::shared_ptr m_null_buffer; + Common::Mutex m_mutex; + std::shared_ptr m_null_buffer; + // TODO: add LRU cache std::map> m_buffers; std::unique_ptr m_readback; RangeSet m_gpu_modified_ranges; diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index cfdf75f2d..0960fc81b 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -1,11 +1,8 @@ #include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "common/assert.h" -#include "common/common.h" #include "common/logging/log.h" #include "common/profiler.h" -#include "common/stringUtils.h" -#include "common/threads.h" #include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/hardwareContext.h" #include "graphics/guest_gpu/tile.h" @@ -16,264 +13,17 @@ #include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/render.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/presentation/displayBuffer.h" #include #include -#include -#include -#include -#include namespace Libs::Graphics { static std::atomic g_render_color_log_count = 0; -static float ColorClearUnorm(uint32_t value, uint32_t bits) { - return static_cast(value) / static_cast((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(value); - if ((value & sign_bit) != 0) { - signed_value = static_cast(value | ~mask); - } - - const auto denominator = static_cast((1u << (bits - 1u)) - 1u); - return std::max(-1.0f, static_cast(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(mantissa), -24); - } - - if (exponent == 0x1fu) { - return mantissa == 0 ? sign_mul * std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - - return sign_mul * - std::ldexp(static_cast(0x400u | mantissa), static_cast(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(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(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(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(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(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(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) void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw, 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. // 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 // that metadata path is implemented; render-pass load must preserve contents. 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"); } - width = rt.attrib2.width + 1; - height = rt.attrib2.height + 1; - const auto bytes_per_element = RenderGetColorBpp(rt.info.format) / 8u; + width = rt.attrib2.width + 1; + height = rt.attrib2.height + 1; + 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) { 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) { - const auto rt_format = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type, - rt.info.channel_order); - (void)reuse_existing_render_texture; RenderTargetInfo target {}; target.address = rt.base.addr; target.size = backing_size; - target.format = rt_format.format; + target.format = target_format.format; target.width = width; target.height = height; 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.levels = levels; target.layers = view.image_layers; @@ -525,7 +275,7 @@ void ResolveRenderColorTarget(uint64_t submit_id, CommandBuffer* buffer, const H r->extent = view_extent; r->base_mip_level = rt.view.current_mip_level; r->buffer_size = backing_size; - r->export_mapping = rt_format.export_mapping; + r->export_mapping = target_format.export_mapping; } else { const auto layout = static_cast(rt.info.format); const auto type = static_cast(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->base_mip_level = 0; r->buffer_size = video_image.size; - r->export_mapping = TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type, - rt.info.channel_order) - .export_mapping; + r->export_mapping = target_format.export_mapping; } } diff --git a/src/graphics/host_gpu/renderer/context.cpp b/src/graphics/host_gpu/renderer/context.cpp index d815a8cd6..d60ad7623 100644 --- a/src/graphics/host_gpu/renderer/context.cpp +++ b/src/graphics/host_gpu/renderer/context.cpp @@ -10,19 +10,35 @@ #include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/descriptorCache.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/renderContext.h" -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vma.h" #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/presentation/window.h" #include +#include #include #include #include namespace Libs::Graphics { static std::atomic 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(result)); + } +} + class CommandPool { public: CommandPool() = default; @@ -34,18 +50,19 @@ public: KYTY_CLASS_NO_COPY(CommandPool); - VulkanCommandPool* GetPool(int id) { - if (m_pool[id] == nullptr) { - Create(id); + VulkanCommandPool* GetPool(int queue_id) { + RequireValidQueueId(queue_id); + if (m_pools[queue_id] == nullptr) { + Create(queue_id); } - return m_pool[id]; + return m_pools[queue_id]; } void DeleteAll(); private: - void Create(int id); + void Create(int queue_id); - VulkanCommandPool* m_pool[GraphicContext::QUEUES_NUM] = {}; + std::array m_pools {}; }; RenderContext* g_render_ctx = nullptr; @@ -90,28 +107,28 @@ void GraphicsRenderCreateContext() { g_render_ctx->SetGraphicCtx(WindowGetGraphicContext()); } -void CommandPool::Create(int id) { - auto* ctx = g_render_ctx->GetGraphicCtx(); +void CommandPool::Create(int queue_id) { + RequireValidQueueId(queue_id); + EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(id < 0 || id >= GraphicContext::QUEUES_NUM); - auto*& pool = m_pool[id]; + auto* ctx = g_render_ctx->GetGraphicCtx(); + auto*& pool = m_pools[queue_id]; EXIT_IF(pool != nullptr); EXIT_IF(ctx == nullptr); EXIT_IF(ctx->device == nullptr); - EXIT_IF(ctx->queues[id].family == static_cast(-1)); + EXIT_IF(ctx->queues[queue_id].family == static_cast(-1)); pool = new VulkanCommandPool; vk::CommandPoolCreateInfo pool_info {}; pool_info.sType = vk::StructureType::eCommandPoolCreateInfo; 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; - ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool); - - EXIT_NOT_IMPLEMENTED(pool->pool == nullptr); + const auto result = ctx->device.createCommandPool(&pool_info, nullptr, &pool->pool); + EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool->pool == nullptr); pool->buffers_count = 8; pool->buffers = std::make_unique(pool->buffers_count); @@ -162,7 +179,7 @@ void CommandPool::Create(int id) { void CommandPool::DeleteAll() { auto* ctx = g_render_ctx->GetGraphicCtx(); - for (auto& pool: m_pool) { + for (auto& pool: m_pools) { if (pool != nullptr) { EXIT_IF(ctx == nullptr); EXIT_IF(ctx->device == nullptr); @@ -194,6 +211,14 @@ bool CommandBuffer::IsInvalid() const { 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() { EXIT_IF(!IsInvalid()); @@ -204,7 +229,7 @@ void CommandBuffer::Allocate() { for (uint32_t i = 0; i < m_pool->buffers_count; i++) { if (!m_pool->busy[i]) { m_pool->busy[i] = true; - m_pool->buffers[i].reset(vk::CommandBufferResetFlagBits::eReleaseResources); + ResetNativeCommandBuffer(m_pool->buffers[i]); m_index = i; break; } @@ -223,9 +248,8 @@ void CommandBuffer::Free() { m_host_stream.Release(); m_pool->busy[m_index] = false; - m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources); - RecycleDescriptorsAfterFence(); - m_fence_resources.ReleaseAfterFence(); + ResetNativeCommandBuffer(m_pool->buffers[m_index]); + ReleaseResourcesAfterFence(); m_index = static_cast(-1); EXIT_NOT_IMPLEMENTED(!IsInvalid()); @@ -258,9 +282,7 @@ void CommandBuffer::RecycleDescriptorsAfterFence() { } void CommandBuffer::Begin() const { - EXIT_IF(IsInvalid()); - - auto buffer = m_pool->buffers[m_index]; + auto buffer = Handle(); vk::CommandBufferBeginInfo begin_info {}; begin_info.sType = vk::StructureType::eCommandBufferBeginInfo; @@ -274,9 +296,7 @@ void CommandBuffer::Begin() const { } void CommandBuffer::End() const { - EXIT_IF(IsInvalid()); - - auto buffer = m_pool->buffers[m_index]; + auto buffer = Handle(); auto result = buffer.end(); @@ -295,159 +315,48 @@ void CommandBuffer::SetDebugInfo(uint32_t op, uint64_t submit_id, uint32_t arg0, } void CommandBuffer::Execute() { - EXIT_IF(IsInvalid()); - 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(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(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); + Submit(nullptr, {}, nullptr); } void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore signal_semaphore) { - EXIT_IF(IsInvalid()); - 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(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(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(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); + Submit(nullptr, {}, ResolveSignalSemaphore(signal_semaphore)); } void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore, vk::PipelineStageFlags wait_stage, 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(m_execute); - EXIT_IF(wait_semaphore == nullptr); - 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]; - } + const bool has_wait = wait_semaphore != nullptr; + const bool has_signal = signal_semaphore != nullptr; + auto buffer = Handle(); + auto fence = m_pool->fences[m_index]; vk::SubmitInfo submit_info {}; submit_info.sType = vk::StructureType::eSubmitInfo; submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &wait_semaphore; - submit_info.pWaitDstStageMask = &wait_stage; + submit_info.waitSemaphoreCount = has_wait ? 1u : 0u; + submit_info.pWaitSemaphores = has_wait ? &wait_semaphore : nullptr; + submit_info.pWaitDstStageMask = has_wait ? &wait_stage : nullptr; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffer; - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &signal_semaphore; + submit_info.signalSemaphoreCount = has_signal ? 1u : 0u; + 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 = g_render_ctx->GetGraphicCtx()->device.resetFences(1, &fence); + auto result = ctx->device.resetFences(1, &fence); if (result != vk::Result::eSuccess) { LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(), static_cast(result)); @@ -486,20 +395,16 @@ void CommandBuffer::ExecuteWithSemaphore(vk::Semaphore wait_semaphore, 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() { - const bool was_executed = m_execute; - 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(); + FinalizeFence(false); } void CommandBuffer::WaitForFenceOnly() { @@ -521,19 +426,35 @@ void CommandBuffer::WaitForFenceOnly() { } void CommandBuffer::WaitForFenceAndReset() { + FinalizeFence(true); +} + +void CommandBuffer::FinalizeFence(bool reset_recording) { const bool was_executed = m_execute; WaitForFenceOnly(); if (was_executed) { m_execute = false; m_fence_waited = false; - m_pool->buffers[m_index].reset(vk::CommandBufferResetFlagBits::eReleaseResources); - m_recording_generation++; + if (reset_recording) { + ResetNativeCommandBuffer(m_pool->buffers[m_index]); + m_recording_generation++; + } + } + if (reset_recording) { + m_host_stream.Reset(); } - m_host_stream.Reset(); if (was_executed) { - RecycleDescriptorsAfterFence(); - m_fence_resources.ReleaseAfterFence(); + ReleaseResourcesAfterFence(); } + DeleteBuffersAfterFence(); +} + +void CommandBuffer::ReleaseResourcesAfterFence() { + RecycleDescriptorsAfterFence(); + m_fence_resources.ReleaseAfterFence(); +} + +void CommandBuffer::DeleteBuffersAfterFence() { for (auto* buffer: m_delete_after_fence) { VulkanDeleteBuffer(g_render_ctx->GetGraphicCtx(), buffer); delete buffer; @@ -543,9 +464,7 @@ void CommandBuffer::WaitForFenceAndReset() { void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t requested_color_count, RenderDepthInfo* depth) const { - EXIT_IF(IsInvalid()); - - auto buffer = m_pool->buffers[m_index]; + auto buffer = Handle(); EXIT_IF(framebuffer == 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.image = depth->vulkan_buffer->image; 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.levelCount = 1; image_memory_barrier.subresourceRange.baseArrayLayer = 0; @@ -665,9 +584,7 @@ void CommandBuffer::BeginRenderPass(VulkanFramebuffer* framebuffer, RenderColorI } void CommandBuffer::EndRenderPass() const { - EXIT_IF(IsInvalid()); - - auto buffer = m_pool->buffers[m_index]; + auto buffer = Handle(); buffer.endRenderPass(); } diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index 193541143..f0c91419d 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -16,7 +16,7 @@ #include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/render.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/presentation/displayBuffer.h" diff --git a/src/graphics/host_gpu/renderer/descriptorCache.cpp b/src/graphics/host_gpu/renderer/descriptorCache.cpp index 2525a2e86..c681a3659 100644 --- a/src/graphics/host_gpu/renderer/descriptorCache.cpp +++ b/src/graphics/host_gpu/renderer/descriptorCache.cpp @@ -102,15 +102,10 @@ vk::DescriptorImageInfo MakeDescriptorImageInfo(const DescriptorCache::TextureBi } // namespace -void DescriptorCache::Init() { - m_initialized = true; -} - vk::DescriptorSetLayout DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stage, const ShaderRecompiler::IR::Program& program) { EXIT_IF(gctx == nullptr); - Init(); const auto key = LayoutKey(stage, program); if (const auto found = m_descriptor_set_layouts.find(key); found != m_descriptor_set_layouts.end()) { @@ -132,8 +127,8 @@ DescriptorCache::GetDescriptorSetLayoutInternal(GraphicContext* gctx, Stage stag info.bindingCount = static_cast(bindings.size()); info.pBindings = bindings.data(); vk::DescriptorSetLayout layout = nullptr; - gctx->device.createDescriptorSetLayout(&info, nullptr, &layout); - EXIT_NOT_IMPLEMENTED(layout == nullptr); + const auto result = gctx->device.createDescriptorSetLayout(&info, nullptr, &layout); + EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || layout == nullptr); m_descriptor_set_layouts.emplace(key, layout); return layout; } @@ -157,8 +152,8 @@ void DescriptorCache::CreatePool(GraphicContext* gctx) { info.maxSets = MaxSets; const auto pool_id = static_cast(m_pools.size()); auto& pool = m_pools.emplace_back(); - gctx->device.createDescriptorPool(&info, nullptr, &pool.pool); - EXIT_NOT_IMPLEMENTED(pool.pool == nullptr); + const auto result = gctx->device.createDescriptorPool(&info, nullptr, &pool.pool); + EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess || pool.pool == nullptr); pool.next_free_pool = m_first_free_pool; m_first_free_pool = pool_id; } @@ -198,7 +193,6 @@ VulkanDescriptorSet* DescriptorCache::Allocate(Stage } return new VulkanDescriptorSet {sets.back(), layout, pool_id}; } - pool.free = false; m_first_free_pool = pool.next_free_pool; break; } diff --git a/src/graphics/host_gpu/renderer/descriptorCache.h b/src/graphics/host_gpu/renderer/descriptorCache.h index de1a77060..cd11a623e 100644 --- a/src/graphics/host_gpu/renderer/descriptorCache.h +++ b/src/graphics/host_gpu/renderer/descriptorCache.h @@ -22,10 +22,6 @@ struct Program; class CommandBuffer; struct ShaderStageRuntime; -struct VulkanDescriptor { - vk::DescriptorSet descriptor_set = nullptr; -}; - struct VulkanDescriptorSet { vk::DescriptorSet set = nullptr; vk::DescriptorSetLayout layout = nullptr; @@ -38,12 +34,6 @@ struct BufferView { vk::DeviceSize range = VK_WHOLE_SIZE; }; -struct ShaderAddressWriteRange { - VulkanBuffer* buffer = nullptr; - uint64_t address = 0; - uint64_t size = 0; -}; - class DescriptorCache { public: enum class Stage { Unknown, Vertex, Pixel, Compute }; @@ -74,7 +64,7 @@ public: }; DescriptorCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; } + ~DescriptorCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(DescriptorCache); vk::DescriptorSetLayout GetDescriptorSetLayout(Stage stage, @@ -87,10 +77,8 @@ private: struct Pool { vk::DescriptorPool pool = nullptr; int next_free_pool = -1; - bool free = true; }; - void Init(); void CreatePool(GraphicContext* gctx); VulkanDescriptorSet* Allocate(Stage stage, const ShaderRecompiler::IR::Program& program); vk::DescriptorSetLayout @@ -103,17 +91,12 @@ private: std::unordered_map> m_free_sets_by_layout; std::map, vk::DescriptorSetLayout> m_descriptor_set_layouts; - bool m_initialized = false; }; -const char* storage_usage_name(ShaderStorageUsage usage); -vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format); -std::vector BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, - vk::PipelineBindPoint pipeline_bind_point, - vk::PipelineLayout layout, - const ShaderStageRuntime& runtime, - vk::ShaderStageFlags vk_stage, - DescriptorCache::Stage stage); +void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, + vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout, + const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, + DescriptorCache::Stage stage); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/descriptors.cpp b/src/graphics/host_gpu/renderer/descriptors.cpp index 556e2eb5f..fe6a8a8c7 100644 --- a/src/graphics/host_gpu/renderer/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/descriptors.cpp @@ -23,7 +23,7 @@ #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderTargetBarriers.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/vulkanCommon.h" #include "graphics/presentation/displayBuffer.h" @@ -34,9 +34,9 @@ #include #include -#include #include #include +#include #ifdef min #undef min @@ -71,14 +71,6 @@ static const char* VulkanImageTypeName(VulkanImageType type) { } } -vk::ImageAspectFlags DepthStencilAspectMask(vk::Format format) { - auto ret = static_cast(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) { EXIT_IF(image == nullptr); @@ -126,25 +118,10 @@ static VulkanImage* GetDummyStorageTexture(TextureVariant variant) { TextureVariantIs3D(variant)); } -static ShaderBufferResource -NativeBufferDescriptor(const ShaderRecompiler::IR::DescriptorValue& descriptor) { - ShaderBufferResource result; - std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields); - 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 void CopyNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& source, + std::span destination) { + EXIT_IF(source.dword_count != destination.size()); + std::copy_n(source.dwords.begin(), destination.size(), destination.begin()); } 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, const ShaderRecompiler::IR::ImageResource& resource, const ShaderRecompiler::IR::DescriptorValue& value) { - auto descriptor = NativeTextureDescriptor(value); - const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage || - resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; - const auto variant = NativeTextureVariant(resource); + ShaderTextureResource descriptor; + CopyNativeDescriptor(value, descriptor.fields); + const bool storage = resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImage || + resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; + const auto variant = NativeTextureVariant(resource); if (storage) { 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", static_cast(resource.kind), format, address); } - const auto view_format = TextureGetFormat(format, storage ? TextureFormatUsage::Storage - : TextureFormatUsage::Sampled); + const auto view_format = TextureGetFormat(format); const auto type = static_cast(descriptor.Type()); const auto target_view = 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, 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(), program.info.sampled_pairs.end(), [&](const auto& pair) { return pair.sampler == index && @@ -776,12 +754,10 @@ static BufferView NativeUpload(CommandBuffer* command_buffer, std::span BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, - vk::PipelineBindPoint pipeline_bind_point, - vk::PipelineLayout layout, - const ShaderStageRuntime& runtime, - vk::ShaderStageFlags vk_stage, - DescriptorCache::Stage stage) { +void BindDescriptors(uint64_t submit_id, CommandBuffer* buffer, + vk::PipelineBindPoint pipeline_bind_point, vk::PipelineLayout layout, + const ShaderStageRuntime& runtime, vk::ShaderStageFlags vk_stage, + DescriptorCache::Stage stage) { KYTY_PROFILER_FUNCTION(); EXIT_IF(buffer == nullptr || !runtime); const auto& program = *runtime.program; @@ -790,15 +766,16 @@ std::vector BindDescriptors(uint64_t submit_id, Command if (!ShaderRecompiler::IR::ValidateResourceSpecialization(program, snapshot, &error)) { 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); DescriptorCache::NativeDescriptors descriptors; descriptors.buffers.reserve(program.info.buffers.size()); for (uint32_t i = 0; i < program.info.buffers.size(); i++) { + ShaderBufferResource descriptor; + CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields); descriptors.buffers.push_back( - NativeStorageBuffer(submit_id, buffer, NativeBufferDescriptor(snapshot.buffers[i]), - program.info.buffers[i])); + NativeStorageBuffer(submit_id, buffer, descriptor, program.info.buffers[i])); } descriptors.images.reserve(program.info.images.size()); for (uint32_t i = 0; i < program.info.images.size(); i++) { @@ -816,17 +793,9 @@ std::vector BindDescriptors(uint64_t submit_id, Command descriptors.samplers.push_back(NativeSampler(program, i, snapshot.samplers[i])); } descriptors.addresses.reserve(program.info.addresses.size()); - std::vector address_writes; for (uint32_t i = 0; i < program.info.addresses.size(); i++) { - auto view = NativeAddressBuffer(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(view.range)}); - } + descriptors.addresses.push_back(NativeAddressBuffer( + submit_id, buffer, program.info.addresses[i], snapshot.addresses[i])); } if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != @@ -893,7 +862,6 @@ std::vector BindDescriptors(uint64_t submit_id, Command vk_buffer.pushConstants(layout, vk_stage, program.bindings.push_constant_offset, program.bindings.push_constant_size, user_data.data()); } - return address_writes; } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/descriptors.h b/src/graphics/host_gpu/renderer/descriptors.h index 5d9a5d438..b29a55a02 100644 --- a/src/graphics/host_gpu/renderer/descriptors.h +++ b/src/graphics/host_gpu/renderer/descriptors.h @@ -1,16 +1,29 @@ #ifndef 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/shader/recompiler/ShaderIR.h" #include "graphics/shader/shaderBindings.h" #include +#include +#include namespace Libs::Graphics { struct VulkanImage; +template +[[nodiscard]] T DecodeNativeDescriptor(const ShaderRecompiler::IR::DescriptorValue& value) { + static_assert(std::is_trivially_copyable_v); + 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 { vk::ImageViewType type = static_cast(VK_IMAGE_VIEW_TYPE_MAX_ENUM); uint32_t base_layer = 0; diff --git a/src/graphics/host_gpu/renderer/dummyTextureCache.cpp b/src/graphics/host_gpu/renderer/dummyTextureCache.cpp index 68f35bac6..ec3614061 100644 --- a/src/graphics/host_gpu/renderer/dummyTextureCache.cpp +++ b/src/graphics/host_gpu/renderer/dummyTextureCache.cpp @@ -2,7 +2,7 @@ #include "common/assert.h" #include "graphics/host_gpu/renderer/image.h" -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" namespace Libs::Graphics { @@ -20,11 +20,11 @@ DummyTextureCache::~DummyTextureCache() { return; } - VulkanDeviceWaitIdle(m_ctx); + Transfer::WaitForGraphicsIdle(m_ctx); const auto destroy = [this](auto& slots) { for (auto& slot: slots) { if (slot.image != nullptr) { - ImageOps::Destroy(m_ctx, slot.image, &slot.memory); + ImageOps::Destroy(m_ctx, slot.image); 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& slot = slots[DummyTextureIndex(uint_format, image_3d)]; if (slot.image == nullptr) { - slot.image = ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, - usage == Usage::Storage, &slot.memory); + slot.image = + ImageOps::CreateDummyTexture(ctx, uint_format, image_3d, usage == Usage::Storage); } return slot.image; } diff --git a/src/graphics/host_gpu/renderer/dummyTextureCache.h b/src/graphics/host_gpu/renderer/dummyTextureCache.h index e157502f7..7a394d19e 100644 --- a/src/graphics/host_gpu/renderer/dummyTextureCache.h +++ b/src/graphics/host_gpu/renderer/dummyTextureCache.h @@ -24,7 +24,6 @@ public: private: struct Slot { GpuTextureVulkanImage* image = nullptr; - VulkanMemory memory {}; }; Common::Mutex m_mutex; diff --git a/src/graphics/host_gpu/renderer/framebufferCache.cpp b/src/graphics/host_gpu/renderer/framebufferCache.cpp index b660a7f94..58971dbe9 100644 --- a/src/graphics/host_gpu/renderer/framebufferCache.cpp +++ b/src/graphics/host_gpu/renderer/framebufferCache.cpp @@ -6,7 +6,6 @@ #include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/renderContext.h" -#include "graphics/host_gpu/utils.h" #include "graphics/host_gpu/vulkanCommon.h" #include @@ -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; framebuffer->render_pass = nullptr; framebuffer->framebuffer = nullptr; @@ -120,23 +132,6 @@ VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* colors, 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] = {}; for (uint32_t i = 0; i < color_count; i++) { 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 diff --git a/src/graphics/host_gpu/renderer/framebufferCache.h b/src/graphics/host_gpu/renderer/framebufferCache.h index c8825465e..223d70a0f 100644 --- a/src/graphics/host_gpu/renderer/framebufferCache.h +++ b/src/graphics/host_gpu/renderer/framebufferCache.h @@ -50,7 +50,7 @@ inline uint64_t render_pass_compat_id(uint32_t color_count, const vk::Format* co class FramebufferCache { public: FramebufferCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; } + ~FramebufferCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(FramebufferCache); VulkanFramebuffer* CreateFramebuffer(RenderColorInfo* colors, uint32_t color_count, @@ -59,8 +59,6 @@ public: void FreeFramebufferByDepth(DepthStencilVulkanImage* image); private: - VideoOutVulkanImage* CreateDummyBuffer(vk::Format format, uint32_t width, uint32_t height); - struct Framebuffer { VulkanFramebuffer* framebuffer = nullptr; uint64_t image_id[RENDER_COLOR_ATTACHMENTS_MAX] = {}; @@ -74,9 +72,8 @@ private: bool depth_read_only = false; }; - Common::Mutex m_mutex; - std::vector m_framebuffers; - std::vector m_dummy_buffers; + Common::Mutex m_mutex; + std::vector m_framebuffers; }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/gdsBuffer.cpp b/src/graphics/host_gpu/renderer/gdsBuffer.cpp index 970911a0f..b89e33be7 100644 --- a/src/graphics/host_gpu/renderer/gdsBuffer.cpp +++ b/src/graphics/host_gpu/renderer/gdsBuffer.cpp @@ -1,7 +1,7 @@ #include "graphics/host_gpu/renderer/gdsBuffer.h" #include "common/assert.h" -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vma.h" namespace Libs::Graphics { diff --git a/src/graphics/host_gpu/renderer/gdsBuffer.h b/src/graphics/host_gpu/renderer/gdsBuffer.h index 872d7fd9b..265c9eae9 100644 --- a/src/graphics/host_gpu/renderer/gdsBuffer.h +++ b/src/graphics/host_gpu/renderer/gdsBuffer.h @@ -14,7 +14,7 @@ namespace Libs::Graphics { class GdsBuffer { public: GdsBuffer() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; } + ~GdsBuffer() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(GdsBuffer); void Clear(GraphicContext* ctx, uint64_t dw_offset, uint32_t dw_num, uint32_t clear_value); diff --git a/src/graphics/host_gpu/renderer/image.cpp b/src/graphics/host_gpu/renderer/image.cpp index 2df401a7a..a12a66fc2 100644 --- a/src/graphics/host_gpu/renderer/image.cpp +++ b/src/graphics/host_gpu/renderer/image.cpp @@ -10,7 +10,8 @@ #include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/imageView.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 @@ -40,7 +41,7 @@ TextureImageCreateParams MakeImageParams(const ImageInfo& info, bool storage) { params.image_layout = TextureUploadDestination::MipLevels; params.allow_cube_view = !storage; 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::k32Float)); 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, - VulkanMemory* memory, vk::ComponentMapping* components) { + vk::ComponentMapping* components) { if (components == nullptr) { EXIT("TextureCache: invalid texture component output\n"); } auto* image = storage ? static_cast(new StorageTextureVulkanImage) : new TextureVulkanImage; - *components = TextureCreateImage(ctx, image, memory, MakeImageParams(info, storage)); + *components = TextureCreateImage(ctx, image, MakeImageParams(info, storage)); 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); } if (refresh) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } const auto slice_size = info.size / info.layers; const auto upload_size = slice_size * layer_count; @@ -204,16 +205,16 @@ void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* ima return; } if (info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && - UtilBufferIsTiled(info.address, slice_size)) { - UtilScratchBuffer scratch(slice_size); + Transfer::GuestBufferIsTiled(info.address, slice_size)) { + Transfer::ScratchBuffer scratch(slice_size); TileConvertTiledToLinearRenderTarget( scratch.Data(), reinterpret_cast(info.address), info.width, info.height, info.pitch, info.bytes_per_element, slice_size); - UtilFillImage(ctx, image, scratch.Data(), slice_size, info.pitch, - vk::ImageLayout::eGeneral); + Transfer::UploadImage(ctx, image, scratch.Data(), slice_size, info.pitch, + vk::ImageLayout::eGeneral); } else { - UtilFillImage(ctx, image, reinterpret_cast(info.address), slice_size, - info.pitch, vk::ImageLayout::eGeneral); + Transfer::UploadImage(ctx, image, reinterpret_cast(info.address), slice_size, + info.pitch, vk::ImageLayout::eGeneral); } } @@ -222,8 +223,7 @@ void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, UploadRenderTargetLayers(ctx, image, info, 0, info.layers, refresh); } -RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info, - VulkanMemory* memory) { +RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info) { auto* image = new RenderTextureVulkanImage; image->extent.width = info.width; image->extent.height = info.height; @@ -231,33 +231,30 @@ RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, const RenderTa image->mip_levels = info.levels; image->layers = info.layers; image->layout = vk::ImageLayout::eUndefined; - UtilResetImageViews(image); vk::ImageCreateInfo create {}; - create.sType = vk::StructureType::eImageCreateInfo; - create.flags = RenderTargetCreateFlags(info.format); - create.imageType = vk::ImageType::e2D; - create.extent = {info.width, info.height, 1}; - create.mipLevels = info.levels; - create.arrayLayers = info.layers; - create.format = info.format; - create.tiling = vk::ImageTiling::eOptimal; - create.initialLayout = vk::ImageLayout::eUndefined; - create.usage = RenderTargetUsage(ctx, info.format, create.flags); - create.sharingMode = vk::SharingMode::eExclusive; - create.samples = vk::SampleCountFlagBits::e1; - memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, &create, image, memory)) { + create.sType = vk::StructureType::eImageCreateInfo; + create.flags = RenderTargetCreateFlags(info.format); + create.imageType = vk::ImageType::e2D; + create.extent = {info.width, info.height, 1}; + create.mipLevels = info.levels; + create.arrayLayers = info.layers; + create.format = info.format; + create.tiling = vk::ImageTiling::eOptimal; + create.initialLayout = vk::ImageLayout::eUndefined; + create.usage = RenderTargetUsage(ctx, info.format, create.flags); + create.sharingMode = vk::SharingMode::eExclusive; + create.samples = vk::SampleCountFlagBits::e1; + image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; + if (!VulkanCreateImage(ctx, create, image)) { EXIT("TextureCache: failed to create render target, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - image->memory = *memory; ImageViewOps::CreateRenderTargetViews(ctx, image); return image; } -DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, - VulkanMemory* memory) { +DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info) { vk::ImageCreateInfo create {}; create.sType = vk::StructureType::eImageCreateInfo; create.imageType = vk::ImageType::e2D; @@ -278,22 +275,20 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge static_cast(info.format), static_cast(create.usage)); } - auto* image = new DepthStencilVulkanImage; - image->extent.width = info.width; - image->extent.height = info.height; - image->guest_pitch = info.pitch; - image->layers = info.layers; - image->format = info.format; - image->layout = vk::ImageLayout::eUndefined; - image->compressed = false; - UtilResetImageViews(image); - memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, &create, image, memory)) { + auto* image = new DepthStencilVulkanImage; + image->extent.width = info.width; + image->extent.height = info.height; + image->guest_pitch = info.pitch; + image->layers = info.layers; + image->format = info.format; + image->layout = vk::ImageLayout::eUndefined; + image->compressed = false; + image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; + if (!VulkanCreateImage(ctx, create, image)) { EXIT("TextureCache: failed to create depth target, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - image->memory = *memory; ImageViewOps::CreateDepthViews(ctx, image); return image; } @@ -334,34 +329,31 @@ void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { (void)RenderTargetUsage(ctx, info.format, vk::ImageCreateFlags {}); } -VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info, - VulkanMemory* memory) { +VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info) { auto* image = new VideoOutVulkanImage; image->extent.width = info.width; image->extent.height = info.height; image->format = info.format; image->layout = vk::ImageLayout::eUndefined; - UtilResetImageViews(image); vk::ImageCreateInfo create {}; - create.sType = vk::StructureType::eImageCreateInfo; - create.imageType = vk::ImageType::e2D; - create.extent = {info.width, info.height, 1}; - create.mipLevels = 1; - create.arrayLayers = 1; - create.format = info.format; - create.tiling = vk::ImageTiling::eOptimal; - create.initialLayout = vk::ImageLayout::eUndefined; - create.flags = RenderTargetCreateFlags(info.format); - create.usage = RenderTargetUsage(ctx, info.format, create.flags); - create.sharingMode = vk::SharingMode::eExclusive; - create.samples = vk::SampleCountFlagBits::e1; - memory->property = vk::MemoryPropertyFlagBits::eDeviceLocal; - if (!VulkanCreateImage(ctx, &create, image, memory)) { + create.sType = vk::StructureType::eImageCreateInfo; + create.imageType = vk::ImageType::e2D; + create.extent = {info.width, info.height, 1}; + create.mipLevels = 1; + create.arrayLayers = 1; + create.format = info.format; + create.tiling = vk::ImageTiling::eOptimal; + create.initialLayout = vk::ImageLayout::eUndefined; + create.flags = RenderTargetCreateFlags(info.format); + create.usage = RenderTargetUsage(ctx, info.format, create.flags); + create.sharingMode = vk::SharingMode::eExclusive; + create.samples = vk::SampleCountFlagBits::e1; + image->memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal; + if (!VulkanCreateImage(ctx, create, image)) { EXIT("TextureCache: failed to create video-out image, addr=0x%016" PRIx64 " extent=%ux%u format=%d\n", info.address, info.width, info.height, static_cast(info.format)); } - image->memory = *memory; ImageViewOps::CreateVideoOutViews(ctx, image); return image; } @@ -374,10 +366,10 @@ void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const Video info.address, info.metadata_address, info.dcc_control); } if (refresh) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } image->layout = vk::ImageLayout::eUndefined; - UtilScratchBuffer scratch(info.size); + Transfer::ScratchBuffer scratch(info.size); TileConvertTiledToLinearRenderTarget( scratch.Data(), reinterpret_cast(info.address), info.width, info.height, 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]); } } - 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, - bool storage, VulkanMemory* memory) { - if (memory == nullptr || memory->allocation != nullptr) { - EXIT("TextureCache: invalid dummy texture memory slot, slot=%p allocation=%p storage=%d\n", - static_cast(memory), - memory == nullptr ? nullptr : static_cast(memory->allocation), storage); - } + bool storage) { auto* image = storage ? static_cast(new StorageTextureVulkanImage) : new TextureVulkanImage; auto usage = storage ? TextureFormatUsage::Storage : TextureFormatUsage::Sampled; @@ -404,69 +392,52 @@ GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, auto owner = storage ? "DummyStorageTexture" : "DummySampledTexture"; 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; - 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, params.levels, params.depth, params.allow_cube_view, params.view_usage); return image; } -void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory) { - KYTY_PROFILER_BLOCK("TextureCache::DeleteGpuTexture"); +void Destroy(GraphicContext* ctx, VulkanImage* image) { + KYTY_PROFILER_BLOCK("TextureCache::DeleteImage"); + EXIT_IF(ctx == nullptr || image == nullptr || g_render_ctx == nullptr); - EXIT_IF(ctx == nullptr); - EXIT_IF(image == nullptr); + switch (image->type) { + case VulkanImageType::RenderTexture: + case VulkanImageType::VideoOut: + g_render_ctx->GetFramebufferCache()->FreeFramebufferByColor(image); + break; + case VulkanImageType::DepthStencil: + g_render_ctx->GetFramebufferCache()->FreeFramebufferByDepth( + static_cast(image)); + break; + case VulkanImageType::Texture: + case VulkanImageType::StorageTexture: break; + case VulkanImageType::Unknown: EXIT("cannot destroy an untyped Vulkan image\n"); + } ImageViewOps::DestroyViews(ctx, image); - VulkanDeleteImage(ctx, image, memory); + VulkanDeleteImage(ctx, image); switch (image->type) { case VulkanImageType::Texture: delete static_cast(image); break; case VulkanImageType::StorageTexture: delete static_cast(image); break; - default: EXIT("unsupported gpu texture image type: %d\n", static_cast(image->type)); + case VulkanImageType::RenderTexture: + delete static_cast(image); + break; + case VulkanImageType::DepthStencil: + delete static_cast(image); + break; + case VulkanImageType::VideoOut: delete static_cast(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 Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/image.h b/src/graphics/host_gpu/renderer/image.h index 17c46f9a2..05922fea9 100644 --- a/src/graphics/host_gpu/renderer/image.h +++ b/src/graphics/host_gpu/renderer/image.h @@ -15,7 +15,7 @@ struct GpuTextureVulkanImage; struct GraphicContext; struct RenderTextureVulkanImage; struct VideoOutVulkanImage; -struct VulkanMemory; +struct VulkanImage; struct Image final: ImageInfo { Image& operator=(const ImageInfo& value) { @@ -101,37 +101,31 @@ private: namespace ImageOps { [[nodiscard]] GpuTextureVulkanImage* CreateTexture(GraphicContext* ctx, const ImageInfo& info, - bool storage, VulkanMemory* memory, - vk::ComponentMapping* components); + bool storage, vk::ComponentMapping* components); void CreateTextureViews(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, bool storage, vk::ComponentMapping components); -[[nodiscard]] RenderTextureVulkanImage* -CreateRenderTarget(GraphicContext* ctx, const RenderTargetInfo& info, VulkanMemory* memory); -[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element); +[[nodiscard]] RenderTextureVulkanImage* CreateRenderTarget(GraphicContext* ctx, + const RenderTargetInfo& info); +[[nodiscard]] uint32_t RenderTargetTransferFormat(uint32_t bytes_per_element); void UploadRenderTargetLayers(GraphicContext* ctx, RenderTextureVulkanImage* image, const RenderTargetInfo& info, uint32_t base_layer, uint32_t layer_count, bool refresh); void UploadRenderTarget(GraphicContext* ctx, RenderTextureVulkanImage* image, const RenderTargetInfo& info, bool refresh); -[[nodiscard]] DepthStencilVulkanImage* -CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info, VulkanMemory* memory); +[[nodiscard]] DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, + const DepthTargetInfo& info); void ValidateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); -[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info, - VulkanMemory* memory); +[[nodiscard]] VideoOutVulkanImage* CreateVideoOut(GraphicContext* ctx, const VideoOutInfo& info); void UploadVideoOut(GraphicContext* ctx, VideoOutVulkanImage* image, const VideoOutInfo& info, bool refresh); [[nodiscard]] GpuTextureVulkanImage* CreateDummyTexture(GraphicContext* ctx, bool uint_format, - bool image_3d, bool storage, - VulkanMemory* memory); + bool image_3d, bool storage); -void Destroy(GraphicContext* ctx, GpuTextureVulkanImage* image, VulkanMemory* memory); -void Destroy(GraphicContext* ctx, RenderTextureVulkanImage* image, VulkanMemory* memory); -void Destroy(GraphicContext* ctx, DepthStencilVulkanImage* image, VulkanMemory* memory); -void Destroy(GraphicContext* ctx, VideoOutVulkanImage* image, VulkanMemory* memory); +void Destroy(GraphicContext* ctx, VulkanImage* image); } // namespace ImageOps diff --git a/src/graphics/host_gpu/renderer/imageView.cpp b/src/graphics/host_gpu/renderer/imageView.cpp index 02ccb6ef9..db9fdc43d 100644 --- a/src/graphics/host_gpu/renderer/imageView.cpp +++ b/src/graphics/host_gpu/renderer/imageView.cpp @@ -3,7 +3,6 @@ #include "common/assert.h" #include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/renderer/textureCache.h" -#include "graphics/host_gpu/utils.h" #include @@ -11,28 +10,72 @@ namespace Libs::Graphics { 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(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(result), static_cast(image->format), + static_cast(create_info.format), view_index); + } +} + void CreateRenderTargetView(GraphicContext* ctx, VulkanImage* image, int index, vk::ComponentSwizzle r, vk::ComponentSwizzle g, vk::ComponentSwizzle b, vk::ComponentSwizzle a, vk::ImageViewType type = vk::ImageViewType::e2D, vk::Format view_format = vk::Format::eUndefined, vk::ImageUsageFlags view_usage = {}, uint32_t level_count = 0) { const auto layer_count = type == vk::ImageViewType::e2DArray ? image->layers : 1u; - UtilCreateImageView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, - 0, layer_count, level_count == 0 ? image->mip_levels : level_count, - view_format, view_usage); + CreateView(ctx, image, index, type, vk::ImageAspectFlagBits::eColor, {r, g, b, a}, 0, 0, + layer_count, level_count == 0 ? image->mip_levels : level_count, view_format, + view_usage); } } // namespace namespace ImageViewOps { -vk::ImageAspectFlags DepthAspectMask(vk::Format format) noexcept { - auto aspects = vk::ImageAspectFlags {vk::ImageAspectFlagBits::eDepth}; - if (format == vk::Format::eD16UnormS8Uint || format == vk::Format::eD24UnormS8Uint || - format == vk::Format::eD32SfloatS8Uint) { - aspects |= vk::ImageAspectFlagBits::eStencil; +vk::ImageAspectFlags DepthAspectMask(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(format)); } - return aspects; } bool FormatSupportsStorage(GraphicContext* ctx, vk::Format format) { @@ -68,11 +111,11 @@ void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* imag } void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) { - UtilCreateImageView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, - DepthAspectMask(image->format), - {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, - vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, - 0, 0, 1, 1); + CreateView(ctx, image, VulkanImage::VIEW_DEFAULT, vk::ImageViewType::e2D, + DepthAspectMask(image->format), + {vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity}, + 0, 0, 1, 1); } void CreateVideoOutViews(GraphicContext* ctx, VideoOutVulkanImage* image) { @@ -338,7 +381,7 @@ vk::ImageView TextureCache::GetStorageTextureSampledView(GraphicContext* static_cast(image), info.type, info.depth, info.base_level, info.levels, 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) && !IsR32UintFloatReinterpretation(image->format, view_format)) { EXIT("TextureCache: incompatible sampled view of storage texture, image_format=%d" diff --git a/src/graphics/host_gpu/renderer/imageView.h b/src/graphics/host_gpu/renderer/imageView.h index 99a74a920..20399e1f8 100644 --- a/src/graphics/host_gpu/renderer/imageView.h +++ b/src/graphics/host_gpu/renderer/imageView.h @@ -215,7 +215,7 @@ ValidateStorageImageResource(const ShaderRecompiler::IR::ImageResource& resource 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); void CreateRenderTargetViews(GraphicContext* ctx, RenderTextureVulkanImage* image); diff --git a/src/graphics/host_gpu/renderer/internal.h b/src/graphics/host_gpu/renderer/internal.h deleted file mode 100644 index 267c04221..000000000 --- a/src/graphics/host_gpu/renderer/internal.h +++ /dev/null @@ -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_ diff --git a/src/graphics/host_gpu/renderer/pipelineCache.cpp b/src/graphics/host_gpu/renderer/pipelineCache.cpp index a23df54e6..f5c4e5f6a 100644 --- a/src/graphics/host_gpu/renderer/pipelineCache.cpp +++ b/src/graphics/host_gpu/renderer/pipelineCache.cpp @@ -1,22 +1,16 @@ #include "graphics/host_gpu/renderer/pipelineCache.h" #include "common/assert.h" -#include "common/emulatorConfig.h" #include "common/logging/log.h" #include "common/profiler.h" -#include "common/stringUtils.h" -#include "graphics/guest_gpu/graphicsRun.h" #include "graphics/guest_gpu/hardwareContext.h" #include "graphics/host_gpu/renderer/colorRenderTarget.h" #include "graphics/host_gpu/renderer/debug.h" #include "graphics/host_gpu/renderer/depthRenderTarget.h" #include "graphics/host_gpu/renderer/framebufferCache.h" -#include "graphics/host_gpu/renderer/renderContext.h" -#include "graphics/host_gpu/utils.h" #include #include -#include #include #include @@ -44,26 +38,6 @@ bool PipelineStaticParameters::operator==(const PipelineStaticParameters& other) 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( VulkanFramebuffer* framebuffer, RenderColorInfo* colors, uint32_t color_count, 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)); EXIT_IF(!inserted); - DumpPipeline("create", *iter->second); return iter->second.get(); } @@ -231,69 +204,4 @@ PipelineCache::CreateComputePipeline(ShaderComputeInputInfo* input_info, 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 diff --git a/src/graphics/host_gpu/renderer/pipelineCache.h b/src/graphics/host_gpu/renderer/pipelineCache.h index 3b0dd26dc..5757aa457 100644 --- a/src/graphics/host_gpu/renderer/pipelineCache.h +++ b/src/graphics/host_gpu/renderer/pipelineCache.h @@ -4,7 +4,6 @@ #include "common/abi.h" #include "common/assert.h" #include "common/common.h" -#include "common/file.h" #include "common/threads.h" #include "graphics/host_gpu/renderer/renderTarget.h" #include "graphics/host_gpu/vulkanCommon.h" @@ -15,7 +14,6 @@ #include #include #include -#include namespace Libs::Graphics { @@ -86,7 +84,7 @@ static_assert(sizeof(PipelineStaticParameters) == class PipelineCache { public: PipelineCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~PipelineCache() { KYTY_NOT_IMPLEMENTED; } + ~PipelineCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(PipelineCache); struct Pipeline { @@ -112,8 +110,6 @@ public: ComputePipeline* CreateComputePipeline(ShaderComputeInputInfo* input_info, const HW::ComputeShaderInfo* cs_regs, std::span cs_spirv); - void DeletePipeline(Pipeline* pipeline); - void DeleteAllPipelines(); private: 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, GraphicsPipelineKeyHash> m_graphics_pipelines; diff --git a/src/graphics/host_gpu/renderer/render.h b/src/graphics/host_gpu/renderer/render.h index f40a2dedb..c3fc94198 100644 --- a/src/graphics/host_gpu/renderer/render.h +++ b/src/graphics/host_gpu/renderer/render.h @@ -69,7 +69,7 @@ private: class CommandBuffer { public: explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); } - virtual ~CommandBuffer() { Free(); } + ~CommandBuffer() { Free(); } KYTY_CLASS_NO_COPY(CommandBuffer); @@ -95,16 +95,21 @@ public: void RetainResourceUntilFence(std::shared_ptr resource); void RecycleDescriptorAfterFence(VulkanDescriptorSet* set); - [[nodiscard]] uint32_t GetIndex() const { return m_index; } - [[nodiscard]] int GetQueue() const { return m_queue; } - VulkanCommandPool* GetPool() { return m_pool; } - [[nodiscard]] bool IsExecute() const { return m_execute; } + [[nodiscard]] vk::CommandBuffer Handle() const; + [[nodiscard]] int GetQueue() const { return m_queue; } + [[nodiscard]] bool IsExecute() const { return m_execute; } [[nodiscard]] uint64_t GetRecordingGeneration() const { return m_recording_generation; } private: 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; uint32_t m_index = static_cast(-1); diff --git a/src/graphics/host_gpu/renderer/renderCompute.cpp b/src/graphics/host_gpu/renderer/renderCompute.cpp index 7c02ecf56..8d2bcc7ba 100644 --- a/src/graphics/host_gpu/renderer/renderCompute.cpp +++ b/src/graphics/host_gpu/renderer/renderCompute.cpp @@ -14,15 +14,15 @@ #include "graphics/host_gpu/objects/label.h" #include "graphics/host_gpu/renderer/depthRenderTarget.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/imageInfo.h" #include "graphics/host_gpu/renderer/pipelineCache.h" #include "graphics/host_gpu/renderer/render.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/shaderSubgroup.h" -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/shader/recompiler/ShaderIR.h" @@ -528,15 +528,15 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context for (;;) { 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( &input_info, &sh_ctx->GetCs(), cs_shader); vk_buffer.bindPipeline(vk::PipelineBindPoint::eCompute, pipeline->pipeline); - const auto address_writes = BindDescriptors( - submit_id, buffer, vk::PipelineBindPoint::eCompute, pipeline->pipeline_layout, - input_info.stage, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); + BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eCompute, + pipeline->pipeline_layout, input_info.stage, + vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); if (buffer->GetRecordingGeneration() != recording_generation) { 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); bool has_storage_writes = HasShaderBufferWrites(input_info.stage); - has_storage_writes = MarkShaderAddressWrites(address_writes) || has_storage_writes; has_storage_writes = std::any_of( program.info.images.begin(), program.info.images.end(), diff --git a/src/graphics/host_gpu/renderer/renderContext.cpp b/src/graphics/host_gpu/renderer/renderContext.cpp index 8e09dfa56..ef54c4ea5 100644 --- a/src/graphics/host_gpu/renderer/renderContext.cpp +++ b/src/graphics/host_gpu/renderer/renderContext.cpp @@ -19,8 +19,6 @@ void RenderContext::SetGraphicCtx(GraphicContext* ctx) { } GraphicContext* RenderContext::GetGraphicCtx() { - EXIT_IF(g_render_ctx == nullptr); - { Common::LockGuard lock(m_graphic_ctx_mutex); if (m_graphic_ctx != nullptr) { diff --git a/src/graphics/host_gpu/renderer/renderContext.h b/src/graphics/host_gpu/renderer/renderContext.h index 400b8026a..c2ee5f1fd 100644 --- a/src/graphics/host_gpu/renderer/renderContext.h +++ b/src/graphics/host_gpu/renderer/renderContext.h @@ -24,7 +24,7 @@ constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800; class RenderContext { public: RenderContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~RenderContext() { KYTY_NOT_IMPLEMENTED; } + ~RenderContext() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(RenderContext); void SetGraphicCtx(GraphicContext* ctx); diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index bf80c5ac0..62aaec9ea 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -22,11 +22,9 @@ #include "graphics/host_gpu/renderer/pipelineCache.h" #include "graphics/host_gpu/renderer/render.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/shaderSubgroup.h" -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/shader/recompiler/ShaderIR.h" @@ -47,6 +45,25 @@ 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(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(program.user_data_base)) { + const auto index = + static_cast(program.info.vertex_offset_sgpr) - program.user_data_base; + if (index < resources.user_data.size()) { + return static_cast(resources.user_data[index]); + } + } + + return 0; +} + static std::atomic g_draw_state_log_count = 0; static std::atomic g_draw_input_log_count = 0; static std::atomic 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 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(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(r.Type()), static_cast(r.Format()), - static_cast(r.Width5()) + 1u, static_cast(r.Height5()) + 1u, - static_cast(r.Depth()) + 1u, - std::max(static_cast(r.LastLevel()), - static_cast(r.MaxMip())) + - 1u, - static_cast(r.BaseLevel()), static_cast(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(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(r.ClampX()), - static_cast(r.ClampY()), static_cast(r.ClampZ()), - static_cast(r.XyMagFilter()), static_cast(r.XyMinFilter()), - static_cast(r.ZFilter()), static_cast(r.MipFilter()), - static_cast(r.MinLod()), static_cast(r.MaxLod()), - static_cast(r.LodBias()), r.fields[0], r.fields[1], r.fields[2], r.fields[3]); - } -} - static void VulkanCmdSetColorWriteEnableEXT(GraphicContext* ctx, vk::CommandBuffer command_buffer, uint32_t attachment_count, 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->render_pass == nullptr); - state->vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + state->vk_buffer = buffer->Handle(); return true; } @@ -851,8 +808,10 @@ static void LogDrawStateIfNeeded(HW::Context* ctx, HW::UserConfig* ucfg, const D return; } - LogDrawTargetState(draw.name, state.color_info[0], state.depth_info, ctx, ucfg, - state.ps_input_info, draw.index_count, draw.flags); + if (state.ps_active) { + 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, draw.index_count, index_addr); // 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) { SetDrawDebugPhase(buffer, submit_id, draw, 0x200u); } - const auto vs_address_writes = - BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, - pipeline->pipeline_layout, state->vs_input_info.stage, - vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex); + BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, + pipeline->pipeline_layout, state->vs_input_info.stage, + vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex); - std::vector ps_address_writes; if (state->ps_active) { LogDrawPhase(draw.name, "BindDescriptorsPS"); if (set_auto_debug) { SetDrawDebugPhase(buffer, submit_id, draw, 0x300u); } - ps_address_writes = - BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, - pipeline->pipeline_layout, state->ps_input_info.stage, - vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel); + BindDescriptors(submit_id, buffer, vk::PipelineBindPoint::eGraphics, + pipeline->pipeline_layout, state->ps_input_info.stage, + vk::ShaderStageFlagBits::eFragment, DescriptorCache::Stage::Pixel); } if (buffer->GetRecordingGeneration() != recording_generation) { continue; @@ -1008,15 +964,11 @@ static void ExecutePreparedDraw(uint64_t submit_id, CommandBuffer* buffer, HW::C } buffer->EndRenderPass(); vk::PipelineStageFlags shader_write_stages = {}; - const bool vs_wrote_buffers = HasShaderBufferWrites(state->vs_input_info.stage); - const bool vs_wrote_addresses = MarkShaderAddressWrites(vs_address_writes); - if (vs_wrote_buffers || vs_wrote_addresses) { + if (HasShaderBufferWrites(state->vs_input_info.stage)) { shader_write_stages |= vk::PipelineStageFlagBits::eVertexShader; } if (state->ps_active) { - const bool ps_wrote_buffers = HasShaderBufferWrites(state->ps_input_info.stage); - const bool ps_wrote_addresses = MarkShaderAddressWrites(ps_address_writes); - if (ps_wrote_buffers || ps_wrote_addresses) { + if (HasShaderBufferWrites(state->ps_input_info.stage)) { 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)}; 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; } diff --git a/src/graphics/host_gpu/renderer/renderDraw.h b/src/graphics/host_gpu/renderer/renderDraw.h index 383d4ddf0..6ff662cf5 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.h +++ b/src/graphics/host_gpu/renderer/renderDraw.h @@ -10,6 +10,7 @@ namespace Libs::Graphics { struct ImageImageCopy; struct RenderColorInfo; +struct ShaderVertexInputInfo; #pragma pack(push, 1) @@ -43,6 +44,8 @@ static_assert(sizeof(PipelineDynamicParameters) == [[nodiscard]] ImageImageCopy MakeColorResolveCopy(const RenderColorInfo& src, const RenderColorInfo& dst, uint32_t width, uint32_t height); +[[nodiscard]] int32_t ResolveVertexOffset(uint32_t index_offset, + const ShaderVertexInputInfo& vs_input_info); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderInternal.h b/src/graphics/host_gpu/renderer/renderInternal.h deleted file mode 100644 index 14eb6f238..000000000 --- a/src/graphics/host_gpu/renderer/renderInternal.h +++ /dev/null @@ -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 - -namespace Libs::Graphics { - -template -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_ diff --git a/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp b/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp index 95a7c05b0..3ceb86b09 100644 --- a/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp +++ b/src/graphics/host_gpu/renderer/renderTargetBarriers.cpp @@ -11,11 +11,11 @@ #include "graphics/guest_gpu/tile.h" #include "graphics/host_gpu/graphicContext.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/imageView.h" #include "graphics/host_gpu/renderer/render.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/presentation/displayBuffer.h" @@ -34,7 +34,7 @@ void GraphicsRenderMemoryBarrier(CommandBuffer* buffer) { Common::LockGuard lock(g_render_ctx->GetMutex()); - auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; + auto vk_buffer = buffer->Handle(); VulkanMemoryBarrier mem_barrier {}; 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, vk::ImageLayout new_layout) { EXIT_IF(image == nullptr); @@ -144,9 +142,9 @@ void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanI barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image->image; - barrier.subresourceRange = {DepthStencilAspectMask(image->format), 0, VK_REMAINING_MIP_LEVELS, - 0, image->layers}; - const auto stages = static_cast( + barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image->format), 0, + VK_REMAINING_MIP_LEVELS, 0, image->layers}; + const auto stages = static_cast( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer); 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.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = image->image; - image_memory_barrier.subresourceRange.aspectMask = DepthStencilAspectMask(image->format); - image_memory_barrier.subresourceRange.baseMipLevel = 0; - image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + image_memory_barrier.subresourceRange.aspectMask = + ImageViewOps::DepthAspectMask(image->format); + 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.layerCount = image->layers; @@ -205,7 +204,7 @@ void GraphicsRenderTextureBarrier(CommandBuffer* buffer, uint64_t vaddr, uint64_ 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); if (native == nullptr) { @@ -220,7 +219,7 @@ void GraphicsRenderDepthStencilBarrier(CommandBuffer* buffer, uint64_t vaddr, ui 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); if (native == nullptr) { EXIT("depth-target barrier range has no cached image\n"); diff --git a/src/graphics/host_gpu/renderer/renderVertex.cpp b/src/graphics/host_gpu/renderer/renderVertex.cpp deleted file mode 100644 index 8cac5a225..000000000 --- a/src/graphics/host_gpu/renderer/renderVertex.cpp +++ /dev/null @@ -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(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(program.user_data_base)) { - const auto index = - static_cast(program.info.vertex_offset_sgpr) - program.user_data_base; - if (index < resources.user_data.size()) { - return static_cast(resources.user_data[index]); - } - } - - return 0; -} - -} // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderVertex.h b/src/graphics/host_gpu/renderer/renderVertex.h deleted file mode 100644 index 2cdcc1e13..000000000 --- a/src/graphics/host_gpu/renderer/renderVertex.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_ -#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERVERTEX_H_ - -#include - -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_ diff --git a/src/graphics/host_gpu/renderer/samplerCache.cpp b/src/graphics/host_gpu/renderer/samplerCache.cpp index b93bbcb8f..f1eb50cb9 100644 --- a/src/graphics/host_gpu/renderer/samplerCache.cpp +++ b/src/graphics/host_gpu/renderer/samplerCache.cpp @@ -143,8 +143,9 @@ vk::Sampler SamplerCache::GetSampler(const ShaderSamplerResource& r) { } vk::Sampler vk_sampler = nullptr; - g_render_ctx->GetGraphicCtx()->device.createSampler(&sampler_info, nullptr, &vk_sampler); - EXIT_NOT_IMPLEMENTED(vk_sampler == nullptr); + const auto result = + 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); return vk_sampler; diff --git a/src/graphics/host_gpu/renderer/samplerCache.h b/src/graphics/host_gpu/renderer/samplerCache.h index b4a8dc965..a06b6793e 100644 --- a/src/graphics/host_gpu/renderer/samplerCache.h +++ b/src/graphics/host_gpu/renderer/samplerCache.h @@ -17,7 +17,7 @@ namespace Libs::Graphics { class SamplerCache { public: SamplerCache() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~SamplerCache() { KYTY_NOT_IMPLEMENTED; } + ~SamplerCache() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(SamplerCache); vk::Sampler GetSampler(const ShaderSamplerResource& r); diff --git a/src/graphics/host_gpu/renderer/shaderResourceBarrier.cpp b/src/graphics/host_gpu/renderer/shaderResourceBarrier.cpp index 74fc49447..1e824cf74 100644 --- a/src/graphics/host_gpu/renderer/shaderResourceBarrier.cpp +++ b/src/graphics/host_gpu/renderer/shaderResourceBarrier.cpp @@ -1,7 +1,6 @@ #include "graphics/host_gpu/renderer/shaderResourceBarrier.h" #include "common/assert.h" -#include "graphics/host_gpu/renderer/descriptorCache.h" #include "graphics/shader/shader.h" #include "graphics/shader/shaderBindings.h" @@ -108,13 +107,6 @@ CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program, return writes; } -bool MarkShaderAddressWrites(const std::vector& writes) { - if (!writes.empty()) { - EXIT("shader address writes are unsupported\n"); - } - return false; -} - bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) { EXIT_IF(!runtime); return !CollectShaderBufferWrites(*runtime.program, *runtime.resources).empty(); diff --git a/src/graphics/host_gpu/renderer/shaderResourceBarrier.h b/src/graphics/host_gpu/renderer/shaderResourceBarrier.h index 7e6bf0426..6c57cc6cb 100644 --- a/src/graphics/host_gpu/renderer/shaderResourceBarrier.h +++ b/src/graphics/host_gpu/renderer/shaderResourceBarrier.h @@ -8,7 +8,6 @@ namespace Libs::Graphics { -struct ShaderAddressWriteRange; struct ShaderStageRuntime; struct ShaderBufferWriteRange { @@ -26,7 +25,6 @@ vk::BufferMemoryBarrier MakeGdsDependency(const VulkanBuffer& buffer); std::vector CollectShaderBufferWrites(const ShaderRecompiler::IR::Program& program, const ShaderRecompiler::IR::ResourceSnapshot& resources); -bool MarkShaderAddressWrites(const std::vector& writes); bool HasShaderBufferWrites(const ShaderStageRuntime& runtime); void ShaderWriteBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages); diff --git a/src/graphics/host_gpu/renderer/streamBuffer.cpp b/src/graphics/host_gpu/renderer/streamBuffer.cpp index 39dadea95..c67d7076d 100644 --- a/src/graphics/host_gpu/renderer/streamBuffer.cpp +++ b/src/graphics/host_gpu/renderer/streamBuffer.cpp @@ -4,7 +4,7 @@ #include "common/logging/log.h" #include "common/profiler.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 diff --git a/src/graphics/host_gpu/renderer/sync.cpp b/src/graphics/host_gpu/renderer/sync.cpp index 7ec31f63c..9bf8d5990 100644 --- a/src/graphics/host_gpu/renderer/sync.cpp +++ b/src/graphics/host_gpu/renderer/sync.cpp @@ -14,7 +14,9 @@ #include "kernel/pthread.h" #include "libs/errno.h" +#include #include +#include namespace Libs::Graphics::Sync { @@ -71,6 +73,104 @@ static bool CompleteDisplayBufferFlip(const uint64_t* args) { 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 debug_args = {}; + uint64_t debug_data = 0; + std::optional 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(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(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(size); + const auto value_low = static_cast(value); + const auto value_high = static_cast(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() { auto tsc = LibKernel::KernelReadTsc(); 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, uint32_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWrite), submit_id, 4, value, - 0, 0, reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Write); } void WriteAtEndOfPipeGds32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t dw_offset, uint32_t dw_num) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWrite), submit_id, - dw_offset, dw_num, 0, 0, reinterpret_cast(dst_gpu_addr)); + const auto destination = reinterpret_cast(dst_gpu_addr); + RecordEndOfPipeSignal({ + .buffer = buffer, + .submit_id = submit_id, + .debug_operation = CommandBufferDebugOp::EopWrite, + .debug_args = {dw_offset, dw_num, 0, 0}, + .debug_data = destination, + .destination = destination, + }); } void WriteAtEndOfPipe64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWrite), submit_id, 8, - static_cast(value), static_cast(value >> 32u), 0, - reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); } void WriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWrite), submit_id, 8, 0, 0, - 0, reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), 0, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Write); LOGF_COLOR(Log::Color::BrightGreen, "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, uint64_t* dst_gpu_addr, uint64_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBack), submit_id, 8, 0, - 0, 0, reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), 0, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); LOGF_COLOR(Log::Color::BrightGreen, "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, uint64_t* dst_gpu_addr, uint64_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBack), submit_id, 8, - static_cast(value), static_cast(value >> 32u), 0, - reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::WriteBack); } void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBack), submit_id, 4, - value, 0, 0, reinterpret_cast(dst_gpu_addr)); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::WriteBack); } void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBack), submit_id, 8, - context_id, static_cast(value), - static_cast(value >> 32u), - reinterpret_cast(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(args[0])); - return true; - }, - args); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::InterruptWriteBack, + context_id); } void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBack), submit_id, 4, - context_id, value, 0, reinterpret_cast(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(args[0])); - return true; - }, - args); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::InterruptWriteBack, + context_id); } void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer* buffer, uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopInterrupt), submit_id, 8, - context_id, static_cast(value), - static_cast(value >> 32u), - reinterpret_cast(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(args[0])); - return true; - }, - args); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id); } void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopInterrupt), submit_id, 4, - context_id, value, 0, reinterpret_cast(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(args[0])); - return true; - }, - args); + RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, + EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id); } 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, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopWriteBackFlip), submit_id, - static_cast(handle), static_cast(index), - static_cast(flip_mode), value, static_cast(flip_arg)); - const uint64_t args[LABEL_ARGS_MAX] = {request_id}; - SubmitLabel( - buffer, CompleteDisplayBufferFlip, - [](const uint64_t* /*args*/) { - EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->TriggerEopEvent(0); - return true; - }, - args); + const auto destination = reinterpret_cast(dst_gpu_addr); + RecordEndOfPipeSignal({ + .buffer = buffer, + .submit_id = submit_id, + .debug_operation = CommandBufferDebugOp::EopWriteBackFlip, + .debug_args = {static_cast(handle), static_cast(index), + static_cast(flip_mode), value}, + .debug_data = static_cast(flip_arg), + .destination = destination, + .completion = EndOfPipeCompletion::FlipAndInterrupt, + .completion_data = request_id, + }); } void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer* buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(dst_gpu_addr == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopFlip), submit_id, - static_cast(handle), static_cast(index), - static_cast(flip_mode), value, static_cast(flip_arg)); - const uint64_t args[LABEL_ARGS_MAX] = {request_id}; - SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args); + const auto destination = reinterpret_cast(dst_gpu_addr); + RecordEndOfPipeSignal({ + .buffer = buffer, + .submit_id = submit_id, + .debug_operation = CommandBufferDebugOp::EopFlip, + .debug_args = {static_cast(handle), static_cast(index), + static_cast(flip_mode), value}, + .debug_data = static_cast(flip_arg), + .destination = destination, + .completion = EndOfPipeCompletion::Flip, + .completion_data = request_id, + }); } void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer* buffer, int handle, int index, int flip_mode, int64_t flip_arg, uint64_t request_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); - - buffer->SetDebugInfo(static_cast(CommandBufferDebugOp::EopOnlyFlip), submit_id, - static_cast(handle), static_cast(index), - static_cast(flip_mode), 0, static_cast(flip_arg)); - - const uint64_t args[LABEL_ARGS_MAX] = {request_id}; - SubmitLabel(buffer, CompleteDisplayBufferFlip, nullptr, args); + RecordEndOfPipeSignal({ + .buffer = buffer, + .submit_id = submit_id, + .debug_operation = CommandBufferDebugOp::EopOnlyFlip, + .debug_args = {static_cast(handle), static_cast(index), + static_cast(flip_mode), 0}, + .debug_data = static_cast(flip_arg), + .completion = EndOfPipeCompletion::Flip, + .completion_data = request_id, + }); } void TriggerEopEventAtEndOfPipe(CommandBuffer* buffer, uint32_t context_id) { - EXIT_IF(g_render_ctx == nullptr); - EXIT_IF(buffer == nullptr); - EXIT_IF(buffer->IsInvalid()); + ValidateEndOfPipeSignal({.buffer = buffer}); uint64_t args[LABEL_ARGS_MAX] = {static_cast(context_id)}; - - SubmitLabel( - buffer, nullptr, - [](const uint64_t* args) { - EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->TriggerEopEvent(static_cast(args[0])); - return true; - }, - args); + SubmitLabel(buffer, nullptr, TriggerEopEventCallback, args); } 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); - 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); } @@ -422,7 +418,7 @@ void ReadGds(uint32_t* dst, uint32_t dw_offset, uint32_t dw_size) { void DeleteBuffers() { EXIT_IF(g_render_ctx == nullptr); - g_render_ctx->GetBufferCache()->DeleteAll(g_render_ctx->GetGraphicCtx()); + g_render_ctx->GetBufferCache()->ResetNullBuffer(); } } // namespace Libs::Graphics::Sync diff --git a/src/graphics/host_gpu/renderer/textureCache.cpp b/src/graphics/host_gpu/renderer/textureCache.cpp index 20e5b1a02..4248b5607 100644 --- a/src/graphics/host_gpu/renderer/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/textureCache.cpp @@ -18,7 +18,8 @@ #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderTargetBarriers.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 @@ -104,9 +105,8 @@ struct TextureCache::CachedImage { RenderTargetInfo target; DepthTargetInfo depth; VideoOutInfo video_out; - GraphicContext* ctx = nullptr; - VulkanImage* image = nullptr; - VulkanMemory memory; + GraphicContext* ctx = nullptr; + VulkanImage* image = nullptr; bool gpu_modified = false; bool buffer_modified = false; bool stencil_initialized = false; @@ -119,21 +119,7 @@ struct TextureCache::CachedImage { static_cast(ctx), static_cast(image), static_cast(kind), registered); } - switch (kind) { - case Kind::Texture: - case Kind::StorageTexture: - ImageOps::Destroy(ctx, static_cast(image), &memory); - break; - case Kind::RenderTarget: - ImageOps::Destroy(ctx, static_cast(image), &memory); - break; - case Kind::DepthTarget: - ImageOps::Destroy(ctx, static_cast(image), &memory); - break; - case Kind::VideoOut: - ImageOps::Destroy(ctx, static_cast(image), &memory); - break; - } + ImageOps::Destroy(ctx, image); image = nullptr; } @@ -465,10 +451,10 @@ struct TextureCache::ReadbackWorker { download.resize(info.size); std::fill(download.begin(), download.end(), 0); const auto regions = - MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width, - info.height, vk::ImageAspectFlagBits::eDepth); - UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image, - cached.image->layout); + Transfer::MakeLayeredImageBufferCopies(info.layers, slice_size, info.pitch, info.width, + info.height, vk::ImageAspectFlagBits::eDepth); + Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image, + cached.image->layout); guest.resize(info.size); cache.m_tiler.TileImage(guest.data(), download.data(), info); Libs::LibKernel::Memory::WriteBacking(info.address, guest.data(), info.size); @@ -478,11 +464,11 @@ struct TextureCache::ReadbackWorker { [[nodiscard]] ReadbackRange DownloadColorImage(CachedImage& cached) { const bool storage = cached.kind == CachedImage::Kind::StorageTexture; const bool target = cached.kind == CachedImage::Kind::RenderTarget; - const auto info = storage ? MakeColorImageTransferInfo( - cached.info, Prospero::SurfaceFormat(cached.info.format), - Prospero::NumBytesPerElement(cached.info.format)) - : MakeColorImageTransferInfo(cached.target); - const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear); + const auto info = + storage ? MakeColorImageTransferInfo(cached.info, VulkanFormat(cached.info.format), + Prospero::NumBytesPerElement(cached.info.format)) + : MakeColorImageTransferInfo(cached.target); + const bool linear = info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear); const bool tiled_target = target && IsTiledRenderTarget(cached.target); const bool tiled_storage = storage && info.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget); @@ -520,10 +506,10 @@ struct TextureCache::ReadbackWorker { } download.resize(info.size); std::fill(download.begin(), download.end(), 0); - const auto regions = - MakeLayeredImageBufferCopies(layers, slice_size, info.pitch, info.width, info.height); - UtilFillBuffer(cached.ctx, download.data(), info.size, regions, cached.image, - cached.image->layout); + const auto regions = Transfer::MakeLayeredImageBufferCopies(layers, slice_size, info.pitch, + info.width, info.height); + Transfer::DownloadImage(cached.ctx, download.data(), info.size, regions, cached.image, + cached.image->layout); if (tiled_target || tiled_storage) { guest.resize(info.size); const RenderTargetInfo layout = @@ -959,7 +945,7 @@ void TextureCache::RetireSampledTargetAliases(GraphicContext* ctx, const ImageIn } RequireRetirementIsolation(retire, "sampled target", requested.address, requested.size); if (wait_idle) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } for (auto* cached: retire) { if (!cached->gpu_modified) { @@ -1080,7 +1066,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag if (selected == nullptr) { return; } - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); const auto transfer = m_readback->DownloadDepthTarget(*selected, false); m_memory_tracker.ForEachDownloadRange(transfer.address, transfer.size, [](uint64_t, uint64_t) noexcept {}); @@ -1091,7 +1077,7 @@ void TextureCache::RetireStorageDepthAliasLocked(GraphicContext* ctx, const Imag TextureCache::~TextureCache() { m_readback.reset(); if (!m_images.empty()) { - VulkanDeviceWaitIdle(m_images.front()->ctx); + Transfer::WaitForGraphicsIdle(m_images.front()->ctx); } for (const auto& image: m_images) { UnregisterImageLocked(*image, false); @@ -1136,7 +1122,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c info.address, info.size, metadata_read); } std::shared_ptr 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) { if (cached->kind != CachedImage::Kind::StorageTexture) { continue; @@ -1266,7 +1252,7 @@ VulkanImage* TextureCache::FindTexture(CommandBuffer* command, GraphicContext* c cached->info = info; cached->ctx = ctx; 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( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { @@ -1402,7 +1388,7 @@ StorageTextureVulkanImage* TextureCache::FindStorageTexture(CommandBuffer* com cached->info = info; cached->ctx = ctx; 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( info.address, info.size, true, [](uint64_t, uint64_t) noexcept {}, [&]() noexcept { @@ -1610,7 +1596,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* cached->kind = CachedImage::Kind::RenderTarget; cached->target = info; 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; if (preserve_native) { command->RetainResourceUntilFence(native_image_source); @@ -1636,7 +1622,7 @@ RenderTextureVulkanImage* TextureCache::FindRenderTarget(CommandBuffer* regions.reserve(static_cast(native_image_source->image->layers) * native_image_source->image->mip_levels); 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 { m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, @@ -1885,7 +1871,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G cached->depth = info; cached->ctx = ctx; cached->stencil_initialized = !has_stencil; - cached->image = ImageOps::CreateDepthTarget(ctx, info, &cached->memory); + cached->image = ImageOps::CreateDepthTarget(ctx, info); if (discarded_depth_source != nullptr) { command->RetainResourceUntilFence(discarded_depth_source); } @@ -1939,13 +1925,13 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G AppendLayerCopies(regions, native_depth_source->image, vk::ImageAspectFlagBits::eStencil); } - UtilImageToImage(command, regions, cached->image, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + Transfer::CopyImage(command, regions, cached->image, + vk::ImageLayout::eDepthStencilAttachmentOptimal); cached->gpu_modified = true; } else { if (sampled_depth_source != nullptr && (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.height != info.height)) { EXIT("TextureCache: sampled-depth native source is inconsistent\n"); @@ -1967,11 +1953,11 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G break; case DepthTransitionSource::Native: command->RetainResourceUntilFence(sampled_depth_source); - UtilCopyImageWithBuffer(command, ctx, sampled_depth_source->image, - vk::ImageAspectFlagBits::eColor, cached->image, - vk::ImageAspectFlagBits::eDepth, - info.bytes_per_element, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + Transfer::CopyImageViaBuffer( + command, ctx, sampled_depth_source->image, + vk::ImageAspectFlagBits::eColor, cached->image, + vk::ImageAspectFlagBits::eDepth, info.bytes_per_element, + vk::ImageLayout::eDepthStencilAttachmentOptimal); break; } }); @@ -2036,7 +2022,7 @@ TextureCache::RegisterVideoOutSurfaces(GraphicContext* ctx, cached->kind = CachedImage::Kind::VideoOut; cached->video_out = info; cached->ctx = ctx; - cached->image = ImageOps::CreateVideoOut(ctx, info, &cached->memory); + cached->image = ImageOps::CreateVideoOut(ctx, info); if (info.compression == VideoOutCompression::Uncompressed) { m_memory_tracker.ForEachUploadRange( info.address, info.size, false, [](uint64_t, uint64_t) noexcept {}, @@ -2147,7 +2133,7 @@ void TextureCache::UnregisterVideoOutSurfaces(const std::vectorAddress(), cached->Size()); } } - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); for (auto* cached: selected) { if (cached->gpu_modified) { m_memory_tracker.UnmarkRegionAsGpuModified(cached->Address(), cached->Size()); @@ -2269,7 +2255,7 @@ bool TextureCache::ClearImageFromBuffer(CommandBuffer* command, uint64_t vaddr, image_cpu_modified); } - auto vk_buffer = command->GetPool()->buffers[command->GetIndex()]; + auto vk_buffer = command->Handle(); if (aspect == ClearAspect::Color) { vk::ClearColorValue clear {}; if (!DecodePackedColorClear(match->image->format, packed_clear, &clear)) { @@ -2438,7 +2424,7 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint const auto& info = cached.info; target.address = info.address; target.size = info.size; - target.format = Prospero::SurfaceFormat(info.format); + target.format = VulkanFormat(info.format); target.width = info.width; target.height = info.height; 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. // The vectors and Vulkan staging allocation retain capacity; a future PS5 GPU tiler can replace // this block without changing alias classification or ownership transitions. - VulkanDeviceWaitIdle(cached.ctx); + Transfer::WaitForGraphicsIdle(cached.ctx); m_buffer_transition_linear.resize(target.size); std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0); std::vector regions; @@ -2533,11 +2519,11 @@ void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached, uint upload.dst_y, upload.dst_z, upload.aspect}); } } else { - regions = MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch, - target.width, target.height); + regions = Transfer::MakeLayeredImageBufferCopies(target.layers, slice_size, target.pitch, + target.width, target.height); } - UtilFillBuffer(cached.ctx, m_buffer_transition_linear.data(), target.size, regions, - cached.image, cached.image->layout); + Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), target.size, regions, + cached.image, cached.image->layout); if (storage) { m_buffer_transition_guest.resize(target.size); 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(info.format), info.guest_format, info.bytes_per_element, has_stencil, has_htile, cached.gpu_modified, cached.buffer_modified); } - VulkanDeviceWaitIdle(cached.ctx); + Transfer::WaitForGraphicsIdle(cached.ctx); m_buffer_transition_linear.resize(info.size); std::fill(m_buffer_transition_linear.begin(), m_buffer_transition_linear.end(), 0); - const auto regions = MakeLayeredImageBufferCopies(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, - cached.image->layout); + const auto regions = Transfer::MakeLayeredImageBufferCopies( + 1, info.size, info.pitch, info.width, info.height, vk::ImageAspectFlagBits::eDepth); + Transfer::DownloadImage(cached.ctx, m_buffer_transition_linear.data(), info.size, regions, + cached.image, cached.image->layout); m_buffer_transition_guest.resize(info.size); 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(), @@ -3169,7 +3155,7 @@ void TextureCache::UnmapMemory(uint64_t vaddr, uint64_t size) { } } if (wait_ctx != nullptr) { - VulkanDeviceWaitIdle(wait_ctx); + Transfer::WaitForGraphicsIdle(wait_ctx); } for (auto& cached: m_images) { if (!cached->OverlapsRange(vaddr, size, false) || !cached->gpu_modified) { diff --git a/src/graphics/host_gpu/renderer/tiler.cpp b/src/graphics/host_gpu/renderer/tiler.cpp index 7afa38efd..6cc23ef1e 100644 --- a/src/graphics/host_gpu/renderer/tiler.cpp +++ b/src/graphics/host_gpu/renderer/tiler.cpp @@ -7,7 +7,8 @@ #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/objects/textureCommon.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 @@ -26,7 +27,7 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* " host_slice=0x%016" PRIx64 " layers=%u\n", slice_size, host_slice_size, info.layers); } - UtilScratchBuffer host_linear(host_upload_size); + Transfer::ScratchBuffer host_linear(host_upload_size); std::vector guest_linear(slice_size / sizeof(uint16_t)); std::vector regions; regions.reserve(info.layers); @@ -48,14 +49,14 @@ static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* region.aspect = vk::ImageAspectFlagBits::eDepth; regions.push_back(region); } - UtilFillImage(ctx, image, host_linear.Data(), host_upload_size, regions, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + Transfer::UploadImage(ctx, image, host_linear.Data(), host_upload_size, regions, + vk::ImageLayout::eDepthStencilAttachmentOptimal); } void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info, const BufferImageCopySource& source, bool refresh, bool storage) const { if (refresh) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } const bool array_texture = TextureIsLayeredTexture(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, bool refresh, uint32_t base_layer) const { if (refresh) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) { switch (info.format) { @@ -93,7 +94,7 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image, } } const auto slice_size = info.size / info.layers; - UtilScratchBuffer linear(info.size); + Transfer::ScratchBuffer linear(info.size); std::vector regions; regions.reserve(info.layers); 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; regions.push_back(region); } - UtilFillImage(ctx, image, linear.Data(), info.size, regions, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + Transfer::UploadImage(ctx, image, linear.Data(), info.size, regions, + vk::ImageLayout::eDepthStencilAttachmentOptimal); } void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, @@ -121,10 +122,10 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image, const auto stencil_pitch = TileGetTexturePitch( stencil_format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth)); if (refresh) { - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); } const auto slice_size = info.stencil_size / info.layers; - UtilScratchBuffer linear(info.stencil_size); + Transfer::ScratchBuffer linear(info.stencil_size); std::vector regions; regions.reserve(info.layers); 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; regions.push_back(region); } - UtilFillImage(ctx, image, linear.Data(), info.stencil_size, regions, - vk::ImageLayout::eDepthStencilAttachmentOptimal); + Transfer::UploadImage(ctx, image, linear.Data(), info.stencil_size, regions, + vk::ImageLayout::eDepthStencilAttachmentOptimal); } 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, info.depth, info.pitch, info.tile, info.size, true, false, false, "StorageTextureReadback"); - auto regions = TextureBuildUploadRegions(layout, Prospero::SurfaceFormat(info.format), - info.width, info.height, info.depth, info.levels, - false, false, TextureUploadDestination::MipLevels, - TextureUploadSliceLayout::MipChainPerSlice); + auto regions = TextureBuildUploadRegions( + layout, VulkanFormat(info.format), info.width, info.height, info.depth, info.levels, false, + false, TextureUploadDestination::MipLevels, TextureUploadSliceLayout::MipChainPerSlice); std::memset(dst, 0, info.size); for (uint32_t level = 0; level < info.levels; level++) { const auto& level_size = layout.level_sizes[level]; diff --git a/src/graphics/host_gpu/utils.cpp b/src/graphics/host_gpu/transfer.cpp similarity index 77% rename from src/graphics/host_gpu/utils.cpp rename to src/graphics/host_gpu/transfer.cpp index 7cc91c950..0e39b050f 100644 --- a/src/graphics/host_gpu/utils.cpp +++ b/src/graphics/host_gpu/transfer.cpp @@ -1,10 +1,11 @@ -#include "graphics/host_gpu/utils.h" +#include "graphics/host_gpu/transfer.h" #include "common/assert.h" #include "common/logging/log.h" #include "common/profiler.h" #include "common/threads.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/renderContext.h" #include "graphics/host_gpu/vma.h" @@ -16,7 +17,7 @@ #include #include -namespace Libs::Graphics { +namespace Libs::Graphics::Transfer { static Common::Mutex g_scratch_buffer_mutex; static std::unique_ptr g_scratch_buffer; @@ -43,7 +44,7 @@ std::vector MakeLayeredImageBufferCopies(uint32_t layers, uint6 return regions; } -UtilScratchBuffer::UtilScratchBuffer(uint64_t size) { +ScratchBuffer::ScratchBuffer(uint64_t size) { EXIT_IF(size == 0); g_scratch_buffer_mutex.Lock(); @@ -56,11 +57,11 @@ UtilScratchBuffer::UtilScratchBuffer(uint64_t size) { m_data = g_scratch_buffer.get(); } -UtilScratchBuffer::~UtilScratchBuffer() { +ScratchBuffer::~ScratchBuffer() { 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 == 0) { return false; @@ -80,7 +81,7 @@ bool UtilBufferIsTiled(uint64_t vaddr, uint64_t size) { return true; } -void VulkanDeviceWaitIdle(GraphicContext* ctx) { +void WaitForGraphicsIdle(GraphicContext* ctx) { Common::Mutex* locked[GraphicContext::QUEUES_NUM] {}; int locked_num = 0; @@ -117,64 +118,17 @@ void VulkanDeviceWaitIdle(GraphicContext* ctx) { 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(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(result), static_cast(image->format), - static_cast(create_info.format), view_index); - } -} - static void SetImageLayout(vk::CommandBuffer buffer, VulkanImage* dst_image, uint32_t base_level, uint32_t levels, vk::ImageAspectFlags aspect_mask, vk::ImageLayout old_image_layout, vk::ImageLayout new_image_layout); template -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 // not touch every caller. CommandBuffer command(GraphicContext::QUEUE_UTIL); command.Begin(); - recorder(&command, command.GetPool()->buffers[command.GetIndex()]); + recorder(&command, command.Handle()); command.End(); command.Execute(); command.WaitForFence(); @@ -220,18 +174,6 @@ static void SetBufferMemoryBarrier(vk::CommandBuffer command, vk::Buffer buffer, 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(format)); - } -} - [[nodiscard]] static vk::ImageAspectFlags GetTransferAspects(const VulkanImage& image, vk::ImageAspectFlags copy_aspect) { 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 || copy_aspect == vk::ImageAspectFlagBits::eStencil) { - const auto aspects = GetDepthStencilAspects(image.format); + const auto aspects = ImageViewOps::DepthAspectMask(image.format); if (!(copy_aspect & aspects)) { EXIT("image transfer aspect is unavailable: format=%d copy=0x%x available=0x%x\n", static_cast(image.format), @@ -257,7 +199,7 @@ static void RecordBufferToImageCopy(CommandBuffer& command, VulkanBuffer& src_bu std::span regions, vk::ImageAspectFlags transition_aspects, 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, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, @@ -301,7 +243,7 @@ ConvertImageBufferCopies(std::span regions) { static void RecordImageToBuffer(CommandBuffer& command, VulkanImage& src_image, VulkanBuffer& dst_buffer, std::span regions, vk::ImageLayout final_layout) { - auto vk_command = command.GetPool()->buffers[command.GetIndex()]; + auto vk_command = command.Handle(); vk::ImageAspectFlags aspects = {}; for (const auto& region: regions) { aspects |= GetTransferAspects(src_image, region.aspect); @@ -399,7 +341,7 @@ public: 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); }); @@ -411,7 +353,7 @@ public: vk::ImageLayout src_layout) { Common::LockGuard lock(m_mutex); 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); }); std::memcpy(dst_data, m_mapped_data, size); @@ -435,9 +377,9 @@ private: Common::LockGuard lock(m_mutex); CopyFromHost(ctx, src_data, size, vk::BufferUsageFlagBits::eTransferSrc); if constexpr (WaitIdle) { - VulkanDeviceWaitIdle(ctx); + WaitForGraphicsIdle(ctx); } - ExecuteImmediateUtilCommands(recorder); + ExecuteImmediateCommands(recorder); } 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_readback_staging_buffer; -static Common::Mutex g_compressed_image_copy_mutex; -static VulkanBuffer g_compressed_image_copy_buffer; - -bool UtilIsBcFormat(vk::Format format) { +bool IsBlockCompressedFormat(vk::Format format) { return format == vk::Format::eBc1RgbUnormBlock || format == vk::Format::eBc1RgbSrgbBlock || format == vk::Format::eBc1RgbaUnormBlock || format == vk::Format::eBc1RgbaSrgbBlock || 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; } -uint32_t UtilGetBcBlockSize(vk::Format format) { +uint32_t BlockCompressedBytesPerBlock(vk::Format format) { switch (format) { case vk::Format::eBc1RgbUnormBlock: 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) { switch (type) { case StagingBufferType::Texture: return &g_texture_staging_buffer; @@ -551,6 +472,13 @@ static ReusableStagingBuffer* GetStagingBuffer(StagingBufferType type) { 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, uint32_t levels, vk::ImageAspectFlags aspect_mask, 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; } -static bool CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r, - VulkanImage* dst_image) { +static uint64_t CompressedImageCopyBufferSize(const ImageImageCopy& r, + const VulkanImage& dst_image) { if (r.src_aspect != vk::ImageAspectFlagBits::eColor || - r.dst_aspect != vk::ImageAspectFlagBits::eColor || !UtilIsBcFormat(dst_image->format)) { - return false; + r.dst_aspect != vk::ImageAspectFlagBits::eColor || + !IsBlockCompressedFormat(dst_image.format)) { + return 0; } 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) { - return false; + return 0; } auto block_width = (r.width + 3u) / 4u; auto block_height = (r.height + 3u) / 4u; if (block_width > r.src_image->extent.width || block_height > r.src_image->extent.height) { - return false; + return 0; } + return static_cast(block_width) * block_height * dst_block_size; +} - auto* ctx = WindowGetGraphicContext(); - auto* copy_buffer = GetCompressedImageCopyBuffer(ctx, static_cast(block_width) * - block_height * dst_block_size); +static void CopyBlockImageToCompressedImage(vk::CommandBuffer vk_buffer, const ImageImageCopy& r, + VulkanImage* dst_image, VulkanBuffer* copy_buffer) { + 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 = 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, vk::ImageLayout::eTransferSrcOptimal, src_layout); - - return true; } -void UtilImageToImage(CommandBuffer* buffer, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout) { - auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; +void CopyImage(CommandBuffer* buffer, std::span regions, + VulkanImage* dst_image, vk::ImageLayout dst_layout) { + auto vk_buffer = buffer->Handle(); bool same_image_copy = false; vk::ImageAspectFlags dst_transition_aspects = {}; @@ -777,15 +710,28 @@ void UtilImageToImage(CommandBuffer* buffer, std::span reg SetImageLayout(vk_buffer, dst_image, 0, VK_REMAINING_MIP_LEVELS, dst_transition_aspects, 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) { vk::ImageCopy region; auto src_layout = r.src_image->layout; - if (r.src_aspect == vk::ImageAspectFlagBits::eColor && - r.dst_aspect == vk::ImageAspectFlagBits::eColor && - CopyBlockImageToCompressedImage(vk_buffer, r, dst_image)) { + if (CompressedImageCopyBufferSize(r, *dst_image) != 0) { + CopyBlockImageToCompressedImage(vk_buffer, r, dst_image, compressed_copy_buffer); continue; } @@ -817,10 +763,10 @@ void UtilImageToImage(CommandBuffer* buffer, std::span reg vk::ImageLayout::eTransferDstOptimal, 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 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) { if (!IsSingleImageAspect(src_aspect) || !IsSingleImageAspect(dst_aspect) || (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 || @@ -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 // barriers below. The preservation policy stays isolated here so a future scheduler can replace // this synchronization without changing texture-cache ownership logic. - VulkanDeviceWaitIdle(ctx); + WaitForGraphicsIdle(ctx); auto* copy_buffer = new VulkanBuffer; copy_buffer->usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; @@ -857,7 +803,7 @@ void UtilCopyImageWithBuffer(CommandBuffer* buffer, GraphicContext* ctx, VulkanI VulkanCreateBuffer(ctx, copy_buffer_size, 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 final_layout = dst_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); } -void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image, - VulkanSwapchain* dst_swapchain) { - auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; +void BlitToSwapchain(CommandBuffer* buffer, VulkanImage* src_image, + VulkanSwapchain* dst_swapchain) { + auto vk_buffer = buffer->Handle(); if (src_image->layout != vk::ImageLayout::eTransferSrcOptimal) { EXIT("invalid prepared presentation image, image=%p vk_image=%p layout=%d\n", static_cast(src_image), @@ -939,9 +885,8 @@ void UtilBlitPreparedImage(CommandBuffer* buffer, VulkanImage* src_image, vk::Filter::eLinear); } -void UtilClearColorImage(CommandBuffer* buffer, VulkanImage* image, - const vk::ClearColorValue& color) { - auto vk_buffer = buffer->GetPool()->buffers[buffer->GetIndex()]; +void ClearColorImage(CommandBuffer* buffer, VulkanImage* image, const vk::ClearColorValue& color) { + auto vk_buffer = buffer->Handle(); SetImageLayout(vk_buffer, image, 0, 1, vk::ImageAspectFlagBits::eColor, image->layout, vk::ImageLayout::eTransferDstOptimal); 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); } -void VulkanCreateBuffer(GraphicContext* gctx, uint64_t size, VulkanBuffer* buffer) { - KYTY_PROFILER_FUNCTION(); - - 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(buffer->memory.property); - - vk::Buffer::CType native_buffer = VK_NULL_HANDLE; - const auto result = static_cast(vmaCreateBuffer( - gctx->allocator, static_cast(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(memory->property); - - vk::Image::CType native_image = VK_NULL_HANDLE; - const auto result = static_cast(vmaCreateImage( - gctx->allocator, static_cast(*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) { +void UploadImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_data, uint64_t size, + uint32_t src_pitch, vk::ImageLayout dst_layout) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0); @@ -1059,9 +907,9 @@ void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_ vk::ImageLayout::eUndefined, 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) { +void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t dst_pitch, + VulkanImage* src_image, vk::ImageLayout src_layout, + vk::ImageAspectFlags aspect) { KYTY_PROFILER_FUNCTION(); 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); } -void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, - std::span regions, VulkanImage* src_image, - vk::ImageLayout src_layout) { +void DownloadImage(GraphicContext* ctx, void* dst_data, uint64_t size, + std::span regions, VulkanImage* src_image, + vk::ImageLayout src_layout) { KYTY_PROFILER_FUNCTION(); EXIT_IF(size == 0 || regions.empty()); GetStagingBuffer(StagingBufferType::ReadBack) ->DownloadFromImage(ctx, dst_data, size, regions, src_image, src_layout); } -void UtilSetImageLayoutOptimal(VulkanImage* image) { - ExecuteImmediateUtilCommands([&](CommandBuffer*, vk::CommandBuffer vk_command) { - 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 regions, vk::ImageLayout dst_layout) { +void UploadImage(GraphicContext* ctx, VulkanImage* image, const void* src_data, uint64_t size, + std::span regions, vk::ImageLayout dst_layout) { EXIT_IF(size == 0 || regions.empty()); GetStagingBuffer(StagingBufferType::Texture) ->UploadToImage(ctx, image, src_data, size, regions, dst_layout); } -void UtilFillImage(GraphicContext* ctx, std::span regions, - VulkanImage* dst_image, vk::ImageLayout dst_layout) { - ExecuteImmediateUtilCommands([&](CommandBuffer* command, vk::CommandBuffer) { - UtilImageToImage(command, regions, dst_image, dst_layout); +void CopyImageImmediate(GraphicContext* ctx, std::span regions, + VulkanImage* dst_image, vk::ImageLayout dst_layout) { + ExecuteImmediateCommands([&](CommandBuffer* command, vk::CommandBuffer) { + CopyImage(command, regions, dst_image, dst_layout); }); } -void UtilFillImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data, - uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) { +void UploadImage(GraphicContext* ctx, DepthStencilVulkanImage* image, const void* src_data, + uint64_t size, uint32_t src_pitch, vk::ImageAspectFlags aspect) { EXIT_IF(size == 0); GetStagingBuffer(StagingBufferType::Texture) ->UploadToImage(ctx, image, src_data, size, src_pitch, aspect, image->layout, vk::ImageLayout::eDepthStencilAttachmentOptimal); } -void UtilUploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, - uint64_t dst_offset, const void* src_data, uint64_t size) { +void UploadBuffer(GraphicContext* ctx, StagingBufferType type, VulkanBuffer* dst_buffer, + uint64_t dst_offset, const void* src_data, uint64_t size) { EXIT_IF(size == 0); 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); } -void UtilReleaseCachedResources(GraphicContext* ctx) { - 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) { +void CopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t 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, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, 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* dst_data, uint64_t size) { +void DownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t src_offset, + void* dst_data, uint64_t size) { EXIT_IF(size == 0); EXIT_IF(src_offset > src_buffer->buffer_size || size > src_buffer->buffer_size - src_offset); 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; 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, vk::AccessFlagBits::eMemoryWrite, vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eAllCommands, @@ -1196,4 +1026,4 @@ void UtilDownloadBuffer(GraphicContext* ctx, VulkanBuffer* src_buffer, uint64_t VulkanDeleteBuffer(ctx, &readback); } -} // namespace Libs::Graphics +} // namespace Libs::Graphics::Transfer diff --git a/src/graphics/host_gpu/transfer.h b/src/graphics/host_gpu/transfer.h new file mode 100644 index 000000000..b65380066 --- /dev/null +++ b/src/graphics/host_gpu/transfer.h @@ -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 +#include +#include + +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 +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 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 regions, vk::ImageLayout dst_layout); +void CopyImageImmediate(GraphicContext* ctx, std::span 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 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 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(odd ? mip_width : 0); + mip_y += static_cast(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_ diff --git a/src/graphics/host_gpu/utils.h b/src/graphics/host_gpu/utils.h deleted file mode 100644 index 859f3a6e6..000000000 --- a/src/graphics/host_gpu/utils.h +++ /dev/null @@ -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 -#include -#include - -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 -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 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 regions, vk::ImageLayout dst_layout); -void UtilFillImage(GraphicContext* ctx, std::span 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 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 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(odd ? mip_width : 0); - mip_y += static_cast(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_ */ diff --git a/src/graphics/host_gpu/vma.cpp b/src/graphics/host_gpu/vma.cpp index cbedd2025..63e812c6a 100644 --- a/src/graphics/host_gpu/vma.cpp +++ b/src/graphics/host_gpu/vma.cpp @@ -17,15 +17,11 @@ #include "common/assert.h" #include "common/logging/log.h" #include "common/profiler.h" -#include "common/stringUtils.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/vma.h" #include #include -#include -#include -#include 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(); - EXIT_IF(ctx == nullptr || memory == nullptr || memory->memory != nullptr || - memory->allocation != nullptr || ctx->allocator == nullptr || - memory->requirements.size == 0); + EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || + buffer->buffer != nullptr || buffer->memory.allocation != nullptr || size == 0); - const auto& properties = ctx->GetPhysicalDeviceMemoryProperties(); - uint32_t index = 0; - for (; index < properties.memoryTypeCount; index++) { - if ((memory->requirements.memoryTypeBits & (uint32_t {1} << index)) != 0 && - (properties.memoryTypes[index].propertyFlags & memory->property) == memory->property) { - break; - } - } + 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 info {}; - info.requiredFlags = static_cast(memory->property); - memory->unique_id = VulkanNextMemoryUniqueId(); - const auto result = static_cast(vmaAllocateMemory( - ctx->allocator, - static_cast(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; - } + VmaAllocationCreateInfo alloc_info {}; + alloc_info.requiredFlags = + static_cast(buffer->memory.property); - VulkanLogMemoryBudget(ctx); - std::vector stats; - for (uint32_t i = 0; i < properties.memoryTypeCount; i++) { - stats.push_back(fmt::format("{}, {}, {}", i, g_memory_stats.count[i].load(), - g_memory_stats.allocated[i].load())); + vk::Buffer::CType native_buffer = VK_NULL_HANDLE; + const auto result = static_cast(vmaCreateBuffer( + ctx->allocator, static_cast(buffer_info), + &alloc_info, &native_buffer, &buffer->memory.allocation, &buffer->memory.allocation_info)); + buffer->buffer = native_buffer; + if (result != vk::Result::eSuccess) { + VulkanLogMemoryBudget(ctx); } - EXIT("size = %" PRIu64 ", index = %u, error: %s:%s\n", memory->requirements.size, index, - VulkanToString(result).c_str(), Common::Concat(stats, '\n').c_str()); - return false; + EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); + + 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(); - EXIT_IF(ctx == nullptr || memory == nullptr || ctx->allocator == nullptr || - memory->allocation == nullptr); - vmaFreeMemory(ctx->allocator, memory->allocation); - VulkanUntrackAllocation(memory); - memory->memory = nullptr; - memory->allocation = nullptr; - memory->allocation_info = {}; - memory->offset = 0; + EXIT_IF(ctx == nullptr || ctx->allocator == nullptr || buffer == nullptr || + buffer->buffer == nullptr || buffer->memory.allocation == nullptr); + + VulkanUntrackAllocation(&buffer->memory); + vmaDestroyBuffer(ctx->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* 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(memory.property); + + vk::Image::CType native_image = VK_NULL_HANDLE; + const auto result = static_cast(vmaCreateImage( + ctx->allocator, static_cast(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) { @@ -185,22 +220,4 @@ void VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory) { 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(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(vmaBindBufferMemory(ctx->allocator, memory->allocation, - buffer->buffer)) != vk::Result::eSuccess); -} - } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/vma.h b/src/graphics/host_gpu/vma.h index 88a9f0d49..ab4cc572c 100644 --- a/src/graphics/host_gpu/vma.h +++ b/src/graphics/host_gpu/vma.h @@ -2,6 +2,7 @@ #define EMULATOR_SRC_GRAPHICS_HOST_GPU_VMA_H_ #include "common/common.h" +#include "graphics/host_gpu/vulkanCommon.h" namespace Libs::Graphics { @@ -16,12 +17,13 @@ uint64_t VulkanNextMemoryUniqueId(); void VulkanTrackAllocation(const VulkanMemory* memory); void VulkanUntrackAllocation(const VulkanMemory* memory); void VulkanLogMemoryBudget(GraphicContext* ctx); -bool VulkanAllocate(GraphicContext* ctx, VulkanMemory* memory); -void VulkanFree(GraphicContext* ctx, VulkanMemory* memory); +void VulkanCreateBuffer(GraphicContext* ctx, uint64_t size, VulkanBuffer* buffer); +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 VulkanUnmapMemory(GraphicContext* ctx, VulkanMemory* memory); -void VulkanBindImageMemory(GraphicContext* ctx, VulkanImage* image, VulkanMemory* memory); -void VulkanBindBufferMemory(GraphicContext* ctx, VulkanBuffer* buffer, VulkanMemory* memory); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/vulkanCommon.cpp b/src/graphics/host_gpu/vulkanCommon.cpp index 4a1cc7b68..74c173491 100644 --- a/src/graphics/host_gpu/vulkanCommon.cpp +++ b/src/graphics/host_gpu/vulkanCommon.cpp @@ -1,8 +1,95 @@ #include "graphics/host_gpu/vulkanCommon.h" +#include "common/assert.h" +#include "graphics/guest_gpu/gpu_defs.h" + +#include + VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE 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 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) { return vk::to_string(value); @@ -20,4 +107,16 @@ std::string VulkanToString(vk::QueueFlags 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(result)); + } +} + } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/vulkanCommon.h b/src/graphics/host_gpu/vulkanCommon.h index 04ebd2e91..eff804423 100644 --- a/src/graphics/host_gpu/vulkanCommon.h +++ b/src/graphics/host_gpu/vulkanCommon.h @@ -10,7 +10,9 @@ #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include #include +#include #include #include @@ -27,6 +29,29 @@ std::string VulkanToString(vk::Result value); std::string VulkanToString(vk::Format value); std::string VulkanToString(vk::ImageLayout value); std::string VulkanToString(vk::QueueFlags value); +vk::Format VulkanFormat(uint32_t guest_format); +void RequireVulkanSuccess(vk::Result result, const char* operation); + +template +[[nodiscard]] std::vector EnumerateVulkan(const char* operation, Enumerator&& enumerate) { + for (;;) { + uint32_t count = 0; + RequireVulkanSuccess(enumerate(&count, nullptr), operation); + if (count == 0) { + return {}; + } + + std::vector 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 diff --git a/src/graphics/presentation/videoOut.cpp b/src/graphics/presentation/videoOut.cpp index 011e3033d..10cc818a8 100644 --- a/src/graphics/presentation/videoOut.cpp +++ b/src/graphics/presentation/videoOut.cpp @@ -57,6 +57,15 @@ constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED = 0; constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_COMPRESSED = 1; 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 { uint32_t reserved0; uint32_t tiling_mode; @@ -160,10 +169,10 @@ struct VideoOutConfig { class FlipQueue { public: FlipQueue() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~FlipQueue() { KYTY_NOT_IMPLEMENTED; } + ~FlipQueue() { KYTY_NOT_IMPLEMENTED; } 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); void Prepare(uint64_t request_id, Graphics::CommandBuffer* buffer); uint64_t PrepareNextCpu(Graphics::CommandBuffer* buffer); @@ -183,7 +192,7 @@ private: int index; int64_t flip_arg; uint64_t submit_ptc; - bool gpu_eop; + FlipRequestSource source; RequestState state; Graphics::PreparedFrame* frame; }; @@ -203,7 +212,7 @@ public: static constexpr int VIDEO_OUT_NUM_MAX = 2; VideoOutContext() { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); } - virtual ~VideoOutContext() { KYTY_NOT_IMPLEMENTED; } + ~VideoOutContext() { KYTY_NOT_IMPLEMENTED; } KYTY_CLASS_NO_COPY(VideoOutContext); @@ -240,6 +249,167 @@ private: static VideoOutContext* g_video_out_context = nullptr; +using VideoOutEventQueues = std::vector; + +static uintptr_t VideoOutEventId(VideoOutEventKind kind) { + return static_cast(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(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(reinterpret_cast(trigger_data)); + + return static_cast(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(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(eq), handle, reinterpret_cast(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(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 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; } +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, uint64_t address, uint64_t metadata_address, Graphics::VideoOutCompression compression) { @@ -396,54 +598,27 @@ void VideoOutContext::Close(int handle) { EXIT_NOT_IMPLEMENTED(handle >= VIDEO_OUT_NUM_MAX); 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(); - if (m_video_out_ctx[handle].closing) { + config.mutex.Lock(); + if (config.closing) { EXIT("video-out handle is already closing\n"); } - m_video_out_ctx[handle].closing = true; - if (m_flip_queue.HasPending(&m_video_out_ctx[handle], VIDEO_OUT_BUFFER_INDEX_BLACK, + config.closing = true; + if (m_flip_queue.HasPending(&config, 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"); } - for (auto& flip_eq: m_video_out_ctx[handle].flip_eqs) { - if (flip_eq != nullptr) { - auto result = EventQueue::KernelDeleteEvent(flip_eq, VIDEO_OUT_EVENT_FLIP, - EventQueue::KERNEL_EVFILT_VIDEO_OUT); - 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(); + DeleteVideoOutEventsLocked(config.flip_eqs, VideoOutEventKind::Flip); + DeleteVideoOutEventsLocked(config.pre_vblank_eqs, VideoOutEventKind::PreVblankStart); + DeleteVideoOutEventsLocked(config.vblank_eqs, VideoOutEventKind::Vblank); + DeleteVideoOutEventsLocked(config.output_mode_eqs, VideoOutEventKind::OutputMode); - m_video_out_ctx[handle].flip_rate = 0; + config.flip_rate = 0; std::vector 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) || (buffer.buffer_vulkan != nullptr && (buffer.buffer_size == 0 || buffer.buffer_pitch == 0))) { @@ -459,21 +634,17 @@ void VideoOutContext::Close(int handle) { } Graphics::g_render_ctx->GetTextureCache()->UnregisterVideoOutSurfaces(images); } - for (auto& buffer: m_video_out_ctx[handle].buffers) { - buffer.buffer = nullptr; - buffer.buffer_vulkan = nullptr; - buffer.buffer_size = 0; - buffer.buffer_pitch = 0; - buffer.set_id = 0; + for (auto& buffer: config.buffers) { + buffer = VideoOutBufferInfo {}; } - m_video_out_ctx[handle].buffers_sets.clear(); - for (bool unregistering: m_video_out_ctx[handle].unregistering) { + config.buffers_sets.clear(); + for (bool unregistering: config.unregistering) { if (unregistering) { EXIT("video-out close raced with buffer unregistration\n"); } } - m_video_out_ctx[handle].mutex.Unlock(); + config.mutex.Unlock(); } VideoOutConfig* VideoOutContext::Get(int handle) { @@ -503,15 +674,8 @@ void VideoOutContext::VblankBegin() { ctx.pre_vblank_status.reserved = LibKernel::KernelReadTsc(); ctx.pre_vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter(); - for (auto& vblank_eq: ctx.pre_vblank_eqs) { - if (vblank_eq != nullptr) { - auto result = EventQueue::KernelTriggerEvent( - vblank_eq, VIDEO_OUT_EVENT_PRE_VBLANK_START, - EventQueue::KERNEL_EVFILT_VIDEO_OUT, - reinterpret_cast(ctx.pre_vblank_status.count)); - EXIT_NOT_IMPLEMENTED(result != OK); - } - } + TriggerVideoOutEventsLocked(ctx.pre_vblank_eqs, VideoOutEventKind::PreVblankStart, + reinterpret_cast(ctx.pre_vblank_status.count)); ctx.mutex.Unlock(); } } @@ -529,14 +693,8 @@ void VideoOutContext::VblankEnd() { ctx.vblank_status.reserved = LibKernel::KernelReadTsc(); ctx.vblank_status.processTimeCounter = LibKernel::KernelGetProcessTimeCounter(); - for (auto& vblank_eq: ctx.vblank_eqs) { - if (vblank_eq != nullptr) { - auto result = EventQueue::KernelTriggerEvent( - vblank_eq, VIDEO_OUT_EVENT_VBLANK, EventQueue::KERNEL_EVFILT_VIDEO_OUT, - reinterpret_cast(ctx.vblank_status.count)); - EXIT_NOT_IMPLEMENTED(result != OK); - } - } + TriggerVideoOutEventsLocked(ctx.vblank_eqs, VideoOutEventKind::Vblank, + reinterpret_cast(ctx.vblank_status.count)); ctx.mutex.Unlock(); } } @@ -574,7 +732,7 @@ Presentation::DisplayBufferImage VideoOutContext::FindImage(const void* buffer, 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) { EXIT_IF(cfg == nullptr || request_id == nullptr); 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) { return false; } - auto& pending = gpu_eop ? m_requests : m_cpu_requests; + auto& pending = source == FlipRequestSource::GpuEop ? m_requests : m_cpu_requests; Request r {}; 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.flip_arg = flip_arg; r.submit_ptc = LibKernel::KernelGetProcessTimeCounter(); - r.gpu_eop = gpu_eop; + r.source = source; r.state = RequestState::Reserved; 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(m_requests.size() + m_cpu_requests.size()); cfg->flip_status.submitProcessTimeCounter = r.submit_ptc; - if (gpu_eop) { + if (source == FlipRequestSource::GpuEop) { 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.currentBuffer = r.index; r.cfg->flip_status.flipPendingNum = static_cast(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--; } @@ -792,14 +950,8 @@ bool FlipQueue::Flip(uint32_t micros) { m_mutex.Unlock(); r.cfg->mutex.Lock(); - for (auto& flip_eq: r.cfg->flip_eqs) { - if (flip_eq != nullptr) { - auto result = EventQueue::KernelTriggerEvent(flip_eq, VIDEO_OUT_EVENT_FLIP, - EventQueue::KERNEL_EVFILT_VIDEO_OUT, - reinterpret_cast(r.flip_arg)); - EXIT_NOT_IMPLEMENTED(result != OK); - } - } + TriggerVideoOutEventsLocked(r.cfg->flip_eqs, VideoOutEventKind::Flip, + reinterpret_cast(r.flip_arg)); r.cfg->mutex.Unlock(); if (Config::GraphicsDebugDumpEnabled() && @@ -926,398 +1078,42 @@ KYTY_SYSV_ABI int VideoOutSetFlipRate(int handle, int rate) { 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(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(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(reinterpret_cast(trigger_data)); - - return static_cast(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(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(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(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) { PRINT_NAME(); - - 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); + return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::Flip); } KYTY_SYSV_ABI int VideoOutAddFlipEvent(EventQueue::KernelEqueue eq, int handle, void* udata) { PRINT_NAME(); - - 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; + return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::Flip, udata); } KYTY_SYSV_ABI int VideoOutDeleteVblankEvent(EventQueue::KernelEqueue eq, int handle) { PRINT_NAME(); - - 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); + return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::Vblank); } KYTY_SYSV_ABI int VideoOutDeletePreVblankStartEvent(EventQueue::KernelEqueue eq, int handle) { PRINT_NAME(); - - 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); + return DeleteVideoOutEvent(handle, eq, VideoOutEventKind::PreVblankStart); } KYTY_SYSV_ABI int VideoOutAddVblankEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, void* udata) { PRINT_NAME(); - - 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; + return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::Vblank, udata); } KYTY_SYSV_ABI int VideoOutAddPreVblankStartEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, void* udata) { PRINT_NAME(); - - 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; + return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::PreVblankStart, udata); } KYTY_SYSV_ABI int VideoOutAddOutputModeEvent(LibKernel::EventQueue::KernelEqueue eq, int handle, void* udata) { PRINT_NAME(); - - 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(eq), handle, reinterpret_cast(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(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; + return RegisterVideoOutEvent(handle, eq, VideoOutEventKind::OutputMode, udata); } 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++) { 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) { - LOGF("\t buffers[%d]: ignoring reserved fields {%p, %p}\n", i, - buffers[i].reserved[0], buffers[i].reserved[1]); + LOGF("\t buffers[%d]: ignoring reserved fields {%p, %p}\n", i, buffers[i].reserved[0], + buffers[i].reserved[1]); } const auto data_address = reinterpret_cast(buffers[i].data); const auto metadata_address = reinterpret_cast(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) { PRINT_NAME(); - EXIT_IF(g_video_out_context == nullptr); - - auto* ctx = g_video_out_context->Get(handle); - if (ctx == nullptr) { - return VIDEO_OUT_ERROR_INVALID_HANDLE; - } - - if (flip_mode < VIDEO_OUT_FLIP_MODE_VSYNC || flip_mode > VIDEO_OUT_FLIP_MODE_VSYNC_MULTI) { + uint64_t request_id = 0; + const int result = + ReserveFlipRequest(handle, index, flip_mode, flip_arg, FlipRequestSource::Cpu, &request_id); + if (result == VIDEO_OUT_ERROR_INVALID_VALUE) { LOGF("\t unsupported flip_mode = %d\n", flip_mode); - return VIDEO_OUT_ERROR_INVALID_VALUE; } - - if (!IsValidBufferIndex(index)) { - 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; - } + if (result != OK) { + return result; } 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 || buffer == nullptr || request_id == nullptr); - auto* ctx = VideoOut::g_video_out_context->Get(handle); - if (ctx == nullptr) { - return VideoOut::VIDEO_OUT_ERROR_INVALID_HANDLE; - } - - 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; - } + const int result = VideoOut::ReserveFlipRequest( + handle, index, flip_mode, flip_arg, VideoOut::FlipRequestSource::GpuEop, request_id); + if (result != OK) { + return result; } 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->output_mode = mode; - for (auto& output_mode_eq: ctx->output_mode_eqs) { - if (output_mode_eq != nullptr) { - auto trigger_result = EventQueue::KernelTriggerEvent( - output_mode_eq, VIDEO_OUT_EVENT_SET_MODE, EventQueue::KERNEL_EVFILT_VIDEO_OUT, - reinterpret_cast(ctx->output_mode)); - EXIT_NOT_IMPLEMENTED(trigger_result != OK); - } - } + TriggerVideoOutEventsLocked(ctx->output_mode_eqs, VideoOutEventKind::OutputMode, + reinterpret_cast(ctx->output_mode)); ctx->mutex.Unlock(); return OK; diff --git a/src/graphics/presentation/window/swapchain.cpp b/src/graphics/presentation/window/swapchain.cpp index a568b87f7..b207e149f 100644 --- a/src/graphics/presentation/window/swapchain.cpp +++ b/src/graphics/presentation/window/swapchain.cpp @@ -29,7 +29,7 @@ #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/renderer/render.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/vulkanCommon.h" #include "graphics/presentation/renderDoc.h" @@ -155,7 +155,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk } if (dst.image != nullptr) { EXIT_IF(!dst.view_cache.views.empty()); - VulkanDeleteImage(ctx, &dst, &dst.memory); + VulkanDeleteImage(ctx, &dst); dst.memory = {}; } @@ -178,7 +178,7 @@ static void ConfigurePreparedFrame(PreparedFrame* frame, vk::Extent2D extent, vk create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; create.sharingMode = vk::SharingMode::eExclusive; 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", dst.extent.width, dst.extent.height, static_cast(dst.format)); } @@ -248,13 +248,19 @@ VulkanSwapchain::~VulkanSwapchain() = default; 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); - EXIT_NOT_IMPLEMENTED(*swapchain_images_count == 0); + auto images = EnumerateVulkan( + "vkGetSwapchainImagesKHR", [&](uint32_t* count, vk::Image* values) { + return device.getSwapchainImagesKHR(swapchain, count, values); + }); + EXIT_NOT_IMPLEMENTED(images.empty()); - *swapchain_images = std::make_unique(*swapchain_images_count); - device.getSwapchainImagesKHR(swapchain, swapchain_images_count, swapchain_images->get()); + *swapchain_images_count = static_cast(images.size()); + *swapchain_images = std::make_unique(images.size()); + std::copy(images.begin(), images.end(), swapchain_images->get()); *swapchain_image_views = std::make_unique(*swapchain_images_count); 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.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; @@ -330,7 +339,7 @@ static void VulkanDeleteSwapchain(GraphicContext* ctx, VulkanSwapchain* s) { } auto swapchain_owner = std::unique_ptr(s); - VulkanDeviceWaitIdle(ctx); + Transfer::WaitForGraphicsIdle(ctx); if (s->image_acquired_semaphores != nullptr) { 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); const std::array copies {ImageImageCopy { .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; } @@ -421,7 +430,7 @@ PreparedFrame* WindowPrepareBlankFrame(CommandBuffer* buffer, uint32_t width, ui ConfigurePreparedFrame(frame, {width, height}, format); vk::ClearColorValue clear {}; clear.float32[3] = opaque ? 1.0f : 0.0f; - UtilClearColorImage(buffer, &frame->image, clear); + Transfer::ClearColorImage(buffer, &frame->image, clear); return frame; } @@ -475,11 +484,11 @@ void WindowPresentFrame(PreparedFrame* frame) { frame->present_commands->WaitForFenceAndReset(); auto& buffer = *frame->present_commands; - auto vk_buffer = buffer.GetPool()->buffers[buffer.GetIndex()]; + auto vk_buffer = buffer.Handle(); buffer.Begin(); - UtilBlitPreparedImage(&buffer, &frame->image, swapchain); + Transfer::BlitToSwapchain(&buffer, &frame->image, swapchain); vk::ImageMemoryBarrier pre_present_barrier {}; pre_present_barrier.sType = vk::StructureType::eImageMemoryBarrier; diff --git a/src/graphics/presentation/window/vulkanWindow.cpp b/src/graphics/presentation/window/vulkanWindow.cpp index 69a135dc8..090793380 100644 --- a/src/graphics/presentation/window/vulkanWindow.cpp +++ b/src/graphics/presentation/window/vulkanWindow.cpp @@ -28,7 +28,7 @@ #include "common/timer.h" #include "graphics/host_gpu/graphicContext.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/vulkanCommon.h" #include "graphics/presentation/renderDoc.h" @@ -81,36 +81,34 @@ static bool HasLayer(const std::vector& layers, const char* void VulkanGetSurfaceCapabilities(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface, SurfaceCapabilities* r) { - physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities); + RequireVulkanSuccess(physical_device.getSurfaceCapabilitiesKHR(surface, &r->capabilities), + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - uint32_t formats_count = 0; - physical_device.getSurfaceFormatsKHR(surface, &formats_count, nullptr); + r->formats = EnumerateVulkan( // @suppress("Ambiguous problem") + "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( // @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(formats_count); // @suppress("Ambiguous problem") - physical_device.getSurfaceFormatsKHR(surface, &formats_count, r->formats.data()); - - 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(present_modes_count); // @suppress("Ambiguous problem") - physical_device.getSurfacePresentModesKHR(surface, &present_modes_count, - r->present_modes.data()); - - r->format_srgb_bgra32 = false; + r->format_srgb_bgra32 = false; + r->format_unorm_bgra32 = false; for (const auto& f: r->formats) { if (f.format == vk::Format::eB8G8R8A8Srgb && f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { r->format_srgb_bgra32 = true; - break; } if (f.format == vk::Format::eB8G8R8A8Unorm && f.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { r->format_unorm_bgra32 = true; + } + if (r->format_srgb_bgra32 && r->format_unorm_bgra32) { break; } } @@ -131,7 +129,6 @@ struct QueueInfo { uint32_t index = 0; bool graphics = false; bool compute = false; - bool transfer = false; bool present = false; }; @@ -141,7 +138,6 @@ struct VulkanQueues { std::vector available; std::vector graphics; std::vector compute; - std::vector transfer; std::vector present; }; @@ -163,10 +159,6 @@ static void VulkanDumpQueues(const VulkanQueues& qs) { for (const auto& q: qs.compute) { 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"); for (const auto& q: qs.present) { 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, 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(surface == nullptr); @@ -191,7 +183,8 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s uint32_t family = 0; for (auto& f: queue_families) { 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", VulkanToString(f.queueFlags).c_str(), f.queueCount, @@ -203,7 +196,6 @@ static VulkanQueues VulkanFindQueues(vk::PhysicalDevice device, vk::SurfaceKHR s info.index = i; info.graphics = static_cast(f.queueFlags & vk::QueueFlagBits::eGraphics); info.compute = static_cast(f.queueFlags & vk::QueueFlagBits::eCompute); - info.transfer = static_cast(f.queueFlags & vk::QueueFlagBits::eTransfer); info.present = (presentation_supported == VK_TRUE); 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); return qs; @@ -261,16 +252,15 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa EXIT_IF(out_device == nullptr); EXIT_IF(out_queues == nullptr); - uint32_t devices_count = 0; - instance.enumeratePhysicalDevices(&devices_count, nullptr); + auto devices = EnumerateVulkan( + "vkEnumeratePhysicalDevices", [&](uint32_t* count, vk::PhysicalDevice* values) { + return instance.enumeratePhysicalDevices(count, values); + }); + EXIT_NOT_IMPLEMENTED(devices.empty()); - EXIT_NOT_IMPLEMENTED(devices_count == 0); - - std::vector devices(devices_count); - instance.enumeratePhysicalDevices(&devices_count, devices.data()); - - vk::PhysicalDevice best_device = nullptr; - VulkanQueues best_queues; + vk::PhysicalDevice best_device = nullptr; + VulkanQueues best_queues; + SurfaceCapabilities best_capabilities; for (const auto& device: devices) { bool skip_device = false; @@ -313,15 +303,14 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa device.getFeatures2(&device_features2); - auto qs = VulkanFindQueues( - device, surface, GraphicContext::QUEUE_GFX_NUM, GraphicContext::QUEUE_COMPUTE_NUM, - GraphicContext::QUEUE_UTIL_NUM, GraphicContext::QUEUE_PRESENT_NUM); + auto qs = + VulkanFindQueues(device, surface, GraphicContext::QUEUE_GFX_NUM, + GraphicContext::QUEUE_COMPUTE_NUM, GraphicContext::QUEUE_PRESENT_NUM); VulkanDumpQueues(qs); if (qs.graphics.size() != GraphicContext::QUEUE_GFX_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) { LOGF("Not enough queues\n"); skip_device = true; @@ -387,14 +376,12 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa } if (!skip_device) { - uint32_t extensions_count = 0; - device.enumerateDeviceExtensionProperties(nullptr, &extensions_count, nullptr); - - EXIT_NOT_IMPLEMENTED(extensions_count == 0); - - std::vector available_extensions(extensions_count); - device.enumerateDeviceExtensionProperties(nullptr, &extensions_count, - available_extensions.data()); + auto available_extensions = EnumerateVulkan( + "vkEnumerateDeviceExtensionProperties", + [&](uint32_t* count, vk::ExtensionProperties* values) { + return device.enumerateDeviceExtensionProperties(nullptr, count, values); + }); + EXIT_NOT_IMPLEMENTED(available_extensions.empty()); for (const char* ext: device_extensions) { if (!HasExtension(available_extensions, ext)) { @@ -411,10 +398,11 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa } } + SurfaceCapabilities candidate_capabilities; 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)) { LOGF("Surface cannot be destination of blit\n"); skip_device = true; @@ -510,13 +498,17 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa if (best_device == nullptr || device_properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) { - best_device = device; - best_queues = qs; + best_device = device; + best_queues = qs; + best_capabilities = std::move(candidate_capabilities); } } *out_device = best_device; *out_queues = best_queues; + if (best_device != nullptr) { + *out_capabilities = std::move(best_capabilities); + } } 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(r == nullptr); - uint32_t required_extensions_count = 0; - uint32_t available_extensions_count = 0; - uint32_t available_layers_count = 0; + uint32_t required_extensions_count = 0; 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 != r->required_extensions.size()); - vk::enumerateInstanceExtensionProperties(nullptr, &available_extensions_count, nullptr); - - r->available_extensions = std::vector( - available_extensions_count); // @suppress("Ambiguous problem") - std::memset(r->available_extensions.data(), 0, - 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->available_extensions = + EnumerateVulkan( // @suppress("Ambiguous problem") + "vkEnumerateInstanceExtensionProperties", + [](uint32_t* count, vk::ExtensionProperties* values) { + return vk::enumerateInstanceExtensionProperties(nullptr, count, values); + }); r->enable_validation_layers = Config::VulkanValidationEnabled(); @@ -750,15 +735,10 @@ static void VulkanGetExtensions(SDL_Window* window, VulkanExtensions* r) { ext.specVersion); } - vk::enumerateInstanceLayerProperties(&available_layers_count, nullptr); - - r->available_layers = - std::vector(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()); + r->available_layers = EnumerateVulkan( // @suppress("Ambiguous problem") + "vkEnumerateInstanceLayerProperties", [](uint32_t* count, vk::LayerProperties* values) { + return vk::enumerateInstanceLayerProperties(count, values); + }); for (const auto& l: r->available_layers) { 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) { - vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", - &available_extensions_count, nullptr); - - std::vector available_extensions(available_extensions_count); - - vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", - &available_extensions_count, - available_extensions.data()); + auto available_extensions = EnumerateVulkan( + "vkEnumerateInstanceExtensionProperties", + [](uint32_t* count, vk::ExtensionProperties* values) { + return vk::enumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", + count, values); + }); for (const auto& ext: available_extensions) { 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->device == nullptr); EXIT_IF(queues.graphics.size() != 1); - EXIT_IF(queues.transfer.size() != 1); EXIT_IF(queues.present.size() != 1); EXIT_IF(!(queues.compute.size() >= 1 && 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].index = info.index; EXIT_IF(ctx->queues[id].vk_queue != nullptr); ctx->device.getQueue(ctx->queues[id].family, ctx->queues[id].index, &ctx->queues[id].vk_queue); 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].index = ctx->queues[GraphicContext::QUEUE_GFX].index; ctx->queues[GraphicContext::QUEUE_UTIL].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 " "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++) { - bool with_mutex = (GraphicContext::QUEUE_COMPUTE_NUM == queues.compute.size()); 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++) { @@ -919,10 +891,7 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) if (queue.vk_queue == nullptr) { continue; } - - if (queue.mutex == nullptr) { - queue.mutex = new Common::Mutex; - } + EXIT_IF(queue.mutex != nullptr); for (int other_id = 0; other_id < id; other_id++) { auto& other = ctx->queues[other_id]; @@ -930,14 +899,15 @@ static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues) continue; } - if (other.mutex == nullptr && queue.mutex != nullptr) { - other.mutex = queue.mutex; - } else { - queue.mutex = other.mutex; - } + EXIT_IF(other.mutex == nullptr); + queue.mutex = other.mutex; LOGF("Vulkan queue: sharing mutex for queue ids %d and %d\n", other_id, id); 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()); { - uint32_t extensions_count = 0; - ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( - nullptr, &extensions_count, nullptr); - - std::vector available_extensions(extensions_count); - ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( - nullptr, &extensions_count, available_extensions.data()); + auto available_extensions = EnumerateVulkan( + "vkEnumerateDeviceExtensionProperties", + [&](uint32_t* count, vk::ExtensionProperties* values) { + return ctx->graphic_ctx.physical_device.enumerateDeviceExtensionProperties( + nullptr, count, values); + }); if (HasExtension(available_extensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) { device_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); diff --git a/src/graphics/presentation/window/window.cpp b/src/graphics/presentation/window/window.cpp index 58b8624ef..3148c33dd 100644 --- a/src/graphics/presentation/window/window.cpp +++ b/src/graphics/presentation/window/window.cpp @@ -30,7 +30,7 @@ #include "common/timer.h" #include "graphics/host_gpu/graphicContext.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/vulkanCommon.h" #include "graphics/presentation/renderDoc.h" diff --git a/src/graphics/shader/recompiler/BufferFormat.h b/src/graphics/shader/recompiler/BufferFormat.h index 01cef98b6..03942a7a1 100644 --- a/src/graphics/shader/recompiler/BufferFormat.h +++ b/src/graphics/shader/recompiler/BufferFormat.h @@ -224,20 +224,6 @@ constexpr uint32_t GetFormatComponentCount(Prospero::BufferFormat format) { 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) { const auto info = GetFormatInfo(format); if (component >= info.component_count) { diff --git a/src/graphics/shader/recompiler/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ResourceMaterialization.cpp index 2aeb0e4e4..785791251 100644 --- a/src/graphics/shader/recompiler/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ResourceMaterialization.cpp @@ -1,8 +1,9 @@ #include "graphics/shader/recompiler/ResourceMaterialization.h" #include "graphics/guest_gpu/gpu_format.h" -#include "graphics/shader/recompiler/BufferFormat.h" +#include "graphics/shader/shaderBindings.h" +#include #include namespace Libs::Graphics::ShaderRecompiler::IR { @@ -36,16 +37,12 @@ uint32_t DescriptorImageSwizzle(const DescriptorValue& descriptor) { return descriptor.dwords[3] & 0xfffu; } -uint32_t DescriptorPackedStride(const DescriptorValue& descriptor) { - const auto stride = (descriptor.dwords[1] >> 16u) & 0x3fffu; - const auto swizzle = (descriptor.dwords[1] >> 31u) & 1u; - const auto index_stride = (descriptor.dwords[3] >> 21u) & 3u; - const auto add_tid = (descriptor.dwords[3] >> 23u) & 1u; - return stride | (swizzle << 14u) | (index_stride << 16u) | (add_tid << 20u); -} - -uint32_t DescriptorBufferFormat(const DescriptorValue& descriptor) { - return (descriptor.dwords[3] >> 12u) & 0x7fu; +bool DecodeBufferDescriptor(const DescriptorValue& descriptor, ShaderBufferResource& result) { + if (descriptor.dword_count != std::size(result.fields)) { + return false; + } + std::copy_n(descriptor.dwords.begin(), std::size(result.fields), result.fields); + return true; } uint64_t AddressSpecialization(const AddressResource& resource, @@ -130,10 +127,16 @@ bool ValidateResourceSpecialization(const Program& program, const ResourceSnapsh return false; } for (uint32_t i = 0; i < program.info.buffers.size(); i++) { - const auto& buffer = program.info.buffers[i]; - const auto& descriptor = snapshot.buffers[i]; - if (buffer.packed_stride != DescriptorPackedStride(descriptor) || - buffer.descriptor_format != DescriptorBufferFormat(descriptor)) { + const auto& buffer = program.info.buffers[i]; + ShaderBufferResource descriptor; + if (!DecodeBufferDescriptor(snapshot.buffers[i], 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) { *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; for (uint32_t i = 0; i < next.buffers.size(); i++) { - next.buffers[i].packed_stride = DescriptorPackedStride(snapshot.buffers[i]); - next.buffers[i].descriptor_format = DescriptorBufferFormat(snapshot.buffers[i]); + ShaderBufferResource descriptor; + 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++) { next.addresses[i].specialized_base = diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index 3ca1a0629..7ce1a142f 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -205,11 +205,6 @@ static void ExitShaderRecompilerFailure(const char* label, uint64_t shader_hash, reason != nullptr ? reason : ""); } -bool ShaderBindingResearchGuardEnabled() { - return Config::GraphicsDebugDumpEnabled() || - Config::GetShaderLogDirection() != Config::ShaderLogDirection::Silent; -} - static const ShaderBinaryInfo* GetBinaryInfo(const uint32_t* code) { EXIT_IF(code == nullptr); diff --git a/src/graphics/shader/shader.h b/src/graphics/shader/shader.h index ef25b30c4..7d182437d 100644 --- a/src/graphics/shader/shader.h +++ b/src/graphics/shader/shader.h @@ -242,7 +242,6 @@ bool ShaderCompileSpirvPS(const HW::PixelShaderInfo* regs, const HW::ShaderRegis std::vector* spirv); bool ShaderCompileSpirvCS(const HW::ComputeShaderInfo* regs, const HW::ShaderRegisters* sh, ShaderComputeInputInfo* input_info, std::vector* spirv); -bool ShaderBindingResearchGuardEnabled(); bool ShaderAddressValid(uint64_t addr); } // namespace Libs::Graphics diff --git a/src/graphics/shader/shaderBindings.h b/src/graphics/shader/shaderBindings.h index dbb63a4da..051c142de 100644 --- a/src/graphics/shader/shaderBindings.h +++ b/src/graphics/shader/shaderBindings.h @@ -52,7 +52,6 @@ struct ShaderBufferResource { [[nodiscard]] uint32_t DstSelXYZW() const { return (fields[3] >> 0u) & 0xFFFu; } [[nodiscard]] bool AddTid() const { return ((fields[3] >> 23u) & 0x1u) == 1; } [[nodiscard]] uint8_t IndexStride() const { return (fields[3] >> 21u) & 0x3u; } - [[nodiscard]] uint32_t IndexStrideRecords() const { return 8u << IndexStride(); } [[nodiscard]] uint32_t PackedStride() const { return Stride() | (static_cast(SwizzleEnabled()) << 14u) | (static_cast(IndexStride()) << 16u) | @@ -70,13 +69,6 @@ struct ShaderBufferResource { struct ShaderTextureResource { uint32_t fields[8] = {0}; - void UpdateAddress40(uint64_t gpu_addr) { - auto lo = static_cast(gpu_addr & 0xffffffffu); - auto hi = static_cast(gpu_addr >> 32u); - fields[0] = lo; - fields[1] = (fields[1] & 0xffffff00u) | (hi & 0x000000ffu); - } - [[nodiscard]] uint16_t MinLod() const { return (fields[1] >> 8u) & 0xFFFu; } [[nodiscard]] uint8_t DstSelX() const { return (fields[3] >> 0u) & 0x7u; } [[nodiscard]] uint8_t DstSelY() const { return (fields[3] >> 3u) & 0x7u; } @@ -126,8 +118,6 @@ struct ShaderTextureResource { struct ShaderSamplerResource { 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 ClampY() const { return (fields[0] >> 3u) & 0x7u; } [[nodiscard]] uint8_t ClampZ() const { return (fields[0] >> 6u) & 0x7u; } diff --git a/src/main.cpp b/src/main.cpp index 3cba5ae80..88992fa1d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,8 +57,6 @@ static void PrintUsage() { ::printf(" --printf-output-file Guest printf output file.\n"); ::printf(" --profiler-direction None or Network.\n"); ::printf(" --spirv-debug-printf Enable SPIR-V debug printf.\n"); - ::printf(" --pipeline-dump Enable pipeline dumps.\n"); - ::printf(" --pipeline-dump-folder Pipeline dump folder.\n"); ::printf(" --ngg-rectlist-draw Draw rect-list auto draws using the NGG " "4-vertex path.\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()); 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") { if (!ParseBool(value, options.config.ngg_rectlist_draw_enabled)) { ::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str()); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 4af564f57..1ad0d96d2 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -20,12 +20,11 @@ #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/renderer/renderDraw.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/sync.h" #include "graphics/host_gpu/renderer/textureCache.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/shader/recompiler/BindingLayout.h" #include "graphics/shader/recompiler/ShaderDecoder.h" @@ -2481,10 +2480,10 @@ private: void Destroy() { if (m_device != nullptr) { - m_device.waitIdle(); + RequireVulkanSuccess(m_device.waitIdle(), "vkDeviceWaitIdle"); if (m_runtime_context.allocator != nullptr) { GraphicsRenderReleaseThreadCommandPools(); - UtilReleaseCachedResources(&m_runtime_context); + Transfer::ReleaseCachedResources(&m_runtime_context); vmaDestroyAllocator(m_runtime_context.allocator); m_runtime_context.allocator = nullptr; } @@ -10664,8 +10663,8 @@ void CheckRenderTargetTileRoundTrip() { "layered render-target conversion crossed array slices"); } } - const auto regions = - MakeLayeredImageBufferCopies(layers, storage.size, pitch, width, height); + const auto regions = Transfer::MakeLayeredImageBufferCopies( + layers, storage.size, pitch, width, height); Require("RenderTargetTileRoundTrip", "layered regions", regions.size() == layers && regions[0].offset == 0 && regions[1].offset == storage.size &&