diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 6d16d03e5f..86851ed67f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1254,17 +1254,73 @@ void BufferCache
::BindHostTransformFeedbackBuffers() {
if (maxwell3d->regs.transform_feedback_enabled == 0) {
return;
}
- HostBindings 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 window_indices{};
+ std::array 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(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 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;
diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h
index 97bcc65f92..8368986b9e 100644
--- a/src/video_core/buffer_cache/buffer_cache_base.h
+++ b/src/video_core/buffer_cache/buffer_cache_base.h
@@ -184,6 +184,7 @@ class BufferCache : public VideoCommon::ChannelSetupCaches GetMaxComputeWorkGroupCount() const {
const auto& count = properties.properties.limits.maxComputeWorkGroupCount;
return {count[0], count[1], count[2]};