blob: 2263172c52a713147e968d17d001f598f4abaab0 [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.com8295dc12011-05-02 12:53:34 +000029#define ENABLE_OFFSCREEN_AA 0
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000030
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.com8295dc12011-05-02 12:53:34 +0000417bool GrContext::doOffscreenAA(GrDrawTarget* target,
418 const GrPaint& paint,
419 bool isLines) const {
420#if !ENABLE_OFFSCREEN_AA
421 return false;
422#else
423 if (!paint.fAntiAlias) {
424 return false;
425 }
426 if (isLines && fGpu->supportsAALines()) {
427 return false;
428 }
429 if (target->getRenderTarget()->isMultisampled()) {
430 return false;
431 }
432 // we have to be sure that the blend equation is expressible
433 // as simple src / dst coeffecients when the source
434 // is already modulated by the coverage fraction.
435 // We could use dual-source blending to get the correct per-pixel
436 // dst coeffecient for the remaining cases.
437 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
438 kOne_BlendCoeff != paint.fDstBlendCoeff &&
439 kISA_BlendCoeff != paint.fDstBlendCoeff) {
440 return false;
441 }
442 return true;
443#endif
444}
445
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000446bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
447 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000448 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000449 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000450 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000451
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000452 GrAssert(NULL == record->fEntry0);
453 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000454
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000455 int boundW = boundRect.width();
456 int boundH = boundRect.height();
457 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000458
459 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000460 if (requireStencil) {
461 desc.fFlags = kRenderTarget_GrTextureFlagBit;
462 } else {
463 desc.fFlags = kRenderTarget_GrTextureFlagBit |
464 kNoStencil_GrTextureFlagBit;
465 }
466
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000467 desc.fFormat = kRGBA_8888_GrPixelConfig;
468
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000469 int scale;
470 // Using MSAA seems to be slower for some yet unknown reason.
471 if (false && fGpu->supportsFullsceneAA()) {
472 scale = GR_Scalar1;
473 desc.fAALevel = kMed_GrAALevel;
474 } else {
475 scale = 4;
476 desc.fAALevel = kNone_GrAALevel;
477 }
478
479 desc.fWidth = scale * size;
480 desc.fHeight = scale * size;
481
482 record->fEntry0 = this->lockKeylessTexture(desc);
483
484 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000485 return false;
486 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000487
488 if (scale > 1) {
489 desc.fWidth /= 2;
490 desc.fHeight /= 2;
491 record->fEntry1 = this->lockKeylessTexture(desc);
492 if (NULL == record->fEntry1) {
493 this->unlockTexture(record->fEntry0);
494 record->fEntry0 = NULL;
495 return false;
496 }
497 }
498
499 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
500 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000501
502 target->saveCurrentDrawState(&record->fSavedState);
503
504 GrPaint tempPaint;
505 tempPaint.reset();
506 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000507 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000508
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000509 GrMatrix transM;
510 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
511 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000512 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000513 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000514 target->postConcatViewMatrix(scaleM);
515
516 // clip gets applied in second pass
517 target->disableState(GrDrawTarget::kClip_StateBit);
518
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000519 GrIRect clear(0, 0, scale * boundW, scale * boundH);
520 target->clear(&clear, 0x0);
521
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000522 return true;
523}
524
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000525void GrContext::offscreenAAPass2(GrDrawTarget* target,
526 const GrPaint& paint,
527 const GrIRect& boundRect,
528 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000529
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000530 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000531
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000532 bool downsample = NULL != record->fEntry1;
533
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000534 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000535 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000536 GrSamplerState::kClamp_WrapMode, true);
537
538 GrTexture* src = record->fEntry0->texture();
539 int scale;
540
541 if (downsample) {
542 scale = 2;
543 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
544
545 // Do 2x2 downsample from first to second
546 target->setTexture(kOffscreenStage, src);
547 target->setRenderTarget(dst);
548 target->setViewMatrix(GrMatrix::I());
549 sampleM.setScale(scale * GR_Scalar1 / src->width(),
550 scale * GR_Scalar1 / src->height());
551 sampler.setMatrix(sampleM);
552 target->setSamplerState(kOffscreenStage, sampler);
553 GrRect rect(0, 0,
554 scale * boundRect.width(),
555 scale * boundRect.height());
556 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
557
558 src = record->fEntry1->texture();
559 } else {
560 scale = 1;
561 GrIRect rect(0, 0, boundRect.width(), boundRect.height());
562 src->asRenderTarget()->overrideResolveRect(rect);
563 }
564
565 // setup for draw back to main RT
566 target->restoreDrawState(record->fSavedState);
567 if (NULL != paint.getTexture()) {
568 GrMatrix invVM;
569 if (target->getViewInverse(&invVM)) {
570 target->preConcatSamplerMatrix(0, invVM);
571 }
572 }
573 target->setViewMatrix(GrMatrix::I());
574
575 target->setTexture(kOffscreenStage, src);
576 sampleM.setScale(scale * GR_Scalar1 / src->width(),
577 scale * GR_Scalar1 / src->height());
578 sampler.setMatrix(sampleM);
579 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
580 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000581 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000582
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000583 GrRect dstRect(boundRect);
584 int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1);
585 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000586
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000587 this->unlockTexture(record->fEntry0);
588 record->fEntry0 = NULL;
589 if (downsample) {
590 this->unlockTexture(record->fEntry1);
591 record->fEntry1 = NULL;
592 }
593 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000594}
595
596////////////////////////////////////////////////////////////////////////////////
597
bsalomon@google.com27847de2011-02-22 20:59:41 +0000598/* create a triangle strip that strokes the specified triangle. There are 8
599 unique vertices, but we repreat the last 2 to close up. Alternatively we
600 could use an indices array, and then only send 8 verts, but not sure that
601 would be faster.
602 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000603static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604 GrScalar width) {
605 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000606 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000607
608 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
609 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
610 verts[2].set(rect.fRight - rad, rect.fTop + rad);
611 verts[3].set(rect.fRight + rad, rect.fTop - rad);
612 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
613 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
614 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
615 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
616 verts[8] = verts[0];
617 verts[9] = verts[1];
618}
619
bsalomon@google.com205d4602011-04-25 12:43:45 +0000620static GrColor getColorForMesh(const GrPaint& paint) {
621 if (NULL == paint.getTexture()) {
622 return paint.fColor;
623 } else {
624 unsigned a = GrColorUnpackA(paint.fColor);
625 return GrColorPackRGBA(a, a, a, a);
626 }
627}
628
629static void setInsetFan(GrPoint* pts, size_t stride,
630 const GrRect& r, GrScalar dx, GrScalar dy) {
631 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
632}
633
634static const uint16_t gFillAARectIdx[] = {
635 0, 1, 5, 5, 4, 0,
636 1, 2, 6, 6, 5, 1,
637 2, 3, 7, 7, 6, 2,
638 3, 0, 4, 4, 7, 3,
639 4, 5, 6, 6, 7, 4,
640};
641
642int GrContext::aaFillRectIndexCount() const {
643 return GR_ARRAY_COUNT(gFillAARectIdx);
644}
645
646GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
647 if (NULL == fAAFillRectIndexBuffer) {
648 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
649 false);
650 GrAssert(NULL != fAAFillRectIndexBuffer);
651#if GR_DEBUG
652 bool updated =
653#endif
654 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
655 sizeof(gFillAARectIdx));
656 GR_DEBUGASSERT(updated);
657 }
658 return fAAFillRectIndexBuffer;
659}
660
661static const uint16_t gStrokeAARectIdx[] = {
662 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
663 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
664 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
665 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
666
667 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
668 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
669 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
670 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
671
672 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
673 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
674 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
675 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
676};
677
678int GrContext::aaStrokeRectIndexCount() const {
679 return GR_ARRAY_COUNT(gStrokeAARectIdx);
680}
681
682GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
683 if (NULL == fAAStrokeRectIndexBuffer) {
684 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
685 false);
686 GrAssert(NULL != fAAStrokeRectIndexBuffer);
687#if GR_DEBUG
688 bool updated =
689#endif
690 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
691 sizeof(gStrokeAARectIdx));
692 GR_DEBUGASSERT(updated);
693 }
694 return fAAStrokeRectIndexBuffer;
695}
696
697void GrContext::fillAARect(GrDrawTarget* target,
698 const GrPaint& paint,
699 const GrRect& devRect) {
700
701 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
702 if (NULL != paint.getTexture()) {
703 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
704 }
705
706 size_t vsize = GrDrawTarget::VertexSize(layout);
707
708 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
709
710 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
711
712 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
713 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
714
715 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
716 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
717
718 verts += sizeof(GrPoint);
719 for (int i = 0; i < 4; ++i) {
720 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
721 }
722
723 GrColor innerColor = getColorForMesh(paint);
724 verts += 4 * vsize;
725 for (int i = 0; i < 4; ++i) {
726 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
727 }
728
729 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
730
731 target->drawIndexed(kTriangles_PrimitiveType, 0,
732 0, 8, this->aaFillRectIndexCount());
733}
734
735void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
736 const GrRect& devRect, const GrVec& devStrokeSize) {
737 const GrScalar& dx = devStrokeSize.fX;
738 const GrScalar& dy = devStrokeSize.fY;
739 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
740 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
741
742 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
743
744 if (NULL != paint.getTexture()) {
745 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
746 }
747
748 GrScalar spare;
749 {
750 GrScalar w = devRect.width() - dx;
751 GrScalar h = devRect.height() - dy;
752 spare = GrMin(w, h);
753 }
754
755 if (spare <= 0) {
756 GrRect r(devRect);
757 r.inset(-rx, -ry);
758 fillAARect(target, paint, r);
759 return;
760 }
761
762 size_t vsize = GrDrawTarget::VertexSize(layout);
763
764 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
765
766 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
767
768 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
769 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
770 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
771 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
772
773 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
774 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
775 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
776 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
777
778 verts += sizeof(GrPoint);
779 for (int i = 0; i < 4; ++i) {
780 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
781 }
782
783 GrColor innerColor = getColorForMesh(paint);
784 verts += 4 * vsize;
785 for (int i = 0; i < 8; ++i) {
786 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
787 }
788
789 verts += 8 * vsize;
790 for (int i = 0; i < 8; ++i) {
791 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
792 }
793
794 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
795 target->drawIndexed(kTriangles_PrimitiveType,
796 0, 0, 16, aaStrokeRectIndexCount());
797}
798
799static bool apply_aa_to_rect(GrDrawTarget* target,
800 GrGpu* gpu,
801 const GrPaint& paint,
802 const GrRect& rect,
803 GrScalar width,
804 const GrMatrix* matrix,
805 GrMatrix* combinedMatrix,
806 GrRect* devRect) {
807 // we use a simple alpha ramp to do aa on axis-aligned rects
808 // do AA with alpha ramp if the caller requested AA, the rect
809 // will be axis-aligned,the render target is not
810 // multisampled, and the rect won't land on integer coords.
811
812 if (!paint.fAntiAlias) {
813 return false;
814 }
815
816 if (target->getRenderTarget()->isMultisampled()) {
817 return false;
818 }
819
820 if (0 == width && gpu->supportsAALines()) {
821 return false;
822 }
823
824 if (!target->getViewMatrix().preservesAxisAlignment()) {
825 return false;
826 }
827
828 if (NULL != matrix &&
829 !matrix->preservesAxisAlignment()) {
830 return false;
831 }
832
833 *combinedMatrix = target->getViewMatrix();
834 if (NULL != matrix) {
835 combinedMatrix->preConcat(*matrix);
836 GrAssert(combinedMatrix->preservesAxisAlignment());
837 }
838
839 combinedMatrix->mapRect(devRect, rect);
840 devRect->sort();
841
842 if (width < 0) {
843 return !devRect->isIRect();
844 } else {
845 return true;
846 }
847}
848
bsalomon@google.com27847de2011-02-22 20:59:41 +0000849void GrContext::drawRect(const GrPaint& paint,
850 const GrRect& rect,
851 GrScalar width,
852 const GrMatrix* matrix) {
853
854 bool textured = NULL != paint.getTexture();
855
856 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
857
bsalomon@google.com205d4602011-04-25 12:43:45 +0000858 GrRect devRect = rect;
859 GrMatrix combinedMatrix;
860 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
861 &combinedMatrix, &devRect);
862
863 if (doAA) {
864 GrDrawTarget::AutoViewMatrixRestore avm(target);
865 if (textured) {
866 GrMatrix inv;
867 if (combinedMatrix.invert(&inv)) {
868 target->preConcatSamplerMatrix(0, inv);
869 }
870 }
871 target->setViewMatrix(GrMatrix::I());
872 if (width >= 0) {
873 GrVec strokeSize;;
874 if (width > 0) {
875 strokeSize.set(width, width);
876 combinedMatrix.mapVec(&strokeSize);
877 strokeSize.setAbs(strokeSize);
878 } else {
879 strokeSize.set(GR_Scalar1, GR_Scalar1);
880 }
881 strokeAARect(target, paint, devRect, strokeSize);
882 } else {
883 fillAARect(target, paint, devRect);
884 }
885 return;
886 }
887
bsalomon@google.com27847de2011-02-22 20:59:41 +0000888 if (width >= 0) {
889 // TODO: consider making static vertex buffers for these cases.
890 // Hairline could be done by just adding closing vertex to
891 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000892 GrVertexLayout layout = textured ?
893 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
894 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000895 static const int worstCaseVertCount = 10;
896 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
897
898 if (!geo.succeeded()) {
899 return;
900 }
901
902 GrPrimitiveType primType;
903 int vertCount;
904 GrPoint* vertex = geo.positions();
905
906 if (width > 0) {
907 vertCount = 10;
908 primType = kTriangleStrip_PrimitiveType;
909 setStrokeRectStrip(vertex, rect, width);
910 } else {
911 // hairline
912 vertCount = 5;
913 primType = kLineStrip_PrimitiveType;
914 vertex[0].set(rect.fLeft, rect.fTop);
915 vertex[1].set(rect.fRight, rect.fTop);
916 vertex[2].set(rect.fRight, rect.fBottom);
917 vertex[3].set(rect.fLeft, rect.fBottom);
918 vertex[4].set(rect.fLeft, rect.fTop);
919 }
920
921 GrDrawTarget::AutoViewMatrixRestore avmr;
922 if (NULL != matrix) {
923 avmr.set(target);
924 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000925 if (textured) {
926 target->preConcatSamplerMatrix(0, *matrix);
927 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000928 }
929
930 target->drawNonIndexed(primType, 0, vertCount);
931 } else {
932 #if GR_STATIC_RECT_VB
933 GrVertexLayout layout = (textured) ?
934 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
935 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000936 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000937 fGpu->getUnitSquareVertexBuffer());
938 GrDrawTarget::AutoViewMatrixRestore avmr(target);
939 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000940 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000941 0, rect.height(), rect.fTop,
942 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000943
944 if (NULL != matrix) {
945 m.postConcat(*matrix);
946 }
947
948 target->preConcatViewMatrix(m);
949
950 if (textured) {
951 target->preConcatSamplerMatrix(0, m);
952 }
953 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
954 #else
955 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
956 #endif
957 }
958}
959
960void GrContext::drawRectToRect(const GrPaint& paint,
961 const GrRect& dstRect,
962 const GrRect& srcRect,
963 const GrMatrix* dstMatrix,
964 const GrMatrix* srcMatrix) {
965
966 if (NULL == paint.getTexture()) {
967 drawRect(paint, dstRect, -1, dstMatrix);
968 return;
969 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000970
bsalomon@google.com27847de2011-02-22 20:59:41 +0000971 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
972
973#if GR_STATIC_RECT_VB
974 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
975
976 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
977 GrDrawTarget::AutoViewMatrixRestore avmr(target);
978
979 GrMatrix m;
980
981 m.setAll(dstRect.width(), 0, dstRect.fLeft,
982 0, dstRect.height(), dstRect.fTop,
983 0, 0, GrMatrix::I()[8]);
984 if (NULL != dstMatrix) {
985 m.postConcat(*dstMatrix);
986 }
987 target->preConcatViewMatrix(m);
988
989 m.setAll(srcRect.width(), 0, srcRect.fLeft,
990 0, srcRect.height(), srcRect.fTop,
991 0, 0, GrMatrix::I()[8]);
992 if (NULL != srcMatrix) {
993 m.postConcat(*srcMatrix);
994 }
995 target->preConcatSamplerMatrix(0, m);
996
997 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
998 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
999#else
1000
1001 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001002#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001003 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001004#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001005 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1006#endif
1007
1008 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1009 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1010 srcRects[0] = &srcRect;
1011 srcMatrices[0] = srcMatrix;
1012
1013 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1014#endif
1015}
1016
1017void GrContext::drawVertices(const GrPaint& paint,
1018 GrPrimitiveType primitiveType,
1019 int vertexCount,
1020 const GrPoint positions[],
1021 const GrPoint texCoords[],
1022 const GrColor colors[],
1023 const uint16_t indices[],
1024 int indexCount) {
1025 GrVertexLayout layout = 0;
1026 int vertexSize = sizeof(GrPoint);
1027
1028 GrDrawTarget::AutoReleaseGeometry geo;
1029
1030 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1031
1032 if (NULL != paint.getTexture()) {
1033 if (NULL == texCoords) {
1034 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1035 } else {
1036 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
1037 vertexSize += sizeof(GrPoint);
1038 }
1039 }
1040
1041 if (NULL != colors) {
1042 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1043 vertexSize += sizeof(GrColor);
1044 }
1045
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001046 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001047 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001048 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001049
bsalomon@google.com27847de2011-02-22 20:59:41 +00001050 if (sizeof(GrPoint) != vertexSize) {
1051 if (!geo.set(target, layout, vertexCount, 0)) {
1052 GrPrintf("Failed to get space for vertices!");
1053 return;
1054 }
1055 int texOffsets[GrDrawTarget::kMaxTexCoords];
1056 int colorOffset;
1057 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1058 texOffsets,
1059 &colorOffset);
1060 void* curVertex = geo.vertices();
1061
1062 for (int i = 0; i < vertexCount; ++i) {
1063 *((GrPoint*)curVertex) = positions[i];
1064
1065 if (texOffsets[0] > 0) {
1066 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1067 }
1068 if (colorOffset > 0) {
1069 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1070 }
1071 curVertex = (void*)((intptr_t)curVertex + vsize);
1072 }
1073 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001074 // we don't do offscreen AA when we have per-vertex tex coords or colors
1075 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1076 GrRect b;
1077 b.setBounds(positions, vertexCount);
1078 target->getViewMatrix().mapRect(&b);
1079 b.roundOut(&bounds);
1080
1081 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1082 doAA = true;
1083 }
1084 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001085 target->setVertexSourceToArray(layout, positions, vertexCount);
1086 }
1087
1088 if (NULL != indices) {
1089 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001090 }
1091
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001092 if (NULL != indices) {
1093 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001094 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001095 target->drawNonIndexed(primitiveType, 0, vertexCount);
1096 }
1097
1098 if (doAA) {
1099 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001100 }
1101}
1102
1103
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001104///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105
1106void GrContext::drawPath(const GrPaint& paint,
1107 GrPathIter* path,
1108 GrPathFill fill,
1109 const GrPoint* translate) {
1110
bsalomon@google.com27847de2011-02-22 20:59:41 +00001111 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001112 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001113
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001114 if (!IsFillInverted(fill) && // will be relaxed soon
1115 !pr->supportsAA(target, path, fill) &&
1116 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001117
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001118 OffscreenRecord record;
1119 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001120
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001121 // compute bounds as intersection of rt size, clip, and path
1122 GrIRect bound(0, 0,
1123 target->getRenderTarget()->width(),
1124 target->getRenderTarget()->height());
1125 if (target->getClip().hasConservativeBounds()) {
1126 GrIRect clipIBounds;
1127 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1128 if (!bound.intersectWith(clipIBounds)) {
1129 return;
1130 }
1131 }
1132 GrRect pathBounds;
1133 if (path->getConservativeBounds(&pathBounds)) {
1134 GrIRect pathIBounds;
1135 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1136 pathBounds.roundOut(&pathIBounds);
1137 if (!bound.intersectWith(pathIBounds)) {
1138 return;
1139 }
1140 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001141
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001142 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1143 pr->drawPath(target, 0, path, fill, translate);
1144 this->offscreenAAPass2(target, paint, bound, &record);
1145 return;
1146 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001147 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001148 GrDrawTarget::StageBitfield enabledStages = 0;
1149 if (NULL != paint.getTexture()) {
1150 enabledStages |= 1;
1151 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001152
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001153 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001154}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001155
bsalomon@google.comd302f142011-03-03 13:54:13 +00001156void GrContext::drawPath(const GrPaint& paint,
1157 const GrPath& path,
1158 GrPathFill fill,
1159 const GrPoint* translate) {
1160 GrPath::Iter iter(path);
1161 this->drawPath(paint, &iter, fill, translate);
1162}
1163
1164
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165////////////////////////////////////////////////////////////////////////////////
1166
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001167void GrContext::flush(int flagsBitfield) {
1168 if (kDiscard_FlushBit & flagsBitfield) {
1169 fDrawBuffer->reset();
1170 } else {
1171 flushDrawBuffer();
1172 }
1173
1174 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175 fGpu->forceRenderTargetFlush();
1176 }
1177}
1178
1179void GrContext::flushText() {
1180 if (kText_DrawCategory == fLastDrawCategory) {
1181 flushDrawBuffer();
1182 }
1183}
1184
1185void GrContext::flushDrawBuffer() {
1186#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1187 fDrawBuffer->playback(fGpu);
1188 fDrawBuffer->reset();
1189#endif
1190}
1191
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001192bool GrContext::readTexturePixels(GrTexture* texture,
1193 int left, int top, int width, int height,
1194 GrPixelConfig config, void* buffer) {
1195
1196 // TODO: code read pixels for textures that aren't rendertargets
1197
1198 this->flush();
1199 GrRenderTarget* target = texture->asRenderTarget();
1200 if (NULL != target) {
1201 return fGpu->readPixels(target,
1202 left, top, width, height,
1203 config, buffer);
1204 } else {
1205 return false;
1206 }
1207}
1208
1209bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1210 int left, int top, int width, int height,
1211 GrPixelConfig config, void* buffer) {
1212 uint32_t flushFlags = 0;
1213 if (NULL == target) {
1214 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1215 }
1216
1217 this->flush(flushFlags);
1218 return fGpu->readPixels(target,
1219 left, top, width, height,
1220 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001221}
1222
1223void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001224 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225 size_t stride) {
1226
1227 // TODO: when underlying api has a direct way to do this we should use it
1228 // (e.g. glDrawPixels on desktop GL).
1229
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001230 const GrTextureDesc desc = {
1231 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001232 };
1233 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1234 if (NULL == texture) {
1235 return;
1236 }
1237
1238 this->flush(true);
1239
1240 GrAutoUnref aur(texture);
1241 GrDrawTarget::AutoStateRestore asr(fGpu);
1242
1243 GrMatrix matrix;
1244 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1245 fGpu->setViewMatrix(matrix);
1246
1247 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1248 fGpu->setAlpha(0xFF);
1249 fGpu->setBlendFunc(kOne_BlendCoeff,
1250 kZero_BlendCoeff);
1251 fGpu->setTexture(0, texture);
1252
1253 GrSamplerState sampler;
1254 sampler.setClampNoFilter();
1255 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1256 sampler.setMatrix(matrix);
1257 fGpu->setSamplerState(0, sampler);
1258
1259 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1260 static const int VCOUNT = 4;
1261
1262 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1263 if (!geo.succeeded()) {
1264 return;
1265 }
1266 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1267 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1268}
1269////////////////////////////////////////////////////////////////////////////////
1270
1271void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1272 target->setTexture(0, paint.getTexture());
1273 target->setSamplerState(0, paint.fSampler);
1274 target->setColor(paint.fColor);
1275
1276 if (paint.fDither) {
1277 target->enableState(GrDrawTarget::kDither_StateBit);
1278 } else {
1279 target->disableState(GrDrawTarget::kDither_StateBit);
1280 }
1281 if (paint.fAntiAlias) {
1282 target->enableState(GrDrawTarget::kAntialias_StateBit);
1283 } else {
1284 target->disableState(GrDrawTarget::kAntialias_StateBit);
1285 }
1286 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1287}
1288
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001289GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290 DrawCategory category) {
1291 if (category != fLastDrawCategory) {
1292 flushDrawBuffer();
1293 fLastDrawCategory = category;
1294 }
1295 SetPaint(paint, fGpu);
1296 GrDrawTarget* target = fGpu;
1297 switch (category) {
1298 case kText_DrawCategory:
1299#if DEFER_TEXT_RENDERING
1300 target = fDrawBuffer;
1301 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1302#else
1303 target = fGpu;
1304#endif
1305 break;
1306 case kUnbuffered_DrawCategory:
1307 target = fGpu;
1308 break;
1309 case kBuffered_DrawCategory:
1310 target = fDrawBuffer;
1311 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1312 break;
1313 }
1314 return target;
1315}
1316
1317////////////////////////////////////////////////////////////////////////////////
1318
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001320 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001321 fGpu->setRenderTarget(target);
1322}
1323
1324GrRenderTarget* GrContext::getRenderTarget() {
1325 return fGpu->getRenderTarget();
1326}
1327
1328const GrRenderTarget* GrContext::getRenderTarget() const {
1329 return fGpu->getRenderTarget();
1330}
1331
1332const GrMatrix& GrContext::getMatrix() const {
1333 return fGpu->getViewMatrix();
1334}
1335
1336void GrContext::setMatrix(const GrMatrix& m) {
1337 fGpu->setViewMatrix(m);
1338}
1339
1340void GrContext::concatMatrix(const GrMatrix& m) const {
1341 fGpu->preConcatViewMatrix(m);
1342}
1343
1344static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1345 intptr_t mask = 1 << shift;
1346 if (pred) {
1347 bits |= mask;
1348 } else {
1349 bits &= ~mask;
1350 }
1351 return bits;
1352}
1353
1354void GrContext::resetStats() {
1355 fGpu->resetStats();
1356}
1357
1358const GrGpu::Stats& GrContext::getStats() const {
1359 return fGpu->getStats();
1360}
1361
1362void GrContext::printStats() const {
1363 fGpu->printStats();
1364}
1365
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001366GrContext::GrContext(GrGpu* gpu) :
1367 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1368 gpu->supportsStencilWrapOps()) {
1369
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370 fGpu = gpu;
1371 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001372 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001373
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001374 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1375 fGpu->setClipPathRenderer(fCustomPathRenderer);
1376
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1378 MAX_TEXTURE_CACHE_BYTES);
1379 fFontCache = new GrFontCache(fGpu);
1380
1381 fLastDrawCategory = kUnbuffered_DrawCategory;
1382
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001383 fDrawBuffer = NULL;
1384 fDrawBufferVBAllocPool = NULL;
1385 fDrawBufferIBAllocPool = NULL;
1386
bsalomon@google.com205d4602011-04-25 12:43:45 +00001387 fAAFillRectIndexBuffer = NULL;
1388 fAAStrokeRectIndexBuffer = NULL;
1389
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001390 this->setupDrawBuffer();
1391}
1392
1393void GrContext::setupDrawBuffer() {
1394
1395 GrAssert(NULL == fDrawBuffer);
1396 GrAssert(NULL == fDrawBufferVBAllocPool);
1397 GrAssert(NULL == fDrawBufferIBAllocPool);
1398
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001400 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001401 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1403 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001404 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001405 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001406 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1408
1409 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1410 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411#endif
1412
1413#if BATCH_RECT_TO_RECT
1414 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1415#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416}
1417
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1419 GrDrawTarget* target;
1420#if DEFER_TEXT_RENDERING
1421 target = prepareToDraw(paint, kText_DrawCategory);
1422#else
1423 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1424#endif
1425 SetPaint(paint, target);
1426 return target;
1427}
1428
1429const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1430 return fGpu->getQuadIndexBuffer();
1431}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001432
1433GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1434 GrPathIter* path,
1435 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001436 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001437 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1438 return fCustomPathRenderer;
1439 } else {
1440 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1441 return &fDefaultPathRenderer;
1442 }
1443}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001444