diff options
Diffstat (limited to 'src/mali_dri.c')
-rw-r--r-- | src/mali_dri.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/mali_dri.c b/src/mali_dri.c new file mode 100644 index 0000000..937fee5 --- /dev/null +++ b/src/mali_dri.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2010 ARM Limited. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include "mali_dri.h" + +#define IGNORE( a ) ( a = a ) + +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) + + +extern XF86ModuleData dri2ModuleData; + +typedef struct +{ + PixmapPtr pPixmap; + unsigned int attachment; + Bool isPageFlipped; +} MaliDRI2BufferPrivateRec, *MaliDRI2BufferPrivatePtr; + +static DRI2Buffer2Ptr MaliDRI2CreateBuffer( DrawablePtr pDraw, unsigned int attachment, unsigned int format ) +{ + ScreenPtr pScreen = pDraw->pScreen; + DRI2Buffer2Ptr buffer; + MaliDRI2BufferPrivatePtr privates; + PixmapPtr pPixmap; + PrivPixmap *privPixmap; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MaliPtr fPtr = MALIPTR(pScrn); + + buffer = calloc(1, sizeof *buffer); + if ( NULL == buffer ) return NULL; + + privates = calloc(1, sizeof *privates); + if ( NULL == privates ) + { + free( buffer ); + return NULL; + } + + /* initialize privates info to default values */ + privates->pPixmap = NULL; + privates->attachment = attachment; + privates->isPageFlipped = FALSE; + + /* initialize buffer info to default values */ + buffer->attachment = attachment; + buffer->driverPrivate = privates; + buffer->format = format; + buffer->flags = 0; + + if ( DRI2CanFlip( pDraw ) && fPtr->use_pageflipping && DRAWABLE_PIXMAP != pDraw->type) + { + ump_secure_id ump_id = UMP_INVALID_SECURE_ID; + + if ( (fPtr->fb_lcd_var.yres*2) > fPtr->fb_lcd_var.yres_virtual ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] lcd driver does not have enough virtual y resolution. Need: %i Have: %i\n", + __FUNCTION__, __LINE__, fPtr->fb_lcd_var.yres*2, fPtr->fb_lcd_var.yres_virtual ); + return NULL; + } + + (void)ioctl(fPtr->fb_lcd_fd, GET_UMP_SECURE_ID, &ump_id ); + + if ( UMP_INVALID_SECURE_ID == ump_id ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] failed to retrieve UMP memory handle for flipping\n", __FUNCTION__, __LINE__ ); + + free( buffer ); + free( privates ); + return NULL; + } + + buffer->name = ump_id; + + if ( DRI2BufferBackLeft == attachment ) + { + /* Use the "flags" attribute in order to provide EGL with enough information to offset the provided UMP memory for this buffer + * Flags will only be set in cases where it is possible to do page flipping instead of offscreen rendering with EXA copy + * Offset is set to the second virtual screen, in y direction + * Example: + * Physical resolution: 1366 x 768 + * Virtual resolution: 1366 x 1536 + * Offset: 768 + */ + buffer->flags = (fPtr->fb_lcd_var.xres_virtual * fPtr->fb_lcd_var.bits_per_pixel/8) * fPtr->fb_lcd_var.yres; + + /* make sure the display offset is set to a known state */ + if ( ioctl( fPtr->fb_lcd_fd, FBIOGET_VSCREENINFO, &fPtr->fb_lcd_var ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] failed in FBIOGET_VSCREENINFO\n", __FUNCTION__, __LINE__ ); + free( buffer ); + free( privates ); + return NULL; + } + + fPtr->fb_lcd_var.yoffset = fPtr->fb_lcd_var.yres; + fPtr->fb_lcd_var.activate = FB_ACTIVATE_NOW; + + if ( ioctl( fPtr->fb_lcd_fd, FBIOPUT_VSCREENINFO, &fPtr->fb_lcd_var ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] failed in FBIOPUT_VSCREENINFO\n", __FUNCTION__, __LINE__ ); + free( buffer ); + free( privates ); + return NULL; + } + } + + if ( DRAWABLE_PIXMAP == pDraw->type ) pPixmap = (PixmapPtr)pDraw; + else pPixmap = pScreen->GetWindowPixmap( (WindowPtr) pDraw ); + + privates->isPageFlipped = TRUE; + + pPixmap->refcnt++; + + buffer->pitch = pPixmap->devKind; + if ( 0 == buffer->pitch ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] Warning: Autocalculating pitch\n", __FUNCTION__, __LINE__ ); + buffer->pitch = ( (pPixmap->drawable.width*pPixmap->drawable.bitsPerPixel) + 7 ) / 8; + } + buffer->cpp = pPixmap->drawable.bitsPerPixel / 8; + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] Enabled Page Flipping (pitch: %i flags: %i width: %i height: %i)\n", __FUNCTION__, __LINE__, buffer->pitch, buffer->flags, pPixmap->drawable.width, pPixmap->drawable.height ); + + ioctl( fPtr->fb_lcd_fd, FBIOGET_VSCREENINFO, &fPtr->fb_lcd_var ); + } + else + { + if ( DRI2BufferFrontLeft == attachment ) + { + if ( DRAWABLE_PIXMAP == pDraw->type ) pPixmap = (PixmapPtr)pDraw; + else pPixmap = pScreen->GetWindowPixmap( (WindowPtr) pDraw ); + + pPixmap->refcnt++; + } + else + { + /* create a new pixmap for the offscreen data */ + pPixmap = (*pScreen->CreatePixmap)( pScreen, pDraw->width, pDraw->height, (format != 0) ? format : pDraw->depth, 0 ); + if ( NULL == pPixmap ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] unable to allocate pixmap\n", __FUNCTION__, __LINE__ ); + free( buffer ); + free( privates ); + return NULL; + } + + exaMoveInPixmap(pPixmap); + } + + privates->pPixmap = pPixmap; + privPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate( pPixmap ); + buffer->pitch = pPixmap->devKind; + buffer->cpp = pPixmap->drawable.bitsPerPixel / 8; + buffer->name = ump_secure_id_get( privPixmap->mem_info->handle ); + } + + return buffer; +} + +static void MaliDRI2DestroyBuffer( DrawablePtr pDraw, DRI2Buffer2Ptr buffer ) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MaliPtr fPtr = MALIPTR(pScrn); + + if ( NULL != buffer ) + { + MaliDRI2BufferPrivatePtr private = buffer->driverPrivate; + ScreenPtr pScreen = pDraw->pScreen; + + if ( NULL != private ) + { + if ( TRUE == private->isPageFlipped ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "[%s:%d] Setting back to zero offset\n", __FUNCTION__, __LINE__ ); + fPtr->fb_lcd_var.yoffset = 0; + fPtr->fb_lcd_var.activate = FB_ACTIVATE_NOW; + + if ( ioctl( fPtr->fb_lcd_fd, FBIOPUT_VSCREENINFO, &fPtr->fb_lcd_var ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_WARNING, "[%s:%d] failed in FBIOPUT_VSCREENINFO\n", __FUNCTION__, __LINE__ ); + } + } + if( NULL != private->pPixmap ) (*pScreen->DestroyPixmap)(private->pPixmap); + } + + free( private ); + free( buffer ); + } +} + +static void MaliDRI2CopyRegion( DrawablePtr pDraw, RegionPtr pRegion, DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer ) +{ + GCPtr pGC; + RegionPtr copyRegion; + ScreenPtr pScreen = pDraw->pScreen; + MaliDRI2BufferPrivatePtr srcPrivate = pSrcBuffer->driverPrivate; + MaliDRI2BufferPrivatePtr dstPrivate = pDstBuffer->driverPrivate; + DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft) ? pDraw : &srcPrivate->pPixmap->drawable; + DrawablePtr dst = (dstPrivate->attachment == DRI2BufferFrontLeft) ? pDraw : &dstPrivate->pPixmap->drawable; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MaliPtr fPtr = MALIPTR(pScrn); + + if ( TRUE == dstPrivate->isPageFlipped && TRUE == srcPrivate->isPageFlipped ) + { + fPtr->fb_lcd_var.yoffset = (fPtr->fb_lcd_var.yoffset + fPtr->fb_lcd_var.yres) % (fPtr->fb_lcd_var.yres*2); + + +#if 1 + if ( ioctl( fPtr->fb_lcd_fd, FBIOPUT_VSCREENINFO, &fPtr->fb_lcd_var ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_WARNING, "[%s:%d] failed in FBIOPUT_VSCREENINFO (offset: %i)\n", __FUNCTION__, __LINE__, fPtr->fb_lcd_var.yoffset ); + } + + if ( fPtr->use_pageflipping_vsync ) + { + fPtr->fb_lcd_var.activate = FB_ACTIVATE_VBL; + if ( ioctl( fPtr->fb_lcd_fd, FBIO_WAITFORVSYNC, 0 ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_WARNING, "[%s:%d] failed in FBIO_WAITFORVSYNC\n", __FUNCTION__, __LINE__ ); + } + } +#else + if ( ioctl( fPtr->fb_lcd_fd, FBIOPAN_DISPLAY, &fPtr->fb_lcd_var ) < 0 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_WARNING, "[%s:%d] failed in FBIOPAN_DISPLAY (offset: %i)\n", __FUNCTION__, __LINE__, fPtr->fb_lcd_var.yoffset ); + } +#endif + ioctl( fPtr->fb_lcd_fd, FBIOGET_VSCREENINFO, &fPtr->fb_lcd_var ); + + return; + } + + if ( DRI2BufferFakeFrontLeft == srcPrivate->attachment || DRI2BufferFakeFrontLeft == dstPrivate->attachment ) return; + + pGC = GetScratchGC(pDraw->depth, pScreen); + + copyRegion = REGION_CREATE( pScreen, NULL, 0 ); + REGION_COPY( pScreen, copyRegion, pRegion ); + (*pGC->funcs->ChangeClip)(pGC, CT_REGION, copyRegion, 0 ); + ValidateGC( dst, pGC ); + (*pGC->ops->CopyArea)( src, dst, pGC, 0, 0, pDraw->width, pDraw->height, 0, 0 ); + + FreeScratchGC(pGC); +} + +Bool MaliDRI2ScreenInit( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MaliPtr fPtr = MALIPTR(pScrn); + DRI2InfoRec info; + int dri2_major = 2, dri2_minor = 0, i; + struct stat sbuf; + dev_t d; + char *p; + + if ( xf86LoaderCheckSymbol( "DRI2Version") ) DRI2Version( &dri2_major, &dri2_minor ); + + if ( dri2_minor < 1 ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "%s requires DRI2 module version 1.1.0 or later\n", __func__); + return FALSE; + } + + xf86DrvMsg( pScrn->scrnIndex, X_INFO, "DRI2 version: %i.%i\n", dri2_major, dri2_minor ); + + + /* extract deviceName */ + info.fd = fPtr->drm_fd; + fstat( info.fd, &sbuf ); + d = sbuf.st_rdev; + + p = fPtr->deviceName; + for ( i=0; i<DRM_MAX_MINOR; i++ ) + { + sprintf( p, DRM_DEV_NAME, DRM_DIR_NAME, i ); + if ( stat( p, &sbuf ) == 0 && sbuf.st_rdev == d ) break; + } + + if ( i == DRM_MAX_MINOR ) + { + xf86DrvMsg( pScrn->scrnIndex, X_ERROR, "%s failed to open drm device\n", __func__ ); + return FALSE; + } + + + info.driverName = "Mali DRI2"; + info.deviceName = p; + +#if DRI2INFOREC_VERSION == 1 + info.version = 1; + info.CreateBuffers = MaliDRI2CreateBuffers; + info.DestroyBuffers = MaliDRI2DestroyBuffers; +#elif DRI2INFOREC_VERSION == 2 + info.version = 2; + info.CreateBuffer = MaliDRI2CreateBuffer; + info.DestroyBuffer = MaliDRI2DestroyBuffer; +#else + info.version = 3; + info.CreateBuffer = MaliDRI2CreateBuffer; + info.DestroyBuffer = MaliDRI2DestroyBuffer; +#endif + + info.CopyRegion = MaliDRI2CopyRegion; + + if ( FALSE == DRI2ScreenInit( pScreen, &info ) ) return FALSE; + + return TRUE; +} + +void MaliDRI2CloseScreen( ScreenPtr pScreen ) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + MaliPtr fPtr = MALIPTR(pScrn); + + DRI2CloseScreen( pScreen ); + + fPtr->dri_render = DRI_NONE; +} |