blob: 57d313ce152f98f6c3933c9adb90ab8e6a000af5 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
reed@google.comac10a2d2010-12-22 21:39:39 +000017#include "GrGpu.h"
18#include "GrMemory.h"
19#include "GrTextStrike.h"
20#include "GrTextureCache.h"
21#include "GrClipIterator.h"
22#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000023#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000024#include "GrBufferAllocPool.h"
25
26// probably makes no sense for this to be less than a page
27static size_t VERTEX_POOL_VB_SIZE = 1 << 12;
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29///////////////////////////////////////////////////////////////////////////////
30
31size_t GrTexture::BytesPerPixel(PixelConfig config) {
32 switch (config) {
33 case kAlpha_8_PixelConfig:
34 case kIndex_8_PixelConfig:
35 return 1;
36 case kRGB_565_PixelConfig:
37 case kRGBA_4444_PixelConfig:
38 return 2;
39 case kRGBA_8888_PixelConfig:
40 case kRGBX_8888_PixelConfig:
41 return 4;
42 default:
43 return 0;
44 }
45}
46
47bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
48 switch (config) {
49 case GrTexture::kRGB_565_PixelConfig:
50 case GrTexture::kRGBX_8888_PixelConfig:
51 return true;
52 default:
53 return false;
54 }
55}
56
57
58///////////////////////////////////////////////////////////////////////////////
59
60extern void gr_run_unittests();
61
62GrGpu::GrGpu() : f8bitPaletteSupport(false),
bsalomon@google.com1c13c962011-02-14 16:51:21 +000063 fCurrPoolVertexBuffer(NULL),
64 fCurrPoolStartVertex(0),
65 fCurrPoolIndexBuffer(NULL),
66 fCurrPoolStartIndex(0),
67 fVertexPool(NULL),
68 fIndexPool(NULL),
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000069 fQuadIndexBuffer(NULL),
70 fUnitSquareVertexBuffer(NULL) {
reed@google.comac10a2d2010-12-22 21:39:39 +000071#if GR_DEBUG
72// gr_run_unittests();
73#endif
74 resetStats();
75}
76
77GrGpu::~GrGpu() {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000078 GrSafeUnref(fQuadIndexBuffer);
79 GrSafeUnref(fUnitSquareVertexBuffer);
bsalomon@google.com1c13c962011-02-14 16:51:21 +000080 delete fVertexPool;
81 delete fIndexPool;
reed@google.comac10a2d2010-12-22 21:39:39 +000082}
83
84void GrGpu::resetContext() {
85}
86
87void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000088#if GR_DEBUG
89 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
90#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000091}
92
93///////////////////////////////////////////////////////////////////////////////
94
bsalomon@google.com1c13c962011-02-14 16:51:21 +000095static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +000096
reed@google.com8195f672011-01-12 18:14:28 +000097GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +000098
bsalomon@google.com1c13c962011-02-14 16:51:21 +000099static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 for (int i = 0; i < quadCount; ++i) {
101 indices[6 * i + 0] = 4 * i + 0;
102 indices[6 * i + 1] = 4 * i + 1;
103 indices[6 * i + 2] = 4 * i + 2;
104 indices[6 * i + 3] = 4 * i + 0;
105 indices[6 * i + 4] = 4 * i + 2;
106 indices[6 * i + 5] = 4 * i + 3;
107 }
108}
109
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000110const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000111 if (NULL == fQuadIndexBuffer) {
112 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
113 GrGpu* me = const_cast<GrGpu*>(this);
114 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
115 if (NULL != fQuadIndexBuffer) {
116 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
117 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000118 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000119 fQuadIndexBuffer->unlock();
120 } else {
121 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000122 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000123 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
124 fQuadIndexBuffer->unref();
125 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000126 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000127 }
128 GrFree(indices);
129 }
130 }
131 }
132
133 return fQuadIndexBuffer;
134}
135
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000136const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000137 if (NULL == fUnitSquareVertexBuffer) {
138
139 static const GrPoint DATA[] = {
140 GrPoint(0, 0),
141 GrPoint(GR_Scalar1,0),
142 GrPoint(GR_Scalar1,GR_Scalar1),
143 GrPoint(0, GR_Scalar1)
144 };
145 static const size_t SIZE = sizeof(DATA);
146
147 GrGpu* me = const_cast<GrGpu*>(this);
148 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
149 if (NULL != fUnitSquareVertexBuffer) {
150 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
151 fUnitSquareVertexBuffer->unref();
152 fUnitSquareVertexBuffer = NULL;
153 GrCrash("Can't get vertices into buffer!");
154 }
155 }
156 }
157
158 return fUnitSquareVertexBuffer;
159}
160
reed@google.comac10a2d2010-12-22 21:39:39 +0000161///////////////////////////////////////////////////////////////////////////////
162
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000163void GrGpu::clipWillBeSet(const GrClip& newClip) {
164 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000165 fClipState.fClipIsDirty = true;
166 }
167}
168
169bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
170 const GrIRect* r = NULL;
171
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000172 // we check this early because we need a valid
173 // render target to setup stencil clipping
174 // before even going into flushGraphicsState
175 if (NULL == fCurrDrawState.fRenderTarget) {
176 GrAssert(!"No render target bound.");
177 return false;
178 }
179
reed@google.comac10a2d2010-12-22 21:39:39 +0000180 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
181 fClipState.fClipInStencil = fClip.countRects() > 1;
182
183 if (fClipState.fClipInStencil &&
184 (fClipState.fClipIsDirty ||
185 fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
186
187 AutoStateRestore asr(this);
188 AutoGeometrySrcRestore agsr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000189
190 // We have to use setVertexSourceToBuffer (and index) in order
191 // to ensure we correctly restore the client's geom sources.
192 // We tack the clip verts onto the vertex pool but we don't
193 // use the various helper functions because of their side effects.
reed@google.comac10a2d2010-12-22 21:39:39 +0000194
195 int rectTotal = fClip.countRects();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000196 if (NULL == fVertexPool) {
197 fVertexPool = new GrVertexBufferAllocPool(this,
198 true,
199 VERTEX_POOL_VB_SIZE,
200 1);
201 }
202 const GrVertexBuffer* vertexBuffer;
203 int vStart;
204 GrPoint* rectVertices =
205 reinterpret_cast<GrPoint*>(fVertexPool->makeSpace(0,
206 rectTotal * 4,
207 &vertexBuffer,
208 &vStart));
209 for (int r = 0; r < rectTotal; ++r) {
210 const GrIRect& rect = fClip.getRects()[r];
211 rectVertices[4 * r].setIRectFan(rect.fLeft, rect.fTop,
212 rect.fRight, rect.fBottom);
213 }
214 fVertexPool->unlock();
215 this->setVertexSourceToBuffer(0, vertexBuffer);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000216 this->setIndexSourceToBuffer(getQuadIndexBuffer());
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000217 this->setViewMatrix(GrMatrix::I());
218 // don't clip the clip or recurse!
219 this->disableState(kClip_StateBit);
220 this->eraseStencilClip();
221 this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 int currRect = 0;
223 while (currRect < rectTotal) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000224 int rectCount = GrMin(MAX_QUADS,
reed@google.comac10a2d2010-12-22 21:39:39 +0000225 rectTotal - currRect);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000226 this->drawIndexed(kTriangles_PrimitiveType,
227 vStart + currRect * 4,
228 0,
229 rectCount*4,
230 rectCount*6);
reed@google.comac10a2d2010-12-22 21:39:39 +0000231 currRect += rectCount;
232 }
233 fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
234 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000235
reed@google.comac10a2d2010-12-22 21:39:39 +0000236 fClipState.fClipIsDirty = false;
237 if (!fClipState.fClipInStencil) {
238 r = &fClip.getBounds();
239 }
240 }
241 // Must flush the scissor after graphics state
242 if (!flushGraphicsState(type)) {
243 return false;
244 }
245 flushScissor(r);
246 return true;
247}
248
249
250///////////////////////////////////////////////////////////////////////////////
251
252void GrGpu::drawIndexed(PrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000253 int startVertex,
254 int startIndex,
255 int vertexCount,
256 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000257 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
258 fReservedGeometry.fLocked);
259 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
260 fReservedGeometry.fLocked);
261
262 if (!setupClipAndFlushState(type)) {
263 return;
264 }
265
266#if GR_COLLECT_STATS
267 fStats.fVertexCnt += vertexCount;
268 fStats.fIndexCnt += indexCount;
269 fStats.fDrawCnt += 1;
270#endif
271
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000272 int sVertex = startVertex;
273 int sIndex = startIndex;
274 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000275
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000276 drawIndexedHelper(type, sVertex, sIndex,
reed@google.comac10a2d2010-12-22 21:39:39 +0000277 vertexCount, indexCount);
278}
279
280void GrGpu::drawNonIndexed(PrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000281 int startVertex,
282 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
284 fReservedGeometry.fLocked);
285
286 if (!setupClipAndFlushState(type)) {
287 return;
288 }
289#if GR_COLLECT_STATS
290 fStats.fVertexCnt += vertexCount;
291 fStats.fDrawCnt += 1;
292#endif
293
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000294 int sVertex = startVertex;
295 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000296
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000297 drawNonIndexedHelper(type, sVertex, vertexCount);
298}
299
300void GrGpu::finalizeReservedVertices() {
301 GrAssert(NULL != fVertexPool);
302 fVertexPool->unlock();
303}
304
305void GrGpu::finalizeReservedIndices() {
306 GrAssert(NULL != fIndexPool);
307 fIndexPool->unlock();
308}
309
310void GrGpu::prepareVertexPool() {
311 if (NULL == fVertexPool) {
312 fVertexPool = new GrVertexBufferAllocPool(this, true, VERTEX_POOL_VB_SIZE, 1);
313 } else {
314 fVertexPool->reset();
315 }
316}
317
318void GrGpu::prepareIndexPool() {
319 if (NULL == fVertexPool) {
320 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
321 } else {
322 fIndexPool->reset();
323 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000324}
325
326bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
327 void** vertices,
328 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000329 GrAssert(!fReservedGeometry.fLocked);
330 size_t reservedVertexSpace = 0;
331
332 if (fReservedGeometry.fVertexCount) {
333 GrAssert(NULL != vertices);
334
335 prepareVertexPool();
336
337 *vertices = fVertexPool->makeSpace(vertexLayout,
338 fReservedGeometry.fVertexCount,
339 &fCurrPoolVertexBuffer,
340 &fCurrPoolStartVertex);
341 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000342 return false;
343 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000344 reservedVertexSpace = VertexSize(vertexLayout) *
345 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000346 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000347 if (fReservedGeometry.fIndexCount) {
348 GrAssert(NULL != indices);
349
350 prepareIndexPool();
351
352 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
353 &fCurrPoolIndexBuffer,
354 &fCurrPoolStartIndex);
355 if (NULL == *indices) {
356 fVertexPool->putBack(reservedVertexSpace);
357 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 return false;
359 }
360 }
361 return true;
362}
363
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000364void GrGpu::releaseGeometryHelper() {}
365
366void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
367 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
368 prepareVertexPool();
369#if GR_DEBUG
370 bool success =
371#endif
372 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
373 vertexCount,
374 vertexArray,
375 &fCurrPoolVertexBuffer,
376 &fCurrPoolStartVertex);
377 GR_DEBUGASSERT(success);
378}
379
380void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
381 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
382 prepareIndexPool();
383#if GR_DEBUG
384 bool success =
385#endif
386 fIndexPool->appendIndices(indexCount,
387 indexArray,
388 &fCurrPoolIndexBuffer,
389 &fCurrPoolStartIndex);
390 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000391}
392
393///////////////////////////////////////////////////////////////////////////////
394
395const GrGpu::Stats& GrGpu::getStats() const {
396 return fStats;
397}
398
399void GrGpu::resetStats() {
400 memset(&fStats, 0, sizeof(fStats));
401}
402
403void GrGpu::printStats() const {
404 if (GR_COLLECT_STATS) {
405 GrPrintf(
406 "-v-------------------------GPU STATS----------------------------v-\n"
407 "Stats collection is: %s\n"
408 "Draws: %04d, Verts: %04d, Indices: %04d\n"
409 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
410 "TexCreates: %04d, RTCreates:%04d\n"
411 "-^--------------------------------------------------------------^-\n",
412 (GR_COLLECT_STATS ? "ON" : "OFF"),
413 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
414 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
415 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
416 }
417}
418
419////////////////////////////////////////////////////////////////////////////////
420
421GrTexture::~GrTexture() {
422 // use this to set a break-point if needed
423// Gr_clz(3);
424}
425
426const GrSamplerState GrSamplerState::gClampNoFilter(
427 GrSamplerState::kClamp_WrapMode,
428 GrSamplerState::kClamp_WrapMode,
429 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000430 GrMatrix::I(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000431 false);
432
433
434
435