blob: c6340bdc0b5d68a59617d9cbe105925ebb92be23 [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[]) {
77// GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
78}
79
80///////////////////////////////////////////////////////////////////////////////
81
82bool GrGpu::canDisableBlend() const {
83 if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
84 (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
85 return true;
86 }
87
88 // If we have vertex color without alpha then we can't force blend off
89 if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
90 0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
91 return false;
92 }
93
94 // If the src coef will always be 1...
95 bool fullSrc = kSA_BlendCoeff == fCurrDrawState.fSrcBlend ||
96 kOne_BlendCoeff == fCurrDrawState.fSrcBlend;
97
98 // ...and the dst coef is always 0...
99 bool noDst = kISA_BlendCoeff == fCurrDrawState.fDstBlend ||
100 kZero_BlendCoeff == fCurrDrawState.fDstBlend;
101
102 // ...and there isn't a texture with an alpha channel...
103 bool noTexAlpha = !VertexHasTexCoords(fGeometrySrc.fVertexLayout) ||
104 fCurrDrawState.fTexture->config() == GrTexture::kRGB_565_PixelConfig ||
105 fCurrDrawState.fTexture->config() == GrTexture::kRGBX_8888_PixelConfig;
106
107 // ...then we disable blend.
108 return fullSrc && noDst && noTexAlpha;
109}
110
111///////////////////////////////////////////////////////////////////////////////
112
113static const int MAX_QUADS = 512; // max possible: (1 << 14) - 1;
114
115GR_STATIC_ASSERT(4 * MAX_QUADS <= UINT16_MAX);
116
117static inline void fillIndices(uint16_t* indices, int quadCount) {
118 for (int i = 0; i < quadCount; ++i) {
119 indices[6 * i + 0] = 4 * i + 0;
120 indices[6 * i + 1] = 4 * i + 1;
121 indices[6 * i + 2] = 4 * i + 2;
122 indices[6 * i + 3] = 4 * i + 0;
123 indices[6 * i + 4] = 4 * i + 2;
124 indices[6 * i + 5] = 4 * i + 3;
125 }
126}
127
128const GrIndexBuffer* GrGpu::quadIndexBuffer() const {
129 if (NULL == fQuadIndexBuffer) {
130 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
131 GrGpu* me = const_cast<GrGpu*>(this);
132 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
133 if (NULL != fQuadIndexBuffer) {
134 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
135 if (NULL != indices) {
136 fillIndices(indices, MAX_QUADS);
137 fQuadIndexBuffer->unlock();
138 } else {
139 indices = (uint16_t*)GrMalloc(SIZE);
140 fillIndices(indices, MAX_QUADS);
141 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
142 fQuadIndexBuffer->unref();
143 fQuadIndexBuffer = NULL;
144 GrAssert(!"Can't get indices into buffer!");
145 }
146 GrFree(indices);
147 }
148 }
149 }
150
151 return fQuadIndexBuffer;
152}
153
154int GrGpu::maxQuadsInIndexBuffer() const {
155 return (NULL == this->quadIndexBuffer()) ? 0 : MAX_QUADS;
156}
157
158///////////////////////////////////////////////////////////////////////////////
159
160void GrGpu::clipWillChange(const GrClip& clip) {
161 if (clip != fClip) {
162 fClipState.fClipIsDirty = true;
163 }
164}
165
166bool GrGpu::setupClipAndFlushState(PrimitiveType type) {
167 const GrIRect* r = NULL;
168
169 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
170 fClipState.fClipInStencil = fClip.countRects() > 1;
171
172 if (fClipState.fClipInStencil &&
173 (fClipState.fClipIsDirty ||
174 fClipState.fStencilClipTarget != fCurrDrawState.fRenderTarget)) {
175
176 AutoStateRestore asr(this);
177 AutoGeometrySrcRestore agsr(this);
178 this->disableState(kClip_StateBit);
179 eraseStencilClip();
180
181 int rectTotal = fClip.countRects();
182 static const int PtsPerRect = 4;
183 // this may be called while geometry is already reserved by the
184 // client. So we use our own vertex array where we avoid malloc
185 // if we have 4 or fewer rects.
186 GrAutoSTMalloc<PtsPerRect * 4, GrPoint> vertices(PtsPerRect *
187 rectTotal);
188 this->setVertexSourceToArray(vertices.get(), 0);
189 int currRect = 0;
190 while (currRect < rectTotal) {
191 int rectCount = GrMin(this->maxQuadsInIndexBuffer(),
192 rectTotal - currRect);
193
194 GrPoint* verts = (GrPoint*)vertices +
195 (currRect * PtsPerRect);
196
197 for (int i = 0; i < rectCount; i++) {
198 GrRect r(fClip.getRects()[i + currRect]);
199 verts = r.setRectFan(verts);
200 }
201 this->setIndexSourceToBuffer(quadIndexBuffer());
202
203 this->setViewMatrix(GrMatrix::I());
204 this->setStencilPass((GrDrawTarget::StencilPass)kSetClip_StencilPass);
205 this->drawIndexed(GrGpu::kTriangles_PrimitiveType,
206 currRect * PtsPerRect, 0,
207 rectCount * PtsPerRect, rectCount * 6);
208
209 currRect += rectCount;
210 }
211 fClipState.fStencilClipTarget = fCurrDrawState.fRenderTarget;
212 }
213 fClipState.fClipIsDirty = false;
214 if (!fClipState.fClipInStencil) {
215 r = &fClip.getBounds();
216 }
217 }
218 // Must flush the scissor after graphics state
219 if (!flushGraphicsState(type)) {
220 return false;
221 }
222 flushScissor(r);
223 return true;
224}
225
226
227///////////////////////////////////////////////////////////////////////////////
228
229void GrGpu::drawIndexed(PrimitiveType type,
230 uint32_t startVertex,
231 uint32_t startIndex,
232 uint32_t vertexCount,
233 uint32_t indexCount) {
234 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
235 fReservedGeometry.fLocked);
236 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
237 fReservedGeometry.fLocked);
238
239 if (!setupClipAndFlushState(type)) {
240 return;
241 }
242
243#if GR_COLLECT_STATS
244 fStats.fVertexCnt += vertexCount;
245 fStats.fIndexCnt += indexCount;
246 fStats.fDrawCnt += 1;
247#endif
248
249 setupGeometry(startVertex, startIndex, vertexCount, indexCount);
250
251 drawIndexedHelper(type, startVertex, startIndex,
252 vertexCount, indexCount);
253}
254
255void GrGpu::drawNonIndexed(PrimitiveType type,
256 uint32_t startVertex,
257 uint32_t vertexCount) {
258 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
259 fReservedGeometry.fLocked);
260
261 if (!setupClipAndFlushState(type)) {
262 return;
263 }
264#if GR_COLLECT_STATS
265 fStats.fVertexCnt += vertexCount;
266 fStats.fDrawCnt += 1;
267#endif
268
269 setupGeometry(startVertex, 0, vertexCount, 0);
270
271 drawNonIndexedHelper(type, startVertex, vertexCount);
272}
273
274bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
275 void** vertices,
276 void** indices) {
277 GrAssert((fReservedGeometry.fVertexCount == 0) ||
278 (NULL != vertices));
279 if (NULL != vertices) {
280 *vertices = fVertices.realloc(VertexSize(vertexLayout) *
281 fReservedGeometry.fVertexCount);
282 if (!*vertices && fReservedGeometry.fVertexCount) {
283 return false;
284 }
285 }
286 GrAssert((fReservedGeometry.fIndexCount == 0) ||
287 (NULL != indices));
288 if (NULL != indices) {
289 *indices = fIndices.realloc(sizeof(uint16_t) *
290 fReservedGeometry.fIndexCount);
291 if (!*indices && fReservedGeometry.fIndexCount) {
292 return false;
293 }
294 }
295 return true;
296}
297
298void GrGpu::releaseGeometryHelper() {
299 return;
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304const GrGpu::Stats& GrGpu::getStats() const {
305 return fStats;
306}
307
308void GrGpu::resetStats() {
309 memset(&fStats, 0, sizeof(fStats));
310}
311
312void GrGpu::printStats() const {
313 if (GR_COLLECT_STATS) {
314 GrPrintf(
315 "-v-------------------------GPU STATS----------------------------v-\n"
316 "Stats collection is: %s\n"
317 "Draws: %04d, Verts: %04d, Indices: %04d\n"
318 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
319 "TexCreates: %04d, RTCreates:%04d\n"
320 "-^--------------------------------------------------------------^-\n",
321 (GR_COLLECT_STATS ? "ON" : "OFF"),
322 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
323 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
324 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
325 }
326}
327
328////////////////////////////////////////////////////////////////////////////////
329
330GrTexture::~GrTexture() {
331 // use this to set a break-point if needed
332// Gr_clz(3);
333}
334
335const GrSamplerState GrSamplerState::gClampNoFilter(
336 GrSamplerState::kClamp_WrapMode,
337 GrSamplerState::kClamp_WrapMode,
338 GrSamplerState::kNormal_SampleMode,
339 false);
340
341
342
343