diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2017-12-26 02:51:20 +0300 |
---|---|---|
committer | Dmitry Osipenko <digetx@gmail.com> | 2017-12-26 22:14:29 +0300 |
commit | 7aa916e62e8dade42bccc185a71a43860345aa19 (patch) | |
tree | 7227591aa7ebe63a3f2cac1d39cf0f4b33977f29 | |
parent | e968275ac2bb18a6a9ef3e336ab982d43d03bf46 (diff) |
Implement dynamic surface allocation
This reduces memory usage up to 2x. Couple fixes for zero-copy are also
incorporated in this patch.
-rw-r--r-- | src/presentation_queue.c | 161 | ||||
-rw-r--r-- | src/surface.c | 209 | ||||
-rw-r--r-- | src/surface_bitmap.c | 32 | ||||
-rw-r--r-- | src/surface_mixer.c | 71 | ||||
-rw-r--r-- | src/surface_output.c | 7 | ||||
-rw-r--r-- | src/surface_shared.c | 74 | ||||
-rw-r--r-- | src/surface_video.c | 17 | ||||
-rw-r--r-- | src/vdpau_tegra.c | 27 | ||||
-rw-r--r-- | src/vdpau_tegra.h | 16 |
9 files changed, 374 insertions, 240 deletions
diff --git a/src/presentation_queue.c b/src/presentation_queue.c index 20810af..8f06370 100644 --- a/src/presentation_queue.c +++ b/src/presentation_queue.c @@ -29,6 +29,67 @@ static VdpTime get_time(void) return (VdpTime)tp.tv_sec * 1000000000ULL + (VdpTime)tp.tv_nsec; } +static void pqt_display_surface_to_idle_state(tegra_pqt *pqt) +{ + tegra_surface *surf = pqt->disp_surf; + + if (!surf) { + return; + } + + pthread_mutex_lock(&surf->lock); + if (surf->status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) { + surf->status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; + pthread_cond_signal(&surf->idle_cond); + } + pthread_mutex_unlock(&surf->lock); + + unref_surface(surf); + pqt->disp_surf = NULL; +} + +static void pqt_display_surface(tegra_pqt *pqt, tegra_surface *surf) +{ + tegra_device *dev = pqt->dev; + + if (surf->set_bg && surf->bg_color != pqt->bg_color) { + XSetWindowBackground(dev->display, pqt->drawable, surf->bg_color); + XClearWindow(dev->display, pqt->drawable); + + pqt->bg_color = surf->bg_color; + } + + if (surf->shared) { + XvPutImage(dev->display, dev->xv_port, + pqt->drawable, pqt->gc, + surf->shared->xv_img, + surf->shared->src_x0, + surf->shared->src_y0, + surf->shared->src_width, + surf->shared->src_height, + surf->shared->dst_x0, + surf->shared->dst_y0, + surf->shared->dst_width, + surf->shared->dst_height); + } else { + XvPutImage(dev->display, dev->xv_port, + pqt->drawable, pqt->gc, + surf->xv_img, + 0, 0, surf->disp_width, surf->disp_height, + 0, 0, surf->disp_width, surf->disp_height); + } + + XSync(dev->display, 0); + + surf->first_presentation_time = get_time(); + surf->status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; + + if (pqt->disp_surf != surf) { + pqt_display_surface_to_idle_state(pqt); + pqt->disp_surf = surf; + } +} + static void * x11_thr(void *opaque) { tegra_pq *pq = opaque; @@ -74,17 +135,7 @@ static void * x11_thr(void *opaque) pthread_mutex_lock(&pq->lock); if (pqt->disp_surf) { - XvPutImage(dev->display, dev->xv_port, - pqt->drawable, pqt->gc, - pqt->disp_surf->xv_img, - 0, 0, - pqt->disp_surf->disp_width, - pqt->disp_surf->disp_height, - 0, 0, - pqt->disp_surf->disp_width, - pqt->disp_surf->disp_height); - - XSync(dev->display, 0); + pqt_display_surface(pqt, pqt->disp_surf); } pthread_mutex_unlock(&pq->lock); @@ -93,30 +144,10 @@ static void * x11_thr(void *opaque) return NULL; } -static void pqt_display_surface_to_idle_state(tegra_pqt *pqt) -{ - tegra_surface *surf = pqt->disp_surf; - - if (!surf) { - return; - } - - pthread_mutex_lock(&surf->lock); - if (surf->status == VDP_PRESENTATION_QUEUE_STATUS_VISIBLE) { - surf->status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; - pthread_cond_signal(&surf->idle_cond); - } - pthread_mutex_unlock(&surf->lock); - - unref_surface(surf); - pqt->disp_surf = NULL; -} - static void * presentation_queue_thr(void *opaque) { tegra_pq *pq = opaque; tegra_pqt *pqt = pq->pqt; - tegra_device *dev = pqt->dev; tegra_surface *surf, *tmp; struct timespec tp; VdpTime time = UINT64_MAX; @@ -176,48 +207,7 @@ static void * presentation_queue_thr(void *opaque) goto del_surface; } - if (surf->set_bg && surf->bg_color != pqt->bg_color) { - XSetWindowBackground(dev->display, pqt->drawable, - surf->bg_color); - XClearWindow(dev->display, pqt->drawable); - - pqt->bg_color = surf->bg_color; - } - - if (surf->shared) { - XvPutImage(dev->display, dev->xv_port, - pqt->drawable, pqt->gc, - surf->shared->xv_img, - surf->shared->src_x0, - surf->shared->src_y0, - surf->shared->src_width, - surf->shared->src_height, - surf->shared->dst_x0, - surf->shared->dst_y0, - surf->shared->dst_width, - surf->shared->dst_height); - } else { - XvPutImage(dev->display, dev->xv_port, - pqt->drawable, pqt->gc, - surf->xv_img, - 0, 0, - surf->disp_width, - surf->disp_height, - 0, 0, - surf->disp_width, - surf->disp_height); - } - - XSync(dev->display, 0); - - surf->first_presentation_time = get_time(); - surf->status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; - - if (pqt->disp_surf != surf) { - pqt_display_surface_to_idle_state(pqt); - pqt->disp_surf = surf; - } - + pqt_display_surface(pqt, surf); ref_surface(surf); del_surface: LIST_DEL(&surf->list_item); @@ -441,7 +431,6 @@ VdpStatus vdp_presentation_queue_display( tegra_surface *surf = get_surface(surface); tegra_pq *pq = get_presentation_queue(presentation_queue); tegra_pqt *pqt; - tegra_device *dev; VdpTime time; if (pq == NULL) { @@ -449,7 +438,6 @@ VdpStatus vdp_presentation_queue_display( } pqt = pq->pqt; - dev = pqt->dev; /* This will happen on surface allocation failure. */ if (surf == NULL) { @@ -466,7 +454,7 @@ VdpStatus vdp_presentation_queue_display( pthread_cond_signal(&pq->cond); pthread_mutex_unlock(&pq->lock); - return VDP_STATUS_INVALID_HANDLE; + return VDP_STATUS_RESOURCES; } pthread_mutex_lock(&pq->lock); @@ -476,26 +464,14 @@ VdpStatus vdp_presentation_queue_display( LIST_DEL(&surf->list_item); } - surf->disp_width = clip_width ?: surf->xv_img->width; - surf->disp_height = clip_height ?: surf->xv_img->height; + ref_surface(surf); + surf->disp_width = clip_width ?: surf->width; + surf->disp_height = clip_height ?: surf->height; surf->idle_hack = false; /* XXX: X11 app won't survive threading without XInitThreads() */ if (earliest_presentation_time == 0 || !_Xglobal_lock) { - XvPutImage(dev->display, dev->xv_port, - pqt->drawable, pqt->gc, - surf->xv_img, - 0, 0, - surf->disp_width, - surf->disp_height, - 0, 0, - surf->disp_width, - surf->disp_height); - - XSync(dev->display, 0); - - surf->status = VDP_PRESENTATION_QUEUE_STATUS_VISIBLE; - surf->first_presentation_time = get_time(); + pqt_display_surface(pqt, surf); surf->idle_hack = true; pthread_mutex_unlock(&surf->lock); @@ -504,7 +480,6 @@ VdpStatus vdp_presentation_queue_display( return VDP_STATUS_OK; } - ref_surface(surf); LIST_ADDTAIL(&surf->list_item, &pq->surf_list); surf->status = VDP_PRESENTATION_QUEUE_STATUS_QUEUED; diff --git a/src/surface.c b/src/surface.c index 11d8a58..3db26a9 100644 --- a/src/surface.c +++ b/src/surface.c @@ -36,12 +36,34 @@ static uint32_t get_unused_surface_id(void) return id; } -tegra_surface *alloc_surface(tegra_device *dev, - uint32_t width, uint32_t height, - VdpRGBAFormat rgba_format, - int output, int video) +int dynamic_alloc_surface_data(tegra_surface *surf) { - tegra_surface *surf = calloc(1, sizeof(tegra_surface)); + if (!surf->data_allocated) { + return alloc_surface_data(surf); + } + + return 0; +} + +int dynamic_release_surface_data(tegra_surface *surf) +{ + if (surf->data_allocated) { + return release_surface_data(surf); + } + + surf->data_dirty = false; + + return 0; +} + +int alloc_surface_data(tegra_surface *surf) +{ + tegra_device *dev = surf->dev; + uint32_t width = surf->width; + uint32_t height = surf->height; + VdpRGBAFormat rgba_format = surf->rgba_format; + int output = surf->flags & SURFACE_OUTPUT; + int video = surf->flags & SURFACE_VIDEO; pixman_image_t *pix = NULL; XvImage *xv_img = NULL; struct tegra_vde_h264_frame *frame = NULL; @@ -51,11 +73,7 @@ tegra_surface *alloc_surface(tegra_device *dev, uint32_t *pitches = NULL; int ret; - if (!surf) { - return NULL; - } - - if (!video){ + if (!video) { pixman_format_code_t pfmt; enum pixel_format pixbuf_fmt; void *data; @@ -72,6 +90,7 @@ tegra_surface *alloc_surface(tegra_device *dev, break; default: + ret = -EINVAL; goto err_cleanup; } @@ -106,12 +125,7 @@ tegra_surface *alloc_surface(tegra_device *dev, } if (video) { - frame = calloc(1, sizeof(struct tegra_vde_h264_frame)); - - if (frame == NULL) { - ret = -ENOMEM; - goto err_cleanup; - } + frame = surf->frame; frame->y_fd = -1; frame->cb_fd = -1; @@ -231,6 +245,10 @@ tegra_surface *alloc_surface(tegra_device *dev, case VDP_RGBA_FORMAT_B8G8R8A8: format_id = FOURCC_PASSTHROUGH_XRGB8888; break; + + default: + ret = -EINVAL; + goto err_cleanup; } xv_img = XvCreateImage(dev->display, dev->xv_port, @@ -263,33 +281,12 @@ tegra_surface *alloc_surface(tegra_device *dev, pitches[0] = pixbuf->pitch; } - ret = pthread_mutex_init(&surf->lock, NULL); - if (ret != 0) { - ErrorMsg("pthread_mutex_init failed\n"); - goto err_cleanup; - } - - ret = pthread_cond_init(&surf->idle_cond, NULL); - if (ret != 0) { - ErrorMsg("pthread_cond_init failed\n"); - goto err_cleanup; - } - - atomic_set(&surf->refcnt, 1); - surf->status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; surf->pix = pix; surf->xv_img = xv_img; - surf->frame = frame; - surf->flags = video ? SURFACE_VIDEO : 0; - surf->flags |= output ? SURFACE_OUTPUT : 0; surf->pixbuf = pixbuf; - surf->dev = dev; - surf->width = width; - surf->height = height; + surf->data_allocated = true; - ref_device(dev); - - return surf; + return 0; err_cleanup: if (xv_img != NULL) { @@ -313,9 +310,116 @@ err_cleanup: close(frame->aux_fd); } + return ret; +} + +int release_surface_data(tegra_surface *surf) +{ + assert(surf->data_allocated); + + if (surf->pixbuf != NULL) { + host1x_pixelbuffer_free(surf->pixbuf); + surf->pixbuf = NULL; + } + + if (surf->pix != NULL) { + pixman_image_unref(surf->pix); + surf->pix = NULL; + } + + if (surf->xv_img != NULL) { + free(surf->xv_img->data); + XFree(surf->xv_img); + surf->xv_img = NULL; + } + + if (surf->frame != NULL) { + drm_tegra_bo_unref(surf->aux_bo); + close(surf->frame->y_fd); + close(surf->frame->cb_fd); + close(surf->frame->cr_fd); + close(surf->frame->aux_fd); + + surf->frame->y_fd = -1; + surf->frame->cb_fd = -1; + surf->frame->cr_fd = -1; + surf->frame->aux_fd = -1; + + surf->y_data = NULL; + surf->cb_data = NULL; + surf->cr_data = NULL; + } + + surf->data_allocated = false; + + return 0; +} + +tegra_surface *alloc_surface(tegra_device *dev, + uint32_t width, uint32_t height, + VdpRGBAFormat rgba_format, + int output, int video) +{ + tegra_surface *surf = calloc(1, sizeof(tegra_surface)); + struct tegra_vde_h264_frame *frame = NULL; + pthread_mutexattr_t mutex_attrs; + int ret; + + if (!surf) { + return NULL; + } + + if (video) { + frame = calloc(1, sizeof(struct tegra_vde_h264_frame)); + + if (frame == NULL) { + ret = -ENOMEM; + goto err_cleanup; + } + } + + pthread_mutexattr_init(&mutex_attrs); + pthread_mutexattr_settype(&mutex_attrs, PTHREAD_MUTEX_RECURSIVE); + + ret = pthread_mutex_init(&surf->lock, &mutex_attrs); + if (ret != 0) { + ErrorMsg("pthread_mutex_init failed\n"); + goto err_cleanup; + } + + ret = pthread_cond_init(&surf->idle_cond, NULL); + if (ret != 0) { + ErrorMsg("pthread_cond_init failed\n"); + goto err_cleanup; + } + + atomic_set(&surf->refcnt, 1); + surf->status = VDP_PRESENTATION_QUEUE_STATUS_IDLE; + surf->frame = frame; + surf->flags = video ? SURFACE_VIDEO : 0; + surf->flags |= output ? SURFACE_OUTPUT : 0; + surf->dev = dev; + surf->width = width; + surf->height = height; + surf->rgba_format = rgba_format; + + if (!output) { + ret = alloc_surface_data(surf); + if (ret != 0) { + goto err_cleanup; + } + } + + ref_device(dev); + + return surf; + +err_cleanup: free(frame); free(surf); + ErrorMsg("failed to allocate surface %d %s\n", ret, strerror(ret)); + return NULL; } @@ -332,7 +436,7 @@ uint32_t create_surface(tegra_device *dev, surf = alloc_surface(dev, width, height, rgba_format, output, video); if (surf == NULL) { - return VDP_INVALID_HANDLE; + return VDP_STATUS_RESOURCES; } pthread_mutex_lock(&global_lock); @@ -369,30 +473,7 @@ VdpStatus unref_surface(tegra_surface *surf) shared_surface_kill_disp(surf); } - if (surf->pixbuf != NULL) { - host1x_pixelbuffer_free(surf->pixbuf); - surf->pixbuf = NULL; - } - - if (surf->pix != NULL) { - pixman_image_unref(surf->pix); - surf->pix = NULL; - } - - if (surf->xv_img != NULL) { - free(surf->xv_img->data); - XFree(surf->xv_img); - surf->xv_img = NULL; - } - - if (surf->frame != NULL) { - drm_tegra_bo_unref(surf->aux_bo); - close(surf->frame->y_fd); - close(surf->frame->cb_fd); - close(surf->frame->cr_fd); - close(surf->frame->aux_fd); - } - + dynamic_release_surface_data(surf); unref_device(surf->dev); free(surf->frame); diff --git a/src/surface_bitmap.c b/src/surface_bitmap.c index e1cd208..86d4113 100644 --- a/src/surface_bitmap.c +++ b/src/surface_bitmap.c @@ -96,29 +96,14 @@ VdpStatus vdp_bitmap_surface_get_parameters(VdpBitmapSurface surface, VdpBool *frequently_accessed) { tegra_surface *surf = get_surface(surface); - pixman_image_t *pix; - pixman_format_code_t pfmt; if (surf == NULL) { return VDP_STATUS_INVALID_HANDLE; } - pix = surf->pix; - pfmt = pixman_image_get_format(pix); - - switch (pfmt) { - case PIXMAN_a8r8g8b8: - *rgba_format = VDP_RGBA_FORMAT_R8G8B8A8; - break; - case PIXMAN_a8b8g8r8: - *rgba_format = VDP_RGBA_FORMAT_B8G8R8A8; - break; - default: - abort(); - } - - *width = pixman_image_get_width(pix); - *height = pixman_image_get_height(pix); + *rgba_format = surf->rgba_format; + *width = surf->width; + *height = surf->height; *frequently_accessed = VDP_FALSE; return VDP_STATUS_OK; @@ -136,11 +121,22 @@ VdpStatus vdp_bitmap_surface_put_bits_native(VdpBitmapSurface surface, void *surf_data; uint32_t width, height; uint32_t x0, y0; + int err; if (surf == NULL) { return VDP_STATUS_INVALID_HANDLE; } + if (surf->flags & SURFACE_OUTPUT) { + err = shared_surface_transfer_video(surf); + if (err) { + return err; + } + + /* XXX: check whether dirty data is overridden by surface blit */ + surf->data_dirty = true; + } + pix = surf->pix; pfmt = pixman_image_get_format(pix); surf_data = pixman_image_get_data(pix); diff --git a/src/surface_mixer.c b/src/surface_mixer.c index dac046d..3da0000 100644 --- a/src/surface_mixer.c +++ b/src/surface_mixer.c @@ -364,6 +364,7 @@ VdpStatus vdp_video_mixer_render( uint32_t bg_width, bg_height, bg_x0, bg_y0; uint32_t bg_color; bool draw_background = false; + int ret; if (dest_surf == NULL || mix == NULL) { return VDP_STATUS_INVALID_HANDLE; @@ -407,34 +408,38 @@ VdpStatus vdp_video_mixer_render( bg_y0 = 0; } - draw_background = (dst_vid_y0 != bg_y0 || - dst_vid_x0 != bg_x0 || - dst_vid_height < bg_height || - dst_vid_width < bg_width); - dest_surf->set_bg = false; + bg_color = (int)(mix->bg_color.alpha * 255) << 24; - if (draw_background && !bg_surf) { - bg_color = (int)(mix->bg_color.alpha * 255) << 24; + switch (dest_surf->rgba_format) { + case VDP_RGBA_FORMAT_B8G8R8A8: + bg_color |= (int)(mix->bg_color.red * 255) << 16; + bg_color |= (int)(mix->bg_color.green * 255) << 8; + bg_color |= (int)(mix->bg_color.blue * 255) << 0; + break; - switch (dest_surf->pixbuf->format) { - case PIX_BUF_FMT_ARGB8888: - bg_color |= (int)(mix->bg_color.red * 255) << 16; - bg_color |= (int)(mix->bg_color.green * 255) << 8; - bg_color |= (int)(mix->bg_color.blue * 255) << 0; - break; + case VDP_RGBA_FORMAT_R8G8B8A8: + bg_color |= (int)(mix->bg_color.blue * 255) << 16; + bg_color |= (int)(mix->bg_color.green * 255) << 8; + bg_color |= (int)(mix->bg_color.red * 255) << 0; + break; - case PIX_BUF_FMT_ABGR8888: - bg_color |= (int)(mix->bg_color.blue * 255) << 16; - bg_color |= (int)(mix->bg_color.green * 255) << 8; - bg_color |= (int)(mix->bg_color.red * 255) << 0; - break; + default: + abort(); + } - default: - abort(); - } + draw_background = (dst_vid_y0 != bg_y0 || + dst_vid_x0 != bg_x0 || + dst_vid_height < bg_height || + dst_vid_width < bg_width); + if (draw_background && !bg_surf) { if (background_source_rect) { + ret = dynamic_alloc_surface_data(dest_surf); + if (ret) { + return VDP_STATUS_RESOURCES; + } + host1x_gr2d_clear_rect_clipped(mix->dev->stream, dest_surf->pixbuf, bg_color, @@ -452,6 +457,11 @@ VdpStatus vdp_video_mixer_render( } if (draw_background && bg_surf) { + ret = dynamic_alloc_surface_data(dest_surf); + if (ret) { + return VDP_STATUS_RESOURCES; + } + host1x_gr2d_surface_blit(mix->dev->stream, bg_surf->pixbuf, dest_surf->pixbuf, @@ -467,7 +477,7 @@ VdpStatus vdp_video_mixer_render( if (!draw_background) { shared = create_shared_surface(dest_surf, video_surf, - mix->csc_matrix, + &mix->csc_matrix, src_vid_x0, src_vid_y0, src_vid_width, @@ -476,6 +486,23 @@ VdpStatus vdp_video_mixer_render( dst_vid_y0, dst_vid_width, dst_vid_height); + if (!shared) { + ret = dynamic_alloc_surface_data(dest_surf); + if (ret) { + return VDP_STATUS_RESOURCES; + } + + host1x_gr2d_clear_rect_clipped(mix->dev->stream, + dest_surf->pixbuf, + bg_color, + bg_x0, bg_y0, + bg_width, bg_height, + dst_vid_x0, dst_vid_y0, + dst_vid_x0 + dst_vid_width, + dst_vid_y0 + dst_vid_height, + true); + dest_surf->set_bg = false; + } } if (!shared) { diff --git a/src/surface_output.c b/src/surface_output.c index 1b65564..f5ebdd9 100644 --- a/src/surface_output.c +++ b/src/surface_output.c @@ -223,6 +223,11 @@ VdpStatus vdp_output_surface_render_bitmap_surface( src_surf = get_surface(source_surface); + ret = shared_surface_transfer_video(dst_surf); + if (ret) { + return VDP_STATUS_RESOURCES; + } + dst_pix = dst_surf->pix; dst_data = pixman_image_get_data(dst_pix); @@ -243,8 +248,6 @@ VdpStatus vdp_output_surface_render_bitmap_surface( dst_y0 = 0; } - shared_surface_transfer_video(dst_surf); - if (source_surface == VDP_INVALID_HANDLE) { ret = host1x_gr2d_clear_rect(dst_surf->dev->stream, dst_surf->pixbuf, diff --git a/src/surface_shared.c b/src/surface_shared.c index 8cd6f1e..dddd9e5 100644 --- a/src/surface_shared.c +++ b/src/surface_shared.c @@ -61,41 +61,50 @@ static XvImage * create_video_xv(tegra_surface *video) return xv_img; } -tegra_shared_surface *create_shared_surface(tegra_surface *disp, - tegra_surface *video, - VdpCSCMatrix const csc_matrix, - uint32_t src_x0, - uint32_t src_y0, - uint32_t src_width, - uint32_t src_height, - uint32_t dst_x0, - uint32_t dst_y0, - uint32_t dst_width, - uint32_t dst_height) +static bool custom_csc(VdpCSCMatrix const *csc_matrix) { - tegra_shared_surface *shared; int i, k; + if (memcmp(*csc_matrix, CSC_BT_601, sizeof(VdpCSCMatrix)) == 0 || + memcmp(*csc_matrix, CSC_BT_709, sizeof(VdpCSCMatrix)) == 0) + return false; + for (i = 0; i < 3; i++) for (k = 0; k < 3; k++) - if (fabs(csc_matrix[i][k] - CSC_BT_601[i][k]) > 0.01f) + if (fabs((*csc_matrix)[i][k] - CSC_BT_601[i][k]) > 0.01f) goto check_709; - goto shared_alloc; + return false; /* XXX: Tegra's CSC is hardcoded to BT601 in the kernel driver */ check_709: for (i = 0; i < 3; i++) for (k = 0; k < 3; k++) - if (fabs(csc_matrix[i][k] - CSC_BT_709[i][k]) > 0.01f) - goto custom_csc; + if (fabs((*csc_matrix)[i][k] - CSC_BT_709[i][k]) > 0.01f) + return true; - goto shared_alloc; + return false; +} -custom_csc: - return NULL; +tegra_shared_surface *create_shared_surface(tegra_surface *disp, + tegra_surface *video, + VdpCSCMatrix const *csc_matrix, + uint32_t src_x0, + uint32_t src_y0, + uint32_t src_width, + uint32_t src_height, + uint32_t dst_x0, + uint32_t dst_y0, + uint32_t dst_width, + uint32_t dst_height) +{ + tegra_shared_surface *shared; + int ret; + + if (disp->data_dirty || custom_csc(csc_matrix)) { + return NULL; + } -shared_alloc: shared = calloc(1, sizeof(tegra_shared_surface)); if (!shared) { return NULL; @@ -123,6 +132,13 @@ shared_alloc: return NULL; } + ret = dynamic_release_surface_data(disp); + if (ret) { + free(shared->xv_img); + free(shared); + return NULL; + } + ref_surface(video); video->shared = shared; disp->shared = shared; @@ -175,10 +191,11 @@ tegra_surface * shared_surface_swap_video(tegra_surface *old) return new; } -void shared_surface_transfer_video(tegra_surface *disp) +int shared_surface_transfer_video(tegra_surface *disp) { tegra_shared_surface *shared; tegra_surface *video; + int ret; assert(disp->flags & SURFACE_OUTPUT); @@ -191,8 +208,16 @@ void shared_surface_transfer_video(tegra_surface *disp) } pthread_mutex_unlock(&shared_lock); + ret = dynamic_alloc_surface_data(disp); + if (ret) { + if (shared) { + goto unref; + } + return ret; + } + if (!shared) { - return; + return 0; } if (disp->set_bg) { @@ -222,10 +247,12 @@ void shared_surface_transfer_video(tegra_surface *disp) shared->dst_y0, shared->dst_width, shared->dst_height); - +unref: unref_surface(disp); unref_surface(video); unref_shared_surface(shared); + + return 0; } void shared_surface_kill_disp(tegra_surface *disp) @@ -233,6 +260,7 @@ void shared_surface_kill_disp(tegra_surface *disp) tegra_shared_surface *shared = NULL; assert(disp->flags & SURFACE_OUTPUT); + disp->data_dirty = false; pthread_mutex_lock(&shared_lock); diff --git a/src/surface_video.c b/src/surface_video.c index 9fc424a..03b435f 100644 --- a/src/surface_video.c +++ b/src/surface_video.c @@ -198,27 +198,34 @@ VdpStatus vdp_video_surface_put_bits_y_cb_cr( void const *const *source_data, uint32_t const *source_pitches) { - tegra_surface *surf = get_surface_ref(surface); + tegra_surface *surf, *orig = get_surface_ref(surface); void *src_y = (void *)source_data[0]; void *src_cr = (void *)source_data[1]; void *src_cb = (void *)source_data[2]; int width, height; int ret; - if (surf == NULL) { + if (orig == NULL) { return VDP_STATUS_INVALID_HANDLE; } - assert(surf->flags & SURFACE_VIDEO); - switch (source_ycbcr_format) { case VDP_YCBCR_FORMAT_YV12: break; default: - unref_surface(surf); + unref_surface(orig); return VDP_STATUS_NO_IMPLEMENTATION; } + surf = shared_surface_swap_video(orig); + + if (orig != surf) { + unref_surface(orig); + ref_surface(surf); + } + + assert(surf->flags & SURFACE_VIDEO); + ret = sync_video_frame_dmabufs(surf, WRITE_START); if (ret) { diff --git a/src/vdpau_tegra.c b/src/vdpau_tegra.c index 1f3352a..e0e0ef3 100644 --- a/src/vdpau_tegra.c +++ b/src/vdpau_tegra.c @@ -140,9 +140,7 @@ void replace_surface(tegra_surface *old_surf, tegra_surface *new_surf) if (old_surf != new_surf) { assert(tegra_surfaces[old_surf->surface_id] == old_surf); - new_surf->surface_id = old_surf->surface_id; - old_surf->surface_id = MAX_SURFACES_NB; tegra_surfaces[new_surf->surface_id] = new_surf; } @@ -288,15 +286,22 @@ VdpStatus vdp_generate_csc_matrix(VdpProcamp *procamp, return VDP_STATUS_INVALID_STRUCT_VERSION; } - uvcos = procamp->saturation * cosf(procamp->hue); - uvsin = procamp->saturation * sinf(procamp->hue); - - for (i = 0; i < 3; i++) { - float u = (*csc_matrix)[i][1] * uvcos + (*csc_matrix)[i][2] * uvsin; - float v = (*csc_matrix)[i][1] * uvsin + (*csc_matrix)[i][2] * uvcos; - (*csc_matrix)[i][0] = procamp->contrast; - (*csc_matrix)[i][1] = u; - (*csc_matrix)[i][2] = v; + if (procamp->hue != 0.0f || + procamp->saturation != 1.0f || + procamp->contrast != 1.0f) { + uvcos = procamp->saturation * cosf(procamp->hue); + uvsin = procamp->saturation * sinf(procamp->hue); + + for (i = 0; i < 3; i++) { + float u = (*csc_matrix)[i][1] * uvcos + (*csc_matrix)[i][2] * uvsin; + float v = (*csc_matrix)[i][1] * uvsin + (*csc_matrix)[i][2] * uvcos; + (*csc_matrix)[i][0] = procamp->contrast; + (*csc_matrix)[i][1] = u; + (*csc_matrix)[i][2] = v; + (*csc_matrix)[i][3] = -(u + v) / 2; + (*csc_matrix)[i][3] += 0.5 - procamp->contrast / 2; + (*csc_matrix)[i][3] += procamp->brightness; + } } return VDP_STATUS_OK; diff --git a/src/vdpau_tegra.h b/src/vdpau_tegra.h index cd67b0d..cf26e1f 100644 --- a/src/vdpau_tegra.h +++ b/src/vdpau_tegra.h @@ -180,6 +180,10 @@ typedef struct tegra_surface { uint32_t bg_color; bool set_bg; + + VdpRGBAFormat rgba_format; + bool data_allocated; + bool data_dirty; } tegra_surface; typedef struct tegra_decoder { @@ -246,6 +250,14 @@ tegra_pq * get_presentation_queue(VdpPresentationQueue presentation_queue); void set_presentation_queue(VdpPresentationQueue presentation_queue, tegra_pq *pq); +int dynamic_alloc_surface_data(tegra_surface *surf); + +int dynamic_release_surface_data(tegra_surface *surf); + +int alloc_surface_data(tegra_surface *surf); + +int release_surface_data(tegra_surface *surf); + uint32_t create_surface(tegra_device *dev, uint32_t width, uint32_t height, @@ -283,7 +295,7 @@ int sync_video_frame_dmabufs(tegra_surface *surf, enum frame_sync type); tegra_shared_surface *create_shared_surface(tegra_surface *disp, tegra_surface *video, - VdpCSCMatrix const csc_matrix, + VdpCSCMatrix const *csc_matrix, uint32_t src_x0, uint32_t src_y0, uint32_t src_width, @@ -299,7 +311,7 @@ void unref_shared_surface(tegra_shared_surface *shared); tegra_surface * shared_surface_swap_video(tegra_surface *old); -void shared_surface_transfer_video(tegra_surface *disp); +int shared_surface_transfer_video(tegra_surface *disp); void shared_surface_kill_disp(tegra_surface *disp); |