| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * Copyright 2016 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 SkRasterPipeline_DEFINED |
| 9 #define SkRasterPipeline_DEFINED |
| 10 |
| 11 #include "SkNx.h" |
| 12 #include "SkTArray.h" |
| 13 #include "SkTypes.h" |
| 14 |
| 15 /** |
| 16 * SkRasterPipeline provide a cheap way to chain together a pixel processing pip
eline. |
| 17 * |
| 18 * It's particularly designed for situations where the potential pipeline is ext
remely |
| 19 * combinatoric: {N dst formats} x {M source formats} x {K mask formats} x {C tr
ansfer modes} ... |
| 20 * No one wants to write specialized routines for all those combinations, and if
we did, we'd |
| 21 * end up bloating our code size dramatically. SkRasterPipeline stages can be c
hained together |
| 22 * at runtime, so we can scale this problem linearly rather than combinatoricall
y. |
| 23 * |
| 24 * Each stage is represented by a function conforming to a common interface, SkR
asterPipeline::Fn, |
| 25 * and by an arbitrary context pointer (TODO: make this tidier with lambdas?).
Fn's arguments, |
| 26 * and sometimes custom calling convention, are designed to maximize the amount
of data we can |
| 27 * pass along the pipeline cheaply. On many machines they all stay in registers
the entire time. |
| 28 * |
| 29 * The meaning of the arguments to Fn are sometimes fixed... |
| 30 * - The Stage* always represents the current stage, mainly providing access
to ctx(). |
| 31 * - The size_t is always the destination x coordinate. If you need y, put i
t in your context. |
| 32 * - By the time the shader's done, the first four vectors should hold source
red, |
| 33 * green, blue, and alpha, up to 4 pixels' worth each. |
| 34 * |
| 35 * ...and sometimes flexible: |
| 36 * - In the shader, the first four vectors can be used for anything, e.g. sam
ple coordinates. |
| 37 * - The last four vectors are scratch registers that can be used to communic
ate between |
| 38 * stages; transfer modes use these to hold the original destination pixel
components. |
| 39 * |
| 40 * On some platforms the last four vectors are slower to work with than the othe
r arguments. |
| 41 * |
| 42 * When done mutating its arguments and/or context, a stage can either: |
| 43 * 1) call st->next() with its mutated arguments, chaining to the next stage o
f the pipeline; or |
| 44 * 2) return, indicating the pipeline is complete for these pixels. |
| 45 * |
| 46 * Some obvious stages that typically return are those that write a color to a d
estination pointer, |
| 47 * but any stage can short-circuit the rest of the pipeline by returning instead
of calling next(). |
| 48 */ |
| 49 |
| 50 class SkRasterPipeline { |
| 51 public: |
| 52 struct Stage; |
| 53 using Fn = SK_VECTORCALL void(*)(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, |
| 54 Sk4f,Sk4f,Sk4f,Sk4f); |
| 55 struct Stage { |
| 56 template <typename T = void> |
| 57 T ctx() { return static_cast<T>(fCtx); } |
| 58 |
| 59 SK_ALWAYS_INLINE void next(size_t x, Sk4f v0, Sk4f v1, Sk4f v2, Sk4f v3, |
| 60 Sk4f v4, Sk4f v5, Sk4f v6, Sk4f v7)
{ |
| 61 // Stages are logically a pipeline, and physically are contiguous in
an array. |
| 62 // To get to the next stage, we just increment our pointer to the ne
xt array element. |
| 63 fNext(this+1, x, v0,v1,v2,v3, v4,v5,v6,v7); |
| 64 } |
| 65 |
| 66 // It makes next() a good bit cheaper if we hold the next function to ca
ll here, |
| 67 // rather than logically simpler choice of the function implementing thi
s stage. |
| 68 Fn fNext; |
| 69 void* fCtx; |
| 70 }; |
| 71 |
| 72 |
| 73 SkRasterPipeline(); |
| 74 |
| 75 // Run the pipeline constructed with append(), walking x through [0,n), |
| 76 // generally in 4 pixel steps, but sometimes 1 pixel at a time. |
| 77 void run(size_t n); |
| 78 |
| 79 // Use this append() if your stage is sensitive to the number of pixels you'
re working with: |
| 80 // - body will always be called for a full 4 pixels |
| 81 // - tail will always be called for a single pixel |
| 82 // Typically this is only an essential distintion for stages that read or wr
ite memory. |
| 83 void append(Fn body, const void* body_ctx, |
| 84 Fn tail, const void* tail_ctx); |
| 85 |
| 86 // Most stages don't actually care if they're working on 4 or 1 pixel. |
| 87 void append(Fn fn, const void* ctx = nullptr) { |
| 88 this->append(fn, ctx, fn, ctx); |
| 89 } |
| 90 |
| 91 // Most 4 pixel or 1 pixel variants share the same context pointer. |
| 92 void append(Fn body, Fn tail, const void* ctx = nullptr) { |
| 93 this->append(body, ctx, tail, ctx); |
| 94 } |
| 95 |
| 96 private: |
| 97 using Stages = SkSTArray<10, Stage, /*MEM_COPY=*/true>; |
| 98 |
| 99 static void Rewire(Stages*); |
| 100 |
| 101 Stages fBody, |
| 102 fTail; |
| 103 bool fReadyToRun = false; |
| 104 }; |
| 105 |
| 106 #endif//SkRasterPipeline_DEFINED |
| OLD | NEW |