OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkRasterPipeline_DEFINED | 8 #ifndef SkRasterPipeline_DEFINED |
9 #define SkRasterPipeline_DEFINED | 9 #define SkRasterPipeline_DEFINED |
10 | 10 |
(...skipping 27 matching lines...) Expand all Loading... |
38 * stages; transfer modes use these to hold the original destination pixel
components. | 38 * stages; transfer modes use these to hold the original destination pixel
components. |
39 * | 39 * |
40 * On some platforms the last four vectors are slower to work with than the othe
r arguments. | 40 * On some platforms the last four vectors are slower to work with than the othe
r arguments. |
41 * | 41 * |
42 * When done mutating its arguments and/or context, a stage can either: | 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 | 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. | 44 * 2) return, indicating the pipeline is complete for these pixels. |
45 * | 45 * |
46 * Some obvious stages that typically return are those that write a color to a d
estination pointer, | 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(). | 47 * but any stage can short-circuit the rest of the pipeline by returning instead
of calling next(). |
| 48 * |
| 49 * TODO: explain EasyFn and SK_RASTER_STAGE |
48 */ | 50 */ |
49 | 51 |
50 class SkRasterPipeline { | 52 class SkRasterPipeline { |
51 public: | 53 public: |
52 struct Stage; | 54 struct Stage; |
53 using Fn = void(SK_VECTORCALL *)(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, | 55 using Fn = void(SK_VECTORCALL *)(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, |
54 Sk4f,Sk4f,Sk4f,Sk4f); | 56 Sk4f,Sk4f,Sk4f,Sk4f); |
| 57 using EasyFn = void(void*, size_t, Sk4f&, Sk4f&, Sk4f&, Sk4f&, |
| 58 Sk4f&, Sk4f&, Sk4f&, Sk4f&); |
| 59 |
55 struct Stage { | 60 struct Stage { |
56 template <typename T> | 61 template <typename T> |
57 T ctx() { return static_cast<T>(fCtx); } | 62 T ctx() { return static_cast<T>(fCtx); } |
58 | 63 |
59 void SK_VECTORCALL next(size_t x, Sk4f v0, Sk4f v1, Sk4f v2, Sk4f v3, | 64 void SK_VECTORCALL next(size_t x, Sk4f v0, Sk4f v1, Sk4f v2, Sk4f v3, |
60 Sk4f v4, Sk4f v5, Sk4f v6, Sk4f v7) { | 65 Sk4f v4, Sk4f v5, Sk4f v6, Sk4f v7) { |
61 // Stages are logically a pipeline, and physically are contiguous in
an array. | 66 // 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. | 67 // 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); | 68 fNext(this+1, x, v0,v1,v2,v3, v4,v5,v6,v7); |
64 } | 69 } |
(...skipping 22 matching lines...) Expand all Loading... |
87 // Most stages don't actually care if they're working on 4 or 1 pixel. | 92 // Most stages don't actually care if they're working on 4 or 1 pixel. |
88 void append(Fn fn, const void* ctx = nullptr) { | 93 void append(Fn fn, const void* ctx = nullptr) { |
89 this->append(fn, ctx, fn, ctx); | 94 this->append(fn, ctx, fn, ctx); |
90 } | 95 } |
91 | 96 |
92 // Most 4 pixel or 1 pixel variants share the same context pointer. | 97 // Most 4 pixel or 1 pixel variants share the same context pointer. |
93 void append(Fn body, Fn tail, const void* ctx = nullptr) { | 98 void append(Fn body, Fn tail, const void* ctx = nullptr) { |
94 this->append(body, ctx, tail, ctx); | 99 this->append(body, ctx, tail, ctx); |
95 } | 100 } |
96 | 101 |
| 102 |
| 103 // Versions of append that can be used with static EasyFns (see SK_RASTER_ST
AGE). |
| 104 template <EasyFn body, EasyFn tail> |
| 105 void append(const void* body_ctx, const void* tail_ctx) { |
| 106 this->append(Easy<body>, body_ctx, |
| 107 Easy<tail>, tail_ctx); |
| 108 } |
| 109 |
| 110 template <EasyFn fn> |
| 111 void append(const void* ctx = nullptr) { this->append<fn, fn>(ctx, ctx); } |
| 112 |
| 113 template <EasyFn body, EasyFn tail> |
| 114 void append(const void* ctx = nullptr) { this->append<body, tail>(ctx, ctx);
} |
| 115 |
| 116 |
97 // Append all stages to this pipeline. | 117 // Append all stages to this pipeline. |
98 void extend(const SkRasterPipeline&); | 118 void extend(const SkRasterPipeline&); |
99 | 119 |
100 private: | 120 private: |
101 using Stages = SkSTArray<10, Stage, /*MEM_COPY=*/true>; | 121 using Stages = SkSTArray<10, Stage, /*MEM_COPY=*/true>; |
102 | 122 |
103 // This no-op default makes fBodyStart and fTailStart unconditionally safe t
o call, | 123 // This no-op default makes fBodyStart and fTailStart unconditionally safe t
o call, |
104 // and is always the last stage's fNext as a sort of safety net to make sure
even a | 124 // and is always the last stage's fNext as a sort of safety net to make sure
even a |
105 // buggy pipeline can't walk off its own end. | 125 // buggy pipeline can't walk off its own end. |
106 static void SK_VECTORCALL JustReturn(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, | 126 static void SK_VECTORCALL JustReturn(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, |
107 Sk4f,Sk4f,Sk4f,Sk4f); | 127 Sk4f,Sk4f,Sk4f,Sk4f); |
108 | 128 |
| 129 template <EasyFn kernel> |
| 130 static void SK_VECTORCALL Easy(SkRasterPipeline::Stage* st, size_t x, |
| 131 Sk4f r, Sk4f g, Sk4f b, Sk4f a, |
| 132 Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) { |
| 133 kernel(st->ctx<void*>(), x, r,g,b,a, dr,dg,db,da); |
| 134 st->next(x, r,g,b,a, dr,dg,db,da); |
| 135 } |
| 136 |
109 Stages fBody, | 137 Stages fBody, |
110 fTail; | 138 fTail; |
111 Fn fBodyStart = &JustReturn, | 139 Fn fBodyStart = &JustReturn, |
112 fTailStart = &JustReturn; | 140 fTailStart = &JustReturn; |
113 }; | 141 }; |
114 | 142 |
| 143 // These are always static, and we _really_ want them to inline. |
| 144 // If you find yourself wanting a non-inline stage, write a SkRasterPipeline::Fn
directly. |
| 145 #define SK_RASTER_STAGE(name) \ |
| 146 static SK_ALWAYS_INLINE void name(void* ctx, size_t x, \ |
| 147 Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, \ |
| 148 Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) |
| 149 |
115 #endif//SkRasterPipeline_DEFINED | 150 #endif//SkRasterPipeline_DEFINED |
OLD | NEW |