diff options
Diffstat (limited to 'src/quick/scenegraph/qsgcontext.cpp')
-rw-r--r-- | src/quick/scenegraph/qsgcontext.cpp | 513 |
1 files changed, 46 insertions, 467 deletions
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 842afe9dff..d52f69c7a3 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -38,27 +38,13 @@ ****************************************************************************/ #include <QtQuick/private/qsgcontext_p.h> -#include <QtQuick/private/qsgbatchrenderer_p.h> -#include <QtQuick/private/qsgdistancefieldutil_p.h> -#include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h> -#include <QtQuick/private/qsgdefaultrectanglenode_p.h> -#include <QtQuick/private/qsgdefaultimagenode_p.h> -#include <QtQuick/private/qsgdefaultpainternode_p.h> -#include <QtQuick/private/qsgdefaultglyphnode_p.h> -#include <QtQuick/private/qsgdistancefieldglyphnode_p.h> -#include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h> -#include <QtQuick/private/qsgatlastexture_p.h> -#include <QtQuick/private/qsgrenderloop_p.h> -#include <QtQuick/private/qsgdefaultlayer_p.h> - #include <QtQuick/private/qsgtexture_p.h> #include <QtQuick/private/qquickpixmapcache_p.h> +#include <QtQuick/private/qsgadaptationlayer_p.h> #include <QGuiApplication> #include <QScreen> -#include <QOpenGLContext> #include <QQuickWindow> -#include <QtGui/qopenglframebufferobject.h> #include <private/qqmlglobal_p.h> @@ -69,8 +55,6 @@ #include <private/qobject_p.h> #include <qmutex.h> -DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) - /* Comments about this class from Gunnar: @@ -114,31 +98,9 @@ Q_LOGGING_CATEGORY(QSG_LOG_TIME_GLYPH, "qt.scenegraph.time.glyph") // Timing inside the renderer base class Q_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER, "qt.scenegraph.time.renderer") -class QSGContextPrivate : public QObjectPrivate +bool qsg_useConsistentTiming() { -public: - QSGContextPrivate() - : antialiasingMethod(QSGContext::UndecidedAntialiasing) - , distanceFieldDisabled(qmlDisableDistanceField()) - , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing) - , distanceFieldAntialiasingDecided(false) - { - } - - ~QSGContextPrivate() - { - } - - QMutex mutex; - QSGContext::AntialiasingMethod antialiasingMethod; - bool distanceFieldDisabled; - QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing; - bool distanceFieldAntialiasingDecided; -}; - -static bool qsg_useConsistentTiming() -{ - static int use = -1; + int use = -1; if (use < 0) { use = !qEnvironmentVariableIsEmpty("QSG_FIXED_ANIMATION_STEP") && qgetenv("QSG_FIXED_ANIMATION_STEP") != "no" ? 1 : 0; @@ -274,20 +236,6 @@ public: QSGTexture *texture; }; -namespace QSGMultisampleAntialiasing { - class ImageNode : public QSGDefaultImageNode { - public: - void setAntialiasing(bool) { } - }; - - - class RectangleNode : public QSGDefaultRectangleNode { - public: - void setAntialiasing(bool) { } - }; -} - - /*! \class QSGContext @@ -300,92 +248,16 @@ namespace QSGMultisampleAntialiasing { */ QSGContext::QSGContext(QObject *parent) : - QObject(*(new QSGContextPrivate), parent) + QObject(parent) { - Q_D(QSGContext); - if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QSG_DISTANCEFIELD_ANTIALIASING"))) { - const QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING"); - d->distanceFieldAntialiasingDecided = true; - if (mode == "subpixel") - d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing; - else if (mode == "subpixel-lowq") - d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing; - else if (mode == "gray") - d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing; - } - - // Adds compatibility with Qt 5.3 and earlier's QSG_RENDER_TIMING - if (qEnvironmentVariableIsSet("QSG_RENDER_TIMING")) { - const_cast<QLoggingCategory &>(QSG_LOG_TIME_GLYPH()).setEnabled(QtDebugMsg, true); - const_cast<QLoggingCategory &>(QSG_LOG_TIME_TEXTURE()).setEnabled(QtDebugMsg, true); - const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERER()).setEnabled(QtDebugMsg, true); - const_cast<QLoggingCategory &>(QSG_LOG_TIME_RENDERLOOP()).setEnabled(QtDebugMsg, true); - const_cast<QLoggingCategory &>(QSG_LOG_TIME_COMPILATION()).setEnabled(QtDebugMsg, true); - } } - QSGContext::~QSGContext() { } -QSGRenderContext *QSGContext::createRenderContext() +void QSGContext::renderContextInitialized(QSGRenderContext *) { - return new QSGRenderContext(this); -} - -void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) -{ - Q_D(QSGContext); - - d->mutex.lock(); - if (d->antialiasingMethod == UndecidedAntialiasing) { - if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_ANTIALIASING_METHOD"))) { - const QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD"); - if (aaType == "msaa") - d->antialiasingMethod = MsaaAntialiasing; - else if (aaType == "vertex") - d->antialiasingMethod = VertexAntialiasing; - } - if (d->antialiasingMethod == UndecidedAntialiasing) { - if (renderContext->openglContext()->format().samples() > 0) - d->antialiasingMethod = MsaaAntialiasing; - else - d->antialiasingMethod = VertexAntialiasing; - } - } - - // With OpenGL ES, except for Angle on Windows, use GrayAntialiasing, unless - // some value had been requested explicitly. This could not be decided - // before without a context. Now the context is ready. - if (!d->distanceFieldAntialiasingDecided) { - d->distanceFieldAntialiasingDecided = true; -#ifndef Q_OS_WIN32 - if (renderContext->openglContext()->isOpenGLES()) - d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing; -#endif - } - - static bool dumped = false; - if (!dumped && QSG_LOG_INFO().isDebugEnabled()) { - dumped = true; - QSurfaceFormat format = renderContext->openglContext()->format(); - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - qCDebug(QSG_LOG_INFO) << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); - qCDebug(QSG_LOG_INFO) << "Depth Buffer: " << format.depthBufferSize(); - qCDebug(QSG_LOG_INFO) << "Stencil Buffer: " << format.stencilBufferSize(); - qCDebug(QSG_LOG_INFO) << "Samples: " << format.samples(); - qCDebug(QSG_LOG_INFO) << "GL_VENDOR: " << (const char *) funcs->glGetString(GL_VENDOR); - qCDebug(QSG_LOG_INFO) << "GL_RENDERER: " << (const char *) funcs->glGetString(GL_RENDERER); - qCDebug(QSG_LOG_INFO) << "GL_VERSION: " << (const char *) funcs->glGetString(GL_VERSION); - QSet<QByteArray> exts = renderContext->openglContext()->extensions(); - QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e; - qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData(); - qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << renderContext->maxTextureSize(); - qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext); - } - - d->mutex.unlock(); } void QSGContext::renderContextInvalidated(QSGRenderContext *) @@ -396,9 +268,9 @@ void QSGContext::renderContextInvalidated(QSGRenderContext *) /*! Convenience factory function for creating a colored rectangle with the given geometry. */ -QSGRectangleNode *QSGContext::createRectangleNode(const QRectF &rect, const QColor &c) +QSGInternalRectangleNode *QSGContext::createInternalRectangleNode(const QRectF &rect, const QColor &c) { - QSGRectangleNode *node = createRectangleNode(); + QSGInternalRectangleNode *node = createInternalRectangleNode(); node->setRect(rect); node->setColor(c); node->update(); @@ -406,139 +278,76 @@ QSGRectangleNode *QSGContext::createRectangleNode(const QRectF &rect, const QCol } /*! - Factory function for scene graph backends of the Rectangle element. - */ -QSGRectangleNode *QSGContext::createRectangleNode() -{ - Q_D(QSGContext); - return d->antialiasingMethod == MsaaAntialiasing - ? new QSGMultisampleAntialiasing::RectangleNode - : new QSGDefaultRectangleNode; -} - -/*! - Factory function for scene graph backends of the Image element. - */ -QSGImageNode *QSGContext::createImageNode() -{ - Q_D(QSGContext); - return d->antialiasingMethod == MsaaAntialiasing - ? new QSGMultisampleAntialiasing::ImageNode - : new QSGDefaultImageNode; -} - -/*! - Factory function for scene graph backends of Painter elements + Creates a new shader effect helper instance. This function is called on the + gui thread, unlike the others. This is necessary in order to provide + adaptable, backend-specific shader effect functionality to the gui thread too. */ -QSGPainterNode *QSGContext::createPainterNode(QQuickPaintedItem *item) +QSGGuiThreadShaderEffectManager *QSGContext::createGuiThreadShaderEffectManager() { - return new QSGDefaultPainterNode(item); + return nullptr; } /*! - Factory function for scene graph backends of the Text elements; + Creates a new shader effect node. The default of returning nullptr is + valid as long as the backend does not claim SupportsShaderEffectNode or + ignoring ShaderEffect elements is acceptable. */ -QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) +QSGShaderEffectNode *QSGContext::createShaderEffectNode(QSGRenderContext *, QSGGuiThreadShaderEffectManager *) { - Q_D(QSGContext); - - if (d->distanceFieldDisabled || preferNativeGlyphNode) { - return new QSGDefaultGlyphNode; - } else { - QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc); - node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing); - return node; - } + return nullptr; } /*! - * Factory function for scene graph backends of the QStyle stylable elements. Returns a - * null pointer if the backend doesn't provide its own node type. - */ -QSGNinePatchNode *QSGContext::createNinePatchNode() -{ - return 0; -} - -/*! - Factory function for scene graph backends of layers. + Creates a new animation driver. */ -QSGLayer *QSGContext::createLayer(QSGRenderContext *renderContext) -{ - return new QSGDefaultLayer(renderContext); -} - -QSurfaceFormat QSGContext::defaultSurfaceFormat() const +QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent) { - QSurfaceFormat format = QSurfaceFormat::defaultFormat(); - static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); - static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER"); - static bool enableDebug = qEnvironmentVariableIsSet("QSG_OPENGL_DEBUG"); - format.setDepthBufferSize(useDepth ? 24 : 0); - format.setStencilBufferSize(useStencil ? 8 : 0); - if (enableDebug) - format.setOption(QSurfaceFormat::DebugContext); - if (QQuickWindow::hasDefaultAlphaBuffer()) - format.setAlphaBufferSize(8); - format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - return format; + return new QSGAnimationDriver(parent); } -/*! - Returns the minimum supported framebuffer object size. - */ - QSize QSGContext::minimumFBOSize() const { return QSize(1, 1); } - - /*! - Sets whether or not the scene graph should use the distance field technique to render text - */ -void QSGContext::setDistanceFieldEnabled(bool enabled) + Returns a pointer to the (presumably) global renderer interface. + + \note This function may be called on the gui thread in order to get access + to QSGRendererInterface::graphicsApi() and other getters. + + \note it is expected that the simple queries (graphicsApi, shaderType, + etc.) are available regardless of the render context validity (i.e. + scenegraph status). This does not apply to engine-specific getters like + getResource(). In the end this means that this function must always return + a valid object in subclasses, even when renderContext->isValid() is false. + The typical pattern is to implement the QSGRendererInterface in the + QSGContext or QSGRenderContext subclass itself, whichever is more suitable. + */ +QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext) { - d_func()->distanceFieldDisabled = !enabled; + Q_UNUSED(renderContext); + qWarning("QSGRendererInterface not implemented"); + return nullptr; } - -/*! - Returns true if the scene graph uses the distance field technique to render text - */ -bool QSGContext::isDistanceFieldEnabled() const +QSGRenderContext::QSGRenderContext(QSGContext *context) + : m_sg(context) + , m_distanceFieldCacheManager(0) { - return !d_func()->distanceFieldDisabled; } - - -/*! - Creates a new animation driver. - */ - -QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent) +QSGRenderContext::~QSGRenderContext() { - return new QSGAnimationDriver(parent); } -QSGRenderContext::QSGRenderContext(QSGContext *context) - : m_gl(0) - , m_sg(context) - , m_atlasManager(0) - , m_depthStencilManager(0) - , m_distanceFieldCacheManager(0) - , m_maxTextureSize(0) - , m_brokenIBOs(false) - , m_serializedRender(false) - , m_attachToGLContext(true) +void QSGRenderContext::initialize(void *context) { + Q_UNUSED(context); } -QSGRenderContext::~QSGRenderContext() +void QSGRenderContext::invalidate() { - invalidate(); } void QSGRenderContext::endSync() @@ -547,49 +356,14 @@ void QSGRenderContext::endSync() m_texturesToDelete.clear(); } -static QBasicMutex qsg_framerender_mutex; - -void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) -{ - if (m_serializedRender) - qsg_framerender_mutex.lock(); - - renderer->renderScene(fboId); - - if (m_serializedRender) - qsg_framerender_mutex.unlock(); - -} - /*! Factory function for scene graph backends of the distance-field glyph cache. */ -QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &font) -{ - if (!m_distanceFieldCacheManager) - m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager; - - QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); - if (!cache) { - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); - m_distanceFieldCacheManager->insertCache(font, cache); - } - - return cache; -} - -void QSGRenderContext::setAttachToGLContext(bool attach) +QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &) { - Q_ASSERT(!isValid()); - m_attachToGLContext = attach; + return nullptr; } -#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext" - -QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context) -{ - return qobject_cast<QSGRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>()); -} void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine) { @@ -598,178 +372,18 @@ void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine) } /*! - Initializes the scene graph render context with the GL context \a context. This also - emits the ready() signal so that the QML graph can start building scene graph nodes. - */ -void QSGRenderContext::initialize(QOpenGLContext *context) -{ - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); - - // Sanity check the surface format, in case it was overridden by the application - QSurfaceFormat requested = m_sg->defaultSurfaceFormat(); - QSurfaceFormat actual = context->format(); - if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0) - qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors"); - if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0) - qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors"); - - if (!m_atlasManager) - m_atlasManager = new QSGAtlasTexture::Manager(); - - Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!"); - m_gl = context; - if (m_attachToGLContext) { - Q_ASSERT(!context->property(QSG_RENDERCONTEXT_PROPERTY).isValid()); - context->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this)); - } - m_sg->renderContextInitialized(this); - -#ifdef Q_OS_LINUX - const char *vendor = (const char *) funcs->glGetString(GL_VENDOR); - if (vendor && strstr(vendor, "nouveau")) - m_brokenIBOs = true; - const char *renderer = (const char *) funcs->glGetString(GL_RENDERER); - if (renderer && strstr(renderer, "llvmpipe")) - m_serializedRender = true; - if (vendor && renderer && strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16")) - m_brokenIBOs = true; -#endif - - emit initialized(); -} - -void QSGRenderContext::invalidate() -{ - if (!m_gl) - return; - - qDeleteAll(m_texturesToDelete); - m_texturesToDelete.clear(); - - qDeleteAll(m_textures); - m_textures.clear(); - - /* The cleanup of the atlas textures is a bit intriguing. - As part of the cleanup in the threaded render loop, we - do: - 1. call this function - 2. call QCoreApp::sendPostedEvents() to immediately process - any pending deferred deletes. - 3. delete the GL context. - - As textures need the atlas manager while cleaning up, the - manager needs to be cleaned up after the textures, so - we post a deleteLater here at the very bottom so it gets - deferred deleted last. - - Another alternative would be to use a QPointer in - QSGAtlasTexture::Texture, but this seemed simpler. - */ - m_atlasManager->invalidate(); - m_atlasManager->deleteLater(); - m_atlasManager = 0; - - // The following piece of code will read/write to the font engine's caches, - // potentially from different threads. However, this is safe because this - // code is only called from QQuickWindow's shutdown which is called - // only when the GUI is blocked, and multiple threads will call it in - // sequence. (see qsgdefaultglyphnode_p.cpp's init()) - for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(), - end = m_fontEnginesToClean.constEnd(); it != end; ++it) { - (*it)->clearGlyphCache(m_gl); - if (!(*it)->ref.deref()) - delete *it; - } - m_fontEnginesToClean.clear(); - - delete m_depthStencilManager; - m_depthStencilManager = 0; - - delete m_distanceFieldCacheManager; - m_distanceFieldCacheManager = 0; - - if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this)) - m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); - m_gl = 0; - - m_sg->renderContextInvalidated(this); - emit invalidated(); -} - -/*! - Returns a shared pointer to a depth stencil buffer that can be used with \a fbo. - */ -QSharedPointer<QSGDepthStencilBuffer> QSGRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo) -{ - if (!m_gl) - return QSharedPointer<QSGDepthStencilBuffer>(); - QSGDepthStencilBufferManager *manager = depthStencilBufferManager(); - QSGDepthStencilBuffer::Format format; - format.size = fbo->size(); - format.samples = fbo->format().samples(); - format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment; - QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format); - if (buffer.isNull()) { - buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format)); - manager->insertBuffer(buffer); - } - return buffer; -} - -/*! - Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom - implementations of \l depthStencilBufferForFbo(). - */ -QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager() -{ - if (!m_gl) - return 0; - if (!m_depthStencilManager) - m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl); - return m_depthStencilManager; -} - - -/*! Factory function for texture objects. If \a image is a valid image, the QSGTexture::setImage function will be called with \a image as argument. */ -QSGTexture *QSGRenderContext::createTexture(const QImage &image, uint flags) const -{ - bool atlas = flags & CreateTexture_Atlas; - bool mipmap = flags & CreateTexture_Mipmap; - bool alpha = flags & CreateTexture_Alpha; - - // The atlas implementation is only supported from the render thread and - // does not support mipmaps. - if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) { - QSGTexture *t = m_atlasManager->create(image, alpha); - if (t) - return t; - } - - QSGPlainTexture *texture = new QSGPlainTexture(); - texture->setImage(image); - if (texture->hasAlphaChannel() && !alpha) - texture->setHasAlphaChannel(false); - - return texture; -} - /*! Factory function for the scene graph renderers. The renderers are used for the toplevel renderer and once for every QQuickShaderEffectSource used in the QML scene. */ -QSGRenderer *QSGRenderContext::createRenderer() -{ - return new QSGBatchRenderer::Renderer(this); -} QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window) { @@ -799,41 +413,6 @@ void QSGRenderContext::textureFactoryDestroyed(QObject *o) m_mutex.unlock(); } -/*! - Compile \a shader, optionally using \a vertexCode and \a fragmentCode as - replacement for the source code supplied by \a shader. - - If \a vertexCode or \a fragmentCode is supplied, the caller is responsible - for setting up attribute bindings. - - \a material is supplied in case the implementation needs to take the - material flags into account. - */ - -void QSGRenderContext::compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode, const char *fragmentCode) -{ - Q_UNUSED(material); - if (vertexCode || fragmentCode) { - Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0, - "QSGRenderContext::compile()", - "materials with custom compile step cannot have custom vertex/fragment code"); - QOpenGLShaderProgram *p = shader->program(); - p->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader()); - p->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader()); - p->link(); - if (!p->isLinked()) - qWarning() << "shader compilation failed:" << endl << p->log(); - } else { - shader->compile(); - } -} - -void QSGRenderContext::initialize(QSGMaterialShader *shader) -{ - shader->program()->bind(); - shader->initialize(); -} - #include "qsgcontext.moc" QT_END_NAMESPACE |