1/*
2 * Copyright 2017 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 GrSimpleMeshDrawOpHelper_DEFINED
9#define GrSimpleMeshDrawOpHelper_DEFINED
10
11#include "GrMeshDrawOp.h"
12#include "GrOpFlushState.h"
13#include "GrPipeline.h"
14
15struct SkRect;
16
17/**
18 * This class can be used to help implement simple mesh draw ops. It reduces the amount of
19 * boilerplate code to type and also provides a mechanism for optionally allocating space for a
20 * GrProcessorSet based on a GrPaint. It is intended to be used by ops that construct a single
21 * GrPipeline for a uniform primitive color and a GrPaint.
22 */
23class GrSimpleMeshDrawOpHelper {
24public:
25    struct MakeArgs;
26
27    /**
28     * This can be used by a Op class to perform allocation and initialization such that a
29     * GrProcessorSet (if required) is allocated as part of the the same allocation that as
30     * the Op instance. It requires that Op implements a constructor of the form:
31     *      Op(MakeArgs, GrColor, OpArgs...)
32     * which is public or made accessible via 'friend'.
33     */
34    template <typename Op, typename... OpArgs>
35    static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs);
36
37    enum class Flags : uint32_t {
38        kNone = 0x0,
39        kSnapVerticesToPixelCenters = 0x1,
40    };
41    GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
42
43    GrSimpleMeshDrawOpHelper(const MakeArgs&, GrAAType, Flags = Flags::kNone);
44    ~GrSimpleMeshDrawOpHelper();
45
46    GrSimpleMeshDrawOpHelper() = delete;
47    GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete;
48    GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete;
49
50    GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const;
51
52    bool isCompatible(const GrSimpleMeshDrawOpHelper& that, const GrCaps&, const SkRect& thisBounds,
53                      const SkRect& thatBounds) const;
54
55    /**
56     * Finalizes the processor set and determines whether the destination must be provided
57     * to the fragment shader as a texture for blending.
58     *
59     * @param geometryCoverage Describes the coverage output of the op's geometry processor
60     * @param geometryColor An in/out param. As input this informs processor analysis about the
61     *                      color the op expects to output from its geometry processor. As output
62     *                      this may be set to a known color in which case the op must output this
63     *                      color from its geometry processor instead.
64     */
65    GrDrawOp::RequiresDstTexture xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip,
66                                                      GrPixelConfigIsClamped dstIsClamped,
67                                                      GrProcessorAnalysisCoverage geometryCoverage,
68                                                      GrProcessorAnalysisColor* geometryColor);
69
70    /**
71     * Version of above that can be used by ops that have a constant color geometry processor
72     * output. The op passes this color as 'geometryColor' and after return if 'geometryColor' has
73     * changed the op must override its geometry processor color output with the new color.
74     */
75    GrDrawOp::RequiresDstTexture xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*,
76                                                      GrPixelConfigIsClamped dstIsClamped,
77                                                      GrProcessorAnalysisCoverage geometryCoverage,
78                                                      GrColor* geometryColor);
79
80    bool usesLocalCoords() const {
81        SkASSERT(fDidAnalysis);
82        return fUsesLocalCoords;
83    }
84
85    bool compatibleWithAlphaAsCoverage() const { return fCompatibleWithAlphaAsCoveage; }
86
87    /** Makes a pipeline that consumes the processor set and the op's applied clip. */
88    GrPipeline* makePipeline(GrMeshDrawOp::Target* target) {
89        return this->internalMakePipeline(target, this->pipelineInitArgs(target));
90    }
91
92    struct MakeArgs {
93    private:
94        MakeArgs() = default;
95
96        GrProcessorSet* fProcessorSet;
97        uint32_t fSRGBFlags;
98
99        friend class GrSimpleMeshDrawOpHelper;
100    };
101
102    void visitProxies(const std::function<void(GrSurfaceProxy*)>& func) const {
103        if (fProcessors) {
104            fProcessors->visitProxies(func);
105        }
106    }
107
108    SkString dumpInfo() const;
109
110protected:
111    GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
112    uint32_t pipelineFlags() const { return fPipelineFlags; }
113
114    GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const;
115
116    GrPipeline* internalMakePipeline(GrMeshDrawOp::Target*, const GrPipeline::InitArgs&);
117
118private:
119    GrProcessorSet* fProcessors;
120    unsigned fPipelineFlags : 8;
121    unsigned fAAType : 2;
122    unsigned fRequiresDstTexture : 1;
123    unsigned fUsesLocalCoords : 1;
124    unsigned fCompatibleWithAlphaAsCoveage : 1;
125    SkDEBUGCODE(unsigned fMadePipeline : 1;)
126    SkDEBUGCODE(unsigned fDidAnalysis : 1;)
127};
128
129/**
130 * This class extends GrSimpleMeshDrawOpHelper to support an optional GrUserStencilSettings. This
131 * uses private inheritance because it non-virtually overrides methods in the base class and should
132 * never be used with a GrSimpleMeshDrawOpHelper pointer or reference.
133 */
134class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper {
135public:
136    using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs;
137    using Flags = GrSimpleMeshDrawOpHelper::Flags;
138    using GrSimpleMeshDrawOpHelper::visitProxies;
139
140    // using declarations can't be templated, so this is a pass through function instead.
141    template <typename Op, typename... OpArgs>
142    static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs) {
143        return GrSimpleMeshDrawOpHelper::FactoryHelper<Op, OpArgs...>(
144                std::move(paint), std::forward<OpArgs>(opArgs)...);
145    }
146
147    GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs&, GrAAType, const GrUserStencilSettings*,
148                                        Flags = Flags::kNone);
149
150    GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const;
151
152    using GrSimpleMeshDrawOpHelper::xpRequiresDstTexture;
153    using GrSimpleMeshDrawOpHelper::usesLocalCoords;
154    using GrSimpleMeshDrawOpHelper::compatibleWithAlphaAsCoverage;
155
156    bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that, const GrCaps&,
157                      const SkRect& thisBounds, const SkRect& thatBounds) const;
158
159    const GrPipeline* makePipeline(GrMeshDrawOp::Target*);
160
161    SkString dumpInfo() const;
162
163private:
164    const GrUserStencilSettings* fStencilSettings;
165    typedef GrSimpleMeshDrawOpHelper INHERITED;
166};
167
168template <typename Op, typename... OpArgs>
169std::unique_ptr<GrDrawOp> GrSimpleMeshDrawOpHelper::FactoryHelper(GrPaint&& paint,
170                                                                  OpArgs... opArgs) {
171    MakeArgs makeArgs;
172    makeArgs.fSRGBFlags = GrPipeline::SRGBFlagsFromPaint(paint);
173    GrColor color = paint.getColor();
174    if (paint.isTrivial()) {
175        makeArgs.fProcessorSet = nullptr;
176        return std::unique_ptr<GrDrawOp>(new Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
177    } else {
178        char* mem = (char*)GrOp::operator new(sizeof(Op) + sizeof(GrProcessorSet));
179        char* setMem = mem + sizeof(Op);
180        makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint));
181        return std::unique_ptr<GrDrawOp>(
182                new (mem) Op(makeArgs, color, std::forward<OpArgs>(opArgs)...));
183    }
184}
185
186GR_MAKE_BITFIELD_CLASS_OPS(GrSimpleMeshDrawOpHelper::Flags)
187
188#endif
189