src/opengl/qpaintengine_opengl.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
     8 **
     8 **
   106 #define DEBUG_OVERRIDE(state) { state ? ++DEBUG_OVERRIDE_FLAG : --DEBUG_OVERRIDE_FLAG; }
   106 #define DEBUG_OVERRIDE(state) { state ? ++DEBUG_OVERRIDE_FLAG : --DEBUG_OVERRIDE_FLAG; }
   107 #define DEBUG_ONCE if ((DEBUG_TEMP_FLAG = DEBUG_OVERRIDE_FLAG) && 0) ; else for (static int DEBUG_ONCE_FLAG = false; !DEBUG_ONCE_FLAG || DEBUG_TEMP_FLAG; DEBUG_ONCE_FLAG = true, DEBUG_TEMP_FLAG = false)
   107 #define DEBUG_ONCE if ((DEBUG_TEMP_FLAG = DEBUG_OVERRIDE_FLAG) && 0) ; else for (static int DEBUG_ONCE_FLAG = false; !DEBUG_ONCE_FLAG || DEBUG_TEMP_FLAG; DEBUG_ONCE_FLAG = true, DEBUG_TEMP_FLAG = false)
   108 #define DEBUG_ONCE_STR(str) DEBUG_ONCE qDebug() << (str);
   108 #define DEBUG_ONCE_STR(str) DEBUG_ONCE qDebug() << (str);
   109 #endif
   109 #endif
   110 
   110 
       
   111 #ifdef Q_WS_X11
       
   112 static bool qt_nvidiaFboNeedsFinish = false;
       
   113 #endif
       
   114 
   111 static inline void qt_glColor4ubv(unsigned char *col)
   115 static inline void qt_glColor4ubv(unsigned char *col)
   112 {
   116 {
   113     glColor4f(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, col[3]/255.0f);
   117     glColor4f(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, col[3]/255.0f);
   114 }
   118 }
   115 
   119 
   421     if (!offscreen || !bound)
   425     if (!offscreen || !bound)
   422         return;
   426         return;
   423 
   427 
   424 #ifdef Q_WS_X11
   428 #ifdef Q_WS_X11
   425     // workaround for bug in nvidia driver versions 9x.xx
   429     // workaround for bug in nvidia driver versions 9x.xx
   426     if (QGLExtensions::nvidiaFboNeedsFinish)
   430     if (qt_nvidiaFboNeedsFinish)
   427         glFinish();
   431         glFinish();
   428 #endif
   432 #endif
   429 
   433 
   430     DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
   434     DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
   431 
   435 
   475     return ctx;
   479     return ctx;
   476 }
   480 }
   477 
   481 
   478 bool QGLOffscreen::isSupported()
   482 bool QGLOffscreen::isSupported()
   479 {
   483 {
   480     return (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); // for fbo
   484     return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject); // for fbo
   481 }
   485 }
   482 
   486 
   483 struct QDrawQueueItem
   487 struct QDrawQueueItem
   484 {
   488 {
   485     QDrawQueueItem(qreal _opacity,
   489     QDrawQueueItem(qreal _opacity,
  1264 
  1268 
  1265     for (int i = 0; i < 4; ++i)
  1269     for (int i = 0; i < 4; ++i)
  1266         for (int j = 0; j < 4; ++j)
  1270         for (int j = 0; j < 4; ++j)
  1267             d->mv_matrix[i][j] = (i == j ? qreal(1) : qreal(0));
  1271             d->mv_matrix[i][j] = (i == j ? qreal(1) : qreal(0));
  1268 
  1272 
  1269     bool has_frag_program = (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram)
  1273     bool has_frag_program = (QGLExtensions::glExtensions() & QGLExtensions::FragmentProgram)
  1270                             && (pdev->devType() != QInternal::Pixmap);
  1274                             && (pdev->devType() != QInternal::Pixmap);
  1271 
  1275 
  1272     QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
  1276     QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
  1273     if (!ctx) {
  1277     if (!ctx) {
  1274         qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
  1278         qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
  1277 
  1281 
  1278     if (has_frag_program)
  1282     if (has_frag_program)
  1279         has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx);
  1283         has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx);
  1280 
  1284 
  1281     d->use_stencil_method = d->device->format().stencil()
  1285     d->use_stencil_method = d->device->format().stencil()
  1282                             && (QGLExtensions::glExtensions & QGLExtensions::StencilWrap);
  1286                             && (QGLExtensions::glExtensions() & QGLExtensions::StencilWrap);
  1283     if (d->device->format().directRendering()
  1287     if (d->device->format().directRendering()
  1284         && (d->use_stencil_method && QGLExtensions::glExtensions & QGLExtensions::StencilTwoSide))
  1288         && (d->use_stencil_method && QGLExtensions::glExtensions() & QGLExtensions::StencilTwoSide))
  1285         d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
  1289         d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
       
  1290 
       
  1291 #ifdef Q_WS_X11
       
  1292     static bool nvidia_workaround_needs_init = true;
       
  1293     if (nvidia_workaround_needs_init) {
       
  1294         // nvidia 9x.xx unix drivers contain a bug which requires us to
       
  1295         // call glFinish before releasing an fbo to avoid painting
       
  1296         // artifacts
       
  1297         const QByteArray versionString(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
       
  1298         const int pos = versionString.indexOf("NVIDIA");
       
  1299         if (pos >= 0) {
       
  1300             const float nvidiaDriverVersion = versionString.mid(pos + strlen("NVIDIA")).toFloat();
       
  1301             qt_nvidiaFboNeedsFinish = nvidiaDriverVersion >= 90.0 && nvidiaDriverVersion < 100.0;
       
  1302         }
       
  1303         nvidia_workaround_needs_init = false;
       
  1304     }
       
  1305 #endif
  1286 
  1306 
  1287 #ifndef QT_OPENGL_ES
  1307 #ifndef QT_OPENGL_ES
  1288     if (!ctx->d_ptr->internal_context) {
  1308     if (!ctx->d_ptr->internal_context) {
  1289         glGetDoublev(GL_PROJECTION_MATRIX, &d->projection_matrix[0][0]);
  1309         glGetDoublev(GL_PROJECTION_MATRIX, &d->projection_matrix[0][0]);
  1290         glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
  1310         glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
  1331         glDisableClientState(GL_COLOR_ARRAY);
  1351         glDisableClientState(GL_COLOR_ARRAY);
  1332         glDisableClientState(GL_NORMAL_ARRAY);
  1352         glDisableClientState(GL_NORMAL_ARRAY);
  1333         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  1353         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  1334         glDisableClientState(GL_VERTEX_ARRAY);
  1354         glDisableClientState(GL_VERTEX_ARRAY);
  1335 
  1355 
  1336         if (QGLExtensions::glExtensions & QGLExtensions::SampleBuffers)
  1356         if (QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers)
  1337             glDisable(GL_MULTISAMPLE);
  1357             glDisable(GL_MULTISAMPLE);
  1338         glDisable(GL_TEXTURE_2D);
  1358         glDisable(GL_TEXTURE_2D);
  1339         if (QGLExtensions::glExtensions & QGLExtensions::TextureRectangle)
  1359         if (QGLExtensions::glExtensions() & QGLExtensions::TextureRectangle)
  1340             glDisable(GL_TEXTURE_RECTANGLE_NV);
  1360             glDisable(GL_TEXTURE_RECTANGLE_NV);
  1341         glDisable(GL_STENCIL_TEST);
  1361         glDisable(GL_STENCIL_TEST);
  1342         glDisable(GL_CULL_FACE);
  1362         glDisable(GL_CULL_FACE);
  1343         glDisable(GL_LIGHTING);
  1363         glDisable(GL_LIGHTING);
  1344         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1364         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1532 void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF &)
  1552 void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF &)
  1533 {
  1553 {
  1534 #ifdef QT_OPENGL_ES
  1554 #ifdef QT_OPENGL_ES
  1535     Q_UNUSED(brush);
  1555     Q_UNUSED(brush);
  1536 #else
  1556 #else
  1537     bool has_mirrored_repeat = QGLExtensions::glExtensions & QGLExtensions::MirroredRepeat;
  1557     bool has_mirrored_repeat = QGLExtensions::glExtensions() & QGLExtensions::MirroredRepeat;
  1538     Qt::BrushStyle style = brush.style();
  1558     Qt::BrushStyle style = brush.style();
  1539 
  1559 
  1540     QTransform m = brush.transform();
  1560     QTransform m = brush.transform();
  1541 
  1561 
  1542     if (has_mirrored_repeat && style == Qt::LinearGradientPattern) {
  1562     if (has_mirrored_repeat && style == Qt::LinearGradientPattern) {
  2096 
  2116 
  2097 static inline bool needsEmulation(Qt::BrushStyle style)
  2117 static inline bool needsEmulation(Qt::BrushStyle style)
  2098 {
  2118 {
  2099     return !(style == Qt::SolidPattern
  2119     return !(style == Qt::SolidPattern
  2100              || (style == Qt::LinearGradientPattern
  2120              || (style == Qt::LinearGradientPattern
  2101                  && (QGLExtensions::glExtensions & QGLExtensions::MirroredRepeat)));
  2121                  && (QGLExtensions::glExtensions() & QGLExtensions::MirroredRepeat)));
  2102 }
  2122 }
  2103 
  2123 
  2104 void QOpenGLPaintEnginePrivate::updateUseEmulation()
  2124 void QOpenGLPaintEnginePrivate::updateUseEmulation()
  2105 {
  2125 {
  2106     use_emulation = !use_fragment_programs
  2126     use_emulation = !use_fragment_programs
  2418         if (d->use_fragment_programs && QGLOffscreen::isSupported()
  2438         if (d->use_fragment_programs && QGLOffscreen::isSupported()
  2419             && (hints & QPainter::HighQualityAntialiasing)) {
  2439             && (hints & QPainter::HighQualityAntialiasing)) {
  2420             d->high_quality_antialiasing = true;
  2440             d->high_quality_antialiasing = true;
  2421         } else {
  2441         } else {
  2422             d->high_quality_antialiasing = false;
  2442             d->high_quality_antialiasing = false;
  2423             if (QGLExtensions::glExtensions & QGLExtensions::SampleBuffers)
  2443             if (QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers)
  2424                 glEnable(GL_MULTISAMPLE);
  2444                 glEnable(GL_MULTISAMPLE);
  2425         }
  2445         }
  2426     } else {
  2446     } else {
  2427         d->high_quality_antialiasing = false;
  2447         d->high_quality_antialiasing = false;
  2428         if (QGLExtensions::glExtensions & QGLExtensions::SampleBuffers)
  2448         if (QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers)
  2429             glDisable(GL_MULTISAMPLE);
  2449             glDisable(GL_MULTISAMPLE);
  2430     }
  2450     }
  2431 
  2451 
  2432     if (d->high_quality_antialiasing) {
  2452     if (d->high_quality_antialiasing) {
  2433         d->offscreen.initialize();
  2453         d->offscreen.initialize();
  2434 
  2454 
  2435         if (!d->offscreen.isValid()) {
  2455         if (!d->offscreen.isValid()) {
  2436             DEBUG_ONCE_STR("Unable to initialize offscreen, disabling high quality antialiasing");
  2456             DEBUG_ONCE_STR("Unable to initialize offscreen, disabling high quality antialiasing");
  2437             d->high_quality_antialiasing = false;
  2457             d->high_quality_antialiasing = false;
  2438             if (QGLExtensions::glExtensions & QGLExtensions::SampleBuffers)
  2458             if (QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers)
  2439                 glEnable(GL_MULTISAMPLE);
  2459                 glEnable(GL_MULTISAMPLE);
  2440         }
  2460         }
  2441     }
  2461     }
  2442 
  2462 
  2443     d->has_antialiasing = d->high_quality_antialiasing
  2463     d->has_antialiasing = d->high_quality_antialiasing
  2444                           || ((hints & QPainter::Antialiasing)
  2464                           || ((hints & QPainter::Antialiasing)
  2445                               && (QGLExtensions::glExtensions & QGLExtensions::SampleBuffers));
  2465                               && (QGLExtensions::glExtensions() & QGLExtensions::SampleBuffers));
  2446 }
  2466 }
  2447 
  2467 
  2448 
  2468 
  2449 void QOpenGLPaintEnginePrivate::setPorterDuffData(float a, float b, float x, float y, float z)
  2469 void QOpenGLPaintEnginePrivate::setPorterDuffData(float a, float b, float x, float y, float z)
  2450 {
  2470 {
  4520 typedef QHash<glyph_t, QGLGlyphCoord*>  QGLGlyphHash;
  4540 typedef QHash<glyph_t, QGLGlyphCoord*>  QGLGlyphHash;
  4521 typedef QHash<QFontEngine*, QGLGlyphHash*> QGLFontGlyphHash;
  4541 typedef QHash<QFontEngine*, QGLGlyphHash*> QGLFontGlyphHash;
  4522 typedef QHash<quint64, QGLFontTexture*> QGLFontTexHash;
  4542 typedef QHash<quint64, QGLFontTexture*> QGLFontTexHash;
  4523 typedef QHash<const QGLContext*, QGLFontGlyphHash*> QGLContextHash;
  4543 typedef QHash<const QGLContext*, QGLFontGlyphHash*> QGLContextHash;
  4524 
  4544 
       
  4545 static inline void qt_delete_glyph_hash(QGLGlyphHash *hash)
       
  4546 {
       
  4547     qDeleteAll(*hash);
       
  4548     delete hash;
       
  4549 }
       
  4550 
  4525 class QGLGlyphCache : public QObject
  4551 class QGLGlyphCache : public QObject
  4526 {
  4552 {
  4527     Q_OBJECT
  4553     Q_OBJECT
  4528 public:
  4554 public:
  4529     QGLGlyphCache() : QObject(0) { current_cache = 0; }
  4555     QGLGlyphCache() : QObject(0) { current_cache = 0; }
  4560     for (int i=0; i < keys.size(); ++i) {
  4586     for (int i=0; i < keys.size(); ++i) {
  4561         QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
  4587         QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
  4562         if (font_cache->find(fe) != font_cache->end()) {
  4588         if (font_cache->find(fe) != font_cache->end()) {
  4563             ctx = keys.at(i);
  4589             ctx = keys.at(i);
  4564             QGLGlyphHash *cache = font_cache->take(fe);
  4590             QGLGlyphHash *cache = font_cache->take(fe);
  4565             delete cache;
  4591             qt_delete_glyph_hash(cache);
  4566             break;
  4592             break;
  4567         }
  4593         }
  4568     }
  4594     }
  4569 
  4595 
  4570     quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
  4596     quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
  4597 
  4623 
  4598     if (font_cache) {
  4624     if (font_cache) {
  4599         QList<QFontEngine *> keys = font_cache->keys();
  4625         QList<QFontEngine *> keys = font_cache->keys();
  4600         for (int i=0; i < keys.size(); ++i) {
  4626         for (int i=0; i < keys.size(); ++i) {
  4601             QFontEngine *fe = keys.at(i);
  4627             QFontEngine *fe = keys.at(i);
  4602             delete font_cache->take(fe);
  4628             qt_delete_glyph_hash(font_cache->take(fe));
  4603             quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
  4629             quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe);
  4604             QGLFontTexture *font_tex = qt_font_textures.take(font_key);
  4630             QGLFontTexture *font_tex = qt_font_textures.take(font_key);
  4605             if (font_tex) {
  4631             if (font_tex) {
  4606 #ifdef Q_WS_MAC
  4632 #ifdef Q_WS_MAC
  4607                 if (
  4633                 if (
  4638     qt_font_textures.clear();
  4664     qt_font_textures.clear();
  4639 
  4665 
  4640     QList<const QGLContext *> keys = qt_context_cache.keys();
  4666     QList<const QGLContext *> keys = qt_context_cache.keys();
  4641     for (int i=0; i < keys.size(); ++i) {
  4667     for (int i=0; i < keys.size(); ++i) {
  4642         QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
  4668         QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i));
  4643         qDeleteAll(*font_cache);
  4669         QGLFontGlyphHash::Iterator it = font_cache->begin();
       
  4670         for (; it != font_cache->end(); ++it)
       
  4671             qt_delete_glyph_hash(it.value());
  4644         font_cache->clear();
  4672         font_cache->clear();
  4645     }
  4673     }
  4646     qDeleteAll(qt_context_cache);
  4674     qDeleteAll(qt_context_cache);
  4647     qt_context_cache.clear();
  4675     qt_context_cache.clear();
  4648 }
  4676 }
  4921     glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
  4949     glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
  4922     glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
  4950     glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
  4923 
  4951 
  4924     glEnableClientState(GL_VERTEX_ARRAY);
  4952     glEnableClientState(GL_VERTEX_ARRAY);
  4925     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  4953     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  4926     bool antialias = !(ti.fontEngine->fontDef.styleStrategy & QFont::NoAntialias);
  4954     bool antialias = !(ti.fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
       
  4955                    && (d->matrix.type() > QTransform::TxTranslate);
  4927     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
  4956     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
  4928     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
  4957     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
  4929 
  4958 
  4930     for (int i=0; i< glyphs.size(); ++i) {
  4959     for (int i=0; i< glyphs.size(); ++i) {
  4931         QGLGlyphCoord *g = qt_glyph_cache()->lookup(ti.fontEngine, glyphs[i]);
  4960         QGLGlyphCoord *g = qt_glyph_cache()->lookup(ti.fontEngine, glyphs[i]);