This one works quite well.
$ rm -f f; for i in `seq 1000`; do cat tmux.h >>f; done
$ time cat f
outside = 2.714
tmux = 9.133
screen = 11.416
diff --git a/input.c b/input.c
index 17f81dd7..4653c992 100644
--- a/input.c
+++ b/input.c
@@ -871,9 +871,10 @@ input_parse(struct window_pane *wp)
buf = EVBUFFER_DATA(evb);
len = EVBUFFER_LENGTH(evb);
- notify_input(wp, evb);
off = 0;
+ notify_input(wp, evb);
+
log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
ictx->state->name, len, (int)len, buf);
diff --git a/screen-write.c b/screen-write.c
index 227316cb..c8ea1be5 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -38,47 +38,111 @@ static const struct grid_cell screen_write_pad_cell = {
GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 }
};
-#define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x))
-#define screen_dirty_clear(s, sx, sy, ex, ey) \
- do { \
- if (s->dirty != NULL) { \
- bit_nclear(s->dirty, \
- screen_dirty_bit(s, sx, sy), \
- screen_dirty_bit(s, ex, ey)); \
- } \
- } while (0)
+struct screen_write_dirty_item {
+ struct grid_cell gc;
+ u_int x;
+
+ TAILQ_ENTRY (screen_write_dirty_item) entry;
+};
+static struct screen_write_dirty_item **screen_write_dirty;
+static u_int screen_write_dirty_x;
+static u_int screen_write_dirty_y;
+
+/* Set a dirty bit. */
+static void
+screen_write_dirty_set(struct screen_write_ctx *ctx, u_int x, u_int y,
+ const struct grid_cell *gc)
+{
+ struct screen_write_dirty_item *di;
+
+ di = &screen_write_dirty[y][x];
+ if (di->gc.data.size == 0) {
+ TAILQ_INSERT_TAIL(&ctx->dirtylist[y], di, entry);
+ ctx->dirty++;
+ }
+
+ di->x = x;
+ memcpy(&di->gc, gc, sizeof di->gc);
+}
+
+/* Clear a dirty region. */
+static void
+screen_write_dirty_clear(struct screen_write_ctx *ctx, u_int sx, u_int sy,
+ u_int ex, u_int ey)
+{
+ struct screen_write_dirty_item *di, *di1;
+ u_int y;
+
+ for (y = sy; y < ey + 1; y++) {
+ if (TAILQ_EMPTY (&ctx->dirtylist[y]))
+ continue;
+ TAILQ_FOREACH_SAFE(di, &ctx->dirtylist[y], entry, di1) {
+ if (di->x < sx || di->x > ex)
+ continue;
+ di->gc.data.size = 0;
+ TAILQ_REMOVE(&ctx->dirtylist[y], di, entry);
+ }
+ }
+}
+
+/* Allocate dirty table. */
+static void
+screen_write_dirty_allocate(struct screen_write_ctx *ctx)
+{
+ u_int sx, sy, y;
+ size_t size;
+
+ sx = screen_size_x(ctx->s);
+ sy = screen_size_y(ctx->s);
+
+ if (screen_write_dirty_x >= sx && screen_write_dirty_y >= sy)
+ return;
+ size = 0;
+
+ for (y = 0; y < screen_write_dirty_y; y++)
+ free(screen_write_dirty[y]);
+ free(screen_write_dirty);
+
+ screen_write_dirty = xcalloc(sy, sizeof *screen_write_dirty);
+ size += (sy * sizeof *screen_write_dirty);
+ for (y = 0; y < sy; y++) {
+ screen_write_dirty[y] = xcalloc(sx,
+ sizeof **screen_write_dirty);
+ size += (sx * sizeof **screen_write_dirty);
+ }
+
+ screen_write_dirty_x = sx;
+ screen_write_dirty_y = sy;
+
+ log_debug("%s: allocated %zu bytes", __func__, size);
+}
/* Initialize writing with a window. */
void
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp,
struct screen *s)
{
- u_int size;
- char tmp[16];
- const char *cp = tmp;
+ char tmp[16];
+ u_int y;
ctx->wp = wp;
if (wp != NULL && s == NULL)
ctx->s = wp->screen;
else
ctx->s = s;
+ screen_write_dirty_allocate (ctx);
- size = screen_size_x(ctx->s) * screen_size_y(ctx->s);
- if (ctx->s->dirtysize != size) {
- free(ctx->s->dirty);
- ctx->s->dirty = NULL;
- ctx->s->dirtysize = size;
- }
+ ctx->dirtylist = xcalloc(screen_size_y(ctx->s), sizeof *ctx->dirtylist);
+ for (y = 0; y < screen_size_y(ctx->s); y++)
+ TAILQ_INIT(&ctx->dirtylist[y]);
ctx->dirty = 0;
ctx->cells = ctx->written = ctx->skipped = 0;
- if (wp == NULL)
- cp = "no pane";
- else
+ if (wp != NULL)
snprintf(tmp, sizeof tmp, "pane %%%u", wp->id);
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s),
- screen_size_y(ctx->s), cp);
+ screen_size_y(ctx->s), wp == NULL ? "no pane" : tmp);
}
/* Finish writing. */
@@ -89,49 +153,45 @@ screen_write_stop(struct screen_write_ctx *ctx)
log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__,
ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped);
+
+ free(ctx->dirtylist);
}
/* Flush outstanding cell writes. */
static void
screen_write_flush(struct screen_write_ctx *ctx)
{
- struct screen *s = ctx->s;
- struct tty_ctx ttyctx;
- u_int x, y, offset, cx, cy, dirty;
- struct grid_cell gc;
+ struct screen *s = ctx->s;
+ struct screen_write_dirty_item *di;
+ u_int cx, cy, y;
+ struct tty_ctx ttyctx;
if (ctx->dirty == 0)
return;
- dirty = 0;
log_debug("%s: dirty %u", __func__, ctx->dirty);
cx = s->cx;
cy = s->cy;
- offset = 0;
- for (y = 0; y < screen_size_y(s); y++) {
- for (x = 0; x < screen_size_x(s); x++) {
- offset++;
- if (!bit_test(s->dirty, offset - 1))
- continue;
- bit_clear(s->dirty, offset - 1);
-
- screen_write_cursormove(ctx, x, y);
- grid_view_get_cell(s->grid, x, y, &gc);
-
+ for (y = 0; y < screen_size_y(ctx->s); y++) {
+ if (TAILQ_EMPTY(&ctx->dirtylist[y]))
+ continue;
+ TAILQ_FOREACH(di, &ctx->dirtylist[y], entry) {
+ screen_write_cursormove(ctx, di->x, y);
screen_write_initctx(ctx, &ttyctx);
- ttyctx.cell = &gc;
+
+ ttyctx.cell = &di->gc;
tty_write(tty_cmd_cell, &ttyctx);
ctx->written++;
- if (++dirty == ctx->dirty)
- break;
+ di->gc.data.size = 0;
}
- if (dirty == ctx->dirty)
- break;
+ TAILQ_INIT(&ctx->dirtylist[y]);
}
ctx->dirty = 0;
+ ctx->scrolled = 0;
+
s->cx = cx;
s->cy = cy;
}
@@ -590,7 +650,7 @@ screen_write_alignmenttest(struct screen_write_ctx *ctx)
screen_write_initctx(ctx, &ttyctx);
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
memcpy(&gc, &grid_default_cell, sizeof gc);
utf8_set(&gc.data, 'E');
@@ -679,7 +739,8 @@ screen_write_clearcharacter(struct screen_write_ctx *ctx,
u_int nx)
screen_write_initctx(ctx, &ttyctx);
if (s->cx <= screen_size_x(s) - 1) {
- screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, s->cx + nx - 1,
+ s->cy);
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8);
} else
return;
@@ -798,7 +859,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int
bg)
if (gl->cellsize == 0 && bg == 8)
return;
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
tty_write(tty_cmd_clearline, &ttyctx);
@@ -820,7 +881,7 @@ screen_write_clearendofline(struct screen_write_ctx *ctx,
u_int bg)
if (s->cx > sx - 1 || (s->cx >= gl->cellsize && bg == 8))
return;
- screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg);
tty_write(tty_cmd_clearendofline, &ttyctx);
@@ -838,10 +899,10 @@ screen_write_clearstartofline(struct screen_write_ctx
*ctx, u_int bg)
ttyctx.bg = bg;
if (s->cx > sx - 1) {
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
} else {
- screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg);
}
@@ -901,6 +962,8 @@ screen_write_scrollregion(struct screen_write_ctx *ctx,
u_int rupper,
s->rupper = rupper;
s->rlower = rlower;
+
+ ctx->scrolled = 0;
}
/* Line feed. */
@@ -909,8 +972,11 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int
wrapped)
{
struct screen *s = ctx->s;
struct grid_line *gl;
- struct tty_ctx ttyctx;
- u_int sx = screen_size_x(s), sy = screen_size_y(s);
+ struct tty_ctx ttyctx;
+ u_int y, sx, sy;
+
+ sx = screen_size_x(s);
+ sy = screen_size_y(s);
screen_write_initctx(ctx, &ttyctx);
@@ -921,14 +987,38 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int
wrapped)
gl->flags &= ~GRID_LINE_WRAPPED;
if (s->cy == s->rlower) {
- screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper);
- screen_write_flush(ctx);
+ /*
+ * Clear the dirty cells for th etop line of the region and
+ * move all the dirty cells in the region up by one, so they
+ * match the cells on screen after the scroll.
+ */
+ TAILQ_INIT(&ctx->dirtylist[s->rupper]);
+ free(screen_write_dirty[s->rupper]);
+
+ for (y = s->rupper; y < s->rlower; y++) {
+ screen_write_dirty[y] = screen_write_dirty[y + 1];
+ memcpy(&ctx->dirtylist[y], &ctx->dirtylist[y + 1],
+ sizeof *ctx->dirtylist);
+ }
+
+ TAILQ_INIT(&ctx->dirtylist[s->rlower]);
+ screen_write_dirty[s->rlower] = xcalloc(sx,
+ sizeof **screen_write_dirty);
+
+ /*
+ * Scroll the grid. Also scroll the terminal, unless we have
+ * already scrolled more than the region, in which case we
+ * would just be scrolling in more blank lines.
+ */
grid_view_scroll_region_up(s->grid, s->rupper, s->rlower);
+ if (ctx->scrolled < s->rlower - s->rupper) {
+ ttyctx.num = wrapped;
+ tty_write(tty_cmd_linefeed, &ttyctx);
+ } else
+ log_debug("ignoring line feed %u", ctx->scrolled);
+ ctx->scrolled++;
} else if (s->cy < sy - 1)
s->cy++;
-
- ttyctx.num = wrapped;
- tty_write(tty_cmd_linefeed, &ttyctx);
}
/* Carriage return (cursor to start of line). */
@@ -953,15 +1043,16 @@ screen_write_clearendofscreen(struct screen_write_ctx
*ctx, u_int bg)
/* Scroll into history if it is enabled and clearing entire screen. */
if (s->cx == 0 && s->cy == 0 && s->grid->flags & GRID_HISTORY) {
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
grid_view_clear_history(s->grid, bg);
} else {
if (s->cx <= sx - 1) {
- screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, s->cx, s->cy, sx - 1,
+ s->cy);
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1,
bg);
}
- screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, s->cy + 1, sx - 1, sy - 1);
grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1),
bg);
}
@@ -980,14 +1071,14 @@ screen_write_clearstartofscreen(struct screen_write_ctx
*ctx)
screen_write_initctx(ctx, &ttyctx);
if (s->cy > 0) {
- screen_dirty_clear(s, 0, 0, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, s->cy);
grid_view_clear(s->grid, 0, 0, sx, s->cy, 8);
}
if (s->cx > sx - 1) {
- screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, sx - 1, s->cy);
grid_view_clear(s->grid, 0, s->cy, sx, 1, 8);
} else {
- screen_dirty_clear(s, 0, s->cy, s->cx, s->cy);
+ screen_write_dirty_clear(ctx, 0, s->cy, s->cx, s->cy);
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8);
}
@@ -1005,7 +1096,7 @@ screen_write_clearscreen(struct screen_write_ctx *ctx,
u_int bg)
screen_write_initctx(ctx, &ttyctx);
ttyctx.bg = bg;
- screen_dirty_clear(s, 0, 0, sx - 1, sy - 1);
+ screen_write_dirty_clear(ctx, 0, 0, sx - 1, sy - 1);
/* Scroll into history if it is enabled. */
if (s->grid->flags & GRID_HISTORY)
@@ -1180,24 +1271,8 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
ctx->written++;
- } else {
- /*
- * If wp is NULL, we are not updating the terminal and
- * don't care about actually writing the cells
- * (tty_write will just return). So don't even bother
- * allocating the dirty array.
- */
- if (ctx->wp != NULL && s->dirty == NULL) {
- log_debug("%s: allocating %u bits", __func__,
- s->dirtysize);
- s->dirty = bit_alloc(s->dirtysize);
- }
- if (s->dirty != NULL) {
- bit_set(s->dirty, screen_dirty_bit(s,
- ttyctx.ocx, ttyctx.ocy));
- ctx->dirty++;
- }
- }
+ } else if (ctx->wp != NULL)
+ screen_write_dirty_set(ctx, ttyctx.ocx, ttyctx.ocy, gc);
} else
ctx->skipped++;
}
diff --git a/screen.c b/screen.c
index d6fbfecd..6088c14a 100644
--- a/screen.c
+++ b/screen.c
@@ -40,9 +40,6 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int
hlimit)
s->ccolour = xstrdup("");
s->tabs = NULL;
- s->dirty = NULL;
- s->dirtysize = 0;
-
screen_reinit(s);
}
@@ -69,7 +66,6 @@ screen_reinit(struct screen *s)
void
screen_free(struct screen *s)
{
- free(s->dirty);
free(s->tabs);
free(s->title);
free(s->ccolour);
diff --git a/tmux.h b/tmux.h
index 9dee7a1a..24402e8f 100644
--- a/tmux.h
+++ b/tmux.h
@@ -72,9 +72,9 @@ struct tmuxproc;
* of times.
*/
#define READ_FAST_SIZE 16384
-#define READ_SLOW_SIZE 128
+#define READ_SLOW_SIZE 4096
-#define READ_FULL_SIZE (4096 - 16)
+#define READ_FULL_SIZE (READ_FAST_SIZE - 16)
#define READ_EMPTY_SIZE 16
#define READ_CHANGE_HITS 3
@@ -662,17 +662,18 @@ struct screen {
bitstr_t *tabs;
- bitstr_t *dirty;
- u_int dirtysize;
-
struct screen_sel sel;
};
/* Screen write context. */
+struct screen_write_dirty_item;
struct screen_write_ctx {
struct window_pane *wp;
struct screen *s;
+
+ TAILQ_HEAD(, screen_write_dirty_item) *dirtylist;
u_int dirty;
+ u_int scrolled;
u_int cells;
u_int written;
--
You received this message because you are subscribed to the Google Groups
"tmux-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.