14642e01fSmrg/* 24642e01fSmrg * Copyright © 2007, 2008 Red Hat, Inc. 34642e01fSmrg * 44642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 54642e01fSmrg * copy of this software and associated documentation files (the "Soft- 64642e01fSmrg * ware"), to deal in the Software without restriction, including without 74642e01fSmrg * limitation the rights to use, copy, modify, merge, publish, distribute, 84642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the 94642e01fSmrg * Software is furnished to do so, provided that the above copyright 104642e01fSmrg * notice(s) and this permission notice appear in all copies of the Soft- 114642e01fSmrg * ware and that both the above copyright notice(s) and this permission 124642e01fSmrg * notice appear in supporting documentation. 134642e01fSmrg * 144642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 154642e01fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 164642e01fSmrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 174642e01fSmrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 184642e01fSmrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 194642e01fSmrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 204642e01fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 214642e01fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 224642e01fSmrg * MANCE OF THIS SOFTWARE. 234642e01fSmrg * 244642e01fSmrg * Except as contained in this notice, the name of a copyright holder shall 254642e01fSmrg * not be used in advertising or otherwise to promote the sale, use or 264642e01fSmrg * other dealings in this Software without prior written authorization of 274642e01fSmrg * the copyright holder. 284642e01fSmrg * 294642e01fSmrg * Authors: 304642e01fSmrg * Kristian Høgsberg (krh@redhat.com) 314642e01fSmrg */ 324642e01fSmrg 334642e01fSmrg#ifdef HAVE_XORG_CONFIG_H 344642e01fSmrg#include <xorg-config.h> 354642e01fSmrg#endif 364642e01fSmrg 376747b715Smrg#include <errno.h> 386747b715Smrg#ifdef WITH_LIBDRM 394642e01fSmrg#include <xf86drm.h> 406747b715Smrg#endif 416747b715Smrg#include "list.h" 424642e01fSmrg#include "scrnintstr.h" 434642e01fSmrg#include "windowstr.h" 446747b715Smrg#include "dixstruct.h" 454642e01fSmrg#include "dri2.h" 46f7df2e56Smrg#include "dri2int.h" 47f7df2e56Smrg#include "damage.h" 484642e01fSmrg#include "xf86.h" 494642e01fSmrg 50f7df2e56SmrgCARD8 dri2_major; /* version of DRI2 supported by DDX */ 516747b715SmrgCARD8 dri2_minor; 526747b715Smrg 53f7df2e56Smrguint32_t prime_id_allocate_bitmask; 54f7df2e56Smrg 556747b715Smrgstatic DevPrivateKeyRec dri2ScreenPrivateKeyRec; 56f7df2e56Smrg 576747b715Smrg#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec) 586747b715Smrg 596747b715Smrgstatic DevPrivateKeyRec dri2WindowPrivateKeyRec; 60f7df2e56Smrg 616747b715Smrg#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec) 626747b715Smrg 636747b715Smrgstatic DevPrivateKeyRec dri2PixmapPrivateKeyRec; 64f7df2e56Smrg 656747b715Smrg#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec) 666747b715Smrg 67f7df2e56Smrgstatic DevPrivateKeyRec dri2ClientPrivateKeyRec; 68f7df2e56Smrg 69f7df2e56Smrg#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec) 70f7df2e56Smrg 71f7df2e56Smrg#define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \ 72f7df2e56Smrg dri2ClientPrivateKey)) 73f7df2e56Smrg 74f7df2e56Smrgtypedef struct _DRI2Client { 75f7df2e56Smrg int prime_id; 76f7df2e56Smrg} DRI2ClientRec, *DRI2ClientPtr; 77f7df2e56Smrg 78f7df2e56Smrgstatic RESTYPE dri2DrawableRes; 796747b715Smrg 806747b715Smrgtypedef struct _DRI2Screen *DRI2ScreenPtr; 814642e01fSmrg 824642e01fSmrgtypedef struct _DRI2Drawable { 83f7df2e56Smrg DRI2ScreenPtr dri2_screen; 84f7df2e56Smrg DrawablePtr drawable; 85f7df2e56Smrg struct xorg_list reference_list; 86f7df2e56Smrg int width; 87f7df2e56Smrg int height; 88f7df2e56Smrg DRI2BufferPtr *buffers; 89f7df2e56Smrg int bufferCount; 90f7df2e56Smrg unsigned int swapsPending; 91f7df2e56Smrg int swap_interval; 92f7df2e56Smrg CARD64 swap_count; 93f7df2e56Smrg int64_t target_sbc; /* -1 means no SBC wait outstanding */ 94f7df2e56Smrg CARD64 last_swap_target; /* most recently queued swap target */ 95f7df2e56Smrg CARD64 last_swap_msc; /* msc at completion of most recent swap */ 96f7df2e56Smrg CARD64 last_swap_ust; /* ust at completion of most recent swap */ 97f7df2e56Smrg int swap_limit; /* for N-buffering */ 98f7df2e56Smrg unsigned blocked[3]; 99f7df2e56Smrg Bool needInvalidate; 100f7df2e56Smrg int prime_id; 1015a112b11Smrg PixmapPtr prime_secondary_pixmap; 102f7df2e56Smrg PixmapPtr redirectpixmap; 1034642e01fSmrg} DRI2DrawableRec, *DRI2DrawablePtr; 1044642e01fSmrg 1054642e01fSmrgtypedef struct _DRI2Screen { 106f7df2e56Smrg ScreenPtr screen; 107f7df2e56Smrg int refcnt; 108f7df2e56Smrg unsigned int numDrivers; 109f7df2e56Smrg const char **driverNames; 110f7df2e56Smrg const char *deviceName; 111f7df2e56Smrg int fd; 112f7df2e56Smrg unsigned int lastSequence; 113f7df2e56Smrg int prime_id; 114f7df2e56Smrg 115f7df2e56Smrg DRI2CreateBufferProcPtr CreateBuffer; 116f7df2e56Smrg DRI2DestroyBufferProcPtr DestroyBuffer; 117f7df2e56Smrg DRI2CopyRegionProcPtr CopyRegion; 118f7df2e56Smrg DRI2ScheduleSwapProcPtr ScheduleSwap; 119f7df2e56Smrg DRI2GetMSCProcPtr GetMSC; 120f7df2e56Smrg DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC; 121f7df2e56Smrg DRI2AuthMagic2ProcPtr AuthMagic; 122f7df2e56Smrg DRI2AuthMagicProcPtr LegacyAuthMagic; 123f7df2e56Smrg DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify; 124f7df2e56Smrg DRI2SwapLimitValidateProcPtr SwapLimitValidate; 125f7df2e56Smrg DRI2GetParamProcPtr GetParam; 126f7df2e56Smrg 127f7df2e56Smrg HandleExposuresProcPtr HandleExposures; 128f7df2e56Smrg 129f7df2e56Smrg ConfigNotifyProcPtr ConfigNotify; 130f7df2e56Smrg SetWindowPixmapProcPtr SetWindowPixmap; 131f7df2e56Smrg DRI2CreateBuffer2ProcPtr CreateBuffer2; 132f7df2e56Smrg DRI2DestroyBuffer2ProcPtr DestroyBuffer2; 133f7df2e56Smrg DRI2CopyRegion2ProcPtr CopyRegion2; 1346747b715Smrg} DRI2ScreenRec; 1354642e01fSmrg 136f7df2e56Smrgstatic void 137f7df2e56Smrgdestroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id); 138f7df2e56Smrg 139f7df2e56Smrgenum DRI2WakeType { 140f7df2e56Smrg WAKE_SBC, 141f7df2e56Smrg WAKE_MSC, 142f7df2e56Smrg WAKE_SWAP, 143f7df2e56Smrg}; 144f7df2e56Smrg 145f7df2e56Smrg#define Wake(c, t) (void *)((uintptr_t)(c) | (t)) 146f7df2e56Smrg 147f7df2e56Smrgstatic Bool 148f7df2e56Smrgdri2WakeClient(ClientPtr client, void *closure) 149f7df2e56Smrg{ 150f7df2e56Smrg ClientWakeup(client); 151f7df2e56Smrg return TRUE; 152f7df2e56Smrg} 153f7df2e56Smrg 154f7df2e56Smrgstatic Bool 155f7df2e56Smrgdri2WakeAll(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t) 156f7df2e56Smrg{ 157f7df2e56Smrg int count; 158f7df2e56Smrg 159f7df2e56Smrg if (!pPriv->blocked[t]) 160f7df2e56Smrg return FALSE; 161f7df2e56Smrg 162f7df2e56Smrg count = ClientSignalAll(client, dri2WakeClient, Wake(pPriv, t)); 163f7df2e56Smrg pPriv->blocked[t] -= count; 164f7df2e56Smrg return count; 165f7df2e56Smrg} 166f7df2e56Smrg 167f7df2e56Smrgstatic Bool 168f7df2e56Smrgdri2Sleep(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t) 169f7df2e56Smrg{ 170f7df2e56Smrg if (ClientSleep(client, dri2WakeClient, Wake(pPriv, t))) { 171f7df2e56Smrg pPriv->blocked[t]++; 172f7df2e56Smrg return TRUE; 173f7df2e56Smrg } 174f7df2e56Smrg return FALSE; 175f7df2e56Smrg} 176f7df2e56Smrg 1774642e01fSmrgstatic DRI2ScreenPtr 1784642e01fSmrgDRI2GetScreen(ScreenPtr pScreen) 1794642e01fSmrg{ 1804642e01fSmrg return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey); 1814642e01fSmrg} 1824642e01fSmrg 183f7df2e56Smrgstatic ScreenPtr 1845a112b11SmrgGetScreenPrime(ScreenPtr primary, int prime_id) 185f7df2e56Smrg{ 1865a112b11Smrg ScreenPtr secondary; 1877e31ba66Smrg if (prime_id == 0) { 1885a112b11Smrg return primary; 189f7df2e56Smrg } 1905a112b11Smrg xorg_list_for_each_entry(secondary, &primary->secondary_list, secondary_head) { 191f7df2e56Smrg DRI2ScreenPtr ds; 192f7df2e56Smrg 1935a112b11Smrg if (!secondary->is_offload_secondary) 1947e31ba66Smrg continue; 1957e31ba66Smrg 1965a112b11Smrg ds = DRI2GetScreen(secondary); 197f7df2e56Smrg if (ds == NULL) 198f7df2e56Smrg continue; 199f7df2e56Smrg 200f7df2e56Smrg if (ds->prime_id == prime_id) 2015a112b11Smrg return secondary; 202f7df2e56Smrg } 2035a112b11Smrg return primary; 204f7df2e56Smrg} 205f7df2e56Smrg 206f7df2e56Smrgstatic DRI2ScreenPtr 2075a112b11SmrgDRI2GetScreenPrime(ScreenPtr primary, int prime_id) 208f7df2e56Smrg{ 2095a112b11Smrg ScreenPtr secondary = GetScreenPrime(primary, prime_id); 2105a112b11Smrg return DRI2GetScreen(secondary); 211f7df2e56Smrg} 212f7df2e56Smrg 2134642e01fSmrgstatic DRI2DrawablePtr 2144642e01fSmrgDRI2GetDrawable(DrawablePtr pDraw) 2154642e01fSmrg{ 2166747b715Smrg WindowPtr pWin; 2176747b715Smrg PixmapPtr pPixmap; 2184642e01fSmrg 2196747b715Smrg switch (pDraw->type) { 2206747b715Smrg case DRAWABLE_WINDOW: 221f7df2e56Smrg pWin = (WindowPtr) pDraw; 222f7df2e56Smrg return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey); 2236747b715Smrg case DRAWABLE_PIXMAP: 224f7df2e56Smrg pPixmap = (PixmapPtr) pDraw; 225f7df2e56Smrg return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey); 2266747b715Smrg default: 227f7df2e56Smrg return NULL; 2284642e01fSmrg } 2294642e01fSmrg} 2304642e01fSmrg 2316747b715Smrgstatic DRI2DrawablePtr 2326747b715SmrgDRI2AllocateDrawable(DrawablePtr pDraw) 2336747b715Smrg{ 234f7df2e56Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 2356747b715Smrg DRI2DrawablePtr pPriv; 236f7df2e56Smrg CARD64 ust; 2376747b715Smrg WindowPtr pWin; 2386747b715Smrg PixmapPtr pPixmap; 2396747b715Smrg 2406747b715Smrg pPriv = malloc(sizeof *pPriv); 2414642e01fSmrg if (pPriv == NULL) 242f7df2e56Smrg return NULL; 2434642e01fSmrg 2446747b715Smrg pPriv->dri2_screen = ds; 2456747b715Smrg pPriv->drawable = pDraw; 2464642e01fSmrg pPriv->width = pDraw->width; 2474642e01fSmrg pPriv->height = pDraw->height; 2484642e01fSmrg pPriv->buffers = NULL; 2494642e01fSmrg pPriv->bufferCount = 0; 2506747b715Smrg pPriv->swapsPending = 0; 2516747b715Smrg pPriv->swap_count = 0; 2526747b715Smrg pPriv->target_sbc = -1; 2536747b715Smrg pPriv->swap_interval = 1; 2546747b715Smrg /* Initialize last swap target from DDX if possible */ 255f7df2e56Smrg if (!ds->GetMSC || !(*ds->GetMSC) (pDraw, &ust, &pPriv->last_swap_target)) 256f7df2e56Smrg pPriv->last_swap_target = 0; 2576747b715Smrg 258f7df2e56Smrg memset(pPriv->blocked, 0, sizeof(pPriv->blocked)); 259f7df2e56Smrg pPriv->swap_limit = 1; /* default to double buffering */ 2606747b715Smrg pPriv->last_swap_msc = 0; 2616747b715Smrg pPriv->last_swap_ust = 0; 262f7df2e56Smrg xorg_list_init(&pPriv->reference_list); 263f7df2e56Smrg pPriv->needInvalidate = FALSE; 264f7df2e56Smrg pPriv->redirectpixmap = NULL; 2655a112b11Smrg pPriv->prime_secondary_pixmap = NULL; 2666747b715Smrg if (pDraw->type == DRAWABLE_WINDOW) { 267f7df2e56Smrg pWin = (WindowPtr) pDraw; 268f7df2e56Smrg dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv); 269f7df2e56Smrg } 270f7df2e56Smrg else { 271f7df2e56Smrg pPixmap = (PixmapPtr) pDraw; 272f7df2e56Smrg dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv); 2734642e01fSmrg } 2744642e01fSmrg 2756747b715Smrg return pPriv; 2766747b715Smrg} 2776747b715Smrg 278f7df2e56SmrgBool 279f7df2e56SmrgDRI2SwapLimit(DrawablePtr pDraw, int swap_limit) 280f7df2e56Smrg{ 281f7df2e56Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 282f7df2e56Smrg DRI2ScreenPtr ds; 283f7df2e56Smrg 284f7df2e56Smrg if (!pPriv) 285f7df2e56Smrg return FALSE; 286f7df2e56Smrg 287f7df2e56Smrg ds = pPriv->dri2_screen; 288f7df2e56Smrg 289f7df2e56Smrg if (!ds->SwapLimitValidate || !ds->SwapLimitValidate(pDraw, swap_limit)) 290f7df2e56Smrg return FALSE; 291f7df2e56Smrg 292f7df2e56Smrg pPriv->swap_limit = swap_limit; 293f7df2e56Smrg 294f7df2e56Smrg /* Check throttling */ 295f7df2e56Smrg if (pPriv->swapsPending >= pPriv->swap_limit) 296f7df2e56Smrg return TRUE; 297f7df2e56Smrg 298f7df2e56Smrg dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 299f7df2e56Smrg return TRUE; 300f7df2e56Smrg} 301f7df2e56Smrg 3026747b715Smrgtypedef struct DRI2DrawableRefRec { 303f7df2e56Smrg XID id; 304f7df2e56Smrg XID dri2_id; 305f7df2e56Smrg DRI2InvalidateProcPtr invalidate; 306f7df2e56Smrg void *priv; 307f7df2e56Smrg struct xorg_list link; 3086747b715Smrg} DRI2DrawableRefRec, *DRI2DrawableRefPtr; 3096747b715Smrg 3106747b715Smrgstatic DRI2DrawableRefPtr 3116747b715SmrgDRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id) 3126747b715Smrg{ 3138794ceb6Swiz DRI2DrawableRefPtr ref = NULL; 3146747b715Smrg 315f7df2e56Smrg xorg_list_for_each_entry(ref, &pPriv->reference_list, link) { 316f7df2e56Smrg if (ref->id == id) 317f7df2e56Smrg return ref; 3186747b715Smrg } 319f7df2e56Smrg 3206747b715Smrg return NULL; 3216747b715Smrg} 3226747b715Smrg 3236747b715Smrgstatic int 3246747b715SmrgDRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id, 325f7df2e56Smrg DRI2InvalidateProcPtr invalidate, void *priv) 3266747b715Smrg{ 3276747b715Smrg DRI2DrawableRefPtr ref; 3286747b715Smrg 3296747b715Smrg ref = malloc(sizeof *ref); 3306747b715Smrg if (ref == NULL) 331f7df2e56Smrg return BadAlloc; 332f7df2e56Smrg 3339ace9065Smrg if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) { 334f7df2e56Smrg free(ref); 335f7df2e56Smrg return BadAlloc; 3369ace9065Smrg } 3376747b715Smrg if (!DRI2LookupDrawableRef(pPriv, id)) 338f7df2e56Smrg if (!AddResource(id, dri2DrawableRes, pPriv)) { 339f7df2e56Smrg FreeResourceByType(dri2_id, dri2DrawableRes, TRUE); 340f7df2e56Smrg free(ref); 341f7df2e56Smrg return BadAlloc; 3429ace9065Smrg } 3436747b715Smrg 3446747b715Smrg ref->id = id; 345f7df2e56Smrg ref->dri2_id = dri2_id; 3466747b715Smrg ref->invalidate = invalidate; 3476747b715Smrg ref->priv = priv; 348f7df2e56Smrg xorg_list_add(&ref->link, &pPriv->reference_list); 3496747b715Smrg 3506747b715Smrg return Success; 3516747b715Smrg} 3526747b715Smrg 3536747b715Smrgint 354f7df2e56SmrgDRI2CreateDrawable2(ClientPtr client, DrawablePtr pDraw, XID id, 355f7df2e56Smrg DRI2InvalidateProcPtr invalidate, void *priv, 356f7df2e56Smrg XID *dri2_id_out) 3576747b715Smrg{ 3586747b715Smrg DRI2DrawablePtr pPriv; 359d566a54bSmrg DRI2ClientPtr dri2_client; 3606747b715Smrg XID dri2_id; 3616747b715Smrg int rc; 3626747b715Smrg 363d566a54bSmrg if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 364d566a54bSmrg return BadValue; 365d566a54bSmrg 366d566a54bSmrg dri2_client = dri2ClientPrivate(client); 367d566a54bSmrg 3686747b715Smrg pPriv = DRI2GetDrawable(pDraw); 3696747b715Smrg if (pPriv == NULL) 370f7df2e56Smrg pPriv = DRI2AllocateDrawable(pDraw); 3716747b715Smrg if (pPriv == NULL) 372f7df2e56Smrg return BadAlloc; 373f7df2e56Smrg 374f7df2e56Smrg pPriv->prime_id = dri2_client->prime_id; 375f7df2e56Smrg 3766747b715Smrg dri2_id = FakeClientID(client->index); 3776747b715Smrg rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv); 3786747b715Smrg if (rc != Success) 379f7df2e56Smrg return rc; 380f7df2e56Smrg 381f7df2e56Smrg if (dri2_id_out) 382f7df2e56Smrg *dri2_id_out = dri2_id; 3836747b715Smrg 3846747b715Smrg return Success; 3856747b715Smrg} 3866747b715Smrg 387f7df2e56Smrgint 388f7df2e56SmrgDRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, 389f7df2e56Smrg DRI2InvalidateProcPtr invalidate, void *priv) 390f7df2e56Smrg{ 391f7df2e56Smrg return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL); 392f7df2e56Smrg} 393f7df2e56Smrg 394f7df2e56Smrgstatic int 395f7df2e56SmrgDRI2DrawableGone(void *p, XID id) 3966747b715Smrg{ 3976747b715Smrg DRI2DrawablePtr pPriv = p; 398f7df2e56Smrg DRI2DrawableRefPtr ref, next; 3996747b715Smrg WindowPtr pWin; 4006747b715Smrg PixmapPtr pPixmap; 4016747b715Smrg DrawablePtr pDraw; 4026747b715Smrg int i; 4036747b715Smrg 404f7df2e56Smrg xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { 405f7df2e56Smrg if (ref->dri2_id == id) { 406f7df2e56Smrg xorg_list_del(&ref->link); 407f7df2e56Smrg /* If this was the last ref under this X drawable XID, 408f7df2e56Smrg * unregister the X drawable resource. */ 409f7df2e56Smrg if (!DRI2LookupDrawableRef(pPriv, ref->id)) 410f7df2e56Smrg FreeResourceByType(ref->id, dri2DrawableRes, TRUE); 411f7df2e56Smrg free(ref); 412f7df2e56Smrg break; 413f7df2e56Smrg } 4146747b715Smrg 415f7df2e56Smrg if (ref->id == id) { 416f7df2e56Smrg xorg_list_del(&ref->link); 417f7df2e56Smrg FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE); 418f7df2e56Smrg free(ref); 419f7df2e56Smrg } 4206747b715Smrg } 4216747b715Smrg 422f7df2e56Smrg if (!xorg_list_is_empty(&pPriv->reference_list)) 423f7df2e56Smrg return Success; 4246747b715Smrg 4256747b715Smrg pDraw = pPriv->drawable; 4266747b715Smrg if (pDraw->type == DRAWABLE_WINDOW) { 427f7df2e56Smrg pWin = (WindowPtr) pDraw; 428f7df2e56Smrg dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL); 429f7df2e56Smrg } 430f7df2e56Smrg else { 431f7df2e56Smrg pPixmap = (PixmapPtr) pDraw; 432f7df2e56Smrg dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); 433f7df2e56Smrg } 434f7df2e56Smrg 4355a112b11Smrg if (pPriv->prime_secondary_pixmap) { 4365a112b11Smrg (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap); 4375a112b11Smrg (*pPriv->prime_secondary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap); 4386747b715Smrg } 4396747b715Smrg 4406747b715Smrg if (pPriv->buffers != NULL) { 441f7df2e56Smrg for (i = 0; i < pPriv->bufferCount; i++) 442f7df2e56Smrg destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id); 4436747b715Smrg 444f7df2e56Smrg free(pPriv->buffers); 4456747b715Smrg } 4466747b715Smrg 447f7df2e56Smrg if (pPriv->redirectpixmap) { 448f7df2e56Smrg (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE); 449f7df2e56Smrg (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap); 450f7df2e56Smrg } 451f7df2e56Smrg 452f7df2e56Smrg dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 453f7df2e56Smrg dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC); 454f7df2e56Smrg dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC); 455f7df2e56Smrg 4566747b715Smrg free(pPriv); 4576747b715Smrg 4584642e01fSmrg return Success; 4594642e01fSmrg} 4604642e01fSmrg 461f7df2e56Smrgstatic DRI2BufferPtr 462f7df2e56Smrgcreate_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw, 463f7df2e56Smrg unsigned int attachment, unsigned int format) 464f7df2e56Smrg{ 465f7df2e56Smrg DRI2BufferPtr buffer; 466f7df2e56Smrg if (ds->CreateBuffer2) 467f7df2e56Smrg buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen, 468f7df2e56Smrg DRI2GetDrawable(pDraw)->prime_id), 469f7df2e56Smrg pDraw, attachment, format); 470f7df2e56Smrg else 471f7df2e56Smrg buffer = (*ds->CreateBuffer)(pDraw, attachment, format); 472f7df2e56Smrg return buffer; 473f7df2e56Smrg} 474f7df2e56Smrg 475f7df2e56Smrgstatic void 476f7df2e56Smrgdestroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id) 477f7df2e56Smrg{ 478f7df2e56Smrg ScreenPtr primeScreen; 479f7df2e56Smrg DRI2ScreenPtr ds; 480f7df2e56Smrg primeScreen = GetScreenPrime(pDraw->pScreen, prime_id); 481f7df2e56Smrg ds = DRI2GetScreen(primeScreen); 482f7df2e56Smrg if (ds->DestroyBuffer2) 483f7df2e56Smrg (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer); 484f7df2e56Smrg else 485f7df2e56Smrg (*ds->DestroyBuffer)(pDraw, buffer); 486f7df2e56Smrg} 487f7df2e56Smrg 48852397711Smrgstatic int 48952397711Smrgfind_attachment(DRI2DrawablePtr pPriv, unsigned attachment) 49052397711Smrg{ 49152397711Smrg int i; 49252397711Smrg 49352397711Smrg if (pPriv->buffers == NULL) { 494f7df2e56Smrg return -1; 49552397711Smrg } 49652397711Smrg 49752397711Smrg for (i = 0; i < pPriv->bufferCount; i++) { 498f7df2e56Smrg if ((pPriv->buffers[i] != NULL) 499f7df2e56Smrg && (pPriv->buffers[i]->attachment == attachment)) { 500f7df2e56Smrg return i; 501f7df2e56Smrg } 50252397711Smrg } 50352397711Smrg 50452397711Smrg return -1; 50552397711Smrg} 50652397711Smrg 5076747b715Smrgstatic Bool 50852397711Smrgallocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, 509f7df2e56Smrg DRI2DrawablePtr pPriv, 510f7df2e56Smrg unsigned int attachment, unsigned int format, 511f7df2e56Smrg int dimensions_match, DRI2BufferPtr * buffer) 51252397711Smrg{ 5136747b715Smrg int old_buf = find_attachment(pPriv, attachment); 51452397711Smrg 51552397711Smrg if ((old_buf < 0) 516f7df2e56Smrg || attachment == DRI2BufferFrontLeft 517f7df2e56Smrg || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) { 518f7df2e56Smrg *buffer = create_buffer(ds, pDraw, attachment, format); 519f7df2e56Smrg return TRUE; 520f7df2e56Smrg 521f7df2e56Smrg } 522f7df2e56Smrg else { 523f7df2e56Smrg *buffer = pPriv->buffers[old_buf]; 524f7df2e56Smrg 525f7df2e56Smrg if (ds->ReuseBufferNotify) 526f7df2e56Smrg (*ds->ReuseBufferNotify) (pDraw, *buffer); 5276747b715Smrg 528f7df2e56Smrg pPriv->buffers[old_buf] = NULL; 529f7df2e56Smrg return FALSE; 53052397711Smrg } 5316747b715Smrg} 5326747b715Smrg 5336747b715Smrgstatic void 5346747b715Smrgupdate_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, 535f7df2e56Smrg DRI2BufferPtr * buffers, int out_count, int *width, 536f7df2e56Smrg int *height) 5376747b715Smrg{ 5386747b715Smrg int i; 53952397711Smrg 5406747b715Smrg if (pPriv->buffers != NULL) { 541f7df2e56Smrg for (i = 0; i < pPriv->bufferCount; i++) { 542f7df2e56Smrg if (pPriv->buffers[i] != NULL) { 543f7df2e56Smrg destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id); 544f7df2e56Smrg } 545f7df2e56Smrg } 5466747b715Smrg 547f7df2e56Smrg free(pPriv->buffers); 5486747b715Smrg } 5496747b715Smrg 5506747b715Smrg pPriv->buffers = buffers; 551f7df2e56Smrg pPriv->bufferCount = out_count; 5526747b715Smrg pPriv->width = pDraw->width; 5536747b715Smrg pPriv->height = pDraw->height; 5546747b715Smrg *width = pPriv->width; 5556747b715Smrg *height = pPriv->height; 55652397711Smrg} 55752397711Smrg 5586747b715Smrgstatic DRI2BufferPtr * 55952397711Smrgdo_get_buffers(DrawablePtr pDraw, int *width, int *height, 560f7df2e56Smrg unsigned int *attachments, int count, int *out_count, 561f7df2e56Smrg int has_format) 5624642e01fSmrg{ 5634642e01fSmrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 564f7df2e56Smrg DRI2ScreenPtr ds; 565f7df2e56Smrg DRI2BufferPtr *buffers; 56652397711Smrg int need_real_front = 0; 56752397711Smrg int need_fake_front = 0; 56852397711Smrg int have_fake_front = 0; 56952397711Smrg int front_format = 0; 570b1d344b3Smrg int dimensions_match; 5716747b715Smrg int buffers_changed = 0; 57252397711Smrg int i; 57352397711Smrg 574b1d344b3Smrg if (!pPriv) { 575f7df2e56Smrg *width = pDraw->width; 576f7df2e56Smrg *height = pDraw->height; 577f7df2e56Smrg *out_count = 0; 578f7df2e56Smrg return NULL; 579b1d344b3Smrg } 580b1d344b3Smrg 581f7df2e56Smrg ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 582f7df2e56Smrg 583b1d344b3Smrg dimensions_match = (pDraw->width == pPriv->width) 584f7df2e56Smrg && (pDraw->height == pPriv->height); 5856747b715Smrg 5869ace9065Smrg buffers = calloc((count + 1), sizeof(buffers[0])); 587f7df2e56Smrg if (!buffers) 588f7df2e56Smrg goto err_out; 5896747b715Smrg 5906747b715Smrg for (i = 0; i < count; i++) { 591f7df2e56Smrg const unsigned attachment = *(attachments++); 592f7df2e56Smrg const unsigned format = (has_format) ? *(attachments++) : 0; 593f7df2e56Smrg 594f7df2e56Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, 595f7df2e56Smrg format, dimensions_match, &buffers[i])) 596f7df2e56Smrg buffers_changed = 1; 597f7df2e56Smrg 598f7df2e56Smrg if (buffers[i] == NULL) 599f7df2e56Smrg goto err_out; 600f7df2e56Smrg 601f7df2e56Smrg /* If the drawable is a window and the front-buffer is requested, 602f7df2e56Smrg * silently add the fake front-buffer to the list of requested 603f7df2e56Smrg * attachments. The counting logic in the loop accounts for the case 604f7df2e56Smrg * where the client requests both the fake and real front-buffer. 605f7df2e56Smrg */ 606f7df2e56Smrg if (attachment == DRI2BufferBackLeft) { 607f7df2e56Smrg need_real_front++; 608f7df2e56Smrg front_format = format; 609f7df2e56Smrg } 610f7df2e56Smrg 611f7df2e56Smrg if (attachment == DRI2BufferFrontLeft) { 612f7df2e56Smrg need_real_front--; 613f7df2e56Smrg front_format = format; 614f7df2e56Smrg 615f7df2e56Smrg if (pDraw->type == DRAWABLE_WINDOW) { 616f7df2e56Smrg need_fake_front++; 617f7df2e56Smrg } 618f7df2e56Smrg } 619f7df2e56Smrg 620f7df2e56Smrg if (pDraw->type == DRAWABLE_WINDOW) { 621f7df2e56Smrg if (attachment == DRI2BufferFakeFrontLeft) { 622f7df2e56Smrg need_fake_front--; 623f7df2e56Smrg have_fake_front = 1; 624f7df2e56Smrg } 625f7df2e56Smrg } 6266747b715Smrg } 62752397711Smrg 6286747b715Smrg if (need_real_front > 0) { 629f7df2e56Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft, 630f7df2e56Smrg front_format, dimensions_match, 631f7df2e56Smrg &buffers[i])) 632f7df2e56Smrg buffers_changed = 1; 633f7df2e56Smrg 634f7df2e56Smrg if (buffers[i] == NULL) 635f7df2e56Smrg goto err_out; 636f7df2e56Smrg i++; 6376747b715Smrg } 63852397711Smrg 6396747b715Smrg if (need_fake_front > 0) { 640f7df2e56Smrg if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft, 641f7df2e56Smrg front_format, dimensions_match, 642f7df2e56Smrg &buffers[i])) 643f7df2e56Smrg buffers_changed = 1; 64452397711Smrg 645f7df2e56Smrg if (buffers[i] == NULL) 646f7df2e56Smrg goto err_out; 64752397711Smrg 648f7df2e56Smrg i++; 649f7df2e56Smrg have_fake_front = 1; 6504642e01fSmrg } 6514642e01fSmrg 6526747b715Smrg *out_count = i; 65352397711Smrg 654f7df2e56Smrg update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, 655f7df2e56Smrg height); 65652397711Smrg 65752397711Smrg /* If the client is getting a fake front-buffer, pre-fill it with the 65852397711Smrg * contents of the real front-buffer. This ensures correct operation of 65952397711Smrg * applications that call glXWaitX before calling glDrawBuffer. 66052397711Smrg */ 6616747b715Smrg if (have_fake_front && buffers_changed) { 662f7df2e56Smrg BoxRec box; 663f7df2e56Smrg RegionRec region; 66452397711Smrg 665f7df2e56Smrg box.x1 = 0; 666f7df2e56Smrg box.y1 = 0; 667f7df2e56Smrg box.x2 = pPriv->width; 668f7df2e56Smrg box.y2 = pPriv->height; 669f7df2e56Smrg RegionInit(®ion, &box, 0); 67052397711Smrg 671f7df2e56Smrg DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 672f7df2e56Smrg DRI2BufferFrontLeft); 67352397711Smrg } 6744642e01fSmrg 675f7df2e56Smrg pPriv->needInvalidate = TRUE; 676f7df2e56Smrg 6774642e01fSmrg return pPriv->buffers; 6786747b715Smrg 679f7df2e56Smrg err_out: 6806747b715Smrg 6816747b715Smrg *out_count = 0; 6826747b715Smrg 683f7df2e56Smrg if (buffers) { 684f7df2e56Smrg for (i = 0; i < count; i++) { 685f7df2e56Smrg if (buffers[i] != NULL) 686f7df2e56Smrg destroy_buffer(pDraw, buffers[i], 0); 687f7df2e56Smrg } 6886747b715Smrg 689f7df2e56Smrg free(buffers); 690f7df2e56Smrg buffers = NULL; 691f7df2e56Smrg } 6926747b715Smrg 693f7df2e56Smrg update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, 694f7df2e56Smrg height); 6956747b715Smrg 6966747b715Smrg return buffers; 6974642e01fSmrg} 6984642e01fSmrg 6996747b715SmrgDRI2BufferPtr * 70052397711SmrgDRI2GetBuffers(DrawablePtr pDraw, int *width, int *height, 701f7df2e56Smrg unsigned int *attachments, int count, int *out_count) 70252397711Smrg{ 70352397711Smrg return do_get_buffers(pDraw, width, height, attachments, count, 704f7df2e56Smrg out_count, FALSE); 70552397711Smrg} 70652397711Smrg 7076747b715SmrgDRI2BufferPtr * 70852397711SmrgDRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, 709f7df2e56Smrg unsigned int *attachments, int count, int *out_count) 71052397711Smrg{ 71152397711Smrg return do_get_buffers(pDraw, width, height, attachments, count, 712f7df2e56Smrg out_count, TRUE); 71352397711Smrg} 71452397711Smrg 7156747b715Smrgstatic void 7166747b715SmrgDRI2InvalidateDrawable(DrawablePtr pDraw) 7176747b715Smrg{ 7186747b715Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 7198794ceb6Swiz DRI2DrawableRefPtr ref = NULL; 7206747b715Smrg 721f7df2e56Smrg if (!pPriv || !pPriv->needInvalidate) 7226747b715Smrg return; 7236747b715Smrg 724f7df2e56Smrg pPriv->needInvalidate = FALSE; 725f7df2e56Smrg 726f7df2e56Smrg xorg_list_for_each_entry(ref, &pPriv->reference_list, link) 727f7df2e56Smrg ref->invalidate(pDraw, ref->priv, ref->id); 7286747b715Smrg} 7296747b715Smrg 7306747b715Smrg/* 7316747b715Smrg * In the direct rendered case, we throttle the clients that have more 7326747b715Smrg * than their share of outstanding swaps (and thus busy buffers) when a 7336747b715Smrg * new GetBuffers request is received. In the AIGLX case, we allow the 7346747b715Smrg * client to get the new buffers, but throttle when the next GLX request 7356747b715Smrg * comes in (see __glXDRIcontextWait()). 7366747b715Smrg */ 7376747b715SmrgBool 7386747b715SmrgDRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) 7396747b715Smrg{ 7406747b715Smrg DRI2DrawablePtr pPriv; 7416747b715Smrg 7426747b715Smrg pPriv = DRI2GetDrawable(pDraw); 7436747b715Smrg if (pPriv == NULL) 744f7df2e56Smrg return FALSE; 7456747b715Smrg 7466747b715Smrg /* Throttle to swap limit */ 747f7df2e56Smrg if (pPriv->swapsPending >= pPriv->swap_limit) { 748f7df2e56Smrg if (dri2Sleep(client, pPriv, WAKE_SWAP)) { 749f7df2e56Smrg ResetCurrentRequest(client); 750f7df2e56Smrg client->sequence--; 751f7df2e56Smrg return TRUE; 752f7df2e56Smrg } 7536747b715Smrg } 7546747b715Smrg 7556747b715Smrg return FALSE; 7566747b715Smrg} 7576747b715Smrg 7586747b715Smrgvoid 7596747b715SmrgDRI2BlockClient(ClientPtr client, DrawablePtr pDraw) 7606747b715Smrg{ 7616747b715Smrg DRI2DrawablePtr pPriv; 7626747b715Smrg 7636747b715Smrg pPriv = DRI2GetDrawable(pDraw); 7646747b715Smrg if (pPriv == NULL) 765f7df2e56Smrg return; 766f7df2e56Smrg 767f7df2e56Smrg dri2Sleep(client, pPriv, WAKE_MSC); 768f7df2e56Smrg} 769f7df2e56Smrg 770f7df2e56Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable) 771f7df2e56Smrg{ 772f7df2e56Smrg if (drawable->type == DRAWABLE_PIXMAP) 773f7df2e56Smrg return (PixmapPtr)drawable; 774f7df2e56Smrg else { 775f7df2e56Smrg struct _Window *pWin = (struct _Window *)drawable; 776f7df2e56Smrg return drawable->pScreen->GetWindowPixmap(pWin); 777f7df2e56Smrg } 778f7df2e56Smrg} 779f7df2e56Smrg 780f7df2e56Smrg/* 781f7df2e56Smrg * A TraverseTree callback to invalidate all windows using the same 782f7df2e56Smrg * pixmap 783f7df2e56Smrg */ 784f7df2e56Smrgstatic int 785f7df2e56SmrgDRI2InvalidateWalk(WindowPtr pWin, void *data) 786f7df2e56Smrg{ 787f7df2e56Smrg if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data) 788f7df2e56Smrg return WT_DONTWALKCHILDREN; 789f7df2e56Smrg DRI2InvalidateDrawable(&pWin->drawable); 790f7df2e56Smrg return WT_WALKCHILDREN; 791f7df2e56Smrg} 792f7df2e56Smrg 793f7df2e56Smrgstatic void 794f7df2e56SmrgDRI2InvalidateDrawableAll(DrawablePtr pDraw) 795f7df2e56Smrg{ 796f7df2e56Smrg if (pDraw->type == DRAWABLE_WINDOW) { 797f7df2e56Smrg WindowPtr pWin = (WindowPtr) pDraw; 798f7df2e56Smrg PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin); 799f7df2e56Smrg 800f7df2e56Smrg /* 801f7df2e56Smrg * Find the top-most window using this pixmap 802f7df2e56Smrg */ 803f7df2e56Smrg while (pWin->parent && 804f7df2e56Smrg pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap) 805f7df2e56Smrg pWin = pWin->parent; 806f7df2e56Smrg 807f7df2e56Smrg /* 808f7df2e56Smrg * Walk the sub-tree to invalidate all of the 809f7df2e56Smrg * windows using the same pixmap 810f7df2e56Smrg */ 811f7df2e56Smrg TraverseTree(pWin, DRI2InvalidateWalk, pPixmap); 812f7df2e56Smrg DRI2InvalidateDrawable(&pPixmap->drawable); 813f7df2e56Smrg } 814f7df2e56Smrg else 815f7df2e56Smrg DRI2InvalidateDrawable(pDraw); 816f7df2e56Smrg} 817f7df2e56Smrg 818f7df2e56SmrgDrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest) 819f7df2e56Smrg{ 820f7df2e56Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 821f7df2e56Smrg PixmapPtr spix; 822f7df2e56Smrg PixmapPtr mpix = GetDrawablePixmap(pDraw); 8235a112b11Smrg ScreenPtr primary, secondary; 824f7df2e56Smrg Bool ret; 8256747b715Smrg 8265a112b11Smrg primary = mpix->drawable.pScreen; 827f7df2e56Smrg 828f7df2e56Smrg if (pDraw->type == DRAWABLE_WINDOW) { 829f7df2e56Smrg WindowPtr pWin = (WindowPtr)pDraw; 830f7df2e56Smrg PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin); 831f7df2e56Smrg 832f7df2e56Smrg if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) { 833f7df2e56Smrg if (pPriv->redirectpixmap && 834f7df2e56Smrg pPriv->redirectpixmap->drawable.width == pDraw->width && 835f7df2e56Smrg pPriv->redirectpixmap->drawable.height == pDraw->height && 836f7df2e56Smrg pPriv->redirectpixmap->drawable.depth == pDraw->depth) { 837f7df2e56Smrg mpix = pPriv->redirectpixmap; 838f7df2e56Smrg } else { 8395a112b11Smrg if (primary->ReplaceScanoutPixmap) { 8405a112b11Smrg mpix = (*primary->CreatePixmap)(primary, pDraw->width, pDraw->height, 841f7df2e56Smrg pDraw->depth, CREATE_PIXMAP_USAGE_SHARED); 842f7df2e56Smrg if (!mpix) 843f7df2e56Smrg return NULL; 844f7df2e56Smrg 8455a112b11Smrg ret = (*primary->ReplaceScanoutPixmap)(pDraw, mpix, TRUE); 846f7df2e56Smrg if (ret == FALSE) { 8475a112b11Smrg (*primary->DestroyPixmap)(mpix); 848f7df2e56Smrg return NULL; 849f7df2e56Smrg } 850f7df2e56Smrg pPriv->redirectpixmap = mpix; 851f7df2e56Smrg } else 852f7df2e56Smrg return NULL; 853f7df2e56Smrg } 854f7df2e56Smrg } else if (pPriv->redirectpixmap) { 8555a112b11Smrg (*primary->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE); 8565a112b11Smrg (*primary->DestroyPixmap)(pPriv->redirectpixmap); 857f7df2e56Smrg pPriv->redirectpixmap = NULL; 858f7df2e56Smrg } 859f7df2e56Smrg } 860f7df2e56Smrg 8615a112b11Smrg secondary = GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 862f7df2e56Smrg 863f7df2e56Smrg /* check if the pixmap is still fine */ 8645a112b11Smrg if (pPriv->prime_secondary_pixmap) { 8655a112b11Smrg if (pPriv->prime_secondary_pixmap->primary_pixmap == mpix) 8665a112b11Smrg return &pPriv->prime_secondary_pixmap->drawable; 867f7df2e56Smrg else { 8685a112b11Smrg PixmapUnshareSecondaryPixmap(pPriv->prime_secondary_pixmap); 8695a112b11Smrg (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap); 8705a112b11Smrg (*secondary->DestroyPixmap)(pPriv->prime_secondary_pixmap); 8715a112b11Smrg pPriv->prime_secondary_pixmap = NULL; 872f7df2e56Smrg } 873f7df2e56Smrg } 874f7df2e56Smrg 8755a112b11Smrg spix = PixmapShareToSecondary(mpix, secondary); 876f7df2e56Smrg if (!spix) 877f7df2e56Smrg return NULL; 878f7df2e56Smrg 8795a112b11Smrg pPriv->prime_secondary_pixmap = spix; 880f7df2e56Smrg#ifdef COMPOSITE 881f7df2e56Smrg spix->screen_x = mpix->screen_x; 882f7df2e56Smrg spix->screen_y = mpix->screen_y; 883f7df2e56Smrg#endif 884f7df2e56Smrg 885f7df2e56Smrg DRI2InvalidateDrawableAll(pDraw); 886f7df2e56Smrg return &spix->drawable; 887f7df2e56Smrg} 888f7df2e56Smrg 889f7df2e56Smrgstatic void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 890f7df2e56Smrg DRI2BufferPtr pDest, DRI2BufferPtr pSrc) 891f7df2e56Smrg{ 892f7df2e56Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); 893f7df2e56Smrg DRI2ScreenPtr ds; 894f7df2e56Smrg ScreenPtr primeScreen; 895f7df2e56Smrg 896f7df2e56Smrg primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id); 897f7df2e56Smrg ds = DRI2GetScreen(primeScreen); 898f7df2e56Smrg 899f7df2e56Smrg if (ds->CopyRegion2) 900f7df2e56Smrg (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc); 901f7df2e56Smrg else 902f7df2e56Smrg (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc); 903f7df2e56Smrg 904f7df2e56Smrg /* cause damage to the box */ 905f7df2e56Smrg if (pPriv->prime_id) { 906f7df2e56Smrg BoxRec box; 907f7df2e56Smrg RegionRec region; 908f7df2e56Smrg box.x1 = 0; 909f7df2e56Smrg box.x2 = box.x1 + pDraw->width; 910f7df2e56Smrg box.y1 = 0; 911f7df2e56Smrg box.y2 = box.y1 + pDraw->height; 912f7df2e56Smrg RegionInit(®ion, &box, 1); 913f7df2e56Smrg RegionTranslate(®ion, pDraw->x, pDraw->y); 914f7df2e56Smrg DamageRegionAppend(pDraw, ®ion); 915f7df2e56Smrg DamageRegionProcessPending(pDraw); 916f7df2e56Smrg RegionUninit(®ion); 917f7df2e56Smrg } 9186747b715Smrg} 9196747b715Smrg 9204642e01fSmrgint 9214642e01fSmrgDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 922f7df2e56Smrg unsigned int dest, unsigned int src) 9234642e01fSmrg{ 9244642e01fSmrg DRI2DrawablePtr pPriv; 925f7df2e56Smrg DRI2BufferPtr pDestBuffer, pSrcBuffer; 926f7df2e56Smrg int i; 9274642e01fSmrg 9284642e01fSmrg pPriv = DRI2GetDrawable(pDraw); 9294642e01fSmrg if (pPriv == NULL) 930f7df2e56Smrg return BadDrawable; 9314642e01fSmrg 9324642e01fSmrg pDestBuffer = NULL; 9334642e01fSmrg pSrcBuffer = NULL; 934f7df2e56Smrg for (i = 0; i < pPriv->bufferCount; i++) { 935f7df2e56Smrg if (pPriv->buffers[i]->attachment == dest) 936f7df2e56Smrg pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 937f7df2e56Smrg if (pPriv->buffers[i]->attachment == src) 938f7df2e56Smrg pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 9394642e01fSmrg } 9404642e01fSmrg if (pSrcBuffer == NULL || pDestBuffer == NULL) 941f7df2e56Smrg return BadValue; 94252397711Smrg 943f7df2e56Smrg dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer); 9444642e01fSmrg 9454642e01fSmrg return Success; 9464642e01fSmrg} 9474642e01fSmrg 9486747b715Smrg/* Can this drawable be page flipped? */ 9496747b715SmrgBool 9506747b715SmrgDRI2CanFlip(DrawablePtr pDraw) 9516747b715Smrg{ 9526747b715Smrg ScreenPtr pScreen = pDraw->pScreen; 9536747b715Smrg WindowPtr pWin, pRoot; 9546747b715Smrg PixmapPtr pWinPixmap, pRootPixmap; 9556747b715Smrg 9566747b715Smrg if (pDraw->type == DRAWABLE_PIXMAP) 957f7df2e56Smrg return TRUE; 9586747b715Smrg 9596747b715Smrg pRoot = pScreen->root; 9606747b715Smrg pRootPixmap = pScreen->GetWindowPixmap(pRoot); 9616747b715Smrg 9626747b715Smrg pWin = (WindowPtr) pDraw; 9636747b715Smrg pWinPixmap = pScreen->GetWindowPixmap(pWin); 9646747b715Smrg if (pRootPixmap != pWinPixmap) 965f7df2e56Smrg return FALSE; 9666747b715Smrg if (!RegionEqual(&pWin->clipList, &pRoot->winSize)) 967f7df2e56Smrg return FALSE; 9686747b715Smrg 9698223e2f2Smrg /* Does the window match the pixmap exactly? */ 970f7df2e56Smrg if (pDraw->x != 0 || pDraw->y != 0 || 9718223e2f2Smrg#ifdef COMPOSITE 972f7df2e56Smrg pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y || 9738223e2f2Smrg#endif 974f7df2e56Smrg pDraw->width != pWinPixmap->drawable.width || 975f7df2e56Smrg pDraw->height != pWinPixmap->drawable.height) 976f7df2e56Smrg return FALSE; 9778223e2f2Smrg 9786747b715Smrg return TRUE; 9796747b715Smrg} 9806747b715Smrg 9816747b715Smrg/* Can we do a pixmap exchange instead of a blit? */ 9826747b715SmrgBool 9836747b715SmrgDRI2CanExchange(DrawablePtr pDraw) 9846747b715Smrg{ 9856747b715Smrg return FALSE; 9866747b715Smrg} 9876747b715Smrg 9884642e01fSmrgvoid 9896747b715SmrgDRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, 990f7df2e56Smrg unsigned int tv_sec, unsigned int tv_usec) 9914642e01fSmrg{ 9924642e01fSmrg DRI2DrawablePtr pPriv; 9934642e01fSmrg 9944642e01fSmrg pPriv = DRI2GetDrawable(pDraw); 9954642e01fSmrg if (pPriv == NULL) 996f7df2e56Smrg return; 9974642e01fSmrg 998f7df2e56Smrg ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec, 999f7df2e56Smrg frame, pPriv->swap_count); 100052397711Smrg 1001f7df2e56Smrg dri2WakeAll(client, pPriv, WAKE_MSC); 10026747b715Smrg} 10036747b715Smrg 10046747b715Smrgstatic void 10056747b715SmrgDRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, 1006f7df2e56Smrg unsigned int tv_sec, unsigned int tv_usec) 10076747b715Smrg{ 1008f7df2e56Smrg ScreenPtr pScreen = pDraw->pScreen; 10096747b715Smrg DRI2DrawablePtr pPriv; 10106747b715Smrg 10116747b715Smrg pPriv = DRI2GetDrawable(pDraw); 10126747b715Smrg if (pPriv == NULL) { 10136747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1014f7df2e56Smrg "[DRI2] %s: bad drawable\n", __func__); 1015f7df2e56Smrg return; 10166747b715Smrg } 10176747b715Smrg 10186747b715Smrg /* 10196747b715Smrg * Swap completed. 10206747b715Smrg * Wake the client iff: 10216747b715Smrg * - it was waiting on SBC 10226747b715Smrg * - was blocked due to GLX make current 10236747b715Smrg * - was blocked due to swap throttling 10246747b715Smrg * - is not blocked due to an MSC wait 10256747b715Smrg */ 1026f7df2e56Smrg if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) { 1027f7df2e56Smrg if (dri2WakeAll(client, pPriv, WAKE_SBC)) { 1028f7df2e56Smrg ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec, 1029f7df2e56Smrg frame, pPriv->swap_count); 1030f7df2e56Smrg pPriv->target_sbc = -1; 1031f7df2e56Smrg } 10326747b715Smrg } 1033f7df2e56Smrg 1034f7df2e56Smrg dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP); 10356747b715Smrg} 10366747b715Smrg 10376747b715Smrgvoid 10386747b715SmrgDRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, 1039f7df2e56Smrg unsigned int tv_sec, unsigned int tv_usec, int type, 1040f7df2e56Smrg DRI2SwapEventPtr swap_complete, void *swap_data) 10416747b715Smrg{ 1042f7df2e56Smrg ScreenPtr pScreen = pDraw->pScreen; 10436747b715Smrg DRI2DrawablePtr pPriv; 1044f7df2e56Smrg CARD64 ust = 0; 1045f7df2e56Smrg BoxRec box; 1046f7df2e56Smrg RegionRec region; 104752397711Smrg 10486747b715Smrg pPriv = DRI2GetDrawable(pDraw); 10496747b715Smrg if (pPriv == NULL) { 10506747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1051f7df2e56Smrg "[DRI2] %s: bad drawable\n", __func__); 1052f7df2e56Smrg return; 105352397711Smrg } 105452397711Smrg 10556747b715Smrg pPriv->swapsPending--; 10566747b715Smrg pPriv->swap_count++; 10574642e01fSmrg 10586747b715Smrg box.x1 = 0; 10596747b715Smrg box.y1 = 0; 10606747b715Smrg box.x2 = pDraw->width; 10616747b715Smrg box.y2 = pDraw->height; 10626747b715Smrg RegionInit(®ion, &box, 0); 10636747b715Smrg DRI2CopyRegion(pDraw, ®ion, DRI2BufferFakeFrontLeft, 1064f7df2e56Smrg DRI2BufferFrontLeft); 10656747b715Smrg 1066f7df2e56Smrg ust = ((CARD64) tv_sec * 1000000) + tv_usec; 10676747b715Smrg if (swap_complete) 1068f7df2e56Smrg swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); 10696747b715Smrg 10706747b715Smrg pPriv->last_swap_msc = frame; 10716747b715Smrg pPriv->last_swap_ust = ust; 10726747b715Smrg 10736747b715Smrg DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); 10746747b715Smrg} 10756747b715Smrg 10766747b715SmrgBool 10776747b715SmrgDRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) 10786747b715Smrg{ 10796747b715Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 10806747b715Smrg 10816747b715Smrg /* If we're currently waiting for a swap on this drawable, reset 1082f7df2e56Smrg * the request and suspend the client. */ 1083f7df2e56Smrg if (pPriv && pPriv->swapsPending) { 1084f7df2e56Smrg if (dri2Sleep(client, pPriv, WAKE_SWAP)) { 1085f7df2e56Smrg ResetCurrentRequest(client); 1086f7df2e56Smrg client->sequence--; 1087f7df2e56Smrg return TRUE; 1088f7df2e56Smrg } 10894642e01fSmrg } 10906747b715Smrg 10916747b715Smrg return FALSE; 10926747b715Smrg} 10936747b715Smrg 1094f7df2e56Smrg 1095f7df2e56Smrg 10966747b715Smrgint 10976747b715SmrgDRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 1098f7df2e56Smrg CARD64 divisor, CARD64 remainder, CARD64 * swap_target, 1099f7df2e56Smrg DRI2SwapEventPtr func, void *data) 11006747b715Smrg{ 1101f7df2e56Smrg ScreenPtr pScreen = pDraw->pScreen; 1102f7df2e56Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 11036747b715Smrg DRI2DrawablePtr pPriv; 1104f7df2e56Smrg DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; 1105f7df2e56Smrg int ret, i; 1106f7df2e56Smrg CARD64 ust, current_msc; 11076747b715Smrg 11086747b715Smrg pPriv = DRI2GetDrawable(pDraw); 11096747b715Smrg if (pPriv == NULL) { 11106747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1111f7df2e56Smrg "[DRI2] %s: bad drawable\n", __func__); 1112f7df2e56Smrg return BadDrawable; 11136747b715Smrg } 11146747b715Smrg 1115f7df2e56Smrg /* According to spec, return expected swapbuffers count SBC after this swap 1116f7df2e56Smrg * will complete. This is ignored unless we return Success, but it must be 1117f7df2e56Smrg * initialized on every path where we return Success or the caller will send 1118f7df2e56Smrg * an uninitialized value off the stack to the client. So let's initialize 1119f7df2e56Smrg * it as early as possible, just to be sure. 1120f7df2e56Smrg */ 1121f7df2e56Smrg *swap_target = pPriv->swap_count + pPriv->swapsPending + 1; 1122f7df2e56Smrg 11236747b715Smrg for (i = 0; i < pPriv->bufferCount; i++) { 1124f7df2e56Smrg if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) 1125f7df2e56Smrg pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 1126f7df2e56Smrg if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) 1127f7df2e56Smrg pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; 11286747b715Smrg } 11296747b715Smrg if (pSrcBuffer == NULL || pDestBuffer == NULL) { 11306747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1131f7df2e56Smrg "[DRI2] %s: drawable has no back or front?\n", __func__); 1132f7df2e56Smrg return BadDrawable; 11336747b715Smrg } 11346747b715Smrg 11356747b715Smrg /* Old DDX or no swap interval, just blit */ 1136f7df2e56Smrg if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) { 1137f7df2e56Smrg BoxRec box; 1138f7df2e56Smrg RegionRec region; 11396747b715Smrg 1140f7df2e56Smrg box.x1 = 0; 1141f7df2e56Smrg box.y1 = 0; 1142f7df2e56Smrg box.x2 = pDraw->width; 1143f7df2e56Smrg box.y2 = pDraw->height; 1144f7df2e56Smrg RegionInit(®ion, &box, 0); 11456747b715Smrg 1146f7df2e56Smrg pPriv->swapsPending++; 11476747b715Smrg 1148f7df2e56Smrg dri2_copy_region(pDraw, ®ion, pDestBuffer, pSrcBuffer); 1149f7df2e56Smrg DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, 1150f7df2e56Smrg func, data); 1151f7df2e56Smrg return Success; 11526747b715Smrg } 11536747b715Smrg 11546747b715Smrg /* 11556747b715Smrg * In the simple glXSwapBuffers case, all params will be 0, and we just 11566747b715Smrg * need to schedule a swap for the last swap target + the swap interval. 11576747b715Smrg */ 11586747b715Smrg if (target_msc == 0 && divisor == 0 && remainder == 0) { 1159f7df2e56Smrg /* If the current vblank count of the drawable's crtc is lower 1160f7df2e56Smrg * than the count stored in last_swap_target from a previous swap 1161f7df2e56Smrg * then reinitialize last_swap_target to the current crtc's msc, 1162f7df2e56Smrg * otherwise the swap will hang. This will happen if the drawable 1163f7df2e56Smrg * is moved to a crtc with a lower refresh rate, or a crtc that just 1164f7df2e56Smrg * got enabled. 1165f7df2e56Smrg */ 1166f7df2e56Smrg if (ds->GetMSC) { 1167f7df2e56Smrg if (!(*ds->GetMSC) (pDraw, &ust, ¤t_msc)) 1168f7df2e56Smrg pPriv->last_swap_target = 0; 1169f7df2e56Smrg 1170f7df2e56Smrg if (current_msc < pPriv->last_swap_target) 1171f7df2e56Smrg pPriv->last_swap_target = current_msc; 1172f7df2e56Smrg 1173f7df2e56Smrg } 1174f7df2e56Smrg 1175f7df2e56Smrg /* 1176f7df2e56Smrg * Swap target for this swap is last swap target + swap interval since 1177f7df2e56Smrg * we have to account for the current swap count, interval, and the 1178f7df2e56Smrg * number of pending swaps. 1179f7df2e56Smrg */ 1180f7df2e56Smrg target_msc = pPriv->last_swap_target + pPriv->swap_interval; 1181f7df2e56Smrg 11826747b715Smrg } 11836747b715Smrg 11846747b715Smrg pPriv->swapsPending++; 1185f7df2e56Smrg ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer, 1186f7df2e56Smrg &target_msc, divisor, remainder, func, data); 11876747b715Smrg if (!ret) { 1188f7df2e56Smrg pPriv->swapsPending--; /* didn't schedule */ 11896747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1190f7df2e56Smrg "[DRI2] %s: driver failed to schedule swap\n", __func__); 1191f7df2e56Smrg return BadDrawable; 11926747b715Smrg } 11936747b715Smrg 1194f7df2e56Smrg pPriv->last_swap_target = target_msc; 11956747b715Smrg 1196f7df2e56Smrg DRI2InvalidateDrawableAll(pDraw); 11976747b715Smrg 11986747b715Smrg return Success; 11996747b715Smrg} 12006747b715Smrg 12016747b715Smrgvoid 12026747b715SmrgDRI2SwapInterval(DrawablePtr pDrawable, int interval) 12036747b715Smrg{ 1204f7df2e56Smrg ScreenPtr pScreen = pDrawable->pScreen; 12056747b715Smrg DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); 12066747b715Smrg 12076747b715Smrg if (pPriv == NULL) { 12086747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1209f7df2e56Smrg "[DRI2] %s: bad drawable\n", __func__); 1210f7df2e56Smrg return; 12116747b715Smrg } 12126747b715Smrg 12136747b715Smrg /* fixme: check against arbitrary max? */ 12146747b715Smrg pPriv->swap_interval = interval; 12156747b715Smrg} 12166747b715Smrg 12176747b715Smrgint 1218f7df2e56SmrgDRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc) 12196747b715Smrg{ 12206747b715Smrg ScreenPtr pScreen = pDraw->pScreen; 12216747b715Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 12226747b715Smrg DRI2DrawablePtr pPriv; 12236747b715Smrg Bool ret; 12246747b715Smrg 12256747b715Smrg pPriv = DRI2GetDrawable(pDraw); 12266747b715Smrg if (pPriv == NULL) { 12276747b715Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1228f7df2e56Smrg "[DRI2] %s: bad drawable\n", __func__); 1229f7df2e56Smrg return BadDrawable; 12306747b715Smrg } 12316747b715Smrg 12326747b715Smrg if (!ds->GetMSC) { 1233f7df2e56Smrg *ust = 0; 1234f7df2e56Smrg *msc = 0; 1235f7df2e56Smrg *sbc = pPriv->swap_count; 1236f7df2e56Smrg return Success; 12376747b715Smrg } 12386747b715Smrg 12396747b715Smrg /* 12406747b715Smrg * Spec needs to be updated to include unmapped or redirected 12416747b715Smrg * drawables 12426747b715Smrg */ 12436747b715Smrg 1244f7df2e56Smrg ret = (*ds->GetMSC) (pDraw, ust, msc); 12456747b715Smrg if (!ret) 1246f7df2e56Smrg return BadDrawable; 12476747b715Smrg 12486747b715Smrg *sbc = pPriv->swap_count; 12496747b715Smrg 12506747b715Smrg return Success; 12516747b715Smrg} 12526747b715Smrg 12536747b715Smrgint 12546747b715SmrgDRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, 1255f7df2e56Smrg CARD64 divisor, CARD64 remainder) 12566747b715Smrg{ 12576747b715Smrg DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); 12586747b715Smrg DRI2DrawablePtr pPriv; 12596747b715Smrg Bool ret; 12606747b715Smrg 12616747b715Smrg pPriv = DRI2GetDrawable(pDraw); 12626747b715Smrg if (pPriv == NULL) 1263f7df2e56Smrg return BadDrawable; 12646747b715Smrg 12656747b715Smrg /* Old DDX just completes immediately */ 12666747b715Smrg if (!ds->ScheduleWaitMSC) { 1267f7df2e56Smrg DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); 12686747b715Smrg 1269f7df2e56Smrg return Success; 12706747b715Smrg } 12716747b715Smrg 1272f7df2e56Smrg ret = 1273f7df2e56Smrg (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder); 12746747b715Smrg if (!ret) 1275f7df2e56Smrg return BadDrawable; 12766747b715Smrg 12776747b715Smrg return Success; 12786747b715Smrg} 12796747b715Smrg 12806747b715Smrgint 12816747b715SmrgDRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc) 12826747b715Smrg{ 12836747b715Smrg DRI2DrawablePtr pPriv; 12846747b715Smrg 12856747b715Smrg pPriv = DRI2GetDrawable(pDraw); 12866747b715Smrg if (pPriv == NULL) 1287f7df2e56Smrg return BadDrawable; 1288f7df2e56Smrg 1289f7df2e56Smrg if (pPriv->target_sbc != -1) /* already in use */ 1290f7df2e56Smrg return BadDrawable; 12916747b715Smrg 12926747b715Smrg /* target_sbc == 0 means to block until all pending swaps are 12936747b715Smrg * finished. Recalculate target_sbc to get that behaviour. 12946747b715Smrg */ 12956747b715Smrg if (target_sbc == 0) 12966747b715Smrg target_sbc = pPriv->swap_count + pPriv->swapsPending; 12976747b715Smrg 12986747b715Smrg /* If current swap count already >= target_sbc, reply and 12996747b715Smrg * return immediately with (ust, msc, sbc) triplet of 13006747b715Smrg * most recent completed swap. 13016747b715Smrg */ 13026747b715Smrg if (pPriv->swap_count >= target_sbc) { 13036747b715Smrg ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust, 13046747b715Smrg pPriv->last_swap_msc, pPriv->swap_count); 13056747b715Smrg return Success; 13064642e01fSmrg } 13076747b715Smrg 1308f7df2e56Smrg if (!dri2Sleep(client, pPriv, WAKE_SBC)) 1309f7df2e56Smrg return BadAlloc; 13106747b715Smrg 1311f7df2e56Smrg pPriv->target_sbc = target_sbc; 13126747b715Smrg return Success; 13136747b715Smrg} 13146747b715Smrg 13156747b715SmrgBool 13166747b715SmrgDRI2HasSwapControl(ScreenPtr pScreen) 13176747b715Smrg{ 13186747b715Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 13196747b715Smrg 13206747b715Smrg return ds->ScheduleSwap && ds->GetMSC; 13214642e01fSmrg} 13224642e01fSmrg 13234642e01fSmrgBool 1324f7df2e56SmrgDRI2Connect(ClientPtr client, ScreenPtr pScreen, 1325f7df2e56Smrg unsigned int driverType, int *fd, 1326f7df2e56Smrg const char **driverName, const char **deviceName) 13274642e01fSmrg{ 13286747b715Smrg DRI2ScreenPtr ds; 1329f7df2e56Smrg uint32_t prime_id = DRI2DriverPrimeId(driverType); 1330f7df2e56Smrg uint32_t driver_id = driverType & 0xffff; 13314642e01fSmrg 13326747b715Smrg if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1333f7df2e56Smrg return FALSE; 13344642e01fSmrg 1335f7df2e56Smrg ds = DRI2GetScreenPrime(pScreen, prime_id); 1336f7df2e56Smrg if (ds == NULL) 1337f7df2e56Smrg return FALSE; 13384642e01fSmrg 1339f7df2e56Smrg if (driver_id >= ds->numDrivers || 1340f7df2e56Smrg !ds->driverNames[driver_id]) 1341f7df2e56Smrg return FALSE; 1342f7df2e56Smrg 1343f7df2e56Smrg *driverName = ds->driverNames[driver_id]; 13444642e01fSmrg *deviceName = ds->deviceName; 1345f7df2e56Smrg *fd = ds->fd; 1346f7df2e56Smrg 1347f7df2e56Smrg if (client) { 1348f7df2e56Smrg DRI2ClientPtr dri2_client; 1349f7df2e56Smrg dri2_client = dri2ClientPrivate(client); 1350f7df2e56Smrg dri2_client->prime_id = prime_id; 1351f7df2e56Smrg } 13524642e01fSmrg 13534642e01fSmrg return TRUE; 13544642e01fSmrg} 13554642e01fSmrg 1356f7df2e56Smrgstatic int 1357f7df2e56SmrgDRI2AuthMagic (ScreenPtr pScreen, uint32_t magic) 13584642e01fSmrg{ 13594642e01fSmrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1360f7df2e56Smrg if (ds == NULL) 1361f7df2e56Smrg return -EINVAL; 13624642e01fSmrg 1363f7df2e56Smrg return (*ds->LegacyAuthMagic) (ds->fd, magic); 1364f7df2e56Smrg} 1365f7df2e56Smrg 1366f7df2e56SmrgBool 1367f7df2e56SmrgDRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic) 1368f7df2e56Smrg{ 1369f7df2e56Smrg DRI2ScreenPtr ds; 1370d566a54bSmrg DRI2ClientPtr dri2_client; 1371f7df2e56Smrg ScreenPtr primescreen; 1372f7df2e56Smrg 1373d566a54bSmrg if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey)) 1374d566a54bSmrg return FALSE; 1375d566a54bSmrg 1376d566a54bSmrg dri2_client = dri2ClientPrivate(client); 1377d566a54bSmrg 1378f7df2e56Smrg ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id); 1379f7df2e56Smrg if (ds == NULL) 13806747b715Smrg return FALSE; 13814642e01fSmrg 1382f7df2e56Smrg primescreen = GetScreenPrime(pScreen, dri2_client->prime_id); 1383f7df2e56Smrg if ((*ds->AuthMagic)(primescreen, magic)) 1384f7df2e56Smrg return FALSE; 13854642e01fSmrg return TRUE; 13864642e01fSmrg} 13874642e01fSmrg 13886747b715Smrgstatic int 13896747b715SmrgDRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, 1390f7df2e56Smrg WindowPtr pSib) 13916747b715Smrg{ 1392f7df2e56Smrg DrawablePtr pDraw = (DrawablePtr) pWin; 13936747b715Smrg ScreenPtr pScreen = pDraw->pScreen; 13946747b715Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 13956747b715Smrg DRI2DrawablePtr dd = DRI2GetDrawable(pDraw); 13966747b715Smrg int ret; 13976747b715Smrg 13986747b715Smrg if (ds->ConfigNotify) { 1399f7df2e56Smrg pScreen->ConfigNotify = ds->ConfigNotify; 14006747b715Smrg 1401f7df2e56Smrg ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib); 14026747b715Smrg 1403f7df2e56Smrg ds->ConfigNotify = pScreen->ConfigNotify; 1404f7df2e56Smrg pScreen->ConfigNotify = DRI2ConfigNotify; 1405f7df2e56Smrg if (ret) 1406f7df2e56Smrg return ret; 14076747b715Smrg } 14086747b715Smrg 14096747b715Smrg if (!dd || (dd->width == w && dd->height == h)) 1410f7df2e56Smrg return Success; 14116747b715Smrg 14126747b715Smrg DRI2InvalidateDrawable(pDraw); 14136747b715Smrg return Success; 14146747b715Smrg} 14156747b715Smrg 1416f7df2e56Smrgstatic void 1417f7df2e56SmrgDRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix) 1418f7df2e56Smrg{ 1419f7df2e56Smrg ScreenPtr pScreen = pWin->drawable.pScreen; 1420f7df2e56Smrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 1421f7df2e56Smrg 1422f7df2e56Smrg pScreen->SetWindowPixmap = ds->SetWindowPixmap; 1423f7df2e56Smrg (*pScreen->SetWindowPixmap) (pWin, pPix); 1424f7df2e56Smrg ds->SetWindowPixmap = pScreen->SetWindowPixmap; 1425f7df2e56Smrg pScreen->SetWindowPixmap = DRI2SetWindowPixmap; 1426f7df2e56Smrg 1427f7df2e56Smrg DRI2InvalidateDrawable(&pWin->drawable); 1428f7df2e56Smrg} 1429f7df2e56Smrg 1430f7df2e56Smrg#define MAX_PRIME DRI2DriverPrimeMask 1431f7df2e56Smrgstatic int 1432f7df2e56Smrgget_prime_id(void) 1433f7df2e56Smrg{ 1434f7df2e56Smrg int i; 1435f7df2e56Smrg /* start at 1, prime id 0 is just normal driver */ 1436f7df2e56Smrg for (i = 1; i < MAX_PRIME; i++) { 1437f7df2e56Smrg if (prime_id_allocate_bitmask & (1 << i)) 1438f7df2e56Smrg continue; 1439f7df2e56Smrg 1440f7df2e56Smrg prime_id_allocate_bitmask |= (1 << i); 1441f7df2e56Smrg return i; 1442f7df2e56Smrg } 1443f7df2e56Smrg return -1; 1444f7df2e56Smrg} 1445f7df2e56Smrg 1446f7df2e56Smrg#include "pci_ids/pci_id_driver_map.h" 1447f7df2e56Smrg 1448f7df2e56Smrgstatic char * 1449f7df2e56Smrgdri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info) 1450f7df2e56Smrg{ 14517e31ba66Smrg#ifdef WITH_LIBDRM 1452f7df2e56Smrg int i, j; 14537e31ba66Smrg char *driver = NULL; 14547e31ba66Smrg drmDevicePtr dev; 1455f7df2e56Smrg 14567e31ba66Smrg /* For non-PCI devices and drmGetDevice fail, just assume that 14577e31ba66Smrg * the 3D driver is named the same as the kernel driver. This is 14587e31ba66Smrg * currently true for vc4 and msm (freedreno). 1459f7df2e56Smrg */ 14607e31ba66Smrg if (drmGetDevice(info->fd, &dev) || dev->bustype != DRM_BUS_PCI) { 1461f7df2e56Smrg drmVersionPtr version = drmGetVersion(info->fd); 1462f7df2e56Smrg 1463f7df2e56Smrg if (!version) { 1464f7df2e56Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1465f7df2e56Smrg "[DRI2] Couldn't drmGetVersion() on non-PCI device, " 1466f7df2e56Smrg "no driver name found.\n"); 1467f7df2e56Smrg return NULL; 1468f7df2e56Smrg } 1469f7df2e56Smrg 14707e31ba66Smrg driver = strndup(version->name, version->name_len); 1471f7df2e56Smrg drmFreeVersion(version); 14727e31ba66Smrg return driver; 1473f7df2e56Smrg } 1474f7df2e56Smrg 1475f7df2e56Smrg for (i = 0; driver_map[i].driver; i++) { 14767e31ba66Smrg if (dev->deviceinfo.pci->vendor_id != driver_map[i].vendor_id) 1477f7df2e56Smrg continue; 1478f7df2e56Smrg 14797e31ba66Smrg if (driver_map[i].num_chips_ids == -1) { 14807e31ba66Smrg driver = strdup(driver_map[i].driver); 14817e31ba66Smrg goto out; 14827e31ba66Smrg } 1483f7df2e56Smrg 1484f7df2e56Smrg for (j = 0; j < driver_map[i].num_chips_ids; j++) { 14857e31ba66Smrg if (driver_map[i].chip_ids[j] == dev->deviceinfo.pci->device_id) { 14867e31ba66Smrg driver = strdup(driver_map[i].driver); 14877e31ba66Smrg goto out; 14887e31ba66Smrg } 1489f7df2e56Smrg } 1490f7df2e56Smrg } 1491f7df2e56Smrg 1492f7df2e56Smrg xf86DrvMsg(pScreen->myNum, X_ERROR, 1493f7df2e56Smrg "[DRI2] No driver mapping found for PCI device " 1494f7df2e56Smrg "0x%04x / 0x%04x\n", 14957e31ba66Smrg dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id); 14967e31ba66Smrgout: 14977e31ba66Smrg drmFreeDevice(&dev); 14987e31ba66Smrg return driver; 14997e31ba66Smrg#else 1500f7df2e56Smrg return NULL; 15017e31ba66Smrg#endif 1502f7df2e56Smrg} 1503f7df2e56Smrg 15044642e01fSmrgBool 15054642e01fSmrgDRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) 15064642e01fSmrg{ 15074642e01fSmrg DRI2ScreenPtr ds; 1508f7df2e56Smrg 1509f7df2e56Smrg const char *driverTypeNames[] = { 1510f7df2e56Smrg "DRI", /* DRI2DriverDRI */ 1511f7df2e56Smrg "VDPAU", /* DRI2DriverVDPAU */ 15126747b715Smrg }; 15136747b715Smrg unsigned int i; 15146747b715Smrg CARD8 cur_minor; 15156747b715Smrg 15166747b715Smrg if (info->version < 3) 1517f7df2e56Smrg return FALSE; 15184642e01fSmrg 15196747b715Smrg if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 1520f7df2e56Smrg return FALSE; 15216747b715Smrg 15226747b715Smrg if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0)) 1523f7df2e56Smrg return FALSE; 15246747b715Smrg 15256747b715Smrg if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 1526f7df2e56Smrg return FALSE; 1527f7df2e56Smrg 1528f7df2e56Smrg if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec))) 1529f7df2e56Smrg return FALSE; 15306747b715Smrg 15316747b715Smrg ds = calloc(1, sizeof *ds); 15324642e01fSmrg if (!ds) 1533f7df2e56Smrg return FALSE; 15344642e01fSmrg 1535f7df2e56Smrg ds->screen = pScreen; 1536f7df2e56Smrg ds->fd = info->fd; 1537f7df2e56Smrg ds->deviceName = info->deviceName; 1538f7df2e56Smrg dri2_major = 1; 15396747b715Smrg 1540f7df2e56Smrg ds->CreateBuffer = info->CreateBuffer; 1541f7df2e56Smrg ds->DestroyBuffer = info->DestroyBuffer; 1542f7df2e56Smrg ds->CopyRegion = info->CopyRegion; 15437e31ba66Smrg cur_minor = 1; 154452397711Smrg 15456747b715Smrg if (info->version >= 4) { 1546f7df2e56Smrg ds->ScheduleSwap = info->ScheduleSwap; 1547f7df2e56Smrg ds->ScheduleWaitMSC = info->ScheduleWaitMSC; 1548f7df2e56Smrg ds->GetMSC = info->GetMSC; 1549f7df2e56Smrg cur_minor = 3; 1550f7df2e56Smrg } 155152397711Smrg 15526747b715Smrg if (info->version >= 5) { 1553f7df2e56Smrg ds->LegacyAuthMagic = info->AuthMagic; 1554f7df2e56Smrg } 1555f7df2e56Smrg 1556f7df2e56Smrg if (info->version >= 6) { 1557f7df2e56Smrg ds->ReuseBufferNotify = info->ReuseBufferNotify; 1558f7df2e56Smrg ds->SwapLimitValidate = info->SwapLimitValidate; 1559f7df2e56Smrg } 1560f7df2e56Smrg 1561f7df2e56Smrg if (info->version >= 7) { 1562f7df2e56Smrg ds->GetParam = info->GetParam; 1563f7df2e56Smrg cur_minor = 4; 1564f7df2e56Smrg } 1565f7df2e56Smrg 15667e31ba66Smrg if (info->version >= 8) { 15677e31ba66Smrg ds->AuthMagic = info->AuthMagic2; 15687e31ba66Smrg } 15697e31ba66Smrg 1570f7df2e56Smrg if (info->version >= 9) { 1571f7df2e56Smrg ds->CreateBuffer2 = info->CreateBuffer2; 1572f7df2e56Smrg if (info->CreateBuffer2 && pScreen->isGPU) { 1573f7df2e56Smrg ds->prime_id = get_prime_id(); 1574f7df2e56Smrg if (ds->prime_id == -1) { 1575f7df2e56Smrg free(ds); 1576f7df2e56Smrg return FALSE; 1577f7df2e56Smrg } 1578f7df2e56Smrg } 1579f7df2e56Smrg ds->DestroyBuffer2 = info->DestroyBuffer2; 1580f7df2e56Smrg ds->CopyRegion2 = info->CopyRegion2; 15816747b715Smrg } 15826747b715Smrg 15836747b715Smrg /* 15846747b715Smrg * if the driver doesn't provide an AuthMagic function or the info struct 1585f7df2e56Smrg * version is too low, call through LegacyAuthMagic 15866747b715Smrg */ 1587f7df2e56Smrg if (!ds->AuthMagic) { 1588f7df2e56Smrg ds->AuthMagic = DRI2AuthMagic; 1589f7df2e56Smrg /* 1590f7df2e56Smrg * If the driver doesn't provide an AuthMagic function 1591f7df2e56Smrg * it relies on the old method (using libdrm) or fails 1592f7df2e56Smrg */ 1593f7df2e56Smrg if (!ds->LegacyAuthMagic) 15946747b715Smrg#ifdef WITH_LIBDRM 1595f7df2e56Smrg ds->LegacyAuthMagic = drmAuthMagic; 15966747b715Smrg#else 1597f7df2e56Smrg goto err_out; 15986747b715Smrg#endif 1599f7df2e56Smrg } 16006747b715Smrg 16016747b715Smrg /* Initialize minor if needed and set to minimum provied by DDX */ 16026747b715Smrg if (!dri2_minor || dri2_minor > cur_minor) 1603f7df2e56Smrg dri2_minor = cur_minor; 16046747b715Smrg 16056747b715Smrg if (info->version == 3 || info->numDrivers == 0) { 1606f7df2e56Smrg /* Driver too old: use the old-style driverName field */ 1607f7df2e56Smrg ds->numDrivers = info->driverName ? 1 : 2; 1608f7df2e56Smrg ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames)); 1609f7df2e56Smrg if (!ds->driverNames) 1610f7df2e56Smrg goto err_out; 1611f7df2e56Smrg 1612f7df2e56Smrg if (info->driverName) { 1613f7df2e56Smrg ds->driverNames[0] = info->driverName; 1614f7df2e56Smrg } else { 16155a112b11Smrg /* FIXME dri2_probe_driver_name() returns a strdup-ed string, 16165a112b11Smrg * currently this gets leaked */ 1617f7df2e56Smrg ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info); 1618f7df2e56Smrg if (!ds->driverNames[0]) 1619f7df2e56Smrg return FALSE; 16205a112b11Smrg 16215a112b11Smrg /* There is no VDPAU driver for i965, fallback to the generic 16225a112b11Smrg * OpenGL/VAAPI va_gl backend to emulate VDPAU on i965. */ 16235a112b11Smrg if (strcmp(ds->driverNames[0], "i965") == 0) 16245a112b11Smrg ds->driverNames[1] = "va_gl"; 1625f7df2e56Smrg } 1626f7df2e56Smrg } 1627f7df2e56Smrg else { 1628f7df2e56Smrg ds->numDrivers = info->numDrivers; 1629f7df2e56Smrg ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames)); 1630f7df2e56Smrg if (!ds->driverNames) 1631f7df2e56Smrg goto err_out; 1632f7df2e56Smrg memcpy(ds->driverNames, info->driverNames, 1633f7df2e56Smrg info->numDrivers * sizeof(*ds->driverNames)); 163452397711Smrg } 16354642e01fSmrg 16364642e01fSmrg dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); 16374642e01fSmrg 16386747b715Smrg ds->ConfigNotify = pScreen->ConfigNotify; 16396747b715Smrg pScreen->ConfigNotify = DRI2ConfigNotify; 16406747b715Smrg 1641f7df2e56Smrg ds->SetWindowPixmap = pScreen->SetWindowPixmap; 1642f7df2e56Smrg pScreen->SetWindowPixmap = DRI2SetWindowPixmap; 1643f7df2e56Smrg 16444642e01fSmrg xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); 16457e31ba66Smrg for (i = 0; i < ARRAY_SIZE(driverTypeNames); i++) { 1646f7df2e56Smrg if (i < ds->numDrivers && ds->driverNames[i]) { 1647f7df2e56Smrg xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] %s driver: %s\n", 1648f7df2e56Smrg driverTypeNames[i], ds->driverNames[i]); 1649f7df2e56Smrg } 16506747b715Smrg } 16514642e01fSmrg 16524642e01fSmrg return TRUE; 16536747b715Smrg 1654f7df2e56Smrg err_out: 16556747b715Smrg xf86DrvMsg(pScreen->myNum, X_WARNING, 1656f7df2e56Smrg "[DRI2] Initialization failed for info version %d.\n", 1657f7df2e56Smrg info->version); 16586747b715Smrg free(ds); 16596747b715Smrg return FALSE; 16604642e01fSmrg} 16614642e01fSmrg 16624642e01fSmrgvoid 16634642e01fSmrgDRI2CloseScreen(ScreenPtr pScreen) 16644642e01fSmrg{ 16654642e01fSmrg DRI2ScreenPtr ds = DRI2GetScreen(pScreen); 16664642e01fSmrg 1667f7df2e56Smrg pScreen->ConfigNotify = ds->ConfigNotify; 1668f7df2e56Smrg pScreen->SetWindowPixmap = ds->SetWindowPixmap; 1669f7df2e56Smrg 1670f7df2e56Smrg if (ds->prime_id) 1671f7df2e56Smrg prime_id_allocate_bitmask &= ~(1 << ds->prime_id); 16726747b715Smrg free(ds->driverNames); 16736747b715Smrg free(ds); 16744642e01fSmrg dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL); 16754642e01fSmrg} 16764642e01fSmrg 1677475c125cSmrg/* Called by InitExtensions() */ 1678475c125cSmrgBool 1679475c125cSmrgDRI2ModuleSetup(void) 1680475c125cSmrg{ 1681475c125cSmrg dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable"); 1682475c125cSmrg if (!dri2DrawableRes) 1683f7df2e56Smrg return FALSE; 1684475c125cSmrg 1685475c125cSmrg return TRUE; 1686475c125cSmrg} 16874642e01fSmrg 168852397711Smrgvoid 168952397711SmrgDRI2Version(int *major, int *minor) 169052397711Smrg{ 169152397711Smrg if (major != NULL) 1692f7df2e56Smrg *major = 1; 169352397711Smrg 169452397711Smrg if (minor != NULL) 1695f7df2e56Smrg *minor = 2; 1696f7df2e56Smrg} 1697f7df2e56Smrg 1698f7df2e56Smrgint 1699f7df2e56SmrgDRI2GetParam(ClientPtr client, 1700f7df2e56Smrg DrawablePtr drawable, 1701f7df2e56Smrg CARD64 param, 1702f7df2e56Smrg BOOL *is_param_recognized, 1703f7df2e56Smrg CARD64 *value) 1704f7df2e56Smrg{ 1705f7df2e56Smrg DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen); 1706f7df2e56Smrg char high_byte = (param >> 24); 1707f7df2e56Smrg 1708f7df2e56Smrg switch (high_byte) { 1709f7df2e56Smrg case 0: 1710f7df2e56Smrg /* Parameter names whose high_byte is 0 are reserved for the X 1711f7df2e56Smrg * server. The server currently recognizes no parameters. 1712f7df2e56Smrg */ 1713f7df2e56Smrg goto not_recognized; 1714f7df2e56Smrg case 1: 1715f7df2e56Smrg /* Parameter names whose high byte is 1 are reserved for the DDX. */ 1716f7df2e56Smrg if (ds->GetParam) 1717f7df2e56Smrg return ds->GetParam(client, drawable, param, 1718f7df2e56Smrg is_param_recognized, value); 1719f7df2e56Smrg else 1720f7df2e56Smrg goto not_recognized; 1721f7df2e56Smrg default: 1722f7df2e56Smrg /* Other parameter names are reserved for future use. They are never 1723f7df2e56Smrg * recognized. 1724f7df2e56Smrg */ 1725f7df2e56Smrg goto not_recognized; 1726f7df2e56Smrg } 1727f7df2e56Smrg 1728f7df2e56Smrgnot_recognized: 1729f7df2e56Smrg *is_param_recognized = FALSE; 1730f7df2e56Smrg return Success; 173152397711Smrg} 1732