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 GrBatchBuffer_DEFINED
9 #define GrBatchBuffer_DEFINED
10 
11 #include "GrBufferAllocPool.h"
12 #include "batches/GrVertexBatch.h"
13 
14 class GrResourceProvider;
15 
16 /** Simple class that performs the upload on behalf of a GrBatchUploader. */
17 class GrBatchUploader::TextureUploader {
18 public:
TextureUploader(GrGpu * gpu)19     TextureUploader(GrGpu* gpu) : fGpu(gpu) { SkASSERT(gpu); }
20 
21     /**
22         * Updates the pixels in a rectangle of a texture.
23         *
24         * @param left          left edge of the rectangle to write (inclusive)
25         * @param top           top edge of the rectangle to write (inclusive)
26         * @param width         width of rectangle to write in pixels.
27         * @param height        height of rectangle to write in pixels.
28         * @param config        the pixel config of the source buffer
29         * @param buffer        memory to read pixels from
30         * @param rowBytes      number of bytes between consecutive rows. Zero
31         *                      means rows are tightly packed.
32         */
writeTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes)33     bool writeTexturePixels(GrTexture* texture,
34                             int left, int top, int width, int height,
35                             GrPixelConfig config, const void* buffer,
36                             size_t rowBytes) {
37         return fGpu->writePixels(texture, left, top, width, height, config, buffer, rowBytes);
38     }
39 
40 private:
41     GrGpu* fGpu;
42 };
43 
44 /** Tracks the state across all the GrBatches in a GrDrawTarget flush. */
45 class GrBatchFlushState {
46 public:
47     GrBatchFlushState(GrGpu*, GrResourceProvider*);
48 
~GrBatchFlushState()49     ~GrBatchFlushState() { this->reset(); }
50 
advanceToken()51     void advanceToken() { ++fCurrentToken; }
52 
advanceLastFlushedToken()53     void advanceLastFlushedToken() { ++fLastFlushedToken; }
54 
55     /** Inserts an upload to be executred after all batches in the flush prepared their draws
56         but before the draws are executed to the backend 3D API. */
addASAPUpload(GrBatchUploader * upload)57     void addASAPUpload(GrBatchUploader* upload) {
58         fAsapUploads.push_back().reset(SkRef(upload));
59     }
60 
caps()61     const GrCaps& caps() const { return *fGpu->caps(); }
resourceProvider()62     GrResourceProvider* resourceProvider() const { return fResourceProvider; }
63 
64     /** Has the token been flushed to the backend 3D API. */
hasTokenBeenFlushed(GrBatchToken token)65     bool hasTokenBeenFlushed(GrBatchToken token) const { return fLastFlushedToken >= token; }
66 
67     /** The current token advances once for every contiguous set of uninterrupted draws prepared
68         by a batch. */
currentToken()69     GrBatchToken currentToken() const { return fCurrentToken; }
70 
71     /** The last token flushed to all the way to the backend API. */
lastFlushedToken()72     GrBatchToken lastFlushedToken() const { return fLastFlushedToken; }
73 
74     /** This is a magic token that can be used to indicate that an upload should occur before
75         any draws for any batch in the current flush execute. */
asapToken()76     GrBatchToken asapToken() const { return fLastFlushedToken + 1; }
77 
78     void* makeVertexSpace(size_t vertexSize, int vertexCount,
79                           const GrVertexBuffer** buffer, int* startVertex);
80     uint16_t* makeIndexSpace(int indexCount, const GrIndexBuffer** buffer, int* startIndex);
81 
82     /** This is called after each batch has a chance to prepare its draws and before the draws
83         are issued. */
preIssueDraws()84     void preIssueDraws() {
85         fVertexPool.unmap();
86         fIndexPool.unmap();
87         int uploadCount = fAsapUploads.count();
88         for (int i = 0; i < uploadCount; i++) {
89             fAsapUploads[i]->upload(&fUploader);
90         }
91         fAsapUploads.reset();
92     }
93 
putBackIndices(size_t indices)94     void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
95 
putBackVertexSpace(size_t sizeInBytes)96     void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); }
97 
uploader()98     GrBatchUploader::TextureUploader* uploader() { return &fUploader; }
99 
gpu()100     GrGpu* gpu() { return fGpu; }
101 
reset()102     void reset() {
103         fVertexPool.reset();
104         fIndexPool.reset();
105     }
106 
107 private:
108     GrGpu*                                          fGpu;
109     GrBatchUploader::TextureUploader                fUploader;
110 
111     GrResourceProvider*                             fResourceProvider;
112 
113     GrVertexBufferAllocPool                         fVertexPool;
114     GrIndexBufferAllocPool                          fIndexPool;
115 
116     SkTArray<SkAutoTUnref<GrBatchUploader>, true>   fAsapUploads;
117 
118     GrBatchToken                                    fCurrentToken;
119 
120     GrBatchToken                                    fLastFlushedToken;
121 };
122 
123 /**
124  * GrDrawBatch instances use this object to allocate space for their geometry and to issue the draws
125  * that render their batch.
126  */
127 class GrDrawBatch::Target {
128 public:
Target(GrBatchFlushState * state,GrDrawBatch * batch)129     Target(GrBatchFlushState* state, GrDrawBatch* batch) : fState(state), fBatch(batch) {}
130 
upload(GrBatchUploader * upload)131     void upload(GrBatchUploader* upload) {
132         if (this->asapToken() == upload->lastUploadToken()) {
133             fState->addASAPUpload(upload);
134         } else {
135             fBatch->fInlineUploads.push_back().reset(SkRef(upload));
136         }
137     }
138 
hasTokenBeenFlushed(GrBatchToken token)139     bool hasTokenBeenFlushed(GrBatchToken token) const {
140         return fState->hasTokenBeenFlushed(token);
141     }
currentToken()142     GrBatchToken currentToken() const { return fState->currentToken(); }
asapToken()143     GrBatchToken asapToken() const { return fState->asapToken(); }
144 
caps()145     const GrCaps& caps() const { return fState->caps(); }
146 
resourceProvider()147     GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); }
148 
149 protected:
batch()150     GrDrawBatch* batch() { return fBatch; }
state()151     GrBatchFlushState* state() { return fState; }
152 
153 private:
154     GrBatchFlushState*  fState;
155     GrDrawBatch*        fBatch;
156 };
157 
158 /** Extension of GrDrawBatch::Target for use by GrVertexBatch. Adds the ability to create vertex
159     draws. */
160 class GrVertexBatch::Target : public GrDrawBatch::Target {
161 public:
Target(GrBatchFlushState * state,GrVertexBatch * batch)162     Target(GrBatchFlushState* state, GrVertexBatch* batch) : INHERITED(state, batch) {}
163 
initDraw(const GrPrimitiveProcessor * primProc,const GrPipeline * pipeline)164     void initDraw(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline) {
165         GrVertexBatch::DrawArray* draws = this->vertexBatch()->fDrawArrays.addToTail();
166         draws->fPrimitiveProcessor.reset(primProc);
167         this->state()->advanceToken();
168     }
169 
draw(const GrVertices & vertices)170     void draw(const GrVertices& vertices) {
171         this->vertexBatch()->fDrawArrays.tail()->fDraws.push_back(vertices);
172     }
173 
makeVertexSpace(size_t vertexSize,int vertexCount,const GrVertexBuffer ** buffer,int * startVertex)174     void* makeVertexSpace(size_t vertexSize, int vertexCount,
175                           const GrVertexBuffer** buffer, int* startVertex) {
176         return this->state()->makeVertexSpace(vertexSize, vertexCount, buffer, startVertex);
177     }
178 
makeIndexSpace(int indexCount,const GrIndexBuffer ** buffer,int * startIndex)179     uint16_t* makeIndexSpace(int indexCount, const GrIndexBuffer** buffer, int* startIndex) {
180         return this->state()->makeIndexSpace(indexCount, buffer, startIndex);
181     }
182 
183     /** Helpers for batches which over-allocate and then return data to the pool. */
putBackIndices(int indices)184     void putBackIndices(int indices) { this->state()->putBackIndices(indices); }
putBackVertices(int vertices,size_t vertexStride)185     void putBackVertices(int vertices, size_t vertexStride) {
186         this->state()->putBackVertexSpace(vertices * vertexStride);
187     }
188 
189 private:
vertexBatch()190     GrVertexBatch* vertexBatch() { return static_cast<GrVertexBatch*>(this->batch()); }
191     typedef GrDrawBatch::Target INHERITED;
192 };
193 
194 #endif
195