Krita Source Code Documentation
Loading...
Searching...
No Matches
KisDabCacheBase Class Reference

The KisDabCacheBase class provides caching for dabs into the brush paintop. More...

#include <kis_dab_cache_base.h>

+ Inheritance diagram for KisDabCacheBase:

Classes

struct  DabPosition
 
struct  Private
 
struct  SavedDabParameters
 

Public Member Functions

void disableSubpixelPrecision ()
 
 KisDabCacheBase ()
 
bool needSeparateOriginal (KisTextureOption *textureOption, KisSharpnessOption *sharpnessOption) const
 
void setMirrorPostprocessing (KisMirrorOption *option)
 
void setPrecisionOption (KisPrecisionOption *option)
 
 ~KisDabCacheBase ()
 

Protected Member Functions

void fetchDabGenerationInfo (bool hasDabInCache, KisDabCacheUtils::DabRenderingResources *resources, const KisDabCacheUtils::DabRequestInfo &request, KisDabCacheUtils::DabGenerationInfo *di, bool *shouldUseCache)
 

Private Member Functions

KisDabCacheBase::DabPosition calculateDabRect (KisBrushSP brush, const QPointF &cursorPoint, KisDabShape, const KisPaintInformation &info, const MirrorProperties &mirrorProperties, KisSharpnessOption *sharpnessOption)
 
SavedDabParameters getDabParameters (KisBrushSP brush, const KoColor &color, KisDabShape const &, const KisPaintInformation &info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength, MirrorProperties mirrorProperties)
 

Private Attributes

Private *const m_d
 

Detailed Description

The KisDabCacheBase class provides caching for dabs into the brush paintop.

This class adds caching of the dabs to the paintop system of Krita. Such cache makes the execution of the benchmarks up to 2 times faster. Subjectively, the real painting becomes much faster, especially with huge brushes. Artists report up to 20% speed gain while painting.

Of course, such caching makes the painting a bit less precise: we need to tolerate subpixel differences to allow the cache to work. Sometimes small difference in the size of a dab can also be acceptable. That is why I introduced levels of precision. They are graded from 1 to 5: from the fastest and less precise to the slowest, but with the best quality. You can see the slider in the paintop settings dialog. The ToolTip text explains which features of the brush are sacrificed on each precision level.

The texturing and mirroring problems are solved.

Definition at line 42 of file kis_dab_cache_base.h.

Constructor & Destructor Documentation

◆ KisDabCacheBase()

KisDabCacheBase::KisDabCacheBase ( )

Definition at line 90 of file kis_dab_cache_base.cpp.

91 : m_d(new Private())
92{
93}

◆ ~KisDabCacheBase()

KisDabCacheBase::~KisDabCacheBase ( )

Definition at line 95 of file kis_dab_cache_base.cpp.

96{
97 delete m_d;
98}

References m_d.

Member Function Documentation

◆ calculateDabRect()

KisDabCacheBase::DabPosition KisDabCacheBase::calculateDabRect ( KisBrushSP brush,
const QPointF & cursorPoint,
KisDabShape shape,
const KisPaintInformation & info,
const MirrorProperties & mirrorProperties,
KisSharpnessOption * sharpnessOption )
inlineprivate

Definition at line 173 of file kis_dab_cache_base.cpp.

