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_BLPIPE_P_H
8#define BLEND2D_BLPIPE_P_H
9
10#include "./blapi-internal_p.h"
11#include "./blpipedefs_p.h"
12#include "./blsimd_p.h"
13
14//! \cond INTERNAL
15//! \addtogroup blend2d_internal
16//! \{
17
18// ============================================================================
19// [Forward Declarations]
20// ============================================================================
21
22struct BLPipeRuntime;
23struct BLPipeProvider;
24struct BLPipeLookupCache;
25
26// ============================================================================
27// [Constants]
28// ============================================================================
29
30enum BLPipeRuntimeType : uint32_t {
31 //! Fixed runtime that doesn't use JIT (can be either reference or optimized).
32 BL_PIPE_RUNTIME_TYPE_FIXED = 0,
33 //! Runtime that uses PipeGen - JIT optimized pipelines.
34 BL_PIPE_RUNTIME_TYPE_PIPEGEN = 1,
35
36 //! Count of pipeline runtime types.
37 BL_PIPE_RUNTIME_TYPE_COUNT
38};
39
40enum BLPipeRuntimeFlags : uint32_t {
41 BL_PIPE_RUNTIME_FLAG_ISOLATED = 0x00000001
42};
43
44// ============================================================================
45// [BLPipeRuntime]
46// ============================================================================
47
48//! This is a base class used by either `BLPipeGenRuntime` (for dynamic piplines)
49//! or `BLFixedPipeRuntime` for static pipelines. The purpose of this class is
50//! to create interface that is used by the rendering context so it doesn't
51//! have to know which kind of pipelines it uses.
52struct BLPipeRuntime {
53 //! Type of the runtime, see `BLPipeRuntimeType`.
54 uint8_t _runtimeType;
55 //! Reserved for future use.
56 uint8_t _reserved;
57 //! Size of this runtime in bytes.
58 uint16_t _runtimeSize;
59 //! Runtime flags, see `BLPipeRuntimeFlags`.
60 uint32_t _runtimeFlags;
61
62 //! Runtime destructor.
63 void (BL_CDECL* _destroy)(BLPipeRuntime* self) BL_NOEXCEPT;
64
65 //! Functions exposed by the runtime that are copied to `BLPipeProvider` to
66 //! make them local in the rendering context. It seems hacky, but this removes
67 //! one extra indirection that would be needed if they were virtual.
68 struct Funcs {
69 BLPipeFillFunc (BL_CDECL* get)(BLPipeRuntime* self, uint32_t signature, BLPipeLookupCache* cache) BL_NOEXCEPT;
70 BLPipeFillFunc (BL_CDECL* test)(BLPipeRuntime* self, uint32_t signature, BLPipeLookupCache* cache) BL_NOEXCEPT;
71 } _funcs;
72
73 BL_INLINE uint32_t runtimeType() const noexcept { return _runtimeType; }
74 BL_INLINE uint32_t runtimeFlags() const noexcept { return _runtimeFlags; }
75 BL_INLINE uint32_t runtimeSize() const noexcept { return _runtimeSize; }
76
77 BL_INLINE void destroy() noexcept { _destroy(this); }
78};
79
80// ============================================================================
81// [BLPipeProvider]
82// ============================================================================
83
84struct BLPipeProvider {
85 BLPipeRuntime* _runtime;
86 BLPipeRuntime::Funcs _funcs;
87
88 BL_INLINE BLPipeProvider() noexcept
89 : _runtime(nullptr),
90 _funcs {} {}
91
92 BL_INLINE bool isInitialized() const noexcept {
93 return _runtime != nullptr;
94 }
95
96 BL_INLINE void init(BLPipeRuntime* runtime) noexcept {
97 _runtime = runtime;
98 _funcs = runtime->_funcs;
99 }
100
101 BL_INLINE void reset() noexcept {
102 memset(this, 0, sizeof(*this));
103 }
104
105 BL_INLINE BLPipeRuntime* runtime() const noexcept { return _runtime; }
106 BL_INLINE BLPipeFillFunc get(uint32_t signature, BLPipeLookupCache* cache = nullptr) const noexcept { return _funcs.get(_runtime, signature, cache); }
107 BL_INLINE BLPipeFillFunc test(uint32_t signature, BLPipeLookupCache* cache = nullptr) const noexcept { return _funcs.test(_runtime, signature, cache); }
108};
109
110// ============================================================================
111// [BLPipeLookupCache]
112// ============================================================================
113
114//! Pipe lookup cache is a local cache used by the rendering engine to store
115//! `N` recently used pipelines so it doesn't have to use `BLPipeProvider` that
116//! may would call `BLPipeRuntime` to query (or compile) the required pipeline.
117struct BLPipeLookupCache {
118 //! Number of cached pipelines, must be multiply of 4.
119 enum : uint32_t { N = 8 };
120
121 //! Array of signatures for the lookup, uninitialized signatures should be zero.
122 uint32_t _signs[N];
123 //! Array of functions matching signatures from `_signs` array. There is one
124 //! extra function at the end that must always be `nullptr` and is returned
125 //! when a signature isn't matched.
126 void* _funcs[N + 1];
127 //! Index where a next signature will be written (incremental, wraps to zero).
128 size_t _currentIndex;
129
130 BL_INLINE void reset() { memset(this, 0, sizeof(*this)); }
131
132 BL_INLINE void* _lookup(uint32_t signature) const noexcept {
133 #if defined(BL_TARGET_OPT_SSE2) && 0
134 using namespace SIMD;
135 static_assert(N == 8, "This code is written for N == 8");
136
137 I128 vSign = vseti128u32(signature);
138 I128 v0123 = vcmpeqi32(vloadi128u(_signs + 0), vSign);
139 I128 v4567 = vcmpeqi32(vloadi128u(_signs + 4), vSign);
140
141 uint32_t m0123 = uint32_t(_mm_movemask_ps(vcast<F128>(v0123)));
142 uint32_t m4567 = uint32_t(_mm_movemask_ps(vcast<F128>(v4567)) << 4);
143
144 uint32_t i = blBitCtz(m0123 + m4567 + (1u << N));
145 return _funcs[i];
146 #else
147 size_t i;
148 for (i = 0; i < N; i++)
149 if (_signs[i] == signature)
150 break;
151 return _funcs[i];
152 #endif
153 }
154
155 BL_INLINE void _store(uint32_t signature, void* func) noexcept {
156 _signs[_currentIndex] = signature;
157 _funcs[_currentIndex] = func;
158
159 if (++_currentIndex >= N)
160 _currentIndex = 0;
161 }
162
163 template<typename Func>
164 BL_INLINE Func lookup(uint32_t signature) const noexcept { return (Func)_lookup(signature); }
165
166 template<typename Func>
167 BL_INLINE void store(uint32_t signature, Func func) noexcept { _store(signature, (void*)func); }
168};
169
170//! \}
171//! \endcond
172
173#endif // BLEND2D_BLPIPE_P_H
174