nodes/QskTextureRenderer.cpp

Functions

  Name
uint qskCreateTextureOpenGL(const QSize & size, QskTextureRenderer::PaintHelper * helper)
uint qskCreateTextureRaster(const QSize & size, QskTextureRenderer::PaintHelper * helper)

Functions Documentation

function qskCreateTextureOpenGL

static uint qskCreateTextureOpenGL(
    const QSize & size,
    QskTextureRenderer::PaintHelper * helper
)

function qskCreateTextureRaster

static uint qskCreateTextureRaster(
    const QSize & size,
    QskTextureRenderer::PaintHelper * helper
)

Source code

/******************************************************************************
 * QSkinny - Copyright (C) 2016 Uwe Rathmann
 * This file may be used under the terms of the QSkinny License, Version 1.0
 *****************************************************************************/

#include "QskTextureRenderer.h"
#include "QskColorFilter.h"
#include "QskGraphic.h"
#include "QskSetup.h"

#include <qopenglcontext.h>
#include <qopenglextrafunctions.h>
#include <qopenglframebufferobject.h>
#include <qopenglfunctions.h>
#include <qopenglpaintdevice.h>
#include <qopengltexture.h>

#include <qimage.h>
#include <qpainter.h>

#include <qquickwindow.h>
#include <qsgtexture.h>

#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
    #include <qsgtexture_platform.h>
#endif

static uint qskCreateTextureOpenGL(
    const QSize& size, QskTextureRenderer::PaintHelper* helper )
{
    const int width = size.width();
    const int height = size.height();

    QOpenGLFramebufferObjectFormat format1;
    format1.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );

    // ### TODO: get samples from window instead
    format1.setSamples( QOpenGLContext::currentContext()->format().samples() );

    QOpenGLFramebufferObject multisampledFbo( width, height, format1 );

    QOpenGLPaintDevice pd( width, height );
    pd.setPaintFlipped( true );

    {
        QPainter painter( &pd );

        painter.setCompositionMode( QPainter::CompositionMode_Source );
        painter.fillRect( 0, 0, width, height, Qt::transparent );
        painter.setCompositionMode( QPainter::CompositionMode_SourceOver );

        helper->paint( &painter, size );

#if 1
        if ( format1.samples() > 0 )
        {
            /*
                Multisampling in the window surface might get lost
                as a side effect of rendering to the FBO.
                weired, needs to be investigated more
             */
            painter.setRenderHint( QPainter::Antialiasing, true );
        }
#endif
    }

    QOpenGLFramebufferObjectFormat format2;
    format2.setAttachment( QOpenGLFramebufferObject::NoAttachment );

    QOpenGLFramebufferObject fbo( width, height, format2 );

    const QRect fboRect( 0, 0, width, height );

    QOpenGLFramebufferObject::blitFramebuffer(
        &fbo, fboRect, &multisampledFbo, fboRect );

    return fbo.takeTexture();
}

static uint qskCreateTextureRaster(
    const QSize& size, QskTextureRenderer::PaintHelper* helper )
{
    QImage image( size, QImage::Format_RGBA8888_Premultiplied );
    image.fill( Qt::transparent );

    {
        QPainter painter( &image );
        helper->paint( &painter, size );
    }

    const auto target = QOpenGLTexture::Target2D;

    auto context = QOpenGLContext::currentContext();
    if ( context == nullptr )
        return 0;

    auto& f = *context->functions();

    GLint oldTexture; // we can't rely on having OpenGL Direct State Access
    f.glGetIntegerv( QOpenGLTexture::BindingTarget2D, &oldTexture );

    GLuint textureId;
    f.glGenTextures( 1, &textureId );

    f.glBindTexture( target, textureId );

    f.glTexParameteri( target, GL_TEXTURE_MIN_FILTER, QOpenGLTexture::Nearest );
    f.glTexParameteri( target, GL_TEXTURE_MAG_FILTER, QOpenGLTexture::Nearest );

    f.glTexParameteri( target, GL_TEXTURE_WRAP_S, QOpenGLTexture::ClampToEdge );
    f.glTexParameteri( target, GL_TEXTURE_WRAP_T, QOpenGLTexture::ClampToEdge );

    if ( QOpenGLTexture::hasFeature( QOpenGLTexture::ImmutableStorage ) )
    {
        auto& ef = *context->extraFunctions();
        ef.glTexStorage2D( target, 1,
            QOpenGLTexture::RGBA8_UNorm, image.width(), image.height() );

        f.glTexSubImage2D( target, 0, 0, 0, image.width(), image.height(),
            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
    }
    else
    {
        f.glTexImage2D( target, 0, QOpenGLTexture::RGBA8_UNorm,
            image.width(), image.height(), 0,
            QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits() );
    }

    f.glBindTexture( target, oldTexture );

    return textureId;
}

QSGTexture* QskTextureRenderer::textureFromId(
    QQuickWindow* window, uint textureId, const QSize& size )
{
    const auto flags = static_cast< QQuickWindow::CreateTextureOptions >(
        QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture );

    QSGTexture* texture;

#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )

    texture = QNativeInterface::QSGOpenGLTexture::fromNative(
        textureId, window, size, flags );

#elif QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )

    const int nativeLayout = 0; // VkImageLayout in case of Vulkan

    texture = window->createTextureFromNativeObject(
        QQuickWindow::NativeObjectTexture, &textureId, nativeLayout, size, flags );

#else

    texture = window->createTextureFromId( textureId, size, flags );

#endif

    return texture;
}

QskTextureRenderer::PaintHelper::~PaintHelper()
{
}

uint QskTextureRenderer::createTexture(
    RenderMode renderMode, const QSize& size, PaintHelper* helper )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
    // Qt6.0.0 is buggy when using FBOs. So let's disable it for the moment TODO ...
    renderMode = Raster;
#endif
    if ( renderMode == AutoDetect )
    {
        if ( qskSetup->testItemUpdateFlag( QskQuickItem::PreferRasterForTextures ) )
            renderMode = Raster;
        else
            renderMode = OpenGL;
    }

    if ( renderMode == Raster )
        return qskCreateTextureRaster( size, helper );
    else
        return qskCreateTextureOpenGL( size, helper );
}

uint QskTextureRenderer::createTextureFromGraphic(
    RenderMode renderMode, const QSize& size,
    const QskGraphic& graphic, const QskColorFilter& colorFilter,
    Qt::AspectRatioMode aspectRatioMode )
{
    class PaintHelper : public QskTextureRenderer::PaintHelper
    {
      public:
        PaintHelper( const QskGraphic& graphic,
                const QskColorFilter& filter, Qt::AspectRatioMode aspectRatioMode )
            : m_graphic( graphic )
            , m_filter( filter )
            , m_aspectRatioMode( aspectRatioMode )
        {
        }

        void paint( QPainter* painter, const QSize& size ) override
        {
            const QRect rect( 0, 0, size.width(), size.height() );
            m_graphic.render( painter, rect, m_filter, m_aspectRatioMode );
        }

      private:
        const QskGraphic& m_graphic;
        const QskColorFilter& m_filter;
        const Qt::AspectRatioMode m_aspectRatioMode;
    };

    PaintHelper helper( graphic, colorFilter, aspectRatioMode );
    return createTexture( renderMode, size, &helper );
}

Updated on 28 July 2023 at 14:02:30 CEST