diff options
author | Dmitry Osipenko <digetx@gmail.com> | 2017-12-28 15:56:34 +0300 |
---|---|---|
committer | Dmitry Osipenko <digetx@gmail.com> | 2017-12-28 16:38:27 +0300 |
commit | d4cc5f199c730c064f9d2725d862984e5768b90a (patch) | |
tree | c32092c7d921a791d258e1b050e8b9c938c7cfe9 | |
parent | 3fbb7186859307f8a5508d89a7c16e216b814747 (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.c | 51 | ||||
-rw-r--r-- | src/presentation_queue.c | 100 | ||||
-rw-r--r-- | src/surface.c | 7 | ||||
-rw-r--r-- | src/surface_bitmap.c | 13 | ||||
-rw-r--r-- | src/surface_mixer.c | 81 | ||||
-rw-r--r-- | src/surface_output.c | 43 | ||||
-rw-r--r-- | src/surface_video.c | 34 | ||||
-rw-r--r-- | src/vdpau_tegra.c | 122 | ||||
-rw-r--r-- | src/vdpau_tegra.h | 65 |
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; |