src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the plugins of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "pvrqwsdrawable_p.h"
       
    43 #include <stdio.h>
       
    44 #include <stdlib.h>
       
    45 #include <string.h>
       
    46 #include <sys/types.h>
       
    47 #include <sys/mman.h>
       
    48 #include <sys/ioctl.h>
       
    49 #include <linux/fb.h>
       
    50 #include <fcntl.h>
       
    51 #include <unistd.h>
       
    52 
       
    53 PvrQwsDisplay pvrQwsDisplay;
       
    54 
       
    55 static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable);
       
    56 
       
    57 /* Initialize the /dev/fbN device for a specific screen */
       
    58 static int pvrQwsInitFbScreen(int screen)
       
    59 {
       
    60     struct fb_var_screeninfo var;
       
    61     struct fb_fix_screeninfo fix;
       
    62     unsigned long start;
       
    63     unsigned long length;
       
    64     int width, height, stride;
       
    65     PVR2DFORMAT format;
       
    66     void *mapped;
       
    67     int fd, bytesPerPixel;
       
    68     char name[64];
       
    69     PVR2DMEMINFO *memInfo;
       
    70     unsigned long pageAddresses[2];
       
    71 
       
    72     /* Bail out if already initialized, or the number is incorrect */
       
    73     if (screen < 0 || screen >= PVRQWS_MAX_SCREENS)
       
    74         return 0;
       
    75     if (pvrQwsDisplay.screens[screen].initialized)
       
    76         return 1;
       
    77 
       
    78     /* Open the framebuffer and fetch its properties */
       
    79     sprintf(name, "/dev/fb%d", screen);
       
    80     fd = open(name, O_RDWR, 0);
       
    81     if (fd < 0) {
       
    82         perror(name);
       
    83         return 0;
       
    84     }
       
    85     if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) {
       
    86         perror("FBIOGET_VSCREENINFO");
       
    87         close(fd);
       
    88         return 0;
       
    89     }
       
    90     if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) {
       
    91         perror("FBIOGET_FSCREENINFO");
       
    92         close(fd);
       
    93         return 0;
       
    94     }
       
    95     width = var.xres;
       
    96     height = var.yres;
       
    97     bytesPerPixel = var.bits_per_pixel / 8;
       
    98     stride = var.xres * bytesPerPixel;
       
    99     format = PVR2D_1BPP;
       
   100     if (var.bits_per_pixel == 16) {
       
   101         if (var.red.length == 5 && var.green.length == 6 &&
       
   102             var.blue.length == 5 && var.red.offset == 11 &&
       
   103             var.green.offset == 5 && var.blue.offset == 0) {
       
   104             format = PVR2D_RGB565;
       
   105         }
       
   106         if (var.red.length == 4 && var.green.length == 4 &&
       
   107             var.blue.length == 4 && var.transp.length == 4 &&
       
   108             var.red.offset == 8 && var.green.offset == 4 &&
       
   109             var.blue.offset == 0 && var.transp.offset == 12) {
       
   110             format = PVR2D_ARGB4444;
       
   111         }
       
   112     } else if (var.bits_per_pixel == 32) {
       
   113         if (var.red.length == 8 && var.green.length == 8 &&
       
   114             var.blue.length == 8 && var.transp.length == 8 &&
       
   115             var.red.offset == 16 && var.green.offset == 8 &&
       
   116             var.blue.offset == 0 && var.transp.offset == 24) {
       
   117             format = PVR2D_ARGB8888;
       
   118         }
       
   119     }
       
   120     if (format == PVR2D_1BPP) {
       
   121         fprintf(stderr, "%s: could not find a suitable PVR2D pixel format\n", name);
       
   122         close(fd);
       
   123         return 0;
       
   124     }
       
   125     start = fix.smem_start;
       
   126     length = var.xres_virtual * var.yres_virtual * bytesPerPixel;
       
   127 
       
   128     if (screen == 0) {
       
   129         /* We use PVR2DGetFrameBuffer to map the first screen.
       
   130            On some chipsets it is more reliable than using PVR2DMemWrap */
       
   131         mapped = 0;
       
   132         memInfo = 0;
       
   133     } else {
       
   134         /* Other screens: map the framebuffer region into memory */
       
   135         mapped = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
       
   136         if (!mapped || mapped == (void *)(-1)) {
       
   137             perror("mmap");
       
   138             close(fd);
       
   139             return 0;
       
   140         }
       
   141 
       
   142         /* Allocate a PVR2D memory region for the framebuffer */
       
   143         memInfo = 0;
       
   144         if (pvrQwsDisplay.context) {
       
   145             pageAddresses[0] = start & 0xFFFFF000;
       
   146             pageAddresses[1] = 0;
       
   147             if (PVR2DMemWrap
       
   148                     (pvrQwsDisplay.context, mapped, PVR2D_WRAPFLAG_CONTIGUOUS,
       
   149                      length, pageAddresses, &memInfo) != PVR2D_OK) {
       
   150                 munmap(mapped, length);
       
   151                 close(fd);
       
   152                 return 0;
       
   153             }
       
   154         }
       
   155     }
       
   156 
       
   157     /* We don't need the file descriptor any more */
       
   158     close(fd);
       
   159 
       
   160     /* The framebuffer is ready, so initialize the PvrQwsScreenInfo */
       
   161     pvrQwsDisplay.screens[screen].screenRect.x = 0;
       
   162     pvrQwsDisplay.screens[screen].screenRect.y = 0;
       
   163     pvrQwsDisplay.screens[screen].screenRect.width = width;
       
   164     pvrQwsDisplay.screens[screen].screenRect.height = height;
       
   165     pvrQwsDisplay.screens[screen].screenStride = stride;
       
   166     pvrQwsDisplay.screens[screen].pixelFormat = format;
       
   167     pvrQwsDisplay.screens[screen].bytesPerPixel = bytesPerPixel;
       
   168     pvrQwsDisplay.screens[screen].screenDrawable = 0;
       
   169     if (mapped) {
       
   170         /* Don't set these fields if mapped is 0, because PVR2DGetFrameBuffer
       
   171            may have already been called and set them */
       
   172         pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
       
   173         pvrQwsDisplay.screens[screen].mapped = mapped;
       
   174     }
       
   175     pvrQwsDisplay.screens[screen].mappedLength = length;
       
   176     pvrQwsDisplay.screens[screen].screenStart = start;
       
   177     pvrQwsDisplay.screens[screen].needsUnmap = (mapped != 0);
       
   178     pvrQwsDisplay.screens[screen].initialized = 1;
       
   179     return 1;
       
   180 }
       
   181 
       
   182 /* Called when a new drawable is added to ensure that we have a
       
   183    PVR2D context and framebuffer PVR2DMEMINFO blocks */
       
   184 static int pvrQwsAddDrawable(void)
       
   185 {
       
   186     int numDevs, screen;
       
   187     PVR2DDEVICEINFO *devs;
       
   188     unsigned long devId;
       
   189     unsigned long pageAddresses[2];
       
   190     PVR2DMEMINFO *memInfo;
       
   191     PVR2DDISPLAYINFO displayInfo;
       
   192 
       
   193     /* Bail out early if this is not the first drawable */
       
   194     if (pvrQwsDisplay.numDrawables > 0) {
       
   195         ++(pvrQwsDisplay.numDrawables);
       
   196         return 1;
       
   197     }
       
   198 
       
   199     /* Find the first PVR2D device in the system and open it */
       
   200     numDevs = PVR2DEnumerateDevices(0);
       
   201     if (numDevs <= 0)
       
   202         return 0;
       
   203     devs = (PVR2DDEVICEINFO *)malloc(sizeof(PVR2DDEVICEINFO) * numDevs);
       
   204     if (!devs)
       
   205         return 0;
       
   206     if (PVR2DEnumerateDevices(devs) != PVR2D_OK) {
       
   207         free(devs);
       
   208         return 0;
       
   209     }
       
   210     devId = devs[0].ulDevID;
       
   211     free(devs);
       
   212     if (PVR2DCreateDeviceContext(devId, &pvrQwsDisplay.context, 0) != PVR2D_OK)
       
   213         return 0;
       
   214     pvrQwsDisplay.numFlipBuffers = 0;
       
   215     pvrQwsDisplay.flipChain = 0;
       
   216     if (PVR2DGetDeviceInfo(pvrQwsDisplay.context, &displayInfo) == PVR2D_OK) {
       
   217         if (displayInfo.ulMaxFlipChains > 0 && displayInfo.ulMaxBuffersInChain > 0)
       
   218             pvrQwsDisplay.numFlipBuffers = displayInfo.ulMaxBuffersInChain;
       
   219         if (pvrQwsDisplay.numFlipBuffers > PVRQWS_MAX_FLIP_BUFFERS)
       
   220             pvrQwsDisplay.numFlipBuffers = PVRQWS_MAX_FLIP_BUFFERS;
       
   221     }
       
   222 
       
   223     /* Create the PVR2DMEMINFO blocks for the active framebuffers */
       
   224     for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
       
   225         if (screen != 0 && pvrQwsDisplay.screens[screen].mapped) {
       
   226             pageAddresses[0]
       
   227                 = pvrQwsDisplay.screens[screen].screenStart & 0xFFFFF000;
       
   228             pageAddresses[1] = 0;
       
   229             if (PVR2DMemWrap
       
   230                     (pvrQwsDisplay.context,
       
   231                      pvrQwsDisplay.screens[screen].mapped,
       
   232                      PVR2D_WRAPFLAG_CONTIGUOUS,
       
   233                      pvrQwsDisplay.screens[screen].mappedLength,
       
   234                      pageAddresses, &memInfo) != PVR2D_OK) {
       
   235                 PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
       
   236                 pvrQwsDisplay.context = 0;
       
   237                 return 0;
       
   238             }
       
   239             pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
       
   240         } else if (screen == 0) {
       
   241             if (PVR2DGetFrameBuffer
       
   242                     (pvrQwsDisplay.context,
       
   243                      PVR2D_FB_PRIMARY_SURFACE, &memInfo) != PVR2D_OK) {
       
   244                 fprintf(stderr, "QWSWSEGL: could not get the primary framebuffer surface\n");
       
   245                 PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
       
   246                 pvrQwsDisplay.context = 0;
       
   247                 return 0;
       
   248             }
       
   249             pvrQwsDisplay.screens[screen].frameBuffer = memInfo;
       
   250             pvrQwsDisplay.screens[screen].mapped = memInfo->pBase;
       
   251         }
       
   252     }
       
   253 
       
   254     /* Create a flip chain for the screen if supported by the hardware */
       
   255     pvrQwsDisplay.usePresentBlit = 0;
       
   256     if (pvrQwsDisplay.numFlipBuffers > 0) {
       
   257         long stride = 0;
       
   258         unsigned long flipId = 0;
       
   259         unsigned long numBuffers;
       
   260         if (PVR2DCreateFlipChain(pvrQwsDisplay.context, 0,
       
   261                                  //PVR2D_CREATE_FLIPCHAIN_SHARED |
       
   262                                  //PVR2D_CREATE_FLIPCHAIN_QUERY,
       
   263                                  pvrQwsDisplay.numFlipBuffers,
       
   264                                  pvrQwsDisplay.screens[0].screenRect.width,
       
   265                                  pvrQwsDisplay.screens[0].screenRect.height,
       
   266                                  pvrQwsDisplay.screens[0].pixelFormat,
       
   267                                  &stride, &flipId, &(pvrQwsDisplay.flipChain))
       
   268                 == PVR2D_OK) {
       
   269             pvrQwsDisplay.screens[0].screenStride = stride;
       
   270             PVR2DGetFlipChainBuffers(pvrQwsDisplay.context,
       
   271                                      pvrQwsDisplay.flipChain,
       
   272                                      &numBuffers,
       
   273                                      pvrQwsDisplay.flipBuffers);
       
   274         } else {
       
   275             pvrQwsDisplay.flipChain = 0;
       
   276             pvrQwsDisplay.numFlipBuffers = 0;
       
   277         }
       
   278 
       
   279         /* PVR2DPresentBlt is a little more reliable than PVR2DBlt
       
   280            when flip chains are present, even if we cannot create a
       
   281            flip chain at the moment */
       
   282         pvrQwsDisplay.usePresentBlit = 1;
       
   283     }
       
   284 
       
   285     /* The context is ready to go */
       
   286     ++(pvrQwsDisplay.numDrawables);
       
   287     return 1;
       
   288 }
       
   289 
       
   290 /* Called when the last drawable is destroyed.  The PVR2D context
       
   291    will be destroyed but the raw framebuffer memory will stay mapped */
       
   292 static void pvrQwsDestroyContext(void)
       
   293 {
       
   294     int screen;
       
   295     for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
       
   296         if (pvrQwsDisplay.screens[screen].frameBuffer) {
       
   297             PVR2DMemFree
       
   298                 (pvrQwsDisplay.context, 
       
   299                  pvrQwsDisplay.screens[screen].frameBuffer);
       
   300             pvrQwsDisplay.screens[screen].frameBuffer = 0;
       
   301         }
       
   302     }
       
   303 
       
   304     if (pvrQwsDisplay.numFlipBuffers > 0)
       
   305         PVR2DDestroyFlipChain(pvrQwsDisplay.context, pvrQwsDisplay.flipChain);
       
   306     PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
       
   307     pvrQwsDisplay.context = 0;
       
   308     pvrQwsDisplay.flipChain = 0;
       
   309     pvrQwsDisplay.numFlipBuffers = 0;
       
   310     pvrQwsDisplay.usePresentBlit = 0;
       
   311 }
       
   312 
       
   313 int pvrQwsDisplayOpen(void)
       
   314 {
       
   315     int screen;
       
   316 
       
   317     /* If the display is already open, increase reference count and return */
       
   318     if (pvrQwsDisplay.refCount > 0) {
       
   319         ++(pvrQwsDisplay.refCount);
       
   320         return 1;
       
   321     }
       
   322 
       
   323     /* Open the framebuffer and map it directly */
       
   324     if (!pvrQwsInitFbScreen(0)) {
       
   325         --(pvrQwsDisplay.refCount);
       
   326         return 0;
       
   327     }
       
   328 
       
   329     /* Clear the other screens.  We will create them if they are referenced */
       
   330     for (screen = 1; screen < PVRQWS_MAX_SCREENS; ++screen)
       
   331         memset(&(pvrQwsDisplay.screens[screen]), 0, sizeof(PvrQwsScreenInfo));
       
   332 
       
   333     /* The display is open and ready */
       
   334     ++(pvrQwsDisplay.refCount);
       
   335     return 1;
       
   336 }
       
   337 
       
   338 void pvrQwsDisplayClose(void)
       
   339 {
       
   340     int screen;
       
   341 
       
   342     if (pvrQwsDisplay.refCount == 0)
       
   343         return;
       
   344     if (--(pvrQwsDisplay.refCount) > 0)
       
   345         return;
       
   346 
       
   347     /* Prevent pvrQwsDestroyContext from being called for the time being */
       
   348     ++pvrQwsDisplay.numDrawables;
       
   349 
       
   350     /* Free the screens */
       
   351     for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) {
       
   352         PvrQwsScreenInfo *info = &(pvrQwsDisplay.screens[screen]);
       
   353         if (info->screenDrawable)
       
   354             pvrQwsDestroyDrawableForced(info->screenDrawable);
       
   355         if (info->frameBuffer)
       
   356             PVR2DMemFree(pvrQwsDisplay.context, info->frameBuffer);
       
   357         if (info->mapped && info->needsUnmap)
       
   358             munmap(info->mapped, info->mappedLength);
       
   359     }
       
   360 
       
   361     /* Now it is safe to destroy the PVR2D context */
       
   362     --pvrQwsDisplay.numDrawables;
       
   363     if (pvrQwsDisplay.context)
       
   364         PVR2DDestroyDeviceContext(pvrQwsDisplay.context);
       
   365 
       
   366     memset(&pvrQwsDisplay, 0, sizeof(pvrQwsDisplay));
       
   367 }
       
   368 
       
   369 int pvrQwsDisplayIsOpen(void)
       
   370 {
       
   371     return (pvrQwsDisplay.refCount > 0);
       
   372 }
       
   373 
       
   374 /* Ensure that a specific screen has been initialized */
       
   375 static int pvrQwsEnsureScreen(int screen)
       
   376 {
       
   377     if (screen < 0 || screen >= PVRQWS_MAX_SCREENS)
       
   378         return 0;
       
   379     if (!screen)
       
   380         return 1;
       
   381     return pvrQwsInitFbScreen(screen);
       
   382 }
       
   383 
       
   384 PvrQwsDrawable *pvrQwsScreenWindow(int screen)
       
   385 {
       
   386     PvrQwsDrawable *drawable;
       
   387 
       
   388     if (!pvrQwsEnsureScreen(screen))
       
   389         return 0;
       
   390 
       
   391     drawable = pvrQwsDisplay.screens[screen].screenDrawable;
       
   392     if (drawable)
       
   393         return drawable;
       
   394 
       
   395     drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
       
   396     if (!drawable)
       
   397         return 0;
       
   398 
       
   399     drawable->type = PvrQwsScreen;
       
   400     drawable->screen = screen;
       
   401     drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
       
   402     drawable->rect = pvrQwsDisplay.screens[screen].screenRect;
       
   403     drawable->visibleRects[0] = drawable->rect;
       
   404     drawable->numVisibleRects = 1;
       
   405     drawable->isFullScreen = 1;
       
   406 
       
   407     if (!pvrQwsAddDrawable()) {
       
   408         free(drawable);
       
   409         return 0;
       
   410     }
       
   411 
       
   412     pvrQwsDisplay.screens[screen].screenDrawable = drawable;
       
   413 
       
   414     return drawable;
       
   415 }
       
   416 
       
   417 PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect)
       
   418 {
       
   419     PvrQwsDrawable *drawable;
       
   420 
       
   421     if (!pvrQwsEnsureScreen(screen))
       
   422         return 0;
       
   423 
       
   424     drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
       
   425     if (!drawable)
       
   426         return 0;
       
   427 
       
   428     drawable->type = PvrQwsWindow;
       
   429     drawable->winId = winId;
       
   430     drawable->refCount = 1;
       
   431     drawable->screen = screen;
       
   432     drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
       
   433     drawable->rect = *rect;
       
   434 
       
   435     if (!pvrQwsAddDrawable()) {
       
   436         free(drawable);
       
   437         return 0;
       
   438     }
       
   439 
       
   440     drawable->nextWinId = pvrQwsDisplay.firstWinId;
       
   441     pvrQwsDisplay.firstWinId = drawable;
       
   442 
       
   443     return drawable;
       
   444 }
       
   445 
       
   446 PvrQwsDrawable *pvrQwsFetchWindow(long winId)
       
   447 {
       
   448     PvrQwsDrawable *drawable = pvrQwsDisplay.firstWinId;
       
   449     while (drawable != 0 && drawable->winId != winId)
       
   450         drawable = drawable->nextWinId;
       
   451 
       
   452     if (drawable)
       
   453         ++(drawable->refCount);
       
   454     return drawable;
       
   455 }
       
   456 
       
   457 int pvrQwsReleaseWindow(PvrQwsDrawable *drawable)
       
   458 {
       
   459     if (drawable->type == PvrQwsWindow)
       
   460         return (--(drawable->refCount) <= 0);
       
   461     else
       
   462         return 0;
       
   463 }
       
   464 
       
   465 PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen)
       
   466 {
       
   467     PvrQwsDrawable *drawable;
       
   468 
       
   469     if (!pvrQwsEnsureScreen(screen))
       
   470         return 0;
       
   471 
       
   472     drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable));
       
   473     if (!drawable)
       
   474         return 0;
       
   475 
       
   476     drawable->type = PvrQwsPixmap;
       
   477     drawable->screen = screen;
       
   478     drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat;
       
   479     drawable->rect.x = 0;
       
   480     drawable->rect.y = 0;
       
   481     drawable->rect.width = width;
       
   482     drawable->rect.height = height;
       
   483 
       
   484     if (!pvrQwsAddDrawable()) {
       
   485         free(drawable);
       
   486         return 0;
       
   487     }
       
   488 
       
   489     return drawable;
       
   490 }
       
   491 
       
   492 static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable)
       
   493 {
       
   494     /* Remove the drawable from the display's winId list */
       
   495     PvrQwsDrawable *current = pvrQwsDisplay.firstWinId;
       
   496     PvrQwsDrawable *prev = 0;
       
   497     while (current != 0 && current != drawable) {
       
   498         prev = current;
       
   499         current = current->nextWinId;
       
   500     }
       
   501     if (current != 0) {
       
   502         if (prev)
       
   503             prev->nextWinId = current->nextWinId;
       
   504         else
       
   505             pvrQwsDisplay.firstWinId = current->nextWinId;
       
   506     }
       
   507 
       
   508     pvrQwsFreeBuffers(drawable);
       
   509     free(drawable);
       
   510 
       
   511     --pvrQwsDisplay.numDrawables;
       
   512     if (pvrQwsDisplay.numDrawables == 0)
       
   513         pvrQwsDestroyContext();
       
   514 }
       
   515 
       
   516 void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable)
       
   517 {
       
   518     if (drawable && drawable->type != PvrQwsScreen)
       
   519         pvrQwsDestroyDrawableForced(drawable);
       
   520 }
       
   521 
       
   522 PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable)
       
   523 {
       
   524     return drawable->type;
       
   525 }
       
   526 
       
   527 void pvrQwsSetVisibleRegion
       
   528         (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects)
       
   529 {
       
   530     int index, indexOut;
       
   531     PvrQwsRect *rect;
       
   532     PvrQwsRect *screenRect;
       
   533 
       
   534     /* Visible regions don't make sense for pixmaps */
       
   535     if (drawable->type == PvrQwsPixmap)
       
   536         return;
       
   537 
       
   538     /* Restrict the number of rectangles to prevent buffer overflow */
       
   539     if (numRects > PVRQWS_MAX_VISIBLE_RECTS)
       
   540         numRects = PVRQWS_MAX_VISIBLE_RECTS;
       
   541     if (numRects > 0)
       
   542         memcpy(drawable->visibleRects, rects, numRects * sizeof(PvrQwsRect));
       
   543 
       
   544     /* Convert the rectangles into screen-relative co-ordinates and
       
   545        then clamp them to the screen boundaries.  If any of the
       
   546        clamped rectangles are empty, remove them from the list */
       
   547     screenRect = &(pvrQwsDisplay.screens[drawable->screen].screenRect);
       
   548     indexOut = 0;
       
   549     for (index = 0, rect = drawable->visibleRects; index < numRects; ++index, ++rect) {
       
   550         if (rect->x < 0) {
       
   551             rect->width += rect->x;
       
   552             rect->x = 0;
       
   553             if (rect->width < 0)
       
   554                 rect->width = 0;
       
   555         } else if (rect->x >= screenRect->width) {
       
   556             rect->x = screenRect->width;
       
   557             rect->width = 0;
       
   558         }
       
   559         if ((rect->x + rect->width) > screenRect->width) {
       
   560             rect->width = screenRect->width - rect->x;
       
   561         }
       
   562         if (rect->y < 0) {
       
   563             rect->height += rect->y;
       
   564             rect->y = 0;
       
   565             if (rect->height < 0)
       
   566                 rect->height = 0;
       
   567         } else if (rect->y >= screenRect->height) {
       
   568             rect->y = screenRect->height;
       
   569             rect->height = 0;
       
   570         }
       
   571         if ((rect->y + rect->height) > screenRect->height) {
       
   572             rect->height = screenRect->height - rect->y;
       
   573         }
       
   574         if (rect->width > 0 && rect->height > 0) {
       
   575             if (index != indexOut)
       
   576                 drawable->visibleRects[indexOut] = *rect;
       
   577             ++indexOut;
       
   578         }
       
   579     }
       
   580     drawable->numVisibleRects = indexOut;
       
   581 }
       
   582 
       
   583 void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable)
       
   584 {
       
   585     if (drawable->type != PvrQwsPixmap)
       
   586         drawable->numVisibleRects = 0;
       
   587 }
       
   588 
       
   589 void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect)
       
   590 {
       
   591     /* We can only change the geometry of window drawables */
       
   592     if (drawable->type != PvrQwsWindow)
       
   593         return;
       
   594 
       
   595     /* If the position has changed, then clear the visible region */
       
   596     if (drawable->rect.x != rect->x || drawable->rect.y != rect->y) {
       
   597         drawable->rect.x = rect->x;
       
   598         drawable->rect.y = rect->y;
       
   599         drawable->numVisibleRects = 0;
       
   600     }
       
   601 
       
   602     /* If the size has changed, then clear the visible region and
       
   603        invalidate the drawable's buffers.  Invalidating the buffers
       
   604        will force EGL to recreate the drawable, which will then
       
   605        allocate new buffers for the new size */
       
   606     if (drawable->rect.width != rect->width ||
       
   607             drawable->rect.height != rect->height) {
       
   608         drawable->rect.width = rect->width;
       
   609         drawable->rect.height = rect->height;
       
   610         drawable->numVisibleRects = 0;
       
   611         pvrQwsInvalidateBuffers(drawable);
       
   612     }
       
   613 }
       
   614 
       
   615 void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect)
       
   616 {
       
   617     *rect = drawable->rect;
       
   618 }
       
   619 
       
   620 void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle)
       
   621 {
       
   622     if (drawable->rotationAngle != angle) {
       
   623         drawable->rotationAngle = angle;
       
   624 
       
   625         /* Force the buffers to be recreated if the rotation angle changes */
       
   626         pvrQwsInvalidateBuffers(drawable);
       
   627     }
       
   628 }
       
   629 
       
   630 int pvrQwsGetStride(PvrQwsDrawable *drawable)
       
   631 {
       
   632     if (drawable->backBuffersValid)
       
   633         return drawable->strideBytes;
       
   634     else
       
   635         return 0;
       
   636 }
       
   637 
       
   638 PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable)
       
   639 {
       
   640     return (PvrQwsPixelFormat)(drawable->pixelFormat);
       
   641 }
       
   642 
       
   643 void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable)
       
   644 {
       
   645     if (drawable->backBuffersValid)
       
   646         return drawable->backBuffers[drawable->currentBackBuffer]->pBase;
       
   647     else
       
   648         return 0;
       
   649 }
       
   650 
       
   651 int pvrQwsAllocBuffers(PvrQwsDrawable *drawable)
       
   652 {
       
   653     int index;
       
   654     int numBuffers = PVRQWS_MAX_BACK_BUFFERS;
       
   655     if (drawable->type == PvrQwsPixmap)
       
   656         numBuffers = 1;
       
   657     if (drawable->backBuffers[0]) {
       
   658         if (drawable->backBuffersValid)
       
   659             return 1;
       
   660         if (!drawable->usingFlipBuffers) {
       
   661             for (index = 0; index < numBuffers; ++index)
       
   662                 PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
       
   663         }
       
   664     }
       
   665     drawable->stridePixels = (drawable->rect.width + 31) & ~31;
       
   666     drawable->strideBytes =
       
   667         drawable->stridePixels *
       
   668         pvrQwsDisplay.screens[drawable->screen].bytesPerPixel;
       
   669     drawable->usingFlipBuffers =
       
   670         (pvrQwsDisplay.numFlipBuffers > 0 && drawable->isFullScreen);
       
   671     if (drawable->usingFlipBuffers) {
       
   672         if (numBuffers > (int)(pvrQwsDisplay.numFlipBuffers))
       
   673             numBuffers = pvrQwsDisplay.numFlipBuffers;
       
   674         for (index = 0; index < numBuffers; ++index)
       
   675             drawable->backBuffers[index] = pvrQwsDisplay.flipBuffers[index];
       
   676     } else {
       
   677         for (index = 0; index < numBuffers; ++index) {
       
   678             if (PVR2DMemAlloc(pvrQwsDisplay.context,
       
   679                               drawable->strideBytes * drawable->rect.height,
       
   680                               128, 0,
       
   681                               &(drawable->backBuffers[index])) != PVR2D_OK) {
       
   682                 while (--index >= 0)
       
   683                     PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
       
   684                 memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers));
       
   685                 drawable->backBuffersValid = 0;
       
   686                 return 0;
       
   687             }
       
   688         }
       
   689     }
       
   690     for (index = numBuffers; index < PVRQWS_MAX_BACK_BUFFERS; ++index) {
       
   691         drawable->backBuffers[index] = drawable->backBuffers[0];
       
   692     }
       
   693     drawable->backBuffersValid = 1;
       
   694     drawable->currentBackBuffer = 0;
       
   695     return 1;
       
   696 }
       
   697 
       
   698 void pvrQwsFreeBuffers(PvrQwsDrawable *drawable)
       
   699 {
       
   700     int index;
       
   701     int numBuffers = PVRQWS_MAX_BACK_BUFFERS;
       
   702     if (drawable->type == PvrQwsPixmap)
       
   703         numBuffers = 1;
       
   704     if (!drawable->usingFlipBuffers) {
       
   705         for (index = 0; index < numBuffers; ++index) {
       
   706             if (drawable->backBuffers[index])
       
   707                 PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]);
       
   708         }
       
   709     }
       
   710     memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers));
       
   711     drawable->backBuffersValid = 0;
       
   712     drawable->usingFlipBuffers = 0;
       
   713 }
       
   714 
       
   715 void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable)
       
   716 {
       
   717     drawable->backBuffersValid = 0;
       
   718 }
       
   719 
       
   720 int pvrQwsGetBuffers
       
   721     (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render)
       
   722 {
       
   723     if (!drawable->backBuffersValid)
       
   724         return 0;
       
   725     *render = drawable->backBuffers[drawable->currentBackBuffer];
       
   726     *source = drawable->backBuffers
       
   727         [(drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) %
       
   728                 PVRQWS_MAX_BACK_BUFFERS];
       
   729     return 1;
       
   730 }
       
   731 
       
   732 int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly)
       
   733 {
       
   734     PVR2DMEMINFO *buffer;
       
   735     PvrQwsRect *rect;
       
   736     int index;
       
   737 
       
   738     /* Bail out if the back buffers have been invalidated */
       
   739     if (!drawable->backBuffersValid)
       
   740         return 0;
       
   741 
       
   742     /* If there is a swap function, then use that instead */
       
   743     if (drawable->swapFunction) {
       
   744         (*(drawable->swapFunction))(drawable, drawable->userData, repaintOnly);
       
   745         if (!repaintOnly) {
       
   746             drawable->currentBackBuffer
       
   747                 = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS;
       
   748         }
       
   749         return 1;
       
   750     }
       
   751 
       
   752     /* Iterate through the visible rectangles and blit them to the screen */
       
   753     if (!repaintOnly) {
       
   754         index = drawable->currentBackBuffer;
       
   755     } else {
       
   756         index = (drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1)
       
   757                         % PVRQWS_MAX_BACK_BUFFERS;
       
   758     }
       
   759     buffer = drawable->backBuffers[index];
       
   760     rect = drawable->visibleRects;
       
   761     if (drawable->usingFlipBuffers) {
       
   762         PVR2DPresentFlip(pvrQwsDisplay.context, pvrQwsDisplay.flipChain, buffer, 0);
       
   763     } else if (pvrQwsDisplay.usePresentBlit && drawable->numVisibleRects > 0) {
       
   764         PVR2DRECT pvrRects[PVRQWS_MAX_VISIBLE_RECTS];
       
   765         for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) {
       
   766             pvrRects[index].left = rect->x;
       
   767             pvrRects[index].top = rect->y;
       
   768             pvrRects[index].right = rect->x + rect->width;
       
   769             pvrRects[index].bottom = rect->y + rect->height;
       
   770         }
       
   771         for (index = 0; index < drawable->numVisibleRects; index += 4) {
       
   772             int numClip = drawable->numVisibleRects - index;
       
   773             if (numClip > 4)    /* No more than 4 clip rects at a time */
       
   774                 numClip = 4;
       
   775             PVR2DSetPresentBltProperties
       
   776                 (pvrQwsDisplay.context,
       
   777                  PVR2D_PRESENT_PROPERTY_SRCSTRIDE |
       
   778                  PVR2D_PRESENT_PROPERTY_DSTSIZE |
       
   779                  PVR2D_PRESENT_PROPERTY_DSTPOS |
       
   780                  PVR2D_PRESENT_PROPERTY_CLIPRECTS,
       
   781                  drawable->strideBytes,
       
   782                  drawable->rect.width, drawable->rect.height,
       
   783                  drawable->rect.x, drawable->rect.y,
       
   784                  numClip, pvrRects + index, 0);
       
   785             PVR2DPresentBlt(pvrQwsDisplay.context, buffer, 0);
       
   786         }
       
   787         PVR2DQueryBlitsComplete(pvrQwsDisplay.context, buffer, 1);
       
   788     } else {
       
   789         /* TODO: use PVR2DBltClipped for faster transfers of clipped windows */
       
   790         PVR2DBLTINFO blit;
       
   791         for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) {
       
   792             memset(&blit, 0, sizeof(blit));
       
   793 
       
   794             blit.CopyCode = PVR2DROPcopy;
       
   795             blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL;
       
   796 
       
   797             blit.pSrcMemInfo = buffer;
       
   798             blit.SrcStride = drawable->strideBytes;
       
   799             blit.SrcX = rect->x - drawable->rect.x;
       
   800             blit.SrcY = rect->y - drawable->rect.y;
       
   801             blit.SizeX = rect->width;
       
   802             blit.SizeY = rect->height;
       
   803             blit.SrcFormat = drawable->pixelFormat;
       
   804 
       
   805             blit.pDstMemInfo = pvrQwsDisplay.screens[drawable->screen].frameBuffer;
       
   806             blit.DstStride = pvrQwsDisplay.screens[drawable->screen].screenStride;
       
   807             blit.DstX = rect->x;
       
   808             blit.DstY = rect->y;
       
   809             blit.DSizeX = rect->width;
       
   810             blit.DSizeY = rect->height;
       
   811             blit.DstFormat = pvrQwsDisplay.screens[drawable->screen].pixelFormat;
       
   812 
       
   813             PVR2DBlt(pvrQwsDisplay.context, &blit);
       
   814         }
       
   815     }
       
   816 
       
   817     /* Swap the buffers */
       
   818     if (!repaintOnly) {
       
   819         drawable->currentBackBuffer
       
   820             = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS;
       
   821     }
       
   822     return 1;
       
   823 }
       
   824 
       
   825 void pvrQwsSetSwapFunction
       
   826     (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData)
       
   827 {
       
   828     drawable->swapFunction = func;
       
   829     drawable->userData = userData;
       
   830 }