video/out/kitty: make kitty vo ten times faster by avoiding strlen

When playing a video, 55% of CPU used in strlen, callgraph flip_page: ta_talloc_strdup_append ,
ta_talloc_asprintf_append and ta_talloc_strndup_append .

Before the fix: 2 fps when playing 1080p 24 fps video (--vo-kitty-use-shm=no),
24 fps after the fix.

video/out/kitty: move bstr cmd to priv
This commit is contained in:
Sami Farin authored and Kacper Michajłow committed 2025-02-05 04:53:42 +01:00
1 parent 38ad1ed03b
commit fa9c2a35dd
1 file changed
+38 -26
+38 -26
View File
@@ -48,7 +48,7 @@
#define DEFAULT_WIDTH 80
#define DEFAULT_HEIGHT 25
static inline void write_str(const char *s)
static inline void write_bstr(bstr bs)
{
// On POSIX platforms, write() is the fastest method. It also is the only
// one that allows atomic writes so mpv’s output will not be interrupted
@@ -57,25 +57,31 @@ static inline void write_str(const char *s)
// exceeding PIPE_BUF, but at least Linux does seem to implement it that
// way.
#if HAVE_POSIX
int remain = strlen(s);
size_t remain = bs.len;
unsigned char *pos = bs.start;
while (remain > 0) {
ssize_t written = write(STDOUT_FILENO, s, remain);
ssize_t written = write(STDOUT_FILENO, pos, remain);
if (written < 0)
return;
remain -= written;
s += written;
pos += written;
}
#else
printf("%s", s);
fwrite(bs.start, 1, bs.len, stdout);
fflush(stdout);
#endif
}
static inline void write_str(unsigned char* s)
{
write_bstr(bstr0(s));
}
#define KITTY_ESC_IMG "\033_Ga=T,f=24,s=%d,v=%d,C=1,q=2,m=1;"
#define KITTY_ESC_IMG_SHM "\033_Ga=T,t=s,f=24,s=%d,v=%d,C=1,q=2,m=1;%s\033\\"
#define KITTY_ESC_CONTINUE "\033_Gm=%d;"
#define KITTY_ESC_END "\033\\"
#define KITTY_ESC_DELETE_ALL "\033_Ga=d;\033\\"
static const bstr KITTY_ESC_END = bstr0_lit("\033\\");
static const bstr KITTY_ESC_DELETE_ALL = bstr0_lit("\033_Ga=d;\033\\");
struct vo_kitty_opts {
int width, height, top, left, rows, cols;
@@ -91,6 +97,7 @@ struct priv {
char *shm_path, *shm_path_b64;
int buffer_size, output_size;
int shm_fd;
bstr cmd;
int left, top, width, height, cols, rows;
@@ -126,6 +133,7 @@ static void free_bufs(struct vo* vo)
talloc_free(p->frame);
talloc_free(p->output);
talloc_free(p->cmd.start);
if (p->opts.use_shm) {
close_shm(p);
@@ -177,7 +185,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params)
struct priv *p = vo->priv;
vo->want_redraw = true;
write_str(KITTY_ESC_DELETE_ALL);
write_bstr(KITTY_ESC_DELETE_ALL);
if (p->opts.config_clear)
write_str(TERM_ESC_CLEAR_SCREEN);
@@ -292,36 +300,40 @@ done:
static void flip_page(struct vo *vo)
{
struct priv* p = vo->priv;
if (p->buffer == NULL)
struct priv *p = vo->priv;
if (!p->buffer)
return;
char *cmd = talloc_asprintf(NULL, TERM_ESC_GOTO_YX, p->top, p->left);
p->cmd.len = 0;
// Start with ESC to position the cursor
bstr_xappend_asprintf(NULL, &p->cmd, TERM_ESC_GOTO_YX, p->top, p->left);
if (p->opts.use_shm) {
cmd = talloc_asprintf_append(cmd, KITTY_ESC_IMG_SHM, p->width, p->height, p->shm_path_b64);
bstr_xappend_asprintf(NULL, &p->cmd, KITTY_ESC_IMG_SHM,
p->width, p->height, p->shm_path_b64);
} else {
if (p->output == NULL) {
talloc_free(cmd);
if (!p->output) {
return;
}
cmd = talloc_asprintf_append(cmd, KITTY_ESC_IMG, p->width, p->height);
for (int offset = 0, noffset;; offset += noffset) {
if (offset)
cmd = talloc_asprintf_append(cmd, KITTY_ESC_CONTINUE, offset < p->output_size);
noffset = MPMIN(4096, p->output_size - offset);
cmd = talloc_strndup_append(cmd, p->output + offset, noffset);
cmd = talloc_strdup_append(cmd, KITTY_ESC_END);
bstr_xappend_asprintf(NULL, &p->cmd, KITTY_ESC_IMG, p->width, p->height);
if (offset >= p->output_size)
break;
for (int offset = 0; offset < p->output_size; ) {
int chunk = MPMIN(4096, p->output_size - offset);
if (offset > 0)
bstr_xappend_asprintf(NULL, &p->cmd, KITTY_ESC_CONTINUE,
offset + chunk < p->output_size);
// Append at max chunk bytes
bstr_xappend(NULL, &p->cmd, (bstr){p->output + offset, chunk});
bstr_xappend(NULL, &p->cmd, KITTY_ESC_END);
offset += chunk;
}
}
write_str(cmd);
talloc_free(cmd);
write_bstr(p->cmd);
#if HAVE_POSIX
if (p->opts.use_shm)