diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index 6b876056d..d37fec456 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -791,13 +791,6 @@ TextureCache::OverlapResult TextureCache::ResolveOverlap(const ImageInfo& reques if (const auto depth_id = ResolveDepthOverlap(requested, binding, cached_id)) { return {depth_id}; } - if (requested.IsBlock() && !cached.info.IsBlock()) { - return {ExpandImage(requested, cached_id)}; - } - if (requested.data.size == cached.info.data.size && - (requested.IsVolume() || cached.info.IsVolume())) { - return {ExpandImage(requested, cached_id)}; - } // Equal pitch does not imply equal mip placement: a changed extent can move // a level into or out of the mip tail. These are separate guest layouts. if (requested.tile_mode != cached.info.tile_mode || @@ -808,6 +801,13 @@ TextureCache::OverlapResult TextureCache::ResolveOverlap(const ImageInfo& reques } return {merged_id}; } + if (requested.IsBlock() && !cached.info.IsBlock()) { + return {ExpandImage(requested, cached_id)}; + } + if (requested.data.size == cached.info.data.size && + (requested.IsVolume() || cached.info.IsVolume())) { + return {ExpandImage(requested, cached_id)}; + } // PPSA08394 // A view cannot change the native image type or grow its extent. if (requested.data.size == cached.info.data.size && @@ -878,9 +878,7 @@ TextureCache::OverlapResult TextureCache::ResolveOverlap(const ImageInfo& reques ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId source_id) { RefreshCopySource(source_id); const auto expanded_id = InsertImage(info); - auto& expanded = m_slot_images[expanded_id]; auto& source = m_slot_images[source_id]; - expanded.usage = source.usage; if (source.binding.is_bound || source.binding.is_target) { source.binding.needs_rebind = true; } @@ -926,22 +924,12 @@ TextureCache::BuildTextureTransfer(const Image& image, BindingType binding, const bool upload = direction == TransferDirection::Upload; const bool render_target = binding == BindingType::RenderTarget; const bool video_out = binding == BindingType::VideoOut; - auto format = info.guest_format; uint32_t layers = info.TransferLayers(); bool volume = info.IsVolume(); - bool allow_depth_tile = upload; const char* owner = "TextureCache readback"; TextureTransfer transfer; - transfer.swap_bgra16 = info.bgra16 && (!upload || render_target || video_out); - if (render_target) { - format = ImageOps::RenderTargetTransferFormat(info.bytes_per_block); - } - if (video_out) { - allow_depth_tile = false; - } else if (render_target || binding == BindingType::Storage) { - allow_depth_tile = true; - } + transfer.swap_bgra16 = info.bgra16; if (upload) { if ((render_target || video_out) && (info.resources.layers == 0 || info.data.size % info.resources.layers != 0 || @@ -963,9 +951,9 @@ TextureCache::BuildTextureTransfer(const Image& image, BindingType binding, } } - transfer.layout = TextureCalcUploadLayout(format, info.extent.width, info.extent.height, - info.resources.levels, layers, info.tile_mode, - info.data.size, allow_depth_tile, volume, owner); + transfer.layout = TextureCalcUploadLayout(info.guest_format, info.extent.width, + info.extent.height, info.resources.levels, layers, + info.tile_mode, info.data.size, volume, owner); transfer.regions = TextureBuildImageCopies(transfer.layout); if (info.IsDepth()) { for (auto& region: transfer.regions) { diff --git a/src/graphics/host_gpu/renderer/image/textureCommon.cpp b/src/graphics/host_gpu/renderer/image/textureCommon.cpp index 85f3a91f3..ea90c5c0b 100644 --- a/src/graphics/host_gpu/renderer/image/textureCommon.cpp +++ b/src/graphics/host_gpu/renderer/image/textureCommon.cpp @@ -175,8 +175,7 @@ SurfaceFormatInfo TextureGetSurfaceFormatInfo(Prospero::BufferFormat format) { TextureUploadLayout TextureCalcUploadLayout(Prospero::BufferFormat format, uint32_t width, uint32_t height, uint32_t levels, uint32_t depth, Prospero::TileMode tile_mode, uint64_t upload_size, - bool allow_depth_tile, bool volume_texture, - const char* owner) { + bool volume_texture, const char* owner) { TextureUploadLayout layout {}; layout.surface.description = { format, @@ -204,8 +203,7 @@ TextureUploadLayout TextureCalcUploadLayout(Prospero::BufferFormat format, uint3 static_cast(format)); } } else { - if ((tile_mode == Prospero::TileMode::kDepth && !allow_depth_tile) || - !TileGetTiledTextureLayout(description, layout.surface)) { + if (!TileGetTiledTextureLayout(description, layout.surface)) { EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u " "size=%" PRIu64 " extent=%ux%u levels=%u\n", owner, static_cast(format), static_cast(tile_mode), diff --git a/src/graphics/host_gpu/renderer/image/textureCommon.h b/src/graphics/host_gpu/renderer/image/textureCommon.h index 57480144f..a88de4e36 100644 --- a/src/graphics/host_gpu/renderer/image/textureCommon.h +++ b/src/graphics/host_gpu/renderer/image/textureCommon.h @@ -47,8 +47,7 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(Prospero::ChannelLayout layo TextureUploadLayout TextureCalcUploadLayout(Prospero::BufferFormat format, uint32_t width, uint32_t height, uint32_t levels, uint32_t depth, Prospero::TileMode tile_mode, uint64_t upload_size, - bool allow_depth_tile, bool volume_texture, - const char* owner); + bool volume_texture, const char* owner); std::vector TextureBuildImageCopies(const TextureUploadLayout& layout); bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector& regions, const TextureUploadLayout& layout, uint32_t levels, diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 0b3b519df..a59645b58 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -5437,6 +5437,91 @@ public: previous = id; } + // The game reuses a raw render target allocation for a larger BC5 mip + // chain. Equal block extents do not make their guest tiling compatible. + constexpr uint64_t bc5_alias_offset = 0x1800000; + TileSurfaceLayout bc5_surface{}; + Require(name, "BC5 alias layout", + TileGetTiledTextureLayout( + {.format = Prospero::BufferFormat::kBc5UNorm, + .tile_mode = Prospero::TileMode::kStandard64KB, + .width = 1024, .height = 1024, .levels = 11}, bc5_surface) && + bc5_surface.total_size == 0x160000, + "captured BC5 allocation no longer has its 0x160000-byte footprint"); + std::memset(memory + bc5_alias_offset, 0, bc5_surface.total_size); + auto raw_alias = MakeLinearDesc( + base + bc5_alias_offset, 0x100000, vk::Format::eR32G32B32A32Sfloat, + Prospero::BufferFormat::k32_32_32_32Float, Prospero::ImageType::kColor2D, + {256, 256, 1}, 1, 16, 1); + raw_alias.type = BindingType::RenderTarget; + raw_alias.info.tile_mode = Prospero::TileMode::kRenderTarget; + raw_alias.view_info.usage = vk::ImageUsageFlagBits::eColorAttachment; + const auto raw_alias_id = texture_cache.FindImage(raw_alias); + (void)texture_cache.FindRenderTarget(raw_alias_id, raw_alias); + vk::ClearValue raw_alias_clear{}; + std::fill_n(raw_alias_clear.color.float32.data(), 4, 1.0f); + TextureCacheTestAccess::ClearImage( + texture_cache, scheduler.Current(), raw_alias_id, + {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, raw_alias_clear); + Require(name, "BC5 alias CPU overwrite", + resources.InvalidateMemory(base + bc5_alias_offset, + bc5_surface.total_size), + "new BC5 data could not invalidate the old render target"); + std::vector bc5_guest(bc5_surface.total_size / sizeof(u32)); + std::iota(bc5_guest.begin(), bc5_guest.end(), 0x41000000u); + std::memcpy(memory + bc5_alias_offset, bc5_guest.data(), + bc5_surface.total_size); + auto bc5_alias = MakeLinearDesc( + base + bc5_alias_offset, bc5_surface.total_size, vk::Format::eBc5UnormBlock, + Prospero::BufferFormat::kBc5UNorm, Prospero::ImageType::kColor2D, + {1024, 1024, 1}, 1, 16, 1); + bc5_alias.info.resources.levels = 11; + bc5_alias.info.tile_mode = Prospero::TileMode::kStandard64KB; + bc5_alias.view_info.level_count = 11; + std::vector bc5_probes; + std::vector bc5_expected; + for (u32 level = 0; level < 11; ++level) { + const auto &layout = bc5_surface.mips[level]; + bc5_alias.info.mip_layout[level] = { + layout.offset, layout.size, layout.padded_width, layout.padded_height}; + u32 offset = 0; + Require(name, "BC5 alias block address", + TileGetBlockOffset(bc5_surface.texture.block, layout.tail_x, + layout.tail_y, 0, offset), + "BC5 mip origin could not be addressed in guest memory"); + vk::BufferImageCopy copy{}; + copy.bufferOffset = bc5_expected.size() * sizeof(u32); + copy.imageSubresource = {vk::ImageAspectFlagBits::eColor, level, 0, 1}; + copy.imageExtent = {std::min(1024u >> level, 4u), + std::min(1024u >> level, 4u), 1}; + bc5_probes.push_back(copy); + const auto word = (layout.offset + offset) / sizeof(u32); + bc5_expected.insert(bc5_expected.end(), bc5_guest.begin() + word, + bc5_guest.begin() + word + 4); + } + const auto bc5_alias_id = texture_cache.FindImage(bc5_alias); + Require(name, "BC5 alias owner separation", + bc5_alias_id != raw_alias_id && + TextureCacheTestAccess::Contains(texture_cache, raw_alias_id) && + !texture_cache.GetImage(bc5_alias_id).usage.render_target && + texture_cache.GetImage(bc5_alias_id).info.tile_mode == + Prospero::TileMode::kStandard64KB, + "BC5 image expanded the unrelated raw render target or inherited its usage"); + (void)texture_cache.FindTexture(bc5_alias_id, bc5_alias); + auto bc5_readback = CreateHostBuffer( + name, bc5_expected.size() * sizeof(u32), + vk::BufferUsageFlagBits::eTransferDst, std::vector(bc5_expected.size())); + texture_cache.GetImage(bc5_alias_id).Download( + bc5_probes, bc5_readback.buffer, 0, bc5_readback.size); + HostReadBarrier(bc5_readback.buffer, bc5_readback.size, + vk::PipelineStageFlagBits::eTransfer, + vk::AccessFlagBits::eTransferWrite); + scheduler.Finish(); + Require(name, "BC5 alias mip contents", + ReadBuffer(name, bc5_readback, bc5_expected.size()) == bc5_expected, + "raw render-target copying overwrote the BC5 guest mip layout"); + DestroyBuffer(&bc5_readback); + // A formatted Buffer read must use the private // Exercise the cache-native image-copy path. Use a request larger // than the stream shortcut and poison guest backing @@ -6838,7 +6923,7 @@ public: std::memset(memory + layered_offset, 0, layered_guest_size); const auto layered_layout = TextureCalcUploadLayout( Prospero::BufferFormat::k32Float, 2, 2, 2, 2, - Prospero::TileMode::kLinear, layered_guest_size, true, false, + Prospero::TileMode::kLinear, layered_guest_size, false, "UnifiedTextureCacheFlow"); const auto layered_upload_regions = TextureBuildImageCopies(layered_layout); @@ -15799,7 +15884,7 @@ public: TileSizeAlign total{}; TileGetTextureSize(format, 128, 128, 1, tile, &total, nullptr, nullptr); const auto layout = TextureCalcUploadLayout( - format, 128, 128, 1, 1, tile, total.size, false, false, name); + format, 128, 128, 1, 1, tile, total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "FMASK policy", @@ -15835,7 +15920,7 @@ public: const auto layout = TextureCalcUploadLayout(format, width, height, 1, 1, mode.tile, - total.size, false, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; if (!TextureBuildGpuTileInfos(total.size, regions, layout, 1, infos)) { @@ -15932,7 +16017,7 @@ public: nullptr); const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, tile, - total.size, false, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; const bool built = @@ -15959,7 +16044,7 @@ public: total); const auto layout = TextureCalcUploadLayout(format, width, height, 1, layers, tile, - total.size, true, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; const bool built = @@ -15984,7 +16069,7 @@ public: nullptr, nullptr); const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, mode.tile, - total.size, false, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "odd mip infos", @@ -16023,7 +16108,7 @@ public: nullptr, nullptr); const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, mode.tile, - total.size, true, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "2D mip tail seam", @@ -16049,7 +16134,7 @@ public: total); const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, tile, - total.size, false, true, name); + total.size, true, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; const bool built = @@ -16080,7 +16165,7 @@ public: total); const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, tile, - total.size, false, true, name); + total.size, true, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "3D BC mip infos", @@ -16102,7 +16187,7 @@ public: nullptr); const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, tile, - total.size, false, false, name); + total.size, false, name); const auto regions = TextureBuildImageCopies(layout); Require(name, "linear BC native regions", regions.size() == levels && @@ -16144,7 +16229,7 @@ public: test.tile, true, total); const auto layout = TextureCalcUploadLayout(test.format, width, height, levels, depth, - test.tile, total.size, true, true, name); + test.tile, total.size, true, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; const bool built = @@ -16203,7 +16288,7 @@ public: true, total); const auto layout = TextureCalcUploadLayout(tail.format, width, height, levels, depth, - tile, total.size, false, true, name); + tile, total.size, true, name); const auto regions = TextureBuildImageCopies(layout); std::vector infos; bool valid = total.size == 8192 && @@ -16325,7 +16410,7 @@ public: volume_size); const auto volume_layout = TextureCalcUploadLayout( volume_format, volume_width, volume_height, volume_levels, volume_depth, - volume_tile, volume_size.size, true, true, name); + volume_tile, volume_size.size, true, name); const auto volume_copies = TextureBuildImageCopies(volume_layout); std::vector volume_source(volume_size.size / sizeof(u32), 0); std::vector> volume_probes; @@ -34060,7 +34145,7 @@ void CheckStorageTextureLinearUploadLayout() { TileGetTextureTotalSize(format, width, height, depth, 1, tile, false, total); const auto layout = TextureCalcUploadLayout(format, width, height, 1, depth, tile, total.size, - true, false, "StorageTextureLinearTest"); + false, "StorageTextureLinearTest"); const auto regions = TextureBuildImageCopies(layout); Require("StorageTextureLinearUpload", "layout", pitch == width && total.size == 0x1fa4000 && total.align == 256 && @@ -34089,7 +34174,7 @@ void CheckStorageTextureDepthTileUploadLayout() { TileGetTextureTotalSize(format, width, height, depth, 1, tile, false, total); const auto layout = TextureCalcUploadLayout(format, width, height, 1, depth, tile, total.size, - true, false, "StorageTextureDepthTileTest"); + false, "StorageTextureDepthTileTest"); const auto regions = TextureBuildImageCopies(layout); Require("StorageTextureDepthTileUpload", "PPSA14053 layout", pitch == 256 && padded.width == 256 && padded.height == 256 && @@ -34415,7 +34500,7 @@ void CheckStorageTextureVolumeUploadLayout() { Prospero::TileMode::kRenderTarget, true, total); const auto layout = TextureCalcUploadLayout( format, width, height, 1, depth, Prospero::TileMode::kRenderTarget, - total.size, true, true, "StorageTextureVolumeTest"); + total.size, true, "StorageTextureVolumeTest"); const auto regions = TextureBuildImageCopies(layout); Require( "StorageTextureVolumeUpload", "layout", @@ -34450,7 +34535,7 @@ void CheckStorageTextureVolumeMipRegions() { TileGetTextureTotalSize(format, width, height, depth, levels, tile, true, total); const auto layout = TextureCalcUploadLayout( - format, width, height, levels, depth, tile, total.size, true, true, + format, width, height, levels, depth, tile, total.size, true, "StorageTextureVolumeMipTest"); const auto copies = TextureBuildImageCopies(layout);