code moved to QskColorRamp

This commit is contained in:
Uwe Rathmann 2022-11-16 17:26:50 +01:00
parent d327a68fc1
commit 974e7372dd
4 changed files with 219 additions and 183 deletions

170
src/nodes/QskColorRamp.cpp Normal file
View File

@ -0,0 +1,170 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskColorRamp.h"
#include "QskRgbValue.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qrhi_p.h>
#include <private/qsgplaintexture_p.h>
QSK_QT_PRIVATE_END
#include <qcoreapplication.h>
namespace
{
class Texture : public QSGPlainTexture
{
public:
Texture( const QskGradientStops& stops, QGradient::Spread spread )
{
/*
Qt creates tables of 1024 colors, while Chrome, Firefox, and Android
seem to use 256 colors only ( according to maybe outdated sources
from the internet ),
*/
setImage( QskRgb::colorTable( 256, stops ) );
const auto wrapMode = this->wrapMode( spread );
setHorizontalWrapMode( wrapMode );
setVerticalWrapMode( wrapMode );
setFiltering( QSGTexture::Linear );
};
private:
static inline QSGTexture::WrapMode wrapMode( QGradient::Spread spread )
{
switch ( spread )
{
case QGradient::RepeatSpread:
return QSGTexture::Repeat;
case QGradient::ReflectSpread:
return QSGTexture::MirroredRepeat;
default:
return QSGTexture::ClampToEdge;
}
}
};
class HashKey
{
public:
inline bool operator==( const HashKey& other ) const
{
return rhi == other.rhi && spread == other.spread && stops == other.stops;
}
const void* rhi;
const QskGradientStops stops;
const QGradient::Spread spread;
};
inline size_t qHash( const HashKey& key, size_t seed = 0 )
{
size_t values = seed + key.spread;
for ( const auto& stop : key.stops )
values += stop.rgb();
return values;
}
class Cache
{
public:
~Cache() { qDeleteAll( m_hashTable ); }
void cleanupRhi( const QRhi* );
Texture* texture( const void* rhi,
const QskGradientStops&, QGradient::Spread );
private:
QHash< HashKey, Texture* > m_hashTable;
QVector< const QRhi* > m_rhiTable; // no QSet: we usually have only one entry
};
static Cache* s_cache;
}
static void qskCleanupCache()
{
delete s_cache;
s_cache = nullptr;
}
static void qskCleanupRhi( const QRhi* rhi )
{
if ( s_cache )
s_cache->cleanupRhi( rhi );
}
Texture* Cache::texture( const void* rhi,
const QskGradientStops& stops, QGradient::Spread spread )
{
const HashKey key { rhi, stops, spread };
auto texture = m_hashTable[key];
if ( texture == nullptr )
{
texture = new Texture( stops, spread );
m_hashTable[ key ] = texture;
if ( rhi != nullptr )
{
auto myrhi = ( QRhi* )rhi;
if ( !m_rhiTable.contains( myrhi ) )
{
myrhi->addCleanupCallback( qskCleanupRhi );
m_rhiTable += myrhi;
}
}
}
return texture;
}
void Cache::cleanupRhi( const QRhi* rhi )
{
for ( auto it = m_hashTable.begin(); it != m_hashTable.end(); )
{
if ( it.key().rhi == rhi )
{
delete it.value();
it = m_hashTable.erase( it );
}
else
{
++it;
}
}
m_rhiTable.removeAll( rhi );
}
QSGTexture* QskColorRamp::texture( const void* rhi,
const QskGradientStops& stops, QGradient::Spread spread )
{
if ( s_cache == nullptr )
{
s_cache = new Cache();
/*
For RHI we have QRhi::addCleanupCallback, but with
OpenGL we would have to fiddle around with QOpenGLSharedResource
But as the OpenGL path is only for Qt5 we do not want to spend
much energy on finetuning the resource management.
*/
qAddPostRoutine( qskCleanupCache );
}
return s_cache->texture( rhi, stops, spread );
}

21
src/nodes/QskColorRamp.h Normal file
View File

