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 "include/private/GrRecordingContext.h"
12 #include "src/gpu/GrMemoryPool.h"
13 #include "src/gpu/GrOpFlushState.h"
14 #include "src/gpu/GrPipeline.h"
15 #include "src/gpu/GrRecordingContextPriv.h"
16 #include "src/gpu/ops/GrMeshDrawOp.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(GrRecordingContext*, GrPaint&&, OpArgs...);
40 
41     // Here we allow callers to specify a subset of the GrPipeline::InputFlags upon creation.
42     enum class InputFlags : uint8_t {
43         kNone = 0,
44         kSnapVerticesToPixelCenters = (uint8_t)GrPipeline::InputFlags::kSnapVerticesToPixelCenters,
45     };
46     GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(InputFlags);
47 
48     GrSimpleMeshDrawOpHelper(const MakeArgs&, GrAAType, InputFlags = InputFlags::kNone);
49     ~GrSimpleMeshDrawOpHelper();
50 
51     GrSimpleMeshDrawOpHelper() = delete;
52     GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete;
53     GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete;
54 
55     GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const;
56 
57     // noneAACompatibleWithCoverage should be set to true if the op can properly render a non-AA
58     // primitive merged into a coverage-based op.
59     bool isCompatible(const GrSimpleMeshDrawOpHelper& that, const GrCaps&, const SkRect& thisBounds,
60                       const SkRect& thatBounds, bool noneAACompatibleWithCoverage = false) const;
61 
62     /**
63      * Finalizes the processor set and determines whether the destination must be provided
64      * to the fragment shader as a texture for blending.
65      *
66      * @param geometryCoverage Describes the coverage output of the op's geometry processor
67      * @param geometryColor An in/out param. As input this informs processor analysis about the
68      *                      color the op expects to output from its geometry processor. As output
69      *                      this may be set to a known color in which case the op must output this
70      *                      color from its geometry processor instead.
71      */
finalizeProcessors(const GrCaps & caps,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType clampType,GrProcessorAnalysisCoverage geometryCoverage,GrProcessorAnalysisColor * geometryColor)72     GrProcessorSet::Analysis finalizeProcessors(
73             const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
74             GrClampType clampType, GrProcessorAnalysisCoverage geometryCoverage,
75             GrProcessorAnalysisColor* geometryColor) {
76         return this->finalizeProcessors(
77                 caps, clip, &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, clampType,
78                 geometryCoverage, geometryColor);
79     }
80 
81     /**
82      * Version of above that can be used by ops that have a constant color geometry processor
83      * output. The op passes this color as 'geometryColor' and after return if 'geometryColor' has
84      * changed the op must override its geometry processor color output with the new color.
85      */
86     GrProcessorSet::Analysis finalizeProcessors(
87             const GrCaps&, const GrAppliedClip*, bool hasMixedSampledCoverage, GrClampType,
88             GrProcessorAnalysisCoverage geometryCoverage, SkPMColor4f* geometryColor,
89             bool* wideColor);
90 
isTrivial()91     bool isTrivial() const {
92       return fProcessors == nullptr;
93     }
94 
usesLocalCoords()95     bool usesLocalCoords() const {
96         SkASSERT(fDidAnalysis);
97         return fUsesLocalCoords;
98     }
99 
compatibleWithCoverageAsAlpha()100     bool compatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
101 
102     struct MakeArgs {
103     private:
104         MakeArgs() = default;
105 
106         GrProcessorSet* fProcessorSet;
107 
108         friend class GrSimpleMeshDrawOpHelper;
109     };
110 
visitProxies(const GrOp::VisitProxyFunc & func)111     void visitProxies(const GrOp::VisitProxyFunc& func) const {
112         if (fProcessors) {
113             fProcessors->visitProxies(func);
114         }
115     }
116 
117 #ifdef SK_DEBUG
118     SkString dumpInfo() const;
119 #endif
aaType()120     GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
121 
setAAType(GrAAType aaType)122     void setAAType(GrAAType aaType) {
123       fAAType = static_cast<unsigned>(aaType);
124     }
125 
126     void executeDrawsAndUploads(const GrOp*, GrOpFlushState*, const SkRect& chainBounds);
127 
128 protected:
pipelineFlags()129     GrPipeline::InputFlags pipelineFlags() const { return fPipelineFlags; }
130 
131     GrProcessorSet::Analysis finalizeProcessors(
132             const GrCaps& caps, const GrAppliedClip*, const GrUserStencilSettings*,
133             bool hasMixedSampledCoverage, GrClampType, GrProcessorAnalysisCoverage geometryCoverage,
134             GrProcessorAnalysisColor* geometryColor);
135 
136     GrProcessorSet* fProcessors;
137     GrPipeline::InputFlags fPipelineFlags;
138     unsigned fAAType : 2;
139     unsigned fUsesLocalCoords : 1;
140     unsigned fCompatibleWithCoverageAsAlpha : 1;
141     SkDEBUGCODE(unsigned fMadePipeline : 1;)
142     SkDEBUGCODE(unsigned fDidAnalysis : 1;)
143 };
144 
145 /**
146  * This class extends GrSimpleMeshDrawOpHelper to support an optional GrUserStencilSettings. This
147  * uses private inheritance because it non-virtually overrides methods in the base class and should
148  * never be used with a GrSimpleMeshDrawOpHelper pointer or reference.
149  */
150 class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper {
151 public:
152     using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs;
153     using InputFlags = GrSimpleMeshDrawOpHelper::InputFlags;
154 
155     using GrSimpleMeshDrawOpHelper::visitProxies;
156 
157     // using declarations can't be templated, so this is a pass through function instead.
158     template <typename Op, typename... OpArgs>
FactoryHelper(GrRecordingContext * context,GrPaint && paint,OpArgs...opArgs)159     static std::unique_ptr<GrDrawOp> FactoryHelper(GrRecordingContext* context, GrPaint&& paint,
160                                                    OpArgs... opArgs) {
161         return GrSimpleMeshDrawOpHelper::FactoryHelper<Op, OpArgs...>(
162                 context, std::move(paint), std::forward<OpArgs>(opArgs)...);
163     }
164 
165     GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs&, GrAAType, const GrUserStencilSettings*,
166                                         InputFlags = InputFlags::kNone);
167 
168     GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const;
169 
finalizeProcessors(const GrCaps & caps,const GrAppliedClip * clip,bool hasMixedSampledCoverage,GrClampType clampType,GrProcessorAnalysisCoverage geometryCoverage,GrProcessorAnalysisColor * geometryColor)170     GrProcessorSet::Analysis finalizeProcessors(
171             const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
172             GrClampType clampType, GrProcessorAnalysisCoverage geometryCoverage,
173             GrProcessorAnalysisColor* geometryColor) {
174         return this->INHERITED::finalizeProcessors(
175                 caps, clip, fStencilSettings, hasMixedSampledCoverage, clampType, geometryCoverage,
176                 geometryColor);
177     }
178 
179     GrProcessorSet::Analysis finalizeProcessors(
180             const GrCaps&, const GrAppliedClip*, bool hasMixedSampledCoverage, GrClampType,
181             GrProcessorAnalysisCoverage geometryCoverage, SkPMColor4f* geometryColor, bool*
182             wideColor);
183 
184     using GrSimpleMeshDrawOpHelper::aaType;
185     using GrSimpleMeshDrawOpHelper::setAAType;
186     using GrSimpleMeshDrawOpHelper::isTrivial;
187     using GrSimpleMeshDrawOpHelper::usesLocalCoords;
188     using GrSimpleMeshDrawOpHelper::compatibleWithCoverageAsAlpha;
189 
190     bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that, const GrCaps&,
191                       const SkRect& thisBounds, const SkRect& thatBounds,
192                       bool noneAACompatibleWithCoverage = false) const;
193 
194     void executeDrawsAndUploads(const GrOp*, GrOpFlushState*, const SkRect& chainBounds);
195 
196 #ifdef SK_DEBUG
197     SkString dumpInfo() const;
198 #endif
199 
200 private:
201     const GrUserStencilSettings* fStencilSettings;
202     typedef GrSimpleMeshDrawOpHelper INHERITED;
203 };
204 
205 template <typename Op, typename... OpArgs>
FactoryHelper(GrRecordingContext * context,GrPaint && paint,OpArgs...opArgs)206 std::unique_ptr<GrDrawOp> GrSimpleMeshDrawOpHelper::FactoryHelper(GrRecordingContext* context,
207                                                                   GrPaint&& paint,
208                                                                   OpArgs... opArgs) {
209     GrOpMemoryPool* pool = context->priv().opMemoryPool();
210 
211     MakeArgs makeArgs;
212 
213     if (paint.isTrivial()) {
214         makeArgs.fProcessorSet = nullptr;
215         return pool->allocate<Op>(makeArgs, paint.getColor4f(), std::forward<OpArgs>(opArgs)...);
216     } else {
217         char* mem = (char*) pool->allocate(sizeof(Op) + sizeof(GrProcessorSet));
218         char* setMem = mem + sizeof(Op);
219         auto color = paint.getColor4f();
220         makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint));
221         return std::unique_ptr<GrDrawOp>(new (mem) Op(makeArgs, color,
222                                                       std::forward<OpArgs>(opArgs)...));
223     }
224 }
225 
226 GR_MAKE_BITFIELD_CLASS_OPS(GrSimpleMeshDrawOpHelper::InputFlags)
227 
228 #endif
229