blob: 36247471ad1e3246273270ab3f085debee1084a6 [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
17
18#include "GrGpu.h"
19#include "GrMemory.h"
20#include "GrTextStrike.h"
21#include "GrTextureCache.h"
22#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000024#include "GrVertexBuffer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000025
26///////////////////////////////////////////////////////////////////////////////
27
28size_t GrTexture::BytesPerPixel(PixelConfig config) {
29 switch (config) {
30 case kAlpha_8_PixelConfig:
31 case kIndex_8_PixelConfig:
32 return 1;
33 case kRGB_565_PixelConfig:
34 case kRGBA_4444_PixelConfig:
35 return 2;
36 case kRGBA_8888_PixelConfig:
37 case kRGBX_8888_PixelConfig:
38 return 4;
39 default:
40 return 0;
41 }
42}
43
44bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
45 switch (config) {
46 case GrTexture::kRGB_565_PixelConfig:
47 case GrTexture::kRGBX_8888_PixelConfig:
48 return true;
49 default:
50 return false;
51 }
52}
53
54
55///////////////////////////////////////////////////////////////////////////////
56
57extern void gr_run_unittests();
58
59GrGpu::GrGpu() : f8bitPaletteSupport(false),
60 fNPOTTextureSupport(kNone_NPOTTextureType),
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000061 fQuadIndexBuffer(NULL),
62 fUnitSquareVertexBuffer(NULL) {
reed@google.comac10a2d2010-12-22 21:39:39 +000063#if GR_DEBUG
64// gr_run_unittests();
65#endif
66 resetStats();
67}
68
69GrGpu::~GrGpu() {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000070 GrSafeUnref(fQuadIndexBuffer);
71 GrSafeUnref(fUnitSquareVertexBuffer);
reed@google.comac10a2d2010-12-22 21:39:39 +000072}
73
74void GrGpu::resetContext() {
75}
76
77void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000078#if GR_DEBUG
79 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
80#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000081}
82
83///////////////////////////////////////////////////////////////////////////////
84
85bool GrGpu::canDisableBlend() const {
86 if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
87 (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
88 return true;
89 }
90
91 // If we have vertex color without alpha then we can't force blend off
92 if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
93 0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
94 return false;
95 }
96
97 // If the src coef will always be 1...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000098 if (kSA_BlendCoeff != fCurrDrawState.fSrcBlend &&
99 kOne_BlendCoeff != fCurrDrawState.fSrcBlend) {
100 return false;
101 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000102
103 // ...and the dst coef is always 0...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000104 if (kISA_BlendCoeff != fCurrDrawState.fDstBlend &&
105 kZero_BlendCoeff != fCurrDrawState.fDstBlend) {
106 return false;
107 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000108
109 // ...and there isn't a texture with an alpha channel...
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000110 for (int s = 0; s < kNumStages; ++s) {
111 if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
112 GrAssert(NULL != fCurrDrawState.fTextures[s]);
113 GrTexture::PixelConfig config = fCurrDrawState.fTextures[s]->config();
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000114
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000115 if (GrTexture::kRGB_565_PixelConfig != config &&
116 GrTexture::kRGBX_8888_PixelConfig != config) {
117 return false;
118 }
119 }
120 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000121
122 // ...then we disable blend.
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000123 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000124}
125
126///////////////////////////////////////////////////////////////////////////////
127
128static const int MAX_QUADS = 512; // max possible: (1 << 14) - 1;
129
reed@google.com8195f672011-01-12 18:14:28 +0000130GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000131
132static inline void fillIndices(uint16_t* indices, int quadCount) {
133 for (int i = 0; i < quadCount; ++i) {
134 indices[6 * i + 0] = 4 * i + 0;
135 indices[6 * i + 1] = 4 * i + 1;
136 indices[6 * i + 2] = 4 * i + 2;
137 indices[6 * i + 3] = 4 * i + 0;
138 indices[6 * i + 4] = 4 * i + 2;
139 indices[6 * i + 5] = 4 * i + 3;
140 }
141}
142
143const GrIndexBuffer* GrGpu::quadIndexBuffer() const {
144 if (NULL == fQuadIndexBuffer) {
145 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
146 GrGpu* me = const_cast<GrGpu*>(this);
147 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
148 if (NULL != fQuadIndexBuffer) {
149 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
150 if (NULL != indices) {
151 fillIndices(indices, MAX_QUADS);
152 fQuadIndexBuffer->unlock();
153 } else {
154 indices = (uint16_t*)GrMalloc(SIZE);
155 fillIndices(indices, MAX_QUADS);
156 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
157 fQuadIndexBuffer->unref();
158 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000159 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 }
161 GrFree(indices);
162 }
163 }
164 }
165
166 return fQuadIndexBuffer;
167}
168
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000169const GrVertexBuffer* GrGpu::unitSquareVertexBuffer() const {
170 if (NULL == fUnitSquareVertexBuffer) {
171
172 static const GrPoint DATA[] = {
173 GrPoint(0, 0),
174 GrPoint(GR_Scalar1,0),
175 GrPoint(GR_Scalar1,GR_Scalar1),
176 GrPoint(0, GR_Scalar1)
177 };
178 static const size_t SIZE = sizeof(DATA);
179
180 GrGpu* me = const_cast<GrGpu*>(this);
181 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
182 if (NULL != fUnitSquareVertexBuffer) {
183 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
184 fUnitSquareVertexBuffer->unref();
185 fUnitSquareVertexBuffer = NULL;
186 GrCrash("Can't get vertices into buffer!");
187 }
188 }
189 }
190
191 return fUnitSquareVertexBuffer;
192}
193
reed@google.comac10a2d2010-12-22 21:39:39 +0000194int GrGpu::maxQuadsInIndexBuffer() const {
195 return (NULL == this->quadIndexBuffer()) ? 0 : MAX_QUADS;
196}
197
198///////////////////////////////////////////////////////////////////////////////
199
200void GrGpu::clipWillChange(const GrClip& clip) {
201 if (clip != fClip) {
202 fClipState.fClipIsDirty = true;
203 }
204}
205
206bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
207 const GrIRect* r = NULL;
208
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000209 // we check this early because we need a valid
210 // render target to setup stencil clipping
211 // before even going into flushGraphicsState
212 if (NULL == fCurrDrawState.fRenderTarget) {
213 GrAssert(!"No render target bound.");
214 return false;
215 }
216
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
218 fClipState.fClipInStencil = fClip.countRects() > 1;
219
220 if (fClipState.fClipInStencil &&
221 (fClipState.fClipIsDirty ||
222 fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
223
224 AutoStateRestore asr(this);
225 AutoGeometrySrcRestore agsr(this);
226 this->disableState(kClip_StateBit);
227 eraseStencilClip();
228
229 int rectTotal = fClip.countRects();
230 static const int PtsPerRect = 4;
231 // this may be called while geometry is already reserved by the
232 // client. So we use our own vertex array where we avoid malloc
233 // if we have 4 or fewer rects.
234 GrAutoSTMalloc<PtsPerRect * 4, GrPoint> vertices(PtsPerRect *
235 rectTotal);
236 this->setVertexSourceToArray(vertices.get(), 0);
237 int currRect = 0;
238 while (currRect < rectTotal) {
239 int rectCount = GrMin(this->maxQuadsInIndexBuffer(),
240 rectTotal - currRect);
241
242 GrPoint* verts = (GrPoint*)vertices +
243 (currRect * PtsPerRect);
244
245 for (int i = 0; i < rectCount; i++) {
246 GrRect r(fClip.getRects()[i + currRect]);
247 verts = r.setRectFan(verts);
248 }
249 this->setIndexSourceToBuffer(quadIndexBuffer());
250
251 this->setViewMatrix(GrMatrix::I());
252 this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
253 this->drawIndexed(GrGpu::kTriangles_PrimitiveType,
254 currRect * PtsPerRect, 0,
255 rectCount * PtsPerRect, rectCount * 6);
256
257 currRect += rectCount;
258 }
259 fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
260 }
261 fClipState.fClipIsDirty = false;
262 if (!fClipState.fClipInStencil) {
263 r = &fClip.getBounds();
264 }
265 }
266 // Must flush the scissor after graphics state
267 if (!flushGraphicsState(type)) {
268 return false;
269 }
270 flushScissor(r);
271 return true;
272}
273
274
275///////////////////////////////////////////////////////////////////////////////
276
277void GrGpu::drawIndexed(PrimitiveType type,
278 uint32_t startVertex,
279 uint32_t startIndex,
280 uint32_t vertexCount,
281 uint32_t indexCount) {
282 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
283 fReservedGeometry.fLocked);
284 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
285 fReservedGeometry.fLocked);
286
287 if (!setupClipAndFlushState(type)) {
288 return;
289 }
290
291#if GR_COLLECT_STATS
292 fStats.fVertexCnt += vertexCount;
293 fStats.fIndexCnt += indexCount;
294 fStats.fDrawCnt += 1;
295#endif
296
297 setupGeometry(startVertex, startIndex, vertexCount, indexCount);
298
299 drawIndexedHelper(type, startVertex, startIndex,
300 vertexCount, indexCount);
301}
302
303void GrGpu::drawNonIndexed(PrimitiveType type,
304 uint32_t startVertex,
305 uint32_t vertexCount) {
306 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
307 fReservedGeometry.fLocked);
308
309 if (!setupClipAndFlushState(type)) {
310 return;
311 }
312#if GR_COLLECT_STATS
313 fStats.fVertexCnt += vertexCount;
314 fStats.fDrawCnt += 1;
315#endif
316
317 setupGeometry(startVertex, 0, vertexCount, 0);
318
319 drawNonIndexedHelper(type, startVertex, vertexCount);
320}
321
322bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
323 void** vertices,
324 void** indices) {
325 GrAssert((fReservedGeometry.fVertexCount == 0) ||
326 (NULL != vertices));
327 if (NULL != vertices) {
328 *vertices = fVertices.realloc(VertexSize(vertexLayout) *
329 fReservedGeometry.fVertexCount);
330 if (!*vertices && fReservedGeometry.fVertexCount) {
331 return false;
332 }
333 }
334 GrAssert((fReservedGeometry.fIndexCount == 0) ||
335 (NULL != indices));
336 if (NULL != indices) {
337 *indices = fIndices.realloc(sizeof(uint16_t) *
338 fReservedGeometry.fIndexCount);
339 if (!*indices && fReservedGeometry.fIndexCount) {
340 return false;
341 }
342 }
343 return true;
344}
345
346void GrGpu::releaseGeometryHelper() {
347 return;
348}
349
350///////////////////////////////////////////////////////////////////////////////
351
352const GrGpu::Stats& GrGpu::getStats() const {
353 return fStats;
354}
355
356void GrGpu::resetStats() {
357 memset(&fStats, 0, sizeof(fStats));
358}
359
360void GrGpu::printStats() const {
361 if (GR_COLLECT_STATS) {
362 GrPrintf(
363 "-v-------------------------GPU STATS----------------------------v-\n"
364 "Stats collection is: %s\n"
365 "Draws: %04d, Verts: %04d, Indices: %04d\n"
366 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
367 "TexCreates: %04d, RTCreates:%04d\n"
368 "-^--------------------------------------------------------------^-\n",
369 (GR_COLLECT_STATS ? "ON" : "OFF"),
370 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
371 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
372 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
373 }
374}
375
376////////////////////////////////////////////////////////////////////////////////
377
378GrTexture::~GrTexture() {
379 // use this to set a break-point if needed
380// Gr_clz(3);
381}
382
383const GrSamplerState GrSamplerState::gClampNoFilter(
384 GrSamplerState::kClamp_WrapMode,
385 GrSamplerState::kClamp_WrapMode,
386 GrSamplerState::kNormal_SampleMode,
387 false);
388
389
390
391