Browse Source

Fixed various issues

Removed CompletedSparseImages as its completely dead code
Fixed issues with sparse_segments that caused the watermark system to skip segments
pull/3737/head
Forrest Mark X 4 weeks ago
committed by crueter
parent
commit
721a2135a0
  1. 81
      src/video_core/renderer_vulkan/vk_compute_pass.cpp
  2. 55
      src/video_core/texture_cache/accelerated_swizzle.cpp
  3. 78
      src/video_core/texture_cache/accelerated_swizzle.h
  4. 197
      src/video_core/texture_cache/texture_cache.h
  5. 2
      src/video_core/texture_cache/texture_cache_base.h

81
src/video_core/renderer_vulkan/vk_compute_pass.cpp

@ -709,9 +709,12 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
using namespace VideoCommon::Accelerated;
const u32 MAX_BATCH_SLICES = (std::min)(z_count, image.info.size.depth);
static constexpr u32 MAX_WINDOW_SLICES = 4;
static constexpr float AREA_GROWTH_LIMIT = 3.0f;
// Removing the if (!image.has_compute_unswizzle_buffer) check here is not ideal but MAX_BATCH_SLICES can changed mid-way through and I don't want to cause device loss or corruption
image.AllocateComputeUnswizzleBuffer(MAX_BATCH_SLICES);
// This may cause issues so needs thorough testing, if works fine this is a win to reduce vram usage
image.AllocateComputeUnswizzleBuffer((std::min)(MAX_BATCH_SLICES, MAX_WINDOW_SLICES));
ASSERT(swizzles.size() == 1);
const auto& sw = swizzles[0];
@ -787,25 +790,8 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
continue;
}
u32 ox0 = 0, oy0 = 0, ox1 = blocks_x, oy1 = blocks_y;
if (!slice_bounds.empty()) {
bool any = false;
u32 ux0 = blocks_x, uy0 = blocks_y, ux1 = 0, uy1 = 0;
for (u32 z = z_src; z < z_src + sub_len; ++z) {
if (z >= static_cast<u32>(slice_bounds.size())) { any = false; break; }
const auto& b = slice_bounds[z];
if (b.x1 <= b.x0 || b.y1 <= b.y0) continue;
ux0 = (std::min)(ux0, b.x0);
uy0 = (std::min)(uy0, b.y0);
ux1 = (std::max)(ux1, b.x1);
uy1 = (std::max)(uy1, b.y1);
any = true;
}
if (any) { ox0 = ux0; oy0 = uy0; ox1 = ux1; oy1 = uy1; }
}
// Uncomment if junk data appears
//UnswizzleZeroChunk(image, z_dst, sub_len);
/*UnswizzleZeroChunk(image, z_dst, sub_len);
scheduler.Record([dst_image = image.Handle(), aspect = image.AspectMask()](vk::CommandBuffer cmdbuf) {
if (dst_image == VK_NULL_HANDLE) return;
@ -823,11 +809,60 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, barrier);
});
});*/
u32 win_offset = 0;
while (win_offset < sub_len) {
const u32 wz_start = z_src + win_offset;
const u32 wz_dst = z_dst + win_offset;
u32 win_len = 0;
u32 ux0 = blocks_x, uy0 = blocks_y, ux1 = 0, uy1 = 0;
u64 slice_area_sum = 0;
bool any_in_window = false;
while (win_offset + win_len < sub_len && win_len < MAX_WINDOW_SLICES) {
const u32 z = wz_start + win_len;
const bool have_box = !slice_bounds.empty() &&
z < static_cast<u32>(slice_bounds.size());
const auto b = have_box ? slice_bounds[z] : SliceBBox{};
const bool slice_populated = b.x1 > b.x0 && b.y1 > b.y0;
if (slice_populated) {
const u32 cx0 = any_in_window ? (std::min)(ux0, b.x0) : b.x0;
const u32 cy0 = any_in_window ? (std::min)(uy0, b.y0) : b.y0;
const u32 cx1 = any_in_window ? (std::max)(ux1, b.x1) : b.x1;
const u32 cy1 = any_in_window ? (std::max)(uy1, b.y1) : b.y1;
const u64 candidate_area =
static_cast<u64>(cx1 - cx0) * (cy1 - cy0);
const u64 candidate_slice_sum = slice_area_sum +
static_cast<u64>(b.x1 - b.x0) * (b.y1 - b.y0);
if (any_in_window && static_cast<float>(candidate_area) > (AREA_GROWTH_LIMIT * static_cast<float>(candidate_slice_sum))) {
break;
}
ux0 = cx0; uy0 = cy0; ux1 = cx1; uy1 = cy1;
slice_area_sum = candidate_slice_sum;
any_in_window = true;
}
++win_len;
}
if (win_len == 0) {
win_len = 1;
}
UnswizzleChunk(image, swizzled, sw, params,
ox0, oy0, ox1 - ox0, oy1 - oy0,
z_src, z_dst, sub_len);
const u32 ox0 = any_in_window ? ux0 : 0;
const u32 oy0 = any_in_window ? uy0 : 0;
const u32 ox1 = any_in_window ? ux1 : blocks_x;
const u32 oy1 = any_in_window ? uy1 : blocks_y;
UnswizzleChunk(image, swizzled, sw, params,
ox0, oy0, ox1 - ox0, oy1 - oy0,
wz_start, wz_dst, win_len);
win_offset += win_len;
}
sub_offset += sub_len;
}

