ThirtyBitImageItem { id: thirtyBitImageItem objectName: "thirtyBitImageItem" anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.bottom: parent.bottom width: (implicitWidth / implicitHeight) * height anchors.margins: 10 // layer.enabled: true }
QSGLayer *QSGContext::createLayer(QSGRenderContext *renderContext) { return new QSGDefaultLayer(renderContext); }
QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context) : QSGLayer() , m_item(0) , m_device_pixel_ratio(1) , m_format(GL_RGBA) , m_renderer(0) , m_fbo(0) , m_secondaryFbo(0) , m_transparentTexture(0) #ifdef QSG_DEBUG_FBO_OVERLAY , m_debugOverlay(0) #endif , m_context(context) , m_mipmap(false) , m_live(true) , m_recursive(false) , m_dirtyTexture(true) , m_multisamplingChecked(false) , m_multisampling(false) , m_grab(false) , m_mirrorHorizontal(false) , m_mirrorVertical(true) { }
void QSGDefaultLayer::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_RGBA) { if (m_transparentTexture == 0) { funcs->glGenTextures(1, &m_transparentTexture); funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); const uint zero = 0; funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero); } else { funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); } } else { funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); updateBindOptions(); } }
#ifndef QT_NO_LIBRARY Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph"))) #endif struct QSGAdaptionPluginData { QSGAdaptionPluginData() : tried(false) , factory(0) { } ~QSGAdaptionPluginData() { } bool tried; QSGContextFactoryInterface *factory; QString deviceName; }; Q_GLOBAL_STATIC(QSGAdaptionPluginData, qsg_adaptation_data) /*! \fn QSGContext *QSGContext::createDefaultContext() Creates a default scene graph context for the current hardware. This may load a device-specific plugin. */ QSGContext *QSGContext::createDefaultContext() { QSGAdaptionPluginData *plugin = contextFactory(); if (plugin->factory) return plugin->factory->create(plugin->deviceName); return new QSGContext(); } QSGAdaptionPluginData *contextFactory() { QSGAdaptionPluginData *plugin = qsg_adaptation_data(); if (!plugin->tried) { plugin->tried = true; const QStringList args = QGuiApplication::arguments(); QString device; for (int index = 0; index < args.count(); ++index) { if (args.at(index).startsWith(QLatin1String("--device="))) { device = args.at(index).mid(9); break; } } if (device.isEmpty()) device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE")); #ifndef QT_NO_LIBRARY if (!device.isEmpty()) { const int index = loader()->indexOf(device); if (index != -1) plugin->factory = qobject_cast<QSGContextFactoryInterface*>(loader()->instance(index)); plugin->deviceName = device; #ifndef QT_NO_DEBUG if (!plugin->factory) { qWarning("Could not create scene graph context for device '%s'" " - check that plugins are installed correctly in %s", qPrintable(device), qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath))); } #endif } #endif // QT_NO_LIBRARY } return plugin; }
The key lines of code are bolded. We want createDefaultContext()
to return an instance of ThirtyBitSGContext.
In order for that to happen, contextFactory()
has to discover our plugin. With the QMLSCENE_DEVICE
environment variable set to ThirtyBitSGContextPlugin,
the following is sufficient for plugin discovery:#include < QtCore/qplugin.h> #include < QtQuick/private/qsgcontext_p.h> #include < QtQuick/private/qsgcontextplugin_p.h> #include < QObject> class QSGContextFactoryInterface; class ThirtyBitSGContextPlugin : public QObject, public QSGContextFactoryInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSGContextFactoryInterface" FILE "ThirtyBitSGContextPlugin.json") Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface) public: ThirtyBitSGContextPlugin(QObject *parent = 0); QSGContext* create(const QString& key) const override; QStringList keys() const override; virtual QQuickTextureFactory *createTextureFactoryFromImage(const QImage &) override { return 0; } virtual QSGRenderLoop *createWindowManager() override { return 0; } };
#include "ThirtyBitSGContextPlugin.h" #include "ThirtyBitSGContext.h" #include "ThirtyBitSGContextPlugin.h" #include "ThirtyBitSGContext.h" ThirtyBitSGContextPlugin::ThirtyBitSGContextPlugin(QObject *parent) : QObject(parent) { } QStringList ThirtyBitSGContextPlugin::keys() const { // This never seems to be invoked. Perhaps it is vestigial? It does appear to be // redundant, given that the json metadata file contains a "Keys" entry. QStringList ret; ret << "ThirtyBitSGContextPlugin"; return ret; } QSGContext* ThirtyBitSGContextPlugin::create(const QString& key) const { return new ThirtyBitSGContext(); }ThirtyBitSGContextPlugin.json:
{ "Keys" : [ "ThirtyBitSGContextPlugin" ] }
#pragma once class QSGContext; class QSGLayer; class ThirtyBitSGContext : public QSGContext { public: explicit ThirtyBitSGContext(QObject* parent=nullptr); QSGLayer* createLayer(QSGRenderContext* renderContext) override; };
#include < QtQuick/private/qsgcontext_p.h> #include < QtQuick/private/qsgdefaultlayer_p.h> #include "ThirtyBitSGContext.h" #include "ThirtyBitSGLayer.h" ThirtyBitSGContext::ThirtyBitSGContext(QObject* parent) : QSGContext(parent) { } QSGLayer* ThirtyBitSGContext::createLayer(QSGRenderContext* renderContext) { qDebug() << "QSGLayer* createLayer(QSGRenderContext* renderContext)"; return new ThirtyBitSGLayer(renderContext); }
#pragma once #include < QtQuick/private/qsgadaptationlayer_p.h> #include < QtQuick/private/qsgcontext_p.h> #include < qsgsimplerectnode.h> #define QSG_DEBUG_FBO_OVERLAY class ThirtyBitSGLayer : public QSGLayer { Q_OBJECT public: ThirtyBitSGLayer(QSGRenderContext *context); ~ThirtyBitSGLayer(); bool updateTexture() Q_DECL_OVERRIDE; // The item's "paint node", not effect node. QSGNode *item() const { return m_item; } void setItem(QSGNode *item) Q_DECL_OVERRIDE; QRectF rect() const { return m_rect; } void setRect(const QRectF &rect) Q_DECL_OVERRIDE; QSize size() const { return m_size; } void setSize(const QSize &size) Q_DECL_OVERRIDE; void setHasMipmaps(bool mipmap) Q_DECL_OVERRIDE; void bind() Q_DECL_OVERRIDE; bool hasAlphaChannel() const Q_DECL_OVERRIDE; bool hasMipmaps() const Q_DECL_OVERRIDE; int textureId() const Q_DECL_OVERRIDE; QSize textureSize() const Q_DECL_OVERRIDE { return m_size; } GLenum format() const { return m_format; } void setFormat(GLenum format) Q_DECL_OVERRIDE; bool live() const { return bool(m_live); } void setLive(bool live) Q_DECL_OVERRIDE; bool recursive() const { return bool(m_recursive); } void setRecursive(bool recursive) Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal ratio) Q_DECL_OVERRIDE { m_device_pixel_ratio = ratio; } bool mirrorHorizontal() const { return bool(m_mirrorHorizontal); } void setMirrorHorizontal(bool mirror) Q_DECL_OVERRIDE; bool mirrorVertical() const { return bool(m_mirrorVertical); } void setMirrorVertical(bool mirror) Q_DECL_OVERRIDE; void scheduleUpdate() Q_DECL_OVERRIDE; QImage toImage() const Q_DECL_OVERRIDE; QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE; public Q_SLOTS: void markDirtyTexture() Q_DECL_OVERRIDE; void invalidated() Q_DECL_OVERRIDE; protected: void grab(); QSGNode *m_item; QRectF m_rect; QSize m_size; qreal m_device_pixel_ratio; GLenum m_format; QSGRenderer *m_renderer; QOpenGLFramebufferObject *m_fbo; QOpenGLFramebufferObject *m_secondaryFbo; QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer; GLuint m_transparentTexture; #ifdef QSG_DEBUG_FBO_OVERLAY QSGSimpleRectNode *m_debugOverlay; #endif QSGRenderContext *m_context; uint m_mipmap : 1; uint m_live : 1; uint m_recursive : 1; uint m_dirtyTexture : 1; uint m_multisamplingChecked : 1; uint m_multisampling : 1; uint m_grab : 1; uint m_mirrorHorizontal : 1; uint m_mirrorVertical : 1; };
ThirtyBitSGLayer.cpp:#include < QtQuick/private/qsgdefaultlayer_p.h> #include < QOpenGLFramebufferObject> #include "ThirtyBitSGLayer.h" #include < QtQml/private/qqmlglobal_p.h> #include < QtQuick/private/qsgrenderer_p.h> #ifdef QSG_DEBUG_FBO_OVERLAY DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) #endif DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH) namespace { class BindableFbo : public QSGBindable { public: BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil); virtual ~BindableFbo(); void bind() const Q_DECL_OVERRIDE; private: QOpenGLFramebufferObject *m_fbo; QSGDepthStencilBuffer *m_depthStencil; }; BindableFbo::BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil) : m_fbo(fbo) , m_depthStencil(depthStencil) { } BindableFbo::~BindableFbo() { if (qmlFboFlushBeforeDetach()) QOpenGLContext::currentContext()->functions()->glFlush(); if (m_depthStencil) m_depthStencil->detach(); } void BindableFbo::bind() const { m_fbo->bind(); if (m_depthStencil) m_depthStencil->attach(); } } ThirtyBitSGLayer::ThirtyBitSGLayer(QSGRenderContext *context) : QSGLayer() , m_item(0) , m_device_pixel_ratio(1) , m_format(GL_RGB10_A2) , m_renderer(0) , m_fbo(0) , m_secondaryFbo(0) , m_transparentTexture(0) #ifdef QSG_DEBUG_FBO_OVERLAY , m_debugOverlay(0) #endif , m_context(context) , m_mipmap(false) , m_live(true) , m_recursive(false) , m_dirtyTexture(true) , m_multisamplingChecked(false) , m_multisampling(false) , m_grab(false) , m_mirrorHorizontal(false) , m_mirrorVertical(true) { } ThirtyBitSGLayer::~ThirtyBitSGLayer() { invalidated(); } void ThirtyBitSGLayer::invalidated() { delete m_renderer; m_renderer = 0; delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; #ifdef QSG_DEBUG_FBO_OVERLAY delete m_debugOverlay; m_debugOverlay = 0; #endif if (m_transparentTexture) { QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_transparentTexture); m_transparentTexture = 0; } } int ThirtyBitSGLayer::textureId() const { return m_fbo ? m_fbo->texture() : 0; } bool ThirtyBitSGLayer::hasAlphaChannel() const { switch(m_format) { case GL_RGB: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_RGB16F: case GL_RGB32F: case GL_R11F_G11F_B10F: return false; default: return true; } } bool ThirtyBitSGLayer::hasMipmaps() const { return m_mipmap; } void ThirtyBitSGLayer::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_RGB10_A2) { if (m_transparentTexture == 0) { funcs->glGenTextures(1, &m_transparentTexture); funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); const uint zero = 0; funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero); } else { funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture); } } else { funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); updateBindOptions(); } } bool ThirtyBitSGLayer::updateTexture() { bool doGrab = (m_live || m_grab) && m_dirtyTexture; if (doGrab) grab(); if (m_grab) emit scheduledUpdateCompleted(); m_grab = false; return doGrab; } void ThirtyBitSGLayer::setHasMipmaps(bool mipmap) { if (mipmap == m_mipmap) return; m_mipmap = mipmap; if (m_mipmap && m_fbo && !m_fbo->format().mipmap()) markDirtyTexture(); } void ThirtyBitSGLayer::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 ThirtyBitSGLayer::setRect(const QRectF &rect) { if (rect == m_rect) return; m_rect = rect; markDirtyTexture(); } void ThirtyBitSGLayer::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 ThirtyBitSGLayer::setFormat(GLenum) { // NOPE! We're keeping 30-bit fidelity. } void ThirtyBitSGLayer::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 ThirtyBitSGLayer::scheduleUpdate() { if (m_grab) return; m_grab = true; if (m_dirtyTexture) emit updateRequested(); } void ThirtyBitSGLayer::setRecursive(bool recursive) { m_recursive = recursive; } void ThirtyBitSGLayer::setMirrorHorizontal(bool mirror) { m_mirrorHorizontal = mirror; } void ThirtyBitSGLayer::setMirrorVertical(bool mirror) { m_mirrorVertical = mirror; } void ThirtyBitSGLayer::markDirtyTexture() { m_dirtyTexture = true; if (m_live || m_grab) emit updateRequested(); } void ThirtyBitSGLayer::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'. } QImage ThirtyBitSGLayer::toImage() const { if (m_fbo) return m_fbo->toImage(); return QImage(); } QRectF ThirtyBitSGLayer::normalizedTextureSubRect() const { return QRectF(m_mirrorHorizontal ? 1 : 0, m_mirrorVertical ? 0 : 1, m_mirrorHorizontal ? -1 : 1, m_mirrorVertical ? 1 : -1); } #includeQT_BEGIN_NAMESPACE QSGDepthStencilBuffer::QSGDepthStencilBuffer(QOpenGLContext *context, const Format &format) : m_functions(context) , m_manager(0) , m_format(format) , m_depthBuffer(0) , m_stencilBuffer(0) { // 'm_manager' is set by QSGDepthStencilBufferManager::insertBuffer(). } QSGDepthStencilBuffer::~QSGDepthStencilBuffer() { if (m_manager) m_manager->m_buffers.remove(m_format); } void QSGDepthStencilBuffer::attach() { m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer); } void QSGDepthStencilBuffer::detach() { m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); m_functions.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); } #ifndef GL_DEPTH24_STENCIL8_OES #define GL_DEPTH24_STENCIL8_OES 0x88F0 #endif #ifndef GL_DEPTH_COMPONENT24_OES #define GL_DEPTH_COMPONENT24_OES 0x81A6 #endif QSGDefaultDepthStencilBuffer::QSGDefaultDepthStencilBuffer(QOpenGLContext *context, const Format &format) : QSGDepthStencilBuffer(context, format) { const GLsizei width = format.size.width(); const GLsizei height = format.size.height(); if (format.attachments == (DepthAttachment | StencilAttachment) && m_functions.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil)) { m_functions.glGenRenderbuffers(1, &m_depthBuffer); m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { #if defined(QT_OPENGL_ES_2) m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples, GL_DEPTH24_STENCIL8_OES, width, height); #else m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples, GL_DEPTH24_STENCIL8, width, height); #endif } else { #if defined(QT_OPENGL_ES_2) m_functions.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height); #else m_functions.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); #endif } m_stencilBuffer = m_depthBuffer; } if (!m_depthBuffer && (format.attachments & DepthAttachment)) { m_functions.glGenRenderbuffers(1, &m_depthBuffer); m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); GLenum internalFormat = GL_DEPTH_COMPONENT; if (context->isOpenGLES()) internalFormat = m_functions.hasOpenGLExtension(QOpenGLExtensions::Depth24) ? GL_DEPTH_COMPONENT24_OES : GL_DEPTH_COMPONENT16; if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples, internalFormat, width, height); } else { m_functions.glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height); } } if (!m_stencilBuffer && (format.attachments & StencilAttachment)) { m_functions.glGenRenderbuffers(1, &m_stencilBuffer); m_functions.glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer); #ifdef QT_OPENGL_ES const GLenum internalFormat = GL_STENCIL_INDEX8; #else const GLenum internalFormat = context->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; #endif if (format.samples && m_functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { m_functions.glRenderbufferStorageMultisample(GL_RENDERBUFFER, format.samples, internalFormat, width, height); } else { m_functions.glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height); } } } QSGDefaultDepthStencilBuffer::~QSGDefaultDepthStencilBuffer() { free(); } void QSGDefaultDepthStencilBuffer::free() { if (m_depthBuffer) m_functions.glDeleteRenderbuffers(1, &m_depthBuffer); if (m_stencilBuffer && m_stencilBuffer != m_depthBuffer) m_functions.glDeleteRenderbuffers(1, &m_stencilBuffer); m_depthBuffer = m_stencilBuffer = 0; } QSGDepthStencilBufferManager::~QSGDepthStencilBufferManager() { for (Hash::const_iterator it = m_buffers.constBegin(), cend = m_buffers.constEnd(); it != cend; ++it) { QSGDepthStencilBuffer *buffer = it.value().data(); buffer->free(); buffer->m_manager = 0; } } QSharedPointer<QSGDepthStencilBuffer> QSGDepthStencilBufferManager::bufferForFormat(const QSGDepthStencilBuffer::Format &fmt) { Hash::const_iterator it = m_buffers.constFind(fmt); if (it != m_buffers.constEnd()) return it.value().toStrongRef(); return QSharedPointer<QSGDepthStencilBuffer>(); } void QSGDepthStencilBufferManager::insertBuffer(const QSharedPointer<QSGDepthStencilBuffer> &buffer) { Q_ASSERT(buffer->m_manager == 0); Q_ASSERT(!m_buffers.contains(buffer->m_format)); buffer->m_manager = this; m_buffers.insert(buffer->m_format, buffer.toWeakRef()); } uint qHash(const QSGDepthStencilBuffer::Format &format) { return qHash(qMakePair(format.size.width(), format.size.height())) ^ (uint(format.samples) << 12) ^ (uint(format.attachments) << 28); } QT_END_NAMESPACE
You may note that the body of ThirtyBitSGLayer::setFormat
has been replaced by the comment, NOPE!
We're keeping 30-bit fidelity. This is necessary because the
QObject side of our
ThirtyBitSGLayer class
remains QQuickItemLayer,
and QQuickItemLayer
calls ThirtyBitSGLayer::setFormat
to demand that we revert back to inferior bullshit 24-bit color,
which we don't want to do. So, we don't. Ha!July 2009 August 2009 September 2009 October 2009 November 2009 December 2009 January 2010 September 2010 December 2010 January 2011 February 2011 April 2011 June 2011 August 2011 February 2012 June 2012 July 2012 August 2012 October 2012 November 2012 January 2014 April 2014 June 2014 August 2014 September 2014 October 2014 January 2015 March 2015 April 2015 June 2015 November 2015 December 2015 January 2016 June 2016 August 2016 January 2017 March 2017 April 2018 April 2019 June 2019 January 2020
Subscribe to Posts [Atom]