summaryrefslogtreecommitdiffstats
path: root/src/opengl/qgl.cpp
diff options
context:
space:
mode:
authorKurt Korbatits <kurt.korbatits@nokia.com>2010-01-07 23:30:02 (GMT)
committerKurt Korbatits <kurt.korbatits@nokia.com>2010-01-07 23:30:02 (GMT)
commit3f3e86d6fce5bb781bc41def35d0f15c58ef769c (patch)
treef79a0317d168a1961c11c2b8f3b772029e2902e1 /src/opengl/qgl.cpp
parentdbbf451755d34be44f6b7ac2e7c03ffe5528fb1b (diff)
parenta3c1b0703575ed5fc364011c73dc104ecdb8ef0c (diff)
downloadQt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.zip
Qt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.tar.gz
Qt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.tar.bz2
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt-multimedia-team into 4.6
Diffstat (limited to 'src/opengl/qgl.cpp')
-rw-r--r--src/opengl/qgl.cpp199
1 files changed, 122 insertions, 77 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 1bd1b91..c3e4a2e 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -397,8 +397,7 @@ static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
\i \link setDirectRendering() Direct rendering:\endlink Enabled.
\i \link setOverlay() Overlay:\endlink Disabled.
\i \link setPlane() Plane:\endlink 0 (i.e., normal plane).
- \i \link setSampleBuffers() Multisample buffers:\endlink Enabled on
- OpenGL/ES 2.0, disabled on other platforms.
+ \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
\endlist
*/
@@ -1437,6 +1436,18 @@ void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
m_guards = guard->m_next;
}
+const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
+{
+ if (!ctx)
+ return 0;
+ QList<const QGLContext *> shares
+ (QGLContextPrivate::contextGroup(ctx)->shares());
+ if (shares.size() >= 2)
+ return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0);
+ else
+ return 0;
+}
+
QGLContextPrivate::~QGLContextPrivate()
{
if (!group->m_refs.deref()) {
@@ -1485,6 +1496,8 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
current_fbo = 0;
default_fbo = 0;
active_engine = 0;
+ for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
+ vertexAttributeArraysEnabledState[i] = false;
}
QGLContext* QGLContext::currentCtx = 0;
@@ -1730,12 +1743,6 @@ struct DDSFormat {
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
#endif
-Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg)
-Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
-{
- return _qgl_share_reg();
-}
-
/*!
\class QGLContext
\brief The QGLContext class encapsulates an OpenGL rendering context.
@@ -1875,6 +1882,35 @@ void QGLContextPrivate::cleanup()
{
}
+#define ctx q_ptr
+void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled)
+{
+ Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT);
+ Q_ASSERT(glEnableVertexAttribArray);
+
+ if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled)
+ glDisableVertexAttribArray(arrayIndex);
+
+ if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled)
+ glEnableVertexAttribArray(arrayIndex);
+
+ vertexAttributeArraysEnabledState[arrayIndex] = enabled;
+}
+
+void QGLContextPrivate::syncGlState()
+{
+ Q_ASSERT(glEnableVertexAttribArray);
+ for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) {
+ if (vertexAttributeArraysEnabledState[i])
+ glEnableVertexAttribArray(i);
+ else
+ glDisableVertexAttribArray(i);
+ }
+
+}
+#undef ctx
+
+
/*!
\overload
@@ -2064,6 +2100,29 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
// #define QGL_BIND_TEXTURE_DEBUG
+// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout
+static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
+{
+ const int width = img.width();
+ const int height = img.height();
+
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
+ || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian))
+ {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+ } else {
+ for (int i = 0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x = 0; x < width; ++x)
+ p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
+ }
+ }
+}
+
QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
const qint64 key, QGLContext::BindOptions options)
{
@@ -2216,23 +2275,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
// 32 in the switch above is for the RGB16 case, where we set
// the format to GL_RGB
Q_ASSERT(img.depth() == 32);
- const int width = img.width();
- const int height = img.height();
-
- if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
- || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
- for (int i=0; i < height; ++i) {
- uint *p = (uint *) img.scanLine(i);
- for (int x=0; x<width; ++x)
- p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
- }
- } else {
- for (int i=0; i < height; ++i) {
- uint *p = (uint *) img.scanLine(i);
- for (int x=0; x<width; ++x)
- p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
- }
- }
+ qgl_byteSwapImage(img, pixel_type);
}
#ifdef QT_OPENGL_ES
// OpenGL/ES requires that the internal and external formats be identical.
@@ -2948,7 +2991,7 @@ bool QGLContext::create(const QGLContext* shareContext)
wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer();
}
if (d->sharing) // ok, we managed to share
- qgl_share_reg()->addShare(this, shareContext);
+ QGLContextGroup::addShare(this, shareContext);
return d->valid;
}
@@ -3804,6 +3847,11 @@ bool QGLWidget::event(QEvent *e)
}
#if defined(QT_OPENGL_ES)
+ // A re-parent is likely to destroy the X11 window and re-create it. It is important
+ // that we free the EGL surface _before_ the winID changes - otherwise we can leak.
+ if (e->type() == QEvent::ParentAboutToChange)
+ d->glcx->d_func()->destroyEglSurfaceForDevice();
+
if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) {
// The window may have been re-created during re-parent or state change - if so, the EGL
// surface will need to be re-created.
@@ -4291,6 +4339,7 @@ static void qt_save_gl_state()
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
@@ -4344,6 +4393,10 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
\note This function clears the stencil buffer.
\note This function is not supported on OpenGL/ES systems.
+
+ \note This function temporarily disables depth-testing when the
+ text is drawn.
+
\l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
@@ -4362,9 +4415,9 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
int height = d->glcx->device()->height();
bool auto_swap = autoBufferSwap();
+ QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+ qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
QPaintEngine *engine = paintEngine();
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
if (engine->isActive()) {
@@ -4384,11 +4437,6 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
d->disable_clear_on_painter_begin = true;
- if (engine->type() == QPaintEngine::OpenGL2) {
- qt_save_gl_state();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
p = new QPainter(this);
}
@@ -4412,11 +4460,8 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
delete p;
setAutoBufferSwap(auto_swap);
d->disable_clear_on_painter_begin = false;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_restore_gl_state();
}
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+ qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
#else // QT_OPENGL_ES
Q_UNUSED(x);
Q_UNUSED(y);
@@ -4434,6 +4479,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
have the labels move with the model as it is rotated etc.
\note This function is not supported on OpenGL/ES systems.
+
+ \note If depth testing is enabled before this function is called,
+ then the drawn text will be depth-tested against the models that
+ have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)}
+ before calling this function to annotate the models without
+ depth-testing the text.
+
\l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
@@ -4457,9 +4509,9 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
&win_x, &win_y, &win_z);
win_y = height - win_y; // y is inverted
+ QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+ qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
QPaintEngine *engine = paintEngine();
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
@@ -4473,8 +4525,6 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
d->disable_clear_on_painter_begin = true;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_save_gl_state();
p = new QPainter(this);
}
@@ -4503,13 +4553,10 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
p->end();
delete p;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_restore_gl_state();
setAutoBufferSwap(auto_swap);
d->disable_clear_on_painter_begin = false;
}
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+ qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
#else // QT_OPENGL_ES
Q_UNUSED(x);
Q_UNUSED(y);
@@ -4823,38 +4870,39 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent,
void QGLExtensions::init_extensions()
{
- QList<QByteArray> extensions = QByteArray(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))).split(' ');
- if (extensions.contains("GL_ARB_texture_rectangle"))
+ QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
+
+ if (extensions.match("GL_ARB_texture_rectangle"))
glExtensions |= TextureRectangle;
- if (extensions.contains("GL_ARB_multisample"))
+ if (extensions.match("GL_ARB_multisample"))
glExtensions |= SampleBuffers;
- if (extensions.contains("GL_SGIS_generate_mipmap"))
+ if (extensions.match("GL_SGIS_generate_mipmap"))
glExtensions |= GenerateMipmap;
- if (extensions.contains("GL_ARB_texture_compression"))
+ if (extensions.match("GL_ARB_texture_compression"))
glExtensions |= TextureCompression;
- if (extensions.contains("GL_EXT_texture_compression_s3tc"))
+ if (extensions.match("GL_EXT_texture_compression_s3tc"))
glExtensions |= DDSTextureCompression;
- if (extensions.contains("GL_OES_compressed_ETC1_RGB8_texture"))
+ if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture"))
glExtensions |= ETC1TextureCompression;
- if (extensions.contains("GL_IMG_texture_compression_pvrtc"))
+ if (extensions.match("GL_IMG_texture_compression_pvrtc"))
glExtensions |= PVRTCTextureCompression;
- if (extensions.contains("GL_ARB_fragment_program"))
+ if (extensions.match("GL_ARB_fragment_program"))
glExtensions |= FragmentProgram;
- if (extensions.contains("GL_ARB_fragment_shader"))
+ if (extensions.match("GL_ARB_fragment_shader"))
glExtensions |= FragmentShader;
- if (extensions.contains("GL_ARB_texture_mirrored_repeat"))
+ if (extensions.match("GL_ARB_texture_mirrored_repeat"))
glExtensions |= MirroredRepeat;
- if (extensions.contains("GL_EXT_framebuffer_object"))
+ if (extensions.match("GL_EXT_framebuffer_object"))
glExtensions |= FramebufferObject;
- if (extensions.contains("GL_EXT_stencil_two_side"))
+ if (extensions.match("GL_EXT_stencil_two_side"))
glExtensions |= StencilTwoSide;
- if (extensions.contains("GL_EXT_stencil_wrap"))
+ if (extensions.match("GL_EXT_stencil_wrap"))
glExtensions |= StencilWrap;
- if (extensions.contains("GL_EXT_packed_depth_stencil"))
+ if (extensions.match("GL_EXT_packed_depth_stencil"))
glExtensions |= PackedDepthStencil;
- if (extensions.contains("GL_NV_float_buffer"))
+ if (extensions.match("GL_NV_float_buffer"))
glExtensions |= NVFloatBuffer;
- if (extensions.contains("GL_ARB_pixel_buffer_object"))
+ if (extensions.match("GL_ARB_pixel_buffer_object"))
glExtensions |= PixelBufferObject;
#if defined(QT_OPENGL_ES_2)
glExtensions |= FramebufferObject;
@@ -4862,26 +4910,26 @@ void QGLExtensions::init_extensions()
glExtensions |= FragmentShader;
#endif
#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
- if (extensions.contains("GL_OES_framebuffer_object"))
+ if (extensions.match("GL_OES_framebuffer_object"))
glExtensions |= FramebufferObject;
#endif
#if defined(QT_OPENGL_ES)
- if (extensions.contains("GL_OES_packed_depth_stencil"))
+ if (extensions.match("GL_OES_packed_depth_stencil"))
glExtensions |= PackedDepthStencil;
#endif
- if (extensions.contains("GL_ARB_framebuffer_object")) {
+ if (extensions.match("GL_ARB_framebuffer_object")) {
// ARB_framebuffer_object also includes EXT_framebuffer_blit.
glExtensions |= FramebufferObject;
glExtensions |= FramebufferBlit;
}
- if (extensions.contains("GL_EXT_framebuffer_blit"))
+ if (extensions.match("GL_EXT_framebuffer_blit"))
glExtensions |= FramebufferBlit;
- if (extensions.contains("GL_ARB_texture_non_power_of_two"))
+ if (extensions.match("GL_ARB_texture_non_power_of_two"))
glExtensions |= NPOTTextures;
- if (extensions.contains("GL_EXT_bgra"))
+ if (extensions.match("GL_EXT_bgra"))
glExtensions |= BGRATextureFormat;
}
@@ -4929,7 +4977,7 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
-void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) {
Q_ASSERT(context && share);
if (context->d_ptr->group == share->d_ptr->group)
return;
@@ -4950,11 +4998,7 @@ void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *sha
group->m_shares.append(context);
}
-QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
- return context->d_ptr->group->m_shares;
-}
-
-void QGLShareRegister::removeShare(const QGLContext *context) {
+void QGLContextGroup::removeShare(const QGLContext *context) {
// Remove the context from the group.
QGLContextGroup *group = context->d_ptr->group;
if (group->m_shares.isEmpty())
@@ -5363,11 +5407,12 @@ QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len)
// Restore the default pixel alignment for later texture uploads.
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- // Set the invert flag for the texture.
+ // Set the invert flag for the texture. The "vertical flip"
+ // flag in PVR is the opposite sense to our sense of inversion.
if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0)
- options |= QGLContext::InvertedYBindOption;
- else
options &= ~QGLContext::InvertedYBindOption;
+ else
+ options |= QGLContext::InvertedYBindOption;
return QSize(pvrHeader->width, pvrHeader->height);
}