Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_gap_map.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Maciej Jesionowski <yavnrh@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#ifndef __KIS_GAP_MAP_H
8#define __KIS_GAP_MAP_H
9
10#include <kis_types.h>
11#include <KoAlwaysInline.h>
12#include <kis_shared.h>
13#include <QRect>
14#include <kis_paint_device.h>
16
17#define KIS_GAP_MAP_MEASURE_ELAPSED_TIME 0
18
19// Asserts are disabled by default in performance-critical code.
20#define KIS_GAP_MAP_DEBUG_LOGGING_AND_ASSERTS 0
21
23{
24public:
26 : m_pixelSize(paintDevice->pixelSize())
27 , m_accessor(paintDevice->createRandomAccessorNG())
28 , m_tile(-1, -1)
29 , m_tileRawData(nullptr)
30 {
31 // We start in an invalid state ((-1,-1) tile), so that the data pointer is fetched
32 // after the paint device has been set up (e.g. default color and fill).
33 }
34
35 quint8* tileRawData(int tileX, int tileY)
36 {
37 if ((m_tile.x() != tileX) || (m_tile.y() != tileY)) {
38 m_accessor->moveTo(tileX * TileSize, tileY * TileSize);
40
41 m_tile.setX(tileX);
42 m_tile.setY(tileY);
43
44#if KIS_GAP_MAP_DEBUG_LOGGING_AND_ASSERTS
47#endif
48 }
49
50 return m_tileRawData;
51 }
52
53 ALWAYS_INLINE quint8* rawData(int x, int y)
54 {
55 const int tileX = x / TileSize;
56 const int tileY = y / TileSize;
57 const int localX = x & (TileSize - 1);
58 const int localY = y & (TileSize - 1);
59
60 m_tileRawData = tileRawData(tileX, tileY);
61
62 return m_tileRawData + m_pixelSize * (localX + TileSize * localY);
63 }
64
65private:
66 static constexpr int TileSize = 64;
67
68 const quint32 m_pixelSize;
69
71 QPoint m_tile;
73};
74
80class KRITAIMAGE_EXPORT KisGapMap : public KisShared
81{
82public:
84 static constexpr quint16 DISTANCE_INFINITE = UINT16_MAX;
85
94 typedef std::function<bool(KisPaintDevice* devicePtr, const QRect& rect)> FillOpacityFunc;
95
104 KisGapMap(int gapSize,
105 const QRect& mapBounds,
106 const FillOpacityFunc& fillOpacityFunc);
107
113 ALWAYS_INLINE quint16 distance(int x, int y)
114 {
115 if (isDistanceAvailable(x, y)) {
116 return dataPtr(x, y)->distance;
117 } else {
118 return lazyDistance(x, y);
119 }
120 }
121
123 {
124 return m_gapSize;
125 }
126
127#if KIS_GAP_MAP_MEASURE_ELAPSED_TIME
128public:
129 quint64 opacityElapsedMillis() const
130 {
131 return m_opacityElapsedNanos / 1000000ull;
132 }
133
134 quint64 distanceElapsedMillis() const
135 {
136 return m_distanceElapsedNanos / 1000000ull;
137 }
138
139private:
140 quint64 m_opacityElapsedNanos = 0;
141 quint64 m_distanceElapsedNanos = 0;
142#endif
143
144private:
146
148 static constexpr int TileSize = 64;
149
150 typedef quint8 TileFlags;
152 {
153 TILE_DISTANCE_LOADED = 0x1,
154 TILE_OPACITY_LOADED = 0x2,
155 TILE_HAS_OPAQUE_PIXELS = 0x4,
156 };
157
158 struct Data
159 {
160 quint16 distance;
161 quint8 opacity;
163 };
164 static_assert(sizeof(Data) == sizeof(quint32));
165
166 void loadOpacityTiles(const QRect& tileRect);
167 void loadDistanceTile(const QPoint& tile, const QRect& nearbyTilesRect, int guardBand);
168 void distanceSearchRowInnerLoop(bool boundsCheck, int y, int x1, int x2);
169 quint16 lazyDistance(int x, int y);
170
171 // Templates are used to generate optimized versions of the same function
172 // (i.e., the if conditions can be removed at compilation time).
173
174 template<bool BoundsCheck, typename CoordinateTransform>
175 void gapDistanceSearch(int x, int y, CoordinateTransform op);
176
177 template<bool BoundsCheck> ALWAYS_INLINE bool isOpaque(int x, int y);
178 template<bool BoundsCheck> ALWAYS_INLINE bool isOpaque(const QPoint& p);
179 void updateDistance(const QPoint& globalPosition, quint16 newDistance);
180
182 {
183 return (*tileFlagsPtr(x / TileSize, y / TileSize) & TILE_DISTANCE_LOADED) != 0;
184 }
185
187 {
188 return reinterpret_cast<Data*>(m_accessor->rawData(x, y));
189 }
190
191 ALWAYS_INLINE TileFlags* tileFlagsPtr(int tileX, int tileY)
192 {
193 return reinterpret_cast<TileFlags*>(
194 m_accessor->tileRawData(tileX, tileY) + offsetof(Data, flags));
195 }
196
197 const int m_gapSize;
198 const QSize m_size;
199 const QSize m_numTiles;
200 const FillOpacityFunc m_fillOpacityFunc;
201
204
206 std::unique_ptr<KisTileOptimizedAccessor> m_accessor;
207};
208
209#endif /* __KIS_GAP_MAP_H */
const Params2D p
#define ALWAYS_INLINE
#define UINT16_MAX
virtual quint8 * rawData()=0
Q_DISABLE_COPY(KisGapMap)
const QSize m_numTiles
Map size in tiles.
quint8 TileFlags
const FillOpacityFunc m_fillOpacityFunc
A callback to get the opacity data from the fill class.
std::unique_ptr< KisTileOptimizedAccessor > m_accessor
An accessor for the paint device.
const int m_gapSize
Gap size in pixels for this map.
ALWAYS_INLINE bool isOpaque(const QPoint &p)
ALWAYS_INLINE bool isOpaque(int x, int y)
ALWAYS_INLINE quint16 distance(int x, int y)
std::function< bool(KisPaintDevice *devicePtr, const QRect &rect) FillOpacityFunc)
Definition kis_gap_map.h:94
const QSize m_size
Size in pixels of the opacity/gap map.
QPoint m_tilePosition
The position of the currently computed tile compared to the whole region.
ALWAYS_INLINE Data * dataPtr(int x, int y)
ALWAYS_INLINE TileFlags * tileFlagsPtr(int tileX, int tileY)
ALWAYS_INLINE int gapSize() const
KisPaintDeviceSP m_deviceSp
A 32-bit per pixel paint device that holds the distance and other data.
ALWAYS_INLINE bool isDistanceAvailable(int x, int y)
Data * m_tileDataPtr
The pointer to the currently computed tile data.
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
virtual qint32 numContiguousColumns(qint32 x) const =0
quint8 * tileRawData(int tileX, int tileY)
Definition kis_gap_map.h:35
const quint32 m_pixelSize
Definition kis_gap_map.h:68
KisTileOptimizedAccessor(KisPaintDeviceSP &paintDevice)
Definition kis_gap_map.h:25
static constexpr int TileSize
Definition kis_gap_map.h:66
ALWAYS_INLINE quint8 * rawData(int x, int y)
Definition kis_gap_map.h:53
KisRandomAccessorSP m_accessor
Definition kis_gap_map.h:70
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
TileFlags flags