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