diff options
Diffstat (limited to 'src/gui/opengl/qopenglpaintengine.cpp')
-rw-r--r-- | src/gui/opengl/qopenglpaintengine.cpp | 136 |
1 files changed, 99 insertions, 37 deletions
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 90652a5ab8..aeb4fc0b7a 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -99,6 +99,12 @@ QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate() { delete shaderManager; + vertexBuffer.destroy(); + texCoordBuffer.destroy(); + opacityBuffer.destroy(); + indexBuffer.destroy(); + vao.destroy(); + if (elementIndicesVBOId != 0) { funcs.glDeleteBuffers(1, &elementIndicesVBOId); elementIndicesVBOId = 0; @@ -578,6 +584,12 @@ void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QO setCoords(staticVertexCoordinateArray, dest); setCoords(staticTextureCoordinateArray, srcTextureRect); + setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true); + + uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); + uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8); + funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } @@ -664,6 +676,11 @@ void QOpenGL2PaintEngineExPrivate::resetGLState() float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; funcs.glVertexAttrib4fv(3, color); } + if (vao.isCreated()) { + vao.release(); + funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); + funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } } void QOpenGL2PaintEngineEx::endNativePainting() @@ -696,16 +713,16 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode) } if (newMode == ImageDrawingMode) { - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray); + uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); + uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8); } if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) { - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data(), vertexCoordinateArray.vertexCount() * 2); + uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data(), textureCoordinateArray.vertexCount() * 2); if (newMode == ImageOpacityArrayDrawingMode) - setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data()); + uploadData(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data(), opacityArray.size()); } // This needs to change when we implement high-quality anti-aliasing... @@ -761,6 +778,8 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (matrixDirty) updateMatrix(); + const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint); + const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); // Check to see if there's any hints @@ -824,9 +843,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) prepareForDraw(currentBrush.isOpaque()); #ifdef QT_OPENGL_CACHE_AS_VBOS funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + uploadData(QT_VERTEX_COORD_ATTR, 0, cache->vertexCount); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); #else - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); + uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2); #endif funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount); @@ -881,7 +901,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) // Flatten the path at the current scale factor and fill it into the cache struct. if (updateCache) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); cache->vertexCount = polys.vertices.size() / 2; cache->indexCount = polys.indices.size(); cache->primitiveType = GL_TRIANGLES; @@ -920,6 +940,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) #ifdef QT_OPENGL_CACHE_AS_VBOS funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); + uploadData(QT_VERTEX_COORDS_ATTR, 0, cache->vertexCount); setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); if (cache->indexType == QVertexIndexVector::UnsignedInt) funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); @@ -928,11 +949,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); #else - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); - if (cache->indexType == QVertexIndexVector::UnsignedInt) - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices); - else - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices); + uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2); + const GLenum indexValueType = cache->indexType == QVertexIndexVector::UnsignedInt ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + const bool useIndexVbo = uploadIndexData(cache->indices, indexValueType, cache->indexCount); + funcs.glDrawElements(cache->primitiveType, cache->indexCount, indexValueType, useIndexVbo ? nullptr : cache->indices); #endif } else { @@ -950,18 +970,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) && (bbox.top() > -0x8000 * inverseScale) && (bbox.bottom() < 0x8000 * inverseScale); if (withinLimits) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); QVarLengthArray<float> vertices(polys.vertices.size()); for (int i = 0; i < polys.vertices.size(); ++i) vertices[i] = float(inverseScale * polys.vertices.at(i)); prepareForDraw(currentBrush.isOpaque()); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData()); - if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) - funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data()); - else - funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data()); + uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size()); + const GLenum indexValueType = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; + const bool useIndexVbo = uploadIndexData(polys.indices.data(), indexValueType, polys.indices.size()); + funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), indexValueType, useIndexVbo ? nullptr : polys.indices.data()); } else { // We can't handle big, concave painter paths with OpenGL without stencil buffer. qWarning("Painter path exceeds +/-32767 pixels."); @@ -1083,7 +1102,8 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, } else { funcs.glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); } - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); + + uploadData(QT_VERTEX_COORDS_ATTR, data, count * 2); funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count); #endif } @@ -1213,7 +1233,8 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect) { setCoords(staticVertexCoordinateArray, boundingRect); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); + + uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } @@ -1222,16 +1243,12 @@ void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stop GLenum primitive) { // Now setup the pointer to the vertex array: - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); + uploadData(QT_VERTEX_COORDS_ATTR, data, stops[stopCount-1] * 2); int previousStop = 0; for (int i=0; i<stopCount; ++i) { int stop = stops[i]; -/* - qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); - for (int i=previousStop; i<stop; ++i) - qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y); -*/ + funcs.glDrawArrays(primitive, previousStop, stop - previousStop); previousStop = stop; } @@ -1323,14 +1340,9 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p if (opaque) { prepareForDraw(opaque); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); - funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); - -// QBrush b(Qt::green); -// d->setBrush(&b); -// d->prepareForDraw(true); -// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); + uploadData(QT_VERTEX_COORDS_ATTR, stroker.vertices(), stroker.vertexCount()); + funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); } else { qreal width = qpen_widthf(pen) / 2; if (width == 0) @@ -1839,8 +1851,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly } if (glyphFormat != QFontEngine::Format_ARGB || recreateVertexArrays) { - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); - setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); + uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data(), vertexCoordinates->vertexCount() * 2); + uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data(), textureCoordinates->vertexCount() * 2); } if (!snapToPixelGrid) { @@ -1904,7 +1916,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly #if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); #else - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); + const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); + funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); #endif shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2); @@ -1955,7 +1968,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); #else - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); + const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); + funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); #endif } @@ -2074,6 +2088,15 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) return false; } + if (d->ctx != QOpenGLContext::currentContext() + || (d->ctx && QOpenGLContext::currentContext() && d->ctx->format() != QOpenGLContext::currentContext()->format())) { + d->vertexBuffer.destroy(); + d->texCoordBuffer.destroy(); + d->opacityBuffer.destroy(); + d->indexBuffer.destroy(); + d->vao.destroy(); + } + d->ctx = QOpenGLContext::currentContext(); d->ctx->d_func()->active_engine = this; @@ -2081,6 +2104,42 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) d->funcs.initializeOpenGLFunctions(); + // Generate a new Vertex Array Object if we don't have one already. We can + // only hit the VAO-based path when using a core profile context. This is + // because while non-core contexts can support VAOs via extensions, legacy + // components like the QtOpenGL module do not know about VAOs. There are + // still tests for QGL-QOpenGL paint engine interoperability, so keep the + // status quo for now, and avoid introducing a VAO in non-core contexts. + const bool needsVAO = d->ctx->format().profile() == QSurfaceFormat::CoreProfile + && d->ctx->format().version() >= qMakePair(3, 2); + if (needsVAO && !d->vao.isCreated()) { + bool created = d->vao.create(); + + // If we managed to create it then we have a profile that supports VAOs + if (created) { + d->vao.bind(); + + // Generate a new Vertex Buffer Object if we don't have one already + if (!d->vertexBuffer.isCreated()) { + d->vertexBuffer.create(); + // Set its usage to StreamDraw, we will use this buffer only a few times before refilling it + d->vertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + if (!d->texCoordBuffer.isCreated()) { + d->texCoordBuffer.create(); + d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + if (!d->opacityBuffer.isCreated()) { + d->opacityBuffer.create(); + d->opacityBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + if (!d->indexBuffer.isCreated()) { + d->indexBuffer.create(); + d->indexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); + } + } + } + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) d->vertexAttributeArraysEnabledState[i] = false; @@ -2162,6 +2221,9 @@ void QOpenGL2PaintEngineEx::ensureActive() Q_D(QOpenGL2PaintEngineEx); QOpenGLContext *ctx = d->ctx; + if (d->vao.isCreated()) + d->vao.bind(); + if (isActive() && ctx->d_func()->active_engine != this) { ctx->d_func()->active_engine = this; d->needsSync = true; |