diff --git a/.github/workflows/fork-windows-check.yml b/.github/workflows/fork-windows-check.yml index df03d8dde3..97675f7590 100644 --- a/.github/workflows/fork-windows-check.yml +++ b/.github/workflows/fork-windows-check.yml @@ -8,6 +8,8 @@ on: - .github/workflows/fork-windows-check.yml - .github/workflows/build-windows.yml - src/CMakeLists.txt + - src/video_core/** + - src/shader_recompiler/** - src/yuzu/** - src/yuzu_cmd/** - src/qt_common/** diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 1d4b4c82d0..8988780d17 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -2001,12 +2001,19 @@ void TextureCache

::UploadLayers(Image& image, std::span layers) { std::vector copies; for (size_t i = 0; i < layers.size(); ++i) { const GPUVAddr layer_addr = image.gpu_addr + u64{layers[i]} * image.info.layer_stride; - Tegra::Memory::GpuGuestMemory - swizzle_data(*gpu_memory, layer_addr, image.info.layer_stride, - &swizzle_data_buffer); - auto layer_copies = - UnswizzleImage(*gpu_memory, layer_addr, layer_info, swizzle_data, - staging.mapped_span.subspan(i * layer_size, layer_size)); + const std::span layer_out = staging.mapped_span.subspan(i * layer_size, layer_size); + auto layer_copies = [&] { + if (layer_info.type == ImageType::Linear) { + // Read straight from guest memory; no copy into swizzle_data first. + return UnswizzleLinearImage(*gpu_memory, layer_addr, layer_info, + image.info.layer_stride, layer_out); + } + Tegra::Memory::GpuGuestMemory + swizzle_data(*gpu_memory, layer_addr, image.info.layer_stride, + &swizzle_data_buffer); + return UnswizzleImage(*gpu_memory, layer_addr, layer_info, swizzle_data, + layer_out); + }(); for (BufferImageCopy copy : layer_copies) { copy.buffer_offset += i * layer_size; copy.image_subresource.base_layer = static_cast(layers[i]); @@ -2073,6 +2080,23 @@ void TextureCache

::UploadImageContents(Image& image, StagingBuffer& staging) return; } + if (image.info.type == ImageType::Linear) { + // A linear image is read straight from guest memory into its destination: copying it + // into swizzle_data first, as below, read it twice (3% of the split's back thread with + // Pokopia's town in view). + if (True(image.flags & ImageFlagBits::Converted)) { + unswizzle_data_buffer.resize_destructive(image.unswizzled_size_bytes); + auto copies = UnswizzleLinearImage(*gpu_memory, gpu_addr, image.info, + image.guest_size_bytes, unswizzle_data_buffer); + ConvertImage(unswizzle_data_buffer, image.info, mapped_span, copies); + image.UploadMemory(staging, copies); + } else { + const auto copies = UnswizzleLinearImage(*gpu_memory, gpu_addr, image.info, + image.guest_size_bytes, mapped_span); + image.UploadMemory(staging, copies); + } + return; + } Tegra::Memory::GpuGuestMemory swizzle_data( *gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer); if (True(image.flags & ImageFlagBits::Converted)) { diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 09e9513a5b..b4abb3b0d4 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -850,6 +850,32 @@ bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config return gpu_memory.GpuToCpuAddress(address, guest_size_bytes).has_value(); } +boost::container::small_vector UnswizzleLinearImage( + Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, + size_t guest_size_bytes, std::span output) { + const u32 bpp_log2 = BytesPerBlockLog2(info.format); + const Extent2D tile_size = DefaultBlockSize(info.format); + const Extent3D size = info.size; + ASSERT(output.size_bytes() >= guest_size_bytes); + gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes); + + ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch); + return {{ + .buffer_offset = 0, + .buffer_size = guest_size_bytes, + .buffer_row_length = info.pitch * tile_size.width >> bpp_log2, + .buffer_image_height = size.height, + .image_subresource = + { + .base_level = 0, + .base_layer = 0, + .num_layers = 1, + }, + .image_offset = {0, 0, 0}, + .image_extent = size, + }}; +} + boost::container::small_vector UnswizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, @@ -861,24 +887,7 @@ boost::container::small_vector UnswizzleImage(Tegra::Memory const Extent3D size = info.size; if (info.type == ImageType::Linear) { - ASSERT(output.size_bytes() >= guest_size_bytes); - gpu_memory.ReadBlockUnsafe(gpu_addr, output.data(), guest_size_bytes); - - ASSERT((info.pitch >> bpp_log2) << bpp_log2 == info.pitch); - return {{ - .buffer_offset = 0, - .buffer_size = guest_size_bytes, - .buffer_row_length = info.pitch * tile_size.width >> bpp_log2, - .buffer_image_height = size.height, - .image_subresource = - { - .base_level = 0, - .base_layer = 0, - .num_layers = 1, - }, - .image_offset = {0, 0, 0}, - .image_extent = size, - }}; + return UnswizzleLinearImage(gpu_memory, gpu_addr, info, guest_size_bytes, output); } const LevelInfo level_info = MakeLevelInfo(info); const s32 num_layers = info.resources.layers; diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index d91ee74c52..fa12cd1c4d 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h @@ -103,6 +103,11 @@ void ExecuteUnswizzlePlan(Tegra::MemoryManager& gpu_memory, const UnswizzlePlan& Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, std::span input, std::span output); +/// Read a linear guest image directly into the staging destination. +[[nodiscard]] boost::container::small_vector UnswizzleLinearImage( + Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info, + size_t guest_size_bytes, std::span output); + /// For a single-layer 2D block-linear image of 1x1-texel blocks: the host sparse blocks /// (tile_width x tile_height texels) that the guest byte ranges (offset, size) touch, merged into /// runs along x. Levels from tail_level on (the host's mip tail) come whole.