Browse Source

Fixed GPU async unswizzle

Fixed typo in unswizzle method name
Added experimental change to try and vastly speed up the GPU async processing without degrading too much performance
pull/3737/head
Forrest Mark X 2 days ago
parent
commit
6874cfdc60
  1. 2
      src/qt_common/config/shared_translation.cpp
  2. 126
      src/video_core/texture_cache/texture_cache.h
  3. 1
      src/video_core/texture_cache/texture_cache_base.h

2
src/qt_common/config/shared_translation.cpp

@ -169,7 +169,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for " tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for "
"decoding, or perform no decoding at all (black screen on videos).\n" "decoding, or perform no decoding at all (black screen on videos).\n"
"In most cases, GPU decoding provides the best performance.")); "In most cases, GPU decoding provides the best performance."));
INSERT(Settings, accelerate_unswizzle, tr("Texture Unsiwzzle Method:"),
INSERT(Settings, accelerate_unswizzle, tr("Texture Unswizzle Method:"),
tr("This option controls how generic textures should be unswizzled.\n" tr("This option controls how generic textures should be unswizzled.\n"
"CPU: Use the CPU for unswizzling (recommended).\n" "CPU: Use the CPU for unswizzling (recommended).\n"
"GPU: Use the GPU's compute shaders to unswizzling generic textures.")); "GPU: Use the GPU's compute shaders to unswizzling generic textures."));

126
src/video_core/texture_cache/texture_cache.h

