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