Rework buffer memory layout

Move offset, size and stride to separate chunk structure that we
can keep in shared memory.
Add shared metadata type to hold the memory block holding the
metadata.
This commit is contained in:
Wim Taymans 2016-12-15 14:57:34 +01:00
parent 5e8a3afe17
commit 0d0385b881
13 changed files with 328 additions and 241 deletions

View file

@ -266,11 +266,18 @@ static void
connection_parse_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *cmd) connection_parse_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *cmd)
{ {
void *p; void *p;
unsigned int i;
p = conn->in.data; p = conn->in.data;
memcpy (cmd, p, sizeof (PinosMessageUseBuffers)); memcpy (cmd, p, sizeof (PinosMessageUseBuffers));
if (cmd->buffers) if (cmd->buffers)
cmd->buffers = SPA_MEMBER (p, SPA_PTR_TO_INT (cmd->buffers), PinosMessageMemRef); cmd->buffers = SPA_MEMBER (p, SPA_PTR_TO_INT (cmd->buffers), PinosMessageBuffer);
for (i = 0; i < cmd->n_buffers; i++) {
if (cmd->buffers[i].buffer)
cmd->buffers[i].buffer = pinos_serialize_buffer_deserialize (conn->in.data,
SPA_PTR_TO_INT (cmd->buffers[i].buffer));
}
} }
static void static void
@ -751,24 +758,32 @@ connection_add_use_buffers (PinosConnection *conn, uint32_t dest_id, PinosMessag
size_t len; size_t len;
int i; int i;
PinosMessageUseBuffers *d; PinosMessageUseBuffers *d;
PinosMessageMemRef *mr; PinosMessageBuffer *b;
void *p;
/* calculate length */ /* calculate length */
len = sizeof (PinosMessageUseBuffers); len = sizeof (PinosMessageUseBuffers);
len += ub->n_buffers * sizeof (PinosMessageMemRef); len += ub->n_buffers * sizeof (PinosMessageBuffer);
for (i = 0; i < ub->n_buffers; i++)
len += pinos_serialize_buffer_get_size (ub->buffers[i].buffer);
d = connection_add_message (conn, dest_id, PINOS_MESSAGE_USE_BUFFERS, len); d = connection_add_message (conn, dest_id, PINOS_MESSAGE_USE_BUFFERS, len);
memcpy (d, ub, sizeof (PinosMessageUseBuffers)); memcpy (d, ub, sizeof (PinosMessageUseBuffers));
mr = SPA_MEMBER (d, sizeof (PinosMessageUseBuffers), void); b = SPA_MEMBER (d, sizeof (PinosMessageUseBuffers), void);
p = SPA_MEMBER (b, ub->n_buffers * sizeof (PinosMessageBuffer), void);
if (d->n_buffers) if (d->n_buffers)
d->buffers = SPA_INT_TO_PTR (SPA_PTRDIFF (mr, d)); d->buffers = SPA_INT_TO_PTR (SPA_PTRDIFF (b, d));
else else
d->buffers = 0; d->buffers = 0;
for (i = 0; i < ub->n_buffers; i++) for (i = 0; i < ub->n_buffers; i++) {
memcpy (&mr[i], &ub->buffers[i], sizeof (PinosMessageMemRef)); memcpy (&b[i], &ub->buffers[i], sizeof (PinosMessageBuffer));
len = pinos_serialize_buffer_serialize (p, b[i].buffer);
b[i].buffer = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d));
p += len;
}
} }
static void static void

View file

@ -286,10 +286,11 @@ typedef struct {
} PinosMessageAddMem; } PinosMessageAddMem;
typedef struct { typedef struct {
SpaBuffer *buffer;
uint32_t mem_id; uint32_t mem_id;
off_t offset; off_t offset;
size_t size; size_t size;
} PinosMessageMemRef; } PinosMessageBuffer;
/* PINOS_MESSAGE_USE_BUFFERS */ /* PINOS_MESSAGE_USE_BUFFERS */
typedef struct { typedef struct {
@ -297,7 +298,7 @@ typedef struct {
SpaDirection direction; SpaDirection direction;
uint32_t port_id; uint32_t port_id;
unsigned int n_buffers; unsigned int n_buffers;
PinosMessageMemRef *buffers; PinosMessageBuffer *buffers;
} PinosMessageUseBuffers; } PinosMessageUseBuffers;
PinosConnection * pinos_connection_new (int fd); PinosConnection * pinos_connection_new (int fd);

View file

@ -30,7 +30,7 @@ pinos_serialize_buffer_get_size (const SpaBuffer *buffer)
size = sizeof (SpaBuffer); size = sizeof (SpaBuffer);
for (i = 0; i < buffer->n_metas; i++) for (i = 0; i < buffer->n_metas; i++)
size += sizeof (SpaMeta) + buffer->metas[i].size; size += sizeof (SpaMeta);
for (i = 0; i < buffer->n_datas; i++) for (i = 0; i < buffer->n_datas; i++)
size += sizeof (SpaData); size += sizeof (SpaData);
return size; return size;
@ -57,12 +57,8 @@ pinos_serialize_buffer_serialize (void *dest, const SpaBuffer *buffer)
tb->metas = SPA_INT_TO_PTR (SPA_PTRDIFF (mp, tb)); tb->metas = SPA_INT_TO_PTR (SPA_PTRDIFF (mp, tb));
tb->datas = SPA_INT_TO_PTR (SPA_PTRDIFF (dp, tb)); tb->datas = SPA_INT_TO_PTR (SPA_PTRDIFF (dp, tb));
for (i = 0; i < tb->n_metas; i++) { for (i = 0; i < tb->n_metas; i++)
memcpy (&mp[i], &buffer->metas[i], sizeof (SpaMeta)); memcpy (&mp[i], &buffer->metas[i], sizeof (SpaMeta));
memcpy (p, mp[i].data, mp[i].size);
mp[i].data = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tb));
p += mp[i].size;
}
for (i = 0; i < tb->n_datas; i++) for (i = 0; i < tb->n_datas; i++)
memcpy (&dp[i], &buffer->datas[i], sizeof (SpaData)); memcpy (&dp[i], &buffer->datas[i], sizeof (SpaData));
@ -78,17 +74,21 @@ pinos_serialize_buffer_deserialize (void *src, off_t offset)
b = SPA_MEMBER (src, offset, SpaBuffer); b = SPA_MEMBER (src, offset, SpaBuffer);
if (b->metas) if (b->metas)
b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta);
for (i = 0; i < b->n_metas; i++) {
SpaMeta *m = &b->metas[i];
if (m->data)
m->data = SPA_MEMBER (b, SPA_PTR_TO_INT (m->data), void);
}
if (b->datas) if (b->datas)
b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData);
return b; return b;
} }
SpaBuffer *
pinos_serialize_buffer_copy_into (void *dest, const SpaBuffer *buffer)
{
if (buffer == NULL)
return NULL;
pinos_serialize_buffer_serialize (dest, buffer);
return pinos_serialize_buffer_deserialize (dest, 0);
}
size_t size_t
pinos_serialize_format_get_size (const SpaFormat *format) pinos_serialize_format_get_size (const SpaFormat *format)

