diff options
author | 2016-07-12 15:01:26 -0700 | |
---|---|---|
committer | 2016-07-12 15:01:26 -0700 | |
commit | 281b33fdd909ee3f43192cdf950ce00e3df62407 (patch) | |
tree | 807d54decaa74522b811d17740f3e6e959a519de /src/core/SkRasterPipeline.h | |
parent | 7438bfc0804d021aa92cdd5ea644994a4248f3db (diff) |
SkRasterPipeline preliminaries
Re-uploading to see if I can get a CL number < 2^31.
patch from issue 2147533002 at patchset 240001 (http://crrev.com/2147533002#ps240001)
Already reviewed at the other crrev link.
TBR=
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2147533002
CQ_INCLUDE_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
Review-Url: https://codereview.chromium.org/2144573004
Diffstat (limited to 'src/core/SkRasterPipeline.h')
-rw-r--r-- | src/core/SkRasterPipeline.h | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h new file mode 100644 index 0000000000..8ae7bb1f2e --- /dev/null +++ b/src/core/SkRasterPipeline.h @@ -0,0 +1,104 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRasterPipeline_DEFINED +#define SkRasterPipeline_DEFINED + +#include "SkNx.h" +#include "SkTArray.h" +#include "SkTypes.h" + +/** + * SkRasterPipeline provides a cheap way to chain together a pixel processing pipeline. + * + * It's particularly designed for situations where the potential pipeline is extremely + * combinatoric: {N dst formats} x {M source formats} x {K mask formats} x {C transfer modes} ... + * No one wants to write specialized routines for all those combinations, and if we did, we'd + * end up bloating our code size dramatically. SkRasterPipeline stages can be chained together + * at runtime, so we can scale this problem linearly rather than combinatorically. + * + * Each stage is represented by a function conforming to a common interface, SkRasterPipeline::Fn, + * and by an arbitrary context pointer. Fn's arguments, and sometimes custom calling convention, + * are designed to maximize the amount of data we can pass along the pipeline cheaply. + * On many machines all arguments stay in registers the entire time. + * + * The meaning of the arguments to Fn are sometimes fixed... + * - The Stage* always represents the current stage, mainly providing access to ctx(). + * - The size_t is always the destination x coordinate. If you need y, put it in your context. + * - By the time the shader's done, the first four vectors should hold source red, + * green, blue, and alpha, up to 4 pixels' worth each. + * + * ...and sometimes flexible: + * - In the shader, the first four vectors can be used for anything, e.g. sample coordinates. + * - The last four vectors are scratch registers that can be used to communicate between + * stages; transfer modes use these to hold the original destination pixel components. + * + * On some platforms the last four vectors are slower to work with than the other arguments. + * + * When done mutating its arguments and/or context, a stage can either: + * 1) call st->next() with its mutated arguments, chaining to the next stage of the pipeline; or + * 2) return, indicating the pipeline is complete for these pixels. + * + * Some obvious stages that typically return are those that write a color to a destination pointer, + * but any stage can short-circuit the rest of the pipeline by returning instead of calling next(). + */ + +class SkRasterPipeline { +public: + struct Stage; + using Fn = void(SK_VECTORCALL *)(Stage*, size_t, Sk4f,Sk4f,Sk4f,Sk4f, + Sk4f,Sk4f,Sk4f,Sk4f); + struct Stage { + template <typename T> + T ctx() { return static_cast<T>(fCtx); } + + void SK_VECTORCALL next(size_t x, Sk4f v0, Sk4f v1, Sk4f v2, Sk4f v3, + Sk4f v4, Sk4f v5, Sk4f v6, Sk4f v7) { + // Stages are logically a pipeline, and physically are contiguous in an array. + // To get to the next stage, we just increment our pointer to the next array element. + fNext(this+1, x, v0,v1,v2,v3, v4,v5,v6,v7); + } + + // It makes next() a good bit cheaper if we hold the next function to call here, + // rather than logically simpler choice of the function implementing this stage. + Fn fNext; + void* fCtx; + }; + + + SkRasterPipeline(); + + // Run the pipeline constructed with append(), walking x through [0,n), + // generally in 4 pixel steps, but sometimes 1 pixel at a time. + void run(size_t n); + + // Use this append() if your stage is sensitive to the number of pixels you're working with: + // - body will always be called for a full 4 pixels + // - tail will always be called for a single pixel + // Typically this is only an essential distintion for stages that read or write memory. + void append(Fn body, const void* body_ctx, + Fn tail, const void* tail_ctx); + + // Most stages don't actually care if they're working on 4 or 1 pixel. + void append(Fn fn, const void* ctx = nullptr) { + this->append(fn, ctx, fn, ctx); + } + + // Most 4 pixel or 1 pixel variants share the same context pointer. + void append(Fn body, Fn tail, const void* ctx = nullptr) { + this->append(body, ctx, tail, ctx); + } + +private: + using Stages = SkSTArray<10, Stage, /*MEM_COPY=*/true>; + + Stages fBody, + fTail; + bool fReadyToRun = false; +}; + +#endif//SkRasterPipeline_DEFINED |