55
src/video_core/texture_cache/accelerated_swizzle.cpp

@ -20,9 +20,6 @@ using Tegra::Texture::GOB_SIZE_X_SHIFT;
using Tegra::Texture::GOB_SIZE_Y_SHIFT;
using VideoCore::Surface::BytesPerBlock;
constexpr u32 GOB_SIZE_Y = 8;
constexpr u32 GOB_SIZE = 512;
BlockLinearSwizzle2DParams MakeBlockLinearSwizzle2DParams(const SwizzleParameters& swizzle,
const ImageInfo& info) {
const Extent3D block = swizzle.block;
@ -69,56 +66,4 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter
};
}
SliceBBox BoundSliceByteRange(u64 start_off, u64 end_off,
u32 block_size, u32 x_shift,
u32 block_height, u32 block_height_mask,
u32 bytes_per_block,
u32 blocks_x, u32 blocks_y) {
if (start_off >= end_off) {
return {};
}
const u32 column_pitch = 1u << x_shift;
const u32 blocks_per_column = 64u / bytes_per_block;
const u32 rows_per_group = 1u << block_height;
const u32 y_per_band = GOB_SIZE_Y << block_height;
const u64 band_start = start_off / block_size;
const u64 band_end = (end_off - 1) / block_size;
SliceBBox box;
if (band_start == band_end) {
const u64 wb_start = start_off - band_start * block_size;
const u64 wb_end = (end_off - 1) - band_start * block_size;
const u32 col_start = static_cast<u32>(wb_start / column_pitch);
const u32 col_end = static_cast<u32>(wb_end / column_pitch);
if (col_start == col_end) {
const u32 row_start = static_cast<u32>(wb_start % column_pitch) / GOB_SIZE;
const u32 row_end = static_cast<u32>(wb_end % column_pitch) / GOB_SIZE;
box.x0 = col_start * blocks_per_column;
box.x1 = (col_start + 1) * blocks_per_column;
box.y0 = (static_cast<u32>(band_start) * rows_per_group + row_start) * GOB_SIZE_Y;
box.y1 = (static_cast<u32>(band_start) * rows_per_group + row_end + 1) * GOB_SIZE_Y;
} else {
box.x0 = col_start * blocks_per_column;
box.x1 = (col_end + 1) * blocks_per_column;
box.y0 = static_cast<u32>(band_start) * y_per_band;
box.y1 = box.y0 + y_per_band;
}
} else {
box.x0 = 0;
box.x1 = blocks_x;
box.y0 = static_cast<u32>(band_start) * y_per_band;
box.y1 = static_cast<u32>(band_end + 1) * y_per_band;
}
box.x1 = (std::min)(box.x1, blocks_x);
box.y1 = (std::min)(box.y1, blocks_y);
return box;
}
} // namespace VideoCommon::Accelerated

