fix: reduce shader usage
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <qsggeometry.h>
|
||||
#include <qsgnode.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
BlobInvertedRect::BlobInvertedRect(QQuickItem* parent) : BlobShape(parent) {}
|
||||
@@ -129,6 +130,10 @@ QSGNode* BlobInvertedRect::updatePaintNode(
|
||||
material->m_invertedInner,
|
||||
m_cachedInvertedInner,
|
||||
sizeof(m_cachedInvertedInner));
|
||||
memcpy(
|
||||
material->m_invertedOuterRadii,
|
||||
m_cachedInvertedOuterRadii,
|
||||
sizeof(m_cachedInvertedOuterRadii));
|
||||
|
||||
const int count =
|
||||
static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
@@ -173,6 +178,64 @@ void BlobInvertedRect::setBorderBottom(qreal v) {
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setOuterRadius(qreal v) {
|
||||
if (qFuzzyCompare(m_outerRadius, v)) return;
|
||||
m_outerRadius = v;
|
||||
emit outerRadiusChanged();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setOuterTopLeftRadius(qreal v) {
|
||||
if (qFuzzyCompare(m_outerTopLeftRadius, v)) return;
|
||||
m_outerTopLeftRadius = v;
|
||||
emit outerTopLeftRadiusChanged();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setOuterTopRightRadius(qreal v) {
|
||||
if (qFuzzyCompare(m_outerTopRightRadius, v)) return;
|
||||
m_outerTopRightRadius = v;
|
||||
emit outerTopRightRadiusChanged();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setOuterBottomLeftRadius(qreal v) {
|
||||
if (qFuzzyCompare(m_outerBottomLeftRadius, v)) return;
|
||||
m_outerBottomLeftRadius = v;
|
||||
emit outerBottomLeftRadiusChanged();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setOuterBottomRightRadius(qreal v) {
|
||||
if (qFuzzyCompare(m_outerBottomRightRadius, v)) return;
|
||||
m_outerBottomRightRadius = v;
|
||||
emit outerBottomRightRadiusChanged();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::outerCornerRadii(float out[4]) const {
|
||||
const auto maxR = static_cast<float>(std::min(width(), height())) * 0.5f;
|
||||
const auto base = std::min(static_cast<float>(m_outerRadius), maxR);
|
||||
out[0] = std::min(
|
||||
m_outerTopRightRadius >= 0 ? static_cast<float>(m_outerTopRightRadius)
|
||||
: base,
|
||||
maxR);
|
||||
out[1] = std::min(
|
||||
m_outerBottomRightRadius >= 0
|
||||
? static_cast<float>(m_outerBottomRightRadius)
|
||||
: base,
|
||||
maxR);
|
||||
out[2] = std::min(
|
||||
m_outerBottomLeftRadius >= 0
|
||||
? static_cast<float>(m_outerBottomLeftRadius)
|
||||
: base,
|
||||
maxR);
|
||||
out[3] = std::min(
|
||||
m_outerTopLeftRadius >= 0 ? static_cast<float>(m_outerTopLeftRadius)
|
||||
: base,
|
||||
maxR);
|
||||
}
|
||||
|
||||
void BlobInvertedRect::registerWithGroup() {
|
||||
if (m_group) m_group->setInvertedRect(this);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,21 @@ class BlobInvertedRect : public BlobShape {
|
||||
Q_PROPERTY(
|
||||
qreal borderBottom READ borderBottom WRITE setBorderBottom NOTIFY
|
||||
borderBottomChanged)
|
||||
Q_PROPERTY(
|
||||
qreal outerRadius READ outerRadius WRITE setOuterRadius NOTIFY
|
||||
outerRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal outerTopLeftRadius READ outerTopLeftRadius WRITE
|
||||
setOuterTopLeftRadius NOTIFY outerTopLeftRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal outerTopRightRadius READ outerTopRightRadius WRITE
|
||||
setOuterTopRightRadius NOTIFY outerTopRightRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal outerBottomLeftRadius READ outerBottomLeftRadius WRITE
|
||||
setOuterBottomLeftRadius NOTIFY outerBottomLeftRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal outerBottomRightRadius READ outerBottomRightRadius WRITE
|
||||
setOuterBottomRightRadius NOTIFY outerBottomRightRadiusChanged)
|
||||
|
||||
public:
|
||||
explicit BlobInvertedRect(QQuickItem* parent = nullptr);
|
||||
@@ -40,15 +55,47 @@ class BlobInvertedRect : public BlobShape {
|
||||
|
||||
void setBorderBottom(qreal v);
|
||||
|
||||
[[nodiscard]] qreal outerRadius() const { return m_outerRadius; }
|
||||
|
||||
void setOuterRadius(qreal v);
|
||||
|
||||
// Per-corner outer radii. -1 falls back to outerRadius (mirrors BlobRect).
|
||||
[[nodiscard]] qreal outerTopLeftRadius() const { return m_outerTopLeftRadius; }
|
||||
|
||||
void setOuterTopLeftRadius(qreal v);
|
||||
|
||||
[[nodiscard]] qreal outerTopRightRadius() const { return m_outerTopRightRadius; }
|
||||
|
||||
void setOuterTopRightRadius(qreal v);
|
||||
|
||||
[[nodiscard]] qreal outerBottomLeftRadius() const {
|
||||
return m_outerBottomLeftRadius;
|
||||
}
|
||||
|
||||
void setOuterBottomLeftRadius(qreal v);
|
||||
|
||||
[[nodiscard]] qreal outerBottomRightRadius() const {
|
||||
return m_outerBottomRightRadius;
|
||||
}
|
||||
|
||||
void setOuterBottomRightRadius(qreal v);
|
||||
|
||||
signals:
|
||||
void borderLeftChanged();
|
||||
void borderRightChanged();
|
||||
void borderTopChanged();
|
||||
void borderBottomChanged();
|
||||
void outerRadiusChanged();
|
||||
void outerTopLeftRadiusChanged();
|
||||
void outerTopRightRadiusChanged();
|
||||
void outerBottomLeftRadiusChanged();
|
||||
void outerBottomRightRadiusChanged();
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool isInvertedRect() const override { return true; }
|
||||
|
||||
void outerCornerRadii(float out[4]) const override;
|
||||
|
||||
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
|
||||
|
||||
void registerWithGroup() override;
|
||||
@@ -59,4 +106,10 @@ class BlobInvertedRect : public BlobShape {
|
||||
qreal m_borderRight = 0;
|
||||
qreal m_borderTop = 0;
|
||||
qreal m_borderBottom = 0;
|
||||
|
||||
qreal m_outerRadius = 0;
|
||||
qreal m_outerTopLeftRadius = -1;
|
||||
qreal m_outerTopRightRadius = -1;
|
||||
qreal m_outerBottomLeftRadius = -1;
|
||||
qreal m_outerBottomRightRadius = -1;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ bool BlobMaterialShader::updateUniformData(
|
||||
Q_UNUSED(oldMaterial);
|
||||
auto* mat = static_cast<BlobMaterial*>(newMaterial);
|
||||
QByteArray* buf = state.uniformData();
|
||||
Q_ASSERT(buf->size() >= 1472);
|
||||
Q_ASSERT(buf->size() >= 1488);
|
||||
|
||||
if (state.isMatrixDirty()) {
|
||||
const QMatrix4x4 m = state.combinedMatrix();
|
||||
@@ -105,5 +105,8 @@ bool BlobMaterialShader::updateUniformData(
|
||||
memcpy(buf->data() + 1440, &mat->m_shadowRadius, 4);
|
||||
memcpy(buf->data() + 1456, mat->m_shadowColor, 16);
|
||||
|
||||
// Outer edge corner radii, after shadowColor, at 1472.
|
||||
memcpy(buf->data() + 1472, mat->m_invertedOuterRadii, 16);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ class BlobMaterial : public QSGMaterial {
|
||||
// puts these after rectData.
|
||||
float m_shadowRadius = 0.0f;
|
||||
float m_shadowColor[4] = {0.0f, 0.0f, 0.0f, 0.5f};
|
||||
// Outer-edge corner radii (tr, br, bl, tl). Matches the uniform block, which
|
||||
// puts this after shadowColor.
|
||||
float m_invertedOuterRadii[4] = {};
|
||||
BlobRectData m_rects[16] = {};
|
||||
};
|
||||
|
||||
|
||||
@@ -240,6 +240,8 @@ void BlobShape::updatePolish() {
|
||||
m_cachedInvertedRadius = 0;
|
||||
memset(m_cachedInvertedOuter, 0, sizeof(m_cachedInvertedOuter));
|
||||
memset(m_cachedInvertedInner, 0, sizeof(m_cachedInvertedInner));
|
||||
memset(
|
||||
m_cachedInvertedOuterRadii, 0, sizeof(m_cachedInvertedOuterRadii));
|
||||
|
||||
auto* inv = m_group->invertedRect();
|
||||
if (inv) {
|
||||
@@ -290,6 +292,9 @@ void BlobShape::updatePolish() {
|
||||
m_cachedInvertedInner[1] = innerCY;
|
||||
m_cachedInvertedInner[2] = innerHW;
|
||||
m_cachedInvertedInner[3] = innerHH;
|
||||
|
||||
static_cast<BlobShape*>(inv)->outerCornerRadii(
|
||||
m_cachedInvertedOuterRadii);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +422,10 @@ QSGNode* BlobShape::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
material->m_invertedInner,
|
||||
m_cachedInvertedInner,
|
||||
sizeof(m_cachedInvertedInner));
|
||||
memcpy(
|
||||
material->m_invertedOuterRadii,
|
||||
m_cachedInvertedOuterRadii,
|
||||
sizeof(m_cachedInvertedOuterRadii));
|
||||
|
||||
const int count =
|
||||
static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
|
||||
@@ -61,6 +61,16 @@ class BlobShape : public QQuickItem {
|
||||
|
||||
virtual void cornerRadii(float out[4]) const;
|
||||
|
||||
// Outer-edge corner radii. Only the inverted rect draws an outer frame edge,
|
||||
// so the base has no outer rounding and returns zeros. Subclasses that expose
|
||||
// outer corner properties override this (order: tr, br, bl, tl).
|
||||
virtual void outerCornerRadii(float out[4]) const {
|
||||
out[0] = 0;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
}
|
||||
|
||||
virtual void updatePhysics() {}
|
||||
|
||||
virtual void registerWithGroup();
|
||||
@@ -88,4 +98,5 @@ class BlobShape : public QQuickItem {
|
||||
float m_cachedInvertedRadius = 0;
|
||||
float m_cachedInvertedOuter[4] = {};
|
||||
float m_cachedInvertedInner[4] = {};
|
||||
float m_cachedInvertedOuterRadii[4] = {};
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ layout(std140, binding = 0) uniform buf {
|
||||
vec4 rectData[80];
|
||||
float shadowRadius;
|
||||
vec4 shadowColor;
|
||||
vec4 invertedOuterRadii;
|
||||
};
|
||||
|
||||
float sdRoundedBox(vec2 p, vec2 center, vec2 halfSize, float radius) {
|
||||
@@ -55,7 +56,8 @@ float smax(float a, float b, float k) {
|
||||
|
||||
float smaxSharpA(float a, float b, float k) {
|
||||
// smax variant that keeps a's boundary sharp (no inward rounding at a = 0).
|
||||
// Used for the frame outer edge so it always fills to the edges.
|
||||
// Used for the frame inner side, so the outer edge keeps its own shape and
|
||||
// always fills to the edges.
|
||||
float h = max(k - abs(a - b), 0.0) / k;
|
||||
float blend = h * h * h * k * (1.0 / 6.0);
|
||||
blend *= smoothstep(0.0, k * 0.5, -a);
|
||||
@@ -182,7 +184,12 @@ void main() {
|
||||
}
|
||||
|
||||
if (hasInverted != 0) {
|
||||
float dOuter = sdBox(pixel, invertedOuter.xy, invertedOuter.zw) - 1.0;
|
||||
// Outer edge rounds with its own per-corner radii. With all-zero radii
|
||||
// sdRoundedBox4 equals sdBox, so a frame that sets no outer radius is
|
||||
// unchanged. smaxSharpA keeps this boundary authoritative for the fill.
|
||||
float dOuter =
|
||||
sdRoundedBox4(pixel, invertedOuter.xy, invertedOuter.zw,
|
||||
invertedOuterRadii) - 1.0;
|
||||
float dInner =
|
||||
sdRoundedBox(pixel, invertedInner.xy, invertedInner.zw, invertedRadius);
|
||||
|
||||
@@ -248,7 +255,13 @@ void main() {
|
||||
|
||||
dInner -= sinkValue;
|
||||
|
||||
float dFrame = smaxSharpA(dOuter, -dInner, smoothFactor);
|
||||
// dOuter is already a true circle (sdRoundedBox4). Keep it exact whenever the
|
||||
// outer arc is the active boundary; a smax term added there would pull the
|
||||
// arc's sides inward (curvature/tangent mismatch), so the corner would not be
|
||||
// a circle. Only blend on the inner side, where the inner boundary is active.
|
||||
float negInner = -dInner;
|
||||
float dFrame = dOuter >= negInner ? dOuter
|
||||
: smaxSharpA(dOuter, negInner, smoothFactor);
|
||||
|
||||
mergedSdf = smin(mergedSdf, dFrame, smoothFactor);
|
||||
if (dFrame < minDist) {
|
||||
|
||||
Reference in New Issue
Block a user