diff options
| author | Morteza Jamshidi <morteza.jamshidi@qt.io> | 2025-12-05 14:59:23 +0100 |
|---|---|---|
| committer | Morteza Jamshidi <morteza.jamshidi@qt.io> | 2025-12-18 14:08:35 +0100 |
| commit | eaebe6716d0bc7aea7503048e243d269837411c8 (patch) | |
| tree | afa1c7512669891b47f405f5646453387ea45b9a /src | |
| parent | 70b885d2cd4eff2aa1ee08368893105666d5a92b (diff) | |
ColorDialog: use canvas to draw color picker for software renderer
When backend renderer is software ShaderEffect doesn't render anything,
so we use canvas renderer as a fallback.
Fixes: QTBUG-139362
Change-Id: Id22305ab48d52f9bf2373c88f87cbb10c115999c
Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
Diffstat (limited to 'src')
5 files changed, 219 insertions, 8 deletions
diff --git a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt index 4bb0812239..2c6d8fc5a1 100644 --- a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt +++ b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt @@ -279,9 +279,13 @@ qt_internal_add_resource(QuickDialogs2QuickImpl "QuickDialogs2QuickImpl" ) qt_internal_add_shaders(QuickDialogs2QuickImpl "QuickDialogs2QuickImplShaders" + BATCHABLE + PRECOMPILE + OPTIMIZED PREFIX "/qt-project.org/imports/QtQuick/Dialogs/quickimpl" FILES + "shaders/SaturationLightness.vert" "shaders/SaturationLightness.frag" SILENT ) diff --git a/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml b/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml index 5ad394657e..bef30ce3a8 100644 --- a/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml +++ b/src/quickdialogs/quickdialogsquickimpl/qml/SaturationLightnessPicker.qml @@ -18,15 +18,9 @@ SaturationLightnessPickerImpl { border.color: "#353637" } - contentItem: ShaderEffect { - scale: contentItem.width / width - layer.enabled: true - layer.smooth: true + contentItem: SaturationLightnessPickerCanvas { anchors.fill: parent - - property alias hue: control.hue - - fragmentShader: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.frag.qsb" + hue: control.hue } handle: PickerHandle { diff --git a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp index 02aad6198c..1969a4f548 100644 --- a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp +++ b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker.cpp @@ -4,6 +4,8 @@ #include "qquicksaturationlightnesspicker_p.h" #include "qquickabstractcolorpicker_p_p.h" +#include "qsgsimpletexturenode.h" +#include "qsgtexture.h" #include <QtQuickTemplates2/private/qquickcontrol_p_p.h> #include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h> @@ -22,6 +24,173 @@ QQuickSaturationLightnessPickerPrivate::QQuickSaturationLightnessPickerPrivate() m_hsl = true; } +class QQuickSaturationLightnessPickerMaterialShader : public QSGMaterialShader +{ +public: + QQuickSaturationLightnessPickerMaterialShader() { + setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/imports/QtQuick/Dialogs/quickimpl/shaders/SaturationLightness.frag.qsb")); + } + + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; +}; + +class QQuickSaturationLightnessPickerMaterial : public QSGMaterial +{ +public: + QQuickSaturationLightnessPickerMaterial() { setFlag(Blending, true); } + QSGMaterialType* type() const override { static QSGMaterialType t; return &t; } + QSGMaterialShader* createShader(QSGRendererInterface::RenderMode renderMode) const override{ + Q_UNUSED(renderMode); + return new QQuickSaturationLightnessPickerMaterialShader(); + } + float hue = 0.0f; +}; + +bool QQuickSaturationLightnessPickerMaterialShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + Q_ASSERT(!oldMaterial || newMaterial->type() == oldMaterial->type()); + + QQuickSaturationLightnessPickerMaterial *mat = + static_cast<QQuickSaturationLightnessPickerMaterial*>(newMaterial); + QQuickSaturationLightnessPickerMaterial *oldMat = + static_cast<QQuickSaturationLightnessPickerMaterial*>(oldMaterial); + + bool changed = false; + QByteArray *buf = state.uniformData(); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; + } + + if (state.isOpacityDirty() || !oldMat) { + float opacity = state.opacity(); + memcpy(buf->data() + 64, &opacity, sizeof(float)); + changed = true; + } + + if (!oldMat || mat->hue != oldMat->hue) { + float hue = mat->hue; + memcpy(buf->data() + 64 + 4, &hue, sizeof(float)); + changed = true; + } + + return changed; +} + +QQuickSaturationLightnessPickerCanvas::QQuickSaturationLightnessPickerCanvas(QQuickItem *parent) + : QQuickItem(parent), m_hue(0) { + setFlag(ItemHasContents, true); +} + +void QQuickSaturationLightnessPickerCanvas::setHue(qreal h) +{ + if (h == m_hue) + return; + m_hue = h; + m_image = QImage(); + emit hueChanged(); + update(); +} + +QSGNode *QQuickSaturationLightnessPickerCanvas::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + QSGGeometryNode *node = nullptr; + + bool shaderSupported = false; + if (window()) { + QSGRendererInterface::GraphicsApi api = window()->rendererInterface()->graphicsApi(); + switch (api) { + case QSGRendererInterface::OpenGL: + case QSGRendererInterface::Vulkan: + case QSGRendererInterface::Metal: + case QSGRendererInterface::Direct3D11: + shaderSupported = true; + break; + default: + shaderSupported = false; + } + } + if (shaderSupported) { + // GPU path + QSGGeometryNode* geomNode = static_cast<QSGGeometryNode*>(oldNode); + QSGGeometry* geom; + if (!geomNode) { + geomNode = new QSGGeometryNode(); + geom = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4); + geom->setDrawingMode(QSGGeometry::DrawTriangleStrip); + geomNode->setGeometry(geom); + geomNode->setFlag(QSGNode::OwnsGeometry); + + auto* mat = new QQuickSaturationLightnessPickerMaterial(); + geomNode->setMaterial(mat); + geomNode->setFlag(QSGNode::OwnsMaterial); + } + else { + geom = geomNode->geometry(); + } + + if (m_lastSize != size()) { + m_lastSize = size(); + + auto *v = geom->vertexDataAsTexturedPoint2D(); + v[0].set(0, 0, 0, 0); + v[1].set(width(), 0, 1, 0); + v[2].set(0, height(), 0, 1); + v[3].set(width(), height(), 1, 1); + + geomNode->markDirty(QSGNode::DirtyGeometry); + } + + auto* mat = static_cast<QQuickSaturationLightnessPickerMaterial*>(geomNode->material()); + if (mat->hue != m_hue) { + mat->hue = m_hue; + geomNode->markDirty(QSGNode::DirtyMaterial); + } + node = geomNode; + + } else { + // CPU path + QSGSimpleTextureNode *texNode = static_cast<QSGSimpleTextureNode*>(oldNode); + if (!texNode) texNode = new QSGSimpleTextureNode(); + if (m_image.size().isNull() || m_image.size() != QSize(width(), height())) + m_image = generateImage(width(), height(), m_hue); + QSGTexture *tex = window()->createTextureFromImage(m_image); + texNode->setTexture(tex); + texNode->setOwnsTexture(true); + texNode->setRect(0,0,width(),height()); + node = texNode; + } + return node; +} + +QImage QQuickSaturationLightnessPickerCanvas::generateImage(int width, int height, double hue01) const +{ + QImage img(width, height, QImage::Format_RGB32); + QRgb* bits = reinterpret_cast<QRgb*>(img.bits()); + double hue = hue01 * 360.0; + + // Pre-calculate RGB values for each saturation-lightness pair + std::vector<QRgb> lut(256 * 256); + for (int s = 0; s < 256; ++s) { + for (int l = 0; l < 256; ++l) { + lut[s * 256 + l] = QColor::fromHsl(hue, s, l).rgb(); + } + } + + for (int y = 0; y < height; ++y) { + int saturation = static_cast<int>((1.0 - double(y) / (height - 1)) * 255); + QRgb* row = bits + y * width; + for (int x = 0; x < width; ++x) { + int lightness = static_cast<int>(double(x) / (width - 1) * 255); + row[x] = lut[saturation * 256 + lightness]; + } + } + return img; +} + QQuickSaturationLightnessPicker::QQuickSaturationLightnessPicker(QQuickItem *parent) : QQuickAbstractColorPicker(*(new QQuickSaturationLightnessPickerPrivate), parent) { diff --git a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h index bf651bffe8..8ab801b4a4 100644 --- a/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h +++ b/src/quickdialogs/quickdialogsquickimpl/qquicksaturationlightnesspicker_p.h @@ -23,6 +23,32 @@ QT_BEGIN_NAMESPACE class QQuickSaturationLightnessPickerPrivate; +class Q_QUICKDIALOGS2QUICKIMPL_EXPORT QQuickSaturationLightnessPickerCanvas : public QQuickItem +{ + Q_OBJECT + QML_NAMED_ELEMENT(SaturationLightnessPickerCanvas) + Q_PROPERTY(qreal hue READ hue WRITE setHue NOTIFY hueChanged FINAL) + +public: + QQuickSaturationLightnessPickerCanvas(QQuickItem *parent = nullptr); + + qreal hue() const { return m_hue; } + void setHue(qreal h); + +signals: + void hueChanged(); + +protected: + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; + +private: + qreal m_hue; + QImage m_image; + QSizeF m_lastSize; + + QImage generateImage(int width, int height, double hue01) const; +}; + class Q_QUICKDIALOGS2QUICKIMPL_EXPORT QQuickSaturationLightnessPicker : public QQuickAbstractColorPicker { diff --git a/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert b/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert new file mode 100644 index 0000000000..cbae4d98a1 --- /dev/null +++ b/src/quickdialogs/quickdialogsquickimpl/shaders/SaturationLightness.vert @@ -0,0 +1,18 @@ +#version 440 + +layout(location = 0) in vec4 qt_VertexPosition; +layout(location = 1) in vec2 qt_VertexTexCoord; + +layout(location = 0) out vec2 qt_TexCoord0; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float hue; +}; + +void main() +{ + qt_TexCoord0 = qt_VertexTexCoord; + gl_Position = qt_Matrix * qt_VertexPosition; +} |
