fix(agc): read a 16-bit integer view of a depth plane as its stored values

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michon 2026-09-30 17:53:52 +02:00
parent ac70928d86
commit bbf430e22d
9 changed files with 33 additions and 5 deletions

View File

@ -92,7 +92,7 @@ public:
const bool d16 = target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT;
const auto expected = stencil ? VK_FORMAT_R8_UINT : d16 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R32_SFLOAT;
const auto format = ResolveTextureFormat(resource.format);
const bool depthBits = !stencil && !d16 && words.size() >= 4 && ShaderRecompiler::IsDepthBitsTexture(words[1], words[3]);
const bool depthBits = !stencil && words.size() >= 4 && ShaderRecompiler::DepthBitsTextureWidth(words[1], words[3]) == (d16 ? 16u : 32u);
if ((format != expected && !depthBits) || resource.dimension != TextureDimension::k2D || resource.width != target.extent.width || resource.height != target.extent.height || resource.baseLevel != 0 || resource.lastLevel != 0 || resource.baseArray != 0) {
char text[448];
std::snprintf(text, sizeof(text), "AGC graphics: sampling the %s plane of depth surface 0x%llx (%ux%u, vk format %d) as a %ux%u texture of guest format %u (vk %d), tile mode %u, dimension %d, levels %u-%u, slice %u is not implemented (T# %08x %08x %08x %08x %08x %08x %08x %08x)",

View File

@ -265,11 +265,18 @@ std::shared_ptr<StorageTexture> sampledStorageSource(const Context& context, con
std::shared_ptr<Texture> cachedTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components, std::uint64_t guestBytes = 0) {
CaptureTrace::Log("sampled-lookup address=%llx width=%u height=%u dcc=%llx", static_cast<unsigned long long>(resource.baseAddress), resource.width, resource.height, static_cast<unsigned long long>(resource.dccAddress));
if (auto depth = DepthSurfaceTexture(context, words, resource, components)) return depth;
if (words.size() >= 4 && ShaderRecompiler::IsDepthBitsTexture(words[1], words[3])) {
const auto depthBitsWidth = words.size() >= 4 ? ShaderRecompiler::DepthBitsTextureWidth(words[1], words[3]) : 0u;
if (depthBitsWidth == 32u) {
char text[160];
std::snprintf(text, sizeof(text), "AGC graphics: 32-bit integer read of the depth-layout texture 0x%llx, which is no depth surface drawn with, is not implemented", static_cast<unsigned long long>(resource.baseAddress));
throw std::runtime_error(text);
}
constexpr auto unorm16 = static_cast<std::uint32_t>(ShaderRecompiler::IrBufferFormat::Format16UNorm);
if (depthBitsWidth == 16u && resource.format != unorm16) {
auto normalized = resource;
normalized.format = unorm16;
return cachedTexture(context, words, normalized, components, guestBytes);
}
static const bool disabled = std::getenv("APS5_NO_TEXTURE_CACHE") != nullptr;
const bool profile = LookupOutcomes::Profiled();
const auto start = profile ? std::chrono::steady_clock::now() : std::chrono::steady_clock::time_point{};

View File

@ -51,6 +51,7 @@ struct ImageResource {
bool cube = false;
bool r128 = false;
bool depthBits = false;
bool depthUnorm16 = false;
std::uint32_t indirectRoot = NoIndirectImage;
std::uint32_t indirectMappingOffset = 0;
std::uint32_t indirectSearchIterations = 0;

View File

@ -30,6 +30,7 @@ struct ResourceSpecialization {
bool cube = false;
bool fmask = false;
bool depthBits = false;
bool depthUnorm16 = false;
bool operator==(const Image& other) const;
};

View File

@ -43,6 +43,7 @@ struct DecodedImage {
bool cube = false;
bool fmask = false;
bool depthBits = false;
bool depthUnorm16 = false;
};
ShaderBufferResource decodeBufferDescriptor(const DescriptorValue& value) {
@ -164,6 +165,7 @@ DecodedImage decodeImageDescriptor(const DescriptorValue& descriptor, const Imag
decoded.numericClass = SampledTextureNumericClass(format);
if (!storage && !base.depthCompare && IsDepthBitsTexture(descriptor.dwords[1], descriptor.dwords[3])) {
decoded.depthBits = true;
decoded.depthUnorm16 = DepthBitsTextureWidth(descriptor.dwords[1], descriptor.dwords[3]) == 16u;
decoded.numericClass = IrTextureNumericClass::Float;
decoded.shaderSwizzle = descriptorImageSwizzle(descriptor);
}
@ -530,6 +532,7 @@ void buildResourceSpecialization(const IrResourcePlan& plan, ResourceSnapshot& s
entry.cube = decoded.cube;
entry.fmask = decoded.fmask;
entry.depthBits = decoded.depthBits;
entry.depthUnorm16 = decoded.depthUnorm16;
result.images.push_back(entry);
}
@ -615,6 +618,7 @@ void ResourceMaterializer::Apply(IrProgram& program, const ResourceSpecializatio
image.indirectSearchIterations = source.indirectSearchIterations;
image.cube = source.cube;
image.depthBits = source.depthBits;
image.depthUnorm16 = source.depthUnorm16;
image.indirectResources.clear();
}
for (std::uint32_t index = 0; index < images.size(); index++) {
@ -880,7 +884,7 @@ bool ResourceSpecialization::Buffer::operator==(const Buffer& other) const {
}
bool ResourceSpecialization::Image::operator==(const Image& other) const {
return numericClass == other.numericClass && dimension == other.dimension && mipCount == other.mipCount && conversionFormat == other.conversionFormat && shaderSwizzle == other.shaderSwizzle && indirectRoot == other.indirectRoot && indirectMappingOffset == other.indirectMappingOffset && indirectSearchIterations == other.indirectSearchIterations && cube == other.cube && fmask == other.fmask && depthBits == other.depthBits;
return numericClass == other.numericClass && dimension == other.dimension && mipCount == other.mipCount && conversionFormat == other.conversionFormat && shaderSwizzle == other.shaderSwizzle && indirectRoot == other.indirectRoot && indirectMappingOffset == other.indirectMappingOffset && indirectSearchIterations == other.indirectSearchIterations && cube == other.cube && fmask == other.fmask && depthBits == other.depthBits && depthUnorm16 == other.depthUnorm16;
}
bool ResourceSpecialization::operator==(const ResourceSpecialization& other) const {

View File

@ -20,6 +20,7 @@ enum class ImageType : std::uint32_t {
[[nodiscard]] bool IsFmaskTextureFormat(IrBufferFormat format);
[[nodiscard]] IrTextureNumericClass SampledTextureNumericClass(IrBufferFormat format);
[[nodiscard]] IrBufferFormat RemapTextureFormat(IrBufferFormat format);
[[nodiscard]] std::uint32_t DepthBitsTextureWidth(std::uint32_t word1, std::uint32_t word3);
[[nodiscard]] bool IsDepthBitsTexture(std::uint32_t word1, std::uint32_t word3);
}

View File

@ -121,11 +121,17 @@ IrBufferFormat RemapTextureFormat(IrBufferFormat format) {
return format == IrBufferFormat::Format11_11_10UInt ? IrBufferFormat::Format32UInt : format;
}
bool IsDepthBitsTexture(std::uint32_t word1, std::uint32_t word3) {
std::uint32_t DepthBitsTextureWidth(std::uint32_t word1, std::uint32_t word3) {
const auto format = static_cast<IrBufferFormat>((word1 >> 20u) & 0x1ffu);
const auto swizzle = (word3 >> 20u) & 0x1fu;
const bool depthLayout = swizzle == 4u || swizzle == 8u || swizzle == 16u || swizzle == 20u || swizzle == 24u;
return depthLayout && (format == IrBufferFormat::Format32UInt || format == IrBufferFormat::Format32SInt);
if (!depthLayout) return 0u;
if (format == IrBufferFormat::Format32UInt || format == IrBufferFormat::Format32SInt) return 32u;
return format == IrBufferFormat::Format16UInt ? 16u : 0u;
}
bool IsDepthBitsTexture(std::uint32_t word1, std::uint32_t word3) {
return DepthBitsTextureWidth(word1, word3) != 0u;
}
}

View File

@ -396,6 +396,7 @@ void encodeInfo(Writer& writer, const CompiledShaderInfo& compiled) {
out.Value(image.cube);
out.Value(image.r128);
out.Value(image.depthBits);
out.Value(image.depthUnorm16);
out.Value(image.indirectRoot);
out.Value(image.indirectMappingOffset);
out.Value(image.indirectSearchIterations);
@ -482,6 +483,7 @@ void decodeInfo(Reader& reader, CompiledShaderInfo& compiled) {
in.Value(image.cube);
in.Value(image.r128);
in.Value(image.depthBits);
in.Value(image.depthUnorm16);
in.Value(image.indirectRoot);
in.Value(image.indirectMappingOffset);
in.Value(image.indirectSearchIterations);
@ -793,6 +795,7 @@ void BuildKey(const RecompileRequest& request, std::uint32_t hostSubgroupSize, c
out.Value(image.cube);
out.Value(image.fmask);
out.Value(image.depthBits);
out.Value(image.depthUnorm16);
});
writer.Values(std::span<const std::uint32_t>(specialization.boundDescriptors));
const auto& switches = switchKey();

View File

@ -308,6 +308,11 @@ std::uint32_t ResultVector(SpirvValueEmitContext& ctx, const ImageEmitAccess& ac
}
const auto scalar = state.module.AllocateId();
state.module.AddFunction(spv::OpCompositeExtract, ImageScalarType(state, valueClass), scalar, value, index);
if (access.image.depthUnorm16) {
const auto scaled = Binary(state, spv::OpFMul, TypeF32(state), scalar, ConstantF32Value(state, 65535.0f));
component[index] = Unary(state, spv::OpConvertFToU, TypeU32(state), Binary(state, spv::OpFAdd, TypeF32(state), scaled, ConstantF32Value(state, 0.5f)));
continue;
}
component[index] = SampledComponentBits(ctx, scalar, valueClass);
}
const auto result = state.module.AllocateId();