Browse Source

[TEST] Add XFB binding

CamilleLaVey 3 days ago
parent
commit
119c41f614
  1. 62
      src/video_core/buffer_cache/buffer_cache.h
  2. 1
      src/video_core/buffer_cache/buffer_cache_base.h
  3. 14
      src/video_core/renderer_vulkan/vk_buffer_cache.cpp
  4. 17
      src/video_core/renderer_vulkan/vk_buffer_cache.h
  5. 8
      src/video_core/vulkan_common/vulkan_device.h

62
src/video_core/buffer_cache/buffer_cache.h

@ -1254,17 +1254,73 @@ void BufferCache<P>::BindHostTransformFeedbackBuffers() {
if (maxwell3d->regs.transform_feedback_enabled == 0) {
return;
}
HostBindings<typename P::Buffer> host_bindings;
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const auto is_active = [&](u32 index) {
const Binding& binding = channel_state->transform_feedback_buffers[index];
const auto& control = maxwell3d->regs.transform_feedback.controls[index];
const bool has_layout = control.varying_count != 0 || control.stride != 0;
return has_layout && binding.buffer_id != NULL_BUFFER_ID && binding.size != 0;
};
std::array<u64, NUM_TRANSFORM_FEEDBACK_BUFFERS> window_indices{};
std::array<u64, NUM_TRANSFORM_FEEDBACK_BUFFERS> window_offsets{};
u32 window_mask = 0;
if constexpr (USE_UNIFIED_DIRECT_BINDING) {
if (runtime.SupportsUnifiedTransformFeedbackBinding()) {
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
if (!is_active(index)) {
continue;
}
const Binding& binding = channel_state->transform_feedback_buffers[index];
if (binding.size > runtime.UnifiedMaxTransformFeedbackBufferSize()) {
continue;
}
if (ResolveUnifiedDirectBinding(binding.device_addr, binding.size,
UNIFIED_TRANSFORM_FEEDBACK_BINDING_ALIGNMENT,
window_indices[index], window_offsets[index])) {
window_mask |= 1u << index;
}
}
}
}
if constexpr (USE_UNIFIED_DIRECT_BINDING) {
if (window_mask != 0) {
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const Binding& binding = channel_state->transform_feedback_buffers[index];
if (((window_mask >> index) & 1) != 0) {
TouchBuffer(slot_buffers[binding.buffer_id], binding.buffer_id);
MarkWrittenBufferInPlace(binding.device_addr, binding.size);
runtime.BindTransformFeedbackBufferFromWindow(
index, window_indices[index], static_cast<u32>(window_offsets[index]),
binding.size);
continue;
}
if (!is_active(index)) {
runtime.BindNullTransformFeedbackBuffer(index);
continue;
}
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
const u32 size = binding.size;
SynchronizeBuffer(buffer, binding.device_addr, size);
MarkWrittenBuffer(binding.buffer_id, binding.device_addr, size);
const u32 offset = buffer.Offset(binding.device_addr);
buffer.MarkUsage(offset, size);
runtime.BindTransformFeedbackBuffer(index, buffer, offset, size);
}
return;
}
}
HostBindings<typename P::Buffer> host_bindings;
for (u32 index = 0; index < NUM_TRANSFORM_FEEDBACK_BUFFERS; ++index) {
const Binding& binding = channel_state->transform_feedback_buffers[index];
Buffer* host_buffer = &slot_buffers[NULL_BUFFER_ID];
u32 offset = 0;
u32 size = 0;
if (has_layout && binding.buffer_id != NULL_BUFFER_ID && binding.size != 0) {
if (is_active(index)) {
Buffer& buffer = slot_buffers[binding.buffer_id];
TouchBuffer(buffer, binding.buffer_id);
size = binding.size;

1
src/video_core/buffer_cache/buffer_cache_base.h

@ -184,6 +184,7 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
static constexpr bool USE_UNIFIED_UPLOADS = P::USE_UNIFIED_UPLOADS;
static constexpr bool USE_UNIFIED_DIRECT_BINDING = P::USE_UNIFIED_DIRECT_BINDING;
static constexpr u64 UNIFIED_VERTEX_BINDING_ALIGNMENT = 4;
static constexpr u64 UNIFIED_TRANSFORM_FEEDBACK_BINDING_ALIGNMENT = 4;
#ifdef YUZU_LEGACY
static constexpr s64 TARGET_THRESHOLD = 3_GiB;

14
src/video_core/renderer_vulkan/vk_buffer_cache.cpp

@ -492,16 +492,20 @@ void BufferCacheRuntime::UnifiedMemoryHostBarrier() {
}
void BufferCacheRuntime::UnifiedMemoryShaderWriteBarrier() {
static constexpr VkMemoryBarrier SHADER_WRITE_BARRIER{
const bool has_transform_feedback = device.IsExtTransformFeedbackSupported();
const VkMemoryBarrier write_barrier{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
(has_transform_feedback ? VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT : 0),
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
};
const VkPipelineStageFlags src_stages =
vk::PIPELINE_STAGE_GRAPHICS_COMPUTE |
(has_transform_feedback ? VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT : 0);
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, VK_PIPELINE_STAGE_HOST_BIT, 0,
SHADER_WRITE_BARRIER);
scheduler.Record([write_barrier, src_stages](vk::CommandBuffer cmdbuf) {
cmdbuf.PipelineBarrier(src_stages, VK_PIPELINE_STAGE_HOST_BIT, 0, write_barrier);
});
}

17
src/video_core/renderer_vulkan/vk_buffer_cache.h

@ -170,6 +170,23 @@ public:
return device.GetTexelBufferAlignment();
}
[[nodiscard]] bool SupportsUnifiedTransformFeedbackBinding() const noexcept {
return SupportsUnifiedDirectBinding() && device.IsExtTransformFeedbackSupported();
}
[[nodiscard]] u64 UnifiedMaxTransformFeedbackBufferSize() const noexcept {
return device.GetMaxTransformFeedbackBufferSize();
}
void BindTransformFeedbackBufferFromWindow(u32 index, size_t window_index, u32 offset,
u32 size) {
BindTransformFeedbackBuffer(index, UnifiedWindowBuffer(window_index), offset, size);
}
void BindNullTransformFeedbackBuffer(u32 index) {
BindTransformFeedbackBuffer(index, VK_NULL_HANDLE, 0, 0);
}
void BindBufferFromWindow(size_t window_index, u32 offset, u32 size) {
guest_descriptor_queue.AddBuffer(UnifiedWindowBuffer(window_index),
UnifiedWindowAddress(window_index), offset, size);

8
src/video_core/vulkan_common/vulkan_device.h

@ -352,11 +352,17 @@ public:
return properties.properties.limits.maxUniformBufferRange;
}
/// Returns texel buffer alignment requirement.
/// Returns transform feedback buffer alignment requirement.
VkDeviceSize GetMaxTransformFeedbackBufferSize() const {
return properties.transform_feedback.maxTransformFeedbackBufferSize;
}
// Returns texel buffer alignment requirement.
VkDeviceSize GetTexelBufferAlignment() const {
return properties.properties.limits.minTexelBufferOffsetAlignment;
}
/// Returns the maximum number of workgroups that can be dispatched in a single dimension.
std::array<u32, 3> GetMaxComputeWorkGroupCount() const {
const auto& count = properties.properties.limits.maxComputeWorkGroupCount;
return {count[0], count[1], count[2]};

Loading…
Cancel
Save