Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/fork-windows-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/**
Expand Down
36 changes: 30 additions & 6 deletions src/video_core/texture_cache/texture_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -2001,12 +2001,19 @@ void TextureCache<P>::UploadLayers(Image& image, std::span<const u32> layers) {
std::vector<BufferImageCopy> 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<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead>
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<u8> 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<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead>
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<s32>(layers[i]);
Expand Down Expand Up @@ -2073,6 +2080,23 @@ void TextureCache<P>::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<u8, Tegra::Memory::GuestMemoryFlags::UnsafeRead> swizzle_data(
*gpu_memory, gpu_addr, image.guest_size_bytes, &swizzle_data_buffer);
if (True(image.flags & ImageFlagBits::Converted)) {
Expand Down
45 changes: 27 additions & 18 deletions src/video_core/texture_cache/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<BufferImageCopy, 16> UnswizzleLinearImage(
Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info,
size_t guest_size_bytes, std::span<u8> 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<BufferImageCopy, 16> UnswizzleImage(Tegra::MemoryManager& gpu_memory,
GPUVAddr gpu_addr,
const ImageInfo& info,
Expand All @@ -861,24 +887,7 @@ boost::container::small_vector<BufferImageCopy, 16> 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;
Expand Down
5 changes: 5 additions & 0 deletions src/video_core/texture_cache/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ void ExecuteUnswizzlePlan(Tegra::MemoryManager& gpu_memory, const UnswizzlePlan&
Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info,
std::span<const u8> input, std::span<u8> output);

/// Read a linear guest image directly into the staging destination.
[[nodiscard]] boost::container::small_vector<BufferImageCopy, 16> UnswizzleLinearImage(
Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const ImageInfo& info,
size_t guest_size_bytes, std::span<u8> 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.
Expand Down
Loading