void SSGQuickLayer::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; markDirtyTexture(); }
void QSGDefaultLayer::setFormat(GLenum format) { if (format == m_format) return; m_format = format; markDirtyTexture(); }
void QSGDefaultLayer::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; markDirtyTexture(); }
void QQuickContext2DTexture::paintWithoutTiles(QQuickContext2DCommandBuffer *ccb) { if (!ccb || ccb->isEmpty()) return; QPaintDevice* device = beginPainting(); if (!device) { endPainting(); return; } QPainter p; p.begin(device); if (m_antialiasing) p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, true); else p.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing | QPainter::TextAntialiasing, false); if (m_smooth) p.setRenderHint(QPainter::SmoothPixmapTransform, true); else p.setRenderHint(QPainter::SmoothPixmapTransform, false); p.setCompositionMode(QPainter::CompositionMode_SourceOver); ccb->replay(&p, m_state, scaleFactor()); endPainting(); markDirtyTexture(); }
void SSGQuickLayer::setHasMipmaps(bool mipmap) { if (mipmap == m_mipmap) return; m_mipmap = mipmap; if (m_mipmap && m_fbo && !m_fbo->format().mipmap()) markDirtyTexture(); }
void SSGQuickLayer::setLive(bool live) { if (live == m_live) return; m_live = live; if (m_live && (!m_item || m_size.isNull())) { delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_depthStencilBuffer.clear(); } markDirtyTexture(); }
void SSGQuickLayer::setSize(const QSize &size) { if (size == m_size) return; m_size = size; if (m_live && m_size.isNull()) { delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_depthStencilBuffer.clear(); } markDirtyTexture(); }
void SSGQuickLayer::setItem(QSGNode *item) { if (item == m_item) return; m_item = item; if (m_live && !m_item) { delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_depthStencilBuffer.clear(); } markDirtyTexture(); }
void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb) { QQuickContext2D::mutex.lock(); if (canvasDestroyed()) { delete ccb; QQuickContext2D::mutex.unlock(); return; } QQuickContext2D::mutex.unlock(); #if QT_CONFIG(opengl) GLAcquireContext currentContext(m_gl, m_surface); #endif if (!m_tiledCanvas) { paintWithoutTiles(ccb); delete ccb; return; } QRect tiledRegion = createTiles(m_canvasWindow.intersected(QRect(QPoint(0, 0), m_canvasSize))); if (!tiledRegion.isEmpty()) { QRect dirtyRect; for (QQuickContext2DTile* tile : qAsConst(m_tiles)) { if (tile->dirty()) { if (dirtyRect.isEmpty()) dirtyRect = tile->rect(); else dirtyRect |= tile->rect(); } } if (beginPainting()) { QQuickContext2D::State oldState = m_state; for (QQuickContext2DTile* tile : qAsConst(m_tiles)) { if (tile->dirty()) { ccb->replay(tile->createPainter(m_smooth, m_antialiasing), oldState, scaleFactor()); tile->drawFinished(); tile->markDirty(false); } compositeTile(tile); } endPainting(); m_state = oldState; markDirtyTexture(); } } delete ccb; }
void SSGQuickLayer::grab() { if (!m_item || m_size.isNull()) { delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; m_depthStencilBuffer.clear(); m_dirtyTexture = false; return; } QSGNode *root = m_item; while (root->firstChild() && root->type() != QSGNode::RootNodeType) root = root->firstChild(); if (root->type() != QSGNode::RootNodeType) return; if (!m_renderer) { m_renderer = m_context->createRenderer(); connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture())); } m_renderer->setDevicePixelRatio(m_device_pixel_ratio); m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); bool deleteFboLater = false; if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format || (!m_fbo->format().mipmap() && m_mipmap)) { if (!m_multisamplingChecked) { if (m_context->openglContext()->format().samples() <= 1) { m_multisampling = false; } else { const QSet<QByteArray> extensions = m_context->openglContext()->extensions(); m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample")) && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit")); } m_multisamplingChecked = true; } if (m_multisampling) { // Don't delete the FBO right away in case it is used recursively. deleteFboLater = true; delete m_secondaryFbo; QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setSamples(m_context->openglContext()->format().samples()); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo); } } } if (m_recursive && !m_secondaryFbo) { // m_fbo already created, m_recursive was just set. Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } // Render texture. root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update. m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update. #ifdef QSG_DEBUG_FBO_OVERLAY if (qmlFboOverlay()) { if (!m_debugOverlay) m_debugOverlay = new QSGSimpleRectNode(); m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height())); m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40)); root->appendChildNode(m_debugOverlay); } #endif m_dirtyTexture = false; m_renderer->setDeviceRect(m_size); m_renderer->setViewportRect(m_size); QRectF mirrored(m_mirrorHorizontal ? m_rect.right() : m_rect.left(), m_mirrorVertical ? m_rect.bottom() : m_rect.top(), m_mirrorHorizontal ? -m_rect.width() : m_rect.width(), m_mirrorVertical ? -m_rect.height() : m_rect.height()); m_renderer->setProjectionMatrixToRect(mirrored); m_renderer->setClearColor(Qt::transparent); if (m_multisampling) { m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); format.setAttachment(QOpenGLFramebufferObject::NoAttachment); format.setMipmap(m_mipmap); format.setSamples(0); m_fbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } QRect r(QPoint(), m_size); QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r); } else { if (m_recursive) { m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); m_fbo = new QOpenGLFramebufferObject(m_size, format); funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } qSwap(m_fbo, m_secondaryFbo); } else { m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data())); } } if (m_mipmap) { funcs->glBindTexture(GL_TEXTURE_2D, textureId()); funcs->glGenerateMipmap(GL_TEXTURE_2D); } root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update. #ifdef QSG_DEBUG_FBO_OVERLAY if (qmlFboOverlay()) root->removeChildNode(m_debugOverlay); #endif if (m_recursive) markDirtyTexture(); // Continuously update if 'live' and 'recursive'. }
void QQuickShaderEffectCommon::updateMaterial(QQuickShaderEffectNode *node, QQuickShaderEffectMaterial *material, bool updateUniforms, bool updateUniformValues, bool updateTextureProviders) { if (updateUniforms) { for (int i = 0; i < material->textureProviders.size(); ++i) { QSGTextureProvider *t = material->textureProviders.at(i); if (t) { QObject::disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture())); QObject::disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*))); } } // First make room in the textureProviders array. Set to proper value further down. int textureProviderCount = 0; for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) { for (int i = 0; i < uniformData[shaderType].size(); ++i) { if (uniformData[shaderType].at(i).specialType == UniformData::Sampler) ++textureProviderCount; } material->uniforms[shaderType] = uniformData[shaderType]; } material->textureProviders.fill(0, textureProviderCount); updateUniformValues = false; updateTextureProviders = true; } if (updateUniformValues) { for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) { Q_ASSERT(uniformData[shaderType].size() == material->uniforms[shaderType].size()); for (int i = 0; i < uniformData[shaderType].size(); ++i) material->uniforms[shaderType][i].value = uniformData[shaderType].at(i).value; } } if (updateTextureProviders) { int index = 0; for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) { for (int i = 0; i < uniformData[shaderType].size(); ++i) { const UniformData &d = uniformData[shaderType].at(i); if (d.specialType != UniformData::Sampler) continue; QSGTextureProvider *oldProvider = material->textureProviders.at(index); QSGTextureProvider *newProvider = 0; QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value)); if (source && source->isTextureProvider()) newProvider = source->textureProvider(); if (newProvider != oldProvider) { if (oldProvider) { QObject::disconnect(oldProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture())); QObject::disconnect(oldProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*))); } if (newProvider) { Q_ASSERT_X(newProvider->thread() == QThread::currentThread(), "QQuickShaderEffect::updatePaintNode", "Texture provider must belong to the rendering thread"); QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture())); QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*))); } else { const char *typeName = source ? source->metaObject()->className() : d.value.typeName(); qWarning("ShaderEffect: Property '%s' is not assigned a valid texture provider (%s).", d.name.constData(), typeName); } material->textureProviders[index] = newProvider; } ++index; } } Q_ASSERT(index == material->textureProviders.size()); } }