Home | History | Annotate | Download | only in gpu
      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 
     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. */
     28     void addASAPUpload(GrDrawOp::DeferredUploadFn&& upload) {
     29         fAsapUploads.emplace_back(std::move(upload));
     30     }
     31 
     32     const GrCaps& caps() const;
     33     GrResourceProvider* resourceProvider() const { return fResourceProvider; }
     34 
     35     /** Has the token been flushed to the backend 3D API. */
     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. */
     41     GrDrawOpUploadToken issueDrawToken() {
     42         return GrDrawOpUploadToken(++fLastIssuedToken.fSequenceNumber);
     43     }
     44 
     45     /** Call every time a draw that was issued a token is flushed */
     46     void flushToken() { ++fLastFlushedToken.fSequenceNumber; }
     47 
     48     /** Gets the next draw token that will be issued. */
     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. */
     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. */
     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 
     83     void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
     84 
     85     void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); }
     86 
     87     GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; }
     88     void setCommandBuffer(GrGpuCommandBuffer* buffer) { fCommandBuffer = buffer; }
     89 
     90     GrGpu* gpu() { return fGpu; }
     91 
     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 
    105     void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; }
    106 
    107     const DrawOpArgs& drawOpArgs() const {
    108         SkASSERT(fOpArgs);
    109         return *fOpArgs;
    110     }
    111 
    112     template <typename... 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:
    158     Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {}
    159 
    160     /** Returns the token of the draw that this upload will occur before. */
    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. */
    169     GrDrawOpUploadToken addAsapUpload(DeferredUploadFn&& upload) {
    170         fState->addASAPUpload(std::move(upload));
    171         return fState->nextTokenToFlush();
    172     }
    173 
    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. */
    181     GrDrawOpUploadToken nextDrawToken() const { return fState->nextDrawToken(); }
    182 
    183     const GrCaps& caps() const { return fState->caps(); }
    184 
    185     GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); }
    186 
    187 protected:
    188     GrDrawOp* op() { return fOp; }
    189     GrOpFlushState* state() { return fState; }
    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:
    201     Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {}
    202 
    203     void draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline, const GrMesh& mesh);
    204 
    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 
    210     uint16_t* makeIndexSpace(int indexCount, const GrBuffer** buffer, int* startIndex) {
    211         return this->state()->makeIndexSpace(indexCount, buffer, startIndex);
    212     }
    213 
    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 
    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. */
    230     void putBackIndices(int indices) { this->state()->putBackIndices(indices); }
    231     void putBackVertices(int vertices, size_t vertexStride) {
    232         this->state()->putBackVertexSpace(vertices * vertexStride);
    233     }
    234 
    235     GrRenderTarget* renderTarget() const { return this->state()->drawOpArgs().fRenderTarget; }
    236 
    237     const GrAppliedClip* clip() const { return this->state()->drawOpArgs().fAppliedClip; }
    238 
    239     const GrXferProcessor::DstProxy& dstProxy() const {
    240         return this->state()->drawOpArgs().fDstProxy;
    241     }
    242 
    243     template <typename... 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      * */
    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:
    265     GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); }
    266     typedef GrDrawOp::Target INHERITED;
    267 };
    268 
    269 #endif
    270