179{
180 qint32 x = 0, y = 0;
181 qreal subPixelX = 0.0, subPixelY = 0.0;
182
183 if (mirrorProperties.coordinateSystemFlipped) {
184 shape = KisDabShape(shape.scale(), shape.ratio(), 2 * M_PI - shape.rotation());
185 }
186
187 QPointF hotSpot = brush->hotSpot(shape, info);
188 QPointF pt = cursorPoint - hotSpot;
189
190 if (sharpnessOption) {
191 sharpnessOption->apply(info, pt, x, y, subPixelX, subPixelY);
192 }
193 else {
194 KisPaintOp::splitCoordinate(pt.x(), &x, &subPixelX);
195 KisPaintOp::splitCoordinate(pt.y(), &y, &subPixelY);
196 }
197
199 subPixelX = 0;
200 subPixelY = 0;
201 }
202
203 if (qIsNaN(subPixelX)) {
204 subPixelX = 0;
205 }
206
207 if (qIsNaN(subPixelY)) {
208 subPixelY = 0;
209 }
210
211 int width = brush->maskWidth(shape, subPixelX, subPixelY, info);
212 int height = brush->maskHeight(shape, subPixelX, subPixelY, info);
213
214 if (mirrorProperties.horizontalMirror) {
215 subPixelX = Private::positiveFraction(-(cursorPoint.x() + hotSpot.x()));
216 width = brush->maskWidth(shape, subPixelX, subPixelY, info);
217 x = qRound(cursorPoint.x() + subPixelX + hotSpot.x()) - width;
218 }
219
220 if (mirrorProperties.verticalMirror) {
221 subPixelY = Private::positiveFraction(-(cursorPoint.y() + hotSpot.y()));
222 height = brush->maskHeight(shape, subPixelX, subPixelY, info);
223 y = qRound(cursorPoint.y() + subPixelY + hotSpot.y()) - height;
224 }
225
226 return DabPosition(QRect(x, y, width, height),
227 QPointF(subPixelX, subPixelY),
228 shape.rotation());
229}
qreal scale() const
qreal rotation() const
qreal ratio() const
void apply(const KisPaintInformation &info, const QPointF &pt, qint32 &x, qint32 &y, qreal &xFraction, qreal &yFraction) const
#define M_PI
Definition kis_global.h:111
static qreal positiveFraction(qreal x)
static void splitCoordinate(qreal coordinate, qint32 *whole, qreal *fraction)

References KisSharpnessOption::apply(), MirrorProperties::coordinateSystemFlipped, MirrorProperties::horizontalMirror, m_d, M_PI, KisDabCacheBase::Private::positiveFraction(), KisDabShape::ratio(), KisDabShape::rotation(), KisDabShape::scale(), KisPaintOp::splitCoordinate(), KisDabCacheBase::Private::subPixelPrecisionDisabled, and MirrorProperties::verticalMirror.

◆ disableSubpixelPrecision()

void KisDabCacheBase::disableSubpixelPrecision ( )

Disables handling of the subPixelX and subPixelY values, this is needed at least for the Color Smudge paint op, which reads aligned areas from image, so additional offsets generated by the subpixel precision should be avoided

Definition at line 110 of file kis_dab_cache_base.cpp.

111{
113}

References m_d, and KisDabCacheBase::Private::subPixelPrecisionDisabled.

◆ fetchDabGenerationInfo()

void KisDabCacheBase::fetchDabGenerationInfo ( bool hasDabInCache,
KisDabCacheUtils::DabRenderingResources * resources,
const KisDabCacheUtils::DabRequestInfo & request,
KisDabCacheUtils::DabGenerationInfo * di,
bool * shouldUseCache )
protected

Fetches all the necessary information for dab generation and tells if the caller must should reuse the preciously returned dab. * Please note that KisDabCacheBase has an internal state, that keeps the parameters of the previously generated (on a cache-miss) dab. This function automatically updates this state when 'shouldUseCache == false'. Therefore, the caller must generate the dab if and only if when 'shouldUseCache == false'. Otherwise the internal state will become inconsistent.

Parameters
hasDabInCacheshows if the caller has something in its cache
resourcesrendering resources available for this dab
requestthe request information
di(OUT) calculated dab generation information
shouldUseCache(OUT) shows whether the caller must use cache or not

Definition at line 231 of file kis_dab_cache_base.cpp.

