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

#include <KisOverlayPaintDeviceWrapper.h>

Classes

struct  Private
 

Public Types

enum  OverlayMode { NormalMode = 0 , PreciseMode , LazyPreciseMode }
 

Public Member Functions

void beginTransaction (KUndo2Command *parent=0)
 
KisPaintDeviceSP createPreciseCompositionSourceDevice ()
 
KUndo2CommandendTransaction ()
 
KisPaintDeviceSP externalDestination () const
 
 KisOverlayPaintDeviceWrapper (KisPaintDeviceSP source, int numOverlays=1, OverlayMode mode=NormalMode, const KoColorSpace *forcedOverlayColorSpace=nullptr)
 
KisPaintDeviceSP overlay (int index=0) const
 
const KoColorSpaceoverlayColorSpace () const
 
void readRect (const QRect &rc)
 
void readRects (const QVector< QRect > &rects)
 
void setExternalDestination (KisPaintDeviceSP device)
 
KisPaintDeviceSP source () const
 
void writeRect (const QRect &rc, int index=0)
 
void writeRects (const QVector< QRect > &rects, int index=0)
 
 ~KisOverlayPaintDeviceWrapper ()
 

Private Attributes

const QScopedPointer< Privatem_d
 

Friends

struct KisChangeOverlayWrapperCommand
 

Detailed Description

A special wrapper class for a paint device that allows working with parts of the source paint device using an overlay, that is without modifying the device itself. The overlay may have higher bit depth if PreciseMode or LazyPreciseMode is used.

For example, you have an RGBA8 paint device, but you want all the blending happen in higher bit depth. You wrap your paint device (source paint device) into KisOverlayPaintDeviceWrapper, and the wrapper creates a temporary device (precise overlay paint device) in RGBA16 colorspace. Then you work with this precise paint device as usual, uploading and downloading pixel data to/from the source paint device using readRect() and writeRect()

In LazyPreciseMode, if the source device is already "precise", that is having the bit depth higher than 8 bit per channel, no temporary device is created. All the operations are forwarded directly to the source device.

In some cases (e.g. when trying to maintain a separate heightmap channel), you may want to have multiple overlays.

When doing conversions between U8 and U16 color spaces, the overlay will try to use AVX2-optimized algorithms.

Example:

// initialize the wrapper with the source device,
// it creates a precise device if needed
// Download the data from the source device. The rects
// that have already been read will be cached and will
// never be read twice.
wrapper.readRect(accessRect);
// start modifying the data
KisPainter gc(wrapper.overlay());
// low opacity might be handled incorrectly in the original
// color space, but we work in a precise one!
gc.setOpacity(1);
gc.bitBlt(accessRect.topLeft(), someOtherDevice, accessRect);
// ... repeat multiple times if needed ...
// upload the data back to the original source device
wrapper.writeRect(accessRect);

Definition at line 67 of file KisOverlayPaintDeviceWrapper.h.

Member Enumeration Documentation

◆ OverlayMode

Constructor & Destructor Documentation

◆ KisOverlayPaintDeviceWrapper()

KisOverlayPaintDeviceWrapper::KisOverlayPaintDeviceWrapper ( KisPaintDeviceSP source,
int numOverlays = 1,
KisOverlayPaintDeviceWrapper::OverlayMode mode = NormalMode,
const KoColorSpace * forcedOverlayColorSpace = nullptr )

Create an overlay wrapper and attach it to device.

If mode is NormalMode, then numOverlays are created. All overlays will have the same (possible "imprecise") colorspace as source.

If mode is PreciseMode, then numOverlays are created. If source has "imprecise" color space (U8), then overlays will be upgraded to a "precise" color space (U16).

If mode is LazyPreciseMode and numOverlays is 1, then the overlay will be created only in case when precise color space is needed. Otherwise, the mode behaves like PreciseMode

Parameters
devicesource device
numOverlaysthe number of overlays to create
modemode to use
forcedOverlayColorSpaceforced color space to use for overlay. Passing non- null as forcedOverlayColorSpace will override precise color space decision process. This argument is useful for cases when two overlay devices need to have exactly the same color space (e.g. in colorsmudge overlay mode).

Definition at line 66 of file KisOverlayPaintDeviceWrapper.cpp.

