blob: d3904e00a603feb415270f2a6ae3b189b3873c8f [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.com6aa25c32011-04-27 19:55:29 +0000394void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000395 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000396 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000397}
398
399void GrContext::drawPaint(const GrPaint& paint) {
400 // set rect to be big enough to fill the space, but not super-huge, so we
401 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000402 GrRect r;
403 r.setLTRB(0, 0,
404 GrIntToScalar(getRenderTarget()->width()),
405 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406 GrMatrix inverse;
407 if (fGpu->getViewInverse(&inverse)) {
408 inverse.mapRect(&r);
409 } else {
410 GrPrintf("---- fGpu->getViewInverse failed\n");
411 }
412 this->drawRect(paint, r);
413}
414
bsalomon@google.com205d4602011-04-25 12:43:45 +0000415////////////////////////////////////////////////////////////////////////////////
416
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000417bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
418 bool requireStencil,
419 OffscreenRecord* record) {
420#if !ENABLE_SSAA
421 return false;
422#endif
423
424 GrAssert(NULL == record->fEntry);
425
426 int width = this->getRenderTarget()->width();
427 int height = this->getRenderTarget()->height();
428
429 GrTextureDesc desc;
430 desc.fAALevel = kNone_GrAALevel;
431 if (requireStencil) {
432 desc.fFlags = kRenderTarget_GrTextureFlagBit;
433 } else {
434 desc.fFlags = kRenderTarget_GrTextureFlagBit |
435 kNoStencil_GrTextureFlagBit;
436 }
437
438 desc.fWidth = 2 * width;
439 desc.fHeight = 2 * height;
440 desc.fFormat = kRGBA_8888_GrPixelConfig;
441
442 record->fEntry = this->lockKeylessTexture(desc);
443 if (NULL == record->fEntry) {
444 return false;
445 }
446 GrRenderTarget* offscreen = record->fEntry->texture()->asRenderTarget();
447 GrAssert(NULL != offscreen);
448
449 target->saveCurrentDrawState(&record->fSavedState);
450
451 GrPaint tempPaint;
452 tempPaint.reset();
453 SetPaint(tempPaint, target);
454 target->setRenderTarget(offscreen);
455
456 GrMatrix scaleM;
457 scaleM.setScale(2 * GR_Scalar1, 2 * GR_Scalar1);
458 target->postConcatViewMatrix(scaleM);
459
460 // clip gets applied in second pass
461 target->disableState(GrDrawTarget::kClip_StateBit);
462
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000463 target->clear(NULL, 0x0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000464 return true;
465}
466
467void GrContext::setupOffscreenAAPass2(GrDrawTarget* target,
468 const GrPaint& paint,
469 OffscreenRecord* record) {
470
471 GrAssert(NULL != record->fEntry);
472 GrTexture* offscreen = record->fEntry->texture();
473 GrAssert(NULL != offscreen);
474
475 target->restoreDrawState(record->fSavedState);
476
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000477 target->setTexture(kOffscreenStage, offscreen);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000478 GrMatrix sampleM;
479 sampleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
480 GR_Scalar1 / target->getRenderTarget()->height());
481 sampleM.preConcat(target->getViewMatrix());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000482
483 // use bilinear filtering to get downsample
484 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
485 GrSamplerState::kClamp_WrapMode,
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000486 sampleM, true);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000487 target->setSamplerState(kOffscreenStage, sampler);
488}
489
490void GrContext::endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
491 this->unlockTexture(record->fEntry);
492 record->fEntry = NULL;
493
494 target->restoreDrawState(record->fSavedState);
495}
496
497////////////////////////////////////////////////////////////////////////////////
498
bsalomon@google.com27847de2011-02-22 20:59:41 +0000499/* create a triangle strip that strokes the specified triangle. There are 8
500 unique vertices, but we repreat the last 2 to close up. Alternatively we
501 could use an indices array, and then only send 8 verts, but not sure that
502 would be faster.
503 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000504static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000505 GrScalar width) {
506 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000507 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000508
509 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
510 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
511 verts[2].set(rect.fRight - rad, rect.fTop + rad);
512 verts[3].set(rect.fRight + rad, rect.fTop - rad);
513 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
514 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
515 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
516 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
517 verts[8] = verts[0];
518 verts[9] = verts[1];
519}
520
bsalomon@google.com205d4602011-04-25 12:43:45 +0000521static GrColor getColorForMesh(const GrPaint& paint) {
522 if (NULL == paint.getTexture()) {
523 return paint.fColor;
524 } else {
525 unsigned a = GrColorUnpackA(paint.fColor);
526 return GrColorPackRGBA(a, a, a, a);
527 }
528}
529
530static void setInsetFan(GrPoint* pts, size_t stride,
531 const GrRect& r, GrScalar dx, GrScalar dy) {
532 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
533}
534
535static const uint16_t gFillAARectIdx[] = {
536 0, 1, 5, 5, 4, 0,
537 1, 2, 6, 6, 5, 1,
538 2, 3, 7, 7, 6, 2,
539 3, 0, 4, 4, 7, 3,
540 4, 5, 6, 6, 7, 4,
541};
542
543int GrContext::aaFillRectIndexCount() const {
544 return GR_ARRAY_COUNT(gFillAARectIdx);
545}
546
547GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
548 if (NULL == fAAFillRectIndexBuffer) {
549 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
550 false);
551 GrAssert(NULL != fAAFillRectIndexBuffer);
552#if GR_DEBUG
553 bool updated =
554#endif
555 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
556 sizeof(gFillAARectIdx));
557 GR_DEBUGASSERT(updated);
558 }
559 return fAAFillRectIndexBuffer;
560}
561
562static const uint16_t gStrokeAARectIdx[] = {
563 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
564 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
565 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
566 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
567
568 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
569 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
570 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
571 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
572
573 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
574 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
575 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
576 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
577};
578
579int GrContext::aaStrokeRectIndexCount() const {
580 return GR_ARRAY_COUNT(gStrokeAARectIdx);
581}
582
583GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
584 if (NULL == fAAStrokeRectIndexBuffer) {
585 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
586 false);
587 GrAssert(NULL != fAAStrokeRectIndexBuffer);
588#if GR_DEBUG
589 bool updated =
590#endif
591 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
592 sizeof(gStrokeAARectIdx));
593 GR_DEBUGASSERT(updated);
594 }
595 return fAAStrokeRectIndexBuffer;
596}
597
598void GrContext::fillAARect(GrDrawTarget* target,
599 const GrPaint& paint,
600 const GrRect& devRect) {
601
602 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
603 if (NULL != paint.getTexture()) {
604 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
605 }
606
607 size_t vsize = GrDrawTarget::VertexSize(layout);
608
609 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
610
611 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
612
613 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
614 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
615
616 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
617 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
618
619 verts += sizeof(GrPoint);
620 for (int i = 0; i < 4; ++i) {
621 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
622 }
623
624 GrColor innerColor = getColorForMesh(paint);
625 verts += 4 * vsize;
626 for (int i = 0; i < 4; ++i) {
627 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
628 }
629
630 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
631
632 target->drawIndexed(kTriangles_PrimitiveType, 0,
633 0, 8, this->aaFillRectIndexCount());
634}
635
636void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
637 const GrRect& devRect, const GrVec& devStrokeSize) {
638 const GrScalar& dx = devStrokeSize.fX;
639 const GrScalar& dy = devStrokeSize.fY;
640 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
641 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
642
643 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
644
645 if (NULL != paint.getTexture()) {
646 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
647 }
648
649 GrScalar spare;
650 {
651 GrScalar w = devRect.width() - dx;
652 GrScalar h = devRect.height() - dy;
653 spare = GrMin(w, h);
654 }
655
656 if (spare <= 0) {
657 GrRect r(devRect);
658 r.inset(-rx, -ry);
659 fillAARect(target, paint, r);
660 return;
661 }
662
663 size_t vsize = GrDrawTarget::VertexSize(layout);
664
665 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
666
667 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
668
669 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
670 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
671 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
672 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
673
674 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
675 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
676 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
677 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
678
679 verts += sizeof(GrPoint);
680 for (int i = 0; i < 4; ++i) {
681 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
682 }
683
684 GrColor innerColor = getColorForMesh(paint);
685 verts += 4 * vsize;
686 for (int i = 0; i < 8; ++i) {
687 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
688 }
689
690 verts += 8 * vsize;
691 for (int i = 0; i < 8; ++i) {
692 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
693 }
694
695 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
696 target->drawIndexed(kTriangles_PrimitiveType,
697 0, 0, 16, aaStrokeRectIndexCount());
698}
699
700static bool apply_aa_to_rect(GrDrawTarget* target,
701 GrGpu* gpu,
702 const GrPaint& paint,
703 const GrRect& rect,
704 GrScalar width,
705 const GrMatrix* matrix,
706 GrMatrix* combinedMatrix,
707 GrRect* devRect) {
708 // we use a simple alpha ramp to do aa on axis-aligned rects
709 // do AA with alpha ramp if the caller requested AA, the rect
710 // will be axis-aligned,the render target is not
711 // multisampled, and the rect won't land on integer coords.
712
713 if (!paint.fAntiAlias) {
714 return false;
715 }
716
717 if (target->getRenderTarget()->isMultisampled()) {
718 return false;
719 }
720
721 if (0 == width && gpu->supportsAALines()) {
722 return false;
723 }
724
725 if (!target->getViewMatrix().preservesAxisAlignment()) {
726 return false;
727 }
728
729 if (NULL != matrix &&
730 !matrix->preservesAxisAlignment()) {
731 return false;
732 }
733
734 *combinedMatrix = target->getViewMatrix();
735 if (NULL != matrix) {
736 combinedMatrix->preConcat(*matrix);
737 GrAssert(combinedMatrix->preservesAxisAlignment());
738 }
739
740 combinedMatrix->mapRect(devRect, rect);
741 devRect->sort();
742
743 if (width < 0) {
744 return !devRect->isIRect();
745 } else {
746 return true;
747 }
748}
749
bsalomon@google.com27847de2011-02-22 20:59:41 +0000750void GrContext::drawRect(const GrPaint& paint,
751 const GrRect& rect,
752 GrScalar width,
753 const GrMatrix* matrix) {
754
755 bool textured = NULL != paint.getTexture();
756
757 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
758
bsalomon@google.com205d4602011-04-25 12:43:45 +0000759 GrRect devRect = rect;
760 GrMatrix combinedMatrix;
761 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
762 &combinedMatrix, &devRect);
763
764 if (doAA) {
765 GrDrawTarget::AutoViewMatrixRestore avm(target);
766 if (textured) {
767 GrMatrix inv;
768 if (combinedMatrix.invert(&inv)) {
769 target->preConcatSamplerMatrix(0, inv);
770 }
771 }
772 target->setViewMatrix(GrMatrix::I());
773 if (width >= 0) {
774 GrVec strokeSize;;
775 if (width > 0) {
776 strokeSize.set(width, width);
777 combinedMatrix.mapVec(&strokeSize);
778 strokeSize.setAbs(strokeSize);
779 } else {
780 strokeSize.set(GR_Scalar1, GR_Scalar1);
781 }
782 strokeAARect(target, paint, devRect, strokeSize);
783 } else {
784 fillAARect(target, paint, devRect);
785 }
786 return;
787 }
788
bsalomon@google.com27847de2011-02-22 20:59:41 +0000789 if (width >= 0) {
790 // TODO: consider making static vertex buffers for these cases.
791 // Hairline could be done by just adding closing vertex to
792 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000793 GrVertexLayout layout = textured ?
794 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
795 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000796 static const int worstCaseVertCount = 10;
797 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
798
799 if (!geo.succeeded()) {
800 return;
801 }
802
803 GrPrimitiveType primType;
804 int vertCount;
805 GrPoint* vertex = geo.positions();
806
807 if (width > 0) {
808 vertCount = 10;
809 primType = kTriangleStrip_PrimitiveType;
810 setStrokeRectStrip(vertex, rect, width);
811 } else {
812 // hairline
813 vertCount = 5;
814 primType = kLineStrip_PrimitiveType;
815 vertex[0].set(rect.fLeft, rect.fTop);
816 vertex[1].set(rect.fRight, rect.fTop);
817 vertex[2].set(rect.fRight, rect.fBottom);
818 vertex[3].set(rect.fLeft, rect.fBottom);
819 vertex[4].set(rect.fLeft, rect.fTop);
820 }
821
822 GrDrawTarget::AutoViewMatrixRestore avmr;
823 if (NULL != matrix) {
824 avmr.set(target);
825 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000826 if (textured) {
827 target->preConcatSamplerMatrix(0, *matrix);
828 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000829 }
830
831 target->drawNonIndexed(primType, 0, vertCount);
832 } else {
833 #if GR_STATIC_RECT_VB
834 GrVertexLayout layout = (textured) ?
835 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
836 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000837 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000838 fGpu->getUnitSquareVertexBuffer());
839 GrDrawTarget::AutoViewMatrixRestore avmr(target);
840 GrMatrix m;
841 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000842 0, rect.height(), rect.fTop,
843 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000844
845 if (NULL != matrix) {
846 m.postConcat(*matrix);
847 }
848
849 target->preConcatViewMatrix(m);
850
851 if (textured) {
852 target->preConcatSamplerMatrix(0, m);
853 }
854 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
855 #else
856 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
857 #endif
858 }
859}
860
861void GrContext::drawRectToRect(const GrPaint& paint,
862 const GrRect& dstRect,
863 const GrRect& srcRect,
864 const GrMatrix* dstMatrix,
865 const GrMatrix* srcMatrix) {
866
867 if (NULL == paint.getTexture()) {
868 drawRect(paint, dstRect, -1, dstMatrix);
869 return;
870 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000871
bsalomon@google.com27847de2011-02-22 20:59:41 +0000872 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
873
874#if GR_STATIC_RECT_VB
875 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
876
877 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
878 GrDrawTarget::AutoViewMatrixRestore avmr(target);
879
880 GrMatrix m;
881
882 m.setAll(dstRect.width(), 0, dstRect.fLeft,
883 0, dstRect.height(), dstRect.fTop,
884 0, 0, GrMatrix::I()[8]);
885 if (NULL != dstMatrix) {
886 m.postConcat(*dstMatrix);
887 }
888 target->preConcatViewMatrix(m);
889
890 m.setAll(srcRect.width(), 0, srcRect.fLeft,
891 0, srcRect.height(), srcRect.fTop,
892 0, 0, GrMatrix::I()[8]);
893 if (NULL != srcMatrix) {
894 m.postConcat(*srcMatrix);
895 }
896 target->preConcatSamplerMatrix(0, m);
897
898 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
899 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
900#else
901
902 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000903#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000904 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000905#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
907#endif
908
909 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
910 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
911 srcRects[0] = &srcRect;
912 srcMatrices[0] = srcMatrix;
913
914 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
915#endif
916}
917
918void GrContext::drawVertices(const GrPaint& paint,
919 GrPrimitiveType primitiveType,
920 int vertexCount,
921 const GrPoint positions[],
922 const GrPoint texCoords[],
923 const GrColor colors[],
924 const uint16_t indices[],
925 int indexCount) {
926 GrVertexLayout layout = 0;
927 int vertexSize = sizeof(GrPoint);
928
929 GrDrawTarget::AutoReleaseGeometry geo;
930
931 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
932
933 if (NULL != paint.getTexture()) {
934 if (NULL == texCoords) {
935 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
936 } else {
937 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
938 vertexSize += sizeof(GrPoint);
939 }
940 }
941
942 if (NULL != colors) {
943 layout |= GrDrawTarget::kColor_VertexLayoutBit;
944 vertexSize += sizeof(GrColor);
945 }
946
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000947 bool doOffscreenAA = false;
948 OffscreenRecord record;
949 if (paint.fAntiAlias &&
950 !this->getRenderTarget()->isMultisampled() &&
951 !(GrIsPrimTypeLines(primitiveType) && fGpu->supportsAALines()) &&
952 this->setupOffscreenAAPass1(target, false, &record)) {
953 doOffscreenAA = true;
954 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(kOffscreenStage);
955 }
956
bsalomon@google.com27847de2011-02-22 20:59:41 +0000957 if (sizeof(GrPoint) != vertexSize) {
958 if (!geo.set(target, layout, vertexCount, 0)) {
959 GrPrintf("Failed to get space for vertices!");
960 return;
961 }
962 int texOffsets[GrDrawTarget::kMaxTexCoords];
963 int colorOffset;
964 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
965 texOffsets,
966 &colorOffset);
967 void* curVertex = geo.vertices();
968
969 for (int i = 0; i < vertexCount; ++i) {
970 *((GrPoint*)curVertex) = positions[i];
971
972 if (texOffsets[0] > 0) {
973 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
974 }
975 if (colorOffset > 0) {
976 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
977 }
978 curVertex = (void*)((intptr_t)curVertex + vsize);
979 }
980 } else {
981 target->setVertexSourceToArray(layout, positions, vertexCount);
982 }
983
984 if (NULL != indices) {
985 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000986 }
987
988 if (doOffscreenAA) {
989 // draw to the offscreen
990 if (NULL != indices) {
991 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
992 } else {
993 target->drawNonIndexed(primitiveType, 0, vertexCount);
994 }
995 // When there are custom texture coordinates we can't just draw
996 // a quad to sample the offscreen. Instead we redraw the geometry to
997 // specify the texture coords. This isn't quite right either, primitives
998 // will only be eroded at the edges, not expanded into partial pixels.
999 bool useRect = 0 == (layout & GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));
1000 if (useRect) {
1001 target->setViewMatrix(GrMatrix::I());
1002 }
1003 this->setupOffscreenAAPass2(target, paint, &record);
1004 if (useRect) {
1005 geo.set(NULL, 0, 0, 0);
1006 int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
1007 stages |= (1 << kOffscreenStage);
1008 GrRect dstRect(0, 0,
1009 target->getRenderTarget()->width(),
1010 target->getRenderTarget()->height());
1011 target->drawSimpleRect(dstRect, NULL, stages);
1012 target->drawSimpleRect(dstRect, NULL, stages);
1013 } else {
1014 if (NULL != indices) {
1015 target->drawIndexed (primitiveType, 0, 0, vertexCount, indexCount);
1016 } else {
1017 target->drawNonIndexed(primitiveType, 0, vertexCount);
1018 }
1019 }
1020 this->endOffscreenAA(target, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001021 } else {
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001022 if (NULL != indices) {
1023 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1024 } else {
1025 target->drawNonIndexed(primitiveType, 0, vertexCount);
1026 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001027 }
1028}
1029
1030
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001031///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001032
1033void GrContext::drawPath(const GrPaint& paint,
1034 GrPathIter* path,
1035 GrPathFill fill,
1036 const GrPoint* translate) {
1037
bsalomon@google.com27847de2011-02-22 20:59:41 +00001038 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001039 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001040
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001041 if (paint.fAntiAlias &&
1042 !this->getRenderTarget()->isMultisampled() &&
1043 !pr->supportsAA()) {
1044
1045 OffscreenRecord record;
1046 bool needsStencil = pr->requiresStencilPass(target, path, fill);
1047 if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
1048 pr->drawPath(target, 0, path, fill, translate);
1049
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001050 target->setViewMatrix(GrMatrix::I());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001051 this->setupOffscreenAAPass2(target, paint, &record);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001052
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001053 int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
1054 stages |= (1 << kOffscreenStage);
1055 GrRect dstRect(0, 0,
1056 target->getRenderTarget()->width(),
1057 target->getRenderTarget()->height());
1058 target->drawSimpleRect(dstRect, NULL, stages);
1059
1060 this->endOffscreenAA(target, &record);
1061 return;
1062 }
1063 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001064 GrDrawTarget::StageBitfield enabledStages = 0;
1065 if (NULL != paint.getTexture()) {
1066 enabledStages |= 1;
1067 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001068
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001069 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001070}
bsalomon@google.comd302f142011-03-03 13:54:13 +00001071void GrContext::drawPath(const GrPaint& paint,
1072 const GrPath& path,
1073 GrPathFill fill,
1074 const GrPoint* translate) {
1075 GrPath::Iter iter(path);
1076 this->drawPath(paint, &iter, fill, translate);
1077}
1078
1079
bsalomon@google.com27847de2011-02-22 20:59:41 +00001080////////////////////////////////////////////////////////////////////////////////
1081
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001082void GrContext::flush(int flagsBitfield) {
1083 if (kDiscard_FlushBit & flagsBitfield) {
1084 fDrawBuffer->reset();
1085 } else {
1086 flushDrawBuffer();
1087 }
1088
1089 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001090 fGpu->forceRenderTargetFlush();
1091 }
1092}
1093
1094void GrContext::flushText() {
1095 if (kText_DrawCategory == fLastDrawCategory) {
1096 flushDrawBuffer();
1097 }
1098}
1099
1100void GrContext::flushDrawBuffer() {
1101#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1102 fDrawBuffer->playback(fGpu);
1103 fDrawBuffer->reset();
1104#endif
1105}
1106
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001107bool GrContext::readTexturePixels(GrTexture* texture,
1108 int left, int top, int width, int height,
1109 GrPixelConfig config, void* buffer) {
1110
1111 // TODO: code read pixels for textures that aren't rendertargets
1112
1113 this->flush();
1114 GrRenderTarget* target = texture->asRenderTarget();
1115 if (NULL != target) {
1116 return fGpu->readPixels(target,
1117 left, top, width, height,
1118 config, buffer);
1119 } else {
1120 return false;
1121 }
1122}
1123
1124bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1125 int left, int top, int width, int height,
1126 GrPixelConfig config, void* buffer) {
1127 uint32_t flushFlags = 0;
1128 if (NULL == target) {
1129 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1130 }
1131
1132 this->flush(flushFlags);
1133 return fGpu->readPixels(target,
1134 left, top, width, height,
1135 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001136}
1137
1138void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001139 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001140 size_t stride) {
1141
1142 // TODO: when underlying api has a direct way to do this we should use it
1143 // (e.g. glDrawPixels on desktop GL).
1144
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001145 const GrTextureDesc desc = {
1146 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001147 };
1148 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1149 if (NULL == texture) {
1150 return;
1151 }
1152
1153 this->flush(true);
1154
1155 GrAutoUnref aur(texture);
1156 GrDrawTarget::AutoStateRestore asr(fGpu);
1157
1158 GrMatrix matrix;
1159 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1160 fGpu->setViewMatrix(matrix);
1161
1162 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1163 fGpu->setAlpha(0xFF);
1164 fGpu->setBlendFunc(kOne_BlendCoeff,
1165 kZero_BlendCoeff);
1166 fGpu->setTexture(0, texture);
1167
1168 GrSamplerState sampler;
1169 sampler.setClampNoFilter();
1170 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1171 sampler.setMatrix(matrix);
1172 fGpu->setSamplerState(0, sampler);
1173
1174 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1175 static const int VCOUNT = 4;
1176
1177 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1178 if (!geo.succeeded()) {
1179 return;
1180 }
1181 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1182 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1183}
1184////////////////////////////////////////////////////////////////////////////////
1185
1186void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1187 target->setTexture(0, paint.getTexture());
1188 target->setSamplerState(0, paint.fSampler);
1189 target->setColor(paint.fColor);
1190
1191 if (paint.fDither) {
1192 target->enableState(GrDrawTarget::kDither_StateBit);
1193 } else {
1194 target->disableState(GrDrawTarget::kDither_StateBit);
1195 }
1196 if (paint.fAntiAlias) {
1197 target->enableState(GrDrawTarget::kAntialias_StateBit);
1198 } else {
1199 target->disableState(GrDrawTarget::kAntialias_StateBit);
1200 }
1201 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1202}
1203
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001204GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205 DrawCategory category) {
1206 if (category != fLastDrawCategory) {
1207 flushDrawBuffer();
1208 fLastDrawCategory = category;
1209 }
1210 SetPaint(paint, fGpu);
1211 GrDrawTarget* target = fGpu;
1212 switch (category) {
1213 case kText_DrawCategory:
1214#if DEFER_TEXT_RENDERING
1215 target = fDrawBuffer;
1216 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1217#else
1218 target = fGpu;
1219#endif
1220 break;
1221 case kUnbuffered_DrawCategory:
1222 target = fGpu;
1223 break;
1224 case kBuffered_DrawCategory:
1225 target = fDrawBuffer;
1226 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1227 break;
1228 }
1229 return target;
1230}
1231
1232////////////////////////////////////////////////////////////////////////////////
1233
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001235 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 fGpu->setRenderTarget(target);
1237}
1238
1239GrRenderTarget* GrContext::getRenderTarget() {
1240 return fGpu->getRenderTarget();
1241}
1242
1243const GrRenderTarget* GrContext::getRenderTarget() const {
1244 return fGpu->getRenderTarget();
1245}
1246
1247const GrMatrix& GrContext::getMatrix() const {
1248 return fGpu->getViewMatrix();
1249}
1250
1251void GrContext::setMatrix(const GrMatrix& m) {
1252 fGpu->setViewMatrix(m);
1253}
1254
1255void GrContext::concatMatrix(const GrMatrix& m) const {
1256 fGpu->preConcatViewMatrix(m);
1257}
1258
1259static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1260 intptr_t mask = 1 << shift;
1261 if (pred) {
1262 bits |= mask;
1263 } else {
1264 bits &= ~mask;
1265 }
1266 return bits;
1267}
1268
1269void GrContext::resetStats() {
1270 fGpu->resetStats();
1271}
1272
1273const GrGpu::Stats& GrContext::getStats() const {
1274 return fGpu->getStats();
1275}
1276
1277void GrContext::printStats() const {
1278 fGpu->printStats();
1279}
1280
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001281GrContext::GrContext(GrGpu* gpu) :
1282 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1283 gpu->supportsStencilWrapOps()) {
1284
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 fGpu = gpu;
1286 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001287 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001288
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001289 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1290 fGpu->setClipPathRenderer(fCustomPathRenderer);
1291
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1293 MAX_TEXTURE_CACHE_BYTES);
1294 fFontCache = new GrFontCache(fGpu);
1295
1296 fLastDrawCategory = kUnbuffered_DrawCategory;
1297
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001298 fDrawBuffer = NULL;
1299 fDrawBufferVBAllocPool = NULL;
1300 fDrawBufferIBAllocPool = NULL;
1301
bsalomon@google.com205d4602011-04-25 12:43:45 +00001302 fAAFillRectIndexBuffer = NULL;
1303 fAAStrokeRectIndexBuffer = NULL;
1304
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001305 this->setupDrawBuffer();
1306}
1307
1308void GrContext::setupDrawBuffer() {
1309
1310 GrAssert(NULL == fDrawBuffer);
1311 GrAssert(NULL == fDrawBufferVBAllocPool);
1312 GrAssert(NULL == fDrawBufferIBAllocPool);
1313
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001315 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001316 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1318 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001319 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001320 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001321 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1323
1324 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1325 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326#endif
1327
1328#if BATCH_RECT_TO_RECT
1329 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1330#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331}
1332
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1334 GrDrawTarget* target;
1335#if DEFER_TEXT_RENDERING
1336 target = prepareToDraw(paint, kText_DrawCategory);
1337#else
1338 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1339#endif
1340 SetPaint(paint, target);
1341 return target;
1342}
1343
1344const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1345 return fGpu->getQuadIndexBuffer();
1346}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001347
1348GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1349 GrPathIter* path,
1350 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001351 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001352 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1353 return fCustomPathRenderer;
1354 } else {
1355 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1356 return &fDefaultPathRenderer;
1357 }
1358}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001359