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