/**************************************************************************** ** ** 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$ ** ****************************************************************************/ #define GL_GLEXT_PROTOTYPES #include "shivavgwindowsurface.h" #include #if defined(Q_WS_X11) #include "private/qt_x11_p.h" #include "qx11info_x11.h" #include extern QX11Info *qt_x11Info(const QPaintDevice *pd); #endif // Define this to use framebuffer objects. //#define QVG_USE_FBO 1 #include QT_BEGIN_NAMESPACE class QShivaContext { public: QShivaContext(); ~QShivaContext(); bool makeCurrent(ShivaVGWindowSurfacePrivate *surface); void doneCurrent(); bool initialized; QSize currentSize; ShivaVGWindowSurfacePrivate *currentSurface; }; Q_GLOBAL_STATIC(QShivaContext, shivaContext); class ShivaVGWindowSurfacePrivate { public: ShivaVGWindowSurfacePrivate() : isCurrent(false) , needsResize(true) , engine(0) #if defined(QVG_USE_FBO) , fbo(0) , texture(0) #endif #if defined(Q_WS_X11) , drawable(0) , context(0) #endif { } ~ShivaVGWindowSurfacePrivate(); void ensureContext(QWidget *widget); QSize size; bool isCurrent; bool needsResize; QVGPaintEngine *engine; #if defined(QVG_USE_FBO) GLuint fbo; GLuint texture; #endif #if defined(Q_WS_X11) GLXDrawable drawable; GLXContext context; #endif }; QShivaContext::QShivaContext() : initialized(false) , currentSurface(0) { } QShivaContext::~QShivaContext() { if (initialized) vgDestroyContextSH(); } bool QShivaContext::makeCurrent(ShivaVGWindowSurfacePrivate *surface) { if (currentSurface) currentSurface->isCurrent = false; surface->isCurrent = true; currentSurface = surface; currentSize = surface->size; #if defined(Q_WS_X11) glXMakeCurrent(X11->display, surface->drawable, surface->context); #endif if (!initialized) { if (!vgCreateContextSH(currentSize.width(), currentSize.height())) { qWarning("vgCreateContextSH(%d, %d): could not create context", currentSize.width(), currentSize.height()); return false; } initialized = true; } else { vgResizeSurfaceSH(currentSize.width(), currentSize.height()); } #if defined(QVG_USE_FBO) if (surface->fbo) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface->fbo); else glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); #endif return true; } void QShivaContext::doneCurrent() { if (currentSurface) { currentSurface->isCurrent = false; currentSurface = 0; } #if defined(Q_WS_X11) glXMakeCurrent(X11->display, 0, 0); #endif } ShivaVGWindowSurfacePrivate::~ShivaVGWindowSurfacePrivate() { #if defined(QVG_USE_FBO) if (fbo) { glDeleteTextures(1, &texture); glDeleteFramebuffersEXT(1, &fbo); } #endif } void ShivaVGWindowSurfacePrivate::ensureContext(QWidget *widget) { #if defined(Q_WS_X11) Window win = widget->winId(); if (win != drawable) { if (context) glXDestroyContext(X11->display, context); drawable = win; } if (context == 0) { const QX11Info *xinfo = qt_x11Info(widget); int spec[64]; int i = 0; spec[i++] = GLX_DOUBLEBUFFER; spec[i++] = GLX_DEPTH_SIZE; spec[i++] = 1; spec[i++] = GLX_STENCIL_SIZE; spec[i++] = 1; spec[i++] = GLX_RGBA; spec[i++] = GLX_RED_SIZE; spec[i++] = 1; spec[i++] = GLX_GREEN_SIZE; spec[i++] = 1; spec[i++] = GLX_BLUE_SIZE; spec[i++] = 1; spec[i++] = GLX_SAMPLE_BUFFERS_ARB; spec[i++] = 1; spec[i++] = GLX_SAMPLES_ARB; spec[i++] = 4; spec[i] = XNone; XVisualInfo *visual = glXChooseVisual (xinfo->display(), xinfo->screen(), spec); context = glXCreateContext(X11->display, visual, 0, True); if (!context) qWarning("glXCreateContext: could not create GL context for VG rendering"); } #else Q_UNUSED(widget); #endif #if defined(QVG_USE_FBO) if (needsResize && fbo) { #if defined(Q_WS_X11) glXMakeCurrent(X11->display, drawable, context); #endif glDeleteTextures(1, &texture); glDeleteFramebuffersEXT(1, &fbo); #if defined(Q_WS_X11) glXMakeCurrent(X11->display, 0, 0); #endif fbo = 0; texture = 0; } if (!fbo) { #if defined(Q_WS_X11) glXMakeCurrent(X11->display, drawable, context); #endif glGenFramebuffersEXT(1, &fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texture, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); #if defined(Q_WS_X11) glXMakeCurrent(X11->display, 0, 0); #endif } #endif needsResize = false; } ShivaVGWindowSurface::ShivaVGWindowSurface(QWidget *window) : QWindowSurface(window), d_ptr(new ShivaVGWindowSurfacePrivate) { } ShivaVGWindowSurface::~ShivaVGWindowSurface() { if (d_ptr->isCurrent) { shivaContext()->doneCurrent(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } #if defined(Q_WS_X11) if (d_ptr->context) glXDestroyContext(X11->display, d_ptr->context); #endif delete d_ptr; } QPaintDevice *ShivaVGWindowSurface::paintDevice() { d_ptr->ensureContext(window()); shivaContext()->makeCurrent(d_ptr); glClearDepth(0.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); return this; } void ShivaVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(region); Q_UNUSED(offset); QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); d_ptr->ensureContext(parent); QShivaContext *context = shivaContext(); if (!d_ptr->isCurrent) context->makeCurrent(d_ptr); #if defined(QVG_USE_FBO) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); if (d_ptr->fbo) { static GLfloat const vertices[][2] = { {-1, -1}, {1, -1}, {1, 1}, {-1, 1} }; static GLfloat const texCoords[][2] = { {0, 0}, {1, 0}, {1, 1}, {0, 1} }; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glVertexPointer(2, GL_FLOAT, 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glBindTexture(GL_TEXTURE_2D, d_ptr->texture); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); } #endif #if defined(Q_WS_X11) glXSwapBuffers(X11->display, d_ptr->drawable); #endif context->doneCurrent(); } void ShivaVGWindowSurface::setGeometry(const QRect &rect) { QWindowSurface::setGeometry(rect); d_ptr->needsResize = true; d_ptr->size = rect.size(); } bool ShivaVGWindowSurface::scroll(const QRegion &area, int dx, int dy) { return QWindowSurface::scroll(area, dx, dy); } void ShivaVGWindowSurface::beginPaint(const QRegion ®ion) { // Nothing to do here. Q_UNUSED(region); } void ShivaVGWindowSurface::endPaint(const QRegion ®ion) { // Nothing to do here. Q_UNUSED(region); } Q_GLOBAL_STATIC(QVGPaintEngine, sharedPaintEngine); QPaintEngine *ShivaVGWindowSurface::paintEngine() const { if (!d_ptr->engine) d_ptr->engine = sharedPaintEngine(); return d_ptr->engine; } int ShivaVGWindowSurface::metric(PaintDeviceMetric met) const { return qt_paint_device_metric(window(), met); } QT_END_NAMESPACE