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 |
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]); |