diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index e7a27f38f..89381e20a 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -597,30 +597,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthRenderTarget) { uint32_t count = 1; if (cmd_id == 0xC0016900) { - HW::DepthZInfo r; - - // r.expclear_enabled = (buffer[0] & 0x08000000u) != 0; - // r.format = (buffer[0] >> Pm4::DB_Z_INFO_FORMAT_SHIFT) & - // Pm4::DB_Z_INFO_FORMAT_MASK; r.num_samples = (buffer[0] >> - // Pm4::DB_Z_INFO_NUM_SAMPLES_SHIFT) & Pm4::DB_Z_INFO_NUM_SAMPLES_MASK; r.tile_mode_index = - //(buffer[0] >> Pm4::DB_Z_INFO_TILE_MODE_INDEX_SHIFT) & Pm4::DB_Z_INFO_TILE_MODE_INDEX_MASK; - // r.tile_surface_enable = ((buffer[0] >> Pm4::DB_Z_INFO_TILE_SURFACE_ENABLE_SHIFT) & - // Pm4::DB_Z_INFO_TILE_SURFACE_ENABLE_MASK) !=0 - // r.zrange_precision = (buffer[0] >> Pm4::DB_Z_INFO_ZRANGE_PRECISION_SHIFT) & - // Pm4::DB_Z_INFO_ZRANGE_PRECISION_MASK; - - r.format = KYTY_PM4_GET(buffer[0], DB_Z_INFO, FORMAT); - r.num_samples = KYTY_PM4_GET(buffer[0], DB_Z_INFO, NUM_SAMPLES); - r.embedded_sample_locations = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ITERATE_FLUSH) != 0; - r.partially_resident = KYTY_PM4_GET(buffer[0], DB_Z_INFO, PARTIALLY_RESIDENT) != 0; - r.num_mip_levels = KYTY_PM4_GET(buffer[0], DB_Z_INFO, MAXMIP); - r.tile_mode_index = KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_MODE_INDEX); - r.plane_compression = KYTY_PM4_GET(buffer[0], DB_Z_INFO, DECOMPRESS_ON_N_ZPLANES); - r.expclear_enabled = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ALLOW_EXPCLEAR) != 0; - r.tile_surface_enable = KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; - r.zrange_precision = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ZRANGE_PRECISION); - - cp.GetCtx().SetDepthZInfo(r); + cp.GetCtx().SetDepthZInfo(HW::DepthZInfo::Decode(buffer[0])); } else if (cmd_id == 0xC0086900) { if (dw >= 22 && buffer[8] == 0xC0016900 && buffer[9] == Pm4::DB_DEPTH_INFO && buffer[11] == 0xC0016900 && buffer[12] == Pm4::DB_DEPTH_VIEW && @@ -631,51 +608,8 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthRenderTarget) { HW::DepthRenderTarget z; - // z.z_info.expclear_enabled = (buffer[0] & 0x08000000u) != 0; - // z.z_info.format = (buffer[0] >> Pm4::DB_Z_INFO_FORMAT_SHIFT) & - // Pm4::DB_Z_INFO_FORMAT_MASK; z.z_info.num_samples = (buffer[0] >> - // Pm4::DB_Z_INFO_NUM_SAMPLES_SHIFT) & Pm4::DB_Z_INFO_NUM_SAMPLES_MASK; - // z.z_info.tile_mode_index = (buffer[0] >> - // Pm4::DB_Z_INFO_TILE_MODE_INDEX_SHIFT) & - // Pm4::DB_Z_INFO_TILE_MODE_INDEX_MASK; z.z_info.tile_surface_enable = - // KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; - // z.z_info.zrange_precision = (buffer[0] >> Pm4::DB_Z_INFO_ZRANGE_PRECISION_SHIFT) & - // Pm4::DB_Z_INFO_ZRANGE_PRECISION_MASK; - - z.z_info.format = KYTY_PM4_GET(buffer[0], DB_Z_INFO, FORMAT); - z.z_info.num_samples = KYTY_PM4_GET(buffer[0], DB_Z_INFO, NUM_SAMPLES); - z.z_info.embedded_sample_locations = - KYTY_PM4_GET(buffer[0], DB_Z_INFO, ITERATE_FLUSH) != 0; - z.z_info.partially_resident = - KYTY_PM4_GET(buffer[0], DB_Z_INFO, PARTIALLY_RESIDENT) != 0; - z.z_info.num_mip_levels = KYTY_PM4_GET(buffer[0], DB_Z_INFO, MAXMIP); - z.z_info.tile_mode_index = KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_MODE_INDEX); - z.z_info.plane_compression = - KYTY_PM4_GET(buffer[0], DB_Z_INFO, DECOMPRESS_ON_N_ZPLANES); - z.z_info.expclear_enabled = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ALLOW_EXPCLEAR) != 0; - z.z_info.tile_surface_enable = - KYTY_PM4_GET(buffer[0], DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; - z.z_info.zrange_precision = KYTY_PM4_GET(buffer[0], DB_Z_INFO, ZRANGE_PRECISION); - - // z.stencil_info.expclear_enabled = (buffer[1] & 0x08000000u) != 0; - // z.stencil_info.tile_split = (buffer[1] >> 13u) & 0x7u; - // z.stencil_info.format = KYTY_PM4_GET(buffer[1], - // DB_STENCIL_INFO, FORMAT); z.stencil_info.tile_mode_index = - // KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_MODE_INDEX); - // z.stencil_info.tile_stencil_disable = KYTY_PM4_GET(buffer[1], - // DB_STENCIL_INFO, TILE_STENCIL_DISABLE); - z.stencil_info.format = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, FORMAT); - z.stencil_info.texture_compatible_stencil = - KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, ITERATE_FLUSH) != 0; - z.stencil_info.partially_resident = - KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, PARTIALLY_RESIDENT) != 0; - z.stencil_info.tile_split = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, RESERVED_FIELD_1); - z.stencil_info.tile_mode_index = - KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_MODE_INDEX); - z.stencil_info.expclear_enabled = - KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, ALLOW_EXPCLEAR) != 0; - z.stencil_info.tile_stencil_disable = - KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_STENCIL_DISABLE) != 0; + z.z_info = HW::DepthZInfo::Decode(buffer[0]); + z.stencil_info = HW::DepthStencilInfo::Decode(buffer[1]); z.z_read_base_addr = static_cast(buffer[2]) << 8u; z.stencil_read_base_addr = static_cast(buffer[3]) << 8u; @@ -1252,26 +1186,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetStencilInfo) { EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0016900); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_INFO); - HW::DepthStencilInfo r; - - // r.expclear_enabled = (buffer[0] & 0x08000000u) != 0; - // r.tile_split = (buffer[0] >> 13u) & 0x7u; - // r.format = (buffer[0] >> Pm4::DB_STENCIL_INFO_FORMAT_SHIFT) & - // Pm4::DB_STENCIL_INFO_FORMAT_MASK; r.tile_mode_index = (buffer[0] >> - // Pm4::DB_STENCIL_INFO_TILE_MODE_INDEX_SHIFT) & Pm4::DB_STENCIL_INFO_TILE_MODE_INDEX_MASK; - // r.tile_stencil_disable = - // ((buffer[0] >> Pm4::DB_STENCIL_INFO_TILE_STENCIL_DISABLE_SHIFT) & - // Pm4::DB_STENCIL_INFO_TILE_STENCIL_DISABLE_MASK) != 0; - - r.format = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, FORMAT); - r.texture_compatible_stencil = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, ITERATE_FLUSH) != 0; - r.partially_resident = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, PARTIALLY_RESIDENT) != 0; - r.tile_split = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, RESERVED_FIELD_1); - r.tile_mode_index = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_MODE_INDEX); - r.expclear_enabled = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, ALLOW_EXPCLEAR) != 0; - r.tile_stencil_disable = KYTY_PM4_GET(buffer[1], DB_STENCIL_INFO, TILE_STENCIL_DISABLE) != 0; - - cp.GetCtx().SetDepthStencilInfo(r); + cp.GetCtx().SetDepthStencilInfo(HW::DepthStencilInfo::Decode(buffer[0])); return 1; } @@ -3757,18 +3672,7 @@ void GraphicsInitJmpTablesCxIndirect() { }; g_hw_ctx_indirect_func[Pm4::DB_Z_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HW::DepthZInfo r; - r.format = KYTY_PM4_GET(value, DB_Z_INFO, FORMAT); - r.num_samples = KYTY_PM4_GET(value, DB_Z_INFO, NUM_SAMPLES); - r.embedded_sample_locations = KYTY_PM4_GET(value, DB_Z_INFO, ITERATE_FLUSH) != 0; - r.partially_resident = KYTY_PM4_GET(value, DB_Z_INFO, PARTIALLY_RESIDENT) != 0; - r.num_mip_levels = KYTY_PM4_GET(value, DB_Z_INFO, MAXMIP); - r.tile_mode_index = KYTY_PM4_GET(value, DB_Z_INFO, TILE_MODE_INDEX); - r.plane_compression = KYTY_PM4_GET(value, DB_Z_INFO, DECOMPRESS_ON_N_ZPLANES); - r.expclear_enabled = KYTY_PM4_GET(value, DB_Z_INFO, ALLOW_EXPCLEAR) != 0; - r.tile_surface_enable = KYTY_PM4_GET(value, DB_Z_INFO, TILE_SURFACE_ENABLE) != 0; - r.zrange_precision = KYTY_PM4_GET(value, DB_Z_INFO, ZRANGE_PRECISION); - cp.GetCtx().SetDepthZInfo(r); + cp.GetCtx().SetDepthZInfo(HW::DepthZInfo::Decode(value)); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { @@ -3796,15 +3700,7 @@ void GraphicsInitJmpTablesCxIndirect() { }; g_hw_ctx_indirect_func[Pm4::DB_STENCIL_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { - HW::DepthStencilInfo r; - r.format = KYTY_PM4_GET(value, DB_STENCIL_INFO, FORMAT); - r.texture_compatible_stencil = KYTY_PM4_GET(value, DB_STENCIL_INFO, ITERATE_FLUSH) != 0; - r.partially_resident = KYTY_PM4_GET(value, DB_STENCIL_INFO, PARTIALLY_RESIDENT) != 0; - r.tile_split = KYTY_PM4_GET(value, DB_STENCIL_INFO, RESERVED_FIELD_1); - r.tile_mode_index = KYTY_PM4_GET(value, DB_STENCIL_INFO, TILE_MODE_INDEX); - r.expclear_enabled = KYTY_PM4_GET(value, DB_STENCIL_INFO, ALLOW_EXPCLEAR) != 0; - r.tile_stencil_disable = KYTY_PM4_GET(value, DB_STENCIL_INFO, TILE_STENCIL_DISABLE) != 0; - cp.GetCtx().SetDepthStencilInfo(r); + cp.GetCtx().SetDepthStencilInfo(HW::DepthStencilInfo::Decode(value)); }; g_hw_ctx_indirect_func[Pm4::DB_Z_READ_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { diff --git a/src/graphics/guest_gpu/gpu_defs.h b/src/graphics/guest_gpu/gpu_defs.h index 3aa363457..098174229 100644 --- a/src/graphics/guest_gpu/gpu_defs.h +++ b/src/graphics/guest_gpu/gpu_defs.h @@ -142,6 +142,24 @@ enum class StencilFormat : uint32_t { k8UInt = 1, }; +enum class TextureCompatiblePlaneCompression : uint32_t { + kDisable = 0x00000000, + kEnable = 0x02900800, + kBitMask = 0x02900800, +}; + +enum class TextureCompatibleStencil : uint32_t { + kDisable = 0x00000000, + kEnable = 0x00100800, + kBitMask = 0x00100800, +}; + +enum class ZCompareBase : uint32_t { + kZMin = 0x00000000, + kZMax = 0x80000000, + kBitMask = 0x80000000, +}; + enum class TileMode : uint32_t { kLinear = 0x00, kStandard256B = 0x01, diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index 454c2191a..073e411cd 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -3,6 +3,7 @@ #include "common/abi.h" #include "common/common.h" +#include "graphics/guest_gpu/gpu_defs.h" namespace Libs::Graphics::HW { @@ -131,26 +132,66 @@ struct RenderTarget { }; struct DepthZInfo { - uint32_t format = 0; - uint32_t tile_mode_index = 0; - uint32_t num_samples = 0; - uint32_t zrange_precision = 0; - bool tile_surface_enable = false; - bool expclear_enabled = false; - bool embedded_sample_locations = false; - bool partially_resident = false; - uint8_t num_mip_levels = 0; - uint8_t plane_compression = 0; + uint32_t format = 0; + uint32_t num_samples = 0; + Prospero::TextureCompatiblePlaneCompression texture_compatibility = + Prospero::TextureCompatiblePlaneCompression::kDisable; + Prospero::ZCompareBase z_compare_base = Prospero::ZCompareBase::kZMin; + bool htile_acceleration = false; + bool expclear_enabled = false; + bool partially_resident = false; + uint8_t max_mip_level = 0; + + [[nodiscard]] static DepthZInfo Decode(uint32_t value) { + DepthZInfo info; + info.format = value & 0x3u; + info.num_samples = (value >> 2u) & 0x3u; + info.texture_compatibility = static_cast( + value & Prospero::GpuEnumValue(Prospero::TextureCompatiblePlaneCompression::kBitMask)); + info.partially_resident = (value & 0x00001000u) != 0; + info.max_mip_level = static_cast((value >> 16u) & 0x0fu); + info.expclear_enabled = (value & 0x08000000u) != 0; + info.htile_acceleration = (value & 0x20000000u) != 0; + info.z_compare_base = static_cast( + value & Prospero::GpuEnumValue(Prospero::ZCompareBase::kBitMask)); + return info; + } + + [[nodiscard]] bool HasValidTextureCompatibility() const { + switch (texture_compatibility) { + case Prospero::TextureCompatiblePlaneCompression::kDisable: + case Prospero::TextureCompatiblePlaneCompression::kEnable: return true; + default: return false; + } + } }; struct DepthStencilInfo { - uint32_t format = 0; - uint32_t tile_mode_index = 0; - uint32_t tile_split = 0; - bool expclear_enabled = false; - bool tile_stencil_disable = false; - bool texture_compatible_stencil = false; - bool partially_resident = false; + uint32_t format = 0; + Prospero::TextureCompatibleStencil texture_compatibility = + Prospero::TextureCompatibleStencil::kDisable; + bool expclear_enabled = false; + bool htile_stencil_disabled = false; + bool partially_resident = false; + + [[nodiscard]] static DepthStencilInfo Decode(uint32_t value) { + DepthStencilInfo info; + info.format = value & 0x1u; + info.texture_compatibility = static_cast( + value & Prospero::GpuEnumValue(Prospero::TextureCompatibleStencil::kBitMask)); + info.partially_resident = (value & 0x00001000u) != 0; + info.expclear_enabled = (value & 0x08000000u) != 0; + info.htile_stencil_disabled = (value & 0x20000000u) != 0; + return info; + } + + [[nodiscard]] bool HasValidTextureCompatibility() const { + switch (texture_compatibility) { + case Prospero::TextureCompatibleStencil::kDisable: + case Prospero::TextureCompatibleStencil::kEnable: return true; + default: return false; + } + } }; struct DepthRenderTargetDepthInfo { diff --git a/src/graphics/host_gpu/renderer/debug.cpp b/src/graphics/host_gpu/renderer/debug.cpp index 0760e8d43..6b0b41503 100644 --- a/src/graphics/host_gpu/renderer/debug.cpp +++ b/src/graphics/host_gpu/renderer/debug.cpp @@ -430,21 +430,17 @@ static void ZPrint(const char* func, const HW::DepthRenderTarget& z) { LOGF("%s\n", func); LOGF("\t z_info.format = 0x%08" PRIx32 "\n" - "\t z_info.tile_mode_index = 0x%08" PRIx32 "\n" "\t z_info.num_samples = 0x%08" PRIx32 "\n" - "\t z_info.tile_surface_enable = %s\n" + "\t z_info.texture_compatibility = 0x%08" PRIx32 "\n" + "\t z_info.htile_acceleration = %s\n" "\t z_info.expclear_enabled = %s\n" - "\t z_info.zrange_precision = 0x%08" PRIx32 "\n" - "\t z_info.embedded_sample_locations = %s\n" + "\t z_info.z_compare_base = 0x%08" PRIx32 "\n" "\t z_info.partially_resident = %s\n" - "\t z_info.num_mip_levels = 0x%02" PRIx8 "\n" - "\t z_info.plane_compression = 0x%02" PRIx8 "\n" + "\t z_info.max_mip_level = 0x%02" PRIx8 "\n" "\t stencil_info.format = 0x%08" PRIx32 "\n" - "\t stencil_info.tile_stencil_disable = %s\n" + "\t stencil_info.texture_compatibility = 0x%08" PRIx32 "\n" + "\t stencil_info.htile_stencil_disabled = %s\n" "\t stencil_info.expclear_enabled = %s\n" - "\t stencil_info.tile_mode_index = 0x%08" PRIx32 "\n" - "\t stencil_info.tile_split = 0x%08" PRIx32 "\n" - "\t stencil_info.texture_compatible_stencil = %s\n" "\t stencil_info.partially_resident = %s\n" "\t depth_info.addr5_swizzle_mask = 0x%08" PRIx32 "\n" "\t depth_info.array_mode = 0x%08" PRIx32 "\n" @@ -477,15 +473,15 @@ static void ZPrint(const char* func, const HW::DepthRenderTarget& z) { "\t height = 0x%08" PRIx32 "\n" "\t size.x_max = 0x%04" PRIx16 "\n" "\t size.y_max = 0x%04" PRIx16 "\n", - z.z_info.format, z.z_info.tile_mode_index, z.z_info.num_samples, - z.z_info.tile_surface_enable ? "true" : "false", - z.z_info.expclear_enabled ? "true" : "false", z.z_info.zrange_precision, - z.z_info.embedded_sample_locations ? "true" : "false", - z.z_info.partially_resident ? "true" : "false", z.z_info.num_mip_levels, - z.z_info.plane_compression, z.stencil_info.format, - z.stencil_info.tile_stencil_disable ? "true" : "false", - z.stencil_info.expclear_enabled ? "true" : "false", z.stencil_info.tile_mode_index, - z.stencil_info.tile_split, z.stencil_info.texture_compatible_stencil ? "true" : "false", + z.z_info.format, z.z_info.num_samples, + Prospero::GpuEnumValue(z.z_info.texture_compatibility), + z.z_info.htile_acceleration ? "true" : "false", + z.z_info.expclear_enabled ? "true" : "false", + Prospero::GpuEnumValue(z.z_info.z_compare_base), + z.z_info.partially_resident ? "true" : "false", z.z_info.max_mip_level, + z.stencil_info.format, Prospero::GpuEnumValue(z.stencil_info.texture_compatibility), + z.stencil_info.htile_stencil_disabled ? "true" : "false", + z.stencil_info.expclear_enabled ? "true" : "false", z.stencil_info.partially_resident ? "true" : "false", z.depth_info.addr5_swizzle_mask, z.depth_info.array_mode, z.depth_info.pipe_config, z.depth_info.bank_width, z.depth_info.bank_height, z.depth_info.macro_tile_aspect, z.depth_info.num_banks, @@ -502,36 +498,17 @@ static void ZPrint(const char* func, const HW::DepthRenderTarget& z) { // NOLINTNEXTLINE(readability-function-cognitive-complexity) static void ZCheck(const HW::DepthRenderTarget& z) { + EXIT_NOT_IMPLEMENTED(!z.z_info.HasValidTextureCompatibility()); + EXIT_NOT_IMPLEMENTED(!z.stencil_info.HasValidTextureCompatibility()); if (z.z_info.format == 0) { EXIT_NOT_IMPLEMENTED(z.z_info.format != 0); - EXIT_NOT_IMPLEMENTED(z.z_info.tile_mode_index != 0); EXIT_NOT_IMPLEMENTED(z.z_info.num_samples != 0); - EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != false); + EXIT_NOT_IMPLEMENTED(z.z_info.htile_acceleration != false); EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); - if (z.z_info.zrange_precision != 0) { - LOGF("Warning: zrange_precision != 0\n"); - // z.z_info.zrange_precision = 0; - } - if (z.z_info.embedded_sample_locations) { - static bool logged = false; - if (!logged) { - LOGF("DepthTarget: temporary: ignoring embedded sample locations\n"); - logged = true; - } - } EXIT_NOT_IMPLEMENTED(z.z_info.partially_resident != false); - EXIT_NOT_IMPLEMENTED(z.z_info.num_mip_levels != 0); - if (z.z_info.plane_compression != 0) { - static bool logged = false; - if (!logged) { - LOGF("DepthTarget: temporary: ignoring PS5 plane_compression=0x%02" PRIx8 "\n", - z.z_info.plane_compression); - logged = true; - } - } + EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0); } else { EXIT_NOT_IMPLEMENTED(z.z_info.format != 0x00000001 && z.z_info.format != 0x00000003); - // EXIT_NOT_IMPLEMENTED(z.z_info.tile_mode_index != 0x00000002); if (z.z_info.num_samples != 0x00000000) { static bool logged = false; if (!logged) { @@ -540,56 +517,17 @@ static void ZCheck(const HW::DepthRenderTarget& z) { logged = true; } } - // EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != true); EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); - if (z.z_info.zrange_precision != 0x00000001) { - static bool logged = false; - if (!logged) { - LOGF("DepthTarget: temporary: ignoring zrange_precision=0x%08" PRIx32 "\n", - z.z_info.zrange_precision); - logged = true; - } - } - if (z.z_info.embedded_sample_locations) { - static bool logged = false; - if (!logged) { - LOGF("DepthTarget: temporary: ignoring embedded sample locations\n"); - logged = true; - } - } EXIT_NOT_IMPLEMENTED(z.z_info.partially_resident != false); - EXIT_NOT_IMPLEMENTED(z.z_info.num_mip_levels != 0); - if (z.z_info.plane_compression != 0) { - static bool logged = false; - if (!logged) { - LOGF("DepthTarget: temporary: ignoring PS5 plane_compression=0x%02" PRIx8 "\n", - z.z_info.plane_compression); - logged = true; - } - } + EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 0); } if (z.stencil_info.format == 0) { - // EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_stencil_disable != false); EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_mode_index != 0); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_split != 0); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.texture_compatible_stencil != true); EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false); } else { - // EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0x00000001); - if (z.stencil_info.tile_stencil_disable != true) { - - static std::atomic log_count {0}; - if (log_count.fetch_add(1) < 16) { - LOGF("DepthTarget: temporary: ignoring PS5 HTILE stencil acceleration\n"); - } - } + EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0x00000001); EXIT_NOT_IMPLEMENTED(z.stencil_info.expclear_enabled != false); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_mode_index != 0x00000002); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.tile_split != 0x00000002); - // EXIT_NOT_IMPLEMENTED(z.stencil_info.texture_compatible_stencil != true); EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false); } diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index c3d556e92..502f73ba6 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -87,7 +87,7 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) { // NOLINTNEXTLINE(readability-function-cognitive-complexity) void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, - RenderDepthInfo& r) { + RenderDepthInfo& r) { KYTY_PROFILER_FUNCTION(); (void)submit_id; const auto& hw = buffer.GetRegisters(); @@ -102,31 +102,34 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB if (!depth_active && !stencil_active) { return; } + if (!z.z_info.HasValidTextureCompatibility() || + !z.stencil_info.HasValidTextureCompatibility()) { + DepthFatal("invalid PS5 depth texture-compatibility encoding"); + } const bool attachment_unbound = z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kInvalid) && z.stencil_info.format == Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid) && - z.z_info.tile_mode_index == 0 && z.z_info.num_samples == 0 && - z.z_info.zrange_precision <= 1 && !z.z_info.expclear_enabled && - !z.z_info.embedded_sample_locations && !z.z_info.partially_resident && - z.z_info.num_mip_levels == 0 && z.z_info.plane_compression == 0 && - z.stencil_info.tile_mode_index == 0 && z.stencil_info.tile_split == 0 && - !z.stencil_info.expclear_enabled && !z.stencil_info.texture_compatible_stencil && - !z.stencil_info.partially_resident && z.depth_view.slice_start == 0 && - z.depth_view.slice_max == 0 && z.depth_view.current_mip_level == 0 && - !z.depth_view.depth_write_disable && !z.depth_view.stencil_write_disable && - z.depth_info.addr5_swizzle_mask == 0 && z.depth_info.array_mode == 0 && - z.depth_info.pipe_config == 0 && z.depth_info.bank_width == 0 && - z.depth_info.bank_height == 0 && z.depth_info.macro_tile_aspect == 0 && - z.depth_info.num_banks == 0 && z.htile_surface.linear == 0 && - z.htile_surface.full_cache == 0 && z.htile_surface.htile_uses_preload_win == 0 && - z.htile_surface.preload == 0 && z.htile_surface.prefetch_width == 0 && - z.htile_surface.prefetch_height == 0 && z.htile_surface.dst_outside_zero_to_one == 0 && - z.z_read_base_addr == 0 && z.z_write_base_addr == 0 && z.stencil_read_base_addr == 0 && + z.z_info.num_samples == 0 && + z.z_info.texture_compatibility == Prospero::TextureCompatiblePlaneCompression::kDisable && + !z.z_info.expclear_enabled && !z.z_info.partially_resident && z.z_info.max_mip_level == 0 && + z.stencil_info.texture_compatibility == Prospero::TextureCompatibleStencil::kDisable && + !z.stencil_info.expclear_enabled && !z.stencil_info.partially_resident && + z.depth_view.slice_start == 0 && z.depth_view.slice_max == 0 && + z.depth_view.current_mip_level == 0 && !z.depth_view.depth_write_disable && + !z.depth_view.stencil_write_disable && z.depth_info.addr5_swizzle_mask == 0 && + z.depth_info.array_mode == 0 && z.depth_info.pipe_config == 0 && + z.depth_info.bank_width == 0 && z.depth_info.bank_height == 0 && + z.depth_info.macro_tile_aspect == 0 && z.depth_info.num_banks == 0 && + z.htile_surface.linear == 0 && z.htile_surface.full_cache == 0 && + z.htile_surface.htile_uses_preload_win == 0 && z.htile_surface.preload == 0 && + z.htile_surface.prefetch_width == 0 && z.htile_surface.prefetch_height == 0 && + z.htile_surface.dst_outside_zero_to_one == 0 && z.z_read_base_addr == 0 && + z.z_write_base_addr == 0 && z.stencil_read_base_addr == 0 && z.stencil_write_base_addr == 0 && z.htile_data_base_addr == 0 && // DB_DEPTH_SIZE_XY is independent state and may remain programmed after the attachment // formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its // presence alone must not manufacture a depth attachment. - !z.z_info.tile_surface_enable && !z.width_height_valid && !z.pitch_height_valid && + !z.z_info.htile_acceleration && !z.width_height_valid && !z.pitch_height_valid && z.size.x_max == 0 && z.size.y_max == 0 && z.pitch_div8_minus1 == 0 && z.height_div8_minus1 == 0 && z.slice_div64_minus1 == 0 && z.width == 0 && z.height == 0; if (attachment_unbound) { @@ -138,13 +141,13 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB } const bool has_stencil = z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid); - const bool has_htile = z.z_info.tile_surface_enable; + const bool has_htile = z.z_info.htile_acceleration; const auto samples = render_sample_count(z.z_info.num_samples); if (samples == 0) { DepthFatal("unsupported depth fragment count: %u", z.z_info.num_samples); } const bool htile_stencil_compat = depth_htile_stencil_acceleration_compatible( - has_stencil, has_htile, z.stencil_info.tile_stencil_disable); + has_stencil, has_htile, z.stencil_info.htile_stencil_disabled); const auto view = ResolveTargetViewInfo(z.depth_view.slice_start, z.depth_view.slice_max); switch (view.type) { case TargetViewType::Image2D: break; @@ -155,14 +158,10 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB DepthFatal("invalid depth view: base=%u last=%u", z.depth_view.slice_start, z.depth_view.slice_max); } - // Prospero defines the compression-disable bits as tile writeback policy. Vulkan attachments - // expose the same logical depth/stencil values regardless of the driver's backing compression. if ((stencil_active && !has_stencil) || rc.resummarize_enable || rc.copy_centroid || rc.copy_sample != 0 || z.z_info.expclear_enabled || z.stencil_info.expclear_enabled || - z.z_info.embedded_sample_locations || z.z_info.partially_resident || - z.stencil_info.partially_resident || z.z_info.plane_compression != 0 || - z.z_info.num_mip_levels != 0 || z.z_info.tile_mode_index != 0 || - z.z_info.zrange_precision > 1 || z.depth_view.current_mip_level != 0 || + z.z_info.partially_resident || z.stencil_info.partially_resident || + z.z_info.max_mip_level != 0 || z.depth_view.current_mip_level != 0 || z.depth_info.addr5_swizzle_mask != 0 || z.depth_info.array_mode != 0 || z.depth_info.pipe_config != 0 || z.depth_info.bank_width != 0 || z.depth_info.bank_height != 0 || z.depth_info.macro_tile_aspect != 0 || @@ -176,27 +175,16 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB DepthFatal("unsupported depth register state"); } if (has_stencil) { - // Prospero defines Hi-Stencil as HTile-backed acceleration of the logical stencil plane. - // Keep the plane native in Vulkan while tracking HTile separately. if (z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt) || - z.stencil_info.tile_mode_index != 0 || z.stencil_info.tile_split != 0 || - !htile_stencil_compat || z.stencil_info.texture_compatible_stencil || - z.stencil_read_base_addr == 0 || + !htile_stencil_compat || z.stencil_read_base_addr == 0 || z.stencil_write_base_addr != z.stencil_read_base_addr || (z.stencil_read_base_addr & 0xffffu) != 0 || z.depth_view.stencil_write_disable) { DepthFatal("unsupported stencil attachment state"); } - if (!z.stencil_info.tile_stencil_disable) { - static std::atomic_bool logged = false; - if (!logged.load(std::memory_order_relaxed) && - !logged.exchange(true, std::memory_order_relaxed)) { - LOGF("DepthTarget: compatibility: using native stencil with PS5 HTILE " - "acceleration\n"); - } - } } else if (z.stencil_read_base_addr != 0 || z.stencil_write_base_addr != 0 || - z.stencil_info.tile_mode_index != 0 || z.stencil_info.tile_split != 0 || - !htile_stencil_compat || z.stencil_info.texture_compatible_stencil) { + !htile_stencil_compat || + z.stencil_info.texture_compatibility != + Prospero::TextureCompatibleStencil::kDisable) { DepthFatal("stencil state without an active stencil attachment"); } if (has_htile) { @@ -271,16 +259,16 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB (has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) { DepthFatal("layered depth backing range is invalid"); } - r.htile = has_htile; - r.width = width; - r.height = height; - r.samples = samples; - r.depth_buffer_size = depth_backing_size; - r.depth_buffer_vaddr = z.z_read_base_addr; - r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0; - r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0; - r.htile_buffer_size = has_htile ? htile_backing_size : 0; - r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; + r.htile = has_htile; + r.width = width; + r.height = height; + r.samples = samples; + r.depth_buffer_size = depth_backing_size; + r.depth_buffer_vaddr = z.z_read_base_addr; + r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0; + r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 0; + r.htile_buffer_size = has_htile ? htile_backing_size : 0; + r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; r.depth_clear_enable = rc.depth_clear_enable; r.depth_meta_clear_enable = false; r.depth_load_clear_enable = r.depth_clear_enable; @@ -334,13 +322,13 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB r.size[1] = r.stencil_buffer_size; } TextureCache::ImageDesc desc {}; - desc.type = TextureCache::BindingType::DepthTarget; - desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size}; - desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size}; - desc.info.pixel_format = r.format; - desc.info.guest_format = guest_format; - desc.info.type = Prospero::ImageType::kColor2D; - desc.info.extent = {width, height, 1}; + desc.type = TextureCache::BindingType::DepthTarget; + desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size}; + desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size}; + desc.info.pixel_format = r.format; + desc.info.guest_format = guest_format; + desc.info.type = Prospero::ImageType::kColor2D; + desc.info.extent = {width, height, 1}; desc.info.resources = {1, view.image_layers}; desc.info.pitch = pitch; desc.info.bytes_per_block = bytes; @@ -350,20 +338,20 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB desc.info.metadata.range = {r.htile_buffer_vaddr, r.htile_buffer_size}; desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None; desc.info.metadata.stencil_compressed = - has_stencil && has_htile && !z.stencil_info.tile_stencil_disable; + has_stencil && has_htile && !z.stencil_info.htile_stencil_disabled; desc.view_info.format = r.format; desc.view_info.type = view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray; - desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format); - desc.view_info.base_level = 0; - desc.view_info.level_count = 1; - desc.view_info.base_layer = view.base_layer; - desc.view_info.layer_count = view.layer_count; - desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; - r.desc = std::move(desc); - auto& cache = m_context.GetTextureCache(); - r.image_id = cache.FindImage(r.desc); - r.image_view = nullptr; + desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format); + desc.view_info.base_level = 0; + desc.view_info.level_count = 1; + desc.view_info.base_layer = view.base_layer; + desc.view_info.layer_count = view.layer_count; + desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; + r.desc = std::move(desc); + auto& cache = m_context.GetTextureCache(); + r.image_id = cache.FindImage(r.desc); + r.image_view = nullptr; BindRenderTarget(r.image_id); } @@ -372,7 +360,7 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const { return {}; } - const auto available = ImageViewOps::DepthAspectMask(format); + const auto available = ImageViewOps::DepthAspectMask(format); vk::ImageAspectFlags writes {}; if ((available & vk::ImageAspectFlagBits::eDepth) && (depth_load_clear_enable || (depth_test_enable && depth_write_enable))) { @@ -415,9 +403,8 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const { (can_pass && depth_fail && state.depthFailOp != vk::StencilOp::eKeep); }; if (stencil_clear_enable || - (stencil_test_enable && - (face_writes(stencil_static_front, stencil_dynamic_front) || - face_writes(stencil_static_back, stencil_dynamic_back)))) { + (stencil_test_enable && (face_writes(stencil_static_front, stencil_dynamic_front) || + face_writes(stencil_static_back, stencil_dynamic_back)))) { writes |= vk::ImageAspectFlagBits::eStencil; } return writes; diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.h b/src/graphics/host_gpu/renderer/depthRenderTarget.h index c5f1ca296..4b4898d65 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.h +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.h @@ -14,12 +14,12 @@ namespace Libs::Graphics { class RenderCommandBuffer; inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile, - bool acceleration_disabled) { - return acceleration_disabled || (has_stencil && has_htile); + bool htile_stencil_disabled) { + return htile_stencil_disabled || (has_stencil && has_htile); } struct RenderDepthInfo { - TextureCache::ImageDesc desc; + TextureCache::ImageDesc desc; vk::Format format = vk::Format::eUndefined; uint32_t width = 0; uint32_t height = 0; @@ -65,11 +65,11 @@ inline bool depth_attachment_read_only(const RenderDepthInfo& depth) { } inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) { - const auto available = ImageViewOps::DepthAspectMask(depth.format); - const auto writes = depth.AttachmentWriteAspects(); - const bool has_depth = static_cast(available & vk::ImageAspectFlagBits::eDepth); - const bool has_stencil = static_cast(available & vk::ImageAspectFlagBits::eStencil); - const bool depth_write = static_cast(writes & vk::ImageAspectFlagBits::eDepth); + const auto available = ImageViewOps::DepthAspectMask(depth.format); + const auto writes = depth.AttachmentWriteAspects(); + const bool has_depth = static_cast(available & vk::ImageAspectFlagBits::eDepth); + const bool has_stencil = static_cast(available & vk::ImageAspectFlagBits::eStencil); + const bool depth_write = static_cast(writes & vk::ImageAspectFlagBits::eDepth); const bool stencil_write = static_cast(writes & vk::ImageAspectFlagBits::eStencil); if (!has_stencil) { return depth_write ? vk::ImageLayout::eDepthAttachmentOptimal diff --git a/src/graphics/host_gpu/renderer/descriptors.cpp b/src/graphics/host_gpu/renderer/descriptors.cpp index 091c2a0cb..8bb4a0cdf 100644 --- a/src/graphics/host_gpu/renderer/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/descriptors.cpp @@ -73,11 +73,12 @@ static Prospero::ImageType TextureBaseType(Prospero::ImageType type) { } } -static BufferView NativeStorageBuffer(RenderContext& context, - CommandBuffer& command_buffer, +static BufferView NativeStorageBuffer(RenderContext& context, CommandBuffer& command_buffer, const ShaderBufferResource& descriptor, - const ShaderRecompiler::IR::BufferResource& resource) { + const ShaderRecompiler::IR::BufferResource& resource, + uint32_t& buffer_offset) { BufferView result; + buffer_offset = 0; const auto address = descriptor.Base48(); const auto stride = descriptor.Stride(); @@ -93,25 +94,27 @@ static BufferView NativeStorageBuffer(RenderContext& const auto& graphics = context.GetGraphics(); const auto alignment = graphics.StorageMinAlignment(); if (alignment == 0 || - size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange || - BufferCache::CACHING_PAGE_SIZE % alignment != 0) { + size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) { EXIT("storage buffer range or device alignment is unsupported\n"); } auto binding = context.GetBufferCache().ObtainBuffer( command_buffer, address, size, resource.written, resource.read, resource.formatted); - if (binding.offset % alignment != 0) { - EXIT("storage buffer binding is not device-aligned\n"); + const auto aligned_offset = binding.offset - binding.offset % alignment; + const auto adjustment = binding.offset - aligned_offset; + const auto max_range = graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange; + if (adjustment % sizeof(uint32_t) != 0 || adjustment >= 256 || size > max_range - adjustment) { + EXIT("storage buffer offset adjustment is unsupported\n"); } + buffer_offset = static_cast(adjustment); result.owner = std::move(binding.owner); result.buffer = binding.buffer; - result.offset = binding.offset; - result.range = static_cast(size); + result.offset = aligned_offset; + result.range = static_cast(size + adjustment); return result; } static BufferView -NativeAddressBuffer(RenderContext& context, - CommandBuffer& command_buffer, +NativeAddressBuffer(RenderContext& context, CommandBuffer& command_buffer, const ShaderRecompiler::IR::AddressResource& resource, const ShaderRecompiler::IR::ResourceSnapshot::Address& address) { BufferView result; @@ -122,11 +125,11 @@ NativeAddressBuffer(RenderContext& conte if (resource.written) { EXIT("writable address resources are unsupported\n"); } - const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat - ? ShaderRecompiler::IR::FlatAddressWindowSize - : static_cast(context.GetGraphics() - .GetPhysicalDeviceProperties() - .limits.maxStorageBufferRange); + const auto limit = + resource.kind == ShaderRecompiler::IR::ResourceKind::Flat + ? ShaderRecompiler::IR::FlatAddressWindowSize + : static_cast( + context.GetGraphics().GetPhysicalDeviceProperties().limits.maxStorageBufferRange); uint64_t size = 0; const auto access = HostMemoryAccess::Mapped; if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) { @@ -291,7 +294,7 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag descriptor.BaseArray5() == 0; TileBlockLayout depth_block {}; const auto depth_bpe = Prospero::RenderTargetBytesPerElement(descriptor.Format()); - const bool supported_depth_tile = + const bool supported_depth_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) && !resource.read && !Prospero::IsFmaskTextureFormat(descriptor.Format()) && (is_2d || is_2d_array) && TileGetBlockLayout(TileBlockFamily::Depth64KB, depth_bpe, depth_block); @@ -301,9 +304,9 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag const bool supported_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kLinear) || tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || supported_depth_tile || supported_standard_tile; - const bool supported_swizzle = IsValidImageSwizzle(descriptor.DstSelXYZW()) && - (descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || - !resource.read); + const bool supported_swizzle = + IsValidImageSwizzle(descriptor.DstSelXYZW()) && + (descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || !resource.read); const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_2d; return (is_2d || is_2d_array || is_3d) && supported_tile && supported_mip_view && descriptor.BaseLevel() == descriptor.LastLevel() && @@ -321,7 +324,7 @@ static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descr (static_cast(descriptor.LastLevel()) << 16u) | (static_cast(descriptor.TileMode()) << 20u) | (static_cast(descriptor.Type()) << 28u); - const uint32_t expected_field4 = + const uint32_t expected_field4 = descriptor.Depth() | (static_cast(descriptor.BaseArray5()) << 16u); return (descriptor.fields[1] & field1_reserved_mask) == 0 && (descriptor.fields[2] & field2_reserved_mask) == 0 && @@ -354,8 +357,8 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, resource.atomic, resource.depth_compare, descriptor.BaseLevel(), descriptor.LastLevel(), descriptor.MaxMip(), descriptor.MinLod(), descriptor.BaseArray5(), descriptor.BCSwizzle(), descriptor.MsaaDepth(), Prospero::RenderTargetBytesPerElement(format), - IsValidImageSwizzle(descriptor.DstSelXYZW()), - descriptor.Base40(), size, static_cast(descriptor.Width5()) + 1u, + IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size, + static_cast(descriptor.Width5()) + 1u, static_cast(descriptor.Height5()) + 1u, static_cast(descriptor.Depth()) + 1u, descriptor.Type(), format, descriptor.TileMode(), descriptor.DstSelXYZW(), resource.read, resource.written, @@ -371,17 +374,15 @@ struct NullImageSpec { static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) { const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint || resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; - return uint_image - ? NullImageSpec {vk::Format::eR32Uint, - Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)} - : NullImageSpec {vk::Format::eR32Sfloat, - Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)}; + return uint_image ? NullImageSpec {vk::Format::eR32Uint, + Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)} + : NullImageSpec {vk::Format::eR32Sfloat, + Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)}; } -static TextureCache::ImageDesc -NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource, - TextureCache::BindingType binding) { - const auto spec = NullTextureSpec(resource); +static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource, + TextureCache::BindingType binding) { + const auto spec = NullTextureSpec(resource); TextureCache::ImageDesc desc {}; desc.info.pixel_format = spec.format; desc.info.guest_format = spec.guest_format; @@ -394,9 +395,9 @@ NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource, desc.view_info.format = desc.info.pixel_format; desc.view_info.type = vk::ImageViewType::e2D; desc.view_info.aspect = vk::ImageAspectFlagBits::eColor; - desc.view_info.usage = - binding == TextureCache::BindingType::Storage ? vk::ImageUsageFlagBits::eStorage - : vk::ImageUsageFlagBits::eSampled; + desc.view_info.usage = binding == TextureCache::BindingType::Storage + ? vk::ImageUsageFlagBits::eStorage + : vk::ImageUsageFlagBits::eSampled; desc.type = binding; return desc; } @@ -446,8 +447,7 @@ static void PopulateTextureMipLayout(ImageInfo& info) { static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource, const ShaderTextureResource& descriptor, vk::Format format, - bool storage, uint32_t view_levels, - uint32_t image_layers) { + bool storage, uint32_t view_levels, uint32_t image_layers) { ImageViewInfo view {}; view.format = format; view.aspect = vk::ImageAspectFlagBits::eColor; @@ -480,8 +480,8 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& } DescriptorCache::TextureBinding -RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource, - const ShaderRecompiler::IR::DescriptorValue& value) { +RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource, + const ShaderRecompiler::IR::DescriptorValue& value) { ShaderTextureResource descriptor; CopyNativeDescriptor(value, descriptor.fields); const bool storage = resource.written; @@ -491,9 +491,9 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour auto& texture_cache = m_context.GetTextureCache(); if (descriptor.IsNull()) { - auto desc = NullTextureDesc(resource, storage ? TextureCache::BindingType::Storage - : TextureCache::BindingType::Texture); - const auto id = texture_cache.FindImage(desc); + auto desc = NullTextureDesc(resource, storage ? TextureCache::BindingType::Storage + : TextureCache::BindingType::Texture); + const auto id = texture_cache.FindImage(desc); return {id, nullptr, std::move(desc)}; } @@ -504,12 +504,10 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour const auto last_level = descriptor.LastLevel(); const auto type = TextureType(descriptor); const bool multisampled = - type == Prospero::ImageType::kColor2DMsaa || - type == Prospero::ImageType::kColor2DMsaaArray; - const auto levels = multisampled ? 1u : static_cast(descriptor.MaxMip()) + 1u; - const auto tile = descriptor.TileMode(); - const bool msaa_tile = - tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget); + type == Prospero::ImageType::kColor2DMsaa || type == Prospero::ImageType::kColor2DMsaaArray; + const auto levels = multisampled ? 1u : static_cast(descriptor.MaxMip()) + 1u; + const auto tile = descriptor.TileMode(); + const bool msaa_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget); const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray; if ((!multisampled && (base_level > last_level || last_level >= levels)) || (multisampled && @@ -519,7 +517,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour EXIT("unsupported texture mip view: base=%u last=%u levels=%u\n", base_level, last_level, levels); } - const auto samples = multisampled ? 1u << last_level : 1u; + const auto samples = multisampled ? 1u << last_level : 1u; const auto view_levels = multisampled ? 1u : static_cast(last_level - base_level) + 1u; const auto depth = static_cast(descriptor.Depth()) + 1u; @@ -535,26 +533,25 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour static_cast(resource.kind), format, address); } - const bool volume = type == Prospero::ImageType::kColor3D; - const bool layered = type == Prospero::ImageType::kColor1DArray || - type == Prospero::ImageType::kColor2DArray || - type == Prospero::ImageType::kColor2DMsaaArray; - const auto image_layers = layered ? depth : 1u; - uint32_t pitch = 0; + const bool volume = type == Prospero::ImageType::kColor3D; + const bool layered = type == Prospero::ImageType::kColor1DArray || + type == Prospero::ImageType::kColor2DArray || + type == Prospero::ImageType::kColor2DMsaaArray; + const auto image_layers = layered ? depth : 1u; + uint32_t pitch = 0; TileSizeAlign size {}; if (multisampled) { const auto bytes = Prospero::NumBytesPerElement(format); pitch = TileGetRenderTargetPitch(width, bytes, last_level); - if (pitch == 0 || - !TileGetRenderTargetSize(width, height, pitch, bytes, size, last_level) || + if (pitch == 0 || !TileGetRenderTargetSize(width, height, pitch, bytes, size, last_level) || size.size > UINT32_MAX / image_layers) { EXIT("unsupported multisample texture layout\n"); } size.size *= image_layers; } else { pitch = TileGetTexturePitch(format, width, levels, tile); - TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, pitch, - levels, tile, volume, size); + TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, pitch, levels, + tile, volume, size); } EXIT_NOT_IMPLEMENTED(size.size == 0 || size.align == 0 || (address & (static_cast(size.align) - 1u)) != 0); @@ -564,8 +561,8 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour resource.written); } - const auto pixel_format = TextureGetFormat(format); - const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); + const auto pixel_format = TextureGetFormat(format); + const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); TextureCache::ImageDesc desc {}; desc.info.data = {address, size.size}; desc.info.pixel_format = pixel_format; @@ -585,11 +582,10 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour } desc.view_info = TextureViewInfo(resource, descriptor, pixel_format, storage, view_levels, desc.info.resources.layers); - desc.type = storage ? TextureCache::BindingType::Storage - : TextureCache::BindingType::Texture; + desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture; - auto id = texture_cache.FindImage(desc); - auto* image = &texture_cache.GetImage(id); + auto id = texture_cache.FindImage(desc); + auto* image = &texture_cache.GetImage(id); const bool stencil_association = static_cast(image->depth_id); if (stencil_association) { id = image->depth_id; @@ -610,7 +606,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour return {id, nullptr, std::move(desc)}; } -static vk::Sampler NativeSampler(RenderContext& context, +static vk::Sampler NativeSampler(RenderContext& context, const ShaderRecompiler::IR::Program& program, uint32_t index, const ShaderRecompiler::IR::DescriptorValue& value) { ShaderSamplerResource descriptor; @@ -631,8 +627,7 @@ static BufferView NativeUpload(RenderContext& context, CommandBuffer& command_bu std::span data) { EXIT_IF(data.empty()); EXIT_IF(command_buffer.IsInvalid() || command_buffer.IsExecute()); - auto binding = - context.GetBufferCache().UploadTransient(data.data(), data.size_bytes(), 256); + auto binding = context.GetBufferCache().UploadTransient(data.data(), data.size_bytes(), 256); return {.owner = std::move(binding.owner), .buffer = binding.buffer, .offset = binding.offset, @@ -660,8 +655,8 @@ void RenderExecutor::BindImage(ImageId id, bool storage) { } void RenderExecutor::BindRenderTarget(ImageId id) { - auto& image = m_context.GetTextureCache().GetImage(id); - image.binding.is_target = true; + auto& image = m_context.GetTextureCache().GetImage(id); + image.binding.is_target = true; TrackImageBinding(id); } @@ -672,9 +667,10 @@ void RenderExecutor::ResetBindings() { m_bound_images.clear(); } -DescriptorCache::PreparedBindings -RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& runtime, - vk::ShaderStageFlags shader_stage, DescriptorCache::Stage stage) { +DescriptorCache::PreparedBindings RenderExecutor::PrepareBindings(CommandBuffer& buffer, + const ShaderStageRuntime& runtime, + vk::ShaderStageFlags shader_stage, + DescriptorCache::Stage stage) { KYTY_PROFILER_FUNCTION(); EXIT_IF(!runtime); const auto& program = *runtime.program; @@ -691,12 +687,6 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& prepared.stage = stage; auto& descriptors = prepared.resources; 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(m_context, buffer, descriptor, program.info.buffers[i])); - } descriptors.images.reserve(program.info.images.size()); for (uint32_t i = 0; i < program.info.images.size(); i++) { auto binding = ResolveTexture(program.info.images[i], snapshot.images[i]); @@ -705,13 +695,7 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& } descriptors.samplers.reserve(program.info.samplers.size()); for (uint32_t i = 0; i < program.info.samplers.size(); i++) { - descriptors.samplers.push_back( - NativeSampler(m_context, program, i, snapshot.samplers[i])); - } - descriptors.addresses.reserve(program.info.addresses.size()); - for (uint32_t i = 0; i < program.info.addresses.size(); i++) { - descriptors.addresses.push_back(NativeAddressBuffer( - m_context, buffer, program.info.addresses[i], snapshot.addresses[i])); + descriptors.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i])); } if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != @@ -719,10 +703,11 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& prepared.flattened_srt.assign(snapshot.flattened_srt.begin(), snapshot.flattened_srt.end()); } - prepared.user_data.reserve(program.bindings.user_data_registers.size()); + prepared.user_data.reserve(program.bindings.ShaderDataDwords()); for (const auto reg: program.bindings.user_data_registers) { prepared.user_data.push_back(snapshot.user_data[reg - program.user_data_base]); } + prepared.user_data.resize(program.bindings.ShaderDataDwords()); if (ShaderRecompiler::IR::FindBinding( program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) { descriptors.gds.buffer = m_context.GetBufferCache().GetGdsBuffer().Handle(); @@ -730,21 +715,28 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& return prepared; } -void RenderExecutor::RebindBuffers(CommandBuffer& buffer, - DescriptorCache::PreparedBindings& prepared) { +void RenderExecutor::RebindBuffers(CommandBuffer& buffer, + DescriptorCache::PreparedBindings& prepared) { KYTY_PROFILER_FUNCTION(); EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); const auto& program = *prepared.program; const auto& snapshot = *prepared.snapshot; auto& resources = prepared.resources; + const auto& layout = program.bindings; resources.buffers.clear(); resources.buffers.reserve(program.info.buffers.size()); + EXIT_IF(prepared.user_data.size() != layout.ShaderDataDwords()); + std::fill(prepared.user_data.begin() + layout.buffer_offset_dword, prepared.user_data.end(), 0); for (uint32_t i = 0; i < program.info.buffers.size(); i++) { ShaderBufferResource descriptor; CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields); - resources.buffers.push_back( - NativeStorageBuffer(m_context, buffer, descriptor, program.info.buffers[i])); + uint32_t buffer_offset = 0; + resources.buffers.push_back(NativeStorageBuffer(m_context, buffer, descriptor, + program.info.buffers[i], buffer_offset)); + const auto dword = layout.buffer_offset_dword + i / 4u; + const auto shift = (i % 4u) * 8u; + prepared.user_data[dword] |= buffer_offset << shift; } resources.addresses.clear(); resources.addresses.reserve(program.info.addresses.size()); @@ -754,8 +746,8 @@ void RenderExecutor::RebindBuffers(CommandBuffer& buffer, } } -void RenderExecutor::RebindImages(CommandBuffer& buffer, - DescriptorCache::PreparedBindings& prepared) { +void RenderExecutor::RebindImages(CommandBuffer& buffer, + DescriptorCache::PreparedBindings& prepared) { KYTY_PROFILER_FUNCTION(); EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); const auto& program = *prepared.program; @@ -765,8 +757,7 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer, auto& texture_cache = m_context.GetTextureCache(); for (uint32_t i = 0; i < program.info.images.size(); i++) { const auto old_image = texture_cache.ResolveOwner(images[i].image_id); - if (old_image == nullptr || - (!old_image->registered && !old_image->info.data.Empty()) || + if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) || old_image->binding.needs_rebind) { if (old_image != nullptr) { old_image->binding = {}; @@ -775,10 +766,10 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer, BindImage(images[i].image_id, images[i].desc.type == TextureCache::BindingType::Storage); } - auto& binding = images[i]; - binding.image_view = texture_cache.FindTexture(binding.image_id, binding.desc); - auto& image = texture_cache.GetImage(binding.image_id); - const bool storage = binding.desc.type == TextureCache::BindingType::Storage; + auto& binding = images[i]; + binding.image_view = texture_cache.FindTexture(binding.image_id, binding.desc); + auto& image = texture_cache.GetImage(binding.image_id); + const bool storage = binding.desc.type == TextureCache::BindingType::Storage; image.usage.storage |= storage; image.usage.texture |= !storage; } @@ -786,7 +777,7 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer, RenderExecutor::GraphicsBindings RenderExecutor::PrepareGraphicsBindings(CommandBuffer& buffer, const ShaderStageRuntime& vertex, - const ShaderStageRuntime& pixel, bool pixel_active) { + const ShaderStageRuntime& pixel, bool pixel_active) { GraphicsBindings bindings { .vertex = PrepareBindings(buffer, vertex, vk::ShaderStageFlagBits::eVertex, DescriptorCache::Stage::Vertex), @@ -822,10 +813,10 @@ static void RetainBindings(CommandBuffer& buffer, } } -void RenderExecutor::CommitBindings(CommandBuffer& buffer, - vk::PipelineBindPoint pipeline_bind_point, - vk::PipelineLayout layout, - DescriptorCache::PreparedBindings& prepared) { +void RenderExecutor::CommitBindings(CommandBuffer& buffer, + vk::PipelineBindPoint pipeline_bind_point, + vk::PipelineLayout layout, + DescriptorCache::PreparedBindings& prepared) { KYTY_PROFILER_FUNCTION(); EXIT_IF(prepared.program == nullptr || prepared.stage == DescriptorCache::Stage::Unknown || prepared.committed); @@ -852,7 +843,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, } for (uint32_t i = 0; i < program.info.images.size(); i++) { - auto& image = m_context.GetTextureCache().GetImage(descriptors.images[i].image_id); + auto& image = m_context.GetTextureCache().GetImage(descriptors.images[i].image_id); auto& binding = descriptors.images[i]; const auto& view = binding.desc.view_info; const ImageSubresourceRange range {view.base_level, view.level_count, view.base_layer, @@ -860,9 +851,9 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, const bool storage = binding.desc.type == TextureCache::BindingType::Storage; if (image.info.data.Empty()) { image.Transit(vk::ImageLayout::eGeneral, - storage ? vk::AccessFlagBits2::eShaderRead | - vk::AccessFlagBits2::eShaderWrite - : vk::AccessFlagBits2::eShaderRead, + storage + ? vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eShaderWrite + : vk::AccessFlagBits2::eShaderRead, range, vk_buffer); } else if ((image.binding.force_general || image.binding.is_target) && !image.info.IsDepth()) { @@ -877,7 +868,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer, range, vk_buffer); } else { image.Transit(image.info.IsDepth() ? vk::ImageLayout::eDepthStencilReadOnlyOptimal - : vk::ImageLayout::eShaderReadOnlyOptimal, + : vk::ImageLayout::eShaderReadOnlyOptimal, vk::AccessFlagBits2::eShaderRead, range, vk_buffer); } binding.layout = image.backing.state.layout; diff --git a/src/graphics/shader/recompiler/BindingLayout.cpp b/src/graphics/shader/recompiler/BindingLayout.cpp index bef599d17..3415d6541 100644 --- a/src/graphics/shader/recompiler/BindingLayout.cpp +++ b/src/graphics/shader/recompiler/BindingLayout.cpp @@ -213,6 +213,8 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std } return false; } + next.buffer_offset_dword = static_cast(next.user_data_registers.size()); + next.buffer_offset_count = static_cast(program.info.buffers.size()); if (!program.info.buffers.empty()) { std::vector resources(program.info.buffers.size()); @@ -269,8 +271,8 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std const auto available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u; const auto push_limit = std::min(options.max_push_dwords, available_push_dwords); - if (next.user_data_registers.size() <= push_limit) { - next.push_constant_size = static_cast(next.user_data_registers.size() * 4u); + if (next.ShaderDataDwords() <= push_limit) { + next.push_constant_size = next.ShaderDataDwords() * sizeof(uint32_t); } else { AddBinding(next, DescriptorBindingKind::UserData); } diff --git a/src/graphics/shader/recompiler/ResourceMaterialization.cpp b/src/graphics/shader/recompiler/ResourceMaterialization.cpp index 1d01b482c..5546f3fd6 100644 --- a/src/graphics/shader/recompiler/ResourceMaterialization.cpp +++ b/src/graphics/shader/recompiler/ResourceMaterialization.cpp @@ -249,6 +249,12 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime, auto cursor = values.begin(); next.buffers.assign(cursor, cursor + program.info.buffers.size()); cursor += program.info.buffers.size(); + for (auto& descriptor: next.buffers) { + ShaderBufferResource buffer; + if (DecodeBufferDescriptor(descriptor, buffer) && buffer.Type() != 0) { + descriptor.dwords.fill(0); + } + } next.images.assign(cursor, cursor + program.info.images.size()); cursor += program.info.images.size(); for (auto& descriptor: next.images) { diff --git a/src/graphics/shader/recompiler/ShaderIR.h b/src/graphics/shader/recompiler/ShaderIR.h index 4b86e71f2..7124f5e08 100644 --- a/src/graphics/shader/recompiler/ShaderIR.h +++ b/src/graphics/shader/recompiler/ShaderIR.h @@ -705,9 +705,15 @@ struct BindingLayout { uint32_t descriptor_set = 0; uint32_t push_constant_offset = 0; uint32_t push_constant_size = 0; + uint32_t buffer_offset_dword = 0; + uint32_t buffer_offset_count = 0; std::vector user_data_registers; std::vector descriptors; + [[nodiscard]] uint32_t ShaderDataDwords() const { + return buffer_offset_dword + (buffer_offset_count + 3u) / 4u; + } + bool operator==(const BindingLayout& other) const = default; }; diff --git a/src/graphics/shader/recompiler/SpirvEmitter.cpp b/src/graphics/shader/recompiler/SpirvEmitter.cpp index f482dbb41..f7799ada5 100644 --- a/src/graphics/shader/recompiler/SpirvEmitter.cpp +++ b/src/graphics/shader/recompiler/SpirvEmitter.cpp @@ -238,7 +238,7 @@ bool ValidateNativeProgram(const IR::Program& program, std::string* error) { if (!program.srt.reads.empty()) { Expect(Kind::FlattenedSrt); } - if (!program.bindings.user_data_registers.empty() && program.bindings.push_constant_size == 0) { + if (program.bindings.ShaderDataDwords() != 0 && program.bindings.push_constant_size == 0) { Expect(Kind::UserData); } @@ -263,8 +263,10 @@ bool ValidateNativeProgram(const IR::Program& program, std::string* error) { } } const auto has_user_storage = present[static_cast(Kind::UserData)]; - if ((!has_user_storage && - program.bindings.push_constant_size != program.bindings.user_data_registers.size() * 4u) || + if (program.bindings.buffer_offset_dword != program.bindings.user_data_registers.size() || + program.bindings.buffer_offset_count != program.info.buffers.size() || + (!has_user_storage && + program.bindings.push_constant_size != program.bindings.ShaderDataDwords() * 4u) || (has_user_storage && program.bindings.push_constant_size != 0) || !std::is_sorted(program.bindings.user_data_registers.begin(), program.bindings.user_data_registers.end()) || @@ -408,10 +410,10 @@ bool ProgramRequiresExactSubgroupSize(const IR::Program& program) { } bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources, - const ShaderVertexInputInfo* vertex_input_info, - const ShaderPixelInputInfo* pixel_input_info, - const ShaderComputeInputInfo* compute_input_info, std::vector& spirv, - std::string* error) { + const ShaderVertexInputInfo* vertex_input_info, + const ShaderPixelInputInfo* pixel_input_info, + const ShaderComputeInputInfo* compute_input_info, std::vector& spirv, + std::string* error) { using namespace Emitter; if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex && diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp index 0c3f55c9d..10c2ddb1b 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterControlFlow.cpp @@ -134,7 +134,7 @@ bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& d return false; } -uint32_t EmitVsharpDwordLoad(EmitterState& state, uint32_t dword_index) { +uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index) { if (state.push_constant_variable != 0) { const auto pointer = state.builder.AllocateId(); const auto value = state.builder.AllocateId(); @@ -172,7 +172,7 @@ uint32_t InitialRegisterValue(const EmitterState& state, IR::Register reg) { uint32_t EmitInitialRegisterValue(EmitterState& state, IR::Register reg) { uint32_t dword_index = 0; if (UserDataDwordIndex(state, reg, dword_index)) { - return EmitVsharpDwordLoad(state, dword_index); + return EmitShaderDataDwordLoad(state, dword_index); } return ConstantU32(state, InitialRegisterValue(state, reg)); } @@ -1064,6 +1064,7 @@ void EmitFunction(EmitterState& state, const IR::Program& program) { EmitComputeInputRegisters(state); EmitPixelInputRegisters(state); EmitVertexInputRegisters(state); + EmitStorageBufferOffsets(state); if (state.dispatcher_fallback) { EmitDispatcherFunction(state, program); state.builder.AddFunction({OpFunctionEnd}); diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h index 096019f5f..23a4a587d 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterInternal.h @@ -355,6 +355,7 @@ struct EmitterState { uint32_t storage_buffer_array_type = 0; uint32_t ptr_storage_buffer_array = 0; uint32_t storage_buffer_variable = 0; + std::array storage_buffer_offsets {}; uint32_t address_memory_array_type = 0; uint32_t ptr_address_memory_array = 0; uint32_t address_memory_variable = 0; @@ -837,6 +838,8 @@ uint32_t EmitNotEqualZeroBool(EmitterState& state, uint32_t value); uint32_t EmitSelectU32Value(EmitterState& state, uint32_t condition, uint32_t true_value, uint32_t false_value); +uint32_t EmitShaderDataDwordLoad(EmitterState& state, uint32_t dword_index); + uint32_t EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src, uint32_t src_count); @@ -854,6 +857,8 @@ uint32_t EmitOptionalLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t bool IsStorageBufferMemoryKind(IR::ResourceKind kind); +void EmitStorageBufferOffsets(EmitterState& state); + uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t offset, uint32_t soffset); diff --git a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp index 4a46dd199..d7c553060 100644 --- a/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp +++ b/src/graphics/shader/recompiler/spirvEmitter/spirvEmitterMemory.cpp @@ -210,6 +210,17 @@ bool IsStorageBufferMemoryKind(IR::ResourceKind kind) { } } +void EmitStorageBufferOffsets(EmitterState& state) { + for (uint32_t i = 0; i < state.program.bindings.buffer_offset_count; i++) { + const auto word = EmitShaderDataDwordLoad( + state, state.program.bindings.buffer_offset_dword + i / 4u); + const auto shift = ConstantU32(state, (i % 4u) * 8u + 2u); + state.storage_buffer_offsets[i] = EmitBinaryU32( + state, OpBitwiseAnd, + EmitBinaryU32(state, OpShiftRightLogical, word, shift), ConstantU32(state, 0x3fu)); + } +} + uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst, uint32_t index, uint32_t offset, uint32_t soffset) { const auto& mem = inst.memory; @@ -398,6 +409,15 @@ StorageBufferBindingForMemory(EmitterState& state, const IR::MemoryInfo& mem, ui return binding; } +uint32_t EmitStorageBufferIndex(EmitterState& state, const IR::MemoryInfo& mem, uint32_t index, + uint32_t use_pc) { + if (IsFlatMemoryKind(mem.kind)) { + return index; + } + const auto binding = StorageBufferBindingForMemory(state, mem, use_pc); + return EmitAddU32(state, index, state.storage_buffer_offsets[binding.array_index]); +} + uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInfo& mem, uint32_t use_pc) { if (IsFlatMemoryKind(mem.kind)) { @@ -422,7 +442,8 @@ uint32_t EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInf } uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryInfo& mem, - uint32_t index, uint32_t use_pc) { + uint32_t index, uint32_t use_pc) { + index = EmitStorageBufferIndex(state, mem, index, use_pc); const auto object = EmitStorageBufferObjectPointer(state, mem, use_pc); const auto length = state.builder.AllocateId(); const auto in_bounds = state.builder.AllocateId(); @@ -432,7 +453,8 @@ uint32_t EmitStorageBufferElementInBounds(EmitterState& state, const IR::MemoryI } uint32_t EmitStorageBufferElementPointer(EmitterState& state, const IR::MemoryInfo& mem, - uint32_t index, uint32_t use_pc) { + uint32_t index, uint32_t use_pc) { + index = EmitStorageBufferIndex(state, mem, index, use_pc); if (IsFlatMemoryKind(mem.kind)) { if (state.address_memory_variable == 0) { ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index dc18047a7..3fe969472 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -995,6 +995,8 @@ static void ShaderAppendNativeSpecialization(std::vector& ids.push_back(program.bindings.descriptor_set); ids.push_back(program.bindings.push_constant_offset); ids.push_back(program.bindings.push_constant_size); + ids.push_back(program.bindings.buffer_offset_dword); + ids.push_back(program.bindings.buffer_offset_count); ids.push_back(static_cast(program.bindings.user_data_registers.size())); ids.insert(ids.end(), program.bindings.user_data_registers.begin(), program.bindings.user_data_registers.end()); diff --git a/tests/ResourceTrackingTests.cpp b/tests/ResourceTrackingTests.cpp index c3eb7679b..1a2da7e1f 100644 --- a/tests/ResourceTrackingTests.cpp +++ b/tests/ResourceTrackingTests.cpp @@ -1065,6 +1065,31 @@ void TestInvalidImagesMaterializeAsNull() { "invalid storage image descriptor was not normalized to null"); } +void TestInvalidBuffersMaterializeAsNull() { + Program program; + program.stage = ShaderType::Compute; + program.user_data_count = 4; + program.blocks.resize(1); + program.blocks[0].instructions = {BufferUse(0x40, 0)}; + Prepare(program); + + constexpr std::array valid = { + 0x0000100c, 0x00100000, 0x00000001, 0x0004dfac}; + auto invalid = valid; + invalid[3] |= 1u << 30u; + std::string error; + ResourceSnapshot snapshot; + Check(MaterializeResources(program, {invalid}, snapshot, &error) && + std::all_of(snapshot.buffers[0].dwords.begin(), + snapshot.buffers[0].dwords.begin() + 4, + [](uint32_t word) { return word == 0; }), + "invalid buffer descriptor was not normalized to null"); + Check(MaterializeResources(program, {valid}, snapshot, &error) && + std::equal(valid.begin(), valid.end(), + snapshot.buffers[0].dwords.begin()), + "valid buffer descriptor was normalized"); +} + void TestMaterializationFailureIsTransactional() { Program program; program.blocks.resize(1); @@ -1381,6 +1406,9 @@ void TestNativeBindingLayout() { FindBinding(program.bindings, DescriptorBindingKind::StorageUint2DArray); const auto *samplers = FindBinding(program.bindings, DescriptorBindingKind::Samplers); + const auto *shader_data = + FindBinding(program.bindings, DescriptorBindingKind::UserData); + const auto shader_data_dwords = program.bindings.ShaderDataDwords(); Check( program.bindings.descriptor_set == 3 && buffers != nullptr && sampled2d != nullptr && sampled_array != nullptr && @@ -1393,12 +1421,19 @@ void TestNativeBindingLayout() { sampled2d->resources == std::vector{0} && sampled_array->resources == std::vector{1} && storage3d->resources == std::vector{2} && - storage_uint_array->resources == std::vector{3} && - samplers->resources == std::vector{0} && - !program.bindings.user_data_registers.empty() && - program.bindings.push_constant_size != 0 && - FindBinding(program.bindings, DescriptorBindingKind::FlattenedSrt) == - nullptr && + storage_uint_array->resources == std::vector{3} && + samplers->resources == std::vector{0} && + !program.bindings.user_data_registers.empty() && + program.bindings.buffer_offset_dword == + program.bindings.user_data_registers.size() && + program.bindings.buffer_offset_count == 1 && + ((program.bindings.push_constant_size == + shader_data_dwords * sizeof(uint32_t) && + shader_data == nullptr) || + (program.bindings.push_constant_size == 0 && + shader_data != nullptr && shader_data->binding == 6)) && + FindBinding(program.bindings, DescriptorBindingKind::FlattenedSrt) == + nullptr && program.binding_layout_complete, "native binding allocator did not preserve dense typed resource groups"); } @@ -1907,6 +1942,7 @@ int main() { RUN(TestSrtPatchPlanValidation); RUN(TestMaterializationSharesReadConstEvaluation); RUN(TestInvalidImagesMaterializeAsNull); + RUN(TestInvalidBuffersMaterializeAsNull); RUN(TestMaterializationFailureIsTransactional); RUN(TestResourceSpecializationIsTypedAndTransactional); RUN(TestRuntimeSpecializationCoversBakedBufferAndAddressFields); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 644894aca..02a9f6904 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -38,6 +38,7 @@ #include "graphics/shader/recompiler/ShaderDecoder.h" #include "graphics/shader/recompiler/ShaderRecompiler.h" #include "graphics/shader/recompiler/SpirvBuilder.h" +#include "graphics/shader/recompiler/SpirvEmitter.h" #include "graphics/shader/shader.h" #include "kernel/memory.h" @@ -723,6 +724,8 @@ struct TestCase { u32 image_descriptor_swizzle = DstSel(4, 5, 6, 7); bool compile_only = false; size_t storage_buffer_range_dwords = 0; + std::vector storage_buffer_offsets; + bool force_shader_data_storage = false; std::optional flat_memory_base; std::vector gds_initial; std::vector expected_gds; @@ -849,6 +852,29 @@ CompiledShader CompileCase(const TestCase &test) { if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) { Fail(test.name, "decode/IR", error.c_str()); } + if (test.force_shader_data_storage) { + result.program.bindings = {}; + result.program.binding_layout_complete = false; + if (!ShaderRecompiler::IR::AllocateBindings( + result.program, {.max_push_dwords = 0}, &error)) { + Fail(test.name, "binding layout", error.c_str()); + } + const auto *shader_data = ShaderRecompiler::IR::FindBinding( + result.program.bindings, + ShaderRecompiler::IR::DescriptorBindingKind::UserData); + Require(test.name, "binding layout", + result.program.bindings.user_data_registers.empty() && + result.program.bindings.push_constant_size == 0 && + shader_data != nullptr, + "offset-only shader data did not use its storage fallback"); + std::vector storage_spirv; + if (!ShaderRecompiler::Spirv::EmitProgram( + result.program, result.resources, nullptr, nullptr, + options.compute_input_info, storage_spirv, &error)) { + Fail(test.name, "SPIR-V emit", error.c_str()); + } + result.spirv = std::move(storage_spirv); + } Require(test.name, "SPIR-V emit", !result.spirv.empty(), "recompiler returned empty SPIR-V"); ValidateSpirv(test.name, result.spirv); @@ -858,6 +884,16 @@ CompiledShader CompileCase(const TestCase &test) { packed_user_data.push_back( result.resources.user_data[reg - result.program.user_data_base]); } + packed_user_data.resize(result.program.bindings.ShaderDataDwords()); + for (u32 i = 0; i < result.program.bindings.buffer_offset_count; i++) { + const auto offset = i < test.storage_buffer_offsets.size() + ? test.storage_buffer_offsets[i] + : 0u; + Require(test.name, "shader data", offset % sizeof(u32) == 0 && offset < 256, + "storage buffer offset is not representable"); + packed_user_data[result.program.bindings.buffer_offset_dword + i / 4u] |= + offset << ((i % 4u) * 8u); + } return {std::move(result.spirv), std::move(result.program), std::move(result.resources.flattened_srt), std::move(packed_user_data)}; @@ -924,6 +960,7 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) { packed_user_data.push_back( result.resources.user_data[reg - result.program.user_data_base]); } + packed_user_data.resize(result.program.bindings.ShaderDataDwords()); return {std::move(result.spirv), std::move(result.program), std::move(result.resources.flattened_srt), std::move(packed_user_data)}; @@ -1785,9 +1822,8 @@ public: const auto depth_attachment = depth.FindView(depth_attachment_info); Require(name, "depth views", depth_first != nullptr && depth_again == depth_first && - depth_alias == depth_first && - depth_array != nullptr && depth_array != depth_first && - depth_attachment != nullptr && + depth_alias == depth_first && depth_array != nullptr && + depth_array != depth_first && depth_attachment != nullptr && depth_attachment != depth_array && depth.views.views.size() == 3, "unified depth view cache lost sampled/attachment identity"); @@ -2547,8 +2583,7 @@ public: auto uncompressed_block = MakeLinearDesc( base + block_alias_offset, sizeof(block_alias_data), vk::Format::eR32G32B32A32Uint, - Prospero::GpuEnumValue( - Prospero::BufferFormat::k32_32_32_32UInt), + Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32UInt), Prospero::ImageType::kColor2D, {1, 1, 1}, 1, 16, 1); const auto uncompressed_block_image = texture_cache.FindImage(uncompressed_block); @@ -2568,15 +2603,16 @@ public: std::array block_alias_after{}; std::memcpy(block_alias_after.data(), memory + block_alias_offset, sizeof(block_alias_after)); - Require(name, "compressed view expansion", - compressed_block_image && - compressed_block_image != uncompressed_block_image && - texture_cache.GetImage(compressed_block_image) - .backing.format == vk::Format::eBc3UnormBlock && - compressed_block_download && - block_alias_after == block_alias_data, - "size-compatible compressed alias did not preserve its native " - "contents"); + Require( + name, "compressed view expansion", + compressed_block_image && + compressed_block_image != uncompressed_block_image && + texture_cache.GetImage(compressed_block_image).backing.format == + vk::Format::eBc3UnormBlock && + compressed_block_download && + block_alias_after == block_alias_data, + "size-compatible compressed alias did not preserve its native " + "contents"); ImageInfo resolve_source_info{}; resolve_source_info.pixel_format = vk::Format::eR8G8B8A8Unorm; @@ -3317,8 +3353,10 @@ public: name, "unformatted buffer/image alias", unformatted_alias_buffer.buffer != nullptr && texture_cache.GetImage(unformatted_alias_image).IsGpuModified() && - !texture_cache.GetImage(unformatted_alias_image).IsBufferModified(), - "read-only unformatted buffer alias did not follow ordinary BufferCache acquisition"); + !texture_cache.GetImage(unformatted_alias_image) + .IsBufferModified(), + "read-only unformatted buffer alias did not follow ordinary " + "BufferCache acquisition"); if (unformatted_alias_buffer.owner != nullptr) { command.RetainResourceUntilFence(unformatted_alias_buffer.owner); } @@ -5243,15 +5281,23 @@ public: "ownership became visible"); constexpr uint64_t phased_depth_address = base + 0x90000; + constexpr uint64_t phased_stencil_address = base + 0xa0000; constexpr uint64_t phased_htile_address = base + 0xb0000; HW::DepthRenderTarget phased_depth_target{}; phased_depth_target.z_info.format = Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F); - phased_depth_target.z_info.tile_surface_enable = true; - phased_depth_target.z_info.zrange_precision = 1; - phased_depth_target.stencil_info.tile_stencil_disable = true; + phased_depth_target.z_info.texture_compatibility = + Prospero::TextureCompatiblePlaneCompression::kEnable; + phased_depth_target.z_info.htile_acceleration = true; + phased_depth_target.z_info.z_compare_base = Prospero::ZCompareBase::kZMax; + phased_depth_target.stencil_info.format = + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt); + phased_depth_target.stencil_info.texture_compatibility = + Prospero::TextureCompatibleStencil::kEnable; phased_depth_target.z_read_base_addr = phased_depth_address; phased_depth_target.z_write_base_addr = phased_depth_address; + phased_depth_target.stencil_read_base_addr = phased_stencil_address; + phased_depth_target.stencil_write_base_addr = phased_stencil_address; phased_depth_target.htile_data_base_addr = phased_htile_address; phased_depth_target.size.valid = true; registers.SetDepthRenderTarget(phased_depth_target); @@ -5265,16 +5311,34 @@ public: RenderDepthInfo phased_depth{}; RenderExecutorTestAccess::ResolveRenderDepthTarget( executor, 1, scheduler.Current(), phased_depth); + auto non_texture_compatible_target = phased_depth_target; + non_texture_compatible_target.z_info.texture_compatibility = + Prospero::TextureCompatiblePlaneCompression::kDisable; + non_texture_compatible_target.stencil_info.texture_compatibility = + Prospero::TextureCompatibleStencil::kDisable; + registers.SetDepthRenderTarget(non_texture_compatible_target); + RenderDepthInfo non_texture_compatible_depth{}; + RenderExecutorTestAccess::ResolveRenderDepthTarget( + executor, 1, scheduler.Current(), non_texture_compatible_depth); Require( - name, "HTile discovery purity", + name, "depth texture compatibility identity", phased_depth.image_id && phased_depth.htile && + non_texture_compatible_depth.image_id == phased_depth.image_id && + non_texture_compatible_depth.desc.info.data == + phased_depth.desc.info.data && + non_texture_compatible_depth.desc.info.stencil == + phased_depth.desc.info.stencil && + non_texture_compatible_depth.desc.info.metadata.range == + phased_depth.desc.info.metadata.range && + phased_depth.desc.info.metadata.stencil_compressed && !phased_depth.depth_clear_enable && !phased_depth.depth_meta_clear_enable && !texture_cache.IsMeta(phased_depth.htile_buffer_vaddr) && !texture_cache.GetImage(phased_depth.image_id).IsGpuModified() && !texture_cache.GetImage(phased_depth.image_id).usage.depth_target, - "depth discovery registered, consumed, or GPU-owned HTile " - "state before final acquisition"); + "valid PS5 texture-compatibility policy changed logical depth image " + "identity or discovery side effects"); + registers.SetDepthRenderTarget(phased_depth_target); RenderColorInfo no_color{}; auto phased_rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &no_color, 0, phased_depth); @@ -5340,8 +5404,8 @@ public: "replacement"); constexpr uint64_t array_target_address = base + 0xd0000; - auto array_target = - make_target_desc(array_target_address, target_mip_size, {128, 128, 1}); + auto array_target = make_target_desc(array_target_address, + target_mip_size, {128, 128, 1}); const auto array_target_id = texture_cache.FindImage(array_target); const auto array_target_owner = TextureCacheTestAccess::Owner(texture_cache, array_target_id); @@ -5353,16 +5417,14 @@ public: const auto encoded_array_address = array_target_address >> 8u; constexpr auto array_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt); - array_texture.fields[0] = - static_cast(encoded_array_address); + array_texture.fields[0] = static_cast(encoded_array_address); array_texture.fields[1] = static_cast(encoded_array_address >> 32u) | (array_format << 20u) | (3u << 30u); array_texture.fields[2] = (127u >> 2u) | (127u << 14u); array_texture.fields[3] = DstSel(4, 5, 6, 7) | (linear << 20u) | - (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) - << 28u); + (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) << 28u); array_texture.fields[4] = 1; ShaderRecompiler::IR::Program array_program{}; @@ -5388,13 +5450,11 @@ public: std::move(array_snapshot))}; auto array_binding = executor.PrepareBindings( - scheduler.Current(), array_runtime, - vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); + scheduler.Current(), array_runtime, vk::ShaderStageFlagBits::eCompute, + DescriptorCache::Stage::Compute); executor.RebindImages(scheduler.Current(), array_binding); - const auto expanded_array_id = - array_binding.resources.images[0].image_id; - const auto &expanded_array = - texture_cache.GetImage(expanded_array_id); + const auto expanded_array_id = array_binding.resources.images[0].image_id; + const auto &expanded_array = texture_cache.GetImage(expanded_array_id); Require( name, "2D target to array backing expansion", array_target_view != nullptr && array_target_owner != nullptr && @@ -5424,27 +5484,26 @@ public: auto array_rendering = RenderExecutorTestAccess::AcquireRenderTargets( executor, scheduler.Current(), &rebound_array_target, 1, no_array_depth); - Require( - name, "expanded array target rebind", - rebound_array_target.image_id == expanded_array_id && - rebound_array_target.image_view != nullptr && - array_rendering.num_color_attachments == 1 && - array_rendering.color_attachments[0].image_view == - rebound_array_target.image_view && - array_rendering.width == 128 && array_rendering.height == 128 && - array_rendering.num_layers == 1 && - texture_cache.GetImage(expanded_array_id).binding.is_bound && - texture_cache.GetImage(expanded_array_id).binding.is_target, - "the retained single-layer target did not rebind to the expanded " - "backing"); + Require(name, "expanded array target rebind", + rebound_array_target.image_id == expanded_array_id && + rebound_array_target.image_view != nullptr && + array_rendering.num_color_attachments == 1 && + array_rendering.color_attachments[0].image_view == + rebound_array_target.image_view && + array_rendering.width == 128 && + array_rendering.height == 128 && + array_rendering.num_layers == 1 && + texture_cache.GetImage(expanded_array_id).binding.is_bound && + texture_cache.GetImage(expanded_array_id).binding.is_target, + "the retained single-layer target did not rebind to the expanded " + "backing"); RenderExecutorTestAccess::ResetBindings(executor); auto colliding_msaa_texture = array_texture; colliding_msaa_texture.fields[3] = DstSel(4, 5, 6, 7) | (1u << 16u) | (Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) | - (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) - << 28u); + (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) << 28u); colliding_msaa_texture.fields[4] = 0; colliding_msaa_texture.fields[5] = (7u << 20u) | (1u << 4u); ShaderRecompiler::IR::DescriptorValue colliding_msaa_descriptor{}; @@ -5501,26 +5560,22 @@ public: auto msaa_texture = array_texture; const auto encoded_msaa_address = msaa_target_address >> 8u; - msaa_texture.fields[0] = - static_cast(encoded_msaa_address); + msaa_texture.fields[0] = static_cast(encoded_msaa_address); msaa_texture.fields[1] = static_cast(encoded_msaa_address >> 32u) | (array_format << 20u) | (3u << 30u); msaa_texture.fields[3] = DstSel(4, 5, 6, 7) | (2u << 16u) | (Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) | - (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) - << 28u); + (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) << 28u); msaa_texture.fields[4] = 0; msaa_texture.fields[5] = (7u << 20u) | (2u << 4u); ShaderRecompiler::IR::DescriptorValue msaa_descriptor{}; - std::copy(std::begin(msaa_texture.fields), - std::end(msaa_texture.fields), + std::copy(std::begin(msaa_texture.fields), std::end(msaa_texture.fields), msaa_descriptor.dwords.begin()); msaa_descriptor.dword_count = 8; - auto msaa_program = - std::make_shared( - *array_runtime.program); + auto msaa_program = std::make_shared( + *array_runtime.program); msaa_program->info.images[0].dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D; auto msaa_snapshot = @@ -5529,8 +5584,8 @@ public: ShaderStageRuntime msaa_runtime{std::move(msaa_program), std::move(msaa_snapshot)}; auto msaa_binding = executor.PrepareBindings( - scheduler.Current(), msaa_runtime, - vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); + scheduler.Current(), msaa_runtime, vk::ShaderStageFlagBits::eCompute, + DescriptorCache::Stage::Compute); executor.RebindImages(scheduler.Current(), msaa_binding); const auto &resolved_msaa = msaa_binding.resources.images[0]; Require( @@ -5538,10 +5593,8 @@ public: msaa_target_view != nullptr && resolved_msaa.image_id == msaa_target_id && resolved_msaa.image_view != nullptr && - resolved_msaa.desc.info.type == - Prospero::ImageType::kColor2D && - resolved_msaa.desc.info.resources == - ImageSubresources{1, 1} && + resolved_msaa.desc.info.type == Prospero::ImageType::kColor2D && + resolved_msaa.desc.info.resources == ImageSubresources{1, 1} && resolved_msaa.desc.info.samples == msaa_samples && resolved_msaa.desc.info.data.size == 0x40000 && resolved_msaa.desc.view_info.level_count == 1 && @@ -5562,9 +5615,8 @@ public: std::end(msaa_array_texture.fields), msaa_array_descriptor.dwords.begin()); msaa_array_descriptor.dword_count = 8; - auto msaa_array_program = - std::make_shared( - *msaa_runtime.program); + auto msaa_array_program = std::make_shared( + *msaa_runtime.program); msaa_array_program->info.images[0].dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; auto msaa_array_snapshot = @@ -5576,26 +5628,24 @@ public: scheduler.Current(), msaa_array_runtime, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); executor.RebindImages(scheduler.Current(), msaa_array_binding); - const auto &resolved_msaa_array = - msaa_array_binding.resources.images[0]; - Require( - name, "MSAA array backing expansion", - resolved_msaa_array.image_id != msaa_target_id && - resolved_msaa_array.image_view != nullptr && - resolved_msaa_array.desc.info.type == - Prospero::ImageType::kColor2D && - resolved_msaa_array.desc.info.resources == - ImageSubresources{1, 2} && - resolved_msaa_array.desc.info.samples == msaa_samples && - resolved_msaa_array.desc.info.data.size == 0x80000 && - resolved_msaa_array.desc.view_info.type == - vk::ImageViewType::e2DArray && - resolved_msaa_array.desc.view_info.layer_count == 2 && - texture_cache.GetImage(resolved_msaa_array.image_id) - .backing.layers == 2 && - texture_cache.GetImage(resolved_msaa_array.image_id) - .backing.samples == msaa_samples, - "MSAA array view did not expand the matching Color2D backing"); + const auto &resolved_msaa_array = msaa_array_binding.resources.images[0]; + Require(name, "MSAA array backing expansion", + resolved_msaa_array.image_id != msaa_target_id && + resolved_msaa_array.image_view != nullptr && + resolved_msaa_array.desc.info.type == + Prospero::ImageType::kColor2D && + resolved_msaa_array.desc.info.resources == + ImageSubresources{1, 2} && + resolved_msaa_array.desc.info.samples == msaa_samples && + resolved_msaa_array.desc.info.data.size == 0x80000 && + resolved_msaa_array.desc.view_info.type == + vk::ImageViewType::e2DArray && + resolved_msaa_array.desc.view_info.layer_count == 2 && + texture_cache.GetImage(resolved_msaa_array.image_id) + .backing.layers == 2 && + texture_cache.GetImage(resolved_msaa_array.image_id) + .backing.samples == msaa_samples, + "MSAA array view did not expand the matching Color2D backing"); RenderExecutorTestAccess::ResetBindings(executor); ImageDesc depth{}; @@ -5902,14 +5952,14 @@ public: std::move(stencil_storage_snapshot))}; auto storage_redirected = executor.PrepareBindings( scheduler.Current(), stencil_storage_runtime, - vk::ShaderStageFlagBits::eCompute, - DescriptorCache::Stage::Compute); + vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); executor.RebindImages(scheduler.Current(), storage_redirected); - Require(name, "storage stencil acquisition", - storage_redirected.resources.images[0].image_id == depth_id && - storage_redirected.resources.images[0].image_view != nullptr && - texture_cache.GetImage(depth_id).usage.storage, - "storage stencil binding did not acquire the associated depth owner"); + Require( + name, "storage stencil acquisition", + storage_redirected.resources.images[0].image_id == depth_id && + storage_redirected.resources.images[0].image_view != nullptr && + texture_cache.GetImage(depth_id).usage.storage, + "storage stencil binding did not acquire the associated depth owner"); RenderExecutorTestAccess::ResetBindings(executor); resources.UnmapMemory(base, allocation_size, GpuAccess::ReadWrite); scheduler.Finish(); @@ -6399,13 +6449,17 @@ public: const auto *buffers = Binding(Kind::Buffers); if (buffers != nullptr) { buffer_infos.resize(buffers->resources.size()); - for (auto &info : buffer_infos) { + for (u32 i = 0; i < buffer_infos.size(); i++) { + auto &info = buffer_infos[i]; info.buffer = buffer.buffer; info.offset = 0; info.range = buffer.size; if (test.storage_buffer_range_dwords != 0) { + const auto offset = i < test.storage_buffer_offsets.size() + ? test.storage_buffer_offsets[i] + : 0u; info.range = static_cast( - test.storage_buffer_range_dwords * sizeof(u32)); + test.storage_buffer_range_dwords * sizeof(u32) + offset); Require(test.name, "dispatch", info.range <= buffer.size, "storage buffer descriptor range exceeds backing buffer"); } @@ -11731,6 +11785,58 @@ TestCase BufferStoreDwordIdxenUsesDescriptorStride() { return test; } +TestCase BufferStoreDwordAppliesHostOffset() { + using O = ShaderOpcode; + + std::vector code; + AppendVMovLiteral(&code, 0, 0xabcdef01u); + code.push_back(EncodeMubuf0(0x1cu, 0, false, false)); + code.push_back(EncodeMubuf1(0, 0, 20)); + AppendEnd(&code); + + TestCase test; + test.name = "BufferStoreDwordAppliesHostOffset"; + test.code = code; + test.initial = {0x11111111u, 0x22222222u, 0x33333333u, 0}; + test.expected = {0x11111111u, 0x22222222u, 0x33333333u, 0xabcdef01u}; + test.storage_buffer_range_dwords = 1; + test.storage_buffer_offsets = {12}; + test.opcodes = {O::VMovB32, O::BufferStoreDword, O::SEndpgm}; + test.user_data = MakeStructuredStorageBufferData(4, 1); + test.has_user_data = true; + return test; +} + +TestCase BufferOffsetsUsePackedLaneAndStorageFallback() { + using O = ShaderOpcode; + + std::vector code; + for (u32 base : {0u, 4u}) { + AppendSMovLiteral(&code, base, 0x1000u + base * 0x1000u); + AppendSMovLiteral(&code, base + 1u, 4u << 16u); + AppendSMovLiteral(&code, base + 2u, 1u); + AppendSMovLiteral(&code, base + 3u, 1u << 24u); + } + AppendVMovLiteral(&code, 0, 0x12345678u); + code.push_back(EncodeMubuf0(0x1cu, 0, false, false)); + code.push_back(EncodeMubuf1(0, 0, 20)); + AppendVMovLiteral(&code, 1, 0xabcdef01u); + code.push_back(EncodeMubuf0(0x1cu, 0, false, false)); + code.push_back(EncodeMubuf1(1, 1, 20)); + AppendEnd(&code); + + TestCase test; + test.name = "BufferOffsetsUsePackedLaneAndStorageFallback"; + test.code = std::move(code); + test.initial = {0, 0, 0, 0}; + test.expected = {0x12345678u, 0, 0, 0xabcdef01u}; + test.storage_buffer_range_dwords = 1; + test.storage_buffer_offsets = {0, 12}; + test.force_shader_data_storage = true; + test.opcodes = {O::SMovB32, O::VMovB32, O::BufferStoreDword, O::SEndpgm}; + return test; +} + TestCase BufferLoadVariants() { using O = ShaderOpcode; @@ -14359,6 +14465,8 @@ std::vector MakeCases() { AddCase(BufferLoadDwordNoAddressFlagsIgnoresVaddr); AddCase(BufferLoadDwordIdxenUsesDescriptorStride); AddCase(BufferStoreDwordIdxenUsesDescriptorStride); + AddCase(BufferStoreDwordAppliesHostOffset); + AddCase(BufferOffsetsUsePackedLaneAndStorageFallback); AddCase(BufferLoadVariants); AddCase(BufferStoreVariants); AddCase(BufferFormatVariants); @@ -14730,8 +14838,7 @@ void CheckReverseRenderTargetFormatContract() { vk::Format::eR8G8B8A8Unorm, DstSel(4, 5, 6, 2)); } else if (std::strcmp(kind, "sampled-incompatible-format") == 0) { - (void)SelectSampledColorView(vk::Format::eR8Unorm, - vk::Format::eR16Unorm, + (void)SelectSampledColorView(vk::Format::eR8Unorm, vk::Format::eR16Unorm, DstSel(4, 0, 0, 1)); } else if (std::strcmp(kind, "sampled-invalid-high") == 0) { (void)SelectSampledColorView(vk::Format::eR8G8B8A8Unorm, @@ -14831,8 +14938,7 @@ void CheckSampledColorViews() { valid_swizzles += valid; } Require("SampledColorViews", "all PS5 read swizzles", - valid_swizzles == 1296 && - !IsValidImageSwizzle(DstSel(4, 5, 6, 2)) && + valid_swizzles == 1296 && !IsValidImageSwizzle(DstSel(4, 5, 6, 2)) && !IsValidImageSwizzle(DstSel(4, 5, 6, 3)) && !IsValidImageSwizzle(0x1000), "valid PS5 sampled mappings were rejected or reserved selectors were " @@ -14857,8 +14963,7 @@ void CheckSampledColorViews() { DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4), "R8 did not select its 000R component-mapped view"); Require("SampledColorViews", "mutable R8 uint/unorm 000R", - SelectSampledColorView(vk::Format::eR8Uint, - vk::Format::eR8Unorm, + SelectSampledColorView(vk::Format::eR8Uint, vk::Format::eR8Unorm, DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4), "compatible R8 integer target sampled view was rejected"); Require("SampledColorViews", "R16G16 RG01", @@ -15486,9 +15591,9 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) { ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; cube_resource.read = true; cube_resource.depth_compare = true; - const auto cube_view = ResolveTargetTextureView( - cube_resource, Prospero::ImageType::kCube, 0, - cube_image.info.resources.layers); + const auto cube_view = + ResolveTargetTextureView(cube_resource, Prospero::ImageType::kCube, 0, + cube_image.info.resources.layers); Require("SampledDepthDescriptor", "normalized depth cube", IsSupportedDepthTargetDescriptor(cube_descriptor, cube_image) && IsSupportedDepthTextureEncoding(cube_descriptor) && @@ -15741,9 +15846,9 @@ void CheckBasicStorageTextureDescriptor() { "basic 3D storage descriptor fixture is malformed"); ValidateStorageTexture(BasicStorageTextureResource(), descriptor, 0x10000); - const ShaderTextureResource extended{{ - 0x204aca00u, 0xc4700000u, 0x000fc00fu, 0xa1b00facu, - 0x0000003fu, 0x00700000u, 0x006b0000u, 0x00204b0au}}; + const ShaderTextureResource extended{{0x204aca00u, 0xc4700000u, 0x000fc00fu, + 0xa1b00facu, 0x0000003fu, 0x00700000u, + 0x006b0000u, 0x00204b0au}}; auto extended_resource = BasicStorageTextureResource(); extended_resource.read = false; Require("BasicStorageTexture", "extended descriptor", @@ -15776,18 +15881,17 @@ void CheckBasicStorageTextureDescriptor() { ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000); const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor(); - Require("BasicStorageTexture", "PPSA06228 R11G11B10 descriptor", - r11g11b10.Base40() == 0x10c6b50000ull && - r11g11b10.Width5() + 1u == 1920 && - r11g11b10.Height5() + 1u == 1080 && - r11g11b10.Depth() + 1u == 1 && - r11g11b10.Format() == - Prospero::GpuEnumValue( - Prospero::BufferFormat::k11_11_10Float) && - r11g11b10.TileMode() == - Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && - r11g11b10.DstSelXYZW() == DstSel(4, 5, 6, 1), - "PPSA06228 R11G11B10 storage descriptor fixture is malformed"); + Require( + "BasicStorageTexture", "PPSA06228 R11G11B10 descriptor", + r11g11b10.Base40() == 0x10c6b50000ull && + r11g11b10.Width5() + 1u == 1920 && r11g11b10.Height5() + 1u == 1080 && + r11g11b10.Depth() + 1u == 1 && + r11g11b10.Format() == + Prospero::GpuEnumValue(Prospero::BufferFormat::k11_11_10Float) && + r11g11b10.TileMode() == + Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && + r11g11b10.DstSelXYZW() == DstSel(4, 5, 6, 1), + "PPSA06228 R11G11B10 storage descriptor fixture is malformed"); ValidateStorageTexture(BasicBgraStorageTextureResource(), r11g11b10, 0x870000); ValidateStorageColorView(vk::Format::eB10G11R11UfloatPack32, @@ -15878,8 +15982,7 @@ void CheckBasicStorageTextureDescriptor() { if (!IsValidImageSwizzle(swizzle)) { continue; } - all_swizzles.fields[3] = - (all_swizzles.fields[3] & ~0xfffu) | swizzle; + all_swizzles.fields[3] = (all_swizzles.fields[3] & ~0xfffu) | swizzle; ValidateStorageTexture(BasicLinearStorageTextureResource(), all_swizzles, 0x800); ValidateStorageColorView(vk::Format::eR16G16B16A16Sfloat, @@ -15921,15 +16024,13 @@ void CheckBasicStorageTextureDescriptor() { ValidateStorageTexture(BasicUintArrayStorageTextureResource(), uint_array, 0x10000); - const auto standard4kb_array = - Standard4KBUintArrayStorageTextureDescriptor(); + const auto standard4kb_array = Standard4KBUintArrayStorageTextureDescriptor(); const auto standard4kb_pitch = TileGetTexturePitch( standard4kb_array.Format(), 1, 1, standard4kb_array.TileMode()); TileSizeAlign standard4kb_size{}; TileGetTextureTotalSize(standard4kb_array.Format(), 1, 1, 1, - standard4kb_pitch, 1, - standard4kb_array.TileMode(), false, - standard4kb_size); + standard4kb_pitch, 1, standard4kb_array.TileMode(), + false, standard4kb_size); Require("BasicStorageTexture", "Standard4KB uint 2D-array descriptor", standard4kb_array.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && @@ -15947,9 +16048,9 @@ void CheckBasicStorageTextureDescriptor() { auto based_standard4kb_array = standard4kb_array; based_standard4kb_array.fields[0] = 0x006c6800u; based_standard4kb_array.fields[4] = 0x00010001u; - const auto based_standard4kb_pitch = TileGetTexturePitch( - based_standard4kb_array.Format(), 1, 1, - based_standard4kb_array.TileMode()); + const auto based_standard4kb_pitch = + TileGetTexturePitch(based_standard4kb_array.Format(), 1, 1, + based_standard4kb_array.TileMode()); TileSizeAlign based_standard4kb_size{}; TileGetTextureTotalSize( based_standard4kb_array.Format(), 1, 1, @@ -15963,8 +16064,7 @@ void CheckBasicStorageTextureDescriptor() { based_standard4kb_size.align == 0x1000, "captured based Standard4KB array view is malformed"); ValidateStorageTexture(BasicUintArrayStorageTextureResource(), - based_standard4kb_array, - based_standard4kb_size.size); + based_standard4kb_array, based_standard4kb_size.size); const auto uint_volume = BasicUintVolumeStorageTextureDescriptor(); Require("BasicStorageTexture", "uint 3D descriptor", @@ -15983,9 +16083,9 @@ void CheckBasicStorageTextureDescriptor() { ValidateStorageTexture(BasicUintVolumeStorageTextureResource(), uint_volume, 0x10000); - const ShaderTextureResource tiled_uint_volume{{ - 0x1ac0e530u, 0xc0b00000u, 0x0003c003u, 0xa0500004u, - 0x0000000fu, 0x00700000u, 0x00000000u, 0x00000000u}}; + const ShaderTextureResource tiled_uint_volume{ + {0x1ac0e530u, 0xc0b00000u, 0x0003c003u, 0xa0500004u, 0x0000000fu, + 0x00700000u, 0x00000000u, 0x00000000u}}; Require("BasicStorageTexture", "tiled uint 3D descriptor", tiled_uint_volume.Width5() + 1u == 16 && tiled_uint_volume.Height5() + 1u == 16 && @@ -16028,14 +16128,14 @@ void CheckBasicStorageTextureDescriptor() { Prospero::GpuEnumValue(Prospero::TileMode::kDepth) && d16_depth_tile.DstSelXYZW() == DstSel(4, 0, 0, 1), "PPSA10112 writable D16 depth-plane descriptor fixture is malformed"); - const auto d16_pitch = TileGetTexturePitch( - d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, 1, - d16_depth_tile.TileMode()); + const auto d16_pitch = + TileGetTexturePitch(d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, + 1, d16_depth_tile.TileMode()); TileSizeAlign d16_size{}; - TileGetTextureTotalSize( - d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, - d16_depth_tile.Height5() + 1u, d16_depth_tile.Depth() + 1u, d16_pitch, 1, - d16_depth_tile.TileMode(), false, d16_size); + TileGetTextureTotalSize(d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, + d16_depth_tile.Height5() + 1u, + d16_depth_tile.Depth() + 1u, d16_pitch, 1, + d16_depth_tile.TileMode(), false, d16_size); Require("BasicStorageTexture", "PPSA10112 D16 depth-tile footprint", d16_pitch == 256 && d16_size.size == 0x20000 && d16_size.align == 0x10000, @@ -16064,8 +16164,8 @@ void CheckBasicStorageTextureDescriptor() { for (const char *kind : {"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read", "bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read", - "reserved-swizzle", "array-base-out-of-range", "array-mip-view", "reserved", - "uint-format", "uint-resource-float-format", + "reserved-swizzle", "array-base-out-of-range", "array-mip-view", + "reserved", "uint-format", "uint-resource-float-format", "depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) { std::string command = std::string("\"") + path + "\" --storage-texture-descriptor-death " + kind; @@ -16484,6 +16584,38 @@ void CheckDepthHtileStencilCompatibility() { std::printf("[host] %-32s ok\n", "DepthHtileStencilCompatibility"); } +void CheckPs5DepthRegisterDecoding() { + constexpr uint32_t captured_z = 0x22900803u; + constexpr uint32_t captured_stencil = 0x00100801u; + const auto z = HW::DepthZInfo::Decode(captured_z); + const auto stencil = HW::DepthStencilInfo::Decode(captured_stencil); + Require( + "Ps5DepthRegisterDecoding", "captured texture-compatible state", + z.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F) && + z.num_samples == 0 && z.htile_acceleration && !z.expclear_enabled && + !z.partially_resident && z.max_mip_level == 0 && + z.z_compare_base == Prospero::ZCompareBase::kZMin && + z.texture_compatibility == + Prospero::TextureCompatiblePlaneCompression::kEnable && + z.HasValidTextureCompatibility() && + stencil.format == + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt) && + !stencil.htile_stencil_disabled && !stencil.expclear_enabled && + !stencil.partially_resident && + stencil.texture_compatibility == + Prospero::TextureCompatibleStencil::kEnable && + stencil.HasValidTextureCompatibility(), + "valid PS5 depth/stencil aggregate encodings were not decoded exactly"); + + const auto malformed_z = HW::DepthZInfo::Decode(0x00000803u); + const auto malformed_stencil = HW::DepthStencilInfo::Decode(0x00100001u); + Require("Ps5DepthRegisterDecoding", "malformed aggregate state", + !malformed_z.HasValidTextureCompatibility() && + !malformed_stencil.HasValidTextureCompatibility(), + "partial texture-compatible aggregate encodings were accepted"); + std::printf("[host] %-32s ok\n", "Ps5DepthRegisterDecoding"); +} + void CheckStencilAttachmentAccess() { PipelineStencilStaticState state{vk::StencilOp::eKeep, vk::StencilOp::eKeep, vk::StencilOp::eKeep, @@ -17023,6 +17155,24 @@ void CheckPm4AcquireMemNoOp(RenderContext &renderer) { std::printf("[host] %-32s ok\n", "Pm4AcquireMemNoOp"); } +void CheckPm4StencilInfoValueLane(RenderContext &renderer) { + CommandProcessor processor(renderer); + constexpr std::array payload{0x00100801u, 0x28000000u}; + const auto consumed = + HwCtxSetStencilInfo(processor, 0xC0016900u, Pm4::DB_STENCIL_INFO, + payload.data(), 1); + const auto &stencil = processor.GetCtx().GetDepthStencilInfo(); + Require( + "Pm4StencilInfoValueLane", "standalone register value", consumed == 1 && + stencil.format == + Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt) && + stencil.texture_compatibility == + Prospero::TextureCompatibleStencil::kEnable && + !stencil.expclear_enabled && !stencil.htile_stencil_disabled, + "standalone DB_STENCIL_INFO did not decode its sole payload value"); + std::printf("[host] %-32s ok\n", "Pm4StencilInfoValueLane"); +} + void CheckPm4WaitResume(RenderContext &renderer) { GraphicsInitJmpTables(); CommandProcessor processor(renderer); @@ -17272,6 +17422,7 @@ int main(int argc, char **argv) { CheckStorageTextureVolumeMipRegions(); CheckStorageTextureGpuOwnedRebindState(); CheckNativeMsaaState(); + CheckPs5DepthRegisterDecoding(); CheckDepthHtileStencilCompatibility(); CheckStencilAttachmentAccess(); CheckDepthAttachmentWrites(); @@ -17289,6 +17440,7 @@ int main(int argc, char **argv) { CheckReferenceClockScale(); CheckVulkan13FeatureRequirements(); CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer()); + CheckPm4StencilInfoValueLane(vulkan.RuntimeRenderer()); CheckPm4WaitResume(vulkan.RuntimeRenderer()); CheckPm4CeCompletion(vulkan.RuntimeRenderer()); CheckEmbeddedFetchVertexOffset();