mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-05 13:30:02 -05:00
mem: align memory to requested alignment
Improve the allocators to always align the buffer memory to the requested alignment Use aligned read and writes for sse functions and check alignment, optionally falling back to unaligned path. Add more tests and benchmark cases Check and warn for misaligned memory in plugins.
This commit is contained in:
parent
dd66469570
commit
13bf70a8dd
19 changed files with 736 additions and 516 deletions
|
|
@ -69,7 +69,7 @@ struct port {
|
|||
struct spa_handle *spa_handle;
|
||||
struct spa_node *spa_node;
|
||||
|
||||
float empty[MAX_BUFFER_SIZE];
|
||||
float empty[MAX_BUFFER_SIZE + 15];
|
||||
};
|
||||
|
||||
struct node {
|
||||
|
|
@ -101,14 +101,15 @@ static void init_buffer(struct port *port, uint32_t id)
|
|||
b->datas[0].flags = 0;
|
||||
b->datas[0].fd = -1;
|
||||
b->datas[0].mapoffset = 0;
|
||||
b->datas[0].maxsize = sizeof(port->empty);
|
||||
b->datas[0].data = port->empty;
|
||||
b->datas[0].maxsize = SPA_ROUND_DOWN_N(sizeof(port->empty), 16);
|
||||
b->datas[0].data = SPA_PTR_ALIGN(port->empty, 16, void);
|
||||
b->datas[0].chunk = b->chunk;
|
||||
b->datas[0].chunk->offset = 0;
|
||||
b->datas[0].chunk->size = 0;
|
||||
b->datas[0].chunk->stride = 0;
|
||||
port->bufs[id] = &b->buf;
|
||||
memset(port->empty, 0, sizeof(port->empty));
|
||||
pw_log_debug("%p %d", b->datas[0].data, b->datas[0].maxsize);
|
||||
}
|
||||
|
||||
static void init_port(struct port *p, enum spa_direction direction)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ struct impl {
|
|||
uint32_t stride;
|
||||
|
||||
bool started;
|
||||
float empty[MAX_SAMPLES];
|
||||
float empty[MAX_SAMPLES + 15];
|
||||
};
|
||||
|
||||
#define CHECK_FREE_IN_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS && !this->in_ports[(p)].valid)
|
||||
|
|
@ -632,10 +632,12 @@ impl_node_port_use_buffers(struct spa_node *node,
|
|||
if (!((d[0].type == SPA_DATA_MemPtr ||
|
||||
d[0].type == SPA_DATA_MemFd ||
|
||||
d[0].type == SPA_DATA_DmaBuf) && d[0].data != NULL)) {
|
||||
spa_log_error(this->log, NAME " %p: invalid memory on buffer %p", this,
|
||||
buffers[i]);
|
||||
spa_log_error(this->log, NAME " %p: invalid memory on buffer %d", this, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!SPA_IS_ALIGNED(d[0].data, 16)) {
|
||||
spa_log_warn(this->log, NAME " %p: memory on buffer %d not aligned", this, i);
|
||||
}
|
||||
if (direction == SPA_DIRECTION_OUTPUT)
|
||||
queue_buffer(this, port, b);
|
||||
}
|
||||
|
|
@ -717,23 +719,27 @@ impl_node_port_send_command(struct spa_node *node,
|
|||
#include <xmmintrin.h>
|
||||
static void mix_2(float *dst, float *src1, float *src2, int n_samples)
|
||||
{
|
||||
int i, unrolled;
|
||||
int n, unrolled;
|
||||
__m128 in[2];
|
||||
|
||||
unrolled = n_samples / 4;
|
||||
n_samples &= 3;
|
||||
if (SPA_IS_ALIGNED(src1, 16) &&
|
||||
SPA_IS_ALIGNED(src2, 16) &&
|
||||
SPA_IS_ALIGNED(dst, 16))
|
||||
unrolled = n_samples / 4;
|
||||
else
|
||||
unrolled = 0;
|
||||
|
||||
for (i = 0; unrolled--; i += 4) {
|
||||
in[0] = _mm_loadu_ps(&src1[i]),
|
||||
in[1] = _mm_loadu_ps(&src2[i]),
|
||||
for (n = 0; unrolled--; n += 4) {
|
||||
in[0] = _mm_load_ps(&src1[n]),
|
||||
in[1] = _mm_load_ps(&src2[n]),
|
||||
in[0] = _mm_add_ps(in[0], in[1]);
|
||||
_mm_storeu_ps(&dst[i], in[0]);
|
||||
_mm_store_ps(&dst[n], in[0]);
|
||||
}
|
||||
for (; n_samples--; i++) {
|
||||
in[0] = _mm_load_ss(&src1[i]),
|
||||
in[1] = _mm_load_ss(&src2[i]),
|
||||
for (; n < n_samples; n++) {
|
||||
in[0] = _mm_load_ss(&src1[n]),
|
||||
in[1] = _mm_load_ss(&src2[n]),
|
||||
in[0] = _mm_add_ss(in[0], in[1]);
|
||||
_mm_store_ss(&dst[i], in[0]);
|
||||
_mm_store_ss(&dst[n], in[0]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
@ -825,13 +831,13 @@ static int impl_node_process(struct spa_node *node)
|
|||
|
||||
outb->buffer->n_datas = 1;
|
||||
outb->buffer->datas = outb->datas;
|
||||
outb->datas[0].data = this->empty;
|
||||
outb->datas[0].data = SPA_PTR_ALIGN(this->empty, 16, void);
|
||||
outb->datas[0].chunk = outb->chunk;
|
||||
outb->datas[0].chunk->offset = 0;
|
||||
outb->datas[0].chunk->size = n_samples * sizeof(float);
|
||||
outb->datas[0].chunk->stride = sizeof(float);
|
||||
|
||||
dst = this->empty;
|
||||
dst = outb->datas[0].data;
|
||||
if (n_buffers == 0) {
|
||||
memset(dst, 0, n_samples * sizeof(float));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,7 +837,7 @@ do_port_use_buffers(struct impl *impl,
|
|||
|
||||
data_size = 0;
|
||||
for (j = 0; j < buffers[i]->n_metas; j++) {
|
||||
data_size += buffers[i]->metas[j].size;
|
||||
data_size += SPA_ROUND_UP_N(buffers[i]->metas[j].size, 8);
|
||||
}
|
||||
for (j = 0; j < buffers[i]->n_datas; j++) {
|
||||
struct spa_data *d = buffers[i]->datas;
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ static int alloc_buffers(struct pw_link *this,
|
|||
uint32_t n_datas,
|
||||
size_t *data_sizes,
|
||||
ssize_t *data_strides,
|
||||
size_t *data_aligns,
|
||||
struct allocation *allocation)
|
||||
{
|
||||
int res;
|
||||
|
|
@ -452,12 +453,13 @@ static int alloc_buffers(struct pw_link *this,
|
|||
|
||||
metas[n_metas].type = type;
|
||||
metas[n_metas].size = size;
|
||||
meta_size += metas[n_metas].size;
|
||||
meta_size += SPA_ROUND_UP_N(metas[n_metas].size, 8);
|
||||
n_metas++;
|
||||
skel_size += sizeof(struct spa_meta);
|
||||
}
|
||||
}
|
||||
data_size += meta_size;
|
||||
data_size = SPA_ROUND_UP_N(data_size, data_aligns[0]);
|
||||
|
||||
/* data */
|
||||
for (i = 0; i < n_datas; i++) {
|
||||
|
|
@ -492,7 +494,7 @@ static int alloc_buffers(struct pw_link *this,
|
|||
m->type = metas[j].type;
|
||||
m->size = metas[j].size;
|
||||
m->data = p;
|
||||
p = SPA_MEMBER(p, m->size, void);
|
||||
p = SPA_MEMBER(p, SPA_ROUND_UP_N(m->size, 8), void);
|
||||
}
|
||||
/* pointer to data structure */
|
||||
b->n_datas = n_datas;
|
||||
|
|
@ -509,7 +511,7 @@ static int alloc_buffers(struct pw_link *this,
|
|||
d->type = SPA_DATA_MemFd;
|
||||
d->flags = 0;
|
||||
d->fd = m->fd;
|
||||
d->mapoffset = SPA_PTRDIFF(ddp, m->ptr);
|
||||
d->mapoffset = SPA_ROUND_UP_N(SPA_PTRDIFF(ddp, m->ptr), data_aligns[i]);
|
||||
d->maxsize = data_sizes[j];
|
||||
d->data = SPA_MEMBER(m->ptr, d->mapoffset, void);
|
||||
d->chunk->offset = 0;
|
||||
|
|
@ -701,9 +703,10 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
|
||||
uint32_t i, offset, n_params;
|
||||
uint32_t max_buffers;
|
||||
size_t minsize = 8192, stride = 0;
|
||||
size_t minsize = 8192, stride = 0, align;
|
||||
size_t data_sizes[1];
|
||||
ssize_t data_strides[1];
|
||||
size_t data_aligns[1];
|
||||
|
||||
n_params = param_filter(this, input, output, SPA_PARAM_Buffers, &b);
|
||||
n_params += param_filter(this, input, output, SPA_PARAM_Meta, &b);
|
||||
|
|
@ -720,25 +723,29 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
|
||||
max_buffers = MAX_BUFFERS;
|
||||
minsize = stride = 0;
|
||||
align = 8;
|
||||
param = find_param(params, n_params, SPA_TYPE_OBJECT_ParamBuffers);
|
||||
if (param) {
|
||||
uint32_t qmax_buffers = max_buffers,
|
||||
qminsize = minsize, qstride = stride;
|
||||
qminsize = minsize, qstride = stride, qalign = align;
|
||||
|
||||
spa_pod_parse_object(param,
|
||||
SPA_TYPE_OBJECT_ParamBuffers, NULL,
|
||||
SPA_PARAM_BUFFERS_buffers, SPA_POD_Int(&qmax_buffers),
|
||||
SPA_PARAM_BUFFERS_size, SPA_POD_Int(&qminsize),
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(&qstride));
|
||||
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(&qstride),
|
||||
SPA_PARAM_BUFFERS_align, SPA_POD_Int(&qalign));
|
||||
|
||||
max_buffers =
|
||||
qmax_buffers == 0 ? max_buffers : SPA_MIN(qmax_buffers,
|
||||
max_buffers);
|
||||
minsize = SPA_MAX(minsize, qminsize);
|
||||
stride = SPA_MAX(stride, qstride);
|
||||
align = SPA_MAX(align, qalign);
|
||||
|
||||
pw_log_debug("%d %d %d -> %zd %zd %d", qminsize, qstride, qmax_buffers,
|
||||
minsize, stride, max_buffers);
|
||||
pw_log_debug("%d %d %d %d -> %zd %zd %d %zd",
|
||||
qminsize, qstride, qmax_buffers, qalign,
|
||||
minsize, stride, max_buffers, align);
|
||||
} else {
|
||||
pw_log_warn("no buffers param");
|
||||
minsize = 8192;
|
||||
|
|
@ -754,6 +761,7 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
|
||||
data_sizes[0] = minsize;
|
||||
data_strides[0] = stride;
|
||||
data_aligns[0] = align;
|
||||
|
||||
if ((res = alloc_buffers(this,
|
||||
max_buffers,
|
||||
|
|
@ -761,6 +769,7 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s
|
|||
params,
|
||||
1,
|
||||
data_sizes, data_strides,
|
||||
data_aligns,
|
||||
&allocation)) < 0) {
|
||||
asprintf(&error, "error alloc buffers: %d", res);
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -1075,7 +1075,7 @@ client_node_port_use_buffers(void *object,
|
|||
struct spa_meta *m = &b->metas[j];
|
||||
memcpy(m, &buffers[i].buffer->metas[j], sizeof(struct spa_meta));
|
||||
m->data = SPA_MEMBER(bmem.map.ptr, offset, void);
|
||||
offset += m->size;
|
||||
offset += SPA_ROUND_UP_N(m->size, 8);
|
||||
}
|
||||
|
||||
for (j = 0; j < b->n_datas; j++) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue