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; uint32_t count = 1;
if (cmd_id == 0xC0016900) { if (cmd_id == 0xC0016900) {
HW::DepthZInfo r; cp.GetCtx().SetDepthZInfo(HW::DepthZInfo::Decode(buffer[0]));
// 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);
} else if (cmd_id == 0xC0086900) { } else if (cmd_id == 0xC0086900) {
if (dw >= 22 && buffer[8] == 0xC0016900 && buffer[9] == Pm4::DB_DEPTH_INFO && if (dw >= 22 && buffer[8] == 0xC0016900 && buffer[9] == Pm4::DB_DEPTH_INFO &&
buffer[11] == 0xC0016900 && buffer[12] == Pm4::DB_DEPTH_VIEW && buffer[11] == 0xC0016900 && buffer[12] == Pm4::DB_DEPTH_VIEW &&
@@ -631,51 +608,8 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthRenderTarget) {
HW::DepthRenderTarget z; HW::DepthRenderTarget z;
// z.z_info.expclear_enabled = (buffer[0] & 0x08000000u) != 0; z.z_info = HW::DepthZInfo::Decode(buffer[0]);
// z.z_info.format = (buffer[0] >> Pm4::DB_Z_INFO_FORMAT_SHIFT) & z.stencil_info = HW::DepthStencilInfo::Decode(buffer[1]);
// 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_read_base_addr = static_cast<uint64_t>(buffer[2]) << 8u; z.z_read_base_addr = static_cast<uint64_t>(buffer[2]) << 8u;
z.stencil_read_base_addr = static_cast<uint64_t>(buffer[3]) << 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_id != 0xC0016900);
EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_INFO); EXIT_NOT_IMPLEMENTED(cmd_offset != Pm4::DB_STENCIL_INFO);
HW::DepthStencilInfo r; cp.GetCtx().SetDepthStencilInfo(HW::DepthStencilInfo::Decode(buffer[0]));
// 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);
return 1; return 1;
} }
@@ -3757,18 +3672,7 @@ void GraphicsInitJmpTablesCxIndirect() {
}; };
g_hw_ctx_indirect_func[Pm4::DB_Z_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { g_hw_ctx_indirect_func[Pm4::DB_Z_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
HW::DepthZInfo r; cp.GetCtx().SetDepthZInfo(HW::DepthZInfo::Decode(value));
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);
}; };
g_hw_ctx_indirect_func[Pm4::DB_DEPTH_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) { 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) { g_hw_ctx_indirect_func[Pm4::DB_STENCIL_INFO] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
HW::DepthStencilInfo r; cp.GetCtx().SetDepthStencilInfo(HW::DepthStencilInfo::Decode(value));
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);
}; };
g_hw_ctx_indirect_func[Pm4::DB_Z_READ_BASE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { 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, 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 { enum class TileMode : uint32_t {
kLinear = 0x00, kLinear = 0x00,
kStandard256B = 0x01, kStandard256B = 0x01,
+58 -17
View File
@@ -3,6 +3,7 @@
#include "common/abi.h" #include "common/abi.h"
#include "common/common.h" #include "common/common.h"
#include "graphics/guest_gpu/gpu_defs.h"
namespace Libs::Graphics::HW { namespace Libs::Graphics::HW {
@@ -131,26 +132,66 @@ struct RenderTarget {
}; };
struct DepthZInfo { struct DepthZInfo {
uint32_t format = 0; uint32_t format = 0;
uint32_t tile_mode_index = 0; uint32_t num_samples = 0;
uint32_t num_samples = 0; Prospero::TextureCompatiblePlaneCompression texture_compatibility =
uint32_t zrange_precision = 0; Prospero::TextureCompatiblePlaneCompression::kDisable;
bool tile_surface_enable = false; Prospero::ZCompareBase z_compare_base = Prospero::ZCompareBase::kZMin;
bool expclear_enabled = false; bool htile_acceleration = false;
bool embedded_sample_locations = false; bool expclear_enabled = false;
bool partially_resident = false; bool partially_resident = false;
uint8_t num_mip_levels = 0; uint8_t max_mip_level = 0;
uint8_t plane_compression = 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 { struct DepthStencilInfo {
uint32_t format = 0; uint32_t format = 0;
uint32_t tile_mode_index = 0; Prospero::TextureCompatibleStencil texture_compatibility =
uint32_t tile_split = 0; Prospero::TextureCompatibleStencil::kDisable;
bool expclear_enabled = false; bool expclear_enabled = false;
bool tile_stencil_disable = false; bool htile_stencil_disabled = false;
bool texture_compatible_stencil = false; bool partially_resident = 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 { 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("%s\n", func);
LOGF("\t z_info.format = 0x%08" PRIx32 "\n" 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.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.expclear_enabled = %s\n"
"\t z_info.zrange_precision = 0x%08" PRIx32 "\n" "\t z_info.z_compare_base = 0x%08" PRIx32 "\n"
"\t z_info.embedded_sample_locations = %s\n"
"\t z_info.partially_resident = %s\n" "\t z_info.partially_resident = %s\n"
"\t z_info.num_mip_levels = 0x%02" PRIx8 "\n" "\t z_info.max_mip_level = 0x%02" PRIx8 "\n"
"\t z_info.plane_compression = 0x%02" PRIx8 "\n"
"\t stencil_info.format = 0x%08" PRIx32 "\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.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 stencil_info.partially_resident = %s\n"
"\t depth_info.addr5_swizzle_mask = 0x%08" PRIx32 "\n" "\t depth_info.addr5_swizzle_mask = 0x%08" PRIx32 "\n"
"\t depth_info.array_mode = 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 height = 0x%08" PRIx32 "\n"
"\t size.x_max = 0x%04" PRIx16 "\n" "\t size.x_max = 0x%04" PRIx16 "\n"
"\t size.y_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.format, z.z_info.num_samples,
z.z_info.tile_surface_enable ? "true" : "false", Prospero::GpuEnumValue(z.z_info.texture_compatibility),
z.z_info.expclear_enabled ? "true" : "false", z.z_info.zrange_precision, z.z_info.htile_acceleration ? "true" : "false",
z.z_info.embedded_sample_locations ? "true" : "false", z.z_info.expclear_enabled ? "true" : "false",
z.z_info.partially_resident ? "true" : "false", z.z_info.num_mip_levels, Prospero::GpuEnumValue(z.z_info.z_compare_base),
z.z_info.plane_compression, z.stencil_info.format, z.z_info.partially_resident ? "true" : "false", z.z_info.max_mip_level,
z.stencil_info.tile_stencil_disable ? "true" : "false", z.stencil_info.format, Prospero::GpuEnumValue(z.stencil_info.texture_compatibility),
z.stencil_info.expclear_enabled ? "true" : "false", z.stencil_info.tile_mode_index, z.stencil_info.htile_stencil_disabled ? "true" : "false",
z.stencil_info.tile_split, z.stencil_info.texture_compatible_stencil ? "true" : "false", z.stencil_info.expclear_enabled ? "true" : "false",
z.stencil_info.partially_resident ? "true" : "false", z.depth_info.addr5_swizzle_mask, 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.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, 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) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
static void ZCheck(const HW::DepthRenderTarget& z) { 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) { if (z.z_info.format == 0) {
EXIT_NOT_IMPLEMENTED(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.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); 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.partially_resident != false);
EXIT_NOT_IMPLEMENTED(z.z_info.num_mip_levels != 0); EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 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;
}
}
} else { } else {
EXIT_NOT_IMPLEMENTED(z.z_info.format != 0x00000001 && z.z_info.format != 0x00000003); 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) { if (z.z_info.num_samples != 0x00000000) {
static bool logged = false; static bool logged = false;
if (!logged) { if (!logged) {
@@ -540,56 +517,17 @@ static void ZCheck(const HW::DepthRenderTarget& z) {
logged = true; logged = true;
} }
} }
// EXIT_NOT_IMPLEMENTED(z.z_info.tile_surface_enable != true);
EXIT_NOT_IMPLEMENTED(z.z_info.expclear_enabled != false); 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.partially_resident != false);
EXIT_NOT_IMPLEMENTED(z.z_info.num_mip_levels != 0); EXIT_NOT_IMPLEMENTED(z.z_info.max_mip_level != 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;
}
}
} }
if (z.stencil_info.format == 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.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); EXIT_NOT_IMPLEMENTED(z.stencil_info.partially_resident != false);
} else { } else {
// EXIT_NOT_IMPLEMENTED(z.stencil_info.format != 0x00000001); 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.expclear_enabled != false); 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); 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) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer, void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandBuffer& buffer,
RenderDepthInfo& r) { RenderDepthInfo& r) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
(void)submit_id; (void)submit_id;
const auto& hw = buffer.GetRegisters(); const auto& hw = buffer.GetRegisters();
@@ -102,31 +102,34 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
if (!depth_active && !stencil_active) { if (!depth_active && !stencil_active) {
return; return;
} }
if (!z.z_info.HasValidTextureCompatibility() ||
!z.stencil_info.HasValidTextureCompatibility()) {
DepthFatal("invalid PS5 depth texture-compatibility encoding");
}
const bool attachment_unbound = const bool attachment_unbound =
z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kInvalid) && z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kInvalid) &&
z.stencil_info.format == Prospero::GpuEnumValue(Prospero::StencilFormat::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.num_samples == 0 &&
z.z_info.zrange_precision <= 1 && !z.z_info.expclear_enabled && z.z_info.texture_compatibility == Prospero::TextureCompatiblePlaneCompression::kDisable &&
!z.z_info.embedded_sample_locations && !z.z_info.partially_resident && !z.z_info.expclear_enabled && !z.z_info.partially_resident && z.z_info.max_mip_level == 0 &&
z.z_info.num_mip_levels == 0 && z.z_info.plane_compression == 0 && z.stencil_info.texture_compatibility == Prospero::TextureCompatibleStencil::kDisable &&
z.stencil_info.tile_mode_index == 0 && z.stencil_info.tile_split == 0 && !z.stencil_info.expclear_enabled && !z.stencil_info.partially_resident &&
!z.stencil_info.expclear_enabled && !z.stencil_info.texture_compatible_stencil && z.depth_view.slice_start == 0 && z.depth_view.slice_max == 0 &&
!z.stencil_info.partially_resident && z.depth_view.slice_start == 0 && z.depth_view.current_mip_level == 0 && !z.depth_view.depth_write_disable &&
z.depth_view.slice_max == 0 && z.depth_view.current_mip_level == 0 && !z.depth_view.stencil_write_disable && z.depth_info.addr5_swizzle_mask == 0 &&
!z.depth_view.depth_write_disable && !z.depth_view.stencil_write_disable && z.depth_info.array_mode == 0 && z.depth_info.pipe_config == 0 &&
z.depth_info.addr5_swizzle_mask == 0 && z.depth_info.array_mode == 0 && z.depth_info.bank_width == 0 && z.depth_info.bank_height == 0 &&
z.depth_info.pipe_config == 0 && z.depth_info.bank_width == 0 && z.depth_info.macro_tile_aspect == 0 && z.depth_info.num_banks == 0 &&
z.depth_info.bank_height == 0 && z.depth_info.macro_tile_aspect == 0 && z.htile_surface.linear == 0 && z.htile_surface.full_cache == 0 &&
z.depth_info.num_banks == 0 && z.htile_surface.linear == 0 && z.htile_surface.htile_uses_preload_win == 0 && z.htile_surface.preload == 0 &&
z.htile_surface.full_cache == 0 && z.htile_surface.htile_uses_preload_win == 0 && z.htile_surface.prefetch_width == 0 && z.htile_surface.prefetch_height == 0 &&
z.htile_surface.preload == 0 && z.htile_surface.prefetch_width == 0 && z.htile_surface.dst_outside_zero_to_one == 0 && z.z_read_base_addr == 0 &&
z.htile_surface.prefetch_height == 0 && z.htile_surface.dst_outside_zero_to_one == 0 && z.z_write_base_addr == 0 && z.stencil_read_base_addr == 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 && 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 // 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 // formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its
// presence alone must not manufacture a depth attachment. // 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.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; z.height_div8_minus1 == 0 && z.slice_div64_minus1 == 0 && z.width == 0 && z.height == 0;
if (attachment_unbound) { if (attachment_unbound) {
@@ -138,13 +141,13 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB
} }
const bool has_stencil = const bool has_stencil =
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid); 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); const auto samples = render_sample_count(z.z_info.num_samples);
if (samples == 0) { if (samples == 0) {
DepthFatal("unsupported depth fragment count: %u", z.z_info.num_samples); DepthFatal("unsupported depth fragment count: %u", z.z_info.num_samples);
} }
const bool htile_stencil_compat = depth_htile_stencil_acceleration_compatible( 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); const auto view = ResolveTargetViewInfo(z.depth_view.slice_start, z.depth_view.slice_max);
switch (view.type) { switch (view.type) {
case TargetViewType::Image2D: break; 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, DepthFatal("invalid depth view: base=%u last=%u", z.depth_view.slice_start,
z.depth_view.slice_max); 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 || 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 || 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.z_info.partially_resident || z.stencil_info.partially_resident ||
z.stencil_info.partially_resident || z.z_info.plane_compression != 0 || z.z_info.max_mip_level != 0 || z.depth_view.current_mip_level != 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.depth_info.addr5_swizzle_mask != 0 || z.depth_info.array_mode != 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.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.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"); DepthFatal("unsupported depth register state");
} }
if (has_stencil) { 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) || 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_read_base_addr == 0 ||
!htile_stencil_compat || z.stencil_info.texture_compatible_stencil ||
z.stencil_read_base_addr == 0 ||
z.stencil_write_base_addr != z.stencil_read_base_addr || z.stencil_write_base_addr != z.stencil_read_base_addr ||
(z.stencil_read_base_addr & 0xffffu) != 0 || z.depth_view.stencil_write_disable) { (z.stencil_read_base_addr & 0xffffu) != 0 || z.depth_view.stencil_write_disable) {
DepthFatal("unsupported stencil attachment state"); 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 || } 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 ||
!htile_stencil_compat || z.stencil_info.texture_compatible_stencil) { z.stencil_info.texture_compatibility !=
Prospero::TextureCompatibleStencil::kDisable) {
DepthFatal("stencil state without an active stencil attachment"); DepthFatal("stencil state without an active stencil attachment");
} }
if (has_htile) { 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)) { (has_htile && htile_backing_size > TRACKER_ADDRESS_SIZE - z.htile_data_base_addr)) {
DepthFatal("layered depth backing range is invalid"); DepthFatal("layered depth backing range is invalid");
} }
r.htile = has_htile; r.htile = has_htile;
r.width = width; r.width = width;
r.height = height; r.height = height;
r.samples = samples; r.samples = samples;
r.depth_buffer_size = depth_backing_size; r.depth_buffer_size = depth_backing_size;
r.depth_buffer_vaddr = z.z_read_base_addr; r.depth_buffer_vaddr = z.z_read_base_addr;
r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0; r.stencil_buffer_size = has_stencil ? stencil_backing_size : 0;
r.stencil_buffer_vaddr = has_stencil ? z.stencil_read_base_addr : 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_size = has_htile ? htile_backing_size : 0;
r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0; r.htile_buffer_vaddr = has_htile ? z.htile_data_base_addr : 0;
r.depth_clear_enable = rc.depth_clear_enable; r.depth_clear_enable = rc.depth_clear_enable;
r.depth_meta_clear_enable = false; r.depth_meta_clear_enable = false;
r.depth_load_clear_enable = r.depth_clear_enable; 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; r.size[1] = r.stencil_buffer_size;
} }
TextureCache::ImageDesc desc {}; TextureCache::ImageDesc desc {};
desc.type = TextureCache::BindingType::DepthTarget; desc.type = TextureCache::BindingType::DepthTarget;
desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size}; desc.info.data = {r.depth_buffer_vaddr, r.depth_buffer_size};
desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size}; desc.info.stencil = {r.stencil_buffer_vaddr, r.stencil_buffer_size};
desc.info.pixel_format = r.format; desc.info.pixel_format = r.format;
desc.info.guest_format = guest_format; desc.info.guest_format = guest_format;
desc.info.type = Prospero::ImageType::kColor2D; desc.info.type = Prospero::ImageType::kColor2D;
desc.info.extent = {width, height, 1}; desc.info.extent = {width, height, 1};
desc.info.resources = {1, view.image_layers}; desc.info.resources = {1, view.image_layers};
desc.info.pitch = pitch; desc.info.pitch = pitch;
desc.info.bytes_per_block = bytes; 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.range = {r.htile_buffer_vaddr, r.htile_buffer_size};
desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None; desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None;
desc.info.metadata.stencil_compressed = 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.format = r.format;
desc.view_info.type = desc.view_info.type =
view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray; view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray;
desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format); desc.view_info.aspect = ImageViewOps::DepthAspectMask(r.format);
desc.view_info.base_level = 0; desc.view_info.base_level = 0;
desc.view_info.level_count = 1; desc.view_info.level_count = 1;
desc.view_info.base_layer = view.base_layer; desc.view_info.base_layer = view.base_layer;
desc.view_info.layer_count = view.layer_count; desc.view_info.layer_count = view.layer_count;
desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
r.desc = std::move(desc); r.desc = std::move(desc);
auto& cache = m_context.GetTextureCache(); auto& cache = m_context.GetTextureCache();
r.image_id = cache.FindImage(r.desc); r.image_id = cache.FindImage(r.desc);
r.image_view = nullptr; r.image_view = nullptr;
BindRenderTarget(r.image_id); BindRenderTarget(r.image_id);
} }
@@ -372,7 +360,7 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
return {}; return {};
} }
const auto available = ImageViewOps::DepthAspectMask(format); const auto available = ImageViewOps::DepthAspectMask(format);
vk::ImageAspectFlags writes {}; vk::ImageAspectFlags writes {};
if ((available & vk::ImageAspectFlagBits::eDepth) && if ((available & vk::ImageAspectFlagBits::eDepth) &&
(depth_load_clear_enable || (depth_test_enable && depth_write_enable))) { (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); (can_pass && depth_fail && state.depthFailOp != vk::StencilOp::eKeep);
}; };
if (stencil_clear_enable || if (stencil_clear_enable ||
(stencil_test_enable && (stencil_test_enable && (face_writes(stencil_static_front, stencil_dynamic_front) ||
(face_writes(stencil_static_front, stencil_dynamic_front) || face_writes(stencil_static_back, stencil_dynamic_back)))) {
face_writes(stencil_static_back, stencil_dynamic_back)))) {
writes |= vk::ImageAspectFlagBits::eStencil; writes |= vk::ImageAspectFlagBits::eStencil;
} }
return writes; return writes;
@@ -14,12 +14,12 @@ namespace Libs::Graphics {
class RenderCommandBuffer; class RenderCommandBuffer;
inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile, inline constexpr bool depth_htile_stencil_acceleration_compatible(bool has_stencil, bool has_htile,
bool acceleration_disabled) { bool htile_stencil_disabled) {
return acceleration_disabled || (has_stencil && has_htile); return htile_stencil_disabled || (has_stencil && has_htile);
} }
struct RenderDepthInfo { struct RenderDepthInfo {
TextureCache::ImageDesc desc; TextureCache::ImageDesc desc;
vk::Format format = vk::Format::eUndefined; vk::Format format = vk::Format::eUndefined;
uint32_t width = 0; uint32_t width = 0;
uint32_t height = 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) { inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
const auto available = ImageViewOps::DepthAspectMask(depth.format); const auto available = ImageViewOps::DepthAspectMask(depth.format);
const auto writes = depth.AttachmentWriteAspects(); const auto writes = depth.AttachmentWriteAspects();
const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth); const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth);
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil); const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
const bool depth_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eDepth); const bool depth_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eDepth);
const bool stencil_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eStencil); const bool stencil_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eStencil);
if (!has_stencil) { if (!has_stencil) {
return depth_write ? vk::ImageLayout::eDepthAttachmentOptimal 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, static BufferView NativeStorageBuffer(RenderContext& context, CommandBuffer& command_buffer,
CommandBuffer& command_buffer,
const ShaderBufferResource& descriptor, const ShaderBufferResource& descriptor,
const ShaderRecompiler::IR::BufferResource& resource) { const ShaderRecompiler::IR::BufferResource& resource,
uint32_t& buffer_offset) {
BufferView result; BufferView result;
buffer_offset = 0;
const auto address = descriptor.Base48(); const auto address = descriptor.Base48();
const auto stride = descriptor.Stride(); const auto stride = descriptor.Stride();
@@ -93,25 +94,27 @@ static BufferView NativeStorageBuffer(RenderContext&
const auto& graphics = context.GetGraphics(); const auto& graphics = context.GetGraphics();
const auto alignment = graphics.StorageMinAlignment(); const auto alignment = graphics.StorageMinAlignment();
if (alignment == 0 || if (alignment == 0 ||
size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange || size > graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange) {
BufferCache::CACHING_PAGE_SIZE % alignment != 0) {
EXIT("storage buffer range or device alignment is unsupported\n"); EXIT("storage buffer range or device alignment is unsupported\n");
} }
auto binding = context.GetBufferCache().ObtainBuffer( auto binding = context.GetBufferCache().ObtainBuffer(
command_buffer, address, size, resource.written, resource.read, resource.formatted); command_buffer, address, size, resource.written, resource.read, resource.formatted);
if (binding.offset % alignment != 0) { const auto aligned_offset = binding.offset - binding.offset % alignment;
EXIT("storage buffer binding is not device-aligned\n"); 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.owner = std::move(binding.owner);
result.buffer = binding.buffer; result.buffer = binding.buffer;
result.offset = binding.offset; result.offset = aligned_offset;
result.range = static_cast<vk::DeviceSize>(size); result.range = static_cast<vk::DeviceSize>(size + adjustment);
return result; return result;
} }
static BufferView static BufferView
NativeAddressBuffer(RenderContext& context, NativeAddressBuffer(RenderContext& context, CommandBuffer& command_buffer,
CommandBuffer& command_buffer,
const ShaderRecompiler::IR::AddressResource& resource, const ShaderRecompiler::IR::AddressResource& resource,
const ShaderRecompiler::IR::ResourceSnapshot::Address& address) { const ShaderRecompiler::IR::ResourceSnapshot::Address& address) {
BufferView result; BufferView result;
@@ -122,11 +125,11 @@ NativeAddressBuffer(RenderContext& conte
if (resource.written) { if (resource.written) {
EXIT("writable address resources are unsupported\n"); EXIT("writable address resources are unsupported\n");
} }
const auto limit = resource.kind == ShaderRecompiler::IR::ResourceKind::Flat const auto limit =
? ShaderRecompiler::IR::FlatAddressWindowSize resource.kind == ShaderRecompiler::IR::ResourceKind::Flat
: static_cast<uint64_t>(context.GetGraphics() ? ShaderRecompiler::IR::FlatAddressWindowSize
.GetPhysicalDeviceProperties() : static_cast<uint64_t>(
.limits.maxStorageBufferRange); context.GetGraphics().GetPhysicalDeviceProperties().limits.maxStorageBufferRange);
uint64_t size = 0; uint64_t size = 0;
const auto access = HostMemoryAccess::Mapped; const auto access = HostMemoryAccess::Mapped;
if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) { if (!HostMemoryQueryRange(address.binding_base, limit, access, size)) {
@@ -291,7 +294,7 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
descriptor.BaseArray5() == 0; descriptor.BaseArray5() == 0;
TileBlockLayout depth_block {}; TileBlockLayout depth_block {};
const auto depth_bpe = Prospero::RenderTargetBytesPerElement(descriptor.Format()); 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 && tile == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) && !resource.read &&
!Prospero::IsFmaskTextureFormat(descriptor.Format()) && (is_2d || is_2d_array) && !Prospero::IsFmaskTextureFormat(descriptor.Format()) && (is_2d || is_2d_array) &&
TileGetBlockLayout(TileBlockFamily::Depth64KB, depth_bpe, depth_block); 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) || const bool supported_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kLinear) ||
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) ||
supported_depth_tile || supported_standard_tile; supported_depth_tile || supported_standard_tile;
const bool supported_swizzle = IsValidImageSwizzle(descriptor.DstSelXYZW()) && const bool supported_swizzle =
(descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || IsValidImageSwizzle(descriptor.DstSelXYZW()) &&
!resource.read); (descriptor.DstSelXYZW() == DstSel(4, 5, 6, 7) || !resource.read);
const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_2d; const bool supported_mip_view = descriptor.BaseLevel() == 0 || is_2d;
return (is_2d || is_2d_array || is_3d) && supported_tile && supported_mip_view && return (is_2d || is_2d_array || is_3d) && supported_tile && supported_mip_view &&
descriptor.BaseLevel() == descriptor.LastLevel() && 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.LastLevel()) << 16u) |
(static_cast<uint32_t>(descriptor.TileMode()) << 20u) | (static_cast<uint32_t>(descriptor.TileMode()) << 20u) |
(static_cast<uint32_t>(descriptor.Type()) << 28u); (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); descriptor.Depth() | (static_cast<uint32_t>(descriptor.BaseArray5()) << 16u);
return (descriptor.fields[1] & field1_reserved_mask) == 0 && return (descriptor.fields[1] & field1_reserved_mask) == 0 &&
(descriptor.fields[2] & field2_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(), resource.atomic, resource.depth_compare, descriptor.BaseLevel(), descriptor.LastLevel(),
descriptor.MaxMip(), descriptor.MinLod(), descriptor.BaseArray5(), descriptor.BCSwizzle(), descriptor.MaxMip(), descriptor.MinLod(), descriptor.BaseArray5(), descriptor.BCSwizzle(),
descriptor.MsaaDepth(), Prospero::RenderTargetBytesPerElement(format), descriptor.MsaaDepth(), Prospero::RenderTargetBytesPerElement(format),
IsValidImageSwizzle(descriptor.DstSelXYZW()), IsValidImageSwizzle(descriptor.DstSelXYZW()), descriptor.Base40(), size,
descriptor.Base40(), size, static_cast<uint32_t>(descriptor.Width5()) + 1u, static_cast<uint32_t>(descriptor.Width5()) + 1u,
static_cast<uint32_t>(descriptor.Height5()) + 1u, static_cast<uint32_t>(descriptor.Height5()) + 1u,
static_cast<uint32_t>(descriptor.Depth()) + 1u, descriptor.Type(), format, static_cast<uint32_t>(descriptor.Depth()) + 1u, descriptor.Type(), format,
descriptor.TileMode(), descriptor.DstSelXYZW(), resource.read, resource.written, descriptor.TileMode(), descriptor.DstSelXYZW(), resource.read, resource.written,
@@ -371,17 +374,15 @@ struct NullImageSpec {
static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) { static NullImageSpec NullTextureSpec(const ShaderRecompiler::IR::ImageResource& resource) {
const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint || const bool uint_image = resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint ||
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
return uint_image return uint_image ? NullImageSpec {vk::Format::eR32Uint,
? NullImageSpec {vk::Format::eR32Uint, Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)}
Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt)} : NullImageSpec {vk::Format::eR32Sfloat,
: NullImageSpec {vk::Format::eR32Sfloat, Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)};
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float)};
} }
static TextureCache::ImageDesc static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource,
NullTextureDesc(const ShaderRecompiler::IR::ImageResource& resource, TextureCache::BindingType binding) {
TextureCache::BindingType binding) { const auto spec = NullTextureSpec(resource);
const auto spec = NullTextureSpec(resource);
TextureCache::ImageDesc desc {}; TextureCache::ImageDesc desc {};
desc.info.pixel_format = spec.format; desc.info.pixel_format = spec.format;
desc.info.guest_format = spec.guest_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.format = desc.info.pixel_format;
desc.view_info.type = vk::ImageViewType::e2D; desc.view_info.type = vk::ImageViewType::e2D;
desc.view_info.aspect = vk::ImageAspectFlagBits::eColor; desc.view_info.aspect = vk::ImageAspectFlagBits::eColor;
desc.view_info.usage = desc.view_info.usage = binding == TextureCache::BindingType::Storage
binding == TextureCache::BindingType::Storage ? vk::ImageUsageFlagBits::eStorage ? vk::ImageUsageFlagBits::eStorage
: vk::ImageUsageFlagBits::eSampled; : vk::ImageUsageFlagBits::eSampled;
desc.type = binding; desc.type = binding;
return desc; return desc;
} }
@@ -446,8 +447,7 @@ static void PopulateTextureMipLayout(ImageInfo& info) {
static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource, static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor, vk::Format format, const ShaderTextureResource& descriptor, vk::Format format,
bool storage, uint32_t view_levels, bool storage, uint32_t view_levels, uint32_t image_layers) {
uint32_t image_layers) {
ImageViewInfo view {}; ImageViewInfo view {};
view.format = format; view.format = format;
view.aspect = vk::ImageAspectFlagBits::eColor; view.aspect = vk::ImageAspectFlagBits::eColor;
@@ -480,8 +480,8 @@ static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource&
} }
DescriptorCache::TextureBinding DescriptorCache::TextureBinding
RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource, RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderRecompiler::IR::DescriptorValue& value) { const ShaderRecompiler::IR::DescriptorValue& value) {
ShaderTextureResource descriptor; ShaderTextureResource descriptor;
CopyNativeDescriptor(value, descriptor.fields); CopyNativeDescriptor(value, descriptor.fields);
const bool storage = resource.written; const bool storage = resource.written;
@@ -491,9 +491,9 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour
auto& texture_cache = m_context.GetTextureCache(); auto& texture_cache = m_context.GetTextureCache();
if (descriptor.IsNull()) { if (descriptor.IsNull()) {
auto desc = NullTextureDesc(resource, storage ? TextureCache::BindingType::Storage auto desc = NullTextureDesc(resource, storage ? TextureCache::BindingType::Storage
: TextureCache::BindingType::Texture); : TextureCache::BindingType::Texture);
const auto id = texture_cache.FindImage(desc); const auto id = texture_cache.FindImage(desc);
return {id, nullptr, std::move(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 last_level = descriptor.LastLevel();
const auto type = TextureType(descriptor); const auto type = TextureType(descriptor);
const bool multisampled = const bool multisampled =
type == Prospero::ImageType::kColor2DMsaa || type == Prospero::ImageType::kColor2DMsaa || type == Prospero::ImageType::kColor2DMsaaArray;
type == Prospero::ImageType::kColor2DMsaaArray; const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u;
const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u; const auto tile = descriptor.TileMode();
const auto tile = descriptor.TileMode(); const bool msaa_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
const bool msaa_tile =
tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget);
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray; const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray;
if ((!multisampled && (base_level > last_level || last_level >= levels)) || if ((!multisampled && (base_level > last_level || last_level >= levels)) ||
(multisampled && (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, EXIT("unsupported texture mip view: base=%u last=%u levels=%u\n", base_level, last_level,
levels); levels);
} }
const auto samples = multisampled ? 1u << last_level : 1u; const auto samples = multisampled ? 1u << last_level : 1u;
const auto view_levels = const auto view_levels =
multisampled ? 1u : static_cast<uint32_t>(last_level - base_level) + 1u; multisampled ? 1u : static_cast<uint32_t>(last_level - base_level) + 1u;
const auto depth = static_cast<uint32_t>(descriptor.Depth()) + 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); static_cast<uint32_t>(resource.kind), format, address);
} }
const bool volume = type == Prospero::ImageType::kColor3D; const bool volume = type == Prospero::ImageType::kColor3D;
const bool layered = type == Prospero::ImageType::kColor1DArray || const bool layered = type == Prospero::ImageType::kColor1DArray ||
type == Prospero::ImageType::kColor2DArray || type == Prospero::ImageType::kColor2DArray ||
type == Prospero::ImageType::kColor2DMsaaArray; type == Prospero::ImageType::kColor2DMsaaArray;
const auto image_layers = layered ? depth : 1u; const auto image_layers = layered ? depth : 1u;
uint32_t pitch = 0; uint32_t pitch = 0;
TileSizeAlign size {}; TileSizeAlign size {};
if (multisampled) { if (multisampled) {
const auto bytes = Prospero::NumBytesPerElement(format); const auto bytes = Prospero::NumBytesPerElement(format);
pitch = TileGetRenderTargetPitch(width, bytes, last_level); pitch = TileGetRenderTargetPitch(width, bytes, last_level);
if (pitch == 0 || if (pitch == 0 || !TileGetRenderTargetSize(width, height, pitch, bytes, size, last_level) ||
!TileGetRenderTargetSize(width, height, pitch, bytes, size, last_level) ||
size.size > UINT32_MAX / image_layers) { size.size > UINT32_MAX / image_layers) {
EXIT("unsupported multisample texture layout\n"); EXIT("unsupported multisample texture layout\n");
} }
size.size *= image_layers; size.size *= image_layers;
} else { } else {
pitch = TileGetTexturePitch(format, width, levels, tile); pitch = TileGetTexturePitch(format, width, levels, tile);
TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, pitch, TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, pitch, levels,
levels, tile, volume, size); tile, volume, size);
} }
EXIT_NOT_IMPLEMENTED(size.size == 0 || size.align == 0 || EXIT_NOT_IMPLEMENTED(size.size == 0 || size.align == 0 ||
(address & (static_cast<uint64_t>(size.align) - 1u)) != 0); (address & (static_cast<uint64_t>(size.align) - 1u)) != 0);
@@ -564,8 +561,8 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour
resource.written); resource.written);
} }
const auto pixel_format = TextureGetFormat(format); const auto pixel_format = TextureGetFormat(format);
const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format); const auto block_bytes = Prospero::BlockCompressedBytesPerBlock(format);
TextureCache::ImageDesc desc {}; TextureCache::ImageDesc desc {};
desc.info.data = {address, size.size}; desc.info.data = {address, size.size};
desc.info.pixel_format = pixel_format; 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.view_info = TextureViewInfo(resource, descriptor, pixel_format, storage, view_levels,
desc.info.resources.layers); desc.info.resources.layers);
desc.type = storage ? TextureCache::BindingType::Storage desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture;
: TextureCache::BindingType::Texture;
auto id = texture_cache.FindImage(desc); auto id = texture_cache.FindImage(desc);
auto* image = &texture_cache.GetImage(id); auto* image = &texture_cache.GetImage(id);
const bool stencil_association = static_cast<bool>(image->depth_id); const bool stencil_association = static_cast<bool>(image->depth_id);
if (stencil_association) { if (stencil_association) {
id = image->depth_id; id = image->depth_id;
@@ -610,7 +606,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& resour
return {id, nullptr, std::move(desc)}; 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::Program& program, uint32_t index,
const ShaderRecompiler::IR::DescriptorValue& value) { const ShaderRecompiler::IR::DescriptorValue& value) {
ShaderSamplerResource descriptor; ShaderSamplerResource descriptor;
@@ -631,8 +627,7 @@ static BufferView NativeUpload(RenderContext& context, CommandBuffer& command_bu
std::span<const uint32_t> data) { std::span<const uint32_t> data) {
EXIT_IF(data.empty()); EXIT_IF(data.empty());
EXIT_IF(command_buffer.IsInvalid() || command_buffer.IsExecute()); EXIT_IF(command_buffer.IsInvalid() || command_buffer.IsExecute());
auto binding = auto binding = context.GetBufferCache().UploadTransient(data.data(), data.size_bytes(), 256);
context.GetBufferCache().UploadTransient(data.data(), data.size_bytes(), 256);
return {.owner = std::move(binding.owner), return {.owner = std::move(binding.owner),
.buffer = binding.buffer, .buffer = binding.buffer,
.offset = binding.offset, .offset = binding.offset,
@@ -660,8 +655,8 @@ void RenderExecutor::BindImage(ImageId id, bool storage) {
} }
void RenderExecutor::BindRenderTarget(ImageId id) { void RenderExecutor::BindRenderTarget(ImageId id) {
auto& image = m_context.GetTextureCache().GetImage(id); auto& image = m_context.GetTextureCache().GetImage(id);
image.binding.is_target = true; image.binding.is_target = true;
TrackImageBinding(id); TrackImageBinding(id);
} }
@@ -672,9 +667,10 @@ void RenderExecutor::ResetBindings() {
m_bound_images.clear(); m_bound_images.clear();
} }
DescriptorCache::PreparedBindings DescriptorCache::PreparedBindings RenderExecutor::PrepareBindings(CommandBuffer& buffer,
RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime& runtime, const ShaderStageRuntime& runtime,
vk::ShaderStageFlags shader_stage, DescriptorCache::Stage stage) { vk::ShaderStageFlags shader_stage,
DescriptorCache::Stage stage) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(!runtime); EXIT_IF(!runtime);
const auto& program = *runtime.program; const auto& program = *runtime.program;
@@ -691,12 +687,6 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime&
prepared.stage = stage; prepared.stage = stage;
auto& descriptors = prepared.resources; auto& descriptors = prepared.resources;
descriptors.buffers.reserve(program.info.buffers.size()); descriptors.buffers.reserve(program.info.buffers.size());
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
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()); descriptors.images.reserve(program.info.images.size());
for (uint32_t i = 0; i < program.info.images.size(); i++) { for (uint32_t i = 0; i < program.info.images.size(); i++) {
auto binding = ResolveTexture(program.info.images[i], snapshot.images[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()); descriptors.samplers.reserve(program.info.samplers.size());
for (uint32_t i = 0; i < program.info.samplers.size(); i++) { for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
descriptors.samplers.push_back( descriptors.samplers.push_back(NativeSampler(m_context, program, i, snapshot.samplers[i]));
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]));
} }
if (ShaderRecompiler::IR::FindBinding( if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::FlattenedSrt) != 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.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) { 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.push_back(snapshot.user_data[reg - program.user_data_base]);
} }
prepared.user_data.resize(program.bindings.ShaderDataDwords());
if (ShaderRecompiler::IR::FindBinding( if (ShaderRecompiler::IR::FindBinding(
program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) { program.bindings, ShaderRecompiler::IR::DescriptorBindingKind::Gds) != nullptr) {
descriptors.gds.buffer = m_context.GetBufferCache().GetGdsBuffer().Handle(); descriptors.gds.buffer = m_context.GetBufferCache().GetGdsBuffer().Handle();
@@ -730,21 +715,28 @@ RenderExecutor::PrepareBindings(CommandBuffer& buffer, const ShaderStageRuntime&
return prepared; return prepared;
} }
void RenderExecutor::RebindBuffers(CommandBuffer& buffer, void RenderExecutor::RebindBuffers(CommandBuffer& buffer,
DescriptorCache::PreparedBindings& prepared) { DescriptorCache::PreparedBindings& prepared) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr);
const auto& program = *prepared.program; const auto& program = *prepared.program;
const auto& snapshot = *prepared.snapshot; const auto& snapshot = *prepared.snapshot;
auto& resources = prepared.resources; auto& resources = prepared.resources;
const auto& layout = program.bindings;
resources.buffers.clear(); resources.buffers.clear();
resources.buffers.reserve(program.info.buffers.size()); 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++) { for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
ShaderBufferResource descriptor; ShaderBufferResource descriptor;
CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields); CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields);
resources.buffers.push_back( uint32_t buffer_offset = 0;
NativeStorageBuffer(m_context, buffer, descriptor, program.info.buffers[i])); 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.clear();
resources.addresses.reserve(program.info.addresses.size()); resources.addresses.reserve(program.info.addresses.size());
@@ -754,8 +746,8 @@ void RenderExecutor::RebindBuffers(CommandBuffer& buffer,
} }
} }
void RenderExecutor::RebindImages(CommandBuffer& buffer, void RenderExecutor::RebindImages(CommandBuffer& buffer,
DescriptorCache::PreparedBindings& prepared) { DescriptorCache::PreparedBindings& prepared) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr); EXIT_IF(prepared.program == nullptr || prepared.snapshot == nullptr);
const auto& program = *prepared.program; const auto& program = *prepared.program;
@@ -765,8 +757,7 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer,
auto& texture_cache = m_context.GetTextureCache(); auto& texture_cache = m_context.GetTextureCache();
for (uint32_t i = 0; i < program.info.images.size(); i++) { for (uint32_t i = 0; i < program.info.images.size(); i++) {
const auto old_image = texture_cache.ResolveOwner(images[i].image_id); const auto old_image = texture_cache.ResolveOwner(images[i].image_id);
if (old_image == nullptr || if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
(!old_image->registered && !old_image->info.data.Empty()) ||
old_image->binding.needs_rebind) { old_image->binding.needs_rebind) {
if (old_image != nullptr) { if (old_image != nullptr) {
old_image->binding = {}; old_image->binding = {};
@@ -775,10 +766,10 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer,
BindImage(images[i].image_id, BindImage(images[i].image_id,
images[i].desc.type == TextureCache::BindingType::Storage); images[i].desc.type == TextureCache::BindingType::Storage);
} }
auto& binding = images[i]; auto& binding = images[i];
binding.image_view = texture_cache.FindTexture(binding.image_id, binding.desc); binding.image_view = texture_cache.FindTexture(binding.image_id, binding.desc);
auto& image = texture_cache.GetImage(binding.image_id); auto& image = texture_cache.GetImage(binding.image_id);
const bool storage = binding.desc.type == TextureCache::BindingType::Storage; const bool storage = binding.desc.type == TextureCache::BindingType::Storage;
image.usage.storage |= storage; image.usage.storage |= storage;
image.usage.texture |= !storage; image.usage.texture |= !storage;
} }
@@ -786,7 +777,7 @@ void RenderExecutor::RebindImages(CommandBuffer& buffer,
RenderExecutor::GraphicsBindings RenderExecutor::GraphicsBindings
RenderExecutor::PrepareGraphicsBindings(CommandBuffer& buffer, const ShaderStageRuntime& vertex, RenderExecutor::PrepareGraphicsBindings(CommandBuffer& buffer, const ShaderStageRuntime& vertex,
const ShaderStageRuntime& pixel, bool pixel_active) { const ShaderStageRuntime& pixel, bool pixel_active) {
GraphicsBindings bindings { GraphicsBindings bindings {
.vertex = PrepareBindings(buffer, vertex, vk::ShaderStageFlagBits::eVertex, .vertex = PrepareBindings(buffer, vertex, vk::ShaderStageFlagBits::eVertex,
DescriptorCache::Stage::Vertex), DescriptorCache::Stage::Vertex),
@@ -822,10 +813,10 @@ static void RetainBindings(CommandBuffer& buffer,
} }
} }
void RenderExecutor::CommitBindings(CommandBuffer& buffer, void RenderExecutor::CommitBindings(CommandBuffer& buffer,
vk::PipelineBindPoint pipeline_bind_point, vk::PipelineBindPoint pipeline_bind_point,
vk::PipelineLayout layout, vk::PipelineLayout layout,
DescriptorCache::PreparedBindings& prepared) { DescriptorCache::PreparedBindings& prepared) {
KYTY_PROFILER_FUNCTION(); KYTY_PROFILER_FUNCTION();
EXIT_IF(prepared.program == nullptr || prepared.stage == DescriptorCache::Stage::Unknown || EXIT_IF(prepared.program == nullptr || prepared.stage == DescriptorCache::Stage::Unknown ||
prepared.committed); prepared.committed);
@@ -852,7 +843,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
} }
for (uint32_t i = 0; i < program.info.images.size(); i++) { 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]; auto& binding = descriptors.images[i];
const auto& view = binding.desc.view_info; const auto& view = binding.desc.view_info;
const ImageSubresourceRange range {view.base_level, view.level_count, view.base_layer, 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; const bool storage = binding.desc.type == TextureCache::BindingType::Storage;
if (image.info.data.Empty()) { if (image.info.data.Empty()) {
image.Transit(vk::ImageLayout::eGeneral, image.Transit(vk::ImageLayout::eGeneral,
storage ? vk::AccessFlagBits2::eShaderRead | storage
vk::AccessFlagBits2::eShaderWrite ? vk::AccessFlagBits2::eShaderRead | vk::AccessFlagBits2::eShaderWrite
: vk::AccessFlagBits2::eShaderRead, : vk::AccessFlagBits2::eShaderRead,
range, vk_buffer); range, vk_buffer);
} else if ((image.binding.force_general || image.binding.is_target) && } else if ((image.binding.force_general || image.binding.is_target) &&
!image.info.IsDepth()) { !image.info.IsDepth()) {
@@ -877,7 +868,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
range, vk_buffer); range, vk_buffer);
} else { } else {
image.Transit(image.info.IsDepth() ? vk::ImageLayout::eDepthStencilReadOnlyOptimal image.Transit(image.info.IsDepth() ? vk::ImageLayout::eDepthStencilReadOnlyOptimal
: vk::ImageLayout::eShaderReadOnlyOptimal, : vk::ImageLayout::eShaderReadOnlyOptimal,
vk::AccessFlagBits2::eShaderRead, range, vk_buffer); vk::AccessFlagBits2::eShaderRead, range, vk_buffer);
} }
binding.layout = image.backing.state.layout; binding.layout = image.backing.state.layout;
@@ -213,6 +213,8 @@ bool AllocateBindings(Program& program, const BindingLayoutOptions& options, std
} }
return false; 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()) { if (!program.info.buffers.empty()) {
std::vector<uint32_t> resources(program.info.buffers.size()); 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 available_push_dwords = (MaxPushConstantBytes - options.push_constant_offset) / 4u;
const auto push_limit = std::min(options.max_push_dwords, available_push_dwords); const auto push_limit = std::min(options.max_push_dwords, available_push_dwords);
if (next.user_data_registers.size() <= push_limit) { if (next.ShaderDataDwords() <= push_limit) {
next.push_constant_size = static_cast<uint32_t>(next.user_data_registers.size() * 4u); next.push_constant_size = next.ShaderDataDwords() * sizeof(uint32_t);
} else { } else {
AddBinding(next, DescriptorBindingKind::UserData); AddBinding(next, DescriptorBindingKind::UserData);
} }
@@ -249,6 +249,12 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
auto cursor = values.begin(); auto cursor = values.begin();
next.buffers.assign(cursor, cursor + program.info.buffers.size()); next.buffers.assign(cursor, cursor + program.info.buffers.size());
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()); next.images.assign(cursor, cursor + program.info.images.size());
cursor += program.info.images.size(); cursor += program.info.images.size();
for (auto& descriptor: next.images) { for (auto& descriptor: next.images) {
@@ -705,9 +705,15 @@ struct BindingLayout {
uint32_t descriptor_set = 0; uint32_t descriptor_set = 0;
uint32_t push_constant_offset = 0; uint32_t push_constant_offset = 0;
uint32_t push_constant_size = 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<uint32_t> user_data_registers;
std::vector<DescriptorBinding> descriptors; 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; 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()) { if (!program.srt.reads.empty()) {
Expect(Kind::FlattenedSrt); 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); 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)]; const auto has_user_storage = present[static_cast<size_t>(Kind::UserData)];
if ((!has_user_storage && if (program.bindings.buffer_offset_dword != program.bindings.user_data_registers.size() ||
program.bindings.push_constant_size != program.bindings.user_data_registers.size() * 4u) || 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) || (has_user_storage && program.bindings.push_constant_size != 0) ||
!std::is_sorted(program.bindings.user_data_registers.begin(), !std::is_sorted(program.bindings.user_data_registers.begin(),
program.bindings.user_data_registers.end()) || 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, bool EmitProgram(const IR::Program& program, const IR::ResourceSnapshot& resources,
const ShaderVertexInputInfo* vertex_input_info, const ShaderVertexInputInfo* vertex_input_info,
const ShaderPixelInputInfo* pixel_input_info, const ShaderPixelInputInfo* pixel_input_info,
const ShaderComputeInputInfo* compute_input_info, std::vector<uint32_t>& spirv, const ShaderComputeInputInfo* compute_input_info, std::vector<uint32_t>& spirv,
std::string* error) { std::string* error) {
using namespace Emitter; using namespace Emitter;
if (program.stage != ShaderType::Compute && program.stage != ShaderType::Vertex && 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; 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) { if (state.push_constant_variable != 0) {
const auto pointer = state.builder.AllocateId(); const auto pointer = state.builder.AllocateId();
const auto value = 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 EmitInitialRegisterValue(EmitterState& state, IR::Register reg) {
uint32_t dword_index = 0; uint32_t dword_index = 0;
if (UserDataDwordIndex(state, reg, dword_index)) { if (UserDataDwordIndex(state, reg, dword_index)) {
return EmitVsharpDwordLoad(state, dword_index); return EmitShaderDataDwordLoad(state, dword_index);
} }
return ConstantU32(state, InitialRegisterValue(state, reg)); return ConstantU32(state, InitialRegisterValue(state, reg));
} }
@@ -1064,6 +1064,7 @@ void EmitFunction(EmitterState& state, const IR::Program& program) {
EmitComputeInputRegisters(state); EmitComputeInputRegisters(state);
EmitPixelInputRegisters(state); EmitPixelInputRegisters(state);
EmitVertexInputRegisters(state); EmitVertexInputRegisters(state);
EmitStorageBufferOffsets(state);
if (state.dispatcher_fallback) { if (state.dispatcher_fallback) {
EmitDispatcherFunction(state, program); EmitDispatcherFunction(state, program);
state.builder.AddFunction({OpFunctionEnd}); state.builder.AddFunction({OpFunctionEnd});
@@ -355,6 +355,7 @@ struct EmitterState {
uint32_t storage_buffer_array_type = 0; uint32_t storage_buffer_array_type = 0;
uint32_t ptr_storage_buffer_array = 0; uint32_t ptr_storage_buffer_array = 0;
uint32_t storage_buffer_variable = 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 address_memory_array_type = 0;
uint32_t ptr_address_memory_array = 0; uint32_t ptr_address_memory_array = 0;
uint32_t address_memory_variable = 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 EmitSelectU32Value(EmitterState& state, uint32_t condition, uint32_t true_value,
uint32_t false_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 EmitByteAddress(EmitterState& state, const IR::Instruction& inst, uint32_t first_src,
uint32_t src_count); uint32_t src_count);
@@ -854,6 +857,8 @@ uint32_t EmitOptionalLogicalAndBool(EmitterState& state, uint32_t lhs, uint32_t
bool IsStorageBufferMemoryKind(IR::ResourceKind kind); bool IsStorageBufferMemoryKind(IR::ResourceKind kind);
void EmitStorageBufferOffsets(EmitterState& state);
uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst, uint32_t EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst,
uint32_t index, uint32_t offset, uint32_t soffset); 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 EmitBufferAddressFromParts(EmitterState& state, const IR::Instruction& inst,
uint32_t index, uint32_t offset, uint32_t soffset) { uint32_t index, uint32_t offset, uint32_t soffset) {
const auto& mem = inst.memory; const auto& mem = inst.memory;
@@ -398,6 +409,15 @@ StorageBufferBindingForMemory(EmitterState& state, const IR::MemoryInfo& mem, ui
return binding; 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 EmitStorageBufferObjectPointer(EmitterState& state, const IR::MemoryInfo& mem,
uint32_t use_pc) { uint32_t use_pc) {
if (IsFlatMemoryKind(mem.kind)) { 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 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 object = EmitStorageBufferObjectPointer(state, mem, use_pc);
const auto length = state.builder.AllocateId(); const auto length = state.builder.AllocateId();
const auto in_bounds = 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 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 (IsFlatMemoryKind(mem.kind)) {
if (state.address_memory_variable == 0) { if (state.address_memory_variable == 0) {
ExitDescriptorBindingFailure(state, IR::DescriptorBindingKind::AddressMemory, 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.descriptor_set);
ids.push_back(program.bindings.push_constant_offset); ids.push_back(program.bindings.push_constant_offset);
ids.push_back(program.bindings.push_constant_size); 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.push_back(static_cast<uint32_t>(program.bindings.user_data_registers.size()));
ids.insert(ids.end(), program.bindings.user_data_registers.begin(), ids.insert(ids.end(), program.bindings.user_data_registers.begin(),
program.bindings.user_data_registers.end()); 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"); "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() { void TestMaterializationFailureIsTransactional() {
Program program; Program program;
program.blocks.resize(1); program.blocks.resize(1);
@@ -1381,6 +1406,9 @@ void TestNativeBindingLayout() {
FindBinding(program.bindings, DescriptorBindingKind::StorageUint2DArray); FindBinding(program.bindings, DescriptorBindingKind::StorageUint2DArray);
const auto *samplers = const auto *samplers =
FindBinding(program.bindings, DescriptorBindingKind::Samplers); FindBinding(program.bindings, DescriptorBindingKind::Samplers);
const auto *shader_data =
FindBinding(program.bindings, DescriptorBindingKind::UserData);
const auto shader_data_dwords = program.bindings.ShaderDataDwords();
Check( Check(
program.bindings.descriptor_set == 3 && buffers != nullptr && program.bindings.descriptor_set == 3 && buffers != nullptr &&
sampled2d != nullptr && sampled_array != nullptr && sampled2d != nullptr && sampled_array != nullptr &&
@@ -1393,12 +1421,19 @@ void TestNativeBindingLayout() {
sampled2d->resources == std::vector<uint32_t>{0} && sampled2d->resources == std::vector<uint32_t>{0} &&
sampled_array->resources == std::vector<uint32_t>{1} && sampled_array->resources == std::vector<uint32_t>{1} &&
storage3d->resources == std::vector<uint32_t>{2} && storage3d->resources == std::vector<uint32_t>{2} &&
storage_uint_array->resources == std::vector<uint32_t>{3} && storage_uint_array->resources == std::vector<uint32_t>{3} &&
samplers->resources == std::vector<uint32_t>{0} && samplers->resources == std::vector<uint32_t>{0} &&
!program.bindings.user_data_registers.empty() && !program.bindings.user_data_registers.empty() &&
program.bindings.push_constant_size != 0 && program.bindings.buffer_offset_dword ==
FindBinding(program.bindings, DescriptorBindingKind::FlattenedSrt) == program.bindings.user_data_registers.size() &&
nullptr && 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, program.binding_layout_complete,
"native binding allocator did not preserve dense typed resource groups"); "native binding allocator did not preserve dense typed resource groups");
} }
@@ -1907,6 +1942,7 @@ int main() {
RUN(TestSrtPatchPlanValidation); RUN(TestSrtPatchPlanValidation);
RUN(TestMaterializationSharesReadConstEvaluation); RUN(TestMaterializationSharesReadConstEvaluation);
RUN(TestInvalidImagesMaterializeAsNull); RUN(TestInvalidImagesMaterializeAsNull);
RUN(TestInvalidBuffersMaterializeAsNull);
RUN(TestMaterializationFailureIsTransactional); RUN(TestMaterializationFailureIsTransactional);
RUN(TestResourceSpecializationIsTypedAndTransactional); RUN(TestResourceSpecializationIsTypedAndTransactional);
RUN(TestRuntimeSpecializationCoversBakedBufferAndAddressFields); RUN(TestRuntimeSpecializationCoversBakedBufferAndAddressFields);
+296 -144
View File
@@ -38,6 +38,7 @@
#include "graphics/shader/recompiler/ShaderDecoder.h" #include "graphics/shader/recompiler/ShaderDecoder.h"
#include "graphics/shader/recompiler/ShaderRecompiler.h" #include "graphics/shader/recompiler/ShaderRecompiler.h"
#include "graphics/shader/recompiler/SpirvBuilder.h" #include "graphics/shader/recompiler/SpirvBuilder.h"
#include "graphics/shader/recompiler/SpirvEmitter.h"
#include "graphics/shader/shader.h" #include "graphics/shader/shader.h"
#include "kernel/memory.h" #include "kernel/memory.h"
@@ -723,6 +724,8 @@ struct TestCase {
u32 image_descriptor_swizzle = DstSel(4, 5, 6, 7); u32 image_descriptor_swizzle = DstSel(4, 5, 6, 7);
bool compile_only = false; bool compile_only = false;
size_t storage_buffer_range_dwords = 0; 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::optional<uint64_t> flat_memory_base;
std::vector<u32> gds_initial; std::vector<u32> gds_initial;
std::vector<u32> expected_gds; std::vector<u32> expected_gds;
@@ -849,6 +852,29 @@ CompiledShader CompileCase(const TestCase &test) {
if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) { if (!ShaderRecompiler::TryRecompile(test.code, options, result, &error)) {
Fail(test.name, "decode/IR", error.c_str()); 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(), Require(test.name, "SPIR-V emit", !result.spirv.empty(),
"recompiler returned empty SPIR-V"); "recompiler returned empty SPIR-V");
ValidateSpirv(test.name, result.spirv); ValidateSpirv(test.name, result.spirv);
@@ -858,6 +884,16 @@ CompiledShader CompileCase(const TestCase &test) {
packed_user_data.push_back( packed_user_data.push_back(
result.resources.user_data[reg - result.program.user_data_base]); 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), return {std::move(result.spirv), std::move(result.program),
std::move(result.resources.flattened_srt), std::move(result.resources.flattened_srt),
std::move(packed_user_data)}; std::move(packed_user_data)};
@@ -924,6 +960,7 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) {
packed_user_data.push_back( packed_user_data.push_back(
result.resources.user_data[reg - result.program.user_data_base]); 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), return {std::move(result.spirv), std::move(result.program),
std::move(result.resources.flattened_srt), std::move(result.resources.flattened_srt),
std::move(packed_user_data)}; std::move(packed_user_data)};
@@ -1785,9 +1822,8 @@ public:
const auto depth_attachment = depth.FindView(depth_attachment_info); const auto depth_attachment = depth.FindView(depth_attachment_info);
Require(name, "depth views", Require(name, "depth views",
depth_first != nullptr && depth_again == depth_first && depth_first != nullptr && depth_again == depth_first &&
depth_alias == depth_first && depth_alias == depth_first && depth_array != nullptr &&
depth_array != nullptr && depth_array != depth_first && depth_array != depth_first && depth_attachment != nullptr &&
depth_attachment != nullptr &&
depth_attachment != depth_array && depth_attachment != depth_array &&
depth.views.views.size() == 3, depth.views.views.size() == 3,
"unified depth view cache lost sampled/attachment identity"); "unified depth view cache lost sampled/attachment identity");
@@ -2547,8 +2583,7 @@ public:
auto uncompressed_block = MakeLinearDesc( auto uncompressed_block = MakeLinearDesc(
base + block_alias_offset, sizeof(block_alias_data), base + block_alias_offset, sizeof(block_alias_data),
vk::Format::eR32G32B32A32Uint, vk::Format::eR32G32B32A32Uint,
Prospero::GpuEnumValue( Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32UInt),
Prospero::BufferFormat::k32_32_32_32UInt),
Prospero::ImageType::kColor2D, {1, 1, 1}, 1, 16, 1); Prospero::ImageType::kColor2D, {1, 1, 1}, 1, 16, 1);
const auto uncompressed_block_image = const auto uncompressed_block_image =
texture_cache.FindImage(uncompressed_block); texture_cache.FindImage(uncompressed_block);
@@ -2568,15 +2603,16 @@ public:
std::array<uint32_t, block_alias_data.size()> block_alias_after{}; std::array<uint32_t, block_alias_data.size()> block_alias_after{};
std::memcpy(block_alias_after.data(), memory + block_alias_offset, std::memcpy(block_alias_after.data(), memory + block_alias_offset,
sizeof(block_alias_after)); sizeof(block_alias_after));
Require(name, "compressed view expansion", Require(
compressed_block_image && name, "compressed view expansion",
compressed_block_image != uncompressed_block_image && compressed_block_image &&
texture_cache.GetImage(compressed_block_image) compressed_block_image != uncompressed_block_image &&
.backing.format == vk::Format::eBc3UnormBlock && texture_cache.GetImage(compressed_block_image).backing.format ==
compressed_block_download && vk::Format::eBc3UnormBlock &&
block_alias_after == block_alias_data, compressed_block_download &&
"size-compatible compressed alias did not preserve its native " block_alias_after == block_alias_data,
"contents"); "size-compatible compressed alias did not preserve its native "
"contents");
ImageInfo resolve_source_info{}; ImageInfo resolve_source_info{};
resolve_source_info.pixel_format = vk::Format::eR8G8B8A8Unorm; resolve_source_info.pixel_format = vk::Format::eR8G8B8A8Unorm;
@@ -3317,8 +3353,10 @@ public:
name, "unformatted buffer/image alias", name, "unformatted buffer/image alias",
unformatted_alias_buffer.buffer != nullptr && unformatted_alias_buffer.buffer != nullptr &&
texture_cache.GetImage(unformatted_alias_image).IsGpuModified() && texture_cache.GetImage(unformatted_alias_image).IsGpuModified() &&
!texture_cache.GetImage(unformatted_alias_image).IsBufferModified(), !texture_cache.GetImage(unformatted_alias_image)
"read-only unformatted buffer alias did not follow ordinary BufferCache acquisition"); .IsBufferModified(),
"read-only unformatted buffer alias did not follow ordinary "
"BufferCache acquisition");
if (unformatted_alias_buffer.owner != nullptr) { if (unformatted_alias_buffer.owner != nullptr) {
command.RetainResourceUntilFence(unformatted_alias_buffer.owner); command.RetainResourceUntilFence(unformatted_alias_buffer.owner);
} }
@@ -5243,15 +5281,23 @@ public:
"ownership became visible"); "ownership became visible");
constexpr uint64_t phased_depth_address = base + 0x90000; constexpr uint64_t phased_depth_address = base + 0x90000;
constexpr uint64_t phased_stencil_address = base + 0xa0000;
constexpr uint64_t phased_htile_address = base + 0xb0000; constexpr uint64_t phased_htile_address = base + 0xb0000;
HW::DepthRenderTarget phased_depth_target{}; HW::DepthRenderTarget phased_depth_target{};
phased_depth_target.z_info.format = phased_depth_target.z_info.format =
Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F); Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F);
phased_depth_target.z_info.tile_surface_enable = true; phased_depth_target.z_info.texture_compatibility =
phased_depth_target.z_info.zrange_precision = 1; Prospero::TextureCompatiblePlaneCompression::kEnable;
phased_depth_target.stencil_info.tile_stencil_disable = true; 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_read_base_addr = phased_depth_address;
phased_depth_target.z_write_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.htile_data_base_addr = phased_htile_address;
phased_depth_target.size.valid = true; phased_depth_target.size.valid = true;
registers.SetDepthRenderTarget(phased_depth_target); registers.SetDepthRenderTarget(phased_depth_target);
@@ -5265,16 +5311,34 @@ public:
RenderDepthInfo phased_depth{}; RenderDepthInfo phased_depth{};
RenderExecutorTestAccess::ResolveRenderDepthTarget( RenderExecutorTestAccess::ResolveRenderDepthTarget(
executor, 1, scheduler.Current(), phased_depth); 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( Require(
name, "HTile discovery purity", name, "depth texture compatibility identity",
phased_depth.image_id && phased_depth.htile && 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_clear_enable &&
!phased_depth.depth_meta_clear_enable && !phased_depth.depth_meta_clear_enable &&
!texture_cache.IsMeta(phased_depth.htile_buffer_vaddr) && !texture_cache.IsMeta(phased_depth.htile_buffer_vaddr) &&
!texture_cache.GetImage(phased_depth.image_id).IsGpuModified() && !texture_cache.GetImage(phased_depth.image_id).IsGpuModified() &&
!texture_cache.GetImage(phased_depth.image_id).usage.depth_target, !texture_cache.GetImage(phased_depth.image_id).usage.depth_target,
"depth discovery registered, consumed, or GPU-owned HTile " "valid PS5 texture-compatibility policy changed logical depth image "
"state before final acquisition"); "identity or discovery side effects");
registers.SetDepthRenderTarget(phased_depth_target);
RenderColorInfo no_color{}; RenderColorInfo no_color{};
auto phased_rendering = RenderExecutorTestAccess::AcquireRenderTargets( auto phased_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
executor, scheduler.Current(), &no_color, 0, phased_depth); executor, scheduler.Current(), &no_color, 0, phased_depth);
@@ -5340,8 +5404,8 @@ public:
"replacement"); "replacement");
constexpr uint64_t array_target_address = base + 0xd0000; constexpr uint64_t array_target_address = base + 0xd0000;
auto array_target = auto array_target = make_target_desc(array_target_address,
make_target_desc(array_target_address, target_mip_size, {128, 128, 1}); target_mip_size, {128, 128, 1});
const auto array_target_id = texture_cache.FindImage(array_target); const auto array_target_id = texture_cache.FindImage(array_target);
const auto array_target_owner = const auto array_target_owner =
TextureCacheTestAccess::Owner(texture_cache, array_target_id); TextureCacheTestAccess::Owner(texture_cache, array_target_id);
@@ -5353,16 +5417,14 @@ public:
const auto encoded_array_address = array_target_address >> 8u; const auto encoded_array_address = array_target_address >> 8u;
constexpr auto array_format = constexpr auto array_format =
Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt); Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt);
array_texture.fields[0] = array_texture.fields[0] = static_cast<uint32_t>(encoded_array_address);
static_cast<uint32_t>(encoded_array_address);
array_texture.fields[1] = array_texture.fields[1] =
static_cast<uint32_t>(encoded_array_address >> 32u) | static_cast<uint32_t>(encoded_array_address >> 32u) |
(array_format << 20u) | (3u << 30u); (array_format << 20u) | (3u << 30u);
array_texture.fields[2] = (127u >> 2u) | (127u << 14u); array_texture.fields[2] = (127u >> 2u) | (127u << 14u);
array_texture.fields[3] = array_texture.fields[3] =
DstSel(4, 5, 6, 7) | (linear << 20u) | DstSel(4, 5, 6, 7) | (linear << 20u) |
(Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) << 28u);
<< 28u);
array_texture.fields[4] = 1; array_texture.fields[4] = 1;
ShaderRecompiler::IR::Program array_program{}; ShaderRecompiler::IR::Program array_program{};
@@ -5388,13 +5450,11 @@ public:
std::move(array_snapshot))}; std::move(array_snapshot))};
auto array_binding = executor.PrepareBindings( auto array_binding = executor.PrepareBindings(
scheduler.Current(), array_runtime, scheduler.Current(), array_runtime, vk::ShaderStageFlagBits::eCompute,
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); DescriptorCache::Stage::Compute);
executor.RebindImages(scheduler.Current(), array_binding); executor.RebindImages(scheduler.Current(), array_binding);
const auto expanded_array_id = const auto expanded_array_id = array_binding.resources.images[0].image_id;
array_binding.resources.images[0].image_id; const auto &expanded_array = texture_cache.GetImage(expanded_array_id);
const auto &expanded_array =
texture_cache.GetImage(expanded_array_id);
Require( Require(
name, "2D target to array backing expansion", name, "2D target to array backing expansion",
array_target_view != nullptr && array_target_owner != nullptr && array_target_view != nullptr && array_target_owner != nullptr &&
@@ -5424,27 +5484,26 @@ public:
auto array_rendering = RenderExecutorTestAccess::AcquireRenderTargets( auto array_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
executor, scheduler.Current(), &rebound_array_target, 1, executor, scheduler.Current(), &rebound_array_target, 1,
no_array_depth); no_array_depth);
Require( Require(name, "expanded array target rebind",
name, "expanded array target rebind", rebound_array_target.image_id == expanded_array_id &&
rebound_array_target.image_id == expanded_array_id && rebound_array_target.image_view != nullptr &&
rebound_array_target.image_view != nullptr && array_rendering.num_color_attachments == 1 &&
array_rendering.num_color_attachments == 1 && array_rendering.color_attachments[0].image_view ==
array_rendering.color_attachments[0].image_view == rebound_array_target.image_view &&
rebound_array_target.image_view && array_rendering.width == 128 &&
array_rendering.width == 128 && array_rendering.height == 128 && array_rendering.height == 128 &&
array_rendering.num_layers == 1 && array_rendering.num_layers == 1 &&
texture_cache.GetImage(expanded_array_id).binding.is_bound && texture_cache.GetImage(expanded_array_id).binding.is_bound &&
texture_cache.GetImage(expanded_array_id).binding.is_target, texture_cache.GetImage(expanded_array_id).binding.is_target,
"the retained single-layer target did not rebind to the expanded " "the retained single-layer target did not rebind to the expanded "
"backing"); "backing");
RenderExecutorTestAccess::ResetBindings(executor); RenderExecutorTestAccess::ResetBindings(executor);
auto colliding_msaa_texture = array_texture; auto colliding_msaa_texture = array_texture;
colliding_msaa_texture.fields[3] = colliding_msaa_texture.fields[3] =
DstSel(4, 5, 6, 7) | (1u << 16u) | DstSel(4, 5, 6, 7) | (1u << 16u) |
(Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) | (Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) |
(Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) << 28u);
<< 28u);
colliding_msaa_texture.fields[4] = 0; colliding_msaa_texture.fields[4] = 0;
colliding_msaa_texture.fields[5] = (7u << 20u) | (1u << 4u); colliding_msaa_texture.fields[5] = (7u << 20u) | (1u << 4u);
ShaderRecompiler::IR::DescriptorValue colliding_msaa_descriptor{}; ShaderRecompiler::IR::DescriptorValue colliding_msaa_descriptor{};
@@ -5501,26 +5560,22 @@ public:
auto msaa_texture = array_texture; auto msaa_texture = array_texture;
const auto encoded_msaa_address = msaa_target_address >> 8u; const auto encoded_msaa_address = msaa_target_address >> 8u;
msaa_texture.fields[0] = msaa_texture.fields[0] = static_cast<uint32_t>(encoded_msaa_address);
static_cast<uint32_t>(encoded_msaa_address);
msaa_texture.fields[1] = msaa_texture.fields[1] =
static_cast<uint32_t>(encoded_msaa_address >> 32u) | static_cast<uint32_t>(encoded_msaa_address >> 32u) |
(array_format << 20u) | (3u << 30u); (array_format << 20u) | (3u << 30u);
msaa_texture.fields[3] = msaa_texture.fields[3] =
DstSel(4, 5, 6, 7) | (2u << 16u) | DstSel(4, 5, 6, 7) | (2u << 16u) |
(Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) | (Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) << 20u) |
(Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) (Prospero::GpuEnumValue(Prospero::ImageType::kColor2DMsaa) << 28u);
<< 28u);
msaa_texture.fields[4] = 0; msaa_texture.fields[4] = 0;
msaa_texture.fields[5] = (7u << 20u) | (2u << 4u); msaa_texture.fields[5] = (7u << 20u) | (2u << 4u);
ShaderRecompiler::IR::DescriptorValue msaa_descriptor{}; ShaderRecompiler::IR::DescriptorValue msaa_descriptor{};
std::copy(std::begin(msaa_texture.fields), std::copy(std::begin(msaa_texture.fields), std::end(msaa_texture.fields),
std::end(msaa_texture.fields),
msaa_descriptor.dwords.begin()); msaa_descriptor.dwords.begin());
msaa_descriptor.dword_count = 8; msaa_descriptor.dword_count = 8;
auto msaa_program = auto msaa_program = std::make_shared<ShaderRecompiler::IR::Program>(
std::make_shared<ShaderRecompiler::IR::Program>( *array_runtime.program);
*array_runtime.program);
msaa_program->info.images[0].dimension = msaa_program->info.images[0].dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2D; ShaderRecompiler::Decoder::ImageDimension::Dim2D;
auto msaa_snapshot = auto msaa_snapshot =
@@ -5529,8 +5584,8 @@ public:
ShaderStageRuntime msaa_runtime{std::move(msaa_program), ShaderStageRuntime msaa_runtime{std::move(msaa_program),
std::move(msaa_snapshot)}; std::move(msaa_snapshot)};
auto msaa_binding = executor.PrepareBindings( auto msaa_binding = executor.PrepareBindings(
scheduler.Current(), msaa_runtime, scheduler.Current(), msaa_runtime, vk::ShaderStageFlagBits::eCompute,
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); DescriptorCache::Stage::Compute);
executor.RebindImages(scheduler.Current(), msaa_binding); executor.RebindImages(scheduler.Current(), msaa_binding);
const auto &resolved_msaa = msaa_binding.resources.images[0]; const auto &resolved_msaa = msaa_binding.resources.images[0];
Require( Require(
@@ -5538,10 +5593,8 @@ public:
msaa_target_view != nullptr && msaa_target_view != nullptr &&
resolved_msaa.image_id == msaa_target_id && resolved_msaa.image_id == msaa_target_id &&
resolved_msaa.image_view != nullptr && resolved_msaa.image_view != nullptr &&
resolved_msaa.desc.info.type == resolved_msaa.desc.info.type == Prospero::ImageType::kColor2D &&
Prospero::ImageType::kColor2D && resolved_msaa.desc.info.resources == ImageSubresources{1, 1} &&
resolved_msaa.desc.info.resources ==
ImageSubresources{1, 1} &&
resolved_msaa.desc.info.samples == msaa_samples && resolved_msaa.desc.info.samples == msaa_samples &&
resolved_msaa.desc.info.data.size == 0x40000 && resolved_msaa.desc.info.data.size == 0x40000 &&
resolved_msaa.desc.view_info.level_count == 1 && resolved_msaa.desc.view_info.level_count == 1 &&
@@ -5562,9 +5615,8 @@ public:
std::end(msaa_array_texture.fields), std::end(msaa_array_texture.fields),
msaa_array_descriptor.dwords.begin()); msaa_array_descriptor.dwords.begin());
msaa_array_descriptor.dword_count = 8; msaa_array_descriptor.dword_count = 8;
auto msaa_array_program = auto msaa_array_program = std::make_shared<ShaderRecompiler::IR::Program>(
std::make_shared<ShaderRecompiler::IR::Program>( *msaa_runtime.program);
*msaa_runtime.program);
msaa_array_program->info.images[0].dimension = msaa_array_program->info.images[0].dimension =
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
auto msaa_array_snapshot = auto msaa_array_snapshot =
@@ -5576,26 +5628,24 @@ public:
scheduler.Current(), msaa_array_runtime, scheduler.Current(), msaa_array_runtime,
vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute); vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
executor.RebindImages(scheduler.Current(), msaa_array_binding); executor.RebindImages(scheduler.Current(), msaa_array_binding);
const auto &resolved_msaa_array = const auto &resolved_msaa_array = msaa_array_binding.resources.images[0];
msaa_array_binding.resources.images[0]; Require(name, "MSAA array backing expansion",
Require( resolved_msaa_array.image_id != msaa_target_id &&
name, "MSAA array backing expansion", resolved_msaa_array.image_view != nullptr &&
resolved_msaa_array.image_id != msaa_target_id && resolved_msaa_array.desc.info.type ==
resolved_msaa_array.image_view != nullptr && Prospero::ImageType::kColor2D &&
resolved_msaa_array.desc.info.type == resolved_msaa_array.desc.info.resources ==
Prospero::ImageType::kColor2D && ImageSubresources{1, 2} &&
resolved_msaa_array.desc.info.resources == resolved_msaa_array.desc.info.samples == msaa_samples &&
ImageSubresources{1, 2} && resolved_msaa_array.desc.info.data.size == 0x80000 &&
resolved_msaa_array.desc.info.samples == msaa_samples && resolved_msaa_array.desc.view_info.type ==
resolved_msaa_array.desc.info.data.size == 0x80000 && vk::ImageViewType::e2DArray &&
resolved_msaa_array.desc.view_info.type == resolved_msaa_array.desc.view_info.layer_count == 2 &&
vk::ImageViewType::e2DArray && texture_cache.GetImage(resolved_msaa_array.image_id)
resolved_msaa_array.desc.view_info.layer_count == 2 && .backing.layers == 2 &&
texture_cache.GetImage(resolved_msaa_array.image_id) texture_cache.GetImage(resolved_msaa_array.image_id)
.backing.layers == 2 && .backing.samples == msaa_samples,
texture_cache.GetImage(resolved_msaa_array.image_id) "MSAA array view did not expand the matching Color2D backing");
.backing.samples == msaa_samples,
"MSAA array view did not expand the matching Color2D backing");
RenderExecutorTestAccess::ResetBindings(executor); RenderExecutorTestAccess::ResetBindings(executor);
ImageDesc depth{}; ImageDesc depth{};
@@ -5902,14 +5952,14 @@ public:
std::move(stencil_storage_snapshot))}; std::move(stencil_storage_snapshot))};
auto storage_redirected = executor.PrepareBindings( auto storage_redirected = executor.PrepareBindings(
scheduler.Current(), stencil_storage_runtime, scheduler.Current(), stencil_storage_runtime,
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute, DescriptorCache::Stage::Compute);
DescriptorCache::Stage::Compute);
executor.RebindImages(scheduler.Current(), storage_redirected); executor.RebindImages(scheduler.Current(), storage_redirected);
Require(name, "storage stencil acquisition", Require(
storage_redirected.resources.images[0].image_id == depth_id && name, "storage stencil acquisition",
storage_redirected.resources.images[0].image_view != nullptr && storage_redirected.resources.images[0].image_id == depth_id &&
texture_cache.GetImage(depth_id).usage.storage, storage_redirected.resources.images[0].image_view != nullptr &&
"storage stencil binding did not acquire the associated depth owner"); texture_cache.GetImage(depth_id).usage.storage,
"storage stencil binding did not acquire the associated depth owner");
RenderExecutorTestAccess::ResetBindings(executor); RenderExecutorTestAccess::ResetBindings(executor);
resources.UnmapMemory(base, allocation_size, GpuAccess::ReadWrite); resources.UnmapMemory(base, allocation_size, GpuAccess::ReadWrite);
scheduler.Finish(); scheduler.Finish();
@@ -6399,13 +6449,17 @@ public:
const auto *buffers = Binding(Kind::Buffers); const auto *buffers = Binding(Kind::Buffers);
if (buffers != nullptr) { if (buffers != nullptr) {
buffer_infos.resize(buffers->resources.size()); 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.buffer = buffer.buffer;
info.offset = 0; info.offset = 0;
info.range = buffer.size; info.range = buffer.size;
if (test.storage_buffer_range_dwords != 0) { 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>( 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, Require(test.name, "dispatch", info.range <= buffer.size,
"storage buffer descriptor range exceeds backing buffer"); "storage buffer descriptor range exceeds backing buffer");
} }
@@ -11731,6 +11785,58 @@ TestCase BufferStoreDwordIdxenUsesDescriptorStride() {
return test; 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() { TestCase BufferLoadVariants() {
using O = ShaderOpcode; using O = ShaderOpcode;
@@ -14359,6 +14465,8 @@ std::vector<TestCase> MakeCases() {
AddCase(BufferLoadDwordNoAddressFlagsIgnoresVaddr); AddCase(BufferLoadDwordNoAddressFlagsIgnoresVaddr);
AddCase(BufferLoadDwordIdxenUsesDescriptorStride); AddCase(BufferLoadDwordIdxenUsesDescriptorStride);
AddCase(BufferStoreDwordIdxenUsesDescriptorStride); AddCase(BufferStoreDwordIdxenUsesDescriptorStride);
AddCase(BufferStoreDwordAppliesHostOffset);
AddCase(BufferOffsetsUsePackedLaneAndStorageFallback);
AddCase(BufferLoadVariants); AddCase(BufferLoadVariants);
AddCase(BufferStoreVariants); AddCase(BufferStoreVariants);
AddCase(BufferFormatVariants); AddCase(BufferFormatVariants);
@@ -14730,8 +14838,7 @@ void CheckReverseRenderTargetFormatContract() {
vk::Format::eR8G8B8A8Unorm, vk::Format::eR8G8B8A8Unorm,
DstSel(4, 5, 6, 2)); DstSel(4, 5, 6, 2));
} else if (std::strcmp(kind, "sampled-incompatible-format") == 0) { } else if (std::strcmp(kind, "sampled-incompatible-format") == 0) {
(void)SelectSampledColorView(vk::Format::eR8Unorm, (void)SelectSampledColorView(vk::Format::eR8Unorm, vk::Format::eR16Unorm,
vk::Format::eR16Unorm,
DstSel(4, 0, 0, 1)); DstSel(4, 0, 0, 1));
} else if (std::strcmp(kind, "sampled-invalid-high") == 0) { } else if (std::strcmp(kind, "sampled-invalid-high") == 0) {
(void)SelectSampledColorView(vk::Format::eR8G8B8A8Unorm, (void)SelectSampledColorView(vk::Format::eR8G8B8A8Unorm,
@@ -14831,8 +14938,7 @@ void CheckSampledColorViews() {
valid_swizzles += valid; valid_swizzles += valid;
} }
Require("SampledColorViews", "all PS5 read swizzles", Require("SampledColorViews", "all PS5 read swizzles",
valid_swizzles == 1296 && valid_swizzles == 1296 && !IsValidImageSwizzle(DstSel(4, 5, 6, 2)) &&
!IsValidImageSwizzle(DstSel(4, 5, 6, 2)) &&
!IsValidImageSwizzle(DstSel(4, 5, 6, 3)) && !IsValidImageSwizzle(DstSel(4, 5, 6, 3)) &&
!IsValidImageSwizzle(0x1000), !IsValidImageSwizzle(0x1000),
"valid PS5 sampled mappings were rejected or reserved selectors were " "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), DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4),
"R8 did not select its 000R component-mapped view"); "R8 did not select its 000R component-mapped view");
Require("SampledColorViews", "mutable R8 uint/unorm 000R", Require("SampledColorViews", "mutable R8 uint/unorm 000R",
SelectSampledColorView(vk::Format::eR8Uint, SelectSampledColorView(vk::Format::eR8Uint, vk::Format::eR8Unorm,
vk::Format::eR8Unorm,
DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4), DstSel(0, 0, 0, 4)) == DstSel(0, 0, 0, 4),
"compatible R8 integer target sampled view was rejected"); "compatible R8 integer target sampled view was rejected");
Require("SampledColorViews", "R16G16 RG01", Require("SampledColorViews", "R16G16 RG01",
@@ -15486,9 +15591,9 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray; ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
cube_resource.read = true; cube_resource.read = true;
cube_resource.depth_compare = true; cube_resource.depth_compare = true;
const auto cube_view = ResolveTargetTextureView( const auto cube_view =
cube_resource, Prospero::ImageType::kCube, 0, ResolveTargetTextureView(cube_resource, Prospero::ImageType::kCube, 0,
cube_image.info.resources.layers); cube_image.info.resources.layers);
Require("SampledDepthDescriptor", "normalized depth cube", Require("SampledDepthDescriptor", "normalized depth cube",
IsSupportedDepthTargetDescriptor(cube_descriptor, cube_image) && IsSupportedDepthTargetDescriptor(cube_descriptor, cube_image) &&
IsSupportedDepthTextureEncoding(cube_descriptor) && IsSupportedDepthTextureEncoding(cube_descriptor) &&
@@ -15741,9 +15846,9 @@ void CheckBasicStorageTextureDescriptor() {
"basic 3D storage descriptor fixture is malformed"); "basic 3D storage descriptor fixture is malformed");
ValidateStorageTexture(BasicStorageTextureResource(), descriptor, 0x10000); ValidateStorageTexture(BasicStorageTextureResource(), descriptor, 0x10000);
const ShaderTextureResource extended{{ const ShaderTextureResource extended{{0x204aca00u, 0xc4700000u, 0x000fc00fu,
0x204aca00u, 0xc4700000u, 0x000fc00fu, 0xa1b00facu, 0xa1b00facu, 0x0000003fu, 0x00700000u,
0x0000003fu, 0x00700000u, 0x006b0000u, 0x00204b0au}}; 0x006b0000u, 0x00204b0au}};
auto extended_resource = BasicStorageTextureResource(); auto extended_resource = BasicStorageTextureResource();
extended_resource.read = false; extended_resource.read = false;
Require("BasicStorageTexture", "extended descriptor", Require("BasicStorageTexture", "extended descriptor",
@@ -15776,18 +15881,17 @@ void CheckBasicStorageTextureDescriptor() {
ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000); ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000);
const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor(); const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor();
Require("BasicStorageTexture", "PPSA06228 R11G11B10 descriptor", Require(
r11g11b10.Base40() == 0x10c6b50000ull && "BasicStorageTexture", "PPSA06228 R11G11B10 descriptor",
r11g11b10.Width5() + 1u == 1920 && r11g11b10.Base40() == 0x10c6b50000ull &&
r11g11b10.Height5() + 1u == 1080 && r11g11b10.Width5() + 1u == 1920 && r11g11b10.Height5() + 1u == 1080 &&
r11g11b10.Depth() + 1u == 1 && r11g11b10.Depth() + 1u == 1 &&
r11g11b10.Format() == r11g11b10.Format() ==
Prospero::GpuEnumValue( Prospero::GpuEnumValue(Prospero::BufferFormat::k11_11_10Float) &&
Prospero::BufferFormat::k11_11_10Float) && r11g11b10.TileMode() ==
r11g11b10.TileMode() == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) && r11g11b10.DstSelXYZW() == DstSel(4, 5, 6, 1),
r11g11b10.DstSelXYZW() == DstSel(4, 5, 6, 1), "PPSA06228 R11G11B10 storage descriptor fixture is malformed");
"PPSA06228 R11G11B10 storage descriptor fixture is malformed");
ValidateStorageTexture(BasicBgraStorageTextureResource(), r11g11b10, ValidateStorageTexture(BasicBgraStorageTextureResource(), r11g11b10,
0x870000); 0x870000);
ValidateStorageColorView(vk::Format::eB10G11R11UfloatPack32, ValidateStorageColorView(vk::Format::eB10G11R11UfloatPack32,
@@ -15878,8 +15982,7 @@ void CheckBasicStorageTextureDescriptor() {
if (!IsValidImageSwizzle(swizzle)) { if (!IsValidImageSwizzle(swizzle)) {
continue; continue;
} }
all_swizzles.fields[3] = all_swizzles.fields[3] = (all_swizzles.fields[3] & ~0xfffu) | swizzle;
(all_swizzles.fields[3] & ~0xfffu) | swizzle;
ValidateStorageTexture(BasicLinearStorageTextureResource(), all_swizzles, ValidateStorageTexture(BasicLinearStorageTextureResource(), all_swizzles,
0x800); 0x800);
ValidateStorageColorView(vk::Format::eR16G16B16A16Sfloat, ValidateStorageColorView(vk::Format::eR16G16B16A16Sfloat,
@@ -15921,15 +16024,13 @@ void CheckBasicStorageTextureDescriptor() {
ValidateStorageTexture(BasicUintArrayStorageTextureResource(), uint_array, ValidateStorageTexture(BasicUintArrayStorageTextureResource(), uint_array,
0x10000); 0x10000);
const auto standard4kb_array = const auto standard4kb_array = Standard4KBUintArrayStorageTextureDescriptor();
Standard4KBUintArrayStorageTextureDescriptor();
const auto standard4kb_pitch = TileGetTexturePitch( const auto standard4kb_pitch = TileGetTexturePitch(
standard4kb_array.Format(), 1, 1, standard4kb_array.TileMode()); standard4kb_array.Format(), 1, 1, standard4kb_array.TileMode());
TileSizeAlign standard4kb_size{}; TileSizeAlign standard4kb_size{};
TileGetTextureTotalSize(standard4kb_array.Format(), 1, 1, 1, TileGetTextureTotalSize(standard4kb_array.Format(), 1, 1, 1,
standard4kb_pitch, 1, standard4kb_pitch, 1, standard4kb_array.TileMode(),
standard4kb_array.TileMode(), false, false, standard4kb_size);
standard4kb_size);
Require("BasicStorageTexture", "Standard4KB uint 2D-array descriptor", Require("BasicStorageTexture", "Standard4KB uint 2D-array descriptor",
standard4kb_array.Type() == standard4kb_array.Type() ==
Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) &&
@@ -15947,9 +16048,9 @@ void CheckBasicStorageTextureDescriptor() {
auto based_standard4kb_array = standard4kb_array; auto based_standard4kb_array = standard4kb_array;
based_standard4kb_array.fields[0] = 0x006c6800u; based_standard4kb_array.fields[0] = 0x006c6800u;
based_standard4kb_array.fields[4] = 0x00010001u; based_standard4kb_array.fields[4] = 0x00010001u;
const auto based_standard4kb_pitch = TileGetTexturePitch( const auto based_standard4kb_pitch =
based_standard4kb_array.Format(), 1, 1, TileGetTexturePitch(based_standard4kb_array.Format(), 1, 1,
based_standard4kb_array.TileMode()); based_standard4kb_array.TileMode());
TileSizeAlign based_standard4kb_size{}; TileSizeAlign based_standard4kb_size{};
TileGetTextureTotalSize( TileGetTextureTotalSize(
based_standard4kb_array.Format(), 1, 1, based_standard4kb_array.Format(), 1, 1,
@@ -15963,8 +16064,7 @@ void CheckBasicStorageTextureDescriptor() {
based_standard4kb_size.align == 0x1000, based_standard4kb_size.align == 0x1000,
"captured based Standard4KB array view is malformed"); "captured based Standard4KB array view is malformed");
ValidateStorageTexture(BasicUintArrayStorageTextureResource(), ValidateStorageTexture(BasicUintArrayStorageTextureResource(),
based_standard4kb_array, based_standard4kb_array, based_standard4kb_size.size);
based_standard4kb_size.size);
const auto uint_volume = BasicUintVolumeStorageTextureDescriptor(); const auto uint_volume = BasicUintVolumeStorageTextureDescriptor();
Require("BasicStorageTexture", "uint 3D descriptor", Require("BasicStorageTexture", "uint 3D descriptor",
@@ -15983,9 +16083,9 @@ void CheckBasicStorageTextureDescriptor() {
ValidateStorageTexture(BasicUintVolumeStorageTextureResource(), uint_volume, ValidateStorageTexture(BasicUintVolumeStorageTextureResource(), uint_volume,
0x10000); 0x10000);
const ShaderTextureResource tiled_uint_volume{{ const ShaderTextureResource tiled_uint_volume{
0x1ac0e530u, 0xc0b00000u, 0x0003c003u, 0xa0500004u, {0x1ac0e530u, 0xc0b00000u, 0x0003c003u, 0xa0500004u, 0x0000000fu,
0x0000000fu, 0x00700000u, 0x00000000u, 0x00000000u}}; 0x00700000u, 0x00000000u, 0x00000000u}};
Require("BasicStorageTexture", "tiled uint 3D descriptor", Require("BasicStorageTexture", "tiled uint 3D descriptor",
tiled_uint_volume.Width5() + 1u == 16 && tiled_uint_volume.Width5() + 1u == 16 &&
tiled_uint_volume.Height5() + 1u == 16 && tiled_uint_volume.Height5() + 1u == 16 &&
@@ -16028,14 +16128,14 @@ void CheckBasicStorageTextureDescriptor() {
Prospero::GpuEnumValue(Prospero::TileMode::kDepth) && Prospero::GpuEnumValue(Prospero::TileMode::kDepth) &&
d16_depth_tile.DstSelXYZW() == DstSel(4, 0, 0, 1), d16_depth_tile.DstSelXYZW() == DstSel(4, 0, 0, 1),
"PPSA10112 writable D16 depth-plane descriptor fixture is malformed"); "PPSA10112 writable D16 depth-plane descriptor fixture is malformed");
const auto d16_pitch = TileGetTexturePitch( const auto d16_pitch =
d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, 1, TileGetTexturePitch(d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u,
d16_depth_tile.TileMode()); 1, d16_depth_tile.TileMode());
TileSizeAlign d16_size{}; TileSizeAlign d16_size{};
TileGetTextureTotalSize( TileGetTextureTotalSize(d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u,
d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, d16_depth_tile.Height5() + 1u,
d16_depth_tile.Height5() + 1u, d16_depth_tile.Depth() + 1u, d16_pitch, 1, d16_depth_tile.Depth() + 1u, d16_pitch, 1,
d16_depth_tile.TileMode(), false, d16_size); d16_depth_tile.TileMode(), false, d16_size);
Require("BasicStorageTexture", "PPSA10112 D16 depth-tile footprint", Require("BasicStorageTexture", "PPSA10112 D16 depth-tile footprint",
d16_pitch == 256 && d16_size.size == 0x20000 && d16_pitch == 256 && d16_size.size == 0x20000 &&
d16_size.align == 0x10000, d16_size.align == 0x10000,
@@ -16064,8 +16164,8 @@ void CheckBasicStorageTextureDescriptor() {
for (const char *kind : for (const char *kind :
{"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read", {"resource", "type", "tile", "mip", "swizzle", "linear-rgb1-read",
"bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read", "bgra-read", "r16-float-read", "r8-unorm-read", "yzwx-read",
"reserved-swizzle", "array-base-out-of-range", "array-mip-view", "reserved", "reserved-swizzle", "array-base-out-of-range", "array-mip-view",
"uint-format", "uint-resource-float-format", "reserved", "uint-format", "uint-resource-float-format",
"depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) { "depth-tile-read", "depth-tile-extent", "depth-tile-fmask"}) {
std::string command = std::string("\"") + path + std::string command = std::string("\"") + path +
"\" --storage-texture-descriptor-death " + kind; "\" --storage-texture-descriptor-death " + kind;
@@ -16484,6 +16584,38 @@ void CheckDepthHtileStencilCompatibility() {
std::printf("[host] %-32s ok\n", "DepthHtileStencilCompatibility"); 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() { void CheckStencilAttachmentAccess() {
PipelineStencilStaticState state{vk::StencilOp::eKeep, vk::StencilOp::eKeep, PipelineStencilStaticState state{vk::StencilOp::eKeep, vk::StencilOp::eKeep,
vk::StencilOp::eKeep, vk::StencilOp::eKeep,
@@ -17023,6 +17155,24 @@ void CheckPm4AcquireMemNoOp(RenderContext &renderer) {
std::printf("[host] %-32s ok\n", "Pm4AcquireMemNoOp"); 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) { void CheckPm4WaitResume(RenderContext &renderer) {
GraphicsInitJmpTables(); GraphicsInitJmpTables();
CommandProcessor processor(renderer); CommandProcessor processor(renderer);
@@ -17272,6 +17422,7 @@ int main(int argc, char **argv) {
CheckStorageTextureVolumeMipRegions(); CheckStorageTextureVolumeMipRegions();
CheckStorageTextureGpuOwnedRebindState(); CheckStorageTextureGpuOwnedRebindState();
CheckNativeMsaaState(); CheckNativeMsaaState();
CheckPs5DepthRegisterDecoding();
CheckDepthHtileStencilCompatibility(); CheckDepthHtileStencilCompatibility();
CheckStencilAttachmentAccess(); CheckStencilAttachmentAccess();
CheckDepthAttachmentWrites(); CheckDepthAttachmentWrites();
@@ -17289,6 +17440,7 @@ int main(int argc, char **argv) {
CheckReferenceClockScale(); CheckReferenceClockScale();
CheckVulkan13FeatureRequirements(); CheckVulkan13FeatureRequirements();
CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer()); CheckPm4AcquireMemNoOp(vulkan.RuntimeRenderer());
CheckPm4StencilInfoValueLane(vulkan.RuntimeRenderer());
CheckPm4WaitResume(vulkan.RuntimeRenderer()); CheckPm4WaitResume(vulkan.RuntimeRenderer());
CheckPm4CeCompletion(vulkan.RuntimeRenderer()); CheckPm4CeCompletion(vulkan.RuntimeRenderer());
CheckEmbeddedFetchVertexOffset(); CheckEmbeddedFetchVertexOffset();