From nobody Fri Nov 24 17:31:57 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4ScMVQ1Pzvz51Npr; Fri, 24 Nov 2023 17:31:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ScMVQ0KKPz4LXb; Fri, 24 Nov 2023 17:31:58 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1700847118; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=tkWLASMCM9kPBBAP8SRO1D8kvOTnVBacsKl+vcyRTaE=; b=Uss3/PeskkB17l6PTdMkj1Boj86xSSBygmLPtQKAqkzWjfN7CmOwgAEcduq8O11s3TNynQ FWShryjKbnXp71nIcpdEMfuqdG46CkaG19ISSVyI/tnopt1xIR85lRVV6ky0la3kMw7iMh iFjobt+cvwSW/tU0KMqEv0eL8hI66mjd4BA9P5qOuV4JJpoWjXULYKw/EviNtIhrV+LmWe s6Rw7K3jLP/sJjf7YSmJVGb5w9RVj4Y5gAM7hSaM6/7vyK+DSfLBoYuANuowT0U6B+A9n9 0AHV21sEF/ACHvDkE/7Fx0y1JOberSmmRl59w4hAQpAM5DkFwQSRcdQGPz5+0Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1700847118; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=tkWLASMCM9kPBBAP8SRO1D8kvOTnVBacsKl+vcyRTaE=; b=BNlLY94T2cJcshV51oi2D21SIvwdq3zd1e3g3N4m5PtmTnakb09lPAY717VtZPsPNMrjuh LbwJysl0fzuhIOrws3a89VgcyisvRakRyuC9m/St7CA3NwAJrg0HFossrTbMUu0WW+lmGg PlQ7o3cKuVzTr/rrH7x98DpEJP16vk5d4TNdTa0hIBjkA4MY/1/EwP8yp9utOj/Bk/UyC5 +ygfH0HE+cBqLf9E+vjvMF5ECsTyByvVSnw07HEuuPYJgl18H/Cgj+BURzIT/IxtkJDQ5a 3nLei00U7anooG+ZeCM8QvoAx9AQExLESeUdLBu/hTpC85x6P9kqpzTin84+mw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1700847118; a=rsa-sha256; cv=none; b=YH/1mxt3MlxFSkAKnqLrC1bLK2+wqODmRwoxNY/My2dgOizGF8pLz7kybvnLkQW9xyCtY8 YyFLM0aZKp9b0XCma8r4VzxBp0jw09bFTLCygHOJkifxQVMzKi+ThJZmva8LeCA07W5bW/ qW4Ngc8Q9ZweCzZlXLVrk+oHfX/Tt5U0SqnV/nJ6D4lMUkZOVAJYkzNYSK6Fyjz0Q3RjyE rpegy7FAbeojehS3lLTKLwQ3ocuFFDPmFDDJ0HKCcYPF7rTILcOU5Vot2PgnKUN/JePasW 2n88SzpDCnKdKt7XZv+vpFdOVXDHnZZZpUmSDT80Sa1U150fMQZLRtdwdFYwRQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ScMVP6M8sztq6; Fri, 24 Nov 2023 17:31:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 3AOHVvSJ061909; Fri, 24 Nov 2023 17:31:57 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 3AOHVv3N061906; Fri, 24 Nov 2023 17:31:57 GMT (envelope-from git) Date: Fri, 24 Nov 2023 17:31:57 GMT Message-Id: <202311241731.3AOHVv3N061906@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: =?utf-8?Q?Jean-S=C3=A9bastien?= =?utf-8?Q?P=C3=A9dron?= Subject: git: 162a2b858854 - main - vt(4): New bitblt_text variant making a copy before unlocking vt_buf List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dumbbell X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 162a2b858854656ddd6b75d290be8a640ba8f324 Auto-Submitted: auto-generated The branch main has been updated by dumbbell: URL: https://cgit.FreeBSD.org/src/commit/?id=162a2b858854656ddd6b75d290be8a640ba8f324 commit 162a2b858854656ddd6b75d290be8a640ba8f324 Author: Jean-Sébastien Pédron AuthorDate: 2023-11-24 17:30:34 +0000 Commit: Jean-Sébastien Pédron CommitDate: 2023-11-24 17:31:33 +0000 vt(4): New bitblt_text variant making a copy before unlocking vt_buf [Why] In the DRM drivers and the integration with vt(4), we need to execute DRM code outside of the vtbuf_lock. The reason is that this DRM code acquires locks which can't be acquired when vtbuf_lock, an MTX_SPIN mutex, is already held. [How] A vt(4) backend can now set the `vd_bitblt_after_vtbuf_unlock` flag to true if it wants to be called outside of vt_buf_lock. In this case, vt(4) uses an internal version of bitblt_text that uses the `vd_drawn` arrays, plus a new `vd_pos_to_flush` array, to track characters to draw/refresh. This internal version then uses the backend's bitblt_bmp callback to draw the characters after vt_buf has been unlocked. Drawing borders and CPU logos is also deferred after the vt_buf lock is released for the same reason. We introduce another lock (a default mutex), only used when the `vd_bitblt_after_vtbuf_unlock` flag is set, to replace part the role of the vt_buf lock and manage concurrent calls to vt_flush(). The `SC_NO_CONSDRAWN` define is dropped because we now always need the `vd_drawn` arrays. Reviewed by: manu Approved by: manu Differential Revision: https://reviews.freebsd.org/D42057 --- sys/dev/vt/vt.h | 19 ++++++ sys/dev/vt/vt_core.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 185 insertions(+), 14 deletions(-) diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h index a21ecea999ec..56a28c0420c7 100644 --- a/sys/dev/vt/vt.h +++ b/sys/dev/vt/vt.h @@ -165,6 +165,9 @@ struct vt_device { term_char_t *vd_drawn; /* (?) Most recent char drawn. */ term_color_t *vd_drawnfg; /* (?) Most recent fg color drawn. */ term_color_t *vd_drawnbg; /* (?) Most recent bg color drawn. */ + + struct mtx vd_flush_lock; /* (?) vt_flush() lock. */ + bool *vd_pos_to_flush;/* (?) Positions to flush. */ }; #define VD_PASTEBUF(vd) ((vd)->vd_pastebuf.vpb_buf) @@ -175,6 +178,14 @@ struct vt_device { #define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) #define VT_LOCK_ASSERT(vd, what) mtx_assert(&(vd)->vd_lock, what) +#define VT_FLUSH_LOCK(vd) \ + if ((vd)->vd_driver->vd_bitblt_after_vtbuf_unlock) \ + mtx_lock(&(vd)->vd_flush_lock) + +#define VT_FLUSH_UNLOCK(vd) \ + if ((vd)->vd_driver->vd_bitblt_after_vtbuf_unlock) \ + mtx_unlock(&(vd)->vd_flush_lock) + void vt_resume(struct vt_device *vd); void vt_resume_flush_timer(struct vt_window *vw, int ms); void vt_suspend(struct vt_device *vd); @@ -376,6 +387,14 @@ struct vt_driver { #define VD_PRIORITY_DUMB 10 #define VD_PRIORITY_GENERIC 100 #define VD_PRIORITY_SPECIFIC 1000 + + /* + * Should vd_bitblt_text() be called after unlocking vtbuf? If true, + * characters are copied before vd_bitblt_bmp() is called. + * + * This is only valid when the default bitblt_text callback is used. + */ + bool vd_bitblt_after_vtbuf_unlock; }; /* diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index 6d44c81181a3..3e4db9a1ba30 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -202,11 +202,10 @@ SET_DECLARE(vt_drv_set, struct vt_driver); static struct terminal vt_consterm; static struct vt_window vt_conswindow; -#ifndef SC_NO_CONSDRAWN static term_char_t vt_consdrawn[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; static term_color_t vt_consdrawnfg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; static term_color_t vt_consdrawnbg[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; -#endif +static bool vt_cons_pos_to_flush[PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)]; struct vt_device vt_consdev = { .vd_driver = NULL, .vd_softc = NULL, @@ -228,11 +227,11 @@ struct vt_device vt_consdev = { .vd_mcursor_bg = TC_BLACK, #endif -#ifndef SC_NO_CONSDRAWN .vd_drawn = vt_consdrawn, .vd_drawnfg = vt_consdrawnfg, .vd_drawnbg = vt_consdrawnbg, -#endif + + .vd_pos_to_flush = vt_cons_pos_to_flush, }; static term_char_t vt_constextbuf[(_VTDEFW) * (VBF_DEFAULT_HISTORY_SIZE)]; static term_char_t *vt_constextbufrows[VBF_DEFAULT_HISTORY_SIZE]; @@ -292,6 +291,7 @@ vt_update_static(void *dummy) printf("VT: init without driver.\n"); mtx_init(&main_vd->vd_lock, "vtdev", NULL, MTX_DEF); + mtx_init(&main_vd->vd_flush_lock, "vtdev flush", NULL, MTX_DEF); cv_init(&main_vd->vd_winswitch, "vtwswt"); } @@ -1348,6 +1348,122 @@ vt_set_border(struct vt_device *vd, const term_rect_t *area, vd->vd_height - 1, 1, c); } +static void +vt_flush_to_buffer(struct vt_device *vd, + const struct vt_window *vw, const term_rect_t *area) +{ + unsigned int col, row; + term_char_t c; + term_color_t fg, bg; + size_t z; + + for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { + for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; + ++col) { + z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; + if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * + PIXEL_WIDTH(VT_FB_MAX_WIDTH)) + continue; + + c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); + vt_determine_colors(c, + VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); + + if (vd->vd_drawn && (vd->vd_drawn[z] == c) && + vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && + vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) { + vd->vd_pos_to_flush[z] = false; + continue; + } + + vd->vd_pos_to_flush[z] = true; + + if (vd->vd_drawn) + vd->vd_drawn[z] = c; + if (vd->vd_drawnfg) + vd->vd_drawnfg[z] = fg; + if (vd->vd_drawnbg) + vd->vd_drawnbg[z] = bg; + } + } +} + +static void +vt_bitblt_buffer(struct vt_device *vd, const struct vt_window *vw, + const term_rect_t *area) +{ + unsigned int col, row, x, y; + struct vt_font *vf; + term_char_t c; + term_color_t fg, bg; + const uint8_t *pattern; + size_t z; + + vf = vw->vw_font; + + for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { + for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; + ++col) { + x = col * vf->vf_width + + vw->vw_draw_area.tr_begin.tp_col; + y = row * vf->vf_height + + vw->vw_draw_area.tr_begin.tp_row; + + z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; + if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * + PIXEL_WIDTH(VT_FB_MAX_WIDTH)) + continue; + if (!vd->vd_pos_to_flush[z]) + continue; + + c = vd->vd_drawn[z]; + fg = vd->vd_drawnfg[z]; + bg = vd->vd_drawnbg[z]; + + pattern = vtfont_lookup(vf, c); + vd->vd_driver->vd_bitblt_bmp(vd, vw, + pattern, NULL, vf->vf_width, vf->vf_height, + x, y, fg, bg); + } + } + +#ifndef SC_NO_CUTPASTE + if (!vd->vd_mshown) + return; + + term_rect_t drawn_area; + + drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; + drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; + drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; + drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; + + if (vt_is_cursor_in_area(vd, &drawn_area)) { + vd->vd_driver->vd_bitblt_bmp(vd, vw, + vd->vd_mcursor->map, vd->vd_mcursor->mask, + vd->vd_mcursor->width, vd->vd_mcursor->height, + vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, + vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, + vd->vd_mcursor_fg, vd->vd_mcursor_bg); + } +#endif +} + +static void +vt_draw_decorations(struct vt_device *vd) +{ + struct vt_window *vw; + const teken_attr_t *a; + + vw = vd->vd_curwindow; + + a = teken_get_curattr(&vw->vw_terminal->tm_emulator); + vt_set_border(vd, &vw->vw_draw_area, a->ta_bgcolor); + + if (vt_draw_logo_cpus) + vtterm_draw_cpu_logos(vd); +} + static int vt_flush(struct vt_device *vd) { @@ -1357,6 +1473,7 @@ vt_flush(struct vt_device *vd) #ifndef SC_NO_CUTPASTE int cursor_was_shown, cursor_moved; #endif + bool needs_refresh; if (inside_vt_flush && KERNEL_PANICKED()) return (0); @@ -1372,8 +1489,9 @@ vt_flush(struct vt_device *vd) if (((vd->vd_flags & VDF_TEXTMODE) == 0) && (vf == NULL)) return (0); - vtbuf_lock(&vw->vw_buf); + VT_FLUSH_LOCK(vd); + vtbuf_lock(&vw->vw_buf); inside_vt_flush = true; #ifndef SC_NO_CUTPASTE @@ -1417,29 +1535,63 @@ vt_flush(struct vt_device *vd) vtbuf_undirty(&vw->vw_buf, &tarea); /* Force a full redraw when the screen contents might be invalid. */ + needs_refresh = false; if (vd->vd_flags & (VDF_INVALID | VDF_SUSPENDED)) { - const teken_attr_t *a; - + needs_refresh = true; vd->vd_flags &= ~VDF_INVALID; - a = teken_get_curattr(&vw->vw_terminal->tm_emulator); - vt_set_border(vd, &vw->vw_draw_area, a->ta_bgcolor); vt_termrect(vd, vf, &tarea); if (vd->vd_driver->vd_invalidate_text) vd->vd_driver->vd_invalidate_text(vd, &tarea); - if (vt_draw_logo_cpus) - vtterm_draw_cpu_logos(vd); } if (tarea.tr_begin.tp_col < tarea.tr_end.tp_col) { - vd->vd_driver->vd_bitblt_text(vd, vw, &tarea); - inside_vt_flush = false; - vtbuf_unlock(&vw->vw_buf); + if (vd->vd_driver->vd_bitblt_after_vtbuf_unlock) { + /* + * When `vd_bitblt_after_vtbuf_unlock` is set to true, + * we first remember the characters to redraw. They are + * already copied to the `vd_drawn` arrays. + * + * We then unlock vt_buf and proceed with the actual + * drawing using the backend driver. + */ + vt_flush_to_buffer(vd, vw, &tarea); + vtbuf_unlock(&vw->vw_buf); + vt_bitblt_buffer(vd, vw, &tarea); + + if (needs_refresh) + vt_draw_decorations(vd); + + /* + * We can reset `inside_vt_flush` after unlocking vtbuf + * here because we also hold vt_flush_lock in this code + * path. + */ + inside_vt_flush = false; + } else { + /* + * When `vd_bitblt_after_vtbuf_unlock` is false, we use + * the backend's `vd_bitblt_text` callback directly. + */ + vd->vd_driver->vd_bitblt_text(vd, vw, &tarea); + + if (needs_refresh) + vt_draw_decorations(vd); + + inside_vt_flush = false; + vtbuf_unlock(&vw->vw_buf); + } + + VT_FLUSH_UNLOCK(vd); + return (1); } inside_vt_flush = false; vtbuf_unlock(&vw->vw_buf); + + VT_FLUSH_UNLOCK(vd); + return (0); }