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/gpu/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
19struct 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 */
27class GrSimpleMeshDrawOpHelper {
28public:
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 kConservativeRaster = (uint8_t)GrPipeline::InputFlags::kConservativeRaster,
46 };
47 GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(InputFlags);
48
49 GrSimpleMeshDrawOpHelper(const MakeArgs&, GrAAType, InputFlags = InputFlags::kNone);
50 ~GrSimpleMeshDrawOpHelper();
51
52 GrSimpleMeshDrawOpHelper() = delete;
53 GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete;
54 GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete;
55
56 GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const;
57
58 // ignoreAAType should be set to true if the op already knows the AA settings are acceptible
59 bool isCompatible(const GrSimpleMeshDrawOpHelper& that, const GrCaps&, const SkRect& thisBounds,
60 const SkRect& thatBounds, bool ignoreAAType = 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 */
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
91 bool isTrivial() const {
92 return fProcessors == nullptr;
93 }
94
95 bool usesLocalCoords() const {
96 SkASSERT(fDidAnalysis);
97 return fUsesLocalCoords;
98 }
99
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
111 void visitProxies(const GrOp::VisitProxyFunc& func) const {
112 if (fProcessors) {
113 fProcessors->visitProxies(func);
114 }
115 }
116
117#if GR_TEST_UTILS
118 SkString dumpInfo() const;
119#endif
120 GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
121
122 void setAAType(GrAAType aaType) {
123 fAAType = static_cast<unsigned>(aaType);
124 }
125
126 static const GrPipeline* CreatePipeline(
127 const GrCaps*,
128 SkArenaAlloc*,
129 GrSwizzle writeViewSwizzle,
130 GrAppliedClip&&,
131 const GrXferProcessor::DstProxyView&,
132 GrProcessorSet&&,
133 GrPipeline::InputFlags pipelineFlags,
134 const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
135 static const GrPipeline* CreatePipeline(
136 GrOpFlushState*,
137 GrProcessorSet&&,
138 GrPipeline::InputFlags pipelineFlags,
139 const GrUserStencilSettings* = &GrUserStencilSettings::kUnused);
140
141 const GrPipeline* createPipeline(GrOpFlushState* flushState);
142
143 static GrProgramInfo* CreateProgramInfo(SkArenaAlloc*,
144 const GrPipeline*,
145 const GrSurfaceProxyView* writeView,
146 GrGeometryProcessor*,
147 GrPrimitiveType);
148
149 // Create a programInfo with the following properties:
150 // its primitive processor uses no textures
151 // it has no dynamic state besides the scissor clip
152 static GrProgramInfo* CreateProgramInfo(const GrCaps*,
153 SkArenaAlloc*,
154 const GrSurfaceProxyView* writeView,
155 GrAppliedClip&&,
156 const GrXferProcessor::DstProxyView&,
157 GrGeometryProcessor*,
158 GrProcessorSet&&,
159 GrPrimitiveType,
160 GrPipeline::InputFlags pipelineFlags
161 = GrPipeline::InputFlags::kNone,
162 const GrUserStencilSettings*
163 = &GrUserStencilSettings::kUnused);
164
165 GrProgramInfo* createProgramInfo(const GrCaps*,
166 SkArenaAlloc*,
167 const GrSurfaceProxyView* writeView,
168 GrAppliedClip&&,
169 const GrXferProcessor::DstProxyView&,
170 GrGeometryProcessor*,
171 GrPrimitiveType);
172
173 GrProcessorSet detachProcessorSet() {
174 return fProcessors ? std::move(*fProcessors) : GrProcessorSet::MakeEmptySet();
175 }
176
177 GrPipeline::InputFlags pipelineFlags() const { return fPipelineFlags; }
178
179protected:
180 GrProcessorSet::Analysis finalizeProcessors(
181 const GrCaps& caps, const GrAppliedClip*, const GrUserStencilSettings*,
182 bool hasMixedSampledCoverage, GrClampType, GrProcessorAnalysisCoverage geometryCoverage,
183 GrProcessorAnalysisColor* geometryColor);
184
185 GrProcessorSet* fProcessors;
186 GrPipeline::InputFlags fPipelineFlags;
187 unsigned fAAType : 2;
188 unsigned fUsesLocalCoords : 1;
189 unsigned fCompatibleWithCoverageAsAlpha : 1;
190 SkDEBUGCODE(unsigned fMadePipeline : 1;)
191 SkDEBUGCODE(unsigned fDidAnalysis : 1;)
192};
193
194template <typename Op, typename... OpArgs>
195std::unique_ptr<GrDrawOp> GrSimpleMeshDrawOpHelper::FactoryHelper(GrRecordingContext* context,
196 GrPaint&& paint,
197 OpArgs&&... opArgs) {
198 GrOpMemoryPool* pool = context->priv().opMemoryPool();
199
200 MakeArgs makeArgs;
201
202 if (paint.isTrivial()) {
203 makeArgs.fProcessorSet = nullptr;
204 return pool->allocate<Op>(makeArgs, paint.getColor4f(), std::forward<OpArgs>(opArgs)...);
205 } else {
206 char* mem = (char*) pool->allocate(sizeof(Op) + sizeof(GrProcessorSet));
207 char* setMem = mem + sizeof(Op);
208 auto color = paint.getColor4f();
209 makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint));
210 return std::unique_ptr<GrDrawOp>(new (mem) Op(makeArgs, color,
211 std::forward<OpArgs>(opArgs)...));
212 }
213}
214
215GR_MAKE_BITFIELD_CLASS_OPS(GrSimpleMeshDrawOpHelper::InputFlags)
216
217#endif
218