diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/plugins/gfxdrivers/powervr | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/plugins/gfxdrivers/powervr')
13 files changed, 2536 insertions, 0 deletions
diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro new file mode 100644 index 0000000..b62894d --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro @@ -0,0 +1,24 @@ +TEMPLATE = lib +TARGET = pvrQWSWSEGL +CONFIG += dll warn_on +CONFIG -= qt + +HEADERS+=\ + pvrqwsdrawable.h \ + pvrqwsdrawable_p.h + +SOURCES+=\ + pvrqwsdrawable.c \ + pvrqwswsegl.c + +INCLUDEPATH += $$QMAKE_INCDIR_OPENGL + +for(p, QMAKE_LIBDIR_OPENGL) { + exists($$p):LIBS += -L$$p +} + +LIBS += -lpvr2d + +DESTDIR = $$QMAKE_LIBDIR_QT +target.path = $$[QT_INSTALL_LIBS] +INSTALLS += target diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c new file mode 100644 index 0000000..5c37253 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c @@ -0,0 +1,856 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvrqwsdrawable_p.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <fcntl.h> +#include <unistd.h> + +PvrQwsDisplay pvrQwsDisplay; + +static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable); + +/* Initialize the /dev/fbN device for a specific screen */ +static int pvrQwsInitFbScreen(int screen) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + unsigned long start; + unsigned long length; + int width, height, stride; + PVR2DFORMAT format; + void *mapped; + int fd, bytesPerPixel; + char name[64]; + PVR2DMEMINFO *memInfo; + unsigned long pageAddresses[2]; + + /* Bail out if already initialized, or the number is incorrect */ + if (screen < 0 || screen >= PVRQWS_MAX_SCREENS) + return 0; + if (pvrQwsDisplay.screens[screen].mapped) + return 1; + + /* Open the framebuffer and fetch its properties */ + sprintf(name, "/dev/fb%d", screen); + fd = open(name, O_RDWR, 0); + if (fd < 0) { + perror(name); + return 0; + } + if (ioctl(fd, FBIOGET_VSCREENINFO, &var) < 0) { + perror("FBIOGET_VSCREENINFO"); + close(fd); + return 0; + } + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix) < 0) { + perror("FBIOGET_FSCREENINFO"); + close(fd); + return 0; + } + width = var.xres; + height = var.yres; + bytesPerPixel = var.bits_per_pixel / 8; + stride = var.xres * bytesPerPixel; + format = PVR2D_1BPP; + if (var.bits_per_pixel == 16) { + if (var.red.length == 5 && var.green.length == 6 && + var.blue.length == 5 && var.red.offset == 11 && + var.green.offset == 5 && var.blue.offset == 0) { + format = PVR2D_RGB565; + } + if (var.red.length == 4 && var.green.length == 4 && + var.blue.length == 4 && var.transp.length == 4 && + var.red.offset == 8 && var.green.offset == 4 && + var.blue.offset == 0 && var.transp.offset == 12) { + format = PVR2D_ARGB4444; + } + } else if (var.bits_per_pixel == 32) { + if (var.red.length == 8 && var.green.length == 8 && + var.blue.length == 8 && var.transp.length == 8 && + var.red.offset == 16 && var.green.offset == 8 && + var.blue.offset == 0 && var.transp.offset == 24) { + format = PVR2D_ARGB8888; + } + } + if (format == PVR2D_1BPP) { + fprintf(stderr, "%s: could not find a suitable PVR2D pixel format\n", name); + close(fd); + return 0; + } + start = fix.smem_start; + length = var.xres_virtual * var.yres_virtual * bytesPerPixel; + + /* Map the framebuffer region into memory */ + mapped = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!mapped || mapped == (void *)(-1)) { + perror("mmap"); + close(fd); + return 0; + } + + /* Allocate a PVR2D memory region for the framebuffer */ + memInfo = 0; + if (pvrQwsDisplay.context) { + pageAddresses[0] = start & 0xFFFFF000; + pageAddresses[1] = 0; + if (PVR2DMemWrap + (pvrQwsDisplay.context, mapped, PVR2D_WRAPFLAG_CONTIGUOUS, + length, pageAddresses, &memInfo) != PVR2D_OK) { + munmap(mapped, length); + close(fd); + return 0; + } + } + + /* We don't need the file descriptor any more */ + close(fd); + + /* The framebuffer is ready, so initialize the PvrQwsScreenInfo */ + pvrQwsDisplay.screens[screen].screenRect.x = 0; + pvrQwsDisplay.screens[screen].screenRect.y = 0; + pvrQwsDisplay.screens[screen].screenRect.width = width; + pvrQwsDisplay.screens[screen].screenRect.height = height; + pvrQwsDisplay.screens[screen].screenStride = stride; + pvrQwsDisplay.screens[screen].pixelFormat = format; + pvrQwsDisplay.screens[screen].bytesPerPixel = bytesPerPixel; + pvrQwsDisplay.screens[screen].frameBuffer = memInfo; + pvrQwsDisplay.screens[screen].screenDrawable = 0; + pvrQwsDisplay.screens[screen].mapped = mapped; + pvrQwsDisplay.screens[screen].mappedLength = length; + pvrQwsDisplay.screens[screen].screenStart = start; + return 1; +} + +/* Called when a new drawable is added to ensure that we have a + PVR2D context and framebuffer PVR2DMEMINFO blocks */ +static int pvrQwsAddDrawable(void) +{ + int numDevs, screen; + PVR2DDEVICEINFO *devs; + unsigned long devId; + unsigned long pageAddresses[2]; + PVR2DMEMINFO *memInfo; + PVR2DDISPLAYINFO displayInfo; + + /* Bail out early if this is not the first drawable */ + if (pvrQwsDisplay.numDrawables > 0) { + ++(pvrQwsDisplay.numDrawables); + return 1; + } + + /* Find the first PVR2D device in the system and open it */ + numDevs = PVR2DEnumerateDevices(0); + if (numDevs <= 0) + return 0; + devs = (PVR2DDEVICEINFO *)malloc(sizeof(PVR2DDEVICEINFO) * numDevs); + if (!devs) + return 0; + if (PVR2DEnumerateDevices(devs) != PVR2D_OK) { + free(devs); + return 0; + } + devId = devs[0].ulDevID; + free(devs); + if (PVR2DCreateDeviceContext(devId, &pvrQwsDisplay.context, 0) != PVR2D_OK) + return 0; + pvrQwsDisplay.numFlipBuffers = 0; + pvrQwsDisplay.flipChain = 0; + if (PVR2DGetDeviceInfo(pvrQwsDisplay.context, &displayInfo) == PVR2D_OK) { + if (displayInfo.ulMaxFlipChains > 0 && displayInfo.ulMaxBuffersInChain > 0) + pvrQwsDisplay.numFlipBuffers = displayInfo.ulMaxBuffersInChain; + if (pvrQwsDisplay.numFlipBuffers > PVRQWS_MAX_FLIP_BUFFERS) + pvrQwsDisplay.numFlipBuffers = PVRQWS_MAX_FLIP_BUFFERS; + } + + /* Create the PVR2DMEMINFO blocks for the active framebuffers */ + for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { + if (pvrQwsDisplay.screens[screen].mapped) { + pageAddresses[0] + = pvrQwsDisplay.screens[screen].screenStart & 0xFFFFF000; + pageAddresses[1] = 0; + if (PVR2DMemWrap + (pvrQwsDisplay.context, + pvrQwsDisplay.screens[screen].mapped, + PVR2D_WRAPFLAG_CONTIGUOUS, + pvrQwsDisplay.screens[screen].mappedLength, + pageAddresses, &memInfo) != PVR2D_OK) { + PVR2DDestroyDeviceContext(pvrQwsDisplay.context); + pvrQwsDisplay.context = 0; + return 0; + } + pvrQwsDisplay.screens[screen].frameBuffer = memInfo; + } + } + + /* Create a flip chain for the screen if supported by the hardware */ + pvrQwsDisplay.usePresentBlit = 0; + if (pvrQwsDisplay.numFlipBuffers > 0) { + long stride = 0; + unsigned long flipId = 0; + unsigned long numBuffers; + if (PVR2DCreateFlipChain(pvrQwsDisplay.context, 0, + //PVR2D_CREATE_FLIPCHAIN_SHARED | + //PVR2D_CREATE_FLIPCHAIN_QUERY, + pvrQwsDisplay.numFlipBuffers, + pvrQwsDisplay.screens[0].screenRect.width, + pvrQwsDisplay.screens[0].screenRect.height, + pvrQwsDisplay.screens[0].pixelFormat, + &stride, &flipId, &(pvrQwsDisplay.flipChain)) + == PVR2D_OK) { + pvrQwsDisplay.screens[0].screenStride = stride; + PVR2DGetFlipChainBuffers(pvrQwsDisplay.context, + pvrQwsDisplay.flipChain, + &numBuffers, + pvrQwsDisplay.flipBuffers); + } else { + pvrQwsDisplay.flipChain = 0; + pvrQwsDisplay.numFlipBuffers = 0; + } + + /* PVR2DPresentBlt is a little more reliable than PVR2DBlt + when flip chains are present, even if we cannot create a + flip chain at the moment */ + pvrQwsDisplay.usePresentBlit = 1; + } + + /* The context is ready to go */ + ++(pvrQwsDisplay.numDrawables); + return 1; +} + +/* Called when the last drawable is destroyed. The PVR2D context + will be destroyed but the raw framebuffer memory will stay mapped */ +static void pvrQwsDestroyContext(void) +{ + int screen; + for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { + if (pvrQwsDisplay.screens[screen].frameBuffer) { + PVR2DMemFree + (pvrQwsDisplay.context, + pvrQwsDisplay.screens[screen].frameBuffer); + pvrQwsDisplay.screens[screen].frameBuffer = 0; + } + } + + if (pvrQwsDisplay.numFlipBuffers > 0) + PVR2DDestroyFlipChain(pvrQwsDisplay.context, pvrQwsDisplay.flipChain); + PVR2DDestroyDeviceContext(pvrQwsDisplay.context); + pvrQwsDisplay.context = 0; + pvrQwsDisplay.flipChain = 0; + pvrQwsDisplay.numFlipBuffers = 0; + pvrQwsDisplay.usePresentBlit = 0; +} + +int pvrQwsDisplayOpen(void) +{ + int screen; + + /* If the display is already open, increase reference count and return */ + if (pvrQwsDisplay.refCount > 0) { + ++(pvrQwsDisplay.refCount); + return 1; + } + + /* Open the framebuffer and map it directly */ + if (!pvrQwsInitFbScreen(0)) { + --(pvrQwsDisplay.refCount); + return 0; + } + + /* Clear the other screens. We will create them if they are referenced */ + for (screen = 1; screen < PVRQWS_MAX_SCREENS; ++screen) + memset(&(pvrQwsDisplay.screens[screen]), 0, sizeof(PvrQwsScreenInfo)); + + /* The display is open and ready */ + ++(pvrQwsDisplay.refCount); + return 1; +} + +void pvrQwsDisplayClose(void) +{ + int screen; + + if (pvrQwsDisplay.refCount == 0) + return; + if (--(pvrQwsDisplay.refCount) > 0) + return; + + /* Prevent pvrQwsDestroyContext from being called for the time being */ + ++pvrQwsDisplay.numDrawables; + + /* Free the screens */ + for (screen = 0; screen < PVRQWS_MAX_SCREENS; ++screen) { + PvrQwsScreenInfo *info = &(pvrQwsDisplay.screens[screen]); + if (info->screenDrawable) + pvrQwsDestroyDrawableForced(info->screenDrawable); + if (info->frameBuffer) + PVR2DMemFree(pvrQwsDisplay.context, info->frameBuffer); + if (info->mapped) + munmap(info->mapped, info->mappedLength); + } + + /* Now it is safe to destroy the PVR2D context */ + --pvrQwsDisplay.numDrawables; + if (pvrQwsDisplay.context) + PVR2DDestroyDeviceContext(pvrQwsDisplay.context); + + memset(&pvrQwsDisplay, 0, sizeof(pvrQwsDisplay)); +} + +int pvrQwsDisplayIsOpen(void) +{ + return (pvrQwsDisplay.refCount > 0); +} + +/* Ensure that a specific screen has been initialized */ +static int pvrQwsEnsureScreen(int screen) +{ + if (screen < 0 || screen >= PVRQWS_MAX_SCREENS) + return 0; + if (!screen) + return 1; + return pvrQwsInitFbScreen(screen); +} + +PvrQwsDrawable *pvrQwsScreenWindow(int screen) +{ + PvrQwsDrawable *drawable; + + if (!pvrQwsEnsureScreen(screen)) + return 0; + + drawable = pvrQwsDisplay.screens[screen].screenDrawable; + if (drawable) + return drawable; + + drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); + if (!drawable) + return 0; + + drawable->type = PvrQwsScreen; + drawable->screen = screen; + drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; + drawable->rect = pvrQwsDisplay.screens[screen].screenRect; + drawable->visibleRects[0] = drawable->rect; + drawable->numVisibleRects = 1; + drawable->isFullScreen = 1; + + if (!pvrQwsAddDrawable()) { + free(drawable); + return 0; + } + + pvrQwsDisplay.screens[screen].screenDrawable = drawable; + + return drawable; +} + +PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect) +{ + PvrQwsDrawable *drawable; + + if (!pvrQwsEnsureScreen(screen)) + return 0; + + drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); + if (!drawable) + return 0; + + drawable->type = PvrQwsWindow; + drawable->winId = winId; + drawable->refCount = 1; + drawable->screen = screen; + drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; + drawable->rect = *rect; + + if (!pvrQwsAddDrawable()) { + free(drawable); + return 0; + } + + drawable->nextWinId = pvrQwsDisplay.firstWinId; + pvrQwsDisplay.firstWinId = drawable; + + return drawable; +} + +PvrQwsDrawable *pvrQwsFetchWindow(long winId) +{ + PvrQwsDrawable *drawable = pvrQwsDisplay.firstWinId; + while (drawable != 0 && drawable->winId != winId) + drawable = drawable->nextWinId; + + if (drawable) + ++(drawable->refCount); + return drawable; +} + +int pvrQwsReleaseWindow(PvrQwsDrawable *drawable) +{ + if (drawable->type == PvrQwsWindow) + return (--(drawable->refCount) <= 0); + else + return 0; +} + +PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen) +{ + PvrQwsDrawable *drawable; + + if (!pvrQwsEnsureScreen(screen)) + return 0; + + drawable = (PvrQwsDrawable *)calloc(1, sizeof(PvrQwsDrawable)); + if (!drawable) + return 0; + + drawable->type = PvrQwsPixmap; + drawable->screen = screen; + drawable->pixelFormat = pvrQwsDisplay.screens[screen].pixelFormat; + drawable->rect.x = 0; + drawable->rect.y = 0; + drawable->rect.width = width; + drawable->rect.height = height; + + if (!pvrQwsAddDrawable()) { + free(drawable); + return 0; + } + + return drawable; +} + +static void pvrQwsDestroyDrawableForced(PvrQwsDrawable *drawable) +{ + /* Remove the drawable from the display's winId list */ + PvrQwsDrawable *current = pvrQwsDisplay.firstWinId; + PvrQwsDrawable *prev = 0; + while (current != 0 && current != drawable) { + prev = current; + current = current->nextWinId; + } + if (current != 0) { + if (prev) + prev->nextWinId = current->nextWinId; + else + pvrQwsDisplay.firstWinId = current->nextWinId; + } + + pvrQwsFreeBuffers(drawable); + free(drawable); + + --pvrQwsDisplay.numDrawables; + if (pvrQwsDisplay.numDrawables == 0) + pvrQwsDestroyContext(); +} + +void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable) +{ + if (drawable && drawable->type != PvrQwsScreen) + pvrQwsDestroyDrawableForced(drawable); +} + +PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable) +{ + return drawable->type; +} + +void pvrQwsSetVisibleRegion + (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects) +{ + int index, indexOut; + PvrQwsRect *rect; + PvrQwsRect *screenRect; + + /* Visible regions don't make sense for pixmaps */ + if (drawable->type == PvrQwsPixmap) + return; + + /* Restrict the number of rectangles to prevent buffer overflow */ + if (numRects > PVRQWS_MAX_VISIBLE_RECTS) + numRects = PVRQWS_MAX_VISIBLE_RECTS; + if (numRects > 0) + memcpy(drawable->visibleRects, rects, numRects * sizeof(PvrQwsRect)); + + /* Convert the rectangles into screen-relative co-ordinates and + then clamp them to the screen boundaries. If any of the + clamped rectangles are empty, remove them from the list */ + screenRect = &(pvrQwsDisplay.screens[drawable->screen].screenRect); + indexOut = 0; + for (index = 0, rect = drawable->visibleRects; index < numRects; ++index, ++rect) { + if (rect->x < 0) { + rect->width += rect->x; + rect->x = 0; + if (rect->width < 0) + rect->width = 0; + } else if (rect->x >= screenRect->width) { + rect->x = screenRect->width; + rect->width = 0; + } + if ((rect->x + rect->width) > screenRect->width) { + rect->width = screenRect->width - rect->x; + } + if (rect->y < 0) { + rect->height += rect->y; + rect->y = 0; + if (rect->height < 0) + rect->height = 0; + } else if (rect->y >= screenRect->height) { + rect->y = screenRect->height; + rect->height = 0; + } + if ((rect->y + rect->height) > screenRect->height) { + rect->height = screenRect->height - rect->y; + } + if (rect->width > 0 && rect->height > 0) { + if (index != indexOut) + drawable->visibleRects[indexOut] = *rect; + ++indexOut; + } + } + drawable->numVisibleRects = indexOut; +} + +void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable) +{ + if (drawable->type != PvrQwsPixmap) + drawable->numVisibleRects = 0; +} + +void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect) +{ + /* We can only change the geometry of window drawables */ + if (drawable->type != PvrQwsWindow) + return; + + /* If the position has changed, then clear the visible region */ + if (drawable->rect.x != rect->x || drawable->rect.y != rect->y) { + drawable->rect.x = rect->x; + drawable->rect.y = rect->y; + drawable->numVisibleRects = 0; + } + + /* If the size has changed, then clear the visible region and + invalidate the drawable's buffers. Invalidating the buffers + will force EGL to recreate the drawable, which will then + allocate new buffers for the new size */ + if (drawable->rect.width != rect->width || + drawable->rect.height != rect->height) { + drawable->rect.width = rect->width; + drawable->rect.height = rect->height; + drawable->numVisibleRects = 0; + pvrQwsInvalidateBuffers(drawable); + } +} + +void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect) +{ + *rect = drawable->rect; +} + +int pvrQwsGetStride(PvrQwsDrawable *drawable) +{ + if (drawable->backBuffersValid) + return drawable->strideBytes; + else + return 0; +} + +PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable) +{ + return (PvrQwsPixelFormat)(drawable->pixelFormat); +} + +void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable) +{ + if (drawable->backBuffersValid) + return drawable->backBuffers[drawable->currentBackBuffer]->pBase; + else + return 0; +} + +int pvrQwsAllocBuffers(PvrQwsDrawable *drawable) +{ + int index; + int numBuffers = PVRQWS_MAX_BACK_BUFFERS; + if (drawable->type == PvrQwsPixmap) + numBuffers = 1; + if (drawable->backBuffers[0]) { + if (drawable->backBuffersValid) + return 1; + if (!drawable->usingFlipBuffers) { + for (index = 0; index < numBuffers; ++index) + PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); + } + } + drawable->stridePixels = (drawable->rect.width + 7) & ~7; + drawable->strideBytes = + drawable->stridePixels * + pvrQwsDisplay.screens[drawable->screen].bytesPerPixel; + drawable->usingFlipBuffers = + (pvrQwsDisplay.numFlipBuffers > 0 && drawable->isFullScreen); + if (drawable->usingFlipBuffers) { + if (numBuffers > (int)(pvrQwsDisplay.numFlipBuffers)) + numBuffers = pvrQwsDisplay.numFlipBuffers; + for (index = 0; index < numBuffers; ++index) + drawable->backBuffers[index] = pvrQwsDisplay.flipBuffers[index]; + } else { + for (index = 0; index < numBuffers; ++index) { + if (PVR2DMemAlloc(pvrQwsDisplay.context, + drawable->strideBytes * drawable->rect.height, + 128, 0, + &(drawable->backBuffers[index])) != PVR2D_OK) { + while (--index >= 0) + PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); + memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers)); + drawable->backBuffersValid = 0; + return 0; + } + } + } + for (index = numBuffers; index < PVRQWS_MAX_BACK_BUFFERS; ++index) { + drawable->backBuffers[index] = drawable->backBuffers[0]; + } + drawable->backBuffersValid = 1; + drawable->currentBackBuffer = 0; + return 1; +} + +void pvrQwsFreeBuffers(PvrQwsDrawable *drawable) +{ + int index; + int numBuffers = PVRQWS_MAX_BACK_BUFFERS; + if (drawable->type == PvrQwsPixmap) + numBuffers = 1; + if (!drawable->usingFlipBuffers) { + for (index = 0; index < numBuffers; ++index) { + if (drawable->backBuffers[index]) + PVR2DMemFree(pvrQwsDisplay.context, drawable->backBuffers[index]); + } + } + memset(drawable->backBuffers, 0, sizeof(drawable->backBuffers)); + drawable->backBuffersValid = 0; + drawable->usingFlipBuffers = 0; +} + +void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable) +{ + drawable->backBuffersValid = 0; +} + +int pvrQwsGetBuffers + (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render) +{ + if (!drawable->backBuffersValid) + return 0; + *render = drawable->backBuffers[drawable->currentBackBuffer]; + *source = drawable->backBuffers + [(drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) % + PVRQWS_MAX_BACK_BUFFERS]; + return 1; +} + +int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly) +{ + PVR2DMEMINFO *buffer; + PvrQwsRect *rect; + int index; + + /* Bail out if the back buffers have been invalidated */ + if (!drawable->backBuffersValid) + return 0; + + /* If there is a swap function, then use that instead */ + if (drawable->swapFunction) { + (*(drawable->swapFunction))(drawable, drawable->userData, repaintOnly); + if (!repaintOnly) { + drawable->currentBackBuffer + = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS; + } + return 1; + } + + /* Iterate through the visible rectangles and blit them to the screen */ + if (!repaintOnly) { + index = drawable->currentBackBuffer; + } else { + index = (drawable->currentBackBuffer + PVRQWS_MAX_BACK_BUFFERS - 1) + % PVRQWS_MAX_BACK_BUFFERS; + } + buffer = drawable->backBuffers[index]; + rect = drawable->visibleRects; + if (drawable->usingFlipBuffers) { + PVR2DPresentFlip(pvrQwsDisplay.context, pvrQwsDisplay.flipChain, buffer, 0); + } else if (pvrQwsDisplay.usePresentBlit && drawable->numVisibleRects > 0) { + PVR2DRECT pvrRects[PVRQWS_MAX_VISIBLE_RECTS]; + for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) { + pvrRects[index].left = rect->x; + pvrRects[index].top = rect->y; + pvrRects[index].right = rect->x + rect->width; + pvrRects[index].bottom = rect->y + rect->height; + } + for (index = 0; index < drawable->numVisibleRects; index += 4) { + int numClip = drawable->numVisibleRects - index; + if (numClip > 4) /* No more than 4 clip rects at a time */ + numClip = 4; + PVR2DSetPresentBltProperties + (pvrQwsDisplay.context, + PVR2D_PRESENT_PROPERTY_SRCSTRIDE | + PVR2D_PRESENT_PROPERTY_DSTSIZE | + PVR2D_PRESENT_PROPERTY_DSTPOS | + PVR2D_PRESENT_PROPERTY_CLIPRECTS, + drawable->strideBytes, + drawable->rect.width, drawable->rect.height, + drawable->rect.x, drawable->rect.y, + numClip, pvrRects + index, 0); + PVR2DPresentBlt(pvrQwsDisplay.context, buffer, 0); + } + PVR2DQueryBlitsComplete(pvrQwsDisplay.context, buffer, 1); + } else { + /* TODO: use PVR2DBltClipped for faster transfers of clipped windows */ + PVR2DBLTINFO blit; + for (index = 0; index < drawable->numVisibleRects; ++index, ++rect) { + memset(&blit, 0, sizeof(blit)); + + blit.CopyCode = PVR2DROPcopy; + blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL; + + blit.pSrcMemInfo = buffer; + blit.SrcStride = drawable->strideBytes; + blit.SrcX = rect->x - drawable->rect.x; + blit.SrcY = rect->y - drawable->rect.y; + blit.SizeX = rect->width; + blit.SizeY = rect->height; + blit.SrcFormat = drawable->pixelFormat; + + blit.pDstMemInfo = pvrQwsDisplay.screens[drawable->screen].frameBuffer; + blit.DstStride = pvrQwsDisplay.screens[drawable->screen].screenStride; + blit.DstX = rect->x; + blit.DstY = rect->y; + blit.DSizeX = rect->width; + blit.DSizeY = rect->height; + blit.DstFormat = pvrQwsDisplay.screens[drawable->screen].pixelFormat; + + PVR2DBlt(pvrQwsDisplay.context, &blit); + } + } + + /* Swap the buffers */ + if (!repaintOnly) { + drawable->currentBackBuffer + = (drawable->currentBackBuffer + 1) % PVRQWS_MAX_BACK_BUFFERS; + } + return 1; +} + +void pvrQwsSetSwapFunction + (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData) +{ + drawable->swapFunction = func; + drawable->userData = userData; +} + +unsigned long pvrQwsGetMemoryId(PvrQwsDrawable *drawable) +{ + unsigned long addr; + unsigned long start; + unsigned long end; + unsigned long off; + unsigned long offset; + FILE *file; + char buffer[BUFSIZ]; + char flags[16]; + + if (!drawable->backBuffersValid) + return 0; + addr = (unsigned long) + (drawable->backBuffers[drawable->currentBackBuffer]->pBase); + + /* Search /proc/self/maps for the memory region that contains "addr". + The file offset for that memory region is the identifier we need */ + file = fopen("/proc/self/maps", "r"); + if (!file) { + perror("/proc/self/maps"); + return 0; + } + offset = 0; + while (fgets(buffer, sizeof(buffer), file)) { + if (sscanf(buffer, "%lx-%lx %s %lx", + &start, &end, flags, &off) < 4) + continue; + if (start <= addr && addr < end) { + offset = off; + break; + } + } + fclose(file); + return offset; +} + +void *pvrQwsMapMemory(unsigned long id, int size) +{ + void *addr; + int fd = open("/dev/pvrsrv", O_RDWR, 0); + if (fd < 0) { + perror("/dev/pvrsrv"); + return 0; + } + addr = mmap(0, (size_t)size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, (off_t)id); + if (addr == (void *)(-1)) { + perror("mmap pvr memory region"); + addr = 0; + } + close(fd); + return addr; +} + +void pvrQwsUnmapMemory(void *addr, int size) +{ + munmap(addr, size); +} diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h new file mode 100644 index 0000000..16872a9 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVRQWSDRAWABLE_H +#define PVRQWSDRAWABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int x, y, width, height; +} PvrQwsRect; + +typedef enum +{ + PvrQwsScreen, + PvrQwsWindow, + PvrQwsPixmap + +} PvrQwsDrawableType; + +typedef enum +{ + PvrQws_1BPP = 0, + PvrQws_RGB565, + PvrQws_ARGB4444, + PvrQws_RGB888, + PvrQws_ARGB8888, + PvrQws_VGAEMU + +} PvrQwsPixelFormat; + +typedef struct _PvrQwsDrawable PvrQwsDrawable; + +typedef void (*PvrQwsSwapFunction) + (PvrQwsDrawable *drawable, void *userData, int repaintOnly); + +/* Open the display and prepare for window operations. The display + can be opened multiple times and each time is reference counted. + The display will be finally closed when the same number of + calls to pvrQwsDisplayClose() have been encountered */ +int pvrQwsDisplayOpen(void); + +/* Close the display */ +void pvrQwsDisplayClose(void); + +/* Determine if the display is already open */ +int pvrQwsDisplayIsOpen(void); + +/* Create a window that represents a particular framebuffer screen. + Initially the visible region will be the whole screen. If the screen + window has already been created, then will return the same value */ +PvrQwsDrawable *pvrQwsScreenWindow(int screen); + +/* Create a top-level window on a particular framebuffer screen. + Initially the window will not have a visible region */ +PvrQwsDrawable *pvrQwsCreateWindow(int screen, long winId, const PvrQwsRect *rect); + +/* Fetch an existing window for a window id and increase its refcount */ +PvrQwsDrawable *pvrQwsFetchWindow(long winId); + +/* Release the refcount on a window. Returns 1 if refcount is zero */ +int pvrQwsReleaseWindow(PvrQwsDrawable *drawable); + +/* Create an off-screen pixmap */ +PvrQwsDrawable *pvrQwsCreatePixmap(int width, int height, int screen); + +/* Destroy a previously-created drawable. Will not destroy screens. */ +void pvrQwsDestroyDrawable(PvrQwsDrawable *drawable); + +/* Get a drawable's type */ +PvrQwsDrawableType pvrQwsGetDrawableType(PvrQwsDrawable *drawable); + +/* Sets the visible region for a window or screen drawable. Pixels within + the specified rectangles will be copied to the framebuffer when the window + or screen is swapped. The rectangles should be in global co-ordinates */ +void pvrQwsSetVisibleRegion + (PvrQwsDrawable *drawable, const PvrQwsRect *rects, int numRects); + +/* Clear the visible region for a window or screen drawable, + effectively removing it from the screen */ +void pvrQwsClearVisibleRegion(PvrQwsDrawable *drawable); + +/* Set the geometry for a drawable. This can only be used on windows */ +void pvrQwsSetGeometry(PvrQwsDrawable *drawable, const PvrQwsRect *rect); + +/* Get the current geometry for a drawable */ +void pvrQwsGetGeometry(PvrQwsDrawable *drawable, PvrQwsRect *rect); + +/* Get the line stride for a drawable. Returns zero if the buffers + are not allocated or have been invalidated */ +int pvrQwsGetStride(PvrQwsDrawable *drawable); + +/* Get the pixel format for a drawable */ +PvrQwsPixelFormat pvrQwsGetPixelFormat(PvrQwsDrawable *drawable); + +/* Get a pointer to the beginning of a drawable's current render buffer. + Returns null if the buffers are not allocated or have been invalidated */ +void *pvrQwsGetRenderBuffer(PvrQwsDrawable *drawable); + +/* Allocate the buffers associated with a drawable. We allocate one buffer + for pixmaps, and several for windows and screens */ +int pvrQwsAllocBuffers(PvrQwsDrawable *drawable); + +/* Free the buffers associated with a drawable */ +void pvrQwsFreeBuffers(PvrQwsDrawable *drawable); + +/* Invalidate the buffers associated with a drawable. The buffers will + still be allocated but the next attempt to swap the buffers will fail */ +void pvrQwsInvalidateBuffers(PvrQwsDrawable *drawable); + +/* Swap the back buffers for a window or screen and copy to the framebuffer */ +int pvrQwsSwapBuffers(PvrQwsDrawable *drawable, int repaintOnly); + +/* Set the swap function for a drawable. When pvrQwsSwapBuffers() + is called on the drawable, the supplied function will be called + instead of copying the drawable contents to the screen. This allows + higher-level compositors to know when a drawable has changed. + The swap function can be set to null to return to normal processing */ +void pvrQwsSetSwapFunction + (PvrQwsDrawable *drawable, PvrQwsSwapFunction func, void *userData); + +/* Get a memory identifier for the indicated drawable's buffer. + The identifier can be passed to another process and then + passed to pvrQwsMapMemory() to map the drawable's buffer into + the other process's address space. Returns zero if the + memory identifier could not be determined. This should only + be used for pixmap drawables */ +unsigned long pvrQwsGetMemoryId(PvrQwsDrawable *drawable); + +/* Map the memory buffer of a foreign application's drawable, as + indicated by "id" and "size". Returns null if the map failed */ +void *pvrQwsMapMemory(unsigned long id, int size); + +/* Unmap the memory obtained from pvrQwsMapMemory() */ +void pvrQwsUnmapMemory(void *addr, int size); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h new file mode 100644 index 0000000..d6c42a6 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVRQWSDRAWABLE_P_H +#define PVRQWSDRAWABLE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// reasons. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include <pvr2d.h> +#include "pvrqwsdrawable.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PVRQWS_MAX_VISIBLE_RECTS 32 +#define PVRQWS_MAX_SCREENS 1 +#define PVRQWS_MAX_BACK_BUFFERS 2 +#define PVRQWS_MAX_FLIP_BUFFERS 2 + +typedef struct { + + PvrQwsRect screenRect; + int screenStride; + PVR2DFORMAT pixelFormat; + int bytesPerPixel; + PVR2DMEMINFO *frameBuffer; + PvrQwsDrawable *screenDrawable; + void *mapped; + int mappedLength; + unsigned long screenStart; + +} PvrQwsScreenInfo; + +typedef struct { + + int refCount; + PvrQwsScreenInfo screens[PVRQWS_MAX_SCREENS]; + PVR2DCONTEXTHANDLE context; + int numDrawables; + unsigned long numFlipBuffers; + PVR2DFLIPCHAINHANDLE flipChain; + PVR2DMEMINFO *flipBuffers[PVRQWS_MAX_FLIP_BUFFERS]; + int usePresentBlit; + PvrQwsDrawable *firstWinId; + +} PvrQwsDisplay; + +extern PvrQwsDisplay pvrQwsDisplay; + +struct _PvrQwsDrawable +{ + PvrQwsDrawableType type; + long winId; + int refCount; + PvrQwsRect rect; + int screen; + PVR2DFORMAT pixelFormat; + PvrQwsRect visibleRects[PVRQWS_MAX_VISIBLE_RECTS]; + int numVisibleRects; + PVR2DMEMINFO *backBuffers[PVRQWS_MAX_BACK_BUFFERS]; + int currentBackBuffer; + int backBuffersValid; + int usingFlipBuffers; + int isFullScreen; + int strideBytes; + int stridePixels; + PvrQwsSwapFunction swapFunction; + void *userData; + PvrQwsDrawable *nextWinId; + +}; + +/* Get the current source and render buffers for a drawable */ +int pvrQwsGetBuffers + (PvrQwsDrawable *drawable, PVR2DMEMINFO **source, PVR2DMEMINFO **render); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c new file mode 100644 index 0000000..f46448e --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <GLES/egltypes.h> +#include <wsegl.h> +#include <pvr2d.h> +#include <string.h> +#include <sys/mman.h> +#include "pvrqwsdrawable_p.h" + +#define WSEGL_UNUSED(x) (void)x; + +/* Capability information for the display */ +static WSEGLCaps const wseglDisplayCaps[] = { + {WSEGL_CAP_WINDOWS_USE_MBX_SYNC, 1}, + {WSEGL_CAP_PIXMAPS_USE_MBX_SYNC, 1}, + {WSEGL_NO_CAPS, 0} +}; + +/* Configuration information for the display */ +static WSEGLConfig wseglDisplayConfigs[] = { + {WSEGL_DRAWABLE_WINDOW, WSEGL_PIXELFORMAT_565, WSEGL_FALSE, + 0, 0, 0, WSEGL_OPAQUE, 0}, + {WSEGL_DRAWABLE_PIXMAP, WSEGL_PIXELFORMAT_565, WSEGL_FALSE, + 0, 0, 0, WSEGL_OPAQUE, 0}, + {WSEGL_NO_DRAWABLE, 0, 0, 0, 0, 0, 0, 0} +}; + +/* Determine if nativeDisplay is a valid display handle */ +static WSEGLError wseglIsDisplayValid(NativeDisplayType nativeDisplay) +{ + /* We only have the default display in this system */ + if (nativeDisplay == WSEGL_DEFAULT_DISPLAY) + return WSEGL_SUCCESS; + else + return WSEGL_BAD_NATIVE_DISPLAY; +} + +/* Initialize a native display for use with WSEGL */ +static WSEGLError wseglInitializeDisplay + (NativeDisplayType nativeDisplay, WSEGLDisplayHandle *display, + const WSEGLCaps **caps, WSEGLConfig **configs) +{ + WSEGLPixelFormat pixelFormat; + + /* Bail out if the native display is incorrect */ + if (nativeDisplay != WSEGL_DEFAULT_DISPLAY) + return WSEGL_CANNOT_INITIALISE; + + /* Open the PVR/QWS display, which will initialize the framebuffer */ + if (!pvrQwsDisplayOpen()) + return WSEGL_CANNOT_INITIALISE; + + /* Convert the PVR2D pixel format into a WSEGL pixel format */ + switch (pvrQwsDisplay.screens[0].pixelFormat) { + case PVR2D_RGB565: + pixelFormat = WSEGL_PIXELFORMAT_565; + break; + + case PVR2D_ARGB4444: + pixelFormat = WSEGL_PIXELFORMAT_4444; + break; + + case PVR2D_ARGB8888: + pixelFormat = WSEGL_PIXELFORMAT_8888; + break; + + default: + pvrQwsDisplayClose(); + return WSEGL_CANNOT_INITIALISE; + } + wseglDisplayConfigs[0].ePixelFormat = pixelFormat; + wseglDisplayConfigs[1].ePixelFormat = pixelFormat; + + /* The display has been initialized */ + *display = (WSEGLDisplayHandle)&pvrQwsDisplay; + *caps = wseglDisplayCaps; + *configs = wseglDisplayConfigs; + return WSEGL_SUCCESS; +} + +/* Close the WSEGL display */ +static WSEGLError wseglCloseDisplay(WSEGLDisplayHandle display) +{ + if (display == (WSEGLDisplayHandle)&pvrQwsDisplay) + pvrQwsDisplayClose(); + return WSEGL_SUCCESS; +} + +/* Create the WSEGL drawable version of a native window */ +static WSEGLError wseglCreateWindowDrawable + (WSEGLDisplayHandle display, WSEGLConfig *config, + WSEGLDrawableHandle *drawable, NativeWindowType nativeWindow, + WSEGLRotationAngle *rotationAngle) +{ + PvrQwsDrawable *draw; + + WSEGL_UNUSED(display); + WSEGL_UNUSED(config); + + /* Check for special handles that indicate framebuffer screens */ + if (nativeWindow >= (NativeWindowType)0 && + nativeWindow < (NativeWindowType)PVRQWS_MAX_SCREENS) { + PvrQwsDrawable *screen = pvrQwsScreenWindow((int)nativeWindow); + if (!screen) + return WSEGL_OUT_OF_MEMORY; + *drawable = (WSEGLDrawableHandle)screen; + if (!pvrQwsAllocBuffers(screen)) + return WSEGL_OUT_OF_MEMORY; + *rotationAngle = WSEGL_ROTATE_0; + return WSEGL_SUCCESS; + } + + /* The native window is the winId - fetch the underlying drawable */ + draw = pvrQwsFetchWindow((long)nativeWindow); + if (!draw) + return WSEGL_BAD_DRAWABLE; + + /* The drawable is ready to go */ + *drawable = (WSEGLDrawableHandle)draw; + *rotationAngle = WSEGL_ROTATE_0; + if (!pvrQwsAllocBuffers(draw)) + return WSEGL_OUT_OF_MEMORY; + return WSEGL_SUCCESS; +} + +/* Create the WSEGL drawable version of a native pixmap */ +static WSEGLError wseglCreatePixmapDrawable + (WSEGLDisplayHandle display, WSEGLConfig *config, + WSEGLDrawableHandle *drawable, NativePixmapType nativePixmap, + WSEGLRotationAngle *rotationAngle) +{ + WSEGL_UNUSED(display); + WSEGL_UNUSED(config); + if (!nativePixmap) + return WSEGL_BAD_NATIVE_PIXMAP; + if (!pvrQwsAllocBuffers((PvrQwsDrawable *)nativePixmap)) + return WSEGL_OUT_OF_MEMORY; + *drawable = (WSEGLDrawableHandle)nativePixmap; + *rotationAngle = WSEGL_ROTATE_0; + return WSEGL_SUCCESS; +} + +/* Delete a specific drawable */ +static WSEGLError wseglDeleteDrawable(WSEGLDrawableHandle _drawable) +{ + PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; + if (!drawable || drawable->type == PvrQwsScreen) + return WSEGL_SUCCESS; + pvrQwsFreeBuffers(drawable); + if (pvrQwsReleaseWindow(drawable)) + pvrQwsDestroyDrawable(drawable); + return WSEGL_SUCCESS; +} + +/* Swap the contents of a drawable to the screen */ +static WSEGLError wseglSwapDrawable + (WSEGLDrawableHandle _drawable, unsigned long data) +{ + WSEGL_UNUSED(data); + PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; + if (drawable->type != PvrQwsPixmap && !pvrQwsSwapBuffers(drawable, 0)) + return WSEGL_BAD_DRAWABLE; + else + return WSEGL_SUCCESS; +} + +/* Set the swap interval of a window drawable */ +static WSEGLError wseglSwapControlInterval + (WSEGLDrawableHandle drawable, unsigned long interval) +{ + WSEGL_UNUSED(drawable); + if (pvrQwsDisplay.flipChain) { + PVR2DSetPresentFlipProperties + (pvrQwsDisplay.context, pvrQwsDisplay.flipChain, + PVR2D_PRESENT_PROPERTY_INTERVAL, 0, 0, 0, NULL, interval); + } + return WSEGL_SUCCESS; +} + +/* Flush native rendering requests on a drawable */ +static WSEGLError wseglWaitNative + (WSEGLDrawableHandle drawable, unsigned long engine) +{ + WSEGL_UNUSED(drawable); + if (engine == WSEGL_DEFAULT_NATIVE_ENGINE) + return WSEGL_SUCCESS; + else + return WSEGL_BAD_NATIVE_ENGINE; +} + +/* Copy color data from a drawable to a native pixmap */ +static WSEGLError wseglCopyFromDrawable + (WSEGLDrawableHandle _drawable, NativePixmapType nativePixmap) +{ + PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; + PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap; + PVR2DBLTINFO blit; + + if (!drawable || !drawable->backBuffersValid) + return WSEGL_BAD_NATIVE_WINDOW; + if (!pixmap || !pixmap->backBuffersValid) + return WSEGL_BAD_NATIVE_PIXMAP; + + memset(&blit, 0, sizeof(blit)); + + blit.CopyCode = PVR2DROPcopy; + blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL; + + blit.pSrcMemInfo = drawable->backBuffers[drawable->currentBackBuffer]; + blit.SrcStride = drawable->strideBytes; + blit.SrcX = 0; + blit.SrcY = 0; + blit.SizeX = drawable->rect.width; + blit.SizeY = drawable->rect.height; + blit.SrcFormat = drawable->pixelFormat; + + blit.pDstMemInfo = pixmap->backBuffers[pixmap->currentBackBuffer]; + blit.DstStride = pixmap->strideBytes; + blit.DstX = 0; + blit.DstY = 0; + blit.DSizeX = pixmap->rect.width; + blit.DSizeY = pixmap->rect.height; + blit.DstFormat = pixmap->pixelFormat; + + PVR2DBlt(pvrQwsDisplay.context, &blit); + PVR2DQueryBlitsComplete + (pvrQwsDisplay.context, pixmap->backBuffers[pixmap->currentBackBuffer], 1); + + return WSEGL_SUCCESS; +} + +/* Copy color data from a PBuffer to a native pixmap */ +static WSEGLError wseglCopyFromPBuffer + (void *address, unsigned long width, unsigned long height, + unsigned long stride, WSEGLPixelFormat format, + NativePixmapType nativePixmap) +{ + PvrQwsDrawable *pixmap = (PvrQwsDrawable *)nativePixmap; + PVR2DFORMAT pixelFormat; + + if (!pixmap) + return WSEGL_BAD_NATIVE_PIXMAP; + + /* We can only copy under certain conditions */ + switch (format) { + case WSEGL_PIXELFORMAT_565: + pixelFormat = PVR2D_RGB565; break; + case WSEGL_PIXELFORMAT_4444: + pixelFormat = PVR2D_ARGB4444; break; + case WSEGL_PIXELFORMAT_8888: + pixelFormat = PVR2D_ARGB8888; break; + default: + return WSEGL_BAD_CONFIG; + } + if (width > (unsigned long)(pixmap->rect.width) || + height > (unsigned long)(pixmap->rect.height) || + pixelFormat != pixmap->pixelFormat) { + return WSEGL_BAD_CONFIG; + } + + /* We'd like to use PVR2DBlt to do this, but there is no easy way + to map the virtual "address" into physical space to be able + to use the hardware assist. Use memcpy to do the work instead. + Note: PBuffer's are upside down, so we copy from the bottom up */ + char *srcaddr = (char *)address; + char *dstaddr = (char *)(pixmap->backBuffers[pixmap->currentBackBuffer]->pBase); + int dststride = pixmap->strideBytes; + int srcwidth = ((int)width) * pvrQwsDisplay.screens[0].bytesPerPixel; + srcaddr += height * stride; + while (height > 0) { + srcaddr -= (int)stride; + memcpy(dstaddr, srcaddr, srcwidth); + dstaddr += dststride; + --height; + } + return WSEGL_SUCCESS; +} + +/* Return the parameters of a drawable that are needed by the EGL layer */ +static WSEGLError wseglGetDrawableParameters + (WSEGLDrawableHandle _drawable, WSEGLDrawableParams *sourceParams, + WSEGLDrawableParams *renderParams) +{ + PvrQwsDrawable *drawable = (PvrQwsDrawable *)_drawable; + PVR2DMEMINFO *source, *render; + WSEGLPixelFormat pixelFormat; + + if (!pvrQwsGetBuffers(drawable, &source, &render)) + return WSEGL_BAD_DRAWABLE; + + switch (drawable->pixelFormat) { + case PVR2D_RGB565: + default: + pixelFormat = WSEGL_PIXELFORMAT_565; + break; + + case PVR2D_ARGB4444: + pixelFormat = WSEGL_PIXELFORMAT_4444; + break; + + case PVR2D_ARGB8888: + pixelFormat = WSEGL_PIXELFORMAT_8888; + break; + } + + sourceParams->ui32Width = drawable->rect.width; + sourceParams->ui32Height = drawable->rect.height; + sourceParams->ui32Stride = drawable->stridePixels; + sourceParams->ePixelFormat = pixelFormat; + sourceParams->pvLinearAddress = source->pBase; + sourceParams->ui32HWAddress = source->ui32DevAddr; + sourceParams->hPrivateData = source->hPrivateData; + + renderParams->ui32Width = drawable->rect.width; + renderParams->ui32Height = drawable->rect.height; + renderParams->ui32Stride = drawable->stridePixels; + renderParams->ePixelFormat = pixelFormat; + renderParams->pvLinearAddress = render->pBase; + renderParams->ui32HWAddress = render->ui32DevAddr; + renderParams->hPrivateData = render->hPrivateData; + + return WSEGL_SUCCESS; +} + +static WSEGL_FunctionTable const wseglFunctions = { + WSEGL_VERSION, + wseglIsDisplayValid, + wseglInitializeDisplay, + wseglCloseDisplay, + wseglCreateWindowDrawable, + wseglCreatePixmapDrawable, + wseglDeleteDrawable, + wseglSwapDrawable, + wseglSwapControlInterval, + wseglWaitNative, + wseglCopyFromDrawable, + wseglCopyFromPBuffer, + wseglGetDrawableParameters +}; + +/* Return the table of WSEGL functions to the EGL implementation */ +const WSEGL_FunctionTable *WSEGL_GetFunctionTablePointer(void) +{ + return &wseglFunctions; +} diff --git a/src/plugins/gfxdrivers/powervr/README b/src/plugins/gfxdrivers/powervr/README new file mode 100644 index 0000000..b830066 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/README @@ -0,0 +1,56 @@ +PowerVR QScreen Driver +====================== + +This QScreen plugin driver allows the QtOpenGl module to integrate with PowerVR +hardware from Imagination Technologies. Using this plugin, applications may use +QGLWidget & QGLPixelBuffer with OpenGL ES. The integration with PowerVR drivers +is built as two libraries: The actual QScreen plugin used by Qt (in the +pvreglscreen directory) and a WSEGL plugin for the PowerVR drivers (in the +QWSWSEGL directory). + +The PowerVR drivers provide the WSEGL plugin API to allow window systems such as +QWS to integrate correctly. In order to use the integration, the WSEGL plugin +(libpvrQWSWSEGL.so, usually installed into the Qt library directory) must be in +the LD library path. The PowerVR driver also needs to be told which WSEGL library +to use. This is done by creating/modifying /etc/powervr.ini: + +[default] +WindowSystem=libpvrQWSWSEGL.so + +Note: It is important that the /etc/powervr.ini file not contain ^M (Ctrl-M) DOS +end of line markers at the end of its lines. If ^M markers are present, then the +libpvrQWSWSEGL.so driver will not be loaded and the default null Linux driver +will be loaded silently instead. Make sure that the end of line markers are +strictly Unix-style markers. + + +*************************************************************************** +* IMPORTANT: To build the QScreen plugin and the WSEGL library it depends * +* on, the pvr2d.h, wsegl.h headers for your platform are required. These * +* can be obtained either through your platform provider or directly from * +* Imagination Technologies. * +*************************************************************************** + + +When you start a Qt/Embedded application, you should modify the QWS_DISPLAY +environment variable to use the "powervr" driver instead of "LinuxFb". For +example, if your original QWS_DISPLAY variable was: + + LinuxFb:mmWidth40:mmHeight54:0 + +then it should be changed to: + + powervr:mmWidth40:mmHeight54:0 + +To test the OpenGL ES integration, you can use the hellogl_es example and run it +on the device with: + + hellogl_es -qws + + +Know Issues: + * A QGLWidget may not have window decorations if it is a top-level window. + * On some platforms, starting a QWS application after the system has been up + for a long time may cause the driver to fail. This is due to fragmentation + of main memory prevening older PowerVR drivers from allocating a contiguous + region of phyical RAM for the GL surface. diff --git a/src/plugins/gfxdrivers/powervr/powervr.pro b/src/plugins/gfxdrivers/powervr/powervr.pro new file mode 100644 index 0000000..f31ad04 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/powervr.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = QWSWSEGL pvreglscreen +CONFIG += ordered diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp new file mode 100644 index 0000000..3a94851 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglscreen.h" +#include "pvreglwindowsurface.h" +#include "pvrqwsdrawable_p.h" +#include <QRegExp> +#include <qwindowsystem_qws.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/kd.h> +#include <fcntl.h> +#include <unistd.h> + +PvrEglScreen::PvrEglScreen(int displayId) + : QGLScreen(displayId) +{ + setOptions(NativeWindows); + setSupportsBlitInClients(true); + setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId)); + fd = -1; + ttyfd = -1; + doGraphicsMode = true; + oldKdMode = KD_TEXT; + if (QWSServer::instance()) + holder = new PvrEglSurfaceHolder(); + else + holder = 0; +} + +PvrEglScreen::~PvrEglScreen() +{ + if (fd >= 0) + ::close(fd); + delete holder; +} + +bool PvrEglScreen::initDevice() +{ + openTty(); + return true; +} + +bool PvrEglScreen::connect(const QString &displaySpec) +{ + if (!pvrQwsDisplayOpen()) + return false; + + // Initialize the QScreen properties. + data = (uchar *)(pvrQwsDisplay.screens[0].mapped); + w = pvrQwsDisplay.screens[0].screenRect.width; + h = pvrQwsDisplay.screens[0].screenRect.height; + lstep = pvrQwsDisplay.screens[0].screenStride; + dw = w; + dh = h; + size = h * lstep; + mapsize = size; + switch (pvrQwsDisplay.screens[0].pixelFormat) { + case PVR2D_RGB565: + d = 16; + setPixelFormat(QImage::Format_RGB16); + break; + case PVR2D_ARGB4444: + d = 16; + setPixelFormat(QImage::Format_ARGB4444_Premultiplied); + break; + case PVR2D_ARGB8888: + d = 32; + setPixelFormat(QImage::Format_ARGB32); + break; + default: + pvrQwsDisplayClose(); + qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat)); + return false; + } + + // Handle display physical size spec. + QStringList displayArgs = displaySpec.split(QLatin1Char(':')); + QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); + int dimIdxW = displayArgs.indexOf(mmWidthRx); + QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)")); + int dimIdxH = displayArgs.indexOf(mmHeightRx); + if (dimIdxW >= 0) { + mmWidthRx.exactMatch(displayArgs.at(dimIdxW)); + physWidth = mmWidthRx.cap(1).toInt(); + if (dimIdxH < 0) + physHeight = dh*physWidth/dw; + } + if (dimIdxH >= 0) { + mmHeightRx.exactMatch(displayArgs.at(dimIdxH)); + physHeight = mmHeightRx.cap(1).toInt(); + if (dimIdxW < 0) + physWidth = dw*physHeight/dh; + } + if (dimIdxW < 0 && dimIdxH < 0) { + const int dpi = 72; + physWidth = qRound(dw * 25.4 / dpi); + physHeight = qRound(dh * 25.4 / dpi); + } + + // Find the name of the tty device to use. + QRegExp ttyRegExp(QLatin1String("tty=(.*)")); + if (displayArgs.indexOf(ttyRegExp) != -1) + ttyDevice = ttyRegExp.cap(1); + if (displayArgs.contains(QLatin1String("nographicsmodeswitch"))) + doGraphicsMode = false; + + // The screen is ready. + return true; +} + +void PvrEglScreen::disconnect() +{ + pvrQwsDisplayClose(); +} + +void PvrEglScreen::shutdownDevice() +{ + closeTty(); +} + +void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion ®ion) +{ + QGLScreen::blit(img, topLeft, region); + sync(); +} + +void PvrEglScreen::solidFill(const QColor &color, const QRegion ®ion) +{ + QGLScreen::solidFill(color, region); + sync(); +} + +bool PvrEglScreen::chooseContext + (QGLContext *context, const QGLContext *shareContext) +{ + // We use PvrEglScreenSurfaceFunctions instead. + Q_UNUSED(context); + Q_UNUSED(shareContext); + return false; +} + +bool PvrEglScreen::hasOpenGL() +{ + return true; +} + +QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const +{ + if (qobject_cast<QGLWidget*>(widget)) + return new PvrEglWindowSurface(widget, (QScreen *)this, displayId); + + return QScreen::createSurface(widget); +} + +QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const +{ + if (key == QLatin1String("PvrEgl")) + return new PvrEglWindowSurface(holder); + + return QScreen::createSurface(key); +} + +void PvrEglScreen::sync() +{ + // Put code here to synchronize 2D and 3D operations if necessary. +} + +void PvrEglScreen::openTty() +{ + const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0}; + + if (ttyDevice.isEmpty()) { + for (const char * const *dev = devs; *dev; ++dev) { + ttyfd = ::open(*dev, O_RDWR); + if (ttyfd != -1) + break; + } + } else { + ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR); + } + + if (ttyfd == -1) + return; + + ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC); + + if (doGraphicsMode) { + ioctl(ttyfd, KDGETMODE, &oldKdMode); + if (oldKdMode != KD_GRAPHICS) { + int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS); + if (ret == -1) + doGraphicsMode = false; + } + } + + // No blankin' screen, no blinkin' cursor!, no cursor! + const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c"; + ::write(ttyfd, termctl, sizeof(termctl)); +} + +void PvrEglScreen::closeTty() +{ + if (ttyfd == -1) + return; + + if (doGraphicsMode) + ioctl(ttyfd, KDSETMODE, oldKdMode); + + // Blankin' screen, blinkin' cursor! + const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c"; + ::write(ttyfd, termctl, sizeof(termctl)); + + ::close(ttyfd); + ttyfd = -1; +} + +bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native) +{ + QWSWindowSurface *surface = + static_cast<QWSWindowSurface *>(widget->windowSurface()); + if (!surface) { + // The widget does not have a surface yet, so give it one. + surface = new PvrEglWindowSurface(widget, screen, displayId); + widget->setWindowSurface(surface); + } else if (surface->key() != QLatin1String("PvrEgl")) { + // The application has attached a QGLContext to an ordinary QWidget. + // Replace the widget's window surface with a new one that can do GL. + QRect geometry = widget->frameGeometry(); + geometry.moveTo(widget->mapToGlobal(QPoint(0, 0))); + surface = new PvrEglWindowSurface(widget, screen, displayId); + surface->setGeometry(geometry); + widget->setWindowSurface(surface); + widget->setAttribute(Qt::WA_NoSystemBackground, true); + } + PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface); + *native = (EGLNativeWindowType)(nsurface->nativeDrawable()); + return true; +} + +// The PowerVR engine on the device needs to allocate about 2Mb of +// contiguous physical memory to manage drawing into a surface. +// +// The problem is that once Qtopia begins its startup sequence, +// it allocates enough memory to severely fragment the physical +// address space on the device. This leaves the PowerVR engine +// unable to allocate the necessary contiguous physical memory +// when an EGL surface is created. +// +// A solution to this is to pre-allocate a dummy surface early +// in the startup sequence before memory becomes fragmented, +// reserving it for any future EGL applications to use. +// +// However, the PowerVR engine has problems managing multiple +// surfaces concurrently, and so real EGL applications end up +// with unacceptably slow frame rates unless the dummy surface +// is destroyed while the real EGL applications are running. +// +// In summary, we need to try to ensure that there is always at +// least one EGL surface active at any given time to reserve the +// memory but destroy the temporary surface when a real surface +// is using the device. That is the purpose of PvrEglSurfaceHolder. + +PvrEglSurfaceHolder::PvrEglSurfaceHolder(QObject *parent) + : QObject(parent) +{ + numRealSurfaces = 0; + + PvrQwsRect rect; + rect.x = 0; + rect.y = 0; + rect.width = 16; + rect.height = 16; + tempSurface = pvrQwsCreateWindow(0, -1, &rect); + + dpy = EGL_NO_DISPLAY; + config = 0; + surface = EGL_NO_SURFACE; + + dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY); + if (!eglInitialize(dpy, 0, 0)) { + qWarning("Could not initialize EGL display - are the drivers loaded?"); + dpy = EGL_NO_DISPLAY; + return; + } + + EGLint attribList[16]; + int temp = 0; + attribList[temp++] = EGL_LEVEL; // Framebuffer level 0 + attribList[temp++] = 0; + attribList[temp++] = EGL_SURFACE_TYPE; + attribList[temp++] = EGL_WINDOW_BIT; + attribList[temp++] = EGL_NONE; + + EGLint numConfigs = 0; + if (!eglChooseConfig(dpy, attribList, &config, 1, &numConfigs) || numConfigs != 1) { + qWarning("Could not find a matching a EGL configuration"); + eglTerminate(dpy); + dpy = EGL_NO_DISPLAY; + return; + } + + surface = eglCreateWindowSurface + (dpy, config, (EGLNativeWindowType)(-1), NULL); + if (surface == EGL_NO_SURFACE) + qWarning("Could not create the temporary EGL surface"); +} + +PvrEglSurfaceHolder::~PvrEglSurfaceHolder() +{ + if (surface != EGL_NO_SURFACE) + eglDestroySurface(dpy, surface); + if (dpy != EGL_NO_DISPLAY) + eglTerminate(dpy); + if (tempSurface) + pvrQwsDestroyDrawable(tempSurface); +} + +// Add a real EGL surface to the system. +void PvrEglSurfaceHolder::addSurface() +{ + ++numRealSurfaces; + if (numRealSurfaces == 1) { + // Destroy the temporary surface while some other application + // is making use of the EGL sub-system for 3D rendering. + if (surface != EGL_NO_SURFACE) { + eglDestroySurface(dpy, surface); + surface = EGL_NO_SURFACE; + } + } +} + +// Remove an actual EGL surface from the system. +void PvrEglSurfaceHolder::removeSurface() +{ + if (numRealSurfaces > 0) { + --numRealSurfaces; + if (numRealSurfaces == 0) { + // The last real EGL surface has been destroyed, so re-create + // the temporary surface. There is a race condition here in + // that Qtopia could allocate a lot of memory just after + // the real EGL surface is destroyed but before we could + // create the temporary surface again. + if (surface == EGL_NO_SURFACE && dpy != EGL_NO_DISPLAY) { + surface = eglCreateWindowSurface + (dpy, config, (EGLNativeWindowType)tempSurface, NULL); + if (surface == EGL_NO_SURFACE) + qWarning("Could not re-create the temporary EGL surface"); + } + } + } +} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h new file mode 100644 index 0000000..ee27e36 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVREGLSCREEN_H +#define PVREGLSCREEN_H + +#include <QScreen> +#include <QGLScreen> +#include "pvrqwsdrawable.h" + +class PvrEglScreenSurfaceFunctions : public QGLScreenSurfaceFunctions +{ +public: + PvrEglScreenSurfaceFunctions(QScreen *s, int screenNum) + : screen(s), displayId(screenNum) {} + + bool createNativeWindow(QWidget *widget, EGLNativeWindowType *native); + +private: + QScreen *screen; + int displayId; +}; + +class PvrEglSurfaceHolder : public QObject +{ + Q_OBJECT +public: + PvrEglSurfaceHolder(QObject *parent=0); + ~PvrEglSurfaceHolder(); + + void addSurface(); + void removeSurface(); + +private: + int numRealSurfaces; + PvrQwsDrawable *tempSurface; + EGLDisplay dpy; + EGLConfig config; + EGLSurface surface; +}; + +class PvrEglScreen : public QGLScreen +{ +public: + PvrEglScreen(int displayId); + ~PvrEglScreen(); + + bool initDevice(); + bool connect(const QString &displaySpec); + void disconnect(); + void shutdownDevice(); + void setMode(int, int, int) {} + + void blit(const QImage &img, const QPoint &topLeft, const QRegion ®ion); + void solidFill(const QColor &color, const QRegion ®ion); + + bool chooseContext(QGLContext *context, const QGLContext *shareContext); + bool hasOpenGL(); + + QWSWindowSurface* createSurface(QWidget *widget) const; + QWSWindowSurface* createSurface(const QString &key) const; + +private: + void sync(); + void openTty(); + void closeTty(); + + int fd; + int ttyfd, oldKdMode; + PvrEglSurfaceHolder *holder; + QString ttyDevice; + bool doGraphicsMode; +}; + +#endif diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro new file mode 100644 index 0000000..691cd2d --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro @@ -0,0 +1,24 @@ +TEMPLATE = lib +TARGET = qgfxpvregl +CONFIG += qt plugin warn_on +QT += opengl + +LIBS += -lpvrQWSWSEGL + +DEFINES += QT_QWS_CLIENTBLIT + +INCLUDEPATH += ../QWSWSEGL + +HEADERS = \ + pvreglscreen.h \ + pvreglwindowsurface.h + +SOURCES = \ + pvreglscreenplugin.cpp \ + pvreglscreen.cpp \ + pvreglwindowsurface.cpp + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers + +target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers +INSTALLS += target diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp new file mode 100644 index 0000000..e9748d6 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglscreen.h" + +#include <QScreenDriverPlugin> +#include <QStringList> + +class PvrEglScreenPlugin : public QScreenDriverPlugin +{ +public: + PvrEglScreenPlugin(); + + QStringList keys() const; + QScreen *create(const QString&, int displayId); +}; + +PvrEglScreenPlugin::PvrEglScreenPlugin() + : QScreenDriverPlugin() +{ +} + +QStringList PvrEglScreenPlugin::keys() const +{ + return (QStringList() << "powervr"); +} + +QScreen* PvrEglScreenPlugin::create(const QString& driver, int displayId) +{ + if (driver.toLower() != "powervr") + return 0; + + return new PvrEglScreen(displayId); +} + +Q_EXPORT_PLUGIN2(qgfxpvregl, PvrEglScreenPlugin) diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp new file mode 100644 index 0000000..e7f4987 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglwindowsurface.h" +#include "pvreglscreen.h" +#include <QScreen> +#include <QDebug> +#include <QWSDisplay> + +PvrEglWindowSurface::PvrEglWindowSurface + (QWidget *widget, QScreen *screen, int screenNum) + : QWSGLWindowSurface(widget) +{ + setSurfaceFlags(QWSWindowSurface::Opaque); + + this->widget = widget; + this->screen = screen; + this->holder = 0; + this->pdevice = 0; + + QPoint pos = offset(widget); + QSize size = widget->size(); + + PvrQwsRect pvrRect; + pvrRect.x = pos.x(); + pvrRect.y = pos.y(); + pvrRect.width = size.width(); + pvrRect.height = size.height(); + + // Try to recover a previous PvrQwsDrawable object for the widget + // if there is one. This can happen when a PvrEglWindowSurface + // is created for a widget, bound to a EGLSurface, and then destroyed. + // When a new PvrEglWindowSurface is created for the widget, it will + // pick up the previous PvrQwsDrawable if the EGLSurface has not been + // destroyed in the meantime. + drawable = pvrQwsFetchWindow((long)widget); + if (drawable) + pvrQwsSetGeometry(drawable, &pvrRect); + else + drawable = pvrQwsCreateWindow(screenNum, (long)widget, &pvrRect); +} + +PvrEglWindowSurface::PvrEglWindowSurface(PvrEglSurfaceHolder *holder) + : QWSGLWindowSurface() +{ + setSurfaceFlags(QWSWindowSurface::Opaque); + drawable = 0; + widget = 0; + screen = 0; + pdevice = 0; + + this->holder = holder; + holder->addSurface(); +} + +PvrEglWindowSurface::~PvrEglWindowSurface() +{ + // Release the PvrQwsDrawable. If it is bound to an EGLSurface, + // then it will stay around until a new PvrEglWindowSurface is + // created for the widget. If it is not bound to an EGLSurface, + // it will be destroyed immediately. + if (drawable && pvrQwsReleaseWindow(drawable)) + pvrQwsDestroyDrawable(drawable); + + if (holder) + holder->removeSurface(); + delete pdevice; +} + +bool PvrEglWindowSurface::isValid() const +{ + return (widget != 0); +} + +void PvrEglWindowSurface::setGeometry(const QRect &rect) +{ + if (drawable) { + // XXX: adjust for the screen offset. + PvrQwsRect pvrRect; + pvrRect.x = rect.x(); + pvrRect.y = rect.y(); + pvrRect.width = rect.width(); + pvrRect.height = rect.height(); + pvrQwsSetGeometry(drawable, &pvrRect); + } + QWSGLWindowSurface::setGeometry(rect); +} + +bool PvrEglWindowSurface::move(const QPoint &offset) +{ + QRect rect = geometry().translated(offset); + if (drawable) { + PvrQwsRect pvrRect; + pvrRect.x = rect.x(); + pvrRect.y = rect.y(); + pvrRect.width = rect.width(); + pvrRect.height = rect.height(); + pvrQwsSetGeometry(drawable, &pvrRect); + } + return QWSGLWindowSurface::move(offset); +} + +QByteArray PvrEglWindowSurface::permanentState() const +{ + // Nothing interesting to pass to the server just yet. + return QByteArray(); +} + +void PvrEglWindowSurface::setPermanentState(const QByteArray &state) +{ + Q_UNUSED(state); +} + +QImage PvrEglWindowSurface::image() const +{ + if (drawable) { + PvrQwsRect pvrRect; + pvrQwsGetGeometry(drawable, &pvrRect); + void *data = pvrQwsGetRenderBuffer(drawable); + if (data) { + return QImage((uchar *)data, pvrRect.width, pvrRect.height, + pvrQwsGetStride(drawable), QImage::Format_RGB16); + } + } + return QImage(); +} + +QPaintDevice *PvrEglWindowSurface::paintDevice() +{ + // Return a dummy paint device because the widget itself + // cannot be painted to this way. + if (!pdevice) + pdevice = new QImage(50, 50, QImage::Format_RGB16); + return pdevice; +} + +void PvrEglWindowSurface::setDirectRegion(const QRegion &r, int id) +{ + QWSGLWindowSurface::setDirectRegion(r, id); + + if (!drawable) + return; + + // Clip the region to the window boundaries in case the child + // is partially outside the geometry of the parent. + QWidget *window = widget->window(); + QRegion region = r; + if (widget != window) { + QRect rect = window->geometry(); + rect.moveTo(window->mapToGlobal(QPoint(0, 0))); + region = region.intersect(rect); + } + + if (region.isEmpty()) { + pvrQwsClearVisibleRegion(drawable); + } else if (region.numRects() == 1) { + QRect rect = region.boundingRect(); + PvrQwsRect pvrRect; + pvrRect.x = rect.x(); + pvrRect.y = rect.y(); + pvrRect.width = rect.width(); + pvrRect.height = rect.height(); + pvrQwsSetVisibleRegion(drawable, &pvrRect, 1); + if (!pvrQwsSwapBuffers(drawable, 1)) + screen->solidFill(QColor(0, 0, 0), region); + } else { + QVector<QRect> rects = region.rects(); + PvrQwsRect *pvrRects = new PvrQwsRect [rects.size()]; + for (int index = 0; index < rects.size(); ++index) { + QRect rect = rects[index]; + pvrRects[index].x = rect.x(); + pvrRects[index].y = rect.y(); + pvrRects[index].width = rect.width(); + pvrRects[index].height = rect.height(); + } + pvrQwsSetVisibleRegion(drawable, pvrRects, rects.size()); + if (!pvrQwsSwapBuffers(drawable, 1)) + screen->solidFill(QColor(0, 0, 0), region); + delete [] pvrRects; + } +} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h new file mode 100644 index 0000000..8bec796 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVREGLWINDOWSURFACE_H +#define PVREGLWINDOWSURFACE_H + +#include <private/qglwindowsurface_qws_p.h> +#include "pvrqwsdrawable.h" + +class QScreen; +class PvrEglSurfaceHolder; + +class PvrEglWindowSurface : public QWSGLWindowSurface +{ +public: + PvrEglWindowSurface(QWidget *widget, QScreen *screen, int screenNum); + PvrEglWindowSurface(PvrEglSurfaceHolder *holder); + ~PvrEglWindowSurface(); + + QString key() const { return QLatin1String("PvrEgl"); } + + bool isValid() const; + + void setGeometry(const QRect &rect); + bool move(const QPoint &offset); + + QByteArray permanentState() const; + void setPermanentState(const QByteArray &state); + + QImage image() const; + QPaintDevice *paintDevice(); + + void setDirectRegion(const QRegion ®ion, int id); + + long nativeDrawable() const { return (long)widget; } + +private: + QWidget *widget; + PvrQwsDrawable *drawable; + QScreen *screen; + PvrEglSurfaceHolder *holder; + QPaintDevice *pdevice; +}; + +#endif |