qskinny/src/graphic/QskGraphicTextureFactory.cpp

174 lines
5.4 KiB
C++
Raw Normal View History

2017-07-21 16:21:34 +00:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskGraphicTextureFactory.h"
2018-07-19 12:10:48 +00:00
#include <qopenglcontext.h>
#include <qopenglframebufferobject.h>
#include <qopenglfunctions.h>
#include <qopenglextrafunctions.h>
2018-08-03 06:15:28 +00:00
#include <qopenglpaintdevice.h>
2018-07-19 12:10:48 +00:00
#include <qopengltexture.h>
2017-07-21 16:21:34 +00:00
2018-07-19 12:10:48 +00:00
#include <qpainter.h>
#include <qquickwindow.h>
2017-07-21 16:21:34 +00:00
static uint qskTextureFBO(
const QRect& rect, Qt::AspectRatioMode scalingMode,
const QskGraphic& graphic, const QskColorFilter& filter )
{
QOpenGLFramebufferObjectFormat format1;
format1.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
// ### TODO: get samples from window instead
format1.setSamples( QOpenGLContext::currentContext()->format().samples() );
2018-07-13 13:09:25 +00:00
const QRect sourceRect( QPoint(), rect.size() );
2017-07-21 16:21:34 +00:00
QOpenGLFramebufferObject multisampledFbo( sourceRect.size(), format1 );
QOpenGLPaintDevice pd( sourceRect.size() );
QPainter painter( &pd );
2018-07-13 13:09:25 +00:00
graphic.render( &painter, sourceRect, filter, scalingMode );
2017-07-21 16:21:34 +00:00
#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
painter.end();
QOpenGLFramebufferObjectFormat format2;
format2.setAttachment( QOpenGLFramebufferObject::NoAttachment );
QOpenGLFramebufferObject fbo( sourceRect.size(), format2 );
// mirror vertically to be compliant with what QQuickTextureFactory expects.
// for some reason we have to add 1 pixel to avoid that the mirrored
// image gets cut off.
const QRect targetRect( sourceRect.x(), sourceRect.bottom() + 1,
sourceRect.width(), -sourceRect.height() );
2018-08-03 06:15:28 +00:00
QOpenGLFramebufferObject::blitFramebuffer(
&fbo, sourceRect, &multisampledFbo, targetRect );
2017-07-21 16:21:34 +00:00
return fbo.takeTexture();
}
static uint qskTextureRaster(
const QRect& rect, Qt::AspectRatioMode scalingMode,
const QskGraphic& graphic, const QskColorFilter& filter )
{
2018-07-13 13:09:25 +00:00
QImage image( rect.size(), QImage::Format_RGBA8888_Premultiplied );
2017-07-21 16:21:34 +00:00
image.fill( Qt::transparent );
2018-07-13 13:09:25 +00:00
2017-07-21 16:21:34 +00:00
{
QPainter painter( &image );
graphic.render( &painter, rect, filter, scalingMode );
}
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 );
2017-07-21 16:21:34 +00:00
return textureId;
}
QskGraphicTextureFactory::QskGraphicTextureFactory()
{
}
QskGraphicTextureFactory::QskGraphicTextureFactory(
2018-08-03 06:15:28 +00:00
const QskGraphic& graphic, const QSize& size )
: m_graphic( graphic )
, m_size( size )
2017-07-21 16:21:34 +00:00
{
}
QskGraphicTextureFactory::~QskGraphicTextureFactory()
{
}
QSGTexture* QskGraphicTextureFactory::createTexture( QQuickWindow* window ) const
{
const QRect textureRect( 0, 0, m_size.width(), m_size.height() );
const uint textureId = createTexture( QskGraphicTextureFactory::OpenGL,
textureRect, Qt::KeepAspectRatio, m_graphic, m_colorFilter );
const auto flags = static_cast< QQuickWindow::CreateTextureOptions >(
QQuickWindow::TextureHasAlphaChannel | QQuickWindow::TextureOwnsGLTexture );
return window->createTextureFromId( textureId, m_size, flags );
}
QSize QskGraphicTextureFactory::textureSize() const
{
return m_size;
}
int QskGraphicTextureFactory::textureByteCount() const
{
return m_size.width() * m_size.height() * 4;
}
QImage QskGraphicTextureFactory::image() const
{
return m_graphic.toImage( m_size, Qt::KeepAspectRatio );
}
2018-07-13 13:09:25 +00:00
// ### TODO: get the FBO samples from the window
2017-07-21 16:21:34 +00:00
uint QskGraphicTextureFactory::createTexture(
RenderMode mode, const QRect& rect, Qt::AspectRatioMode scalingMode,
const QskGraphic& graphic, const QskColorFilter& filter )
{
if ( mode == QskGraphicTextureFactory::Raster )
return qskTextureRaster( rect, scalingMode, graphic, filter );
else
return qskTextureFBO( rect, scalingMode, graphic, filter );
}