jack: optimize get_buffer

Keep track of global mix port.
Calculate the get_buffer function beforehand.
This commit is contained in:
Wim Taymans 2020-09-30 11:59:41 +02:00
parent ac4d4582a4
commit 68bff629b3

View file

@ -127,6 +127,7 @@ struct object {
jack_latency_range_t capture_latency; jack_latency_range_t capture_latency;
jack_latency_range_t playback_latency; jack_latency_range_t playback_latency;
int32_t priority; int32_t priority;
struct port *port;
} port; } port;
}; };
}; };
@ -191,12 +192,15 @@ struct port {
struct spa_io_buffers io; struct spa_io_buffers io;
struct spa_list mix; struct spa_list mix;
struct mix *global_mix;
unsigned int empty_out:1; unsigned int empty_out:1;
unsigned int zeroed:1; unsigned int zeroed:1;
float *emptyptr; float *emptyptr;
float empty[MAX_BUFFER_FRAMES + MAX_ALIGN]; float empty[MAX_BUFFER_FRAMES + MAX_ALIGN];
void *(*get_buffer) (struct port *p, jack_nframes_t frames);
}; };
struct link { struct link {
@ -386,6 +390,17 @@ static void free_object(struct client *c, struct object *o)
spa_list_append(&c->context.free_objects, &o->link); spa_list_append(&c->context.free_objects, &o->link);
} }
static void init_mix(struct mix *mix, uint32_t mix_id, struct port *port)
{
mix->id = mix_id;
mix->port = port;
mix->io = NULL;
mix->n_buffers = 0;
spa_list_init(&mix->queue);
if (mix_id == SPA_ID_INVALID)
port->global_mix = mix;
}
static struct mix *find_mix(struct client *c, struct port *port, uint32_t mix_id) static struct mix *find_mix(struct client *c, struct port *port, uint32_t mix_id)
{ {
struct mix *mix; struct mix *mix;
@ -417,11 +432,7 @@ static struct mix *ensure_mix(struct client *c, struct port *port, uint32_t mix_
spa_list_append(&port->mix, &mix->port_link); spa_list_append(&port->mix, &mix->port_link);
mix->id = mix_id; init_mix(mix, mix_id, port);
mix->port = port;
mix->io = NULL;
mix->n_buffers = 0;
spa_list_init(&mix->queue);
return mix; return mix;
} }
@ -451,6 +462,8 @@ static void free_mix(struct client *c, struct mix *mix)
{ {
clear_buffers(c, mix); clear_buffers(c, mix);
spa_list_remove(&mix->port_link); spa_list_remove(&mix->port_link);
if (mix->id == SPA_ID_INVALID)
mix->port->global_mix = NULL;
spa_list_append(&c->free_mix, &mix->link); spa_list_append(&c->free_mix, &mix->link);
} }
@ -483,6 +496,7 @@ static struct port * alloc_port(struct client *c, enum spa_direction direction)
o->id = SPA_ID_INVALID; o->id = SPA_ID_INVALID;
o->port.node_id = c->node_id; o->port.node_id = c->node_id;
o->port.port_id = p->id; o->port.port_id = p->id;
o->port.port = p;
p->valid = true; p->valid = true;
p->zeroed = false; p->zeroed = false;
@ -728,7 +742,7 @@ static void unhandle_socket(struct client *c)
do_remove_sources, 1, NULL, 0, true, c); do_remove_sources, 1, NULL, 0, true, c);
} }
static void reuse_buffer(struct client *c, struct mix *mix, uint32_t id) static inline void reuse_buffer(struct client *c, struct mix *mix, uint32_t id)
{ {
struct buffer *b; struct buffer *b;
@ -800,9 +814,10 @@ static void convert_to_midi(struct spa_pod_sequence **seq, uint32_t n_seq, void
} }
static void *get_buffer_output(struct client *c, struct port *p, uint32_t frames, uint32_t stride) static inline void *get_buffer_output(struct port *p, uint32_t frames, uint32_t stride)
{ {
struct mix *mix; struct mix *mix;
struct client *c = p->client;
void *ptr = NULL; void *ptr = NULL;
p->io.status = -EPIPE; p->io.status = -EPIPE;
@ -811,7 +826,7 @@ static void *get_buffer_output(struct client *c, struct port *p, uint32_t frames
if (frames == 0) if (frames == 0)
return NULL; return NULL;
if (SPA_LIKELY((mix = find_mix(c, p, -1)) != NULL)) { if (SPA_LIKELY((mix = p->global_mix) != NULL)) {
struct buffer *b; struct buffer *b;
if (SPA_UNLIKELY(mix->n_buffers == 0)) if (SPA_UNLIKELY(mix->n_buffers == 0))
@ -858,12 +873,12 @@ static void process_tee(struct client *c, uint32_t frames)
switch (p->object->port.type_id) { switch (p->object->port.type_id) {
case TYPE_ID_AUDIO: case TYPE_ID_AUDIO:
ptr = get_buffer_output(c, p, frames, sizeof(float)); ptr = get_buffer_output(p, frames, sizeof(float));
if (SPA_LIKELY(ptr != NULL)) if (SPA_LIKELY(ptr != NULL))
memcpy(ptr, p->emptyptr, frames * sizeof(float)); memcpy(ptr, p->emptyptr, frames * sizeof(float));
break; break;
case TYPE_ID_MIDI: case TYPE_ID_MIDI:
ptr = get_buffer_output(c, p, MAX_BUFFER_FRAMES, 1); ptr = get_buffer_output(p, MAX_BUFFER_FRAMES, 1);
if (SPA_LIKELY(ptr != NULL)) if (SPA_LIKELY(ptr != NULL))
convert_from_midi(p->emptyptr, ptr, MAX_BUFFER_FRAMES * sizeof(float)); convert_from_midi(p->emptyptr, ptr, MAX_BUFFER_FRAMES * sizeof(float));
break; break;
@ -1636,7 +1651,7 @@ static int client_node_port_set_param(void *object,
NULL); NULL);
} }
static void *init_buffer(struct port *p) static inline void *init_buffer(struct port *p)
{ {
void *data = p->emptyptr; void *data = p->emptyptr;
if (p->zeroed) if (p->zeroed)
@ -3139,6 +3154,13 @@ float jack_cpu_load (jack_client_t *client)
#include "statistics.c" #include "statistics.c"
static void *get_buffer_input_float(struct port *p, jack_nframes_t frames);
static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames);
static void *get_buffer_input_empty(struct port *p, jack_nframes_t frames);
static void *get_buffer_output_float(struct port *p, jack_nframes_t frames);
static void *get_buffer_output_midi(struct port *p, jack_nframes_t frames);
static void *get_buffer_output_empty(struct port *p, jack_nframes_t frames);
SPA_EXPORT SPA_EXPORT
jack_port_t * jack_port_register (jack_client_t *client, jack_port_t * jack_port_register (jack_client_t *client,
const char *port_name, const char *port_name,
@ -3188,6 +3210,34 @@ jack_port_t * jack_port_register (jack_client_t *client,
init_buffer(p); init_buffer(p);
if (direction == SPA_DIRECTION_INPUT) {
switch (type_id) {
case TYPE_ID_AUDIO:
case TYPE_ID_VIDEO:
p->get_buffer = get_buffer_input_float;
break;
case TYPE_ID_MIDI:
p->get_buffer = get_buffer_input_midi;
break;
default:
p->get_buffer = get_buffer_input_empty;
break;
}
} else {
switch (type_id) {
case TYPE_ID_AUDIO:
case TYPE_ID_VIDEO:
p->get_buffer = get_buffer_output_float;
break;
case TYPE_ID_MIDI:
p->get_buffer = get_buffer_output_midi;
break;
default:
p->get_buffer = get_buffer_output_empty;
break;
}
}
pw_log_debug(NAME" %p: port %p", c, p); pw_log_debug(NAME" %p: port %p", c, p);
spa_list_init(&p->mix); spa_list_init(&p->mix);
@ -3269,7 +3319,7 @@ int jack_port_unregister (jack_client_t *client, jack_port_t *port)
return res; return res;
} }
static inline void *get_buffer_input_float(struct client *c, struct port *p, jack_nframes_t frames) static void *get_buffer_input_float(struct port *p, jack_nframes_t frames)
{ {
struct mix *mix; struct mix *mix;
struct buffer *b; struct buffer *b;
@ -3279,7 +3329,7 @@ static inline void *get_buffer_input_float(struct client *c, struct port *p, jac
spa_list_for_each(mix, &p->mix, port_link) { spa_list_for_each(mix, &p->mix, port_link) {
pw_log_trace_fp(NAME" %p: port %p mix %d.%d get buffer %d", pw_log_trace_fp(NAME" %p: port %p mix %d.%d get buffer %d",
c, p, p->id, mix->id, frames); p->client, p, p->id, mix->id, frames);
io = mix->io; io = mix->io;
if (io == NULL || if (io == NULL ||
io->status != SPA_STATUS_HAVE_DATA || io->status != SPA_STATUS_HAVE_DATA ||
@ -3296,10 +3346,12 @@ static inline void *get_buffer_input_float(struct client *c, struct port *p, jac
p->zeroed = false; p->zeroed = false;
} }
} }
if (ptr == NULL)
ptr = init_buffer(p);
return ptr; return ptr;
} }
static inline void *get_buffer_input_midi(struct client *c, struct port *p, jack_nframes_t frames) static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
{ {
struct mix *mix; struct mix *mix;
struct spa_io_buffers *io; struct spa_io_buffers *io;
@ -3314,7 +3366,7 @@ static inline void *get_buffer_input_midi(struct client *c, struct port *p, jack
void *pod; void *pod;
pw_log_trace_fp(NAME" %p: port %p mix %d.%d get buffer %d", pw_log_trace_fp(NAME" %p: port %p mix %d.%d get buffer %d",
c, p, p->id, mix->id, frames); p->client, p, p->id, mix->id, frames);
io = mix->io; io = mix->io;
if (io == NULL || if (io == NULL ||
@ -3337,68 +3389,45 @@ static inline void *get_buffer_input_midi(struct client *c, struct port *p, jack
return ptr; return ptr;
} }
static inline void *get_buffer_output_float(struct client *c, struct port *p, jack_nframes_t frames) static void *get_buffer_output_float(struct port *p, jack_nframes_t frames)
{ {
void *ptr; void *ptr;
ptr = get_buffer_output(c, p, frames, sizeof(float)); ptr = get_buffer_output(p, frames, sizeof(float));
if (SPA_UNLIKELY(ptr == NULL)) { if (SPA_UNLIKELY(p->empty_out = (ptr == NULL)))
p->empty_out = true;
ptr = p->emptyptr; ptr = p->emptyptr;
} else {
p->empty_out = false;
}
return ptr; return ptr;
} }
static inline void *get_buffer_output_midi(struct client *c, struct port *p, jack_nframes_t frames) static void *get_buffer_output_midi(struct port *p, jack_nframes_t frames)
{ {
p->empty_out = true; p->empty_out = true;
return p->emptyptr; return p->emptyptr;
} }
static void *get_buffer_output_empty(struct port *p, jack_nframes_t frames)
{
p->empty_out = true;
return p->emptyptr;
}
static void *get_buffer_input_empty(struct port *p, jack_nframes_t frames)
{
return init_buffer(p);
}
SPA_EXPORT SPA_EXPORT
void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames) void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames)
{ {
struct object *o = (struct object *) port; struct object *o = (struct object *) port;
struct client *c;
struct port *p; struct port *p;
void *ptr = NULL; void *ptr;
spa_return_val_if_fail(o != NULL, NULL); spa_return_val_if_fail(o != NULL, NULL);
c = o->client; p = o->port.port;
p = GET_PORT(c, GET_DIRECTION(o->port.flags), o->port.port_id); ptr = p->get_buffer(p, frames);
pw_log_trace_fp(NAME" %p: port %p buffer %p empty:%u", p->client, p, ptr, p->empty_out);
if (p->direction == SPA_DIRECTION_INPUT) {
switch (p->object->port.type_id) {
case TYPE_ID_AUDIO:
ptr = get_buffer_input_float(c, p, frames);
break;
case TYPE_ID_MIDI:
ptr = get_buffer_input_midi(c, p, frames);
break;
case TYPE_ID_VIDEO:
ptr = get_buffer_input_float(c, p, frames);
break;
}
if (ptr == NULL) {
ptr = init_buffer(p);
}
} else {
switch (p->object->port.type_id) {
case TYPE_ID_AUDIO:
ptr = get_buffer_output_float(c, p, frames);
break;
case TYPE_ID_MIDI:
ptr = get_buffer_output_midi(c, p, frames);
break;
case TYPE_ID_VIDEO:
ptr = get_buffer_output_float(c, p, frames);
break;
}
}
pw_log_trace_fp(NAME" %p: port %p buffer %p empty:%u", c, p, ptr, p->empty_out);
return ptr; return ptr;
} }