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
14class GrResourceProvider;
15
16/** Simple class that performs the upload on behalf of a GrBatchUploader. */
17class GrBatchUploader::TextureUploader {
18public:
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        */
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
40private:
41    GrGpu* fGpu;
42};
43
44/** Tracks the state across all the GrBatches in a GrDrawTarget flush. */
45class GrBatchFlushState {
46public:
47    GrBatchFlushState(GrGpu*, GrResourceProvider*);
48
49    ~GrBatchFlushState() { this->reset(); }
50
51    void advanceToken() { ++fCurrentToken; }
52
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. */
57    void addASAPUpload(GrBatchUploader* upload) {
58        fAsapUploads.push_back().reset(SkRef(upload));
59    }
60
61    const GrCaps& caps() const { return *fGpu->caps(); }
62    GrResourceProvider* resourceProvider() const { return fResourceProvider; }
63
64    /** Has the token been flushed to the backend 3D API. */
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. */
69    GrBatchToken currentToken() const { return fCurrentToken; }
70
71    /** The last token flushed to all the way to the backend API. */
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. */
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. */
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
94    void putBackIndices(size_t indices) { fIndexPool.putBack(indices * sizeof(uint16_t)); }
95
96    void putBackVertexSpace(size_t sizeInBytes) { fVertexPool.putBack(sizeInBytes); }
97
98    GrBatchUploader::TextureUploader* uploader() { return &fUploader; }
99
100    GrGpu* gpu() { return fGpu; }
101
102    void reset() {
103        fVertexPool.reset();
104        fIndexPool.reset();
105    }
106
107private:
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 */
127class GrDrawBatch::Target {
128public:
129    Target(GrBatchFlushState* state, GrDrawBatch* batch) : fState(state), fBatch(batch) {}
130
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
139    bool hasTokenBeenFlushed(GrBatchToken token) const {
140        return fState->hasTokenBeenFlushed(token);
141    }
142    GrBatchToken currentToken() const { return fState->currentToken(); }
143    GrBatchToken asapToken() const { return fState->asapToken(); }
144
145    const GrCaps& caps() const { return fState->caps(); }
146
147    GrResourceProvider* resourceProvider() const { return fState->resourceProvider(); }
148
149protected:
150    GrDrawBatch* batch() { return fBatch; }
151    GrBatchFlushState* state() { return fState; }
152
153private:
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. */
160class GrVertexBatch::Target : public GrDrawBatch::Target {
161public:
162    Target(GrBatchFlushState* state, GrVertexBatch* batch) : INHERITED(state, batch) {}
163
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
170    void draw(const GrVertices& vertices) {
171        this->vertexBatch()->fDrawArrays.tail()->fDraws.push_back(vertices);
172    }
173
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
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. */
184    void putBackIndices(int indices) { this->state()->putBackIndices(indices); }
185    void putBackVertices(int vertices, size_t vertexStride) {
186        this->state()->putBackVertexSpace(vertices * vertexStride);
187    }
188
189private:
190    GrVertexBatch* vertexBatch() { return static_cast<GrVertexBatch*>(this->batch()); }
191    typedef GrDrawBatch::Target INHERITED;
192};
193
194#endif
195