From: Rob Clark <r...@ti.com> TODO: + implement OSD support.. core should register damage and automatically re-call ScheduleSwapVid.. + automatically re-call ScheduleSwapVid on dri2 drawable resize... --- hw/xfree86/dri2/dri2.c | 364 +++++++++++++++++++++++++++++++++++++-------- hw/xfree86/dri2/dri2.h | 127 ++++++++++++++++- hw/xfree86/dri2/dri2ext.c | 214 +++++++++++++++++++++++++- 3 files changed, 631 insertions(+), 74 deletions(-)
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c index a97508d..89a7fed 100644 --- a/hw/xfree86/dri2/dri2.c +++ b/hw/xfree86/dri2/dri2.c @@ -91,6 +91,8 @@ typedef struct _DRI2Screen { int refcnt; unsigned int numDrivers; const char **driverNames; + unsigned int numFormats; + unsigned int *formats; const char *deviceName; int fd; unsigned int lastSequence; @@ -104,12 +106,27 @@ typedef struct _DRI2Screen { DRI2AuthMagicProcPtr AuthMagic; DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify; DRI2SwapLimitValidateProcPtr SwapLimitValidate; + DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames; + DRI2CreateBufferVidProcPtr CreateBufferVid; + DRI2ScheduleSwapVidProcPtr ScheduleSwapVid; + DRI2SetAttributeProcPtr SetAttribute; + DRI2GetAttributeProcPtr GetAttribute; HandleExposuresProcPtr HandleExposures; ConfigNotifyProcPtr ConfigNotify; } DRI2ScreenRec; +static Bool +supports_video(DRI2ScreenPtr ds) +{ + /* it would be easier if we had a way to track the driverType in the + * DRI2DrawablePtr.. but the DRI2DrawablePtr isn't created at the + * time of DRI2Connect().. + */ + return ds && ds->numFormats && ds->CreateBufferVid && ds->ScheduleSwapVid; +} + static DRI2ScreenPtr DRI2GetScreen(ScreenPtr pScreen) { @@ -296,15 +313,26 @@ DRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id, return Success; } +static void destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr *buffers, int count) +{ + if (buffers != NULL) { + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + int i; + for (i = 0; i < count; i++) + if (buffers[i]) + (*ds->DestroyBuffer)(pDraw, buffers[i]); + + free(buffers); + } +} + static int DRI2DrawableGone(pointer p, XID id) { DRI2DrawablePtr pPriv = p; - DRI2ScreenPtr ds = pPriv->dri2_screen; DRI2DrawableRefPtr ref, next; WindowPtr pWin; PixmapPtr pPixmap; DrawablePtr pDraw; - int i; list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) { if (ref->dri2_id == id) { @@ -336,12 +364,7 @@ static int DRI2DrawableGone(pointer p, XID id) dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL); } - if (pPriv->buffers != NULL) { - for (i = 0; i < pPriv->bufferCount; i++) - (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); - - free(pPriv->buffers); - } + destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount); free(pPriv); @@ -349,7 +372,7 @@ static int DRI2DrawableGone(pointer p, XID id) } static int -find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) +find_attachment(DRI2DrawablePtr pPriv, unsigned attachment, DRI2BufferPtr *buf) { int i; @@ -360,6 +383,8 @@ find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) for (i = 0; i < pPriv->bufferCount; i++) { if ((pPriv->buffers[i] != NULL) && (pPriv->buffers[i]->attachment == attachment)) { + if (buf) + *buf = pPriv->buffers[i]; return i; } } @@ -368,12 +393,24 @@ find_attachment(DRI2DrawablePtr pPriv, unsigned attachment) } static Bool +valid_format(DRI2ScreenPtr ds, unsigned int format) +{ + int i; + for (i = 0; i < ds->numFormats; i++) { + if (format == ds->formats[i]) { + return TRUE; + } + } + return FALSE; +} + +static Bool allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds, DRI2DrawablePtr pPriv, unsigned int attachment, unsigned int format, int dimensions_match, DRI2BufferPtr *buffer) { - int old_buf = find_attachment(pPriv, attachment); + int old_buf = find_attachment(pPriv, attachment, NULL); if ((old_buf < 0) || !dimensions_match @@ -397,18 +434,7 @@ static void update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw, DRI2BufferPtr *buffers, int out_count, int *width, int *height) { - DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); - int i; - - if (pPriv->buffers != NULL) { - for (i = 0; i < pPriv->bufferCount; i++) { - if (pPriv->buffers[i] != NULL) { - (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]); - } - } - - free(pPriv->buffers); - } + destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount); pPriv->buffers = buffers; pPriv->bufferCount = out_count; @@ -453,6 +479,15 @@ do_get_buffers(DrawablePtr pDraw, int *width, int *height, const unsigned attachment = *(attachments++); const unsigned format = (has_format) ? *(attachments++) : 0; + /* note: don't require a valid format for old drivers which don't + * register their supported formats.. + */ + if (has_format && (ds->numFormats > 0) && !valid_format(ds, format)) { + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR, + "[DRI2] %s: bad format: %d\n", __func__, format); + goto err_out; + } + if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment, format, dimensions_match, &buffers[i])) @@ -542,19 +577,11 @@ err_out: *out_count = 0; - if (buffers) { - for (i = 0; i < count; i++) { - if (buffers[i] != NULL) - (*ds->DestroyBuffer)(pDraw, buffers[i]); - } - - free(buffers); - buffers = NULL; - } + destroy_buffers(pDraw, buffers, count); - update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height); + update_dri2_drawable_buffers(pPriv, pDraw, NULL, *out_count, width, height); - return buffers; + return NULL; } DRI2BufferPtr * @@ -573,6 +600,95 @@ DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, out_count, TRUE); } +DRI2BufferPtr * +DRI2GetBuffersVid(DrawablePtr pDraw, int width, int height, + unsigned int *attachments, int count, int *out_count) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); + DRI2BufferPtr *buffers; + int i, n = 0; + + if (!pPriv || !supports_video(ds)) { + *out_count = 0; + return NULL; + } + + buffers = calloc(count, sizeof(buffers[0])); + if (!buffers) + goto err_out; + + for (i = 0; i < count; i++) { + DRI2BufferPtr buf; + const unsigned attachment = *(attachments++); + const unsigned format = *(attachments++); + + /* grow array of stored buffers if needed: */ + if (attachment >= pPriv->bufferCount) { + int n = attachment + 1; + DRI2BufferPtr *newBuffers = realloc(pPriv->buffers, + sizeof(pPriv->buffers[0]) * n); + if (!newBuffers) { + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR, + "[DRI2] %s: allocation failed for buffer: %d\n", + __func__, attachment); + goto err_out; + } + pPriv->buffers = newBuffers; + memset(&pPriv->buffers[pPriv->bufferCount], 0, + (n - pPriv->bufferCount) * sizeof(pPriv->buffers[0])); + pPriv->bufferCount = n; + } + + /* destroy any previous buffer at this attachment slot */ + if (pPriv->buffers[attachment]) { + (*ds->DestroyBuffer)(pDraw, pPriv->buffers[attachment]); + pPriv->buffers[attachment] = NULL; + } + + if ((width == 0) && (height == 0)) { + /* client just wanted us to delete the buffer */ + continue; + } + + if (!valid_format(ds, format)) { + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR, + "[DRI2] %s: bad format: %d\n", __func__, format); + goto err_out; + } + + if (attachment == DRI2BufferFrontLeft) { + buf = (*ds->CreateBuffer)(pDraw, attachment, format); + /* note: don't expose front buffer to client */ + } else { + buf = (*ds->CreateBufferVid)(pDraw, attachment, format, width, height); + buffers[n++] = buf; + } + + if (! buf) { + goto err_out; + } + + pPriv->buffers[attachment] = buf; + } + + *out_count = n; + + return buffers; + +err_out: + + *out_count = 0; + + for (i = 0; i < n; i++) + if (buffers[i]) + pPriv->buffers[buffers[i]->attachment] = NULL; + + destroy_buffers(pDraw, buffers, n); + + return NULL; +} + static void DRI2InvalidateDrawable(DrawablePtr pDraw) { @@ -645,22 +761,14 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, { DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); DRI2DrawablePtr pPriv; - DRI2BufferPtr pDestBuffer, pSrcBuffer; - int i; + DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; pPriv = DRI2GetDrawable(pDraw); if (pPriv == NULL) return BadDrawable; - pDestBuffer = NULL; - pSrcBuffer = NULL; - for (i = 0; i < pPriv->bufferCount; i++) - { - if (pPriv->buffers[i]->attachment == dest) - pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; - if (pPriv->buffers[i]->attachment == src) - pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; - } + find_attachment(pPriv, dest, &pDestBuffer); + find_attachment(pPriv, src, &pSrcBuffer); if (pSrcBuffer == NULL || pDestBuffer == NULL) return BadValue; @@ -827,31 +935,28 @@ DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) return FALSE; } -int -DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, - CARD64 divisor, CARD64 remainder, CARD64 *swap_target, - DRI2SwapEventPtr func, void *data) +static int +swap_buffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + CARD64 divisor, CARD64 remainder, CARD64 *swap_target, + DRI2SwapEventPtr func, void *data, + Bool vid, unsigned int source, BoxPtr b) { ScreenPtr pScreen = pDraw->pScreen; DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); - DRI2DrawablePtr pPriv; + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw); DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; - int ret, i; + int ret; CARD64 ust, current_msc; - pPriv = DRI2GetDrawable(pDraw); - if (pPriv == NULL) { + if ((pPriv == NULL) || (vid && !supports_video(ds))) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[DRI2] %s: bad drawable\n", __func__); return BadDrawable; } - for (i = 0; i < pPriv->bufferCount; i++) { - if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) - pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; - if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) - pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; - } + find_attachment(pPriv, DRI2BufferFrontLeft, &pDestBuffer); + find_attachment(pPriv, source, &pSrcBuffer); + if (pSrcBuffer == NULL || pDestBuffer == NULL) { xf86DrvMsg(pScreen->myNum, X_ERROR, "[DRI2] %s: drawable has no back or front?\n", __func__); @@ -859,7 +964,7 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, } /* Old DDX or no swap interval, just blit */ - if (!ds->ScheduleSwap || !pPriv->swap_interval) { + if ((!ds->ScheduleSwap || !pPriv->swap_interval) && !vid) { BoxRec box; RegionRec region; @@ -895,7 +1000,6 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, if (current_msc < pPriv->last_swap_target) pPriv->last_swap_target = current_msc; - } /* @@ -911,8 +1015,14 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, } pPriv->swapsPending++; - ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, - swap_target, divisor, remainder, func, data); + if (vid) { + DrawablePtr osd = NULL; // TODO + ret = (*ds->ScheduleSwapVid)(client, pDraw, pDestBuffer, pSrcBuffer, + b, osd, swap_target, divisor, remainder, func, data); + } else { + ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, + swap_target, divisor, remainder, func, data); + } if (!ret) { pPriv->swapsPending--; /* didn't schedule */ xf86DrvMsg(pScreen->myNum, X_ERROR, @@ -927,11 +1037,31 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, */ *swap_target = pPriv->swap_count + pPriv->swapsPending; - DRI2InvalidateDrawable(pDraw); + if (!vid) { + DRI2InvalidateDrawable(pDraw); + } return Success; } +int +DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + CARD64 divisor, CARD64 remainder, CARD64 *swap_target, + DRI2SwapEventPtr func, void *data) +{ + return swap_buffers(client, pDraw, target_msc, divisor, remainder, + swap_target, func, data, FALSE, DRI2BufferBackLeft, NULL); +} + +int +DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, + CARD64 divisor, CARD64 remainder, CARD64 *swap_target, + unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data) +{ + return swap_buffers(client, pDraw, target_msc, divisor, remainder, + swap_target, func, data, TRUE, source, b); +} + void DRI2SwapInterval(DrawablePtr pDrawable, int interval) { @@ -1049,6 +1179,77 @@ DRI2HasSwapControl(ScreenPtr pScreen) return ds->ScheduleSwap && ds->GetMSC; } +#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* length in multiple of CARD32's, passed in value should be copied by + * receiver + */ +int +DRI2SetAttribute(DrawablePtr pDraw, Atom attribute, int len, const CARD32 *val) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + int ret = BadMatch; + + if (!supports_video(ds)) { + return BadDrawable; + } + + if (attribute == ATOM("XV_OSD")) { + } else if (ds->SetAttribute) { + ret = (*ds->SetAttribute)(pDraw, attribute, len, val); + } + + return ret; +} + +/* length in multiple of CARD32's, returned val should *not* be free'd + * (unlike similar function on client side) to avoid temporary allocation + * and extra copy. + */ +int +DRI2GetAttribute(DrawablePtr pDraw, Atom attribute, int *len, const CARD32 **val) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + int ret = BadMatch; + + if (!supports_video(ds)) { + return BadDrawable; + } + + if (attribute == ATOM("XV_OSD")) { + } else if (ds->GetAttribute) { + ret = (*ds->GetAttribute)(pDraw, attribute, len, val); + } + + return ret; +} + +int +DRI2GetFormats(ScreenPtr pScreen, unsigned int *nformats, unsigned int **formats) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pScreen); + + if (! supports_video(ds)) { + return BadDrawable; + } + + *nformats = ds->numFormats; + *formats = ds->formats; + + return Success; +} + +unsigned int +DRI2GetExtraBufferNames(DrawablePtr pDraw, DRI2BufferPtr buf, + unsigned int **names, unsigned int **pitches) +{ + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); + if (ds->GetExtraBufferNames) { + return (*ds->GetExtraBufferNames)(pDraw, buf, names, pitches); + } + return 0; +} + Bool DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, const char **driverName, const char **deviceName) @@ -1116,9 +1317,10 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) const char* driverTypeNames[] = { "DRI", /* DRI2DriverDRI */ "VDPAU", /* DRI2DriverVDPAU */ + "XV", /* DRI2DriverXV */ }; unsigned int i; - CARD8 cur_minor; + CARD8 cur_minor = 1; if (info->version < 3) return FALSE; @@ -1156,8 +1358,6 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) ds->ScheduleWaitMSC = info->ScheduleWaitMSC; ds->GetMSC = info->GetMSC; cur_minor = 3; - } else { - cur_minor = 1; } if (info->version >= 5) { @@ -1169,6 +1369,34 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) ds->SwapLimitValidate = info->SwapLimitValidate; } + if (info->version >= 7) { + if ((info->numDrivers > DRI2DriverXV) && + info->driverNames[DRI2DriverXV]) { + /* if driver claims to support DRI2DriverXV, then ensure + * it provides the required fxn ptrs: + */ + if (!info->CreateBufferVid || !info->ScheduleSwapVid) { + xf86DrvMsg(pScreen->myNum, X_WARNING, + "[DRI2] DRI2DriverXV must implement " + "CreateBuffersVid and ScheduleSwapVid.\n"); + goto err_out; + } + } + ds->numFormats = info->numFormats; + ds->formats = malloc(info->numFormats * sizeof(*ds->formats)); + if (!ds->formats) + goto err_out; + memcpy(ds->formats, info->formats, + info->numFormats * sizeof(*ds->formats)); + ds->GetExtraBufferNames = info->GetExtraBufferNames; + ds->CreateBufferVid = info->CreateBufferVid; + ds->ScheduleSwapVid = info->ScheduleSwapVid; + ds->SetAttribute = info->SetAttribute; + ds->GetAttribute = info->GetAttribute; + + cur_minor = 4; + } + /* * if the driver doesn't provide an AuthMagic function or the info struct * version is too low, it relies on the old method (using libdrm) or fail @@ -1218,6 +1446,10 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) err_out: xf86DrvMsg(pScreen->myNum, X_WARNING, "[DRI2] Initialization failed for info version %d.\n", info->version); + if (ds) { + free(ds->formats); + free(ds->driverNames); + } free(ds); return FALSE; } diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h index 9c93209..984943b 100644 --- a/hw/xfree86/dri2/dri2.h +++ b/hw/xfree86/dri2/dri2.h @@ -104,9 +104,60 @@ typedef int (*DRI2ScheduleSwapProcPtr)(ClientPtr client, CARD64 remainder, DRI2SwapEventPtr func, void *data); + +/** + * Schedule a video buffer swap + * + * Drivers should queue an event for the frame count that satisfies the + * parameters passed in. If the event is in the future (i.e. the conditions + * aren't currently satisfied), the server may block the client at the next + * GLX request using DRI2WaitSwap. When the event arrives, drivers should call + * \c DRI2SwapComplete, which will handle waking the client and returning + * the appropriate data. + * + * The DDX is responsible for doing an overlay buffer flip/exchange, or + * scaling/colorconvert blit when the corresponding event arrives. + * + * If the target drawable is resized/damaged, or the osd pixmap is changed/ + * damaged, ScheduleSwapVid can be re-invoked by the core with the same + * source buffer to repair the dri2 video drawable. + * XXX TODO this part isn't implemented in core yet.. + * + * \param client client pointer (used for block/unblock) + * \param pDraw drawable whose count we want + * \param pDestBuffer current front buffer + * \param pSrcBuffer current back buffer + * \param b the crop box + * \param osd the on-screen-display overlay pixmap, should be an ARGB pixmap + * that is blended on top of the video as part of swap. Multiple layers + * to blend over the video should be flattened into a single layer by the + * client + * \param target_msc frame count to wait for + * \param divisor divisor for condition equation + * \param remainder remainder for division equation + * \param func function to call when the swap completes + * \param data data for the callback \p func. + */ +typedef int (*DRI2ScheduleSwapVidProcPtr)(ClientPtr client, + DrawablePtr pDraw, + DRI2BufferPtr pDestBuffer, + DRI2BufferPtr pSrcBuffer, + BoxPtr b, + DrawablePtr osd, + CARD64 *target_msc, + CARD64 divisor, + CARD64 remainder, + DRI2SwapEventPtr func, + void *data); + typedef DRI2BufferPtr (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw, unsigned int attachment, unsigned int format); +typedef DRI2BufferPtr (*DRI2CreateBufferVidProcPtr)(DrawablePtr pDraw, + unsigned int attachment, + unsigned int format, + unsigned int width, + unsigned int height); typedef void (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw, DRI2BufferPtr buffer); /** @@ -181,10 +232,46 @@ typedef void (*DRI2InvalidateProcPtr)(DrawablePtr pDraw, typedef Bool (*DRI2SwapLimitValidateProcPtr)(DrawablePtr pDraw, int swap_limit); + +/** + * An ugly approach to avoid changing DRI2BufferPtr and cause ABI breakage + * between driver and xserver. This only needs to be implemented by drivers + * supporting planar formats with one buffer per plane. + * + * This might be a good argument for having drivers in-tree ;-) + * + * \param pDraw drawable that the buffer belongs to + * \param buf the DRI2 buffer + * \param names array of buffer names + * \param pitches array of buffer pitches + * \return the number of additional buffers, ie. for I420 tri-planar buffer, + * if represented as multiple buffer names, the Y buffer name would be in + * buf->name, this function would return 2, and return the U and V buffer + * names by reference. + */ +typedef unsigned int (*DRI2GetExtraBufferNamesProcPtr)(DrawablePtr pDraw, + DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches); + +/** + * Length in multiple of CARD32's, passed in value should be copied by + * receiver + */ +typedef int (*DRI2SetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute, + int len, const CARD32 *val); + +/** + * Length in multiple of CARD32's, returned val should *not* be free'd + * (unlike similar function on client side) to avoid temporary allocation + * and extra copy. + */ +typedef int (*DRI2GetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute, + int *len, const CARD32 **val); + + /** * Version of the DRI2InfoRec structure defined in this header */ -#define DRI2INFOREC_VERSION 6 +#define DRI2INFOREC_VERSION 7 typedef struct { unsigned int version; /**< Version of this struct */ @@ -217,6 +304,17 @@ typedef struct { DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify; DRI2SwapLimitValidateProcPtr SwapLimitValidate; + + /* added in version 7 */ + + unsigned int numFormats; + const unsigned int *formats; + DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames; + DRI2CreateBufferVidProcPtr CreateBufferVid; + DRI2ScheduleSwapVidProcPtr ScheduleSwapVid; + DRI2SetAttributeProcPtr SetAttribute; + DRI2GetAttributeProcPtr GetAttribute; + } DRI2InfoRec, *DRI2InfoPtr; extern _X_EXPORT int DRI2EventBase; @@ -278,12 +376,21 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, unsigned int *attachments, int count, int *out_count); +extern _X_EXPORT DRI2BufferPtr * DRI2GetBuffersVid(DrawablePtr pDraw, + int width, int height, unsigned int *attachments, int count, + int *out_count); + extern _X_EXPORT void DRI2SwapInterval(DrawablePtr pDrawable, int interval); extern _X_EXPORT Bool DRI2SwapLimit(DrawablePtr pDraw, int swap_limit); extern _X_EXPORT int DRI2SwapBuffers(ClientPtr client, DrawablePtr pDrawable, CARD64 target_msc, CARD64 divisor, CARD64 remainder, CARD64 *swap_target, DRI2SwapEventPtr func, void *data); + +extern _X_EXPORT int DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw, + CARD64 target_msc, CARD64 divisor, CARD64 remainder, CARD64 *swap_target, + unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data); + extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable); extern _X_EXPORT int DRI2GetMSC(DrawablePtr pDrawable, CARD64 *ust, @@ -313,4 +420,22 @@ extern _X_EXPORT void DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, unsigned int tv_sec, unsigned int tv_usec); +extern _X_EXPORT int DRI2SetAttribute(DrawablePtr pDraw, Atom attribute, + int len, const CARD32 *val); +extern _X_EXPORT int DRI2GetAttribute(DrawablePtr pDraw, Atom attribute, + int *len, const CARD32 **val); +extern _X_EXPORT int DRI2GetFormats(ScreenPtr pScreen, + unsigned int *nformats, unsigned int **formats); + +extern _X_EXPORT unsigned int DRI2GetExtraBufferNames(DrawablePtr pDraw, + DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches); + + +/* some utility macros.. maybe could go elsewhere? */ +#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 )) +#define FOURCC_STR(str) FOURCC(str[0], str[1], str[2], str[3]) +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + #endif diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c index 934abf6..e0250b9 100644 --- a/hw/xfree86/dri2/dri2ext.c +++ b/hw/xfree86/dri2/dri2ext.c @@ -76,6 +76,7 @@ ProcDRI2QueryVersion(ClientPtr client) swaps(&stuff->length); REQUEST_SIZE_MATCH(xDRI2QueryVersionReq); + rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; @@ -204,12 +205,13 @@ ProcDRI2DestroyDrawable(ClientPtr client) static int -send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, +send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, int vid, DRI2BufferPtr *buffers, int count, int width, int height) { xDRI2GetBuffersReply rep; - int skip = 0; - int i; + int skip = 0, extra = 0; + unsigned int *names, *pitches; + int i, j; if (buffers == NULL) return BadAlloc; @@ -225,8 +227,24 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, } } + if (vid) { + extra = 4 * (count - skip); + + for (i = 0; i < count; i++) { + /* Do not send the real front buffer of a window to the client. + */ + if ((pDrawable->type == DRAWABLE_WINDOW) + && (buffers[i]->attachment == DRI2BufferFrontLeft)) { + continue; + } + + extra += 8 * DRI2GetExtraBufferNames(pDrawable, buffers[i], + &names, &pitches); + } + } + rep.type = X_Reply; - rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4; + rep.length = ((count - skip) * sizeof(xDRI2Buffer) + extra) / 4; rep.sequenceNumber = client->sequence; rep.width = width; rep.height = height; @@ -249,6 +267,17 @@ send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, buffer.cpp = buffers[i]->cpp; buffer.flags = buffers[i]->flags; WriteToClient(client, sizeof(xDRI2Buffer), &buffer); + + if (vid) { + CARD32 n = DRI2GetExtraBufferNames(pDrawable, buffers[i], + &names, &pitches); + WriteToClient(client, sizeof(n), &n); + for (j = 0; j < n; j++) { + CARD32 name = names[j], pitch = pitches[j]; + WriteToClient(client, sizeof(name), &name); + WriteToClient(client, sizeof(pitch), &pitch); + } + } } return Success; } @@ -276,8 +305,8 @@ ProcDRI2GetBuffers(ClientPtr client) attachments, stuff->count, &count); - return send_buffers_reply(client, pDrawable, buffers, count, width, height); - + return send_buffers_reply(client, pDrawable, FALSE, + buffers, count, width, height); } static int @@ -301,7 +330,40 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client) buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, attachments, stuff->count, &count); - return send_buffers_reply(client, pDrawable, buffers, count, width, height); + return send_buffers_reply(client, pDrawable, FALSE, + buffers, count, width, height); +} + +static int +ProcDRI2GetBuffersVid(ClientPtr client) +{ + REQUEST(xDRI2GetBuffersVidReq); + DrawablePtr pDrawable; + DRI2BufferPtr *buffers; + int status, count; + unsigned int *attachments; + + REQUEST_FIXED_SIZE(xDRI2GetBuffersVidReq, stuff->count * (2 * 4)); + if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess, + &pDrawable, &status)) + return status; + + if (DRI2ThrottleClient(client, pDrawable)) + return Success; + + attachments = (unsigned int *) &stuff[1]; + buffers = DRI2GetBuffersVid(pDrawable, stuff->width, stuff->height, + attachments, stuff->count, &count); + + status = send_buffers_reply(client, pDrawable, TRUE, buffers, count, 0, 0); + + /* note, unlike other DRI2GetBuffers variants, we allow requesting/ + * returning just a subset of buffers.. so array that is returned is + * not the one held in pPriv, so must be free'd + */ + free(buffers); + + return status; } static int @@ -414,6 +476,53 @@ ProcDRI2SwapBuffers(ClientPtr client) return Success; } +static int +ProcDRI2SwapBuffersVid(ClientPtr client) +{ + REQUEST(xDRI2SwapBuffersVidReq); + xDRI2SwapBuffersReply rep; + DrawablePtr pDrawable; + CARD64 target_msc, divisor, remainder, swap_target; + BoxRec b; + int status; + + REQUEST_SIZE_MATCH(xDRI2SwapBuffersVidReq); + + if (!validDrawable(client, stuff->drawable, + DixReadAccess | DixWriteAccess, &pDrawable, &status)) + return status; + + /* + * Ensures an out of control client can't exhaust our swap queue, and + * also orders swaps. + */ + if (DRI2ThrottleClient(client, pDrawable)) + return Success; + + target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); + divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); + remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); + + b.x1 = stuff->x1; + b.y1 = stuff->y1; + b.x2 = stuff->x2; + b.y2 = stuff->y2; + + status = DRI2SwapBuffersVid(client, pDrawable, target_msc, divisor, remainder, + &swap_target, stuff->source, &b, DRI2SwapEvent, pDrawable); + if (status != Success) + return BadDrawable; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + load_swap_reply(&rep, swap_target); + + WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep); + + return Success; +} + static void load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc) { @@ -537,6 +646,87 @@ ProcDRI2WaitSBC(ClientPtr client) } static int +ProcDRI2SetAttribute(ClientPtr client) +{ + REQUEST(xDRI2SetAttributeReq); + DrawablePtr pDrawable; + int status; + int len = (stuff->length * 4 - sizeof(xDRI2SetAttributeReq)) / 4; + + REQUEST_FIXED_SIZE(xDRI2SetAttributeReq, len * 4); + + if (!validDrawable(client, stuff->drawable, + DixReadAccess | DixWriteAccess, &pDrawable, &status)) + return status; + + status = DRI2SetAttribute(pDrawable, stuff->attribute, len, + (const CARD32 *)&stuff[1]); + if (status != Success) + return status; + + return Success; +} + +static int +ProcDRI2GetAttribute(ClientPtr client) +{ + REQUEST(xDRI2GetAttributeReq); + xDRI2GetAttributeReply rep; + DrawablePtr pDrawable; + const CARD32 *val; + int status, len; + + REQUEST_SIZE_MATCH(xDRI2GetAttributeReq); + + if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, + &status)) + return status; + + status = DRI2GetAttribute(pDrawable, stuff->attribute, &len, &val); + if (status != Success) + return status; + + rep.type = X_Reply; + rep.length = len; + rep.sequenceNumber = client->sequence; + WriteToClient(client, sizeof(xDRI2GetAttributeReply), &rep); + WriteToClient(client, len * 4, val); + + return Success; +} + +static int +ProcDRI2GetFormats(ClientPtr client) +{ + REQUEST(xDRI2GetFormatsReq); + xDRI2GetFormatsReply rep; + DrawablePtr pDrawable; + unsigned int i, nformats, *formats; + int status; + + REQUEST_SIZE_MATCH(xDRI2GetFormatsReq); + + if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, + &status)) + return status; + + status = DRI2GetFormats(pDrawable->pScreen, &nformats, &formats); + if (status != Success) + return status; + + rep.type = X_Reply; + rep.length = nformats * sizeof(*formats) / 4; + rep.sequenceNumber = client->sequence; + WriteToClient(client, sizeof(xDRI2GetFormatsReply), &rep); + + for (i = 0; i < nformats; i++) { + WriteToClient(client, sizeof(formats[i]), &formats[i]); + } + + return Success; +} + +static int ProcDRI2Dispatch (ClientPtr client) { REQUEST(xReq); @@ -574,6 +764,16 @@ ProcDRI2Dispatch (ClientPtr client) return ProcDRI2WaitSBC(client); case X_DRI2SwapInterval: return ProcDRI2SwapInterval(client); + case X_DRI2GetBuffersVid: + return ProcDRI2GetBuffersVid(client); + case X_DRI2SwapBuffersVid: + return ProcDRI2SwapBuffersVid(client); + case X_DRI2SetAttribute: + return ProcDRI2SetAttribute(client); + case X_DRI2GetAttribute: + return ProcDRI2GetAttribute(client); + case X_DRI2GetFormats: + return ProcDRI2GetFormats(client); default: return BadRequest; } -- 1.7.5.4 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel