Browse Source

Slightly improve the way sparse texture unswizzling works

pull/3737/head
Forrest Mark X 4 weeks ago
committed by crueter
parent
commit
b7b7c51f75
  1. 2
      src/video_core/renderer_opengl/gl_texture_cache.h
  2. 124
      src/video_core/renderer_vulkan/vk_compute_pass.cpp
  3. 10
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  4. 6
      src/video_core/renderer_vulkan/vk_texture_cache.h
  5. 1
      src/video_core/texture_cache/texture_cache.h

2
src/video_core/renderer_opengl/gl_texture_cache.h

@ -142,6 +142,8 @@ public:
bool HasNativeASTC() const noexcept;
void ReleaseSparseUnswizzleBuffer(Image& image) {}
void TickFrame() {}
StateTracker& GetStateTracker() {

124
src/video_core/renderer_vulkan/vk_compute_pass.cpp

@ -773,23 +773,7 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
}
}
static constexpr u32 MAX_RUNS_PER_BATCH = 8;
const u32 min_run_len = (std::max)(4u, z_count / MAX_RUNS_PER_BATCH);
for (Run& r : runs) {
if (!r.has_data && r.len < min_run_len) {
r.has_data = true;
}
}
boost::container::small_vector<Run, 16> merged;
for (const Run& r : runs) {
if (!merged.empty() && merged.back().has_data == r.has_data) {
merged.back().len += r.len;
} else {
merged.push_back(r);
}
}
for (const Run& r : merged) {
u32 sub_offset = 0;
while (sub_offset < r.len) {
const u32 sub_len = (std::min)(r.len - sub_offset, MAX_BATCH_SLICES);
@ -797,52 +781,80 @@ void BlockLinearUnswizzle3DPass::Unswizzle(
const u32 z_dst = z_image_start + r.start + sub_offset;
if (!r.has_data) {
UnswizzleZeroChunk(image, z_dst, sub_len);
// Uncomment if junk data appears - FMX
//UnswizzleZeroChunk(image, z_dst, sub_len);
sub_offset += sub_len;
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;
u32 win_offset = 0;
while (win_offset < sub_len) {
const u32 win_len = (std::min)(sub_len - win_offset, 1u);
const u32 wz_src = z_src + win_offset;
const u32 wz_dst = z_dst + win_offset;
u32 ox0 = 0, oy0 = 0, ox1 = blocks_x, oy1 = blocks_y;
bool window_is_empty = false;
if (!slice_bounds.empty()) {
bool has_valid_bounds = false;
bool out_of_bounds = false;
u32 ux0 = blocks_x, uy0 = blocks_y, ux1 = 0, uy1 = 0;
for (u32 z = wz_src; z < wz_src + win_len; ++z) {
if (z >= static_cast<u32>(slice_bounds.size())) {
out_of_bounds = true;
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);
has_valid_bounds = true;
}
if (out_of_bounds) {
ox0 = 0; oy0 = 0; ox1 = blocks_x; oy1 = blocks_y;
} else if (has_valid_bounds) {
ox0 = ux0; oy0 = uy0; ox1 = ux1; oy1 = uy1;
} else {
window_is_empty = true;
}
}
if (window_is_empty) {
win_offset += win_len;
continue;
}
if (any) { ox0 = ux0; oy0 = uy0; ox1 = ux1; oy1 = uy1; }
}
// Uncomment if garbage data starts appearing
//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;
const VkImageMemoryBarrier barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image,
.subresourceRange = {aspect, 0, 1, 0, 1},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, barrier);
});
UnswizzleChunk(image, swizzled, sw, params,
ox0, oy0, ox1 - ox0, oy1 - oy0,
z_src, z_dst, sub_len);
scheduler.Record([dst_image = image.Handle(), aspect = image.AspectMask()](vk::CommandBuffer cmdbuf) {
if (dst_image == VK_NULL_HANDLE) return;
const VkImageMemoryBarrier barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image,
.subresourceRange = {aspect, 0, 1, 0, 1},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, barrier);
});
UnswizzleChunk(image, swizzled, sw, params,
ox0, oy0, ox1 - ox0, oy1 - oy0,
wz_src, wz_dst, win_len);
win_offset += win_len;
}
sub_offset += sub_len;
}

10
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -1769,6 +1769,16 @@ std::optional<size_t> TextureCacheRuntime::GetSamplerHeapBudget() const {
}
void TextureCacheRuntime::TickFrame() {
sentenced_unswizzle_buffers.Tick();
}
void TextureCacheRuntime::ReleaseSparseUnswizzleBuffer(Image& image) {
if (image.has_compute_unswizzle_buffer) {
sentenced_unswizzle_buffers.Push(std::move(image.compute_unswizzle_buffer));
image.has_compute_unswizzle_buffer = false;
image.compute_unswizzle_buffer_size = 0;
image.compute_unswizzle_buffer_is_zero = false;
}
std::erase_if(pending_msaa_images, [this](const auto& pending) {
return scheduler.IsFree(pending.first);
});

6
src/video_core/renderer_vulkan/vk_texture_cache.h

@ -17,6 +17,7 @@
#include "video_core/texture_cache/image_view_base.h"
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
#include "video_core/delayed_destruction_ring.h"
namespace Settings {
struct ResolutionScalingInfo;
@ -58,6 +59,8 @@ public:
void FreeDeferredStagingBuffer(StagingBufferRef& ref);
void ReleaseSparseUnswizzleBuffer(Image& image);
void TickFrame();
u64 GetDeviceLocalMemory() const;
@ -157,6 +160,8 @@ public:
static constexpr size_t indexing_slots = 8 * sizeof(size_t);
std::array<vk::Buffer, indexing_slots> buffers{};
VideoCommon::DelayedDestructionRing<vk::Buffer, 8> sentenced_unswizzle_buffers;
std::vector<std::pair<u64, vk::Image>> pending_msaa_images;
ankerl::unordered_dense::map<VkImage, ResolveShadow> resolve_shadows;
};
@ -327,6 +332,7 @@ public:
u64 allocation_tick;
friend class BlockLinearUnswizzle3DPass;
friend class TextureCacheRuntime;
private:
bool BlitScaleHelper(bool scale_up);

1
src/video_core/texture_cache/texture_cache.h

@ -1634,6 +1634,7 @@ void TextureCache<P>::TickAsyncUnswizzle() {
runtime.FreeDeferredStagingBuffer(task.staging_buffer);
image.flags &= ~ImageFlagBits::IsDecoding;
runtime.ReleaseSparseUnswizzleBuffer(image);
unswizzle_queue.pop_front();
}
}

Loading…
Cancel
Save