236{
237 di->info = request.info;
238 di->softnessFactor = request.softnessFactor;
239 di->lightnessStrength = request.lightnessStrength;
240
241 if (m_d->mirrorOption) {
242 di->mirrorProperties = m_d->mirrorOption->apply(request.info);
243 }
244
245 DabPosition position = calculateDabRect(resources->brush,
246 request.cursorPoint,
247 request.shape,
248 request.info,
250 resources->sharpnessOption.data());
251 di->shape = KisDabShape(request.shape.scale(), request.shape.ratio(), position.realAngle);
252 di->dstDabRect = position.rect;
253 di->subPixel = position.subPixel;
254
255 const bool supportsCaching = resources->brush->supportsCaching();
256
257 const KisUniformColorSource *uniformColorSource =
258 resources->colorSource ? dynamic_cast<const KisUniformColorSource*>(resources->colorSource.data()) : 0;
259
260 di->solidColorFill = !resources->colorSource || uniformColorSource;
261 di->paintColor = uniformColorSource ?
262 uniformColorSource->uniformColor() : request.color;
263
264 SavedDabParameters newParams = getDabParameters(resources->brush,
265 di->paintColor,
266 di->shape,
267 di->info,
268 di->subPixel.x(),
269 di->subPixel.y(),
270 di->softnessFactor,
272 di->mirrorProperties);
273
274 int precisionLevel = 4;
275 if (m_d->precisionOption) {
276 const int effectiveDabSize = qMin(newParams.width, newParams.height);
277 precisionLevel = m_d->precisionOption->effectivePrecisionLevel(effectiveDabSize) - 1;
278 }
279 *shouldUseCache = hasDabInCache && supportsCaching && di->solidColorFill &&
280 newParams.compare(m_d->lastSavedDabParameters, precisionLevel);
281
282 if (!*shouldUseCache) {
283 m_d->lastSavedDabParameters = newParams;
284 }
285
286 di->needsPostprocessing = needSeparateOriginal(resources->textureOption.data(), resources->sharpnessOption.data());
287}
KisDabCacheBase::DabPosition calculateDabRect(KisBrushSP brush, const QPointF &cursorPoint, KisDabShape, const KisPaintInformation &info, const MirrorProperties &mirrorProperties, KisSharpnessOption *sharpnessOption)
SavedDabParameters getDabParameters(KisBrushSP brush, const KoColor &color, KisDabShape const &, const KisPaintInformation &info, double subPixelX, double subPixelY, qreal softnessFactor, qreal lightnessStrength, MirrorProperties mirrorProperties)
bool needSeparateOriginal(KisTextureOption *textureOption, KisSharpnessOption *sharpnessOption) const
MirrorProperties apply(const KisPaintInformation &info) const
int effectivePrecisionLevel(qreal effectiveDabSize) const
const KoColor & uniformColor() const
KisPrecisionOption * precisionOption
SavedDabParameters lastSavedDabParameters
QScopedPointer< KisColorSource > colorSource
QScopedPointer< KisSharpnessOption > sharpnessOption
QScopedPointer< KisTextureOption > textureOption

References KisMirrorOption::apply(), KisDabCacheUtils::DabRenderingResources::brush, calculateDabRect(), KisDabCacheUtils::DabRenderingResources::colorSource, KisDabCacheBase::SavedDabParameters::compare(), KisDabCacheUtils::DabGenerationInfo::dstDabRect, KisPrecisionOption::effectivePrecisionLevel(), getDabParameters(), KisDabCacheBase::SavedDabParameters::height, KisDabCacheUtils::DabGenerationInfo::info, KisDabCacheBase::Private::lastSavedDabParameters, KisDabCacheUtils::DabGenerationInfo::lightnessStrength, m_d, KisDabCacheBase::Private::mirrorOption, KisDabCacheUtils::DabGenerationInfo::mirrorProperties, needSeparateOriginal(), KisDabCacheUtils::DabGenerationInfo::needsPostprocessing, KisDabCacheUtils::DabGenerationInfo::paintColor, KisDabCacheBase::Private::precisionOption, KisDabCacheBase::DabPosition::realAngle, KisDabCacheBase::DabPosition::rect, KisDabCacheUtils::DabGenerationInfo::shape, KisDabCacheUtils::DabRenderingResources::sharpnessOption, KisDabCacheUtils::DabGenerationInfo::softnessFactor, KisDabCacheUtils::DabGenerationInfo::solidColorFill, KisDabCacheBase::DabPosition::subPixel, KisDabCacheUtils::DabGenerationInfo::subPixel, KisDabCacheUtils::DabRenderingResources::textureOption, KisUniformColorSource::uniformColor(), and KisDabCacheBase::SavedDabParameters::width.

