From 0d0385b8817a26fbbe62fbfbb018ac64aab4eb9d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 15 Dec 2016 14:57:34 +0100 Subject: [PATCH] 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. --- pinos/client/connection.c | 29 ++- pinos/client/connection.h | 5 +- pinos/client/serialize.c | 22 +-- pinos/client/serialize.h | 1 + pinos/client/stream.c | 57 +++--- pinos/gst/gstpinossink.c | 12 +- pinos/gst/gstpinossrc.c | 12 +- pinos/server/client-node.c | 108 ++++------- pinos/server/link.c | 240 +++++++++++++++--------- spa/include/spa/buffer.h | 48 ++++- spa/lib/debug.c | 20 +- spa/plugins/v4l2/v4l2-utils.c | 13 +- spa/plugins/videotestsrc/videotestsrc.c | 2 +- 13 files changed, 328 insertions(+), 241 deletions(-) diff --git a/pinos/client/connection.c b/pinos/client/connection.c index 877591ff3..7b53cf933 100644 --- a/pinos/client/connection.c +++ b/pinos/client/connection.c @@ -266,11 +266,18 @@ static void connection_parse_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *cmd) { void *p; + unsigned int i; p = conn->in.data; memcpy (cmd, p, sizeof (PinosMessageUseBuffers)); 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 @@ -751,24 +758,32 @@ connection_add_use_buffers (PinosConnection *conn, uint32_t dest_id, PinosMessag size_t len; int i; PinosMessageUseBuffers *d; - PinosMessageMemRef *mr; + PinosMessageBuffer *b; + void *p; /* calculate length */ 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); 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) - d->buffers = SPA_INT_TO_PTR (SPA_PTRDIFF (mr, d)); + d->buffers = SPA_INT_TO_PTR (SPA_PTRDIFF (b, d)); else d->buffers = 0; - for (i = 0; i < ub->n_buffers; i++) - memcpy (&mr[i], &ub->buffers[i], sizeof (PinosMessageMemRef)); + for (i = 0; i < ub->n_buffers; i++) { + 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 diff --git a/pinos/client/connection.h b/pinos/client/connection.h index 96d34b7df..4ea926d57 100644 --- a/pinos/client/connection.h +++ b/pinos/client/connection.h @@ -286,10 +286,11 @@ typedef struct { } PinosMessageAddMem; typedef struct { + SpaBuffer *buffer; uint32_t mem_id; off_t offset; size_t size; -} PinosMessageMemRef; +} PinosMessageBuffer; /* PINOS_MESSAGE_USE_BUFFERS */ typedef struct { @@ -297,7 +298,7 @@ typedef struct { SpaDirection direction; uint32_t port_id; unsigned int n_buffers; - PinosMessageMemRef *buffers; + PinosMessageBuffer *buffers; } PinosMessageUseBuffers; PinosConnection * pinos_connection_new (int fd); diff --git a/pinos/client/serialize.c b/pinos/client/serialize.c index 0b8f949e7..214162242 100644 --- a/pinos/client/serialize.c +++ b/pinos/client/serialize.c @@ -30,7 +30,7 @@ pinos_serialize_buffer_get_size (const SpaBuffer *buffer) size = sizeof (SpaBuffer); 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++) size += sizeof (SpaData); 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->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 (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++) 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); if (b->metas) 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) b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); 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 pinos_serialize_format_get_size (const SpaFormat *format) diff --git a/pinos/client/serialize.h b/pinos/client/serialize.h index 7f8a3035a..568ce879d 100644 --- a/pinos/client/serialize.h +++ b/pinos/client/serialize.h @@ -32,6 +32,7 @@ extern "C" { size_t pinos_serialize_buffer_get_size (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_copy_into (void *dest, const SpaBuffer *buffer); size_t pinos_serialize_format_get_size (const SpaFormat *format); size_t pinos_serialize_format_serialize (void *dest, const SpaFormat *format); diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 41f53935f..01df9e020 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -44,6 +44,7 @@ typedef struct { int fd; uint32_t flags; void *ptr; + off_t offset; size_t size; } MemId; @@ -453,20 +454,13 @@ on_rtsocket_condition (SpaSource *source, read (impl->rtfd, &cmd, 1); if (cmd & PINOS_TRANSPORT_CMD_HAVE_DATA) { - BufferId *bid; - for (i = 0; i < impl->trans->area->n_inputs; i++) { SpaPortInput *input = &impl->trans->inputs[i]; if (input->buffer_id == SPA_ID_INVALID) continue; - if ((bid = find_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); - } + pinos_signal_emit (&stream->new_buffer, stream, input->buffer_id); input->buffer_id = SPA_ID_INVALID; } send_need_input (stream); @@ -652,15 +646,18 @@ stream_dispatch_func (void *object, m = find_mem (stream, p->mem_id); 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 { 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->fd = p->memfd; m->flags = p->flags; m->ptr = NULL; + m->offset = p->offset; m->size = p->size; break; } @@ -675,6 +672,8 @@ stream_dispatch_func (void *object, clear_buffers (stream); for (i = 0; i < p->n_buffers; i++) { + off_t offset = 0; + MemId *mid = find_mem (stream, p->buffers[i].mem_id); if (mid == NULL) { pinos_log_warn ("unknown memory id %u", mid->id); @@ -682,41 +681,28 @@ stream_dispatch_func (void *object, } 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) { mid->ptr = NULL; pinos_log_warn ("Failed to mmap memory %zd %p: %s", mid->size, mid, strerror (errno)); continue; } + mid->ptr = SPA_MEMBER (mid->ptr, mid->offset, void); } len = pinos_array_get_len (&impl->buffer_ids, 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); { 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); - memcpy (b, bid->buf_ptr, size); - - 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); - } + pinos_serialize_buffer_copy_into (b, p->buffers[i].buffer); } - bid->id = b->id; if (bid->id != len) { @@ -727,13 +713,15 @@ stream_dispatch_func (void *object, for (j = 0; j < b->n_metas; j++) { SpaMeta *m = &b->metas[j]; - if (m->data) - m->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (m->data), void); + m->data = SPA_MEMBER (bid->buf_ptr, offset, void); + offset += m->size; } for (j = 0; j < b->n_datas; j++) { SpaData *d = &b->datas[j]; + d->chunk = SPA_MEMBER (bid->buf_ptr, offset + sizeof (SpaChunk) * j, SpaChunk); + switch (d->type) { 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); } @@ -1096,9 +1086,6 @@ pinos_stream_send_buffer (PinosStream *stream, uint8_t cmd = PINOS_TRANSPORT_CMD_HAVE_DATA; 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].status = SPA_RESULT_OK; write (impl->rtfd, &cmd, 1); diff --git a/pinos/gst/gstpinossink.c b/pinos/gst/gstpinossink.c index 5233a97b8..c858ef813 100644 --- a/pinos/gst/gstpinossink.c +++ b/pinos/gst/gstpinossink.c @@ -403,13 +403,13 @@ on_add_buffer (PinosListener *listener, case SPA_DATA_TYPE_DMABUF: { gmem = gst_fd_allocator_alloc (pinossink->allocator, dup (d->fd), - d->maxsize, GST_FD_MEMORY_FLAG_NONE); - gst_memory_resize (gmem, d->offset, d->size); + d->size, GST_FD_MEMORY_FLAG_NONE); + gst_memory_resize (gmem, d->chunk->offset, d->chunk->size); break; } case SPA_DATA_TYPE_MEMPTR: - gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->offset, - d->size, NULL, NULL); + gmem = gst_memory_new_wrapped (0, d->data, d->size, d->chunk->offset, + d->chunk->size, NULL, NULL); break; default: break; @@ -644,8 +644,8 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) for (i = 0; i < data->buf->n_datas; i++) { SpaData *d = &data->buf->datas[i]; GstMemory *mem = gst_buffer_peek_memory (buffer, i); - d->offset = mem->offset; - d->size = mem->size; + d->chunk->offset = mem->offset; + d->chunk->size = mem->size; } gst_buffer_ref (buffer); diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c index 0c0154122..635a8d665 100644 --- a/pinos/gst/gstpinossrc.c +++ b/pinos/gst/gstpinossrc.c @@ -417,13 +417,13 @@ on_add_buffer (PinosListener *listener, case SPA_DATA_TYPE_DMABUF: { gmem = gst_fd_allocator_alloc (pinossrc->fd_allocator, dup (d->fd), - d->maxsize, GST_FD_MEMORY_FLAG_NONE); - gst_memory_resize (gmem, d->offset, d->size); + d->size, GST_FD_MEMORY_FLAG_NONE); + gst_memory_resize (gmem, d->chunk->offset, d->chunk->size); break; } case SPA_DATA_TYPE_MEMPTR: - gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->offset, - d->size, NULL, NULL); + gmem = gst_memory_new_wrapped (0, d->data, d->size, d->chunk->offset, + d->chunk->size, NULL, NULL); default: break; } @@ -488,8 +488,8 @@ on_new_buffer (PinosListener *listener, for (i = 0; i < data->buf->n_datas; i++) { SpaData *d = &data->buf->datas[i]; GstMemory *mem = gst_buffer_peek_memory (buf, i); - mem->offset = d->offset; - mem->size = d->size; + mem->offset = d->chunk->offset; + mem->size = d->chunk->size; } g_queue_push_tail (&pinossrc->queue, buf); diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 2816d7a63..3dd0ccae5 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -66,7 +66,6 @@ struct _ProxyBuffer { off_t offset; size_t size; bool outstanding; - ProxyBuffer *next; }; typedef struct { @@ -610,9 +609,9 @@ spa_proxy_node_port_use_buffers (SpaNode *node, unsigned int i, j; PinosMessageAddMem am; PinosMessageUseBuffers ub; - size_t size, n_mem; - PinosMessageMemRef *memref; - void *p; + size_t n_mem; + PinosMessageBuffer *mb; + SpaMetaShared *msh; if (node == NULL) return SPA_RESULT_INVALID_ARGUMENTS; @@ -630,19 +629,44 @@ spa_proxy_node_port_use_buffers (SpaNode *node, clear_buffers (this, port); - /* find size to store buffers */ - size = 0; + if (n_buffers > 0) { + mb = alloca (n_buffers * sizeof (PinosMessageBuffer)); + } else { + mb = NULL; + } + n_mem = 0; for (i = 0; i < n_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]; memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); b->buffer.datas = b->datas; b->buffer.metas = b->metas; - b->size = SPA_ROUND_UP_N (pinos_serialize_buffer_get_size (buffers[i]), 64); - b->offset = size; + am.direction = direction; + 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++) { 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.flags = d->flags; am.offset = d->offset; - am.size = d->maxsize; + am.size = d->size; pinos_resource_send_message (this->resource, PINOS_MESSAGE_ADD_MEM, &am, @@ -683,78 +707,20 @@ spa_proxy_node_port_use_buffers (SpaNode *node, 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; ub.seq = this->seq++; ub.direction = direction; ub.port_id = port_id; ub.n_buffers = n_buffers; - ub.buffers = memref; + ub.buffers = mb; pinos_resource_send_message (this->resource, PINOS_MESSAGE_USE_BUFFERS, &ub, true); + return SPA_RESULT_RETURN_ASYNC (ub.seq); } @@ -789,6 +755,7 @@ spa_proxy_node_port_alloc_buffers (SpaNode *node, static void copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) { +#if 0 ProxyBuffer *b = &port->buffers[buffer_id]; 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); } } +#endif } static void copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) { +#if 0 ProxyBuffer *b = &port->buffers[buffer_id]; 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); } } +#endif } static SpaResult diff --git a/pinos/server/link.c b/pinos/server/link.c index 2f23f56fe..2b316b1e0 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -201,6 +201,145 @@ find_meta_enable (const SpaPortInfo *info, SpaMetaType type) 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 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; pinos_log_debug ("reusing %d output buffers %p", impl->n_buffers, impl->buffers); } else { - unsigned int i, j; - size_t hdr_size, buf_size, arr_size; - void *p; - unsigned int n_metas, n_datas; + size_t data_sizes[1]; + ssize_t data_strides[1]; - n_metas = 0; - n_datas = 1; - - 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); + data_sizes[0] = minsize; + data_strides[0] = stride; impl->n_buffers = max_buffers; - pinos_memblock_alloc (PINOS_MEMBLOCK_FLAG_WITH_FD | - PINOS_MEMBLOCK_FLAG_MAP_READWRITE | - PINOS_MEMBLOCK_FLAG_SEAL, - impl->n_buffers * (sizeof (SpaBuffer*) + buf_size), - &impl->buffer_mem); - - arr_size = impl->n_buffers * sizeof (SpaBuffer*); - impl->buffers = p = impl->buffer_mem.ptr; - 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; + impl->buffers = alloc_buffers (this, + impl->n_buffers, + oinfo->n_params, + oinfo->params, + 1, + data_sizes, + data_strides, + &impl->buffer_mem); } if (out_flags & SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS) { diff --git a/spa/include/spa/buffer.h b/spa/include/spa/buffer.h index 1b58c56a6..94eb81bf9 100644 --- a/spa/include/spa/buffer.h +++ b/spa/include/spa/buffer.h @@ -36,6 +36,7 @@ typedef struct _SpaBuffer SpaBuffer; * @SPA_META_TYPE_POINTER: a generic pointer * @SPA_META_TYPE_VIDEO_CROP: video cropping region * @SPA_META_TYPE_RINGBUFFER: a ringbuffer + * @SPA_META_TYPE_SHARED: buffer data and metadata memory can be shared */ typedef enum { SPA_META_TYPE_INVALID = 0, @@ -43,6 +44,7 @@ typedef enum { SPA_META_TYPE_POINTER, SPA_META_TYPE_VIDEO_CROP, SPA_META_TYPE_RINGBUFFER, + SPA_META_TYPE_SHARED, } SpaMetaType; /** @@ -119,6 +121,21 @@ typedef struct { SpaRingbuffer ringbuffer; } SpaMetaRingbuffer; +/** + * SpaMetaShared: + * @type: + * @flags: + * @fd: + * @size: + */ +typedef struct { + SpaDataType type; + int flags; + int fd; + off_t offset; + size_t size; +} SpaMetaShared; + /** * SpaMeta: * @type: metadata type @@ -131,26 +148,36 @@ typedef struct { size_t size; } 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: * @type: memory type * @flags: memory flags - * @data: pointer to memory * @fd: file descriptor + * @offset: start offset when mapping @fd * @maxsize: maximum size of the memory - * @offset: offset in @data - * @size: valid size of @data - * @stride: stride of data if applicable + * @data: pointer to memory + * @chunk: pointer to chunk with valid offset */ typedef struct { SpaDataType type; int flags; - void *data; int fd; - size_t maxsize; off_t offset; size_t size; - ssize_t stride; + void *data; + SpaChunk *chunk; } SpaData; /** @@ -169,6 +196,12 @@ struct _SpaBuffer { SpaData *datas; }; + +typedef struct { + unsigned int n_buffers; + SpaBuffer **buffers; +} SpaBufferArray; + static inline void * spa_buffer_find_meta (SpaBuffer *b, SpaMetaType type) { @@ -189,6 +222,7 @@ spa_meta_type_get_size (SpaMetaType type) sizeof (SpaMetaPointer), sizeof (SpaMetaVideoCrop), sizeof (SpaMetaRingbuffer), + sizeof (SpaMetaShared), }; if (type <= 0 || type >= SPA_N_ELEMENTS (header_sizes)) return 0; diff --git a/spa/lib/debug.c b/spa/lib/debug.c index 02e8bb321..8b3582439 100644 --- a/spa/lib/debug.c +++ b/spa/lib/debug.c @@ -30,6 +30,7 @@ struct meta_type_name { { "SpaMetaPointer" }, { "SpaMetaVideoCrop" }, { "SpaMetaRingbuffer" }, + { "SpaMetaShared" }, { "invalid" }, }; #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); 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: spa_debug_dump_mem (m->data, m->size); break; @@ -184,10 +196,12 @@ spa_debug_buffer (const SpaBuffer *buffer) fprintf (stderr, " flags: %d\n", d->flags); fprintf (stderr, " data: %p\n", d->data); fprintf (stderr, " fd: %d\n", d->fd); - fprintf (stderr, " maxsize: %zd\n", d->maxsize); fprintf (stderr, " offset: %zd\n", d->offset); - fprintf (stderr, " size: %zd\n", d->size); - fprintf (stderr, " stride: %zd\n", d->stride); + fprintf (stderr, " maxsize: %zd\n", d->size); + 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; } diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index de291aa10..874fe709d 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -117,7 +117,7 @@ spa_v4l2_clear_buffers (SpaV4l2Source *this) } if (b->allocated) { 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) close (b->outbuf->datas[0].fd); b->outbuf->datas[0].type = SPA_DATA_TYPE_INVALID; @@ -876,7 +876,9 @@ mmap_read (SpaV4l2Source *this) } 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); @@ -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"); 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; break; case SPA_DATA_TYPE_DMABUF: @@ -1047,8 +1049,9 @@ mmap_init (SpaV4l2Source *this, d = buffers[i]->datas; d[0].offset = 0; d[0].size = b->v4l2_buffer.length; - d[0].maxsize = b->v4l2_buffer.length; - d[0].stride = state->fmt.fmt.pix.bytesperline; + d[0].chunk->offset = 0; + d[0].chunk->size = b->v4l2_buffer.length; + d[0].chunk->stride = state->fmt.fmt.pix.bytesperline; if (state->export_buf) { struct v4l2_exportbuffer expbuf; diff --git a/spa/plugins/videotestsrc/videotestsrc.c b/spa/plugins/videotestsrc/videotestsrc.c index be8cf93b9..292882ab6 100644 --- a/spa/plugins/videotestsrc/videotestsrc.c +++ b/spa/plugins/videotestsrc/videotestsrc.c @@ -658,7 +658,7 @@ spa_videotestsrc_node_port_use_buffers (SpaNode *node, continue; } b->ptr = SPA_MEMBER (d[0].data, d[0].offset, void); - b->stride = d[0].stride; + b->stride = d[0].chunk->stride; break; default: break;