Step back + keeping fixes from unified download + shared mem refactor

This commit is contained in:
CamilleLaVey 2026-08-11 18:50:22 -04:00
parent 17463f7b0d
commit d93039fb42
11 changed files with 53 additions and 133 deletions

View file

@ -1971,57 +1971,11 @@ bool BufferCache<P>::TryUnifiedDownloadMemory([[maybe_unused]] Buffer& buffer,
}
}
template <class P>
bool BufferCache<P>::TryUnifiedUploadMemory([[maybe_unused]] Buffer& buffer,
[[maybe_unused]] std::span<const BufferCopy> copies) {
if constexpr (USE_UNIFIED_MEMORY) {
boost::container::small_vector<u64, 4> window_ids;
UnifiedWindowGroups groups;
for (const BufferCopy& copy : copies) {
if (!ResolveUnifiedWindows(buffer.CpuAddr() + copy.dst_offset, copy.dst_offset,
copy.size, window_ids, groups)) {
return false;
}
}
for (const BufferCopy& copy : copies) {
buffer.MarkUsage(copy.dst_offset, copy.size);
}
runtime.PreCopyBarrier();
boost::container::small_vector<BufferCopy, 16> window_source_copies;
for (size_t i = 0; i < window_ids.size(); ++i) {
window_source_copies.clear();
window_source_copies.reserve(groups[i].size());
for (const BufferCopy& copy : groups[i]) {
window_source_copies.push_back(BufferCopy{
.src_offset = copy.dst_offset,
.dst_offset = copy.src_offset,
.size = copy.size,
});
}
const std::span<const BufferCopy> group_span(window_source_copies.data(),
window_source_copies.size());
runtime.CopyFromUnifiedMemory(window_ids[i], buffer, group_span);
}
runtime.FlushUnifiedMemoryCopies();
runtime.PostCopyBarrier();
return true;
} else {
return false;
}
}
template <class P>
void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
[[maybe_unused]] u64 total_size_bytes,
[[maybe_unused]] std::span<BufferCopy> copies) {
if constexpr (USE_MEMORY_MAPS) {
if constexpr (USE_UNIFIED_MEMORY) {
if (runtime.HasUnifiedMemory() &&
!Settings::values.enable_gpu_buffer_readback.GetValue() &&
TryUnifiedUploadMemory(buffer, copies)) {
return;
}
}
auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
const std::span<u8> staging_pointer = upload_staging.mapped_span;
for (BufferCopy& copy : copies) {

View file

@ -465,8 +465,6 @@ private:
bool TryUnifiedDownloadMemory(Buffer& buffer, std::span<BufferCopy> copies);
bool TryUnifiedUploadMemory(Buffer& buffer, std::span<const BufferCopy> copies);
using UnifiedWindowGroups =
boost::container::small_vector<boost::container::small_vector<BufferCopy, 16>, 4>;

View file

@ -238,6 +238,7 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.has_gl_bool_ref_bug = device.HasBoolRefBug(),
.ignore_nan_fp_comparisons = true,
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
.max_shared_memory_size = device.GetMaxComputeSharedMemorySize(),
.min_ssbo_alignment = device.GetShaderStorageBufferAlignment(),
// Use the host limit, but never more than the guest can produce. Maxwell exposes 8 clip
// distances and the SPIR-V output array is sized for at most 8, so clamping here keeps a

View file

@ -412,56 +412,33 @@ void BufferCacheRuntime::TryEnableUnifiedMemory(void* base, size_t size,
}
}
void BufferCacheRuntime::QueueUnifiedCopy(size_t window_index, VkBuffer buffer,
std::span<const VideoCommon::BufferCopy> copies,
bool reads_window) {
if (!unified_memory || buffer == VK_NULL_HANDLE || copies.empty() ||
void BufferCacheRuntime::CopyToUnifiedMemory(
size_t window_index, VkBuffer src_buffer,
std::span<const VideoCommon::BufferCopy> copies) {
if (!unified_memory || src_buffer == VK_NULL_HANDLE || copies.empty() ||
window_index >= unified_memory->GetWindowCount() ||
unified_memory->GetWindowBuffer(window_index) == VK_NULL_HANDLE) {
return;
}
PendingUnifiedCopy& pending = pending_unified_copies.emplace_back();
pending.window = window_index;
pending.buffer = buffer;
pending.reads_window = reads_window;
pending.buffer = src_buffer;
pending.copies.resize(copies.size());
std::ranges::transform(copies, pending.copies.begin(), MakeBufferCopy);
}
void BufferCacheRuntime::CopyToUnifiedMemory(
size_t window_index, VkBuffer src_buffer,
std::span<const VideoCommon::BufferCopy> copies) {
QueueUnifiedCopy(window_index, src_buffer, copies, false);
}
void BufferCacheRuntime::CopyFromUnifiedMemory(
size_t window_index, VkBuffer dst_buffer,
std::span<const VideoCommon::BufferCopy> copies) {
QueueUnifiedCopy(window_index, dst_buffer, copies, true);
}
void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
if (pending_unified_copies.empty()) {
return;
}
struct UnifiedCopyCommand {
VkBuffer buffer;
bool reads_window;
boost::container::small_vector<VkBufferCopy, 8> copies;
};
static constexpr VkMemoryBarrier WINDOW_TRANSFER_BARRIER{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
};
std::stable_sort(pending_unified_copies.begin(), pending_unified_copies.end(),
[](const PendingUnifiedCopy& lhs, const PendingUnifiedCopy& rhs) {
if (lhs.window != rhs.window) {
return lhs.window < rhs.window;
}
return lhs.reads_window && !rhs.reads_window;
});
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer();
@ -478,20 +455,9 @@ void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
const VkBuffer window_buffer = unified_memory->GetWindowBuffer(window);
WindowRanges ranges;
VkAccessFlags window_access = 0;
size_t reads_in_group = 0;
for (size_t index = group_begin; index < group_end; ++index) {
const PendingUnifiedCopy& pending = pending_unified_copies[index];
if (pending.reads_window) {
window_access |= VK_ACCESS_TRANSFER_READ_BIT;
++reads_in_group;
} else {
window_access |= VK_ACCESS_TRANSFER_WRITE_BIT;
}
for (const VkBufferCopy& copy : pending.copies) {
const VkDeviceSize offset =
pending.reads_window ? copy.srcOffset : copy.dstOffset;
ranges.emplace_back(offset, offset + copy.size);
for (const VkBufferCopy& copy : pending_unified_copies[index].copies) {
ranges.emplace_back(copy.dstOffset, copy.dstOffset + copy.size);
}
}
CoalesceWindowRanges(ranges);
@ -504,7 +470,7 @@ void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = window_access,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
.dstQueueFamilyIndex = queue_family,
.buffer = window_buffer,
@ -514,7 +480,7 @@ void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
release.push_back(VkBufferMemoryBarrier{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = window_access,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstAccessMask = 0,
.srcQueueFamilyIndex = queue_family,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
@ -529,37 +495,21 @@ void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
commands.reserve(group_end - group_begin);
for (size_t index = group_begin; index < group_end; ++index) {
PendingUnifiedCopy& pending = pending_unified_copies[index];
commands.push_back(UnifiedCopyCommand{pending.buffer, pending.reads_window,
std::move(pending.copies)});
commands.push_back(UnifiedCopyCommand{pending.buffer, std::move(pending.copies)});
}
const size_t barrier_before_writes = (reads_in_group > 0 && reads_in_group < commands.size())
? reads_in_group
: commands.size();
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([window_buffer, barrier_before_writes, acquire = std::move(acquire),
release = std::move(release),
scheduler.Record([window_buffer, acquire = std::move(acquire), release = std::move(release),
commands = std::move(commands)](vk::CommandBuffer cmdbuf) {
if (!acquire.empty()) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {},
VideoCommon::FixSmallVectorADL(acquire), {});
}
for (size_t index = 0; index < commands.size(); ++index) {
if (index == barrier_before_writes) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
WINDOW_TRANSFER_BARRIER);
}
const UnifiedCopyCommand& command = commands[index];
if (command.reads_window) {
cmdbuf.CopyBuffer(window_buffer, command.buffer,
VideoCommon::FixSmallVectorADL(command.copies));
} else {
for (const UnifiedCopyCommand& command : commands) {
cmdbuf.CopyBuffer(command.buffer, window_buffer,
VideoCommon::FixSmallVectorADL(command.copies));
}
}
if (!release.empty()) {
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, {},

View file

@ -135,9 +135,6 @@ public:
void CopyToUnifiedMemory(size_t window_index, VkBuffer src_buffer,
std::span<const VideoCommon::BufferCopy> copies);
void CopyFromUnifiedMemory(size_t window_index, VkBuffer dst_buffer,
std::span<const VideoCommon::BufferCopy> copies);
void FlushUnifiedMemoryCopies();
void UnifiedMemoryHostBarrier();
@ -268,13 +265,9 @@ private:
struct PendingUnifiedCopy {
size_t window;
VkBuffer buffer;
bool reads_window;
boost::container::small_vector<VkBufferCopy, 8> copies;
};
void QueueUnifiedCopy(size_t window_index, VkBuffer buffer,
std::span<const VideoCommon::BufferCopy> copies, bool reads_window);
void BindBuffer(const Buffer& buffer, u32 offset, u32 size) {
const VkBuffer handle = buffer.Handle();
if (handle == VK_NULL_HANDLE) {

View file

@ -451,6 +451,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
.has_broken_fp32_denorm_flush = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
.ignore_nan_fp_comparisons = false,
.has_broken_spirv_subgroup_mask_vector_extract_dynamic = false,
.max_shared_memory_size = device.GetMaxComputeSharedMemorySize(),
.has_broken_robust =
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
@ -969,19 +970,6 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
}
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
const VkDriverIdKHR driver_id = device.GetDriverID();
const bool needs_shared_mem_clamp =
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
const u32 max_shared_memory = device.GetMaxComputeSharedMemorySize();
if (needs_shared_mem_clamp && program.shared_memory_size > max_shared_memory) {
LOG_WARNING(Render_Vulkan,
"Compute shader {:#016x} requests {}KB shared memory but device max is {}KB - clamping",
key.unique_hash,
program.shared_memory_size / 1024,
max_shared_memory / 1024);
program.shared_memory_size = max_shared_memory;
}
const std::vector<u32> code{EmitSPIRV(profile, program)};
device.SaveShader(code);
vk::ShaderModule spv_module{BuildShader(device, code)};