blob: 0584e4bf05f607bc86472f22d0b76f672e01f208 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
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#include "GrContext.h"
18#include "GrTypes.h"
19#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
22#include "GrPathIter.h"
23#include "GrClipIterator.h"
24#include "GrIndexBuffer.h"
25#include "GrInOrderDrawBuffer.h"
26#include "GrBufferAllocPool.h"
27#include "GrPathRenderer.h"
28
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000029#define ENABLE_SSAA 0
30
bsalomon@google.com27847de2011-02-22 20:59:41 +000031#define DEFER_TEXT_RENDERING 1
32
33#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
34
35static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
36static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
37
38static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
39static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
40
41// We are currently only batching Text and drawRectToRect, both
42// of which use the quad index buffer.
43static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
44static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
45
46GrContext* GrContext::Create(GrGpu::Engine engine,
47 GrGpu::Platform3DContext context3D) {
48 GrContext* ctx = NULL;
49 GrGpu* fGpu = GrGpu::Create(engine, context3D);
50 if (NULL != fGpu) {
51 ctx = new GrContext(fGpu);
52 fGpu->unref();
53 }
54 return ctx;
55}
56
57GrContext* GrContext::CreateGLShaderContext() {
58 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
59}
60
61GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000068 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000075 // abandon first to so destructors
76 // don't try to free the resources in the API.
77 fGpu->abandonResources();
78
bsalomon@google.com8fe72472011-03-30 21:26:44 +000079 delete fDrawBuffer;
80 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000081
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082 delete fDrawBufferVBAllocPool;
83 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000084
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBufferIBAllocPool;
86 fDrawBufferIBAllocPool = NULL;
87
bsalomon@google.com205d4602011-04-25 12:43:45 +000088 GrSafeSetNull(fAAFillRectIndexBuffer);
89 GrSafeSetNull(fAAStrokeRectIndexBuffer);
90
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 fTextureCache->removeAll();
92 fFontCache->freeAll();
93 fGpu->markContextDirty();
94
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 this->setupDrawBuffer();
96}
97
98void GrContext::resetContext() {
99 fGpu->markContextDirty();
100}
101
102void GrContext::freeGpuResources() {
103 this->flush();
104 fTextureCache->removeAll();
105 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000106}
107
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000108////////////////////////////////////////////////////////////////////////////////
109
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000110enum {
111 kNPOTBit = 0x1,
112 kFilterBit = 0x2,
113 kKeylessBit = 0x4,
114};
115
116bool GrContext::finalizeTextureKey(GrTextureKey* key,
117 const GrSamplerState& sampler,
118 bool keyless) const {
119 uint32_t bits = 0;
120 uint16_t width = key->width();
121 uint16_t height = key->height();
122
123 if (!fGpu->npotTextureTileSupport()) {
124 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
125
126 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
127 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
128
129 if (tiled && !isPow2) {
130 bits |= kNPOTBit;
131 if (sampler.isFilter()) {
132 bits |= kFilterBit;
133 }
134 }
135 }
136
137 if (keyless) {
138 bits |= kKeylessBit;
139 }
140 key->finalize(bits);
141 return 0 != bits;
142}
143
bsalomon@google.com27847de2011-02-22 20:59:41 +0000144GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
145 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000147 return fTextureCache->findAndLock(*key);
148}
149
150static void stretchImage(void* dst,
151 int dstW,
152 int dstH,
153 void* src,
154 int srcW,
155 int srcH,
156 int bpp) {
157 GrFixed dx = (srcW << 16) / dstW;
158 GrFixed dy = (srcH << 16) / dstH;
159
160 GrFixed y = dy >> 1;
161
162 int dstXLimit = dstW*bpp;
163 for (int j = 0; j < dstH; ++j) {
164 GrFixed x = dx >> 1;
165 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
166 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
167 for (int i = 0; i < dstXLimit; i += bpp) {
168 memcpy((uint8_t*) dstRow + i,
169 (uint8_t*) srcRow + (x>>16)*bpp,
170 bpp);
171 x += dx;
172 }
173 y += dy;
174 }
175}
176
177GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
178 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000180 void* srcData, size_t rowBytes) {
181 GrAssert(key->width() == desc.fWidth);
182 GrAssert(key->height() == desc.fHeight);
183
184#if GR_DUMP_TEXTURE_UPLOAD
185 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
186#endif
187
188 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000190 if (special) {
191 GrTextureEntry* clampEntry;
192 GrTextureKey clampKey(*key);
193 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
194
195 if (NULL == clampEntry) {
196 clampEntry = createAndLockTexture(&clampKey,
197 GrSamplerState::ClampNoFilter(),
198 desc, srcData, rowBytes);
199 GrAssert(NULL != clampEntry);
200 if (NULL == clampEntry) {
201 return NULL;
202 }
203 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 GrTextureDesc rtDesc = desc;
205 rtDesc.fFlags = rtDesc.fFlags |
206 kRenderTarget_GrTextureFlagBit |
207 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000208 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
209 fGpu->minRenderTargetWidth()));
210 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
211 fGpu->minRenderTargetHeight()));
212
213 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
214
215 if (NULL != texture) {
216 GrDrawTarget::AutoStateRestore asr(fGpu);
217 fGpu->setRenderTarget(texture->asRenderTarget());
218 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000219 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000220 fGpu->setViewMatrix(GrMatrix::I());
221 fGpu->setAlpha(0xff);
222 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
223 fGpu->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kClip_StateBit |
225 GrDrawTarget::kAntialias_StateBit);
226 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
227 GrSamplerState::kClamp_WrapMode,
228 sampler.isFilter());
229 fGpu->setSamplerState(0, stretchSampler);
230
231 static const GrVertexLayout layout =
232 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
233 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
234
235 if (arg.succeeded()) {
236 GrPoint* verts = (GrPoint*) arg.vertices();
237 verts[0].setIRectFan(0, 0,
238 texture->width(),
239 texture->height(),
240 2*sizeof(GrPoint));
241 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
242 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
243 0, 4);
244 entry = fTextureCache->createAndLock(*key, texture);
245 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000246 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000247 } else {
248 // TODO: Our CPU stretch doesn't filter. But we create separate
249 // stretched textures when the sampler state is either filtered or
250 // not. Either implement filtered stretch blit on CPU or just create
251 // one when FBO case fails.
252
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000253 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254 // no longer need to clamp at min RT size.
255 rtDesc.fWidth = GrNextPow2(desc.fWidth);
256 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000257 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000258 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
259 rtDesc.fWidth *
260 rtDesc.fHeight);
261 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
262 srcData, desc.fWidth, desc.fHeight, bpp);
263
264 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
265
266 GrTexture* texture = fGpu->createTexture(rtDesc,
267 stretchedPixels.get(),
268 stretchedRowBytes);
269 GrAssert(NULL != texture);
270 entry = fTextureCache->createAndLock(*key, texture);
271 }
272 fTextureCache->unlock(clampEntry);
273
274 } else {
275 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
276 if (NULL != texture) {
277 entry = fTextureCache->createAndLock(*key, texture);
278 } else {
279 entry = NULL;
280 }
281 }
282 return entry;
283}
284
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000285GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000286 uint32_t p0 = desc.fFormat;
287 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
288 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000289 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
290
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000291 GrTextureEntry* entry = fTextureCache->findAndLock(key);
292 if (NULL == entry) {
293 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
294 if (NULL != texture) {
295 entry = fTextureCache->createAndLock(key, texture);
296 }
297 }
298 // If the caller gives us the same desc/sampler twice we don't want
299 // to return the same texture the second time (unless it was previously
300 // released). So we detach the entry from the cache and reattach at release.
301 if (NULL != entry) {
302 fTextureCache->detach(entry);
303 }
304 return entry;
305}
306
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 if (kKeylessBit & entry->key().getPrivateBits()) {
309 fTextureCache->reattachAndUnlock(entry);
310 } else {
311 fTextureCache->unlock(entry);
312 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000313}
314
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000315GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000316 void* srcData,
317 size_t rowBytes) {
318 return fGpu->createTexture(desc, srcData, rowBytes);
319}
320
321void GrContext::getTextureCacheLimits(int* maxTextures,
322 size_t* maxTextureBytes) const {
323 fTextureCache->getLimits(maxTextures, maxTextureBytes);
324}
325
326void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
327 fTextureCache->setLimits(maxTextures, maxTextureBytes);
328}
329
330int GrContext::getMaxTextureDimension() {
331 return fGpu->maxTextureDimension();
332}
333
334///////////////////////////////////////////////////////////////////////////////
335
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000336GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
337 // validate flags here so that GrGpu subclasses don't have to check
338 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
339 0 != desc.fRenderTargetFlags) {
340 return NULL;
341 }
342 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
343 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
344 return NULL;
345 }
346 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
347 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
348 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
349 return NULL;
350 }
351 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000352}
353
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000354///////////////////////////////////////////////////////////////////////////////
355
bsalomon@google.com27847de2011-02-22 20:59:41 +0000356bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
357 int width, int height) {
358 if (!fGpu->supports8BitPalette()) {
359 return false;
360 }
361
362
363 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
364
365 if (!isPow2) {
366 if (!fGpu->npotTextureSupport()) {
367 return false;
368 }
369
370 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
371 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
372 if (tiled && !fGpu->npotTextureTileSupport()) {
373 return false;
374 }
375 }
376 return true;
377}
378
379////////////////////////////////////////////////////////////////////////////////
380
381void GrContext::setClip(const GrClip& clip) {
382 fGpu->setClip(clip);
383 fGpu->enableState(GrDrawTarget::kClip_StateBit);
384}
385
386void GrContext::setClip(const GrIRect& rect) {
387 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000388 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 fGpu->setClip(clip);
390}
391
392////////////////////////////////////////////////////////////////////////////////
393
bsalomon@google.com398109c2011-04-14 18:40:27 +0000394void GrContext::clear(GrColor color) {
395 // gpu flush call is immediate, must flush.
396 // (could in theory skip draws to current render target.)
397 this->flush();
398 fGpu->clear(color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000399}
400
401void GrContext::drawPaint(const GrPaint& paint) {
402 // set rect to be big enough to fill the space, but not super-huge, so we
403 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000404 GrRect r;
405 r.setLTRB(0, 0,
406 GrIntToScalar(getRenderTarget()->width()),
407 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000408 GrMatrix inverse;
409 if (fGpu->getViewInverse(&inverse)) {
410 inverse.mapRect(&r);
411 } else {
412 GrPrintf("---- fGpu->getViewInverse failed\n");
413 }
414 this->drawRect(paint, r);
415}
416
bsalomon@google.com205d4602011-04-25 12:43:45 +0000417////////////////////////////////////////////////////////////////////////////////
418
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000419bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
420 bool requireStencil,
421 OffscreenRecord* record) {
422#if !ENABLE_SSAA
423 return false;
424#endif
425
426 GrAssert(NULL == record->fEntry);
427
428 int width = this->getRenderTarget()->width();
429 int height = this->getRenderTarget()->height();
430
431 GrTextureDesc desc;
432 desc.fAALevel = kNone_GrAALevel;
433 if (requireStencil) {
434 desc.fFlags = kRenderTarget_GrTextureFlagBit;
435 } else {
436 desc.fFlags = kRenderTarget_GrTextureFlagBit |
437 kNoStencil_GrTextureFlagBit;
438 }
439
440 desc.fWidth = 2 * width;
441 desc.fHeight = 2 * height;
442 desc.fFormat = kRGBA_8888_GrPixelConfig;
443
444 record->fEntry = this->lockKeylessTexture(desc);
445 if (NULL == record->fEntry) {
446 return false;
447 }
448 GrRenderTarget* offscreen = record->fEntry->texture()->asRenderTarget();
449 GrAssert(NULL != offscreen);
450
451 target->saveCurrentDrawState(&record->fSavedState);
452
453 GrPaint tempPaint;
454 tempPaint.reset();
455 SetPaint(tempPaint, target);
456 target->setRenderTarget(offscreen);
457
458 GrMatrix scaleM;
459 scaleM.setScale(2 * GR_Scalar1, 2 * GR_Scalar1);
460 target->postConcatViewMatrix(scaleM);
461
462 // clip gets applied in second pass
463 target->disableState(GrDrawTarget::kClip_StateBit);
464
465 target->clear(0x0);
466 return true;
467}
468
469void GrContext::setupOffscreenAAPass2(GrDrawTarget* target,
470 const GrPaint& paint,
471 OffscreenRecord* record) {
472
473 GrAssert(NULL != record->fEntry);
474 GrTexture* offscreen = record->fEntry->texture();
475 GrAssert(NULL != offscreen);
476
477 target->restoreDrawState(record->fSavedState);
478
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000479 target->setTexture(kOffscreenStage, offscreen);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000480 GrMatrix sampleM;
481 sampleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
482 GR_Scalar1 / target->getRenderTarget()->height());
483 sampleM.preConcat(target->getViewMatrix());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000484
485 // use bilinear filtering to get downsample
486 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
487 GrSamplerState::kClamp_WrapMode,
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000488 sampleM, true);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000489 target->setSamplerState(kOffscreenStage, sampler);
490}
491
492void GrContext::endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
493 this->unlockTexture(record->fEntry);
494 record->fEntry = NULL;
495
496 target->restoreDrawState(record->fSavedState);
497}
498
499////////////////////////////////////////////////////////////////////////////////
500
bsalomon@google.com27847de2011-02-22 20:59:41 +0000501/* create a triangle strip that strokes the specified triangle. There are 8
502 unique vertices, but we repreat the last 2 to close up. Alternatively we
503 could use an indices array, and then only send 8 verts, but not sure that
504 would be faster.
505 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000506static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000507 GrScalar width) {
508 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000509 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000510
511 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
512 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
513 verts[2].set(rect.fRight - rad, rect.fTop + rad);
514 verts[3].set(rect.fRight + rad, rect.fTop - rad);
515 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
516 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
517 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
518 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
519 verts[8] = verts[0];
520 verts[9] = verts[1];
521}
522
bsalomon@google.com205d4602011-04-25 12:43:45 +0000523static GrColor getColorForMesh(const GrPaint& paint) {
524 if (NULL == paint.getTexture()) {
525 return paint.fColor;
526 } else {
527 unsigned a = GrColorUnpackA(paint.fColor);
528 return GrColorPackRGBA(a, a, a, a);
529 }
530}
531
532static void setInsetFan(GrPoint* pts, size_t stride,
533 const GrRect& r, GrScalar dx, GrScalar dy) {
534 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
535}
536
537static const uint16_t gFillAARectIdx[] = {
538 0, 1, 5, 5, 4, 0,
539 1, 2, 6, 6, 5, 1,
540 2, 3, 7, 7, 6, 2,
541 3, 0, 4, 4, 7, 3,
542 4, 5, 6, 6, 7, 4,
543};
544
545int GrContext::aaFillRectIndexCount() const {
546 return GR_ARRAY_COUNT(gFillAARectIdx);
547}
548
549GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
550 if (NULL == fAAFillRectIndexBuffer) {
551 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
552 false);
553 GrAssert(NULL != fAAFillRectIndexBuffer);
554#if GR_DEBUG
555 bool updated =
556#endif
557 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
558 sizeof(gFillAARectIdx));
559 GR_DEBUGASSERT(updated);
560 }
561 return fAAFillRectIndexBuffer;
562}
563
564static const uint16_t gStrokeAARectIdx[] = {
565 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
566 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
567 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
568 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
569
570 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
571 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
572 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
573 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
574
575 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
576 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
577 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
578 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
579};
580
581int GrContext::aaStrokeRectIndexCount() const {
582 return GR_ARRAY_COUNT(gStrokeAARectIdx);
583}
584
585GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
586 if (NULL == fAAStrokeRectIndexBuffer) {
587 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
588 false);
589 GrAssert(NULL != fAAStrokeRectIndexBuffer);
590#if GR_DEBUG
591 bool updated =
592#endif
593 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
594 sizeof(gStrokeAARectIdx));
595 GR_DEBUGASSERT(updated);
596 }
597 return fAAStrokeRectIndexBuffer;
598}
599
600void GrContext::fillAARect(GrDrawTarget* target,
601 const GrPaint& paint,
602 const GrRect& devRect) {
603
604 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
605 if (NULL != paint.getTexture()) {
606 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
607 }
608
609 size_t vsize = GrDrawTarget::VertexSize(layout);
610
611 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
612
613 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
614
615 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
616 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
617
618 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
619 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
620
621 verts += sizeof(GrPoint);
622 for (int i = 0; i < 4; ++i) {
623 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
624 }
625
626 GrColor innerColor = getColorForMesh(paint);
627 verts += 4 * vsize;
628 for (int i = 0; i < 4; ++i) {
629 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
630 }
631
632 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
633
634 target->drawIndexed(kTriangles_PrimitiveType, 0,
635 0, 8, this->aaFillRectIndexCount());
636}
637
638void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
639 const GrRect& devRect, const GrVec& devStrokeSize) {
640 const GrScalar& dx = devStrokeSize.fX;
641 const GrScalar& dy = devStrokeSize.fY;
642 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
643 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
644
645 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
646
647 if (NULL != paint.getTexture()) {
648 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
649 }
650
651 GrScalar spare;
652 {
653 GrScalar w = devRect.width() - dx;
654 GrScalar h = devRect.height() - dy;
655 spare = GrMin(w, h);
656 }
657
658 if (spare <= 0) {
659 GrRect r(devRect);
660 r.inset(-rx, -ry);
661 fillAARect(target, paint, r);
662 return;
663 }
664
665 size_t vsize = GrDrawTarget::VertexSize(layout);
666
667 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
668
669 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
670
671 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
672 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
673 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
674 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
675
676 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
677 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
678 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
679 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
680
681 verts += sizeof(GrPoint);
682 for (int i = 0; i < 4; ++i) {
683 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
684 }
685
686 GrColor innerColor = getColorForMesh(paint);
687 verts += 4 * vsize;
688 for (int i = 0; i < 8; ++i) {
689 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
690 }
691
692 verts += 8 * vsize;
693 for (int i = 0; i < 8; ++i) {
694 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
695 }
696
697 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
698 target->drawIndexed(kTriangles_PrimitiveType,
699 0, 0, 16, aaStrokeRectIndexCount());
700}
701
702static bool apply_aa_to_rect(GrDrawTarget* target,
703 GrGpu* gpu,
704 const GrPaint& paint,
705 const GrRect& rect,
706 GrScalar width,
707 const GrMatrix* matrix,
708 GrMatrix* combinedMatrix,
709 GrRect* devRect) {
710 // we use a simple alpha ramp to do aa on axis-aligned rects
711 // do AA with alpha ramp if the caller requested AA, the rect
712 // will be axis-aligned,the render target is not
713 // multisampled, and the rect won't land on integer coords.
714
715 if (!paint.fAntiAlias) {
716 return false;
717 }
718
719 if (target->getRenderTarget()->isMultisampled()) {
720 return false;
721 }
722
723 if (0 == width && gpu->supportsAALines()) {
724 return false;
725 }
726
727 if (!target->getViewMatrix().preservesAxisAlignment()) {
728 return false;
729 }
730
731 if (NULL != matrix &&
732 !matrix->preservesAxisAlignment()) {
733 return false;
734 }
735
736 *combinedMatrix = target->getViewMatrix();
737 if (NULL != matrix) {
738 combinedMatrix->preConcat(*matrix);
739 GrAssert(combinedMatrix->preservesAxisAlignment());
740 }
741
742 combinedMatrix->mapRect(devRect, rect);
743 devRect->sort();
744
745 if (width < 0) {
746 return !devRect->isIRect();
747 } else {
748 return true;
749 }
750}
751
bsalomon@google.com27847de2011-02-22 20:59:41 +0000752void GrContext::drawRect(const GrPaint& paint,
753 const GrRect& rect,
754 GrScalar width,
755 const GrMatrix* matrix) {
756
757 bool textured = NULL != paint.getTexture();
758
759 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
760
bsalomon@google.com205d4602011-04-25 12:43:45 +0000761 GrRect devRect = rect;
762 GrMatrix combinedMatrix;
763 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
764 &combinedMatrix, &devRect);
765
766 if (doAA) {
767 GrDrawTarget::AutoViewMatrixRestore avm(target);
768 if (textured) {
769 GrMatrix inv;
770 if (combinedMatrix.invert(&inv)) {
771 target->preConcatSamplerMatrix(0, inv);
772 }
773 }
774 target->setViewMatrix(GrMatrix::I());
775 if (width >= 0) {
776 GrVec strokeSize;;
777 if (width > 0) {
778 strokeSize.set(width, width);
779 combinedMatrix.mapVec(&strokeSize);
780 strokeSize.setAbs(strokeSize);
781 } else {
782 strokeSize.set(GR_Scalar1, GR_Scalar1);
783 }
784 strokeAARect(target, paint, devRect, strokeSize);
785 } else {
786 fillAARect(target, paint, devRect);
787 }
788 return;
789 }
790
bsalomon@google.com27847de2011-02-22 20:59:41 +0000791 if (width >= 0) {
792 // TODO: consider making static vertex buffers for these cases.
793 // Hairline could be done by just adding closing vertex to
794 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000795 GrVertexLayout layout = textured ?
796 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
797 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000798 static const int worstCaseVertCount = 10;
799 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
800
801 if (!geo.succeeded()) {
802 return;
803 }
804
805 GrPrimitiveType primType;
806 int vertCount;
807 GrPoint* vertex = geo.positions();
808
809 if (width > 0) {
810 vertCount = 10;
811 primType = kTriangleStrip_PrimitiveType;
812 setStrokeRectStrip(vertex, rect, width);
813 } else {
814 // hairline
815 vertCount = 5;
816 primType = kLineStrip_PrimitiveType;
817 vertex[0].set(rect.fLeft, rect.fTop);
818 vertex[1].set(rect.fRight, rect.fTop);
819 vertex[2].set(rect.fRight, rect.fBottom);
820 vertex[3].set(rect.fLeft, rect.fBottom);
821 vertex[4].set(rect.fLeft, rect.fTop);
822 }
823
824 GrDrawTarget::AutoViewMatrixRestore avmr;
825 if (NULL != matrix) {
826 avmr.set(target);
827 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000828 if (textured) {
829 target->preConcatSamplerMatrix(0, *matrix);
830 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000831 }
832
833 target->drawNonIndexed(primType, 0, vertCount);
834 } else {
835 #if GR_STATIC_RECT_VB
836 GrVertexLayout layout = (textured) ?
837 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
838 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000839 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000840 fGpu->getUnitSquareVertexBuffer());
841 GrDrawTarget::AutoViewMatrixRestore avmr(target);
842 GrMatrix m;
843 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000844 0, rect.height(), rect.fTop,
845 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000846
847 if (NULL != matrix) {
848 m.postConcat(*matrix);
849 }
850
851 target->preConcatViewMatrix(m);
852
853 if (textured) {
854 target->preConcatSamplerMatrix(0, m);
855 }
856 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
857 #else
858 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
859 #endif
860 }
861}
862
863void GrContext::drawRectToRect(const GrPaint& paint,
864 const GrRect& dstRect,
865 const GrRect& srcRect,
866 const GrMatrix* dstMatrix,
867 const GrMatrix* srcMatrix) {
868
869 if (NULL == paint.getTexture()) {
870 drawRect(paint, dstRect, -1, dstMatrix);
871 return;
872 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000873
bsalomon@google.com27847de2011-02-22 20:59:41 +0000874 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
875
876#if GR_STATIC_RECT_VB
877 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
878
879 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
880 GrDrawTarget::AutoViewMatrixRestore avmr(target);
881
882 GrMatrix m;
883
884 m.setAll(dstRect.width(), 0, dstRect.fLeft,
885 0, dstRect.height(), dstRect.fTop,
886 0, 0, GrMatrix::I()[8]);
887 if (NULL != dstMatrix) {
888 m.postConcat(*dstMatrix);
889 }
890 target->preConcatViewMatrix(m);
891
892 m.setAll(srcRect.width(), 0, srcRect.fLeft,
893 0, srcRect.height(), srcRect.fTop,
894 0, 0, GrMatrix::I()[8]);
895 if (NULL != srcMatrix) {
896 m.postConcat(*srcMatrix);
897 }
898 target->preConcatSamplerMatrix(0, m);
899
900 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
901 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
902#else
903
904 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000905#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000907#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000908 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
909#endif
910
911 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
912 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
913 srcRects[0] = &srcRect;
914 srcMatrices[0] = srcMatrix;
915
916 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
917#endif
918}
919
920void GrContext::drawVertices(const GrPaint& paint,
921 GrPrimitiveType primitiveType,
922 int vertexCount,
923 const GrPoint positions[],
924 const GrPoint texCoords[],
925 const GrColor colors[],
926 const uint16_t indices[],
927 int indexCount) {
928 GrVertexLayout layout = 0;
929 int vertexSize = sizeof(GrPoint);
930
931 GrDrawTarget::AutoReleaseGeometry geo;
932
933 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
934
935 if (NULL != paint.getTexture()) {
936 if (NULL == texCoords) {
937 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
938 } else {
939 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
940 vertexSize += sizeof(GrPoint);
941 }
942 }
943
944 if (NULL != colors) {
945 layout |= GrDrawTarget::kColor_VertexLayoutBit;
946 vertexSize += sizeof(GrColor);
947 }
948
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000949 bool doOffscreenAA = false;
950 OffscreenRecord record;
951 if (paint.fAntiAlias &&
952 !this->getRenderTarget()->isMultisampled() &&
953 !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) &&
954 this->setupOffscreenAAPass1(target, false, &record)) {
955 doOffscreenAA = true;
956 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage);
957 }
958
bsalomon@google.com27847de2011-02-22 20:59:41 +0000959 if (sizeof(GrPoint) != vertexSize) {
960 if (!geo.set(target, layout, vertexCount, 0)) {
961 GrPrintf("Failed to get space for vertices!");
962 return;
963 }
964 int texOffsets[GrDrawTarget::kMaxTexCoords];
965 int colorOffset;
966 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
967 texOffsets,
968 &colorOffset);
969 void* curVertex = geo.vertices();
970
971 for (int i = 0; i < vertexCount; ++i) {
972 *((GrPoint*)curVertex) = positions[i];
973
974 if (texOffsets[0] > 0) {
975 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
976 }
977 if (colorOffset > 0) {
978 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
979 }
980 curVertex = (void*)((intptr_t)curVertex + vsize);
981 }
982 } else {
983 target->setVertexSourceToArray(layout, positions, vertexCount);
984 }
985
986 if (NULL != indices) {
987 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000988 }
989
990 if (doOffscreenAA) {
991 // draw to the offscreen
992 if (NULL != indices) {
993 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
994 } else {
995 target->drawNonIndexed(primitiveType, 0, vertexCount);
996 }
997 // When there are custom texture coordinates we can't just draw
998 // a quad to sample the offscreen. Instead we redraw the geometry to
999 // specify the texture coords. This isn't quite right either, primitives
1000 // will only be eroded at the edges, not expanded into partial pixels.
1001 bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));
1002 if (useRect) {
1003 target->setViewMatrix(GrMatrix::I());
1004 }
1005 this->setupOffscreenAAPass2(target, paint, &record);
1006 if (useRect) {
1007 geo.set(NULL, 0, 0, 0);
1008 int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
1009 stages |= (1 << kOffscreenStage);
1010 GrRect dstRect(0, 0,
1011 target->getRenderTarget()->width(),
1012 target->getRenderTarget()->height());
1013 target->drawSimpleRect(dstRect, NULL, stages);
1014 target->drawSimpleRect(dstRect, NULL, stages);
1015 } else {
1016 if (NULL != indices) {
1017 target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount);
1018 } else {
1019 target->drawNonIndexed(primitiveType, 0, vertexCount);
1020 }
1021 }
1022 this->endOffscreenAA(target, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001023 } else {
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001024 if (NULL != indices) {
1025 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1026 } else {
1027 target->drawNonIndexed(primitiveType, 0, vertexCount);
1028 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001029 }
1030}
1031
1032
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001033///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001034
1035void GrContext::drawPath(const GrPaint& paint,
1036 GrPathIter* path,
1037 GrPathFill fill,
1038 const GrPoint* translate) {
1039
bsalomon@google.com27847de2011-02-22 20:59:41 +00001040 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001041 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001043 if (paint.fAntiAlias &&
1044 !this->getRenderTarget()->isMultisampled() &&
1045 !pr->supportsAA()) {
1046
1047 OffscreenRecord record;
1048 bool needsStencil = pr->requiresStencilPass(target, path, fill);
1049 if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
1050 pr->drawPath(target, 0, path, fill, translate);
1051
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001052 target->setViewMatrix(GrMatrix::I());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001053 this->setupOffscreenAAPass2(target, paint, &record);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001054
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001055 int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
1056 stages |= (1 << kOffscreenStage);
1057 GrRect dstRect(0, 0,
1058 target->getRenderTarget()->width(),
1059 target->getRenderTarget()->height());
1060 target->drawSimpleRect(dstRect, NULL, stages);
1061
1062 this->endOffscreenAA(target, &record);
1063 return;
1064 }
1065 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001066 GrDrawTarget::StageBitfield enabledStages = 0;
1067 if (NULL != paint.getTexture()) {
1068 enabledStages |= 1;
1069 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001070
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001071 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001072}
bsalomon@google.comd302f142011-03-03 13:54:13 +00001073void GrContext::drawPath(const GrPaint& paint,
1074 const GrPath& path,
1075 GrPathFill fill,
1076 const GrPoint* translate) {
1077 GrPath::Iter iter(path);
1078 this->drawPath(paint, &iter, fill, translate);
1079}
1080
1081
bsalomon@google.com27847de2011-02-22 20:59:41 +00001082////////////////////////////////////////////////////////////////////////////////
1083
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001084void GrContext::flush(int flagsBitfield) {
1085 if (kDiscard_FlushBit & flagsBitfield) {
1086 fDrawBuffer->reset();
1087 } else {
1088 flushDrawBuffer();
1089 }
1090
1091 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001092 fGpu->forceRenderTargetFlush();
1093 }
1094}
1095
1096void GrContext::flushText() {
1097 if (kText_DrawCategory == fLastDrawCategory) {
1098 flushDrawBuffer();
1099 }
1100}
1101
1102void GrContext::flushDrawBuffer() {
1103#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1104 fDrawBuffer->playback(fGpu);
1105 fDrawBuffer->reset();
1106#endif
1107}
1108
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001109bool GrContext::readTexturePixels(GrTexture* texture,
1110 int left, int top, int width, int height,
1111 GrPixelConfig config, void* buffer) {
1112
1113 // TODO: code read pixels for textures that aren't rendertargets
1114
1115 this->flush();
1116 GrRenderTarget* target = texture->asRenderTarget();
1117 if (NULL != target) {
1118 return fGpu->readPixels(target,
1119 left, top, width, height,
1120 config, buffer);
1121 } else {
1122 return false;
1123 }
1124}
1125
1126bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1127 int left, int top, int width, int height,
1128 GrPixelConfig config, void* buffer) {
1129 uint32_t flushFlags = 0;
1130 if (NULL == target) {
1131 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1132 }
1133
1134 this->flush(flushFlags);
1135 return fGpu->readPixels(target,
1136 left, top, width, height,
1137 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001138}
1139
1140void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001141 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142 size_t stride) {
1143
1144 // TODO: when underlying api has a direct way to do this we should use it
1145 // (e.g. glDrawPixels on desktop GL).
1146
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001147 const GrTextureDesc desc = {
1148 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001149 };
1150 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1151 if (NULL == texture) {
1152 return;
1153 }
1154
1155 this->flush(true);
1156
1157 GrAutoUnref aur(texture);
1158 GrDrawTarget::AutoStateRestore asr(fGpu);
1159
1160 GrMatrix matrix;
1161 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1162 fGpu->setViewMatrix(matrix);
1163
1164 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1165 fGpu->setAlpha(0xFF);
1166 fGpu->setBlendFunc(kOne_BlendCoeff,
1167 kZero_BlendCoeff);
1168 fGpu->setTexture(0, texture);
1169
1170 GrSamplerState sampler;
1171 sampler.setClampNoFilter();
1172 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1173 sampler.setMatrix(matrix);
1174 fGpu->setSamplerState(0, sampler);
1175
1176 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1177 static const int VCOUNT = 4;
1178
1179 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1180 if (!geo.succeeded()) {
1181 return;
1182 }
1183 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1184 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1185}
1186////////////////////////////////////////////////////////////////////////////////
1187
1188void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1189 target->setTexture(0, paint.getTexture());
1190 target->setSamplerState(0, paint.fSampler);
1191 target->setColor(paint.fColor);
1192
1193 if (paint.fDither) {
1194 target->enableState(GrDrawTarget::kDither_StateBit);
1195 } else {
1196 target->disableState(GrDrawTarget::kDither_StateBit);
1197 }
1198 if (paint.fAntiAlias) {
1199 target->enableState(GrDrawTarget::kAntialias_StateBit);
1200 } else {
1201 target->disableState(GrDrawTarget::kAntialias_StateBit);
1202 }
1203 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1204}
1205
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001206GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001207 DrawCategory category) {
1208 if (category != fLastDrawCategory) {
1209 flushDrawBuffer();
1210 fLastDrawCategory = category;
1211 }
1212 SetPaint(paint, fGpu);
1213 GrDrawTarget* target = fGpu;
1214 switch (category) {
1215 case kText_DrawCategory:
1216#if DEFER_TEXT_RENDERING
1217 target = fDrawBuffer;
1218 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1219#else
1220 target = fGpu;
1221#endif
1222 break;
1223 case kUnbuffered_DrawCategory:
1224 target = fGpu;
1225 break;
1226 case kBuffered_DrawCategory:
1227 target = fDrawBuffer;
1228 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1229 break;
1230 }
1231 return target;
1232}
1233
1234////////////////////////////////////////////////////////////////////////////////
1235
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001237 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238 fGpu->setRenderTarget(target);
1239}
1240
1241GrRenderTarget* GrContext::getRenderTarget() {
1242 return fGpu->getRenderTarget();
1243}
1244
1245const GrRenderTarget* GrContext::getRenderTarget() const {
1246 return fGpu->getRenderTarget();
1247}
1248
1249const GrMatrix& GrContext::getMatrix() const {
1250 return fGpu->getViewMatrix();
1251}
1252
1253void GrContext::setMatrix(const GrMatrix& m) {
1254 fGpu->setViewMatrix(m);
1255}
1256
1257void GrContext::concatMatrix(const GrMatrix& m) const {
1258 fGpu->preConcatViewMatrix(m);
1259}
1260
1261static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1262 intptr_t mask = 1 << shift;
1263 if (pred) {
1264 bits |= mask;
1265 } else {
1266 bits &= ~mask;
1267 }
1268 return bits;
1269}
1270
1271void GrContext::resetStats() {
1272 fGpu->resetStats();
1273}
1274
1275const GrGpu::Stats& GrContext::getStats() const {
1276 return fGpu->getStats();
1277}
1278
1279void GrContext::printStats() const {
1280 fGpu->printStats();
1281}
1282
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001283GrContext::GrContext(GrGpu* gpu) :
1284 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1285 gpu->supportsStencilWrapOps()) {
1286
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 fGpu = gpu;
1288 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001289 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001290
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001291 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1292 fGpu->setClipPathRenderer(fCustomPathRenderer);
1293
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1295 MAX_TEXTURE_CACHE_BYTES);
1296 fFontCache = new GrFontCache(fGpu);
1297
1298 fLastDrawCategory = kUnbuffered_DrawCategory;
1299
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001300 fDrawBuffer = NULL;
1301 fDrawBufferVBAllocPool = NULL;
1302 fDrawBufferIBAllocPool = NULL;
1303
bsalomon@google.com205d4602011-04-25 12:43:45 +00001304 fAAFillRectIndexBuffer = NULL;
1305 fAAStrokeRectIndexBuffer = NULL;
1306
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001307 this->setupDrawBuffer();
1308}
1309
1310void GrContext::setupDrawBuffer() {
1311
1312 GrAssert(NULL == fDrawBuffer);
1313 GrAssert(NULL == fDrawBufferVBAllocPool);
1314 GrAssert(NULL == fDrawBufferIBAllocPool);
1315
bsalomon@google.com27847de2011-02-22 20:59:41 +00001316#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001317 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001318 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1320 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001321 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001322 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001323 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1325
1326 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1327 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328#endif
1329
1330#if BATCH_RECT_TO_RECT
1331 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1332#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333}
1334
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1336 GrDrawTarget* target;
1337#if DEFER_TEXT_RENDERING
1338 target = prepareToDraw(paint, kText_DrawCategory);
1339#else
1340 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1341#endif
1342 SetPaint(paint, target);
1343 return target;
1344}
1345
1346const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1347 return fGpu->getQuadIndexBuffer();
1348}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001349
1350GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1351 GrPathIter* path,
1352 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001353 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001354 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1355 return fCustomPathRenderer;
1356 } else {
1357 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1358 return &fDefaultPathRenderer;
1359 }
1360}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001361