diff --git a/inc/mpp_buffer.h b/inc/mpp_buffer.h index 01c9adf3..af02878d 100644 --- a/inc/mpp_buffer.h +++ b/inc/mpp_buffer.h @@ -33,37 +33,69 @@ #define SZ_64M (SZ_1M*64) #define SZ_80M (SZ_1M*80) +/* + * MppBuffer module has several functions: + * + * 1. buffer get / put / reference management / and external commit. + * this part is the basic user interface for MppBuffer. + * + * function: + * + * mpp_buffer_get + * mpp_buffer_put + * mpp_buffer_inc_ref + * mpp_buffer_commit + * + * 2. user buffer working flow control abstraction. + * buffer should attach to certain group, and buffer mode control the buffer usage flow. + * this part is also a part of user interface. + * + * function: + * + * mpp_buffer_group_get + * mpp_buffer_group_normal_get + * mpp_buffer_group_limit_get + * mpp_buffer_group_put + * mpp_buffer_group_limit_config + * + * 3. buffer allocator management + * this part is for allocator on different os, it does not have user interface + * it will support normal buffer, Android ion buffer, Linux v4l2 vb2 buffer + * user can only use MppBufferType to choose. + * + */ typedef void* MppBuffer; typedef void* MppBufferGroup; /* - * mpp buffer pool support two buffer malloc mode: + * mpp buffer group support two work flow mode: * - * native mode: all buffer are generated by mpp and buffer type can be read from MppBuffer + * normal flow: all buffer are generated by MPP * under this mode, buffer pool is maintained internally * * typical call flow: * - * mpp_buffer_group_get() return A - * mpp_buffer_get(A) return a ref +1 -> used - * mpp_buffer_inc_ref(a) ref +1 - * mpp_buffer_put(a) ref -1 - * mpp_buffer_put(a) ref -1 -> unused + * mpp_buffer_group_get() return A + * mpp_buffer_get(A) return a ref +1 -> used + * mpp_buffer_inc_ref(a) ref +1 + * mpp_buffer_put(a) ref -1 + * mpp_buffer_put(a) ref -1 -> unused * mpp_buffer_group_put(A) * - * commit mode: all buffer are commited out of mpp - * under this mode, buffer pool is controlled by external api + * commit flow: all buffer are commited out of MPP + * under this mode, buffers is commit by external api. + * normally MPP only use it but not generate it. * * typical call flow: * * ==== external allocator ==== - * mpp_buffer_group_get() return A + * mpp_buffer_group_get() return A * mpp_buffer_commit(A, x) * mpp_buffer_commit(A, y) * * ======= internal user ====== - * mpp_buffer_get(A) return a - * mpp_buffer_get(A) return b + * mpp_buffer_get(A) return a + * mpp_buffer_get(A) return b * mpp_buffer_put(a) * mpp_buffer_put(b) * @@ -72,9 +104,27 @@ typedef void* MppBufferGroup; * * NOTE: commit interface required group handle to record group information */ + +/* + * mpp buffer group has two buffer limit mode: normal and limit + * + * normal mode: allows any buffer size and always general new buffer is no unused buffer + * is available. + * This mode normally use with normal flow and is used for table / stream buffer + * + * limit mode : restrict the buffer's size and count in the buffer group. if try to calloc + * buffer with different size or extra count it will fail. + * This mode normally use with commit flow and is used for frame buffer + */ + +/* + * NOTE: normal mode is recommanded to work with normal flow, working with limit mode is not. + * limit mode is recommanded to work with commit flow, working with normal mode is not. + */ typedef enum { - MPP_BUFFER_MODE_NATIVE, - MPP_BUFFER_MODE_COMMIT, + MPP_BUFFER_MODE_NORMAL, + MPP_BUFFER_MODE_LIMIT, + MPP_BUFFER_MODE_BUTT, } MppBufferMode; /* @@ -86,6 +136,7 @@ typedef enum { typedef enum { MPP_BUFFER_TYPE_NORMAL, MPP_BUFFER_TYPE_ION, + MPP_BUFFER_TYPE_V4L2, MPP_BUFFER_TYPE_BUTT, } MppBufferType; @@ -101,10 +152,16 @@ typedef struct { MppBufferData data; } MppBufferCommit; -#define BUFFER_GROUP_SIZE_DEFAULT (SZ_1M*80) +#define BUFFER_GROUP_SIZE_DEFAULT (SZ_1M*80) -#define mpp_buffer_get(...) mpp_buffer_get_with_tag(MODULE_TAG, ## __VA_ARGS__) -#define mpp_buffer_group_get(...) mpp_buffer_group_get_with_tag(MODULE_TAG, ## __VA_ARGS__) +#define mpp_buffer_get(...) \ + mpp_buffer_get_with_tag(MODULE_TAG, ## __VA_ARGS__) + +#define mpp_buffer_group_normal_get(...) \ + mpp_buffer_group_get(MODULE_TAG, MPP_BUFFER_MODE_NORMAL, ## __VA_ARGS__) + +#define mpp_buffer_group_limited_get(...) \ + mpp_buffer_group_get(MODULE_TAG, MPP_BUFFER_MODE_LIMIT, ## __VA_ARGS__) #ifdef __cplusplus extern "C" { @@ -120,9 +177,9 @@ MPP_RET mpp_buffer_get_with_tag(const char *tag, MppBufferGroup group, MppBuffer MPP_RET mpp_buffer_put(MppBuffer *buffer); MPP_RET mpp_buffer_inc_ref(MppBuffer buffer); -MPP_RET mpp_buffer_group_get_with_tag(const char *tag, MppBufferGroup *group, MppBufferType type); +MPP_RET mpp_buffer_group_get(const char *tag, MppBufferMode mode, MppBufferGroup *group, MppBufferType type); MPP_RET mpp_buffer_group_put(MppBufferGroup *group); -MPP_RET mpp_buffer_group_set_limit(MppBufferGroup group, size_t limit); +MPP_RET mpp_buffer_group_limit_config(MppBufferGroup group, size_t size, RK_S32 count); #ifdef __cplusplus } diff --git a/mpp/mpp_buffer.cpp b/mpp/mpp_buffer.cpp index 3ec4c6e5..9cf2f04a 100644 --- a/mpp/mpp_buffer.cpp +++ b/mpp/mpp_buffer.cpp @@ -81,15 +81,18 @@ MPP_RET mpp_buffer_inc_ref(MppBuffer buffer) } -MPP_RET mpp_buffer_group_get_with_tag(const char *tag, MppBufferGroup *group, MppBufferType type) +MPP_RET mpp_buffer_group_get(const char *tag, MppBufferMode mode, + MppBufferGroup *group, MppBufferType type) { - if (NULL == group || type >= MPP_BUFFER_TYPE_BUTT) { - mpp_err("mpp_buffer_group_get input invalid group %p type %d\n", - group, type); + if (NULL == group || + type >= MPP_BUFFER_MODE_BUTT || + type >= MPP_BUFFER_TYPE_BUTT) { + mpp_err("mpp_buffer_group_get input invalid group %p mode %d type %d\n", + group, mode, type); return MPP_ERR_UNKNOW; } - return mpp_buffer_group_init((MppBufferGroupImpl**)group, tag, type); + return mpp_buffer_group_init((MppBufferGroupImpl**)group, tag, mode, type); } MPP_RET mpp_buffer_group_put(MppBufferGroup *group) @@ -105,9 +108,18 @@ MPP_RET mpp_buffer_group_put(MppBufferGroup *group) return mpp_buffer_group_deinit(p); } -MPP_RET mpp_buffer_group_set_limit(MppBufferGroup group, size_t limit) +MPP_RET mpp_buffer_group_limit_config(MppBufferGroup group, size_t size, RK_S32 count) { + if (NULL == group || 0 == size || count <= 0) { + mpp_err("mpp_buffer_group_limit_config input invalid group %p size %d count %d\n", + group, size, count); + return MPP_NOK; + } + MppBufferGroupImpl *p = (MppBufferGroupImpl *)group; - return mpp_buffer_group_limit_reset(p, limit); + mpp_assert(p->mode == MPP_BUFFER_MODE_LIMIT); + p->limit_size = size; + p->limit_count = count; + return MPP_OK; } diff --git a/mpp/mpp_buffer_impl.cpp b/mpp/mpp_buffer_impl.cpp index 433152a6..339a037e 100644 --- a/mpp/mpp_buffer_impl.cpp +++ b/mpp/mpp_buffer_impl.cpp @@ -75,16 +75,17 @@ MPP_RET deinit_buffer_no_lock(MppBufferImpl *buffer) list_del_init(&buffer->list_status); MppBufferGroupImpl *group = SEARCH_GROUP_NORMAL(buffer->group_id); if (group) { - if (MPP_BUFFER_MODE_NATIVE == buffer->mode) { + if (MPP_BUFFER_MODE_NORMAL == buffer->mode) { group->alloc_api->free(group->allocator, &buffer->data); } group->usage -= buffer->size; } else { group = SEARCH_GROUP_ORPHAN(buffer->group_id); mpp_assert(group); - mpp_assert(buffer->mode == MPP_BUFFER_MODE_NATIVE); + mpp_assert(buffer->mode == MPP_BUFFER_MODE_NORMAL); group->alloc_api->free(group->allocator, &buffer->data); group->usage -= buffer->size; + group->count--; if (0 == group->usage) deinit_group_no_lock(group); } @@ -149,10 +150,10 @@ MPP_RET mpp_buffer_create(const char *tag, RK_U32 group_id, size_t size, MppBuff } p->data = tmp; - p->mode = MPP_BUFFER_MODE_NATIVE; + p->mode = MPP_BUFFER_MODE_NORMAL; } else { p->data = *data; - p->mode = MPP_BUFFER_MODE_COMMIT; + p->mode = MPP_BUFFER_MODE_LIMIT; } if (NULL == tag) @@ -161,11 +162,13 @@ MPP_RET mpp_buffer_create(const char *tag, RK_U32 group_id, size_t size, MppBuff strncpy(p->tag, tag, sizeof(p->tag)); p->group_id = group_id; p->size = size; + p->type = group->type; p->used = 0; p->ref_count = 0; INIT_LIST_HEAD(&p->list_status); list_add_tail(&p->list_status, &group->list_unused); group->usage += size; + group->count++; } else { mpp_free(p); p = NULL; @@ -248,7 +251,7 @@ MppBufferImpl *mpp_buffer_get_unused(MppBufferGroupImpl *p, size_t size) return buffer; } -MPP_RET mpp_buffer_group_init(MppBufferGroupImpl **group, const char *tag, MppBufferType type) +MPP_RET mpp_buffer_group_init(MppBufferGroupImpl **group, const char *tag, MppBufferMode mode, MppBufferType type) { MppBufferGroupImpl *p = mpp_malloc(MppBufferGroupImpl, 1); if (NULL == p) { @@ -266,9 +269,11 @@ MPP_RET mpp_buffer_group_init(MppBufferGroupImpl **group, const char *tag, MppBu list_add_tail(&p->list_group, &service.list_group); snprintf(p->tag, sizeof(p->tag), "%s_%d", tag, service.group_id); + p->mode = mode; p->type = type; p->limit = BUFFER_GROUP_SIZE_DEFAULT; p->usage = 0; + p->count = 0; p->group_id = service.group_id; // avoid group_id reuse @@ -314,7 +319,7 @@ MPP_RET mpp_buffer_group_deinit(MppBufferGroupImpl *p) // if any buffer with mode MPP_BUFFER_MODE_COMMIT found it should be error MppBufferImpl *pos, *n; list_for_each_entry_safe(pos, n, &p->list_used, MppBufferImpl, list_status) { - mpp_assert(pos->mode != MPP_BUFFER_MODE_COMMIT); + mpp_assert(pos->mode != MPP_BUFFER_MODE_LIMIT); } } @@ -323,15 +328,3 @@ MPP_RET mpp_buffer_group_deinit(MppBufferGroupImpl *p) return MPP_OK; } -MPP_RET mpp_buffer_group_limit_reset(MppBufferGroupImpl *p, size_t limit) -{ - mpp_log("mpp_buffer_group %p limit reset from %u to %u\n", p->limit, limit); - - MPP_BUFFER_SERVICE_LOCK(); - p->limit = limit; - MPP_RET ret = check_buffer_group_limit(p); - MPP_BUFFER_SERVICE_UNLOCK(); - - return ret; -} - diff --git a/mpp/mpp_buffer_impl.h b/mpp/mpp_buffer_impl.h index 1a546e1b..36dc9474 100644 --- a/mpp/mpp_buffer_impl.h +++ b/mpp/mpp_buffer_impl.h @@ -37,10 +37,12 @@ typedef struct MppBufferGroupImpl_t MppBufferGroupImpl; struct MppBufferImpl_t { char tag[MPP_TAG_SIZE]; RK_U32 group_id; - size_t size; - MppBufferData data; + MppBufferType type; MppBufferMode mode; + MppBufferData data; + size_t size; + // used flag is for used/unused list detection RK_U32 used; RK_S32 ref_count; @@ -50,9 +52,15 @@ struct MppBufferImpl_t { struct MppBufferGroupImpl_t { char tag[MPP_TAG_SIZE]; RK_U32 group_id; + MppBufferMode mode; MppBufferType type; + // used in limit mode only + size_t limit_size; + RK_S32 limit_count; + // status record size_t limit; size_t usage; + RK_S32 count; MppAllocator allocator; MppAllocatorApi *alloc_api; @@ -100,9 +108,8 @@ MPP_RET mpp_buffer_ref_inc(MppBufferImpl *buffer); MPP_RET mpp_buffer_ref_dec(MppBufferImpl *buffer); MppBufferImpl *mpp_buffer_get_unused(MppBufferGroupImpl *p, size_t size); -MPP_RET mpp_buffer_group_init(MppBufferGroupImpl **group, const char *tag, MppBufferType type); +MPP_RET mpp_buffer_group_init(MppBufferGroupImpl **group, const char *tag, MppBufferMode mode, MppBufferType type); MPP_RET mpp_buffer_group_deinit(MppBufferGroupImpl *p); -MPP_RET mpp_buffer_group_limit_reset(MppBufferGroupImpl *p, size_t limit); #ifdef __cplusplus } diff --git a/osal/android/os_allocator.c b/osal/android/os_allocator.c index 50203c88..f52c7f1a 100644 --- a/osal/android/os_allocator.c +++ b/osal/android/os_allocator.c @@ -45,6 +45,81 @@ static int ion_close(int fd) return ret; } +static int ion_ioctl(int fd, int req, void *arg) +{ + int ret = ioctl(fd, req, arg); + if (ret < 0) { + mpp_err("ion_ioctl %x failed with code %d: %s\n", req, + ret, strerror(errno)); + return -errno; + } + return ret; +} + +static int ion_alloc(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, ion_user_handle_t *handle) +{ + int ret; + struct ion_allocation_data data = { + .len = len, + .align = align, + .heap_id_mask = heap_mask, + .flags = flags, + }; + + if (handle == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_ALLOC, &data); + if (ret < 0) + return ret; + *handle = data.handle; + return ret; +} + +static int ion_free(int fd, ion_user_handle_t handle) +{ + struct ion_handle_data data = { + .handle = handle, + }; + return ion_ioctl(fd, ION_IOC_FREE, &data); +} + +static int ion_share(int fd, ion_user_handle_t handle, int *share_fd) +{ + int map_fd; + int ret; + struct ion_fd_data data = { + .handle = handle, + }; + + if (share_fd == NULL) + return -EINVAL; + + ret = ion_ioctl(fd, ION_IOC_SHARE, &data); + if (ret < 0) + return ret; + *share_fd = data.fd; + if (*share_fd < 0) { + mpp_err("share ioctl returned negative fd\n"); + return -EINVAL; + } + return ret; +} + +static int ion_alloc_fd(int fd, size_t len, size_t align, unsigned int heap_mask, + unsigned int flags, int *handle_fd) { + ion_user_handle_t handle; + int ret; + + ret = ion_alloc(fd, len, align, heap_mask, flags, &handle); + if (ret < 0) + return ret; + ret = ion_share(fd, handle, handle_fd); + ion_free(fd, handle); + return ret; +} + int os_allocator_open(void **ctx, size_t alignment) { allocator_ion *p = NULL; diff --git a/test/mpp_buffer_test.c b/test/mpp_buffer_test.c index 74d995eb..7633510f 100644 --- a/test/mpp_buffer_test.c +++ b/test/mpp_buffer_test.c @@ -34,6 +34,7 @@ int main() void *commit_ptr[MPP_BUFFER_TEST_COMMIT_COUNT]; MppBuffer normal_buffer[MPP_BUFFER_TEST_NORMAL_COUNT]; size_t size = MPP_BUFFER_TEST_SIZE; + RK_S32 count = MPP_BUFFER_TEST_COMMIT_COUNT; RK_S32 i; mpp_log("mpp_buffer_test start\n"); @@ -42,18 +43,20 @@ int main() memset(commit_buffer, 0, sizeof(commit_buffer)); memset(normal_buffer, 0, sizeof(normal_buffer)); - ret = mpp_buffer_group_get(&group, MPP_BUFFER_TYPE_NORMAL); + ret = mpp_buffer_group_limited_get(&group, MPP_BUFFER_TYPE_NORMAL); if (MPP_OK != ret) { mpp_err("mpp_buffer_test mpp_buffer_group_get failed\n"); goto MPP_BUFFER_failed; } + mpp_buffer_group_limit_config(group, size, count); + mpp_log("mpp_buffer_test commit mode start\n"); commit.type = MPP_BUFFER_TYPE_NORMAL; commit.size = size; - for (i = 0; i < MPP_BUFFER_TEST_COMMIT_COUNT; i++) { + for (i = 0; i < count; i++) { commit_ptr[i] = malloc(size); if (NULL == commit_ptr[i]) { mpp_err("mpp_buffer_test malloc failed\n"); @@ -69,7 +72,7 @@ int main() } } - for (i = 0; i < MPP_BUFFER_TEST_COMMIT_COUNT; i++) { + for (i = 0; i < count; i++) { ret = mpp_buffer_get(group, &commit_buffer[i], size); if (MPP_OK != ret) { mpp_err("mpp_buffer_test mpp_buffer_get commit mode failed\n"); @@ -77,7 +80,7 @@ int main() } } - for (i = 0; i < MPP_BUFFER_TEST_COMMIT_COUNT; i++) { + for (i = 0; i < count; i++) { ret = mpp_buffer_put(&commit_buffer[i]); if (MPP_OK != ret) { mpp_err("mpp_buffer_test mpp_buffer_put commit mode failed\n"); @@ -85,17 +88,25 @@ int main() } } - for (i = 0; i < MPP_BUFFER_TEST_COMMIT_COUNT; i++) { + for (i = 0; i < count; i++) { if (commit_ptr[i]) { free(commit_ptr[i]); commit_ptr[i] = NULL; } } + mpp_buffer_group_put(&group); + mpp_log("mpp_buffer_test commit mode success\n"); mpp_log("mpp_buffer_test normal mode start\n"); + ret = mpp_buffer_group_normal_get(&group, MPP_BUFFER_TYPE_NORMAL); + if (MPP_OK != ret) { + mpp_err("mpp_buffer_test mpp_buffer_group_get failed\n"); + goto MPP_BUFFER_failed; + } + for (i = 0; i < MPP_BUFFER_TEST_NORMAL_COUNT; i++) { ret = mpp_buffer_get(group, &normal_buffer[i], (i+1)*SZ_1K); if (MPP_OK != ret) {