Browse Source

[TEST] Extend binding

CamilleLaVey 3 days ago
parent
commit
f9560a2594
  1. 120
      src/video_core/buffer_cache/buffer_cache.h
  2. 27
      src/video_core/buffer_cache/buffer_cache_base.h
  3. 6
      src/video_core/renderer_vulkan/vk_buffer_cache.cpp
  4. 7
      src/video_core/renderer_vulkan/vk_buffer_cache.h
  5. 29
      src/video_core/renderer_vulkan/vk_query_cache.cpp
  6. 72
      src/video_core/renderer_vulkan/vk_rasterizer.cpp

120
src/video_core/buffer_cache/buffer_cache.h

@ -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>

27
src/video_core/buffer_cache/buffer_cache_base.h

@ -13,6 +13,7 @@
#include <memory>
#include <mutex>
#include <numeric>
#include <optional>
#include <span>
#include <vector>
@ -271,6 +272,20 @@ public:
void BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format,
bool is_written, bool is_image);
struct WindowBufferRef {
u64 window_index;
u32 offset;
};
static constexpr u64 UNIFIED_INDIRECT_BINDING_ALIGNMENT = 4;
static constexpr u64 UNIFIED_COPY_BINDING_ALIGNMENT = 1;
[[nodiscard]] std::optional<WindowBufferRef> TryObtainWindowBuffer(
DAddr device_addr, u32 size, u64 alignment, ObtainBufferOperation post_op);
[[nodiscard]] std::optional<WindowBufferRef> TryObtainWindowBufferGpu(
GPUVAddr gpu_addr, u32 size, u64 alignment, ObtainBufferOperation post_op);
[[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(GPUVAddr gpu_addr, u32 size,
ObtainBufferSynchronize sync_info,
ObtainBufferOperation post_op);
@ -318,6 +333,15 @@ public:
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
[[nodiscard]] const std::optional<WindowBufferRef>& GetDrawIndirectWindow() const noexcept {
return draw_indirect_window;
}
[[nodiscard]] const std::optional<WindowBufferRef>& GetDrawIndirectCountWindow()
const noexcept {
return draw_indirect_count_window;
}
template <typename Func>
void BufferOperations(Func&& func) {
do {
@ -513,6 +537,9 @@ private:
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
std::optional<WindowBufferRef> draw_indirect_window;
std::optional<WindowBufferRef> draw_indirect_count_window;
u32 last_index_count = 0;
u32 enabled_vertex_buffers_mask = 0;

6
src/video_core/renderer_vulkan/vk_buffer_cache.cpp

@ -491,9 +491,9 @@ void BufferCacheRuntime::UnifiedMemoryHostBarrier() {
});
}
void BufferCacheRuntime::UnifiedMemoryShaderWriteBarrier() {
VkAccessFlags src_access = VK_ACCESS_SHADER_WRITE_BIT;
VkPipelineStageFlags src_stages = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE;
void BufferCacheRuntime::UnifiedMemoryWriteBarrier() {
VkAccessFlags src_access = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
VkPipelineStageFlags src_stages = vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER;
if (device.IsExtTransformFeedbackSupported()) {
src_access |= VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT;
src_stages |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT;

7
src/video_core/renderer_vulkan/vk_buffer_cache.h

@ -187,6 +187,11 @@ public:
BindTransformFeedbackBuffer(index, VK_NULL_HANDLE, 0, 0);
}
[[nodiscard]] VkBuffer ResolveWindowHandle(const Buffer& buffer, bool from_window,
size_t window_index) const noexcept {
return from_window ? UnifiedWindowBuffer(window_index) : buffer.Handle();
}
void BindBufferFromWindow(size_t window_index, u32 offset, u32 size) {
guest_descriptor_queue.AddBuffer(UnifiedWindowBuffer(window_index),
UnifiedWindowAddress(window_index), offset, size);
@ -205,7 +210,7 @@ public:
void UnifiedMemoryUploadBarrier();
void UnifiedMemoryShaderWriteBarrier();
void UnifiedMemoryWriteBarrier();
u64 CurrentTick();

29
src/video_core/renderer_vulkan/vk_query_cache.cpp

@ -1412,10 +1412,16 @@ void QueryCacheRuntime::HostConditionalRenderingCompareValueImpl(VideoCommon::Lo
std::scoped_lock lk(impl->buffer_cache.mutex);
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing;
const auto [buffer, offset] =
impl->buffer_cache.ObtainCPUBuffer(object.address, 8, sync_info, post_op);
impl->hcr_buffer = buffer->Handle();
impl->hcr_offset = offset;
if (const auto window = impl->buffer_cache.TryObtainWindowBuffer(
object.address, 8, Vulkan::BufferCache::UNIFIED_INDIRECT_BINDING_ALIGNMENT, post_op)) {
impl->hcr_buffer = impl->buffer_cache.runtime.UnifiedWindowBuffer(window->window_index);
impl->hcr_offset = window->offset;
} else {
const auto [buffer, offset] =
impl->buffer_cache.ObtainCPUBuffer(object.address, 8, sync_info, post_op);
impl->hcr_buffer = buffer->Handle();
impl->hcr_offset = offset;
}
}
if (impl->hcr_is_set) {
if (impl->hcr_setup.buffer == impl->hcr_buffer &&
@ -1446,10 +1452,17 @@ void QueryCacheRuntime::HostConditionalRenderingCompareBCImpl(DAddr address, boo
std::scoped_lock lk(impl->buffer_cache.mutex);
const auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
const auto post_op = VideoCommon::ObtainBufferOperation::DoNothing;
const auto [buffer, offset] =
impl->buffer_cache.ObtainCPUBuffer(address, resolve_size, sync_info, post_op);
to_resolve = buffer->Handle();
to_resolve_offset = static_cast<u32>(offset);
if (const auto window = impl->buffer_cache.TryObtainWindowBuffer(
address, resolve_size,
impl->buffer_cache.runtime.UnifiedStorageBufferAlignment(), post_op)) {
to_resolve = impl->buffer_cache.runtime.UnifiedWindowBuffer(window->window_index);
to_resolve_offset = window->offset;
} else {
const auto [buffer, offset] =
impl->buffer_cache.ObtainCPUBuffer(address, resolve_size, sync_info, post_op);
to_resolve = buffer->Handle();
to_resolve_offset = static_cast<u32>(offset);
}
}
bool was_running = impl->is_hcr_running;
if (was_running) {

72
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -303,11 +303,18 @@ void RasterizerVulkan::DrawIndirect() {
const auto& params = maxwell3d->draw_manager.indirect_state;
buffer_cache.SetDrawIndirect(&params);
PrepareDraw(params.is_indexed, [this, &params] {
const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer();
const auto& buffer = indirect_buffer.first;
const auto& offset = indirect_buffer.second;
VkBuffer buffer_handle;
u32 offset;
if (const auto& window = buffer_cache.GetDrawIndirectWindow()) {
buffer_handle = buffer_cache.runtime.UnifiedWindowBuffer(window->window_index);
offset = window->offset;
} else {
const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer();
buffer_handle = indirect_buffer.first->Handle();
offset = indirect_buffer.second;
}
if (params.is_byte_count) {
scheduler.Record([buffer_obj = buffer->Handle(), offset,
scheduler.Record([buffer_obj = buffer_handle, offset,
stride = params.stride](vk::CommandBuffer cmdbuf) {
cmdbuf.DrawIndirectByteCountEXT(1, 0, buffer_obj, offset, 0,
static_cast<u32>(stride));
@ -315,11 +322,19 @@ void RasterizerVulkan::DrawIndirect() {
return;
}
if (params.include_count) {
const auto count = buffer_cache.GetDrawIndirectCount();
const auto& draw_buffer = count.first;
const auto& offset_base = count.second;
scheduler.Record([draw_buffer_obj = draw_buffer->Handle(),
buffer_obj = buffer->Handle(), offset_base, offset,
VkBuffer draw_buffer_handle;
u32 offset_base;
if (const auto& count_window = buffer_cache.GetDrawIndirectCountWindow()) {
draw_buffer_handle =
buffer_cache.runtime.UnifiedWindowBuffer(count_window->window_index);
offset_base = count_window->offset;
} else {
const auto count = buffer_cache.GetDrawIndirectCount();
draw_buffer_handle = count.first->Handle();
offset_base = count.second;
}
scheduler.Record([draw_buffer_obj = draw_buffer_handle,
buffer_obj = buffer_handle, offset_base, offset,
params](vk::CommandBuffer cmdbuf) {
if (params.is_indexed) {
cmdbuf.DrawIndexedIndirectCount(
@ -333,7 +348,7 @@ void RasterizerVulkan::DrawIndirect() {
});
return;
}
scheduler.Record([buffer_obj = buffer->Handle(), offset, params](vk::CommandBuffer cmdbuf) {
scheduler.Record([buffer_obj = buffer_handle, offset, params](vk::CommandBuffer cmdbuf) {
if (params.is_indexed) {
cmdbuf.DrawIndexedIndirect(buffer_obj, offset,
static_cast<u32>(params.max_draw_counts),
@ -605,11 +620,21 @@ void RasterizerVulkan::DispatchCompute() {
// DispatchIndirect
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
const auto post_op = VideoCommon::ObtainBufferOperation::DiscardWrite;
const auto [buffer, offset] =
buffer_cache.ObtainBuffer(*indirect_address, 12, sync_info, post_op);
VkBuffer indirect_handle;
u32 indirect_base;
if (const auto window = buffer_cache.TryObtainWindowBufferGpu(
*indirect_address, 12, BufferCache::UNIFIED_INDIRECT_BINDING_ALIGNMENT, post_op)) {
indirect_handle = buffer_cache.runtime.UnifiedWindowBuffer(window->window_index);
indirect_base = window->offset;
} else {
const auto [buffer, offset] =
buffer_cache.ObtainBuffer(*indirect_address, 12, sync_info, post_op);
indirect_handle = buffer->Handle();
indirect_base = offset;
}
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([pipeline, indirect_buffer = buffer->Handle(),
indirect_offset = offset](vk::CommandBuffer cmdbuf) {
scheduler.Record([pipeline, indirect_buffer = indirect_handle,
indirect_offset = indirect_base](vk::CommandBuffer cmdbuf) {
if (!pipeline->IsBound()) {
return;
}
@ -1030,8 +1055,19 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
static constexpr auto sync_info = VideoCommon::ObtainBufferSynchronize::FullSynchronize;
const auto post_op = IS_IMAGE_UPLOAD ? VideoCommon::ObtainBufferOperation::DoNothing
: VideoCommon::ObtainBufferOperation::MarkAsWritten;
const auto [buffer, offset] =
buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op);
VkBuffer buffer_handle;
u32 offset;
if (const auto window = buffer_cache.TryObtainWindowBufferGpu(
buffer_operand.address, buffer_size,
BufferCache::UNIFIED_INDIRECT_BINDING_ALIGNMENT, post_op)) {
buffer_handle = buffer_cache.runtime.UnifiedWindowBuffer(window->window_index);
offset = window->offset;
} else {
const auto [buffer, buffer_offset] =
buffer_cache.ObtainBuffer(buffer_operand.address, buffer_size, sync_info, post_op);
buffer_handle = buffer->Handle();
offset = buffer_offset;
}
const auto [image, copy] = texture_cache.DmaBufferImageCopy(
copy_info, buffer_operand, image_operand, image_id, IS_IMAGE_UPLOAD);
@ -1039,12 +1075,12 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info,
if constexpr (IS_IMAGE_UPLOAD) {
texture_cache.PrepareImage(image_id, true, false);
image->UploadMemory(buffer->Handle(), offset, copy_span);
image->UploadMemory(buffer_handle, offset, copy_span);
} else {
if (offset % BytesPerBlock(image->info.format)) {
return false;
}
texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span,
texture_cache.DownloadImageIntoBuffer(image, buffer_handle, offset, copy_span,
buffer_operand.address, buffer_size);
}
return true;

Loading…
Cancel
Save