View file

@ -32,6 +32,7 @@ extern "C" {
size_t pinos_serialize_buffer_get_size (const SpaBuffer *buffer); size_t pinos_serialize_buffer_get_size (const SpaBuffer *buffer);
size_t pinos_serialize_buffer_serialize (void *dest, const SpaBuffer *buffer); size_t pinos_serialize_buffer_serialize (void *dest, const SpaBuffer *buffer);
SpaBuffer * pinos_serialize_buffer_deserialize (void *src, off_t offset); SpaBuffer * pinos_serialize_buffer_deserialize (void *src, off_t offset);
SpaBuffer * pinos_serialize_buffer_copy_into (void *dest, const SpaBuffer *buffer);
size_t pinos_serialize_format_get_size (const SpaFormat *format); size_t pinos_serialize_format_get_size (const SpaFormat *format);
size_t pinos_serialize_format_serialize (void *dest, const SpaFormat *format); size_t pinos_serialize_format_serialize (void *dest, const SpaFormat *format);

View file

@ -44,6 +44,7 @@ typedef struct {
int fd; int fd;
uint32_t flags; uint32_t flags;
void *ptr; void *ptr;
off_t offset;
size_t size; size_t size;
} MemId; } MemId;
@ -453,20 +454,13 @@ on_rtsocket_condition (SpaSource *source,
read (impl->rtfd, &cmd, 1); read (impl->rtfd, &cmd, 1);
if (cmd & PINOS_TRANSPORT_CMD_HAVE_DATA) { if (cmd & PINOS_TRANSPORT_CMD_HAVE_DATA) {
BufferId *bid;
for (i = 0; i < impl->trans->area->n_inputs; i++) { for (i = 0; i < impl->trans->area->n_inputs; i++) {
SpaPortInput *input = &impl->trans->inputs[i]; SpaPortInput *input = &impl->trans->inputs[i];
if (input->buffer_id == SPA_ID_INVALID) if (input->buffer_id == SPA_ID_INVALID)
continue; continue;
if ((bid = find_buffer (stream, input->buffer_id))) { pinos_signal_emit (&stream->new_buffer, stream, input->buffer_id);
for (i = 0; i < bid->buf->n_datas; i++) {
bid->buf->datas[i].size = bid->datas[i].size;
}
pinos_signal_emit (&stream->new_buffer, stream, bid->id);
}
input->buffer_id = SPA_ID_INVALID; input->buffer_id = SPA_ID_INVALID;
} }
send_need_input (stream); send_need_input (stream);
@ -652,15 +646,18 @@ stream_dispatch_func (void *object,
m = find_mem (stream, p->mem_id); m = find_mem (stream, p->mem_id);
if (m) { if (m) {
pinos_log_debug ("update mem %u, fd %d, flags %d, size %zd", p->mem_id, p->memfd, p->flags, p->size); pinos_log_debug ("update mem %u, fd %d, flags %d, off %zd, size %zd",
p->mem_id, p->memfd, p->flags, p->offset, p->size);
} else { } else {
m = pinos_array_add (&impl->mem_ids, sizeof (MemId)); m = pinos_array_add (&impl->mem_ids, sizeof (MemId));
pinos_log_debug ("add mem %u, fd %d, flags %d, size %zd", p->mem_id, p->memfd, p->flags, p->size); pinos_log_debug ("add mem %u, fd %d, flags %d, off %zd, size %zd",
p->mem_id, p->memfd, p->flags, p->offset, p->size);
} }
m->id = p->mem_id; m->id = p->mem_id;
m->fd = p->memfd; m->fd = p->memfd;
m->flags = p->flags; m->flags = p->flags;
m->ptr = NULL; m->ptr = NULL;
m->offset = p->offset;
m->size = p->size; m->size = p->size;
break; break;
} }
@ -675,6 +672,8 @@ stream_dispatch_func (void *object,
clear_buffers (stream); clear_buffers (stream);
for (i = 0; i < p->n_buffers; i++) { for (i = 0; i < p->n_buffers; i++) {
off_t offset = 0;
MemId *mid = find_mem (stream, p->buffers[i].mem_id); MemId *mid = find_mem (stream, p->buffers[i].mem_id);
if (mid == NULL) { if (mid == NULL) {
pinos_log_warn ("unknown memory id %u", mid->id); pinos_log_warn ("unknown memory id %u", mid->id);
@ -682,41 +681,28 @@ stream_dispatch_func (void *object,
} }
if (mid->ptr == NULL) { if (mid->ptr == NULL) {
mid->ptr = mmap (NULL, mid->size, PROT_READ | PROT_WRITE, MAP_SHARED, mid->fd, 0); //mid->ptr = mmap (NULL, mid->size, PROT_READ | PROT_WRITE, MAP_SHARED, mid->fd, mid->offset);
mid->ptr = mmap (NULL, mid->size + mid->offset, PROT_READ | PROT_WRITE, MAP_SHARED, mid->fd, 0);
if (mid->ptr == MAP_FAILED) { if (mid->ptr == MAP_FAILED) {
mid->ptr = NULL; mid->ptr = NULL;
pinos_log_warn ("Failed to mmap memory %zd %p: %s", mid->size, mid, strerror (errno)); pinos_log_warn ("Failed to mmap memory %zd %p: %s", mid->size, mid, strerror (errno));
continue; continue;
} }
mid->ptr = SPA_MEMBER (mid->ptr, mid->offset, void);
} }
len = pinos_array_get_len (&impl->buffer_ids, BufferId); len = pinos_array_get_len (&impl->buffer_ids, BufferId);
bid = pinos_array_add (&impl->buffer_ids, sizeof (BufferId)); bid = pinos_array_add (&impl->buffer_ids, sizeof (BufferId));
b = p->buffers[i].buffer;
bid->buf_ptr = SPA_MEMBER (mid->ptr, p->buffers[i].offset, void); bid->buf_ptr = SPA_MEMBER (mid->ptr, p->buffers[i].offset, void);
{ {
size_t size; size_t size;
unsigned int i;
SpaMeta *m;
b = bid->buf_ptr;
size = sizeof (SpaBuffer);
m = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta);
for (i = 0; i < b->n_metas; i++)
size += sizeof (SpaMeta) + m[i].size;
for (i = 0; i < b->n_datas; i++)
size += sizeof (SpaData);
size = pinos_serialize_buffer_get_size (p->buffers[i].buffer);
b = bid->buf = malloc (size); b = bid->buf = malloc (size);
memcpy (b, bid->buf_ptr, size); pinos_serialize_buffer_copy_into (b, p->buffers[i].buffer);
if (b->metas)
b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta);
if (b->datas) {
bid->datas = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (b->datas), SpaData);
b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData);
}
} }
bid->id = b->id; bid->id = b->id;
if (bid->id != len) { if (bid->id != len) {
@ -727,13 +713,15 @@ stream_dispatch_func (void *object,
for (j = 0; j < b->n_metas; j++) { for (j = 0; j < b->n_metas; j++) {
SpaMeta *m = &b->metas[j]; SpaMeta *m = &b->metas[j];
if (m->data) m->data = SPA_MEMBER (bid->buf_ptr, offset, void);
m->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (m->data), void); offset += m->size;
} }
for (j = 0; j < b->n_datas; j++) { for (j = 0; j < b->n_datas; j++) {
SpaData *d = &b->datas[j]; SpaData *d = &b->datas[j];
d->chunk = SPA_MEMBER (bid->buf_ptr, offset + sizeof (SpaChunk) * j, SpaChunk);
switch (d->type) { switch (d->type) {
case SPA_DATA_TYPE_ID: case SPA_DATA_TYPE_ID:
{ {
@ -757,6 +745,8 @@ stream_dispatch_func (void *object,
} }
} }
spa_debug_buffer (b);
pinos_signal_emit (&stream->add_buffer, stream, bid->id); pinos_signal_emit (&stream->add_buffer, stream, bid->id);
} }
@ -1096,9 +1086,6 @@ pinos_stream_send_buffer (PinosStream *stream,
uint8_t cmd = PINOS_TRANSPORT_CMD_HAVE_DATA; uint8_t cmd = PINOS_TRANSPORT_CMD_HAVE_DATA;
bid->used = true; bid->used = true;
for (i = 0; i < bid->buf->n_datas; i++) {
bid->datas[i].size = bid->buf->datas[i].size;
}
impl->trans->outputs[0].buffer_id = id; impl->trans->outputs[0].buffer_id = id;
impl->trans->outputs[0].status = SPA_RESULT_OK; impl->trans->outputs[0].status = SPA_RESULT_OK;
write (impl->rtfd, &cmd, 1); write (impl->rtfd, &cmd, 1);

View file

@ -403,13 +403,13 @@ on_add_buffer (PinosListener *listener,
case SPA_DATA_TYPE_DMABUF: case SPA_DATA_TYPE_DMABUF:
{ {
gmem = gst_fd_allocator_alloc (pinossink->allocator, dup (d->fd), gmem = gst_fd_allocator_alloc (pinossink->allocator, dup (d->fd),
d->maxsize, GST_FD_MEMORY_FLAG_NONE); d->size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (gmem, d->offset, d->size); gst_memory_resize (gmem, d->chunk->offset, d->chunk->size);
break; break;
} }
case SPA_DATA_TYPE_MEMPTR: case SPA_DATA_TYPE_MEMPTR:
gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->offset, gmem = gst_memory_new_wrapped (0, d->data, d->size, d->chunk->offset,
d->size, NULL, NULL); d->chunk->size, NULL, NULL);
break; break;
default: default:
break; break;
@ -644,8 +644,8 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
for (i = 0; i < data->buf->n_datas; i++) { for (i = 0; i < data->buf->n_datas; i++) {
SpaData *d = &data->buf->datas[i]; SpaData *d = &data->buf->datas[i];
GstMemory *mem = gst_buffer_peek_memory (buffer, i); GstMemory *mem = gst_buffer_peek_memory (buffer, i);
d->offset = mem->offset; d->chunk->offset = mem->offset;
d->size = mem->size; d->chunk->size = mem->size;
} }
gst_buffer_ref (buffer); gst_buffer_ref (buffer);

View file

@ -417,13 +417,13 @@ on_add_buffer (PinosListener *listener,
case SPA_DATA_TYPE_DMABUF: case SPA_DATA_TYPE_DMABUF:
{ {
gmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (d->fd), gmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (d->fd),
d->maxsize, GST_FD_MEMORY_FLAG_NONE); d->size, GST_FD_MEMORY_FLAG_NONE);
gst_memory_resize (gmem, d->offset, d->size); gst_memory_resize (gmem, d->chunk->offset, d->chunk->size);
break; break;
} }
case SPA_DATA_TYPE_MEMPTR: case SPA_DATA_TYPE_MEMPTR:
gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->offset, gmem = gst_memory_new_wrapped (0, d->data, d->size, d->chunk->offset,
d->size, NULL, NULL); d->chunk->size, NULL, NULL);
default: default:
break; break;
} }
@ -488,8 +488,8 @@ on_new_buffer (PinosListener *listener,
for (i = 0; i < data->buf->n_datas; i++) { for (i = 0; i < data->buf->n_datas; i++) {
SpaData *d = &data->buf->datas[i]; SpaData *d = &data->buf->datas[i];
GstMemory *mem = gst_buffer_peek_memory (buf, i); GstMemory *mem = gst_buffer_peek_memory (buf, i);
mem->offset = d->offset; mem->offset = d->chunk->offset;
mem->size = d->size; mem->size = d->chunk->size;
} }
g_queue_push_tail (&pinossrc->queue, buf); g_queue_push_tail (&pinossrc->queue, buf);

View file

@ -66,7 +66,6 @@ struct _ProxyBuffer {
off_t offset; off_t offset;
size_t size; size_t size;
bool outstanding; bool outstanding;
ProxyBuffer *next;
}; };
typedef struct { typedef struct {
@ -610,9 +609,9 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
unsigned int i, j; unsigned int i, j;
PinosMessageAddMem am; PinosMessageAddMem am;
PinosMessageUseBuffers ub; PinosMessageUseBuffers ub;
size_t size, n_mem; size_t n_mem;
PinosMessageMemRef *memref; PinosMessageBuffer *mb;
void *p; SpaMetaShared *msh;
if (node == NULL) if (node == NULL)
return SPA_RESULT_INVALID_ARGUMENTS; return SPA_RESULT_INVALID_ARGUMENTS;
@ -630,19 +629,44 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
clear_buffers (this, port); clear_buffers (this, port);
/* find size to store buffers */ if (n_buffers > 0) {
size = 0; mb = alloca (n_buffers * sizeof (PinosMessageBuffer));
} else {
mb = NULL;
}
n_mem = 0; n_mem = 0;
for (i = 0; i < n_buffers; i++) { for (i = 0; i < n_buffers; i++) {
ProxyBuffer *b = &port->buffers[i]; ProxyBuffer *b = &port->buffers[i];
msh = spa_buffer_find_meta (buffers[i], SPA_META_TYPE_SHARED);
if (msh == NULL) {
spa_log_error (this->log, "missing shared metadata on buffer %d", i);
return SPA_RESULT_ERROR;
}
b->outbuf = buffers[i]; b->outbuf = buffers[i];
memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer));
b->buffer.datas = b->datas; b->buffer.datas = b->datas;
b->buffer.metas = b->metas; b->buffer.metas = b->metas;
b->size = SPA_ROUND_UP_N (pinos_serialize_buffer_get_size (buffers[i]), 64); am.direction = direction;
b->offset = size; am.port_id = port_id;
am.mem_id = n_mem++;
am.type = SPA_DATA_TYPE_MEMFD;
am.memfd = msh->fd;
am.flags = msh->flags;
am.offset = msh->offset;
am.size = msh->size;
pinos_resource_send_message (this->resource,
PINOS_MESSAGE_ADD_MEM,
&am,
false);
mb[i].buffer = &b->buffer;
mb[i].mem_id = am.mem_id;
mb[i].offset = 0;
mb[i].size = am.size;
for (j = 0; j < buffers[i]->n_metas; j++) { for (j = 0; j < buffers[i]->n_metas; j++) {
memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta)); memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta));
@ -663,7 +687,7 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
am.memfd = d->fd; am.memfd = d->fd;
am.flags = d->flags; am.flags = d->flags;
am.offset = d->offset; am.offset = d->offset;
am.size = d->maxsize; am.size = d->size;
pinos_resource_send_message (this->resource, pinos_resource_send_message (this->resource,
PINOS_MESSAGE_ADD_MEM, PINOS_MESSAGE_ADD_MEM,
&am, &am,
@ -683,78 +707,20 @@ spa_proxy_node_port_use_buffers (SpaNode *node,
break; break;
} }
} }
size += b->size;
} }
if (n_buffers > 0) {
/* make mem for the buffers */
port->buffer_mem_id = n_mem++;
if (pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD |
PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
PINOS_MEMBLOCK_FLAG_SEAL,
size,
&port->buffer_mem) < 0) {
spa_log_error (this->log, "Failed to allocate buffer memory");
return SPA_RESULT_ERROR;
}
p = port->buffer_mem.ptr;
for (i = 0; i < n_buffers; i++) {
ProxyBuffer *b = &port->buffers[i];
SpaBuffer *sb;
SpaMeta *sbm;
SpaData *sbd;
pinos_serialize_buffer_serialize (p, &b->buffer);
sb = p;
b->buffer.datas = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData);
sbm = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->metas), SpaMeta);
sbd = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData);
for (j = 0; j < b->buffer.n_metas; j++)
b->metas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbm[j].data), void);
for (j = 0; j < b->buffer.n_datas; j++) {
if (b->datas[j].type == SPA_DATA_TYPE_MEMPTR)
b->datas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbd[j].data), void);
}
p += b->size;
}
am.direction = direction;
am.port_id = port_id;
am.mem_id = port->buffer_mem_id;
am.type = SPA_DATA_TYPE_MEMFD;
am.memfd = port->buffer_mem.fd;
am.flags = 0;
am.offset = 0;
am.size = size;
pinos_resource_send_message (this->resource,
PINOS_MESSAGE_ADD_MEM,
&am,
false);
memref = alloca (n_buffers * sizeof (PinosMessageMemRef));
for (i = 0; i < n_buffers; i++) {
memref[i].mem_id = port->buffer_mem_id;
memref[i].offset = port->buffers[i].offset;
memref[i].size = port->buffers[i].size;
}
} else {
memref = NULL;
}
port->n_buffers = n_buffers; port->n_buffers = n_buffers;
ub.seq = this->seq++; ub.seq = this->seq++;
ub.direction = direction; ub.direction = direction;
ub.port_id = port_id; ub.port_id = port_id;
ub.n_buffers = n_buffers; ub.n_buffers = n_buffers;
ub.buffers = memref; ub.buffers = mb;
pinos_resource_send_message (this->resource, pinos_resource_send_message (this->resource,
PINOS_MESSAGE_USE_BUFFERS, PINOS_MESSAGE_USE_BUFFERS,
&ub, &ub,
true); true);
return SPA_RESULT_RETURN_ASYNC (ub.seq); return SPA_RESULT_RETURN_ASYNC (ub.seq);
} }
@ -789,6 +755,7 @@ spa_proxy_node_port_alloc_buffers (SpaNode *node,
static void static void
copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id)
{ {
#if 0
ProxyBuffer *b = &port->buffers[buffer_id]; ProxyBuffer *b = &port->buffers[buffer_id];
unsigned int i; unsigned int i;
@ -804,11 +771,13 @@ copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id)
memcpy (b->outbuf->datas[i].data, b->datas[i].data, b->buffer.datas[i].size); memcpy (b->outbuf->datas[i].data, b->datas[i].data, b->buffer.datas[i].size);
} }
} }
#endif
} }
static void static void
copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id)
{ {
#if 0
ProxyBuffer *b = &port->buffers[buffer_id]; ProxyBuffer *b = &port->buffers[buffer_id];
unsigned int i; unsigned int i;
@ -824,6 +793,7 @@ copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id)
memcpy (b->datas[i].data, b->outbuf->datas[i].data, b->outbuf->datas[i].size); memcpy (b->datas[i].data, b->outbuf->datas[i].data, b->outbuf->datas[i].size);
} }
} }
#endif
} }
static SpaResult static SpaResult

