intel_dri.c revision 42542f5f
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 6903b705cfSriastradh#include "intel_glamor.h" 7003b705cfSriastradh#include "uxa.h" 7103b705cfSriastradh 7203b705cfSriastradhtypedef struct { 7303b705cfSriastradh int refcnt; 7403b705cfSriastradh PixmapPtr pixmap; 7503b705cfSriastradh} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; 7603b705cfSriastradh 7703b705cfSriastradh#if HAS_DEVPRIVATEKEYREC 7803b705cfSriastradhstatic DevPrivateKeyRec i830_client_key; 7903b705cfSriastradh#else 8003b705cfSriastradhstatic int i830_client_key; 8103b705cfSriastradh#endif 8203b705cfSriastradh 8303b705cfSriastradhstatic uint32_t pixmap_flink(PixmapPtr pixmap) 8403b705cfSriastradh{ 8503b705cfSriastradh struct intel_pixmap *priv = intel_get_pixmap_private(pixmap); 8603b705cfSriastradh uint32_t name; 8703b705cfSriastradh 8803b705cfSriastradh if (priv == NULL || priv->bo == NULL) 8903b705cfSriastradh return 0; 9003b705cfSriastradh 9103b705cfSriastradh if (dri_bo_flink(priv->bo, &name) != 0) 9203b705cfSriastradh return 0; 9303b705cfSriastradh 9442542f5fSchristos priv->pinned |= PIN_DRI2; 9503b705cfSriastradh return name; 9603b705cfSriastradh} 9703b705cfSriastradh 9803b705cfSriastradhstatic PixmapPtr get_front_buffer(DrawablePtr drawable) 9903b705cfSriastradh{ 10003b705cfSriastradh PixmapPtr pixmap; 10103b705cfSriastradh 10203b705cfSriastradh pixmap = get_drawable_pixmap(drawable); 10303b705cfSriastradh if (!intel_get_pixmap_bo(pixmap)) 10403b705cfSriastradh return NULL; 10503b705cfSriastradh 10603b705cfSriastradh pixmap->refcnt++; 10703b705cfSriastradh return pixmap; 10803b705cfSriastradh} 10903b705cfSriastradh 11003b705cfSriastradhstatic PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap) 11103b705cfSriastradh{ 11203b705cfSriastradh ScreenPtr screen = drawable->pScreen; 11303b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 11403b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 11503b705cfSriastradh PixmapPtr old = get_drawable_pixmap(drawable); 11603b705cfSriastradh struct intel_pixmap *priv = intel_get_pixmap_private(pixmap); 11703b705cfSriastradh GCPtr gc; 11803b705cfSriastradh 11903b705cfSriastradh /* With a glamor pixmap, 2D pixmaps are created in texture 12003b705cfSriastradh * and without a static BO attached to it. To support DRI, 12103b705cfSriastradh * we need to create a new textured-drm pixmap and 12203b705cfSriastradh * need to copy the original content to this new textured-drm 12303b705cfSriastradh * pixmap, and then convert the old pixmap to a coherent 12403b705cfSriastradh * textured-drm pixmap which has a valid BO attached to it 12503b705cfSriastradh * and also has a valid texture, thus both glamor and DRI2 12603b705cfSriastradh * can access it. 12703b705cfSriastradh * 12803b705cfSriastradh */ 12903b705cfSriastradh 13003b705cfSriastradh /* Copy the current contents of the pixmap to the bo. */ 13103b705cfSriastradh gc = GetScratchGC(drawable->depth, screen); 13203b705cfSriastradh if (gc) { 13303b705cfSriastradh ValidateGC(&pixmap->drawable, gc); 13403b705cfSriastradh gc->ops->CopyArea(drawable, &pixmap->drawable, 13503b705cfSriastradh gc, 13603b705cfSriastradh 0, 0, 13703b705cfSriastradh drawable->width, 13803b705cfSriastradh drawable->height, 13903b705cfSriastradh 0, 0); 14003b705cfSriastradh FreeScratchGC(gc); 14103b705cfSriastradh } 14203b705cfSriastradh 14303b705cfSriastradh intel_set_pixmap_private(pixmap, NULL); 14403b705cfSriastradh 14503b705cfSriastradh /* Exchange the underlying texture/image. */ 14603b705cfSriastradh intel_glamor_exchange_buffers(intel, old, pixmap); 14703b705cfSriastradh /* And redirect the pixmap to the new bo (for 3D). */ 14803b705cfSriastradh intel_set_pixmap_private(old, priv); 14903b705cfSriastradh old->refcnt++; 15003b705cfSriastradh 15103b705cfSriastradh screen->ModifyPixmapHeader(old, 15203b705cfSriastradh drawable->width, 15303b705cfSriastradh drawable->height, 15403b705cfSriastradh 0, 0, 15503b705cfSriastradh priv->stride, 15603b705cfSriastradh NULL); 15703b705cfSriastradh screen->DestroyPixmap(pixmap); 15803b705cfSriastradh intel_get_screen_private(xf86ScreenToScrn(screen))->needs_flush = TRUE; 15903b705cfSriastradh return old; 16003b705cfSriastradh} 16103b705cfSriastradh 16203b705cfSriastradh#if DRI2INFOREC_VERSION < 2 16303b705cfSriastradhstatic DRI2BufferPtr 16403b705cfSriastradhI830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments, 16503b705cfSriastradh int count) 16603b705cfSriastradh{ 16703b705cfSriastradh ScreenPtr screen = drawable->pScreen; 16803b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 16903b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 17003b705cfSriastradh DRI2BufferPtr buffers; 17103b705cfSriastradh I830DRI2BufferPrivatePtr privates; 17203b705cfSriastradh PixmapPtr pixmap, pDepthPixmap; 17303b705cfSriastradh Bool is_glamor_pixmap = FALSE; 17403b705cfSriastradh int i; 17503b705cfSriastradh 17603b705cfSriastradh buffers = calloc(count, sizeof *buffers); 17703b705cfSriastradh if (buffers == NULL) 17803b705cfSriastradh return NULL; 17903b705cfSriastradh privates = calloc(count, sizeof *privates); 18003b705cfSriastradh if (privates == NULL) { 18103b705cfSriastradh free(buffers); 18203b705cfSriastradh return NULL; 18303b705cfSriastradh } 18403b705cfSriastradh 18503b705cfSriastradh pDepthPixmap = NULL; 18603b705cfSriastradh for (i = 0; i < count; i++) { 18703b705cfSriastradh pixmap = NULL; 18803b705cfSriastradh if (attachments[i] == DRI2BufferFrontLeft) { 18903b705cfSriastradh pixmap = get_front_buffer(drawable); 19003b705cfSriastradh 19103b705cfSriastradh if (pixmap == NULL) { 19203b705cfSriastradh drawable = &(get_drawable_pixmap(drawable)->drawable); 19303b705cfSriastradh is_glamor_pixmap = TRUE; 19403b705cfSriastradh } 19503b705cfSriastradh } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 19603b705cfSriastradh pixmap = pDepthPixmap; 19703b705cfSriastradh pixmap->refcnt++; 19803b705cfSriastradh } 19903b705cfSriastradh 20003b705cfSriastradh if (pixmap == NULL) { 20103b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 20203b705cfSriastradh 20303b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 20403b705cfSriastradh switch (attachments[i]) { 20503b705cfSriastradh case DRI2BufferDepth: 20603b705cfSriastradh if (SUPPORTS_YTILING(intel)) 20703b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 20803b705cfSriastradh else 20903b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 21003b705cfSriastradh break; 21103b705cfSriastradh case DRI2BufferFakeFrontLeft: 21203b705cfSriastradh case DRI2BufferFakeFrontRight: 21303b705cfSriastradh case DRI2BufferBackLeft: 21403b705cfSriastradh case DRI2BufferBackRight: 21503b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 21603b705cfSriastradh break; 21703b705cfSriastradh } 21803b705cfSriastradh } 21903b705cfSriastradh 22003b705cfSriastradh pixmap = screen->CreatePixmap(screen, 22103b705cfSriastradh drawable->width, 22203b705cfSriastradh drawable->height, 22303b705cfSriastradh drawable->depth, 22403b705cfSriastradh hint); 22503b705cfSriastradh if (pixmap == NULL || 22603b705cfSriastradh intel_get_pixmap_bo(pixmap) == NULL) 22703b705cfSriastradh { 22803b705cfSriastradh if (pixmap) 22903b705cfSriastradh screen->DestroyPixmap(pixmap); 23003b705cfSriastradh goto unwind; 23103b705cfSriastradh } 23203b705cfSriastradh 23303b705cfSriastradh if (is_glamor_pixmap) 23403b705cfSriastradh pixmap = fixup_glamor(drawable, pixmap); 23503b705cfSriastradh } 23603b705cfSriastradh 23703b705cfSriastradh if (attachments[i] == DRI2BufferDepth) 23803b705cfSriastradh pDepthPixmap = pixmap; 23903b705cfSriastradh 24003b705cfSriastradh buffers[i].attachment = attachments[i]; 24103b705cfSriastradh buffers[i].pitch = pixmap->devKind; 24203b705cfSriastradh buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 24303b705cfSriastradh buffers[i].driverPrivate = &privates[i]; 24403b705cfSriastradh buffers[i].flags = 0; /* not tiled */ 24503b705cfSriastradh privates[i].refcnt = 1; 24603b705cfSriastradh privates[i].pixmap = pixmap; 24703b705cfSriastradh 24803b705cfSriastradh if ((buffers[i].name = pixmap_flink(pixmap)) == 0) { 24903b705cfSriastradh /* failed to name buffer */ 25003b705cfSriastradh screen->DestroyPixmap(pixmap); 25103b705cfSriastradh goto unwind; 25203b705cfSriastradh } 25303b705cfSriastradh } 25403b705cfSriastradh 25503b705cfSriastradh return buffers; 25603b705cfSriastradh 25703b705cfSriastradhunwind: 25803b705cfSriastradh while (i--) 25903b705cfSriastradh screen->DestroyPixmap(privates[i].pixmap); 26003b705cfSriastradh free(privates); 26103b705cfSriastradh free(buffers); 26203b705cfSriastradh return NULL; 26303b705cfSriastradh} 26403b705cfSriastradh 26503b705cfSriastradhstatic void 26603b705cfSriastradhI830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count) 26703b705cfSriastradh{ 26803b705cfSriastradh ScreenPtr screen = drawable->pScreen; 26903b705cfSriastradh I830DRI2BufferPrivatePtr private; 27003b705cfSriastradh int i; 27103b705cfSriastradh 27203b705cfSriastradh for (i = 0; i < count; i++) { 27303b705cfSriastradh private = buffers[i].driverPrivate; 27403b705cfSriastradh screen->DestroyPixmap(private->pixmap); 27503b705cfSriastradh } 27603b705cfSriastradh 27703b705cfSriastradh if (buffers) { 27803b705cfSriastradh free(buffers[0].driverPrivate); 27903b705cfSriastradh free(buffers); 28003b705cfSriastradh } 28103b705cfSriastradh} 28203b705cfSriastradh 28303b705cfSriastradh#else 28403b705cfSriastradh 28503b705cfSriastradhstatic DRI2Buffer2Ptr 28603b705cfSriastradhI830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, 28703b705cfSriastradh unsigned int format) 28803b705cfSriastradh{ 28903b705cfSriastradh ScreenPtr screen = drawable->pScreen; 29003b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 29103b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 29203b705cfSriastradh DRI2Buffer2Ptr buffer; 29303b705cfSriastradh I830DRI2BufferPrivatePtr privates; 29403b705cfSriastradh PixmapPtr pixmap; 29503b705cfSriastradh Bool is_glamor_pixmap = FALSE; 29603b705cfSriastradh 29703b705cfSriastradh buffer = calloc(1, sizeof *buffer); 29803b705cfSriastradh if (buffer == NULL) 29903b705cfSriastradh return NULL; 30003b705cfSriastradh privates = calloc(1, sizeof *privates); 30103b705cfSriastradh if (privates == NULL) { 30203b705cfSriastradh free(buffer); 30303b705cfSriastradh return NULL; 30403b705cfSriastradh } 30503b705cfSriastradh 30603b705cfSriastradh pixmap = NULL; 30703b705cfSriastradh if (attachment == DRI2BufferFrontLeft) { 30803b705cfSriastradh pixmap = get_front_buffer(drawable); 30903b705cfSriastradh 31003b705cfSriastradh if (pixmap == NULL) { 31103b705cfSriastradh drawable = &(get_drawable_pixmap(drawable)->drawable); 31203b705cfSriastradh is_glamor_pixmap = TRUE; 31303b705cfSriastradh } 31403b705cfSriastradh } 31503b705cfSriastradh 31603b705cfSriastradh if (pixmap == NULL) { 31703b705cfSriastradh unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 31803b705cfSriastradh int pixmap_width = drawable->width; 31903b705cfSriastradh int pixmap_height = drawable->height; 32003b705cfSriastradh int pixmap_cpp = (format != 0) ? format : drawable->depth; 32103b705cfSriastradh 32203b705cfSriastradh if (intel->tiling & INTEL_TILING_3D) { 32303b705cfSriastradh switch (attachment) { 32403b705cfSriastradh case DRI2BufferDepth: 32503b705cfSriastradh case DRI2BufferDepthStencil: 32603b705cfSriastradh case DRI2BufferHiz: 32703b705cfSriastradh if (SUPPORTS_YTILING(intel)) { 32803b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_Y; 32903b705cfSriastradh break; 33003b705cfSriastradh } 33103b705cfSriastradh case DRI2BufferAccum: 33203b705cfSriastradh case DRI2BufferBackLeft: 33303b705cfSriastradh case DRI2BufferBackRight: 33403b705cfSriastradh case DRI2BufferFakeFrontLeft: 33503b705cfSriastradh case DRI2BufferFakeFrontRight: 33603b705cfSriastradh case DRI2BufferFrontLeft: 33703b705cfSriastradh case DRI2BufferFrontRight: 33803b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_X; 33903b705cfSriastradh break; 34003b705cfSriastradh case DRI2BufferStencil: 34103b705cfSriastradh /* 34203b705cfSriastradh * The stencil buffer is W tiled. However, we 34303b705cfSriastradh * request from the kernel a non-tiled buffer 34403b705cfSriastradh * because the GTT is incapable of W fencing. 34503b705cfSriastradh */ 34603b705cfSriastradh hint |= INTEL_CREATE_PIXMAP_TILING_NONE; 34703b705cfSriastradh break; 34803b705cfSriastradh default: 34903b705cfSriastradh free(privates); 35003b705cfSriastradh free(buffer); 35103b705cfSriastradh return NULL; 35203b705cfSriastradh } 35303b705cfSriastradh } 35403b705cfSriastradh 35503b705cfSriastradh /* 35603b705cfSriastradh * The stencil buffer has quirky pitch requirements. From Vol 35703b705cfSriastradh * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 35803b705cfSriastradh * Pitch": 35903b705cfSriastradh * The pitch must be set to 2x the value computed based on 36003b705cfSriastradh * width, as the stencil buffer is stored with two rows 36103b705cfSriastradh * interleaved. 36203b705cfSriastradh * To accomplish this, we resort to the nasty hack of doubling 36303b705cfSriastradh * the drm region's cpp and halving its height. 36403b705cfSriastradh * 36503b705cfSriastradh * If we neglect to double the pitch, then render corruption 36603b705cfSriastradh * occurs. 36703b705cfSriastradh */ 36803b705cfSriastradh if (attachment == DRI2BufferStencil) { 36903b705cfSriastradh pixmap_width = ALIGN(pixmap_width, 64); 37003b705cfSriastradh pixmap_height = ALIGN((pixmap_height + 1) / 2, 64); 37103b705cfSriastradh pixmap_cpp *= 2; 37203b705cfSriastradh } 37303b705cfSriastradh 37403b705cfSriastradh pixmap = screen->CreatePixmap(screen, 37503b705cfSriastradh pixmap_width, 37603b705cfSriastradh pixmap_height, 37703b705cfSriastradh pixmap_cpp, 37803b705cfSriastradh hint); 37903b705cfSriastradh if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) { 38003b705cfSriastradh if (pixmap) 38103b705cfSriastradh screen->DestroyPixmap(pixmap); 38203b705cfSriastradh free(privates); 38303b705cfSriastradh free(buffer); 38403b705cfSriastradh return NULL; 38503b705cfSriastradh } 38603b705cfSriastradh if (is_glamor_pixmap) 38703b705cfSriastradh pixmap = fixup_glamor(drawable, pixmap); 38803b705cfSriastradh } 38903b705cfSriastradh 39003b705cfSriastradh buffer->attachment = attachment; 39103b705cfSriastradh buffer->pitch = pixmap->devKind; 39203b705cfSriastradh buffer->cpp = pixmap->drawable.bitsPerPixel / 8; 39303b705cfSriastradh buffer->driverPrivate = privates; 39403b705cfSriastradh buffer->format = format; 39503b705cfSriastradh buffer->flags = 0; /* not tiled */ 39603b705cfSriastradh privates->refcnt = 1; 39703b705cfSriastradh privates->pixmap = pixmap; 39803b705cfSriastradh 39903b705cfSriastradh if ((buffer->name = pixmap_flink(pixmap)) == 0) { 40003b705cfSriastradh /* failed to name buffer */ 40103b705cfSriastradh screen->DestroyPixmap(pixmap); 40203b705cfSriastradh free(privates); 40303b705cfSriastradh free(buffer); 40403b705cfSriastradh return NULL; 40503b705cfSriastradh } 40603b705cfSriastradh 40703b705cfSriastradh return buffer; 40803b705cfSriastradh} 40903b705cfSriastradh 41003b705cfSriastradhstatic void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer) 41103b705cfSriastradh{ 41203b705cfSriastradh if (buffer && buffer->driverPrivate) { 41303b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 41403b705cfSriastradh if (--private->refcnt == 0) { 41503b705cfSriastradh ScreenPtr screen = private->pixmap->drawable.pScreen; 41603b705cfSriastradh screen->DestroyPixmap(private->pixmap); 41703b705cfSriastradh 41803b705cfSriastradh free(private); 41903b705cfSriastradh free(buffer); 42003b705cfSriastradh } 42103b705cfSriastradh } else 42203b705cfSriastradh free(buffer); 42303b705cfSriastradh} 42403b705cfSriastradh 42503b705cfSriastradh#endif 42603b705cfSriastradh 42703b705cfSriastradhstatic void 42803b705cfSriastradhI830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion, 42903b705cfSriastradh DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer) 43003b705cfSriastradh{ 43103b705cfSriastradh I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate; 43203b705cfSriastradh I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate; 43303b705cfSriastradh ScreenPtr screen = drawable->pScreen; 43403b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 43503b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 43603b705cfSriastradh DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft) 43703b705cfSriastradh ? drawable : &srcPrivate->pixmap->drawable; 43803b705cfSriastradh DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft) 43903b705cfSriastradh ? drawable : &dstPrivate->pixmap->drawable; 44003b705cfSriastradh RegionPtr pCopyClip; 44103b705cfSriastradh GCPtr gc; 44203b705cfSriastradh 44303b705cfSriastradh gc = GetScratchGC(dst->depth, screen); 44403b705cfSriastradh if (!gc) 44503b705cfSriastradh return; 44603b705cfSriastradh 44703b705cfSriastradh pCopyClip = REGION_CREATE(screen, NULL, 0); 44803b705cfSriastradh REGION_COPY(screen, pCopyClip, pRegion); 44903b705cfSriastradh (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0); 45003b705cfSriastradh ValidateGC(dst, gc); 45103b705cfSriastradh 45203b705cfSriastradh /* Wait for the scanline to be outside the region to be copied */ 45303b705cfSriastradh if (scrn->vtSema && 45403b705cfSriastradh pixmap_is_scanout(get_drawable_pixmap(dst)) && 45503b705cfSriastradh intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) { 45603b705cfSriastradh BoxPtr box; 45703b705cfSriastradh BoxRec crtcbox; 45803b705cfSriastradh int y1, y2; 45903b705cfSriastradh int event, load_scan_lines_pipe; 46003b705cfSriastradh xf86CrtcPtr crtc; 46103b705cfSriastradh Bool full_height = FALSE; 46203b705cfSriastradh 46303b705cfSriastradh box = REGION_EXTENTS(unused, gc->pCompositeClip); 46403b705cfSriastradh crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox); 46503b705cfSriastradh 46603b705cfSriastradh /* 46703b705cfSriastradh * Make sure the CRTC is valid and this is the real front 46803b705cfSriastradh * buffer 46903b705cfSriastradh */ 47003b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) { 47103b705cfSriastradh int pipe = intel_crtc_to_pipe(crtc); 47203b705cfSriastradh 47303b705cfSriastradh /* 47403b705cfSriastradh * Make sure we don't wait for a scanline that will 47503b705cfSriastradh * never occur 47603b705cfSriastradh */ 47703b705cfSriastradh y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 47803b705cfSriastradh y2 = (box->y2 <= crtcbox.y2) ? 47903b705cfSriastradh box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 48003b705cfSriastradh 48103b705cfSriastradh if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1)) 48203b705cfSriastradh full_height = TRUE; 48303b705cfSriastradh 48403b705cfSriastradh /* 48503b705cfSriastradh * Pre-965 doesn't have SVBLANK, so we need a bit 48603b705cfSriastradh * of extra time for the blitter to start up and 48703b705cfSriastradh * do its job for a full height blit 48803b705cfSriastradh */ 48903b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen < 040) 49003b705cfSriastradh y2 -= 2; 49103b705cfSriastradh 49203b705cfSriastradh if (pipe == 0) { 49303b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 49403b705cfSriastradh load_scan_lines_pipe = 49503b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 49603b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 49703b705cfSriastradh event = MI_WAIT_FOR_PIPEA_SVBLANK; 49803b705cfSriastradh } else { 49903b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 50003b705cfSriastradh load_scan_lines_pipe = 50103b705cfSriastradh MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 50203b705cfSriastradh if (full_height && INTEL_INFO(intel)->gen >= 040) 50303b705cfSriastradh event = MI_WAIT_FOR_PIPEB_SVBLANK; 50403b705cfSriastradh } 50503b705cfSriastradh 50603b705cfSriastradh if (crtc->mode.Flags & V_INTERLACE) { 50703b705cfSriastradh /* DSL count field lines */ 50803b705cfSriastradh y1 /= 2; 50903b705cfSriastradh y2 /= 2; 51003b705cfSriastradh } 51103b705cfSriastradh 51203b705cfSriastradh BEGIN_BATCH(5); 51303b705cfSriastradh /* 51403b705cfSriastradh * The documentation says that the LOAD_SCAN_LINES 51503b705cfSriastradh * command always comes in pairs. Don't ask me why. 51603b705cfSriastradh */ 51703b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 51803b705cfSriastradh load_scan_lines_pipe); 51903b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 52003b705cfSriastradh OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 52103b705cfSriastradh load_scan_lines_pipe); 52203b705cfSriastradh OUT_BATCH((y1 << 16) | (y2-1)); 52303b705cfSriastradh OUT_BATCH(MI_WAIT_FOR_EVENT | event); 52403b705cfSriastradh ADVANCE_BATCH(); 52503b705cfSriastradh } 52603b705cfSriastradh } 52703b705cfSriastradh 52803b705cfSriastradh /* It's important that this copy gets submitted before the 52903b705cfSriastradh * direct rendering client submits rendering for the next 53003b705cfSriastradh * frame, but we don't actually need to submit right now. The 53103b705cfSriastradh * client will wait for the DRI2CopyRegion reply or the swap 53203b705cfSriastradh * buffer event before rendering, and we'll hit the flush 53303b705cfSriastradh * callback chain before those messages are sent. We submit 53403b705cfSriastradh * our batch buffers from the flush callback chain so we know 53503b705cfSriastradh * that will happen before the client tries to render 53603b705cfSriastradh * again. */ 53703b705cfSriastradh 53803b705cfSriastradh gc->ops->CopyArea(src, dst, gc, 53903b705cfSriastradh 0, 0, 54003b705cfSriastradh drawable->width, drawable->height, 54103b705cfSriastradh 0, 0); 54203b705cfSriastradh 54303b705cfSriastradh FreeScratchGC(gc); 54403b705cfSriastradh 54503b705cfSriastradh /* And make sure the WAIT_FOR_EVENT is queued before any 54603b705cfSriastradh * modesetting/dpms operations on the pipe. 54703b705cfSriastradh */ 54803b705cfSriastradh intel_batch_submit(scrn); 54903b705cfSriastradh} 55003b705cfSriastradh 55103b705cfSriastradhstatic void 55203b705cfSriastradhI830DRI2FallbackBlitSwap(DrawablePtr drawable, 55303b705cfSriastradh DRI2BufferPtr dst, 55403b705cfSriastradh DRI2BufferPtr src) 55503b705cfSriastradh{ 55603b705cfSriastradh BoxRec box; 55703b705cfSriastradh RegionRec region; 55803b705cfSriastradh 55903b705cfSriastradh box.x1 = 0; 56003b705cfSriastradh box.y1 = 0; 56103b705cfSriastradh box.x2 = drawable->width; 56203b705cfSriastradh box.y2 = drawable->height; 56303b705cfSriastradh REGION_INIT(pScreen, ®ion, &box, 0); 56403b705cfSriastradh 56503b705cfSriastradh I830DRI2CopyRegion(drawable, ®ion, dst, src); 56603b705cfSriastradh} 56703b705cfSriastradh 56803b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 56903b705cfSriastradh 57003b705cfSriastradhstatic void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) 57103b705cfSriastradh{ 57203b705cfSriastradh if (buffer) { 57303b705cfSriastradh I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 57403b705cfSriastradh private->refcnt++; 57503b705cfSriastradh } 57603b705cfSriastradh} 57703b705cfSriastradh 57842542f5fSchristosstatic xf86CrtcPtr 57942542f5fSchristosI830DRI2DrawableCrtc(DrawablePtr pDraw) 58003b705cfSriastradh{ 58103b705cfSriastradh ScreenPtr pScreen = pDraw->pScreen; 58203b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 58303b705cfSriastradh BoxRec box, crtcbox; 58442542f5fSchristos xf86CrtcPtr crtc = NULL; 58503b705cfSriastradh 58603b705cfSriastradh box.x1 = pDraw->x; 58703b705cfSriastradh box.y1 = pDraw->y; 58803b705cfSriastradh box.x2 = box.x1 + pDraw->width; 58903b705cfSriastradh box.y2 = box.y1 + pDraw->height; 59003b705cfSriastradh 59142542f5fSchristos if (pDraw->type != DRAWABLE_PIXMAP) 59242542f5fSchristos crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 59303b705cfSriastradh 59403b705cfSriastradh /* Make sure the CRTC is valid and this is the real front buffer */ 59503b705cfSriastradh if (crtc != NULL && !crtc->rotatedData) 59642542f5fSchristos return crtc; 59703b705cfSriastradh 59842542f5fSchristos return NULL; 59903b705cfSriastradh} 60003b705cfSriastradh 60103b705cfSriastradhstatic RESTYPE frame_event_client_type, frame_event_drawable_type; 60203b705cfSriastradh 60303b705cfSriastradhstruct i830_dri2_resource { 60403b705cfSriastradh XID id; 60503b705cfSriastradh RESTYPE type; 60603b705cfSriastradh struct list list; 60703b705cfSriastradh}; 60803b705cfSriastradh 60903b705cfSriastradhstatic struct i830_dri2_resource * 61003b705cfSriastradhget_resource(XID id, RESTYPE type) 61103b705cfSriastradh{ 61203b705cfSriastradh struct i830_dri2_resource *resource; 61303b705cfSriastradh void *ptr; 61403b705cfSriastradh 61503b705cfSriastradh ptr = NULL; 61603b705cfSriastradh dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess); 61703b705cfSriastradh if (ptr) 61803b705cfSriastradh return ptr; 61903b705cfSriastradh 62003b705cfSriastradh resource = malloc(sizeof(*resource)); 62103b705cfSriastradh if (resource == NULL) 62203b705cfSriastradh return NULL; 62303b705cfSriastradh 62403b705cfSriastradh if (!AddResource(id, type, resource)) { 62503b705cfSriastradh free(resource); 62603b705cfSriastradh return NULL; 62703b705cfSriastradh } 62803b705cfSriastradh 62903b705cfSriastradh resource->id = id; 63003b705cfSriastradh resource->type = type; 63103b705cfSriastradh list_init(&resource->list); 63203b705cfSriastradh return resource; 63303b705cfSriastradh} 63403b705cfSriastradh 63503b705cfSriastradhstatic int 63603b705cfSriastradhi830_dri2_frame_event_client_gone(void *data, XID id) 63703b705cfSriastradh{ 63803b705cfSriastradh struct i830_dri2_resource *resource = data; 63903b705cfSriastradh 64003b705cfSriastradh while (!list_is_empty(&resource->list)) { 64103b705cfSriastradh DRI2FrameEventPtr info = 64203b705cfSriastradh list_first_entry(&resource->list, 64303b705cfSriastradh DRI2FrameEventRec, 64403b705cfSriastradh client_resource); 64503b705cfSriastradh 64603b705cfSriastradh list_del(&info->client_resource); 64703b705cfSriastradh info->client = NULL; 64803b705cfSriastradh } 64903b705cfSriastradh free(resource); 65003b705cfSriastradh 65103b705cfSriastradh return Success; 65203b705cfSriastradh} 65303b705cfSriastradh 65403b705cfSriastradhstatic int 65503b705cfSriastradhi830_dri2_frame_event_drawable_gone(void *data, XID id) 65603b705cfSriastradh{ 65703b705cfSriastradh struct i830_dri2_resource *resource = data; 65803b705cfSriastradh 65903b705cfSriastradh while (!list_is_empty(&resource->list)) { 66003b705cfSriastradh DRI2FrameEventPtr info = 66103b705cfSriastradh list_first_entry(&resource->list, 66203b705cfSriastradh DRI2FrameEventRec, 66303b705cfSriastradh drawable_resource); 66403b705cfSriastradh 66503b705cfSriastradh list_del(&info->drawable_resource); 66603b705cfSriastradh info->drawable_id = None; 66703b705cfSriastradh } 66803b705cfSriastradh free(resource); 66903b705cfSriastradh 67003b705cfSriastradh return Success; 67103b705cfSriastradh} 67203b705cfSriastradh 67303b705cfSriastradhstatic Bool 67403b705cfSriastradhi830_dri2_register_frame_event_resource_types(void) 67503b705cfSriastradh{ 67603b705cfSriastradh frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client"); 67703b705cfSriastradh if (!frame_event_client_type) 67803b705cfSriastradh return FALSE; 67903b705cfSriastradh 68003b705cfSriastradh frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable"); 68103b705cfSriastradh if (!frame_event_drawable_type) 68203b705cfSriastradh return FALSE; 68303b705cfSriastradh 68403b705cfSriastradh return TRUE; 68503b705cfSriastradh} 68603b705cfSriastradh 68703b705cfSriastradhstatic XID 68803b705cfSriastradhget_client_id(ClientPtr client) 68903b705cfSriastradh{ 69003b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 69103b705cfSriastradh XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key); 69203b705cfSriastradh#else 69303b705cfSriastradh XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key); 69403b705cfSriastradh#endif 69503b705cfSriastradh if (*ptr == 0) 69603b705cfSriastradh *ptr = FakeClientID(client->index); 69703b705cfSriastradh return *ptr; 69803b705cfSriastradh} 69903b705cfSriastradh 70003b705cfSriastradh/* 70103b705cfSriastradh * Hook this frame event into the server resource 70203b705cfSriastradh * database so we can clean it up if the drawable or 70303b705cfSriastradh * client exits while the swap is pending 70403b705cfSriastradh */ 70503b705cfSriastradhstatic Bool 70603b705cfSriastradhi830_dri2_add_frame_event(DRI2FrameEventPtr info) 70703b705cfSriastradh{ 70803b705cfSriastradh struct i830_dri2_resource *resource; 70903b705cfSriastradh 71003b705cfSriastradh resource = get_resource(get_client_id(info->client), 71103b705cfSriastradh frame_event_client_type); 71203b705cfSriastradh if (resource == NULL) 71303b705cfSriastradh return FALSE; 71403b705cfSriastradh 71503b705cfSriastradh list_add(&info->client_resource, &resource->list); 71603b705cfSriastradh 71703b705cfSriastradh resource = get_resource(info->drawable_id, frame_event_drawable_type); 71803b705cfSriastradh if (resource == NULL) { 71903b705cfSriastradh list_del(&info->client_resource); 72003b705cfSriastradh return FALSE; 72103b705cfSriastradh } 72203b705cfSriastradh 72303b705cfSriastradh list_add(&info->drawable_resource, &resource->list); 72403b705cfSriastradh 72503b705cfSriastradh return TRUE; 72603b705cfSriastradh} 72703b705cfSriastradh 72803b705cfSriastradhstatic void 72942542f5fSchristosi830_dri2_del_frame_event(DRI2FrameEventPtr info) 73003b705cfSriastradh{ 73103b705cfSriastradh list_del(&info->client_resource); 73203b705cfSriastradh list_del(&info->drawable_resource); 73303b705cfSriastradh 73403b705cfSriastradh if (info->front) 73542542f5fSchristos I830DRI2DestroyBuffer(NULL, info->front); 73603b705cfSriastradh if (info->back) 73742542f5fSchristos I830DRI2DestroyBuffer(NULL, info->back); 73803b705cfSriastradh 73903b705cfSriastradh free(info); 74003b705cfSriastradh} 74103b705cfSriastradh 74203b705cfSriastradhstatic struct intel_pixmap * 74303b705cfSriastradhintel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back) 74403b705cfSriastradh{ 74503b705cfSriastradh struct intel_pixmap *new_front, *new_back; 74603b705cfSriastradh RegionRec region; 74703b705cfSriastradh 74803b705cfSriastradh /* Post damage on the front buffer so that listeners, such 74903b705cfSriastradh * as DisplayLink know take a copy and shove it over the USB. 75003b705cfSriastradh * also for sw cursors. 75103b705cfSriastradh */ 75203b705cfSriastradh region.extents.x1 = region.extents.y1 = 0; 75303b705cfSriastradh region.extents.x2 = front->drawable.width; 75403b705cfSriastradh region.extents.y2 = front->drawable.height; 75503b705cfSriastradh region.data = NULL; 75603b705cfSriastradh DamageRegionAppend(&front->drawable, ®ion); 75703b705cfSriastradh 75803b705cfSriastradh new_front = intel_get_pixmap_private(back); 75903b705cfSriastradh new_back = intel_get_pixmap_private(front); 76003b705cfSriastradh intel_set_pixmap_private(front, new_front); 76103b705cfSriastradh intel_set_pixmap_private(back, new_back); 76203b705cfSriastradh new_front->busy = 1; 76303b705cfSriastradh new_back->busy = -1; 76403b705cfSriastradh 76503b705cfSriastradh intel_glamor_exchange_buffers(intel, front, back); 76603b705cfSriastradh 76703b705cfSriastradh DamageRegionProcessPending(&front->drawable); 76803b705cfSriastradh 76903b705cfSriastradh return new_front; 77003b705cfSriastradh} 77103b705cfSriastradh 77203b705cfSriastradhstatic void 77303b705cfSriastradhI830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back) 77403b705cfSriastradh{ 77503b705cfSriastradh I830DRI2BufferPrivatePtr front_priv, back_priv; 77603b705cfSriastradh int tmp; 77703b705cfSriastradh struct intel_pixmap *new_front; 77803b705cfSriastradh 77903b705cfSriastradh front_priv = front->driverPrivate; 78003b705cfSriastradh back_priv = back->driverPrivate; 78103b705cfSriastradh 78203b705cfSriastradh /* Swap BO names so DRI works */ 78303b705cfSriastradh tmp = front->name; 78403b705cfSriastradh front->name = back->name; 78503b705cfSriastradh back->name = tmp; 78603b705cfSriastradh 78703b705cfSriastradh /* Swap pixmap bos */ 78803b705cfSriastradh new_front = intel_exchange_pixmap_buffers(intel, 78903b705cfSriastradh front_priv->pixmap, 79003b705cfSriastradh back_priv->pixmap); 79103b705cfSriastradh dri_bo_unreference (intel->front_buffer); 79203b705cfSriastradh intel->front_buffer = new_front->bo; 79303b705cfSriastradh dri_bo_reference (intel->front_buffer); 79403b705cfSriastradh} 79503b705cfSriastradh 79603b705cfSriastradhstatic PixmapPtr 79703b705cfSriastradhintel_glamor_create_back_pixmap(ScreenPtr screen, 79803b705cfSriastradh PixmapPtr front_pixmap, 79903b705cfSriastradh drm_intel_bo *back_bo) 80003b705cfSriastradh{ 80103b705cfSriastradh PixmapPtr back_pixmap; 80203b705cfSriastradh 80303b705cfSriastradh back_pixmap = screen->CreatePixmap(screen, 80403b705cfSriastradh 0, 80503b705cfSriastradh 0, 80603b705cfSriastradh front_pixmap->drawable.depth, 80703b705cfSriastradh 0); 80803b705cfSriastradh if (back_pixmap == NULL) 80903b705cfSriastradh return NULL; 81003b705cfSriastradh 81103b705cfSriastradh screen->ModifyPixmapHeader(back_pixmap, 81203b705cfSriastradh front_pixmap->drawable.width, 81303b705cfSriastradh front_pixmap->drawable.height, 81403b705cfSriastradh 0, 0, 81503b705cfSriastradh front_pixmap->devKind, 81603b705cfSriastradh 0); 81703b705cfSriastradh intel_set_pixmap_bo(back_pixmap, back_bo); 81803b705cfSriastradh if (!intel_glamor_create_textured_pixmap(back_pixmap)) { 81903b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 82003b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 82103b705cfSriastradh "Failed to create textured back pixmap.\n"); 82203b705cfSriastradh screen->DestroyPixmap(back_pixmap); 82303b705cfSriastradh return NULL; 82403b705cfSriastradh } 82503b705cfSriastradh return back_pixmap; 82603b705cfSriastradh} 82703b705cfSriastradh 82803b705cfSriastradhstatic drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) 82903b705cfSriastradh{ 83003b705cfSriastradh drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap); 83103b705cfSriastradh assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */ 83203b705cfSriastradh return bo; 83303b705cfSriastradh} 83403b705cfSriastradh 83542542f5fSchristosstatic void 83642542f5fSchristosI830DRI2FlipComplete(uint64_t frame, uint64_t usec, void *pageflip_data) 83742542f5fSchristos{ 83842542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 83942542f5fSchristos 84042542f5fSchristos I830DRI2FlipEventHandler((uint32_t) frame, usec / 1000000, 84142542f5fSchristos usec % 1000000, 84242542f5fSchristos info); 84342542f5fSchristos} 84442542f5fSchristos 84542542f5fSchristosstatic void 84642542f5fSchristosI830DRI2FlipAbort(void *pageflip_data) 84742542f5fSchristos{ 84842542f5fSchristos DRI2FrameEventPtr info = pageflip_data; 84942542f5fSchristos 85042542f5fSchristos i830_dri2_del_frame_event(info); 85142542f5fSchristos} 85242542f5fSchristos 85303b705cfSriastradh/* 85403b705cfSriastradh * Our internal swap routine takes care of actually exchanging, blitting, or 85503b705cfSriastradh * flipping buffers as necessary. 85603b705cfSriastradh */ 85703b705cfSriastradhstatic Bool 85803b705cfSriastradhI830DRI2ScheduleFlip(struct intel_screen_private *intel, 85903b705cfSriastradh DrawablePtr draw, 86003b705cfSriastradh DRI2FrameEventPtr info) 86103b705cfSriastradh{ 86203b705cfSriastradh I830DRI2BufferPrivatePtr priv = info->back->driverPrivate; 86303b705cfSriastradh drm_intel_bo *new_back, *old_back; 86403b705cfSriastradh int tmp_name; 86503b705cfSriastradh 86603b705cfSriastradh if (!intel->use_triple_buffer) { 86703b705cfSriastradh info->type = DRI2_SWAP; 86803b705cfSriastradh if (!intel_do_pageflip(intel, 86903b705cfSriastradh get_pixmap_bo(priv), 87042542f5fSchristos info->pipe, FALSE, info, 87142542f5fSchristos I830DRI2FlipComplete, 87242542f5fSchristos I830DRI2FlipAbort)) 87303b705cfSriastradh return FALSE; 87403b705cfSriastradh 87503b705cfSriastradh I830DRI2ExchangeBuffers(intel, info->front, info->back); 87603b705cfSriastradh return TRUE; 87703b705cfSriastradh } 87803b705cfSriastradh 87903b705cfSriastradh if (intel->pending_flip[info->pipe]) { 88003b705cfSriastradh assert(intel->pending_flip[info->pipe]->chain == NULL); 88103b705cfSriastradh intel->pending_flip[info->pipe]->chain = info; 88203b705cfSriastradh return TRUE; 88303b705cfSriastradh } 88403b705cfSriastradh 88503b705cfSriastradh if (intel->back_buffer == NULL) { 88642542f5fSchristos I830DRI2BufferPrivatePtr drvpriv; 88703b705cfSriastradh PixmapPtr front_pixmap, back_pixmap; 88803b705cfSriastradh ScreenPtr screen; 88903b705cfSriastradh 89003b705cfSriastradh new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer", 89103b705cfSriastradh intel->front_buffer->size, 0); 89203b705cfSriastradh if (new_back == NULL) 89303b705cfSriastradh return FALSE; 89403b705cfSriastradh 89503b705cfSriastradh if (intel->front_tiling != I915_TILING_NONE) { 89603b705cfSriastradh uint32_t tiling = intel->front_tiling; 89703b705cfSriastradh drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch); 89803b705cfSriastradh if (tiling != intel->front_tiling) { 89903b705cfSriastradh drm_intel_bo_unreference(new_back); 90003b705cfSriastradh return FALSE; 90103b705cfSriastradh } 90203b705cfSriastradh } 90303b705cfSriastradh 90403b705cfSriastradh drm_intel_bo_disable_reuse(new_back); 90503b705cfSriastradh dri_bo_flink(new_back, &intel->back_name); 90603b705cfSriastradh 90703b705cfSriastradh if ((intel->uxa_flags & UXA_USE_GLAMOR)) { 90803b705cfSriastradh screen = draw->pScreen; 90942542f5fSchristos drvpriv = info->front->driverPrivate; 91042542f5fSchristos front_pixmap = drvpriv->pixmap; 91103b705cfSriastradh 91203b705cfSriastradh back_pixmap = intel_glamor_create_back_pixmap(screen, 91303b705cfSriastradh front_pixmap, 91403b705cfSriastradh new_back); 91503b705cfSriastradh if (back_pixmap == NULL) { 91603b705cfSriastradh drm_intel_bo_unreference(new_back); 91703b705cfSriastradh return FALSE; 91803b705cfSriastradh } 91903b705cfSriastradh intel->back_pixmap = back_pixmap; 92003b705cfSriastradh } 92103b705cfSriastradh } else { 92203b705cfSriastradh new_back = intel->back_buffer; 92303b705cfSriastradh intel->back_buffer = NULL; 92403b705cfSriastradh } 92503b705cfSriastradh 92603b705cfSriastradh old_back = get_pixmap_bo(priv); 92742542f5fSchristos if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) { 92803b705cfSriastradh intel->back_buffer = new_back; 92903b705cfSriastradh return FALSE; 93003b705cfSriastradh } 93103b705cfSriastradh info->type = DRI2_SWAP_CHAIN; 93203b705cfSriastradh intel->pending_flip[info->pipe] = info; 93303b705cfSriastradh 93403b705cfSriastradh priv = info->front->driverPrivate; 93503b705cfSriastradh 93603b705cfSriastradh /* Exchange the current front-buffer with the fresh bo */ 93703b705cfSriastradh 93803b705cfSriastradh intel->back_buffer = intel->front_buffer; 93903b705cfSriastradh drm_intel_bo_reference(intel->back_buffer); 94003b705cfSriastradh if (!(intel->uxa_flags & UXA_USE_GLAMOR)) { 94103b705cfSriastradh intel_set_pixmap_bo(priv->pixmap, new_back); 94203b705cfSriastradh drm_intel_bo_unreference(new_back); 94303b705cfSriastradh } 94403b705cfSriastradh else 94503b705cfSriastradh intel_exchange_pixmap_buffers(intel, priv->pixmap, 94603b705cfSriastradh intel->back_pixmap); 94703b705cfSriastradh 94803b705cfSriastradh tmp_name = info->front->name; 94903b705cfSriastradh info->front->name = intel->back_name; 95003b705cfSriastradh intel->back_name = tmp_name; 95103b705cfSriastradh 95203b705cfSriastradh /* Then flip DRI2 pointers and update the screen pixmap */ 95303b705cfSriastradh I830DRI2ExchangeBuffers(intel, info->front, info->back); 95403b705cfSriastradh DRI2SwapComplete(info->client, draw, 0, 0, 0, 95503b705cfSriastradh DRI2_EXCHANGE_COMPLETE, 95603b705cfSriastradh info->event_complete, 95703b705cfSriastradh info->event_data); 95803b705cfSriastradh return TRUE; 95903b705cfSriastradh} 96003b705cfSriastradh 96103b705cfSriastradhstatic Bool 96203b705cfSriastradhcan_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) 96303b705cfSriastradh{ 96403b705cfSriastradh ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen); 96503b705cfSriastradh struct intel_screen_private *intel = intel_get_screen_private(pScrn); 96603b705cfSriastradh I830DRI2BufferPrivatePtr front_priv = front->driverPrivate; 96703b705cfSriastradh I830DRI2BufferPrivatePtr back_priv = back->driverPrivate; 96803b705cfSriastradh PixmapPtr front_pixmap = front_priv->pixmap; 96903b705cfSriastradh PixmapPtr back_pixmap = back_priv->pixmap; 97003b705cfSriastradh struct intel_pixmap *front_intel = intel_get_pixmap_private(front_pixmap); 97103b705cfSriastradh struct intel_pixmap *back_intel = intel_get_pixmap_private(back_pixmap); 97203b705cfSriastradh 97303b705cfSriastradh if (!pScrn->vtSema) 97403b705cfSriastradh return FALSE; 97503b705cfSriastradh 97642542f5fSchristos if (I830DRI2DrawableCrtc(drawable) == NULL) 97703b705cfSriastradh return FALSE; 97803b705cfSriastradh 97903b705cfSriastradh if (!DRI2CanFlip(drawable)) 98003b705cfSriastradh return FALSE; 98103b705cfSriastradh 98203b705cfSriastradh if (intel->shadow_present) 98303b705cfSriastradh return FALSE; 98403b705cfSriastradh 98503b705cfSriastradh if (!intel->use_pageflipping) 98603b705cfSriastradh return FALSE; 98703b705cfSriastradh 98803b705cfSriastradh if (front_pixmap->drawable.width != back_pixmap->drawable.width) 98903b705cfSriastradh return FALSE; 99003b705cfSriastradh 99103b705cfSriastradh if (front_pixmap->drawable.height != back_pixmap->drawable.height) 99203b705cfSriastradh return FALSE; 99303b705cfSriastradh 99403b705cfSriastradh /* XXX should we be checking depth instead of bpp? */ 99503b705cfSriastradh#if 0 99603b705cfSriastradh if (front_pixmap->drawable.depth != back_pixmap->drawable.depth) 99703b705cfSriastradh return FALSE; 99803b705cfSriastradh#else 99903b705cfSriastradh if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 100003b705cfSriastradh return FALSE; 100103b705cfSriastradh#endif 100203b705cfSriastradh 100303b705cfSriastradh /* prevent an implicit tiling mode change */ 100403b705cfSriastradh if (front_intel->tiling != back_intel->tiling) 100503b705cfSriastradh return FALSE; 100603b705cfSriastradh 100742542f5fSchristos if (front_intel->pinned & ~(PIN_SCANOUT | PIN_DRI2)) 100842542f5fSchristos return FALSE; 100942542f5fSchristos 101003b705cfSriastradh return TRUE; 101103b705cfSriastradh} 101203b705cfSriastradh 101303b705cfSriastradhvoid I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec, 101403b705cfSriastradh unsigned int tv_usec, DRI2FrameEventPtr swap_info) 101503b705cfSriastradh{ 101603b705cfSriastradh intel_screen_private *intel = swap_info->intel; 101703b705cfSriastradh DrawablePtr drawable; 101803b705cfSriastradh int status; 101903b705cfSriastradh 102003b705cfSriastradh if (!swap_info->drawable_id) 102103b705cfSriastradh status = BadDrawable; 102203b705cfSriastradh else 102303b705cfSriastradh status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient, 102403b705cfSriastradh M_ANY, DixWriteAccess); 102503b705cfSriastradh if (status != Success) { 102642542f5fSchristos i830_dri2_del_frame_event(swap_info); 102703b705cfSriastradh return; 102803b705cfSriastradh } 102903b705cfSriastradh 103003b705cfSriastradh 103103b705cfSriastradh switch (swap_info->type) { 103203b705cfSriastradh case DRI2_FLIP: 103303b705cfSriastradh /* If we can still flip... */ 103403b705cfSriastradh if (can_exchange(drawable, swap_info->front, swap_info->back) && 103503b705cfSriastradh I830DRI2ScheduleFlip(intel, drawable, swap_info)) 103603b705cfSriastradh return; 103703b705cfSriastradh 103803b705cfSriastradh /* else fall through to exchange/blit */ 103903b705cfSriastradh case DRI2_SWAP: { 104003b705cfSriastradh I830DRI2FallbackBlitSwap(drawable, 104103b705cfSriastradh swap_info->front, swap_info->back); 104203b705cfSriastradh DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec, 104303b705cfSriastradh DRI2_BLIT_COMPLETE, 104403b705cfSriastradh swap_info->client ? swap_info->event_complete : NULL, 104503b705cfSriastradh swap_info->event_data); 104603b705cfSriastradh break; 104703b705cfSriastradh } 104803b705cfSriastradh case DRI2_WAITMSC: 104903b705cfSriastradh if (swap_info->client) 105003b705cfSriastradh DRI2WaitMSCComplete(swap_info->client, drawable, 105103b705cfSriastradh frame, tv_sec, tv_usec); 105203b705cfSriastradh break; 105303b705cfSriastradh default: 105403b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 105503b705cfSriastradh "%s: unknown vblank event received\n", __func__); 105603b705cfSriastradh /* Unknown type */ 105703b705cfSriastradh break; 105803b705cfSriastradh } 105903b705cfSriastradh 106042542f5fSchristos i830_dri2_del_frame_event(swap_info); 106103b705cfSriastradh} 106203b705cfSriastradh 106303b705cfSriastradhvoid I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, 106403b705cfSriastradh unsigned int tv_usec, DRI2FrameEventPtr flip_info) 106503b705cfSriastradh{ 106603b705cfSriastradh struct intel_screen_private *intel = flip_info->intel; 106703b705cfSriastradh DrawablePtr drawable; 106803b705cfSriastradh DRI2FrameEventPtr chain; 106903b705cfSriastradh 107003b705cfSriastradh drawable = NULL; 107103b705cfSriastradh if (flip_info->drawable_id) 107203b705cfSriastradh dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, 107303b705cfSriastradh M_ANY, DixWriteAccess); 107403b705cfSriastradh 107503b705cfSriastradh 107603b705cfSriastradh /* We assume our flips arrive in order, so we don't check the frame */ 107703b705cfSriastradh switch (flip_info->type) { 107803b705cfSriastradh case DRI2_SWAP: 107903b705cfSriastradh if (!drawable) 108003b705cfSriastradh break; 108103b705cfSriastradh 108203b705cfSriastradh /* Check for too small vblank count of pageflip completion, taking wraparound 108303b705cfSriastradh * into account. This usually means some defective kms pageflip completion, 108403b705cfSriastradh * causing wrong (msc, ust) return values and possible visual corruption. 108503b705cfSriastradh */ 108603b705cfSriastradh if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) { 108703b705cfSriastradh static int limit = 5; 108803b705cfSriastradh 108903b705cfSriastradh /* XXX we are currently hitting this path with older 109003b705cfSriastradh * kernels, so make it quieter. 109103b705cfSriastradh */ 109203b705cfSriastradh if (limit) { 109303b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 109403b705cfSriastradh "%s: Pageflip completion has impossible msc %d < target_msc %d\n", 109503b705cfSriastradh __func__, frame, flip_info->frame); 109603b705cfSriastradh limit--; 109703b705cfSriastradh } 109803b705cfSriastradh 109903b705cfSriastradh /* All-0 values signal timestamping failure. */ 110003b705cfSriastradh frame = tv_sec = tv_usec = 0; 110103b705cfSriastradh } 110203b705cfSriastradh 110303b705cfSriastradh DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, 110403b705cfSriastradh DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, 110503b705cfSriastradh flip_info->event_data); 110603b705cfSriastradh break; 110703b705cfSriastradh 110803b705cfSriastradh case DRI2_SWAP_CHAIN: 110903b705cfSriastradh assert(intel->pending_flip[flip_info->pipe] == flip_info); 111003b705cfSriastradh intel->pending_flip[flip_info->pipe] = NULL; 111103b705cfSriastradh 111203b705cfSriastradh chain = flip_info->chain; 111303b705cfSriastradh if (chain) { 111403b705cfSriastradh DrawablePtr chain_drawable = NULL; 111503b705cfSriastradh if (chain->drawable_id) 111603b705cfSriastradh dixLookupDrawable(&chain_drawable, 111703b705cfSriastradh chain->drawable_id, 111803b705cfSriastradh serverClient, 111903b705cfSriastradh M_ANY, DixWriteAccess); 112003b705cfSriastradh if (chain_drawable == NULL) { 112142542f5fSchristos i830_dri2_del_frame_event(chain); 112203b705cfSriastradh } else if (!can_exchange(chain_drawable, chain->front, chain->back) || 112303b705cfSriastradh !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) { 112403b705cfSriastradh I830DRI2FallbackBlitSwap(chain_drawable, 112503b705cfSriastradh chain->front, 112603b705cfSriastradh chain->back); 112703b705cfSriastradh 112803b705cfSriastradh DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec, 112903b705cfSriastradh DRI2_BLIT_COMPLETE, 113003b705cfSriastradh chain->client ? chain->event_complete : NULL, 113103b705cfSriastradh chain->event_data); 113242542f5fSchristos i830_dri2_del_frame_event(chain); 113303b705cfSriastradh } 113403b705cfSriastradh } 113503b705cfSriastradh break; 113603b705cfSriastradh 113703b705cfSriastradh default: 113803b705cfSriastradh xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 113903b705cfSriastradh "%s: unknown vblank event received\n", __func__); 114003b705cfSriastradh /* Unknown type */ 114103b705cfSriastradh break; 114203b705cfSriastradh } 114303b705cfSriastradh 114442542f5fSchristos i830_dri2_del_frame_event(flip_info); 114503b705cfSriastradh} 114603b705cfSriastradh 114703b705cfSriastradhstatic uint32_t pipe_select(int pipe) 114803b705cfSriastradh{ 114903b705cfSriastradh if (pipe > 1) 115003b705cfSriastradh return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 115103b705cfSriastradh else if (pipe > 0) 115203b705cfSriastradh return DRM_VBLANK_SECONDARY; 115303b705cfSriastradh else 115403b705cfSriastradh return 0; 115503b705cfSriastradh} 115603b705cfSriastradh 115742542f5fSchristosstatic void 115842542f5fSchristosintel_dri2_vblank_handler(ScrnInfoPtr scrn, 115942542f5fSchristos xf86CrtcPtr crtc, 116042542f5fSchristos uint64_t msc, 116142542f5fSchristos uint64_t usec, 116242542f5fSchristos void *data) 116342542f5fSchristos{ 116442542f5fSchristos DRI2FrameEventPtr swap_info = data; 116542542f5fSchristos 116642542f5fSchristos I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info); 116742542f5fSchristos} 116842542f5fSchristos 116942542f5fSchristosstatic void 117042542f5fSchristosintel_dri2_vblank_abort(ScrnInfoPtr scrn, 117142542f5fSchristos xf86CrtcPtr crtc, 117242542f5fSchristos void *data) 117342542f5fSchristos{ 117442542f5fSchristos DRI2FrameEventPtr swap_info = data; 117542542f5fSchristos 117642542f5fSchristos i830_dri2_del_frame_event(swap_info); 117742542f5fSchristos} 117842542f5fSchristos 117903b705cfSriastradh/* 118003b705cfSriastradh * ScheduleSwap is responsible for requesting a DRM vblank event for the 118103b705cfSriastradh * appropriate frame. 118203b705cfSriastradh * 118303b705cfSriastradh * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 118403b705cfSriastradh * the vblank requested can simply be the last queued swap frame + the swap 118503b705cfSriastradh * interval for the drawable. 118603b705cfSriastradh * 118703b705cfSriastradh * In the case of a page flip, we request an event for the last queued swap 118803b705cfSriastradh * frame + swap interval - 1, since we'll need to queue the flip for the frame 118903b705cfSriastradh * immediately following the received event. 119003b705cfSriastradh * 119103b705cfSriastradh * The client will be blocked if it tries to perform further GL commands 119203b705cfSriastradh * after queueing a swap, though in the Intel case after queueing a flip, the 119303b705cfSriastradh * client is free to queue more commands; they'll block in the kernel if 119403b705cfSriastradh * they access buffers busy with the flip. 119503b705cfSriastradh * 119603b705cfSriastradh * When the swap is complete, the driver should call into the server so it 119703b705cfSriastradh * can send any swap complete events that have been requested. 119803b705cfSriastradh */ 119903b705cfSriastradhstatic int 120003b705cfSriastradhI830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 120103b705cfSriastradh DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 120203b705cfSriastradh CARD64 remainder, DRI2SwapEventPtr func, void *data) 120303b705cfSriastradh{ 120403b705cfSriastradh ScreenPtr screen = draw->pScreen; 120503b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 120603b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 120703b705cfSriastradh drmVBlank vbl; 120842542f5fSchristos int ret; 120942542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 121042542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 121142542f5fSchristos int flip = 0; 121203b705cfSriastradh DRI2FrameEventPtr swap_info = NULL; 121303b705cfSriastradh enum DRI2FrameEventType swap_type = DRI2_SWAP; 121442542f5fSchristos uint64_t current_msc, current_ust; 121542542f5fSchristos uint64_t request_msc; 121642542f5fSchristos uint32_t seq; 121703b705cfSriastradh 121803b705cfSriastradh /* Drawable not displayed... just complete the swap */ 121903b705cfSriastradh if (pipe == -1) 122003b705cfSriastradh goto blit_fallback; 122103b705cfSriastradh 122203b705cfSriastradh swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 122303b705cfSriastradh if (!swap_info) 122403b705cfSriastradh goto blit_fallback; 122503b705cfSriastradh 122603b705cfSriastradh swap_info->intel = intel; 122703b705cfSriastradh swap_info->drawable_id = draw->id; 122803b705cfSriastradh swap_info->client = client; 122903b705cfSriastradh swap_info->event_complete = func; 123003b705cfSriastradh swap_info->event_data = data; 123103b705cfSriastradh swap_info->front = front; 123203b705cfSriastradh swap_info->back = back; 123303b705cfSriastradh swap_info->pipe = pipe; 123403b705cfSriastradh 123503b705cfSriastradh if (!i830_dri2_add_frame_event(swap_info)) { 123603b705cfSriastradh free(swap_info); 123703b705cfSriastradh swap_info = NULL; 123803b705cfSriastradh goto blit_fallback; 123903b705cfSriastradh } 124003b705cfSriastradh 124103b705cfSriastradh I830DRI2ReferenceBuffer(front); 124203b705cfSriastradh I830DRI2ReferenceBuffer(back); 124303b705cfSriastradh 124442542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 124542542f5fSchristos if (ret) 124642542f5fSchristos goto blit_fallback; 124703b705cfSriastradh 124803b705cfSriastradh /* Flips need to be submitted one frame before */ 124903b705cfSriastradh if (can_exchange(draw, front, back)) { 125003b705cfSriastradh swap_type = DRI2_FLIP; 125103b705cfSriastradh flip = 1; 125203b705cfSriastradh } 125303b705cfSriastradh 125403b705cfSriastradh swap_info->type = swap_type; 125503b705cfSriastradh 125603b705cfSriastradh /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 125703b705cfSriastradh * Do it early, so handling of different timing constraints 125803b705cfSriastradh * for divisor, remainder and msc vs. target_msc works. 125903b705cfSriastradh */ 126003b705cfSriastradh if (*target_msc > 0) 126103b705cfSriastradh *target_msc -= flip; 126203b705cfSriastradh 126303b705cfSriastradh /* 126403b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc 126503b705cfSriastradh * we just need to make sure target_msc passes before initiating 126603b705cfSriastradh * the swap. 126703b705cfSriastradh */ 126803b705cfSriastradh if (divisor == 0 || current_msc < *target_msc) { 126903b705cfSriastradh /* 127003b705cfSriastradh * If we can, schedule the flip directly from here rather 127103b705cfSriastradh * than waiting for an event from the kernel for the current 127203b705cfSriastradh * (or a past) MSC. 127303b705cfSriastradh */ 127403b705cfSriastradh if (flip && divisor == 0 && current_msc >= *target_msc && 127503b705cfSriastradh I830DRI2ScheduleFlip(intel, draw, swap_info)) 127603b705cfSriastradh return TRUE; 127703b705cfSriastradh 127803b705cfSriastradh vbl.request.type = 127903b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 128003b705cfSriastradh 128103b705cfSriastradh /* If non-pageflipping, but blitting/exchanging, we need to use 128203b705cfSriastradh * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 128303b705cfSriastradh * on. 128403b705cfSriastradh */ 128503b705cfSriastradh if (flip == 0) 128603b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 128703b705cfSriastradh 128803b705cfSriastradh /* If target_msc already reached or passed, set it to 128903b705cfSriastradh * current_msc to ensure we return a reasonable value back 129003b705cfSriastradh * to the caller. This makes swap_interval logic more robust. 129103b705cfSriastradh */ 129203b705cfSriastradh if (current_msc >= *target_msc) 129303b705cfSriastradh *target_msc = current_msc; 129403b705cfSriastradh 129542542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 129642542f5fSchristos if (!seq) 129742542f5fSchristos goto blit_fallback; 129842542f5fSchristos 129942542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, *target_msc); 130042542f5fSchristos vbl.request.signal = seq; 130142542f5fSchristos 130203b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 130303b705cfSriastradh if (ret) { 130403b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 130503b705cfSriastradh "divisor 0 get vblank counter failed: %s\n", 130603b705cfSriastradh strerror(errno)); 130703b705cfSriastradh goto blit_fallback; 130803b705cfSriastradh } 130903b705cfSriastradh 131042542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 131103b705cfSriastradh swap_info->frame = *target_msc; 131203b705cfSriastradh 131303b705cfSriastradh return TRUE; 131403b705cfSriastradh } 131503b705cfSriastradh 131603b705cfSriastradh /* 131703b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 131803b705cfSriastradh * and we need to queue an event that will satisfy the divisor/remainder 131903b705cfSriastradh * equation. 132003b705cfSriastradh */ 132103b705cfSriastradh vbl.request.type = 132203b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 132303b705cfSriastradh if (flip == 0) 132403b705cfSriastradh vbl.request.type |= DRM_VBLANK_NEXTONMISS; 132503b705cfSriastradh 132642542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 132742542f5fSchristos remainder; 132803b705cfSriastradh 132903b705cfSriastradh /* 133003b705cfSriastradh * If the calculated deadline vbl.request.sequence is smaller than 133103b705cfSriastradh * or equal to current_msc, it means we've passed the last point 133203b705cfSriastradh * when effective onset frame seq could satisfy 133303b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 133403b705cfSriastradh * this will happen. 133503b705cfSriastradh 133603b705cfSriastradh * This comparison takes the 1 frame swap delay in pageflipping mode 133703b705cfSriastradh * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 133803b705cfSriastradh * if we are blitting/exchanging instead of flipping. 133903b705cfSriastradh */ 134042542f5fSchristos if (request_msc <= current_msc) 134142542f5fSchristos request_msc += divisor; 134242542f5fSchristos 134342542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 134442542f5fSchristos if (!seq) 134542542f5fSchristos goto blit_fallback; 134603b705cfSriastradh 134703b705cfSriastradh /* Account for 1 frame extra pageflip delay if flip > 0 */ 134842542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc) - flip; 134942542f5fSchristos vbl.request.signal = seq; 135003b705cfSriastradh 135103b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 135203b705cfSriastradh if (ret) { 135303b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 135403b705cfSriastradh "final get vblank counter failed: %s\n", 135503b705cfSriastradh strerror(errno)); 135603b705cfSriastradh goto blit_fallback; 135703b705cfSriastradh } 135803b705cfSriastradh 135903b705cfSriastradh /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 136042542f5fSchristos *target_msc = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence + flip); 136103b705cfSriastradh swap_info->frame = *target_msc; 136203b705cfSriastradh 136303b705cfSriastradh return TRUE; 136403b705cfSriastradh 136503b705cfSriastradhblit_fallback: 136603b705cfSriastradh I830DRI2FallbackBlitSwap(draw, front, back); 136703b705cfSriastradh DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 136803b705cfSriastradh if (swap_info) 136942542f5fSchristos i830_dri2_del_frame_event(swap_info); 137003b705cfSriastradh *target_msc = 0; /* offscreen, so zero out target vblank count */ 137103b705cfSriastradh return TRUE; 137203b705cfSriastradh} 137303b705cfSriastradh 137403b705cfSriastradhstatic uint64_t gettime_us(void) 137503b705cfSriastradh{ 137603b705cfSriastradh struct timespec tv; 137703b705cfSriastradh 137803b705cfSriastradh if (clock_gettime(CLOCK_MONOTONIC, &tv)) 137903b705cfSriastradh return 0; 138003b705cfSriastradh 138103b705cfSriastradh return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; 138203b705cfSriastradh} 138303b705cfSriastradh 138403b705cfSriastradh/* 138503b705cfSriastradh * Get current frame count and frame count timestamp, based on drawable's 138603b705cfSriastradh * crtc. 138703b705cfSriastradh */ 138803b705cfSriastradhstatic int 138903b705cfSriastradhI830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 139003b705cfSriastradh{ 139103b705cfSriastradh ScreenPtr screen = draw->pScreen; 139203b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 139342542f5fSchristos int ret; 139442542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 139503b705cfSriastradh 139603b705cfSriastradh /* Drawable not displayed, make up a *monotonic* value */ 139742542f5fSchristos if (crtc == NULL) { 139842542f5fSchristosfail: 139903b705cfSriastradh *ust = gettime_us(); 140003b705cfSriastradh *msc = 0; 140103b705cfSriastradh return TRUE; 140203b705cfSriastradh } 140303b705cfSriastradh 140442542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, msc, ust); 140503b705cfSriastradh if (ret) { 140603b705cfSriastradh static int limit = 5; 140703b705cfSriastradh if (limit) { 140803b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 140903b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 141003b705cfSriastradh __FUNCTION__, __LINE__, 141103b705cfSriastradh strerror(errno)); 141203b705cfSriastradh limit--; 141303b705cfSriastradh } 141442542f5fSchristos goto fail; 141503b705cfSriastradh } 141603b705cfSriastradh 141703b705cfSriastradh return TRUE; 141803b705cfSriastradh} 141903b705cfSriastradh 142003b705cfSriastradh/* 142103b705cfSriastradh * Request a DRM event when the requested conditions will be satisfied. 142203b705cfSriastradh * 142303b705cfSriastradh * We need to handle the event and ask the server to wake up the client when 142403b705cfSriastradh * we receive it. 142503b705cfSriastradh */ 142603b705cfSriastradhstatic int 142703b705cfSriastradhI830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 142803b705cfSriastradh CARD64 divisor, CARD64 remainder) 142903b705cfSriastradh{ 143003b705cfSriastradh ScreenPtr screen = draw->pScreen; 143103b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 143203b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 143303b705cfSriastradh DRI2FrameEventPtr wait_info; 143403b705cfSriastradh drmVBlank vbl; 143542542f5fSchristos int ret; 143642542f5fSchristos xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw); 143742542f5fSchristos int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1; 143842542f5fSchristos CARD64 current_msc, current_ust, request_msc; 143942542f5fSchristos uint32_t seq; 144003b705cfSriastradh 144103b705cfSriastradh /* Drawable not visible, return immediately */ 144203b705cfSriastradh if (pipe == -1) 144303b705cfSriastradh goto out_complete; 144403b705cfSriastradh 144503b705cfSriastradh wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 144603b705cfSriastradh if (!wait_info) 144703b705cfSriastradh goto out_complete; 144803b705cfSriastradh 144903b705cfSriastradh wait_info->intel = intel; 145003b705cfSriastradh wait_info->drawable_id = draw->id; 145103b705cfSriastradh wait_info->client = client; 145203b705cfSriastradh wait_info->type = DRI2_WAITMSC; 145303b705cfSriastradh 145403b705cfSriastradh if (!i830_dri2_add_frame_event(wait_info)) { 145503b705cfSriastradh free(wait_info); 145603b705cfSriastradh wait_info = NULL; 145703b705cfSriastradh goto out_complete; 145803b705cfSriastradh } 145903b705cfSriastradh 146003b705cfSriastradh /* Get current count */ 146142542f5fSchristos ret = intel_get_crtc_msc_ust(scrn, crtc, ¤t_msc, ¤t_ust); 146242542f5fSchristos if (ret) 146342542f5fSchristos goto out_free; 146403b705cfSriastradh 146503b705cfSriastradh /* 146603b705cfSriastradh * If divisor is zero, or current_msc is smaller than target_msc, 146703b705cfSriastradh * we just need to make sure target_msc passes before waking up the 146803b705cfSriastradh * client. 146903b705cfSriastradh */ 147003b705cfSriastradh if (divisor == 0 || current_msc < target_msc) { 147103b705cfSriastradh /* If target_msc already reached or passed, set it to 147203b705cfSriastradh * current_msc to ensure we return a reasonable value back 147303b705cfSriastradh * to the caller. This keeps the client from continually 147403b705cfSriastradh * sending us MSC targets from the past by forcibly updating 147503b705cfSriastradh * their count on this call. 147603b705cfSriastradh */ 147742542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 147842542f5fSchristos if (!seq) 147942542f5fSchristos goto out_free; 148042542f5fSchristos 148103b705cfSriastradh if (current_msc >= target_msc) 148203b705cfSriastradh target_msc = current_msc; 148303b705cfSriastradh vbl.request.type = 148403b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 148542542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, target_msc); 148642542f5fSchristos vbl.request.signal = seq; 148742542f5fSchristos 148803b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 148903b705cfSriastradh if (ret) { 149003b705cfSriastradh static int limit = 5; 149103b705cfSriastradh if (limit) { 149203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 149303b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 149403b705cfSriastradh __FUNCTION__, __LINE__, 149503b705cfSriastradh strerror(errno)); 149603b705cfSriastradh limit--; 149703b705cfSriastradh } 149803b705cfSriastradh goto out_free; 149903b705cfSriastradh } 150003b705cfSriastradh 150142542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 150203b705cfSriastradh DRI2BlockClient(client, draw); 150303b705cfSriastradh return TRUE; 150403b705cfSriastradh } 150503b705cfSriastradh 150603b705cfSriastradh /* 150703b705cfSriastradh * If we get here, target_msc has already passed or we don't have one, 150803b705cfSriastradh * so we queue an event that will satisfy the divisor/remainder equation. 150903b705cfSriastradh */ 151003b705cfSriastradh vbl.request.type = 151103b705cfSriastradh DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 151203b705cfSriastradh 151342542f5fSchristos request_msc = current_msc - (current_msc % divisor) + 151442542f5fSchristos remainder; 151503b705cfSriastradh /* 151603b705cfSriastradh * If calculated remainder is larger than requested remainder, 151703b705cfSriastradh * it means we've passed the last point where 151803b705cfSriastradh * seq % divisor == remainder, so we need to wait for the next time 151903b705cfSriastradh * that will happen. 152003b705cfSriastradh */ 152103b705cfSriastradh if ((current_msc % divisor) >= remainder) 152242542f5fSchristos request_msc += divisor; 152342542f5fSchristos 152442542f5fSchristos seq = intel_drm_queue_alloc(scrn, crtc, wait_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort); 152542542f5fSchristos if (!seq) 152642542f5fSchristos goto out_free; 152742542f5fSchristos 152842542f5fSchristos vbl.request.sequence = intel_crtc_msc_to_sequence(scrn, crtc, request_msc); 152942542f5fSchristos vbl.request.signal = seq; 153003b705cfSriastradh 153103b705cfSriastradh ret = drmWaitVBlank(intel->drmSubFD, &vbl); 153203b705cfSriastradh if (ret) { 153303b705cfSriastradh static int limit = 5; 153403b705cfSriastradh if (limit) { 153503b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 153603b705cfSriastradh "%s:%d get vblank counter failed: %s\n", 153703b705cfSriastradh __FUNCTION__, __LINE__, 153803b705cfSriastradh strerror(errno)); 153903b705cfSriastradh limit--; 154003b705cfSriastradh } 154103b705cfSriastradh goto out_free; 154203b705cfSriastradh } 154303b705cfSriastradh 154442542f5fSchristos wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence); 154503b705cfSriastradh DRI2BlockClient(client, draw); 154603b705cfSriastradh 154703b705cfSriastradh return TRUE; 154803b705cfSriastradh 154903b705cfSriastradhout_free: 155042542f5fSchristos i830_dri2_del_frame_event(wait_info); 155103b705cfSriastradhout_complete: 155203b705cfSriastradh DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 155303b705cfSriastradh return TRUE; 155403b705cfSriastradh} 155503b705cfSriastradh 155603b705cfSriastradhstatic int dri2_server_generation; 155703b705cfSriastradh#endif 155803b705cfSriastradh 155903b705cfSriastradhstatic int has_i830_dri(void) 156003b705cfSriastradh{ 156103b705cfSriastradh return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 156203b705cfSriastradh} 156303b705cfSriastradh 156403b705cfSriastradhstatic const char *dri_driver_name(intel_screen_private *intel) 156503b705cfSriastradh{ 156642542f5fSchristos#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 156703b705cfSriastradh const char *s = xf86GetOptValString(intel->Options, OPTION_DRI); 156803b705cfSriastradh Bool dummy; 156903b705cfSriastradh 157003b705cfSriastradh if (s == NULL || xf86getBoolValue(&dummy, s)) { 157103b705cfSriastradh if (INTEL_INFO(intel)->gen < 030) 157203b705cfSriastradh return has_i830_dri() ? "i830" : "i915"; 157303b705cfSriastradh else if (INTEL_INFO(intel)->gen < 040) 157403b705cfSriastradh return "i915"; 157503b705cfSriastradh else 157603b705cfSriastradh return "i965"; 157703b705cfSriastradh } 157803b705cfSriastradh 157903b705cfSriastradh return s; 158042542f5fSchristos#else 158142542f5fSchristos if (INTEL_INFO(intel)->gen < 030) 158242542f5fSchristos return has_i830_dri() ? "i830" : "i915"; 158342542f5fSchristos else if (INTEL_INFO(intel)->gen < 040) 158442542f5fSchristos return "i915"; 158542542f5fSchristos else 158642542f5fSchristos return "i965"; 158742542f5fSchristos#endif 158803b705cfSriastradh} 158903b705cfSriastradh 159003b705cfSriastradhBool I830DRI2ScreenInit(ScreenPtr screen) 159103b705cfSriastradh{ 159203b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 159303b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 159403b705cfSriastradh DRI2InfoRec info; 159542542f5fSchristos int dri2scr_major = 1; 159642542f5fSchristos int dri2scr_minor = 0; 159703b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 159842542f5fSchristos const char *driverNames[2]; 159903b705cfSriastradh#endif 160003b705cfSriastradh 160103b705cfSriastradh if (intel->force_fallback) { 160203b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 160303b705cfSriastradh "cannot enable DRI2 whilst forcing software fallbacks\n"); 160403b705cfSriastradh return FALSE; 160503b705cfSriastradh } 160603b705cfSriastradh 160703b705cfSriastradh if (xf86LoaderCheckSymbol("DRI2Version")) 160842542f5fSchristos DRI2Version(&dri2scr_major, &dri2scr_minor); 160903b705cfSriastradh 161042542f5fSchristos if (dri2scr_minor < 1) { 161103b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 161203b705cfSriastradh "DRI2 requires DRI2 module version 1.1.0 or later\n"); 161303b705cfSriastradh return FALSE; 161403b705cfSriastradh } 161503b705cfSriastradh 161603b705cfSriastradh#if HAS_DIXREGISTERPRIVATEKEY 161703b705cfSriastradh if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID))) 161803b705cfSriastradh return FALSE; 161903b705cfSriastradh#else 162003b705cfSriastradh if (!dixRequestPrivate(&i830_client_key, sizeof(XID))) 162103b705cfSriastradh return FALSE; 162203b705cfSriastradh#endif 162303b705cfSriastradh 162403b705cfSriastradh 162503b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 162603b705cfSriastradh if (serverGeneration != dri2_server_generation) { 162703b705cfSriastradh dri2_server_generation = serverGeneration; 162803b705cfSriastradh if (!i830_dri2_register_frame_event_resource_types()) { 162903b705cfSriastradh xf86DrvMsg(scrn->scrnIndex, X_WARNING, 163003b705cfSriastradh "Cannot register DRI2 frame event resources\n"); 163103b705cfSriastradh return FALSE; 163203b705cfSriastradh } 163303b705cfSriastradh } 163403b705cfSriastradh#endif 163503b705cfSriastradh 163603b705cfSriastradh intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD); 163703b705cfSriastradh memset(&info, '\0', sizeof(info)); 163803b705cfSriastradh info.fd = intel->drmSubFD; 163903b705cfSriastradh info.driverName = dri_driver_name(intel); 164003b705cfSriastradh info.deviceName = intel->deviceName; 164103b705cfSriastradh 164203b705cfSriastradh#if DRI2INFOREC_VERSION == 1 164303b705cfSriastradh info.version = 1; 164403b705cfSriastradh info.CreateBuffers = I830DRI2CreateBuffers; 164503b705cfSriastradh info.DestroyBuffers = I830DRI2DestroyBuffers; 164603b705cfSriastradh#elif DRI2INFOREC_VERSION == 2 164703b705cfSriastradh /* The ABI between 2 and 3 was broken so we could get rid of 164803b705cfSriastradh * the multi-buffer alloc functions. Make sure we indicate the 164903b705cfSriastradh * right version so DRI2 can reject us if it's version 3 or above. */ 165003b705cfSriastradh info.version = 2; 165103b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 165203b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 165303b705cfSriastradh#else 165403b705cfSriastradh info.version = 3; 165503b705cfSriastradh info.CreateBuffer = I830DRI2CreateBuffer; 165603b705cfSriastradh info.DestroyBuffer = I830DRI2DestroyBuffer; 165703b705cfSriastradh#endif 165803b705cfSriastradh 165903b705cfSriastradh info.CopyRegion = I830DRI2CopyRegion; 166003b705cfSriastradh#if DRI2INFOREC_VERSION >= 4 166103b705cfSriastradh info.version = 4; 166203b705cfSriastradh info.ScheduleSwap = I830DRI2ScheduleSwap; 166303b705cfSriastradh info.GetMSC = I830DRI2GetMSC; 166403b705cfSriastradh info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC; 166542542f5fSchristos info.numDrivers = 2; 166603b705cfSriastradh info.driverNames = driverNames; 166703b705cfSriastradh driverNames[0] = info.driverName; 166842542f5fSchristos driverNames[1] = info.driverName; 166903b705cfSriastradh#endif 167003b705cfSriastradh 167103b705cfSriastradh return DRI2ScreenInit(screen, &info); 167203b705cfSriastradh} 167303b705cfSriastradh 167403b705cfSriastradhvoid I830DRI2CloseScreen(ScreenPtr screen) 167503b705cfSriastradh{ 167603b705cfSriastradh ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 167703b705cfSriastradh intel_screen_private *intel = intel_get_screen_private(scrn); 167803b705cfSriastradh 167903b705cfSriastradh DRI2CloseScreen(screen); 168003b705cfSriastradh drmFree(intel->deviceName); 168103b705cfSriastradh} 1682