blob: 8acb3dcdd155da90e2e789e941e4ff5900126c00 [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 +0000419struct GrContext::OffscreenRecord {
420 OffscreenRecord() { fEntry = NULL; }
421 ~OffscreenRecord() { GrAssert(NULL == fEntry); }
422
423 GrTextureEntry* fEntry;
424 GrDrawTarget::SavedDrawState fSavedState;
425};
426
427bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
428 bool requireStencil,
429 OffscreenRecord* record) {
430#if !ENABLE_SSAA
431 return false;
432#endif
433
434 GrAssert(NULL == record->fEntry);
435
436 int width = this->getRenderTarget()->width();
437 int height = this->getRenderTarget()->height();
438
439 GrTextureDesc desc;
440 desc.fAALevel = kNone_GrAALevel;
441 if (requireStencil) {
442 desc.fFlags = kRenderTarget_GrTextureFlagBit;
443 } else {
444 desc.fFlags = kRenderTarget_GrTextureFlagBit |
445 kNoStencil_GrTextureFlagBit;
446 }
447
448 desc.fWidth = 2 * width;
449 desc.fHeight = 2 * height;
450 desc.fFormat = kRGBA_8888_GrPixelConfig;
451
452 record->fEntry = this->lockKeylessTexture(desc);
453 if (NULL == record->fEntry) {
454 return false;
455 }
456 GrRenderTarget* offscreen = record->fEntry->texture()->asRenderTarget();
457 GrAssert(NULL != offscreen);
458
459 target->saveCurrentDrawState(&record->fSavedState);
460
461 GrPaint tempPaint;
462 tempPaint.reset();
463 SetPaint(tempPaint, target);
464 target->setRenderTarget(offscreen);
465
466 GrMatrix scaleM;
467 scaleM.setScale(2 * GR_Scalar1, 2 * GR_Scalar1);
468 target->postConcatViewMatrix(scaleM);
469
470 // clip gets applied in second pass
471 target->disableState(GrDrawTarget::kClip_StateBit);
472
473 target->clear(0x0);
474 return true;
475}
476
477void GrContext::setupOffscreenAAPass2(GrDrawTarget* target,
478 const GrPaint& paint,
479 OffscreenRecord* record) {
480
481 GrAssert(NULL != record->fEntry);
482 GrTexture* offscreen = record->fEntry->texture();
483 GrAssert(NULL != offscreen);
484
485 target->restoreDrawState(record->fSavedState);
486
487 target->setViewMatrix(GrMatrix::I());
488 target->setTexture(kOffscreenStage, offscreen);
489 GrMatrix scaleM;
490
491 scaleM.setScale(GR_Scalar1 / target->getRenderTarget()->width(),
492 GR_Scalar1 / target->getRenderTarget()->height());
493
494 // use bilinear filtering to get downsample
495 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
496 GrSamplerState::kClamp_WrapMode,
497 scaleM, true);
498 target->setSamplerState(kOffscreenStage, sampler);
499}
500
501void GrContext::endOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
502 this->unlockTexture(record->fEntry);
503 record->fEntry = NULL;
504
505 target->restoreDrawState(record->fSavedState);
506}
507
508////////////////////////////////////////////////////////////////////////////////
509
bsalomon@google.com27847de2011-02-22 20:59:41 +0000510/* create a triangle strip that strokes the specified triangle. There are 8
511 unique vertices, but we repreat the last 2 to close up. Alternatively we
512 could use an indices array, and then only send 8 verts, but not sure that
513 would be faster.
514 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000515static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000516 GrScalar width) {
517 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000518 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000519
520 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
521 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
522 verts[2].set(rect.fRight - rad, rect.fTop + rad);
523 verts[3].set(rect.fRight + rad, rect.fTop - rad);
524 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
525 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
526 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
527 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
528 verts[8] = verts[0];
529 verts[9] = verts[1];
530}
531
bsalomon@google.com205d4602011-04-25 12:43:45 +0000532static GrColor getColorForMesh(const GrPaint& paint) {
533 if (NULL == paint.getTexture()) {
534 return paint.fColor;
535 } else {
536 unsigned a = GrColorUnpackA(paint.fColor);
537 return GrColorPackRGBA(a, a, a, a);
538 }
539}
540
541static void setInsetFan(GrPoint* pts, size_t stride,
542 const GrRect& r, GrScalar dx, GrScalar dy) {
543 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
544}
545
546static const uint16_t gFillAARectIdx[] = {
547 0, 1, 5, 5, 4, 0,
548 1, 2, 6, 6, 5, 1,
549 2, 3, 7, 7, 6, 2,
550 3, 0, 4, 4, 7, 3,
551 4, 5, 6, 6, 7, 4,
552};
553
554int GrContext::aaFillRectIndexCount() const {
555 return GR_ARRAY_COUNT(gFillAARectIdx);
556}
557
558GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
559 if (NULL == fAAFillRectIndexBuffer) {
560 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
561 false);
562 GrAssert(NULL != fAAFillRectIndexBuffer);
563#if GR_DEBUG
564 bool updated =
565#endif
566 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
567 sizeof(gFillAARectIdx));
568 GR_DEBUGASSERT(updated);
569 }
570 return fAAFillRectIndexBuffer;
571}
572
573static const uint16_t gStrokeAARectIdx[] = {
574 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
575 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
576 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
577 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
578
579 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
580 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
581 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
582 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
583
584 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
585 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
586 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
587 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
588};
589
590int GrContext::aaStrokeRectIndexCount() const {
591 return GR_ARRAY_COUNT(gStrokeAARectIdx);
592}
593
594GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
595 if (NULL == fAAStrokeRectIndexBuffer) {
596 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
597 false);
598 GrAssert(NULL != fAAStrokeRectIndexBuffer);
599#if GR_DEBUG
600 bool updated =
601#endif
602 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
603 sizeof(gStrokeAARectIdx));
604 GR_DEBUGASSERT(updated);
605 }
606 return fAAStrokeRectIndexBuffer;
607}
608
609void GrContext::fillAARect(GrDrawTarget* target,
610 const GrPaint& paint,
611 const GrRect& devRect) {
612
613 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
614 if (NULL != paint.getTexture()) {
615 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
616 }
617
618 size_t vsize = GrDrawTarget::VertexSize(layout);
619
620 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
621
622 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
623
624 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
625 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
626
627 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
628 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
629
630 verts += sizeof(GrPoint);
631 for (int i = 0; i < 4; ++i) {
632 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
633 }
634
635 GrColor innerColor = getColorForMesh(paint);
636 verts += 4 * vsize;
637 for (int i = 0; i < 4; ++i) {
638 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
639 }
640
641 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
642
643 target->drawIndexed(kTriangles_PrimitiveType, 0,
644 0, 8, this->aaFillRectIndexCount());
645}
646
647void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
648 const GrRect& devRect, const GrVec& devStrokeSize) {
649 const GrScalar& dx = devStrokeSize.fX;
650 const GrScalar& dy = devStrokeSize.fY;
651 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
652 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
653
654 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
655
656 if (NULL != paint.getTexture()) {
657 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
658 }
659
660 GrScalar spare;
661 {
662 GrScalar w = devRect.width() - dx;
663 GrScalar h = devRect.height() - dy;
664 spare = GrMin(w, h);
665 }
666
667 if (spare <= 0) {
668 GrRect r(devRect);
669 r.inset(-rx, -ry);
670 fillAARect(target, paint, r);
671 return;
672 }
673
674 size_t vsize = GrDrawTarget::VertexSize(layout);
675
676 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
677
678 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
679
680 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
681 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
682 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
683 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
684
685 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
686 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
687 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
688 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
689
690 verts += sizeof(GrPoint);
691 for (int i = 0; i < 4; ++i) {
692 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
693 }
694
695 GrColor innerColor = getColorForMesh(paint);
696 verts += 4 * vsize;
697 for (int i = 0; i < 8; ++i) {
698 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
699 }
700
701 verts += 8 * vsize;
702 for (int i = 0; i < 8; ++i) {
703 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
704 }
705
706 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
707 target->drawIndexed(kTriangles_PrimitiveType,
708 0, 0, 16, aaStrokeRectIndexCount());
709}
710
711static bool apply_aa_to_rect(GrDrawTarget* target,
712 GrGpu* gpu,
713 const GrPaint& paint,
714 const GrRect& rect,
715 GrScalar width,
716 const GrMatrix* matrix,
717 GrMatrix* combinedMatrix,
718 GrRect* devRect) {
719 // we use a simple alpha ramp to do aa on axis-aligned rects
720 // do AA with alpha ramp if the caller requested AA, the rect
721 // will be axis-aligned,the render target is not
722 // multisampled, and the rect won't land on integer coords.
723
724 if (!paint.fAntiAlias) {
725 return false;
726 }
727
728 if (target->getRenderTarget()->isMultisampled()) {
729 return false;
730 }
731
732 if (0 == width && gpu->supportsAALines()) {
733 return false;
734 }
735
736 if (!target->getViewMatrix().preservesAxisAlignment()) {
737 return false;
738 }
739
740 if (NULL != matrix &&
741 !matrix->preservesAxisAlignment()) {
742 return false;
743 }
744
745 *combinedMatrix = target->getViewMatrix();
746 if (NULL != matrix) {
747 combinedMatrix->preConcat(*matrix);
748 GrAssert(combinedMatrix->preservesAxisAlignment());
749 }
750
751 combinedMatrix->mapRect(devRect, rect);
752 devRect->sort();
753
754 if (width < 0) {
755 return !devRect->isIRect();
756 } else {
757 return true;
758 }
759}
760
bsalomon@google.com27847de2011-02-22 20:59:41 +0000761void GrContext::drawRect(const GrPaint& paint,
762 const GrRect& rect,
763 GrScalar width,
764 const GrMatrix* matrix) {
765
766 bool textured = NULL != paint.getTexture();
767
768 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
769
bsalomon@google.com205d4602011-04-25 12:43:45 +0000770 GrRect devRect = rect;
771 GrMatrix combinedMatrix;
772 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
773 &combinedMatrix, &devRect);
774
775 if (doAA) {
776 GrDrawTarget::AutoViewMatrixRestore avm(target);
777 if (textured) {
778 GrMatrix inv;
779 if (combinedMatrix.invert(&inv)) {
780 target->preConcatSamplerMatrix(0, inv);
781 }
782 }
783 target->setViewMatrix(GrMatrix::I());
784 if (width >= 0) {
785 GrVec strokeSize;;
786 if (width > 0) {
787 strokeSize.set(width, width);
788 combinedMatrix.mapVec(&strokeSize);
789 strokeSize.setAbs(strokeSize);
790 } else {
791 strokeSize.set(GR_Scalar1, GR_Scalar1);
792 }
793 strokeAARect(target, paint, devRect, strokeSize);
794 } else {
795 fillAARect(target, paint, devRect);
796 }
797 return;
798 }
799
bsalomon@google.com27847de2011-02-22 20:59:41 +0000800 if (width >= 0) {
801 // TODO: consider making static vertex buffers for these cases.
802 // Hairline could be done by just adding closing vertex to
803 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000804 GrVertexLayout layout = textured ?
805 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
806 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000807 static const int worstCaseVertCount = 10;
808 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
809
810 if (!geo.succeeded()) {
811 return;
812 }
813
814 GrPrimitiveType primType;
815 int vertCount;
816 GrPoint* vertex = geo.positions();
817
818 if (width > 0) {
819 vertCount = 10;
820 primType = kTriangleStrip_PrimitiveType;
821 setStrokeRectStrip(vertex, rect, width);
822 } else {
823 // hairline
824 vertCount = 5;
825 primType = kLineStrip_PrimitiveType;
826 vertex[0].set(rect.fLeft, rect.fTop);
827 vertex[1].set(rect.fRight, rect.fTop);
828 vertex[2].set(rect.fRight, rect.fBottom);
829 vertex[3].set(rect.fLeft, rect.fBottom);
830 vertex[4].set(rect.fLeft, rect.fTop);
831 }
832
833 GrDrawTarget::AutoViewMatrixRestore avmr;
834 if (NULL != matrix) {
835 avmr.set(target);
836 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000837 if (textured) {
838 target->preConcatSamplerMatrix(0, *matrix);
839 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000840 }
841
842 target->drawNonIndexed(primType, 0, vertCount);
843 } else {
844 #if GR_STATIC_RECT_VB
845 GrVertexLayout layout = (textured) ?
846 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
847 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000848 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000849 fGpu->getUnitSquareVertexBuffer());
850 GrDrawTarget::AutoViewMatrixRestore avmr(target);
851 GrMatrix m;
852 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000853 0, rect.height(), rect.fTop,
854 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000855
856 if (NULL != matrix) {
857 m.postConcat(*matrix);
858 }
859
860 target->preConcatViewMatrix(m);
861
862 if (textured) {
863 target->preConcatSamplerMatrix(0, m);
864 }
865 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
866 #else
867 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
868 #endif
869 }
870}
871
872void GrContext::drawRectToRect(const GrPaint& paint,
873 const GrRect& dstRect,
874 const GrRect& srcRect,
875 const GrMatrix* dstMatrix,
876 const GrMatrix* srcMatrix) {
877
878 if (NULL == paint.getTexture()) {
879 drawRect(paint, dstRect, -1, dstMatrix);
880 return;
881 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000882
bsalomon@google.com27847de2011-02-22 20:59:41 +0000883 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
884
885#if GR_STATIC_RECT_VB
886 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
887
888 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
889 GrDrawTarget::AutoViewMatrixRestore avmr(target);
890
891 GrMatrix m;
892
893 m.setAll(dstRect.width(), 0, dstRect.fLeft,
894 0, dstRect.height(), dstRect.fTop,
895 0, 0, GrMatrix::I()[8]);
896 if (NULL != dstMatrix) {
897 m.postConcat(*dstMatrix);
898 }
899 target->preConcatViewMatrix(m);
900
901 m.setAll(srcRect.width(), 0, srcRect.fLeft,
902 0, srcRect.height(), srcRect.fTop,
903 0, 0, GrMatrix::I()[8]);
904 if (NULL != srcMatrix) {
905 m.postConcat(*srcMatrix);
906 }
907 target->preConcatSamplerMatrix(0, m);
908
909 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
910 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
911#else
912
913 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000914#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000915 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000916#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000917 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
918#endif
919
920 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
921 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
922 srcRects[0] = &srcRect;
923 srcMatrices[0] = srcMatrix;
924
925 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
926#endif
927}
928
929void GrContext::drawVertices(const GrPaint& paint,
930 GrPrimitiveType primitiveType,
931 int vertexCount,
932 const GrPoint positions[],
933 const GrPoint texCoords[],
934 const GrColor colors[],
935 const uint16_t indices[],
936 int indexCount) {
937 GrVertexLayout layout = 0;
938 int vertexSize = sizeof(GrPoint);
939
940 GrDrawTarget::AutoReleaseGeometry geo;
941
942 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
943
944 if (NULL != paint.getTexture()) {
945 if (NULL == texCoords) {
946 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
947 } else {
948 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
949 vertexSize += sizeof(GrPoint);
950 }
951 }
952
953 if (NULL != colors) {
954 layout |= GrDrawTarget::kColor_VertexLayoutBit;
955 vertexSize += sizeof(GrColor);
956 }
957
958 if (sizeof(GrPoint) != vertexSize) {
959 if (!geo.set(target, layout, vertexCount, 0)) {
960 GrPrintf("Failed to get space for vertices!");
961 return;
962 }
963 int texOffsets[GrDrawTarget::kMaxTexCoords];
964 int colorOffset;
965 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
966 texOffsets,
967 &colorOffset);
968 void* curVertex = geo.vertices();
969
970 for (int i = 0; i < vertexCount; ++i) {
971 *((GrPoint*)curVertex) = positions[i];
972
973 if (texOffsets[0] > 0) {
974 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
975 }
976 if (colorOffset > 0) {
977 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
978 }
979 curVertex = (void*)((intptr_t)curVertex + vsize);
980 }
981 } else {
982 target->setVertexSourceToArray(layout, positions, vertexCount);
983 }
984
985 if (NULL != indices) {
986 target->setIndexSourceToArray(indices, indexCount);
987 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
988 } else {
989 target->drawNonIndexed(primitiveType, 0, vertexCount);
990 }
991}
992
993
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000994///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +0000995
996void GrContext::drawPath(const GrPaint& paint,
997 GrPathIter* path,
998 GrPathFill fill,
999 const GrPoint* translate) {
1000
bsalomon@google.com27847de2011-02-22 20:59:41 +00001001 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001002 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001003
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001004 if (paint.fAntiAlias &&
1005 !this->getRenderTarget()->isMultisampled() &&
1006 !pr->supportsAA()) {
1007
1008 OffscreenRecord record;
1009 bool needsStencil = pr->requiresStencilPass(target, path, fill);
1010 if (this->setupOffscreenAAPass1(target, needsStencil, &record)) {
1011 pr->drawPath(target, 0, path, fill, translate);
1012
1013 this->setupOffscreenAAPass2(target, paint, &record);
1014
1015 int stages = (NULL != paint.getTexture()) ? 0x1 : 0x0;
1016 stages |= (1 << kOffscreenStage);
1017 GrRect dstRect(0, 0,
1018 target->getRenderTarget()->width(),
1019 target->getRenderTarget()->height());
1020 target->drawSimpleRect(dstRect, NULL, stages);
1021
1022 this->endOffscreenAA(target, &record);
1023 return;
1024 }
1025 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026 GrDrawTarget::StageBitfield enabledStages = 0;
1027 if (NULL != paint.getTexture()) {
1028 enabledStages |= 1;
1029 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001030
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001031 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001032}
bsalomon@google.comd302f142011-03-03 13:54:13 +00001033void GrContext::drawPath(const GrPaint& paint,
1034 const GrPath& path,
1035 GrPathFill fill,
1036 const GrPoint* translate) {
1037 GrPath::Iter iter(path);
1038 this->drawPath(paint, &iter, fill, translate);
1039}
1040
1041
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042////////////////////////////////////////////////////////////////////////////////
1043
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001044void GrContext::flush(int flagsBitfield) {
1045 if (kDiscard_FlushBit & flagsBitfield) {
1046 fDrawBuffer->reset();
1047 } else {
1048 flushDrawBuffer();
1049 }
1050
1051 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001052 fGpu->forceRenderTargetFlush();
1053 }
1054}
1055
1056void GrContext::flushText() {
1057 if (kText_DrawCategory == fLastDrawCategory) {
1058 flushDrawBuffer();
1059 }
1060}
1061
1062void GrContext::flushDrawBuffer() {
1063#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1064 fDrawBuffer->playback(fGpu);
1065 fDrawBuffer->reset();
1066#endif
1067}
1068
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001069bool GrContext::readTexturePixels(GrTexture* texture,
1070 int left, int top, int width, int height,
1071 GrPixelConfig config, void* buffer) {
1072
1073 // TODO: code read pixels for textures that aren't rendertargets
1074
1075 this->flush();
1076 GrRenderTarget* target = texture->asRenderTarget();
1077 if (NULL != target) {
1078 return fGpu->readPixels(target,
1079 left, top, width, height,
1080 config, buffer);
1081 } else {
1082 return false;
1083 }
1084}
1085
1086bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1087 int left, int top, int width, int height,
1088 GrPixelConfig config, void* buffer) {
1089 uint32_t flushFlags = 0;
1090 if (NULL == target) {
1091 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1092 }
1093
1094 this->flush(flushFlags);
1095 return fGpu->readPixels(target,
1096 left, top, width, height,
1097 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001098}
1099
1100void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001101 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 size_t stride) {
1103
1104 // TODO: when underlying api has a direct way to do this we should use it
1105 // (e.g. glDrawPixels on desktop GL).
1106
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001107 const GrTextureDesc desc = {
1108 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109 };
1110 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1111 if (NULL == texture) {
1112 return;
1113 }
1114
1115 this->flush(true);
1116
1117 GrAutoUnref aur(texture);
1118 GrDrawTarget::AutoStateRestore asr(fGpu);
1119
1120 GrMatrix matrix;
1121 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1122 fGpu->setViewMatrix(matrix);
1123
1124 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1125 fGpu->setAlpha(0xFF);
1126 fGpu->setBlendFunc(kOne_BlendCoeff,
1127 kZero_BlendCoeff);
1128 fGpu->setTexture(0, texture);
1129
1130 GrSamplerState sampler;
1131 sampler.setClampNoFilter();
1132 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1133 sampler.setMatrix(matrix);
1134 fGpu->setSamplerState(0, sampler);
1135
1136 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1137 static const int VCOUNT = 4;
1138
1139 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1140 if (!geo.succeeded()) {
1141 return;
1142 }
1143 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1144 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1145}
1146////////////////////////////////////////////////////////////////////////////////
1147
1148void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1149 target->setTexture(0, paint.getTexture());
1150 target->setSamplerState(0, paint.fSampler);
1151 target->setColor(paint.fColor);
1152
1153 if (paint.fDither) {
1154 target->enableState(GrDrawTarget::kDither_StateBit);
1155 } else {
1156 target->disableState(GrDrawTarget::kDither_StateBit);
1157 }
1158 if (paint.fAntiAlias) {
1159 target->enableState(GrDrawTarget::kAntialias_StateBit);
1160 } else {
1161 target->disableState(GrDrawTarget::kAntialias_StateBit);
1162 }
1163 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1164}
1165
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001166GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167 DrawCategory category) {
1168 if (category != fLastDrawCategory) {
1169 flushDrawBuffer();
1170 fLastDrawCategory = category;
1171 }
1172 SetPaint(paint, fGpu);
1173 GrDrawTarget* target = fGpu;
1174 switch (category) {
1175 case kText_DrawCategory:
1176#if DEFER_TEXT_RENDERING
1177 target = fDrawBuffer;
1178 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1179#else
1180 target = fGpu;
1181#endif
1182 break;
1183 case kUnbuffered_DrawCategory:
1184 target = fGpu;
1185 break;
1186 case kBuffered_DrawCategory:
1187 target = fDrawBuffer;
1188 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1189 break;
1190 }
1191 return target;
1192}
1193
1194////////////////////////////////////////////////////////////////////////////////
1195
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001197 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198 fGpu->setRenderTarget(target);
1199}
1200
1201GrRenderTarget* GrContext::getRenderTarget() {
1202 return fGpu->getRenderTarget();
1203}
1204
1205const GrRenderTarget* GrContext::getRenderTarget() const {
1206 return fGpu->getRenderTarget();
1207}
1208
1209const GrMatrix& GrContext::getMatrix() const {
1210 return fGpu->getViewMatrix();
1211}
1212
1213void GrContext::setMatrix(const GrMatrix& m) {
1214 fGpu->setViewMatrix(m);
1215}
1216
1217void GrContext::concatMatrix(const GrMatrix& m) const {
1218 fGpu->preConcatViewMatrix(m);
1219}
1220
1221static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1222 intptr_t mask = 1 << shift;
1223 if (pred) {
1224 bits |= mask;
1225 } else {
1226 bits &= ~mask;
1227 }
1228 return bits;
1229}
1230
1231void GrContext::resetStats() {
1232 fGpu->resetStats();
1233}
1234
1235const GrGpu::Stats& GrContext::getStats() const {
1236 return fGpu->getStats();
1237}
1238
1239void GrContext::printStats() const {
1240 fGpu->printStats();
1241}
1242
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001243GrContext::GrContext(GrGpu* gpu) :
1244 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1245 gpu->supportsStencilWrapOps()) {
1246
bsalomon@google.com27847de2011-02-22 20:59:41 +00001247 fGpu = gpu;
1248 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001249 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001250
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001251 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1252 fGpu->setClipPathRenderer(fCustomPathRenderer);
1253
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1255 MAX_TEXTURE_CACHE_BYTES);
1256 fFontCache = new GrFontCache(fGpu);
1257
1258 fLastDrawCategory = kUnbuffered_DrawCategory;
1259
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001260 fDrawBuffer = NULL;
1261 fDrawBufferVBAllocPool = NULL;
1262 fDrawBufferIBAllocPool = NULL;
1263
bsalomon@google.com205d4602011-04-25 12:43:45 +00001264 fAAFillRectIndexBuffer = NULL;
1265 fAAStrokeRectIndexBuffer = NULL;
1266
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001267 this->setupDrawBuffer();
1268}
1269
1270void GrContext::setupDrawBuffer() {
1271
1272 GrAssert(NULL == fDrawBuffer);
1273 GrAssert(NULL == fDrawBufferVBAllocPool);
1274 GrAssert(NULL == fDrawBufferIBAllocPool);
1275
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001277 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001278 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1280 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001281 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001282 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001283 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1285
1286 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1287 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288#endif
1289
1290#if BATCH_RECT_TO_RECT
1291 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1292#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293}
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1296 GrDrawTarget* target;
1297#if DEFER_TEXT_RENDERING
1298 target = prepareToDraw(paint, kText_DrawCategory);
1299#else
1300 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1301#endif
1302 SetPaint(paint, target);
1303 return target;
1304}
1305
1306const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1307 return fGpu->getQuadIndexBuffer();
1308}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001309
1310GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1311 GrPathIter* path,
1312 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001313 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001314 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1315 return fCustomPathRenderer;
1316 } else {
1317 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1318 return &fDefaultPathRenderer;
1319 }
1320}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001321