/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** 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 "hybridsurface.h" #include #include #include #include static void error(const char *message) { const EGLint error = eglGetError(); qWarning("HybridSurface error: %s: 0x%x", message, error); } static void imgToVanilla(const QImage *img, VanillaPixmap *pix) { pix->width = img->width(); pix->height = img->height(); pix->stride = img->bytesPerLine(); if (img->depth() == 32) { pix->rSize = pix->gSize = pix->bSize = pix->aSize = 8; pix->lSize = 0; pix->rOffset = 16; pix->gOffset = 8; pix->bOffset = 0; pix->aOffset = 24; } else if (img->format() == QImage::Format_RGB16) { pix->rSize = 5; pix->gSize = 6; pix->bSize = 5; pix->aSize = 0; pix->lSize = 0; pix->rOffset = 11; pix->gOffset = 5; pix->bOffset = 0; pix->aOffset = 0; } pix->padding = pix->padding2 = 0; pix->pixels = const_cast(img->bits()); } HybridSurface::HybridSurface() : QWSGLWindowSurface(), memlock(0) { setSurfaceFlags(Buffered | Opaque); } HybridSurface::HybridSurface(QWidget *w, EGLDisplay disp) : QWSGLWindowSurface(w), memlock(0), display(disp), config(0), surface(EGL_NO_SURFACE), context(EGL_NO_CONTEXT), pdevice(new QWSGLPaintDevice(w)) { setSurfaceFlags(Buffered | Opaque); EGLint configAttribs[] = { EGL_RED_SIZE, 0, EGL_GREEN_SIZE, 0, EGL_BLUE_SIZE, 0, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, EGL_DONT_CARE, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE, EGL_NONE }; EGLBoolean status; EGLint numConfigs; status = eglChooseConfig(display, configAttribs, 0, 0, &numConfigs); if (!status) { error("chooseConfig"); return; } //If there isn't any configuration good enough if (numConfigs < 1) { error("chooseConfig, no matching configurations found"); return; } QVarLengthArray configs(numConfigs); status = eglChooseConfig(display, configAttribs, configs.data(), numConfigs, &numConfigs); if (!status) { error("chooseConfig"); return; } // hw: if used on an image buffer we need to check whether the resulting // configuration matches our requirements exactly! config = configs[0]; context = eglCreateContext(display, config, 0, 0); //(shareContext ? shareContext->d_func()->cx : 0), //configAttribs); if (context == EGL_NO_CONTEXT) error("eglCreateContext"); } HybridSurface::~HybridSurface() { } bool HybridSurface::isValid() const { return true; } void HybridSurface::setGeometry(const QRect &rect, const QRegion &mask) { const QSize size = rect.size(); if (img.size() != size) { // QWidget *win = window(); QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied; const int bytesPerPixel = 4; const int bpl = (size.width() * bytesPerPixel + 3) & ~3; const int imagesize = bpl * size.height(); if (imagesize == 0) { eglDestroySurface(display, surface); mem.detach(); img = QImage(); } else { mem.detach(); if (!mem.create(imagesize)) { perror("HybridSurface::setGeometry allocating shared memory"); qFatal("Error creating shared memory of size %d", imagesize); } uchar *base = static_cast(mem.address()); img = QImage(base, size.width(), size.height(), imageFormat); // setImageMetrics(img, win); imgToVanilla(&img, &vanillaPix); surface = eglCreatePixmapSurface(display, config, &vanillaPix, 0); if (surface == EGL_NO_SURFACE) error("setGeometry:eglCreatePixmapSurface"); } } QWSWindowSurface::setGeometry(rect, mask); } QByteArray HybridSurface::permanentState() const { QByteArray array; array.resize(4 * sizeof(int) + sizeof(QImage::Format) + sizeof(SurfaceFlags)); char *ptr = array.data(); reinterpret_cast(ptr)[0] = mem.id(); reinterpret_cast(ptr)[1] = img.width(); reinterpret_cast(ptr)[2] = img.height(); reinterpret_cast(ptr)[3] = (memlock ? memlock->id() : -1); ptr += 4 * sizeof(int); *reinterpret_cast(ptr) = img.format(); ptr += sizeof(QImage::Format); *reinterpret_cast(ptr) = surfaceFlags(); return array; } void HybridSurface::setPermanentState(const QByteArray &data) { int memId; int width; int height; int lockId; QImage::Format format; SurfaceFlags flags; const char *ptr = data.constData(); memId = reinterpret_cast(ptr)[0]; width = reinterpret_cast(ptr)[1]; height = reinterpret_cast(ptr)[2]; lockId = reinterpret_cast(ptr)[3]; ptr += 4 * sizeof(int); format = *reinterpret_cast(ptr); ptr += sizeof(QImage::Format); flags = *reinterpret_cast(ptr); setSurfaceFlags(flags); // setMemory(memId); if (mem.id() != memId) { mem.detach(); if (!mem.attach(memId)) { perror("QWSSharedMemSurface: attaching to shared memory"); qCritical("QWSSharedMemSurface: Error attaching to" " shared memory 0x%x", memId); } } // setLock(lockId); if (!memlock || memlock->id() == lockId) { delete memlock; memlock = (lockId == -1 ? 0 : new QWSLock(lockId)); } uchar *base = static_cast(mem.address()); img = QImage(base, width, height, format); } QImage HybridSurface::image() const { return img; } QPaintDevice* HybridSurface::paintDevice() { return pdevice; } void HybridSurface::beginPaint(const QRegion ®ion) { QWSGLWindowSurface::beginPaint(region); eglBindAPI(EGL_OPENGL_ES_API); EGLBoolean ok = eglMakeCurrent(display, surface, surface, context); if (!ok) error("qglMakeCurrent"); } bool HybridSurface::lock(int timeout) { Q_UNUSED(timeout); if (!memlock) return true; return memlock->lock(QWSLock::BackingStore); } void HybridSurface::unlock() { if (memlock) memlock->unlock(QWSLock::BackingStore); } QPoint HybridSurface::painterOffset() const { const QWidget *w = window(); if (!w) return QPoint(); if (w->mask().isEmpty()) return QWSWindowSurface::painterOffset(); const QRegion region = w->mask() & w->frameGeometry().translated(-w->geometry().topLeft()); return -region.boundingRect().topLeft(); }