From 2aa0a64f6385c0816d792da90004da97907c44fc Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 23 Sep 2026 19:46:41 +0400 Subject: [PATCH] materialize compressed video-out DCC clears before flip PPSA27624 --- .../host_gpu/renderer/cache/textureCache.cpp | 26 +++++++++++-------- src/graphics/presentation/videoOut.cpp | 7 ++++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index c8cd7c7ec..e5c286107 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -1210,7 +1210,9 @@ void TextureCache::MaterializeDccClear(ImageId id, const ImageDesc& desc, } // Native expanded keys own consumption. Existing buffer tracking publishes this CPU // write to future GPU readers; FillBuffer can fault and must run outside the texture lock. - m_buffer_cache.FillBuffer(address, slice_size, UINT32_MAX, false); + if (desc.type != BindingType::VideoOut) { + m_buffer_cache.FillBuffer(address, slice_size, UINT32_MAX, false); + } } } @@ -1331,16 +1333,6 @@ ImageId TextureCache::FindImage(ImageDesc& desc, bool exact_format) { } } auto& image = m_slot_images[result]; - if (desc.type == BindingType::VideoOut && - desc.info.metadata.compression != VideoOutCompression::Uncompressed) { - const bool guest_dirty = image.IsBufferModified() || image.IsCpuDirty(); - const bool native_current = - (image.usage.render_target || image.IsGpuModified()) && !guest_dirty; - if (!native_current) { - EXIT("TextureCache: compressed video-out read requires clean native GPU " - "contents\n"); - } - } if (view_mip >= 0) { desc.view_info.base_level = static_cast(view_mip); } @@ -1351,6 +1343,18 @@ ImageId TextureCache::FindImage(ImageDesc& desc, bool exact_format) { TouchImage(image); } MaterializeDccClear(result, desc, metadata_base_layer); + if (desc.type == BindingType::VideoOut && + desc.info.metadata.compression != VideoOutCompression::Uncompressed) { + std::scoped_lock lock {m_lock}; + const auto& image = m_slot_images[result]; + const bool guest_dirty = image.IsBufferModified() || image.IsCpuDirty(); + const bool native_current = + (image.usage.render_target || image.IsGpuModified()) && !guest_dirty; + if (!native_current) { + EXIT("TextureCache: compressed video-out read requires clean native GPU " + "contents\n"); + } + } return result; } diff --git a/src/graphics/presentation/videoOut.cpp b/src/graphics/presentation/videoOut.cpp index b2763cff1..b75dd2d36 100644 --- a/src/graphics/presentation/videoOut.cpp +++ b/src/graphics/presentation/videoOut.cpp @@ -565,7 +565,12 @@ Graphics::ImageInfo BufferAttributeGroup::ImageInfo(const VideoOutBuffer& buffer info.bgra16 = pixel_format.bgra16; info.mip_layout[0] = {0, total.size, pitch, attribute.height}; if (compression != Graphics::VideoOutCompression::Uncompressed) { - info.metadata.range = {buffer.metadata_address, 0}; + Graphics::TileSizeAlign dcc_size {}; + if (!Graphics::TileGetDccSize(attribute.width, attribute.height, 1, + pixel_format.bytes_per_element, 1, tile_mode, dcc_size)) { + EXIT("invalid video-out DCC footprint\n"); + } + info.metadata.range = {buffer.metadata_address, dcc_size.size}; info.metadata.kind = Graphics::ImageMetadataKind::Dcc; info.metadata.control = attribute.dcc_control; info.metadata.compression = compression;