aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkLinearBitmapPipeline.h
blob: 91b573df5d8c5a95de93ff3b31a5c82741633c57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * 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 SkLinearBitmapPipeline_DEFINED
#define SkLinearBitmapPipeline_DEFINED

#include "SkColor.h"
#include "SkImageInfo.h"
#include "SkMatrix.h"
#include "SkShader.h"

class SkEmbeddableLinearPipeline;

enum SkGammaType {
    kLinear_SkGammaType,
    kSRGB_SkGammaType,
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// SkLinearBitmapPipeline - encapsulates all the machinery for doing floating point pixel
// processing in a linear color space.
// Note: this class has unusual alignment requirements due to its use of SIMD instructions. The
// class SkEmbeddableLinearPipeline below manages these requirements.
class SkLinearBitmapPipeline {
public:
    SkLinearBitmapPipeline(
        const SkMatrix& inverse,
        SkFilterQuality filterQuality,
        SkShader::TileMode xTile, SkShader::TileMode yTile,
        SkColor paintColor,
        const SkPixmap& srcPixmap);

    SkLinearBitmapPipeline(
        const SkLinearBitmapPipeline& pipeline,
        const SkPixmap& srcPixmap,
        SkXfermode::Mode xferMode,
        const SkImageInfo& dstInfo);

    static bool ClonePipelineForBlitting(
        SkEmbeddableLinearPipeline* pipelineStorage,
        const SkLinearBitmapPipeline& pipeline,
        SkMatrix::TypeMask matrixMask,
        SkShader::TileMode xTileMode,
        SkShader::TileMode yTileMode,
        SkFilterQuality filterQuality,
        const SkPixmap& srcPixmap,
        float finalAlpha,
        SkXfermode::Mode xferMode,
        const SkImageInfo& dstInfo);

    ~SkLinearBitmapPipeline();

    void shadeSpan4f(int x, int y, SkPM4f* dst, int count);
    void blitSpan(int32_t x, int32_t y, void* dst, int count);

    template<typename Base, size_t kSize, typename Next = void>
    class Stage {
    public:
        Stage() : fIsInitialized{false} {}
        ~Stage();

        template<typename Variant, typename... Args>
        void initStage(Next* next, Args&& ... args);

        template<typename Variant, typename... Args>
        void initSink(Args&& ... args);

        template <typename To, typename From>
        To* getInterface();

        // Copy this stage to `cloneToStage` with `next` as its next stage
        // (not necessarily the same as our next, you see), returning `cloneToStage`.
        // Note: There is no cloneSinkTo method because the code usually places the top part of
        // the pipeline on a new sampler.
        Base* cloneStageTo(Next* next, Stage* cloneToStage) const;

        Base* get() const { return reinterpret_cast<Base*>(&fSpace); }
        Base* operator->() const { return this->get(); }
        Base& operator*() const { return *(this->get()); }

    private:
        std::function<void (Next*, void*)> fStageCloner;
        struct SK_STRUCT_ALIGN(16) Space {
            char space[kSize];
        };
        bool fIsInitialized;
        mutable Space fSpace;
    };

///////////////////////////////////////////////////////////////////////////////////////////////////
// PolyMemory
    template <typename Base, size_t kSize>
    class PolyMemory {
    public:
        PolyMemory() : fIsInitialized{false} { }
        ~PolyMemory() {
            if (fIsInitialized) {
                this->get()->~Base();
            }
        }
        template<typename Variant, typename... Args>
        void init(Args&& ... args) {
            SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
                      "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));

            new (&fSpace) Variant(std::forward<Args>(args)...);
            fIsInitialized = true;
        }

        Base* get() const { return reinterpret_cast<Base*>(&fSpace); }
        Base* operator->() const { return this->get(); }
        Base& operator*() const { return *(this->get()); }

    private:
        struct SK_STRUCT_ALIGN(16) Space {
            char space[kSize];
        };
        mutable Space fSpace;
        bool          fIsInitialized;

    };

    class PointProcessorInterface;
    class SampleProcessorInterface;
    class BlendProcessorInterface;
    class DestinationInterface;
    class PixelAccessorInterface;

    // These values were generated by the assert above in Stage::init{Sink|Stage}.
    using MatrixStage  = Stage<PointProcessorInterface,    160, PointProcessorInterface>;
    using TileStage    = Stage<PointProcessorInterface,    160, SampleProcessorInterface>;
    using SampleStage  = Stage<SampleProcessorInterface,   160, BlendProcessorInterface>;
    using BlenderStage = Stage<BlendProcessorInterface,     40>;
    using Accessor     = PolyMemory<PixelAccessorInterface, 64>;

private:
    PointProcessorInterface* fFirstStage;
    MatrixStage              fMatrixStage;
    TileStage                fTileStage;
    SampleStage              fSampleStage;
    BlenderStage             fBlenderStage;
    DestinationInterface*    fLastStage;
    Accessor                 fAccessor;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// SkEmbeddableLinearPipeline - manage stricter alignment needs for SkLinearBitmapPipeline.
class SkEmbeddableLinearPipeline {
public:
    SkEmbeddableLinearPipeline() { }
    ~SkEmbeddableLinearPipeline() {
        if (get() != nullptr) {
            get()->~SkLinearBitmapPipeline();
        }
    }

    template <typename... Args>
    void init(Args&&... args) {
        // Ensure that our pipeline is created at a 16 byte aligned address.
        fPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fPipelineStorage);
        new (fPipeline) SkLinearBitmapPipeline{std::forward<Args>(args)...};
    }

    SkLinearBitmapPipeline* get()        const { return fPipeline;    }
    SkLinearBitmapPipeline& operator*()  const { return *this->get(); }
    SkLinearBitmapPipeline* operator->() const { return  this->get(); }

private:
    enum {
        kActualSize = sizeof(SkLinearBitmapPipeline),
        kPaddedSize = SkAlignPtr(kActualSize + 12),
    };
    void* fPipelineStorage[kPaddedSize / sizeof(void*)];
    SkLinearBitmapPipeline* fPipeline{nullptr};
};

#endif  // SkLinearBitmapPipeline_DEFINED