aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2026-05-17 16:31:41 +0200
committerdec05eba <dec05eba@protonmail.com>2026-05-17 16:31:41 +0200
commit014125425e5f7afd39dea5a7e2b948c59933dc1f (patch)
tree452ee1fcd9225075a8c942362d66f071e2b24475
parent01045800155c74123da48f9cdd8f459d06c40ddc (diff)
Attempt to fix iGPU & dGPU sync issue with kms capture
-rw-r--r--src/capture/kms.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/src/capture/kms.c b/src/capture/kms.c
index fe4eb40..89a86f7 100644
--- a/src/capture/kms.c
+++ b/src/capture/kms.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
+#include <poll.h>
#include <xf86drm.h>
#include <drm_fourcc.h>
@@ -274,6 +275,31 @@ static vec2i swap_vec2i(vec2i value) {
return value;
}
+/* Wait for any pending writer fences on the dma-buf so we don't sample a
+ partially-written buffer. POLLIN on a dma-buf fd is the kernel's portable
+ way to wait on all attached writer fences (works across drivers, unlike
+ relying on Mesa's implicit-sync to honor a fence from another driver).
+ Without this, KMS capture can produce glitched frames in hybrid GPU setups
+ where the buffer on the captured plane is being written by a different
+ GPU/driver than the one gsr is encoding on (e.g. an iGPU client surface
+ shown on a dGPU monitor). The wait is normally a no-op because the fence
+ has already signaled by the time we get here; the timeout is just a guard. */
+static void gsr_capture_kms_wait_for_buffer_fence(const int *fds, int num_fds) {
+ struct pollfd pfds[GSR_KMS_MAX_DMA_BUFS];
+ int num_pfds = 0;
+ for(int i = 0; i < num_fds && num_pfds < GSR_KMS_MAX_DMA_BUFS; ++i) {
+ if(fds[i] <= 0)
+ continue;
+ pfds[num_pfds].fd = fds[i];
+ pfds[num_pfds].events = POLLIN;
+ pfds[num_pfds].revents = 0;
+ ++num_pfds;
+ }
+ if(num_pfds == 0)
+ return;
+ (void)poll(pfds, num_pfds, 100);
+}
+
static EGLImage gsr_capture_kms_create_egl_image(gsr_capture_kms *self, const gsr_kms_response_item *drm_fd, const int *fds, const uint32_t *offsets, const uint32_t *pitches, const uint64_t *modifiers, bool use_modifiers) {
intptr_t img_attr[44];
setup_dma_buf_attrs(img_attr, drm_fd->pixel_format, drm_fd->width, drm_fd->height, fds, offsets, pitches, modifiers, drm_fd->num_dma_bufs, use_modifiers);
@@ -319,6 +345,8 @@ static EGLImage gsr_capture_kms_create_egl_image_with_fallback(gsr_capture_kms *
modifiers[i] = drm_fd->modifier;
}
+ gsr_capture_kms_wait_for_buffer_fence(fds, drm_fd->num_dma_bufs);
+
EGLImage image = NULL;
if(self->no_modifiers_fallback) {
image = gsr_capture_kms_create_egl_image(self, drm_fd, fds, offsets, pitches, modifiers, false);
@@ -452,6 +480,8 @@ static void render_drm_cursor(gsr_capture_kms *self, gsr_color_conversion *color
modifiers[i] = cursor_drm_fd->modifier;
}
+ gsr_capture_kms_wait_for_buffer_fence(fds, cursor_drm_fd->num_dma_bufs);
+
intptr_t img_attr_cursor[44];
setup_dma_buf_attrs(img_attr_cursor, cursor_drm_fd->pixel_format, cursor_drm_fd->width, cursor_drm_fd->height,
fds, offsets, pitches, modifiers, cursor_drm_fd->num_dma_bufs, true);