1 // [Blend2D]
2 // 2D Vector Graphics Powered by a JIT Compiler.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6 
7 #ifndef BLEND2D_PIPEDEFS_P_H
8 #define BLEND2D_PIPEDEFS_P_H
9 
10 #include "./api-internal_p.h"
11 #include "./format_p.h"
12 #include "./gradient_p.h"
13 #include "./matrix_p.h"
14 #include "./pattern_p.h"
15 #include "./runtime_p.h"
16 #include "./support_p.h"
17 #include "./tables_p.h"
18 #include "./simd_p.h"
19 
20 //! \cond INTERNAL
21 //! \addtogroup blend2d_internal
22 //! \{
23 
24 // ============================================================================
25 // [Forward Declarations]
26 // ============================================================================
27 
28 struct BLPipeContextData;
29 struct BLPipeFillData;
30 struct BLPipeFetchData;
31 struct BLPipeSignature;
32 
33 // ============================================================================
34 // [Constants]
35 // ============================================================================
36 
37 //! Global constants used by pipeline and affecting also rasterizers.
38 enum BLPipeGlobalConsts : uint32_t {
39   //! How many pixels are represented by a single bit of a `BLBitWord`.
40   //!
41   //! This is a hardcoded value as it's required by both rasterizer and compositor.
42   //! Before establishing `4` the values [4, 8, 16, 32] were tested. Candidates
43   //! were `4` and `8` where `8` sometimes surpassed `4` in specific workloads,
44   //! but `4` was stable across all tests.
45   //!
46   //! In general increasing `BL_PIPE_PIXELS_PER_ONE_BIT` would result in less
47   //! memory consumed by bit vectors, but would increase the work compositors
48   //! have to do to process cells produced by analytic rasterizer.
49   BL_PIPE_PIXELS_PER_ONE_BIT = 4
50 };
51 
52 //! 8-bit alpha constants used by pipelines and affecting also rasterizers.
53 enum BLPipeA8Consts : uint32_t {
54   BL_PIPE_A8_SHIFT = 8,                     // 8.
55   BL_PIPE_A8_SCALE = 1 << BL_PIPE_A8_SHIFT, // 256.
56   BL_PIPE_A8_MASK  = BL_PIPE_A8_SCALE - 1   // 255.
57 };
58 
59 //! Pipeline extend modes (non-combined).
60 //!
61 //! Pipeline sees extend modes a bit differently in most cases.
62 enum BLPipeExtendMode : uint32_t {
63   BL_PIPE_EXTEND_MODE_PAD         = 0,         //!< Pad, same as `BL_EXTEND_MODE_PAD`.
64   BL_PIPE_EXTEND_MODE_REPEAT      = 1,         //!< Repeat, same as `BL_EXTEND_MODE_REPEAT`.
65   BL_PIPE_EXTEND_MODE_REFLECT     = 2,         //!< Reflect, same as `BL_EXTEND_MODE_REFLECT`.
66   BL_PIPE_EXTEND_MODE_ROR         = 3,         //!< Repeat-or-reflect (the same code-path for both cases).
67 
68   BL_PIPE_EXTEND_MODE_COUNT       = 4          //! Count of pipeline-specific extend modes.
69 };
70 
71 //! Pipeline fill-type.
72 //!
73 //! A unique id describing how a mask of each filled pixel is calculated.
74 enum BLPipeFillType : uint32_t {
75   BL_PIPE_FILL_TYPE_NONE          = 0,         //!< None or uninitialized.
76   BL_PIPE_FILL_TYPE_BOX_AA        = 1,         //!< Fill axis-aligned box.
77   BL_PIPE_FILL_TYPE_BOX_AU        = 2,         //!< Fill axis-unaligned box.
78   BL_PIPE_FILL_TYPE_ANALYTIC      = 3,         //!< Fill analytic non-zero/even-odd.
79 
80   BL_PIPE_FILL_TYPE_COUNT         = 4          //!< Count of fill types.
81 };
82 
83 //! Fill rule mask used during composition of mask produced by analytic-rasterizer.
84 //!
85 //! See blfillpart.cpp how this is used. What you see in these values is
86 //! mask shifted left by one bit as we expect such values in the pipeline.
87 enum BLPipeFillRuleMask : uint32_t {
88   BL_PIPE_FILL_RULE_MASK_NON_ZERO = uint32_t(0xFFFFFFFFu << 1),
89   BL_PIPE_FILL_RULE_MASK_EVEN_ODD = uint32_t(0x000001FFu << 1)
90 };
91 
92 //! Pipeline fetch-type.
93 //!
94 //! A unique id describing how pixels are fetched - supported fetchers include
95 //! solid pixels, patterns (sometimes referred as blits), and gradients.
96 //!
97 //! \note RoR is a shurtcut for repeat-or-reflect - an universal fetcher for both.
98 enum BLPipeFetchType : uint32_t {
99   BL_PIPE_FETCH_TYPE_SOLID  = 0,               //!< Solid fetch.
100 
101   BL_PIPE_FETCH_TYPE_PATTERN_AA_BLIT,          //!< Pattern {aligned} (blit) [Base].
102   BL_PIPE_FETCH_TYPE_PATTERN_AA_PAD,           //!< Pattern {aligned} (pad-x) [Base].
103   BL_PIPE_FETCH_TYPE_PATTERN_AA_REPEAT,        //!< Pattern {aligned} (repeat-large-x) [Optimized].
104   BL_PIPE_FETCH_TYPE_PATTERN_AA_ROR,           //!< Pattern {aligned} (ror-x) [Base].
105   BL_PIPE_FETCH_TYPE_PATTERN_FX_PAD,           //!< Pattern {frac-x} (pad-x) [Optimized].
106   BL_PIPE_FETCH_TYPE_PATTERN_FX_ROR,           //!< Pattern {frac-x} (ror-x) [Optimized].
107   BL_PIPE_FETCH_TYPE_PATTERN_FY_PAD,           //!< Pattern {frac-y} (pad-x) [Optimized].
108   BL_PIPE_FETCH_TYPE_PATTERN_FY_ROR,           //!< Pattern {frac-x} (ror-x) [Optimized].
109   BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_PAD,        //!< Pattern {frac-xy} (pad-x) [Base].
110   BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_ROR,        //!< Pattern {frac-xy} (ror-x) [Base].
111   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_NN_ANY,    //!< Pattern {affine-nearest}  (any) [Base].
112   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_NN_OPT,    //!< Pattern {affine-nearest}  (any) [Optimized].
113   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_BI_ANY,    //!< Pattern {affine-bilinear} (any) [Base].
114   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_BI_OPT,    //!< Pattern {affine-bilinear} (any) [Optimized].
115 
116   BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_PAD,      //!< Linear gradient (pad) [Base].
117   BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_ROR,      //!< Linear gradient (ror) [Base].
118   BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_PAD,      //!< Radial gradient (pad) [Base].
119   BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_REPEAT,   //!< Radial gradient (repeat) [Base].
120   BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_REFLECT,  //!< Radial gradient (reflect) [Base].
121   BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL,         //!< Conical gradient (any) [Base].
122 
123   BL_PIPE_FETCH_TYPE_COUNT,                    //!< Number of fetch types.
124 
125   BL_PIPE_FETCH_TYPE_PIXEL_PTR = 0xFF,         //!< Pixel pointer (special value, not a valid fetch type).
126   BL_PIPE_FETCH_TYPE_FAILURE = 0xFFFFFFFFu,    //!< Invalid fetch type (special value, signalizes error).
127 
128   BL_PIPE_FETCH_TYPE_PATTERN_ANY_FIRST         = BL_PIPE_FETCH_TYPE_PATTERN_AA_BLIT,
129   BL_PIPE_FETCH_TYPE_PATTERN_ANY_LAST          = BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_BI_OPT,
130 
131   BL_PIPE_FETCH_TYPE_PATTERN_AA_FIRST          = BL_PIPE_FETCH_TYPE_PATTERN_AA_BLIT,
132   BL_PIPE_FETCH_TYPE_PATTERN_AA_LAST           = BL_PIPE_FETCH_TYPE_PATTERN_AA_ROR,
133 
134   BL_PIPE_FETCH_TYPE_PATTERN_AU_FIRST          = BL_PIPE_FETCH_TYPE_PATTERN_FX_PAD,
135   BL_PIPE_FETCH_TYPE_PATTERN_AU_LAST           = BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_ROR,
136 
137   BL_PIPE_FETCH_TYPE_PATTERN_FX_FIRST          = BL_PIPE_FETCH_TYPE_PATTERN_FX_PAD,
138   BL_PIPE_FETCH_TYPE_PATTERN_FX_LAST           = BL_PIPE_FETCH_TYPE_PATTERN_FX_ROR,
139 
140   BL_PIPE_FETCH_TYPE_PATTERN_FY_FIRST          = BL_PIPE_FETCH_TYPE_PATTERN_FY_PAD,
141   BL_PIPE_FETCH_TYPE_PATTERN_FY_LAST           = BL_PIPE_FETCH_TYPE_PATTERN_FY_ROR,
142 
143   BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_FIRST       = BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_PAD,
144   BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_LAST        = BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_ROR,
145 
146   BL_PIPE_FETCH_TYPE_PATTERN_SIMPLE_FIRST      = BL_PIPE_FETCH_TYPE_PATTERN_AA_BLIT,
147   BL_PIPE_FETCH_TYPE_PATTERN_SIMPLE_LAST       = BL_PIPE_FETCH_TYPE_PATTERN_FX_FY_ROR,
148 
149   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_FIRST      = BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_NN_ANY,
150   BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_LAST       = BL_PIPE_FETCH_TYPE_PATTERN_AFFINE_BI_OPT,
151 
152   BL_PIPE_FETCH_TYPE_GRADIENT_ANY_FIRST        = BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_PAD,
153   BL_PIPE_FETCH_TYPE_GRADIENT_ANY_LAST         = BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL,
154 
155   BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_FIRST     = BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_PAD,
156   BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_LAST      = BL_PIPE_FETCH_TYPE_GRADIENT_LINEAR_ROR,
157 
158   BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_FIRST     = BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_PAD,
159   BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_LAST      = BL_PIPE_FETCH_TYPE_GRADIENT_RADIAL_REFLECT,
160 
161   BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL_FIRST    = BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL,
162   BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL_LAST     = BL_PIPE_FETCH_TYPE_GRADIENT_CONICAL
163 };
164 
165 //! Masks used by `BLPipeSignature`.
166 //!
167 //! Each mask represents one value in a signature. Each value describes a part
168 //! in a signature like format, composition operator, etc. All parts packed
169 //! together form a 32-bit integer that can be used to uniquely describe the
170 //! whole pipeline and can act as a key or hash-code in pipeline function caches.
171 enum BLPipeSignatureMasks : uint32_t {
172   BL_PIPE_SIGNATURE_DST_FORMAT    = 0x0000000Fu <<  0, // [00..03] {16 values}
173   BL_PIPE_SIGNATURE_SRC_FORMAT    = 0x0000000Fu <<  4, // [04..07] {16 values}
174   BL_PIPE_SIGNATURE_COMP_OP       = 0x0000003Fu <<  8, // [08..13] {64 values}
175   BL_PIPE_SIGNATURE_FILL_TYPE     = 0x00000003u << 14, // [14..15] {4 values}
176   BL_PIPE_SIGNATURE_FETCH_TYPE    = 0x0000001Fu << 16, // [16..20] {32 values}
177   BL_PIPE_SIGNATURE_FETCH_PAYLOAD = 0x000007FFu << 21  // [21..31] {2048 values}
178 };
179 
180 // ============================================================================
181 // [Typedefs]
182 // ============================================================================
183 
184 typedef void (BL_CDECL* BLPipeFillFunc)(void* ctxData, void* fillData, const void* fetchData) BL_NOEXCEPT;
185 
186 // ============================================================================
187 // [BLPipeValue32]
188 // ============================================================================
189 
190 union BLPipeValue32 {
191   uint32_t u;
192   int32_t i;
193   float f;
194 };
195 
196 // ============================================================================
197 // [BLPipeValue64]
198 // ============================================================================
199 
200 union BLPipeValue64 {
201   uint64_t u64;
202   int64_t i64;
203   double d;
204 
205   int32_t i32[2];
206   uint32_t u32[2];
207 
208   int16_t i16[4];
209   uint16_t u16[4];
210 
211 #if BL_BYTE_ORDER == 1234 // LITTLE ENDIAN
212   struct { int32_t  i32Lo, i32Hi; };
213   struct { uint32_t u32Lo, u32Hi; };
214 #else
215   struct { int32_t  i32Hi, i32Lo; };
216   struct { uint32_t u32Hi, u32Lo; };
217 #endif
218 
expandLoToHi()219   BL_INLINE void expandLoToHi() noexcept { u32Hi = u32Lo; }
220 };
221 
222 // ============================================================================
223 // [BLPipeContextData]
224 // ============================================================================
225 
226 struct BLPipeContextData {
227   BLImageData dst;
228 
resetBLPipeContextData229   BL_INLINE void reset() noexcept { memset(this, 0, sizeof(*this)); }
230 };
231 
232 // ============================================================================
233 // [BLPipeFillData]
234 // ============================================================================
235 
236 struct BLPipeFillData {
237   struct Common {
238     //! Rectangle to fill.
239     BLBoxI box;
240     //! Alpha value (range depends on target pixel format).
241     BLPipeValue32 alpha;
242   };
243 
244   //! Rectangle (axis-aligned).
245   struct BoxAA {
246     //! Rectangle to fill.
247     BLBoxI box;
248     //! Alpha value (range depends on target pixel format).
249     BLPipeValue32 alpha;
250   };
251 
252   //! Rectangle (axis-unaligned).
253   struct BoxAU {
254     //! Rectangle to fill.
255     BLBoxI box;
256     //! Alpha value (range depends on target pixel format).
257     BLPipeValue32 alpha;
258 
259     //! Masks of top, middle and bottom part of the rect.
260     //!
261     //! \note The last value `masks[3]` must be zero as it's a sentinel for the pipeline.
262     uint32_t masks[4];
263     //! Height of the middle (1) and last (2) masks.
264     uint32_t heights[2];
265     //! Start width (from 1 to 3).
266     uint32_t startWidth;
267     //! Inner width (from 0 to width).
268     uint32_t innerWidth;
269   };
270 
271   struct Analytic {
272     //! Fill boundary (x0 is ignored, x1 acts as maxWidth, y0/y1 are used normally).
273     BLBoxI box;
274     //! Alpha value (range depends on format).
275     BLPipeValue32 alpha;
276     //! All ones if NonZero or 0x01FF if EvenOdd.
277     uint32_t fillRuleMask;
278 
279     //! Shadow bit-buffer (marks a group of cells which are non-zero).
280     BLBitWord* bitTopPtr;
281     //! Bit-buffer stride (in bytes).
282     size_t bitStride;
283 
284     //! Cell buffer.
285     uint32_t* cellTopPtr;
286     //! Cell stride (in bytes).
287     size_t cellStride;
288   };
289 
290   union {
291     Common common;
292     BoxAA boxAA;
293     BoxAU boxAU;
294     Analytic analytic;
295   };
296 
resetBLPipeFillData297   inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
298 
299   // --------------------------------------------------------------------------
300   // [Init]
301   // --------------------------------------------------------------------------
302 
initBoxAA8bpcBLPipeFillData303   inline uint32_t initBoxAA8bpc(uint32_t alpha, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1) noexcept {
304     // The rendering engine should never pass out-of-range alpha.
305     BL_ASSERT(alpha <= 256);
306 
307     // The rendering engine should never pass invalid box to the pipeline.
308     BL_ASSERT(x0 < x1);
309     BL_ASSERT(y0 < y1);
310 
311     boxAA.alpha.u = alpha;
312     boxAA.box.reset(int(x0), int(y0), int(x1), int(y1));
313     return BL_PIPE_FILL_TYPE_BOX_AA;
314   }
315 
316   template<typename T>
initBoxAU8bpcTBLPipeFillData317   inline uint32_t initBoxAU8bpcT(uint32_t alpha, T x0, T y0, T x1, T y1) noexcept {
318     return initBoxAU8bpc24x8(alpha, uint32_t(blTruncToInt(x0 * T(256))),
319                                     uint32_t(blTruncToInt(y0 * T(256))),
320                                     uint32_t(blTruncToInt(x1 * T(256))),
321                                     uint32_t(blTruncToInt(y1 * T(256))));
322   }
323 
initBoxAU8bpc24x8BLPipeFillData324   uint32_t initBoxAU8bpc24x8(uint32_t alpha, uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1) noexcept {
325     // The rendering engine should never pass out-of-range alpha.
326     BL_ASSERT(alpha <= 256);
327 
328     uint32_t ax0 = x0 >> 8;
329     uint32_t ay0 = y0 >> 8;
330     uint32_t ax1 = x1 >> 8;
331     uint32_t ay1 = y1 >> 8;
332 
333     boxAU.alpha.u = alpha;
334     boxAU.box.reset(int(ax0), int(ay0), int(ax1), int(ay1));
335 
336     // Special case - coordinates are very close (nothing to render).
337     if (x0 >= x1 || y0 >= y1)
338       return BL_PIPE_FILL_TYPE_NONE;
339 
340     // Special case - aligned box.
341     if (((x0 | x1 | y0 | y1) & 0xFFu) == 0u)
342       return BL_PIPE_FILL_TYPE_BOX_AA;
343 
344     uint32_t fx0 = x0 & 0xFFu;
345     uint32_t fy0 = y0 & 0xFFu;
346     uint32_t fx1 = x1 & 0xFFu;
347     uint32_t fy1 = y1 & 0xFFu;
348 
349     boxAU.box.x1 += fx1 != 0;
350     boxAU.box.y1 += fy1 != 0;
351 
352     if (!fx1) fx1 = 256;
353     if (!fy1) fy1 = 256;
354 
355     if (((x0 ^ x1) >> 8) == 0) { fx0 = fx1 - fx0; fx1 = 0; } else { fx0 = 256 - fx0; }
356     if (((y0 ^ y1) >> 8) == 0) { fy0 = fy1 - fy0; fy1 = 0; } else { fy0 = 256 - fy0; }
357 
358     uint32_t fy0_a = fy0 * alpha;
359     uint32_t fy1_a = fy1 * alpha;
360 
361     uint32_t m0 = (fx1 * fy0_a) >> 16;
362     uint32_t m1 = (fx1 * alpha) >>  8;
363     uint32_t m2 = (fx1 * fy0_a) >> 16;
364 
365     uint32_t iw = uint32_t(boxAU.box.x1 - boxAU.box.x0);
366     if (iw > 2) {
367       m0 = (m0 << 8) | (fy0_a >> 8);
368       m1 = (m1 << 8) | alpha;
369       m2 = (m2 << 8) | (fy1_a >> 8);
370     }
371 
372     if (iw > 1) {
373       m0 = (m0 << 8) | ((fx0 * fy0_a) >> 16);
374       m1 = (m1 << 8) | ((fx0 * alpha) >>  8);
375       m2 = (m2 << 8) | ((fx0 * fy1_a) >> 16);
376     }
377 
378     if (!m1)
379       return BL_PIPE_FILL_TYPE_NONE;
380 
381     // Border case - if alpha is too low it can cause `m0` or `m2` to be zero,
382     // which would then confuse the pipeline as it would think to stop instead
383     // of jumping to 'CMask' loop. So we patch `m0`
384     if (!m0) {
385       m0 = m1;
386       boxAU.box.y0++;
387       if (boxAU.box.y0 == boxAU.box.y1)
388         return BL_PIPE_FILL_TYPE_NONE;
389     }
390 
391     uint32_t ih = uint32_t(boxAU.box.y1 - boxAU.box.y0);
392 
393     boxAU.masks[0] = m0;
394     boxAU.masks[1] = m1;
395     boxAU.masks[2] = m2;
396     boxAU.masks[3] = 0;
397     boxAU.heights[0] = ih - 2;
398     boxAU.heights[1] = 1;
399 
400     // There is no middle layer (m1) if the height is 2 pixels or less.
401     if (ih <= 2) {
402       boxAU.masks[1] = boxAU.masks[2];
403       boxAU.masks[2] = 0;
404       boxAU.heights[0] = ih - 1;
405       boxAU.heights[1] = 0;
406     }
407 
408     if (ih <= 1) {
409       boxAU.masks[1] = 0;
410       boxAU.heights[0] = 0;
411     }
412 
413     if (iw > 3) {
414       boxAU.startWidth = 1;
415       boxAU.innerWidth = iw - 2;
416     }
417     else {
418       boxAU.startWidth = iw;
419       boxAU.innerWidth = 0;
420     }
421 
422     return BL_PIPE_FILL_TYPE_BOX_AU;
423   }
424 
initAnalyticBLPipeFillData425   inline uint32_t initAnalytic(uint32_t alpha, BLBitWord* bitTopPtr, size_t bitStride, uint32_t* cellTopPtr, size_t cellStride) noexcept {
426     analytic.alpha.u = alpha;
427     analytic.bitTopPtr = bitTopPtr;
428     analytic.bitStride = bitStride;
429     analytic.cellTopPtr = cellTopPtr;
430     analytic.cellStride = cellStride;
431 
432     return BL_PIPE_FILL_TYPE_ANALYTIC;
433   }
434 };
435 
436 // ============================================================================
437 // [BLPipeFetchData]
438 // ============================================================================
439 
440 //! Blend2D pipeline fetch data.
441 struct alignas(16) BLPipeFetchData {
442   //! Solid fetch data.
443   struct Solid {
444     union {
445       //! 32-bit ARGB, premultiplied.
446       uint32_t prgb32;
447       //! 64-bit ARGB, premultiplied.
448       uint64_t prgb64;
449     };
450 
resetBLPipeFetchData::Solid451     BL_INLINE void reset() noexcept { memset(this, 0, sizeof(*this)); }
452   };
453 
454   //! Pattern fetch data.
455   struct alignas(16) Pattern {
456     //! Source image data.
457     struct SourceData {
458       const uint8_t* pixelData;
459       intptr_t stride;
460       BLSizeI size;
461     };
462 
463     //! Simple pattern data (only identity or translation matrix).
464     struct alignas(16) Simple {
465       //! Translate by x/y (inverted).
466       int32_t tx, ty;
467       //! Repeat/Reflect w/h.
468       int32_t rx, ry;
469       //! Safe X increments by 1..16 (fetchN).
470       BLModuloTable ix;
471       //! 9-bit or 17-bit weight at [0, 0] (A).
472       uint32_t wa;
473       //! 9-bit or 17-bit weight at [1, 0] (B).
474       uint32_t wb;
475       //! 9-bit or 17-bit weight at [0, 1] (C).
476       uint32_t wc;
477       //! 9-bit or 17-bit weight at [1, 1] (D).
478       uint32_t wd;
479     };
480 
481     //! Affine pattern data.
482     struct alignas(16) Affine {
483       //! Single X/Y step in X direction.
484       BLPipeValue64 xx, xy;
485       //! Single X/Y step in Y direction.
486       BLPipeValue64 yx, yy;
487       //! Pattern offset at [0, 0].
488       BLPipeValue64 tx, ty;
489       //! Pattern overflow check.
490       BLPipeValue64 ox, oy;
491       //! Pattern overflow correction (repeat/reflect).
492       BLPipeValue64 rx, ry;
493       //! Two X/Y steps in X direction, used by `fetch4()`.
494       BLPipeValue64 xx2, xy2;
495       //! Pattern padding minimum (0 for PAD, INT32_MIN for other modes).
496       int32_t minX, minY;
497       //! Pattern padding maximum (width-1 and height-1).
498       int32_t maxX, maxY;
499       //! Correction X/Y values in case that maxX/maxY was exceeded (PAD, BILINEAR)
500       int32_t corX, corY;
501       //! Repeated tile width/height (doubled if reflected).
502       double tw, th;
503 
504       //! 32-bit value to be used by [V]PMADDWD instruction to calculate address from Y/X pairs.
505       int16_t addrMul[2];
506     };
507 
508     //! Source image data.
509     SourceData src;
510 
511     union {
512       //! Simple pattern data.
513       Simple simple;
514       //! Affine pattern data.
515       Affine affine;
516     };
517 
resetBLPipeFetchData::Pattern518     BL_INLINE void reset() noexcept { memset(this, 0, sizeof(*this)); }
519   };
520 
521   //! Gradient fetch data.
522   struct alignas(16) Gradient {
523     //! Precomputed lookup table, used by all gradient fetchers.
524     struct LUT {
525       //! Pixel data, array of either 32-bit or 64-bit pixels.
526       const void* data;
527       //! Number of pixels stored in `data`, must be a power of 2.
528       uint32_t size;
529     };
530 
531     //! Linear gradient data.
532     struct alignas(16) Linear {
533       //! Gradient offset of the pixel at [0, 0].
534       BLPipeValue64 pt[2];
535       //! One Y step.
536       BLPipeValue64 dy;
537       //! One X step.
538       BLPipeValue64 dt;
539       //! Two X steps.
540       BLPipeValue64 dt2;
541       //! Reflect/Repeat mask (repeated/reflected size - 1).
542       BLPipeValue64 rep;
543       //! Size mask (gradient size - 1).
544       BLPipeValue32 msk;
545     };
546 
547     //! Radial gradient data.
548     struct alignas(16) Radial {
549       //! Gradient X/Y increments (horizontal).
550       double xx, xy;
551       //! Gradient X/Y increments (vertical).
552       double yx, yy;
553       //! Gradient X/Y offsets of the pixel at [0, 0].
554       double ox, oy;
555 
556       double ax, ay;
557       double fx, fy;
558 
559       double dd, bd;
560       double ddx, ddy;
561       double ddd, scale;
562 
563       int maxi;
564     };
565 
566     //! Conical gradient data.
567     struct alignas(16) Conical {
568       //! Gradient X/Y increments (horizontal).
569       double xx, xy;
570       //! Gradient X/Y increments (vertical).
571       double yx, yy;
572       //! Gradient X/Y offsets of the pixel at [0, 0].
573       double ox, oy;
574       //! Atan2 approximation constants.
575       const BLCommonTable::Conical* consts;
576 
577       int maxi;
578     };
579 
580     //! Precomputed lookup table.
581     LUT lut;
582     //! Union of all possible gradient data types.
583     union {
584       //! Linear gradient specific data.
585       Linear linear;
586       //! Radial gradient specific data.
587       Radial radial;
588       //! Conical gradient specific data.
589       Conical conical;
590     };
591 
resetBLPipeFetchData::Gradient592     BL_INLINE void reset() noexcept { memset(this, 0, sizeof(*this)); }
593   };
594 
595   //! Union of all possible fetch data types.
596   union {
597     //! Solid fetch data.
598     Solid solid;
599     //! Pattern fetch data.
600     Pattern pattern;
601     //! Gradient fetch data.
602     Gradient gradient;
603   };
604 
resetBLPipeFetchData605   BL_INLINE void reset() noexcept { memset(this, 0, sizeof(*this)); }
606 
initPatternSourceBLPipeFetchData607   BL_INLINE void initPatternSource(const uint8_t* pixelData, intptr_t stride, int w, int h) noexcept {
608     pattern.src.pixelData = pixelData;
609     pattern.src.stride = stride;
610     pattern.src.size.reset(w, h);
611   }
612 
initPatternBlitBLPipeFetchData613   BL_INLINE uint32_t initPatternBlit() noexcept {
614     pattern.simple.tx = 0;
615     pattern.simple.ty = 0;
616     pattern.simple.rx = 0;
617     pattern.simple.ry = 0;
618     return BL_PIPE_FETCH_TYPE_PATTERN_AA_BLIT;
619   }
620 
621   BL_HIDDEN uint32_t initPatternAxAy(
622     uint32_t extendMode,
623     int x, int y) noexcept;
624 
625   BL_HIDDEN uint32_t initPatternFxFy(
626     uint32_t extendMode,
627     uint32_t filter,
628     uint32_t bytesPerPixel,
629     int64_t tx64, int64_t ty64) noexcept;
630 
631   BL_HIDDEN uint32_t initPatternAffine(
632     uint32_t extendMode,
633     uint32_t filter,
634     uint32_t bytesPerPixel,
635     const BLMatrix2D& m) noexcept;
636 
637   BL_HIDDEN uint32_t initGradient(
638     uint32_t gradientType,
639     const void* values,
640     uint32_t extendMode,
641     const BLGradientLUT* lut,
642     const BLMatrix2D& m) noexcept;
643 };
644 
645 // ============================================================================
646 // [BLPipeSignature]
647 // ============================================================================
648 
649 //! Pipeline signature packed to a single `uint32_t` value.
650 //!
651 //! Can be used to build signatures as well as it offers the required functionality.
652 struct BLPipeSignature {
653   //! Signature as a 32-bit value.
654   uint32_t value;
655 
656   BL_INLINE BLPipeSignature() noexcept = default;
657   BL_INLINE constexpr BLPipeSignature(const BLPipeSignature&) noexcept = default;
BLPipeSignatureBLPipeSignature658   BL_INLINE explicit constexpr BLPipeSignature(uint32_t value) : value(value) {}
659 
660   BL_INLINE bool operator==(const BLPipeSignature& other) const noexcept { return value == other.value; }
661   BL_INLINE bool operator!=(const BLPipeSignature& other) const noexcept { return value != other.value; }
662 
_getBLPipeSignature663   BL_INLINE uint32_t _get(uint32_t mask) const noexcept {
664     return (this->value & mask) >> blBitShiftOf(mask);
665   }
666 
_setBLPipeSignature667   BL_INLINE void _set(uint32_t mask, uint32_t v) noexcept {
668     BL_ASSERT(v <= (mask >> blBitShiftOf(mask)));
669     this->value = (this->value & ~mask) | (v << blBitShiftOf(mask));
670   }
671 
_addBLPipeSignature672   BL_INLINE void _add(uint32_t mask, uint32_t v) noexcept {
673     BL_ASSERT(v <= (mask >> blBitShiftOf(mask)));
674     this->value |= (v << blBitShiftOf(mask));
675   }
676 
677   //! Reset all values to zero.
resetBLPipeSignature678   BL_INLINE void reset() noexcept { this->value = 0; }
679   //! Reset all values to other signature.
resetBLPipeSignature680   BL_INLINE void reset(uint32_t v) noexcept { this->value = v; }
681 
682   //! Set the signature from a packed 32-bit integer.
setValueBLPipeSignature683   BL_INLINE void setValue(uint32_t v) noexcept { this->value = v; }
684   //! Set the signature from another `BLPipeSignature`.
setValueBLPipeSignature685   BL_INLINE void setValue(const BLPipeSignature& other) noexcept { this->value = other.value; }
686 
687   //! Extracts destination pixel format from the signature.
dstFormatBLPipeSignature688   BL_INLINE uint32_t dstFormat() const noexcept { return _get(BL_PIPE_SIGNATURE_DST_FORMAT); }
689   //! Extracts source pixel format from the signature.
srcFormatBLPipeSignature690   BL_INLINE uint32_t srcFormat() const noexcept { return _get(BL_PIPE_SIGNATURE_SRC_FORMAT); }
691   //! Extracts composition operator from the signature.
compOpBLPipeSignature692   BL_INLINE uint32_t compOp() const noexcept { return _get(BL_PIPE_SIGNATURE_COMP_OP); }
693   //! Extracts sweep type from the signature.
fillTypeBLPipeSignature694   BL_INLINE uint32_t fillType() const noexcept { return _get(BL_PIPE_SIGNATURE_FILL_TYPE); }
695   //! Extracts fetch type from the signature.
fetchTypeBLPipeSignature696   BL_INLINE uint32_t fetchType() const noexcept { return _get(BL_PIPE_SIGNATURE_FETCH_TYPE); }
697   //! Extracts fetch data from the signature.
fetchPayloadBLPipeSignature698   BL_INLINE uint32_t fetchPayload() const noexcept { return _get(BL_PIPE_SIGNATURE_FETCH_PAYLOAD); }
699 
700   //! Add destination pixel format.
setDstFormatBLPipeSignature701   BL_INLINE void setDstFormat(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_DST_FORMAT, v); }
702   //! Add source pixel format.
setSrcFormatBLPipeSignature703   BL_INLINE void setSrcFormat(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_SRC_FORMAT, v); }
704   //! Add clip mode.
setCompOpBLPipeSignature705   BL_INLINE void setCompOp(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_COMP_OP, v); }
706   //! Add sweep type.
setFillTypeBLPipeSignature707   BL_INLINE void setFillType(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_FILL_TYPE, v); }
708   //! Add fetch type.
setFetchTypeBLPipeSignature709   BL_INLINE void setFetchType(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_FETCH_TYPE, v); }
710   //! Add fetch data.
setFetchPayloadBLPipeSignature711   BL_INLINE void setFetchPayload(uint32_t v) noexcept { _set(BL_PIPE_SIGNATURE_FETCH_PAYLOAD, v); }
712 
713   // The following methods are used to build the signature. They use '|' operator
714   // which doesn't clear the previous value, each function is expected to be called
715   // only once when building a new signature.
716 
717   //! Combine with other signature.
addBLPipeSignature718   BL_INLINE void add(uint32_t v) noexcept { this->value |= v; }
719   //! Combine with other signature.
addBLPipeSignature720   BL_INLINE void add(const BLPipeSignature& other) noexcept { this->value |= other.value; }
721 
722   //! Add destination pixel format.
addDstFormatBLPipeSignature723   BL_INLINE void addDstFormat(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_DST_FORMAT, v); }
724   //! Add source pixel format.
addSrcFormatBLPipeSignature725   BL_INLINE void addSrcFormat(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_SRC_FORMAT, v); }
726   //! Add clip mode.
addCompOpBLPipeSignature727   BL_INLINE void addCompOp(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_COMP_OP, v); }
728   //! Add sweep type.
addFillTypeBLPipeSignature729   BL_INLINE void addFillType(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_FILL_TYPE, v); }
730   //! Add fetch type.
addFetchTypeBLPipeSignature731   BL_INLINE void addFetchType(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_FETCH_TYPE, v); }
732   //! Add fetch data.
addFetchPayloadBLPipeSignature733   BL_INLINE void addFetchPayload(uint32_t v) noexcept { _add(BL_PIPE_SIGNATURE_FETCH_PAYLOAD, v); }
734 };
735 
736 //! \}
737 //! \endcond
738 
739 #endif // BLEND2D_PIPEDEFS_P_H
740