render: fix tiled depth comparison textures

Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
Co-authored-by: Mac <me@itsmemac.com>
This commit is contained in:
nmzik
2026-09-05 11:44:11 +04:00
parent b96a30ed88
commit 9641b51925
5 changed files with 241 additions and 59 deletions
+45 -36
View File
@@ -130,7 +130,10 @@ bool TextureCache::SameBacking(const ImageInfo& cached, const ImageInfo& request
TextureCache::BindingType TextureCache::UploadBinding(const Image& image) { TextureCache::BindingType TextureCache::UploadBinding(const Image& image) {
if (image.info.IsDepth()) { if (image.info.IsDepth()) {
return BindingType::DepthTarget; return image.info.tile_mode == Prospero::TileMode::kDepth ||
image.info.tile_mode == Prospero::TileMode::kLinear
? BindingType::DepthTarget
: BindingType::Texture;
} }
if (image.usage.render_target) { if (image.usage.render_target) {
return BindingType::RenderTarget; return BindingType::RenderTarget;
@@ -815,7 +818,7 @@ ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId source_id) {
return expanded_id; return expanded_id;
} }
struct TextureCache::ColorTransferPlan { struct TextureCache::TextureTransferPlan {
TextureUploadLayout layout; TextureUploadLayout layout;
std::vector<vk::BufferImageCopy> regions; std::vector<vk::BufferImageCopy> regions;
std::vector<GpuTileInfo> tiles; std::vector<GpuTileInfo> tiles;
@@ -834,14 +837,14 @@ static uint64_t GetLinearSize(std::span<const GpuTileInfo> tiles) {
} }
struct TextureCache::DownloadPlan { struct TextureCache::DownloadPlan {
ColorTransferPlan color; TextureTransferPlan texture;
bool depth = false; bool depth_target = false;
bool valid = false; bool valid = false;
}; };
TextureCache::ColorTransferPlan TextureCache::TextureTransferPlan
TextureCache::BuildColorTransfer(const Image& image, BindingType binding, TextureCache::BuildTextureTransfer(const Image& image, BindingType binding,
TransferDirection direction) const { TransferDirection direction) const {
const auto& info = image.info; const auto& info = image.info;
auto format = info.guest_format; auto format = info.guest_format;
uint32_t layers = info.TransferLayers(); uint32_t layers = info.TransferLayers();
@@ -850,7 +853,7 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
const char* owner = const char* owner =
direction == TransferDirection::Upload ? "TextureCache" : "TextureCache readback"; direction == TransferDirection::Upload ? "TextureCache" : "TextureCache readback";
ColorTransferPlan plan; TextureTransferPlan plan;
if (direction == TransferDirection::Upload) { if (direction == TransferDirection::Upload) {
switch (binding) { switch (binding) {
case BindingType::Texture: break; case BindingType::Texture: break;
@@ -895,6 +898,11 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
info.resources.levels, layers, info.tile_mode, info.resources.levels, layers, info.tile_mode,
info.data.size, allow_depth_tile, volume, owner); info.data.size, allow_depth_tile, volume, owner);
plan.regions = TextureBuildImageCopies(plan.layout); plan.regions = TextureBuildImageCopies(plan.layout);
if (info.IsDepth()) {
for (auto& region: plan.regions) {
region.imageSubresource.aspectMask = vk::ImageAspectFlagBits::eDepth;
}
}
plan.tiled = plan.layout.surface.description.tile_mode != Prospero::TileMode::kLinear; plan.tiled = plan.layout.surface.description.tile_mode != Prospero::TileMode::kLinear;
if (plan.tiled) { if (plan.tiled) {
if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout, if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout,
@@ -908,12 +916,13 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding,
} }
TextureCache::DownloadPlan TextureCache::BuildDownload(const Image& image) const { TextureCache::DownloadPlan TextureCache::BuildDownload(const Image& image) const {
const auto& info = image.info; const auto& info = image.info;
DownloadPlan plan {.depth = info.IsDepth()}; const auto binding = UploadBinding(image);
DownloadPlan plan {.depth_target = binding == BindingType::DepthTarget};
if (info.samples != 1 || image.backing.samples != 1) { if (info.samples != 1 || image.backing.samples != 1) {
return plan; return plan;
} }
if (plan.depth) { if (plan.depth_target) {
plan.valid = IsSupportedDepthPlaneReadback(info) && info.resources.layers != 0 && plan.valid = IsSupportedDepthPlaneReadback(info) && info.resources.layers != 0 &&
info.data.size % info.resources.layers == 0 && info.data.size % info.resources.layers == 0 &&
Prospero::NumBytesPerElement(info.guest_format) == info.bytes_per_block; Prospero::NumBytesPerElement(info.guest_format) == info.bytes_per_block;
@@ -922,8 +931,8 @@ TextureCache::DownloadPlan TextureCache::BuildDownload(const Image& image) const
if (info.metadata.compression != VideoOutCompression::Uncompressed) { if (info.metadata.compression != VideoOutCompression::Uncompressed) {
return plan; return plan;
} }
plan.color = BuildColorTransfer(image, UploadBinding(image), TransferDirection::Download); plan.texture = BuildTextureTransfer(image, binding, TransferDirection::Download);
plan.valid = plan.color.valid; plan.valid = plan.texture.valid;
return plan; return plan;
} }
@@ -938,9 +947,9 @@ void TextureCache::UploadImage(Image& image, Buffer& source, uint64_t source_off
}; };
if (binding != BindingType::DepthTarget) { if (binding != BindingType::DepthTarget) {
auto plan = BuildColorTransfer(image, binding, TransferDirection::Upload); auto plan = BuildTextureTransfer(image, binding, TransferDirection::Upload);
if (!plan.valid) { if (!plan.valid) {
EXIT("TextureCache: invalid color upload: binding=%u addr=0x%016" PRIx64 EXIT("TextureCache: invalid texture upload: binding=%u addr=0x%016" PRIx64
" size=0x%016" PRIx64 " format=%u tile=%u family=%u extent=%ux%ux%u " " size=0x%016" PRIx64 " format=%u tile=%u family=%u extent=%ux%ux%u "
"pitch=%u levels=%u layers=%u samples=%u\n", "pitch=%u levels=%u layers=%u samples=%u\n",
static_cast<uint32_t>(binding), info.data.address, info.data.size, static_cast<uint32_t>(binding), info.data.address, info.data.size,
@@ -1536,7 +1545,7 @@ void TextureCache::DownloadImageData(Image& image, Buffer& destination, uint64_t
if (!plan.valid) { if (!plan.valid) {
EXIT("TextureCache: invalid image download plan\n"); EXIT("TextureCache: invalid image download plan\n");
} }
if (plan.depth) { if (plan.depth_target) {
if (destination_size != image.info.data.size) { if (destination_size != image.info.data.size) {
EXIT("TextureCache: partial depth image download is unsupported\n"); EXIT("TextureCache: partial depth image download is unsupported\n");
} }
@@ -1544,26 +1553,26 @@ void TextureCache::DownloadImageData(Image& image, Buffer& destination, uint64_t
return; return;
} }
auto& color = plan.color; auto& texture = plan.texture;
const auto transform = color.swap_bgra16 ? TileManager::ColorTransform::SwapBgra16 const auto transform = texture.swap_bgra16 ? TileManager::ColorTransform::SwapBgra16
: TileManager::ColorTransform::None; : TileManager::ColorTransform::None;
if (!color.tiled) { if (!texture.tiled) {
if (transform == TileManager::ColorTransform::SwapBgra16) { if (transform == TileManager::ColorTransform::SwapBgra16) {
auto linear = m_tiler.GetScratchBuffer(destination_size); auto linear = m_tiler.GetScratchBuffer(destination_size);
image.Download(color.regions, linear.buffer, 0, linear.size); image.Download(texture.regions, linear.buffer, 0, linear.size);
m_tiler.SwapBgra16(linear, m_tiler.SwapBgra16(linear,
{destination.Handle(), destination_offset, destination_size}); {destination.Handle(), destination_offset, destination_size});
return; return;
} }
for (auto& copy: color.regions) { for (auto& copy: texture.regions) {
copy.bufferOffset += destination_offset; copy.bufferOffset += destination_offset;
} }
image.Download(color.regions, destination.Handle(), destination_offset, destination_size); image.Download(texture.regions, destination.Handle(), destination_offset, destination_size);
return; return;
} }
m_tiler.TileImage(image, color.regions, destination.Handle(), destination_offset, m_tiler.TileImage(image, texture.regions, destination.Handle(), destination_offset,
destination_size, color.linear_size, color.tiles, transform); destination_size, texture.linear_size, texture.tiles, transform);
} }
bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uint64_t size) { bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uint64_t size) {
@@ -1634,24 +1643,24 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uin
if (!plan.valid) { if (!plan.valid) {
return false; return false;
} }
if (plan.depth && copy_size != image.info.data.size) { if (plan.depth_target && copy_size != image.info.data.size) {
return false; return false;
} }
if (!plan.depth && levels < image.info.resources.levels) { if (!plan.depth_target && levels < image.info.resources.levels) {
auto& color = plan.color; auto& texture = plan.texture;
std::erase_if(color.regions, [levels](const vk::BufferImageCopy& region) { std::erase_if(texture.regions, [levels](const vk::BufferImageCopy& region) {
return region.imageSubresource.mipLevel >= levels; return region.imageSubresource.mipLevel >= levels;
}); });
if (color.regions.empty()) { if (texture.regions.empty()) {
return false; return false;
} }
if (color.tiled) { if (texture.tiled) {
color.tiles.clear(); texture.tiles.clear();
if (!TextureBuildGpuTileInfos(copy_size, color.regions, color.layout, levels, if (!TextureBuildGpuTileInfos(copy_size, texture.regions, texture.layout, levels,
color.tiles)) { texture.tiles)) {
return false; return false;
} }
color.linear_size = GetLinearSize(color.tiles); texture.linear_size = GetLinearSize(texture.tiles);
} }
} }
m_texture_cache.DownloadImageData(image, buffer, buf_offset, copy_size, std::move(plan)); m_texture_cache.DownloadImageData(image, buffer, buf_offset, copy_size, std::move(plan));
+4 -4
View File
@@ -83,7 +83,7 @@ public:
private: private:
enum class TransferDirection { Upload, Download }; enum class TransferDirection { Upload, Download };
struct ColorTransferPlan; struct TextureTransferPlan;
struct DownloadPlan; struct DownloadPlan;
struct MetaDataInfo { struct MetaDataInfo {
@@ -139,9 +139,9 @@ private:
[[nodiscard]] ImageId ExpandImage(const ImageInfo& info, ImageId source); [[nodiscard]] ImageId ExpandImage(const ImageInfo& info, ImageId source);
void RefreshImage(ImageId id); void RefreshImage(ImageId id);
void InitializeImage(ImageId id); void InitializeImage(ImageId id);
[[nodiscard]] ColorTransferPlan BuildColorTransfer(const Image& image, BindingType binding, [[nodiscard]] TextureTransferPlan
TransferDirection direction) const; BuildTextureTransfer(const Image& image, BindingType binding, TransferDirection direction) const;
[[nodiscard]] DownloadPlan BuildDownload(const Image& image) const; [[nodiscard]] DownloadPlan BuildDownload(const Image& image) const;
void UploadImage(Image& image, Buffer& source, uint64_t source_offset); void UploadImage(Image& image, Buffer& source, uint64_t source_offset);
void DownloadImageData(Image& image, Buffer& destination, uint64_t destination_offset, void DownloadImageData(Image& image, Buffer& destination, uint64_t destination_offset,
uint64_t destination_size, DownloadPlan plan); uint64_t destination_size, DownloadPlan plan);
@@ -252,7 +252,7 @@ bool IsSupportedSampledVideoOutView(const ShaderRecompiler::IR::ImageResource& r
descriptor.BaseArray5() == 0; descriptor.BaseArray5() == 0;
} }
bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, const Image& image, bool IsSupportedSampledDepthDescriptor(const ShaderTextureResource& descriptor, const Image& image,
bool r128) { 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;
@@ -291,7 +291,9 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c
(supported_2d || supported_array || supported_cube || supported_msaa_2d || (supported_2d || supported_array || supported_cube || supported_msaa_2d ||
supported_msaa_array) && supported_msaa_array) &&
levels_ok && descriptor.MinLod() == 0 && levels_ok && descriptor.MinLod() == 0 &&
descriptor.TileMode() == Prospero::TileMode::kDepth && descriptor.BCSwizzle() == 0 && descriptor.TileMode() == image.info.tile_mode &&
(!multisampled || descriptor.TileMode() == Prospero::TileMode::kDepth) &&
descriptor.BCSwizzle() == 0 &&
(!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch; (!descriptor.MsaaDepth() || multisampled) && pitch >= width && pitch == image.info.pitch;
} }
@@ -332,12 +334,12 @@ bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, co
image.info.metadata.range.Valid() && image.info.metadata.range.address == metadata_addr; image.info.metadata.range.Valid() && image.info.metadata.range.address == metadata_addr;
} }
static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource& resource, static void ValidateSampledDepthBinding(const ShaderRecompiler::IR::ImageResource& resource,
const ShaderTextureResource& descriptor, const Image* image, const ShaderTextureResource& descriptor, const Image* image,
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, resource.r128); image != nullptr && IsSupportedSampledDepthDescriptor(descriptor, *image, resource.r128);
const bool encoding_ok = const bool encoding_ok =
image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image, resource.r128); image != nullptr && IsSupportedDepthTextureEncoding(descriptor, *image, resource.r128);
const bool format_ok = const bool format_ok =
@@ -348,7 +350,7 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource
const auto descriptor_pitch = const auto descriptor_pitch =
TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u, TileGetTexturePitch(descriptor.Format(), static_cast<uint32_t>(descriptor.Width5()) + 1u,
descriptor.TileMode()); descriptor.TileMode());
EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d " EXIT("unsupported sampled depth image: resource=%d descriptor=%d encoding=%d format=%d "
"class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d " "class=%u numeric=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d "
"guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u " "guest_format=%u swizzle=0x%03x image_format=%d view_format=%d image_layers=%u "
"descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u " "descriptor_type=%u base_array=%u depth=%u descriptor_pitch=%u target_pitch=%u "
@@ -745,7 +747,10 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
ValidateStorageTexture(resource, descriptor, size.size); ValidateStorageTexture(resource, descriptor, size.size);
} }
const auto pixel_format = surface_format.vk_format; const auto* depth_format = resource.depth_compare ? FindGuestDepthFormatPolicy(format) : nullptr;
EXIT_NOT_IMPLEMENTED(resource.depth_compare && depth_format == nullptr);
const auto pixel_format =
depth_format != nullptr ? depth_format->depth_attachment_format : surface_format.vk_format;
const auto storage_view_format = storage && format == Prospero::BufferFormat::k32SInt const auto storage_view_format = storage && format == Prospero::BufferFormat::k32SInt
? vk::Format::eR32Uint ? vk::Format::eR32Uint
: SrgbStorageViewFormat(pixel_format); : SrgbStorageViewFormat(pixel_format);
@@ -784,7 +789,7 @@ TextureBinding RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageR
if (storage) { if (storage) {
EXIT("depth target cannot be bound as a storage image\n"); EXIT("depth target cannot be bound as a storage image\n");
} }
ValidateDepthTargetBinding(resource, descriptor, image, pixel_format, size.size); ValidateSampledDepthBinding(resource, descriptor, image, pixel_format, size.size);
(void)SelectSampledDepthView(image->info.pixel_format, pixel_format, (void)SelectSampledDepthView(image->info.pixel_format, pixel_format,
descriptor.DstSelXYZW()); descriptor.DstSelXYZW());
} else if (storage) { } else if (storage) {
@@ -78,8 +78,8 @@ struct TargetTextureViewInfo {
ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource, 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 IsSupportedSampledDepthDescriptor(const ShaderTextureResource& descriptor,
const Image& image, bool r128 = false); const Image& image, bool r128 = false);
[[nodiscard]] bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor, [[nodiscard]] bool IsSupportedDepthTextureEncoding(const ShaderTextureResource& descriptor,
const Image& image, bool r128 = false); const Image& image, bool r128 = false);
[[nodiscard]] bool [[nodiscard]] bool
+178 -10
View File
@@ -7744,6 +7744,170 @@ public:
std::printf("[gpu] %-32s ok\n", name); std::printf("[gpu] %-32s ok\n", name);
} }
void CheckComparisonDepthTexture() {
constexpr const char *name = "ComparisonDepthTexture";
constexpr uintptr_t base = 0x0000000204200000ull;
constexpr uint64_t allocation_size = 0x10000;
constexpr uint64_t ordinary_address = base + 0x1000;
constexpr std::array<uint16_t, 6> depths{0, 13107, 26214, 39321, 52428, 65535};
constexpr std::array<float, 5> references{0.1f, 0.3f, 0.5f, 0.7f, 0.9f};
EnsureRuntimeContext();
int64_t direct_offset = -1;
Require(name, "direct allocation",
Libs::LibKernel::Memory::KernelAllocateDirectMemory(
0, Libs::LibKernel::Memory::KernelGetDirectMemorySize(),
allocation_size, allocation_size, 0, &direct_offset) == 0,
"comparison texture allocation failed");
void *mapped = reinterpret_cast<void *>(base);
Require(name, "direct mapping",
Libs::LibKernel::Memory::KernelMapDirectMemory(
&mapped, allocation_size, 0x3, 0x10, direct_offset,
allocation_size) == 0 && mapped == reinterpret_cast<void *>(base),
"comparison texture mapping failed");
std::memset(mapped, 0, allocation_size);
for (uint32_t face = 0; face < depths.size(); face++) {
for (const auto address : {base, ordinary_address}) {
std::memcpy(reinterpret_cast<void *>(address + face * 0x100),
&depths[face], sizeof(uint16_t));
}
}
{
RenderContext context(m_runtime_context);
auto &scheduler = context.GetCommandScheduler();
HW::Context registers{};
HW::UserConfig user_config{};
HW::Shader shaders{};
scheduler.Begin(registers, user_config, shaders);
auto &resources = context.GetGpuResources();
auto &cache = resources.GetTextureCache();
auto &executor = context.GetRenderExecutor();
resources.MapMemory(base, allocation_size);
ShaderTextureResource descriptor{{static_cast<uint32_t>(base >> 8u),
0x00700000u, 0, 0xb0100204u, 5, 0x00700000u, 0, 0}};
ShaderSamplerResource sampler_descriptor{{1u << 12u, 0, 1u << 24u, 0}};
TestCase test;
test.name = name;
test.has_user_data = true;
test.image_descriptor_swizzle = descriptor.DstSelXYZW();
std::copy_n(descriptor.fields, 8, test.user_data.begin());
std::copy_n(sampler_descriptor.fields, 4, test.user_data.begin() + 8);
test.user_data[50] = depths.size() * references.size() * sizeof(uint32_t);
test.opcodes = {ShaderOpcode::V_MOV_B32, ShaderOpcode::IMAGE_SAMPLE,
ShaderOpcode::BUFFER_STORE_DWORD, ShaderOpcode::S_ENDPGM};
test.required_spirv = {"OpImageSampleDrefExplicitLod"};
std::vector<uint32_t> promoted_expected;
for (uint32_t face = 0; face < depths.size(); face++) {
for (const auto reference : references) {
AppendVMovLiteral(&test.code, 20, std::bit_cast<uint32_t>(reference));
AppendVMovLiteral(&test.code, 21, std::bit_cast<uint32_t>(1.5f));
AppendVMovLiteral(&test.code, 22, std::bit_cast<uint32_t>(1.5f));
AppendVMovLiteral(&test.code, 23, std::bit_cast<uint32_t>(static_cast<float>(face)));
test.code.push_back(EncodeMimg0(0x2f, 1, 0, false, 3));
test.code.push_back(EncodeMimg1(0, 20, 0, 2));
AppendStoreVgpr(&test.code, 0, static_cast<uint32_t>(test.expected.size()));
test.expected.push_back(reference < static_cast<float>(depths[face]) / 65535.f
? 0x3f800000u : 0u);
promoted_expected.push_back(reference < static_cast<float>(depths[5 - face]) / 65535.f
? 0x3f800000u : 0u);
}
}
AppendEnd(&test.code);
const auto compiled = CompileCase(test, SubgroupSize());
Require(name, "comparison resource", compiled.program.info.images.size() == 1 &&
compiled.program.info.images[0].depth_compare &&
compiled.program.info.images[0].cube,
"native cube comparison did not retain its resource semantics");
ShaderRecompiler::IR::DescriptorValue value{};
value.dword_count = 8;
std::copy_n(descriptor.fields, 8, value.dwords.begin());
auto binding = RenderExecutorTestAccess::ResolveTexture(
executor, compiled.program.info.images[0], value);
const auto view = cache.FindTexture(binding.image_id, binding.desc);
auto &image = cache.GetImage(binding.image_id);
Require(name, "fresh depth backing", view != nullptr &&
image.info.pixel_format == vk::Format::eD16Unorm &&
image.info.guest_format == Prospero::BufferFormat::k16UNorm &&
image.info.tile_mode == Prospero::TileMode::kStandard256B &&
image.info.data.size == 0x600 && image.info.resources.layers == 6,
"comparison texture lost its guest layout or depth representation");
auto ordinary_resource = compiled.program.info.images[0];
ordinary_resource.depth_compare = false;
value.dwords[0] = static_cast<uint32_t>(ordinary_address >> 8u);
auto ordinary = RenderExecutorTestAccess::ResolveTexture(executor, ordinary_resource, value);
(void)cache.FindTexture(ordinary.image_id, ordinary.desc);
auto &color = cache.GetImage(ordinary.image_id);
Require(name, "ordinary R16", color.info.pixel_format == vk::Format::eR16Unorm,
"ordinary R16 sampling unexpectedly acquired a depth format");
scheduler.Finish();
auto output = CreateStorageBuffer(name, {}, test.expected.size());
const auto sampler = context.GetSamplerCache().GetSampler(sampler_descriptor);
Image sampled;
sampled.view = view;
sampled.layout = image.backing.state.layout;
Dispatch(test, compiled, output, nullptr, &sampled, nullptr, nullptr, sampler);
Require(name, "six face comparisons",
ReadBuffer(name, output, test.expected.size()) == test.expected,
"comparison samples lost a depth value or Standard256B face stride");
image.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
{}, scheduler.Current().Handle());
color.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
{}, scheduler.Current().Handle());
for (uint32_t face = 0; face < depths.size(); face++) {
const vk::ImageSubresourceRange depth_range{vk::ImageAspectFlagBits::eDepth, 0, 1, face, 1};
const vk::ClearDepthStencilValue clear_depth{
static_cast<float>(depths[5 - face]) / 65535.f, 0};
scheduler.Current().Handle().clearDepthStencilImage(image.backing.image,
vk::ImageLayout::eTransferDstOptimal, &clear_depth, 1, &depth_range);
const vk::ImageSubresourceRange color_range{vk::ImageAspectFlagBits::eColor, 0, 1, face, 1};
const vk::ClearColorValue clear_color{std::array<float, 4>{
static_cast<float>(depths[5 - face]) / 65535.f, 0.f, 0.f, 0.f}};
scheduler.Current().Handle().clearColorImage(color.backing.image,
vk::ImageLayout::eTransferDstOptimal, &clear_color, 1, &color_range);
}
cache.MarkGpuWritten(binding.image_id);
cache.MarkGpuWritten(ordinary.image_id);
Require(name, "depth readback", TextureCacheTestAccess::TryDownload(cache, binding.image_id),
"ordinary tiled depth readback did not use the shared transfer path");
scheduler.Finish();
scheduler.DrainPriorityOperations();
for (uint32_t face = 0; face < depths.size(); face++) {
uint16_t actual = 0;
std::memcpy(&actual, reinterpret_cast<const void *>(base + face * 0x100), sizeof(actual));
Require(name, "depth guest roundtrip", actual == depths[5 - face],
"GPU depth clear was not written to the correct guest face");
}
auto promoted = RenderExecutorTestAccess::ResolveTexture(
executor, compiled.program.info.images[0], value);
sampled.view = cache.FindTexture(promoted.image_id, promoted.desc);
auto &promoted_image = cache.GetImage(promoted.image_id);
Require(name, "GPU color owner promotion", promoted.image_id != ordinary.image_id &&
promoted_image.info.pixel_format == vk::Format::eD16Unorm &&
promoted_image.IsGpuModified(),
"comparison binding did not preserve the GPU-current color owner");
sampled.layout = promoted_image.backing.state.layout;
scheduler.Finish();
Dispatch(test, compiled, output, nullptr, &sampled, nullptr, nullptr, sampler);
Require(name, "promoted comparisons",
ReadBuffer(name, output, promoted_expected.size()) == promoted_expected,
"color-to-depth ownership conversion changed comparison results");
DestroyBuffer(&output);
RenderExecutorTestAccess::ResetBindings(executor);
resources.UnmapMemory(base, allocation_size);
scheduler.Finish();
}
Require(name, "unmap", Libs::LibKernel::Memory::KernelMunmap(base, allocation_size) == 0,
"comparison texture unmap failed");
Require(name, "release", Libs::LibKernel::Memory::KernelReleaseDirectMemory(
direct_offset, allocation_size) == 0,
"comparison texture release failed");
std::printf("[gpu] %-32s ok\n", name);
}
void CheckRenderExecutorColorStandardTileDiscovery() { void CheckRenderExecutorColorStandardTileDiscovery() {
constexpr const char *name = "RenderExecutorColorStandardTile"; constexpr const char *name = "RenderExecutorColorStandardTile";
constexpr uintptr_t base = 0x0000000203b00000ull; constexpr uintptr_t base = 0x0000000203b00000ull;
@@ -9943,7 +10107,9 @@ public:
image.dimension == image.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim1D || ShaderRecompiler::Decoder::ImageDimension::Dim1D ||
image.dimension == image.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim1DArray; ShaderRecompiler::Decoder::ImageDimension::Dim1DArray ||
image.dimension ==
ShaderRecompiler::Decoder::ImageDimension::Dim2DArray;
} }
Require(test.name, "dispatch", supported, Require(test.name, "dispatch", supported,
"unsupported image dimension needs a matching Vulkan test view"); "unsupported image dimension needs a matching Vulkan test view");
@@ -23648,7 +23814,7 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
Require("SampledDepthDescriptor", "normalized padded pitch", Require("SampledDepthDescriptor", "normalized padded pitch",
descriptor.Width5() + 1u == image.info.extent.width && descriptor.Width5() + 1u == image.info.extent.width &&
descriptor.Height5() + 1u == image.info.extent.height && descriptor.Height5() + 1u == image.info.extent.height &&
IsSupportedDepthTargetDescriptor(descriptor, image), IsSupportedSampledDepthDescriptor(descriptor, image),
"normalized depth image rejected a valid padded descriptor"); "normalized depth image rejected a valid padded descriptor");
const ShaderTextureResource disabled_sampler_tweaks{{ const ShaderTextureResource disabled_sampler_tweaks{{
@@ -23682,7 +23848,7 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
Image msaa_image(context, scheduler, msaa_info); Image msaa_image(context, scheduler, msaa_info);
msaa_image.usage.depth_target = true; msaa_image.usage.depth_target = true;
Require("SampledDepthDescriptor", "uncompressed 2x MSAA depth", Require("SampledDepthDescriptor", "uncompressed 2x MSAA depth",
IsSupportedDepthTargetDescriptor(uncompressed_msaa, msaa_image) && IsSupportedSampledDepthDescriptor(uncompressed_msaa, msaa_image) &&
IsSupportedDepthTextureEncoding(uncompressed_msaa, msaa_image), IsSupportedDepthTextureEncoding(uncompressed_msaa, msaa_image),
"valid uncompressed MSAA depth descriptor required an HTILE " "valid uncompressed MSAA depth descriptor required an HTILE "
"compatibility flag"); "compatibility flag");
@@ -23690,7 +23856,7 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
auto r128_msaa = uncompressed_msaa; auto r128_msaa = uncompressed_msaa;
std::fill(r128_msaa.fields + 4, r128_msaa.fields + 8, 0u); std::fill(r128_msaa.fields + 4, r128_msaa.fields + 8, 0u);
Require("SampledDepthDescriptor", "R128 uncompressed 2x MSAA depth", Require("SampledDepthDescriptor", "R128 uncompressed 2x MSAA depth",
IsSupportedDepthTargetDescriptor(r128_msaa, msaa_image, true) && IsSupportedSampledDepthDescriptor(r128_msaa, msaa_image, true) &&
IsSupportedDepthTextureEncoding(r128_msaa, msaa_image, true), IsSupportedDepthTextureEncoding(r128_msaa, msaa_image, true),
"valid R128 MSAA depth descriptor required omitted dwords"); "valid R128 MSAA depth descriptor required omitted dwords");
@@ -23698,7 +23864,7 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
(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);
Require("SampledDepthDescriptor", "singleton array descriptor", Require("SampledDepthDescriptor", "singleton array descriptor",
IsSupportedDepthTargetDescriptor(descriptor, image), IsSupportedSampledDepthDescriptor(descriptor, image),
"normalized singleton-array depth view was rejected"); "normalized singleton-array depth view was rejected");
descriptor.fields[3] = descriptor.fields[3] =
(descriptor.fields[3] & ~(0xfu << 28u)) | (descriptor.fields[3] & ~(0xfu << 28u)) |
@@ -23723,7 +23889,7 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
ResolveTargetTextureView(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) && IsSupportedSampledDepthDescriptor(cube_descriptor, cube_image) &&
IsSupportedDepthTextureEncoding(cube_descriptor, cube_image) && IsSupportedDepthTextureEncoding(cube_descriptor, cube_image) &&
cube_view.type == vk::ImageViewType::e2DArray && cube_view.type == vk::ImageViewType::e2DArray &&
cube_view.layer_count == 6, cube_view.layer_count == 6,
@@ -23787,14 +23953,14 @@ void CheckSampledDepthDescriptor(RenderContext &renderer) {
(non_square_cube.fields[2] & ~(0x3fffu << 14u)) | (511u << 14u); (non_square_cube.fields[2] & ~(0x3fffu << 14u)) | (511u << 14u);
image.info.pitch = 1344; image.info.pitch = 1344;
const bool rejects_pitch = const bool rejects_pitch =
!IsSupportedDepthTargetDescriptor(descriptor, image); !IsSupportedSampledDepthDescriptor(descriptor, image);
image.info.pitch = 1408; image.info.pitch = 1408;
Require("SampledDepthDescriptor", "normalized hard guards", Require("SampledDepthDescriptor", "normalized hard guards",
rejects_pitch && rejects_pitch &&
!IsSupportedDepthTargetDescriptor(partial_cube, cube_image) && !IsSupportedSampledDepthDescriptor(partial_cube, cube_image) &&
!IsSupportedDepthTargetDescriptor(based_cube, cube_image) && !IsSupportedSampledDepthDescriptor(based_cube, cube_image) &&
!IsSupportedDepthTextureEncoding(reserved_cube, cube_image) && !IsSupportedDepthTextureEncoding(reserved_cube, cube_image) &&
!IsSupportedDepthTargetDescriptor(non_square_cube, cube_image), !IsSupportedSampledDepthDescriptor(non_square_cube, cube_image),
"normalized depth descriptor accepted an incompatible image view"); "normalized depth descriptor accepted an incompatible image view");
std::printf("[host] %-32s ok\n", "SampledDepthDescriptor"); std::printf("[host] %-32s ok\n", "SampledDepthDescriptor");
} }
@@ -26863,6 +27029,7 @@ int main(int argc, char **argv) {
VulkanHarness vulkan; VulkanHarness vulkan;
CheckSampledDepthResource(); CheckSampledDepthResource();
CheckSampledDepthDescriptor(vulkan.RuntimeRenderer()); CheckSampledDepthDescriptor(vulkan.RuntimeRenderer());
vulkan.CheckComparisonDepthTexture();
return 0; return 0;
} }
if (argc == 2 && std::strcmp(argv[1], "--storage-bgra-only") == 0) { if (argc == 2 && std::strcmp(argv[1], "--storage-bgra-only") == 0) {
@@ -26913,6 +27080,7 @@ int main(int argc, char **argv) {
CheckImageTransitionState(vulkan.RuntimeRenderer()); CheckImageTransitionState(vulkan.RuntimeRenderer());
CheckSampledDepthResource(); CheckSampledDepthResource();
CheckSampledDepthDescriptor(vulkan.RuntimeRenderer()); CheckSampledDepthDescriptor(vulkan.RuntimeRenderer());
vulkan.CheckComparisonDepthTexture();
CheckBasicStorageTextureDescriptor(); CheckBasicStorageTextureDescriptor();
CheckStorageTextureLinearUploadLayout(); CheckStorageTextureLinearUploadLayout();
CheckStorageTextureDepthTileUploadLayout(); CheckStorageTextureDepthTileUploadLayout();