• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 GrOpFlushState_DEFINED
9 #define GrOpFlushState_DEFINED
10 
11 #include "GrBufferAllocPool.h"
12 #include "SkArenaAlloc.h"
13 #include "ops/GrMeshDrawOp.h"
14 
15 class GrGpu;
16 class GrGpuCommandBuffer;
17 class GrResourceProvider;
18 
19 /** Tracks the state across all the GrOps (really just the GrDrawOps) in a GrOpList flush. */
20 class GrOpFlushState {
21 public:
22     GrOpFlushState(GrGpu*, GrResourceProvider*);
23 
~GrOpFlushState()24     ~GrOpFlushState() { this->reset(); }
25 
26     /** Inserts an upload to be executed after all ops in the flush prepared their draws but before
27         the draws are executed to the backend 3D API. */
addASAPUpload(GrDrawOp::DeferredUploadFn && upload)28     void addASAPUpload(GrDrawOp::DeferredUploadFn&& upload) {
29         fAsapUploads.emplace_back(std::move(upload));
30     }
31 
32     const GrCaps& caps() const;
resourceProvider()33     GrResourceProvider* resourceProvider() const { return fResourceProvider; }
34 
35     /** Has the token been flushed to the backend 3D API. */
hasDrawBeenFlushed(GrDrawOpUploadToken token)36     bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const {
37         return token.fSequenceNumber <= fLastFlushedToken.fSequenceNumber;
38     }
39 
40     /** Issue a token to an operation that is being enqueued. */
issueDrawToken()41     GrDrawOpUploadToken issueDrawToken() {
42         return GrDrawOpUploadToken(++fLastIssuedToken.fSequenceNumber);
43     }
44 
45     /** Call every time a draw that was issued a token is flushed */
flushToken()46     void flushToken() { ++fLastFlushedToken.fSequenceNumber; }
47 
48     /** Gets the next draw token that will be issued. */
nextDrawToken()49     GrDrawOpUploadToken nextDrawToken() const {
50         return GrDrawOpUploadToken(fLastIssuedToken.fSequenceNumber + 1);
51     }
52 
53     /** The last token flushed to all the way to the backend API. */
nextTokenToFlush()54     GrDrawOpUploadToken nextTokenToFlush() const {
55         return GrDrawOpUploadToken(fLastFlushedToken.fSequenceNumber + 1);
56     }
57 
58     void* makeVertexSpace(size_t vertexSize, int vertexCount,
59                           const GrBuffer** buffer, int* startVertex);
60     uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex);
61 
62     void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount,
63                                  const GrBuffer** buffer, int* startVertex, int* actualVertexCount);
64     uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount,
65                                     const GrBuffer** buffer, int* startIndex,
66                                     int* actualIndexCount);
67 
68     /** This is called after each op has a chance to prepare its draws and before the draws are
69         issued. */
preIssueDraws()70     void preIssueDraws() {
71         fVertexPool.unmap();
72         fIndexPool.unmap();
73         int uploadCount = fAsapUploads.count();
74 
75         for (int i = 0; i < uploadCount; i++) {
76             this->doUpload(fAsapUploads[i]);
77         }
78         fAsapUploads.reset();
79     }
80 
81     void doUpload(GrDrawOp::DeferredUploadFn&);
82 
putBackIndices(size_t indices)83     void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
84 
putBackVertexSpace(size_t sizeInBytes)85     void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); }
86 
commandBuffer()87     GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; }
setCommandBuffer(GrGpuCommandBuffer * buffer)88     void setCommandBuffer(GrGpuCommandBuffer* buffer) { fCommandBuffer = buffer; }
89 
gpu()90     GrGpu* gpu() { return fGpu; }
91 
reset()92     void reset() {
93         fVertexPool.reset();
94         fIndexPool.reset();
95         fPipelines.reset();
96     }
97 
98     /** Additional data required on a per-op basis when executing GrDrawOps. */
99     struct DrawOpArgs {
100         GrRenderTarget*           fRenderTarget;
101         const GrAppliedClip*      fAppliedClip;
102         GrXferProcessor::DstProxy fDstProxy;
103     };
104 
setDrawOpArgs(DrawOpArgs * opArgs)105     void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; }
106 
drawOpArgs()107     const DrawOpArgs& drawOpArgs() const {
108         SkASSERT(fOpArgs);
109         return *fOpArgs;
110     }
111 
112     template <typename... Args>
allocPipeline(Args...args)113     GrPipeline* allocPipeline(Args... args) {
114         return fPipelines.make<GrPipeline>(std::forward<Args>(args)...);
115     }
116 
117 private:
118     GrGpu* fGpu;
119     GrResourceProvider* fResourceProvider;
120     GrGpuCommandBuffer* fCommandBuffer;
121     GrVertexBufferAllocPool fVertexPool;
122     GrIndexBufferAllocPool fIndexPool;
123     SkSTArray<4, GrDrawOp::DeferredUploadFn> fAsapUploads;
124     GrDrawOpUploadToken fLastIssuedToken;
125     GrDrawOpUploadToken fLastFlushedToken;
126     DrawOpArgs* fOpArgs;
127     SkArenaAlloc fPipelines{sizeof(GrPipeline) * 100};
128 };
129 
130 /**
131  * A word about uploads and tokens: Ops should usually schedule their uploads to occur at the
132  * begining of a frame whenever possible. These are called ASAP uploads. Of course, this requires
133  * that there are no draws that have yet to be flushed that rely on the old texture contents. In
134  * that case the ASAP upload would happen prior to the previous draw causing the draw to read the
135  * new (wrong) texture data. In that case they should schedule an inline upload.
136  *
137  * Ops, in conjunction with helpers such as GrDrawOpAtlas, can use the token system to know
138  * what the most recent draw was that referenced a resource (or portion of a resource). Each draw
139  * is assigned a token. A resource (or portion) can be tagged with the most recent draw's
140  * token. The target provides a facility for testing whether the draw corresponding to the token
141  * has been flushed. If it has not been flushed then the op must perform an inline upload instead.
142  * When scheduling an inline upload the op provides the token of the draw that the upload must occur
143  * before. The upload will then occur between the draw that requires the new data but after the
144  * token that requires the old data.
145  *
146  * TODO: Currently the token/upload interface is spread over GrDrawOp, GrMeshDrawOp,
147  * GrDrawOp::Target, and GrMeshDrawOp::Target. However, the interface at the GrDrawOp level is not
148  * complete and isn't useful. We should push it down to GrMeshDrawOp until it is required at the
149  * GrDrawOp level.
150  */
151 
152 /**
153  * GrDrawOp instances use this object to allocate space for their geometry and to issue the draws
154  * that render their op.
155  */
156 class GrDrawOp::Target {
157 public:
Target(GrOpFlushState * state,GrDrawOp * op)158     Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {}
159 
160     /** Returns the token of the draw that this upload will occur before. */
addInlineUpload(DeferredUploadFn && upload)161     GrDrawOpUploadToken addInlineUpload(DeferredUploadFn&& upload) {
162         fOp->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken());
163         return fOp->fInlineUploads.back().fUploadBeforeToken;
164     }
165 
166     /** Returns the token of the draw that this upload will occur before. Since ASAP uploads
167         are done first during a flush, this will be the first token since the most recent
168         flush. */
addAsapUpload(DeferredUploadFn && upload)169     GrDrawOpUploadToken addAsapUpload(DeferredUploadFn&& upload) {
170         fState->addASAPUpload(std::move(upload));
171         return fState->nextTokenToFlush();
172     }
173 
hasDrawBeenFlushed(GrDrawOpUploadToken token)174     bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const {
175         return fState->hasDrawBeenFlushed(token);
176     }
177 
178     /** Gets the next draw token that will be issued by this target. This can be used by an op
179         to record that the next draw it issues will use a resource (e.g. texture) while preparing
180         that draw. */
nextDrawToken()181     GrDrawOpUploadToken nextDrawToken() const { return fState->nextDrawToken(); }
182 
caps()183     const GrCaps& caps() const { return fState->caps(); }
184 
resourceProvider()185     GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); }
186 
187 protected:
op()188     GrDrawOp* op() { return fOp; }
state()189     GrOpFlushState* state() { return fState; }
state()190     const GrOpFlushState* state() const { return fState; }
191 
192 private:
193     GrOpFlushState* fState;
194     GrDrawOp* fOp;
195 };
196 
197 /** Extension of GrDrawOp::Target for use by GrMeshDrawOp. Adds the ability to create vertex
198     draws. */
199 class GrMeshDrawOp::Target : public GrDrawOp::Target {
200 public:
Target(GrOpFlushState * state,GrMeshDrawOp * op)201     Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {}
202 
203     void draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, const GrMesh& mesh);
204 
makeVertexSpace(size_t vertexSize,int vertexCount,const GrBuffer ** buffer,int * startVertex)205     void* makeVertexSpace(size_t vertexSize, int vertexCount,
206                           const GrBuffer** buffer, int* startVertex) {
207         return this->state()->makeVertexSpace(vertexSize, vertexCount, buffer, startVertex);
208     }
209 
makeIndexSpace(int indexCount,const GrBuffer ** buffer,int * startIndex)210     uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex) {
211         return this->state()->makeIndexSpace(indexCount, buffer, startIndex);
212     }
213 
makeVertexSpaceAtLeast(size_t vertexSize,int minVertexCount,int fallbackVertexCount,const GrBuffer ** buffer,int * startVertex,int * actualVertexCount)214     void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount,
215                                  const GrBuffer** buffer, int* startVertex,
216                                  int* actualVertexCount) {
217         return this->state()->makeVertexSpaceAtLeast(vertexSize, minVertexCount,
218                                                      fallbackVertexCount, buffer, startVertex,
219                                                      actualVertexCount);
220     }
221 
makeIndexSpaceAtLeast(int minIndexCount,int fallbackIndexCount,const GrBuffer ** buffer,int * startIndex,int * actualIndexCount)222     uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount,
223                                     const GrBuffer** buffer, int* startIndex,
224                                     int* actualIndexCount) {
225         return this->state()->makeIndexSpaceAtLeast(minIndexCount, fallbackIndexCount, buffer,
226                                                     startIndex, actualIndexCount);
227     }
228 
229     /** Helpers for ops which over-allocate and then return data to the pool. */
putBackIndices(int indices)230     void putBackIndices(int indices) { this->state()->putBackIndices(indices); }
putBackVertices(int vertices,size_t vertexStride)231     void putBackVertices(int vertices, size_t vertexStride) {
232         this->state()->putBackVertexSpace(vertices * vertexStride);
233     }
234 
renderTarget()235     GrRenderTarget* renderTarget() const { return this->state()->drawOpArgs().fRenderTarget; }
236 
clip()237     const GrAppliedClip* clip() const { return this->state()->drawOpArgs().fAppliedClip; }
238 
dstProxy()239     const GrXferProcessor::DstProxy& dstProxy() const {
240         return this->state()->drawOpArgs().fDstProxy;
241     }
242 
243     template <typename... Args>
allocPipeline(Args...args)244     GrPipeline* allocPipeline(Args... args) {
245         return this->state()->allocPipeline(std::forward<Args>(args)...);
246     }
247 
248     /**
249      * Helper that makes a pipeline targeting the op's render target that incorporates the op's
250      * GrAppliedClip.
251      * */
makePipeline(uint32_t pipelineFlags,const GrProcessorSet * processorSet)252     GrPipeline* makePipeline(uint32_t pipelineFlags, const GrProcessorSet* processorSet) {
253         GrPipeline::InitArgs pipelineArgs;
254         pipelineArgs.fFlags = pipelineFlags;
255         pipelineArgs.fProcessors = processorSet;
256         pipelineArgs.fRenderTarget = this->renderTarget();
257         pipelineArgs.fAppliedClip = this->clip();
258         pipelineArgs.fDstProxy = this->dstProxy();
259         pipelineArgs.fCaps = &this->caps();
260         pipelineArgs.fResourceProvider = this->resourceProvider();
261         return this->allocPipeline(pipelineArgs);
262     }
263 
264 private:
meshDrawOp()265     GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); }
266     typedef GrDrawOp::Target INHERITED;
267 };
268 
269 #endif
270