blob: 399eaf8d381e283701857462cbe3f04d3492aab8 [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"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#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
bsalomon@google.com05ef5102011-05-02 21:14:59 +000046GrContext* GrContext::Create(GrEngine engine,
47 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000048 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() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +000058 return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +000059}
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.com05ef5102011-05-02 21:14:59 +0000354GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
355 int stencilBits,
356 bool isMultisampled,
357 int width, int height) {
358#if GR_DEBUG
359 GrPrintf("Using deprecated createPlatformRenderTarget API.");
360#endif
361 return fGpu->createPlatformRenderTarget(platformRenderTarget,
362 stencilBits, isMultisampled,
363 width, height);
364}
365
366GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
367#if GR_DEBUG
368 GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
369#endif
370 return fGpu->createRenderTargetFrom3DApiState();
371}
372
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000373///////////////////////////////////////////////////////////////////////////////
374
bsalomon@google.com27847de2011-02-22 20:59:41 +0000375bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
376 int width, int height) {
377 if (!fGpu->supports8BitPalette()) {
378 return false;
379 }
380
381
382 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
383
384 if (!isPow2) {
385 if (!fGpu->npotTextureSupport()) {
386 return false;
387 }
388
389 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
390 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
391 if (tiled && !fGpu->npotTextureTileSupport()) {
392 return false;
393 }
394 }
395 return true;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000400const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
401
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402void GrContext::setClip(const GrClip& clip) {
403 fGpu->setClip(clip);
404 fGpu->enableState(GrDrawTarget::kClip_StateBit);
405}
406
407void GrContext::setClip(const GrIRect& rect) {
408 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000409 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410 fGpu->setClip(clip);
411}
412
413////////////////////////////////////////////////////////////////////////////////
414
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000415void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000416 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000417 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418}
419
420void GrContext::drawPaint(const GrPaint& paint) {
421 // set rect to be big enough to fill the space, but not super-huge, so we
422 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000423 GrRect r;
424 r.setLTRB(0, 0,
425 GrIntToScalar(getRenderTarget()->width()),
426 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000427 GrMatrix inverse;
428 if (fGpu->getViewInverse(&inverse)) {
429 inverse.mapRect(&r);
430 } else {
431 GrPrintf("---- fGpu->getViewInverse failed\n");
432 }
433 this->drawRect(paint, r);
434}
435
bsalomon@google.com205d4602011-04-25 12:43:45 +0000436////////////////////////////////////////////////////////////////////////////////
437
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000438bool GrContext::doOffscreenAA(GrDrawTarget* target,
439 const GrPaint& paint,
440 bool isLines) const {
441#if !ENABLE_OFFSCREEN_AA
442 return false;
443#else
444 if (!paint.fAntiAlias) {
445 return false;
446 }
447 if (isLines && fGpu->supportsAALines()) {
448 return false;
449 }
450 if (target->getRenderTarget()->isMultisampled()) {
451 return false;
452 }
453 // we have to be sure that the blend equation is expressible
454 // as simple src / dst coeffecients when the source
455 // is already modulated by the coverage fraction.
456 // We could use dual-source blending to get the correct per-pixel
457 // dst coeffecient for the remaining cases.
458 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
459 kOne_BlendCoeff != paint.fDstBlendCoeff &&
460 kISA_BlendCoeff != paint.fDstBlendCoeff) {
461 return false;
462 }
463 return true;
464#endif
465}
466
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000467bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
468 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000469 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000470 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000471 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000472
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000473 GrAssert(NULL == record->fEntry0);
474 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000475
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000476 int boundW = boundRect.width();
477 int boundH = boundRect.height();
478 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000479
480 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000481 if (requireStencil) {
482 desc.fFlags = kRenderTarget_GrTextureFlagBit;
483 } else {
484 desc.fFlags = kRenderTarget_GrTextureFlagBit |
485 kNoStencil_GrTextureFlagBit;
486 }
487
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000488 desc.fFormat = kRGBA_8888_GrPixelConfig;
489
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000490 int scale;
491 // Using MSAA seems to be slower for some yet unknown reason.
492 if (false && fGpu->supportsFullsceneAA()) {
493 scale = GR_Scalar1;
494 desc.fAALevel = kMed_GrAALevel;
495 } else {
496 scale = 4;
497 desc.fAALevel = kNone_GrAALevel;
498 }
499
500 desc.fWidth = scale * size;
501 desc.fHeight = scale * size;
502
503 record->fEntry0 = this->lockKeylessTexture(desc);
504
505 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000506 return false;
507 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000508
509 if (scale > 1) {
510 desc.fWidth /= 2;
511 desc.fHeight /= 2;
512 record->fEntry1 = this->lockKeylessTexture(desc);
513 if (NULL == record->fEntry1) {
514 this->unlockTexture(record->fEntry0);
515 record->fEntry0 = NULL;
516 return false;
517 }
518 }
519
520 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
521 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000522
523 target->saveCurrentDrawState(&record->fSavedState);
524
525 GrPaint tempPaint;
526 tempPaint.reset();
527 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000528 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000529
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000530 GrMatrix transM;
531 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
532 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000533 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000534 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000535 target->postConcatViewMatrix(scaleM);
536
537 // clip gets applied in second pass
538 target->disableState(GrDrawTarget::kClip_StateBit);
539
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000540 GrIRect clear(0, 0, scale * boundW, scale * boundH);
541 target->clear(&clear, 0x0);
542
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000543 return true;
544}
545
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000546void GrContext::offscreenAAPass2(GrDrawTarget* target,
547 const GrPaint& paint,
548 const GrIRect& boundRect,
549 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000550
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000551 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000552
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000553 bool downsample = NULL != record->fEntry1;
554
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000555 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000556 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000557 GrSamplerState::kClamp_WrapMode, true);
558
559 GrTexture* src = record->fEntry0->texture();
560 int scale;
561
562 if (downsample) {
563 scale = 2;
564 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
565
566 // Do 2x2 downsample from first to second
567 target->setTexture(kOffscreenStage, src);
568 target->setRenderTarget(dst);
569 target->setViewMatrix(GrMatrix::I());
570 sampleM.setScale(scale * GR_Scalar1 / src->width(),
571 scale * GR_Scalar1 / src->height());
572 sampler.setMatrix(sampleM);
573 target->setSamplerState(kOffscreenStage, sampler);
574 GrRect rect(0, 0,
575 scale * boundRect.width(),
576 scale * boundRect.height());
577 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
578
579 src = record->fEntry1->texture();
580 } else {
581 scale = 1;
582 GrIRect rect(0, 0, boundRect.width(), boundRect.height());
583 src->asRenderTarget()->overrideResolveRect(rect);
584 }
585
586 // setup for draw back to main RT
587 target->restoreDrawState(record->fSavedState);
588 if (NULL != paint.getTexture()) {
589 GrMatrix invVM;
590 if (target->getViewInverse(&invVM)) {
591 target->preConcatSamplerMatrix(0, invVM);
592 }
593 }
594 target->setViewMatrix(GrMatrix::I());
595
596 target->setTexture(kOffscreenStage, src);
597 sampleM.setScale(scale * GR_Scalar1 / src->width(),
598 scale * GR_Scalar1 / src->height());
599 sampler.setMatrix(sampleM);
600 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
601 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000602 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000603
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000604 GrRect dstRect(boundRect);
605 int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1);
606 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000607
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000608 this->unlockTexture(record->fEntry0);
609 record->fEntry0 = NULL;
610 if (downsample) {
611 this->unlockTexture(record->fEntry1);
612 record->fEntry1 = NULL;
613 }
614 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000615}
616
617////////////////////////////////////////////////////////////////////////////////
618
bsalomon@google.com27847de2011-02-22 20:59:41 +0000619/* create a triangle strip that strokes the specified triangle. There are 8
620 unique vertices, but we repreat the last 2 to close up. Alternatively we
621 could use an indices array, and then only send 8 verts, but not sure that
622 would be faster.
623 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000624static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000625 GrScalar width) {
626 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000627 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000628
629 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
630 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
631 verts[2].set(rect.fRight - rad, rect.fTop + rad);
632 verts[3].set(rect.fRight + rad, rect.fTop - rad);
633 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
634 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
635 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
636 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
637 verts[8] = verts[0];
638 verts[9] = verts[1];
639}
640
bsalomon@google.com205d4602011-04-25 12:43:45 +0000641static GrColor getColorForMesh(const GrPaint& paint) {
642 if (NULL == paint.getTexture()) {
643 return paint.fColor;
644 } else {
645 unsigned a = GrColorUnpackA(paint.fColor);
646 return GrColorPackRGBA(a, a, a, a);
647 }
648}
649
650static void setInsetFan(GrPoint* pts, size_t stride,
651 const GrRect& r, GrScalar dx, GrScalar dy) {
652 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
653}
654
655static const uint16_t gFillAARectIdx[] = {
656 0, 1, 5, 5, 4, 0,
657 1, 2, 6, 6, 5, 1,
658 2, 3, 7, 7, 6, 2,
659 3, 0, 4, 4, 7, 3,
660 4, 5, 6, 6, 7, 4,
661};
662
663int GrContext::aaFillRectIndexCount() const {
664 return GR_ARRAY_COUNT(gFillAARectIdx);
665}
666
667GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
668 if (NULL == fAAFillRectIndexBuffer) {
669 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
670 false);
671 GrAssert(NULL != fAAFillRectIndexBuffer);
672#if GR_DEBUG
673 bool updated =
674#endif
675 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
676 sizeof(gFillAARectIdx));
677 GR_DEBUGASSERT(updated);
678 }
679 return fAAFillRectIndexBuffer;
680}
681
682static const uint16_t gStrokeAARectIdx[] = {
683 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
684 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
685 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
686 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
687
688 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
689 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
690 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
691 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
692
693 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
694 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
695 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
696 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
697};
698
699int GrContext::aaStrokeRectIndexCount() const {
700 return GR_ARRAY_COUNT(gStrokeAARectIdx);
701}
702
703GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
704 if (NULL == fAAStrokeRectIndexBuffer) {
705 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
706 false);
707 GrAssert(NULL != fAAStrokeRectIndexBuffer);
708#if GR_DEBUG
709 bool updated =
710#endif
711 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
712 sizeof(gStrokeAARectIdx));
713 GR_DEBUGASSERT(updated);
714 }
715 return fAAStrokeRectIndexBuffer;
716}
717
718void GrContext::fillAARect(GrDrawTarget* target,
719 const GrPaint& paint,
720 const GrRect& devRect) {
721
722 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
723 if (NULL != paint.getTexture()) {
724 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
725 }
726
727 size_t vsize = GrDrawTarget::VertexSize(layout);
728
729 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
730
731 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
732
733 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
734 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
735
736 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
737 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
738
739 verts += sizeof(GrPoint);
740 for (int i = 0; i < 4; ++i) {
741 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
742 }
743
744 GrColor innerColor = getColorForMesh(paint);
745 verts += 4 * vsize;
746 for (int i = 0; i < 4; ++i) {
747 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
748 }
749
750 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
751
752 target->drawIndexed(kTriangles_PrimitiveType, 0,
753 0, 8, this->aaFillRectIndexCount());
754}
755
756void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
757 const GrRect& devRect, const GrVec& devStrokeSize) {
758 const GrScalar& dx = devStrokeSize.fX;
759 const GrScalar& dy = devStrokeSize.fY;
760 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
761 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
762
763 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
764
765 if (NULL != paint.getTexture()) {
766 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
767 }
768
769 GrScalar spare;
770 {
771 GrScalar w = devRect.width() - dx;
772 GrScalar h = devRect.height() - dy;
773 spare = GrMin(w, h);
774 }
775
776 if (spare <= 0) {
777 GrRect r(devRect);
778 r.inset(-rx, -ry);
779 fillAARect(target, paint, r);
780 return;
781 }
782
783 size_t vsize = GrDrawTarget::VertexSize(layout);
784
785 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
786
787 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
788
789 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
790 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
791 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
792 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
793
794 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
795 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
796 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
797 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
798
799 verts += sizeof(GrPoint);
800 for (int i = 0; i < 4; ++i) {
801 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
802 }
803
804 GrColor innerColor = getColorForMesh(paint);
805 verts += 4 * vsize;
806 for (int i = 0; i < 8; ++i) {
807 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
808 }
809
810 verts += 8 * vsize;
811 for (int i = 0; i < 8; ++i) {
812 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
813 }
814
815 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
816 target->drawIndexed(kTriangles_PrimitiveType,
817 0, 0, 16, aaStrokeRectIndexCount());
818}
819
820static bool apply_aa_to_rect(GrDrawTarget* target,
821 GrGpu* gpu,
822 const GrPaint& paint,
823 const GrRect& rect,
824 GrScalar width,
825 const GrMatrix* matrix,
826 GrMatrix* combinedMatrix,
827 GrRect* devRect) {
828 // we use a simple alpha ramp to do aa on axis-aligned rects
829 // do AA with alpha ramp if the caller requested AA, the rect
830 // will be axis-aligned,the render target is not
831 // multisampled, and the rect won't land on integer coords.
832
833 if (!paint.fAntiAlias) {
834 return false;
835 }
836
837 if (target->getRenderTarget()->isMultisampled()) {
838 return false;
839 }
840
841 if (0 == width && gpu->supportsAALines()) {
842 return false;
843 }
844
845 if (!target->getViewMatrix().preservesAxisAlignment()) {
846 return false;
847 }
848
849 if (NULL != matrix &&
850 !matrix->preservesAxisAlignment()) {
851 return false;
852 }
853
854 *combinedMatrix = target->getViewMatrix();
855 if (NULL != matrix) {
856 combinedMatrix->preConcat(*matrix);
857 GrAssert(combinedMatrix->preservesAxisAlignment());
858 }
859
860 combinedMatrix->mapRect(devRect, rect);
861 devRect->sort();
862
863 if (width < 0) {
864 return !devRect->isIRect();
865 } else {
866 return true;
867 }
868}
869
bsalomon@google.com27847de2011-02-22 20:59:41 +0000870void GrContext::drawRect(const GrPaint& paint,
871 const GrRect& rect,
872 GrScalar width,
873 const GrMatrix* matrix) {
874
875 bool textured = NULL != paint.getTexture();
876
877 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
878
bsalomon@google.com205d4602011-04-25 12:43:45 +0000879 GrRect devRect = rect;
880 GrMatrix combinedMatrix;
881 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
882 &combinedMatrix, &devRect);
883
884 if (doAA) {
885 GrDrawTarget::AutoViewMatrixRestore avm(target);
886 if (textured) {
887 GrMatrix inv;
888 if (combinedMatrix.invert(&inv)) {
889 target->preConcatSamplerMatrix(0, inv);
890 }
891 }
892 target->setViewMatrix(GrMatrix::I());
893 if (width >= 0) {
894 GrVec strokeSize;;
895 if (width > 0) {
896 strokeSize.set(width, width);
897 combinedMatrix.mapVec(&strokeSize);
898 strokeSize.setAbs(strokeSize);
899 } else {
900 strokeSize.set(GR_Scalar1, GR_Scalar1);
901 }
902 strokeAARect(target, paint, devRect, strokeSize);
903 } else {
904 fillAARect(target, paint, devRect);
905 }
906 return;
907 }
908
bsalomon@google.com27847de2011-02-22 20:59:41 +0000909 if (width >= 0) {
910 // TODO: consider making static vertex buffers for these cases.
911 // Hairline could be done by just adding closing vertex to
912 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000913 GrVertexLayout layout = textured ?
914 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
915 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000916 static const int worstCaseVertCount = 10;
917 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
918
919 if (!geo.succeeded()) {
920 return;
921 }
922
923 GrPrimitiveType primType;
924 int vertCount;
925 GrPoint* vertex = geo.positions();
926
927 if (width > 0) {
928 vertCount = 10;
929 primType = kTriangleStrip_PrimitiveType;
930 setStrokeRectStrip(vertex, rect, width);
931 } else {
932 // hairline
933 vertCount = 5;
934 primType = kLineStrip_PrimitiveType;
935 vertex[0].set(rect.fLeft, rect.fTop);
936 vertex[1].set(rect.fRight, rect.fTop);
937 vertex[2].set(rect.fRight, rect.fBottom);
938 vertex[3].set(rect.fLeft, rect.fBottom);
939 vertex[4].set(rect.fLeft, rect.fTop);
940 }
941
942 GrDrawTarget::AutoViewMatrixRestore avmr;
943 if (NULL != matrix) {
944 avmr.set(target);
945 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000946 if (textured) {
947 target->preConcatSamplerMatrix(0, *matrix);
948 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949 }
950
951 target->drawNonIndexed(primType, 0, vertCount);
952 } else {
953 #if GR_STATIC_RECT_VB
954 GrVertexLayout layout = (textured) ?
955 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
956 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000957 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958 fGpu->getUnitSquareVertexBuffer());
959 GrDrawTarget::AutoViewMatrixRestore avmr(target);
960 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000961 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000962 0, rect.height(), rect.fTop,
963 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000964
965 if (NULL != matrix) {
966 m.postConcat(*matrix);
967 }
968
969 target->preConcatViewMatrix(m);
970
971 if (textured) {
972 target->preConcatSamplerMatrix(0, m);
973 }
974 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
975 #else
976 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
977 #endif
978 }
979}
980
981void GrContext::drawRectToRect(const GrPaint& paint,
982 const GrRect& dstRect,
983 const GrRect& srcRect,
984 const GrMatrix* dstMatrix,
985 const GrMatrix* srcMatrix) {
986
987 if (NULL == paint.getTexture()) {
988 drawRect(paint, dstRect, -1, dstMatrix);
989 return;
990 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000991
bsalomon@google.com27847de2011-02-22 20:59:41 +0000992 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
993
994#if GR_STATIC_RECT_VB
995 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
996
997 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
998 GrDrawTarget::AutoViewMatrixRestore avmr(target);
999
1000 GrMatrix m;
1001
1002 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1003 0, dstRect.height(), dstRect.fTop,
1004 0, 0, GrMatrix::I()[8]);
1005 if (NULL != dstMatrix) {
1006 m.postConcat(*dstMatrix);
1007 }
1008 target->preConcatViewMatrix(m);
1009
1010 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1011 0, srcRect.height(), srcRect.fTop,
1012 0, 0, GrMatrix::I()[8]);
1013 if (NULL != srcMatrix) {
1014 m.postConcat(*srcMatrix);
1015 }
1016 target->preConcatSamplerMatrix(0, m);
1017
1018 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1019 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1020#else
1021
1022 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001023#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001024 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001025#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1027#endif
1028
1029 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1030 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1031 srcRects[0] = &srcRect;
1032 srcMatrices[0] = srcMatrix;
1033
1034 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1035#endif
1036}
1037
1038void GrContext::drawVertices(const GrPaint& paint,
1039 GrPrimitiveType primitiveType,
1040 int vertexCount,
1041 const GrPoint positions[],
1042 const GrPoint texCoords[],
1043 const GrColor colors[],
1044 const uint16_t indices[],
1045 int indexCount) {
1046 GrVertexLayout layout = 0;
1047 int vertexSize = sizeof(GrPoint);
1048
1049 GrDrawTarget::AutoReleaseGeometry geo;
1050
1051 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1052
1053 if (NULL != paint.getTexture()) {
1054 if (NULL == texCoords) {
1055 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1056 } else {
1057 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
1058 vertexSize += sizeof(GrPoint);
1059 }
1060 }
1061
1062 if (NULL != colors) {
1063 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1064 vertexSize += sizeof(GrColor);
1065 }
1066
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001067 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001068 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001069 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001070
bsalomon@google.com27847de2011-02-22 20:59:41 +00001071 if (sizeof(GrPoint) != vertexSize) {
1072 if (!geo.set(target, layout, vertexCount, 0)) {
1073 GrPrintf("Failed to get space for vertices!");
1074 return;
1075 }
1076 int texOffsets[GrDrawTarget::kMaxTexCoords];
1077 int colorOffset;
1078 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1079 texOffsets,
1080 &colorOffset);
1081 void* curVertex = geo.vertices();
1082
1083 for (int i = 0; i < vertexCount; ++i) {
1084 *((GrPoint*)curVertex) = positions[i];
1085
1086 if (texOffsets[0] > 0) {
1087 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1088 }
1089 if (colorOffset > 0) {
1090 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1091 }
1092 curVertex = (void*)((intptr_t)curVertex + vsize);
1093 }
1094 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001095 // we don't do offscreen AA when we have per-vertex tex coords or colors
1096 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1097 GrRect b;
1098 b.setBounds(positions, vertexCount);
1099 target->getViewMatrix().mapRect(&b);
1100 b.roundOut(&bounds);
1101
1102 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1103 doAA = true;
1104 }
1105 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001106 target->setVertexSourceToArray(layout, positions, vertexCount);
1107 }
1108
1109 if (NULL != indices) {
1110 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001111 }
1112
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001113 if (NULL != indices) {
1114 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001116 target->drawNonIndexed(primitiveType, 0, vertexCount);
1117 }
1118
1119 if (doAA) {
1120 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001121 }
1122}
1123
1124
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001125///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001126
1127void GrContext::drawPath(const GrPaint& paint,
1128 GrPathIter* path,
1129 GrPathFill fill,
1130 const GrPoint* translate) {
1131
bsalomon@google.com27847de2011-02-22 20:59:41 +00001132 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001133 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001134
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001135 if (!IsFillInverted(fill) && // will be relaxed soon
1136 !pr->supportsAA(target, path, fill) &&
1137 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001138
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001139 OffscreenRecord record;
1140 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001141
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001142 // compute bounds as intersection of rt size, clip, and path
1143 GrIRect bound(0, 0,
1144 target->getRenderTarget()->width(),
1145 target->getRenderTarget()->height());
1146 if (target->getClip().hasConservativeBounds()) {
1147 GrIRect clipIBounds;
1148 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1149 if (!bound.intersectWith(clipIBounds)) {
1150 return;
1151 }
1152 }
1153 GrRect pathBounds;
1154 if (path->getConservativeBounds(&pathBounds)) {
1155 GrIRect pathIBounds;
1156 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1157 pathBounds.roundOut(&pathIBounds);
1158 if (!bound.intersectWith(pathIBounds)) {
1159 return;
1160 }
1161 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001162
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001163 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1164 pr->drawPath(target, 0, path, fill, translate);
1165 this->offscreenAAPass2(target, paint, bound, &record);
1166 return;
1167 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001168 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001169 GrDrawTarget::StageBitfield enabledStages = 0;
1170 if (NULL != paint.getTexture()) {
1171 enabledStages |= 1;
1172 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001173
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001174 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001176
bsalomon@google.comd302f142011-03-03 13:54:13 +00001177void GrContext::drawPath(const GrPaint& paint,
1178 const GrPath& path,
1179 GrPathFill fill,
1180 const GrPoint* translate) {
1181 GrPath::Iter iter(path);
1182 this->drawPath(paint, &iter, fill, translate);
1183}
1184
1185
bsalomon@google.com27847de2011-02-22 20:59:41 +00001186////////////////////////////////////////////////////////////////////////////////
1187
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001188void GrContext::flush(int flagsBitfield) {
1189 if (kDiscard_FlushBit & flagsBitfield) {
1190 fDrawBuffer->reset();
1191 } else {
1192 flushDrawBuffer();
1193 }
1194
1195 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 fGpu->forceRenderTargetFlush();
1197 }
1198}
1199
1200void GrContext::flushText() {
1201 if (kText_DrawCategory == fLastDrawCategory) {
1202 flushDrawBuffer();
1203 }
1204}
1205
1206void GrContext::flushDrawBuffer() {
1207#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1208 fDrawBuffer->playback(fGpu);
1209 fDrawBuffer->reset();
1210#endif
1211}
1212
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001213bool GrContext::readTexturePixels(GrTexture* texture,
1214 int left, int top, int width, int height,
1215 GrPixelConfig config, void* buffer) {
1216
1217 // TODO: code read pixels for textures that aren't rendertargets
1218
1219 this->flush();
1220 GrRenderTarget* target = texture->asRenderTarget();
1221 if (NULL != target) {
1222 return fGpu->readPixels(target,
1223 left, top, width, height,
1224 config, buffer);
1225 } else {
1226 return false;
1227 }
1228}
1229
1230bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1231 int left, int top, int width, int height,
1232 GrPixelConfig config, void* buffer) {
1233 uint32_t flushFlags = 0;
1234 if (NULL == target) {
1235 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1236 }
1237
1238 this->flush(flushFlags);
1239 return fGpu->readPixels(target,
1240 left, top, width, height,
1241 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242}
1243
1244void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001245 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 size_t stride) {
1247
1248 // TODO: when underlying api has a direct way to do this we should use it
1249 // (e.g. glDrawPixels on desktop GL).
1250
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001251 const GrTextureDesc desc = {
1252 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253 };
1254 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1255 if (NULL == texture) {
1256 return;
1257 }
1258
1259 this->flush(true);
1260
1261 GrAutoUnref aur(texture);
1262 GrDrawTarget::AutoStateRestore asr(fGpu);
1263
1264 GrMatrix matrix;
1265 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1266 fGpu->setViewMatrix(matrix);
1267
1268 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1269 fGpu->setAlpha(0xFF);
1270 fGpu->setBlendFunc(kOne_BlendCoeff,
1271 kZero_BlendCoeff);
1272 fGpu->setTexture(0, texture);
1273
1274 GrSamplerState sampler;
1275 sampler.setClampNoFilter();
1276 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1277 sampler.setMatrix(matrix);
1278 fGpu->setSamplerState(0, sampler);
1279
1280 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1281 static const int VCOUNT = 4;
1282
1283 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1284 if (!geo.succeeded()) {
1285 return;
1286 }
1287 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1288 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1289}
1290////////////////////////////////////////////////////////////////////////////////
1291
1292void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1293 target->setTexture(0, paint.getTexture());
1294 target->setSamplerState(0, paint.fSampler);
1295 target->setColor(paint.fColor);
1296
1297 if (paint.fDither) {
1298 target->enableState(GrDrawTarget::kDither_StateBit);
1299 } else {
1300 target->disableState(GrDrawTarget::kDither_StateBit);
1301 }
1302 if (paint.fAntiAlias) {
1303 target->enableState(GrDrawTarget::kAntialias_StateBit);
1304 } else {
1305 target->disableState(GrDrawTarget::kAntialias_StateBit);
1306 }
1307 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1308}
1309
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001310GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311 DrawCategory category) {
1312 if (category != fLastDrawCategory) {
1313 flushDrawBuffer();
1314 fLastDrawCategory = category;
1315 }
1316 SetPaint(paint, fGpu);
1317 GrDrawTarget* target = fGpu;
1318 switch (category) {
1319 case kText_DrawCategory:
1320#if DEFER_TEXT_RENDERING
1321 target = fDrawBuffer;
1322 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1323#else
1324 target = fGpu;
1325#endif
1326 break;
1327 case kUnbuffered_DrawCategory:
1328 target = fGpu;
1329 break;
1330 case kBuffered_DrawCategory:
1331 target = fDrawBuffer;
1332 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1333 break;
1334 }
1335 return target;
1336}
1337
1338////////////////////////////////////////////////////////////////////////////////
1339
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001341 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342 fGpu->setRenderTarget(target);
1343}
1344
1345GrRenderTarget* GrContext::getRenderTarget() {
1346 return fGpu->getRenderTarget();
1347}
1348
1349const GrRenderTarget* GrContext::getRenderTarget() const {
1350 return fGpu->getRenderTarget();
1351}
1352
1353const GrMatrix& GrContext::getMatrix() const {
1354 return fGpu->getViewMatrix();
1355}
1356
1357void GrContext::setMatrix(const GrMatrix& m) {
1358 fGpu->setViewMatrix(m);
1359}
1360
1361void GrContext::concatMatrix(const GrMatrix& m) const {
1362 fGpu->preConcatViewMatrix(m);
1363}
1364
1365static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1366 intptr_t mask = 1 << shift;
1367 if (pred) {
1368 bits |= mask;
1369 } else {
1370 bits &= ~mask;
1371 }
1372 return bits;
1373}
1374
1375void GrContext::resetStats() {
1376 fGpu->resetStats();
1377}
1378
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001379const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380 return fGpu->getStats();
1381}
1382
1383void GrContext::printStats() const {
1384 fGpu->printStats();
1385}
1386
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001387GrContext::GrContext(GrGpu* gpu) :
1388 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1389 gpu->supportsStencilWrapOps()) {
1390
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 fGpu = gpu;
1392 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001393 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001394
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001395 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1396 fGpu->setClipPathRenderer(fCustomPathRenderer);
1397
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1399 MAX_TEXTURE_CACHE_BYTES);
1400 fFontCache = new GrFontCache(fGpu);
1401
1402 fLastDrawCategory = kUnbuffered_DrawCategory;
1403
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001404 fDrawBuffer = NULL;
1405 fDrawBufferVBAllocPool = NULL;
1406 fDrawBufferIBAllocPool = NULL;
1407
bsalomon@google.com205d4602011-04-25 12:43:45 +00001408 fAAFillRectIndexBuffer = NULL;
1409 fAAStrokeRectIndexBuffer = NULL;
1410
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001411 this->setupDrawBuffer();
1412}
1413
1414void GrContext::setupDrawBuffer() {
1415
1416 GrAssert(NULL == fDrawBuffer);
1417 GrAssert(NULL == fDrawBufferVBAllocPool);
1418 GrAssert(NULL == fDrawBufferIBAllocPool);
1419
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001421 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001422 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1424 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001425 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001426 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001427 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1429
1430 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1431 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432#endif
1433
1434#if BATCH_RECT_TO_RECT
1435 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1436#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001437}
1438
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1440 GrDrawTarget* target;
1441#if DEFER_TEXT_RENDERING
1442 target = prepareToDraw(paint, kText_DrawCategory);
1443#else
1444 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1445#endif
1446 SetPaint(paint, target);
1447 return target;
1448}
1449
1450const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1451 return fGpu->getQuadIndexBuffer();
1452}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001453
1454GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1455 GrPathIter* path,
1456 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001457 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001458 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1459 return fCustomPathRenderer;
1460 } else {
1461 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1462 return &fDefaultPathRenderer;
1463 }
1464}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001465