Exemple #1
0
INT CmSurfaceManager::DestroySurfaceInPool(UINT & freeSurfNum,
					   SURFACE_DESTROY_KIND destroyKind)
{
	CmSurface *pSurface = NULL;
	CmBuffer_RT *pSurf1D = NULL;
	CmSurface2D *pSurf2D = NULL;
	CmSurface2DUP *pSurf2DUP = NULL;
	INT status = CM_FAILURE;
	UINT index = m_pCmDevice->ValidSurfaceIndexStart();

	freeSurfNum = 0;

	while (index < m_SurfaceArraySize) {
		pSurface = m_SurfaceArray[index];
		if (!pSurface) {
			index++;
			continue;
		}

		status = CM_FAILURE;

		switch (pSurface->Type()) {
		case CM_ENUM_CLASS_TYPE_CMSURFACE2D:
			pSurf2D = static_cast < CmSurface2D * >(pSurface);
			if (pSurf2D) {
				status = DestroySurface(pSurf2D, destroyKind);
			}
			break;

		case CM_ENUM_CLASS_TYPE_CMBUFFER_RT:
			pSurf1D = static_cast < CmBuffer_RT * >(pSurface);
			if (pSurf1D) {
				status = DestroySurface(pSurf1D, destroyKind);
			}
			break;

		case CM_ENUM_CLASS_TYPE_CMSURFACE2DUP:
			pSurf2DUP = static_cast < CmSurface2DUP * >(pSurface);
			if (pSurf2DUP) {
				status = DestroySurface(pSurf2DUP, destroyKind);
			}
			break;

		default:
			CM_ASSERT(0);
			break;
		}

		if (status == CM_SUCCESS) {
			freeSurfNum++;
		}
		index++;
	}

	return CM_SUCCESS;
}
Exemple #2
0
SwapChain::~SwapChain()
{
  DestroySwapChainImages();
  DestroySwapChain();
  DestroyRenderPass();
  DestroySurface();
}
Exemple #3
0
static void Close(vlc_va_t *va, AVCodecContext *avctx)
{
    vlc_va_sys_t *sys = va->sys;

    for (unsigned i = 0; sys->pool[i] != NULL; i++)
        DestroySurface(sys->pool[i]);
    vdp_release_x11(sys->vdp);
    av_freep(&avctx->hwaccel_context);
    free(sys);
}
Exemple #4
0
INT CmSurfaceManager::DestroySurfaceArrayElement(UINT index)
{
	UINT i = index;

	if (i >= m_SurfaceArraySize)
		return CM_FAILURE;

	CmSurface *pSurface = m_SurfaceArray[i];

	if (pSurface) {
		CmSurface2D *pSurf2D = NULL;
		CmBuffer_RT *pSurf1D = NULL;
		CmSurface2DUP *pSurf2DUP = NULL;

		switch (pSurface->Type()) {
		case CM_ENUM_CLASS_TYPE_CMSURFACE2D:
			pSurf2D = static_cast < CmSurface2D * >(pSurface);
			if (pSurf2D) {
				DestroySurface(pSurf2D, FORCE_DESTROY);
			}
			break;

		case CM_ENUM_CLASS_TYPE_CMBUFFER_RT:
			pSurf1D = static_cast < CmBuffer_RT * >(pSurface);
			if (pSurf1D) {
				DestroySurface(pSurf1D, FORCE_DESTROY);
			}
			break;

		case CM_ENUM_CLASS_TYPE_CMSURFACE2DUP:
			pSurf2DUP = static_cast < CmSurface2DUP * >(pSurface);
			if (pSurf2DUP) {
				DestroySurface(pSurf2DUP, FORCE_DESTROY);
			}
			break;
		default:
			break;
		}
	}

	return CM_SUCCESS;
}
Exemple #5
0
void AndroidEGL::Terminate()
{
	ResetDisplay();
	DestroyContext(PImplData->SharedContext.eglContext);
	PImplData->SharedContext.Reset();
	DestroyContext(PImplData->RenderingContext.eglContext);
	PImplData->RenderingContext.Reset();
	DestroyContext(PImplData->SingleThreadedContext.eglContext);
	PImplData->SingleThreadedContext.Reset();
	DestroySurface();
	TerminateEGL();
}
Exemple #6
0
void cxAndroid::DestroyDisplay()
{
    DestroySurface();
    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    if(context != EGL_NO_CONTEXT){
        eglDestroyContext(display, context);
        context = EGL_NO_CONTEXT;
    }
    if(display != EGL_NO_DISPLAY){
        eglTerminate(display);
        display = EGL_NO_DISPLAY;
    }
}
		SDL_Texture* SDLUtilityTool::LoadImageTexture(const char* file, SDL_Renderer* renderer)
		{
			g_assert(m_initialized);
			SDL_Surface* imageSurface = LoadImageSurface(file);
			g_assert(imageSurface != nullptr);
			SDL_Texture* imageTexture = SDL_CreateTextureFromSurface(renderer, imageSurface);
			LogSDLError();
			g_assert(imageTexture != nullptr);
			DestroySurface(imageSurface);
			LogSDLError();
			m_sdlTextures++;
			m_totalResources++;
			return imageTexture;
		}
