1/*
2* Copyright 2016 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 GrOpsRenderPass_DEFINED
9#define GrOpsRenderPass_DEFINED
10
11#include "include/core/SkDrawable.h"
12#include "src/gpu/GrPipeline.h"
13#include "src/gpu/ops/GrDrawOp.h"
14
15class GrOpFlushState;
16class GrGpu;
17class GrPipeline;
18class GrPrimitiveProcessor;
19class GrProgramInfo;
20class GrRenderTarget;
21class GrScissorState;
22class GrSemaphore;
23struct SkIRect;
24struct SkRect;
25
26/**
27 * The GrOpsRenderPass is a series of commands (draws, clears, and discards), which all target the
28 * same render target. It is possible that these commands execute immediately (GL), or get buffered
29 * up for later execution (Vulkan). GrOps execute into a GrOpsRenderPass.
30 */
31class GrOpsRenderPass {
32public:
33 virtual ~GrOpsRenderPass() {}
34
35 struct LoadAndStoreInfo {
36 GrLoadOp fLoadOp;
37 GrStoreOp fStoreOp;
38 SkPMColor4f fClearColor;
39 };
40
41 // Load-time clears of the stencil buffer are always to 0 so we don't store
42 // an 'fStencilClearValue'
43 struct StencilLoadAndStoreInfo {
44 GrLoadOp fLoadOp;
45 GrStoreOp fStoreOp;
46 };
47
48 void begin();
49 // Signals the end of recording to the GrOpsRenderPass and that it can now be submitted.
50 void end();
51
52 // Updates the internal pipeline state for drawing with the provided GrProgramInfo. Enters an
53 // internal "bad" state if the pipeline could not be set.
54 void bindPipeline(const GrProgramInfo&, const SkRect& drawBounds);
55
56 // The scissor rect is always dynamic state and therefore not stored on GrPipeline. If scissor
57 // test is enabled on the current pipeline, then the client must call setScissorRect() before
58 // drawing. The scissor rect may also be updated between draws without having to bind a new
59 // pipeline.
60 void setScissorRect(const SkIRect&);
61
62 // Binds textures for the primitive processor and any FP on the GrPipeline. Texture bindings are
63 // dynamic state and therefore not set during bindPipeline(). If the current program uses
64 // textures, then the client must call bindTextures() before drawing. The primitive processor
65 // textures may also be updated between draws by calling bindTextures() again with a different
66 // array for primProcTextures. (On subsequent calls, if the backend is capable of updating the
67 // primitive processor textures independently, then it will automatically skip re-binding
68 // FP textures from GrPipeline.)
69 //
70 // If the current program does not use textures, this is a no-op.
71 void bindTextures(const GrPrimitiveProcessor&, const GrSurfaceProxy* const primProcTextures[],
72 const GrPipeline&);
73
74 void bindBuffers(sk_sp<const GrBuffer> indexBuffer, sk_sp<const GrBuffer> instanceBuffer,
75 sk_sp<const GrBuffer> vertexBuffer, GrPrimitiveRestart = GrPrimitiveRestart::kNo);
76
77 // The next several draw*() methods issue draws using the current pipeline state. Before
78 // drawing, the caller must configure the pipeline and dynamic state:
79 //
80 // - Call bindPipeline()
81 // - If the scissor test is enabled, call setScissorRect()
82 // - If the current program uses textures, call bindTextures()
83 // - Call bindBuffers() (even if all buffers are null)
84 void draw(int vertexCount, int baseVertex);
85 void drawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, uint16_t maxIndexValue,
86 int baseVertex);
87
88 // Requires caps.drawInstancedSupport().
89 void drawInstanced(int instanceCount, int baseInstance, int vertexCount, int baseVertex);
90
91 // Requires caps.drawInstancedSupport().
92 void drawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance,
93 int baseVertex);
94
95 // Executes multiple draws from an array of GrDrawIndirectCommand in the provided buffer.
96 //
97 // Requires caps.drawInstancedSupport().
98 //
99 // If caps.nativeDrawIndirectSupport() is unavailable, then 'drawIndirectBuffer' must be a
100 // GrCpuBuffer in order to polyfill. Performance may suffer in this scenario.
101 void drawIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset, int drawCount);
102
103 // Executes multiple draws from an array of GrDrawIndexedIndirectCommand in the provided buffer.
104 //
105 // Requires caps.drawInstancedSupport().
106 //
107 // If caps.nativeDrawIndirectSupport() is unavailable, then 'drawIndirectBuffer' must be a
108 // GrCpuBuffer in order to polyfill. Performance may suffer in this scenario.
109 void drawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t bufferOffset,
110 int drawCount);
111
112 // This is a helper method for drawing a repeating pattern of vertices. The bound index buffer
113 // is understood to contain 'maxPatternRepetitionsInIndexBuffer' repetitions of the pattern.
114 // If more repetitions are required, then we loop.
115 void drawIndexPattern(int patternIndexCount, int patternRepeatCount,
116 int maxPatternRepetitionsInIndexBuffer, int patternVertexCount,
117 int baseVertex);
118
119 // Performs an upload of vertex data in the middle of a set of a set of draws
120 virtual void inlineUpload(GrOpFlushState*, GrDeferredTextureUploadFn&) = 0;
121
122 /**
123 * Clear the owned render target. Clears the full target if 'scissor' is disabled, otherwise it
124 * is restricted to 'scissor'. Must check caps.performPartialClearsAsDraws() before using an
125 * enabled scissor test; must check caps.performColorClearsAsDraws() before using this at all.
126 */
127 void clear(const GrScissorState& scissor, const SkPMColor4f&);
128
129 /**
130 * Same as clear() but modifies the stencil; check caps.performStencilClearsAsDraws() and
131 * caps.performPartialClearsAsDraws().
132 */
133 void clearStencilClip(const GrScissorState& scissor, bool insideStencilMask);
134
135 /**
136 * Executes the SkDrawable object for the underlying backend.
137 */
138 void executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>);
139
140protected:
141 GrOpsRenderPass() : fOrigin(kTopLeft_GrSurfaceOrigin), fRenderTarget(nullptr) {}
142
143 GrOpsRenderPass(GrRenderTarget* rt, GrSurfaceOrigin origin)
144 : fOrigin(origin)
145 , fRenderTarget(rt) {
146 }
147
148 void set(GrRenderTarget* rt, GrSurfaceOrigin origin) {
149 SkASSERT(!fRenderTarget);
150
151 fRenderTarget = rt;
152 fOrigin = origin;
153 }
154
155 GrSurfaceOrigin fOrigin;
156 GrRenderTarget* fRenderTarget;
157
158 // Backends may defer binding of certain buffers if their draw API requires a buffer, or if
159 // their bind methods don't support base values.
160 sk_sp<const GrBuffer> fActiveIndexBuffer;
161 sk_sp<const GrBuffer> fActiveVertexBuffer;
162 sk_sp<const GrBuffer> fActiveInstanceBuffer;
163
164private:
165 virtual GrGpu* gpu() = 0;
166
167 void resetActiveBuffers() {
168 fActiveIndexBuffer.reset();
169 fActiveInstanceBuffer.reset();
170 fActiveVertexBuffer.reset();
171 }
172
173 bool prepareToDraw();
174
175 // overridden by backend-specific derived class to perform the rendering command.
176 virtual void onBegin() {}
177 virtual void onEnd() {}
178 virtual bool onBindPipeline(const GrProgramInfo&, const SkRect& drawBounds) = 0;
179 virtual void onSetScissorRect(const SkIRect&) = 0;
180 virtual bool onBindTextures(const GrPrimitiveProcessor&,
181 const GrSurfaceProxy* const primProcTextures[],
182 const GrPipeline&) = 0;
183 virtual void onBindBuffers(sk_sp<const GrBuffer> indexBuffer, sk_sp<const GrBuffer> instanceBuffer,
184 sk_sp<const GrBuffer> vertexBuffer, GrPrimitiveRestart) = 0;
185 virtual void onDraw(int vertexCount, int baseVertex) = 0;
186 virtual void onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue,
187 uint16_t maxIndexValue, int baseVertex) = 0;
188 virtual void onDrawInstanced(int instanceCount, int baseInstance, int vertexCount,
189 int baseVertex) = 0;
190 virtual void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount,
191 int baseInstance, int baseVertex) = 0;
192 virtual void onDrawIndirect(const GrBuffer*, size_t offset, int drawCount) {
193 SK_ABORT("Not implemented."); // Only called if caps.nativeDrawIndirectSupport().
194 }
195 virtual void onDrawIndexedIndirect(const GrBuffer*, size_t offset, int drawCount) {
196 SK_ABORT("Not implemented."); // Only called if caps.nativeDrawIndirectSupport().
197 }
198 virtual void onClear(const GrScissorState&, const SkPMColor4f&) = 0;
199 virtual void onClearStencilClip(const GrScissorState&, bool insideStencilMask) = 0;
200 virtual void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) {}
201
202 enum class DrawPipelineStatus {
203 kOk = 0,
204 kNotConfigured,
205 kFailedToBind
206 };
207
208 DrawPipelineStatus fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured;
209 GrXferBarrierType fXferBarrierType;
210
211#ifdef SK_DEBUG
212 enum class DynamicStateStatus {
213 kDisabled,
214 kUninitialized,
215 kConfigured
216 };
217
218 DynamicStateStatus fScissorStatus;
219 DynamicStateStatus fTextureBindingStatus;
220 bool fHasIndexBuffer;
221 DynamicStateStatus fInstanceBufferStatus;
222 DynamicStateStatus fVertexBufferStatus;
223#endif
224
225 typedef GrOpsRenderPass INHERITED;
226};
227
228#endif
229