void CompasWidget::paintGL(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); m_world.setToIdentity(); m_world.rotate(180.0f - (m_xRot / 16.0f), 1, 0, 0); m_world.rotate(m_yRot / 16.0f, 0, 1, 0); m_world.rotate(m_zRot / 16.0f, 0, 0, 1); /* QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); m_program->bind(); m_program->setUniformValue(m_projMatrixLoc, m_proj); m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world); QMatrix3x3 normalMatrix = m_world.normalMatrix(); m_program->setUniformValue(m_normalMatrixLoc, normalMatrix); glDrawArrays(GL_TRIANGLES, 0, m_logo.vertexCount()); m_program->release(); */ QOpenGLFunctions *f = context()->functions(); const bool newFrameReady=true; if (newFrameReady) {//new frame ready f->glFrontFace(GL_CW); // because our cube's vertex data is such f->glBindTexture(GL_TEXTURE_2D, m_fbo2->texture()); m_program2->bind(); QOpenGLVertexArrayObject::Binder vaoBinder(m_vao2); // If VAOs are not supported, set the vertex attributes every time. if (!m_vao2->isCreated()){ setupVertexAttribs2(); } static GLfloat angle = 0; QMatrix4x4 m; m.translate(0, 0, -20); m.rotate(90, 0, 0, 1); m.rotate(angle, 0.5, 1, 0); angle += 0.5f; m_program2->setUniformValue(m_matrixLoc, m_proj * m); // Draw the cube. f->glDrawArrays(GL_TRIANGLES, 0, 36); m_program2->release(); } }
void QWaylandBufferMaterial::bind() { QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); const GLenum target = bufferTypes[m_format].textureTarget; ensureTextures(bufferTypes[m_format].planeCount); switch (m_textures.size()) { case 3: gl->glActiveTexture(GL_TEXTURE2); gl->glBindTexture(target, m_textures[2]); case 2: gl->glActiveTexture(GL_TEXTURE1); gl->glBindTexture(target, m_textures[1]); case 1: gl->glActiveTexture(GL_TEXTURE0); gl->glBindTexture(target, m_textures[0]); } }
void QSGVideoMaterial_YUV::bindTexture(int id, int w, int h, const uchar *bits, GLenum format) { QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); functions->glBindTexture(GL_TEXTURE_2D, id); functions->glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, bits); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); }
void SSGQuickLayer::bind() { #ifndef QT_NO_DEBUG if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound())) qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively."); #endif QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); if (!m_fbo && m_format == GL_RGBA32F) { if (m_transparentTexture == 0) { funcs->glGenTextures(1, &m_transparentTexture); funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); const float zero[4] = {0, 0, 0, 0}; funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0, GL_RGBA, GL_FLOAT, zero); } else { funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); } } else { funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); updateBindOptions(); } }
void GLImageProcessor::plot(int w, int h) { vao.bind(); plotProgram->bind(); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); f->glActiveTexture(GL_TEXTURE0); f->glBindTexture(GL_TEXTURE_2D, renderFbo->texture()); f->glViewport(0, 0, w, h); f->glDrawArrays(GL_QUADS, 0, 4); plotProgram->release(); vao.release(); }
void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) { Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); bool updated = material->updateTextureSize(); if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { QVector4D color = material->color(); color *= state.opacity(); updateColor(color); } bool updateRange = false; if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale()) { m_fontScale = material->fontScale(); updateRange = true; } if (state.isMatrixDirty()) { program()->setUniformValue(m_matrix_id, state.combinedMatrix()); m_matrixScale = qSqrt(qAbs(state.determinant())) * state.devicePixelRatio(); updateRange = true; } if (updateRange) { updateAlphaRange(material->glyphCache()->manager()->thresholdFunc(), material->glyphCache()->manager()->antialiasingSpreadFunc()); } Q_ASSERT(material->glyphCache()); if (updated || oldMaterial == 0 || oldMaterial->texture()->textureId != material->texture()->textureId) { updateTextureScale(QVector2D(1.0 / material->textureSize().width(), 1.0 / material->textureSize().height())); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId); if (updated) { // Set the mag/min filters to be linear. We only need to do this when the texture // has been recreated. funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } } }
void TFInteg2DGL::integrate(const float *colormap, int resolution, float basesize, float stepsize) { if (!texFull || resolution != texFull->width()) newResources(resolution); QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); tex1d->setData(QOpenGLTexture::RGBA, QOpenGLTexture::Float32, colormap); // framebuffer object GLint oFbo, viewport[4], activeTex, oTex; newFbo(); f->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oFbo); f->glBindFramebuffer(GL_FRAMEBUFFER, *fbo); f->glClear(GL_COLOR_BUFFER_BIT); // viewport f->glGetIntegerv(GL_VIEWPORT, viewport); f->glViewport(0, 0, resolution, resolution); // 1d texture f->glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); f->glActiveTexture(GL_TEXTURE0); f->glGetIntegerv(GL_TEXTURE_1D, &oTex); f->glBindTexture(GL_TEXTURE_1D, tex1d->textureId()); // paint painter.recreateVAO(); painter.paint("tf1d", 0, "resolution", resolution, "basesize", basesize, "segLen", stepsize); // clean f->glActiveTexture(GL_TEXTURE0); f->glBindTexture(GL_TEXTURE_1D, oTex); f->glActiveTexture(activeTex); // std::unique_ptr<GLubyte[]> pixels(new GLubyte [resolution * resolution * 4]); // f->glReadPixels(0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get()); // QImage image(pixels.get(), resolution, resolution, QImage::Format_RGBA8888); // static QLabel label; // label.resize(resolution, resolution); // label.setPixmap(QPixmap::fromImage(image.mirrored())); // label.show(); f->glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); f->glBindFramebuffer(GL_FRAMEBUFFER, oFbo); }
//TODO move this into a separate centralized texture management class void QWaylandBufferMaterial::ensureTextures(int count) { QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); const GLenum target = bufferTypes[m_format].textureTarget; GLuint texture; for (int plane = m_textures.size(); plane < count; plane++) { gl->glGenTextures(1, &texture); gl->glBindTexture(target, texture); setTextureParameters(target); m_textures << texture; } }
void bind() { QMutexLocker lock(&m_frameMutex); if (m_frame.isValid()) { m_textureId = m_frame.handle().toUInt(); QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); functions->glBindTexture(GL_TEXTURE_2D, m_textureId); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { m_textureId = 0; } }
void QQuickContext2DFBOTexture::endPainting() { QQuickContext2DTexture::endPainting(); // There may not be an FBO due to zero width or height. if (!m_fbo) return; if (m_multisampledFbo) QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo); if (m_gl) { /* When rendering happens on the render thread, the fbo's texture is * used directly for display. If we are on the GUI thread or a * dedicated Canvas render thread, we need to decouple the FBO from * the texture we are displaying in the SG rendering thread to avoid * stalls and read/write issues in the GL pipeline as the FBO's texture * could then potentially be used in different threads. * * We could have gotten away with only one display texture, but this * would have implied that beginPainting would have to wait for SG * to release that texture. */ if (m_onCustomThread) m_mutex.lock(); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); if (m_displayTextures[0] == 0) { m_displayTexture = 1; funcs->glGenTextures(2, m_displayTextures); } m_fbo->bind(); GLuint target = m_displayTexture == 0 ? 1 : 0; funcs->glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]); funcs->glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0); if (m_onCustomThread) m_mutex.unlock(); } m_fbo->bindDefault(); }
void QWaylandBufferMaterial::setTextureForPlane(int plane, uint texture) { if (plane < 0 || plane >= bufferTypes[m_format].planeCount) { qWarning("plane index is out of range"); return; } QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions(); const GLenum target = bufferTypes[m_format].textureTarget; gl->glBindTexture(target, texture); setTextureParameters(target); ensureTextures(plane - 1); if (m_textures.size() <= plane) { m_textures << texture; } else { std::swap(m_textures[plane], texture); gl->glDeleteTextures(1, &texture); } }
GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) { QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); if (cache.size() == maxCacheSize()) { int elem_to_remove = qrand() % maxCacheSize(); quint64 key = cache.keys()[elem_to_remove]; // need to call glDeleteTextures on each removed cache entry: QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key); do { funcs->glDeleteTextures(1, &it.value().texId); } while (++it != cache.constEnd() && it.key() == key); cache.remove(key); // may remove more than 1, but OK } CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode()); uint buffer[1024]; generateGradientColorTable(gradient, buffer, paletteSize(), opacity); funcs->glGenTextures(1, &cache_entry.texId); funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId); funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); return cache.insert(hash_val, cache_entry).value().texId; }
void QSGDistanceFieldGlyphCache::saveTexture(GLuint textureId, int width, int height) const { QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); GLuint fboId; functions->glGenFramebuffers(1, &fboId); GLuint tmpTexture = 0; functions->glGenTextures(1, &tmpTexture); functions->glBindTexture(GL_TEXTURE_2D, tmpTexture); functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); functions->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); functions->glBindTexture(GL_TEXTURE_2D, 0); functions->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId); functions->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tmpTexture, 0); functions->glActiveTexture(GL_TEXTURE0); functions->glBindTexture(GL_TEXTURE_2D, textureId); functions->glDisable(GL_STENCIL_TEST); functions->glDisable(GL_DEPTH_TEST); functions->glDisable(GL_SCISSOR_TEST); functions->glDisable(GL_BLEND); GLfloat textureCoordinateArray[8]; textureCoordinateArray[0] = 0.0f; textureCoordinateArray[1] = 0.0f; textureCoordinateArray[2] = 1.0f; textureCoordinateArray[3] = 0.0f; textureCoordinateArray[4] = 1.0f; textureCoordinateArray[5] = 1.0f; textureCoordinateArray[6] = 0.0f; textureCoordinateArray[7] = 1.0f; GLfloat vertexCoordinateArray[8]; vertexCoordinateArray[0] = -1.0f; vertexCoordinateArray[1] = -1.0f; vertexCoordinateArray[2] = 1.0f; vertexCoordinateArray[3] = -1.0f; vertexCoordinateArray[4] = 1.0f; vertexCoordinateArray[5] = 1.0f; vertexCoordinateArray[6] = -1.0f; vertexCoordinateArray[7] = 1.0f; functions->glViewport(0, 0, width, height); functions->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); functions->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); { static const char *vertexShaderSource = "attribute vec4 vertexCoordsArray; \n" "attribute vec2 textureCoordArray; \n" "varying vec2 textureCoords; \n" "void main(void) \n" "{ \n" " gl_Position = vertexCoordsArray; \n" " textureCoords = textureCoordArray; \n" "} \n"; static const char *fragmentShaderSource = "varying vec2 textureCoords; \n" "uniform sampler2D texture; \n" "void main() \n" "{ \n" " gl_FragColor = texture2D(texture, textureCoords); \n" "} \n"; GLuint vertexShader = functions->glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShader = functions->glCreateShader(GL_FRAGMENT_SHADER); if (vertexShader == 0 || fragmentShader == 0) { GLenum error = functions->glGetError(); qWarning("QSGDistanceFieldGlyphCache::saveTexture: Failed to create shaders. (GL error: %x)", error); return; } functions->glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); functions->glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); functions->glCompileShader(vertexShader); GLint len = 1; functions->glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &len); char infoLog[2048]; functions->glGetShaderInfoLog(vertexShader, 2048, NULL, infoLog); if (qstrlen(infoLog) > 0) qWarning("Problems compiling vertex shader:\n %s", infoLog); functions->glCompileShader(fragmentShader); functions->glGetShaderInfoLog(fragmentShader, 2048, NULL, infoLog); if (qstrlen(infoLog) > 0) qWarning("Problems compiling fragment shader:\n %s", infoLog); GLuint shaderProgram = functions->glCreateProgram(); functions->glAttachShader(shaderProgram, vertexShader); functions->glAttachShader(shaderProgram, fragmentShader); functions->glBindAttribLocation(shaderProgram, 0, "vertexCoordsArray"); functions->glBindAttribLocation(shaderProgram, 1, "textureCoordArray"); functions->glLinkProgram(shaderProgram); functions->glGetProgramInfoLog(shaderProgram, 2048, NULL, infoLog); if (qstrlen(infoLog) > 0) qWarning("Problems linking shaders:\n %s", infoLog); functions->glUseProgram(shaderProgram); functions->glEnableVertexAttribArray(0); functions->glEnableVertexAttribArray(1); int textureUniformLocation = functions->glGetUniformLocation(shaderProgram, "texture"); functions->glUniform1i(textureUniformLocation, 0); } functions->glDrawArrays(GL_TRIANGLE_FAN, 0, 4); { GLenum error = functions->glGetError(); if (error != GL_NO_ERROR) qWarning("glDrawArrays reported error 0x%x", error); } uchar *data = new uchar[width * height * 4]; functions->glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); QImage image(data, width, height, QImage::Format_ARGB32); QByteArray fileName = m_referenceFont.familyName().toLatin1() + '_' + QByteArray::number(textureId); fileName = fileName.replace('/', '_').replace(' ', '_') + ".png"; image.save(QString::fromLocal8Bit(fileName)); { GLenum error = functions->glGetError(); if (error != GL_NO_ERROR) qWarning("glReadPixels reported error 0x%x", error); } functions->glDisableVertexAttribArray(0); functions->glDisableVertexAttribArray(1); functions->glDeleteFramebuffers(1, &fboId); functions->glDeleteTextures(1, &tmpTexture); delete[] data; }
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'. }
GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, BindOptions options) { GLuint id; QOpenGLFunctions *funcs = context->functions(); funcs->glGenTextures(1, &id); funcs->glBindTexture(GL_TEXTURE_2D, id); QImage tx; GLenum externalFormat; GLenum internalFormat; GLuint pixelType; QImage::Format targetFormat = QImage::Format_Invalid; const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2); switch (image.format()) { case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: if (isOpenGL12orBetter) { externalFormat = GL_BGRA; internalFormat = GL_RGBA; pixelType = GL_UNSIGNED_INT_8_8_8_8_REV; } else { #if Q_BYTE_ORDER == Q_BIG_ENDIAN // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian. break; #endif if (static_cast<QOpenGLExtensions*>(context->functions())->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) { // GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 extensions. if (context->isOpenGLES()) { // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external. externalFormat = internalFormat = GL_BGRA; } else { // OpenGL BGRA/BGR format is not allowed as an internal format externalFormat = GL_BGRA; internalFormat = GL_RGBA; } pixelType = GL_UNSIGNED_BYTE; } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) { // Is only allowed as an external format like OpenGL. externalFormat = GL_BGRA; internalFormat = GL_RGBA; pixelType = GL_UNSIGNED_BYTE; } else { // No support for direct ARGB32 upload. break; } } targetFormat = image.format(); break; case QImage::Format_BGR30: case QImage::Format_A2BGR30_Premultiplied: if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) { pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; externalFormat = GL_RGBA; internalFormat = GL_RGB10_A2; targetFormat = image.format(); } break; case QImage::Format_RGB30: case QImage::Format_A2RGB30_Premultiplied: if (isOpenGL12orBetter) { pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; externalFormat = GL_BGRA; internalFormat = GL_RGB10_A2; targetFormat = image.format(); } else if (context->isOpenGLES() && context->format().majorVersion() >= 3) { pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; externalFormat = GL_RGBA; internalFormat = GL_RGB10_A2; targetFormat = QImage::Format_A2BGR30_Premultiplied; } break; case QImage::Format_RGB444: case QImage::Format_RGB555: case QImage::Format_RGB16: if (isOpenGL12orBetter || context->isOpenGLES()) { externalFormat = internalFormat = GL_RGB; pixelType = GL_UNSIGNED_SHORT_5_6_5; targetFormat = QImage::Format_RGB16; } break; case QImage::Format_RGB666: case QImage::Format_RGB888: externalFormat = internalFormat = GL_RGB; pixelType = GL_UNSIGNED_BYTE; targetFormat = QImage::Format_RGB888; break; case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: externalFormat = internalFormat = GL_RGBA; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); break; case QImage::Format_Indexed8: if (options & UseRedFor8BitBindOption) { externalFormat = internalFormat = GL_RED; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); } break; case QImage::Format_Alpha8: if (options & UseRedFor8BitBindOption) { externalFormat = internalFormat = GL_RED; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { externalFormat = internalFormat = GL_ALPHA; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); } break; case QImage::Format_Grayscale8: if (options & UseRedFor8BitBindOption) { externalFormat = internalFormat = GL_RED; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { externalFormat = internalFormat = GL_LUMINANCE; pixelType = GL_UNSIGNED_BYTE; targetFormat = image.format(); } break; default: break; } if (targetFormat == QImage::Format_Invalid) { externalFormat = internalFormat = GL_RGBA; pixelType = GL_UNSIGNED_BYTE; if (!image.hasAlphaChannel()) targetFormat = QImage::Format_RGBX8888; else targetFormat = QImage::Format_RGBA8888; } if (options & PremultipliedAlphaBindOption) { if (targetFormat == QImage::Format_ARGB32) targetFormat = QImage::Format_ARGB32_Premultiplied; else if (targetFormat == QImage::Format_RGBA8888) targetFormat = QImage::Format_RGBA8888_Premultiplied; } else { if (targetFormat == QImage::Format_ARGB32_Premultiplied) targetFormat = QImage::Format_ARGB32; else if (targetFormat == QImage::Format_RGBA8888_Premultiplied) targetFormat = QImage::Format_RGBA8888; } if (image.format() != targetFormat) tx = image.convertToFormat(targetFormat); else tx = image; funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, const_cast<const QImage &>(tx).bits()); int cost = tx.width() * tx.height() * tx.depth() / (1024 * 8); m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost); return id; }
void bind() { QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); QMutexLocker lock(&m_frameMutex); if (m_frame.isValid()) { if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { QSize textureSize = m_frame.size(); int stride = m_frame.bytesPerLine(); switch (m_frame.pixelFormat()) { case QVideoFrame::Format_RGB565: stride /= 2; break; default: stride /= 4; } m_width = qreal(m_frame.width()) / stride; textureSize.setWidth(stride); if (m_textureSize != textureSize) { if (!m_textureSize.isEmpty()) functions->glDeleteTextures(1, &m_textureId); functions->glGenTextures(1, &m_textureId); m_textureSize = textureSize; } GLint dataType = GL_UNSIGNED_BYTE; GLint dataFormat = GL_RGBA; if (m_frame.pixelFormat() == QVideoFrame::Format_RGB565) { dataType = GL_UNSIGNED_SHORT_5_6_5; dataFormat = GL_RGB; } GLint previousAlignment; functions->glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment); functions->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); functions->glActiveTexture(GL_TEXTURE0); functions->glBindTexture(GL_TEXTURE_2D, m_textureId); functions->glTexImage2D(GL_TEXTURE_2D, 0, dataFormat, m_textureSize.width(), m_textureSize.height(), 0, dataFormat, dataType, m_frame.bits()); functions->glPixelStorei(GL_UNPACK_ALIGNMENT, previousAlignment); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); m_frame.unmap(); } m_frame = QVideoFrame(); } else { functions->glActiveTexture(GL_TEXTURE0); functions->glBindTexture(GL_TEXTURE_2D, m_textureId); } }
void QSGVideoMaterial_YUV::bind() { QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); QMutexLocker lock(&m_frameMutex); if (m_frame.isValid()) { if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) { int fw = m_frame.width(); int fh = m_frame.height(); // Frame has changed size, recreate textures... if (m_textureSize != m_frame.size()) { if (!m_textureSize.isEmpty()) functions->glDeleteTextures(m_planeCount, m_textureIds); functions->glGenTextures(m_planeCount, m_textureIds); m_textureSize = m_frame.size(); } GLint previousAlignment; functions->glGetIntegerv(GL_UNPACK_ALIGNMENT, &previousAlignment); functions->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (m_format.pixelFormat() == QVideoFrame::Format_NV12 || m_format.pixelFormat() == QVideoFrame::Format_NV21) { const int y = 0; const int uv = 1; m_planeWidth[0] = m_planeWidth[1] = qreal(fw) / m_frame.bytesPerLine(y); functions->glActiveTexture(GL_TEXTURE1); bindTexture(m_textureIds[1], m_frame.bytesPerLine(uv) / 2, fh / 2, m_frame.bits(uv), GL_LUMINANCE_ALPHA); functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit bindTexture(m_textureIds[0], m_frame.bytesPerLine(y), fh, m_frame.bits(y), GL_LUMINANCE); } else { // YUV420P || YV12 const int y = 0; const int u = m_frame.pixelFormat() == QVideoFrame::Format_YUV420P ? 1 : 2; const int v = m_frame.pixelFormat() == QVideoFrame::Format_YUV420P ? 2 : 1; m_planeWidth[0] = qreal(fw) / m_frame.bytesPerLine(y); m_planeWidth[1] = m_planeWidth[2] = qreal(fw) / (2 * m_frame.bytesPerLine(u)); functions->glActiveTexture(GL_TEXTURE1); bindTexture(m_textureIds[1], m_frame.bytesPerLine(u), fh / 2, m_frame.bits(u), GL_LUMINANCE); functions->glActiveTexture(GL_TEXTURE2); bindTexture(m_textureIds[2], m_frame.bytesPerLine(v), fh / 2, m_frame.bits(v), GL_LUMINANCE); functions->glActiveTexture(GL_TEXTURE0); // Finish with 0 as default texture unit bindTexture(m_textureIds[0], m_frame.bytesPerLine(y), fh, m_frame.bits(y), GL_LUMINANCE); } functions->glPixelStorei(GL_UNPACK_ALIGNMENT, previousAlignment); m_frame.unmap(); } m_frame = QVideoFrame(); } else { // Go backwards to finish with GL_TEXTURE0 for (int i = m_planeCount - 1; i >= 0; --i) { functions->glActiveTexture(GL_TEXTURE0 + i); functions->glBindTexture(GL_TEXTURE_2D, m_textureIds[i]); } } }