graphics: unify buffer bindings and depth target handling

This commit is contained in:
nmzik
2026-07-27 10:12:41 +02:00
parent f43567e12c
commit 142b3c20fa
17 changed files with 669 additions and 564 deletions
@@ -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<uint64_t>(buffer[2]) << 8u;
z.stencil_read_base_addr = static_cast<uint64_t>(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) {
+18
View File
@@ -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,
+58 -17
View File
@@ -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<Prospero::TextureCompatiblePlaneCompression>(
value & Prospero::GpuEnumValue(Prospero::TextureCompatiblePlaneCompression::kBitMask));
info.partially_resident = (value & 0x00001000u) != 0;
info.max_mip_level = static_cast<uint8_t>((value >> 16u) & 0x0fu);
info.expclear_enabled = (value & 0x08000000u) != 0;
info.htile_acceleration = (value & 0x20000000u) != 0;
info.z_compare_base = static_cast<Prospero::ZCompareBase>(
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<Prospero::TextureCompatibleStencil>(
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 {
+21 -83
View File
@@ -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<uint32_t> 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);
}
@@ -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;
@@ -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<bool>(available & vk::ImageAspectFlagBits::eDepth);
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
const bool depth_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eDepth);
const auto available = ImageViewOps::DepthAspectMask(depth.format);
const auto writes = depth.AttachmentWriteAspects();
const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth);
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
const bool depth_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eDepth);
const bool stencil_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eStencil);
if (!has_stencil) {
return depth_write ? vk::ImageLayout::eDepthAttachmentOptimal
+100 -109
View File
@@ -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<uint32_t>(adjustment);
result.owner = std::move(binding.owner);
result.buffer = binding.buffer;
result.offset = binding.offset;
result.range = static_cast<vk::DeviceSize>(size);
result.offset = aligned_offset;
result.range = static_cast<vk::DeviceSize>(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<uint64_t>(context.GetGraphics()
.GetPhysicalDeviceProperties()
.limits.maxStorageBufferRange);
const auto limit =
resource.kind == ShaderRecompiler::IR::ResourceKind::Flat
? ShaderRecompiler::IR::FlatAddressWindowSize
: static_cast<uint64_t>(
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<uint32_t>(descriptor.LastLevel()) << 16u) |
(static_cast<uint32_t>(descriptor.TileMode()) << 20u) |
(static_cast<uint32_t>(descriptor.Type()) << 28u);
const uint32_t expected_field4 =
const uint32_t expected_field4 =
descriptor.Depth() | (static_cast<uint32_t>(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<uint32_t>(descriptor.Width5()) + 1u,
IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size,
static_cast<uint32_t>(descriptor.Width5()) + 1u,
static_cast<uint32_t>(descriptor.Height5()) + 1u,
static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(last_level - base_level) + 1u;
const auto depth = static_cast<uint32_t>(descriptor.Depth()) + 1u;
@@ -535,26 +533,25 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour
static_cast<uint32_t>(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<uint64_t>(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<bool>(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<const uint32_t> 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;
@@ -213,6 +213,8 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std
}
return false;
}
next.buffer_offset_dword = static_cast<uint32_t>(next.user_data_registers.size());
next.buffer_offset_count = static_cast<uint32_t>(program.info.buffers.size());
if (!program.info.buffers.empty()) {
std::vector<uint32_t> 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<uint32_t>(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);
}
@@ -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) {
@@ -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<uint32_t> user_data_registers;
std::vector<DescriptorBinding> descriptors;
[[nodiscard]] uint32_t ShaderDataDwords() const {
return buffer_offset_dword + (buffer_offset_count + 3u) / 4u;
}
bool operator==(const BindingLayout& other) const = default;
};
@@ -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<size_t>(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<uint32_t>& spirv,
std::string* error) {
const ShaderVertexInputInfo* vertex_input_info,
const ShaderPixelInputInfo* pixel_input_info,
const ShaderComputeInputInfo* compute_input_info, std::vector<uint32_t>& spirv,
std::string* error) {
using namespace Emitter;
if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex &&
@@ -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});
@@ -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<uint32_t, IR::ShaderInfo::MaxBuffers> 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);
@@ -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,
+2
View File
@@ -995,6 +995,8 @@ static void ShaderAppendNativeSpecialization(std::vector<uint32_t>&
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<uint32_t>(program.bindings.user_data_registers.size()));
ids.insert(ids.end(), program.bindings.user_data_registers.begin(),
program.bindings.user_data_registers.end());
+42 -6
View File
@@ -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<uint32_t, 4> 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<uint32_t>{0} &&
sampled_array->resources == std::vector<uint32_t>{1} &&
storage3d->resources == std::vector<uint32_t>{2} &&
storage_uint_array->resources == std::vector<uint32_t>{3} &&
samplers->resources == std::vector<uint32_t>{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<uint32_t>{3} &&
samplers->resources == std::vector<uint32_t>{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);
+296 -144
View File
@@ -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<u32> storage_buffer_offsets;
bool force_shader_data_storage = false;
std::optional<uint64_t> flat_memory_base;
std::vector<u32> gds_initial;
std::vector<u32> 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<u32> 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<uint32_t, block_alias_data.size()> 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<uint32_t>(encoded_array_address);
array_texture.fields[0] = static_cast<uint32_t>(encoded_array_address);
array_texture.fields[1] =
static_cast<uint32_t>(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<uint32_t>(encoded_msaa_address);
msaa_texture.fields[0] = static_cast<uint32_t>(encoded_msaa_address);
msaa_texture.fields[1] =
static_cast<uint32_t>(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<ShaderRecompiler::IR::Program>(
*array_runtime.program);
auto msaa_program = std::make_shared<ShaderRecompiler::IR::Program>(
*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<ShaderRecompiler::IR::Program>(
*msaa_runtime.program);
auto msaa_array_program = std::make_shared<ShaderRecompiler::IR::Program>(
*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<vk::DeviceSize>(
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<u32> 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<u32> 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<TestCase> 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<uint32_t, 2> 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();