From f136c46519fe7dd86d0c4bdd62dbd9b568db0567 Mon Sep 17 00:00:00 2001 From: nmzik Date: Fri, 17 Jul 2026 21:56:09 +0200 Subject: [PATCH] preserve DB_DEPTH_SIZE_XY and add tiled readback --- .../command_processor/pm4Handlers.cpp | 2 +- src/graphics/guest_gpu/tile.cpp | 40 ++++++++++++++++++- src/graphics/guest_gpu/tile.h | 4 +- src/graphics/host_gpu/graphicContext.h | 6 +++ .../host_gpu/renderer/depthRenderTarget.cpp | 7 +++- src/graphics/host_gpu/renderer/tiler.cpp | 33 +++++++++++++++ src/graphics/host_gpu/renderer/tiler.h | 1 + 7 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index fec2b9a5..8af12d85 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -4138,7 +4138,7 @@ void GraphicsInitJmpTablesCxIndirect() { HW::DepthDepthSizeXY r; r.x_max = KYTY_PM4_GET(value, DB_DEPTH_SIZE_XY, X_MAX); r.y_max = KYTY_PM4_GET(value, DB_DEPTH_SIZE_XY, Y_MAX); - r.valid = (r.x_max != 0 || r.y_max != 0); + r.valid = true; cp->GetCtx()->SetDepthDepthSizeXY(r); }; g_hw_ctx_indirect_func[Pm4::DB_DEPTH_SIZE] = [](KYTY_HW_CTX_INDIRECT_ARGS) { diff --git a/src/graphics/guest_gpu/tile.cpp b/src/graphics/guest_gpu/tile.cpp index ff51716b..8084300b 100644 --- a/src/graphics/guest_gpu/tile.cpp +++ b/src/graphics/guest_gpu/tile.cpp @@ -1793,6 +1793,32 @@ static void TileConvertTiledToLinearStandard64KB64Elements( } } +static void TileConvertLinearToTiledStandard64KB64Elements( + void* dst, const void* src, uint32_t width_elements, uint32_t height_elements, + uint32_t pitch_elements, uint64_t size, uint64_t dst_size, uint32_t dst_x, uint32_t dst_y) { + if (width_elements > pitch_elements) { + EXIT("invalid linear-to-Standard64KB64 tail conversion, extent=%ux%u pitch=%u " + "size=0x%016" PRIx64 " dst_size=0x%016" PRIx64 " dst=%u,%u\n", + width_elements, height_elements, pitch_elements, size, dst_size, dst_x, dst_y); + } + auto* dst64 = static_cast(dst); + const auto* src64 = static_cast(src); + const auto& tables = GetStandard64KB64Tables(); + const auto size_words = size >> 3u; + const auto dst_size_words = dst_size >> 3u; + for (uint32_t y = 0; y < height_elements; y++) { + const uint64_t src_row = static_cast(y) * pitch_elements; + const uint64_t dst_row = tables.y_words[dst_y + y]; + for (uint32_t x = 0; x < width_elements; x++) { + const uint64_t src_index = src_row + x; + const uint64_t dst_index = dst_row + tables.x_words[dst_x + x]; + if (src_index < size_words && dst_index < dst_size_words) { + dst64[dst_index] = src64[src_index]; + } + } + } +} + static void TileConvertTiledToLinearStandard64KB128Elements( void* dst, const void* src, uint32_t width_elements, uint32_t height_elements, uint32_t pitch_elements, uint64_t size, uint64_t src_size, uint32_t src_x, uint32_t src_y) { @@ -2474,8 +2500,20 @@ void TileConvertTiledToLinearRenderTarget(void* dst, const void* src, uint32_t w void TileConvertLinearToTiledRenderTarget(void* dst, const void* src, uint32_t width, uint32_t height, uint32_t pitch, - uint32_t bytes_per_element, uint64_t size) { + uint32_t bytes_per_element, uint64_t size, + uint64_t dst_size, uint32_t dst_x, uint32_t dst_y) { KYTY_PROFILER_FUNCTION(); + const bool tail_block = dst_size != 0 && (dst_x != 0 || dst_y != 0 || size < dst_size); + if (tail_block) { + //Not sure about this at all + if (bytes_per_element != 8) { + EXIT("unsupported linear-to-tiled render-target tail element size: %u\n", + bytes_per_element); + } + TileConvertLinearToTiledStandard64KB64Elements(dst, src, width, height, pitch, size, + dst_size, dst_x, dst_y); + return; + } if (dst == nullptr || src == nullptr || width == 0 || height == 0 || pitch == 0 || width > pitch || bytes_per_element == 0 || size == 0 || size % bytes_per_element != 0) { diff --git a/src/graphics/guest_gpu/tile.h b/src/graphics/guest_gpu/tile.h index c66ec97b..49a3d8cb 100644 --- a/src/graphics/guest_gpu/tile.h +++ b/src/graphics/guest_gpu/tile.h @@ -44,7 +44,9 @@ void TileConvertTiledToLinearRenderTarget(void* dst, const void* src, uint32_t w uint32_t src_y = 0); void TileConvertLinearToTiledRenderTarget(void* dst, const void* src, uint32_t width, uint32_t height, uint32_t pitch, - uint32_t bytes_per_element, uint64_t size); + uint32_t bytes_per_element, uint64_t size, + uint64_t dst_size = 0, uint32_t dst_x = 0, + uint32_t dst_y = 0); void TileConvertTiledToLinearStandard64KB(void* dst, const void* src, uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, uint64_t size, uint64_t src_size = 0, uint32_t src_x = 0, diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index 343451a2..4ec54f3e 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -130,6 +130,10 @@ struct TextureVulkanImage: public GpuTextureVulkanImage { }; struct StorageTextureVulkanImage: public GpuTextureVulkanImage { + struct StorageView { + uint32_t base_level = 0; + VkImageView view = nullptr; + }; struct SampledView { VkFormat format = VK_FORMAT_UNDEFINED; uint32_t swizzle = 0; @@ -141,6 +145,8 @@ struct StorageTextureVulkanImage: public GpuTextureVulkanImage { StorageTextureVulkanImage(): GpuTextureVulkanImage(VulkanImageType::StorageTexture) {} std::mutex sampled_view_mutex; std::vector sampled_views; + std::mutex storage_view_mutex; + std::vector storage_views; }; struct RenderTextureVulkanImage: public VulkanImage { diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index da12f22e..374f2e02 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -126,7 +126,10 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H z.htile_surface.prefetch_height == 0 && z.htile_surface.dst_outside_zero_to_one == 0 && z.z_read_base_addr == 0 && z.z_write_base_addr == 0 && z.stencil_read_base_addr == 0 && z.stencil_write_base_addr == 0 && z.htile_data_base_addr == 0 && - !z.z_info.tile_surface_enable && !z.size.valid && !z.width_height_valid && + // DB_DEPTH_SIZE_XY is independent state and may remain programmed after the attachment + // formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its + // presence alone must not manufacture a depth attachment. + !z.z_info.tile_surface_enable && !z.width_height_valid && !z.pitch_height_valid && z.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; @@ -215,7 +218,7 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H } else if (z.htile_data_base_addr != 0) { DepthFatal("HTile address without an enabled tile surface"); } - const bool size_xy_valid = z.size.valid && (z.size.x_max != 0 || z.size.y_max != 0); + const bool size_xy_valid = z.size.valid; const bool wh_valid = z.width_height_valid && z.width != 0 && z.height != 0; if (!size_xy_valid && !wh_valid) { DepthFatal("missing depth extent"); diff --git a/src/graphics/host_gpu/renderer/tiler.cpp b/src/graphics/host_gpu/renderer/tiler.cpp index cc0163fb..4b4ce4bc 100644 --- a/src/graphics/host_gpu/renderer/tiler.cpp +++ b/src/graphics/host_gpu/renderer/tiler.cpp @@ -2,6 +2,7 @@ #include "common/assert.h" #include "graphics/guest_gpu/gpu_defs.h" +#include "graphics/guest_gpu/gpu_format.h" #include "graphics/guest_gpu/tile.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/objects/textureCommon.h" @@ -170,6 +171,38 @@ void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) } } +void Tiler::TileImage(void* dst, const void* src, const ImageInfo& info) const { + const bool image_2d = info.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) && + info.depth == 1; + const auto bytes_per_element = Prospero::RenderTargetBytesPerElement(info.format); + if (!image_2d || info.levels == 0 || info.levels > 16 || + info.tile != Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || + bytes_per_element == 0) { + EXIT("Tiler: unsupported storage-texture tile, addr=0x%016" PRIx64 + "+0x%016" PRIx64 " extent=%ux%ux%u levels=%u tile=%u format=%u\n", + info.address, info.size, info.width, info.height, info.depth, info.levels, info.tile, + info.format); + } + auto layout = TextureCalcUploadLayout(info.format, info.width, info.height, info.levels, + info.depth, info.pitch, info.tile, info.size, true, false, + false, "StorageTextureReadback"); + auto regions = TextureBuildUploadRegions( + layout, Prospero::SurfaceFormat(info.format), info.width, info.height, info.depth, + info.levels, false, false, TextureUploadDestination::MipLevels, + TextureUploadSliceLayout::MipChainPerSlice); + std::memset(dst, 0, info.size); + for (uint32_t level = 0; level < info.levels; level++) { + const auto& level_size = layout.level_sizes[level]; + const auto guest_offset = level_size.src_size != 0 ? level_size.src_offset + : level_size.offset; + auto* guest = static_cast(dst) + guest_offset; + const auto* linear = static_cast(src) + regions[level].offset; + TileConvertLinearToTiledRenderTarget( + guest, linear, regions[level].width, regions[level].height, regions[level].pitch, + bytes_per_element, level_size.size, level_size.src_size, level_size.x, level_size.y); + } +} + void Tiler::TileImage(void* dst, const void* src, const DepthTargetInfo& info) const { if (info.stencil_address != 0 || info.stencil_size != 0 || info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) || diff --git a/src/graphics/host_gpu/renderer/tiler.h b/src/graphics/host_gpu/renderer/tiler.h index 5cc19ab0..cede1a43 100644 --- a/src/graphics/host_gpu/renderer/tiler.h +++ b/src/graphics/host_gpu/renderer/tiler.h @@ -25,6 +25,7 @@ public: const DepthTargetInfo& info, const BufferImageCopySource& source, bool refresh, uint32_t base_layer = 0) const; void TileImage(void* dst, const void* src, const RenderTargetInfo& info) const; + void TileImage(void* dst, const void* src, const ImageInfo& info) const; void TileImage(void* dst, const void* src, const DepthTargetInfo& info) const; };