View file

@ -201,6 +201,145 @@ find_meta_enable (const SpaPortInfo *info, SpaMetaType type)
return NULL; return NULL;
} }
static SpaBuffer **
alloc_buffers (PinosLink *this,
unsigned int n_buffers,
unsigned int n_params,
SpaAllocParam **params,
unsigned int n_datas,
size_t *data_sizes,
ssize_t *data_strides,
PinosMemblock *mem)
{
SpaBuffer **buffers, *bp;
unsigned int i;
size_t skel_size, data_size, meta_size;
SpaChunk *cdp;
void *ddp;
unsigned int n_metas;
SpaMeta *metas;
n_metas = data_size = meta_size = 0;
/* each buffer */
skel_size = sizeof (SpaBuffer);
metas = alloca (sizeof (SpaMeta) * n_params + 1);
/* add shared metadata */
metas[n_metas].type = SPA_META_TYPE_SHARED;
metas[n_metas].size = spa_meta_type_get_size (SPA_META_TYPE_SHARED);
meta_size += metas[n_metas].size;
n_metas++;
skel_size += sizeof (SpaMeta);
/* collect metadata */
for (i = 0; i < n_params; i++) {
SpaAllocParam *ap = params[i];
if (ap->type == SPA_ALLOC_PARAM_TYPE_META_ENABLE) {
SpaAllocParamMetaEnable *pme = (SpaAllocParamMetaEnable *) ap;
metas[n_metas].type = pme->type;
metas[n_metas].size = spa_meta_type_get_size (pme->type);
meta_size += metas[n_metas].size;
n_metas++;
skel_size += sizeof (SpaMeta);
}
}
data_size += meta_size;
/* data */
for (i = 0; i < n_datas; i++) {
data_size += sizeof (SpaChunk);
data_size += data_sizes[i];
skel_size += sizeof (SpaData);
}
buffers = calloc (n_buffers, skel_size + sizeof (SpaBuffer *));
/* pointer to buffer structures */
bp = SPA_MEMBER (buffers, n_buffers * sizeof (SpaBuffer *), SpaBuffer);
pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD |
PINOS_MEMBLOCK_FLAG_MAP_READWRITE |
PINOS_MEMBLOCK_FLAG_SEAL,
n_buffers * data_size,
mem);
for (i = 0; i < n_buffers; i++) {
int j;
SpaBuffer *b;
void *p;
buffers[i] = b = SPA_MEMBER (bp, skel_size * i, SpaBuffer);
p = SPA_MEMBER (mem->ptr, data_size * i, void);
b->id = i;
b->n_metas = n_metas;
b->metas = SPA_MEMBER (b, sizeof (SpaBuffer), SpaMeta);
for (j = 0; j < n_metas; j++) {
SpaMeta *m = &b->metas[j];
m->type = metas[j].type;
m->data = p;
m->size = metas[j].size;
switch (m->type) {
case SPA_META_TYPE_SHARED:
{
SpaMetaShared *msh = p;
msh->type = SPA_DATA_TYPE_MEMFD;
msh->flags = 0;
msh->fd = mem->fd;
msh->offset = data_size * i;
msh->size = data_size;
break;
}
case SPA_META_TYPE_RINGBUFFER:
{
SpaMetaRingbuffer *rb = p;
spa_ringbuffer_init (&rb->ringbuffer, data_sizes[0]);
break;
}
default:
break;
}
p += m->size;
}
/* pointer to data structure */
b->n_datas = n_datas;
b->datas = SPA_MEMBER (b->metas, n_metas * sizeof (SpaMeta), SpaData);
cdp = p;
ddp = SPA_MEMBER (cdp, sizeof (SpaChunk) * n_datas, void);
for (j = 0; j < n_datas; j++) {
SpaData *d = &b->datas[j];
d->chunk = &cdp[j];
if (data_sizes[j] > 0) {
d->type = SPA_DATA_TYPE_MEMFD;
d->flags = 0;
d->fd = mem->fd;
d->offset = 0;
d->size = mem->size;
d->data = mem->ptr;
d->chunk->offset = SPA_PTRDIFF (ddp, d->data);
d->chunk->size = data_sizes[j];
d->chunk->stride = data_strides[j];
ddp += data_sizes[j];
} else {
d->type = SPA_DATA_TYPE_INVALID;
d->data = NULL;
}
}
}
return buffers;
}
static SpaResult static SpaResult
do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
{ {
@ -317,98 +456,21 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
impl->allocated = false; impl->allocated = false;
pinos_log_debug ("reusing %d output buffers %p", impl->n_buffers, impl->buffers); pinos_log_debug ("reusing %d output buffers %p", impl->n_buffers, impl->buffers);
} else { } else {
unsigned int i, j; size_t data_sizes[1];
size_t hdr_size, buf_size, arr_size; ssize_t data_strides[1];
void *p;
unsigned int n_metas, n_datas;
n_metas = 0; data_sizes[0] = minsize;
n_datas = 1; data_strides[0] = stride;
hdr_size = sizeof (SpaBuffer);
hdr_size += n_datas * sizeof (SpaData);
for (i = 0; i < oinfo->n_params; i++) {
SpaAllocParam *ap = oinfo->params[i];
if (ap->type == SPA_ALLOC_PARAM_TYPE_META_ENABLE) {
SpaAllocParamMetaEnable *pme = (SpaAllocParamMetaEnable *) ap;
hdr_size += spa_meta_type_get_size (pme->type);
n_metas++;
}
}
hdr_size += n_metas * sizeof (SpaMeta);
buf_size = SPA_ROUND_UP_N (hdr_size + (minsize * blocks), 64);
impl->n_buffers = max_buffers; impl->n_buffers = max_buffers;
pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD | impl->buffers = alloc_buffers (this,
PINOS_MEMBLOCK_FLAG_MAP_READWRITE | impl->n_buffers,
PINOS_MEMBLOCK_FLAG_SEAL, oinfo->n_params,
impl->n_buffers * (sizeof (SpaBuffer*) + buf_size), oinfo->params,
&impl->buffer_mem); 1,
data_sizes,
arr_size = impl->n_buffers * sizeof (SpaBuffer*); data_strides,
impl->buffers = p = impl->buffer_mem.ptr; &impl->buffer_mem);
p = SPA_MEMBER (p, arr_size, void);
for (i = 0; i < impl->n_buffers; i++) {
SpaBuffer *b;
SpaData *d;
void *pd;
unsigned int mi;
b = impl->buffers[i] = SPA_MEMBER (p, buf_size * i, SpaBuffer);
b->id = i;
b->n_metas = n_metas;
b->metas = SPA_MEMBER (b, sizeof (SpaBuffer), SpaMeta);
b->n_datas = n_datas;
b->datas = SPA_MEMBER (b->metas, sizeof (SpaMeta) * n_metas, SpaData);
pd = SPA_MEMBER (b->datas, sizeof (SpaData) * n_datas, void);
for (j = 0, mi = 0; j < oinfo->n_params; j++) {
SpaAllocParam *ap = oinfo->params[j];
if (ap->type == SPA_ALLOC_PARAM_TYPE_META_ENABLE) {
SpaAllocParamMetaEnable *pme = (SpaAllocParamMetaEnable *) ap;
b->metas[mi].type = pme->type;
b->metas[mi].data = pd;
b->metas[mi].size = spa_meta_type_get_size (pme->type);
switch (pme->type) {
case SPA_META_TYPE_RINGBUFFER:
{
SpaMetaRingbuffer *rb = pd;
spa_ringbuffer_init (&rb->ringbuffer, minsize);
break;
}
default:
break;
}
pd = SPA_MEMBER (pd, b->metas[mi].size, void);
mi++;
}
}
d = &b->datas[0];
if (minsize > 0) {
d->type = SPA_DATA_TYPE_MEMFD;
d->flags = 0;
d->data = impl->buffer_mem.ptr;
d->fd = impl->buffer_mem.fd;
d->maxsize = impl->buffer_mem.size;
d->offset = arr_size + hdr_size + (buf_size * i);
d->size = minsize;
d->stride = stride;
} else {
d->type = SPA_DATA_TYPE_INVALID;
d->data = NULL;
}
}
pinos_log_debug ("allocated %d buffers %p %zd", impl->n_buffers, impl->buffers, minsize);
impl->allocated = true;
} }
if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) {

View file

@ -36,6 +36,7 @@ typedef struct _SpaBuffer SpaBuffer;
* @SPA_META_TYPE_POINTER: a generic pointer * @SPA_META_TYPE_POINTER: a generic pointer
* @SPA_META_TYPE_VIDEO_CROP: video cropping region * @SPA_META_TYPE_VIDEO_CROP: video cropping region
* @SPA_META_TYPE_RINGBUFFER: a ringbuffer * @SPA_META_TYPE_RINGBUFFER: a ringbuffer
* @SPA_META_TYPE_SHARED: buffer data and metadata memory can be shared
*/ */
typedef enum { typedef enum {
SPA_META_TYPE_INVALID = 0, SPA_META_TYPE_INVALID = 0,
@ -43,6 +44,7 @@ typedef enum {
SPA_META_TYPE_POINTER, SPA_META_TYPE_POINTER,
SPA_META_TYPE_VIDEO_CROP, SPA_META_TYPE_VIDEO_CROP,
SPA_META_TYPE_RINGBUFFER, SPA_META_TYPE_RINGBUFFER,
SPA_META_TYPE_SHARED,
} SpaMetaType; } SpaMetaType;
/** /**
@ -119,6 +121,21 @@ typedef struct {
SpaRingbuffer ringbuffer; SpaRingbuffer ringbuffer;
} SpaMetaRingbuffer; } SpaMetaRingbuffer;
/**
* SpaMetaShared:
* @type:
* @flags:
* @fd:
* @size:
*/
typedef struct {
SpaDataType type;
int flags;
int fd;
off_t offset;
size_t size;
} SpaMetaShared;
/** /**
* SpaMeta: * SpaMeta:
* @type: metadata type * @type: metadata type
@ -131,26 +148,36 @@ typedef struct {
size_t size; size_t size;
} SpaMeta; } SpaMeta;
/**
* SpaChunk:
* @offset: offset of valid data
* @size: size of valid data
* @stride: stride of data if applicable
*/
typedef struct {
off_t offset;
size_t size;
ssize_t stride;
} SpaChunk;
/** /**
* SpaData: * SpaData:
* @type: memory type * @type: memory type
* @flags: memory flags * @flags: memory flags
* @data: pointer to memory
* @fd: file descriptor * @fd: file descriptor
* @offset: start offset when mapping @fd
* @maxsize: maximum size of the memory * @maxsize: maximum size of the memory
* @offset: offset in @data * @data: pointer to memory
* @size: valid size of @data * @chunk: pointer to chunk with valid offset
* @stride: stride of data if applicable
*/ */
typedef struct { typedef struct {
SpaDataType type; SpaDataType type;
int flags; int flags;
void *data;
int fd; int fd;
size_t maxsize;
off_t offset; off_t offset;
size_t size; size_t size;
ssize_t stride; void *data;
SpaChunk *chunk;
} SpaData; } SpaData;
/** /**
@ -169,6 +196,12 @@ struct _SpaBuffer {
SpaData *datas; SpaData *datas;
}; };
typedef struct {
unsigned int n_buffers;
SpaBuffer **buffers;
} SpaBufferArray;
static inline void * static inline void *
spa_buffer_find_meta (SpaBuffer *b, SpaMetaType type) spa_buffer_find_meta (SpaBuffer *b, SpaMetaType type)
{ {
@ -189,6 +222,7 @@ spa_meta_type_get_size (SpaMetaType type)
sizeof (SpaMetaPointer), sizeof (SpaMetaPointer),
sizeof (SpaMetaVideoCrop), sizeof (SpaMetaVideoCrop),
sizeof (SpaMetaRingbuffer), sizeof (SpaMetaRingbuffer),
sizeof (SpaMetaShared),
}; };
if (type <= 0 || type >= SPA_N_ELEMENTS (header_sizes)) if (type <= 0 || type >= SPA_N_ELEMENTS (header_sizes))
return 0; return 0;

View file

@ -30,6 +30,7 @@ struct meta_type_name {
{ "SpaMetaPointer" }, { "SpaMetaPointer" },
{ "SpaMetaVideoCrop" }, { "SpaMetaVideoCrop" },
{ "SpaMetaRingbuffer" }, { "SpaMetaRingbuffer" },
{ "SpaMetaShared" },
{ "invalid" }, { "invalid" },
}; };
#define META_TYPE_NAME(t) meta_type_names[SPA_CLAMP(t,0,SPA_N_ELEMENTS(meta_type_names)-1)].name #define META_TYPE_NAME(t) meta_type_names[SPA_CLAMP(t,0,SPA_N_ELEMENTS(meta_type_names)-1)].name
@ -172,6 +173,17 @@ spa_debug_buffer (const SpaBuffer *buffer)
fprintf (stderr, " mask2: %zd\n", h->ringbuffer.mask2); fprintf (stderr, " mask2: %zd\n", h->ringbuffer.mask2);
break; break;
} }
case SPA_META_TYPE_SHARED:
{
SpaMetaShared *h = m->data;
fprintf (stderr, " SpaMetaShared:\n");
fprintf (stderr, " type: %d\n", h->type);
fprintf (stderr, " flags: %d\n", h->flags);
fprintf (stderr, " fd: %d\n", h->fd);
fprintf (stderr, " offset: %zd\n", h->offset);
fprintf (stderr, " size: %zd\n", h->size);
break;
}
default: default:
spa_debug_dump_mem (m->data, m->size); spa_debug_dump_mem (m->data, m->size);
break; break;
@ -184,10 +196,12 @@ spa_debug_buffer (const SpaBuffer *buffer)
fprintf (stderr, " flags: %d\n", d->flags); fprintf (stderr, " flags: %d\n", d->flags);
fprintf (stderr, " data: %p\n", d->data); fprintf (stderr, " data: %p\n", d->data);
fprintf (stderr, " fd: %d\n", d->fd); fprintf (stderr, " fd: %d\n", d->fd);
fprintf (stderr, " maxsize: %zd\n", d->maxsize);
fprintf (stderr, " offset: %zd\n", d->offset); fprintf (stderr, " offset: %zd\n", d->offset);
fprintf (stderr, " size: %zd\n", d->size); fprintf (stderr, " maxsize: %zd\n", d->size);
fprintf (stderr, " stride: %zd\n", d->stride); fprintf (stderr, " chunk: %p\n", d->chunk);
fprintf (stderr, " offset: %zd\n", d->chunk->offset);
fprintf (stderr, " size: %zd\n", d->chunk->size);
fprintf (stderr, " stride: %zd\n", d->chunk->stride);
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }

View file

@ -117,7 +117,7 @@ spa_v4l2_clear_buffers (SpaV4l2Source *this)
} }
if (b->allocated) { if (b->allocated) {
if (b->outbuf->datas[0].data) if (b->outbuf->datas[0].data)
munmap (b->outbuf->datas[0].data, b->outbuf->datas[0].maxsize); munmap (b->outbuf->datas[0].data, b->outbuf->datas[0].size);
if (b->outbuf->datas[0].fd != -1) if (b->outbuf->datas[0].fd != -1)
close (b->outbuf->datas[0].fd); close (b->outbuf->datas[0].fd);
b->outbuf->datas[0].type = SPA_DATA_TYPE_INVALID; b->outbuf->datas[0].type = SPA_DATA_TYPE_INVALID;
@ -876,7 +876,9 @@ mmap_read (SpaV4l2Source *this)
} }
d = b->outbuf->datas; d = b->outbuf->datas;
d[0].size = buf.bytesused; d[0].chunk->offset = 0;
d[0].chunk->size = buf.bytesused;
d[0].chunk->stride = state->fmt.fmt.pix.bytesperline;
spa_list_insert (state->ready.prev, &b->list); spa_list_insert (state->ready.prev, &b->list);
@ -970,7 +972,7 @@ spa_v4l2_use_buffers (SpaV4l2Source *this, SpaBuffer **buffers, uint32_t n_buffe
spa_log_error (state->log, "v4l2: need mmaped memory"); spa_log_error (state->log, "v4l2: need mmaped memory");
continue; continue;
} }
b->v4l2_buffer.m.userptr = (unsigned long) SPA_MEMBER (d[0].data, d[0].offset, void *); b->v4l2_buffer.m.userptr = (unsigned long) d[0].data;
b->v4l2_buffer.length = d[0].size; b->v4l2_buffer.length = d[0].size;
break; break;
case SPA_DATA_TYPE_DMABUF: case SPA_DATA_TYPE_DMABUF:
@ -1047,8 +1049,9 @@ mmap_init (SpaV4l2Source *this,
d = buffers[i]->datas; d = buffers[i]->datas;
d[0].offset = 0; d[0].offset = 0;
d[0].size = b->v4l2_buffer.length; d[0].size = b->v4l2_buffer.length;
d[0].maxsize = b->v4l2_buffer.length; d[0].chunk->offset = 0;
d[0].stride = state->fmt.fmt.pix.bytesperline; d[0].chunk->size = b->v4l2_buffer.length;
d[0].chunk->stride = state->fmt.fmt.pix.bytesperline;
if (state->export_buf) { if (state->export_buf) {
struct v4l2_exportbuffer expbuf; struct v4l2_exportbuffer expbuf;

View file

@ -658,7 +658,7 @@ spa_videotestsrc_node_port_use_buffers (SpaNode *node,
continue; continue;
} }
b->ptr = SPA_MEMBER (d[0].data, d[0].offset, void); b->ptr = SPA_MEMBER (d[0].data, d[0].offset, void);
b->stride = d[0].stride; b->stride = d[0].chunk->stride;
break; break;
default: default:
break; break;