blob: 23fa310acb5301a1fa5e4cfa6293f8e58c0aaf53 [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"
jvanverth787cdf92014-12-04 10:46:50 -080010#include "GrFontCache.h"
bsalomon371bcbc2014-12-01 08:19:34 -080011#include "GrGpu.h"
bsalomon371bcbc2014-12-01 08:19:34 -080012#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();
bsalomon371bcbc2014-12-01 08:19:34 -080090
91 fGpu->saveActiveTraceMarkers();
92
93 this->onFlush();
94
95 fGpu->restoreActiveTraceMarkers();
96
97 fFlushing = false;
98 this->reset();
99}
100
101void GrFlushToGpuDrawTarget::willReserveVertexAndIndexSpace(int vertexCount,
102 size_t vertexStride,
103 int indexCount) {
104 // We use geometryHints() to know whether to flush the draw buffer. We
105 // can't flush if we are inside an unbalanced pushGeometrySource.
106 // Moreover, flushing blows away vertex and index data that was
107 // previously reserved. So if the vertex or index data is pulled from
108 // reserved space and won't be released by this request then we can't
109 // flush.
110 bool insideGeoPush = fGeoPoolStateStack.count() > 1;
111
112 bool unreleasedVertexSpace =
113 !vertexCount &&
114 kReserved_GeometrySrcType == this->getGeomSrc().fVertexSrc;
115
116 bool unreleasedIndexSpace =
117 !indexCount &&
118 kReserved_GeometrySrcType == this->getGeomSrc().fIndexSrc;
119
120 int vcount = vertexCount;
121 int icount = indexCount;
122
123 if (!insideGeoPush &&
124 !unreleasedVertexSpace &&
125 !unreleasedIndexSpace &&
126 this->geometryHints(vertexStride, &vcount, &icount)) {
127 this->flush();
128 }
129}
130
131bool GrFlushToGpuDrawTarget::geometryHints(size_t vertexStride,
132 int* vertexCount,
133 int* indexCount) const {
134 // we will recommend a flush if the data could fit in a single
135 // preallocated buffer but none are left and it can't fit
136 // in the current buffer (which may not be prealloced).
137 bool flush = false;
138 if (indexCount) {
139 int32_t currIndices = fIndexPool->currentBufferIndices();
140 if (*indexCount > currIndices &&
141 (!fIndexPool->preallocatedBuffersRemaining() &&
142 *indexCount <= fIndexPool->preallocatedBufferIndices())) {
143
144 flush = true;
145 }
146 *indexCount = currIndices;
147 }
148 if (vertexCount) {
149 int32_t currVertices = fVertexPool->currentBufferVertices(vertexStride);
150 if (*vertexCount > currVertices &&
151 (!fVertexPool->preallocatedBuffersRemaining() &&
152 *vertexCount <= fVertexPool->preallocatedBufferVertices(vertexStride))) {
153
154 flush = true;
155 }
156 *vertexCount = currVertices;
157 }
158 return flush;
159}
160
161bool GrFlushToGpuDrawTarget::onReserveVertexSpace(size_t vertexSize,
162 int vertexCount,
163 void** vertices) {
164 GeometryPoolState& poolState = fGeoPoolStateStack.back();
165 SkASSERT(vertexCount > 0);
166 SkASSERT(vertices);
167 SkASSERT(0 == poolState.fUsedPoolVertexBytes);
168
169 *vertices = fVertexPool->makeSpace(vertexSize,
170 vertexCount,
171 &poolState.fPoolVertexBuffer,
172 &poolState.fPoolStartVertex);
173 return SkToBool(*vertices);
174}
175
176bool GrFlushToGpuDrawTarget::onReserveIndexSpace(int indexCount, void** indices) {
177 GeometryPoolState& poolState = fGeoPoolStateStack.back();
178 SkASSERT(indexCount > 0);
179 SkASSERT(indices);
180 SkASSERT(0 == poolState.fUsedPoolIndexBytes);
181
182 *indices = fIndexPool->makeSpace(indexCount,
183 &poolState.fPoolIndexBuffer,
184 &poolState.fPoolStartIndex);
185 return SkToBool(*indices);
186}
187
188void GrFlushToGpuDrawTarget::releaseReservedVertexSpace() {
189 GeometryPoolState& poolState = fGeoPoolStateStack.back();
190 const GeometrySrcState& geoSrc = this->getGeomSrc();
191
192 // If we get a release vertex space call then our current source should either be reserved
193 // or array (which we copied into reserved space).
194 SkASSERT(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
195
196 // When the caller reserved vertex buffer space we gave it back a pointer
197 // provided by the vertex buffer pool. At each draw we tracked the largest
198 // offset into the pool's pointer that was referenced. Now we return to the
199 // pool any portion at the tail of the allocation that no draw referenced.
200 size_t reservedVertexBytes = geoSrc.fVertexSize * geoSrc.fVertexCount;
201 fVertexPool->putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes);
202 poolState.fUsedPoolVertexBytes = 0;
203 poolState.fPoolVertexBuffer = NULL;
204 poolState.fPoolStartVertex = 0;
205}
206
207void GrFlushToGpuDrawTarget::releaseReservedIndexSpace() {
208 GeometryPoolState& poolState = fGeoPoolStateStack.back();
209 const GeometrySrcState& geoSrc = this->getGeomSrc();
210
211 // If we get a release index space call then our current source should either be reserved
212 // or array (which we copied into reserved space).
213 SkASSERT(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
214
215 // Similar to releaseReservedVertexSpace we return any unused portion at
216 // the tail
217 size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
218 fIndexPool->putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
219 poolState.fUsedPoolIndexBytes = 0;
220 poolState.fPoolIndexBuffer = NULL;
221 poolState.fPoolStartIndex = 0;
222}
223
224void GrFlushToGpuDrawTarget::geometrySourceWillPush() {
225 GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
226 poolState.fUsedPoolVertexBytes = 0;
227 poolState.fUsedPoolIndexBytes = 0;
228#ifdef SK_DEBUG
229 poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
230 poolState.fPoolStartVertex = ~0;
231 poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
232 poolState.fPoolStartIndex = ~0;
233#endif
234}
235
236void GrFlushToGpuDrawTarget::geometrySourceWillPop(const GeometrySrcState& restoredState) {
237 SkASSERT(fGeoPoolStateStack.count() > 1);
238 fGeoPoolStateStack.pop_back();
239 GeometryPoolState& poolState = fGeoPoolStateStack.back();
240 // we have to assume that any slack we had in our vertex/index data
241 // is now unreleasable because data may have been appended later in the
242 // pool.
243 if (kReserved_GeometrySrcType == restoredState.fVertexSrc) {
244 poolState.fUsedPoolVertexBytes = restoredState.fVertexSize * restoredState.fVertexCount;
245 }
246 if (kReserved_GeometrySrcType == restoredState.fIndexSrc) {
247 poolState.fUsedPoolIndexBytes = sizeof(uint16_t) * restoredState.fIndexCount;
248 }
249}
bsalomoneff2c722014-12-02 09:40:12 -0800250
251bool GrFlushToGpuDrawTarget::onCanCopySurface(const GrSurface* dst,
252 const GrSurface* src,
253 const SkIRect& srcRect,
254 const SkIPoint& dstPoint) {
255 return getGpu()->canCopySurface(dst, src, srcRect, dstPoint);
256}
257
258bool GrFlushToGpuDrawTarget::onInitCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) {
259 return getGpu()->initCopySurfaceDstDesc(src, desc);
260}