78
src/video_core/texture_cache/accelerated_swizzle.h

@ -11,6 +11,9 @@
namespace VideoCommon::Accelerated {
constexpr u32 GOB_SIZE_Y = 8;
constexpr u32 GOB_SIZE = 512;
struct BlockLinearSwizzle2DParams {
alignas(16) std::array<u32, 3> origin;
alignas(16) std::array<s32, 3> destination;
@ -45,10 +48,75 @@ struct SliceBBox {
[[nodiscard]] BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(
const SwizzleParameters& swizzle, const ImageInfo& info);
[[nodiscard]] SliceBBox BoundSliceByteRange(u64 start_off, u64 end_off,
u32 block_size, u32 x_shift,
u32 block_height, u32 block_height_mask,
u32 bytes_per_block,
u32 blocks_x, u32 blocks_y);
template <typename Callback>
void ForEachZInGroupOverlap(u64 local_start, u64 local_end,
u32 block_size, u32 x_shift, u32 block_height,
u32 block_height_mask, u32 block_depth, u32 block_depth_mask,
u32 bytes_per_block, u32 blocks_x, u32 blocks_y,
Callback&& on_result) {
if (local_start >= local_end) return;
const u32 z_pitch = GOB_SIZE << block_height;
const u32 column_pitch = 1u << x_shift;
const u32 blocks_per_column = 64u / bytes_per_block;
const u32 rows_per_group = 1u << block_height;
const u32 y_per_band = GOB_SIZE_Y << block_height;
const u32 zz_count = 1u << block_depth;
const u64 band_start = local_start / block_size;
const u64 band_end = (local_end - 1) / block_size;
if (band_start != band_end) {
SliceBBox box;
box.x0 = 0;
box.x1 = blocks_x;
box.y0 = static_cast<u32>(band_start) * y_per_band;
box.y1 = (std::min)(static_cast<u32>(band_end + 1) * y_per_band, blocks_y);
for (u32 zz = 0; zz < zz_count; ++zz) on_result(zz, box);
return;
}
const u64 wb_start = local_start - band_start * block_size;
const u64 wb_end = (local_end - 1) - band_start * block_size;
const u32 col_start = static_cast<u32>(wb_start / column_pitch);
const u32 col_end = static_cast<u32>(wb_end / column_pitch);
if (col_start != col_end) {
SliceBBox box;
box.x0 = col_start * blocks_per_column;
box.x1 = (std::min)((col_end + 1) * blocks_per_column, blocks_x);
box.y0 = static_cast<u32>(band_start) * y_per_band;
box.y1 = (std::min)(box.y0 + y_per_band, blocks_y);
for (u32 zz = 0; zz < zz_count; ++zz) on_result(zz, box);
return;
}
const u64 wc_start = wb_start - static_cast<u64>(col_start) * column_pitch;
const u64 wc_end = wb_end - static_cast<u64>(col_start) * column_pitch;
const u32 zz_start = static_cast<u32>(wc_start / z_pitch);
const u32 zz_end = static_cast<u32>(wc_end / z_pitch);
if (zz_start != zz_end) {
SliceBBox box;
box.x0 = col_start * blocks_per_column;
box.x1 = (std::min)((col_start + 1) * blocks_per_column, blocks_x);
box.y0 = static_cast<u32>(band_start) * y_per_band;
box.y1 = (std::min)(box.y0 + y_per_band, blocks_y);
for (u32 zz = zz_start; zz <= zz_end; ++zz) on_result(zz, box);
return;
}
const u64 wz_start = wc_start - static_cast<u64>(zz_start) * z_pitch;
const u64 wz_end = wc_end - static_cast<u64>(zz_start) * z_pitch;
const u32 row_start = static_cast<u32>(wz_start) / GOB_SIZE;
const u32 row_end = static_cast<u32>(wz_end) / GOB_SIZE;
SliceBBox box;
box.x0 = col_start * blocks_per_column;
box.x1 = (std::min)((col_start + 1) * blocks_per_column, blocks_x);
box.y0 = (static_cast<u32>(band_start) * rows_per_group + row_start) * GOB_SIZE_Y;
box.y1 = (std::min)((static_cast<u32>(band_start) * rows_per_group + row_end + 1) * GOB_SIZE_Y, blocks_y);
on_result(zz_start, box);
}
} // namespace VideoCommon::Accelerated

197
src/video_core/texture_cache/texture_cache.h

@ -184,7 +184,6 @@ void TextureCache<P>::TickFrame() {
sentenced_image_view.Tick();
TickAsyncDecode();
TickAsyncUnswizzle();
//TickCompletedSparseImages();
runtime.TickFrame();
++frame_tick;
@ -1427,12 +1426,16 @@ void TextureCache<P>::TickAsyncUnswizzle() {
const auto segs =
gpu_memory->GetSubmappedRange(image.gpu_addr, image.guest_size_bytes);
task.sparse_segments.assign(segs.begin(), segs.end());
std::sort(task.sparse_segments.begin(), task.sparse_segments.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
task.segment_scan_cursor = 0;
task.slice_has_data.assign(image.info.size.depth, 0u);
task.slice_bounds.assign(image.info.size.depth, {});
if (image.info.size.depth > 1 && !image.slice_offsets.empty()) {
if (image.info.size.depth > 1) {
const auto uploads = FullUploadSwizzles(task.info);
const auto sp = VideoCommon::Accelerated::MakeBlockLinearSwizzle3DParams(
uploads[0], task.info);
@ -1440,34 +1443,40 @@ void TextureCache<P>::TickAsyncUnswizzle() {
task.swizzled_slice_size = swizzled_slice_size;
task.swizzle_block_depth = sp.block_depth;
const bool can_bound_xy = sp.block_depth > 0;
const u32 blocks_x = Common::DivCeil(task.info.size.width, 4u);
const u32 blocks_y = Common::DivCeil(task.info.size.height, 4u);
u32 z_watermark = 0;
const u32 zz_count = 1u << sp.block_depth;
const u32 total_groups = Common::DivCeil(
static_cast<u32>(image.info.size.depth), zz_count);
u32 group_watermark = 0;
for (const auto& [seg_gpu_addr, seg_size] : task.sparse_segments) {
const u64 seg_start = seg_gpu_addr - image.gpu_addr;
const u64 seg_end = seg_start + seg_size;
while (z_watermark < static_cast<u32>(image.info.size.depth) &&
image.slice_offsets[z_watermark] + swizzled_slice_size <= seg_start) {
++z_watermark;
while (group_watermark < total_groups &&
static_cast<u64>(group_watermark) * swizzled_slice_size + swizzled_slice_size <= seg_start) {
++group_watermark;
}
for (u32 z = z_watermark; z < static_cast<u32>(image.info.size.depth); ++z) {
if (image.slice_offsets[z] >= seg_end) break;
task.slice_has_data[z] = 1u;
if (can_bound_xy) {
const u64 slice_off = image.slice_offsets[z];
const u64 local_start = (std::max)(seg_start, slice_off) - slice_off;
const u64 local_end = (std::min)(seg_end, slice_off + swizzled_slice_size) - slice_off;
const auto box = VideoCommon::Accelerated::BoundSliceByteRange(
local_start, local_end, sp.block_size, sp.x_shift,
sp.block_height, sp.block_height_mask, bytes_per_block,
blocks_x, blocks_y);
auto& acc = task.slice_bounds[z];
if (box.x1 > box.x0 && box.y1 > box.y0) {
for (u32 g = group_watermark; g < total_groups; ++g) {
const u64 group_base = static_cast<u64>(g) * swizzled_slice_size;
if (group_base >= seg_end) break;
const u64 local_start = (std::max)(seg_start, group_base) - group_base;
const u64 local_end = (std::min)(seg_end, group_base + swizzled_slice_size) - group_base;
VideoCommon::Accelerated::ForEachZInGroupOverlap(
local_start, local_end,
sp.block_size, sp.x_shift, sp.block_height, sp.block_height_mask,
sp.block_depth, sp.block_depth_mask, bytes_per_block, blocks_x, blocks_y,
[&](u32 zz, const VideoCommon::Accelerated::SliceBBox& box) {
const u32 z = g * zz_count + zz;
if (z >= static_cast<u32>(image.info.size.depth)) return;
task.slice_has_data[z] = 1u;
auto& acc = task.slice_bounds[z];
if (acc.x1 <= acc.x0 || acc.y1 <= acc.y0) {
acc = box;
} else {
@ -1476,8 +1485,7 @@ void TextureCache<P>::TickAsyncUnswizzle() {
acc.x1 = (std::max)(acc.x1, box.x1);
acc.y1 = (std::max)(acc.y1, box.y1);
}
}
}
});
}
}
} else {
@ -1616,22 +1624,6 @@ void TextureCache<P>::TickAsyncUnswizzle() {
(is_final_batch && bytes_ready < task.bytes_per_slice);
if (is_final_batch && all_submitted) {
/*if (task.is_sparse && !task.is_incremental) {
const auto segs =
gpu_memory->GetSubmappedRange(image.gpu_addr, image.guest_size_bytes);
CompletedSparseImage entry;
entry.image_id = task.image_id;
entry.info = task.info;
entry.gpu_addr = image.gpu_addr;
entry.guest_size_bytes = image.guest_size_bytes;
entry.last_segments.assign(segs.begin(), segs.end());
entry.slice_uploaded = task.slice_has_data;
entry.bytes_per_slice = task.bytes_per_slice;
entry.swizzled_slice_size = task.swizzled_slice_size;
entry.swizzle_block_depth = task.swizzle_block_depth;
completed_sparse_images.push_back(std::move(entry));
}*/
runtime.FreeDeferredStagingBuffer(task.staging_buffer);
image.flags &= ~ImageFlagBits::IsDecoding;
runtime.ReleaseSparseUnswizzleBuffer(image);
@ -1639,126 +1631,6 @@ void TextureCache<P>::TickAsyncUnswizzle() {
}
}
// This is my poor attempt at trying to detect if a sparse texture had been remapped and just reprocess what was changed
// This may or may not be slower in some circumstances or not work at all as about halfway through I fried my brain
template <class P>
void TextureCache<P>::TickCompletedSparseImages() {
if (completed_sparse_images.empty()) return;
for (auto it = completed_sparse_images.begin(); it != completed_sparse_images.end(); ) {
CompletedSparseImage& entry = *it;
Image& image = slot_images[entry.image_id];
if (True(image.flags & ImageFlagBits::IsDecoding)) {
++it;
continue;
}
const auto raw_segs =
gpu_memory->GetSubmappedRange(entry.gpu_addr, entry.guest_size_bytes);
const std::vector<std::pair<GPUVAddr, size_t>> current_segs(raw_segs.begin(), raw_segs.end());
if (current_segs == entry.last_segments) {
++it;
continue;
}
std::vector<std::pair<GPUVAddr, size_t>> new_segs;
{
size_t li = 0;
for (const auto& cseg : current_segs) {
while (li < entry.last_segments.size() &&
entry.last_segments[li].first < cseg.first) {
++li;
}
const bool already_known =
li < entry.last_segments.size() &&
entry.last_segments[li].first == cseg.first &&
entry.last_segments[li].second == cseg.second;
if (!already_known) {
new_segs.push_back(cseg);
}
}
}
entry.last_segments = current_segs;
if (new_segs.empty()) {
++it;
continue;
}
if (entry.swizzle_block_depth != 0 || entry.swizzled_slice_size == 0) {
QueueAsyncUnswizzle(image, entry.image_id);
++it;
continue;
}
std::vector<u8> new_slice_bm(image.info.size.depth, 0u);
u32 z_min = image.info.size.depth;
u32 z_max = 0;
for (const auto& [seg_gpu, seg_size] : new_segs) {
const u64 seg_abs_start = seg_gpu - entry.gpu_addr;
const u64 seg_abs_end = seg_abs_start + seg_size;
u32 z_first = static_cast<u32>(seg_abs_start / entry.swizzled_slice_size);
u32 z_last = static_cast<u32>((seg_abs_end - 1) / entry.swizzled_slice_size);
z_first = (std::min)(z_first, image.info.size.depth - 1);
z_last = (std::min)(z_last, image.info.size.depth - 1);
for (u32 z = z_first; z <= z_last; ++z) {
if (entry.slice_uploaded[z]) continue;
new_slice_bm[z] = 1u;
z_min = (std::min)(z_min, z);
z_max = (std::max)(z_max, z);
}
}
if (z_min > z_max) {
++it;
continue;
}
const u32 z_count = z_max - z_min + 1;
image.flags |= ImageFlagBits::IsDecoding;
PendingUnswizzle task{};
task.image_id = entry.image_id;
task.info = entry.info;
task.is_sparse = true;
task.is_incremental = true;
task.staging_base_byte_offset =
static_cast<size_t>(z_min) * entry.swizzled_slice_size;
task.total_size =
static_cast<size_t>(z_count) * entry.swizzled_slice_size;
task.incremental_z_start = z_min;
task.incremental_z_count = z_count;
task.bytes_per_slice = entry.bytes_per_slice;
task.swizzled_slice_size = entry.swizzled_slice_size;
task.swizzle_block_depth = entry.swizzle_block_depth;
task.last_submitted_offset = 0;
task.slice_has_data.resize(z_count, 0u);
for (u32 z = z_min; z <= z_max; ++z) {
task.slice_has_data[z - z_min] = new_slice_bm[z];
}
task.sparse_segments = std::move(new_segs);
task.segment_scan_cursor = 0;
unswizzle_queue.push_front(std::move(task));
for (u32 z = z_min; z <= z_max; ++z) {
entry.slice_uploaded[z] |= new_slice_bm[z];
}
++it;
}
}
template <class P>
bool TextureCache<P>::ScaleUp(Image& image) {
const bool has_copy = image.HasScaled();
@ -2715,11 +2587,6 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
}
slot_images.erase(image_id);
std::erase_if(completed_sparse_images,
[image_id](const CompletedSparseImage& e) {
return e.image_id == image_id;
});
alloc_images.erase(alloc_image_it);
if (alloc_images.empty()) {
image_allocs_table.erase(alloc_it);

2
src/video_core/texture_cache/texture_cache_base.h

@ -438,7 +438,6 @@ private:
void QueueAsyncUnswizzle(Image& image, ImageId image_id);
void TickAsyncUnswizzle();
void TickCompletedSparseImages();
struct CompletedSparseImage {
ImageId image_id;
@ -541,7 +540,6 @@ private:
std::vector<std::unique_ptr<AsyncDecodeContext>> async_decodes;
std::deque<PendingUnswizzle> unswizzle_queue;
std::deque<CompletedSparseImage> completed_sparse_images;
// Join caching
boost::container::small_vector<ImageId, 4> join_overlap_ids;

Loading…
Cancel
Save