fix: route dma-buf straight to GPU thumbnails without CPU probing
Probing every committed buffer with wlr_buffer_begin_data_ptr_access first can stall on GPU fences at 60Hz, visibly slowing GPU clients like alacritty when --overlay-previews is on. Check wlr_buffer_get_dmabuf (a cheap attribute read with no mapping or sync) first and lock dma-bufs directly for GPU import; only non-dma-buf buffers go through the CPU snapshot path.
This commit is contained in:
parent
ca9b5ece2c
commit
8b8137684a
1 changed files with 88 additions and 73 deletions
161
kick.c
161
kick.c
|
|
@ -2706,79 +2706,12 @@ static void thumb_capture(struct kick_window *w) {
|
|||
struct wlr_surface *s = window_surface(w);
|
||||
struct wlr_buffer *b = (s && s->current.buffer) ? s->current.buffer : NULL;
|
||||
if (b && b->width > 0 && b->height > 0) {
|
||||
void *data = NULL;
|
||||
uint32_t fmt = 0;
|
||||
size_t stride = 0;
|
||||
bool begun = wlr_buffer_begin_data_ptr_access(
|
||||
b, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride);
|
||||
bool cpu = begun &&
|
||||
(fmt == DRM_FORMAT_ARGB8888 || fmt == DRM_FORMAT_XRGB8888);
|
||||
if (cpu) {
|
||||
int bw = b->width, bh = b->height;
|
||||
int tw = overlay_preview_snap_w(), th = overlay_preview_snap_h();
|
||||
if (!w->thumb_px || w->thumb_pw != tw || w->thumb_ph != th) {
|
||||
free(w->thumb_px);
|
||||
w->thumb_px = malloc((size_t)tw * th * 4);
|
||||
w->thumb_pw = tw;
|
||||
w->thumb_ph = th;
|
||||
}
|
||||
if (w->thumb_px) {
|
||||
/* Box-averaged downscale: average every source pixel in
|
||||
each destination pixel's block instead of sampling one,
|
||||
so glyph strokes survive as shapes rather than speckle.
|
||||
Average in premultiplied space. */
|
||||
for (int y = 0; y < th; y++) {
|
||||
int sy0 = (int)((int64_t)y * bh / th);
|
||||
int sy1 = (int)(((int64_t)(y + 1) * bh + th - 1) / th);
|
||||
if (sy1 <= sy0) sy1 = sy0 + 1;
|
||||
if (sy1 > bh) sy1 = bh;
|
||||
for (int x = 0; x < tw; x++) {
|
||||
int sx0 = (int)((int64_t)x * bw / tw);
|
||||
int sx1 = (int)(((int64_t)(x + 1) * bw + tw - 1) / tw);
|
||||
if (sx1 <= sx0) sx1 = sx0 + 1;
|
||||
if (sx1 > bw) sx1 = bw;
|
||||
unsigned long sa = 0, sr = 0, sg = 0, sb = 0;
|
||||
unsigned long n = 0;
|
||||
for (int sy = sy0; sy < sy1; sy++) {
|
||||
const uint32_t *row = (const uint32_t *)
|
||||
((const char *)data + (size_t)sy * stride);
|
||||
for (int sx = sx0; sx < sx1; sx++) {
|
||||
uint32_t p = row[sx];
|
||||
unsigned a = (p >> 24) & 0xff;
|
||||
if (fmt == DRM_FORMAT_XRGB8888 || a == 0)
|
||||
a = 0xff;
|
||||
unsigned r = (p >> 16) & 0xff,
|
||||
g = (p >> 8) & 0xff,
|
||||
bl = p & 0xff;
|
||||
sa += a;
|
||||
sr += r * a / 255;
|
||||
sg += g * a / 255;
|
||||
sb += bl * a / 255;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n == 0) n = 1;
|
||||
unsigned a = (unsigned)(sa / n);
|
||||
unsigned r = (unsigned)(sr / n);
|
||||
unsigned g = (unsigned)(sg / n);
|
||||
unsigned bl = (unsigned)(sb / n);
|
||||
w->thumb_px[(size_t)y * tw + x] =
|
||||
(a << 24) | (r << 16) | (g << 8) | bl;
|
||||
}
|
||||
}
|
||||
w->thumb_src = THUMB_SRC_SNAP;
|
||||
w->thumb_dirty = true;
|
||||
}
|
||||
wlr_buffer_end_data_ptr_access(b);
|
||||
if (w->thumb_buf) {
|
||||
/* Source switched back to SHM: drop the GPU buffer lock. */
|
||||
wlr_buffer_unlock(w->thumb_buf);
|
||||
w->thumb_buf = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Not CPU-readable (dma-buf): hold a lock and import at draw. */
|
||||
if (begun)
|
||||
wlr_buffer_end_data_ptr_access(b);
|
||||
/* Route dma-buf straight to the GPU path: probing it with a CPU
|
||||
data-pointer access first can stall on GPU fences at 60Hz, which
|
||||
visibly slows GPU clients like alacritty. get_dmabuf is a cheap
|
||||
attribute read with no mapping or sync involved. */
|
||||
struct wlr_dmabuf_attributes dma;
|
||||
if (wlr_buffer_get_dmabuf(b, &dma)) {
|
||||
if (b != w->thumb_buf) {
|
||||
if (w->thumb_buf)
|
||||
wlr_buffer_unlock(w->thumb_buf);
|
||||
|
|
@ -2786,6 +2719,88 @@ static void thumb_capture(struct kick_window *w) {
|
|||
}
|
||||
w->thumb_src = THUMB_SRC_DMABUF;
|
||||
w->thumb_dirty = true;
|
||||
} else {
|
||||
void *data = NULL;
|
||||
uint32_t fmt = 0;
|
||||
size_t stride = 0;
|
||||
bool begun = wlr_buffer_begin_data_ptr_access(
|
||||
b, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride);
|
||||
bool cpu = begun &&
|
||||
(fmt == DRM_FORMAT_ARGB8888 || fmt == DRM_FORMAT_XRGB8888);
|
||||
if (cpu) {
|
||||
int bw = b->width, bh = b->height;
|
||||
int tw = overlay_preview_snap_w(), th = overlay_preview_snap_h();
|
||||
if (!w->thumb_px || w->thumb_pw != tw || w->thumb_ph != th) {
|
||||
free(w->thumb_px);
|
||||
w->thumb_px = malloc((size_t)tw * th * 4);
|
||||
w->thumb_pw = tw;
|
||||
w->thumb_ph = th;
|
||||
}
|
||||
if (w->thumb_px) {
|
||||
/* Box-averaged downscale: average every source pixel in
|
||||
each destination pixel's block instead of sampling one,
|
||||
so glyph strokes survive as shapes rather than speckle.
|
||||
Average in premultiplied space. */
|
||||
for (int y = 0; y < th; y++) {
|
||||
int sy0 = (int)((int64_t)y * bh / th);
|
||||
int sy1 = (int)(((int64_t)(y + 1) * bh + th - 1) / th);
|
||||
if (sy1 <= sy0) sy1 = sy0 + 1;
|
||||
if (sy1 > bh) sy1 = bh;
|
||||
for (int x = 0; x < tw; x++) {
|
||||
int sx0 = (int)((int64_t)x * bw / tw);
|
||||
int sx1 = (int)(((int64_t)(x + 1) * bw + tw - 1) / tw);
|
||||
if (sx1 <= sx0) sx1 = sx0 + 1;
|
||||
if (sx1 > bw) sx1 = bw;
|
||||
unsigned long sa = 0, sr = 0, sg = 0, sb = 0;
|
||||
unsigned long n = 0;
|
||||
for (int sy = sy0; sy < sy1; sy++) {
|
||||
const uint32_t *row = (const uint32_t *)
|
||||
((const char *)data + (size_t)sy * stride);
|
||||
for (int sx = sx0; sx < sx1; sx++) {
|
||||
uint32_t p = row[sx];
|
||||
unsigned a = (p >> 24) & 0xff;
|
||||
if (fmt == DRM_FORMAT_XRGB8888 || a == 0)
|
||||
a = 0xff;
|
||||
unsigned r = (p >> 16) & 0xff,
|
||||
g = (p >> 8) & 0xff,
|
||||
bl = p & 0xff;
|
||||
sa += a;
|
||||
sr += r * a / 255;
|
||||
sg += g * a / 255;
|
||||
sb += bl * a / 255;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n == 0) n = 1;
|
||||
unsigned a = (unsigned)(sa / n);
|
||||
unsigned r = (unsigned)(sr / n);
|
||||
unsigned g = (unsigned)(sg / n);
|
||||
unsigned bl = (unsigned)(sb / n);
|
||||
w->thumb_px[(size_t)y * tw + x] =
|
||||
(a << 24) | (r << 16) | (g << 8) | bl;
|
||||
}
|
||||
}
|
||||
w->thumb_src = THUMB_SRC_SNAP;
|
||||
w->thumb_dirty = true;
|
||||
}
|
||||
wlr_buffer_end_data_ptr_access(b);
|
||||
if (w->thumb_buf) {
|
||||
/* Source switched back to SHM: drop the GPU buffer lock. */
|
||||
wlr_buffer_unlock(w->thumb_buf);
|
||||
w->thumb_buf = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Readable but unexpected format: hold a lock and import. */
|
||||
if (begun)
|
||||
wlr_buffer_end_data_ptr_access(b);
|
||||
if (b != w->thumb_buf) {
|
||||
if (w->thumb_buf)
|
||||
wlr_buffer_unlock(w->thumb_buf);
|
||||
w->thumb_buf = wlr_buffer_lock(b);
|
||||
}
|
||||
w->thumb_src = THUMB_SRC_DMABUF;
|
||||
w->thumb_dirty = true;
|
||||
}
|
||||
}
|
||||
} else if (s && wlr_surface_get_texture(s)) {
|
||||
/* In-place SHM update: the pixels went straight into the surface
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue