summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2017-12-26 02:51:20 +0300
committerDmitry Osipenko <digetx@gmail.com>2017-12-26 22:14:29 +0300
commit7aa916e62e8dade42bccc185a71a43860345aa19 (patch)
tree7227591aa7ebe63a3f2cac1d39cf0f4b33977f29
parente968275ac2bb18a6a9ef3e336ab982d43d03bf46 (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.c161
-rw-r--r--src/surface.c209
-rw-r--r--src/surface_bitmap.c32
-rw-r--r--src/surface_mixer.c71
-rw-r--r--src/surface_output.c7
-rw-r--r--src/surface_shared.c74
-rw-r--r--src/surface_video.c17
-rw-r--r--src/vdpau_tegra.c27
-rw-r--r--src/vdpau_tegra.h16
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);