|
|
|
@ -820,6 +820,22 @@ void BufferCache<P>::BindHostIndexBuffer() { |
|
|
|
const u32 size = channel_state->index_buffer.size; |
|
|
|
const auto& draw_state = maxwell3d->draw_manager.draw_state; |
|
|
|
if (draw_state.inline_index_draw_indexes.empty()) { |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING && !HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { |
|
|
|
u64 window_index = 0; |
|
|
|
u64 window_offset = 0; |
|
|
|
if (runtime.CanBindIndexBufferDirectly(draw_state.topology, |
|
|
|
draw_state.index_buffer.format) && |
|
|
|
ResolveUnifiedDirectBinding(channel_state->index_buffer.device_addr, size, |
|
|
|
draw_state.index_buffer.FormatSizeInBytes(), |
|
|
|
window_index, window_offset)) { |
|
|
|
runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format, |
|
|
|
draw_state.index_buffer.first, |
|
|
|
draw_state.index_buffer.count, |
|
|
|
runtime.UnifiedWindowBuffer(window_index), |
|
|
|
static_cast<u32>(window_offset), size); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
SynchronizeBuffer(buffer, channel_state->index_buffer.device_addr, size); |
|
|
|
} else { |
|
|
|
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) { |
|
|
|
@ -905,13 +921,30 @@ void BufferCache<P>::BindHostVertexBuffers() { |
|
|
|
const Binding& binding = VertexBufferSlot(index); |
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id]; |
|
|
|
TouchBuffer(buffer, binding.buffer_id); |
|
|
|
SynchronizeBuffer(buffer, binding.device_addr, binding.size); |
|
|
|
u64 window_index = 0; |
|
|
|
u64 window_offset = 0; |
|
|
|
const bool bind_from_window = |
|
|
|
ResolveUnifiedDirectBinding(binding.device_addr, binding.size, |
|
|
|
UNIFIED_VERTEX_BINDING_ALIGNMENT, window_index, |
|
|
|
window_offset); |
|
|
|
if (!bind_from_window) { |
|
|
|
SynchronizeBuffer(buffer, binding.device_addr, binding.size); |
|
|
|
} |
|
|
|
if (!flags[Dirty::VertexBuffer0 + index]) { |
|
|
|
flush_bindings(); |
|
|
|
continue; |
|
|
|
} |
|
|
|
flags[Dirty::VertexBuffer0 + index] = false; |
|
|
|
const u32 stride = maxwell3d->regs.vertex_streams[index].stride; |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
if (bind_from_window) { |
|
|
|
flush_bindings(); |
|
|
|
runtime.BindVertexBuffer(index, runtime.UnifiedWindowBuffer(window_index), |
|
|
|
static_cast<u32>(window_offset), binding.size, |
|
|
|
stride); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
const u32 offset = buffer.Offset(binding.device_addr); |
|
|
|
buffer.MarkUsage(offset, binding.size); |
|
|
|
if (!bindings.buffers.empty() && index != last_index + 1) { |
|
|
|
@ -1084,11 +1117,26 @@ void BufferCache<P>::BindHostGraphicsStorageBuffers(size_t stage) { |
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id]; |
|
|
|
TouchBuffer(buffer, binding.buffer_id); |
|
|
|
const u32 size = binding.size; |
|
|
|
const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; |
|
|
|
|
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING && !NEEDS_BIND_STORAGE_INDEX) { |
|
|
|
u64 window_index = 0; |
|
|
|
u64 window_offset = 0; |
|
|
|
if (!is_written && runtime.SupportsUnifiedDescriptorBinding() && |
|
|
|
size <= runtime.UnifiedMaxStorageBufferRange() && |
|
|
|
ResolveUnifiedDirectBinding(binding.device_addr, size, |
|
|
|
runtime.UnifiedStorageBufferAlignment(), window_index, |
|
|
|
window_offset)) { |
|
|
|
runtime.BindStorageBufferFromWindow(window_index, static_cast<u32>(window_offset), |
|
|
|
size); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
SynchronizeBuffer(buffer, binding.device_addr, size); |
|
|
|
|
|
|
|
const u32 offset = buffer.Offset(binding.device_addr); |
|
|
|
buffer.MarkUsage(offset, size); |
|
|
|
const bool is_written = ((channel_state->written_storage_buffers[stage] >> index) & 1) != 0; |
|
|
|
|
|
|
|
if (is_written) { |
|
|
|
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size); |
|
|
|
@ -1220,12 +1268,27 @@ void BufferCache<P>::BindHostComputeStorageBuffers() { |
|
|
|
Buffer& buffer = slot_buffers[binding.buffer_id]; |
|
|
|
TouchBuffer(buffer, binding.buffer_id); |
|
|
|
const u32 size = binding.size; |
|
|
|
const bool is_written = |
|
|
|
((channel_state->written_compute_storage_buffers >> index) & 1) != 0; |
|
|
|
|
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING && !NEEDS_BIND_STORAGE_INDEX) { |
|
|
|
u64 window_index = 0; |
|
|
|
u64 window_offset = 0; |
|
|
|
if (!is_written && runtime.SupportsUnifiedDescriptorBinding() && |
|
|
|
size <= runtime.UnifiedMaxStorageBufferRange() && |
|
|
|
ResolveUnifiedDirectBinding(binding.device_addr, size, |
|
|
|
runtime.UnifiedStorageBufferAlignment(), window_index, |
|
|
|
window_offset)) { |
|
|
|
runtime.BindStorageBufferFromWindow(window_index, static_cast<u32>(window_offset), |
|
|
|
size); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
SynchronizeBuffer(buffer, binding.device_addr, size); |
|
|
|
|
|
|
|
const u32 offset = buffer.Offset(binding.device_addr); |
|
|
|
buffer.MarkUsage(offset, size); |
|
|
|
const bool is_written = |
|
|
|
((channel_state->written_compute_storage_buffers >> index) & 1) != 0; |
|
|
|
|
|
|
|
if (is_written) { |
|
|
|
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size); |
|
|
|
@ -1780,6 +1843,62 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
bool BufferCache<P>::ResolveUnifiedDirectBinding([[maybe_unused]] DAddr device_addr, |
|
|
|
[[maybe_unused]] u64 size, |
|
|
|
[[maybe_unused]] u64 alignment, |
|
|
|
[[maybe_unused]] u64& window_index, |
|
|
|
[[maybe_unused]] u64& window_offset) { |
|
|
|
if constexpr (USE_UNIFIED_DIRECT_BINDING) { |
|
|
|
if (size == 0 || !runtime.SupportsUnifiedDirectBinding()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const u64 window_size = runtime.UnifiedMemoryWindowSize(); |
|
|
|
if (window_size == 0) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const u8* const physical_base = device_memory.GetPhysicalBase(); |
|
|
|
const u8* const host_ptr = device_memory.GetPointer<u8>(device_addr); |
|
|
|
if (host_ptr == nullptr) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const u64 phys_offset = static_cast<u64>(host_ptr - physical_base); |
|
|
|
const u64 unified_base = runtime.UnifiedMemoryBase(); |
|
|
|
if (phys_offset < unified_base) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const u64 relative = phys_offset - unified_base; |
|
|
|
if (relative + size > runtime.UnifiedMemorySize()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const u64 local_offset = relative % window_size; |
|
|
|
if (local_offset + size > window_size) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (alignment != 0 && (local_offset & (alignment - 1)) != 0) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
u64 contiguous = (std::min)(size, static_cast<u64>(Core::DEVICE_PAGESIZE) - |
|
|
|
(device_addr & Core::DEVICE_PAGEMASK)); |
|
|
|
while (contiguous < size) { |
|
|
|
const u8* const next = device_memory.GetPointer<u8>(device_addr + contiguous); |
|
|
|
if (next == nullptr || |
|
|
|
static_cast<u64>(next - physical_base) != phys_offset + contiguous) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
contiguous += Core::DEVICE_PAGESIZE; |
|
|
|
} |
|
|
|
if (IsRegionGpuModified(device_addr, size)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
window_index = relative / window_size; |
|
|
|
window_offset = local_offset; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <class P> |
|
|
|
bool BufferCache<P>::ResolveUnifiedWindows( |
|
|
|
[[maybe_unused]] DAddr device_addr, [[maybe_unused]] u64 buffer_offset, |
|
|
|
|