Index: src/gpu/GrBatchFlushState.h |
diff --git a/src/gpu/GrBatchFlushState.h b/src/gpu/GrBatchFlushState.h |
index be9d790597671b242b3aba2f5df94f883bbc9575..0b2e2bd239450eb1584a69142b391a8c531cd43f 100644 |
--- a/src/gpu/GrBatchFlushState.h |
+++ b/src/gpu/GrBatchFlushState.h |
@@ -13,34 +13,6 @@ |
class GrResourceProvider; |
-/** Simple class that performs the upload on behalf of a GrBatchUploader. */ |
-class GrBatchUploader::TextureUploader { |
-public: |
- TextureUploader(GrGpu* gpu) : fGpu(gpu) { SkASSERT(gpu); } |
- |
- /** |
- * Updates the pixels in a rectangle of a texture. |
- * |
- * @param left left edge of the rectangle to write (inclusive) |
- * @param top top edge of the rectangle to write (inclusive) |
- * @param width width of rectangle to write in pixels. |
- * @param height height of rectangle to write in pixels. |
- * @param config the pixel config of the source buffer |
- * @param buffer memory to read pixels from |
- * @param rowBytes number of bytes between consecutive rows. Zero |
- * means rows are tightly packed. |
- */ |
- bool writeTexturePixels(GrTexture* texture, |
- int left, int top, int width, int height, |
- GrPixelConfig config, const void* buffer, |
- size_t rowBytes) { |
- return fGpu->writePixels(texture, left, top, width, height, config, buffer, rowBytes); |
- } |
- |
-private: |
- GrGpu* fGpu; |
-}; |
- |
/** Tracks the state across all the GrBatches in a GrDrawTarget flush. */ |
class GrBatchFlushState { |
public: |
@@ -48,32 +20,37 @@ public: |
~GrBatchFlushState() { this->reset(); } |
- void advanceToken() { ++fCurrentToken; } |
- |
- void advanceLastFlushedToken() { ++fLastFlushedToken; } |
- |
- /** Inserts an upload to be executred after all batches in the flush prepared their draws |
+ /** Inserts an upload to be executed after all batches in the flush prepared their draws |
but before the draws are executed to the backend 3D API. */ |
- void addASAPUpload(GrBatchUploader* upload) { |
- fAsapUploads.push_back().reset(SkRef(upload)); |
+ void addASAPUpload(GrDrawBatch::DeferredUploadFn&& upload) { |
+ fAsapUploads.emplace_back(std::move(upload)); |
} |
const GrCaps& caps() const { return *fGpu->caps(); } |
GrResourceProvider* resourceProvider() const { return fResourceProvider; } |
/** Has the token been flushed to the backend 3D API. */ |
- bool hasTokenBeenFlushed(GrBatchToken token) const { return fLastFlushedToken >= token; } |
+ bool hasDrawBeenFlushed(GrBatchDrawToken token) const { |
+ return token.fSequenceNumber <= fLastFlushedToken.fSequenceNumber; |
+ } |
+ |
+ /** Issue a token to an operation that is being enqueued. */ |
+ GrBatchDrawToken issueDrawToken() { |
+ return GrBatchDrawToken(++fLastIssuedToken.fSequenceNumber); |
+ } |
- /** The current token advances once for every contiguous set of uninterrupted draws prepared |
- by a batch. */ |
- GrBatchToken currentToken() const { return fCurrentToken; } |
+ /** Call every time a draw that was issued a token is flushed */ |
+ void flushToken() { ++fLastFlushedToken.fSequenceNumber; } |
- /** The last token flushed to all the way to the backend API. */ |
- GrBatchToken lastFlushedToken() const { return fLastFlushedToken; } |
+ /** Gets the next draw token that will be issued. */ |
+ GrBatchDrawToken nextDrawToken() const { |
+ return GrBatchDrawToken(fLastIssuedToken.fSequenceNumber + 1); |
+ } |
- /** This is a magic token that can be used to indicate that an upload should occur before |
- any draws for any batch in the current flush execute. */ |
- GrBatchToken asapToken() const { return fLastFlushedToken + 1; } |
+ /** The last token flushed to all the way to the backend API. */ |
+ GrBatchDrawToken nextTokenToFlush() const { |
+ return GrBatchDrawToken(fLastFlushedToken.fSequenceNumber + 1); |
+ } |
void* makeVertexSpace(size_t vertexSize, int vertexCount, |
const GrBuffer** buffer, int* startVertex); |
@@ -85,18 +62,28 @@ public: |
fVertexPool.unmap(); |
fIndexPool.unmap(); |
int uploadCount = fAsapUploads.count(); |
+ |
for (int i = 0; i < uploadCount; i++) { |
- fAsapUploads[i]->upload(&fUploader); |
+ this->doUpload(fAsapUploads[i]); |
} |
fAsapUploads.reset(); |
} |
+ void doUpload(GrDrawBatch::DeferredUploadFn& upload) { |
+ GrDrawBatch::WritePixelsFn wp = [this] (GrSurface* surface, |
+ int left, int top, int width, int height, |
+ GrPixelConfig config, const void* buffer, |
+ size_t rowBytes) -> bool { |
+ return this->fGpu->writePixels(surface, left, top, width, height, config, buffer, |
+ rowBytes); |
+ }; |
+ upload(wp); |
+ } |
+ |
void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); } |
void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); } |
- GrBatchUploader::TextureUploader* uploader() { return &fUploader; } |
- |
GrGpu* gpu() { return fGpu; } |
void reset() { |
@@ -105,22 +92,44 @@ public: |
} |
private: |
- GrGpu* fGpu; |
- GrBatchUploader::TextureUploader fUploader; |
- GrResourceProvider* fResourceProvider; |
+ GrGpu* fGpu; |
+ |
+ GrResourceProvider* fResourceProvider; |
- GrVertexBufferAllocPool fVertexPool; |
- GrIndexBufferAllocPool fIndexPool; |
+ GrVertexBufferAllocPool fVertexPool; |
+ GrIndexBufferAllocPool fIndexPool; |
- SkTArray<SkAutoTUnref<GrBatchUploader>, true> fAsapUploads; |
+ SkSTArray<4, GrDrawBatch::DeferredUploadFn> fAsapUploads; |
- GrBatchToken fCurrentToken; |
+ GrBatchDrawToken fLastIssuedToken; |
- GrBatchToken fLastFlushedToken; |
+ GrBatchDrawToken fLastFlushedToken; |
}; |
/** |
+ * A word about uploads and tokens: Batches should usually schedule their uploads to occur at the |
+ * begining of a frame whenever possible. These are called ASAP uploads. Of course, this requires |
+ * that there are no draws that have yet to be flushed that rely on the old texture contents. In |
+ * that case the ASAP upload would happen prior to the previous draw causing the draw to read the |
+ * new (wrong) texture data. In that case they should schedule an inline upload. |
+ * |
+ * Batches, in conjunction with helpers such as GrBatchAtlas, can use the token system to know |
+ * what the most recent draw was that referenced a resource (or portion of a resource). Each draw |
+ * is assigned a token. A resource (or portion) can be tagged with the most recent draw's |
+ * token. The target provides a facility for testing whether the draw corresponding to the token |
+ * has been flushed. If it has not been flushed then the batch must perform an inline upload |
+ * instead. When scheduling an inline upload the batch provides the token of the draw that the |
+ * upload must occur before. The upload will then occur between the draw that requires the new |
+ * data but after the token that requires the old data. |
+ * |
+ * TODO: Currently the token/upload interface is spread over GrDrawBatch, GrVertexBatch, |
+ * GrDrawBatch::Target, and GrVertexBatch::Target. However, the interface at the GrDrawBatch |
+ * level is not complete and isn't useful. We should push it down to GrVertexBatch until it |
+ * is required at the GrDrawBatch level. |
+ */ |
+ |
+/** |
* GrDrawBatch instances use this object to allocate space for their geometry and to issue the draws |
* that render their batch. |
*/ |
@@ -128,19 +137,28 @@ class GrDrawBatch::Target { |
public: |
Target(GrBatchFlushState* state, GrDrawBatch* batch) : fState(state), fBatch(batch) {} |
- void upload(GrBatchUploader* upload) { |
- if (this->asapToken() == upload->lastUploadToken()) { |
- fState->addASAPUpload(upload); |
- } else { |
- fBatch->fInlineUploads.push_back().reset(SkRef(upload)); |
- } |
+ /** Returns the token of the draw that this upload will occur before. */ |
+ GrBatchDrawToken addInlineUpload(DeferredUploadFn&& upload) { |
+ fBatch->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken()); |
+ return fBatch->fInlineUploads.back().fUploadBeforeToken; |
+ } |
+ |
+ /** Returns the token of the draw that this upload will occur before. Since ASAP uploads |
+ are done first during a flush, this will be the first token since the most recent |
+ flush. */ |
+ GrBatchDrawToken addAsapUpload(DeferredUploadFn&& upload) { |
+ fState->addASAPUpload(std::move(upload)); |
+ return fState->nextTokenToFlush(); |
} |
- bool hasTokenBeenFlushed(GrBatchToken token) const { |
- return fState->hasTokenBeenFlushed(token); |
+ bool hasDrawBeenFlushed(GrBatchDrawToken token) const { |
+ return fState->hasDrawBeenFlushed(token); |
} |
- GrBatchToken currentToken() const { return fState->currentToken(); } |
- GrBatchToken asapToken() const { return fState->asapToken(); } |
+ |
+ /** Gets the next draw token that will be issued by this target. This can be used by a batch |
+ to record that the next draw it issues will use a resource (e.g. texture) while preparing |
+ that draw. */ |
+ GrBatchDrawToken nextDrawToken() const { return fState->nextDrawToken(); } |
const GrCaps& caps() const { return fState->caps(); } |
@@ -161,15 +179,7 @@ class GrVertexBatch::Target : public GrDrawBatch::Target { |
public: |
Target(GrBatchFlushState* state, GrVertexBatch* batch) : INHERITED(state, batch) {} |
- void initDraw(const GrPrimitiveProcessor* primProc) { |
- GrVertexBatch::DrawArray* draws = this->vertexBatch()->fDrawArrays.addToTail(); |
- draws->fPrimitiveProcessor.reset(primProc); |
- this->state()->advanceToken(); |
- } |
- |
- void draw(const GrMesh& mesh) { |
- this->vertexBatch()->fDrawArrays.tail()->fDraws.push_back(mesh); |
- } |
+ void draw(const GrGeometryProcessor* gp, const GrMesh& mesh); |
void* makeVertexSpace(size_t vertexSize, int vertexCount, |
const GrBuffer** buffer, int* startVertex) { |