blob: b8604684b110f2af1a8c27c11cee7509d346fc62 [file] [log] [blame]
bsalomon371bcbc2014-12-01 08:19:34 -08001/*
2 * Copyright 2014 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#include "GrFlushToGpuDrawTarget.h"
9#include "GrContext.h"
10#include "GrGpu.h"
11#include "GrTextStrike.h"
12#include "GrBufferAllocPool.h"
13
14GrFlushToGpuDrawTarget::GrFlushToGpuDrawTarget(GrGpu* gpu,
15 GrVertexBufferAllocPool* vertexPool,
16 GrIndexBufferAllocPool* indexPool)
17 : INHERITED(gpu->getContext())
18 , fGpu(SkRef(gpu))
19 , fVertexPool(vertexPool)
20 , fIndexPool(indexPool)
21 , fFlushing(false) {
22
23 fCaps.reset(SkRef(fGpu->caps()));
24
25 SkASSERT(vertexPool);
26 SkASSERT(indexPool);
27
28 GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
29 poolState.fUsedPoolVertexBytes = 0;
30 poolState.fUsedPoolIndexBytes = 0;
31#ifdef SK_DEBUG
32 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
33 poolState.fPoolStartVertex = ~0;
34 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
35 poolState.fPoolStartIndex = ~0;
36#endif
37}
38
39GrFlushToGpuDrawTarget::~GrFlushToGpuDrawTarget() {
40 // This must be called by before the GrDrawTarget destructor
41 this->releaseGeometry();
42}
43
44void GrFlushToGpuDrawTarget::setDrawBuffers(DrawInfo* info, size_t vertexStride) {
45 GeometryPoolState& poolState = fGeoPoolStateStack.back();
46 if (kBuffer_GeometrySrcType == this->getGeomSrc().fVertexSrc) {
47 info->setVertexBuffer(this->getGeomSrc().fVertexBuffer);
48 } else {
49 // Update the bytes used since the last reserve-geom request.
50 size_t bytes = (info->vertexCount() + info->startVertex()) * vertexStride;
51 poolState.fUsedPoolVertexBytes = SkTMax(poolState.fUsedPoolVertexBytes, bytes);
52 info->setVertexBuffer(poolState.fPoolVertexBuffer);
53 info->adjustStartVertex(poolState.fPoolStartVertex);
54 }
55
56 if (info->isIndexed()) {
57 if (kBuffer_GeometrySrcType == this->getGeomSrc().fIndexSrc) {
58 info->setIndexBuffer(this->getGeomSrc().fIndexBuffer);
59 } else {
60 // Update the bytes used since the last reserve-geom request.
61 size_t bytes = (info->indexCount() + info->startIndex()) * sizeof(uint16_t);
62 poolState.fUsedPoolIndexBytes = SkTMax(poolState.fUsedPoolIndexBytes, bytes);
63 info->setIndexBuffer(poolState.fPoolIndexBuffer);
64 info->adjustStartIndex(poolState.fPoolStartIndex);
65 }
66 }
67}
68
69void GrFlushToGpuDrawTarget::reset() {
70 SkASSERT(1 == fGeoPoolStateStack.count());
71 this->resetVertexSource();
72 this->resetIndexSource();
73
74 fVertexPool->reset();
75 fIndexPool->reset();
76
77 this->onReset();
78}
79
80void GrFlushToGpuDrawTarget::flush() {
81 SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
82 SkASSERT(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
83
84 if (fFlushing) {
85 return;
86 }
87 fFlushing = true;
88
89 fGpu->getContext()->getFontCache()->updateTextures();
90 fVertexPool->unmap();
91 fIndexPool->unmap();
92
93 fGpu->saveActiveTraceMarkers();
94
95 this->onFlush();
96
97 fGpu->restoreActiveTraceMarkers();
98
99 fFlushing = false;
100 this->reset();
101}
102
103void GrFlushToGpuDrawTarget::willReserveVertexAndIndexSpace(int vertexCount,
104 size_t vertexStride,
105 int indexCount) {
106 // We use geometryHints() to know whether to flush the draw buffer. We
107 // can't flush if we are inside an unbalanced pushGeometrySource.
108 // Moreover, flushing blows away vertex and index data that was
109 // previously reserved. So if the vertex or index data is pulled from
110 // reserved space and won't be released by this request then we can't
111 // flush.
112 bool insideGeoPush = fGeoPoolStateStack.count() > 1;
113
114 bool unreleasedVertexSpace =
115 !vertexCount &&
116 kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc;
117
118 bool unreleasedIndexSpace =
119 !indexCount &&
120 kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc;
121
122 int vcount = vertexCount;
123 int icount = indexCount;
124
125 if (!insideGeoPush &&
126 !unreleasedVertexSpace &&
127 !unreleasedIndexSpace &&
128 this->geometryHints(vertexStride, &vcount, &icount)) {
129 this->flush();
130 }
131}
132
133bool GrFlushToGpuDrawTarget::geometryHints(size_t vertexStride,
134 int* vertexCount,
135 int* indexCount) const {
136 // we will recommend a flush if the data could fit in a single
137 // preallocated buffer but none are left and it can't fit
138 // in the current buffer (which may not be prealloced).
139 bool flush = false;
140 if (indexCount) {
141 int32_t currIndices = fIndexPool->currentBufferIndices();
142 if (*indexCount > currIndices &&
143 (!fIndexPool->preallocatedBuffersRemaining() &&
144 *indexCount <= fIndexPool->preallocatedBufferIndices())) {
145
146 flush = true;
147 }
148 *indexCount = currIndices;
149 }
150 if (vertexCount) {
151 int32_t currVertices = fVertexPool->currentBufferVertices(vertexStride);
152 if (*vertexCount > currVertices &&
153 (!fVertexPool->preallocatedBuffersRemaining() &&
154 *vertexCount <= fVertexPool->preallocatedBufferVertices(vertexStride))) {
155
156 flush = true;
157 }
158 *vertexCount = currVertices;
159 }
160 return flush;
161}
162
163bool GrFlushToGpuDrawTarget::onReserveVertexSpace(size_t vertexSize,
164 int vertexCount,
165 void** vertices) {
166 GeometryPoolState& poolState = fGeoPoolStateStack.back();
167 SkASSERT(vertexCount > 0);
168 SkASSERT(vertices);
169 SkASSERT(0 == poolState.fUsedPoolVertexBytes);
170
171 *vertices = fVertexPool->makeSpace(vertexSize,
172 vertexCount,
173 &poolState.fPoolVertexBuffer,
174 &poolState.fPoolStartVertex);
175 return SkToBool(*vertices);
176}
177
178bool GrFlushToGpuDrawTarget::onReserveIndexSpace(int indexCount, void** indices) {
179 GeometryPoolState& poolState = fGeoPoolStateStack.back();
180 SkASSERT(indexCount > 0);
181 SkASSERT(indices);
182 SkASSERT(0 == poolState.fUsedPoolIndexBytes);
183
184 *indices = fIndexPool->makeSpace(indexCount,
185 &poolState.fPoolIndexBuffer,
186 &poolState.fPoolStartIndex);
187 return SkToBool(*indices);
188}
189
190void GrFlushToGpuDrawTarget::releaseReservedVertexSpace() {
191 GeometryPoolState& poolState = fGeoPoolStateStack.back();
192 const GeometrySrcState& geoSrc = this->getGeomSrc();
193
194 // If we get a release vertex space call then our current source should either be reserved
195 // or array (which we copied into reserved space).
196 SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
197
198 // When the caller reserved vertex buffer space we gave it back a pointer
199 // provided by the vertex buffer pool. At each draw we tracked the largest
200 // offset into the pool's pointer that was referenced. Now we return to the
201 // pool any portion at the tail of the allocation that no draw referenced.
202 size_t reservedVertexBytes = geoSrc.fVertexSize * geoSrc.fVertexCount;
203 fVertexPool->putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes);
204 poolState.fUsedPoolVertexBytes = 0;
205 poolState.fPoolVertexBuffer = NULL;
206 poolState.fPoolStartVertex = 0;
207}
208
209void GrFlushToGpuDrawTarget::releaseReservedIndexSpace() {
210 GeometryPoolState& poolState = fGeoPoolStateStack.back();
211 const GeometrySrcState& geoSrc = this->getGeomSrc();
212
213 // If we get a release index space call then our current source should either be reserved
214 // or array (which we copied into reserved space).
215 SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
216
217 // Similar to releaseReservedVertexSpace we return any unused portion at
218 // the tail
219 size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
220 fIndexPool->putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
221 poolState.fUsedPoolIndexBytes = 0;
222 poolState.fPoolIndexBuffer = NULL;
223 poolState.fPoolStartIndex = 0;
224}
225
226void GrFlushToGpuDrawTarget::geometrySourceWillPush() {
227 GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
228 poolState.fUsedPoolVertexBytes = 0;
229 poolState.fUsedPoolIndexBytes = 0;
230#ifdef SK_DEBUG
231 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
232 poolState.fPoolStartVertex = ~0;
233 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
234 poolState.fPoolStartIndex = ~0;
235#endif
236}
237
238void GrFlushToGpuDrawTarget::geometrySourceWillPop(const GeometrySrcState& restoredState) {
239 SkASSERT(fGeoPoolStateStack.count() > 1);
240 fGeoPoolStateStack.pop_back();
241 GeometryPoolState& poolState = fGeoPoolStateStack.back();
242 // we have to assume that any slack we had in our vertex/index data
243 // is now unreleasable because data may have been appended later in the
244 // pool.
245 if (kReserved_GeometrySrcType == restoredState.fVertexSrc) {
246 poolState.fUsedPoolVertexBytes = restoredState.fVertexSize * restoredState.fVertexCount;
247 }
248 if (kReserved_GeometrySrcType == restoredState.fIndexSrc) {
249 poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * restoredState.fIndexCount;
250 }
251}