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 "GrBatchAtlas.h"
12 #include "GrBufferAllocPool.h"
13 #include "GrPendingProgramElement.h"
14 #include "GrPipeline.h"
15 #include "GrTRecorder.h"
16 #include "GrVertices.h"
17 
18 /*
19  * GrBatch instances use this object to allocate space for their geometry and to issue the draws
20  * that render their batch.
21  */
22 class GrBatchTarget : public SkNoncopyable {
23 public:
24     typedef GrBatchAtlas::BatchToken BatchToken;
25     GrBatchTarget(GrGpu* gpu);
26 
initDraw(const GrPrimitiveProcessor * primProc,const GrPipeline * pipeline)27     void initDraw(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline) {
28         GrNEW_APPEND_TO_RECORDER(fFlushBuffer, BufferedFlush, (primProc, pipeline));
29         fNumberOfDraws++;
30         fCurrentToken++;
31     }
32 
33     class TextureUploader {
34     public:
TextureUploader(GrGpu * gpu)35         TextureUploader(GrGpu* gpu) : fGpu(gpu) { SkASSERT(gpu); }
36 
37         /**
38          * Updates the pixels in a rectangle of a texture.
39          *
40          * @param left          left edge of the rectangle to write (inclusive)
41          * @param top           top edge of the rectangle to write (inclusive)
42          * @param width         width of rectangle to write in pixels.
43          * @param height        height of rectangle to write in pixels.
44          * @param config        the pixel config of the source buffer
45          * @param buffer        memory to read pixels from
46          * @param rowBytes      number of bytes between consecutive rows. Zero
47          *                      means rows are tightly packed.
48          */
writeTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t rowBytes)49         bool writeTexturePixels(GrTexture* texture,
50                                 int left, int top, int width, int height,
51                                 GrPixelConfig config, const void* buffer,
52                                 size_t rowBytes) {
53             return fGpu->writeTexturePixels(texture, left, top, width, height, config, buffer,
54                                             rowBytes);
55         }
56 
57     private:
58         GrGpu* fGpu;
59     };
60 
61     class Uploader : public SkRefCnt {
62     public:
Uploader(BatchToken lastUploadToken)63         Uploader(BatchToken lastUploadToken) : fLastUploadToken(lastUploadToken) {}
lastUploadToken()64         BatchToken lastUploadToken() const { return fLastUploadToken; }
65         virtual void upload(TextureUploader)=0;
66 
67     private:
68         BatchToken fLastUploadToken;
69     };
70 
upload(Uploader * upload)71     void upload(Uploader* upload) {
72         if (this->asapToken() == upload->lastUploadToken()) {
73             fAsapUploads.push_back().reset(SkRef(upload));
74         } else {
75             fInlineUploads.push_back().reset(SkRef(upload));
76         }
77     }
78 
draw(const GrVertices & vertices)79     void draw(const GrVertices& vertices) {
80         fFlushBuffer.back().fVertexDraws.push_back(vertices);
81     }
82 
isIssued(BatchToken token)83     bool isIssued(BatchToken token) const { return fLastFlushedToken >= token; }
currentToken()84     BatchToken currentToken() const { return fCurrentToken; }
asapToken()85     BatchToken asapToken() const { return fLastFlushedToken + 1; }
86 
87     // TODO much of this complexity goes away when batch is everywhere
resetNumberOfDraws()88     void resetNumberOfDraws() { fNumberOfDraws = 0; }
numberOfDraws()89     int numberOfDraws() const { return fNumberOfDraws; }
preFlush()90     void preFlush() {
91         this->unmapVertexAndIndexBuffers();
92         int updateCount = fAsapUploads.count();
93         for (int i = 0; i < updateCount; i++) {
94             fAsapUploads[i]->upload(TextureUploader(fGpu));
95         }
96         fInlineUpdatesIndex = 0;
97         fIter = FlushBuffer::Iter(fFlushBuffer);
98     }
99     void flushNext(int n);
postFlush()100     void postFlush() {
101         SkASSERT(!fIter.next());
102         fFlushBuffer.reset();
103         fAsapUploads.reset();
104         fInlineUploads.reset();
105     }
106 
107     // TODO This goes away when everything uses batch
currentBatchTracker()108     GrBatchTracker* currentBatchTracker() {
109         SkASSERT(!fFlushBuffer.empty());
110         return &fFlushBuffer.back().fBatchTracker;
111     }
112 
caps()113     const GrDrawTargetCaps& caps() const { return *fGpu->caps(); }
114 
resourceProvider()115     GrResourceProvider* resourceProvider() const { return fGpu->getContext()->resourceProvider(); }
116 
117     void* makeVertSpace(size_t vertexSize, int vertexCount,
118                         const GrVertexBuffer** buffer, int* startVertex);
119     uint16_t* makeIndexSpace(int indexCount,
120                              const GrIndexBuffer** buffer, int* startIndex);
121 
122     // A helper for draws which overallocate and then return data to the pool
putBackIndices(size_t indices)123     void putBackIndices(size_t indices) { fIndexPool->putBack(indices * sizeof(uint16_t)); }
124 
putBackVertices(size_t vertices,size_t vertexStride)125     void putBackVertices(size_t vertices, size_t vertexStride) {
126         fVertexPool->putBack(vertices * vertexStride);
127     }
128 
reset()129     void reset() {
130         fVertexPool->reset();
131         fIndexPool->reset();
132     }
133 
134 private:
unmapVertexAndIndexBuffers()135     void unmapVertexAndIndexBuffers() {
136         fVertexPool->unmap();
137         fIndexPool->unmap();
138     }
139 
140     GrGpu* fGpu;
141     SkAutoTDelete<GrVertexBufferAllocPool> fVertexPool;
142     SkAutoTDelete<GrIndexBufferAllocPool> fIndexPool;
143 
144     typedef void* TBufferAlign; // This wouldn't be enough align if a command used long double.
145 
146     struct BufferedFlush {
BufferedFlushBufferedFlush147         BufferedFlush(const GrPrimitiveProcessor* primProc, const GrPipeline* pipeline)
148             : fPrimitiveProcessor(primProc)
149             , fPipeline(pipeline) {}
150         typedef GrPendingProgramElement<const GrPrimitiveProcessor> ProgramPrimitiveProcessor;
151         ProgramPrimitiveProcessor fPrimitiveProcessor;
152         const GrPipeline* fPipeline;
153         GrBatchTracker fBatchTracker;
154         SkSTArray<1, GrVertices, true> fVertexDraws;
155     };
156 
157     enum {
158         kFlushBufferInitialSizeInBytes = 8 * sizeof(BufferedFlush),
159     };
160 
161     typedef GrTRecorder<BufferedFlush, TBufferAlign> FlushBuffer;
162 
163     FlushBuffer fFlushBuffer;
164     // TODO this is temporary
165     FlushBuffer::Iter fIter;
166     int fNumberOfDraws;
167     BatchToken fCurrentToken;
168     BatchToken fLastFlushedToken; // The next token to be flushed
169     SkTArray<SkAutoTUnref<Uploader>, true> fAsapUploads;
170     SkTArray<SkAutoTUnref<Uploader>, true> fInlineUploads;
171     int fInlineUpdatesIndex;
172 };
173 
174 #endif
175