From 38be0d13830efd2d98281c645c3a60afe05ffece Mon Sep 17 00:00:00 2001 From: Qt by Nokia Date: Wed, 27 Apr 2011 12:05:43 +0200 Subject: Initial import from the monolithic Qt. This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12 --- .../gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro | 26 + .../gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c | 830 +++++++++++++++++++++ .../gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h | 169 +++++ .../gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h | 132 ++++ .../gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c | 402 ++++++++++ src/plugins/gfxdrivers/powervr/README | 66 ++ src/plugins/gfxdrivers/powervr/powervr.pri | 2 + src/plugins/gfxdrivers/powervr/powervr.pro | 3 + .../powervr/pvreglscreen/pvreglscreen.cpp | 351 +++++++++ .../gfxdrivers/powervr/pvreglscreen/pvreglscreen.h | 99 +++ .../powervr/pvreglscreen/pvreglscreen.pro | 27 + .../powervr/pvreglscreen/pvreglscreenplugin.cpp | 74 ++ .../powervr/pvreglscreen/pvreglwindowsurface.cpp | 273 +++++++ .../powervr/pvreglscreen/pvreglwindowsurface.h | 85 +++ 14 files changed, 2539 insertions(+) create mode 100644 src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro create mode 100644 src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c create mode 100644 src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h create mode 100644 src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h create mode 100644 src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c create mode 100644 src/plugins/gfxdrivers/powervr/README create mode 100644 src/plugins/gfxdrivers/powervr/powervr.pri create mode 100644 src/plugins/gfxdrivers/powervr/powervr.pro create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp create mode 100644 src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h (limited to 'src/plugins/gfxdrivers/powervr') diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro new file mode 100644 index 0000000000..595cf45301 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/QWSWSEGL.pro @@ -0,0 +1,26 @@ +TEMPLATE = lib +TARGET = pvrQWSWSEGL +CONFIG += dll warn_on +CONFIG -= qt + +HEADERS+=\ + pvrqwsdrawable.h \ + pvrqwsdrawable_p.h + +SOURCES+=\ + pvrqwsdrawable.c \ + pvrqwswsegl.c + +INCLUDEPATH += $$QMAKE_INCDIR_EGL + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +LIBS += -lpvr2d + +DESTDIR = $$QMAKE_LIBDIR_QT +target.path = $$[QT_INSTALL_LIBS] +INSTALLS += target + +include(../powervr.pri) \ No newline at end of file diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c new file mode 100644 index 0000000000..8dc0120fe1 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.c @@ -0,0 +1,830 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvrqwsdrawable_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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].initialized) + 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 = fix.line_length; + 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; + + if (screen == 0) { + /* We use PVR2DGetFrameBuffer to map the first screen. + On some chipsets it is more reliable than using PVR2DMemWrap */ + mapped = 0; + memInfo = 0; + } else { + /* Other screens: 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].screenDrawable = 0; + if (mapped) { + /* Don't set these fields if mapped is 0, because PVR2DGetFrameBuffer + may have already been called and set them */ + pvrQwsDisplay.screens[screen].frameBuffer = memInfo; + pvrQwsDisplay.screens[screen].mapped = mapped; + } + pvrQwsDisplay.screens[screen].mappedLength = length; + pvrQwsDisplay.screens[screen].screenStart = start; + pvrQwsDisplay.screens[screen].needsUnmap = (mapped != 0); + pvrQwsDisplay.screens[screen].initialized = 1; + 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 (screen != 0 && 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; + } else if (screen == 0) { + if (PVR2DGetFrameBuffer + (pvrQwsDisplay.context, + PVR2D_FB_PRIMARY_SURFACE, &memInfo) != PVR2D_OK) { + fprintf(stderr, "QWSWSEGL: could not get the primary framebuffer surface\n"); + PVR2DDestroyDeviceContext(pvrQwsDisplay.context); + pvrQwsDisplay.context = 0; + return 0; + } + pvrQwsDisplay.screens[screen].frameBuffer = memInfo; + pvrQwsDisplay.screens[screen].mapped = memInfo->pBase; + } + } + + /* 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 && info->needsUnmap) + 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; +} + +void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle) +{ + if (drawable->rotationAngle != angle) { + drawable->rotationAngle = angle; + + /* Force the buffers to be recreated if the rotation angle changes */ + pvrQwsInvalidateBuffers(drawable); + } +} + +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 + 31) & ~31; + 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; +} diff --git a/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h new file mode 100644 index 0000000000..8c8cc27018 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@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); + +/* Set the rotation angle in degrees */ +void pvrQwsSetRotation(PvrQwsDrawable *drawable, int angle); + +/* 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); + +#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 0000000000..3ad0693e02 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwsdrawable_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@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 +#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; + int needsUnmap; + int initialized; + +} 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; + int rotationAngle; + 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 0000000000..f861838e90 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/QWSWSEGL/pvrqwswsegl.c @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "pvrqwsdrawable_p.h" + +#define WSEGL_UNUSED(x) (void)x; + +// If the PVR2D version is not specified, then assume MBX-style headers. +// If the version is defined, then we assume that we have SGX-style headers. +#if !defined(PVR2D_REV_MAJOR) +#define WSEGL_CAP_WINDOWS_USE_HW_SYNC WSEGL_CAP_WINDOWS_USE_MBX_SYNC +#define WSEGL_CAP_PIXMAPS_USE_HW_SYNC WSEGL_CAP_PIXMAPS_USE_MBX_SYNC +#endif + +/* Capability information for the display */ +static WSEGLCaps const wseglDisplayCaps[] = { + {WSEGL_CAP_WINDOWS_USE_HW_SYNC, 1}, + {WSEGL_CAP_PIXMAPS_USE_HW_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; +} + +static WSEGLRotationAngle wseglRotationValue(int degrees) +{ + switch (degrees) { + case 90: return WSEGL_ROTATE_90; + case 180: return WSEGL_ROTATE_180; + case 270: return WSEGL_ROTATE_270; + default: return WSEGL_ROTATE_0; + } +} + +/* 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 = wseglRotationValue(screen->rotationAngle); + 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 = wseglRotationValue(draw->rotationAngle); + 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; + if (pvrQwsDisplay.numFlipBuffers == 0) + 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 0000000000..513e7f5e9e --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/README @@ -0,0 +1,66 @@ +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). + +Qt/Embedded needs to be configured with the QT_QWS_CLIENTBLIT and +QT_NO_QWS_CURSOR defines. + +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. You * +* can find a copy of these headers in src/3rdparty/powervr for SGX based * +* platforms like the TI OMAP3xxx. They probably will not work on MBX * +* because of differences in the layout of certain PVR2D structures. * +* You can tell Qt where to find the actual headers for your system by * +* setting QMAKE_INCDIR_POWERVR in the mkspec. * +*************************************************************************** + +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 + +The driver also supports screen rotation if Qt is configured with the +-qt-gfx-transformed option and the QWS_DISPLAY variable is wrapped in a +"Transformed" declaration: + + Transformed:powervr:mmWidth40:mmHeight54:Rot90:0 + +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.pri b/src/plugins/gfxdrivers/powervr/powervr.pri new file mode 100644 index 0000000000..9df8c0ed5b --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/powervr.pri @@ -0,0 +1,2 @@ + +INCLUDEPATH += $$QMAKE_INCDIR_POWERVR diff --git a/src/plugins/gfxdrivers/powervr/powervr.pro b/src/plugins/gfxdrivers/powervr/powervr.pro new file mode 100644 index 0000000000..f31ad042d8 --- /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 0000000000..c981e0d300 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglscreen.h" +#include "pvreglwindowsurface.h" +#include "pvrqwsdrawable_p.h" +#include +#include +#ifndef QT_NO_QWS_TRANSFORMED +#include +#endif +#include +#include +#include +#include +#include + +//![0] +PvrEglScreen::PvrEglScreen(int displayId) + : QGLScreen(displayId) +{ + setOptions(NativeWindows); + setSupportsBlitInClients(true); + setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId)); +//![0] + fd = -1; + ttyfd = -1; + doGraphicsMode = true; + oldKdMode = KD_TEXT; + parent = 0; + + // Make sure that the EGL layer is initialized and the drivers loaded. + EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY); + if (!eglInitialize(dpy, 0, 0)) + qWarning("Could not initialize EGL display - are the drivers loaded?"); + + // Make sure that screen 0 is initialized. + pvrQwsScreenWindow(0); +} + +PvrEglScreen::~PvrEglScreen() +{ + if (fd >= 0) + ::close(fd); +} + +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_Premultiplied); + 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; +} + +//![1] +QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const +{ + if (qobject_cast(widget)) + return new PvrEglWindowSurface(widget, (PvrEglScreen *)this, displayId); + + return QScreen::createSurface(widget); +} + +QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const +{ + if (key == QLatin1String("PvrEgl")) + return new PvrEglWindowSurface(); + + return QScreen::createSurface(key); +} +//![1] + +#ifndef QT_NO_QWS_TRANSFORMED + +static const QScreen *parentScreen + (const QScreen *current, const QScreen *lookingFor) +{ + if (!current) + return 0; + switch (current->classId()) { + case QScreen::ProxyClass: + case QScreen::TransformedClass: { + const QScreen *child = + static_cast(current)->screen(); + if (child == lookingFor) + return current; + else + return parentScreen(child, lookingFor); + } + // Not reached. + + case QScreen::MultiClass: { + QList screens = current->subScreens(); + foreach (QScreen *screen, screens) { + if (screen == lookingFor) + return current; + const QScreen *parent = parentScreen(screen, lookingFor); + if (parent) + return parent; + } + } + break; + + default: break; + } + return 0; +} + +int PvrEglScreen::transformation() const +{ + // We need to search for our parent screen, which is assumed to be + // "Transformed". If it isn't, then there is no transformation. + // There is no direct method to get the parent screen so we need + // to search every screen until we find ourselves. + if (!parent && qt_screen != this) + parent = parentScreen(qt_screen, this); + if (!parent) + return 0; + if (parent->classId() != QScreen::TransformedClass) + return 0; + return 90 * static_cast(parent) + ->transformOrientation(); +} + +#else + +int PvrEglScreen::transformation() const +{ + return 0; +} + +#endif + +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; +} + +//![2] +bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native) +{ +//![2] + QWSWindowSurface *surface = + static_cast(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(surface); + *native = (EGLNativeWindowType)(nsurface->nativeDrawable()); + return true; +} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h new file mode 100644 index 0000000000..efb2406771 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVREGLSCREEN_H +#define PVREGLSCREEN_H + +#include +#include +#include "pvrqwsdrawable.h" + +class PvrEglScreen; + +class PvrEglScreenSurfaceFunctions : public QGLScreenSurfaceFunctions +{ +public: + PvrEglScreenSurfaceFunctions(PvrEglScreen *s, int screenNum) + : screen(s), displayId(screenNum) {} + + bool createNativeWindow(QWidget *widget, EGLNativeWindowType *native); + +private: + PvrEglScreen *screen; + int displayId; +}; + +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; + + int transformation() const; + +private: + void sync(); + void openTty(); + void closeTty(); + + int fd; + int ttyfd, oldKdMode; + QString ttyDevice; + bool doGraphicsMode; + mutable const QScreen *parent; +}; + +#endif diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro new file mode 100644 index 0000000000..675be85460 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.pro @@ -0,0 +1,27 @@ +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 + +include(../powervr.pri) \ No newline at end of file diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp new file mode 100644 index 0000000000..872285e818 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreenplugin.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglscreen.h" + +#include +#include + +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 0000000000..43648159c8 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pvreglwindowsurface.h" +#include "pvreglscreen.h" +#include +#include +#include + +PvrEglWindowSurface::PvrEglWindowSurface + (QWidget *widget, PvrEglScreen *screen, int screenNum) + : QWSGLWindowSurface(widget) +{ + setSurfaceFlags(QWSWindowSurface::Opaque); + + this->widget = widget; + this->screen = screen; + 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(); + transformRects(&pvrRect, 1); + + // 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); + pvrQwsSetRotation(drawable, screen->transformation()); +} + +PvrEglWindowSurface::PvrEglWindowSurface() + : QWSGLWindowSurface() +{ + setSurfaceFlags(QWSWindowSurface::Opaque); + drawable = 0; + widget = 0; + screen = 0; + pdevice = 0; +} + +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); + + 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(); + transformRects(&pvrRect, 1); + pvrQwsSetGeometry(drawable, &pvrRect); + pvrQwsSetRotation(drawable, screen->transformation()); + } + 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(); + transformRects(&pvrRect, 1); + pvrQwsSetGeometry(drawable, &pvrRect); + pvrQwsSetRotation(drawable, screen->transformation()); + } + 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); +} + +void PvrEglWindowSurface::flush + (QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + // The GL paint engine is responsible for the swapBuffers() call. + // If we were to call the base class's implementation of flush() + // then it would fetch the image() and manually blit it to the + // screeen instead of using the fast PVR2D blit. + Q_UNUSED(widget); + Q_UNUSED(region); + Q_UNUSED(offset); +} + +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), screen->pixelFormat()); + } + } + return QImage(16, 16, screen->pixelFormat()); +} + +QPaintDevice *PvrEglWindowSurface::paintDevice() +{ + return widget; +} + +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.rectCount() == 1) { + QRect rect = region.boundingRect(); + PvrQwsRect pvrRect; + pvrRect.x = rect.x(); + pvrRect.y = rect.y(); + pvrRect.width = rect.width(); + pvrRect.height = rect.height(); + transformRects(&pvrRect, 1); + pvrQwsSetVisibleRegion(drawable, &pvrRect, 1); + pvrQwsSetRotation(drawable, screen->transformation()); + if (!pvrQwsSwapBuffers(drawable, 1)) + screen->solidFill(QColor(0, 0, 0), region); + } else { + QVector 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(); + } + transformRects(pvrRects, rects.size()); + pvrQwsSetVisibleRegion(drawable, pvrRects, rects.size()); + pvrQwsSetRotation(drawable, screen->transformation()); + if (!pvrQwsSwapBuffers(drawable, 1)) + screen->solidFill(QColor(0, 0, 0), region); + delete [] pvrRects; + } +} + +void PvrEglWindowSurface::transformRects(PvrQwsRect *rects, int count) const +{ + switch (screen->transformation()) { + case 0: break; + + case 90: + { + for (int index = 0; index < count; ++index) { + int x = rects[index].y; + int y = screen->height() - (rects[index].x + rects[index].width); + rects[index].x = x; + rects[index].y = y; + qSwap(rects[index].width, rects[index].height); + } + } + break; + + case 180: + { + for (int index = 0; index < count; ++index) { + int x = screen->width() - (rects[index].x + rects[index].width); + int y = screen->height() - (rects[index].y + rects[index].height); + rects[index].x = x; + rects[index].y = y; + } + } + break; + + case 270: + { + for (int index = 0; index < count; ++index) { + int x = screen->width() - (rects[index].y + rects[index].height); + int y = rects[index].x; + rects[index].x = x; + rects[index].y = y; + qSwap(rects[index].width, rects[index].height); + } + } + break; + } +} diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h new file mode 100644 index 0000000000..9f5600c136 --- /dev/null +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglwindowsurface.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PVREGLWINDOWSURFACE_H +#define PVREGLWINDOWSURFACE_H + +#include +#include "pvrqwsdrawable.h" + +class PvrEglScreen; + +class PvrEglWindowSurface : public QWSGLWindowSurface +{ +public: + PvrEglWindowSurface(QWidget *widget, PvrEglScreen *screen, int screenNum); + PvrEglWindowSurface(); + ~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); + + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + + QImage image() const; + QPaintDevice *paintDevice(); + + void setDirectRegion(const QRegion ®ion, int id); + + long nativeDrawable() const { return (long)widget; } + +private: + QWidget *widget; + PvrQwsDrawable *drawable; + PvrEglScreen *screen; + QPaintDevice *pdevice; + + void transformRects(PvrQwsRect *rects, int count) const; +}; + +#endif -- cgit v1.2.3