summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2017-12-28 15:56:34 +0300
committerDmitry Osipenko <digetx@gmail.com>2017-12-28 16:38:27 +0300
commitd4cc5f199c730c064f9d2725d862984e5768b90a (patch)
treec32092c7d921a791d258e1b050e8b9c938c7cfe9
parent3fbb7186859307f8a5508d89a7c16e216b814747 (diff)
Harden refcounts
All known (by me) VDPAU users aren't doing weird things like free-during-use, but VDPAU doc explicitly require to be safe.
-rw-r--r--src/decoder.c51
-rw-r--r--src/presentation_queue.c100
-rw-r--r--src/surface.c7
-rw-r--r--src/surface_bitmap.c13
-rw-r--r--src/surface_mixer.c81
-rw-r--r--src/surface_output.c43
-rw-r--r--src/surface_video.c34
-rw-r--r--src/vdpau_tegra.c122
-rw-r--r--src/vdpau_tegra.h65
9 files changed, 413 insertions, 103 deletions
diff --git a/src/decoder.c b/src/decoder.c
index 8b043df..dd990e1 100644
--- a/src/decoder.c
+++ b/src/decoder.c
@@ -207,6 +207,7 @@ static int get_refs_sorted(struct tegra_vde_h264_frame *dpb_frames,
if (list_head == NULL) {
list_head = &nodes[i];
+ put_surface(surf);
continue;
}
@@ -250,6 +251,8 @@ insert_node:
nodes[i].next = itr;
break;
}
+
+ put_surface(surf);
}
assert(refs_num != 0);
@@ -291,6 +294,8 @@ static int get_refs_dpb_order(struct tegra_vde_h264_frame *dpb_frames,
}
dpb_frames[1 + refs_num++] = *surf->frame;
+
+ put_surface(surf);
}
assert(refs_num != 0);
@@ -486,13 +491,14 @@ VdpStatus vdp_decoder_create(VdpDevice device,
case VDP_DECODER_PROFILE_H264_HIGH: /* MPlayer compatibility */
break;
default:
+ put_device(dev);
return VDP_STATUS_INVALID_DECODER_PROFILE;
}
pthread_mutex_lock(&global_lock);
for (i = 0; i < MAX_DECODERS_NB; i++) {
- dec = get_decoder(i);
+ dec = __get_decoder(i);
if (dec == NULL) {
dec = calloc(1, sizeof(tegra_decoder));
@@ -504,9 +510,12 @@ VdpStatus vdp_decoder_create(VdpDevice device,
pthread_mutex_unlock(&global_lock);
if (i == MAX_SURFACES_NB || dec == NULL) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
+ atomic_set(&dec->refcnt, 1);
+ ref_device(dev);
dec->dev = dev;
dec->width = ALIGN(width, 16);
dec->height = ALIGN(height, 16);
@@ -514,6 +523,25 @@ VdpStatus vdp_decoder_create(VdpDevice device,
*decoder = i;
+ put_device(dev);
+
+ return VDP_STATUS_OK;
+}
+
+void ref_decoder(tegra_decoder *dec)
+{
+ atomic_inc(&dec->refcnt);
+}
+
+VdpStatus unref_decoder(tegra_decoder *dec)
+{
+ if (!atomic_dec_and_test(&dec->refcnt)) {
+ return VDP_STATUS_OK;
+ }
+
+ unref_device(dec->dev);
+ free(dec);
+
return VDP_STATUS_OK;
}
@@ -526,7 +554,9 @@ VdpStatus vdp_decoder_destroy(VdpDecoder decoder)
}
set_decoder(decoder, NULL);
- free(dec);
+ put_decoder(dec);
+
+ unref_decoder(dec);
return VDP_STATUS_OK;
}
@@ -551,13 +581,15 @@ VdpStatus vdp_decoder_render(VdpDecoder decoder,
VdpBitstreamBuffer const *bufs)
{
tegra_decoder *dec = get_decoder(decoder);
- tegra_surface *surf = get_surface(target);
+ tegra_surface *orig, *surf = get_surface(target);
struct drm_tegra_bo *bitstream_bo;
bitstream_reader bitstream_reader;
int bitstream_data_fd;
VdpStatus ret;
if (dec == NULL || surf == NULL) {
+ put_surface(surf);
+ put_decoder(dec);
return VDP_STATUS_INVALID_HANDLE;
}
@@ -566,22 +598,35 @@ VdpStatus vdp_decoder_render(VdpDecoder decoder,
&bitstream_reader);
if (ret != VDP_STATUS_OK) {
+ put_surface(surf);
+ put_decoder(dec);
return ret;
}
+ orig = surf;
surf = shared_surface_swap_video(surf);
+ if (surf != orig) {
+ put_surface(orig);
+ ref_surface(surf);
+ }
+
ret = tegra_decode_h264(dec, surf, picture_info,
bitstream_data_fd, &bitstream_reader);
free_data(bitstream_bo, bitstream_data_fd);
if (ret != VDP_STATUS_OK) {
+ put_surface(surf);
+ put_decoder(dec);
return ret;
}
surf->flags |= SURFACE_YUV_UNCONVERTED;
surf->flags |= SURFACE_DATA_NEEDS_SYNC;
+ put_surface(surf);
+ put_decoder(dec);
+
return VDP_STATUS_OK;
}
diff --git a/src/presentation_queue.c b/src/presentation_queue.c
index 19fb167..9fbb9fd 100644
--- a/src/presentation_queue.c
+++ b/src/presentation_queue.c
@@ -175,6 +175,11 @@ del_surface:
return NULL;
}
+void ref_queue_target(tegra_pqt *pqt)
+{
+ atomic_inc(&pqt->refcnt);
+}
+
VdpStatus unref_queue_target(tegra_pqt *pqt)
{
tegra_device *dev = pqt->dev;
@@ -185,6 +190,7 @@ VdpStatus unref_queue_target(tegra_pqt *pqt)
if (pqt->gc != None)
XFreeGC(dev->display, pqt->gc);
+ unref_device(dev);
free(pqt);
return VDP_STATUS_OK;
@@ -201,7 +207,9 @@ VdpStatus vdp_presentation_queue_target_destroy(
set_presentation_queue_target(presentation_queue_target, NULL);
- return unref_queue_target(pqt);
+ put_queue_target(pqt);
+
+ return VDP_STATUS_OK;
}
VdpStatus vdp_presentation_queue_create(
@@ -218,13 +226,15 @@ VdpStatus vdp_presentation_queue_create(
int ret;
if (dev == NULL || pqt == NULL) {
+ put_device(dev);
+ put_queue_target(pqt);
return VDP_STATUS_INVALID_HANDLE;
}
pthread_mutex_lock(&global_lock);
for (i = 0; i < MAX_PRESENTATION_QUEUES_NB; i++) {
- pq = get_presentation_queue(i);
+ pq = __get_presentation_queue(i);
if (pq == NULL) {
pq = calloc(1, sizeof(tegra_pq));
@@ -236,12 +246,16 @@ VdpStatus vdp_presentation_queue_create(
pthread_mutex_unlock(&global_lock);
if (i == MAX_PRESENTATION_QUEUES_NB || pq == NULL) {
+ put_device(dev);
+ put_queue_target(pqt);
return VDP_STATUS_RESOURCES;
}
ret = pthread_mutex_init(&pq->lock, NULL);
if (ret != 0) {
ErrorMsg("pthread_mutex_init failed\n");
+ put_device(dev);
+ put_queue_target(pqt);
return VDP_STATUS_RESOURCES;
}
@@ -251,12 +265,15 @@ VdpStatus vdp_presentation_queue_create(
ret = pthread_cond_init(&pq->cond, &cond_attrs);
if (ret != 0) {
ErrorMsg("pthread_cond_init failed\n");
+ put_device(dev);
+ put_queue_target(pqt);
return VDP_STATUS_RESOURCES;
}
pthread_condattr_destroy(&cond_attrs);
LIST_INITHEAD(&pq->surf_list);
+ atomic_set(&pq->refcnt, 1);
pq->pqt = pqt;
pthread_attr_init(&thread_attrs);
@@ -266,40 +283,45 @@ VdpStatus vdp_presentation_queue_create(
presentation_queue_thr, pq);
if (ret != 0) {
ErrorMsg("pthread_create failed\n");
+ put_device(dev);
+ put_queue_target(pqt);
return VDP_STATUS_RESOURCES;
}
pthread_attr_destroy(&thread_attrs);
- atomic_inc(&pqt->refcnt);
+ ref_queue_target(pqt);
ref_device(dev);
*presentation_queue = i;
+ put_device(dev);
+ put_queue_target(pqt);
+
return VDP_STATUS_OK;
}
-VdpStatus vdp_presentation_queue_destroy(
- VdpPresentationQueue presentation_queue)
+void ref_presentation_queue(tegra_pq *pq)
+{
+ atomic_inc(&pq->refcnt);
+}
+
+VdpStatus unref_presentation_queue(tegra_pq *pq)
{
- tegra_pq *pq = get_presentation_queue(presentation_queue);
- tegra_pqt *pqt;
tegra_device *dev;
+ tegra_pqt *pqt;
- if (pq == NULL) {
- return VDP_STATUS_INVALID_HANDLE;
- }
+ if (!atomic_dec_and_test(&pq->refcnt))
+ return VDP_STATUS_OK;
pqt = pq->pqt;
dev = pqt->dev;
- set_presentation_queue(presentation_queue, NULL);
-
pthread_mutex_lock(&pq->lock);
-
pq->exit = true;
pthread_cond_signal(&pq->cond);
pthread_mutex_unlock(&pq->lock);
+
pthread_join(pq->disp_thread, NULL);
unref_queue_target(pqt);
@@ -309,6 +331,21 @@ VdpStatus vdp_presentation_queue_destroy(
return VDP_STATUS_OK;
}
+VdpStatus vdp_presentation_queue_destroy(
+ VdpPresentationQueue presentation_queue)
+{
+ tegra_pq *pq = get_presentation_queue(presentation_queue);
+
+ if (pq == NULL) {
+ return VDP_STATUS_INVALID_HANDLE;
+ }
+
+ set_presentation_queue(presentation_queue, NULL);
+ put_presentation_queue(pq);
+
+ return VDP_STATUS_OK;
+}
+
VdpStatus vdp_presentation_queue_set_background_color(
VdpPresentationQueue presentation_queue,
VdpColor *const background_color)
@@ -319,6 +356,8 @@ VdpStatus vdp_presentation_queue_set_background_color(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -332,6 +371,8 @@ VdpStatus vdp_presentation_queue_get_background_color(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -347,6 +388,8 @@ VdpStatus vdp_presentation_queue_get_time(
*current_time = get_time();
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -357,8 +400,8 @@ VdpStatus vdp_presentation_queue_display(
uint32_t clip_height,
VdpTime earliest_presentation_time)
{
- tegra_surface *surf = get_surface(surface);
tegra_pq *pq = get_presentation_queue(presentation_queue);
+ tegra_surface *surf;
tegra_pqt *pqt;
VdpTime time;
@@ -368,8 +411,9 @@ VdpStatus vdp_presentation_queue_display(
pqt = pq->pqt;
- /* This will happen on surface allocation failure. */
+ surf = get_surface(surface);
if (surf == NULL) {
+ /* This will happen on surface allocation failure. */
time = get_time();
if (earliest_presentation_time > time) {
@@ -383,6 +427,8 @@ VdpStatus vdp_presentation_queue_display(
pthread_cond_signal(&pq->cond);
pthread_mutex_unlock(&pq->lock);
+ put_presentation_queue(pq);
+
return VDP_STATUS_RESOURCES;
}
@@ -405,6 +451,9 @@ VdpStatus vdp_presentation_queue_display(
pthread_mutex_unlock(&surf->lock);
pthread_mutex_unlock(&pq->lock);
+ put_surface(surf);
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -418,6 +467,9 @@ VdpStatus vdp_presentation_queue_display(
pthread_cond_signal(&pq->cond);
pthread_mutex_unlock(&pq->lock);
+ put_surface(surf);
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -431,12 +483,12 @@ VdpStatus vdp_presentation_queue_block_until_surface_idle(
VdpStatus ret = VDP_STATUS_ERROR;
if (surf == NULL || pq == NULL) {
+ put_surface(surf);
+ put_presentation_queue(pq);
*first_presentation_time = get_time();
return VDP_STATUS_INVALID_HANDLE;
}
- ref_surface(surf);
-
pthread_mutex_lock(&surf->lock);
if (surf->idle_hack ||
@@ -463,7 +515,8 @@ VdpStatus vdp_presentation_queue_block_until_surface_idle(
unlock:
pthread_mutex_unlock(&surf->lock);
- unref_surface(surf);
+ put_surface(surf);
+ put_presentation_queue(pq);
return ret;
}
@@ -478,6 +531,8 @@ VdpStatus vdp_presentation_queue_query_surface_status(
tegra_pq *pq = get_presentation_queue(presentation_queue);
if (surf == NULL || pq == NULL) {
+ put_surface(surf);
+ put_presentation_queue(pq);
*first_presentation_time = get_time();
return VDP_STATUS_INVALID_HANDLE;
}
@@ -485,6 +540,9 @@ VdpStatus vdp_presentation_queue_query_surface_status(
*status = surf->status;
*first_presentation_time = surf->first_presentation_time;
+ put_surface(surf);
+ put_presentation_queue(pq);
+
return VDP_STATUS_OK;
}
@@ -505,7 +563,7 @@ VdpStatus vdp_presentation_queue_target_create_x11(
pthread_mutex_lock(&global_lock);
for (i = 0; i < MAX_PRESENTATION_QUEUE_TARGETS_NB; i++) {
- pqt = get_presentation_queue_target(i);
+ pqt = __get_presentation_queue_target(i);
if (pqt == NULL) {
pqt = calloc(1, sizeof(tegra_pqt));
@@ -517,10 +575,12 @@ VdpStatus vdp_presentation_queue_target_create_x11(
pthread_mutex_unlock(&global_lock);
if (i == MAX_PRESENTATION_QUEUE_TARGETS_NB || pqt == NULL) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
atomic_set(&pqt->refcnt, 1);
+ ref_device(dev);
pqt->dev = dev;
pqt->drawable = drawable;
pqt->gc = XCreateGC(dev->display, drawable, 0, &values);
@@ -530,5 +590,7 @@ VdpStatus vdp_presentation_queue_target_create_x11(
*target = i;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
diff --git a/src/surface.c b/src/surface.c
index 4a4ae1e..5ab6a9c 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -24,7 +24,7 @@ static uint32_t get_unused_surface_id(void)
uint32_t id;
for (id = 0; id < MAX_SURFACES_NB; id++) {
- if (get_surface(id) == NULL) {
+ if (__get_surface(id) == NULL) {
break;
}
}
@@ -454,6 +454,7 @@ VdpStatus unref_surface(tegra_surface *surf)
unref_device(surf->dev);
pthread_mutex_unlock(&surf->lock);
+ set_surface(surf->surface_id, NULL);
free(surf->frame);
free(surf);
@@ -466,7 +467,9 @@ VdpStatus destroy_surface(tegra_surface *surf)
surf->earliest_presentation_time = 0;
pthread_mutex_unlock(&surf->lock);
- return unref_surface(surf);
+ unref_surface(surf);
+
+ return VDP_STATUS_OK;
}
int sync_video_frame_dmabufs(tegra_surface *surf, enum frame_sync type)
diff --git a/src/surface_bitmap.c b/src/surface_bitmap.c
index bcb0249..d7f573b 100644
--- a/src/surface_bitmap.c
+++ b/src/surface_bitmap.c
@@ -45,6 +45,8 @@ VdpStatus vdp_bitmap_surface_query_capabilities(
*max_width = INT_MAX;
*max_height = INT_MAX;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -65,15 +67,19 @@ VdpStatus vdp_bitmap_surface_create(VdpDevice device,
case VDP_RGBA_FORMAT_B8G8R8A8:
break;
default:
+ put_device(dev);
return VDP_STATUS_INVALID_RGBA_FORMAT;
}
*surface = create_surface(dev, width, height, rgba_format, 0, 0);
if (*surface == VDP_INVALID_HANDLE) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -85,7 +91,7 @@ VdpStatus vdp_bitmap_surface_destroy(VdpBitmapSurface surface)
return VDP_INVALID_HANDLE;
}
- set_surface(surface, NULL);
+ put_surface(surf);
return destroy_surface(surf);
}
@@ -106,6 +112,8 @@ VdpStatus vdp_bitmap_surface_get_parameters(VdpBitmapSurface surface,
*height = surf->height;
*frequently_accessed = VDP_FALSE;
+ put_surface(surf);
+
return VDP_STATUS_OK;
}
@@ -133,6 +141,7 @@ VdpStatus vdp_bitmap_surface_put_bits_native(VdpBitmapSurface surface,
err = shared_surface_transfer_video(surf);
if (err) {
pthread_mutex_unlock(&surf->lock);
+ put_surface(surf);
return err;
}
@@ -171,5 +180,7 @@ VdpStatus vdp_bitmap_surface_put_bits_native(VdpBitmapSurface surface,
pthread_mutex_unlock(&surf->lock);
+ put_surface(surf);
+
return VDP_STATUS_OK;
}
diff --git a/src/surface_mixer.c b/src/surface_mixer.c
index 20a02a7..b8aa5fc 100644
--- a/src/surface_mixer.c
+++ b/src/surface_mixer.c
@@ -69,6 +69,8 @@ VdpStatus vdp_video_mixer_query_feature_support(VdpDevice device,
return VDP_STATUS_INVALID_HANDLE;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -96,6 +98,8 @@ VdpStatus vdp_video_mixer_query_parameter_support(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -121,6 +125,8 @@ VdpStatus vdp_video_mixer_query_attribute_support(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -151,9 +157,12 @@ VdpStatus vdp_video_mixer_query_parameter_value_range(
*(uint32_t *)max_value = INT_MAX;
break;
default:
+ put_device(dev);
return VDP_STATUS_ERROR;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -186,9 +195,12 @@ VdpStatus vdp_video_mixer_query_attribute_value_range(
*(uint8_t *)max_value = 1;
break;
default:
+ put_device(dev);
return VDP_STATUS_ERROR;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -216,6 +228,7 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
const VdpChromaType *chromatype = parameter_values[parameter_count];
if (*chromatype != VDP_CHROMA_TYPE_420) {
+ put_device(dev);
return VDP_STATUS_ERROR;
}
break;
@@ -228,7 +241,7 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
pthread_mutex_lock(&global_lock);
for (i = 0; i < MAX_MIXERS_NB; i++) {
- mix = get_mixer(i);
+ mix = __get_mixer(i);
if (mix == NULL) {
mix = calloc(1, sizeof(tegra_mixer));
@@ -240,6 +253,7 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
pthread_mutex_unlock(&global_lock);
if (i == MAX_MIXERS_NB || mix == NULL) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
@@ -247,10 +261,11 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
if (ret != 0) {
free(mix);
set_mixer(i, NULL);
- ErrorMsg("pthread_mutex_init failed\n");
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
+ atomic_set(&mix->refcnt, 1);
ref_device(dev);
mix->dev = dev;
@@ -258,6 +273,25 @@ VdpStatus vdp_video_mixer_create(VdpDevice device,
*mixer = i;
+ put_device(dev);
+
+ return VDP_STATUS_OK;
+}
+
+void ref_mixer(tegra_mixer *mix)
+{
+ atomic_inc(&mix->refcnt);
+}
+
+VdpStatus unref_mixer(tegra_mixer *mix)
+{
+ if (!atomic_dec_and_test(&mix->refcnt)) {
+ return VDP_STATUS_OK;
+ }
+
+ unref_device(mix->dev);
+ free(mix);
+
return VDP_STATUS_OK;
}
@@ -273,6 +307,8 @@ VdpStatus vdp_video_mixer_set_feature_enables(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_mixer(mix);
+
return VDP_STATUS_OK;
}
@@ -306,6 +342,8 @@ VdpStatus vdp_video_mixer_set_attribute_values(
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+
return VDP_STATUS_OK;
}
@@ -325,6 +363,8 @@ VdpStatus vdp_video_mixer_get_feature_support(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_mixer(mix);
+
return VDP_STATUS_ERROR;
}
@@ -340,6 +380,8 @@ VdpStatus vdp_video_mixer_get_feature_enables(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_mixer(mix);
+
return VDP_STATUS_ERROR;
}
@@ -355,6 +397,8 @@ VdpStatus vdp_video_mixer_get_parameter_values(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_mixer(mix);
+
return VDP_STATUS_ERROR;
}
@@ -370,6 +414,8 @@ VdpStatus vdp_video_mixer_get_attribute_values(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_mixer(mix);
+
return VDP_STATUS_ERROR;
}
@@ -382,11 +428,9 @@ VdpStatus vdp_video_mixer_destroy(VdpVideoMixer mixer)
}
set_mixer(mixer, NULL);
+ put_mixer(mix);
- unref_device(mix->dev);
- free(mix);
-
- return VDP_STATUS_OK;
+ return unref_mixer(mix);
}
VdpStatus vdp_video_mixer_render(
@@ -419,6 +463,10 @@ VdpStatus vdp_video_mixer_render(
int ret;
if (dest_surf == NULL || mix == NULL) {
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
return VDP_STATUS_INVALID_HANDLE;
}
@@ -494,6 +542,10 @@ VdpStatus vdp_video_mixer_render(
if (ret) {
pthread_mutex_unlock(&dest_surf->lock);
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
return VDP_STATUS_RESOURCES;
}
@@ -518,6 +570,10 @@ VdpStatus vdp_video_mixer_render(
if (ret) {
pthread_mutex_unlock(&dest_surf->lock);
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
return VDP_STATUS_RESOURCES;
}
@@ -551,6 +607,10 @@ VdpStatus vdp_video_mixer_render(
if (ret) {
pthread_mutex_unlock(&dest_surf->lock);
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
return VDP_STATUS_RESOURCES;
}
@@ -586,6 +646,10 @@ VdpStatus vdp_video_mixer_render(
if (layers[layer_count].struct_version != VDP_LAYER_VERSION) {
pthread_mutex_unlock(&dest_surf->lock);
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
return VDP_STATUS_INVALID_STRUCT_VERSION;
}
@@ -602,5 +666,10 @@ VdpStatus vdp_video_mixer_render(
pthread_mutex_unlock(&dest_surf->lock);
pthread_mutex_unlock(&mix->lock);
+ put_mixer(mix);
+ put_surface(bg_surf);
+ put_surface(dest_surf);
+ put_surface(video_surf);
+
return VDP_STATUS_OK;
}
diff --git a/src/surface_output.c b/src/surface_output.c
index 516061d..77344c2 100644
--- a/src/surface_output.c
+++ b/src/surface_output.c
@@ -46,6 +46,8 @@ VdpStatus vdp_output_surface_query_get_put_bits_native_capabilities(
*is_supported = VDP_FALSE;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -64,6 +66,8 @@ VdpStatus vdp_output_surface_query_put_bits_indexed_capabilities(
*is_supported = VDP_FALSE;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -81,6 +85,8 @@ VdpStatus vdp_output_surface_query_put_bits_y_cb_cr_capabilities(
*is_supported = VDP_FALSE;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -100,15 +106,19 @@ VdpStatus vdp_output_surface_create(VdpDevice device,
case VDP_RGBA_FORMAT_B8G8R8A8:
break;
default:
+ put_device(dev);
return VDP_STATUS_INVALID_RGBA_FORMAT;
}
*surface = create_surface(dev, width, height, rgba_format, 1, 0);
if (*surface == VDP_INVALID_HANDLE) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -121,13 +131,8 @@ VdpStatus vdp_output_surface_get_parameters(VdpOutputSurface surface,
VdpRGBAFormat *rgba_format,
uint32_t *width, uint32_t *height)
{
- tegra_surface *surf = get_surface(surface);
VdpBool stub;
- if (surf == NULL) {
- return VDP_STATUS_INVALID_HANDLE;
- }
-
return vdp_bitmap_surface_get_parameters(surface, rgba_format,
width, height, &stub);
}
@@ -143,6 +148,8 @@ VdpStatus vdp_output_surface_get_bits_native(VdpOutputSurface surface,
return VDP_STATUS_INVALID_HANDLE;
}
+ put_surface(surf);
+
return VDP_STATUS_NO_IMPLEMENTATION;
}
@@ -170,6 +177,8 @@ VdpStatus vdp_output_surface_put_bits_indexed(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_surface(surf);
+
return VDP_STATUS_NO_IMPLEMENTATION;
}
@@ -187,6 +196,8 @@ VdpStatus vdp_output_surface_put_bits_y_cb_cr(
return VDP_STATUS_INVALID_HANDLE;
}
+ put_surface(surf);
+
return VDP_STATUS_NO_IMPLEMENTATION;
}
@@ -200,7 +211,7 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
uint32_t flags)
{
tegra_surface *dst_surf = get_surface(destination_surface);
- tegra_surface *src_surf;
+ tegra_surface *src_surf = get_surface(source_surface);
pixman_image_t *src_pix;
pixman_image_t *dst_pix;
pixman_format_code_t pfmt;
@@ -214,20 +225,22 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
int need_rotate = 0;
int ret;
- if (dst_surf == NULL) {
+ if (dst_surf == NULL || src_surf == NULL) {
+ put_surface(dst_surf);
+ put_surface(src_surf);
return VDP_STATUS_INVALID_HANDLE;
}
assert(dst_surf->idle_hack ||
dst_surf->status == VDP_PRESENTATION_QUEUE_STATUS_IDLE);
- src_surf = get_surface(source_surface);
-
pthread_mutex_lock(&src_surf->lock);
ret = shared_surface_transfer_video(dst_surf);
if (ret) {
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
return VDP_STATUS_RESOURCES;
}
@@ -259,6 +272,8 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
dst_width, dst_height);
if (ret == 0) {
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
return VDP_STATUS_OK;
}
@@ -273,12 +288,17 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
+
return VDP_STATUS_OK;
}
if (blend_state != NULL) {
if (blend_state->struct_version != VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION) {
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
return VDP_STATUS_INVALID_STRUCT_VERSION;
}
}
@@ -328,6 +348,8 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
dst_x0, dst_y0,
dst_width, dst_height);
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
return VDP_STATUS_OK;
}
@@ -383,6 +405,9 @@ VdpStatus vdp_output_surface_render_bitmap_surface(
pthread_mutex_unlock(&src_surf->lock);
+ put_surface(dst_surf);
+ put_surface(src_surf);
+
return VDP_STATUS_OK;
}
diff --git a/src/surface_video.c b/src/surface_video.c
index 9397314..2f03d1c 100644
--- a/src/surface_video.c
+++ b/src/surface_video.c
@@ -36,6 +36,8 @@ VdpStatus vdp_video_surface_query_capabilities(
*max_width = INT_MAX;
*max_height = INT_MAX;
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -53,6 +55,8 @@ VdpStatus vdp_video_surface_query_get_put_bits_y_cb_cr_capabilities(
*is_supported = (bits_ycbcr_format == VDP_YCBCR_FORMAT_YV12);
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -68,15 +72,19 @@ VdpStatus vdp_video_surface_create(VdpDevice device,
}
if (chroma_type != VDP_CHROMA_TYPE_420) {
+ put_device(dev);
return VDP_STATUS_INVALID_CHROMA_TYPE;
}
*surface = create_surface(dev, width, height, ~0, 0, 1);
if (*surface == VDP_INVALID_HANDLE) {
+ put_device(dev);
return VDP_STATUS_RESOURCES;
}
+ put_device(dev);
+
return VDP_STATUS_OK;
}
@@ -89,7 +97,7 @@ VdpStatus vdp_video_surface_get_parameters(VdpVideoSurface surface,
VdpChromaType *chroma_type,
uint32_t *width, uint32_t *height)
{
- tegra_surface *surf = get_surface_ref(surface);
+ tegra_surface *surf = get_surface(surface);
if (surf == NULL) {
return VDP_STATUS_INVALID_HANDLE;
@@ -109,7 +117,7 @@ VdpStatus vdp_video_surface_get_parameters(VdpVideoSurface surface,
*height = surf->height;
}
- unref_surface(surf);
+ put_surface(surf);
return VDP_STATUS_OK;
}
@@ -120,7 +128,7 @@ VdpStatus vdp_video_surface_get_bits_y_cb_cr(
void *const *destination_data,
uint32_t const *destination_pitches)
{
- tegra_surface *surf = get_surface_ref(surface);
+ tegra_surface *surf = get_surface(surface);
void *dst_y = destination_data[0];
void *dst_cr = destination_data[1];
void *dst_cb = destination_data[2];
@@ -140,7 +148,7 @@ VdpStatus vdp_video_surface_get_bits_y_cb_cr(
break;
default:
pthread_mutex_unlock(&surf->lock);
- unref_surface(surf);
+ put_surface(surf);
return VDP_STATUS_NO_IMPLEMENTATION;
}
@@ -148,7 +156,7 @@ VdpStatus vdp_video_surface_get_bits_y_cb_cr(
if (ret) {
pthread_mutex_unlock(&surf->lock);
- unref_surface(surf);
+ put_surface(surf);
return ret;
}
@@ -186,14 +194,14 @@ VdpStatus vdp_video_surface_get_bits_y_cb_cr(
if (ret) {
pthread_mutex_unlock(&surf->lock);
- unref_surface(surf);
+ put_surface(surf);
return ret;
}
surf->flags &= ~SURFACE_DATA_NEEDS_SYNC;
pthread_mutex_unlock(&surf->lock);
- unref_surface(surf);
+ put_surface(surf);
return VDP_STATUS_OK;
}
@@ -204,7 +212,7 @@ VdpStatus vdp_video_surface_put_bits_y_cb_cr(
void const *const *source_data,
uint32_t const *source_pitches)
{
- tegra_surface *surf, *orig = get_surface_ref(surface);
+ tegra_surface *surf, *orig = get_surface(surface);
void *src_y = (void *)source_data[0];
void *src_cr = (void *)source_data[1];
void *src_cb = (void *)source_data[2];
@@ -221,21 +229,21 @@ VdpStatus vdp_video_surface_put_bits_y_cb_cr(
case VDP_YCBCR_FORMAT_YV12:
break;
default:
- unref_surface(orig);
+ put_surface(orig);
return VDP_STATUS_NO_IMPLEMENTATION;
}
surf = shared_surface_swap_video(orig);
if (orig != surf) {
- unref_surface(orig);
+ put_surface(orig);
ref_surface(surf);
}
ret = sync_video_frame_dmabufs(surf, WRITE_START);
if (ret) {
- unref_surface(surf);
+ put_surface(surf);
return ret;
}
@@ -274,14 +282,14 @@ VdpStatus vdp_video_surface_put_bits_y_cb_cr(
ret = sync_video_frame_dmabufs(surf, WRITE_END);
if (ret) {
- unref_surface(surf);
+ put_surface(surf);
return ret;
}
surf->flags &= ~SURFACE_DATA_NEEDS_SYNC;
surf->flags |= SURFACE_YUV_UNCONVERTED;
- unref_surface(surf);
+ put_surface(surf);
return VDP_STATUS_OK;
}
diff --git a/src/vdpau_tegra.c b/src/vdpau_tegra.c
index e0e0ef3..762f78f 100644
--- a/src/vdpau_tegra.c
+++ b/src/vdpau_tegra.c
@@ -40,23 +40,53 @@ VdpCSCMatrix CSC_BT_709 = {
{ 1.164384f, 2.112402f, 0.000000f },
};
+tegra_decoder * __get_decoder(VdpDecoder decoder)
+{
+ if (decoder >= MAX_DECODERS_NB) {
+ return NULL;
+ }
+
+ return tegra_decoders[decoder];
+}
+
tegra_device * get_device(VdpDevice device)
{
- if (device >= MAX_DEVICES_NB ) {
+ tegra_device *dev = NULL;
+
+ pthread_mutex_lock(&global_lock);
+
+ if (device < MAX_DEVICES_NB) {
+ dev = tegra_devices[device];
+
+ if (dev) {
+ atomic_inc(&dev->refcnt);
+ }
+ } else {
ErrorMsg("Invalid handle %u\n", device);
- return NULL;
}
- return tegra_devices[device];
+ pthread_mutex_unlock(&global_lock);
+
+ return dev;
}
tegra_decoder * get_decoder(VdpDecoder decoder)
{
- if (decoder >= MAX_DECODERS_NB) {
- return NULL;
+ tegra_decoder *dec = NULL;
+
+ pthread_mutex_lock(&global_lock);
+
+ if (decoder < MAX_DECODERS_NB) {
+ dec = tegra_decoders[decoder];
+
+ if (dec) {
+ atomic_inc(&dec->refcnt);
+ }
}
- return tegra_decoders[decoder];
+ pthread_mutex_unlock(&global_lock);
+
+ return dec;
}
void set_decoder(VdpDecoder decoder, tegra_decoder *dec)
@@ -72,7 +102,7 @@ void set_decoder(VdpDecoder decoder, tegra_decoder *dec)
tegra_decoders[decoder] = dec;
}
-tegra_mixer * get_mixer(VdpVideoMixer mixer)
+tegra_mixer * __get_mixer(VdpVideoMixer mixer)
{
if (mixer >= MAX_MIXERS_NB) {
return NULL;
@@ -81,6 +111,25 @@ tegra_mixer * get_mixer(VdpVideoMixer mixer)
return tegra_mixers[mixer];
}
+tegra_mixer * get_mixer(VdpVideoMixer mixer)
+{
+ tegra_mixer *mix = NULL;
+
+ pthread_mutex_lock(&global_lock);
+
+ if (mixer < MAX_MIXERS_NB) {
+ mix = tegra_mixers[mixer];
+
+ if (mix) {
+ atomic_inc(&mix->refcnt);
+ }
+ }
+
+ pthread_mutex_unlock(&global_lock);
+
+ return mix;
+}
+
void set_mixer(VdpVideoMixer mixer, tegra_mixer *mix)
{
if (mixer >= MAX_MIXERS_NB) {
@@ -94,7 +143,7 @@ void set_mixer(VdpVideoMixer mixer, tegra_mixer *mix)
tegra_mixers[mixer] = mix;
}
-tegra_surface * get_surface(VdpBitmapSurface surface)
+tegra_surface * __get_surface(VdpBitmapSurface surface)
{
if (surface >= MAX_SURFACES_NB) {
return NULL;
@@ -103,15 +152,18 @@ tegra_surface * get_surface(VdpBitmapSurface surface)
return tegra_surfaces[surface];
}
-tegra_surface * get_surface_ref(VdpBitmapSurface surface)
+tegra_surface * get_surface(VdpBitmapSurface surface)
{
- tegra_surface *surf;
+ tegra_surface *surf = NULL;
pthread_mutex_lock(&global_lock);
- surf = get_surface(surface);
- if (surf) {
- ref_surface(surf);
+ if (surface < MAX_SURFACES_NB) {
+ surf = tegra_surfaces[surface];
+
+ if (surf) {
+ atomic_inc(&surf->refcnt);
+ }
}
pthread_mutex_unlock(&global_lock);
@@ -141,12 +193,13 @@ 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;
}
}
-tegra_pqt * get_presentation_queue_target(VdpPresentationQueueTarget target)
+tegra_pqt * __get_presentation_queue_target(VdpPresentationQueueTarget target)
{
if (target >= MAX_PRESENTATION_QUEUE_TARGETS_NB) {
return NULL;
@@ -155,6 +208,25 @@ tegra_pqt * get_presentation_queue_target(VdpPresentationQueueTarget target)
return tegra_pqts[target];
}
+tegra_pqt * get_presentation_queue_target(VdpPresentationQueueTarget target)
+{
+ tegra_pqt *pqt = NULL;
+
+ pthread_mutex_lock(&global_lock);
+
+ if (target < MAX_PRESENTATION_QUEUE_TARGETS_NB) {
+ pqt = tegra_pqts[target];
+
+ if (pqt) {
+ atomic_inc(&pqt->refcnt);
+ }
+ }
+
+ pthread_mutex_unlock(&global_lock);
+
+ return pqt;
+}
+
void set_presentation_queue_target(VdpPresentationQueueTarget target,
tegra_pqt *pqt)
{
@@ -169,7 +241,7 @@ void set_presentation_queue_target(VdpPresentationQueueTarget target,
tegra_pqts[target] = pqt;
}
-tegra_pq * get_presentation_queue(VdpPresentationQueue presentation_queue)
+tegra_pq * __get_presentation_queue(VdpPresentationQueue presentation_queue)
{
if (presentation_queue >= MAX_PRESENTATION_QUEUES_NB) {
return NULL;
@@ -178,6 +250,25 @@ tegra_pq * get_presentation_queue(VdpPresentationQueue presentation_queue)
return tegra_pqs[presentation_queue];
}
+tegra_pq * get_presentation_queue(VdpPresentationQueue presentation_queue)
+{
+ tegra_pq *pq = NULL;
+
+ pthread_mutex_lock(&global_lock);
+
+ if (presentation_queue < MAX_PRESENTATION_QUEUES_NB) {
+ pq = tegra_pqs[presentation_queue];
+
+ if (pq) {
+ atomic_inc(&pq->refcnt);
+ }
+ }
+
+ pthread_mutex_unlock(&global_lock);
+
+ return pq;
+}
+
void set_presentation_queue(VdpPresentationQueue presentation_queue,
tegra_pq *pq)
{
@@ -435,6 +526,7 @@ VdpStatus vdp_device_destroy(VdpDevice device)
}
tegra_devices[device] = NULL;
+ put_device(dev);
return unref_device(dev);
}
diff --git a/src/vdpau_tegra.h b/src/vdpau_tegra.h
index b53bbfc..af95802 100644
--- a/src/vdpau_tegra.h
+++ b/src/vdpau_tegra.h
@@ -191,6 +191,7 @@ typedef struct tegra_surface {
typedef struct tegra_decoder {
tegra_device *dev;
+ atomic_t refcnt;
int is_baseline_profile;
uint32_t width;
uint32_t height;
@@ -199,6 +200,7 @@ typedef struct tegra_decoder {
typedef struct tegra_mixer {
struct host1x_csc_params csc;
pthread_mutex_t lock;
+ atomic_t refcnt;
VdpColor bg_color;
tegra_device *dev;
bool custom_csc;
@@ -219,73 +221,71 @@ typedef struct tegra_pq {
pthread_mutex_t lock;
pthread_cond_t cond;
pthread_t disp_thread;
+ atomic_t refcnt;
bool exit;
} tegra_pq;
tegra_device * get_device(VdpDevice device);
-
void ref_device(tegra_device *dev);
-
VdpStatus unref_device(tegra_device *dev);
+#define put_device(__dev) ({ if (__dev) unref_device(__dev); })
+tegra_decoder * __get_decoder(VdpDecoder decoder);
tegra_decoder * get_decoder(VdpDecoder decoder);
-
+void ref_decoder(tegra_decoder *dec);
+VdpStatus unref_decoder(tegra_decoder *dec);
+#define put_decoder(__dec) ({ if (__dec) unref_decoder(__dec); })
void set_decoder(VdpDecoder decoder, tegra_decoder *dec);
+tegra_mixer * __get_mixer(VdpVideoMixer mixer);
tegra_mixer * get_mixer(VdpVideoMixer mixer);
-
+void ref_mixer(tegra_mixer *mix);
+VdpStatus unref_mixer(tegra_mixer *mix);
+#define put_mixer(__mix) ({ if (__mix) unref_mixer(__mix); })
void set_mixer(VdpVideoMixer mixer, tegra_mixer *mix);
+tegra_surface * __get_surface(VdpBitmapSurface surface);
tegra_surface * get_surface(VdpBitmapSurface surface);
-
-tegra_surface * get_surface_ref(VdpBitmapSurface surface);
-
+void ref_surface(tegra_surface *surf);
+VdpStatus unref_surface(tegra_surface *surf);
+#define put_surface(__surf) ({ if (__surf) unref_surface(__surf); })
void set_surface(VdpBitmapSurface surface, tegra_surface *surf);
-
void replace_surface(tegra_surface *old_surf, tegra_surface *new_surf);
-
-tegra_pqt * get_presentation_queue_target(VdpPresentationQueueTarget target);
-
-void set_presentation_queue_target(VdpPresentationQueueTarget target,
- tegra_pqt *pqt);
-
-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,
VdpRGBAFormat rgba_format,
int output,
int video);
-
tegra_surface *alloc_surface(tegra_device *dev,
uint32_t width, uint32_t height,
VdpRGBAFormat rgba_format,
int output, int video);
-
VdpStatus destroy_surface(tegra_surface *surf);
-void ref_surface(tegra_surface *surf);
+tegra_pqt * __get_presentation_queue_target(VdpPresentationQueueTarget target);
+tegra_pqt * get_presentation_queue_target(VdpPresentationQueueTarget target);
+void ref_queue_target(tegra_pqt *pqt);
+VdpStatus unref_queue_target(tegra_pqt *pqt);
+#define put_queue_target(__pqt) ({ if (__pqt) unref_queue_target(__pqt); })
+void set_presentation_queue_target(VdpPresentationQueueTarget target,
+ tegra_pqt *pqt);
-VdpStatus unref_surface(tegra_surface *surf);
+tegra_pq * __get_presentation_queue(VdpPresentationQueue presentation_queue);
+tegra_pq * get_presentation_queue(VdpPresentationQueue presentation_queue);
+void ref_presentation_queue(tegra_pq *pq);
+VdpStatus unref_presentation_queue(tegra_pq *pq);
+#define put_presentation_queue(__pq) ({ if (__pq) unref_presentation_queue(__pq); })
+void set_presentation_queue(VdpPresentationQueue presentation_queue,
+ tegra_pq *pq);
int sync_dmabuf_write_start(int dmabuf_fd);
-
int sync_dmabuf_write_end(int dmabuf_fd);
-
int sync_dmabuf_read_start(int dmabuf_fd);
-
int sync_dmabuf_read_end(int dmabuf_fd);
enum frame_sync {
@@ -308,15 +308,10 @@ tegra_shared_surface *create_shared_surface(tegra_surface *disp,
uint32_t dst_y0,
uint32_t dst_width,
uint32_t dst_height);
-
void ref_shared_surface(tegra_shared_surface *shared);
-
void unref_shared_surface(tegra_shared_surface *shared);
-
tegra_surface * shared_surface_swap_video(tegra_surface *old);
-
int shared_surface_transfer_video(tegra_surface *disp);
-
void shared_surface_kill_disp(tegra_surface *disp);
VdpGetErrorString vdp_get_error_string;