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 ~GrOpFlushState()23 ~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. */ addASAPUpload(GrDrawOp::DeferredUploadFn && upload)27 void addASAPUpload(GrDrawOp::DeferredUploadFn&& upload) { 28 fAsapUploads.emplace_back(std::move(upload)); 29 } 30 caps()31 const GrCaps& caps() const { return *fGpu->caps(); } resourceProvider()32 GrResourceProvider* resourceProvider() const { return fResourceProvider; } 33 34 /** Has the token been flushed to the backend 3D API. */ hasDrawBeenFlushed(GrDrawOpUploadToken token)35 bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const { 36 return token.fSequenceNumber <= fLastFlushedToken.fSequenceNumber; 37 } 38 39 /** Issue a token to an operation that is being enqueued. */ issueDrawToken()40 GrDrawOpUploadToken issueDrawToken() { 41 return GrDrawOpUploadToken(++fLastIssuedToken.fSequenceNumber); 42 } 43 44 /** Call every time a draw that was issued a token is flushed */ flushToken()45 void flushToken() { ++fLastFlushedToken.fSequenceNumber; } 46 47 /** Gets the next draw token that will be issued. */ nextDrawToken()48 GrDrawOpUploadToken nextDrawToken() const { 49 return GrDrawOpUploadToken(fLastIssuedToken.fSequenceNumber + 1); 50 } 51 52 /** The last token flushed to all the way to the backend API. */ nextTokenToFlush()53 GrDrawOpUploadToken nextTokenToFlush() const { 54 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. */ preIssueDraws()63 void preIssueDraws() { 64 fVertexPool.unmap(); 65 fIndexPool.unmap(); 66 int uploadCount = fAsapUploads.count(); 67 68 for (int i = 0; i < uploadCount; i++) { 69 this->doUpload(fAsapUploads[i]); 70 } 71 fAsapUploads.reset(); 72 } 73 doUpload(GrDrawOp::DeferredUploadFn & upload)74 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 size_t rowBytes) -> bool { 79 return this->fGpu->writePixels(surface, left, top, width, height, config, buffer, 80 rowBytes); 81 }; 82 upload(wp); 83 } 84 putBackIndices(size_t indices)85 void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); } 86 putBackVertexSpace(size_t sizeInBytes)87 void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); } 88 commandBuffer()89 GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; } setCommandBuffer(GrGpuCommandBuffer * buffer)90 void setCommandBuffer(GrGpuCommandBuffer* buffer) { fCommandBuffer = buffer; } 91 gpu()92 GrGpu* gpu() { return fGpu; } 93 reset()94 void reset() { 95 fVertexPool.reset(); 96 fIndexPool.reset(); 97 } 98 99 /** Additional data required on a per-op basis when executing GrDrawOps. */ 100 struct DrawOpArgs { 101 GrRenderTarget* fRenderTarget; 102 const GrAppliedClip* fAppliedClip; 103 GrXferProcessor::DstTexture fDstTexture; 104 }; 105 setDrawOpArgs(DrawOpArgs * opArgs)106 void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; } 107 drawOpArgs()108 const DrawOpArgs& drawOpArgs() const { 109 SkASSERT(fOpArgs); 110 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: Target(GrOpFlushState * state,GrDrawOp * op)153 Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {} 154 155 /** Returns the token of the draw that this upload will occur before. */ addInlineUpload(DeferredUploadFn && upload)156 GrDrawOpUploadToken addInlineUpload(DeferredUploadFn&& upload) { 157 fOp->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken()); 158 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. */ addAsapUpload(DeferredUploadFn && upload)164 GrDrawOpUploadToken addAsapUpload(DeferredUploadFn&& upload) { 165 fState->addASAPUpload(std::move(upload)); 166 return fState->nextTokenToFlush(); 167 } 168 hasDrawBeenFlushed(GrDrawOpUploadToken token)169 bool hasDrawBeenFlushed(GrDrawOpUploadToken token) const { 170 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. */ nextDrawToken()176 GrDrawOpUploadToken nextDrawToken() const { return fState->nextDrawToken(); } 177 caps()178 const GrCaps& caps() const { return fState->caps(); } 179 resourceProvider()180 GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); } 181 182 protected: op()183 GrDrawOp* op() { return fOp; } state()184 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: Target(GrOpFlushState * state,GrMeshDrawOp * op)195 Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {} 196 197 void draw(const GrGeometryProcessor* gp, const GrMesh& mesh); 198 makeVertexSpace(size_t vertexSize,int vertexCount,const GrBuffer ** buffer,int * startVertex)199 void* makeVertexSpace(size_t vertexSize, int vertexCount, 200 const GrBuffer** buffer, int* startVertex) { 201 return this->state()->makeVertexSpace(vertexSize, vertexCount, buffer, startVertex); 202 } 203 makeIndexSpace(int indexCount,const GrBuffer ** buffer,int * startIndex)204 uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex) { 205 return this->state()->makeIndexSpace(indexCount, buffer, startIndex); 206 } 207 208 /** Helpers for ops which over-allocate and then return data to the pool. */ putBackIndices(int indices)209 void putBackIndices(int indices) { this->state()->putBackIndices(indices); } putBackVertices(int vertices,size_t vertexStride)210 void putBackVertices(int vertices, size_t vertexStride) { 211 this->state()->putBackVertexSpace(vertices * vertexStride); 212 } 213 214 private: meshDrawOp()215 GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); } 216 typedef GrDrawOp::Target INHERITED; 217 }; 218 219 #endif 220