intel_dri.c revision 13496ba1
103b705cfSriastradh/************************************************************************** 203b705cfSriastradh 303b705cfSriastradhCopyright 2001 VA Linux Systems Inc., Fremont, California. 403b705cfSriastradhCopyright © 2002 by David Dawes 503b705cfSriastradh 603b705cfSriastradhAll Rights Reserved. 703b705cfSriastradh 803b705cfSriastradhPermission is hereby granted, free of charge, to any person obtaining a 903b705cfSriastradhcopy of this software and associated documentation files (the "Software"), 1003b705cfSriastradhto deal in the Software without restriction, including without limitation 1103b705cfSriastradhon the rights to use, copy, modify, merge, publish, distribute, sub 1203b705cfSriastradhlicense, and/or sell copies of the Software, and to permit persons to whom 1303b705cfSriastradhthe Software is furnished to do so, subject to the following conditions: 1403b705cfSriastradh 1503b705cfSriastradhThe above copyright notice and this permission notice (including the next 1603b705cfSriastradhparagraph) shall be included in all copies or substantial portions of the 1703b705cfSriastradhSoftware. 1803b705cfSriastradh 1903b705cfSriastradhTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2003b705cfSriastradhIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2103b705cfSriastradhFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2203b705cfSriastradhATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 2303b705cfSriastradhDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2403b705cfSriastradhOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2503b705cfSriastradhUSE OR OTHER DEALINGS IN THE SOFTWARE. 2603b705cfSriastradh 2703b705cfSriastradh**************************************************************************/ 2803b705cfSriastradh 2903b705cfSriastradh/* 3003b705cfSriastradh * Authors: Jeff Hartmann <jhartmann@valinux.com> 3103b705cfSriastradh * David Dawes <dawes@xfree86.org> 3203b705cfSriastradh * Keith Whitwell <keith@tungstengraphics.com> 3303b705cfSriastradh */ 3403b705cfSriastradh 3503b705cfSriastradh#ifdef HAVE_CONFIG_H 3603b705cfSriastradh#include "config.h" 3703b705cfSriastradh#endif 3803b705cfSriastradh 3903b705cfSriastradh#include <stdio.h> 4003b705cfSriastradh#include <string.h> 4103b705cfSriastradh#include <assert.h> 4203b705cfSriastradh#include <sys/types.h> 4303b705cfSriastradh#include <sys/stat.h> 4403b705cfSriastradh#include <sys/ioctl.h> 4503b705cfSriastradh#include <unistd.h> 4603b705cfSriastradh#include <fcntl.h> 4703b705cfSriastradh#include <sys/time.h> 4803b705cfSriastradh#include <time.h> 4903b705cfSriastradh#include <errno.h> 5003b705cfSriastradh 5142542f5fSchristos#include "xorg-server.h" 5203b705cfSriastradh#include "xf86.h" 5303b705cfSriastradh#include "xf86_OSproc.h" 5403b705cfSriastradh 5503b705cfSriastradh#include "xf86Pci.h" 5603b705cfSriastradh#include "xf86drm.h" 5703b705cfSriastradh 5803b705cfSriastradh#include "windowstr.h" 5903b705cfSriastradh#include "shadow.h" 6003b705cfSriastradh#include "fb.h" 6103b705cfSriastradh 6203b705cfSriastradh#include "intel.h" 6303b705cfSriastradh#include "i830_reg.h" 6403b705cfSriastradh 6503b705cfSriastradh#include "i915_drm.h" 6603b705cfSriastradh 6703b705cfSriastradh#include "dri2.h" 6803b705cfSriastradh 6913496ba1Ssnj#if USE_UXA 7013496ba1Ssnj#include "intel_uxa.h" 7113496ba1Ssnj#endif 7203b705cfSriastradh 7303b705cfSriastradhtypedef struct { 7403b705cfSriastradh int refcnt; 7503b705cfSriastradh PixmapPtr pixmap; 7603b705cfSriastradh} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; 7703b705cfSriastradh 7803b705cfSriastradh#if HAS_DEVPRIVATEKEYREC 7903b705cfSriastradhstatic DevPrivateKeyRec i830_client_key; 8003b705cfSriastradh#else 8103b705cfSriastradhstatic int i830_client_key; 8203b705cfSriastradh#endif 8303b705cfSriastradh 8403b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap) 8503b705cfSriastradh{ 8613496ba1Ssnj struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap); 8703b705cfSriastradh uint32_t name; 8803b705cfSriastradh 8903b705cfSriastradh if (priv == NULL || priv->bo == NULL) 9003b705cfSriastradh return 0; 9103b705cfSriastradh 9203b705cfSriastradh if (dri_bo_flink(priv->bo, &name) != 0) 9303b705cfSriastradh return 0; 9403b705cfSriastradh 9542542f5fSchristos priv->pinned |= PIN_DRI2; 9603b705cfSriastradh return name; 9703b705cfSriastradh} 9803b705cfSriastradh 9903b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable) 10003b705cfSriastradh{ 10103b705cfSriastradh PixmapPtr pixmap; 10203b705cfSriastradh 10303b705cfSriastradh pixmap = get_drawable_pixmap(drawable); 10403b705cfSriastradh if (!intel_get_pixmap_bo(pixmap)) 10503b705cfSriastradh return NULL; 10603b705cfSriastradh 10703b705cfSriastradh pixmap->refcnt++; 10803b705cfSriastradh return pixmap; 10903b705cfSriastradh} 11003b705cfSriastradh 11103b705cfSriastradh#if DRI2INFOREC_VERSION < 2 11203b705cfSriastradhstatic DRI2BufferPtr 11303b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments, 11403b705cfSriastradh int count) 11503b705cfSriastradh{ 11603b705cfSriastradh ScreenPtr screen = drawable->pScreen; 11703b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 11803b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 11903b705cfSriastradh DRI2BufferPtr buffers; 12003b705cfSriastradh I830DRI2BufferPrivatePtr privates; 12103b705cfSriastradh PixmapPtr pixmap, pDepthPixmap; 12203b705cfSriastradh int i; 12303b705cfSriastradh 12403b705cfSriastradh buffers = calloc(count, sizeof *buffers); 12503b705cfSriastradh if (buffers == NULL) 12603b705cfSriastradh return NULL; 12703b705cfSriastradh privates = calloc(count, sizeof *privates); 12803b705cfSriastradh if (privates == NULL) { 12903b705cfSriastradh free(buffers); 13003b705cfSriastradh return NULL; 13103b705cfSriastradh } 13203b705cfSriastradh 13303b705cfSriastradh pDepthPixmap = NULL; 13403b705cfSriastradh for (i = 0; i < count; i++) { 13503b705cfSriastradh pixmap = NULL; 13603b705cfSriastradh if (attachments[i] == DRI2BufferFrontLeft) { 13703b705cfSriastradh pixmap = get_front_buffer(drawable); 13803b705cfSriastradh 13913496ba1Ssnj if (pixmap == NULL) 14003b705cfSriastradh drawable = &(get_drawable_pixmap(drawable)->drawable); 14103b705cfSriastradh } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 14203b705cfSriastradh pixmap = pDepthPixmap; 14303b705cfSriastradh pixmap->refcnt++; 14403b705cfSriastradh } 14503b705cfSriastradh 14603b705cfSriastradh if (pixmap == NULL) { 14703b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 14803b705cfSriastradh 14903b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 15003b705cfSriastradh switch (attachments[i]) { 15103b705cfSriastradh case DRI2BufferDepth: 15203b705cfSriastradh if (SUPPORTS_YTILING(intel)) 15303b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 15403b705cfSriastradh else 15503b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 15603b705cfSriastradh break; 15703b705cfSriastradh case DRI2BufferFakeFrontLeft: 15803b705cfSriastradh case DRI2BufferFakeFrontRight: 15903b705cfSriastradh case DRI2BufferBackLeft: 16003b705cfSriastradh case DRI2BufferBackRight: 16103b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 16203b705cfSriastradh break; 16303b705cfSriastradh } 16403b705cfSriastradh } 16503b705cfSriastradh 16603b705cfSriastradh pixmap = screen->CreatePixmap(screen, 16703b705cfSriastradh drawable->width, 16803b705cfSriastradh drawable->height, 16903b705cfSriastradh drawable->depth, 17003b705cfSriastradh hint); 17103b705cfSriastradh if (pixmap == NULL || 17203b705cfSriastradh intel_get_pixmap_bo(pixmap) == NULL) 17303b705cfSriastradh { 17403b705cfSriastradh if (pixmap) 17503b705cfSriastradh screen->DestroyPixmap(pixmap); 17603b705cfSriastradh goto unwind; 17703b705cfSriastradh } 17803b705cfSriastradh } 17903b705cfSriastradh 18003b705cfSriastradh if (attachments[i] == DRI2BufferDepth) 18103b705cfSriastradh pDepthPixmap = pixmap; 18203b705cfSriastradh 18303b705cfSriastradh buffers[i].attachment = attachments[i]; 18403b705cfSriastradh buffers[i].pitch = pixmap->devKind; 18503b705cfSriastradh buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 18603b705cfSriastradh buffers[i].driverPrivate = &privates[i]; 18703b705cfSriastradh buffers[i].flags = 0; /* not tiled */ 18803b705cfSriastradh privates[i].refcnt = 1; 18903b705cfSriastradh privates[i].pixmap = pixmap; 19003b705cfSriastradh 19103b705cfSriastradh if ((buffers[i].name = pixmap_flink(pixmap)) == 0) { 19203b705cfSriastradh /* failed to name buffer */ 19303b705cfSriastradh screen->DestroyPixmap(pixmap); 19403b705cfSriastradh goto unwind; 19503b705cfSriastradh } 19603b705cfSriastradh } 19703b705cfSriastradh 19803b705cfSriastradh return buffers; 19903b705cfSriastradh 20003b705cfSriastradhunwind: 20103b705cfSriastradh while (i--) 20203b705cfSriastradh screen->DestroyPixmap(privates[i].pixmap); 20303b705cfSriastradh free(privates); 20403b705cfSriastradh free(buffers); 20503b705cfSriastradh return NULL; 20603b705cfSriastradh} 20703b705cfSriastradh 20803b705cfSriastradhstatic void 20903b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count) 21003b705cfSriastradh{ 21103b705cfSriastradh ScreenPtr screen = drawable->pScreen; 21203b705cfSriastradh I830DRI2BufferPrivatePtr private; 21303b705cfSriastradh int i; 21403b705cfSriastradh 21503b705cfSriastradh for (i = 0; i < count; i++) { 21603b705cfSriastradh private = buffers[i].driverPrivate; 21703b705cfSriastradh screen->DestroyPixmap(private->pixmap); 21803b705cfSriastradh } 21903b705cfSriastradh 22003b705cfSriastradh if (buffers) { 22103b705cfSriastradh free(buffers[0].driverPrivate); 22203b705cfSriastradh free(buffers); 22303b705cfSriastradh } 22403b705cfSriastradh} 22503b705cfSriastradh 22603b705cfSriastradh#else 22703b705cfSriastradh 22803b705cfSriastradhstatic DRI2Buffer2Ptr 22903b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, 23003b705cfSriastradh unsigned int format) 23103b705cfSriastradh{ 23203b705cfSriastradh ScreenPtr screen = drawable->pScreen; 23303b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 23403b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 23503b705cfSriastradh DRI2Buffer2Ptr buffer; 23603b705cfSriastradh I830DRI2BufferPrivatePtr privates; 23703b705cfSriastradh PixmapPtr pixmap; 23803b705cfSriastradh 23903b705cfSriastradh buffer = calloc(1, sizeof *buffer); 24003b705cfSriastradh if (buffer == NULL) 24103b705cfSriastradh return NULL; 24203b705cfSriastradh privates = calloc(1, sizeof *privates); 24303b705cfSriastradh if (privates == NULL) { 24403b705cfSriastradh free(buffer); 24503b705cfSriastradh return NULL; 24603b705cfSriastradh } 24703b705cfSriastradh 24803b705cfSriastradh pixmap = NULL; 24903b705cfSriastradh if (attachment == DRI2BufferFrontLeft) { 25003b705cfSriastradh pixmap = get_front_buffer(drawable); 25113496ba1Ssnj if (pixmap == NULL) 25203b705cfSriastradh drawable = &(get_drawable_pixmap(drawable)->drawable); 25303b705cfSriastradh } 25403b705cfSriastradh 25503b705cfSriastradh if (pixmap == NULL) { 25603b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 25703b705cfSriastradh int pixmap_width = drawable->width; 25803b705cfSriastradh int pixmap_height = drawable->height; 25903b705cfSriastradh int pixmap_cpp = (format != 0) ? format : drawable->depth; 26003b705cfSriastradh 26103b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 26203b705cfSriastradh switch (attachment) { 26303b705cfSriastradh case DRI2BufferDepth: 26403b705cfSriastradh case DRI2BufferDepthStencil: 26503b705cfSriastradh case DRI2BufferHiz: 26603b705cfSriastradh if (SUPPORTS_YTILING(intel)) { 26703b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 26803b705cfSriastradh break; 26903b705cfSriastradh } 27003b705cfSriastradh case DRI2BufferAccum: 27103b705cfSriastradh case DRI2BufferBackLeft: 27203b705cfSriastradh case DRI2BufferBackRight: 27303b705cfSriastradh case DRI2BufferFakeFrontLeft: 27403b705cfSriastradh case DRI2BufferFakeFrontRight: 27503b705cfSriastradh case DRI2BufferFrontLeft: 27603b705cfSriastradh case DRI2BufferFrontRight: 27703b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 27803b705cfSriastradh break; 27903b705cfSriastradh case DRI2BufferStencil: 28003b705cfSriastradh /* 28103b705cfSriastradh * The stencil buffer is W tiled. However, we 28203b705cfSriastradh * request from the kernel a non-tiled buffer 28303b705cfSriastradh * because the GTT is incapable of W fencing. 28403b705cfSriastradh */ 28503b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_NONE; 28603b705cfSriastradh break; 28703b705cfSriastradh default: 28803b705cfSriastradh free(privates); 28903b705cfSriastradh free(buffer); 29003b705cfSriastradh return NULL; 29103b705cfSriastradh } 29203b705cfSriastradh } 29303b705cfSriastradh 29403b705cfSriastradh /* 29503b705cfSriastradh * The stencil buffer has quirky pitch requirements. From Vol 29603b705cfSriastradh * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 29703b705cfSriastradh * Pitch": 29803b705cfSriastradh * The pitch must be set to 2x the value computed based on 29903b705cfSriastradh * width, as the stencil buffer is stored with two rows 30003b705cfSriastradh * interleaved. 30103b705cfSriastradh * To accomplish this, we resort to the nasty hack of doubling 30203b705cfSriastradh * the drm region's cpp and halving its height. 30303b705cfSriastradh * 30403b705cfSriastradh * If we neglect to double the pitch, then render corruption 30503b705cfSriastradh * occurs. 30603b705cfSriastradh */ 30703b705cfSriastradh if (attachment == DRI2BufferStencil) { 30803b705cfSriastradh pixmap_width = ALIGN(pixmap_width, 64); 30903b705cfSriastradh pixmap_height = ALIGN((pixmap_height + 1) / 2, 64); 31003b705cfSriastradh pixmap_cpp *= 2; 31103b705cfSriastradh } 31203b705cfSriastradh 31303b705cfSriastradh pixmap = screen->CreatePixmap(screen, 31403b705cfSriastradh pixmap_width, 31503b705cfSriastradh pixmap_height, 31603b705cfSriastradh pixmap_cpp, 31703b705cfSriastradh hint); 31803b705cfSriastradh if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) { 31903b705cfSriastradh if (pixmap) 32003b705cfSriastradh screen->DestroyPixmap(pixmap); 32103b705cfSriastradh free(privates); 32203b705cfSriastradh free(buffer); 32303b705cfSriastradh return NULL; 32403b705cfSriastradh } 32503b705cfSriastradh } 32603b705cfSriastradh 32703b705cfSriastradh buffer->attachment = attachment; 32803b705cfSriastradh buffer->pitch = pixmap->devKind; 32903b705cfSriastradh buffer->cpp = pixmap->drawable.bitsPerPixel / 8; 33003b705cfSriastradh buffer->driverPrivate = privates; 33103b705cfSriastradh buffer->format = format; 33203b705cfSriastradh buffer->flags = 0; /* not tiled */ 33303b705cfSriastradh privates->refcnt = 1; 33403b705cfSriastradh privates->pixmap = pixmap; 33503b705cfSriastradh 33603b705cfSriastradh if ((buffer->name = pixmap_flink(pixmap)) == 0) { 33703b705cfSriastradh /* failed to name buffer */ 33803b705cfSriastradh screen->DestroyPixmap(pixmap); 33903b705cfSriastradh free(privates); 34003b705cfSriastradh free(buffer); 34103b705cfSriastradh return NULL; 34203b705cfSriastradh } 34303b705cfSriastradh 34403b705cfSriastradh return buffer; 34503b705cfSriastradh} 34603b705cfSriastradh 34703b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer) 34803b705cfSriastradh{ 34903b705cfSriastradh if (buffer && buffer->driverPrivate) { 35003b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 35103b705cfSriastradh if (--private->refcnt == 0) { 35203b705cfSriastradh ScreenPtr screen = private->pixmap->drawable.pScreen; 35303b705cfSriastradh screen->DestroyPixmap(private->pixmap); 35403b705cfSriastradh 35503b705cfSriastradh free(private); 35603b705cfSriastradh free(buffer); 35703b705cfSriastradh } 35803b705cfSriastradh } else 35903b705cfSriastradh free(buffer); 36003b705cfSriastradh} 36103b705cfSriastradh 36203b705cfSriastradh#endif 36303b705cfSriastradh 36403b705cfSriastradhstatic void 36503b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion, 36603b705cfSriastradh DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer) 36703b705cfSriastradh{ 36803b705cfSriastradh I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate; 36903b705cfSriastradh I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate; 37003b705cfSriastradh ScreenPtr screen = drawable->pScreen; 37103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 37203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 37303b705cfSriastradh DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft) 37403b705cfSriastradh ? drawable : &srcPrivate->pixmap->drawable; 37503b705cfSriastradh DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft) 37603b705cfSriastradh ? drawable : &dstPrivate->pixmap->drawable; 37703b705cfSriastradh RegionPtr pCopyClip; 37803b705cfSriastradh GCPtr gc; 37903b705cfSriastradh 38003b705cfSriastradh gc = GetScratchGC(dst->depth, screen); 38103b705cfSriastradh if (!gc) 38203b705cfSriastradh return; 38303b705cfSriastradh 38403b705cfSriastradh pCopyClip = REGION_CREATE(screen, NULL, 0); 38503b705cfSriastradh REGION_COPY(screen, pCopyClip, pRegion); 38603b705cfSriastradh (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0); 38703b705cfSriastradh ValidateGC(dst, gc); 38803b705cfSriastradh 38903b705cfSriastradh /* Wait for the scanline to be outside the region to be copied */ 39003b705cfSriastradh if (scrn->vtSema && 39103b705cfSriastradh pixmap_is_scanout(get_drawable_pixmap(dst)) && 39203b705cfSriastradh intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) { 39303b705cfSriastradh BoxPtr box; 39403b705cfSriastradh BoxRec crtcbox; 39503b705cfSriastradh int y1, y2; 39603b705cfSriastradh int event, load_scan_lines_pipe; 39703b705cfSriastradh xf86CrtcPtr crtc; 39803b705cfSriastradh Bool full_height = FALSE; 39903b705cfSriastradh 40003b705cfSriastradh box = REGION_EXTENTS(unused, gc->pCompositeClip); 40103b705cfSriastradh crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox); 40203b705cfSriastradh 40303b705cfSriastradh /* 40403b705cfSriastradh * Make sure the CRTC is valid and this is the real front 40503b705cfSriastradh * buffer 40603b705cfSriastradh */ 40703b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) { 40803b705cfSriastradh int pipe = intel_crtc_to_pipe(crtc); 40903b705cfSriastradh 41003b705cfSriastradh /* 41103b705cfSriastradh * Make sure we don't wait for a scanline that will 41203b705cfSriastradh * never occur 41303b705cfSriastradh */ 41403b705cfSriastradh y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 41503b705cfSriastradh y2 = (box->y2 <= crtcbox.y2) ? 41603b705cfSriastradh box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 41703b705cfSriastradh 41803b705cfSriastradh if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1)) 41903b705cfSriastradh full_height = TRUE; 42003b705cfSriastradh 42103b705cfSriastradh /* 42203b705cfSriastradh * Pre-965 doesn't have SVBLANK, so we need a bit 42303b705cfSriastradh * of extra time for the blitter to start up and 42403b705cfSriastradh * do its job for a full height blit 42503b705cfSriastradh */ 42603b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen < 040) 42703b705cfSriastradh y2 -= 2; 42803b705cfSriastradh 42903b705cfSriastradh if (pipe == 0) { 43003b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 43103b705cfSriastradh load_scan_lines_pipe = 43203b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 43303b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 43403b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SVBLANK; 43503b705cfSriastradh } else { 43603b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 43703b705cfSriastradh load_scan_lines_pipe = 43803b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 43903b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 44003b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SVBLANK; 44103b705cfSriastradh } 44203b705cfSriastradh 44303b705cfSriastradh if (crtc->mode.Flags & V_INTERLACE) { 44403b705cfSriastradh /* DSL count field lines */ 44503b705cfSriastradh y1 /= 2; 44603b705cfSriastradh y2 /= 2; 44703b705cfSriastradh } 44803b705cfSriastradh 44903b705cfSriastradh BEGIN_BATCH(5); 45003b705cfSriastradh /* 45103b705cfSriastradh * The documentation says that the LOAD_SCAN_LINES 45203b705cfSriastradh * command always comes in pairs. Don't ask me why. 45303b705cfSriastradh */ 45403b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 45503b705cfSriastradh load_scan_lines_pipe); 45603b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 45703b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 45803b705cfSriastradh load_scan_lines_pipe); 45903b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 46003b705cfSriastradh OUT_BATCH(MI_WAIT_FOR_EVENT | event); 46103b705cfSriastradh ADVANCE_BATCH(); 46203b705cfSriastradh } 46303b705cfSriastradh } 46403b705cfSriastradh 46503b705cfSriastradh /* It's important that this copy gets submitted before the 46603b705cfSriastradh * direct rendering client submits rendering for the next 46703b705cfSriastradh * frame, but we don't actually need to submit right now. The 46803b705cfSriastradh * client will wait for the DRI2CopyRegion reply or the swap 46903b705cfSriastradh * buffer event before rendering, and we'll hit the flush 47003b705cfSriastradh * callback chain before those messages are sent. We submit 47103b705cfSriastradh * our batch buffers from the flush callback chain so we know 47203b705cfSriastradh * that will happen before the client tries to render 47303b705cfSriastradh * again. */ 47403b705cfSriastradh 47503b705cfSriastradh gc->ops->CopyArea(src, dst, gc, 47603b705cfSriastradh 0, 0, 47703b705cfSriastradh drawable->width, drawable->height, 47803b705cfSriastradh 0, 0); 47903b705cfSriastradh 48003b705cfSriastradh FreeScratchGC(gc); 48103b705cfSriastradh 48203b705cfSriastradh /* And make sure the WAIT_FOR_EVENT is queued before any 48303b705cfSriastradh * modesetting/dpms operations on the pipe. 48403b705cfSriastradh */ 48503b705cfSriastradh intel_batch_submit(scrn); 48603b705cfSriastradh} 48703b705cfSriastradh 48803b705cfSriastradhstatic void 48903b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable, 49003b705cfSriastradh DRI2BufferPtr dst, 49103b705cfSriastradh DRI2BufferPtr src) 49203b705cfSriastradh{ 49303b705cfSriastradh BoxRec box; 49403b705cfSriastradh RegionRec region; 49503b705cfSriastradh 49603b705cfSriastradh box.x1 = 0; 49703b705cfSriastradh box.y1 = 0; 49803b705cfSriastradh box.x2 = drawable->width; 49903b705cfSriastradh box.y2 = drawable->height; 50003b705cfSriastradh REGION_INIT(pScreen, ®ion, &box, 0); 50103b705cfSriastradh 50203b705cfSriastradh I830DRI2CopyRegion(drawable, ®ion, dst, src); 50303b705cfSriastradh} 50403b705cfSriastradh 50503b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 50603b705cfSriastradh 50703b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) 50803b705cfSriastradh{ 50903b705cfSriastradh if (buffer) { 51003b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 51103b705cfSriastradh private->refcnt++; 51203b705cfSriastradh } 51303b705cfSriastradh} 51403b705cfSriastradh 51542542f5fSchristosstatic xf86CrtcPtr 51642542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw) 51703b705cfSriastradh{ 51803b705cfSriastradh ScreenPtr pScreen = pDraw->pScreen; 51903b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 52003b705cfSriastradh BoxRec box, crtcbox; 52142542f5fSchristos xf86CrtcPtr crtc = NULL; 52203b705cfSriastradh 52303b705cfSriastradh box.x1 = pDraw->x; 52403b705cfSriastradh box.y1 = pDraw->y; 52503b705cfSriastradh box.x2 = box.x1 + pDraw->width; 52603b705cfSriastradh box.y2 = box.y1 + pDraw->height; 52703b705cfSriastradh 52842542f5fSchristos if (pDraw->type != DRAWABLE_PIXMAP) 52942542f5fSchristos crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 53003b705cfSriastradh 53103b705cfSriastradh /* Make sure the CRTC is valid and this is the real front buffer */ 53203b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) 53342542f5fSchristos return crtc; 53403b705cfSriastradh 53542542f5fSchristos return NULL; 53603b705cfSriastradh} 53703b705cfSriastradh 53803b705cfSriastradhstatic RESTYPE frame_event_client_type, frame_event_drawable_type; 53903b705cfSriastradh 54003b705cfSriastradhstruct i830_dri2_resource { 54103b705cfSriastradh XID id; 54203b705cfSriastradh RESTYPE type; 54303b705cfSriastradh struct list list; 54403b705cfSriastradh}; 54503b705cfSriastradh 54603b705cfSriastradhstatic struct i830_dri2_resource * 54703b705cfSriastradhget_resource(XID id, RESTYPE type) 54803b705cfSriastradh{ 54903b705cfSriastradh struct i830_dri2_resource *resource; 55003b705cfSriastradh void *ptr; 55103b705cfSriastradh 55203b705cfSriastradh ptr = NULL; 55303b705cfSriastradh dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess); 55403b705cfSriastradh if (ptr) 55503b705cfSriastradh return ptr; 55603b705cfSriastradh 55703b705cfSriastradh resource = malloc(sizeof(*resource)); 55803b705cfSriastradh if (resource == NULL) 55903b705cfSriastradh return NULL; 56003b705cfSriastradh 56103b705cfSriastradh if (!AddResource(id, type, resource)) { 56203b705cfSriastradh free(resource); 56303b705cfSriastradh return NULL; 56403b705cfSriastradh } 56503b705cfSriastradh 56603b705cfSriastradh resource->id = id; 56703b705cfSriastradh resource->type = type; 56803b705cfSriastradh list_init(&resource->list); 56903b705cfSriastradh return resource; 57003b705cfSriastradh} 57103b705cfSriastradh 57203b705cfSriastradhstatic int 57303b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id) 57403b705cfSriastradh{ 57503b705cfSriastradh struct i830_dri2_resource *resource = data; 57603b705cfSriastradh 57703b705cfSriastradh while (!list_is_empty(&resource->list)) { 57803b705cfSriastradh DRI2FrameEventPtr info = 57903b705cfSriastradh list_first_entry(&resource->list, 58003b705cfSriastradh DRI2FrameEventRec, 58103b705cfSriastradh client_resource); 58203b705cfSriastradh 58303b705cfSriastradh list_del(&info->client_resource); 58403b705cfSriastradh info->client = NULL; 58503b705cfSriastradh } 58603b705cfSriastradh free(resource); 58703b705cfSriastradh 58803b705cfSriastradh return Success; 58903b705cfSriastradh} 59003b705cfSriastradh 59103b705cfSriastradhstatic int 59203b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id) 59303b705cfSriastradh{ 59403b705cfSriastradh struct i830_dri2_resource *resource = data; 59503b705cfSriastradh 59603b705cfSriastradh while (!list_is_empty(&resource->list)) { 59703b705cfSriastradh DRI2FrameEventPtr info = 59803b705cfSriastradh list_first_entry(&resource->list, 59903b705cfSriastradh DRI2FrameEventRec, 60003b705cfSriastradh drawable_resource); 60103b705cfSriastradh 60203b705cfSriastradh list_del(&info->drawable_resource); 60303b705cfSriastradh info->drawable_id = None; 60403b705cfSriastradh } 60503b705cfSriastradh free(resource); 60603b705cfSriastradh 60703b705cfSriastradh return Success; 60803b705cfSriastradh} 60903b705cfSriastradh 61003b705cfSriastradhstatic Bool 61103b705cfSriastradhi830_dri2_register_frame_event_resource_types(void) 61203b705cfSriastradh{ 61303b705cfSriastradh frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client"); 61403b705cfSriastradh if (!frame_event_client_type) 61503b705cfSriastradh return FALSE; 61603b705cfSriastradh 61703b705cfSriastradh frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable"); 61803b705cfSriastradh if (!frame_event_drawable_type) 61903b705cfSriastradh return FALSE; 62003b705cfSriastradh 62103b705cfSriastradh return TRUE; 62203b705cfSriastradh} 62303b705cfSriastradh 62403b705cfSriastradhstatic XID 62503b705cfSriastradhget_client_id(ClientPtr client) 62603b705cfSriastradh{ 62703b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 62803b705cfSriastradh XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key); 62903b705cfSriastradh#else 63003b705cfSriastradh XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key); 63103b705cfSriastradh#endif 63203b705cfSriastradh if (*ptr == 0) 63303b705cfSriastradh *ptr = FakeClientID(client->index); 63403b705cfSriastradh return *ptr; 63503b705cfSriastradh} 63603b705cfSriastradh 63703b705cfSriastradh/* 63803b705cfSriastradh * Hook this frame event into the server resource 63903b705cfSriastradh * database so we can clean it up if the drawable or 64003b705cfSriastradh * client exits while the swap is pending 64103b705cfSriastradh */ 64203b705cfSriastradhstatic Bool 64303b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info) 64403b705cfSriastradh{ 64503b705cfSriastradh struct i830_dri2_resource *resource; 64603b705cfSriastradh 64703b705cfSriastradh resource = get_resource(get_client_id(info->client), 64803b705cfSriastradh frame_event_client_type); 64903b705cfSriastradh if (resource == NULL) 65003b705cfSriastradh return FALSE; 65103b705cfSriastradh 65203b705cfSriastradh list_add(&info->client_resource, &resource->list); 65303b705cfSriastradh 65403b705cfSriastradh resource = get_resource(info->drawable_id, frame_event_drawable_type); 65503b705cfSriastradh if (resource == NULL) { 65603b705cfSriastradh list_del(&info->client_resource); 65703b705cfSriastradh return FALSE; 65803b705cfSriastradh } 65903b705cfSriastradh 66003b705cfSriastradh list_add(&info->drawable_resource, &resource->list); 66103b705cfSriastradh 66203b705cfSriastradh return TRUE; 66303b705cfSriastradh} 66403b705cfSriastradh 66503b705cfSriastradhstatic void 66642542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info) 66703b705cfSriastradh{ 66803b705cfSriastradh list_del(&info->client_resource); 66903b705cfSriastradh list_del(&info->drawable_resource); 67003b705cfSriastradh 67103b705cfSriastradh if (info->front) 67242542f5fSchristos I830DRI2DestroyBuffer(NULL, info->front); 67303b705cfSriastradh if (info->back) 67442542f5fSchristos I830DRI2DestroyBuffer(NULL, info->back); 67503b705cfSriastradh 67603b705cfSriastradh free(info); 67703b705cfSriastradh} 67803b705cfSriastradh 67913496ba1Ssnjstatic struct intel_uxa_pixmap * 68003b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back) 68103b705cfSriastradh{ 68213496ba1Ssnj struct intel_uxa_pixmap *new_front = NULL, *new_back; 68303b705cfSriastradh RegionRec region; 68403b705cfSriastradh 68503b705cfSriastradh /* Post damage on the front buffer so that listeners, such 68603b705cfSriastradh * as DisplayLink know take a copy and shove it over the USB. 68703b705cfSriastradh * also for sw cursors. 68803b705cfSriastradh */ 68903b705cfSriastradh region.extents.x1 = region.extents.y1 = 0; 69003b705cfSriastradh region.extents.x2 = front->drawable.width; 69103b705cfSriastradh region.extents.y2 = front->drawable.height; 69203b705cfSriastradh region.data = NULL; 69303b705cfSriastradh DamageRegionAppend(&front->drawable, ®ion); 69403b705cfSriastradh 69513496ba1Ssnj new_front = intel_uxa_get_pixmap_private(back); 69613496ba1Ssnj new_back = intel_uxa_get_pixmap_private(front); 69713496ba1Ssnj intel_uxa_set_pixmap_private(front, new_front); 69813496ba1Ssnj intel_uxa_set_pixmap_private(back, new_back); 69903b705cfSriastradh new_front->busy = 1; 70003b705cfSriastradh new_back->busy = -1; 70103b705cfSriastradh 70203b705cfSriastradh DamageRegionProcessPending(&front->drawable); 70303b705cfSriastradh 70403b705cfSriastradh return new_front; 70503b705cfSriastradh} 70603b705cfSriastradh 70703b705cfSriastradhstatic void 70803b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back) 70903b705cfSriastradh{ 71003b705cfSriastradh I830DRI2BufferPrivatePtr front_priv, back_priv; 71103b705cfSriastradh int tmp; 71213496ba1Ssnj struct intel_uxa_pixmap *new_front; 71303b705cfSriastradh 71403b705cfSriastradh front_priv = front->driverPrivate; 71503b705cfSriastradh back_priv = back->driverPrivate; 71603b705cfSriastradh 71703b705cfSriastradh /* Swap BO names so DRI works */ 71803b705cfSriastradh tmp = front->name; 71903b705cfSriastradh front->name = back->name; 72003b705cfSriastradh back->name = tmp; 72103b705cfSriastradh 72203b705cfSriastradh /* Swap pixmap bos */ 72303b705cfSriastradh new_front = intel_exchange_pixmap_buffers(intel, 72403b705cfSriastradh front_priv->pixmap, 72503b705cfSriastradh back_priv->pixmap); 72603b705cfSriastradh dri_bo_unreference (intel->front_buffer); 72703b705cfSriastradh intel->front_buffer = new_front->bo; 72803b705cfSriastradh dri_bo_reference (intel->front_buffer); 72903b705cfSriastradh} 73003b705cfSriastradh 73103b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) 73203b705cfSriastradh{ 73303b705cfSriastradh drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap); 73403b705cfSriastradh assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */ 73503b705cfSriastradh return bo; 73603b705cfSriastradh} 73703b705cfSriastradh 73842542f5fSchristosstatic void 73942542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data) 74042542f5fSchristos{ 74142542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 74242542f5fSchristos 74342542f5fSchristos I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000, 74442542f5fSchristos usec % 1000000, 74542542f5fSchristos info); 74642542f5fSchristos} 74742542f5fSchristos 74842542f5fSchristosstatic void 74942542f5fSchristosI830DRI2FlipAbort(void *pageflip_data) 75042542f5fSchristos{ 75142542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 75242542f5fSchristos 75342542f5fSchristos i830_dri2_del_frame_event(info); 75442542f5fSchristos} 75542542f5fSchristos 75603b705cfSriastradh/* 75703b705cfSriastradh * Our internal swap routine takes care of actually exchanging, blitting, or 75803b705cfSriastradh * flipping buffers as necessary. 75903b705cfSriastradh */ 76003b705cfSriastradhstatic Bool 76103b705cfSriastradhI830DRI2ScheduleFlip(struct intel_screen_private *intel, 76203b705cfSriastradh DrawablePtr draw, 76303b705cfSriastradh DRI2FrameEventPtr info) 76403b705cfSriastradh{ 76503b705cfSriastradh I830DRI2BufferPrivatePtr priv = info->back->driverPrivate; 76603b705cfSriastradh drm_intel_bo *new_back, *old_back; 76703b705cfSriastradh int tmp_name; 76803b705cfSriastradh 76903b705cfSriastradh if (!intel->use_triple_buffer) { 77003b705cfSriastradh info->type = DRI2_SWAP; 77103b705cfSriastradh if (!intel_do_pageflip(intel, 77203b705cfSriastradh get_pixmap_bo(priv), 77342542f5fSchristos info->pipe, FALSE, info, 77442542f5fSchristos I830DRI2FlipComplete, 77542542f5fSchristos I830DRI2FlipAbort)) 77603b705cfSriastradh return FALSE; 77703b705cfSriastradh 77803b705cfSriastradh I830DRI2ExchangeBuffers(intel, info->front, info->back); 77903b705cfSriastradh return TRUE; 78003b705cfSriastradh } 78103b705cfSriastradh 78203b705cfSriastradh if (intel->pending_flip[info->pipe]) { 78303b705cfSriastradh assert(intel->pending_flip[info->pipe]->chain == NULL); 78403b705cfSriastradh intel->pending_flip[info->pipe]->chain = info; 78503b705cfSriastradh return TRUE; 78603b705cfSriastradh } 78703b705cfSriastradh 78803b705cfSriastradh if (intel->back_buffer == NULL) { 78903b705cfSriastradh new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer", 79003b705cfSriastradh intel->front_buffer->size, 0); 79103b705cfSriastradh if (new_back == NULL) 79203b705cfSriastradh return FALSE; 79303b705cfSriastradh 79403b705cfSriastradh if (intel->front_tiling != I915_TILING_NONE) { 79503b705cfSriastradh uint32_t tiling = intel->front_tiling; 79603b705cfSriastradh drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch); 79703b705cfSriastradh if (tiling != intel->front_tiling) { 79803b705cfSriastradh drm_intel_bo_unreference(new_back); 79903b705cfSriastradh return FALSE; 80003b705cfSriastradh } 80103b705cfSriastradh } 80203b705cfSriastradh 80303b705cfSriastradh drm_intel_bo_disable_reuse(new_back); 80403b705cfSriastradh dri_bo_flink(new_back, &intel->back_name); 80503b705cfSriastradh } else { 80603b705cfSriastradh new_back = intel->back_buffer; 80703b705cfSriastradh intel->back_buffer = NULL; 80803b705cfSriastradh } 80903b705cfSriastradh 81003b705cfSriastradh old_back = get_pixmap_bo(priv); 81142542f5fSchristos if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) { 81203b705cfSriastradh intel->back_buffer = new_back; 81303b705cfSriastradh return FALSE; 81403b705cfSriastradh } 81503b705cfSriastradh info->type = DRI2_SWAP_CHAIN; 81603b705cfSriastradh intel->pending_flip[info->pipe] = info; 81703b705cfSriastradh 81803b705cfSriastradh priv = info->front->driverPrivate; 81903b705cfSriastradh 82003b705cfSriastradh /* Exchange the current front-buffer with the fresh bo */ 82103b705cfSriastradh 82203b705cfSriastradh intel->back_buffer = intel->front_buffer; 82303b705cfSriastradh drm_intel_bo_reference(intel->back_buffer); 82413496ba1Ssnj intel_set_pixmap_bo(priv->pixmap, new_back); 82513496ba1Ssnj drm_intel_bo_unreference(new_back); 82603b705cfSriastradh 82703b705cfSriastradh tmp_name = info->front->name; 82803b705cfSriastradh info->front->name = intel->back_name; 82903b705cfSriastradh intel->back_name = tmp_name; 83003b705cfSriastradh 83103b705cfSriastradh /* Then flip DRI2 pointers and update the screen pixmap */ 83203b705cfSriastradh I830DRI2ExchangeBuffers(intel, info->front, info->back); 83303b705cfSriastradh DRI2SwapComplete(info->client, draw, 0, 0, 0, 83403b705cfSriastradh DRI2_EXCHANGE_COMPLETE, 83503b705cfSriastradh info->event_complete, 83603b705cfSriastradh info->event_data); 83703b705cfSriastradh return TRUE; 83803b705cfSriastradh} 83903b705cfSriastradh 84003b705cfSriastradhstatic Bool 84103b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) 84203b705cfSriastradh{ 84303b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen); 84403b705cfSriastradh struct intel_screen_private *intel = intel_get_screen_private(pScrn); 84503b705cfSriastradh I830DRI2BufferPrivatePtr front_priv = front->driverPrivate; 84603b705cfSriastradh I830DRI2BufferPrivatePtr back_priv = back->driverPrivate; 84703b705cfSriastradh PixmapPtr front_pixmap = front_priv->pixmap; 84803b705cfSriastradh PixmapPtr back_pixmap = back_priv->pixmap; 84913496ba1Ssnj struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap); 85013496ba1Ssnj struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap); 85103b705cfSriastradh 85203b705cfSriastradh if (!pScrn->vtSema) 85303b705cfSriastradh return FALSE; 85403b705cfSriastradh 85542542f5fSchristos if (I830DRI2DrawableCrtc(drawable) == NULL) 85603b705cfSriastradh return FALSE; 85703b705cfSriastradh 85803b705cfSriastradh if (!DRI2CanFlip(drawable)) 85903b705cfSriastradh return FALSE; 86003b705cfSriastradh 86103b705cfSriastradh if (intel->shadow_present) 86203b705cfSriastradh return FALSE; 86303b705cfSriastradh 86403b705cfSriastradh if (!intel->use_pageflipping) 86503b705cfSriastradh return FALSE; 86603b705cfSriastradh 86703b705cfSriastradh if (front_pixmap->drawable.width != back_pixmap->drawable.width) 86803b705cfSriastradh return FALSE; 86903b705cfSriastradh 87003b705cfSriastradh if (front_pixmap->drawable.height != back_pixmap->drawable.height) 87103b705cfSriastradh return FALSE; 87203b705cfSriastradh 87303b705cfSriastradh /* XXX should we be checking depth instead of bpp? */ 87403b705cfSriastradh#if 0 87503b705cfSriastradh if (front_pixmap->drawable.depth != back_pixmap->drawable.depth) 87603b705cfSriastradh return FALSE; 87703b705cfSriastradh#else 87803b705cfSriastradh if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 87903b705cfSriastradh return FALSE; 88003b705cfSriastradh#endif 88103b705cfSriastradh 88203b705cfSriastradh /* prevent an implicit tiling mode change */ 88303b705cfSriastradh if (front_intel->tiling != back_intel->tiling) 88403b705cfSriastradh return FALSE; 88503b705cfSriastradh 88642542f5fSchristos if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2)) 88742542f5fSchristos return FALSE; 88842542f5fSchristos 88903b705cfSriastradh return TRUE; 89003b705cfSriastradh} 89103b705cfSriastradh 89203b705cfSriastradhvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec, 89303b705cfSriastradh unsigned int tv_usec, DRI2FrameEventPtr swap_info) 89403b705cfSriastradh{ 89503b705cfSriastradh intel_screen_private *intel = swap_info->intel; 89603b705cfSriastradh DrawablePtr drawable; 89703b705cfSriastradh int status; 89803b705cfSriastradh 89903b705cfSriastradh if (!swap_info->drawable_id) 90003b705cfSriastradh status = BadDrawable; 90103b705cfSriastradh else 90203b705cfSriastradh status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient, 90303b705cfSriastradh M_ANY, DixWriteAccess); 90403b705cfSriastradh if (status != Success) { 90542542f5fSchristos i830_dri2_del_frame_event(swap_info); 90603b705cfSriastradh return; 90703b705cfSriastradh } 90803b705cfSriastradh 90903b705cfSriastradh 91003b705cfSriastradh switch (swap_info->type) { 91103b705cfSriastradh case DRI2_FLIP: 91203b705cfSriastradh /* If we can still flip... */ 91303b705cfSriastradh if (can_exchange(drawable, swap_info->front, swap_info->back) && 91403b705cfSriastradh I830DRI2ScheduleFlip(intel, drawable, swap_info)) 91503b705cfSriastradh return; 91603b705cfSriastradh 91703b705cfSriastradh /* else fall through to exchange/blit */ 91803b705cfSriastradh case DRI2_SWAP: { 91903b705cfSriastradh I830DRI2FallbackBlitSwap(drawable, 92003b705cfSriastradh swap_info->front, swap_info->back); 92103b705cfSriastradh DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec, 92203b705cfSriastradh DRI2_BLIT_COMPLETE, 92303b705cfSriastradh swap_info->client ? swap_info->event_complete : NULL, 92403b705cfSriastradh swap_info->event_data); 92503b705cfSriastradh break; 92603b705cfSriastradh } 92703b705cfSriastradh case DRI2_WAITMSC: 92803b705cfSriastradh if (swap_info->client) 92903b705cfSriastradh DRI2WaitMSCComplete(swap_info->client, drawable, 93003b705cfSriastradh frame, tv_sec, tv_usec); 93103b705cfSriastradh break; 93203b705cfSriastradh default: 93303b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 93403b705cfSriastradh "%s: unknown vblank event received\n", __func__); 93503b705cfSriastradh /* Unknown type */ 93603b705cfSriastradh break; 93703b705cfSriastradh } 93803b705cfSriastradh 93942542f5fSchristos i830_dri2_del_frame_event(swap_info); 94003b705cfSriastradh} 94103b705cfSriastradh 94203b705cfSriastradhvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, 94303b705cfSriastradh unsigned int tv_usec, DRI2FrameEventPtr flip_info) 94403b705cfSriastradh{ 94503b705cfSriastradh struct intel_screen_private *intel = flip_info->intel; 94603b705cfSriastradh DrawablePtr drawable; 94703b705cfSriastradh DRI2FrameEventPtr chain; 94803b705cfSriastradh 94903b705cfSriastradh drawable = NULL; 95003b705cfSriastradh if (flip_info->drawable_id) 95103b705cfSriastradh dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, 95203b705cfSriastradh M_ANY, DixWriteAccess); 95303b705cfSriastradh 95403b705cfSriastradh 95503b705cfSriastradh /* We assume our flips arrive in order, so we don't check the frame */ 95603b705cfSriastradh switch (flip_info->type) { 95703b705cfSriastradh case DRI2_SWAP: 95803b705cfSriastradh if (!drawable) 95903b705cfSriastradh break; 96003b705cfSriastradh 96103b705cfSriastradh /* Check for too small vblank count of pageflip completion, taking wraparound 96203b705cfSriastradh * into account. This usually means some defective kms pageflip completion, 96303b705cfSriastradh * causing wrong (msc, ust) return values and possible visual corruption. 96403b705cfSriastradh */ 96503b705cfSriastradh if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) { 96603b705cfSriastradh static int limit = 5; 96703b705cfSriastradh 96803b705cfSriastradh /* XXX we are currently hitting this path with older 96903b705cfSriastradh * kernels, so make it quieter. 97003b705cfSriastradh */ 97103b705cfSriastradh if (limit) { 97203b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 97303b705cfSriastradh "%s: Pageflip completion has impossible msc %d < target_msc %d\n", 97403b705cfSriastradh __func__, frame, flip_info->frame); 97503b705cfSriastradh limit--; 97603b705cfSriastradh } 97703b705cfSriastradh 97803b705cfSriastradh /* All-0 values signal timestamping failure. */ 97903b705cfSriastradh frame = tv_sec = tv_usec = 0; 98003b705cfSriastradh } 98103b705cfSriastradh 98203b705cfSriastradh DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, 98303b705cfSriastradh DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, 98403b705cfSriastradh flip_info->event_data); 98503b705cfSriastradh break; 98603b705cfSriastradh 98703b705cfSriastradh case DRI2_SWAP_CHAIN: 98803b705cfSriastradh assert(intel->pending_flip[flip_info->pipe] == flip_info); 98903b705cfSriastradh intel->pending_flip[flip_info->pipe] = NULL; 99003b705cfSriastradh 99103b705cfSriastradh chain = flip_info->chain; 99203b705cfSriastradh if (chain) { 99303b705cfSriastradh DrawablePtr chain_drawable = NULL; 99403b705cfSriastradh if (chain->drawable_id) 99503b705cfSriastradh dixLookupDrawable(&chain_drawable, 99603b705cfSriastradh chain->drawable_id, 99703b705cfSriastradh serverClient, 99803b705cfSriastradh M_ANY, DixWriteAccess); 99903b705cfSriastradh if (chain_drawable == NULL) { 100042542f5fSchristos i830_dri2_del_frame_event(chain); 100103b705cfSriastradh } else if (!can_exchange(chain_drawable, chain->front, chain->back) || 100203b705cfSriastradh !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) { 100303b705cfSriastradh I830DRI2FallbackBlitSwap(chain_drawable, 100403b705cfSriastradh chain->front, 100503b705cfSriastradh chain->back); 100603b705cfSriastradh 100703b705cfSriastradh DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec, 100803b705cfSriastradh DRI2_BLIT_COMPLETE, 100903b705cfSriastradh chain->client ? chain->event_complete : NULL, 101003b705cfSriastradh chain->event_data); 101142542f5fSchristos i830_dri2_del_frame_event(chain); 101203b705cfSriastradh } 101303b705cfSriastradh } 101403b705cfSriastradh break; 101503b705cfSriastradh 101603b705cfSriastradh default: 101703b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 101803b705cfSriastradh "%s: unknown vblank event received\n", __func__); 101903b705cfSriastradh /* Unknown type */ 102003b705cfSriastradh break; 102103b705cfSriastradh } 102203b705cfSriastradh 102342542f5fSchristos i830_dri2_del_frame_event(flip_info); 102403b705cfSriastradh} 102503b705cfSriastradh 102603b705cfSriastradhstatic uint32_t pipe_select(int pipe) 102703b705cfSriastradh{ 102803b705cfSriastradh if (pipe > 1) 102903b705cfSriastradh return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 103003b705cfSriastradh else if (pipe > 0) 103103b705cfSriastradh return DRM_VBLANK_SECONDARY; 103203b705cfSriastradh else 103303b705cfSriastradh return 0; 103403b705cfSriastradh} 103503b705cfSriastradh 103642542f5fSchristosstatic void 103742542f5fSchristosintel_dri2_vblank_handler(ScrnInfoPtr scrn, 103842542f5fSchristos xf86CrtcPtr crtc, 103942542f5fSchristos uint64_t msc, 104042542f5fSchristos uint64_t usec, 104142542f5fSchristos void *data) 104242542f5fSchristos{ 104342542f5fSchristos DRI2FrameEventPtr swap_info = data; 104442542f5fSchristos 104542542f5fSchristos I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info); 104642542f5fSchristos} 104742542f5fSchristos 104842542f5fSchristosstatic void 104942542f5fSchristosintel_dri2_vblank_abort(ScrnInfoPtr scrn, 105042542f5fSchristos xf86CrtcPtr crtc, 105142542f5fSchristos void *data) 105242542f5fSchristos{ 105342542f5fSchristos DRI2FrameEventPtr swap_info = data; 105442542f5fSchristos 105542542f5fSchristos i830_dri2_del_frame_event(swap_info); 105642542f5fSchristos} 105742542f5fSchristos 105803b705cfSriastradh/* 105903b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the 106003b705cfSriastradh * appropriate frame. 106103b705cfSriastradh * 106203b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 106303b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap 106403b705cfSriastradh * interval for the drawable. 106503b705cfSriastradh * 106603b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap 106703b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame 106803b705cfSriastradh * immediately following the received event. 106903b705cfSriastradh * 107003b705cfSriastradh * The client will be blocked if it tries to perform further GL commands 107103b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the 107203b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if 107303b705cfSriastradh * they access buffers busy with the flip. 107403b705cfSriastradh * 107503b705cfSriastradh * When the swap is complete, the driver should call into the server so it 107603b705cfSriastradh * can send any swap complete events that have been requested. 107703b705cfSriastradh */ 107803b705cfSriastradhstatic int 107903b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 108003b705cfSriastradh DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 108103b705cfSriastradh CARD64 remainder, DRI2SwapEventPtr func, void *data) 108203b705cfSriastradh{ 108303b705cfSriastradh ScreenPtr screen = draw->pScreen; 108403b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 108503b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 108603b705cfSriastradh drmVBlank vbl; 108742542f5fSchristos int ret; 108842542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 108942542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 109042542f5fSchristos int flip = 0; 109103b705cfSriastradh DRI2FrameEventPtr swap_info = NULL; 109203b705cfSriastradh enum DRI2FrameEventType swap_type = DRI2_SWAP; 109342542f5fSchristos uint64_t current_msc, current_ust; 109442542f5fSchristos uint64_t request_msc; 109542542f5fSchristos uint32_t seq; 109603b705cfSriastradh 109703b705cfSriastradh /* Drawable not displayed... just complete the swap */ 109803b705cfSriastradh if (pipe == -1) 109903b705cfSriastradh goto blit_fallback; 110003b705cfSriastradh 110103b705cfSriastradh swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 110203b705cfSriastradh if (!swap_info) 110303b705cfSriastradh goto blit_fallback; 110403b705cfSriastradh 110503b705cfSriastradh swap_info->intel = intel; 110603b705cfSriastradh swap_info->drawable_id = draw->id; 110703b705cfSriastradh swap_info->client = client; 110803b705cfSriastradh swap_info->event_complete = func; 110903b705cfSriastradh swap_info->event_data = data; 111003b705cfSriastradh swap_info->front = front; 111103b705cfSriastradh swap_info->back = back; 111203b705cfSriastradh swap_info->pipe = pipe; 111303b705cfSriastradh 111403b705cfSriastradh if (!i830_dri2_add_frame_event(swap_info)) { 111503b705cfSriastradh free(swap_info); 111603b705cfSriastradh swap_info = NULL; 111703b705cfSriastradh goto blit_fallback; 111803b705cfSriastradh } 111903b705cfSriastradh 112003b705cfSriastradh I830DRI2ReferenceBuffer(front); 112103b705cfSriastradh I830DRI2ReferenceBuffer(back); 112203b705cfSriastradh 112342542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 112442542f5fSchristos if (ret) 112542542f5fSchristos goto blit_fallback; 112603b705cfSriastradh 112703b705cfSriastradh /* Flips need to be submitted one frame before */ 112803b705cfSriastradh if (can_exchange(draw, front, back)) { 112903b705cfSriastradh swap_type = DRI2_FLIP; 113003b705cfSriastradh flip = 1; 113103b705cfSriastradh } 113203b705cfSriastradh 113303b705cfSriastradh swap_info->type = swap_type; 113403b705cfSriastradh 113503b705cfSriastradh /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 113603b705cfSriastradh * Do it early, so handling of different timing constraints 113703b705cfSriastradh * for divisor, remainder and msc vs. target_msc works. 113803b705cfSriastradh */ 113903b705cfSriastradh if (*target_msc > 0) 114003b705cfSriastradh *target_msc -= flip; 114103b705cfSriastradh 114203b705cfSriastradh /* 114303b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc 114403b705cfSriastradh * we just need to make sure target_msc passes before initiating 114503b705cfSriastradh * the swap. 114603b705cfSriastradh */ 114703b705cfSriastradh if (divisor == 0 || current_msc < *target_msc) { 114803b705cfSriastradh /* 114903b705cfSriastradh * If we can, schedule the flip directly from here rather 115003b705cfSriastradh * than waiting for an event from the kernel for the current 115103b705cfSriastradh * (or a past) MSC. 115203b705cfSriastradh */ 115303b705cfSriastradh if (flip && divisor == 0 && current_msc >= *target_msc && 115403b705cfSriastradh I830DRI2ScheduleFlip(intel, draw, swap_info)) 115503b705cfSriastradh return TRUE; 115603b705cfSriastradh 115703b705cfSriastradh vbl.request.type = 115803b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 115903b705cfSriastradh 116003b705cfSriastradh /* If non-pageflipping, but blitting/exchanging, we need to use 116103b705cfSriastradh * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 116203b705cfSriastradh * on. 116303b705cfSriastradh */ 116403b705cfSriastradh if (flip == 0) 116503b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 116603b705cfSriastradh 116703b705cfSriastradh /* If target_msc already reached or passed, set it to 116803b705cfSriastradh * current_msc to ensure we return a reasonable value back 116903b705cfSriastradh * to the caller. This makes swap_interval logic more robust. 117003b705cfSriastradh */ 117103b705cfSriastradh if (current_msc >= *target_msc) 117203b705cfSriastradh *target_msc = current_msc; 117303b705cfSriastradh 117442542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 117542542f5fSchristos if (!seq) 117642542f5fSchristos goto blit_fallback; 117742542f5fSchristos 117842542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc); 117942542f5fSchristos vbl.request.signal = seq; 118042542f5fSchristos 118103b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 118203b705cfSriastradh if (ret) { 118303b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 118403b705cfSriastradh "divisor 0 get vblank counter failed: %s\n", 118503b705cfSriastradh strerror(errno)); 118603b705cfSriastradh goto blit_fallback; 118703b705cfSriastradh } 118803b705cfSriastradh 118942542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 119003b705cfSriastradh swap_info->frame = *target_msc; 119103b705cfSriastradh 119203b705cfSriastradh return TRUE; 119303b705cfSriastradh } 119403b705cfSriastradh 119503b705cfSriastradh /* 119603b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 119703b705cfSriastradh * and we need to queue an event that will satisfy the divisor/remainder 119803b705cfSriastradh * equation. 119903b705cfSriastradh */ 120003b705cfSriastradh vbl.request.type = 120103b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 120203b705cfSriastradh if (flip == 0) 120303b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 120403b705cfSriastradh 120542542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 120642542f5fSchristos remainder; 120703b705cfSriastradh 120803b705cfSriastradh /* 120903b705cfSriastradh * If the calculated deadline vbl.request.sequence is smaller than 121003b705cfSriastradh * or equal to current_msc, it means we've passed the last point 121103b705cfSriastradh * when effective onset frame seq could satisfy 121203b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 121303b705cfSriastradh * this will happen. 121403b705cfSriastradh 121503b705cfSriastradh * This comparison takes the 1 frame swap delay in pageflipping mode 121603b705cfSriastradh * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 121703b705cfSriastradh * if we are blitting/exchanging instead of flipping. 121803b705cfSriastradh */ 121942542f5fSchristos if (request_msc <= current_msc) 122042542f5fSchristos request_msc += divisor; 122142542f5fSchristos 122242542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 122342542f5fSchristos if (!seq) 122442542f5fSchristos goto blit_fallback; 122503b705cfSriastradh 122603b705cfSriastradh /* Account for 1 frame extra pageflip delay if flip > 0 */ 122742542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip; 122842542f5fSchristos vbl.request.signal = seq; 122903b705cfSriastradh 123003b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 123103b705cfSriastradh if (ret) { 123203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 123303b705cfSriastradh "final get vblank counter failed: %s\n", 123403b705cfSriastradh strerror(errno)); 123503b705cfSriastradh goto blit_fallback; 123603b705cfSriastradh } 123703b705cfSriastradh 123803b705cfSriastradh /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 123942542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 124003b705cfSriastradh swap_info->frame = *target_msc; 124103b705cfSriastradh 124203b705cfSriastradh return TRUE; 124303b705cfSriastradh 124403b705cfSriastradhblit_fallback: 124503b705cfSriastradh I830DRI2FallbackBlitSwap(draw, front, back); 124603b705cfSriastradh DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 124703b705cfSriastradh if (swap_info) 124842542f5fSchristos i830_dri2_del_frame_event(swap_info); 124903b705cfSriastradh *target_msc = 0; /* offscreen, so zero out target vblank count */ 125003b705cfSriastradh return TRUE; 125103b705cfSriastradh} 125203b705cfSriastradh 125303b705cfSriastradhstatic uint64_t gettime_us(void) 125403b705cfSriastradh{ 125503b705cfSriastradh struct timespec tv; 125603b705cfSriastradh 125703b705cfSriastradh if (clock_gettime(CLOCK_MONOTONIC, &tv)) 125803b705cfSriastradh return 0; 125903b705cfSriastradh 126003b705cfSriastradh return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; 126103b705cfSriastradh} 126203b705cfSriastradh 126303b705cfSriastradh/* 126403b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's 126503b705cfSriastradh * crtc. 126603b705cfSriastradh */ 126703b705cfSriastradhstatic int 126803b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 126903b705cfSriastradh{ 127003b705cfSriastradh ScreenPtr screen = draw->pScreen; 127103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 127242542f5fSchristos int ret; 127342542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 127403b705cfSriastradh 127503b705cfSriastradh /* Drawable not displayed, make up a *monotonic* value */ 127642542f5fSchristos if (crtc == NULL) { 127742542f5fSchristosfail: 127803b705cfSriastradh *ust = gettime_us(); 127903b705cfSriastradh *msc = 0; 128003b705cfSriastradh return TRUE; 128103b705cfSriastradh } 128203b705cfSriastradh 128342542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust); 128403b705cfSriastradh if (ret) { 128503b705cfSriastradh static int limit = 5; 128603b705cfSriastradh if (limit) { 128703b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 128803b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 128903b705cfSriastradh __FUNCTION__, __LINE__, 129003b705cfSriastradh strerror(errno)); 129103b705cfSriastradh limit--; 129203b705cfSriastradh } 129342542f5fSchristos goto fail; 129403b705cfSriastradh } 129503b705cfSriastradh 129603b705cfSriastradh return TRUE; 129703b705cfSriastradh} 129803b705cfSriastradh 129903b705cfSriastradh/* 130003b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied. 130103b705cfSriastradh * 130203b705cfSriastradh * We need to handle the event and ask the server to wake up the client when 130303b705cfSriastradh * we receive it. 130403b705cfSriastradh */ 130503b705cfSriastradhstatic int 130603b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 130703b705cfSriastradh CARD64 divisor, CARD64 remainder) 130803b705cfSriastradh{ 130903b705cfSriastradh ScreenPtr screen = draw->pScreen; 131003b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 131103b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 131203b705cfSriastradh DRI2FrameEventPtr wait_info; 131303b705cfSriastradh drmVBlank vbl; 131442542f5fSchristos int ret; 131542542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 131642542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 131742542f5fSchristos CARD64 current_msc, current_ust, request_msc; 131842542f5fSchristos uint32_t seq; 131903b705cfSriastradh 132003b705cfSriastradh /* Drawable not visible, return immediately */ 132103b705cfSriastradh if (pipe == -1) 132203b705cfSriastradh goto out_complete; 132303b705cfSriastradh 132403b705cfSriastradh wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 132503b705cfSriastradh if (!wait_info) 132603b705cfSriastradh goto out_complete; 132703b705cfSriastradh 132803b705cfSriastradh wait_info->intel = intel; 132903b705cfSriastradh wait_info->drawable_id = draw->id; 133003b705cfSriastradh wait_info->client = client; 133103b705cfSriastradh wait_info->type = DRI2_WAITMSC; 133203b705cfSriastradh 133303b705cfSriastradh if (!i830_dri2_add_frame_event(wait_info)) { 133403b705cfSriastradh free(wait_info); 133503b705cfSriastradh wait_info = NULL; 133603b705cfSriastradh goto out_complete; 133703b705cfSriastradh } 133803b705cfSriastradh 133903b705cfSriastradh /* Get current count */ 134042542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 134142542f5fSchristos if (ret) 134242542f5fSchristos goto out_free; 134303b705cfSriastradh 134403b705cfSriastradh /* 134503b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc, 134603b705cfSriastradh * we just need to make sure target_msc passes before waking up the 134703b705cfSriastradh * client. 134803b705cfSriastradh */ 134903b705cfSriastradh if (divisor == 0 || current_msc < target_msc) { 135003b705cfSriastradh /* If target_msc already reached or passed, set it to 135103b705cfSriastradh * current_msc to ensure we return a reasonable value back 135203b705cfSriastradh * to the caller. This keeps the client from continually 135303b705cfSriastradh * sending us MSC targets from the past by forcibly updating 135403b705cfSriastradh * their count on this call. 135503b705cfSriastradh */ 135642542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 135742542f5fSchristos if (!seq) 135842542f5fSchristos goto out_free; 135942542f5fSchristos 136003b705cfSriastradh if (current_msc >= target_msc) 136103b705cfSriastradh target_msc = current_msc; 136203b705cfSriastradh vbl.request.type = 136303b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 136442542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc); 136542542f5fSchristos vbl.request.signal = seq; 136642542f5fSchristos 136703b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 136803b705cfSriastradh if (ret) { 136903b705cfSriastradh static int limit = 5; 137003b705cfSriastradh if (limit) { 137103b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 137203b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 137303b705cfSriastradh __FUNCTION__, __LINE__, 137403b705cfSriastradh strerror(errno)); 137503b705cfSriastradh limit--; 137603b705cfSriastradh } 137703b705cfSriastradh goto out_free; 137803b705cfSriastradh } 137903b705cfSriastradh 138042542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 138103b705cfSriastradh DRI2BlockClient(client, draw); 138203b705cfSriastradh return TRUE; 138303b705cfSriastradh } 138403b705cfSriastradh 138503b705cfSriastradh /* 138603b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 138703b705cfSriastradh * so we queue an event that will satisfy the divisor/remainder equation. 138803b705cfSriastradh */ 138903b705cfSriastradh vbl.request.type = 139003b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 139103b705cfSriastradh 139242542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 139342542f5fSchristos remainder; 139403b705cfSriastradh /* 139503b705cfSriastradh * If calculated remainder is larger than requested remainder, 139603b705cfSriastradh * it means we've passed the last point where 139703b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 139803b705cfSriastradh * that will happen. 139903b705cfSriastradh */ 140003b705cfSriastradh if ((current_msc % divisor) >= remainder) 140142542f5fSchristos request_msc += divisor; 140242542f5fSchristos 140342542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 140442542f5fSchristos if (!seq) 140542542f5fSchristos goto out_free; 140642542f5fSchristos 140742542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); 140842542f5fSchristos vbl.request.signal = seq; 140903b705cfSriastradh 141003b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 141103b705cfSriastradh if (ret) { 141203b705cfSriastradh static int limit = 5; 141303b705cfSriastradh if (limit) { 141403b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 141503b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 141603b705cfSriastradh __FUNCTION__, __LINE__, 141703b705cfSriastradh strerror(errno)); 141803b705cfSriastradh limit--; 141903b705cfSriastradh } 142003b705cfSriastradh goto out_free; 142103b705cfSriastradh } 142203b705cfSriastradh 142342542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 142403b705cfSriastradh DRI2BlockClient(client, draw); 142503b705cfSriastradh 142603b705cfSriastradh return TRUE; 142703b705cfSriastradh 142803b705cfSriastradhout_free: 142942542f5fSchristos i830_dri2_del_frame_event(wait_info); 143003b705cfSriastradhout_complete: 143103b705cfSriastradh DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 143203b705cfSriastradh return TRUE; 143303b705cfSriastradh} 143403b705cfSriastradh 143503b705cfSriastradhstatic int dri2_server_generation; 143603b705cfSriastradh#endif 143703b705cfSriastradh 143803b705cfSriastradhstatic int has_i830_dri(void) 143903b705cfSriastradh{ 144003b705cfSriastradh return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 144103b705cfSriastradh} 144203b705cfSriastradh 144303b705cfSriastradhstatic const char *dri_driver_name(intel_screen_private *intel) 144403b705cfSriastradh{ 144542542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 144603b705cfSriastradh const char *s = xf86GetOptValString(intel->Options, OPTION_DRI); 144703b705cfSriastradh Bool dummy; 144803b705cfSriastradh 144903b705cfSriastradh if (s == NULL || xf86getBoolValue(&dummy, s)) { 145003b705cfSriastradh if (INTEL_INFO(intel)->gen < 030) 145103b705cfSriastradh return has_i830_dri() ? "i830" : "i915"; 145203b705cfSriastradh else if (INTEL_INFO(intel)->gen < 040) 145303b705cfSriastradh return "i915"; 145403b705cfSriastradh else 145503b705cfSriastradh return "i965"; 145603b705cfSriastradh } 145703b705cfSriastradh 145803b705cfSriastradh return s; 145942542f5fSchristos#else 146042542f5fSchristos if (INTEL_INFO(intel)->gen < 030) 146142542f5fSchristos return has_i830_dri() ? "i830" : "i915"; 146242542f5fSchristos else if (INTEL_INFO(intel)->gen < 040) 146342542f5fSchristos return "i915"; 146442542f5fSchristos else 146542542f5fSchristos return "i965"; 146642542f5fSchristos#endif 146703b705cfSriastradh} 146803b705cfSriastradh 146903b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen) 147003b705cfSriastradh{ 147103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 147203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 147303b705cfSriastradh DRI2InfoRec info; 147442542f5fSchristos int dri2scr_major = 1; 147542542f5fSchristos int dri2scr_minor = 0; 147603b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 147742542f5fSchristos const char *driverNames[2]; 147803b705cfSriastradh#endif 147903b705cfSriastradh 148003b705cfSriastradh if (intel->force_fallback) { 148103b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 148203b705cfSriastradh "cannot enable DRI2 whilst forcing software fallbacks\n"); 148303b705cfSriastradh return FALSE; 148403b705cfSriastradh } 148503b705cfSriastradh 148603b705cfSriastradh if (xf86LoaderCheckSymbol("DRI2Version")) 148742542f5fSchristos DRI2Version(&dri2scr_major, &dri2scr_minor); 148803b705cfSriastradh 148942542f5fSchristos if (dri2scr_minor < 1) { 149003b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 149103b705cfSriastradh "DRI2 requires DRI2 module version 1.1.0 or later\n"); 149203b705cfSriastradh return FALSE; 149303b705cfSriastradh } 149403b705cfSriastradh 149503b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 149603b705cfSriastradh if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID))) 149703b705cfSriastradh return FALSE; 149803b705cfSriastradh#else 149903b705cfSriastradh if (!dixRequestPrivate(&i830_client_key, sizeof(XID))) 150003b705cfSriastradh return FALSE; 150103b705cfSriastradh#endif 150203b705cfSriastradh 150303b705cfSriastradh 150403b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 150503b705cfSriastradh if (serverGeneration != dri2_server_generation) { 150603b705cfSriastradh dri2_server_generation = serverGeneration; 150703b705cfSriastradh if (!i830_dri2_register_frame_event_resource_types()) { 150803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 150903b705cfSriastradh "Cannot register DRI2 frame event resources\n"); 151003b705cfSriastradh return FALSE; 151103b705cfSriastradh } 151203b705cfSriastradh } 151303b705cfSriastradh#endif 151403b705cfSriastradh 151503b705cfSriastradh intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD); 151603b705cfSriastradh memset(&info, '\0', sizeof(info)); 151703b705cfSriastradh info.fd = intel->drmSubFD; 151803b705cfSriastradh info.driverName = dri_driver_name(intel); 151903b705cfSriastradh info.deviceName = intel->deviceName; 152003b705cfSriastradh 152103b705cfSriastradh#if DRI2INFOREC_VERSION == 1 152203b705cfSriastradh info.version = 1; 152303b705cfSriastradh info.CreateBuffers = I830DRI2CreateBuffers; 152403b705cfSriastradh info.DestroyBuffers = I830DRI2DestroyBuffers; 152503b705cfSriastradh#elif DRI2INFOREC_VERSION == 2 152603b705cfSriastradh /* The ABI between 2 and 3 was broken so we could get rid of 152703b705cfSriastradh * the multi-buffer alloc functions. Make sure we indicate the 152803b705cfSriastradh * right version so DRI2 can reject us if it's version 3 or above. */ 152903b705cfSriastradh info.version = 2; 153003b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 153103b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 153203b705cfSriastradh#else 153303b705cfSriastradh info.version = 3; 153403b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 153503b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 153603b705cfSriastradh#endif 153703b705cfSriastradh 153803b705cfSriastradh info.CopyRegion = I830DRI2CopyRegion; 153903b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 154003b705cfSriastradh info.version = 4; 154103b705cfSriastradh info.ScheduleSwap = I830DRI2ScheduleSwap; 154203b705cfSriastradh info.GetMSC = I830DRI2GetMSC; 154303b705cfSriastradh info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC; 154442542f5fSchristos info.numDrivers = 2; 154503b705cfSriastradh info.driverNames = driverNames; 154603b705cfSriastradh driverNames[0] = info.driverName; 154742542f5fSchristos driverNames[1] = info.driverName; 154803b705cfSriastradh#endif 154903b705cfSriastradh 155003b705cfSriastradh return DRI2ScreenInit(screen, &info); 155103b705cfSriastradh} 155203b705cfSriastradh 155303b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen) 155403b705cfSriastradh{ 155503b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 155603b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 155703b705cfSriastradh 155803b705cfSriastradh DRI2CloseScreen(screen); 155903b705cfSriastradh drmFree(intel->deviceName); 156003b705cfSriastradh} 1561