diff options
author | 2017-10-31 14:42:10 -0400 | |
---|---|---|
committer | 2017-10-31 19:01:06 +0000 | |
commit | 29b60c9020ce4376df3d31db15d1aa316d640711 (patch) | |
tree | 86748ea86ae5d10f62d1714e0423487ed4e43a4a /src/gpu/GrOpFlushState.h | |
parent | f78b55cb94f4ac89b76a26d5a56d6380aa8fea6b (diff) |
Make deferred upload handling and draw recording be virtual interfaces implemented by GrOpFlushState.
The motivation for this is to allow other clients of GrDrawOpAtlas. Making GrMeshDrawOp::Target also be an abstract interface is somewhat incidental to this goal.
Bug: skia:
Change-Id: I0987adfa8a269aa2ca94147e933a2827d734c1cc
Reviewed-on: https://skia-review.googlesource.com/65121
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu/GrOpFlushState.h')
-rw-r--r-- | src/gpu/GrOpFlushState.h | 276 |
1 files changed, 80 insertions, 196 deletions
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h index 22d0e81fad..bc3986616d 100644 --- a/src/gpu/GrOpFlushState.h +++ b/src/gpu/GrOpFlushState.h @@ -10,6 +10,7 @@ #include "GrAppliedClip.h" #include "GrBufferAllocPool.h" +#include "GrDeferredUpload.h" #include "SkArenaAlloc.h" #include "ops/GrMeshDrawOp.h" @@ -18,74 +19,76 @@ class GrGpuCommandBuffer; class GrGpuRTCommandBuffer; class GrResourceProvider; -/** Tracks the state across all the GrOps (really just the GrDrawOps) in a GrOpList flush. */ -class GrOpFlushState { -public: - GrOpFlushState(GrGpu*, GrResourceProvider*); +// TODO: Store uploads on GrOpFlushState rather than GrDrawOp and remove this. +class GrDrawOp::FlushStateAccess { +private: + friend class GrOpFlushState; - ~GrOpFlushState() { this->reset(); } + explicit FlushStateAccess(GrDrawOp* op) : fOp(op) {} - /** Inserts an upload to be executed after all ops in the flush prepared their draws but before - the draws are executed to the backend 3D API. */ - void addASAPUpload(GrDeferredTextureUploadFn&& upload) { - fAsapUploads.emplace_back(std::move(upload)); + void addInlineUpload(GrDeferredTextureUploadFn&& upload, GrDeferredUploadToken token) { + fOp->fInlineUploads.emplace_back(std::move(upload), token); } - const GrCaps& caps() const; - GrResourceProvider* resourceProvider() const { return fResourceProvider; } + GrDrawOp* fOp; +}; - /** Has the token been flushed to the backend 3D API. */ - bool hasDrawBeenFlushed(GrDeferredUploadToken token) const { - return token.fSequenceNumber <= fLastFlushedToken.fSequenceNumber; - } +// TODO: Store draw related data on GrOpFlushState rather than GrMeshDrawOp and remove this. +class GrMeshDrawOp::FlushStateAccess { +private: + friend class GrOpFlushState; + using QueuedDraw = GrMeshDrawOp::QueuedDraw; - /** Issue a token to an operation that is being enqueued. */ - GrDeferredUploadToken issueDrawToken() { - return GrDeferredUploadToken(++fLastIssuedToken.fSequenceNumber); - } + explicit FlushStateAccess(GrMeshDrawOp* op) : fOp(op) {} - /** Call every time a draw that was issued a token is flushed */ - void flushToken() { ++fLastFlushedToken.fSequenceNumber; } + void addMesh(const GrMesh& mesh) { fOp->fMeshes.push_back(mesh); } - /** Gets the next draw token that will be issued. */ - GrDeferredUploadToken nextDrawToken() const { - return GrDeferredUploadToken(fLastIssuedToken.fSequenceNumber + 1); + QueuedDraw* lastDraw() { + return fOp->fQueuedDraws.empty() ? nullptr : &fOp->fQueuedDraws.back(); } - /** The last token flushed to all the way to the backend API. */ - GrDeferredUploadToken nextTokenToFlush() const { - return GrDeferredUploadToken(fLastFlushedToken.fSequenceNumber + 1); + QueuedDraw* addDraw() { return &fOp->fQueuedDraws.push_back(); } + + GrDeferredUploadToken lastUploadToken() const { + if (fOp->fInlineUploads.empty()) { + return GrDeferredUploadToken::AlreadyFlushedToken(); + } + return fOp->fInlineUploads.back().fUploadBeforeToken; } - void* makeVertexSpace(size_t vertexSize, int vertexCount, - const GrBuffer** buffer, int* startVertex); - uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex); + void setBaseDrawToken(GrDeferredUploadToken token) { fOp->fBaseDrawToken = token; } - void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount, - const GrBuffer** buffer, int* startVertex, int* actualVertexCount); - uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount, - const GrBuffer** buffer, int* startIndex, - int* actualIndexCount); + GrMeshDrawOp* fOp; +}; + +/** Tracks the state across all the GrOps (really just the GrDrawOps) in a GrOpList flush. */ +class GrOpFlushState final : public GrDeferredUploadTarget, public GrMeshDrawOp::Target { +public: + GrOpFlushState(GrGpu*, GrResourceProvider*); + + ~GrOpFlushState() final { this->reset(); } + + /** Issue a token to an operation that is being enqueued. */ + GrDeferredUploadToken issueDrawToken() { return ++fLastIssuedToken; } + + /** Call every time a draw that was issued a token is flushed */ + void flushToken() { ++fLastFlushedToken; } /** This is called after each op has a chance to prepare its draws and before the draws are issued. */ void preIssueDraws() { fVertexPool.unmap(); fIndexPool.unmap(); - int uploadCount = fAsapUploads.count(); + int uploadCount = fASAPUploads.count(); for (int i = 0; i < uploadCount; i++) { - this->doUpload(fAsapUploads[i]); + this->doUpload(fASAPUploads[i]); } - fAsapUploads.reset(); + fASAPUploads.reset(); } void doUpload(GrDeferredTextureUploadFn&); - void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); } - - void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); } - GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; } // Helper function used by Ops that are only called via RenderTargetOpLists GrGpuRTCommandBuffer* rtCommandBuffer(); @@ -99,184 +102,65 @@ public: fPipelines.reset(); } - /** Additional data required on a per-op basis when executing GrDrawOps. */ - struct DrawOpArgs { + /** Additional data required on a per-op basis when executing GrOps. */ + struct OpArgs { GrRenderTarget* renderTarget() const { return fProxy->priv().peekRenderTarget(); } + GrOp* fOp; // TODO: do we still need the dst proxy here? GrRenderTargetProxy* fProxy; GrAppliedClip* fAppliedClip; GrXferProcessor::DstProxy fDstProxy; }; - void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; } + void setOpArgs(OpArgs* opArgs) { fOpArgs = opArgs; } - const DrawOpArgs& drawOpArgs() const { + const OpArgs& drawOpArgs() const { SkASSERT(fOpArgs); + SkASSERT(fOpArgs->fOp); return *fOpArgs; } - GrAppliedClip detachAppliedClip() { - SkASSERT(fOpArgs); - return fOpArgs->fAppliedClip ? std::move(*fOpArgs->fAppliedClip) : GrAppliedClip(); - } + /** Overrides of GrDeferredUploadTarget. */ - template <typename... Args> - GrPipeline* allocPipeline(Args&&... args) { - return fPipelines.make<GrPipeline>(std::forward<Args>(args)...); - } + GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final; + GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) final; + GrDeferredUploadToken nextDrawToken() const final { return fLastIssuedToken.next(); } + GrDeferredUploadToken nextTokenToFlush() const override { return fLastFlushedToken.next(); } + + /** Overrides of GrMeshDrawOp::Target. */ + + void draw(const GrGeometryProcessor*, const GrPipeline*, const GrMesh&) final; + void* makeVertexSpace(size_t vertexSize, int vertexCount, const GrBuffer**, + int* startVertex) final; + uint16_t* makeIndexSpace(int indexCount, const GrBuffer**, int* startIndex) final; + void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount, + const GrBuffer**, int* startVertex, int* actualVertexCount) final; + uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount, const GrBuffer**, + int* startIndex, int* actualIndexCount) final; + void putBackIndices(int indexCount) final; + void putBackVertices(int vertices, size_t vertexStride) final; + GrRenderTargetProxy* proxy() const final { return fOpArgs->fProxy; } + GrAppliedClip detachAppliedClip() final; + const GrXferProcessor::DstProxy& dstProxy() const final { return fOpArgs->fDstProxy; } + GrDeferredUploadTarget* deferredUploadTarget() final { return this; } + const GrCaps& caps() const final; + GrResourceProvider* resourceProvider() const final { return fResourceProvider; } private: + /** GrMeshDrawOp::Target override. */ + SkArenaAlloc* pipelineArena() override { return &fPipelines; } + GrGpu* fGpu; GrResourceProvider* fResourceProvider; GrGpuCommandBuffer* fCommandBuffer; GrVertexBufferAllocPool fVertexPool; GrIndexBufferAllocPool fIndexPool; - SkSTArray<4, GrDeferredTextureUploadFn> fAsapUploads; + SkSTArray<4, GrDeferredTextureUploadFn> fASAPUploads; GrDeferredUploadToken fLastIssuedToken; GrDeferredUploadToken fLastFlushedToken; - DrawOpArgs* fOpArgs; + OpArgs* fOpArgs; SkArenaAlloc fPipelines{sizeof(GrPipeline) * 100}; }; -/** - * A word about uploads and tokens: Ops 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. - * - * Ops, in conjunction with helpers such as GrDrawOpAtlas, 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 op must perform an inline upload instead. - * When scheduling an inline upload the op 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 GrDrawOp, GrMeshDrawOp, - * GrDrawOp::Target, and GrMeshDrawOp::Target. However, the interface at the GrDrawOp level is not - * complete and isn't useful. We should push it down to GrMeshDrawOp until it is required at the - * GrDrawOp level. - */ - -/** - * GrDrawOp instances use this object to allocate space for their geometry and to issue the draws - * that render their op. - */ -class GrDrawOp::Target { -public: - Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {} - - /** Returns the token of the draw that this upload will occur before. */ - GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&& upload) { - fOp->fInlineUploads.emplace_back(std::move(upload), fState->nextDrawToken()); - return fOp->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. */ - GrDeferredUploadToken addAsapUpload(GrDeferredTextureUploadFn&& upload) { - fState->addASAPUpload(std::move(upload)); - return fState->nextTokenToFlush(); - } - - bool hasDrawBeenFlushed(GrDeferredUploadToken token) const { - return fState->hasDrawBeenFlushed(token); - } - - /** Gets the next draw token that will be issued by this target. This can be used by an op - to record that the next draw it issues will use a resource (e.g. texture) while preparing - that draw. */ - GrDeferredUploadToken nextDrawToken() const { return fState->nextDrawToken(); } - - const GrCaps& caps() const { return fState->caps(); } - - GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); } - -protected: - GrDrawOp* op() { return fOp; } - GrOpFlushState* state() { return fState; } - const GrOpFlushState* state() const { return fState; } - -private: - GrOpFlushState* fState; - GrDrawOp* fOp; -}; - -/** Extension of GrDrawOp::Target for use by GrMeshDrawOp. Adds the ability to create vertex - draws. */ -class GrMeshDrawOp::Target : public GrDrawOp::Target { -public: - Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {} - - void draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, const GrMesh& mesh); - - void* makeVertexSpace(size_t vertexSize, int vertexCount, - const GrBuffer** buffer, int* startVertex) { - return this->state()->makeVertexSpace(vertexSize, vertexCount, buffer, startVertex); - } - - uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex) { - return this->state()->makeIndexSpace(indexCount, buffer, startIndex); - } - - void* makeVertexSpaceAtLeast(size_t vertexSize, int minVertexCount, int fallbackVertexCount, - const GrBuffer** buffer, int* startVertex, - int* actualVertexCount) { - return this->state()->makeVertexSpaceAtLeast(vertexSize, minVertexCount, - fallbackVertexCount, buffer, startVertex, - actualVertexCount); - } - - uint16_t* makeIndexSpaceAtLeast(int minIndexCount, int fallbackIndexCount, - const GrBuffer** buffer, int* startIndex, - int* actualIndexCount) { - return this->state()->makeIndexSpaceAtLeast(minIndexCount, fallbackIndexCount, buffer, - startIndex, actualIndexCount); - } - - /** Helpers for ops which over-allocate and then return data to the pool. */ - void putBackIndices(int indices) { this->state()->putBackIndices(indices); } - void putBackVertices(int vertices, size_t vertexStride) { - this->state()->putBackVertexSpace(vertices * vertexStride); - } - - GrRenderTargetProxy* proxy() const { return this->state()->drawOpArgs().fProxy; } - - const GrAppliedClip* clip() const { return this->state()->drawOpArgs().fAppliedClip; } - - GrAppliedClip detachAppliedClip() { return this->state()->detachAppliedClip(); } - - const GrXferProcessor::DstProxy& dstProxy() const { - return this->state()->drawOpArgs().fDstProxy; - } - - template <typename... Args> - GrPipeline* allocPipeline(Args&&... args) { - return this->state()->allocPipeline(std::forward<Args>(args)...); - } - - /** - * Helper that makes a pipeline targeting the op's render target that incorporates the op's - * GrAppliedClip. - * */ - GrPipeline* makePipeline(uint32_t pipelineFlags, GrProcessorSet&& processorSet, - GrAppliedClip&& clip) { - GrPipeline::InitArgs pipelineArgs; - pipelineArgs.fFlags = pipelineFlags; - pipelineArgs.fProxy = this->proxy(); - pipelineArgs.fDstProxy = this->dstProxy(); - pipelineArgs.fCaps = &this->caps(); - pipelineArgs.fResourceProvider = this->resourceProvider(); - return this->allocPipeline(pipelineArgs, std::move(processorSet), std::move(clip)); - } - -private: - GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); } - typedef GrDrawOp::Target INHERITED; -}; - #endif |