@ -0,0 +1,21 @@
/**********************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_COLOR_RAMP_H
#define QSK_COLOR_RAMP_H
#include "QskGlobal.h"
#include "QskGradientStop.h"
#include <qbrush.h>
class QSGTexture;
namespace QskColorRamp
{
QSGTexture* texture( const void* rhi, const QskGradientStops&, QGradient::Spread );
}
#endif

View File

@ -7,14 +7,15 @@
#include "QskFunctions.h" #include "QskFunctions.h"
#include "QskRgbValue.h" #include "QskRgbValue.h"
#include "QskGradientDirection.h" #include "QskGradientDirection.h"
#include "QskColorRamp.h"
#include <qsgtexture.h>
QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_BEGIN
#include <private/qrhi_p.h> #include <private/qrhi_p.h>
#include <private/qdrawhelper_p.h> #include <private/qdrawhelper_p.h>
#include <private/qsgplaintexture_p.h>
QSK_QT_PRIVATE_END QSK_QT_PRIVATE_END
#include <qcoreapplication.h>
#include <cmath> #include <cmath>
// RHI shaders are supported by Qt 5.15 and Qt 6.x // RHI shaders are supported by Qt 5.15 and Qt 6.x
@ -32,153 +33,6 @@ QSK_QT_PRIVATE_END
using RhiShader = QSGMaterialShader; using RhiShader = QSGMaterialShader;
#endif #endif
namespace
{
class ColorRamp : public QSGPlainTexture
{
public:
ColorRamp( const QskGradientStops& stops, QGradient::Spread spread )
{
/*
Qt creates tables of 1024 colors, while Chrome, Firefox, and Android
seem to use 256 colors only ( according to maybe outdated sources
from the internet ),
*/
setImage( QskRgb::colorTable( 256, stops ) );
const auto wrapMode = this->wrapMode( spread );
setHorizontalWrapMode( wrapMode );
setVerticalWrapMode( wrapMode );
setFiltering( QSGTexture::Linear );
};
private:
static inline QSGTexture::WrapMode wrapMode( QGradient::Spread spread )
{
switch ( spread )
{
case QGradient::RepeatSpread:
return QSGTexture::Repeat;
case QGradient::ReflectSpread:
return QSGTexture::MirroredRepeat;
default:
return QSGTexture::ClampToEdge;
}
}
};
class ColorRampHashKey
{
public:
inline bool operator==( const ColorRampHashKey& other ) const
{
return rhi == other.rhi && spread == other.spread && stops == other.stops;
}
const void* rhi;
const QskGradientStops stops;
const QGradient::Spread spread;
};
inline size_t qHash( const ColorRampHashKey& key, size_t seed = 0 )
{
size_t valus = seed + key.spread;
for ( const auto& stop : key.stops )
valus += stop.rgb();
return valus;
}
class ColorRampCache
{
public:
static ColorRampCache* instance()
{
static ColorRampCache* s_instance = nullptr;
if ( s_instance == nullptr )
{
s_instance = new ColorRampCache();
/*
For RHI we have QRhi::addCleanupCallback, but with
OpenGL we have to fiddle around with QOpenGLSharedResource
So let's keep things simple for the moment. TODO ...
*/
qAddPostRoutine( cleanup );
}
return s_instance;
}
~ColorRampCache()
{
qDeleteAll( m_hashTable );
}
ColorRamp* colorRamp( const void* rhi,
const QskGradientStops& stops, QGradient::Spread spread )
{
const ColorRampHashKey key { rhi, stops, spread };
auto texture = m_hashTable[key];
if ( texture == nullptr )
{
texture = new ColorRamp( stops, spread );
m_hashTable[ key ] = texture;
if ( rhi != nullptr )
{
auto myrhi = ( QRhi* )rhi;
if ( !m_rhiTable.contains( myrhi ) )
{
myrhi->addCleanupCallback( ColorRampCache::cleanupRhi );
m_rhiTable += myrhi;
}
}
}
return texture;
}
private:
static void cleanup()
{
delete instance();
}
static void cleanupRhi( const QRhi *rhi )
{
auto cache = instance();
auto& table = cache->m_hashTable;
for ( auto it = table.begin(); it != table.end(); )
{
if ( it.key().rhi == rhi )
{
delete it.value();
it = table.erase( it );
}
else
{
++it;
}
}
cache->m_rhiTable.removeAll( rhi );
}
QHash< ColorRampHashKey, ColorRamp* > m_hashTable;
QVector< const QRhi* > m_rhiTable;
};
}
namespace namespace
{ {
class GradientMaterial : public QskGradientMaterial class GradientMaterial : public QskGradientMaterial
@ -215,6 +69,8 @@ namespace
virtual QSGMaterialShader* createShader() const = 0; virtual QSGMaterialShader* createShader() const = 0;
#endif #endif
virtual bool setGradient( const QRectF&, const QskGradient& ) = 0;
}; };
#ifdef SHADER_GL #ifdef SHADER_GL
@ -250,9 +106,9 @@ namespace
updateUniformValues( material ); updateUniformValues( material );
auto colorRamp = ColorRampCache::instance()->colorRamp( auto texture = QskColorRamp::texture(
nullptr, material->stops(), material->spread() ); nullptr, material->stops(), material->spread() );
colorRamp->bind(); texture->bind();
} }
char const* const* attributeNames() const override final char const* const* attributeNames() const override final
@ -289,16 +145,16 @@ namespace
auto material = static_cast< const GradientMaterial* >( newMaterial ); auto material = static_cast< const GradientMaterial* >( newMaterial );
auto colorRamp = ColorRampCache::instance()->colorRamp( auto texture = QskColorRamp::texture(
state.rhi(), material->stops(), material->spread() ); state.rhi(), material->stops(), material->spread() );
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) #if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
colorRamp->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() ); texture->updateRhiTexture( state.rhi(), state.resourceUpdateBatch() );
#else #else
colorRamp->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() ); texture->commitTextureOperations( state.rhi(), state.resourceUpdateBatch() );
#endif #endif
textures[0] = colorRamp; textures[0] = texture;
} }
}; };
#endif #endif
@ -314,7 +170,7 @@ namespace
{ {
} }
bool setGradient( const QRectF& rect, const QskGradient& gradient ) bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
{ {
bool changed = false; bool changed = false;
@ -475,7 +331,7 @@ namespace
return &type; return &type;
} }
bool setGradient( const QRectF& rect, const QskGradient& gradient ) bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
{ {
bool changed = false; bool changed = false;
@ -646,7 +502,7 @@ namespace
return &type; return &type;
} }
bool setGradient( const QRectF& rect, const QskGradient& gradient ) bool setGradient( const QRectF& rect, const QskGradient& gradient ) override
{ {
bool changed = false; bool changed = false;
@ -835,33 +691,20 @@ bool QskGradientMaterial::updateGradient( const QRectF& rect, const QskGradient&
{ {
Q_ASSERT( gradient.type() == m_gradientType ); Q_ASSERT( gradient.type() == m_gradientType );
if ( gradient.type() != m_gradientType ) if ( gradient.type() == m_gradientType )
return false; {
switch ( gradient.type() ) switch ( gradient.type() )
{ {
case QskGradient::Linear: case QskGradient::Linear:
{
auto material = static_cast< LinearMaterial* >( this );
return material->setGradient( rect, gradient );
}
case QskGradient::Radial: case QskGradient::Radial:
{
auto material = static_cast< RadialMaterial* >( this );
return material->setGradient( rect, gradient );
}
case QskGradient::Conic: case QskGradient::Conic:
{ {
auto material = static_cast< ConicMaterial* >( this ); auto material = static_cast< GradientMaterial* >( this );
return material->setGradient( rect, gradient ); return material->setGradient( rect, gradient );
} }
default: default:
{
qWarning( "Invalid gradient type" ); qWarning( "Invalid gradient type" );
break;
} }
} }

View File

@ -106,6 +106,7 @@ HEADERS += \
nodes/QskBoxRenderer.h \ nodes/QskBoxRenderer.h \
nodes/QskBoxRendererColorMap.h \ nodes/QskBoxRendererColorMap.h \
nodes/QskBoxShadowNode.h \ nodes/QskBoxShadowNode.h \
nodes/QskColorRamp.h \
nodes/QskGraphicNode.h \ nodes/QskGraphicNode.h \
nodes/QskPaintedNode.h \ nodes/QskPaintedNode.h \
nodes/QskPlainTextRenderer.h \ nodes/QskPlainTextRenderer.h \
@ -131,6 +132,7 @@ SOURCES += \
nodes/QskBoxRendererEllipse.cpp \ nodes/QskBoxRendererEllipse.cpp \
nodes/QskBoxRendererDEllipse.cpp \ nodes/QskBoxRendererDEllipse.cpp \
nodes/QskBoxShadowNode.cpp \ nodes/QskBoxShadowNode.cpp \
nodes/QskColorRamp.cpp \
nodes/QskGraphicNode.cpp \ nodes/QskGraphicNode.cpp \
nodes/QskPaintedNode.cpp \ nodes/QskPaintedNode.cpp \
nodes/QskPlainTextRenderer.cpp \ nodes/QskPlainTextRenderer.cpp \