blob: e406f6f38ff0b9b02a4294c1eba448a979edc9a2 [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
95bool GrGpu::canDisableBlend() const {
96 if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
97 (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
98 return true;
99 }
100
101 // If we have vertex color without alpha then we can't force blend off
102 if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
103 0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
104 return false;
105 }
106
107 // If the src coef will always be 1...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000108 if (kSA_BlendCoeff != fCurrDrawState.fSrcBlend &&
109 kOne_BlendCoeff != fCurrDrawState.fSrcBlend) {
110 return false;
111 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000112
113 // ...and the dst coef is always 0...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000114 if (kISA_BlendCoeff != fCurrDrawState.fDstBlend &&
115 kZero_BlendCoeff != fCurrDrawState.fDstBlend) {
116 return false;
117 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000118
119 // ...and there isn't a texture with an alpha channel...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000120 for (int s = 0; s < kNumStages; ++s) {
121 if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
122 GrAssert(NULL != fCurrDrawState.fTextures[s]);
123 GrTexture::PixelConfig config = fCurrDrawState.fTextures[s]->config();
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000124
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000125 if (GrTexture::kRGB_565_PixelConfig != config &&
126 GrTexture::kRGBX_8888_PixelConfig != config) {
127 return false;
128 }
129 }
130 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000131
132 // ...then we disable blend.
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000133 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000134}
135
136///////////////////////////////////////////////////////////////////////////////
137
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000138static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000139
reed@google.com8195f672011-01-12 18:14:28 +0000140GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000141
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000142static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 for (int i = 0; i < quadCount; ++i) {
144 indices[6 * i + 0] = 4 * i + 0;
145 indices[6 * i + 1] = 4 * i + 1;
146 indices[6 * i + 2] = 4 * i + 2;
147 indices[6 * i + 3] = 4 * i + 0;
148 indices[6 * i + 4] = 4 * i + 2;
149 indices[6 * i + 5] = 4 * i + 3;
150 }
151}
152
153const GrIndexBuffer* GrGpu::quadIndexBuffer() const {
154 if (NULL == fQuadIndexBuffer) {
155 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
156 GrGpu* me = const_cast<GrGpu*>(this);
157 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
158 if (NULL != fQuadIndexBuffer) {
159 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
160 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000161 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000162 fQuadIndexBuffer->unlock();
163 } else {
164 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000165 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000166 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
167 fQuadIndexBuffer->unref();
168 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000169 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000170 }
171 GrFree(indices);
172 }
173 }
174 }
175
176 return fQuadIndexBuffer;
177}
178
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000179const GrVertexBuffer* GrGpu::unitSquareVertexBuffer() const {
180 if (NULL == fUnitSquareVertexBuffer) {
181
182 static const GrPoint DATA[] = {
183 GrPoint(0, 0),
184 GrPoint(GR_Scalar1,0),
185 GrPoint(GR_Scalar1,GR_Scalar1),
186 GrPoint(0, GR_Scalar1)
187 };
188 static const size_t SIZE = sizeof(DATA);
189
190 GrGpu* me = const_cast<GrGpu*>(this);
191 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
192 if (NULL != fUnitSquareVertexBuffer) {
193 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
194 fUnitSquareVertexBuffer->unref();
195 fUnitSquareVertexBuffer = NULL;
196 GrCrash("Can't get vertices into buffer!");
197 }
198 }
199 }
200
201 return fUnitSquareVertexBuffer;
202}
203
reed@google.comac10a2d2010-12-22 21:39:39 +0000204int GrGpu::maxQuadsInIndexBuffer() const {
205 return (NULL == this->quadIndexBuffer()) ? 0 : MAX_QUADS;
206}
207
208///////////////////////////////////////////////////////////////////////////////
209
210void GrGpu::clipWillChange(const GrClip& clip) {
211 if (clip != fClip) {
212 fClipState.fClipIsDirty = true;
213 }
214}
215
216bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
217 const GrIRect* r = NULL;
218
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000219 // we check this early because we need a valid
220 // render target to setup stencil clipping
221 // before even going into flushGraphicsState
222 if (NULL == fCurrDrawState.fRenderTarget) {
223 GrAssert(!"No render target bound.");
224 return false;
225 }
226
reed@google.comac10a2d2010-12-22 21:39:39 +0000227 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
228 fClipState.fClipInStencil = fClip.countRects() > 1;
229
230 if (fClipState.fClipInStencil &&
231 (fClipState.fClipIsDirty ||
232 fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
233
234 AutoStateRestore asr(this);
235 AutoGeometrySrcRestore agsr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000236
237 // We have to use setVertexSourceToBuffer (and index) in order
238 // to ensure we correctly restore the client's geom sources.
239 // We tack the clip verts onto the vertex pool but we don't
240 // use the various helper functions because of their side effects.
reed@google.comac10a2d2010-12-22 21:39:39 +0000241
242 int rectTotal = fClip.countRects();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000243 if (NULL == fVertexPool) {
244 fVertexPool = new GrVertexBufferAllocPool(this,
245 true,
246 VERTEX_POOL_VB_SIZE,
247 1);
248 }
249 const GrVertexBuffer* vertexBuffer;
250 int vStart;
251 GrPoint* rectVertices =
252 reinterpret_cast<GrPoint*>(fVertexPool->makeSpace(0,
253 rectTotal * 4,
254 &vertexBuffer,
255 &vStart));
256 for (int r = 0; r < rectTotal; ++r) {
257 const GrIRect& rect = fClip.getRects()[r];
258 rectVertices[4 * r].setIRectFan(rect.fLeft, rect.fTop,
259 rect.fRight, rect.fBottom);
260 }
261 fVertexPool->unlock();
262 this->setVertexSourceToBuffer(0, vertexBuffer);
263 this->setIndexSourceToBuffer(quadIndexBuffer());
264 this->setViewMatrix(GrMatrix::I());
265 // don't clip the clip or recurse!
266 this->disableState(kClip_StateBit);
267 this->eraseStencilClip();
268 this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
reed@google.comac10a2d2010-12-22 21:39:39 +0000269 int currRect = 0;
270 while (currRect < rectTotal) {
271 int rectCount = GrMin(this->maxQuadsInIndexBuffer(),
272 rectTotal - currRect);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000273 this->drawIndexed(kTriangles_PrimitiveType,
274 vStart + currRect * 4,
275 0,
276 rectCount*4,
277 rectCount*6);
reed@google.comac10a2d2010-12-22 21:39:39 +0000278 currRect += rectCount;
279 }
280 fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
281 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000282
reed@google.comac10a2d2010-12-22 21:39:39 +0000283 fClipState.fClipIsDirty = false;
284 if (!fClipState.fClipInStencil) {
285 r = &fClip.getBounds();
286 }
287 }
288 // Must flush the scissor after graphics state
289 if (!flushGraphicsState(type)) {
290 return false;
291 }
292 flushScissor(r);
293 return true;
294}
295
296
297///////////////////////////////////////////////////////////////////////////////
298
299void GrGpu::drawIndexed(PrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000300 int startVertex,
301 int startIndex,
302 int vertexCount,
303 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000304 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
305 fReservedGeometry.fLocked);
306 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
307 fReservedGeometry.fLocked);
308
309 if (!setupClipAndFlushState(type)) {
310 return;
311 }
312
313#if GR_COLLECT_STATS
314 fStats.fVertexCnt += vertexCount;
315 fStats.fIndexCnt += indexCount;
316 fStats.fDrawCnt += 1;
317#endif
318
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000319 int sVertex = startVertex;
320 int sIndex = startIndex;
321 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000322
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000323 drawIndexedHelper(type, sVertex, sIndex,
reed@google.comac10a2d2010-12-22 21:39:39 +0000324 vertexCount, indexCount);
325}
326
327void GrGpu::drawNonIndexed(PrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000328 int startVertex,
329 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000330 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
331 fReservedGeometry.fLocked);
332
333 if (!setupClipAndFlushState(type)) {
334 return;
335 }
336#if GR_COLLECT_STATS
337 fStats.fVertexCnt += vertexCount;
338 fStats.fDrawCnt += 1;
339#endif
340
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000341 int sVertex = startVertex;
342 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000343
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000344 drawNonIndexedHelper(type, sVertex, vertexCount);
345}
346
347void GrGpu::finalizeReservedVertices() {
348 GrAssert(NULL != fVertexPool);
349 fVertexPool->unlock();
350}
351
352void GrGpu::finalizeReservedIndices() {
353 GrAssert(NULL != fIndexPool);
354 fIndexPool->unlock();
355}
356
357void GrGpu::prepareVertexPool() {
358 if (NULL == fVertexPool) {
359 fVertexPool = new GrVertexBufferAllocPool(this, true, VERTEX_POOL_VB_SIZE, 1);
360 } else {
361 fVertexPool->reset();
362 }
363}
364
365void GrGpu::prepareIndexPool() {
366 if (NULL == fVertexPool) {
367 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
368 } else {
369 fIndexPool->reset();
370 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000371}
372
373bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
374 void** vertices,
375 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000376 GrAssert(!fReservedGeometry.fLocked);
377 size_t reservedVertexSpace = 0;
378
379 if (fReservedGeometry.fVertexCount) {
380 GrAssert(NULL != vertices);
381
382 prepareVertexPool();
383
384 *vertices = fVertexPool->makeSpace(vertexLayout,
385 fReservedGeometry.fVertexCount,
386 &fCurrPoolVertexBuffer,
387 &fCurrPoolStartVertex);
388 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 return false;
390 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000391 reservedVertexSpace = VertexSize(vertexLayout) *
392 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000394 if (fReservedGeometry.fIndexCount) {
395 GrAssert(NULL != indices);
396
397 prepareIndexPool();
398
399 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
400 &fCurrPoolIndexBuffer,
401 &fCurrPoolStartIndex);
402 if (NULL == *indices) {
403 fVertexPool->putBack(reservedVertexSpace);
404 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000405 return false;
406 }
407 }
408 return true;
409}
410
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000411void GrGpu::releaseGeometryHelper() {}
412
413void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
414 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
415 prepareVertexPool();
416#if GR_DEBUG
417 bool success =
418#endif
419 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
420 vertexCount,
421 vertexArray,
422 &fCurrPoolVertexBuffer,
423 &fCurrPoolStartVertex);
424 GR_DEBUGASSERT(success);
425}
426
427void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
428 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
429 prepareIndexPool();
430#if GR_DEBUG
431 bool success =
432#endif
433 fIndexPool->appendIndices(indexCount,
434 indexArray,
435 &fCurrPoolIndexBuffer,
436 &fCurrPoolStartIndex);
437 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000438}
439
440///////////////////////////////////////////////////////////////////////////////
441
442const GrGpu::Stats& GrGpu::getStats() const {
443 return fStats;
444}
445
446void GrGpu::resetStats() {
447 memset(&fStats, 0, sizeof(fStats));
448}
449
450void GrGpu::printStats() const {
451 if (GR_COLLECT_STATS) {
452 GrPrintf(
453 "-v-------------------------GPU STATS----------------------------v-\n"
454 "Stats collection is: %s\n"
455 "Draws: %04d, Verts: %04d, Indices: %04d\n"
456 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
457 "TexCreates: %04d, RTCreates:%04d\n"
458 "-^--------------------------------------------------------------^-\n",
459 (GR_COLLECT_STATS ? "ON" : "OFF"),
460 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
461 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
462 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
463 }
464}
465
466////////////////////////////////////////////////////////////////////////////////
467
468GrTexture::~GrTexture() {
469 // use this to set a break-point if needed
470// Gr_clz(3);
471}
472
473const GrSamplerState GrSamplerState::gClampNoFilter(
474 GrSamplerState::kClamp_WrapMode,
475 GrSamplerState::kClamp_WrapMode,
476 GrSamplerState::kNormal_SampleMode,
477 false);
478
479
480
481