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 "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 
     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. */
     27     void addASAPUpload(GrDrawOp::DeferredUploadFn&& upload) {
     28         fAsapUploads.emplace_back(std::move(upload));
     29     }
     30 
     31     const GrCaps& caps() const { return *fGpu->caps(); }
     32     GrResourceProvider* resourceProvider() const { return fResourceProvider; }
     33 
     34     /** Has the token been flushed to the backend 3D API. */
     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. */
     40     GrDrawOpUploadToken issueDrawToken() {
     41         return GrDrawOpUploadToken(++fLastIssuedToken.fSequenceNumber);
     42     }
     43 
     44     /** Call every time a draw that was issued a token is flushed */
     45     void flushToken() { ++fLastFlushedToken.fSequenceNumber; }
     46 
     47     /** Gets the next draw token that will be issued. */
     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. */
     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. */
     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 
     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 
     85     void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
     86 
     87     void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); }
     88 
     89     GrGpuCommandBuffer* commandBuffer() { return fCommandBuffer; }
     90     void setCommandBuffer(GrGpuCommandBuffer* buffer) { fCommandBuffer = buffer; }
     91 
     92     GrGpu* gpu() { return fGpu; }
     93 
     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 
    106     void setDrawOpArgs(DrawOpArgs* opArgs) { fOpArgs = opArgs; }
    107 
    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:
    153     Target(GrOpFlushState* state, GrDrawOp* op) : fState(state), fOp(op) {}
    154 
    155     /** Returns the token of the draw that this upload will occur before. */
    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. */
    164     GrDrawOpUploadToken addAsapUpload(DeferredUploadFn&& upload) {
    165         fState->addASAPUpload(std::move(upload));
    166         return fState->nextTokenToFlush();
    167     }
    168 
    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. */
    176     GrDrawOpUploadToken nextDrawToken() const { return fState->nextDrawToken(); }
    177 
    178     const GrCaps& caps() const { return fState->caps(); }
    179 
    180     GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); }
    181 
    182 protected:
    183     GrDrawOp* op() { return fOp; }
    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:
    195     Target(GrOpFlushState* state, GrMeshDrawOp* op) : INHERITED(state, op) {}
    196 
    197     void draw(const GrGeometryProcessor* gp, const GrMesh& mesh);
    198 
    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 
    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. */
    209     void putBackIndices(int indices) { this->state()->putBackIndices(indices); }
    210     void putBackVertices(int vertices, size_t vertexStride) {
    211         this->state()->putBackVertexSpace(vertices * vertexStride);
    212     }
    213 
    214 private:
    215     GrMeshDrawOp* meshDrawOp() { return static_cast<GrMeshDrawOp*>(this->op()); }
    216     typedef GrDrawOp::Target INHERITED;
    217 };
    218 
    219 #endif
    220