67 : m_d(new Private())
68{
69 m_d->source = source;
70
72
73 if (forcedOverlayColorSpace) {
74 overlayColorSpace = forcedOverlayColorSpace;
75 } else {
76 const bool usePreciseMode = mode == PreciseMode || mode == LazyPreciseMode;
77
78 if (usePreciseMode &&
80
86 }
87 }
88
89 m_d->usePreciseMode = *source->colorSpace() != *overlayColorSpace;
90
96
98
99 } else if (source->colorSpace()->colorModelId() == CMYKAColorModelID &&
104
106
107 } else if (source->colorSpace()->colorModelId() == YCbCrAColorModelID &&
112
114
115 }
116
117 if (!m_d->usePreciseMode && mode == LazyPreciseMode && numOverlays == 1) {
118 return;
119 }
120
121 for (int i = 0; i < numOverlays; i++) {
127
128 m_d->overlays.append(overlay);
129 }
130}
const KoID YCbCrAColorModelID("YCbCrA", ki18n("YCbCr/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
KisPaintDeviceSP overlay(int index=0) const
const QScopedPointer< Private > m_d
const KoColorSpace * overlayColorSpace() const
bool supportsWraproundMode() const
void setDefaultPixel(const KoColor &defPixel)
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
virtual const KoColorSpace * compositionSourceColorSpace() const
const KoColorSpace * colorSpace() const
void setSupportsWraparoundMode(bool value)
KoColor defaultPixel() const
KisDefaultBoundsBaseSP defaultBounds() const
void moveTo(qint32 x, qint32 y)
QPoint offset() const
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
Definition KoColor.cpp:163
QString id() const
Definition KoID.cpp:63
static KoOptimizedPixelDataScalerU8ToU16Base * createCmykaScaler()
static KoOptimizedPixelDataScalerU8ToU16Base * createRgbaScaler()
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()

References CMYKAColorModelID, KoColorSpace::colorDepthId(), KoColorSpace::colorModelId(), KisPaintDevice::colorSpace(), KoColorSpaceRegistry::colorSpace(), KisPaintDevice::compositionSourceColorSpace(), KoColor::convertedTo(), KoOptimizedPixelDataScalerU8ToU16Factory::createCmykaScaler(), KoOptimizedPixelDataScalerU8ToU16Factory::createRgbaScaler(), KisPaintDevice::defaultBounds(), KisPaintDevice::defaultPixel(), KoID::id(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, Integer8BitsColorDepthID, LazyPreciseMode, m_d, KisPaintDevice::moveTo(), KisPaintDevice::offset(), overlay(), overlayColorSpace(), PreciseMode, KoColorSpace::profile(), RGBAColorModelID, KisPaintDevice::setDefaultBounds(), KisPaintDevice::setDefaultPixel(), KisPaintDevice::setSupportsWraparoundMode(), source(), KisPaintDevice::supportsWraproundMode(), and YCbCrAColorModelID.

◆ ~KisOverlayPaintDeviceWrapper()

KisOverlayPaintDeviceWrapper::~KisOverlayPaintDeviceWrapper ( )

Definition at line 132 of file KisOverlayPaintDeviceWrapper.cpp.

133{
134}

Member Function Documentation

◆ beginTransaction()

void KisOverlayPaintDeviceWrapper::beginTransaction ( KUndo2Command * parent = 0)

Definition at line 306 of file KisOverlayPaintDeviceWrapper.cpp.

307{
308 KIS_SAFE_ASSERT_RECOVER(!m_d->rootTransactionData) {
309 m_d->rootTransactionData.reset();
310 }
311
312 if (!m_d->previousGrid) {
313 m_d->previousGrid.reset(new KisRectsGrid(m_d->grid));
314 }
315
316 m_d->rootTransactionData.reset(new KUndo2Command(parent));
317
318 m_d->changeOverlayCommand = new KisChangeOverlayWrapperCommand(m_d.data());
319 (void) new KisCommandUtils::SkipFirstRedoWrapper(m_d->changeOverlayCommand, m_d->rootTransactionData.data());
320 m_d->changeOverlayCommand->m_oldRectsGrid = m_d->previousGrid;
321
322 for (const auto &overlayDevice : m_d->overlays) {
323 m_d->overlayTransactions.emplace_back(new KisTransaction(overlayDevice, m_d->rootTransactionData.data()));
324 }
325}
A utility class to maintain a sparse grid of loaded/unloaded rects.
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)

References KIS_SAFE_ASSERT_RECOVER, KisChangeOverlayWrapperCommand, m_d, and void().

◆ createPreciseCompositionSourceDevice()

KisPaintDeviceSP KisOverlayPaintDeviceWrapper::createPreciseCompositionSourceDevice ( )

Create a composite source device for being used over overlay().

Please note that one cannot use overlay()->createCompositeSourceDevice() for this purpose because overlay() is just a copy of sourceDevice() and doesn't have overloaded methods for this color space.

TODO: make KisPaintDevice::compositeSourceColorSpace() not a virtual method, but let is be assigned during the lifetime of the paint device. It'll let us remove this extra function.

TODO: this function has rather vague meaning when forcedOverlayColorSpace feature is used

Definition at line 277 of file KisOverlayPaintDeviceWrapper.cpp.

278{
284 KisPaintDeviceSP result;
285
286 if (!m_d->usePreciseMode) {
288 } else {
289 const KoColorSpace *compositionColorSpace =
290 m_d->source->compositionSourceColorSpace();
291
292 const KoColorSpace *preciseCompositionColorSpace =
294 compositionColorSpace->colorModelId().id(),
296 compositionColorSpace->profile());
297
298 KisPaintDeviceSP device = new KisPaintDevice(preciseCompositionColorSpace);
299 device->setDefaultBounds(m_d->source->defaultBounds());
300 result = device;
301 }
302
303 return result;
304}
KisPaintDeviceSP createCompositionSourceDevice() const

References KoColorSpace::colorModelId(), KoColorSpaceRegistry::colorSpace(), KisPaintDevice::createCompositionSourceDevice(), KoID::id(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, m_d, KoColorSpace::profile(), KisPaintDevice::setDefaultBounds(), and source().

◆ endTransaction()

KUndo2Command * KisOverlayPaintDeviceWrapper::endTransaction ( )

Definition at line 327 of file KisOverlayPaintDeviceWrapper.cpp.

328{
329 KUndo2Command *result = nullptr;
330
331 KIS_SAFE_ASSERT_RECOVER(m_d->rootTransactionData) {
332 m_d->overlayTransactions.clear();
333 return result;
334 }
335
336 m_d->previousGrid.reset(new KisRectsGrid(m_d->grid));
337
338 m_d->changeOverlayCommand->m_newRectsGrid = m_d->previousGrid;
339 result = m_d->rootTransactionData.take();
340
341 for (auto &transactionPtr : m_d->overlayTransactions) {
342 // the transactions are assigned as children to m_d->changeOverlayCommand
343 (void) transactionPtr->endAndTake();
344 }
345 m_d->overlayTransactions.clear();
346
347 return result;
348}

References KIS_SAFE_ASSERT_RECOVER, m_d, and void().

◆ externalDestination()

KisPaintDeviceSP KisOverlayPaintDeviceWrapper::externalDestination ( ) const

Definition at line 141 of file KisOverlayPaintDeviceWrapper.cpp.

142{
143 return m_d->externalDestination;
144}

References m_d.

◆ overlay()

KisPaintDeviceSP KisOverlayPaintDeviceWrapper::overlay ( int index = 0) const

Definition at line 151 of file KisOverlayPaintDeviceWrapper.cpp.

152{
153 return !m_d->overlays.isEmpty() ? m_d->overlays[index] : m_d->source;
154}

References m_d.

◆ overlayColorSpace()

const KoColorSpace * KisOverlayPaintDeviceWrapper::overlayColorSpace ( ) const

Definition at line 272 of file KisOverlayPaintDeviceWrapper.cpp.

273{
274 return !m_d->overlays.isEmpty() ? m_d->overlays.first()->colorSpace() : m_d->source->colorSpace();
275}

References m_d.

◆ readRect()

void KisOverlayPaintDeviceWrapper::readRect ( const QRect & rc)

Definition at line 156 of file KisOverlayPaintDeviceWrapper.cpp.

157{
158 readRects({rc});
159}
void readRects(const QVector< QRect > &rects)

References readRects().

◆ readRects()

void KisOverlayPaintDeviceWrapper::readRects ( const QVector< QRect > & rects)

Definition at line 166 of file KisOverlayPaintDeviceWrapper.cpp.

167{
168 if (rects.isEmpty()) return;
169 if (m_d->overlays.isEmpty()) return;
170
171 QRect cropRect = m_d->source->extent();
172 QVector<QRect> rectsToRead;
173
174 Q_FOREACH (const QRect &rc, rects) {
175 if (m_d->source->defaultBounds()->wrapAroundMode()) {
176 const QRect wrapRect = m_d->source->defaultBounds()->imageBorderRect();
177 KisWrappedRect wrappedRect(rc, wrapRect, m_d->source->defaultBounds()->wrapAroundModeAxis());
178 Q_FOREACH (const QRect &wrc, wrappedRect) {
179 rectsToRead += m_d->grid.addRect(wrc);
180 }
181 cropRect &= wrapRect;
182 } else {
183 rectsToRead += m_d->grid.addRect(rc);
184 }
185 }
186
188
189 //TODO: implement synchronization of the offset between the grid and devices
190
191 if (!m_d->scaler) {
192 Q_FOREACH (KisPaintDeviceSP overlay, m_d->overlays) {
193 Q_FOREACH (const QRect &rect, rectsToRead) {
194 const QRect croppedRect = rect & cropRect;
195 if (croppedRect.isEmpty()) continue;
196
197 KisPainter::copyAreaOptimized(croppedRect.topLeft(), m_d->source, overlay, croppedRect);
198 }
199 }
200 } else {
201 KisPaintDeviceSP overlay = m_d->overlays.first();
202
203 KisRandomConstAccessorSP srcIt = m_d->source->createRandomConstAccessorNG();
205
206 auto rectIter = rectsToRead.begin();
207 while (rectIter != rectsToRead.end()) {
208 const QRect croppedRect = *rectIter & cropRect;
209
210 if (!croppedRect.isEmpty()) {
211
213 srcIt, dstIt,
214 [this] (const quint8 *src, int srcRowStride,
215 quint8 *dst, int dstRowStride,
216 int numRows, int numColumns) {
217
218 m_d->scaler->convertU8ToU16(src, srcRowStride,
219 dst, dstRowStride,
220 numRows, numColumns);
221 });
222
223 for (auto it = std::next(m_d->overlays.begin()); it != m_d->overlays.end(); ++it) {
224 KisPaintDeviceSP otherOverlay = *it;
225 KisPainter::copyAreaOptimized(croppedRect.topLeft(), overlay, otherOverlay, croppedRect);
226 }
227 }
228
229 rectIter++;
230 }
231 }
232}
KisRandomAccessorSP createRandomAccessorNG()
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
static void makeGridLikeRectsUnique(QVector< QRect > &rects)
void processTwoDevicesWithStrides(const QRect &rc, KisRandomConstAccessorSP srcIt, KisRandomAccessorSP dstIt, PixelProcessor pixelProcessor)

References KisPainter::copyAreaOptimized(), KisPaintDevice::createRandomAccessorNG(), KisPaintDevice::extent(), m_d, KisRegion::makeGridLikeRectsUnique(), overlay(), and KritaUtils::processTwoDevicesWithStrides().

◆ setExternalDestination()

void KisOverlayPaintDeviceWrapper::setExternalDestination ( KisPaintDeviceSP device)

Definition at line 136 of file KisOverlayPaintDeviceWrapper.cpp.

137{
138 m_d->externalDestination = device;
139}

References m_d.

◆ source()

KisPaintDeviceSP KisOverlayPaintDeviceWrapper::source ( ) const

Definition at line 146 of file KisOverlayPaintDeviceWrapper.cpp.

147{
148 return m_d->source;
149}

References m_d.

◆ writeRect()

void KisOverlayPaintDeviceWrapper::writeRect ( const QRect & rc,
int index = 0 )

Definition at line 161 of file KisOverlayPaintDeviceWrapper.cpp.

162{
163 writeRects({rc}, index);
164}
void writeRects(const QVector< QRect > &rects, int index=0)

References writeRects().

◆ writeRects()

void KisOverlayPaintDeviceWrapper::writeRects ( const QVector< QRect > & rects,
int index = 0 )

Definition at line 234 of file KisOverlayPaintDeviceWrapper.cpp.

235{
236 if (rects.isEmpty()) return;
237 if (m_d->overlays.isEmpty()) return;
238
239 KisPaintDeviceSP destinationDevice =
240 m_d->externalDestination ? m_d->externalDestination : m_d->source;
241
242 if (!m_d->scaler ||
243 (destinationDevice != m_d->source &&
244 *destinationDevice->colorSpace() != *m_d->source->colorSpace())) {
245
246 Q_FOREACH (const QRect &rc, rects) {
247 KIS_SAFE_ASSERT_RECOVER_NOOP(m_d->grid.contains(rc));
248 KisPainter::copyAreaOptimized(rc.topLeft(), m_d->overlays[index], destinationDevice, rc);
249 }
250 } else {
251 KisPaintDeviceSP overlay = m_d->overlays[index];
252
253
255 KisRandomAccessorSP dstIt = destinationDevice->createRandomAccessorNG();
256
257 Q_FOREACH (const QRect &rc, rects) {
259 srcIt, dstIt,
260 [this] (const quint8 *src, int srcRowStride,
261 quint8 *dst, int dstRowStride,
262 int numRows, int numColumns) {
263
264 m_d->scaler->convertU16ToU8(src, srcRowStride,
265 dst, dstRowStride,
266 numRows, numColumns);
267 });
268 }
269 }
270}
KisRandomConstAccessorSP createRandomConstAccessorNG() const
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KisPaintDevice::colorSpace(), KisPainter::copyAreaOptimized(), KisPaintDevice::createRandomAccessorNG(), KisPaintDevice::createRandomConstAccessorNG(), KIS_SAFE_ASSERT_RECOVER_NOOP, m_d, overlay(), and KritaUtils::processTwoDevicesWithStrides().

Friends And Related Symbol Documentation

◆ KisChangeOverlayWrapperCommand

friend struct KisChangeOverlayWrapperCommand
friend

Definition at line 136 of file KisOverlayPaintDeviceWrapper.h.

Member Data Documentation

◆ m_d

const QScopedPointer<Private> KisOverlayPaintDeviceWrapper::m_d
private

Definition at line 138 of file KisOverlayPaintDeviceWrapper.h.


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