|
|
|
@ -204,6 +204,17 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
std::optional<WindowBufferRef> src_window; |
|
|
|
std::optional<WindowBufferRef> dst_window; |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
src_window = TryObtainWindowBuffer(*cpu_src_address, static_cast<u32>(amount), |
|
|
|
UNIFIED_COPY_BINDING_ALIGNMENT, |
|
|
|
ObtainBufferOperation::DoNothing); |
|
|
|
dst_window = TryObtainWindowBuffer(*cpu_dest_address, static_cast<u32>(amount), |
|
|
|
UNIFIED_COPY_BINDING_ALIGNMENT, |
|
|
|
ObtainBufferOperation::DoNothing); |
|
|
|
} |
|
|
|
|
|
|
|
ClearDownload(*cpu_dest_address, amount); |
|
|
|
|
|
|
|
BufferId buffer_a; |
|
|
|
@ -215,11 +226,19 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am |
|
|
|
} while (channel_state->has_deleted_buffers); |
|
|
|
auto& src_buffer = slot_buffers[buffer_a]; |
|
|
|
auto& dest_buffer = slot_buffers[buffer_b]; |
|
|
|
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount)); |
|
|
|
SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount)); |
|
|
|
if (!src_window) { |
|
|
|
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount)); |
|
|
|
} |
|
|
|
if (!dst_window) { |
|
|
|
SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount)); |
|
|
|
} |
|
|
|
const u64 src_copy_offset = |
|
|
|
src_window ? u64{src_window->offset} : u64{src_buffer.Offset(*cpu_src_address)}; |
|
|
|
const u64 dst_copy_offset = |
|
|
|
dst_window ? u64{dst_window->offset} : u64{dest_buffer.Offset(*cpu_dest_address)}; |
|
|
|
std::array copies{BufferCopy{ |
|
|
|
.src_offset = src_buffer.Offset(*cpu_src_address), |
|
|
|
.dst_offset = dest_buffer.Offset(*cpu_dest_address), |
|
|
|
.src_offset = src_copy_offset, |
|
|
|
.dst_offset = dst_copy_offset, |
|
|
|
.size = amount, |
|
|
|
}}; |
|
|
|
|
|
|
|
@ -231,7 +250,9 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am |
|
|
|
tmp_intervals.push_back({new_base_address, size}); |
|
|
|
uncommitted_gpu_modified_ranges.Add(new_base_address, size); |
|
|
|
}; |
|
|
|
gpu_modified_ranges.ForEachInRange(*cpu_src_address, amount, mirror); |
|
|
|
if (!dst_window) { |
|
|
|
gpu_modified_ranges.ForEachInRange(*cpu_src_address, amount, mirror); |
|
|
|
} |
|
|
|
// This subtraction in this order is important for overlapping copies. |
|
|
|
ForgetGpuModifiedRange(*cpu_dest_address, amount); |
|
|
|
const bool has_new_downloads = tmp_intervals.size() != 0; |
|
|
|
@ -239,10 +260,25 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am |
|
|
|
gpu_modified_ranges.Add(pair.first, pair.second); |
|
|
|
} |
|
|
|
const auto& copy = copies[0]; |
|
|
|
src_buffer.MarkUsage(copy.src_offset, copy.size); |
|
|
|
dest_buffer.MarkUsage(copy.dst_offset, copy.size); |
|
|
|
runtime.CopyBuffer(dest_buffer, src_buffer, copies, true); |
|
|
|
if (has_new_downloads) { |
|
|
|
if (!src_window) { |
|
|
|
src_buffer.MarkUsage(copy.src_offset, copy.size); |
|
|
|
} |
|
|
|
if (!dst_window) { |
|
|
|
dest_buffer.MarkUsage(copy.dst_offset, copy.size); |
|
|
|
} |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
runtime.CopyBuffer( |
|
|
|
runtime.ResolveWindowHandle(dest_buffer, dst_window.has_value(), |
|
|
|
dst_window ? dst_window->window_index : 0), |
|
|
|
runtime.ResolveWindowHandle(src_buffer, src_window.has_value(), |
|
|
|
src_window ? src_window->window_index : 0), |
|
|
|
copies, true); |
|
|
|
} else { |
|
|
|
runtime.CopyBuffer(dest_buffer, src_buffer, copies, true); |
|
|
|
} |
|
|
|
if (dst_window) { |
|
|
|
MarkWrittenBufferInPlace(*cpu_dest_address, static_cast<u32>(amount)); |
|
|
|
} else if (has_new_downloads) { |
|
|
|
memory_tracker.MarkRegionAsGpuModified(*cpu_dest_address, amount); |
|
|
|
} |
|
|
|
|
|
|
|
@ -275,6 +311,54 @@ bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
auto BufferCache<P>::TryObtainWindowBuffer([[maybe_unused]] DAddr device_addr, |
|
|
|
[[maybe_unused]] u32 size, |
|
|
|
[[maybe_unused]] u64 alignment, |
|
|
|
[[maybe_unused]] ObtainBufferOperation post_op) |
|
|
|
-> std::optional<WindowBufferRef> { |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
if (!runtime.SupportsUnifiedDirectBinding()) { |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
u64 window_index = 0; |
|
|
|
u64 window_offset = 0; |
|
|
|
if (!ResolveUnifiedDirectBinding(device_addr, size, alignment, window_index, |
|
|
|
window_offset)) { |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
switch (post_op) { |
|
|
|
case ObtainBufferOperation::MarkAsWritten: |
|
|
|
MarkWrittenBufferInPlace(device_addr, size); |
|
|
|
break; |
|
|
|
case ObtainBufferOperation::DiscardWrite: { |
|
|
|
const DAddr aligned_start = Common::AlignDown(device_addr, 64); |
|
|
|
const DAddr aligned_end = Common::AlignUp(device_addr + size, 64); |
|
|
|
const size_t aligned_size = aligned_end - aligned_start; |
|
|
|
ClearDownload(aligned_start, aligned_size); |
|
|
|
ForgetGpuModifiedRange(aligned_start, aligned_size); |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
return WindowBufferRef{window_index, static_cast<u32>(window_offset)}; |
|
|
|
} else { |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
auto BufferCache<P>::TryObtainWindowBufferGpu(GPUVAddr gpu_addr, u32 size, u64 alignment, |
|
|
|
ObtainBufferOperation post_op) |
|
|
|
-> std::optional<WindowBufferRef> { |
|
|
|
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr); |
|
|
|
if (!device_addr) { |
|
|
|
return std::nullopt; |
|
|
|
} |
|
|
|
return TryObtainWindowBuffer(*device_addr, size, alignment, post_op); |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size, |
|
|
|
ObtainBufferSynchronize sync_info, |
|
|
|
@ -752,7 +836,7 @@ void BufferCache<P>::CommitAsyncFlushesHigh() { |
|
|
|
} |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
if (!in_place_downloads.empty()) { |
|
|
|
runtime.UnifiedMemoryShaderWriteBarrier(); |
|
|
|
runtime.UnifiedMemoryWriteBarrier(); |
|
|
|
} |
|
|
|
} |
|
|
|
runtime.PostCopyBarrier(); |
|
|
|
@ -1041,15 +1125,25 @@ void BufferCache<P>::BindHostVertexBuffers() { |
|
|
|
|
|
|
|
template <class P> |
|
|
|
void BufferCache<P>::BindHostDrawIndirectBuffers() { |
|
|
|
const auto bind_buffer = [this](const Binding& binding) { |
|
|
|
const auto bind_buffer = [this](const Binding& binding) -> std::optional<WindowBufferRef> { |
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id]; |
|
|
|
TouchBuffer(buffer, binding.buffer_id); |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
if (auto window = TryObtainWindowBuffer(binding.device_addr, binding.size, |
|
|
|
UNIFIED_INDIRECT_BINDING_ALIGNMENT, |
|
|
|
ObtainBufferOperation::DoNothing)) { |
|
|
|
return window; |
|
|
|
} |
|
|
|
} |
|
|
|
SynchronizeBuffer(buffer, binding.device_addr, binding.size); |
|
|
|
return std::nullopt; |
|
|
|
}; |
|
|
|
draw_indirect_count_window.reset(); |
|
|
|
draw_indirect_window.reset(); |
|
|
|
if (current_draw_indirect->include_count) { |
|
|
|
bind_buffer(channel_state->count_buffer_binding); |
|
|
|
draw_indirect_count_window = bind_buffer(channel_state->count_buffer_binding); |
|
|
|
} |
|
|
|
bind_buffer(channel_state->indirect_buffer_binding); |
|
|
|
draw_indirect_window = bind_buffer(channel_state->indirect_buffer_binding); |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
|