@ -1412,8 +1412,6 @@ void TextureCache<P>::TickAsyncUnswizzle() {
ImageId task_image_id = task.image_id; ImageId task_image_id = task.image_id;
if (task.is_cpu) { if (task.is_cpu) {
// The primary resource drain here is UnswizzleTexture so maybe this won't blow up your SteamDeck
// Also, scary infinite loop possibility ... makes me uncomfortable
while (true) { while (true) {
PendingUnswizzle& current = unswizzle_queue.front(); PendingUnswizzle& current = unswizzle_queue.front();
Image& image = slot_images[task_image_id]; Image& image = slot_images[task_image_id];
@ -1440,8 +1438,27 @@ void TextureCache<P>::TickAsyncUnswizzle() {
} }
} }
} else { } else {
Image& image = slot_images[task_image_id];
TickAsyncUnswizzleGpu(task, image);
while (true) {
PendingUnswizzle& current = unswizzle_queue.front();
Image& image = slot_images[task_image_id];
const size_t offset_before = current.current_offset;
TickAsyncUnswizzleGpu(current, image);
if (unswizzle_queue.empty() || unswizzle_queue.front().image_id != task_image_id) {
break;
}
PendingUnswizzle& refreshed = unswizzle_queue.front();
if (refreshed.current_offset == offset_before) {
break;
}
if (!refreshed.owns_staging_buffer && unswizzle_shared_staging_pending_gpu_read) {
runtime.Finish();
unswizzle_shared_staging_pending_gpu_read = false;
}
}
} }
} }
@ -1576,6 +1593,7 @@ void TextureCache<P>::TickAsyncUnswizzleGpu(PendingUnswizzle& task, Image& image
task.last_submitted_offset = task.last_submitted_offset =
static_cast<size_t>(task.active_z_start) * task.bytes_per_slice; static_cast<size_t>(task.active_z_start) * task.bytes_per_slice;
} }
task.current_batch_start_byte = task.current_offset;
} }
const size_t needed = (std::max)(max_batch_size, size_t{1}); const size_t needed = (std::max)(max_batch_size, size_t{1});
@ -1609,65 +1627,67 @@ void TextureCache<P>::TickAsyncUnswizzleGpu(PendingUnswizzle& task, Image& image
task.initialized = true; task.initialized = true;
} }
// Read data
const size_t active_start_byte = (task.active_z_start < image.slice_offsets.size())
? static_cast<size_t>(image.slice_offsets[task.active_z_start]) : 0;
const size_t active_end_byte = (task.active_z_end < image.slice_offsets.size()) const size_t active_end_byte = (task.active_z_end < image.slice_offsets.size())
? static_cast<size_t>(image.slice_offsets[task.active_z_end]) : task.total_size;
? static_cast<size_t>(image.slice_offsets[task.active_z_end]) : task.total_size;
if (task.current_offset < active_end_byte) { if (task.current_offset < active_end_byte) {
const size_t remaining = active_end_byte - task.current_offset;
size_t copy_amount = (async_unswizzle_chunk_size == 0)
? remaining
: (std::min)(async_unswizzle_chunk_size, remaining);
const size_t batch_capacity_end_byte = (std::min)(
task.current_batch_start_byte + task.staging_buffer.mapped_span.size(), active_end_byte);
if (async_unswizzle_chunk_size > 0 && copy_amount < remaining) {
copy_amount = (copy_amount / task.bytes_per_slice) * task.bytes_per_slice;
if (copy_amount == 0) copy_amount = task.bytes_per_slice;
copy_amount = (std::min)(copy_amount, remaining);
}
if (task.current_offset < batch_capacity_end_byte) {
const size_t remaining = batch_capacity_end_byte - task.current_offset;
size_t copy_amount = (async_unswizzle_chunk_size == 0)
? remaining
: (std::min)(async_unswizzle_chunk_size, remaining);
u8* const staging_base = task.staging_buffer.mapped_span.data();
if (async_unswizzle_chunk_size > 0 && copy_amount < remaining) {
copy_amount = (copy_amount / task.bytes_per_slice) * task.bytes_per_slice;
if (copy_amount == 0) copy_amount = task.bytes_per_slice;
copy_amount = (std::min)(copy_amount, remaining);
}
if (task.is_sparse && task.current_offset == active_start_byte) {
const size_t window_size = active_end_byte - active_start_byte;
std::memset(staging_base, 0, (std::min)(window_size, task.staging_buffer.mapped_span.size()));
}
u8* const staging_base = task.staging_buffer.mapped_span.data();
const size_t base_off = task.staging_base_byte_offset;
const size_t read_start = task.current_offset;
const size_t read_end = read_start + copy_amount;
const size_t abs_start = read_start + base_off;
const size_t abs_end = read_end + base_off;
if (task.is_sparse && task.current_offset == task.current_batch_start_byte) {
const size_t window_size = batch_capacity_end_byte - task.current_batch_start_byte;
std::memset(staging_base, 0, (std::min)(window_size, task.staging_buffer.mapped_span.size()));
}
if (task.is_sparse) {
while (task.segment_scan_cursor < task.sparse_segments.size()) {
const auto& [seg_gpu_addr, seg_size] =
task.sparse_segments[task.segment_scan_cursor];
const size_t seg_abs_start =
static_cast<size_t>(seg_gpu_addr - image.gpu_addr);
const size_t seg_abs_end = seg_abs_start + seg_size;
const size_t base_off = task.staging_base_byte_offset;
const size_t read_start = task.current_offset;
const size_t read_end = read_start + copy_amount;
const size_t abs_start = read_start + base_off;
const size_t abs_end = read_end + base_off;
if (seg_abs_end <= abs_start) { ++task.segment_scan_cursor; continue; }
if (seg_abs_start >= abs_end) { break; }
if (task.is_sparse) {
while (task.segment_scan_cursor < task.sparse_segments.size()) {
const auto& [seg_gpu_addr, seg_size] =
task.sparse_segments[task.segment_scan_cursor];
const size_t seg_abs_start =
static_cast<size_t>(seg_gpu_addr - image.gpu_addr);
const size_t seg_abs_end = seg_abs_start + seg_size;
const size_t ol_abs_start = (std::max)(seg_abs_start, abs_start);
const size_t ol_abs_end = (std::min)(seg_abs_end, abs_end);
const size_t ol_rel_start = (ol_abs_start - base_off) - active_start_byte;
if (seg_abs_end <= abs_start) { ++task.segment_scan_cursor; continue; }
if (seg_abs_start >= abs_end) { break; }
gpu_memory->ReadBlockUnsafe(image.gpu_addr + ol_abs_start,
staging_base + ol_rel_start,
ol_abs_end - ol_abs_start);
const size_t ol_abs_start = (std::max)(seg_abs_start, abs_start);
const size_t ol_abs_end = (std::min)(seg_abs_end, abs_end);
const size_t ol_rel_start = (ol_abs_start - base_off) - task.current_batch_start_byte;
if (seg_abs_end > abs_end) break;
++task.segment_scan_cursor;
gpu_memory->ReadBlockUnsafe(image.gpu_addr + ol_abs_start,
staging_base + ol_rel_start,
ol_abs_end - ol_abs_start);
if (seg_abs_end > abs_end) break;
++task.segment_scan_cursor;
}
} else {
gpu_memory->ReadBlockUnsafe(image.gpu_addr + abs_start,
staging_base + (read_start - task.current_batch_start_byte),
copy_amount);
} }
} else {
gpu_memory->ReadBlockUnsafe(image.gpu_addr + abs_start,
staging_base + (read_start - active_start_byte),
copy_amount);
task.current_offset += copy_amount;
} }
task.current_offset += copy_amount;
} }
const bool is_final_batch = task.current_offset >= active_end_byte; const bool is_final_batch = task.current_offset >= active_end_byte;
@ -1702,6 +1722,7 @@ void TextureCache<P>::TickAsyncUnswizzleGpu(PendingUnswizzle& task, Image& image
sparse_hint, sparse_hint,
false); false);
task.last_submitted_offset += static_cast<size_t>(z_count) * task.bytes_per_slice; task.last_submitted_offset += static_cast<size_t>(z_count) * task.bytes_per_slice;
task.current_batch_start_byte = task.current_offset;
} }
} }
@ -1720,13 +1741,6 @@ void TextureCache<P>::TickAsyncUnswizzleGpu(PendingUnswizzle& task, Image& image
} }
} }
// Send help, I didn't think this would be that complicated to implement
// Whatever, this needlessly over complicated block of code is this way simply to save RAM
//
// Note for Liz:
// Divided everything into helper functions but don't know if this makes everything more confusing.
// Or could possibly cause a speed reduction, I'm not entirely sure what template functions look like in ASM
// So I am unsure if there will be overhead with saving the return location into the stack
template <class P> template <class P>
void TextureCache<P>::InitializeCpuUnswizzleTask(PendingUnswizzle& task, Image& image) { void TextureCache<P>::InitializeCpuUnswizzleTask(PendingUnswizzle& task, Image& image) {
task.total_size = MapSizeBytes(image); task.total_size = MapSizeBytes(image);

1
src/video_core/texture_cache/texture_cache_base.h

@ -159,6 +159,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelI
size_t last_submitted_offset = 0; size_t last_submitted_offset = 0;
size_t staging_base_byte_offset = 0; size_t staging_base_byte_offset = 0;
size_t bytes_per_slice = 0; size_t bytes_per_slice = 0;
size_t current_batch_start_byte = 0;
u64 swizzled_slice_size = 0; u64 swizzled_slice_size = 0;
std::vector<std::pair<GPUVAddr, size_t>> sparse_segments; std::vector<std::pair<GPUVAddr, size_t>> sparse_segments;

Loading…
Cancel
Save