1 /* 2 * Copyright 2023 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkRasterPipelineOpContexts_DEFINED 9 #define SkRasterPipelineOpContexts_DEFINED 10 11 #include <algorithm> 12 #include <cstddef> 13 #include <cstdint> 14 15 namespace SkSL { class TraceHook; } 16 17 // The largest number of pixels we handle at a time. We have a separate value for the largest number 18 // of pixels we handle in the highp pipeline. Many of the context structs in this file are only used 19 // by stages that have no lowp implementation. They can therefore use the (smaller) highp value to 20 // save memory in the arena. 21 inline static constexpr int SkRasterPipeline_kMaxStride = 16; 22 inline static constexpr int SkRasterPipeline_kMaxStride_highp = 16; 23 24 // How much space to allocate for each MemoryCtx scratch buffer, as part of tail-pixel handling. 25 inline static constexpr size_t SkRasterPipeline_MaxScratchPerPatch = 26 std::max(SkRasterPipeline_kMaxStride_highp * 16, // 16 == largest highp bpp (RGBA_F32) 27 SkRasterPipeline_kMaxStride * 4); // 4 == largest lowp bpp (RGBA_8888) 28 29 // These structs hold the context data for many of the Raster Pipeline ops. 30 struct SkRasterPipeline_MemoryCtx { 31 void* pixels; 32 int stride; 33 }; 34 35 // Raster Pipeline typically processes N (4, 8, 16) pixels at a time, in SIMT fashion. If the 36 // number of pixels in a row isn't evenly divisible by N, there will be leftover pixels; this is 37 // called the "tail". To avoid reading or writing past the end of any source or destination buffers 38 // when we reach the tail: 39 // 40 // 1) Source buffers have their tail contents copied to a scratch buffer that is at least N wide. 41 // In practice, each scratch buffer uses SkRasterPipeline_MaxScratchPerPatch bytes. 42 // 2) Each MemoryCtx in the pipeline is patched, such that access to them (at the current scanline 43 // and x-offset) will land in the scratch buffer. 44 // 3) Pipeline is run as normal (with all memory access happening safely in the scratch buffers). 45 // 4) Destination buffers have their tail contents copied back from the scratch buffer. 46 // 5) Each MemoryCtx is "un-patched". 47 // 48 // To do all of this, the pipeline creates a MemoryCtxPatch for each unique MemoryCtx referenced by 49 // the pipeline. 50 struct SkRasterPipeline_MemoryCtxInfo { 51 SkRasterPipeline_MemoryCtx* context; 52 53 int bytesPerPixel; 54 bool load; 55 bool store; 56 }; 57 58 struct SkRasterPipeline_MemoryCtxPatch { 59 SkRasterPipeline_MemoryCtxInfo info; 60 61 void* backup; // Remembers context->pixels so we can restore it 62 std::byte scratch[SkRasterPipeline_MaxScratchPerPatch]; 63 }; 64 65 struct SkRasterPipeline_GatherCtx { 66 const void* pixels; 67 int stride; 68 float width; 69 float height; 70 float weights[16]; // for bicubic and bicubic_clamp_8888 71 // Controls whether pixel i-1 or i is selected when floating point sample position is exactly i. 72 bool roundDownAtInteger = false; 73 }; 74 75 // State shared by save_xy, accumulate, and bilinear_* / bicubic_*. 76 struct SkRasterPipeline_SamplerCtx { 77 float x[SkRasterPipeline_kMaxStride_highp]; 78 float y[SkRasterPipeline_kMaxStride_highp]; 79 float fx[SkRasterPipeline_kMaxStride_highp]; 80 float fy[SkRasterPipeline_kMaxStride_highp]; 81 float scalex[SkRasterPipeline_kMaxStride_highp]; 82 float scaley[SkRasterPipeline_kMaxStride_highp]; 83 84 // for bicubic_[np][13][xy] 85 float weights[16]; 86 float wx[4][SkRasterPipeline_kMaxStride_highp]; 87 float wy[4][SkRasterPipeline_kMaxStride_highp]; 88 }; 89 90 struct SkRasterPipeline_TileCtx { 91 float scale; 92 float invScale; // cache of 1/scale 93 // When in the reflection portion of mirror tiling we need to snap the opposite direction 94 // at integer sample points than when in the forward direction. This controls which way we bias 95 // in the reflection. It should be 1 if SkRasterPipeline_GatherCtx::roundDownAtInteger is true 96 // and otherwise -1. 97 int mirrorBiasDir = -1; 98 }; 99 100 struct SkRasterPipeline_DecalTileCtx { 101 uint32_t mask[SkRasterPipeline_kMaxStride]; 102 float limit_x; 103 float limit_y; 104 // These control which edge of the interval is included (i.e. closed interval at 0 or at limit). 105 // They should be set to limit_x and limit_y if SkRasterPipeline_GatherCtx::roundDownAtInteger 106 // is true and otherwise zero. 107 float inclusiveEdge_x = 0; 108 float inclusiveEdge_y = 0; 109 }; 110 111 enum class SkPerlinNoiseShaderType; 112 113 struct SkRasterPipeline_PerlinNoiseCtx { 114 SkPerlinNoiseShaderType noiseType; 115 float baseFrequencyX, baseFrequencyY; 116 float stitchDataInX, stitchDataInY; 117 bool stitching; 118 int numOctaves; 119 const uint8_t* latticeSelector; // [256 values] 120 const uint16_t* noiseData; // [4 channels][256 elements][vector of 2] 121 }; 122 123 // State used by mipmap_linear_* 124 struct SkRasterPipeline_MipmapCtx { 125 // Original coords, saved before the base level logic 126 float x[SkRasterPipeline_kMaxStride_highp]; 127 float y[SkRasterPipeline_kMaxStride_highp]; 128 129 // Base level color 130 float r[SkRasterPipeline_kMaxStride_highp]; 131 float g[SkRasterPipeline_kMaxStride_highp]; 132 float b[SkRasterPipeline_kMaxStride_highp]; 133 float a[SkRasterPipeline_kMaxStride_highp]; 134 135 // Scale factors to transform base level coords to lower level coords 136 float scaleX; 137 float scaleY; 138 139 float lowerWeight; 140 }; 141 142 struct SkRasterPipeline_CoordClampCtx { 143 float min_x, min_y; 144 float max_x, max_y; 145 }; 146 147 struct SkRasterPipeline_CallbackCtx { 148 void (*fn)(SkRasterPipeline_CallbackCtx* self, 149 int active_pixels /*<= SkRasterPipeline_kMaxStride_highp*/); 150 151 // When called, fn() will have our active pixels available in rgba. 152 // When fn() returns, the pipeline will read back those active pixels from read_from. 153 float rgba[4*SkRasterPipeline_kMaxStride_highp]; 154 float* read_from = rgba; 155 }; 156 157 // state shared by stack_checkpoint and stack_rewind 158 struct SkRasterPipelineStage; 159 160 struct SkRasterPipeline_RewindCtx { 161 float r[SkRasterPipeline_kMaxStride_highp]; 162 float g[SkRasterPipeline_kMaxStride_highp]; 163 float b[SkRasterPipeline_kMaxStride_highp]; 164 float a[SkRasterPipeline_kMaxStride_highp]; 165 float dr[SkRasterPipeline_kMaxStride_highp]; 166 float dg[SkRasterPipeline_kMaxStride_highp]; 167 float db[SkRasterPipeline_kMaxStride_highp]; 168 float da[SkRasterPipeline_kMaxStride_highp]; 169 std::byte* base; 170 SkRasterPipelineStage* stage; 171 }; 172 173 struct SkRasterPipeline_GradientCtx { 174 size_t stopCount; 175 float* fs[4]; 176 float* bs[4]; 177 float* ts; 178 }; 179 180 struct SkRasterPipeline_EvenlySpaced2StopGradientCtx { 181 float f[4]; 182 float b[4]; 183 }; 184 185 struct SkRasterPipeline_2PtConicalCtx { 186 uint32_t fMask[SkRasterPipeline_kMaxStride_highp]; 187 float fP0, 188 fP1; 189 }; 190 191 struct SkRasterPipeline_UniformColorCtx { 192 float r,g,b,a; 193 uint16_t rgba[4]; // [0,255] in a 16-bit lane. 194 }; 195 196 struct SkRasterPipeline_EmbossCtx { 197 SkRasterPipeline_MemoryCtx mul, 198 add; 199 }; 200 201 struct SkRasterPipeline_TablesCtx { 202 const uint8_t *r, *g, *b, *a; 203 }; 204 205 using SkRPOffset = uint32_t; 206 207 struct SkRasterPipeline_InitLaneMasksCtx { 208 uint8_t* tail; 209 }; 210 211 struct SkRasterPipeline_ConstantCtx { 212 int32_t value; 213 SkRPOffset dst; 214 }; 215 216 struct SkRasterPipeline_UniformCtx { 217 int32_t* dst; 218 const int32_t* src; 219 }; 220 221 struct SkRasterPipeline_BinaryOpCtx { 222 SkRPOffset dst; 223 SkRPOffset src; 224 }; 225 226 struct SkRasterPipeline_TernaryOpCtx { 227 SkRPOffset dst; 228 SkRPOffset delta; 229 }; 230 231 struct SkRasterPipeline_MatrixMultiplyCtx { 232 SkRPOffset dst; 233 uint8_t leftColumns, leftRows, rightColumns, rightRows; 234 }; 235 236 struct SkRasterPipeline_SwizzleCtx { 237 // If we are processing more than 16 pixels at a time, an 8-bit offset won't be sufficient and 238 // `offsets` will need to use uint16_t (or dial down the premultiplication). 239 static_assert(SkRasterPipeline_kMaxStride_highp <= 16); 240 241 SkRPOffset dst; 242 uint8_t offsets[4]; // values must be byte offsets (4 * highp-stride * component-index) 243 }; 244 245 struct SkRasterPipeline_ShuffleCtx { 246 int32_t* ptr; 247 int count; 248 uint16_t offsets[16]; // values must be byte offsets (4 * highp-stride * component-index) 249 }; 250 251 struct SkRasterPipeline_SwizzleCopyCtx { 252 int32_t* dst; 253 const int32_t* src; // src values must _not_ overlap dst values 254 uint16_t offsets[4]; // values must be byte offsets (4 * highp-stride * component-index) 255 }; 256 257 struct SkRasterPipeline_CopyIndirectCtx { 258 int32_t* dst; 259 const int32_t* src; 260 const uint32_t *indirectOffset; // this applies to `src` or `dst` based on the op 261 uint32_t indirectLimit; // the indirect offset is clamped to this upper bound 262 uint32_t slots; // the number of slots to copy 263 }; 264 265 struct SkRasterPipeline_SwizzleCopyIndirectCtx : public SkRasterPipeline_CopyIndirectCtx { 266 uint16_t offsets[4]; // values must be byte offsets (4 * highp-stride * component-index) 267 }; 268 269 struct SkRasterPipeline_BranchCtx { 270 int offset; // contains the label ID during compilation, and the program offset when compiled 271 }; 272 273 struct SkRasterPipeline_BranchIfAllLanesActiveCtx : public SkRasterPipeline_BranchCtx { 274 uint8_t* tail = nullptr; // lanes past the tail are _never_ active, so we need to exclude them 275 }; 276 277 struct SkRasterPipeline_BranchIfEqualCtx : public SkRasterPipeline_BranchCtx { 278 int value; 279 const int* ptr; 280 }; 281 282 struct SkRasterPipeline_CaseOpCtx { 283 int expectedValue; 284 SkRPOffset offset; // points to a pair of adjacent I32s: {I32 actualValue, I32 defaultMask} 285 }; 286 287 struct SkRasterPipeline_TraceFuncCtx { 288 const int* traceMask; 289 SkSL::TraceHook* traceHook; 290 int funcIdx; 291 }; 292 293 struct SkRasterPipeline_TraceScopeCtx { 294 const int* traceMask; 295 SkSL::TraceHook* traceHook; 296 int delta; 297 }; 298 299 struct SkRasterPipeline_TraceLineCtx { 300 const int* traceMask; 301 SkSL::TraceHook* traceHook; 302 int lineNumber; 303 }; 304 305 struct SkRasterPipeline_TraceVarCtx { 306 const int* traceMask; 307 SkSL::TraceHook* traceHook; 308 int slotIdx, numSlots; 309 const int* data; 310 const uint32_t *indirectOffset; // can be null; if set, an offset applied to `data` 311 uint32_t indirectLimit; // the indirect offset is clamped to this upper bound 312 }; 313 314 #endif // SkRasterPipelineOpContexts_DEFINED 315