audioconvert: optimize remapping paths

Remove the redundant remap array.
First set up the array with remapped output pointers in case we
can do passthrough output. Make sure stages write to the remapped
array in passthrough.
Remap the input array after unpack/convert.
This avoid an input and output memcpy in the common case of
remapping.
This commit is contained in:
Wim Taymans 2022-07-06 15:01:01 +02:00
parent 565c385228
commit 84d2b2ce3a

View file

@ -166,8 +166,7 @@ struct dir {
unsigned int have_profile:1; unsigned int have_profile:1;
struct spa_latency_info latency; struct spa_latency_info latency;
uint32_t src_remap[MAX_PORTS]; uint32_t remap[MAX_PORTS];
uint32_t dst_remap[MAX_PORTS];
struct convert conv; struct convert conv;
unsigned int need_remap:1; unsigned int need_remap:1;
@ -1125,12 +1124,11 @@ static int setup_in_convert(struct impl *this)
if (src_info.info.raw.position[i] != if (src_info.info.raw.position[i] !=
dst_info.info.raw.position[j]) dst_info.info.raw.position[j])
continue; continue;
in->src_remap[i] = j; in->remap[i] = j;
in->dst_remap[j] = i;
if (i != j) if (i != j)
remap = true; remap = true;
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%d) (%s -> %s)", this, spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
i, in->src_remap[i], j, in->dst_remap[j], i, in->remap[i], j,
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel,
src_info.info.raw.position[i]), src_info.info.raw.position[i]),
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel,
@ -1269,7 +1267,7 @@ static void set_volume(struct impl *this)
vol = &this->props.channel; vol = &this->props.channel;
for (i = 0; i < vol->n_volumes; i++) for (i = 0; i < vol->n_volumes; i++)
volumes[i] = vol->volumes[dir->src_remap[i]]; volumes[i] = vol->volumes[dir->remap[i]];
channelmix_set_volume(&this->mix, this->props.volume, vol->mute, channelmix_set_volume(&this->mix, this->props.volume, vol->mute,
vol->n_volumes, volumes); vol->n_volumes, volumes);
@ -1421,13 +1419,12 @@ static int setup_out_convert(struct impl *this)
if (src_info.info.raw.position[i] != if (src_info.info.raw.position[i] !=
dst_info.info.raw.position[j]) dst_info.info.raw.position[j])
continue; continue;
out->src_remap[i] = j; out->remap[i] = j;
out->dst_remap[j] = i;
if (i != j) if (i != j)
remap = true; remap = true;
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%d) (%s -> %s)", this, spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
i, out->src_remap[i], j, out->dst_remap[j], i, out->remap[i], j,
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel,
src_info.info.raw.position[i]), src_info.info.raw.position[i]),
spa_debug_type_find_short_name(spa_type_audio_channel, spa_debug_type_find_short_name(spa_type_audio_channel,
@ -2229,7 +2226,8 @@ static int impl_node_process(void *object)
{ {
struct impl *this = object; struct impl *this = object;
const void *src_datas[MAX_PORTS], **in_datas; const void *src_datas[MAX_PORTS], **in_datas;
void *dst_datas[MAX_PORTS], *remap_datas[MAX_PORTS], **out_datas; void *dst_datas[MAX_PORTS], *remap_src_datas[MAX_PORTS], *remap_dst_datas[MAX_PORTS];
void **out_datas, **dst_remap;
uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, remap; uint32_t i, j, n_src_datas = 0, n_dst_datas = 0, n_mon_datas = 0, remap;
uint32_t n_samples, max_in, n_out, max_out, quant_samples; uint32_t n_samples, max_in, n_out, max_out, quant_samples;
struct port *port, *ctrlport = NULL; struct port *port, *ctrlport = NULL;
@ -2237,14 +2235,13 @@ static int impl_node_process(void *object)
struct spa_data *bd; struct spa_data *bd;
struct dir *dir; struct dir *dir;
int tmp = 0, res = 0; int tmp = 0, res = 0;
bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough, end_passthrough; bool in_passthrough, mix_passthrough, resample_passthrough, out_passthrough;
bool in_avail = false, flush_in = false, flush_out = false, draining = false, in_empty = true; bool in_avail = false, flush_in = false, flush_out = false, draining = false, in_empty = true;
struct spa_io_buffers *io, *ctrlio = NULL; struct spa_io_buffers *io, *ctrlio = NULL;
const struct spa_pod_sequence *ctrl = NULL; const struct spa_pod_sequence *ctrl = NULL;
dir = &this->dir[SPA_DIRECTION_INPUT]; dir = &this->dir[SPA_DIRECTION_INPUT];
in_passthrough = dir->conv.is_passthrough && !dir->need_remap; in_passthrough = dir->conv.is_passthrough;
max_in = UINT32_MAX; max_in = UINT32_MAX;
/* collect input port data */ /* collect input port data */
@ -2386,8 +2383,6 @@ static int impl_node_process(void *object)
} }
dir = &this->dir[SPA_DIRECTION_OUTPUT]; dir = &this->dir[SPA_DIRECTION_OUTPUT];
out_passthrough = dir->conv.is_passthrough && !dir->need_remap;
/* collect output ports and monitor ports data */ /* collect output ports and monitor ports data */
for (i = 0; i < dir->n_ports; i++) { for (i = 0; i < dir->n_ports; i++) {
port = GET_OUT_PORT(this, i); port = GET_OUT_PORT(this, i);
@ -2464,46 +2459,54 @@ static int impl_node_process(void *object)
} }
} }
} }
mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) &&
(ctrlport == NULL || ctrlport->ctrl == NULL);
out_passthrough = dir->conv.is_passthrough;
if (in_passthrough && mix_passthrough && resample_passthrough)
out_passthrough = false;
if (out_passthrough && dir->need_remap) {
for (i = 0; i < dir->conv.n_channels; i++) {
remap_dst_datas[i] = dst_datas[dir->remap[i]];
spa_log_trace_fp(this->log, "%p: output remap %d -> %d", this, i, dir->remap[i]);
}
dst_remap = (void **)remap_dst_datas;
} else {
dst_remap = (void **)dst_datas;
}
n_out = max_out - SPA_MIN(max_out, this->out_offset); n_out = max_out - SPA_MIN(max_out, this->out_offset);
mix_passthrough = SPA_FLAG_IS_SET(this->mix.flags, CHANNELMIX_FLAG_IDENTITY) && dir = &this->dir[SPA_DIRECTION_INPUT];
(ctrlport == NULL || ctrlport->ctrl == NULL); if (!in_passthrough) {
end_passthrough = mix_passthrough && resample_passthrough && out_passthrough; if (mix_passthrough && resample_passthrough && out_passthrough)
out_datas = (void **)dst_remap;
if (!in_passthrough || end_passthrough) { else
void **tmp_datas;
dir = &this->dir[SPA_DIRECTION_INPUT];
if (end_passthrough) {
out_datas = (void **)dst_datas;
n_samples = SPA_MIN(n_samples, n_out);
}
else {
out_datas = (void **)this->tmp_datas[(tmp++) & 1]; out_datas = (void **)this->tmp_datas[(tmp++) & 1];
}
if (dir->need_remap) {
for (i = 0; i < dir->conv.n_channels; i++) {
remap_datas[i] = out_datas[dir->src_remap[i]];
spa_log_trace_fp(this->log, "%p: %d -> %d", this, dir->src_remap[i], i);
}
tmp_datas = (void **)remap_datas;
} else {
tmp_datas = (void **)out_datas;
}
spa_log_trace_fp(this->log, "%p: convert %d %d", this, n_samples, end_passthrough);
convert_process(&dir->conv, tmp_datas, src_datas, n_samples);
} else { } else {
out_datas = (void **)src_datas; out_datas = (void **)src_datas;
} }
if (dir->need_remap) {
for (i = 0; i < dir->conv.n_channels; i++) {
remap_src_datas[i] = out_datas[dir->remap[i]];
spa_log_trace_fp(this->log, "%p: input remap %d -> %d", this, dir->remap[i], i);
}
out_datas = (void **)remap_src_datas;
}
if (!in_passthrough) {
spa_log_trace_fp(this->log, "%p: input convert %d", this, n_samples);
convert_process(&dir->conv, out_datas, src_datas, n_samples);
}
if (!mix_passthrough) { if (!mix_passthrough) {
in_datas = (const void**)out_datas; in_datas = (const void**)out_datas;
if (resample_passthrough && out_passthrough) { if (resample_passthrough && out_passthrough) {
out_datas = (void **)dst_datas; out_datas = (void **)dst_remap;
n_samples = SPA_MIN(n_samples, n_out); n_samples = SPA_MIN(n_samples, n_out);
} } else {
else
out_datas = (void **)this->tmp_datas[(tmp++) & 1]; out_datas = (void **)this->tmp_datas[(tmp++) & 1];
}
spa_log_trace_fp(this->log, "%p: channelmix %d %d %d", this, n_samples, spa_log_trace_fp(this->log, "%p: channelmix %d %d %d", this, n_samples,
resample_passthrough, out_passthrough); resample_passthrough, out_passthrough);
if (ctrlport != NULL && ctrlport->ctrl != NULL) { if (ctrlport != NULL && ctrlport->ctrl != NULL) {
@ -2516,13 +2519,12 @@ static int impl_node_process(void *object)
channelmix_process(&this->mix, out_datas, in_datas, n_samples); channelmix_process(&this->mix, out_datas, in_datas, n_samples);
} }
} }
if (!resample_passthrough) { if (!resample_passthrough) {
uint32_t in_len, out_len; uint32_t in_len, out_len;
in_datas = (const void**)out_datas; in_datas = (const void**)out_datas;
if (out_passthrough) if (out_passthrough)
out_datas = (void **)dst_datas; out_datas = (void **)dst_remap;
else else
out_datas = (void **)this->tmp_datas[(tmp++) & 1]; out_datas = (void **)this->tmp_datas[(tmp++) & 1];
@ -2543,14 +2545,14 @@ static int impl_node_process(void *object)
dir = &this->dir[SPA_DIRECTION_OUTPUT]; dir = &this->dir[SPA_DIRECTION_OUTPUT];
if (dir->need_remap) { if (dir->need_remap) {
for (i = 0; i < dir->conv.n_channels; i++) { for (i = 0; i < dir->conv.n_channels; i++) {
remap_datas[i] = out_datas[dir->dst_remap[i]]; remap_dst_datas[i] = out_datas[dir->remap[i]];
spa_log_trace_fp(this->log, "%p: %d -> %d", this, i, dir->dst_remap[i]); spa_log_trace_fp(this->log, "%p: output remap %d -> %d", this, i, dir->remap[i]);
} }
in_datas = (const void**)remap_datas; in_datas = (const void**)remap_dst_datas;
} else { } else {
in_datas = (const void**)out_datas; in_datas = (const void**)out_datas;
} }
spa_log_trace_fp(this->log, "%p: convert %d", this, n_samples); spa_log_trace_fp(this->log, "%p: output convert %d", this, n_samples);
convert_process(&dir->conv, dst_datas, in_datas, n_samples); convert_process(&dir->conv, dst_datas, in_datas, n_samples);
} }