VdpStatus softVdpPresentationQueueTargetDestroy(VdpPresentationQueueTarget presentation_queue_target) { VdpPresentationQueueTargetData *pqTargetData = handle_acquire(presentation_queue_target, HANDLETYPE_PRESENTATION_QUEUE_TARGET); if (NULL == pqTargetData) return VDP_STATUS_INVALID_HANDLE; VdpDeviceData *deviceData = pqTargetData->device; if (0 != pqTargetData->refcount) { traceError("warning (softVdpPresentationQueueTargetDestroy): non-zero reference" "count (%d)\n", pqTargetData->refcount); handle_release(presentation_queue_target); return VDP_STATUS_ERROR; } // drawable may be destroyed already, so one should activate global context glx_context_push_thread_local(deviceData); glXDestroyContext(deviceData->display, pqTargetData->glc); GLenum gl_error = glGetError(); glx_context_pop(); if (GL_NO_ERROR != gl_error) { traceError("error (VdpPresentationQueueTargetDestroy): gl error %d\n", gl_error); handle_release(presentation_queue_target); return VDP_STATUS_ERROR; } deviceData->refcount --; handle_expunge(presentation_queue_target); free(pqTargetData); return VDP_STATUS_OK; }
VdpStatus vdpVideoSurfaceDestroy(VdpVideoSurface surface) { VdpVideoSurfaceData *videoSurfData = handle_acquire(surface, HANDLETYPE_VIDEO_SURFACE); if (NULL == videoSurfData) return VDP_STATUS_INVALID_HANDLE; VdpDeviceData *deviceData = videoSurfData->deviceData; glx_ctx_push_thread_local(deviceData); glDeleteTextures(1, &videoSurfData->tex_id); GLenum gl_error = glGetError(); glx_ctx_pop(); if (GL_NO_ERROR != gl_error) { traceError("error (%s): gl error %d\n", __func__, gl_error); handle_release(surface); return VDP_STATUS_ERROR; } if (deviceData->va_available) { // return VA surface to the free list if (videoSurfData->decoder != VDP_INVALID_HANDLE) { VdpDecoderData *dd = handle_acquire(videoSurfData->decoder, HANDLETYPE_DECODER); if (NULL != dd) { free_list_push(dd->free_list, &dd->free_list_head, videoSurfData->rt_idx); handle_release(videoSurfData->decoder); } } // .va_surf will be freed in VdpDecoderDestroy } if (videoSurfData->y_plane) free(videoSurfData->y_plane); if (videoSurfData->u_plane) free(videoSurfData->u_plane); // do not free videoSurfData->v_plane, it's just pointer into the middle of u_plane unref_device(deviceData); handle_expunge(surface); free(videoSurfData); return VDP_STATUS_OK; }
VdpStatus softVdpDecoderDestroy(VdpDecoder decoder) { VdpDecoderData *decoderData = handle_acquire(decoder, HANDLETYPE_DECODER); if (NULL == decoderData) return VDP_STATUS_INVALID_HANDLE; VdpDeviceData *deviceData = decoderData->device; if (deviceData->va_available) { VADisplay va_dpy = deviceData->va_dpy; vaDestroySurfaces(va_dpy, decoderData->render_targets, decoderData->num_render_targets); vaDestroyContext(va_dpy, decoderData->context_id); vaDestroyConfig(va_dpy, decoderData->config_id); } handle_expunge(decoder); deviceData->refcount --; free(decoderData); return VDP_STATUS_OK; }
VdpStatus softVdpPresentationQueueDestroy(VdpPresentationQueue presentation_queue) { VdpPresentationQueueData *pqData = handle_acquire(presentation_queue, HANDLETYPE_PRESENTATION_QUEUE); if (NULL == pqData) return VDP_STATUS_INVALID_HANDLE; pthread_cancel(pqData->worker_thread); if (0 != pthread_join(pqData->worker_thread, NULL)) { traceError("VdpPresentationQueueDestroy: failed to stop worker thread"); handle_release(presentation_queue); return VDP_STATUS_ERROR; } handle_expunge(presentation_queue); pqData->device->refcount --; pqData->target->refcount --; free(pqData); return VDP_STATUS_OK; }
VdpStatus vdpDeviceDestroy(VdpDevice device) { VdpStatus err_code; VdpDeviceData *data = handle_acquire(device, HANDLETYPE_DEVICE); if (NULL == data) return VDP_STATUS_INVALID_HANDLE; if (0 != data->refcount) { // Buggy client forgot to destroy dependend objects or decided that destroying // VdpDevice destroys all child object. Let's try to mitigate and prevent leakage. traceError("warning (%s): non-zero reference count (%d). Trying to free child objects.\n", __func__, data->refcount); void *parent_object = data; handle_execute_for_all(destroy_child_objects, parent_object); } if (0 != data->refcount) { traceError("error (%s): still non-zero reference count (%d)\n", __func__, data->refcount); traceError("Here is the list of objects:\n"); struct { int cnt; int total_cnt; VdpDeviceData *deviceData; } state = { .cnt = 0, .total_cnt = 0, .deviceData = data }; handle_execute_for_all(print_handle_type, &state); traceError("Objects leaked: %d\n", state.cnt); traceError("Objects visited during scan: %d\n", state.total_cnt); err_code = VDP_STATUS_ERROR; goto quit; } // cleaup libva if (data->va_available) vaTerminate(data->va_dpy); glx_ctx_push_thread_local(data); glDeleteTextures(1, &data->watermark_tex_id); glBindFramebuffer(GL_FRAMEBUFFER, 0); destroy_shaders(data); glx_ctx_pop(); glx_ctx_lock(); glXMakeCurrent(data->display, None, NULL); glx_ctx_unlock(); glx_ctx_unref_glc_hash_table(data->display); handle_xdpy_unref(data->display_orig); handle_expunge(device); pthread_mutex_destroy(&data->refcount_mutex); free(data); GLenum gl_error = glGetError(); if (GL_NO_ERROR != gl_error) { traceError("error (%s): gl error %d\n", __func__, gl_error); err_code = VDP_STATUS_ERROR; goto quit_skip_release; } return VDP_STATUS_OK; quit: handle_release(device); quit_skip_release: return err_code; }