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 84fe8aea9eSmrgstatic void I830DRI2FlipEventHandler(unsigned int frame, 85fe8aea9eSmrg unsigned int tv_sec, 86fe8aea9eSmrg unsigned int tv_usec, 87fe8aea9eSmrg DRI2FrameEventPtr flip_info); 88fe8aea9eSmrg 89fe8aea9eSmrgstatic void I830DRI2FrameEventHandler(unsigned int frame, 90fe8aea9eSmrg unsigned int tv_sec, 91fe8aea9eSmrg unsigned int tv_usec, 92fe8aea9eSmrg DRI2FrameEventPtr swap_info); 93fe8aea9eSmrg 94fe8aea9eSmrgstatic void 95fe8aea9eSmrgi830_dri2_del_frame_event(DRI2FrameEventPtr info); 96fe8aea9eSmrg 97fe8aea9eSmrgstatic uint32_t pipe_select(int pipe) 98fe8aea9eSmrg{ 99fe8aea9eSmrg if (pipe > 1) 100fe8aea9eSmrg return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 101fe8aea9eSmrg else if (pipe > 0) 102fe8aea9eSmrg return DRM_VBLANK_SECONDARY; 103fe8aea9eSmrg else 104fe8aea9eSmrg return 0; 105fe8aea9eSmrg} 106fe8aea9eSmrg 107fe8aea9eSmrgstatic void 108fe8aea9eSmrgintel_dri2_vblank_handler(ScrnInfoPtr scrn, 109fe8aea9eSmrg xf86CrtcPtr crtc, 110fe8aea9eSmrg uint64_t msc, 111fe8aea9eSmrg uint64_t usec, 112fe8aea9eSmrg void *data) 113fe8aea9eSmrg{ 114fe8aea9eSmrg I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data); 115fe8aea9eSmrg} 116fe8aea9eSmrg 117fe8aea9eSmrgstatic void 118fe8aea9eSmrgintel_dri2_vblank_abort(ScrnInfoPtr scrn, 119fe8aea9eSmrg xf86CrtcPtr crtc, 120fe8aea9eSmrg void *data) 121fe8aea9eSmrg{ 122fe8aea9eSmrg i830_dri2_del_frame_event(data); 123fe8aea9eSmrg} 124fe8aea9eSmrg 12503b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap) 12603b705cfSriastradh{ 12713496ba1Ssnj struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap); 12803b705cfSriastradh uint32_t name; 12903b705cfSriastradh 13003b705cfSriastradh if (priv == NULL || priv->bo == NULL) 13103b705cfSriastradh return 0; 13203b705cfSriastradh 13303b705cfSriastradh if (dri_bo_flink(priv->bo, &name) != 0) 13403b705cfSriastradh return 0; 13503b705cfSriastradh 13642542f5fSchristos priv->pinned |= PIN_DRI2; 13703b705cfSriastradh return name; 13803b705cfSriastradh} 13903b705cfSriastradh 14003b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable) 14103b705cfSriastradh{ 14203b705cfSriastradh PixmapPtr pixmap; 14303b705cfSriastradh 14403b705cfSriastradh pixmap = get_drawable_pixmap(drawable); 14503b705cfSriastradh if (!intel_get_pixmap_bo(pixmap)) 14603b705cfSriastradh return NULL; 14703b705cfSriastradh 14803b705cfSriastradh pixmap->refcnt++; 14903b705cfSriastradh return pixmap; 15003b705cfSriastradh} 15103b705cfSriastradh 15203b705cfSriastradh#if DRI2INFOREC_VERSION < 2 15303b705cfSriastradhstatic DRI2BufferPtr 15403b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments, 15503b705cfSriastradh int count) 15603b705cfSriastradh{ 15703b705cfSriastradh ScreenPtr screen = drawable->pScreen; 15803b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 15903b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 16003b705cfSriastradh DRI2BufferPtr buffers; 16103b705cfSriastradh I830DRI2BufferPrivatePtr privates; 16203b705cfSriastradh PixmapPtr pixmap, pDepthPixmap; 16303b705cfSriastradh int i; 16403b705cfSriastradh 16503b705cfSriastradh buffers = calloc(count, sizeof *buffers); 16603b705cfSriastradh if (buffers == NULL) 16703b705cfSriastradh return NULL; 16803b705cfSriastradh privates = calloc(count, sizeof *privates); 16903b705cfSriastradh if (privates == NULL) { 17003b705cfSriastradh free(buffers); 17103b705cfSriastradh return NULL; 17203b705cfSriastradh } 17303b705cfSriastradh 17403b705cfSriastradh pDepthPixmap = NULL; 17503b705cfSriastradh for (i = 0; i < count; i++) { 17603b705cfSriastradh pixmap = NULL; 17703b705cfSriastradh if (attachments[i] == DRI2BufferFrontLeft) { 17803b705cfSriastradh pixmap = get_front_buffer(drawable); 17903b705cfSriastradh } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 18003b705cfSriastradh pixmap = pDepthPixmap; 18103b705cfSriastradh pixmap->refcnt++; 18203b705cfSriastradh } 18303b705cfSriastradh 18403b705cfSriastradh if (pixmap == NULL) { 18503b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 18603b705cfSriastradh 18703b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 18803b705cfSriastradh switch (attachments[i]) { 18903b705cfSriastradh case DRI2BufferDepth: 19003b705cfSriastradh if (SUPPORTS_YTILING(intel)) 19103b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 19203b705cfSriastradh else 19303b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 19403b705cfSriastradh break; 19503b705cfSriastradh case DRI2BufferFakeFrontLeft: 19603b705cfSriastradh case DRI2BufferFakeFrontRight: 19703b705cfSriastradh case DRI2BufferBackLeft: 19803b705cfSriastradh case DRI2BufferBackRight: 19903b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 20003b705cfSriastradh break; 20103b705cfSriastradh } 20203b705cfSriastradh } 20303b705cfSriastradh 20403b705cfSriastradh pixmap = screen->CreatePixmap(screen, 20503b705cfSriastradh drawable->width, 20603b705cfSriastradh drawable->height, 20703b705cfSriastradh drawable->depth, 20803b705cfSriastradh hint); 20903b705cfSriastradh if (pixmap == NULL || 21003b705cfSriastradh intel_get_pixmap_bo(pixmap) == NULL) 21103b705cfSriastradh { 21203b705cfSriastradh if (pixmap) 21303b705cfSriastradh screen->DestroyPixmap(pixmap); 21403b705cfSriastradh goto unwind; 21503b705cfSriastradh } 21603b705cfSriastradh } 21703b705cfSriastradh 21803b705cfSriastradh if (attachments[i] == DRI2BufferDepth) 21903b705cfSriastradh pDepthPixmap = pixmap; 22003b705cfSriastradh 22103b705cfSriastradh buffers[i].attachment = attachments[i]; 22203b705cfSriastradh buffers[i].pitch = pixmap->devKind; 22303b705cfSriastradh buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 22403b705cfSriastradh buffers[i].driverPrivate = &privates[i]; 22503b705cfSriastradh buffers[i].flags = 0; /* not tiled */ 22603b705cfSriastradh privates[i].refcnt = 1; 22703b705cfSriastradh privates[i].pixmap = pixmap; 22803b705cfSriastradh 22903b705cfSriastradh if ((buffers[i].name = pixmap_flink(pixmap)) == 0) { 23003b705cfSriastradh /* failed to name buffer */ 23103b705cfSriastradh screen->DestroyPixmap(pixmap); 23203b705cfSriastradh goto unwind; 23303b705cfSriastradh } 23403b705cfSriastradh } 23503b705cfSriastradh 23603b705cfSriastradh return buffers; 23703b705cfSriastradh 23803b705cfSriastradhunwind: 23903b705cfSriastradh while (i--) 24003b705cfSriastradh screen->DestroyPixmap(privates[i].pixmap); 24103b705cfSriastradh free(privates); 24203b705cfSriastradh free(buffers); 24303b705cfSriastradh return NULL; 24403b705cfSriastradh} 24503b705cfSriastradh 24603b705cfSriastradhstatic void 24703b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count) 24803b705cfSriastradh{ 24903b705cfSriastradh ScreenPtr screen = drawable->pScreen; 25003b705cfSriastradh I830DRI2BufferPrivatePtr private; 25103b705cfSriastradh int i; 25203b705cfSriastradh 25303b705cfSriastradh for (i = 0; i < count; i++) { 25403b705cfSriastradh private = buffers[i].driverPrivate; 25503b705cfSriastradh screen->DestroyPixmap(private->pixmap); 25603b705cfSriastradh } 25703b705cfSriastradh 25803b705cfSriastradh if (buffers) { 25903b705cfSriastradh free(buffers[0].driverPrivate); 26003b705cfSriastradh free(buffers); 26103b705cfSriastradh } 26203b705cfSriastradh} 26303b705cfSriastradh 26403b705cfSriastradh#else 26503b705cfSriastradh 26603b705cfSriastradhstatic DRI2Buffer2Ptr 26703b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, 26803b705cfSriastradh unsigned int format) 26903b705cfSriastradh{ 27003b705cfSriastradh ScreenPtr screen = drawable->pScreen; 27103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 27203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 27303b705cfSriastradh DRI2Buffer2Ptr buffer; 27403b705cfSriastradh I830DRI2BufferPrivatePtr privates; 27503b705cfSriastradh PixmapPtr pixmap; 27603b705cfSriastradh 27703b705cfSriastradh buffer = calloc(1, sizeof *buffer); 27803b705cfSriastradh if (buffer == NULL) 27903b705cfSriastradh return NULL; 28003b705cfSriastradh privates = calloc(1, sizeof *privates); 28103b705cfSriastradh if (privates == NULL) { 28203b705cfSriastradh free(buffer); 28303b705cfSriastradh return NULL; 28403b705cfSriastradh } 28503b705cfSriastradh 28603b705cfSriastradh pixmap = NULL; 287fe8aea9eSmrg if (attachment == DRI2BufferFrontLeft) 28803b705cfSriastradh pixmap = get_front_buffer(drawable); 28903b705cfSriastradh 29003b705cfSriastradh if (pixmap == NULL) { 29103b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 29203b705cfSriastradh int pixmap_width = drawable->width; 29303b705cfSriastradh int pixmap_height = drawable->height; 29403b705cfSriastradh int pixmap_cpp = (format != 0) ? format : drawable->depth; 29503b705cfSriastradh 29603b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 29703b705cfSriastradh switch (attachment) { 29803b705cfSriastradh case DRI2BufferDepth: 29903b705cfSriastradh case DRI2BufferDepthStencil: 30003b705cfSriastradh case DRI2BufferHiz: 30103b705cfSriastradh if (SUPPORTS_YTILING(intel)) { 30203b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 30303b705cfSriastradh break; 30403b705cfSriastradh } 30503b705cfSriastradh case DRI2BufferAccum: 30603b705cfSriastradh case DRI2BufferBackLeft: 30703b705cfSriastradh case DRI2BufferBackRight: 30803b705cfSriastradh case DRI2BufferFakeFrontLeft: 30903b705cfSriastradh case DRI2BufferFakeFrontRight: 31003b705cfSriastradh case DRI2BufferFrontLeft: 31103b705cfSriastradh case DRI2BufferFrontRight: 31203b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 31303b705cfSriastradh break; 31403b705cfSriastradh case DRI2BufferStencil: 31503b705cfSriastradh /* 31603b705cfSriastradh * The stencil buffer is W tiled. However, we 31703b705cfSriastradh * request from the kernel a non-tiled buffer 31803b705cfSriastradh * because the GTT is incapable of W fencing. 31903b705cfSriastradh */ 32003b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_NONE; 32103b705cfSriastradh break; 32203b705cfSriastradh default: 32303b705cfSriastradh free(privates); 32403b705cfSriastradh free(buffer); 32503b705cfSriastradh return NULL; 32603b705cfSriastradh } 32703b705cfSriastradh } 32803b705cfSriastradh 32903b705cfSriastradh /* 33003b705cfSriastradh * The stencil buffer has quirky pitch requirements. From Vol 33103b705cfSriastradh * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 33203b705cfSriastradh * Pitch": 33303b705cfSriastradh * The pitch must be set to 2x the value computed based on 33403b705cfSriastradh * width, as the stencil buffer is stored with two rows 33503b705cfSriastradh * interleaved. 33603b705cfSriastradh * To accomplish this, we resort to the nasty hack of doubling 33703b705cfSriastradh * the drm region's cpp and halving its height. 33803b705cfSriastradh * 33903b705cfSriastradh * If we neglect to double the pitch, then render corruption 34003b705cfSriastradh * occurs. 34103b705cfSriastradh */ 34203b705cfSriastradh if (attachment == DRI2BufferStencil) { 34303b705cfSriastradh pixmap_width = ALIGN(pixmap_width, 64); 34403b705cfSriastradh pixmap_height = ALIGN((pixmap_height + 1) / 2, 64); 34503b705cfSriastradh pixmap_cpp *= 2; 34603b705cfSriastradh } 34703b705cfSriastradh 34803b705cfSriastradh pixmap = screen->CreatePixmap(screen, 34903b705cfSriastradh pixmap_width, 35003b705cfSriastradh pixmap_height, 35103b705cfSriastradh pixmap_cpp, 35203b705cfSriastradh hint); 35303b705cfSriastradh if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) { 35403b705cfSriastradh if (pixmap) 35503b705cfSriastradh screen->DestroyPixmap(pixmap); 35603b705cfSriastradh free(privates); 35703b705cfSriastradh free(buffer); 35803b705cfSriastradh return NULL; 35903b705cfSriastradh } 36003b705cfSriastradh } 36103b705cfSriastradh 36203b705cfSriastradh buffer->attachment = attachment; 36303b705cfSriastradh buffer->pitch = pixmap->devKind; 36403b705cfSriastradh buffer->cpp = pixmap->drawable.bitsPerPixel / 8; 36503b705cfSriastradh buffer->driverPrivate = privates; 36603b705cfSriastradh buffer->format = format; 36703b705cfSriastradh buffer->flags = 0; /* not tiled */ 36803b705cfSriastradh privates->refcnt = 1; 36903b705cfSriastradh privates->pixmap = pixmap; 37003b705cfSriastradh 37103b705cfSriastradh if ((buffer->name = pixmap_flink(pixmap)) == 0) { 37203b705cfSriastradh /* failed to name buffer */ 37303b705cfSriastradh screen->DestroyPixmap(pixmap); 37403b705cfSriastradh free(privates); 37503b705cfSriastradh free(buffer); 37603b705cfSriastradh return NULL; 37703b705cfSriastradh } 37803b705cfSriastradh 37903b705cfSriastradh return buffer; 38003b705cfSriastradh} 38103b705cfSriastradh 38203b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer) 38303b705cfSriastradh{ 38403b705cfSriastradh if (buffer && buffer->driverPrivate) { 38503b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 38603b705cfSriastradh if (--private->refcnt == 0) { 38703b705cfSriastradh ScreenPtr screen = private->pixmap->drawable.pScreen; 38803b705cfSriastradh screen->DestroyPixmap(private->pixmap); 38903b705cfSriastradh 39003b705cfSriastradh free(private); 39103b705cfSriastradh free(buffer); 39203b705cfSriastradh } 39303b705cfSriastradh } else 39403b705cfSriastradh free(buffer); 39503b705cfSriastradh} 39603b705cfSriastradh 39703b705cfSriastradh#endif 39803b705cfSriastradh 39903b705cfSriastradhstatic void 40003b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion, 40103b705cfSriastradh DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer) 40203b705cfSriastradh{ 40303b705cfSriastradh I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate; 40403b705cfSriastradh I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate; 40503b705cfSriastradh ScreenPtr screen = drawable->pScreen; 40603b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 40703b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 40803b705cfSriastradh DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft) 40903b705cfSriastradh ? drawable : &srcPrivate->pixmap->drawable; 41003b705cfSriastradh DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft) 41103b705cfSriastradh ? drawable : &dstPrivate->pixmap->drawable; 41203b705cfSriastradh RegionPtr pCopyClip; 41303b705cfSriastradh GCPtr gc; 41403b705cfSriastradh 41503b705cfSriastradh gc = GetScratchGC(dst->depth, screen); 41603b705cfSriastradh if (!gc) 41703b705cfSriastradh return; 41803b705cfSriastradh 41903b705cfSriastradh pCopyClip = REGION_CREATE(screen, NULL, 0); 42003b705cfSriastradh REGION_COPY(screen, pCopyClip, pRegion); 42103b705cfSriastradh (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0); 42203b705cfSriastradh ValidateGC(dst, gc); 42303b705cfSriastradh 42403b705cfSriastradh /* Wait for the scanline to be outside the region to be copied */ 42503b705cfSriastradh if (scrn->vtSema && 42603b705cfSriastradh pixmap_is_scanout(get_drawable_pixmap(dst)) && 42703b705cfSriastradh intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) { 42803b705cfSriastradh BoxPtr box; 42903b705cfSriastradh BoxRec crtcbox; 43003b705cfSriastradh int y1, y2; 43103b705cfSriastradh int event, load_scan_lines_pipe; 43203b705cfSriastradh xf86CrtcPtr crtc; 43303b705cfSriastradh Bool full_height = FALSE; 43403b705cfSriastradh 43503b705cfSriastradh box = REGION_EXTENTS(unused, gc->pCompositeClip); 43603b705cfSriastradh crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox); 43703b705cfSriastradh 43803b705cfSriastradh /* 43903b705cfSriastradh * Make sure the CRTC is valid and this is the real front 44003b705cfSriastradh * buffer 44103b705cfSriastradh */ 44203b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) { 44303b705cfSriastradh int pipe = intel_crtc_to_pipe(crtc); 44403b705cfSriastradh 44503b705cfSriastradh /* 44603b705cfSriastradh * Make sure we don't wait for a scanline that will 44703b705cfSriastradh * never occur 44803b705cfSriastradh */ 44903b705cfSriastradh y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 45003b705cfSriastradh y2 = (box->y2 <= crtcbox.y2) ? 45103b705cfSriastradh box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 45203b705cfSriastradh 45303b705cfSriastradh if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1)) 45403b705cfSriastradh full_height = TRUE; 45503b705cfSriastradh 45603b705cfSriastradh /* 45703b705cfSriastradh * Pre-965 doesn't have SVBLANK, so we need a bit 45803b705cfSriastradh * of extra time for the blitter to start up and 45903b705cfSriastradh * do its job for a full height blit 46003b705cfSriastradh */ 46103b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen < 040) 46203b705cfSriastradh y2 -= 2; 46303b705cfSriastradh 46403b705cfSriastradh if (pipe == 0) { 46503b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 46603b705cfSriastradh load_scan_lines_pipe = 46703b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 46803b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 46903b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SVBLANK; 47003b705cfSriastradh } else { 47103b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 47203b705cfSriastradh load_scan_lines_pipe = 47303b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 47403b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 47503b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SVBLANK; 47603b705cfSriastradh } 47703b705cfSriastradh 47803b705cfSriastradh if (crtc->mode.Flags & V_INTERLACE) { 47903b705cfSriastradh /* DSL count field lines */ 48003b705cfSriastradh y1 /= 2; 48103b705cfSriastradh y2 /= 2; 48203b705cfSriastradh } 48303b705cfSriastradh 48403b705cfSriastradh BEGIN_BATCH(5); 48503b705cfSriastradh /* 48603b705cfSriastradh * The documentation says that the LOAD_SCAN_LINES 48703b705cfSriastradh * command always comes in pairs. Don't ask me why. 48803b705cfSriastradh */ 48903b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 49003b705cfSriastradh load_scan_lines_pipe); 49103b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 49203b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 49303b705cfSriastradh load_scan_lines_pipe); 49403b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 49503b705cfSriastradh OUT_BATCH(MI_WAIT_FOR_EVENT | event); 49603b705cfSriastradh ADVANCE_BATCH(); 49703b705cfSriastradh } 49803b705cfSriastradh } 49903b705cfSriastradh 50003b705cfSriastradh /* It's important that this copy gets submitted before the 50103b705cfSriastradh * direct rendering client submits rendering for the next 50203b705cfSriastradh * frame, but we don't actually need to submit right now. The 50303b705cfSriastradh * client will wait for the DRI2CopyRegion reply or the swap 50403b705cfSriastradh * buffer event before rendering, and we'll hit the flush 50503b705cfSriastradh * callback chain before those messages are sent. We submit 50603b705cfSriastradh * our batch buffers from the flush callback chain so we know 50703b705cfSriastradh * that will happen before the client tries to render 50803b705cfSriastradh * again. */ 50903b705cfSriastradh 51003b705cfSriastradh gc->ops->CopyArea(src, dst, gc, 51103b705cfSriastradh 0, 0, 51203b705cfSriastradh drawable->width, drawable->height, 51303b705cfSriastradh 0, 0); 51403b705cfSriastradh 51503b705cfSriastradh FreeScratchGC(gc); 51603b705cfSriastradh 51703b705cfSriastradh /* And make sure the WAIT_FOR_EVENT is queued before any 51803b705cfSriastradh * modesetting/dpms operations on the pipe. 51903b705cfSriastradh */ 52003b705cfSriastradh intel_batch_submit(scrn); 52103b705cfSriastradh} 52203b705cfSriastradh 52303b705cfSriastradhstatic void 52403b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable, 52503b705cfSriastradh DRI2BufferPtr dst, 52603b705cfSriastradh DRI2BufferPtr src) 52703b705cfSriastradh{ 52803b705cfSriastradh BoxRec box; 52903b705cfSriastradh RegionRec region; 53003b705cfSriastradh 53103b705cfSriastradh box.x1 = 0; 53203b705cfSriastradh box.y1 = 0; 53303b705cfSriastradh box.x2 = drawable->width; 53403b705cfSriastradh box.y2 = drawable->height; 53503b705cfSriastradh REGION_INIT(pScreen, ®ion, &box, 0); 53603b705cfSriastradh 53703b705cfSriastradh I830DRI2CopyRegion(drawable, ®ion, dst, src); 53803b705cfSriastradh} 53903b705cfSriastradh 54003b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 54103b705cfSriastradh 54203b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) 54303b705cfSriastradh{ 54403b705cfSriastradh if (buffer) { 54503b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 54603b705cfSriastradh private->refcnt++; 54703b705cfSriastradh } 54803b705cfSriastradh} 54903b705cfSriastradh 55042542f5fSchristosstatic xf86CrtcPtr 55142542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw) 55203b705cfSriastradh{ 55303b705cfSriastradh ScreenPtr pScreen = pDraw->pScreen; 55403b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 55503b705cfSriastradh BoxRec box, crtcbox; 55642542f5fSchristos xf86CrtcPtr crtc = NULL; 55703b705cfSriastradh 55803b705cfSriastradh box.x1 = pDraw->x; 55903b705cfSriastradh box.y1 = pDraw->y; 56003b705cfSriastradh box.x2 = box.x1 + pDraw->width; 56103b705cfSriastradh box.y2 = box.y1 + pDraw->height; 56203b705cfSriastradh 56342542f5fSchristos if (pDraw->type != DRAWABLE_PIXMAP) 56442542f5fSchristos crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 56503b705cfSriastradh 56603b705cfSriastradh /* Make sure the CRTC is valid and this is the real front buffer */ 56703b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) 56842542f5fSchristos return crtc; 56903b705cfSriastradh 57042542f5fSchristos return NULL; 57103b705cfSriastradh} 57203b705cfSriastradh 57303b705cfSriastradhstatic RESTYPE frame_event_client_type, frame_event_drawable_type; 57403b705cfSriastradh 57503b705cfSriastradhstruct i830_dri2_resource { 57603b705cfSriastradh XID id; 57703b705cfSriastradh RESTYPE type; 57803b705cfSriastradh struct list list; 57903b705cfSriastradh}; 58003b705cfSriastradh 58103b705cfSriastradhstatic struct i830_dri2_resource * 58203b705cfSriastradhget_resource(XID id, RESTYPE type) 58303b705cfSriastradh{ 58403b705cfSriastradh struct i830_dri2_resource *resource; 58503b705cfSriastradh void *ptr; 58603b705cfSriastradh 58703b705cfSriastradh ptr = NULL; 58803b705cfSriastradh dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess); 58903b705cfSriastradh if (ptr) 59003b705cfSriastradh return ptr; 59103b705cfSriastradh 59203b705cfSriastradh resource = malloc(sizeof(*resource)); 59303b705cfSriastradh if (resource == NULL) 59403b705cfSriastradh return NULL; 59503b705cfSriastradh 59603b705cfSriastradh if (!AddResource(id, type, resource)) { 59703b705cfSriastradh free(resource); 59803b705cfSriastradh return NULL; 59903b705cfSriastradh } 60003b705cfSriastradh 60103b705cfSriastradh resource->id = id; 60203b705cfSriastradh resource->type = type; 60303b705cfSriastradh list_init(&resource->list); 60403b705cfSriastradh return resource; 60503b705cfSriastradh} 60603b705cfSriastradh 60703b705cfSriastradhstatic int 60803b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id) 60903b705cfSriastradh{ 61003b705cfSriastradh struct i830_dri2_resource *resource = data; 61103b705cfSriastradh 61203b705cfSriastradh while (!list_is_empty(&resource->list)) { 61303b705cfSriastradh DRI2FrameEventPtr info = 61403b705cfSriastradh list_first_entry(&resource->list, 61503b705cfSriastradh DRI2FrameEventRec, 61603b705cfSriastradh client_resource); 61703b705cfSriastradh 61803b705cfSriastradh list_del(&info->client_resource); 61903b705cfSriastradh info->client = NULL; 62003b705cfSriastradh } 62103b705cfSriastradh free(resource); 62203b705cfSriastradh 62303b705cfSriastradh return Success; 62403b705cfSriastradh} 62503b705cfSriastradh 62603b705cfSriastradhstatic int 62703b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id) 62803b705cfSriastradh{ 62903b705cfSriastradh struct i830_dri2_resource *resource = data; 63003b705cfSriastradh 63103b705cfSriastradh while (!list_is_empty(&resource->list)) { 63203b705cfSriastradh DRI2FrameEventPtr info = 63303b705cfSriastradh list_first_entry(&resource->list, 63403b705cfSriastradh DRI2FrameEventRec, 63503b705cfSriastradh drawable_resource); 63603b705cfSriastradh 63703b705cfSriastradh list_del(&info->drawable_resource); 63803b705cfSriastradh info->drawable_id = None; 63903b705cfSriastradh } 64003b705cfSriastradh free(resource); 64103b705cfSriastradh 64203b705cfSriastradh return Success; 64303b705cfSriastradh} 64403b705cfSriastradh 64503b705cfSriastradhstatic Bool 64603b705cfSriastradhi830_dri2_register_frame_event_resource_types(void) 64703b705cfSriastradh{ 64803b705cfSriastradh frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client"); 64903b705cfSriastradh if (!frame_event_client_type) 65003b705cfSriastradh return FALSE; 65103b705cfSriastradh 65203b705cfSriastradh frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable"); 65303b705cfSriastradh if (!frame_event_drawable_type) 65403b705cfSriastradh return FALSE; 65503b705cfSriastradh 65603b705cfSriastradh return TRUE; 65703b705cfSriastradh} 65803b705cfSriastradh 65903b705cfSriastradhstatic XID 66003b705cfSriastradhget_client_id(ClientPtr client) 66103b705cfSriastradh{ 66203b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 66303b705cfSriastradh XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key); 66403b705cfSriastradh#else 66503b705cfSriastradh XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key); 66603b705cfSriastradh#endif 66703b705cfSriastradh if (*ptr == 0) 66803b705cfSriastradh *ptr = FakeClientID(client->index); 66903b705cfSriastradh return *ptr; 67003b705cfSriastradh} 67103b705cfSriastradh 67203b705cfSriastradh/* 67303b705cfSriastradh * Hook this frame event into the server resource 67403b705cfSriastradh * database so we can clean it up if the drawable or 67503b705cfSriastradh * client exits while the swap is pending 67603b705cfSriastradh */ 67703b705cfSriastradhstatic Bool 67803b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info) 67903b705cfSriastradh{ 68003b705cfSriastradh struct i830_dri2_resource *resource; 68103b705cfSriastradh 68203b705cfSriastradh resource = get_resource(get_client_id(info->client), 68303b705cfSriastradh frame_event_client_type); 68403b705cfSriastradh if (resource == NULL) 68503b705cfSriastradh return FALSE; 68603b705cfSriastradh 68703b705cfSriastradh list_add(&info->client_resource, &resource->list); 68803b705cfSriastradh 68903b705cfSriastradh resource = get_resource(info->drawable_id, frame_event_drawable_type); 69003b705cfSriastradh if (resource == NULL) { 69103b705cfSriastradh list_del(&info->client_resource); 69203b705cfSriastradh return FALSE; 69303b705cfSriastradh } 69403b705cfSriastradh 69503b705cfSriastradh list_add(&info->drawable_resource, &resource->list); 69603b705cfSriastradh 69703b705cfSriastradh return TRUE; 69803b705cfSriastradh} 69903b705cfSriastradh 70003b705cfSriastradhstatic void 70142542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info) 70203b705cfSriastradh{ 70303b705cfSriastradh list_del(&info->client_resource); 70403b705cfSriastradh list_del(&info->drawable_resource); 70503b705cfSriastradh 70603b705cfSriastradh if (info->front) 70742542f5fSchristos I830DRI2DestroyBuffer(NULL, info->front); 70803b705cfSriastradh if (info->back) 70942542f5fSchristos I830DRI2DestroyBuffer(NULL, info->back); 71003b705cfSriastradh 711fe8aea9eSmrg if (info->old_buffer) { 712fe8aea9eSmrg /* Check that the old buffer still matches the front buffer 713fe8aea9eSmrg * in case a mode change occurred before we woke up. 714fe8aea9eSmrg */ 715fe8aea9eSmrg if (info->intel->back_buffer == NULL && 716fe8aea9eSmrg info->old_width == info->intel->scrn->virtualX && 717fe8aea9eSmrg info->old_height == info->intel->scrn->virtualY && 718fe8aea9eSmrg info->old_pitch == info->intel->front_pitch && 719fe8aea9eSmrg info->old_tiling == info->intel->front_tiling) 720fe8aea9eSmrg info->intel->back_buffer = info->old_buffer; 721fe8aea9eSmrg else 722fe8aea9eSmrg dri_bo_unreference(info->old_buffer); 723fe8aea9eSmrg } 724fe8aea9eSmrg 72503b705cfSriastradh free(info); 72603b705cfSriastradh} 72703b705cfSriastradh 72813496ba1Ssnjstatic struct intel_uxa_pixmap * 72903b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back) 73003b705cfSriastradh{ 73113496ba1Ssnj struct intel_uxa_pixmap *new_front = NULL, *new_back; 73203b705cfSriastradh RegionRec region; 73303b705cfSriastradh 73403b705cfSriastradh /* Post damage on the front buffer so that listeners, such 73503b705cfSriastradh * as DisplayLink know take a copy and shove it over the USB. 73603b705cfSriastradh * also for sw cursors. 73703b705cfSriastradh */ 73803b705cfSriastradh region.extents.x1 = region.extents.y1 = 0; 73903b705cfSriastradh region.extents.x2 = front->drawable.width; 74003b705cfSriastradh region.extents.y2 = front->drawable.height; 74103b705cfSriastradh region.data = NULL; 74203b705cfSriastradh DamageRegionAppend(&front->drawable, ®ion); 74303b705cfSriastradh 74413496ba1Ssnj new_front = intel_uxa_get_pixmap_private(back); 74513496ba1Ssnj new_back = intel_uxa_get_pixmap_private(front); 74613496ba1Ssnj intel_uxa_set_pixmap_private(front, new_front); 74713496ba1Ssnj intel_uxa_set_pixmap_private(back, new_back); 74803b705cfSriastradh new_front->busy = 1; 74903b705cfSriastradh new_back->busy = -1; 75003b705cfSriastradh 75103b705cfSriastradh DamageRegionProcessPending(&front->drawable); 75203b705cfSriastradh 75303b705cfSriastradh return new_front; 75403b705cfSriastradh} 75503b705cfSriastradh 75603b705cfSriastradhstatic void 75703b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back) 75803b705cfSriastradh{ 75903b705cfSriastradh I830DRI2BufferPrivatePtr front_priv, back_priv; 76013496ba1Ssnj struct intel_uxa_pixmap *new_front; 76103b705cfSriastradh 76203b705cfSriastradh front_priv = front->driverPrivate; 76303b705cfSriastradh back_priv = back->driverPrivate; 76403b705cfSriastradh 76503b705cfSriastradh /* Swap BO names so DRI works */ 76603b705cfSriastradh front->name = back->name; 767fe8aea9eSmrg back->name = pixmap_flink(front_priv->pixmap); 76803b705cfSriastradh 76903b705cfSriastradh /* Swap pixmap bos */ 77003b705cfSriastradh new_front = intel_exchange_pixmap_buffers(intel, 77103b705cfSriastradh front_priv->pixmap, 77203b705cfSriastradh back_priv->pixmap); 77303b705cfSriastradh dri_bo_unreference (intel->front_buffer); 77403b705cfSriastradh intel->front_buffer = new_front->bo; 77503b705cfSriastradh dri_bo_reference (intel->front_buffer); 77603b705cfSriastradh} 77703b705cfSriastradh 77803b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) 77903b705cfSriastradh{ 78003b705cfSriastradh drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap); 78103b705cfSriastradh assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */ 78203b705cfSriastradh return bo; 78303b705cfSriastradh} 78403b705cfSriastradh 78542542f5fSchristosstatic void 78642542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data) 78742542f5fSchristos{ 78842542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 78942542f5fSchristos 79042542f5fSchristos I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000, 79142542f5fSchristos usec % 1000000, 79242542f5fSchristos info); 79342542f5fSchristos} 79442542f5fSchristos 79542542f5fSchristosstatic void 79642542f5fSchristosI830DRI2FlipAbort(void *pageflip_data) 79742542f5fSchristos{ 79842542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 79942542f5fSchristos 80042542f5fSchristos i830_dri2_del_frame_event(info); 80142542f5fSchristos} 80242542f5fSchristos 80303b705cfSriastradhstatic Bool 804fe8aea9eSmrgallocate_back_buffer(struct intel_screen_private *intel) 80503b705cfSriastradh{ 806fe8aea9eSmrg drm_intel_bo *bo; 807fe8aea9eSmrg int pitch; 808fe8aea9eSmrg uint32_t tiling; 80903b705cfSriastradh 810fe8aea9eSmrg if (intel->back_buffer) 81103b705cfSriastradh return TRUE; 81203b705cfSriastradh 813fe8aea9eSmrg bo = intel_allocate_framebuffer(intel->scrn, 814fe8aea9eSmrg intel->scrn->virtualX, 815fe8aea9eSmrg intel->scrn->virtualY, 816fe8aea9eSmrg intel->cpp, 817fe8aea9eSmrg &pitch, &tiling); 818fe8aea9eSmrg if (bo == NULL) 819fe8aea9eSmrg return FALSE; 82003b705cfSriastradh 821fe8aea9eSmrg if (pitch != intel->front_pitch || tiling != intel->front_tiling) { 822fe8aea9eSmrg drm_intel_bo_unreference(bo); 82303b705cfSriastradh return FALSE; 82403b705cfSriastradh } 82503b705cfSriastradh 826fe8aea9eSmrg intel->back_buffer = bo; 82703b705cfSriastradh return TRUE; 82803b705cfSriastradh} 82903b705cfSriastradh 83003b705cfSriastradhstatic Bool 83103b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) 83203b705cfSriastradh{ 83303b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen); 83403b705cfSriastradh struct intel_screen_private *intel = intel_get_screen_private(pScrn); 83503b705cfSriastradh I830DRI2BufferPrivatePtr front_priv = front->driverPrivate; 83603b705cfSriastradh I830DRI2BufferPrivatePtr back_priv = back->driverPrivate; 83703b705cfSriastradh PixmapPtr front_pixmap = front_priv->pixmap; 83803b705cfSriastradh PixmapPtr back_pixmap = back_priv->pixmap; 83913496ba1Ssnj struct intel_uxa_pixmap *front_intel = intel_uxa_get_pixmap_private(front_pixmap); 84013496ba1Ssnj struct intel_uxa_pixmap *back_intel = intel_uxa_get_pixmap_private(back_pixmap); 84103b705cfSriastradh 84203b705cfSriastradh if (!pScrn->vtSema) 84303b705cfSriastradh return FALSE; 84403b705cfSriastradh 84542542f5fSchristos if (I830DRI2DrawableCrtc(drawable) == NULL) 84603b705cfSriastradh return FALSE; 84703b705cfSriastradh 84803b705cfSriastradh if (!DRI2CanFlip(drawable)) 84903b705cfSriastradh return FALSE; 85003b705cfSriastradh 85103b705cfSriastradh if (intel->shadow_present) 85203b705cfSriastradh return FALSE; 85303b705cfSriastradh 85403b705cfSriastradh if (!intel->use_pageflipping) 85503b705cfSriastradh return FALSE; 85603b705cfSriastradh 85703b705cfSriastradh if (front_pixmap->drawable.width != back_pixmap->drawable.width) 85803b705cfSriastradh return FALSE; 85903b705cfSriastradh 86003b705cfSriastradh if (front_pixmap->drawable.height != back_pixmap->drawable.height) 86103b705cfSriastradh return FALSE; 86203b705cfSriastradh 86303b705cfSriastradh /* XXX should we be checking depth instead of bpp? */ 86403b705cfSriastradh#if 0 86503b705cfSriastradh if (front_pixmap->drawable.depth != back_pixmap->drawable.depth) 86603b705cfSriastradh return FALSE; 86703b705cfSriastradh#else 86803b705cfSriastradh if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 86903b705cfSriastradh return FALSE; 87003b705cfSriastradh#endif 87103b705cfSriastradh 87203b705cfSriastradh /* prevent an implicit tiling mode change */ 87303b705cfSriastradh if (front_intel->tiling != back_intel->tiling) 87403b705cfSriastradh return FALSE; 87503b705cfSriastradh 87642542f5fSchristos if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2)) 87742542f5fSchristos return FALSE; 87842542f5fSchristos 87903b705cfSriastradh return TRUE; 88003b705cfSriastradh} 88103b705cfSriastradh 882fe8aea9eSmrgstatic Bool 883fe8aea9eSmrgqueue_flip(struct intel_screen_private *intel, 884fe8aea9eSmrg DrawablePtr draw, 885fe8aea9eSmrg DRI2FrameEventPtr info) 886fe8aea9eSmrg{ 887fe8aea9eSmrg xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 888fe8aea9eSmrg I830DRI2BufferPrivatePtr priv = info->back->driverPrivate; 889fe8aea9eSmrg drm_intel_bo *old_back = get_pixmap_bo(priv); 890fe8aea9eSmrg 891fe8aea9eSmrg if (crtc == NULL) 892fe8aea9eSmrg return FALSE; 893fe8aea9eSmrg 894fe8aea9eSmrg if (!can_exchange(draw, info->front, info->back)) 895fe8aea9eSmrg return FALSE; 896fe8aea9eSmrg 897fe8aea9eSmrg if (!intel_do_pageflip(intel, old_back, 898fe8aea9eSmrg intel_crtc_to_pipe(crtc), 899fe8aea9eSmrg FALSE, info, 900fe8aea9eSmrg I830DRI2FlipComplete, I830DRI2FlipAbort)) 901fe8aea9eSmrg return FALSE; 902fe8aea9eSmrg 903fe8aea9eSmrg#if DRI2INFOREC_VERSION >= 6 904fe8aea9eSmrg if (intel->use_triple_buffer && allocate_back_buffer(intel)) { 905fe8aea9eSmrg info->old_width = intel->scrn->virtualX; 906fe8aea9eSmrg info->old_height = intel->scrn->virtualY; 907fe8aea9eSmrg info->old_pitch = intel->front_pitch; 908fe8aea9eSmrg info->old_tiling = intel->front_tiling; 909fe8aea9eSmrg info->old_buffer = intel->front_buffer; 910fe8aea9eSmrg dri_bo_reference(info->old_buffer); 911fe8aea9eSmrg 912fe8aea9eSmrg priv = info->front->driverPrivate; 913fe8aea9eSmrg intel_set_pixmap_bo(priv->pixmap, intel->back_buffer); 914fe8aea9eSmrg 915fe8aea9eSmrg dri_bo_unreference(intel->back_buffer); 916fe8aea9eSmrg intel->back_buffer = NULL; 917fe8aea9eSmrg 918fe8aea9eSmrg DRI2SwapLimit(draw, 2); 919fe8aea9eSmrg } else 920fe8aea9eSmrg DRI2SwapLimit(draw, 1); 921fe8aea9eSmrg#endif 922fe8aea9eSmrg 923fe8aea9eSmrg /* Then flip DRI2 pointers and update the screen pixmap */ 924fe8aea9eSmrg I830DRI2ExchangeBuffers(intel, info->front, info->back); 925fe8aea9eSmrg return TRUE; 926fe8aea9eSmrg} 927fe8aea9eSmrg 928fe8aea9eSmrgstatic Bool 929fe8aea9eSmrgqueue_swap(struct intel_screen_private *intel, 930fe8aea9eSmrg DrawablePtr draw, 931fe8aea9eSmrg DRI2FrameEventPtr info) 932fe8aea9eSmrg{ 933fe8aea9eSmrg xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 934fe8aea9eSmrg drmVBlank vbl; 935fe8aea9eSmrg 936fe8aea9eSmrg if (crtc == NULL) 937fe8aea9eSmrg return FALSE; 938fe8aea9eSmrg 939fe8aea9eSmrg vbl.request.type = 940fe8aea9eSmrg DRM_VBLANK_RELATIVE | 941fe8aea9eSmrg DRM_VBLANK_EVENT | 942fe8aea9eSmrg pipe_select(intel_crtc_to_pipe(crtc)); 943fe8aea9eSmrg vbl.request.sequence = 1; 944fe8aea9eSmrg vbl.request.signal = 945fe8aea9eSmrg intel_drm_queue_alloc(intel->scrn, crtc, info, 946fe8aea9eSmrg intel_dri2_vblank_handler, 947fe8aea9eSmrg intel_dri2_vblank_abort); 948fe8aea9eSmrg if (vbl.request.signal == 0) 949fe8aea9eSmrg return FALSE; 950fe8aea9eSmrg 951fe8aea9eSmrg info->type = DRI2_SWAP; 952fe8aea9eSmrg if (drmWaitVBlank(intel->drmSubFD, &vbl)) { 953fe8aea9eSmrg intel_drm_abort_seq(intel->scrn, vbl.request.signal); 954fe8aea9eSmrg return FALSE; 955fe8aea9eSmrg } 956fe8aea9eSmrg 957fe8aea9eSmrg return TRUE; 958fe8aea9eSmrg} 959fe8aea9eSmrg 960fe8aea9eSmrgstatic void I830DRI2FrameEventHandler(unsigned int frame, 961fe8aea9eSmrg unsigned int tv_sec, 962fe8aea9eSmrg unsigned int tv_usec, 963fe8aea9eSmrg DRI2FrameEventPtr swap_info) 96403b705cfSriastradh{ 96503b705cfSriastradh intel_screen_private *intel = swap_info->intel; 96603b705cfSriastradh DrawablePtr drawable; 96703b705cfSriastradh int status; 96803b705cfSriastradh 96903b705cfSriastradh if (!swap_info->drawable_id) 97003b705cfSriastradh status = BadDrawable; 97103b705cfSriastradh else 97203b705cfSriastradh status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient, 97303b705cfSriastradh M_ANY, DixWriteAccess); 97403b705cfSriastradh if (status != Success) { 97542542f5fSchristos i830_dri2_del_frame_event(swap_info); 97603b705cfSriastradh return; 97703b705cfSriastradh } 97803b705cfSriastradh 97903b705cfSriastradh switch (swap_info->type) { 98003b705cfSriastradh case DRI2_FLIP: 98103b705cfSriastradh /* If we can still flip... */ 982fe8aea9eSmrg if (!queue_flip(intel, drawable, swap_info) && 983fe8aea9eSmrg !queue_swap(intel, drawable, swap_info)) { 984fe8aea9eSmrg case DRI2_SWAP: 985fe8aea9eSmrg I830DRI2FallbackBlitSwap(drawable, 986fe8aea9eSmrg swap_info->front, swap_info->back); 987fe8aea9eSmrg DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec, 988fe8aea9eSmrg DRI2_BLIT_COMPLETE, 989fe8aea9eSmrg swap_info->client ? swap_info->event_complete : NULL, 990fe8aea9eSmrg swap_info->event_data); 991fe8aea9eSmrg break; 992fe8aea9eSmrg } 993fe8aea9eSmrg return; 994fe8aea9eSmrg 99503b705cfSriastradh case DRI2_WAITMSC: 99603b705cfSriastradh if (swap_info->client) 99703b705cfSriastradh DRI2WaitMSCComplete(swap_info->client, drawable, 99803b705cfSriastradh frame, tv_sec, tv_usec); 99903b705cfSriastradh break; 100003b705cfSriastradh default: 100103b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 100203b705cfSriastradh "%s: unknown vblank event received\n", __func__); 100303b705cfSriastradh /* Unknown type */ 100403b705cfSriastradh break; 100503b705cfSriastradh } 100603b705cfSriastradh 100742542f5fSchristos i830_dri2_del_frame_event(swap_info); 100803b705cfSriastradh} 100903b705cfSriastradh 1010fe8aea9eSmrgstatic void I830DRI2FlipEventHandler(unsigned int frame, 1011fe8aea9eSmrg unsigned int tv_sec, 1012fe8aea9eSmrg unsigned int tv_usec, 1013fe8aea9eSmrg DRI2FrameEventPtr flip_info) 101403b705cfSriastradh{ 101503b705cfSriastradh struct intel_screen_private *intel = flip_info->intel; 101603b705cfSriastradh DrawablePtr drawable; 101703b705cfSriastradh 101803b705cfSriastradh drawable = NULL; 101903b705cfSriastradh if (flip_info->drawable_id) 102003b705cfSriastradh dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, 102103b705cfSriastradh M_ANY, DixWriteAccess); 102203b705cfSriastradh 102303b705cfSriastradh 102403b705cfSriastradh /* We assume our flips arrive in order, so we don't check the frame */ 102503b705cfSriastradh switch (flip_info->type) { 1026fe8aea9eSmrg case DRI2_FLIP: 102703b705cfSriastradh case DRI2_SWAP: 102803b705cfSriastradh if (!drawable) 102903b705cfSriastradh break; 103003b705cfSriastradh 103103b705cfSriastradh /* Check for too small vblank count of pageflip completion, taking wraparound 103203b705cfSriastradh * into account. This usually means some defective kms pageflip completion, 103303b705cfSriastradh * causing wrong (msc, ust) return values and possible visual corruption. 103403b705cfSriastradh */ 103503b705cfSriastradh if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) { 103603b705cfSriastradh static int limit = 5; 103703b705cfSriastradh 103803b705cfSriastradh /* XXX we are currently hitting this path with older 103903b705cfSriastradh * kernels, so make it quieter. 104003b705cfSriastradh */ 104103b705cfSriastradh if (limit) { 104203b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 104303b705cfSriastradh "%s: Pageflip completion has impossible msc %d < target_msc %d\n", 104403b705cfSriastradh __func__, frame, flip_info->frame); 104503b705cfSriastradh limit--; 104603b705cfSriastradh } 104703b705cfSriastradh 104803b705cfSriastradh /* All-0 values signal timestamping failure. */ 104903b705cfSriastradh frame = tv_sec = tv_usec = 0; 105003b705cfSriastradh } 105103b705cfSriastradh 105203b705cfSriastradh DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, 105303b705cfSriastradh DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, 105403b705cfSriastradh flip_info->event_data); 105503b705cfSriastradh break; 105603b705cfSriastradh 105703b705cfSriastradh default: 105803b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 105903b705cfSriastradh "%s: unknown vblank event received\n", __func__); 106003b705cfSriastradh /* Unknown type */ 106103b705cfSriastradh break; 106203b705cfSriastradh } 106303b705cfSriastradh 106442542f5fSchristos i830_dri2_del_frame_event(flip_info); 106503b705cfSriastradh} 106603b705cfSriastradh 106703b705cfSriastradh/* 106803b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the 106903b705cfSriastradh * appropriate frame. 107003b705cfSriastradh * 107103b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 107203b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap 107303b705cfSriastradh * interval for the drawable. 107403b705cfSriastradh * 107503b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap 107603b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame 107703b705cfSriastradh * immediately following the received event. 107803b705cfSriastradh * 107903b705cfSriastradh * The client will be blocked if it tries to perform further GL commands 108003b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the 108103b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if 108203b705cfSriastradh * they access buffers busy with the flip. 108303b705cfSriastradh * 108403b705cfSriastradh * When the swap is complete, the driver should call into the server so it 108503b705cfSriastradh * can send any swap complete events that have been requested. 108603b705cfSriastradh */ 108703b705cfSriastradhstatic int 108803b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 108903b705cfSriastradh DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 109003b705cfSriastradh CARD64 remainder, DRI2SwapEventPtr func, void *data) 109103b705cfSriastradh{ 109203b705cfSriastradh ScreenPtr screen = draw->pScreen; 109303b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 109403b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 109503b705cfSriastradh drmVBlank vbl; 109642542f5fSchristos int ret; 109742542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 109842542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 109942542f5fSchristos int flip = 0; 110003b705cfSriastradh DRI2FrameEventPtr swap_info = NULL; 110142542f5fSchristos uint64_t current_msc, current_ust; 110242542f5fSchristos uint64_t request_msc; 110342542f5fSchristos uint32_t seq; 110403b705cfSriastradh 110503b705cfSriastradh /* Drawable not displayed... just complete the swap */ 110603b705cfSriastradh if (pipe == -1) 110703b705cfSriastradh goto blit_fallback; 110803b705cfSriastradh 110903b705cfSriastradh swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 111003b705cfSriastradh if (!swap_info) 111103b705cfSriastradh goto blit_fallback; 111203b705cfSriastradh 111303b705cfSriastradh swap_info->intel = intel; 111403b705cfSriastradh swap_info->drawable_id = draw->id; 111503b705cfSriastradh swap_info->client = client; 111603b705cfSriastradh swap_info->event_complete = func; 111703b705cfSriastradh swap_info->event_data = data; 111803b705cfSriastradh swap_info->front = front; 111903b705cfSriastradh swap_info->back = back; 1120fe8aea9eSmrg swap_info->type = DRI2_SWAP; 112103b705cfSriastradh 112203b705cfSriastradh if (!i830_dri2_add_frame_event(swap_info)) { 112303b705cfSriastradh free(swap_info); 112403b705cfSriastradh swap_info = NULL; 112503b705cfSriastradh goto blit_fallback; 112603b705cfSriastradh } 112703b705cfSriastradh 112803b705cfSriastradh I830DRI2ReferenceBuffer(front); 112903b705cfSriastradh I830DRI2ReferenceBuffer(back); 113003b705cfSriastradh 113142542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 113242542f5fSchristos if (ret) 113342542f5fSchristos goto blit_fallback; 113403b705cfSriastradh 1135fe8aea9eSmrg /* 1136fe8aea9eSmrg * If we can, schedule the flip directly from here rather 1137fe8aea9eSmrg * than waiting for an event from the kernel for the current 1138fe8aea9eSmrg * (or a past) MSC. 1139fe8aea9eSmrg */ 1140fe8aea9eSmrg if (divisor == 0 && 1141fe8aea9eSmrg current_msc >= *target_msc && 1142fe8aea9eSmrg queue_flip(intel, draw, swap_info)) 1143fe8aea9eSmrg return TRUE; 1144fe8aea9eSmrg 114503b705cfSriastradh if (can_exchange(draw, front, back)) { 1146fe8aea9eSmrg swap_info->type = DRI2_FLIP; 1147fe8aea9eSmrg /* Flips need to be submitted one frame before */ 1148fe8aea9eSmrg if (*target_msc > 0) 1149fe8aea9eSmrg --*target_msc; 1150fe8aea9eSmrg flip = 1; 115103b705cfSriastradh } 115203b705cfSriastradh 1153fe8aea9eSmrg#if DRI2INFOREC_VERSION >= 6 1154fe8aea9eSmrg DRI2SwapLimit(draw, 1); 1155fe8aea9eSmrg#endif 115603b705cfSriastradh 115703b705cfSriastradh /* 115803b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc 115903b705cfSriastradh * we just need to make sure target_msc passes before initiating 116003b705cfSriastradh * the swap. 116103b705cfSriastradh */ 116203b705cfSriastradh if (divisor == 0 || current_msc < *target_msc) { 116303b705cfSriastradh vbl.request.type = 116403b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 116503b705cfSriastradh 116603b705cfSriastradh /* If non-pageflipping, but blitting/exchanging, we need to use 116703b705cfSriastradh * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 116803b705cfSriastradh * on. 116903b705cfSriastradh */ 117003b705cfSriastradh if (flip == 0) 117103b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 117203b705cfSriastradh 117303b705cfSriastradh /* If target_msc already reached or passed, set it to 117403b705cfSriastradh * current_msc to ensure we return a reasonable value back 117503b705cfSriastradh * to the caller. This makes swap_interval logic more robust. 117603b705cfSriastradh */ 1177fe8aea9eSmrg if (current_msc > *target_msc) 117803b705cfSriastradh *target_msc = current_msc; 117903b705cfSriastradh 118042542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 118142542f5fSchristos if (!seq) 118242542f5fSchristos goto blit_fallback; 118342542f5fSchristos 118442542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc); 118542542f5fSchristos vbl.request.signal = seq; 118642542f5fSchristos 118703b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 118803b705cfSriastradh if (ret) { 118903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 119003b705cfSriastradh "divisor 0 get vblank counter failed: %s\n", 119103b705cfSriastradh strerror(errno)); 1192fe8aea9eSmrg intel_drm_abort_seq(intel->scrn, seq); 1193fe8aea9eSmrg swap_info = NULL; 119403b705cfSriastradh goto blit_fallback; 119503b705cfSriastradh } 119603b705cfSriastradh 119742542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 119803b705cfSriastradh swap_info->frame = *target_msc; 119903b705cfSriastradh 120003b705cfSriastradh return TRUE; 120103b705cfSriastradh } 120203b705cfSriastradh 120303b705cfSriastradh /* 120403b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 120503b705cfSriastradh * and we need to queue an event that will satisfy the divisor/remainder 120603b705cfSriastradh * equation. 120703b705cfSriastradh */ 120803b705cfSriastradh vbl.request.type = 120903b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 121003b705cfSriastradh if (flip == 0) 121103b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 121203b705cfSriastradh 121342542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 121442542f5fSchristos remainder; 121503b705cfSriastradh 121603b705cfSriastradh /* 121703b705cfSriastradh * If the calculated deadline vbl.request.sequence is smaller than 121803b705cfSriastradh * or equal to current_msc, it means we've passed the last point 121903b705cfSriastradh * when effective onset frame seq could satisfy 122003b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 122103b705cfSriastradh * this will happen. 122203b705cfSriastradh 122303b705cfSriastradh * This comparison takes the 1 frame swap delay in pageflipping mode 122403b705cfSriastradh * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 122503b705cfSriastradh * if we are blitting/exchanging instead of flipping. 122603b705cfSriastradh */ 122742542f5fSchristos if (request_msc <= current_msc) 122842542f5fSchristos request_msc += divisor; 122942542f5fSchristos 123042542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 123142542f5fSchristos if (!seq) 123242542f5fSchristos goto blit_fallback; 123303b705cfSriastradh 123403b705cfSriastradh /* Account for 1 frame extra pageflip delay if flip > 0 */ 123542542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip; 123642542f5fSchristos vbl.request.signal = seq; 123703b705cfSriastradh 123803b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 123903b705cfSriastradh if (ret) { 124003b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 124103b705cfSriastradh "final get vblank counter failed: %s\n", 124203b705cfSriastradh strerror(errno)); 124303b705cfSriastradh goto blit_fallback; 124403b705cfSriastradh } 124503b705cfSriastradh 124603b705cfSriastradh /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 124742542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 124803b705cfSriastradh swap_info->frame = *target_msc; 124903b705cfSriastradh 125003b705cfSriastradh return TRUE; 125103b705cfSriastradh 125203b705cfSriastradhblit_fallback: 125303b705cfSriastradh I830DRI2FallbackBlitSwap(draw, front, back); 125403b705cfSriastradh DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 125503b705cfSriastradh if (swap_info) 125642542f5fSchristos i830_dri2_del_frame_event(swap_info); 125703b705cfSriastradh *target_msc = 0; /* offscreen, so zero out target vblank count */ 125803b705cfSriastradh return TRUE; 125903b705cfSriastradh} 126003b705cfSriastradh 126103b705cfSriastradhstatic uint64_t gettime_us(void) 126203b705cfSriastradh{ 126303b705cfSriastradh struct timespec tv; 126403b705cfSriastradh 126503b705cfSriastradh if (clock_gettime(CLOCK_MONOTONIC, &tv)) 126603b705cfSriastradh return 0; 126703b705cfSriastradh 126803b705cfSriastradh return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; 126903b705cfSriastradh} 127003b705cfSriastradh 127103b705cfSriastradh/* 127203b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's 127303b705cfSriastradh * crtc. 127403b705cfSriastradh */ 127503b705cfSriastradhstatic int 127603b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 127703b705cfSriastradh{ 127803b705cfSriastradh ScreenPtr screen = draw->pScreen; 127903b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 128042542f5fSchristos int ret; 128142542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 128203b705cfSriastradh 128303b705cfSriastradh /* Drawable not displayed, make up a *monotonic* value */ 128442542f5fSchristos if (crtc == NULL) { 128542542f5fSchristosfail: 128603b705cfSriastradh *ust = gettime_us(); 128703b705cfSriastradh *msc = 0; 128803b705cfSriastradh return TRUE; 128903b705cfSriastradh } 129003b705cfSriastradh 129142542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust); 129203b705cfSriastradh if (ret) { 129303b705cfSriastradh static int limit = 5; 129403b705cfSriastradh if (limit) { 129503b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 129603b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 129703b705cfSriastradh __FUNCTION__, __LINE__, 129803b705cfSriastradh strerror(errno)); 129903b705cfSriastradh limit--; 130003b705cfSriastradh } 130142542f5fSchristos goto fail; 130203b705cfSriastradh } 130303b705cfSriastradh 130403b705cfSriastradh return TRUE; 130503b705cfSriastradh} 130603b705cfSriastradh 130703b705cfSriastradh/* 130803b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied. 130903b705cfSriastradh * 131003b705cfSriastradh * We need to handle the event and ask the server to wake up the client when 131103b705cfSriastradh * we receive it. 131203b705cfSriastradh */ 131303b705cfSriastradhstatic int 131403b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 131503b705cfSriastradh CARD64 divisor, CARD64 remainder) 131603b705cfSriastradh{ 131703b705cfSriastradh ScreenPtr screen = draw->pScreen; 131803b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 131903b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 132003b705cfSriastradh DRI2FrameEventPtr wait_info; 132103b705cfSriastradh drmVBlank vbl; 132242542f5fSchristos int ret; 132342542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 132442542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 132542542f5fSchristos CARD64 current_msc, current_ust, request_msc; 132642542f5fSchristos uint32_t seq; 132703b705cfSriastradh 132803b705cfSriastradh /* Drawable not visible, return immediately */ 132903b705cfSriastradh if (pipe == -1) 133003b705cfSriastradh goto out_complete; 133103b705cfSriastradh 133203b705cfSriastradh wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 133303b705cfSriastradh if (!wait_info) 133403b705cfSriastradh goto out_complete; 133503b705cfSriastradh 133603b705cfSriastradh wait_info->intel = intel; 133703b705cfSriastradh wait_info->drawable_id = draw->id; 133803b705cfSriastradh wait_info->client = client; 133903b705cfSriastradh wait_info->type = DRI2_WAITMSC; 134003b705cfSriastradh 134103b705cfSriastradh if (!i830_dri2_add_frame_event(wait_info)) { 134203b705cfSriastradh free(wait_info); 134303b705cfSriastradh goto out_complete; 134403b705cfSriastradh } 134503b705cfSriastradh 134603b705cfSriastradh /* Get current count */ 134742542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 134842542f5fSchristos if (ret) 134942542f5fSchristos goto out_free; 135003b705cfSriastradh 135103b705cfSriastradh /* 135203b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc, 135303b705cfSriastradh * we just need to make sure target_msc passes before waking up the 135403b705cfSriastradh * client. 135503b705cfSriastradh */ 135603b705cfSriastradh if (divisor == 0 || current_msc < target_msc) { 135703b705cfSriastradh /* If target_msc already reached or passed, set it to 135803b705cfSriastradh * current_msc to ensure we return a reasonable value back 135903b705cfSriastradh * to the caller. This keeps the client from continually 136003b705cfSriastradh * sending us MSC targets from the past by forcibly updating 136103b705cfSriastradh * their count on this call. 136203b705cfSriastradh */ 136342542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 136442542f5fSchristos if (!seq) 136542542f5fSchristos goto out_free; 136642542f5fSchristos 136703b705cfSriastradh if (current_msc >= target_msc) 136803b705cfSriastradh target_msc = current_msc; 136903b705cfSriastradh vbl.request.type = 137003b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 137142542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc); 137242542f5fSchristos vbl.request.signal = seq; 137342542f5fSchristos 137403b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 137503b705cfSriastradh if (ret) { 137603b705cfSriastradh static int limit = 5; 137703b705cfSriastradh if (limit) { 137803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 137903b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 138003b705cfSriastradh __FUNCTION__, __LINE__, 138103b705cfSriastradh strerror(errno)); 138203b705cfSriastradh limit--; 138303b705cfSriastradh } 1384fe8aea9eSmrg intel_drm_abort_seq(intel->scrn, seq); 1385fe8aea9eSmrg goto out_complete; 138603b705cfSriastradh } 138703b705cfSriastradh 138842542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 138903b705cfSriastradh DRI2BlockClient(client, draw); 139003b705cfSriastradh return TRUE; 139103b705cfSriastradh } 139203b705cfSriastradh 139303b705cfSriastradh /* 139403b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 139503b705cfSriastradh * so we queue an event that will satisfy the divisor/remainder equation. 139603b705cfSriastradh */ 139703b705cfSriastradh vbl.request.type = 139803b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 139903b705cfSriastradh 140042542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 140142542f5fSchristos remainder; 140203b705cfSriastradh /* 140303b705cfSriastradh * If calculated remainder is larger than requested remainder, 140403b705cfSriastradh * it means we've passed the last point where 140503b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 140603b705cfSriastradh * that will happen. 140703b705cfSriastradh */ 140803b705cfSriastradh if ((current_msc % divisor) >= remainder) 140942542f5fSchristos request_msc += divisor; 141042542f5fSchristos 141142542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 141242542f5fSchristos if (!seq) 141342542f5fSchristos goto out_free; 141442542f5fSchristos 141542542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); 141642542f5fSchristos vbl.request.signal = seq; 141703b705cfSriastradh 141803b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 141903b705cfSriastradh if (ret) { 142003b705cfSriastradh static int limit = 5; 142103b705cfSriastradh if (limit) { 142203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 142303b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 142403b705cfSriastradh __FUNCTION__, __LINE__, 142503b705cfSriastradh strerror(errno)); 142603b705cfSriastradh limit--; 142703b705cfSriastradh } 1428fe8aea9eSmrg intel_drm_abort_seq(intel->scrn, seq); 1429fe8aea9eSmrg goto out_complete; 143003b705cfSriastradh } 143103b705cfSriastradh 143242542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 143303b705cfSriastradh DRI2BlockClient(client, draw); 143403b705cfSriastradh 143503b705cfSriastradh return TRUE; 143603b705cfSriastradh 143703b705cfSriastradhout_free: 143842542f5fSchristos i830_dri2_del_frame_event(wait_info); 143903b705cfSriastradhout_complete: 144003b705cfSriastradh DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 144103b705cfSriastradh return TRUE; 144203b705cfSriastradh} 144303b705cfSriastradh 144403b705cfSriastradhstatic int dri2_server_generation; 144503b705cfSriastradh#endif 144603b705cfSriastradh 144703b705cfSriastradhstatic int has_i830_dri(void) 144803b705cfSriastradh{ 144903b705cfSriastradh return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 145003b705cfSriastradh} 145103b705cfSriastradh 1452fe8aea9eSmrgstatic int 1453fe8aea9eSmrgnamecmp(const char *s1, const char *s2) 1454fe8aea9eSmrg{ 1455fe8aea9eSmrg char c1, c2; 1456fe8aea9eSmrg 1457fe8aea9eSmrg if (!s1 || *s1 == 0) { 1458fe8aea9eSmrg if (!s2 || *s2 == 0) 1459fe8aea9eSmrg return 0; 1460fe8aea9eSmrg else 1461fe8aea9eSmrg return 1; 1462fe8aea9eSmrg } 1463fe8aea9eSmrg 1464fe8aea9eSmrg while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1465fe8aea9eSmrg s1++; 1466fe8aea9eSmrg 1467fe8aea9eSmrg while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1468fe8aea9eSmrg s2++; 1469fe8aea9eSmrg 1470fe8aea9eSmrg c1 = isupper(*s1) ? tolower(*s1) : *s1; 1471fe8aea9eSmrg c2 = isupper(*s2) ? tolower(*s2) : *s2; 1472fe8aea9eSmrg while (c1 == c2) { 1473fe8aea9eSmrg if (c1 == '\0') 1474fe8aea9eSmrg return 0; 1475fe8aea9eSmrg 1476fe8aea9eSmrg s1++; 1477fe8aea9eSmrg while (*s1 == '_' || *s1 == ' ' || *s1 == '\t') 1478fe8aea9eSmrg s1++; 1479fe8aea9eSmrg 1480fe8aea9eSmrg s2++; 1481fe8aea9eSmrg while (*s2 == '_' || *s2 == ' ' || *s2 == '\t') 1482fe8aea9eSmrg s2++; 1483fe8aea9eSmrg 1484fe8aea9eSmrg c1 = isupper(*s1) ? tolower(*s1) : *s1; 1485fe8aea9eSmrg c2 = isupper(*s2) ? tolower(*s2) : *s2; 1486fe8aea9eSmrg } 1487fe8aea9eSmrg 1488fe8aea9eSmrg return c1 - c2; 1489fe8aea9eSmrg} 1490fe8aea9eSmrg 1491fe8aea9eSmrgstatic Bool is_level(const char **str) 1492fe8aea9eSmrg{ 1493fe8aea9eSmrg const char *s = *str; 1494fe8aea9eSmrg char *end; 1495fe8aea9eSmrg unsigned val; 1496fe8aea9eSmrg 1497fe8aea9eSmrg if (s == NULL || *s == '\0') 1498fe8aea9eSmrg return TRUE; 1499fe8aea9eSmrg 1500fe8aea9eSmrg if (namecmp(s, "on") == 0) 1501fe8aea9eSmrg return TRUE; 1502fe8aea9eSmrg if (namecmp(s, "true") == 0) 1503fe8aea9eSmrg return TRUE; 1504fe8aea9eSmrg if (namecmp(s, "yes") == 0) 1505fe8aea9eSmrg return TRUE; 1506fe8aea9eSmrg 1507fe8aea9eSmrg if (namecmp(s, "0") == 0) 1508fe8aea9eSmrg return TRUE; 1509fe8aea9eSmrg if (namecmp(s, "off") == 0) 1510fe8aea9eSmrg return TRUE; 1511fe8aea9eSmrg if (namecmp(s, "false") == 0) 1512fe8aea9eSmrg return TRUE; 1513fe8aea9eSmrg if (namecmp(s, "no") == 0) 1514fe8aea9eSmrg return TRUE; 1515fe8aea9eSmrg 1516fe8aea9eSmrg val = strtoul(s, &end, 0); 1517fe8aea9eSmrg if (val && *end == '\0') 1518fe8aea9eSmrg return TRUE; 1519fe8aea9eSmrg if (val && *end == ':') 1520fe8aea9eSmrg *str = end + 1; 1521fe8aea9eSmrg return FALSE; 1522fe8aea9eSmrg} 1523fe8aea9eSmrg 1524fe8aea9eSmrgstatic const char *options_get_dri(intel_screen_private *intel) 152503b705cfSriastradh{ 152642542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 1527fe8aea9eSmrg return xf86GetOptValString(intel->Options, OPTION_DRI); 1528fe8aea9eSmrg#else 1529fe8aea9eSmrg return NULL; 1530fe8aea9eSmrg#endif 1531fe8aea9eSmrg} 153203b705cfSriastradh 1533fe8aea9eSmrgstatic const char *dri_driver_name(intel_screen_private *intel) 1534fe8aea9eSmrg{ 1535fe8aea9eSmrg const char *s = options_get_dri(intel); 1536fe8aea9eSmrg 1537fe8aea9eSmrg if (is_level(&s)) { 153803b705cfSriastradh if (INTEL_INFO(intel)->gen < 030) 153903b705cfSriastradh return has_i830_dri() ? "i830" : "i915"; 154003b705cfSriastradh else if (INTEL_INFO(intel)->gen < 040) 154103b705cfSriastradh return "i915"; 154203b705cfSriastradh else 154303b705cfSriastradh return "i965"; 154403b705cfSriastradh } 154503b705cfSriastradh 154603b705cfSriastradh return s; 154703b705cfSriastradh} 154803b705cfSriastradh 154903b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen) 155003b705cfSriastradh{ 155103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 155203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 155303b705cfSriastradh DRI2InfoRec info; 155442542f5fSchristos int dri2scr_major = 1; 155542542f5fSchristos int dri2scr_minor = 0; 155603b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 155742542f5fSchristos const char *driverNames[2]; 155803b705cfSriastradh#endif 155903b705cfSriastradh 156003b705cfSriastradh if (intel->force_fallback) { 156103b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 156203b705cfSriastradh "cannot enable DRI2 whilst forcing software fallbacks\n"); 156303b705cfSriastradh return FALSE; 156403b705cfSriastradh } 156503b705cfSriastradh 156603b705cfSriastradh if (xf86LoaderCheckSymbol("DRI2Version")) 156742542f5fSchristos DRI2Version(&dri2scr_major, &dri2scr_minor); 156803b705cfSriastradh 156942542f5fSchristos if (dri2scr_minor < 1) { 157003b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 157103b705cfSriastradh "DRI2 requires DRI2 module version 1.1.0 or later\n"); 157203b705cfSriastradh return FALSE; 157303b705cfSriastradh } 157403b705cfSriastradh 157503b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 157603b705cfSriastradh if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID))) 157703b705cfSriastradh return FALSE; 157803b705cfSriastradh#else 157903b705cfSriastradh if (!dixRequestPrivate(&i830_client_key, sizeof(XID))) 158003b705cfSriastradh return FALSE; 158103b705cfSriastradh#endif 158203b705cfSriastradh 158303b705cfSriastradh 158403b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 158503b705cfSriastradh if (serverGeneration != dri2_server_generation) { 158603b705cfSriastradh dri2_server_generation = serverGeneration; 158703b705cfSriastradh if (!i830_dri2_register_frame_event_resource_types()) { 158803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 158903b705cfSriastradh "Cannot register DRI2 frame event resources\n"); 159003b705cfSriastradh return FALSE; 159103b705cfSriastradh } 159203b705cfSriastradh } 159303b705cfSriastradh#endif 159403b705cfSriastradh 159503b705cfSriastradh intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD); 159603b705cfSriastradh memset(&info, '\0', sizeof(info)); 159703b705cfSriastradh info.fd = intel->drmSubFD; 159803b705cfSriastradh info.driverName = dri_driver_name(intel); 159903b705cfSriastradh info.deviceName = intel->deviceName; 160003b705cfSriastradh 160103b705cfSriastradh#if DRI2INFOREC_VERSION == 1 160203b705cfSriastradh info.version = 1; 160303b705cfSriastradh info.CreateBuffers = I830DRI2CreateBuffers; 160403b705cfSriastradh info.DestroyBuffers = I830DRI2DestroyBuffers; 160503b705cfSriastradh#elif DRI2INFOREC_VERSION == 2 160603b705cfSriastradh /* The ABI between 2 and 3 was broken so we could get rid of 160703b705cfSriastradh * the multi-buffer alloc functions. Make sure we indicate the 160803b705cfSriastradh * right version so DRI2 can reject us if it's version 3 or above. */ 160903b705cfSriastradh info.version = 2; 161003b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 161103b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 161203b705cfSriastradh#else 161303b705cfSriastradh info.version = 3; 161403b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 161503b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 161603b705cfSriastradh#endif 161703b705cfSriastradh 161803b705cfSriastradh info.CopyRegion = I830DRI2CopyRegion; 161903b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 162003b705cfSriastradh info.version = 4; 162103b705cfSriastradh info.ScheduleSwap = I830DRI2ScheduleSwap; 162203b705cfSriastradh info.GetMSC = I830DRI2GetMSC; 162303b705cfSriastradh info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC; 162442542f5fSchristos info.numDrivers = 2; 162503b705cfSriastradh info.driverNames = driverNames; 162603b705cfSriastradh driverNames[0] = info.driverName; 1627fe8aea9eSmrg driverNames[1] = "va_gl"; 162803b705cfSriastradh#endif 162903b705cfSriastradh 163003b705cfSriastradh return DRI2ScreenInit(screen, &info); 163103b705cfSriastradh} 163203b705cfSriastradh 163303b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen) 163403b705cfSriastradh{ 163503b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 163603b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 163703b705cfSriastradh 163803b705cfSriastradh DRI2CloseScreen(screen); 163903b705cfSriastradh drmFree(intel->deviceName); 164003b705cfSriastradh} 1641