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