◆ getDabParameters()

KisDabCacheBase::SavedDabParameters KisDabCacheBase::getDabParameters ( KisBrushSP brush,
const KoColor & color,
KisDabShape const & shape,
const KisPaintInformation & info,
double subPixelX,
double subPixelY,
qreal softnessFactor,
qreal lightnessStrength,
MirrorProperties mirrorProperties )
inlineprivate

Definition at line 116 of file kis_dab_cache_base.cpp.

124{
125 SavedDabParameters params;
126
127 params.color = color;
128 params.angle = shape.rotation();
129 params.width = brush->maskWidth(shape, subPixelX, subPixelY, info);
130 params.height = brush->maskHeight(shape, subPixelX, subPixelY, info);
131 params.subPixelX = subPixelX;
132 params.subPixelY = subPixelY;
133 params.softnessFactor = softnessFactor;
134 params.lightnessStrength = lightnessStrength;
135 params.index = brush->brushIndex();
136 params.mirrorProperties = mirrorProperties;
137 params.ratio = shape.ratio();
138
139 return params;
140}

References KisDabCacheBase::SavedDabParameters::angle, KisDabCacheBase::SavedDabParameters::color, KisDabCacheBase::SavedDabParameters::height, KisDabCacheBase::SavedDabParameters::index, KisDabCacheBase::SavedDabParameters::lightnessStrength, KisDabCacheBase::SavedDabParameters::mirrorProperties, KisDabShape::ratio(), KisDabCacheBase::SavedDabParameters::ratio, KisDabShape::rotation(), KisDabCacheBase::SavedDabParameters::softnessFactor, KisDabCacheBase::SavedDabParameters::subPixelX, KisDabCacheBase::SavedDabParameters::subPixelY, and KisDabCacheBase::SavedDabParameters::width.

◆ needSeparateOriginal()

bool KisDabCacheBase::needSeparateOriginal ( KisTextureOption * textureOption,
KisSharpnessOption * sharpnessOption ) const

Return true if the dab needs postprocessing by special options like 'texture' or 'sharpness'

Definition at line 142 of file kis_dab_cache_base.cpp.

144{
145 return (textureOption && textureOption->m_enabled) ||
146 (sharpnessOption && sharpnessOption->isChecked());
147}
bool isChecked() const

References KisCurveOption::isChecked(), and KisTextureOption::m_enabled.

◆ setMirrorPostprocessing()

void KisDabCacheBase::setMirrorPostprocessing ( KisMirrorOption * option)

Definition at line 100 of file kis_dab_cache_base.cpp.

101{
102 m_d->mirrorOption = option;
103}

References m_d, and KisDabCacheBase::Private::mirrorOption.

◆ setPrecisionOption()

void KisDabCacheBase::setPrecisionOption ( KisPrecisionOption * option)

Definition at line 105 of file kis_dab_cache_base.cpp.

106{
107 m_d->precisionOption = option;
108}

References m_d, and KisDabCacheBase::Private::precisionOption.

Member Data Documentation

◆ m_d

Private* const KisDabCacheBase::m_d
private

Definition at line 109 of file kis_dab_cache_base.h.


The documentation for this class was generated from the following files: