shader: honor RDNA2 128-bit image descriptors

This commit is contained in:
nmzik
2026-08-20 21:57:10 +02:00
parent bc5709e1bd
commit 0966938dc8
13 changed files with 122 additions and 37 deletions
@@ -233,7 +233,8 @@ bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& r
descriptor.BaseArray5() == 0; descriptor.BaseArray5() == 0;
} }
bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image) { bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image,
bool r128) {
const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u; const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u;
const auto height = static_cast<uint32_t>(descriptor.Height5()) + 1u; const auto height = static_cast<uint32_t>(descriptor.Height5()) + 1u;
const auto type = descriptor.Type(); const auto type = descriptor.Type();
@@ -262,10 +263,11 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c
const bool levels_ok = const bool levels_ok =
multisampled multisampled
? descriptor.BaseLevel() == 0 && descriptor.LastLevel() >= 1 && ? descriptor.BaseLevel() == 0 && descriptor.LastLevel() >= 1 &&
descriptor.LastLevel() <= 3 && descriptor.MaxMip() == descriptor.LastLevel() && descriptor.LastLevel() <= 3 &&
(r128 || descriptor.MaxMip() == descriptor.LastLevel()) &&
image.info.resources.levels == 1 && image.info.samples == samples image.info.resources.levels == 1 && image.info.samples == samples
: descriptor.BaseLevel() == 0 && descriptor.LastLevel() == 0 && : descriptor.BaseLevel() == 0 && descriptor.LastLevel() == 0 &&
descriptor.MaxMip() == 0 && image.info.samples == 1; (r128 || descriptor.MaxMip() == 0) && image.info.samples == 1;
return image.info.IsDepth() && width == image.info.extent.width && return image.info.IsDepth() && width == image.info.extent.width &&
height == image.info.extent.height && height == image.info.extent.height &&
(supported_2d || supported_array || supported_cube || supported_msaa_2d || (supported_2d || supported_array || supported_cube || supported_msaa_2d ||
@@ -275,7 +277,8 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c
(!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch; (!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch;
} }
bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, const Image& image) { bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, const Image& image,
bool r128) {
constexpr uint32_t field1_reserved_mask = 0x200fff00u; constexpr uint32_t field1_reserved_mask = 0x200fff00u;
constexpr uint32_t field2_reserved_mask = 0xf0003000u; constexpr uint32_t field2_reserved_mask = 0xf0003000u;
const uint32_t field3_expected = descriptor.DstSelXYZW() | const uint32_t field3_expected = descriptor.DstSelXYZW() |
@@ -286,12 +289,16 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co
const uint32_t field4_expected = descriptor.Depth() | (descriptor.BaseArray5() << 16u); const uint32_t field4_expected = descriptor.Depth() | (descriptor.BaseArray5() << 16u);
const uint32_t field5_expected = (static_cast<uint32_t>(descriptor.PerfMod5()) << 20u) | const uint32_t field5_expected = (static_cast<uint32_t>(descriptor.PerfMod5()) << 20u) |
(static_cast<uint32_t>(descriptor.MaxMip()) << 4u); (static_cast<uint32_t>(descriptor.MaxMip()) << 4u);
const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 && const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 &&
(descriptor.fields[2] & field2_reserved_mask) == 0 && (descriptor.fields[2] & field2_reserved_mask) == 0 &&
descriptor.fields[3] == field3_expected && descriptor.fields[3] == field3_expected;
descriptor.fields[4] == field4_expected && if (r128) {
descriptor.fields[5] == field5_expected; return common && descriptor.fields[4] == 0 && descriptor.fields[5] == 0 &&
if (!common || (descriptor.fields[6] == 0 && descriptor.fields[7] != 0)) { descriptor.fields[6] == 0 && descriptor.fields[7] == 0;
}
const bool full = common && descriptor.fields[4] == field4_expected &&
descriptor.fields[5] == field5_expected;
if (!full || (descriptor.fields[6] == 0 && descriptor.fields[7] != 0)) {
return false; return false;
} }
if (descriptor.fields[6] == 0) { if (descriptor.fields[6] == 0) {
@@ -312,9 +319,9 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
vk::Format view_format, uint64_t size) { vk::Format view_format, uint64_t size) {
const bool resource_ok = IsSupportedSampledDepthResource(resource); const bool resource_ok = IsSupportedSampledDepthResource(resource);
const bool descriptor_ok = const bool descriptor_ok =
image != nullptr && IsSupportedDepthTargetDescriptor(descriptor, *image); image != nullptr && IsSupportedDepthTargetDescriptor(descriptor, *image, resource.r128);
const bool encoding_ok = const bool encoding_ok =
image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image); image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image, resource.r128);
const bool format_ok = const bool format_ok =
image != nullptr && IsSupportedSampledDepthFormat(image->info.pixel_format, view_format); image != nullptr && IsSupportedSampledDepthFormat(image->info.pixel_format, view_format);
if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) { if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) {
@@ -404,17 +411,20 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag
const bool supported_swizzle = const bool supported_swizzle =
IsValidImageSwizzle(swizzle) && IsValidImageSwizzle(swizzle) &&
(swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic); (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic);
const auto max_mip = resource.r128 ? descriptor.LastLevel() : descriptor.MaxMip();
const auto view_last_level = const auto view_last_level =
resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage
? descriptor.LastLevel() ? descriptor.LastLevel()
: std::min(descriptor.LastLevel(), descriptor.MaxMip()); : std::min(descriptor.LastLevel(), max_mip);
return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile && return (is_1d || is_1d_array || is_2d || is_2d_array || is_3d) && supported_tile &&
descriptor.BaseLevel() <= view_last_level && view_last_level <= descriptor.MaxMip() && descriptor.BaseLevel() <= view_last_level && view_last_level <= max_mip &&
descriptor.MinLod() == 0 && supported_swizzle && descriptor.BCSwizzle() == 0 && descriptor.MinLod() == 0 && supported_swizzle && descriptor.BCSwizzle() == 0 &&
!descriptor.MsaaDepth(); !descriptor.MsaaDepth();
} }
static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descriptor) { static bool IsSupportedStorageTextureEncoding(
const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor) {
constexpr uint32_t field1_reserved_mask = 0x200fff00u; constexpr uint32_t field1_reserved_mask = 0x200fff00u;
constexpr uint32_t field2_reserved_mask = 0xf0003000u; constexpr uint32_t field2_reserved_mask = 0xf0003000u;
constexpr uint32_t field5_expected = 0x00700000u; constexpr uint32_t field5_expected = 0x00700000u;
@@ -426,9 +436,14 @@ static bool IsSupportedStorageTextureEncoding(const ShaderTextureResource& descr
(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 && const bool common = (descriptor.fields[1] & field1_reserved_mask) == 0 &&
(descriptor.fields[2] & field2_reserved_mask) == 0 && (descriptor.fields[2] & field2_reserved_mask) == 0 &&
descriptor.fields[3] == expected_field3 && descriptor.fields[4] == expected_field4 && descriptor.fields[3] == expected_field3;
if (resource.r128) {
return common && descriptor.fields[4] == 0 && descriptor.fields[5] == 0 &&
descriptor.fields[6] == 0 && descriptor.fields[7] == 0;
}
return common && descriptor.fields[4] == expected_field4 &&
(descriptor.fields[5] & ~field5_max_mip_mask) == field5_expected; (descriptor.fields[5] & ~field5_max_mip_mask) == field5_expected;
} }
@@ -437,7 +452,7 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource,
const auto format = descriptor.Format(); const auto format = descriptor.Format();
const bool resource_ok = IsSupportedStorageImageResource(resource); const bool resource_ok = IsSupportedStorageImageResource(resource);
const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor); const bool descriptor_ok = IsSupportedStorageTextureDescriptor(resource, descriptor);
const bool encoding_ok = IsSupportedStorageTextureEncoding(descriptor); const bool encoding_ok = IsSupportedStorageTextureEncoding(resource, descriptor);
const bool uint_resource = const bool uint_resource =
resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint; resource.kind == ShaderRecompiler::IR::ResourceKind::StorageImageUint;
const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource && const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource &&
@@ -631,19 +646,19 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso
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 = IsMultisampledTexture(type); const bool multisampled = IsMultisampledTexture(type);
const auto levels = multisampled ? 1u : static_cast<uint32_t>(descriptor.MaxMip()) + 1u; const auto max_mip = resource.r128 ? last_level : descriptor.MaxMip();
const auto levels = multisampled ? 1u : static_cast<uint32_t>(max_mip) + 1u;
const bool dynamic_storage = const bool dynamic_storage =
storage && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage; storage && resource.mip_mode == ShaderRecompiler::IR::ImageMipMode::DynamicStorage;
const auto view_last_level = const auto view_last_level =
!multisampled && !dynamic_storage ? std::min(last_level, descriptor.MaxMip()) : last_level; !multisampled && !dynamic_storage ? std::min(last_level, max_mip) : last_level;
const auto tile = descriptor.TileMode(); const auto tile = descriptor.TileMode();
const bool depth_tile = tile == Prospero::TileMode::kDepth; const bool depth_tile = tile == Prospero::TileMode::kDepth;
const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget; const bool msaa_tile = depth_tile || tile == Prospero::TileMode::kRenderTarget;
const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray; const bool msaa_array = type == Prospero::ImageType::kColor2DMsaaArray;
if ((!multisampled && (base_level > view_last_level || view_last_level >= levels)) || if ((!multisampled && (base_level > view_last_level || view_last_level >= levels)) ||
(multisampled && (multisampled &&
(base_level != 0 || last_level == 0 || last_level > 3 || (base_level != 0 || last_level == 0 || last_level > 3 || max_mip != last_level || !msaa_tile ||
descriptor.MaxMip() != last_level || !msaa_tile ||
(descriptor.MsaaDepth() && !depth_tile) || (descriptor.MsaaDepth() && !depth_tile) ||
(!msaa_array && (descriptor.Depth() != 0 || descriptor.BaseArray5() != 0))))) { (!msaa_array && (descriptor.Depth() != 0 || descriptor.BaseArray5() != 0))))) {
EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u " EXIT("unsupported texture mip view: base=%u last=%u levels=%u max=%u type=%u tile=%u "
@@ -34,9 +34,11 @@ ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
Prospero::ImageType type, uint32_t base_layer, uint32_t image_layers); Prospero::ImageType type, uint32_t base_layer, uint32_t image_layers);
[[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, [[nodiscard]] bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
const Image& image); const Image& image,
bool r128 = false);
[[nodiscard]] bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, [[nodiscard]] bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor,
const Image& image); const Image& image,
bool r128 = false);
[[nodiscard]] bool [[nodiscard]] bool
IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource, IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor, const Image& image); const ShaderTextureResource& descriptor, const Image& image);
@@ -279,7 +279,7 @@ void RenderExecutor::DispatchDirect(uint64_t submit_id, RenderCommandBuffer& buf
r.Type() == Prospero::ImageType::kColor2DMsaa || r.Type() == Prospero::ImageType::kColor2DMsaa ||
r.Type() == Prospero::ImageType::kColor2DMsaaArray r.Type() == Prospero::ImageType::kColor2DMsaaArray
? 1u ? 1u
: static_cast<uint32_t>(r.MaxMip()) + 1u, : static_cast<uint32_t>(image.r128 ? r.LastLevel() : r.MaxMip()) + 1u,
static_cast<uint32_t>(r.TileMode())); static_cast<uint32_t>(r.TileMode()));
} }
for (uint32_t i = 0; i < program.info.samplers.size(); i++) { for (uint32_t i = 0; i < program.info.samplers.size(); i++) {
@@ -309,6 +309,7 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
const uint32_t vaddr = word1 & 0xffu; const uint32_t vaddr = word1 & 0xffu;
const uint32_t srsrc = (word1 >> 16u) & 0x1fu; const uint32_t srsrc = (word1 >> 16u) & 0x1fu;
const uint32_t ssamp = (word1 >> 21u) & 0x1fu; const uint32_t ssamp = (word1 >> 21u) & 0x1fu;
const bool r128 = ((word0 >> 15u) & 0x1u) != 0u;
const bool a16 = ((word1 >> 30u) & 0x1u) != 0u; const bool a16 = ((word1 >> 30u) & 0x1u) != 0u;
const bool d16 = ((word1 >> 31u) & 0x1u) != 0u; const bool d16 = ((word1 >> 31u) & 0x1u) != 0u;
const auto* sample = LookupSample(opcode); const auto* sample = LookupSample(opcode);
@@ -332,6 +333,7 @@ void DecodeMimg(uint32_t pc, std::span<const uint32_t> code, uint32_t word_index
inst.image_sample_flags |= ImageSampleFlagA16; inst.image_sample_flags |= ImageSampleFlagA16;
} }
inst.image_dimension = dimension; inst.image_dimension = dimension;
inst.image_r128 = r128;
inst.image_nsa_dwords = nsa_dwords; inst.image_nsa_dwords = nsa_dwords;
for (uint32_t i = 0; i < nsa_dwords * 4u; i++) { for (uint32_t i = 0; i < nsa_dwords * 4u; i++) {
inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu; inst.image_nsa_addr[i] = (code[word_index + 2u + i / 4u] >> ((i % 4u) * 8u)) & 0xffu;
@@ -157,6 +157,9 @@ std::string FormatMimg(const Instruction& inst) {
if (inst.data_bits == 16u) { if (inst.data_bits == 16u) {
text += " d16=1"; text += " d16=1";
} }
if (inst.image_r128) {
text += " r128=1";
}
switch (inst.opcode) { switch (inst.opcode) {
case Opcode::IMAGE_SAMPLE: case Opcode::IMAGE_SAMPLE:
case Opcode::IMAGE_GATHER4_LZ: case Opcode::IMAGE_GATHER4_LZ:
@@ -667,6 +667,7 @@ struct Instruction {
bool slc = false; bool slc = false;
bool idxen = false; bool idxen = false;
bool offen = false; bool offen = false;
bool image_r128 = false;
int32_t branch_offset = 0; int32_t branch_offset = 0;
uint32_t branch_target = 0; uint32_t branch_target = 0;
struct { struct {
@@ -52,11 +52,13 @@ IR::Value Translator::GetScalarAddressResource(uint32_t base) {
} }
IR::Value Translator::GetImageResource(const IR::MemoryInfo& memory) { IR::Value Translator::GetImageResource(const IR::MemoryInfo& memory) {
const auto dword = [&](uint32_t index) {
return memory.image_r128 && index >= 4u ? IR::U32(IR::Value(0u))
: GetResourceDword(memory.resource, index);
};
return ir.Emit(IR::ValueOpcode::GetImageResource, return ir.Emit(IR::ValueOpcode::GetImageResource,
{GetResourceDword(memory.resource, 0), GetResourceDword(memory.resource, 1), {dword(0), dword(1), dword(2), dword(3), dword(4), dword(5), dword(6),
GetResourceDword(memory.resource, 2), GetResourceDword(memory.resource, 3), dword(7)});
GetResourceDword(memory.resource, 4), GetResourceDword(memory.resource, 5),
GetResourceDword(memory.resource, 6), GetResourceDword(memory.resource, 7)});
} }
IR::Value Translator::GetSamplerResource(const IR::MemoryInfo& memory) { IR::Value Translator::GetSamplerResource(const IR::MemoryInfo& memory) {
@@ -232,6 +232,7 @@ MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded, ResourceKi
mem.formatted = decoded.formatted; mem.formatted = decoded.formatted;
mem.image_has_mip = decoded.opcode == Decoder::Opcode::IMAGE_LOAD_MIP || mem.image_has_mip = decoded.opcode == Decoder::Opcode::IMAGE_LOAD_MIP ||
decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP; decoded.opcode == Decoder::Opcode::IMAGE_STORE_MIP;
mem.image_r128 = decoded.image_r128;
mem.glc = decoded.glc; mem.glc = decoded.glc;
mem.slc = decoded.slc; mem.slc = decoded.slc;
mem.idxen = decoded.idxen; mem.idxen = decoded.idxen;
@@ -119,6 +119,7 @@ struct MemoryInfo {
bool formatted = false; bool formatted = false;
bool image_has_mip = false; bool image_has_mip = false;
bool image_cube = false; bool image_cube = false;
bool image_r128 = false;
bool glc = false; bool glc = false;
bool slc = false; bool slc = false;
bool idxen = false; bool idxen = false;
@@ -226,6 +227,7 @@ struct ImageResource {
bool atomic = false; bool atomic = false;
bool depth_compare = false; bool depth_compare = false;
bool cube = false; bool cube = false;
bool r128 = false;
uint32_t indirect_root = NoIndirectImage; uint32_t indirect_root = NoIndirectImage;
uint32_t indirect_mapping_offset = 0; uint32_t indirect_mapping_offset = 0;
uint32_t indirect_mapping_capacity = 0; uint32_t indirect_mapping_capacity = 0;
@@ -98,14 +98,14 @@ std::string MemoryInfoToString(const MemoryInfo& mem) {
" ; {} resource={} sampler={} offset={} offset2={} dmask=0x{:x} data_dwords={} " " ; {} resource={} sampler={} offset={} offset2={} dmask=0x{:x} data_dwords={} "
"data_bits={} component={}/{} dfmt={} nfmt={} signed={} typed={} formatted={} segment={} " "data_bits={} component={}/{} dfmt={} nfmt={} signed={} typed={} formatted={} segment={} "
"glc={} slc={} idxen={} offen={} image_flags=0x{:x} image_dim={} image_addr={} " "glc={} slc={} idxen={} offen={} image_flags=0x{:x} image_dim={} image_addr={} "
"image_mip={}", "image_mip={} image_r128={}",
ResourceKindToString(mem.kind).c_str(), mem.resource, mem.sampler, mem.offset, ResourceKindToString(mem.kind).c_str(), mem.resource, mem.sampler, mem.offset,
mem.secondary_offset, mem.dmask, mem.data_dwords, mem.data_bits, mem.component_index, mem.secondary_offset, mem.dmask, mem.data_dwords, mem.data_bits, mem.component_index,
mem.component_count, mem.data_format, mem.number_format, mem.data_signed ? 1u : 0u, mem.component_count, mem.data_format, mem.number_format, mem.data_signed ? 1u : 0u,
mem.typed ? 1u : 0u, mem.formatted ? 1u : 0u, mem.memory_segment, mem.glc ? 1u : 0u, mem.typed ? 1u : 0u, mem.formatted ? 1u : 0u, mem.memory_segment, mem.glc ? 1u : 0u,
mem.slc ? 1u : 0u, mem.idxen ? 1u : 0u, mem.offen ? 1u : 0u, mem.image_sample_flags, mem.slc ? 1u : 0u, mem.idxen ? 1u : 0u, mem.offen ? 1u : 0u, mem.image_sample_flags,
Decoder::ImageDimensionToString(mem.image_dimension), mem.image_address_components, Decoder::ImageDimensionToString(mem.image_dimension), mem.image_address_components,
mem.image_has_mip ? 1u : 0u); mem.image_has_mip ? 1u : 0u, mem.image_r128 ? 1u : 0u);
if (mem.image_nsa_dwords != 0) { if (mem.image_nsa_dwords != 0) {
text += fmt::format(" image_nsa_dwords={} image_nsa_addr=", mem.image_nsa_dwords); text += fmt::format(" image_nsa_dwords={} image_nsa_addr=", mem.image_nsa_dwords);
const auto count = const auto count =
@@ -52,18 +52,23 @@ bool NullImageDescriptor(const DescriptorValue& descriptor) {
return descriptor.dwords[0] == 0 && (descriptor.dwords[1] & 0xffu) == 0; return descriptor.dwords[0] == 0 && (descriptor.dwords[1] & 0xffu) == 0;
} }
bool ValidImageDescriptor(const DescriptorValue& descriptor) { bool ValidImageDescriptor(const DescriptorValue& descriptor, bool r128 = false) {
const auto type = static_cast<Prospero::ImageType>((descriptor.dwords[3] >> 28u) & 0xfu); const auto type = static_cast<Prospero::ImageType>((descriptor.dwords[3] >> 28u) & 0xfu);
const auto format = static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu); const auto format = static_cast<Prospero::BufferFormat>((descriptor.dwords[1] >> 20u) & 0x1ffu);
if (type < Prospero::ImageType::kColor1D || format == Prospero::BufferFormat::kInvalid) { if (type < Prospero::ImageType::kColor1D || format == Prospero::BufferFormat::kInvalid) {
return false; return false;
} }
if (r128 && type != Prospero::ImageType::kColor1D &&
type != Prospero::ImageType::kColor2D && type != Prospero::ImageType::kColor2DMsaa) {
return false;
}
if (type == Prospero::ImageType::kColor2DMsaa || if (type == Prospero::ImageType::kColor2DMsaa ||
type == Prospero::ImageType::kColor2DMsaaArray) { type == Prospero::ImageType::kColor2DMsaaArray) {
const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu; const auto base_level = (descriptor.dwords[3] >> 12u) & 0xfu;
const auto fragments = (descriptor.dwords[3] >> 16u) & 0xfu; const auto fragments = (descriptor.dwords[3] >> 16u) & 0xfu;
const auto max_mip = (descriptor.dwords[5] >> 4u) & 0xfu; const auto max_mip = (descriptor.dwords[5] >> 4u) & 0xfu;
return base_level == 0 && fragments >= 1 && fragments <= 3 && max_mip == fragments; return base_level == 0 && fragments >= 1 && fragments <= 3 &&
(r128 || max_mip == fragments);
} }
return true; return true;
} }
@@ -644,7 +649,7 @@ bool MaterializeResources(const Program& program, const SrtRuntime& runtime,
} }
} else { } else {
auto descriptor = *cursor++; auto descriptor = *cursor++;
if (!ValidImageDescriptor(descriptor)) { if (!ValidImageDescriptor(descriptor, image.r128)) {
descriptor.dwords.fill(0); descriptor.dwords.fill(0);
} }
next.images[image_index] = descriptor; next.images[image_index] = descriptor;
@@ -652,7 +652,7 @@ private:
auto& image = m_info.images[i]; auto& image = m_info.images[i];
if (image.source == source && image.kind == memory.kind && if (image.source == source && image.kind == memory.kind &&
image.dimension == memory.image_dimension && image.mip_mode == mip && image.dimension == memory.image_dimension && image.mip_mode == mip &&
image.depth_compare == depth) { image.depth_compare == depth && image.r128 == memory.image_r128) {
Merge(image, op, pc); Merge(image, op, pc);
return i; return i;
} }
@@ -667,6 +667,7 @@ private:
image.dimension = memory.image_dimension; image.dimension = memory.image_dimension;
image.mip_mode = mip; image.mip_mode = mip;
image.depth_compare = depth; image.depth_compare = depth;
image.r128 = memory.image_r128;
Merge(image, op, pc); Merge(image, op, pc);
m_info.images.push_back(image); m_info.images.push_back(image);
return static_cast<uint32_t>(m_info.images.size() - 1); return static_cast<uint32_t>(m_info.images.size() - 1);
+52 -1
View File
@@ -570,10 +570,11 @@ constexpr u32 EncodeSmem1(u32 offset, u32 soffset = 0) {
} }
constexpr u32 EncodeMimg0(u32 opcode, u32 dmask, u32 nsa_dwords = 0, constexpr u32 EncodeMimg0(u32 opcode, u32 dmask, u32 nsa_dwords = 0,
bool glc = false, u32 dim = 1) { bool glc = false, u32 dim = 1, bool r128 = false) {
return (0x3cu << 26u) | ((opcode >> 7u) & 0x1u) | return (0x3cu << 26u) | ((opcode >> 7u) & 0x1u) |
((nsa_dwords & 0x3u) << 1u) | ((dim & 0x7u) << 3u) | ((nsa_dwords & 0x3u) << 1u) | ((dim & 0x7u) << 3u) |
((dmask & 0xfu) << 8u) | (glc ? (1u << 13u) : 0u) | ((dmask & 0xfu) << 8u) | (glc ? (1u << 13u) : 0u) |
(r128 ? (1u << 15u) : 0u) |
((opcode & 0x7fu) << 18u); ((opcode & 0x7fu) << 18u);
} }
@@ -17625,6 +17626,35 @@ TestCase ImageLoadR32UintUsesIntegerSampledImage() {
return test; return test;
} }
TestCase ImageLoadR128IgnoresAdjacentMaskSgprs() {
using O = ShaderOpcode;
std::vector<u32> code;
AppendVMovU32(&code, 20, 2);
AppendVMovU32(&code, 21, 1);
code.push_back(EncodeSop1(0x04, 4, 126)); // s_mov_b64 s[4:5], exec
code.push_back(EncodeMimg0(0x00, 0x1, 0, false, 1, true));
code.push_back(EncodeMimg1(0, 20));
AppendStoreVgpr(&code, 0, 0);
AppendEnd(&code);
TestCase test;
test.name = "ImageLoadR128IgnoresAdjacentMaskSgprs";
test.code = code;
test.expected = {0xdeadbeefu};
test.opcodes = {O::V_MOV_B32, O::S_MOV_B64, O::IMAGE_LOAD,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.sampled_image_rgba.resize(16);
test.sampled_image_rgba[6] = 0xdeadbeefu;
test.sampled_image_format = vk::Format::eR32Uint;
test.sampled_image_dwords_per_pixel = 1;
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32UInt);
test.has_user_data = true;
test.decoded_counts = {{"r128=1", 1}};
test.native_ir_counts = {{"image_r128=1", 1}};
return test;
}
TestCase ImageLoad1DUsesScalarCoordinate() { TestCase ImageLoad1DUsesScalarCoordinate() {
using O = ShaderOpcode; using O = ShaderOpcode;
@@ -19095,6 +19125,7 @@ std::vector<TestCase> MakeCases() {
AddCase(BufferAtomicFMaxContendedWorkgroup); AddCase(BufferAtomicFMaxContendedWorkgroup);
AddCase(ImageLoadVariants); AddCase(ImageLoadVariants);
AddCase(ImageLoadR32UintUsesIntegerSampledImage); AddCase(ImageLoadR32UintUsesIntegerSampledImage);
AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs);
AddCase(ImageLoad1DUsesScalarCoordinate); AddCase(ImageLoad1DUsesScalarCoordinate);
AddCase(ImageLoad1DArrayUsesLayerCoordinate); AddCase(ImageLoad1DArrayUsesLayerCoordinate);
AddCase(ImageLoad1DArrayDescriptorUsesSelectedLayer); AddCase(ImageLoad1DArrayDescriptorUsesSelectedLayer);
@@ -20278,6 +20309,13 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
"valid uncompressed MSAA depth descriptor required an HTILE " "valid uncompressed MSAA depth descriptor required an HTILE "
"compatibility flag"); "compatibility flag");
auto r128_msaa = uncompressed_msaa;
std::fill(r128_msaa.fields + 4, r128_msaa.fields + 8, 0u);
Require("SampledDepthDescriptor", "R128 uncompressed 2x MSAA depth",
IsSupportedDepthTargetDescriptor(r128_msaa, msaa_image, true) &&
IsSupportedDepthTextureEncoding(r128_msaa, msaa_image, true),
"valid R128 MSAA depth descriptor required omitted dwords");
descriptor.fields[3] = descriptor.fields[3] =
(descriptor.fields[3] & ~(0xfu << 28u)) | (descriptor.fields[3] & ~(0xfu << 28u)) |
(static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u); (static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u);
@@ -20670,6 +20708,19 @@ void CheckBasicStorageTextureDescriptor() {
"PPSA02604 BGRA 2D storage descriptor fixture is malformed"); "PPSA02604 BGRA 2D storage descriptor fixture is malformed");
ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000); ValidateStorageTexture(BasicBgraStorageTextureResource(), bgra, 0x870000);
const ShaderTextureResource r128{{0x0202e500u, 0xc8200000u, 0x010dc1dfu,
0x91b00facu, 0, 0, 0, 0}};
auto r128_resource = BasicBgraStorageTextureResource();
r128_resource.r128 = true;
Require("BasicStorageTexture", "PPSA01736 R128 descriptor",
r128.Base40() == 0x202e50000ull && r128.Width5() + 1u == 1920 &&
r128.Height5() + 1u == 1080 && r128.Depth() + 1u == 1 &&
r128.Format() == Prospero::BufferFormat::k8_8_8_8Srgb &&
r128.TileMode() == Prospero::TileMode::kRenderTarget &&
r128.DstSelXYZW() == DstSel(4, 5, 6, 7),
"PPSA01736 R128 storage descriptor fixture is malformed");
ValidateStorageTexture(r128_resource, r128, 0x870000);
const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor(); const auto r11g11b10 = Ppsa06228R11G11B10StorageTextureDescriptor();
Require("BasicStorageTexture", "PPSA06228 R11G11B10 descriptor", Require("BasicStorageTexture", "PPSA06228 R11G11B10 descriptor",
r11g11b10.Base40() == 0x10c6b50000ull && r11g11b10.Base40() == 0x10c6b50000ull &&