Exemple #8
0
bool SwapChain::RecreateSurface(void* native_handle)
{
  // Destroy the old swap chain, images, and surface.
  DestroyRenderPass();
  DestroySwapChainImages();
  DestroySwapChain();
  DestroySurface();

  // Re-create the surface with the new native handle
  m_native_handle = native_handle;
  m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), native_handle);
  if (m_surface == VK_NULL_HANDLE)
    return false;

  // Finally re-create the swap chain
  if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateRenderPass())
    return false;

  return true;
}
WindowEGLImpl::~WindowEGLImpl()
{
	DestroySurface();
	DeinitEGL();
}
Exemple #10
0
/*
 * InternalSurfaceRelease
 *
 * Done with a surface.	  if no one else is using it, then we can free it.
 * Also called by ProcessSurfaceCleanup, EnumSurfaces and DD_Release.
 *
 * Assumes the lock is taken on the driver.
 */
DWORD InternalSurfaceRelease( LPDDRAWI_DDRAWSURFACE_INT this_int )
{
    LPDDRAWI_DDRAWSURFACE_LCL	this_lcl;
    LPDDRAWI_DDRAWSURFACE_GBL	this;
    LPATTACHLIST		pattachlist;
    DWORD			intrefcnt;
    DWORD			lclrefcnt;
    DWORD			gblrefcnt;
    DWORD			pid;
    LPDDRAWI_DIRECTDRAW_LCL	pdrv_lcl;
    LPDDRAWI_DIRECTDRAW_GBL 	pdrv;
    BOOL			root_object_deleted;
    BOOL			do_free;
    DWORD                       caps;

    this_lcl = this_int->lpLcl;
    this = this_lcl->lpGbl;

    /*
     * check owner of surface
     */
    pid = GETCURRPID();
    /*
     * don't allow someone to free an implicitly created surface
     */
    if( (this->dwRefCnt == 1) && (this_lcl->dwFlags & DDRAWISURF_IMPLICITCREATE) )
    {
	DPF_ERR( "Cannot free an implicitly created surface" );
	return 0;
    }

    /*
     * remove locks taken on this surface by the current process
     */
    pdrv_lcl = this_lcl->lpSurfMore->lpDD_lcl;
    pdrv = pdrv_lcl->lpGbl;
    if( (this_lcl->dwLocalRefCnt & ~OBJECT_ISROOT) == 1 )
    {
	RemoveProcessLocks( pdrv_lcl, this, pid );
    }

    /*
     * decrement the reference count.  if it hits zero, free the surface
     */
    this->dwRefCnt--;
    gblrefcnt = this->dwRefCnt;
    this_lcl->dwLocalRefCnt--;
    lclrefcnt = this_lcl->dwLocalRefCnt & ~OBJECT_ISROOT;
    this_int->dwIntRefCnt--;
    intrefcnt = this_int->dwIntRefCnt;

    DPF( 4, "DD_Surface_Release, Reference Count: Global = %ld Local = %ld Int = %ld",
         gblrefcnt, lclrefcnt, intrefcnt );

    /*
     * local object at zero?
     */
    root_object_deleted = FALSE;
    if( lclrefcnt == 0 )
    {
	LPDDRAWI_DDRAWSURFACE_INT	curr_int;
	LPDDRAWI_DDRAWSURFACE_LCL	curr_lcl;
	LPDDRAWI_DDRAWSURFACE_GBL	curr;
	DWORD				refcnt;

	/*
	 * see if we are deleting the root object
	 */
	if( this_lcl->dwLocalRefCnt & OBJECT_ISROOT )
	{
	    root_object_deleted = TRUE;
	}


	/*
	 * reset if primary surface is the one being released
	 */
	if( this_lcl->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE )
	{

	    /*
	     * restore GDI stuff if this is the GDI driver
	     */
	    if( pdrv->dwFlags & DDRAWI_DISPLAYDRV )
	    {
		if( !SURFACE_LOST( this_lcl ) )
		{
		    DPF( 2, "Resetting primary surface");
	
		    /*
		     * flip to the original primary surface if not emulated
		     */
		    if( !(this_lcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
			!(this->dwGlobalFlags & DDRAWISURFGBL_ISGDISURFACE)) //pdrv->fpPrimaryOrig != this->fpVidMem) )
		    {
			FlipToGDISurface( pdrv_lcl, this_int ); //, pdrv->fpPrimaryOrig );
		    }
		}
    
		/*
		 * Cause the GDI surface to be redrawn if the mode was ever changed.
		 */
                if (pdrv_lcl->dwLocalFlags & DDRAWILCL_MODEHASBEENCHANGED)
         		RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
				 RDW_ALLCHILDREN );
	    }
	}

	/*
	 * if an overlay, remove surface from the overlay Z order list
	 */
	if( this_lcl->ddsCaps.dwCaps & DDSCAPS_OVERLAY )
	{
	    // Remove surface from doubly linked list
	    this_lcl->dbnOverlayNode.prev->next = this_lcl->dbnOverlayNode.next;
	    this_lcl->dbnOverlayNode.next->prev = this_lcl->dbnOverlayNode.prev;

            // If this surface is overlaying an emulated surface, we must notify
            // the HEL that it needs to eventually update the part of the surface
            // touched by this overlay.
            if( this_lcl->lpSurfaceOverlaying != NULL )
            {
        	// We have a pointer to the surface being overlayed, check to 
        	// see if it is being emulated.
        	if( this_lcl->lpSurfaceOverlaying->lpLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY )
        	{
        	    // Mark the destination region of this overlay as dirty.
        	    DD_Surface_AddOverlayDirtyRect(
        		(LPDIRECTDRAWSURFACE)(this_lcl->lpSurfaceOverlaying),
			&(this_lcl->rcOverlayDest) );
        	}
		DD_Surface_Release( 
		    (LPDIRECTDRAWSURFACE)(this_lcl->lpSurfaceOverlaying) );
            }
	}

	/*
	 * hide a hardware overlay...
	 */
	if( (this_lcl->ddsCaps.dwCaps & DDSCAPS_OVERLAY) &&
	    (this_lcl->ddsCaps.dwCaps & DDSCAPS_VISIBLE) &&
	    (this_lcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) )
	{
	    LPDDHALSURFCB_UPDATEOVERLAY	uohalfn;
	    LPDDHALSURFCB_UPDATEOVERLAY	uofn;
	    DWORD			rc;
	    DDHAL_UPDATEOVERLAYDATA	uod;

	    uofn = pdrv_lcl->lpDDCB->HALDDSurface.UpdateOverlay;
	    uohalfn = pdrv_lcl->lpDDCB->cbDDSurfaceCallbacks.UpdateOverlay;
	    if( (uohalfn != NULL) && (NULL != this_lcl->lpSurfaceOverlaying) )
	    {
		DPF( 2, "Turning off hardware overlay" );
		uod.UpdateOverlay = uohalfn;
		uod.lpDD = pdrv;
		uod.lpDDSrcSurface = this_lcl;
		uod.lpDDDestSurface = this_lcl->lpSurfaceOverlaying->lpLcl;
		uod.dwFlags = DDOVER_HIDE;
		DOHALCALL( UpdateOverlay, uofn, uod, rc, FALSE );
	    }
	}

	/*
	 * release all implicitly created attached surfaces
	 */
	pattachlist = GetAttachList( this_lcl );
	this_lcl->dwFlags |= DDRAWISURF_ISFREE;
	while( pattachlist != NULL )
	{
	    BOOL    was_implicit;
	    /*
	     * break all attachments
	     */
	    curr_int = pattachlist->lpIAttached;
	    if( pattachlist->dwFlags & DDAL_IMPLICIT )
		was_implicit = TRUE;
	    else
		was_implicit = FALSE;

	    DPF(3, "Deleting attachment from %08lx to %08lx (implicit = %d)", 
		curr_int, this_int, was_implicit);
       	    DeleteOneAttachment( this_int, curr_int, TRUE, DOA_DELETEIMPLICIT );
	    // If the attachment was not implicit then curr_int may possibly have 
	    // been destroyed as a result of DeleteOneAttachment.
	    if( was_implicit )
	    {
		curr_lcl = curr_int->lpLcl;
		curr = curr_lcl->lpGbl;

		/*
		 * release an implicitly created surface
		 */
		if( !(curr_lcl->dwFlags & DDRAWISURF_ISFREE) )
		{
		    if( curr_lcl->dwFlags & DDRAWISURF_IMPLICITCREATE )
		    {
			refcnt = curr_int->dwIntRefCnt;
			curr_lcl->dwFlags &= ~DDRAWISURF_IMPLICITCREATE;
			while( refcnt > 0 )
			{
			    InternalSurfaceRelease( curr_int );
			    refcnt--;
			}
		    }
		}
	    }
	    /*
	     * start again at the beginning of the list because
	     * DeleteOneAttachment may have modified the attachment list.
	     * HACKHACK:  this fn call is needed to get around a compiler bug
	     */
	    pattachlist = GetAttachList( this_lcl );
	}

        /*
         * Free the nodes in the IUnknown list and release all the interfaces.
         */
	FreeIUnknowns( this_lcl, TRUE );

        /*
	 * If a palette is attached to this surface remove it (and, as a
	 * side effect, release it).
	 */
	if( this_lcl->lpDDPalette )
	    DD_Surface_SetPalette( (LPDIRECTDRAWSURFACE) this_int, NULL );

        /*
         * Release the attached clipper (if any).
         */
        if( this_lcl->lpSurfMore->lpDDIClipper )
            DD_Clipper_Release( (LPDIRECTDRAWCLIPPER)this_lcl->lpSurfMore->lpDDIClipper );

	/*
	 * remove all attachments to us from other surfaces
	 */
	pattachlist = this_lcl->lpAttachListFrom;
	while( pattachlist != NULL )
	{
	    curr_int = pattachlist->lpIAttached;
	    DPF( 3, "Deleting attachment from %08lx", curr_int );
	    DeleteOneAttachment( curr_int, this_int, TRUE, DOA_DELETEIMPLICIT );
	    /*
	     * start again at the beginning of the list because
	     * DeleteOneAttachment may have modified the attachment list.
	     * HACKHACK:  this fn call is needed to get around a compiler bug
	     */
	    pattachlist = GetAttachListFrom( this_lcl );
	}
	this_lcl->dwFlags &= ~DDRAWISURF_ISFREE;
    }

    /*
     * root object at zero?
     */
    do_free = FALSE;
    if( gblrefcnt == 0 )
    {
	/*
	 * get rid of all memory associated with this surface
	 */
	DestroySurface( this_lcl );

	this_lcl->dwFlags |= DDRAWISURF_INVALID;
	do_free = TRUE;

	/*
	 * if this was the final delete, but this wasn't the root object,
	 * then we need to delete the dangling object
	 */
	if( !root_object_deleted )
	{
	    LPDDRAWI_DDRAWSURFACE_LCL	root_lcl;

	    /*
	     * Get the start of the root global data object.  Since the
	     * global data always follows the local data, we just need
	     * to back up the size of the local data to get the start of
	     * the allocated block.
	     *
	     * NOTE: The local surface allocation now includes the
	     * additional local surface structure (DDRAWI_DDRAWSURFACE_MORE).
	     * So we need to back up by the size of that structure also.
	     *
	     * Since all duplicated surfaces have the same local data,
	     * we just need to test this surface for overlay data to determine
	     * if the root object had overlay data.
	     */
	    if( this_lcl->dwFlags & DDRAWISURF_HASOVERLAYDATA )
	    {
		root_lcl = (LPVOID) (((LPSTR) this) - ( sizeof( DDRAWI_DDRAWSURFACE_LCL ) +
		                                        sizeof( DDRAWI_DDRAWSURFACE_MORE ) ) );
	    }
	    else
	    {
		root_lcl = (LPVOID) (((LPSTR) this) - ( offsetof( DDRAWI_DDRAWSURFACE_LCL, ddckCKSrcOverlay ) +
							sizeof( DDRAWI_DDRAWSURFACE_MORE ) ) );
	    }
	    MemFree( root_lcl );
	}
    }
    else if( lclrefcnt == 0 )
    {
	/*
	 * only remove the object if it wasn't the root.   if it
	 * was the root, we must leave it dangling until the last
	 * object referencing it goes away.
	 */
	if( !root_object_deleted )
	{
	    do_free = TRUE;
	}
    }

    caps = this_lcl->ddsCaps.dwCaps;
    /*
     * If we are releasing an interface to a primary surface, update the pointer to the primary 
     * surface stored in the local driver object.  If another interface to the primary surface exists, 
     * store that one.  Otherwise, set the pointer to NULL.
     */
    if( intrefcnt == 0 )
    {
	if( caps & DDSCAPS_PRIMARYSURFACE )
	{
	    if( this_lcl->lpSurfMore->lpDD_lcl )
	    {
		this_lcl->lpSurfMore->lpDD_lcl->lpPrimary = findOtherInterface(this_int, this_lcl, pdrv);
	    }
	}
#ifdef SHAREDZ
	if( caps & DDSCAPS_SHAREDBACKBUFFER )
	{
	    if( this_lcl->lpSurfMore->lpDD_lcl )
	    {
		this_lcl->lpSurfMore->lpDD_lcl->lpSharedBack = findOtherInterface(this_int, this_lcl, pdrv);
	    }
	}
	if( caps & DDSCAPS_SHAREDZBUFFER )
	{
	    if( this_lcl->lpSurfMore->lpDD_lcl )
	    {
		this_lcl->lpSurfMore->lpDD_lcl->lpSharedZ = findOtherInterface(this_int, this_lcl, pdrv);
	    }
	}
#endif
    }

    /*
     * free the object if needed
     */
    if( do_free )
    {
	this_lcl->lpGbl = NULL;

        #ifdef WINNT
        /*
         * Free the associated NT kernel-mode object only if it is a vram surface, it is not
	 * an execute buffer, and it has not yet been freed in the kernel
         */
        if (!(caps & (DDSCAPS_EXECUTEBUFFER|DDSCAPS_SYSTEMMEMORY) ) && this_lcl->hDDSurface )
        {
            DPF(9,"Deleting NT kernel-mode object handle %08x",this_lcl->hDDSurface);
            if (!DdDeleteSurfaceObject(this_lcl))
                DPF(9,"DdDeleteSurfaceObject failed");
        }
        #endif
	MemFree( this_lcl );
    }

    /*
     * interface at zero?
     */
    if( intrefcnt == 0)
    {
	LPDDRAWI_DDRAWSURFACE_INT	curr_int;
	LPDDRAWI_DDRAWSURFACE_INT	last_int;
	/*
	 * remove surface from list of all surfaces
	 */
	curr_int = pdrv->dsList;
	last_int = NULL;
	while( curr_int != this_int )
	{
	    last_int = curr_int;
	    curr_int = curr_int->lpLink;
	    if( curr_int == NULL )
	    {
		DPF_ERR( "Surface not in list!" );
		return 0;
	    }
	}
	if( last_int == NULL )
	{
	    pdrv->dsList = pdrv->dsList->lpLink;
	}
	else
	{
	    last_int->lpLink = curr_int->lpLink;
	}

	/*
	 * just in case someone comes back in with this pointer, set
	 * an invalid vtbl & data ptr.
	 */
	this_int->lpVtbl = NULL;
	this_int->lpLcl = NULL;
	MemFree( this_int );
    }
    return intrefcnt;

} /* InternalSurfaceRelease */
Exemple #11
0
void AndroidEGL::UnBind()
{
	ResetDisplay();
	DestroySurface();
}
Exemple #12
0
void cxAndroid::onAppCmd(int8_t cmd)
{
    switch (cmd) {
        case APP_CMD_INIT_WINDOW:{
            InitSurface();
            break;
        }
        case APP_CMD_TERM_WINDOW:{
            animating = 0;
            DestroySurface();
            break;
        }
        case APP_CMD_INPUT_CHANGED:{
            break;
        }
        case APP_CMD_WINDOW_RESIZED:{
            cxEngine::Instance()->Layout(width, height);
            animating = true;
            break;
        }
        case APP_CMD_WINDOW_REDRAW_NEEDED:{
            break;
        }
        case APP_CMD_CONTENT_RECT_CHANGED:{
            break;
        }
        case APP_CMD_GAINED_FOCUS:{
            break;
        }
        case APP_CMD_LOST_FOCUS:{
            animating = false;
            break;
        }
        case APP_CMD_CONFIG_CHANGED:{
            break;
        }
        case APP_CMD_LOW_MEMORY:{
            cxEngine::Instance()->Warning();
            break;
        }
        case APP_CMD_START:{
            break;
        }
        case APP_CMD_RESUME:{
            cxEngine::Instance()->Resume();
            animating = true;
            break;
        }
        case APP_CMD_SAVE_STATE:{
            break;
        }
        case APP_CMD_PAUSE:{
            animating = false;
            cxEngine::Instance()->Pause();
            break;
        }
        case APP_CMD_STOP:{
            animating = false;
            break;
        }
        case APP_CMD_DESTROY:{
            animating = false;
            destroyReq = true;
            break;
        }
        default:{
            break;
        }
    }
}
Exemple #13
0
static int Open(vlc_va_t *va, AVCodecContext *avctx, enum PixelFormat pix_fmt,
                const es_format_t *fmt, picture_sys_t *p_sys)
{
    if (pix_fmt != AV_PIX_FMT_VDPAU)
        return VLC_EGENERIC;

    (void) fmt;
    (void) p_sys;
    void *func;
    VdpStatus err;
    VdpChromaType type;
    uint32_t width, height;

    if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height))
        return VLC_EGENERIC;

    switch (type)
    {
        case VDP_CHROMA_TYPE_420:
        case VDP_CHROMA_TYPE_422:
        case VDP_CHROMA_TYPE_444:
            break;
        default:
            msg_Err(va, "unsupported chroma type %"PRIu32, type);
            return VLC_EGENERIC;
    }

    if (!vlc_xlib_init(VLC_OBJECT(va)))
    {
        msg_Err(va, "Xlib is required for VDPAU");
        return VLC_EGENERIC;
    }

    unsigned refs = avctx->refs + 2 * avctx->thread_count + 5;
    vlc_va_sys_t *sys = malloc(sizeof (*sys)
                               + (refs + 1) * sizeof (sys->pool[0]));
    if (unlikely(sys == NULL))
       return VLC_ENOMEM;

    sys->type = type;
    sys->width = width;
    sys->height = height;

    err = vdp_get_x11(NULL, -1, &sys->vdp, &sys->device);
    if (err != VDP_STATUS_OK)
    {
        free(sys);
        return VLC_EGENERIC;
    }

    unsigned flags = AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH;

    err = vdp_get_proc_address(sys->vdp, sys->device,
                               VDP_FUNC_ID_GET_PROC_ADDRESS, &func);
    if (err != VDP_STATUS_OK)
        goto error;

    if (av_vdpau_bind_context(avctx, sys->device, func, flags))
        goto error;
    va->sys = sys;

    unsigned i = 0;
    while (i < refs)
    {
        sys->pool[i] = CreateSurface(va);
        if (sys->pool[i] == NULL)
            break;
        i++;
    }
    sys->pool[i] = NULL;

    if (i < avctx->refs + 3u)
    {
        msg_Err(va, "not enough video RAM");
        while (i > 0)
            DestroySurface(sys->pool[--i]);
        goto error;
    }

    if (i < refs)
        msg_Warn(va, "video RAM low (allocated %u of %u buffers)",
                 i, refs);

    const char *infos;
    if (vdp_get_information_string(sys->vdp, &infos) != VDP_STATUS_OK)
        infos = "VDPAU";

    va->description = infos;
    va->get = Lock;
    va->release = NULL;
    va->extract = Copy;
    return VLC_SUCCESS;

error:
    vdp_release_x11(sys->vdp);
    free(sys);
    return VLC_EGENERIC;
}