GrContext.cpp revision d38f137e9b813f8193675ebd3dfbfe8bc42639e9
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
12#include "GrContext.h"
13#include "GrGpu.h"
14#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
16#include "GrPathRenderer.h"
17#include "GrPathUtils.h"
18#include "GrResourceCache.h"
19#include "GrStencilBuffer.h"
20#include "GrTextStrike.h"
21#include "SkTLazy.h"
22#include "SkTrace.h"
23
24// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
27
28#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
32// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
34#define DISABLE_COVERAGE_AA_FOR_BLEND 1
35
36static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
38
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
47GrContext* GrContext::Create(GrEngine engine,
48                             GrPlatform3DContext context3D) {
49    GrContext* ctx = NULL;
50    GrGpu* fGpu = GrGpu::Create(engine, context3D);
51    if (NULL != fGpu) {
52        ctx = new GrContext(fGpu);
53        fGpu->unref();
54    }
55    return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
59    return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
60}
61
62GrContext::~GrContext() {
63    this->flush();
64    delete fTextureCache;
65    delete fFontCache;
66    delete fDrawBuffer;
67    delete fDrawBufferVBAllocPool;
68    delete fDrawBufferIBAllocPool;
69
70    GrSafeUnref(fAAFillRectIndexBuffer);
71    GrSafeUnref(fAAStrokeRectIndexBuffer);
72    fGpu->unref();
73    GrSafeUnref(fPathRendererChain);
74}
75
76void GrContext::contextLost() {
77    contextDestroyed();
78    this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
82    // abandon first to so destructors
83    // don't try to free the resources in the API.
84    fGpu->abandonResources();
85
86    // a path renderer may be holding onto resources that
87    // are now unusable
88    GrSafeSetNull(fPathRendererChain);
89
90    delete fDrawBuffer;
91    fDrawBuffer = NULL;
92
93    delete fDrawBufferVBAllocPool;
94    fDrawBufferVBAllocPool = NULL;
95
96    delete fDrawBufferIBAllocPool;
97    fDrawBufferIBAllocPool = NULL;
98
99    GrSafeSetNull(fAAFillRectIndexBuffer);
100    GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
102    fTextureCache->removeAll();
103    fFontCache->freeAll();
104    fGpu->markContextDirty();
105}
106
107void GrContext::resetContext() {
108    fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112    this->flush();
113    fTextureCache->removeAll();
114    fFontCache->freeAll();
115    // a path renderer may be holding onto resources
116    GrSafeSetNull(fPathRendererChain);
117}
118
119////////////////////////////////////////////////////////////////////////////////
120
121int GrContext::PaintStageVertexLayoutBits(
122                            const GrPaint& paint,
123                            const bool hasTexCoords[GrPaint::kTotalStages]) {
124    int stageMask = paint.getActiveStageMask();
125    int layout = 0;
126    for (int i = 0; i < GrPaint::kTotalStages; ++i) {
127        if ((1 << i) & stageMask) {
128            if (NULL != hasTexCoords && hasTexCoords[i]) {
129                layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
130            } else {
131                layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
132            }
133        }
134    }
135    return layout;
136}
137
138
139////////////////////////////////////////////////////////////////////////////////
140
141enum {
142    // flags for textures
143    kNPOTBit            = 0x1,
144    kFilterBit          = 0x2,
145    kScratchBit         = 0x4,
146
147    // resource type
148    kTextureBit         = 0x8,
149    kStencilBufferBit   = 0x10
150};
151
152GrTexture* GrContext::TextureCacheEntry::texture() const {
153    if (NULL == fEntry) {
154        return NULL;
155    } else {
156        return (GrTexture*) fEntry->resource();
157    }
158}
159
160namespace {
161// returns true if this is a "special" texture because of gpu NPOT limitations
162bool gen_texture_key_values(const GrGpu* gpu,
163                            const GrSamplerState& sampler,
164                            GrContext::TextureKey clientKey,
165                            int width,
166                            int height,
167                            bool scratch,
168                            uint32_t v[4]) {
169    GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
170    // we assume we only need 16 bits of width and height
171    // assert that texture creation will fail anyway if this assumption
172    // would cause key collisions.
173    GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
174    v[0] = clientKey & 0xffffffffUL;
175    v[1] = (clientKey >> 32) & 0xffffffffUL;
176    v[2] = width | (height << 16);
177
178    v[3] = 0;
179    if (!gpu->getCaps().fNPOTTextureTileSupport) {
180        bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
181
182        bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183                     (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
184
185        if (tiled && !isPow2) {
186            v[3] |= kNPOTBit;
187            if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
188                v[3] |= kFilterBit;
189            }
190        }
191    }
192
193    if (scratch) {
194        v[3] |= kScratchBit;
195    }
196
197    v[3] |= kTextureBit;
198
199    return v[3] & kNPOTBit;
200}
201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205                            int sampleCnt, uint32_t v[4]) {
206    v[0] = width;
207    v[1] = height;
208    v[2] = sampleCnt;
209    v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213                            uint32_t v[4]) {
214    gen_stencil_key_values(sb->width(), sb->height(),
215                           sb->numSamples(), v);
216}
217}
218
219GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
220                                                           int width,
221                                                           int height,
222                                                const GrSamplerState& sampler) {
223    uint32_t v[4];
224    gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
225    GrResourceKey resourceKey(v);
226    return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
227                                            GrResourceCache::kNested_LockType));
228}
229
230GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
231    uint32_t v[4];
232    gen_stencil_key_values(sb, v);
233    GrResourceKey resourceKey(v);
234    return fTextureCache->createAndLock(resourceKey, sb);
235}
236
237GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
238                                              int sampleCnt) {
239    uint32_t v[4];
240    gen_stencil_key_values(width, height, sampleCnt, v);
241    GrResourceKey resourceKey(v);
242    GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
243                                            GrResourceCache::kSingle_LockType);
244    if (NULL != entry) {
245        GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
246        return sb;
247    } else {
248        return NULL;
249    }
250}
251
252void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
253    fTextureCache->unlock(sbEntry);
254}
255
256static void stretchImage(void* dst,
257                         int dstW,
258                         int dstH,
259                         void* src,
260                         int srcW,
261                         int srcH,
262                         int bpp) {
263    GrFixed dx = (srcW << 16) / dstW;
264    GrFixed dy = (srcH << 16) / dstH;
265
266    GrFixed y = dy >> 1;
267
268    int dstXLimit = dstW*bpp;
269    for (int j = 0; j < dstH; ++j) {
270        GrFixed x = dx >> 1;
271        void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
272        void* dstRow = (uint8_t*)dst + j*dstW*bpp;
273        for (int i = 0; i < dstXLimit; i += bpp) {
274            memcpy((uint8_t*) dstRow + i,
275                   (uint8_t*) srcRow + (x>>16)*bpp,
276                   bpp);
277            x += dx;
278        }
279        y += dy;
280    }
281}
282
283GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
284                                                const GrSamplerState& sampler,
285                                                const GrTextureDesc& desc,
286                                                void* srcData, size_t rowBytes) {
287    SK_TRACE_EVENT0("GrContext::createAndLockTexture");
288
289#if GR_DUMP_TEXTURE_UPLOAD
290    GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
291#endif
292
293    TextureCacheEntry entry;
294    uint32_t v[4];
295    bool special = gen_texture_key_values(fGpu, sampler, key,
296                                          desc.fWidth, desc.fHeight, false, v);
297    GrResourceKey resourceKey(v);
298
299    if (special) {
300        TextureCacheEntry clampEntry =
301                            findAndLockTexture(key, desc.fWidth, desc.fHeight,
302                                               GrSamplerState::ClampNoFilter());
303
304        if (NULL == clampEntry.texture()) {
305            clampEntry = createAndLockTexture(key,
306                                              GrSamplerState::ClampNoFilter(),
307                                              desc, srcData, rowBytes);
308            GrAssert(NULL != clampEntry.texture());
309            if (NULL == clampEntry.texture()) {
310                return entry;
311            }
312        }
313        GrTextureDesc rtDesc = desc;
314        rtDesc.fFlags =  rtDesc.fFlags |
315                         kRenderTarget_GrTextureFlagBit |
316                         kNoStencil_GrTextureFlagBit;
317        rtDesc.fWidth  =
318            GrNextPow2(GrMax<int>(desc.fWidth,
319                                  fGpu->getCaps().fMinRenderTargetWidth));
320        rtDesc.fHeight =
321            GrNextPow2(GrMax<int>(desc.fHeight,
322                                  fGpu->getCaps().fMinRenderTargetHeight));
323
324        GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
325
326        if (NULL != texture) {
327            GrDrawTarget::AutoStateRestore asr(fGpu);
328            fGpu->setRenderTarget(texture->asRenderTarget());
329            fGpu->setTexture(0, clampEntry.texture());
330            fGpu->disableStencil();
331            fGpu->setViewMatrix(GrMatrix::I());
332            fGpu->setAlpha(0xff);
333            fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
334            fGpu->disableState(GrDrawTarget::kDither_StateBit |
335                               GrDrawTarget::kClip_StateBit   |
336                               GrDrawTarget::kAntialias_StateBit);
337            GrSamplerState::Filter filter;
338            // if filtering is not desired then we want to ensure all
339            // texels in the resampled image are copies of texels from
340            // the original.
341            if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
342                filter = GrSamplerState::kNearest_Filter;
343            } else {
344                filter = GrSamplerState::kBilinear_Filter;
345            }
346            GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
347                                          GrSamplerState::kClamp_WrapMode,
348                                          filter);
349            fGpu->setSamplerState(0, stretchSampler);
350
351            static const GrVertexLayout layout =
352                                GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
353            GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
354
355            if (arg.succeeded()) {
356                GrPoint* verts = (GrPoint*) arg.vertices();
357                verts[0].setIRectFan(0, 0,
358                                     texture->width(),
359                                     texture->height(),
360                                     2*sizeof(GrPoint));
361                verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
362                fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
363                                     0, 4);
364                entry.set(fTextureCache->createAndLock(resourceKey, texture));
365            }
366            texture->releaseRenderTarget();
367        } else {
368            // TODO: Our CPU stretch doesn't filter. But we create separate
369            // stretched textures when the sampler state is either filtered or
370            // not. Either implement filtered stretch blit on CPU or just create
371            // one when FBO case fails.
372
373            rtDesc.fFlags = kNone_GrTextureFlags;
374            // no longer need to clamp at min RT size.
375            rtDesc.fWidth  = GrNextPow2(desc.fWidth);
376            rtDesc.fHeight = GrNextPow2(desc.fHeight);
377            int bpp = GrBytesPerPixel(desc.fFormat);
378            SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
379                                                     rtDesc.fWidth *
380                                                     rtDesc.fHeight);
381            stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
382                         srcData, desc.fWidth, desc.fHeight, bpp);
383
384            size_t stretchedRowBytes = rtDesc.fWidth * bpp;
385
386            GrTexture* texture = fGpu->createTexture(rtDesc,
387                                                     stretchedPixels.get(),
388                                                     stretchedRowBytes);
389            GrAssert(NULL != texture);
390            entry.set(fTextureCache->createAndLock(resourceKey, texture));
391        }
392        fTextureCache->unlock(clampEntry.cacheEntry());
393
394    } else {
395        GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
396        if (NULL != texture) {
397            entry.set(fTextureCache->createAndLock(resourceKey, texture));
398        }
399    }
400    return entry;
401}
402
403namespace {
404inline void gen_scratch_tex_key_values(const GrGpu* gpu,
405                                       const GrTextureDesc& desc,
406                                       uint32_t v[4]) {
407    // Instead of a client-provided key of the texture contents
408    // we create a key of from the descriptor.
409    GrContext::TextureKey descKey = desc.fAALevel |
410                                    (desc.fFlags << 8) |
411                                    ((uint64_t) desc.fFormat << 32);
412    // this code path isn't friendly to tiling with NPOT restricitons
413    // We just pass ClampNoFilter()
414    gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
415                            desc.fWidth, desc.fHeight, true, v);
416}
417}
418
419GrContext::TextureCacheEntry GrContext::lockScratchTexture(
420                                                const GrTextureDesc& inDesc,
421                                                ScratchTexMatch match) {
422
423    GrTextureDesc desc = inDesc;
424    if (kExact_ScratchTexMatch != match) {
425        // bin by pow2 with a reasonable min
426        static const int MIN_SIZE = 256;
427        desc.fWidth  = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
428        desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
429    }
430
431    uint32_t p0 = desc.fFormat;
432    uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
433
434    GrResourceEntry* entry;
435    int origWidth = desc.fWidth;
436    int origHeight = desc.fHeight;
437    bool doubledW = false;
438    bool doubledH = false;
439
440    do {
441        uint32_t v[4];
442        gen_scratch_tex_key_values(fGpu, desc, v);
443        GrResourceKey key(v);
444        entry = fTextureCache->findAndLock(key,
445                                           GrResourceCache::kNested_LockType);
446        // if we miss, relax the fit of the flags...
447        // then try doubling width... then height.
448        if (NULL != entry || kExact_ScratchTexMatch == match) {
449            break;
450        }
451        if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
452            desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
453        } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
454            desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
455        } else if (!doubledW) {
456            desc.fFlags = inDesc.fFlags;
457            desc.fWidth *= 2;
458            doubledW = true;
459        } else if (!doubledH) {
460            desc.fFlags = inDesc.fFlags;
461            desc.fWidth = origWidth;
462            desc.fHeight *= 2;
463            doubledH = true;
464        } else {
465            break;
466        }
467
468    } while (true);
469
470    if (NULL == entry) {
471        desc.fFlags = inDesc.fFlags;
472        desc.fWidth = origWidth;
473        desc.fHeight = origHeight;
474        GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
475        if (NULL != texture) {
476            uint32_t v[4];
477            gen_scratch_tex_key_values(fGpu, desc, v);
478            GrResourceKey key(v);
479            entry = fTextureCache->createAndLock(key, texture);
480        }
481    }
482
483    // If the caller gives us the same desc/sampler twice we don't want
484    // to return the same texture the second time (unless it was previously
485    // released). So we detach the entry from the cache and reattach at release.
486    if (NULL != entry) {
487        fTextureCache->detach(entry);
488    }
489    return TextureCacheEntry(entry);
490}
491
492void GrContext::unlockTexture(TextureCacheEntry entry) {
493    // If this is a scratch texture we detached it from the cache
494    // while it was locked (to avoid two callers simultaneously getting
495    // the same texture).
496    if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
497        fTextureCache->reattachAndUnlock(entry.cacheEntry());
498    } else {
499        fTextureCache->unlock(entry.cacheEntry());
500    }
501}
502
503GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
504                                            void* srcData,
505                                            size_t rowBytes) {
506    return fGpu->createTexture(desc, srcData, rowBytes);
507}
508
509void GrContext::getTextureCacheLimits(int* maxTextures,
510                                      size_t* maxTextureBytes) const {
511    fTextureCache->getLimits(maxTextures, maxTextureBytes);
512}
513
514void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
515    fTextureCache->setLimits(maxTextures, maxTextureBytes);
516}
517
518int GrContext::getMaxTextureSize() const {
519    return fGpu->getCaps().fMaxTextureSize;
520}
521
522int GrContext::getMaxRenderTargetSize() const {
523    return fGpu->getCaps().fMaxRenderTargetSize;
524}
525
526///////////////////////////////////////////////////////////////////////////////
527
528GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
529    // validate flags here so that GrGpu subclasses don't have to check
530    if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
531        0 != desc.fRenderTargetFlags) {
532        return NULL;
533    }
534    if (desc.fSampleCnt &&
535        (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
536        return NULL;
537    }
538    if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
539        desc.fSampleCnt &&
540        !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
541        return NULL;
542    }
543    return fGpu->createPlatformSurface(desc);
544}
545
546///////////////////////////////////////////////////////////////////////////////
547
548bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
549                                          int width, int height) const {
550    const GrDrawTarget::Caps& caps = fGpu->getCaps();
551    if (!caps.f8BitPaletteSupport) {
552        return false;
553    }
554
555    bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
556
557    if (!isPow2) {
558        if (!caps.fNPOTTextureSupport) {
559            return false;
560        }
561
562        bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
563                     sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
564        if (tiled && !caps.fNPOTTextureTileSupport) {
565            return false;
566        }
567    }
568    return true;
569}
570
571////////////////////////////////////////////////////////////////////////////////
572
573const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
574
575void GrContext::setClip(const GrClip& clip) {
576    fGpu->setClip(clip);
577    fGpu->enableState(GrDrawTarget::kClip_StateBit);
578}
579
580void GrContext::setClip(const GrIRect& rect) {
581    GrClip clip;
582    clip.setFromIRect(rect);
583    fGpu->setClip(clip);
584}
585
586////////////////////////////////////////////////////////////////////////////////
587
588void GrContext::clear(const GrIRect* rect, const GrColor color) {
589    this->flush();
590    fGpu->clear(rect, color);
591}
592
593void GrContext::drawPaint(const GrPaint& paint) {
594    // set rect to be big enough to fill the space, but not super-huge, so we
595    // don't overflow fixed-point implementations
596    GrRect r;
597    r.setLTRB(0, 0,
598              GrIntToScalar(getRenderTarget()->width()),
599              GrIntToScalar(getRenderTarget()->height()));
600    GrAutoMatrix am;
601    GrMatrix inverse;
602    SkTLazy<GrPaint> tmpPaint;
603    const GrPaint* p = &paint;
604    // We attempt to map r by the inverse matrix and draw that. mapRect will
605    // map the four corners and bound them with a new rect. This will not
606    // produce a correct result for some perspective matrices.
607    if (!this->getMatrix().hasPerspective()) {
608        if (!fGpu->getViewInverse(&inverse)) {
609            GrPrintf("Could not invert matrix");
610            return;
611        }
612        inverse.mapRect(&r);
613    } else {
614        if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
615            if (!fGpu->getViewInverse(&inverse)) {
616                GrPrintf("Could not invert matrix");
617                return;
618            }
619            tmpPaint.set(paint);
620            tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
621            p = tmpPaint.get();
622        }
623        am.set(this, GrMatrix::I());
624    }
625    // by definition this fills the entire clip, no need for AA
626    if (paint.fAntiAlias) {
627        if (!tmpPaint.isValid()) {
628            tmpPaint.set(paint);
629            p = tmpPaint.get();
630        }
631        GrAssert(p == tmpPaint.get());
632        tmpPaint.get()->fAntiAlias = false;
633    }
634    this->drawRect(*p, r);
635}
636
637////////////////////////////////////////////////////////////////////////////////
638
639namespace {
640inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
641    return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
642}
643}
644
645struct GrContext::OffscreenRecord {
646    enum Downsample {
647        k4x4TwoPass_Downsample,
648        k4x4SinglePass_Downsample,
649        kFSAA_Downsample
650    }                              fDownsample;
651    int                            fTileSizeX;
652    int                            fTileSizeY;
653    int                            fTileCountX;
654    int                            fTileCountY;
655    int                            fScale;
656    GrAutoScratchTexture           fOffscreen0;
657    GrAutoScratchTexture           fOffscreen1;
658    GrDrawTarget::SavedDrawState   fSavedState;
659    GrClip                         fClip;
660};
661
662bool GrContext::doOffscreenAA(GrDrawTarget* target,
663                              bool isHairLines) const {
664#if !GR_USE_OFFSCREEN_AA
665    return false;
666#else
667    if (!target->isAntialiasState()) {
668        return false;
669    }
670    // Line primitves are always rasterized as 1 pixel wide.
671    // Super-sampling would make them too thin but MSAA would be OK.
672    if (isHairLines &&
673        (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
674        return false;
675    }
676    if (target->getRenderTarget()->isMultisampled()) {
677        return false;
678    }
679    if (disable_coverage_aa_for_blend(target)) {
680#if GR_DEBUG
681        GrPrintf("Turning off AA to correctly apply blend.\n");
682#endif
683        return false;
684    }
685    return true;
686#endif
687}
688
689bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
690                                      bool requireStencil,
691                                      const GrIRect& boundRect,
692                                      GrPathRenderer* pr,
693                                      OffscreenRecord* record) {
694
695    GrAssert(GR_USE_OFFSCREEN_AA);
696
697    GrAssert(NULL == record->fOffscreen0.texture());
698    GrAssert(NULL == record->fOffscreen1.texture());
699    GrAssert(!boundRect.isEmpty());
700
701    int boundW = boundRect.width();
702    int boundH = boundRect.height();
703
704    GrTextureDesc desc;
705
706    desc.fWidth  = GrMin(fMaxOffscreenAASize, boundW);
707    desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
708
709    if (requireStencil) {
710        desc.fFlags = kRenderTarget_GrTextureFlagBit;
711    } else {
712        desc.fFlags = kRenderTarget_GrTextureFlagBit |
713                      kNoStencil_GrTextureFlagBit;
714    }
715
716    desc.fFormat = kRGBA_8888_GrPixelConfig;
717
718    if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
719        record->fDownsample = OffscreenRecord::kFSAA_Downsample;
720        record->fScale = 1;
721        desc.fAALevel = kMed_GrAALevel;
722    } else {
723        record->fDownsample = fGpu->getCaps().fShaderSupport ?
724                                OffscreenRecord::k4x4SinglePass_Downsample :
725                                OffscreenRecord::k4x4TwoPass_Downsample;
726        record->fScale = OFFSCREEN_SSAA_SCALE;
727        // both downsample paths assume this
728        GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
729        desc.fAALevel = kNone_GrAALevel;
730    }
731
732    desc.fWidth *= record->fScale;
733    desc.fHeight *= record->fScale;
734    record->fOffscreen0.set(this, desc);
735    if (NULL == record->fOffscreen0.texture()) {
736        return false;
737    }
738    // the approximate lookup might have given us some slop space, might as well
739    // use it when computing the tiles size.
740    // these are scale values, will adjust after considering
741    // the possible second offscreen.
742    record->fTileSizeX = record->fOffscreen0.texture()->width();
743    record->fTileSizeY = record->fOffscreen0.texture()->height();
744
745    if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
746        desc.fWidth /= 2;
747        desc.fHeight /= 2;
748        record->fOffscreen1.set(this, desc);
749        if (NULL == record->fOffscreen1.texture()) {
750            return false;
751        }
752        record->fTileSizeX = GrMin(record->fTileSizeX,
753                                   2 * record->fOffscreen0.texture()->width());
754        record->fTileSizeY = GrMin(record->fTileSizeY,
755                                   2 * record->fOffscreen0.texture()->height());
756    }
757    record->fTileSizeX /= record->fScale;
758    record->fTileSizeY /= record->fScale;
759
760    record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
761    record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
762
763    record->fClip = target->getClip();
764
765    target->saveCurrentDrawState(&record->fSavedState);
766    return true;
767}
768
769void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
770                                      const GrIRect& boundRect,
771                                      int tileX, int tileY,
772                                      OffscreenRecord* record) {
773
774    GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
775    GrAssert(NULL != offRT0);
776
777    GrPaint tempPaint;
778    tempPaint.reset();
779    SetPaint(tempPaint, target);
780    target->setRenderTarget(offRT0);
781
782    GrMatrix transM;
783    int left = boundRect.fLeft + tileX * record->fTileSizeX;
784    int top =  boundRect.fTop  + tileY * record->fTileSizeY;
785    transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
786    target->postConcatViewMatrix(transM);
787    GrMatrix scaleM;
788    scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
789    target->postConcatViewMatrix(scaleM);
790
791    int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
792                                               record->fTileSizeX;
793    int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
794                                               record->fTileSizeY;
795    GrIRect clear = SkIRect::MakeWH(record->fScale * w,
796                                    record->fScale * h);
797    target->setClip(GrClip(clear));
798#if 0
799    // visualize tile boundaries by setting edges of offscreen to white
800    // and interior to tranparent. black.
801    target->clear(&clear, 0xffffffff);
802
803    static const int gOffset = 2;
804    GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
805                                       record->fScale * w - gOffset,
806                                       record->fScale * h - gOffset);
807    target->clear(&clear2, 0x0);
808#else
809    target->clear(&clear, 0x0);
810#endif
811}
812
813void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
814                                 const GrPaint& paint,
815                                 const GrIRect& boundRect,
816                                 int tileX, int tileY,
817                                 OffscreenRecord* record) {
818    SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
819    GrAssert(NULL != record->fOffscreen0.texture());
820    GrDrawTarget::AutoGeometryPush agp(target);
821    GrIRect tileRect;
822    tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
823    tileRect.fTop  = boundRect.fTop  + tileY * record->fTileSizeY,
824    tileRect.fRight = (tileX == record->fTileCountX-1) ?
825                        boundRect.fRight :
826                        tileRect.fLeft + record->fTileSizeX;
827    tileRect.fBottom = (tileY == record->fTileCountY-1) ?
828                        boundRect.fBottom :
829                        tileRect.fTop + record->fTileSizeY;
830
831    GrSamplerState::Filter filter;
832    if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
833        filter = GrSamplerState::k4x4Downsample_Filter;
834    } else {
835        filter = GrSamplerState::kBilinear_Filter;
836    }
837
838    GrMatrix sampleM;
839    GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
840                           GrSamplerState::kClamp_WrapMode, filter);
841
842    GrTexture* src = record->fOffscreen0.texture();
843    int scale;
844
845    enum {
846        kOffscreenStage = GrPaint::kTotalStages,
847    };
848
849    if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
850        GrAssert(NULL != record->fOffscreen1.texture());
851        scale = 2;
852        GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
853
854        // Do 2x2 downsample from first to second
855        target->setTexture(kOffscreenStage, src);
856        target->setRenderTarget(dst);
857        target->setViewMatrix(GrMatrix::I());
858        sampleM.setScale(scale * GR_Scalar1 / src->width(),
859                         scale * GR_Scalar1 / src->height());
860        sampler.setMatrix(sampleM);
861        target->setSamplerState(kOffscreenStage, sampler);
862        GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
863                                     SkIntToScalar(scale * tileRect.height()));
864        target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
865
866        src = record->fOffscreen1.texture();
867    } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
868        scale = 1;
869        GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
870        src->asRenderTarget()->overrideResolveRect(rect);
871    } else {
872        GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
873                 record->fDownsample);
874        scale = 4;
875    }
876
877    // setup for draw back to main RT, we use the original
878    // draw state setup by the caller plus an additional coverage
879    // stage to handle the AA resolve. Also, we use an identity
880    // view matrix and so pre-concat sampler matrices with view inv.
881    int stageMask = paint.getActiveStageMask();
882
883    target->restoreDrawState(record->fSavedState);
884    target->setClip(record->fClip);
885
886    if (stageMask) {
887        GrMatrix invVM;
888        if (target->getViewInverse(&invVM)) {
889            target->preConcatSamplerMatrices(stageMask, invVM);
890        }
891    }
892    // This is important when tiling, otherwise second tile's
893    // pass 1 view matrix will be incorrect.
894    GrDrawTarget::AutoViewMatrixRestore avmr(target);
895
896    target->setViewMatrix(GrMatrix::I());
897
898    target->setTexture(kOffscreenStage, src);
899    sampleM.setScale(scale * GR_Scalar1 / src->width(),
900                     scale * GR_Scalar1 / src->height());
901    sampler.setMatrix(sampleM);
902    sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
903                         SkIntToScalar(-tileRect.fTop));
904    sampler.preConcatMatrix(sampleM);
905    target->setSamplerState(kOffscreenStage, sampler);
906
907    GrRect dstRect;
908    int stages = (1 << kOffscreenStage) | stageMask;
909    dstRect.set(tileRect);
910    target->drawSimpleRect(dstRect, NULL, stages);
911}
912
913void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
914                                   GrPathRenderer* pr,
915                                   OffscreenRecord* record) {
916    target->restoreDrawState(record->fSavedState);
917}
918
919////////////////////////////////////////////////////////////////////////////////
920
921/*  create a triangle strip that strokes the specified triangle. There are 8
922 unique vertices, but we repreat the last 2 to close up. Alternatively we
923 could use an indices array, and then only send 8 verts, but not sure that
924 would be faster.
925 */
926static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
927                               GrScalar width) {
928    const GrScalar rad = GrScalarHalf(width);
929    rect.sort();
930
931    verts[0].set(rect.fLeft + rad, rect.fTop + rad);
932    verts[1].set(rect.fLeft - rad, rect.fTop - rad);
933    verts[2].set(rect.fRight - rad, rect.fTop + rad);
934    verts[3].set(rect.fRight + rad, rect.fTop - rad);
935    verts[4].set(rect.fRight - rad, rect.fBottom - rad);
936    verts[5].set(rect.fRight + rad, rect.fBottom + rad);
937    verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
938    verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
939    verts[8] = verts[0];
940    verts[9] = verts[1];
941}
942
943static void setInsetFan(GrPoint* pts, size_t stride,
944                        const GrRect& r, GrScalar dx, GrScalar dy) {
945    pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
946}
947
948static const uint16_t gFillAARectIdx[] = {
949    0, 1, 5, 5, 4, 0,
950    1, 2, 6, 6, 5, 1,
951    2, 3, 7, 7, 6, 2,
952    3, 0, 4, 4, 7, 3,
953    4, 5, 6, 6, 7, 4,
954};
955
956int GrContext::aaFillRectIndexCount() const {
957    return GR_ARRAY_COUNT(gFillAARectIdx);
958}
959
960GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
961    if (NULL == fAAFillRectIndexBuffer) {
962        fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
963                                                         false);
964        if (NULL != fAAFillRectIndexBuffer) {
965    #if GR_DEBUG
966            bool updated =
967    #endif
968            fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
969                                               sizeof(gFillAARectIdx));
970            GR_DEBUGASSERT(updated);
971        }
972    }
973    return fAAFillRectIndexBuffer;
974}
975
976static const uint16_t gStrokeAARectIdx[] = {
977    0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
978    1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
979    2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
980    3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
981
982    0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
983    1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
984    2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
985    3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
986
987    0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
988    1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
989    2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
990    3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
991};
992
993int GrContext::aaStrokeRectIndexCount() const {
994    return GR_ARRAY_COUNT(gStrokeAARectIdx);
995}
996
997GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
998    if (NULL == fAAStrokeRectIndexBuffer) {
999        fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1000                                                           false);
1001        if (NULL != fAAStrokeRectIndexBuffer) {
1002    #if GR_DEBUG
1003            bool updated =
1004    #endif
1005            fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1006                                                 sizeof(gStrokeAARectIdx));
1007            GR_DEBUGASSERT(updated);
1008        }
1009    }
1010    return fAAStrokeRectIndexBuffer;
1011}
1012
1013static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1014                                     bool useCoverage) {
1015    GrVertexLayout layout = 0;
1016    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
1017        if (NULL != target->getTexture(s)) {
1018            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1019        }
1020    }
1021    if (useCoverage) {
1022        layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1023    } else {
1024        layout |= GrDrawTarget::kColor_VertexLayoutBit;
1025    }
1026    return layout;
1027}
1028
1029void GrContext::fillAARect(GrDrawTarget* target,
1030                           const GrRect& devRect,
1031                           bool useVertexCoverage) {
1032    GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
1033
1034    size_t vsize = GrDrawTarget::VertexSize(layout);
1035
1036    GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
1037    if (!geo.succeeded()) {
1038        GrPrintf("Failed to get space for vertices!\n");
1039        return;
1040    }
1041    GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1042    if (NULL == indexBuffer) {
1043        GrPrintf("Failed to create index buffer!\n");
1044        return;
1045    }
1046
1047    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1048
1049    GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1050    GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1051
1052    setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1053    setInsetFan(fan1Pos, vsize, devRect,  GR_ScalarHalf,  GR_ScalarHalf);
1054
1055    verts += sizeof(GrPoint);
1056    for (int i = 0; i < 4; ++i) {
1057        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1058    }
1059
1060    GrColor innerColor;
1061    if (useVertexCoverage) {
1062        innerColor = 0xffffffff;
1063    } else {
1064        innerColor = target->getColor();
1065    }
1066
1067    verts += 4 * vsize;
1068    for (int i = 0; i < 4; ++i) {
1069        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1070    }
1071
1072    target->setIndexSourceToBuffer(indexBuffer);
1073
1074    target->drawIndexed(kTriangles_PrimitiveType, 0,
1075                         0, 8, this->aaFillRectIndexCount());
1076}
1077
1078void GrContext::strokeAARect(GrDrawTarget* target,
1079                             const GrRect& devRect,
1080                             const GrVec& devStrokeSize,
1081                             bool useVertexCoverage) {
1082    const GrScalar& dx = devStrokeSize.fX;
1083    const GrScalar& dy = devStrokeSize.fY;
1084    const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1085    const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1086
1087    GrScalar spare;
1088    {
1089        GrScalar w = devRect.width() - dx;
1090        GrScalar h = devRect.height() - dy;
1091        spare = GrMin(w, h);
1092    }
1093
1094    if (spare <= 0) {
1095        GrRect r(devRect);
1096        r.inset(-rx, -ry);
1097        fillAARect(target, r, useVertexCoverage);
1098        return;
1099    }
1100    GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
1101    size_t vsize = GrDrawTarget::VertexSize(layout);
1102
1103    GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
1104    if (!geo.succeeded()) {
1105        GrPrintf("Failed to get space for vertices!\n");
1106        return;
1107    }
1108    GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1109    if (NULL == indexBuffer) {
1110        GrPrintf("Failed to create index buffer!\n");
1111        return;
1112    }
1113
1114    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1115
1116    GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1117    GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1118    GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1119    GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1120
1121    setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1122    setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1123    setInsetFan(fan2Pos, vsize, devRect,  rx - GR_ScalarHalf,  ry - GR_ScalarHalf);
1124    setInsetFan(fan3Pos, vsize, devRect,  rx + GR_ScalarHalf,  ry + GR_ScalarHalf);
1125
1126    verts += sizeof(GrPoint);
1127    for (int i = 0; i < 4; ++i) {
1128        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1129    }
1130
1131    GrColor innerColor;
1132    if (useVertexCoverage) {
1133        innerColor = 0xffffffff;
1134    } else {
1135        innerColor = target->getColor();
1136    }
1137    verts += 4 * vsize;
1138    for (int i = 0; i < 8; ++i) {
1139        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1140    }
1141
1142    verts += 8 * vsize;
1143    for (int i = 0; i < 8; ++i) {
1144        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1145    }
1146
1147    target->setIndexSourceToBuffer(indexBuffer);
1148    target->drawIndexed(kTriangles_PrimitiveType,
1149                        0, 0, 16, aaStrokeRectIndexCount());
1150}
1151
1152/**
1153 * Returns true if the rects edges are integer-aligned.
1154 */
1155static bool isIRect(const GrRect& r) {
1156    return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1157           GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1158}
1159
1160static bool apply_aa_to_rect(GrDrawTarget* target,
1161                             const GrRect& rect,
1162                             GrScalar width,
1163                             const GrMatrix* matrix,
1164                             GrMatrix* combinedMatrix,
1165                             GrRect* devRect,
1166                             bool* useVertexCoverage) {
1167    // we use a simple alpha ramp to do aa on axis-aligned rects
1168    // do AA with alpha ramp if the caller requested AA, the rect
1169    // will be axis-aligned,the render target is not
1170    // multisampled, and the rect won't land on integer coords.
1171
1172    if (!target->isAntialiasState()) {
1173        return false;
1174    }
1175
1176    // we are keeping around the "tweak the alpha" trick because
1177    // it is our only hope for the fixed-pipe implementation.
1178    // In a shader implementation we can give a separate coverage input
1179    *useVertexCoverage = false;
1180    if (!target->canTweakAlphaForCoverage()) {
1181        if (target->getCaps().fSupportPerVertexCoverage) {
1182            if (disable_coverage_aa_for_blend(target)) {
1183#if GR_DEBUG
1184                GrPrintf("Turning off AA to correctly apply blend.\n");
1185#endif
1186                return false;
1187            } else {
1188                *useVertexCoverage = true;
1189            }
1190        } else {
1191            GrPrintf("Rect AA dropped because no support for coverage.\n");
1192            return false;
1193        }
1194    }
1195
1196    if (target->getRenderTarget()->isMultisampled()) {
1197        return false;
1198    }
1199
1200    if (0 == width && target->willUseHWAALines()) {
1201        return false;
1202    }
1203
1204    if (!target->getViewMatrix().preservesAxisAlignment()) {
1205        return false;
1206    }
1207
1208    if (NULL != matrix &&
1209        !matrix->preservesAxisAlignment()) {
1210        return false;
1211    }
1212
1213    *combinedMatrix = target->getViewMatrix();
1214    if (NULL != matrix) {
1215        combinedMatrix->preConcat(*matrix);
1216        GrAssert(combinedMatrix->preservesAxisAlignment());
1217    }
1218
1219    combinedMatrix->mapRect(devRect, rect);
1220    devRect->sort();
1221
1222    if (width < 0) {
1223        return !isIRect(*devRect);
1224    } else {
1225        return true;
1226    }
1227}
1228
1229void GrContext::drawRect(const GrPaint& paint,
1230                         const GrRect& rect,
1231                         GrScalar width,
1232                         const GrMatrix* matrix) {
1233    SK_TRACE_EVENT0("GrContext::drawRect");
1234
1235    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1236    int stageMask = paint.getActiveStageMask();
1237
1238    GrRect devRect = rect;
1239    GrMatrix combinedMatrix;
1240    bool useVertexCoverage;
1241    bool doAA = apply_aa_to_rect(target, rect, width, matrix,
1242                                 &combinedMatrix, &devRect, &useVertexCoverage);
1243
1244    if (doAA) {
1245        GrDrawTarget::AutoViewMatrixRestore avm(target);
1246        if (stageMask) {
1247            GrMatrix inv;
1248            if (combinedMatrix.invert(&inv)) {
1249                target->preConcatSamplerMatrices(stageMask, inv);
1250            }
1251        }
1252        target->setViewMatrix(GrMatrix::I());
1253        if (width >= 0) {
1254            GrVec strokeSize;;
1255            if (width > 0) {
1256                strokeSize.set(width, width);
1257                combinedMatrix.mapVectors(&strokeSize, 1);
1258                strokeSize.setAbs(strokeSize);
1259            } else {
1260                strokeSize.set(GR_Scalar1, GR_Scalar1);
1261            }
1262            strokeAARect(target, devRect, strokeSize, useVertexCoverage);
1263        } else {
1264            fillAARect(target, devRect, useVertexCoverage);
1265        }
1266        return;
1267    }
1268
1269    if (width >= 0) {
1270        // TODO: consider making static vertex buffers for these cases.
1271        // Hairline could be done by just adding closing vertex to
1272        // unitSquareVertexBuffer()
1273        GrVertexLayout layout =  PaintStageVertexLayoutBits(paint, NULL);
1274
1275        static const int worstCaseVertCount = 10;
1276        GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1277
1278        if (!geo.succeeded()) {
1279            GrPrintf("Failed to get space for vertices!\n");
1280            return;
1281        }
1282
1283        GrPrimitiveType primType;
1284        int vertCount;
1285        GrPoint* vertex = geo.positions();
1286
1287        if (width > 0) {
1288            vertCount = 10;
1289            primType = kTriangleStrip_PrimitiveType;
1290            setStrokeRectStrip(vertex, rect, width);
1291        } else {
1292            // hairline
1293            vertCount = 5;
1294            primType = kLineStrip_PrimitiveType;
1295            vertex[0].set(rect.fLeft, rect.fTop);
1296            vertex[1].set(rect.fRight, rect.fTop);
1297            vertex[2].set(rect.fRight, rect.fBottom);
1298            vertex[3].set(rect.fLeft, rect.fBottom);
1299            vertex[4].set(rect.fLeft, rect.fTop);
1300        }
1301
1302        GrDrawTarget::AutoViewMatrixRestore avmr;
1303        if (NULL != matrix) {
1304            avmr.set(target);
1305            target->preConcatViewMatrix(*matrix);
1306            target->preConcatSamplerMatrices(stageMask, *matrix);
1307        }
1308
1309        target->drawNonIndexed(primType, 0, vertCount);
1310    } else {
1311        #if GR_STATIC_RECT_VB
1312            GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1313            const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1314            if (NULL == sqVB) {
1315                GrPrintf("Failed to create static rect vb.\n");
1316                return;
1317            }
1318            target->setVertexSourceToBuffer(layout, sqVB);
1319            GrDrawTarget::AutoViewMatrixRestore avmr(target);
1320            GrMatrix m;
1321            m.setAll(rect.width(),    0,             rect.fLeft,
1322                        0,            rect.height(), rect.fTop,
1323                        0,            0,             GrMatrix::I()[8]);
1324
1325            if (NULL != matrix) {
1326                m.postConcat(*matrix);
1327            }
1328
1329            target->preConcatViewMatrix(m);
1330            target->preConcatSamplerMatrices(stageMask, m);
1331
1332            target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1333        #else
1334            target->drawSimpleRect(rect, matrix, stageMask);
1335        #endif
1336    }
1337}
1338
1339void GrContext::drawRectToRect(const GrPaint& paint,
1340                               const GrRect& dstRect,
1341                               const GrRect& srcRect,
1342                               const GrMatrix* dstMatrix,
1343                               const GrMatrix* srcMatrix) {
1344    SK_TRACE_EVENT0("GrContext::drawRectToRect");
1345
1346    // srcRect refers to paint's first texture
1347    if (NULL == paint.getTexture(0)) {
1348        drawRect(paint, dstRect, -1, dstMatrix);
1349        return;
1350    }
1351
1352    GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1353
1354#if GR_STATIC_RECT_VB
1355    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1356
1357    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1358    GrDrawTarget::AutoViewMatrixRestore avmr(target);
1359
1360    GrMatrix m;
1361
1362    m.setAll(dstRect.width(), 0,                dstRect.fLeft,
1363             0,               dstRect.height(), dstRect.fTop,
1364             0,               0,                GrMatrix::I()[8]);
1365    if (NULL != dstMatrix) {
1366        m.postConcat(*dstMatrix);
1367    }
1368    target->preConcatViewMatrix(m);
1369
1370    // srcRect refers to first stage
1371    int otherStageMask = paint.getActiveStageMask() &
1372                         (~(1 << GrPaint::kFirstTextureStage));
1373    if (otherStageMask) {
1374        target->preConcatSamplerMatrices(otherStageMask, m);
1375    }
1376
1377    m.setAll(srcRect.width(), 0,                srcRect.fLeft,
1378             0,               srcRect.height(), srcRect.fTop,
1379             0,               0,                GrMatrix::I()[8]);
1380    if (NULL != srcMatrix) {
1381        m.postConcat(*srcMatrix);
1382    }
1383    target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
1384
1385    const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1386    if (NULL == sqVB) {
1387        GrPrintf("Failed to create static rect vb.\n");
1388        return;
1389    }
1390    target->setVertexSourceToBuffer(layout, sqVB);
1391    target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1392#else
1393
1394    GrDrawTarget* target;
1395#if BATCH_RECT_TO_RECT
1396    target = this->prepareToDraw(paint, kBuffered_DrawCategory);
1397#else
1398    target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1399#endif
1400
1401    const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1402    const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1403    srcRects[0] = &srcRect;
1404    srcMatrices[0] = srcMatrix;
1405
1406    target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1407#endif
1408}
1409
1410void GrContext::drawVertices(const GrPaint& paint,
1411                             GrPrimitiveType primitiveType,
1412                             int vertexCount,
1413                             const GrPoint positions[],
1414                             const GrPoint texCoords[],
1415                             const GrColor colors[],
1416                             const uint16_t indices[],
1417                             int indexCount) {
1418    SK_TRACE_EVENT0("GrContext::drawVertices");
1419
1420    GrDrawTarget::AutoReleaseGeometry geo;
1421
1422    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1423
1424    bool hasTexCoords[GrPaint::kTotalStages] = {
1425        NULL != texCoords,   // texCoordSrc provides explicit stage 0 coords
1426        0                    // remaining stages use positions
1427    };
1428
1429    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
1430
1431    if (NULL != colors) {
1432        layout |= GrDrawTarget::kColor_VertexLayoutBit;
1433    }
1434    int vertexSize = GrDrawTarget::VertexSize(layout);
1435
1436    if (sizeof(GrPoint) != vertexSize) {
1437        if (!geo.set(target, layout, vertexCount, 0)) {
1438            GrPrintf("Failed to get space for vertices!\n");
1439            return;
1440        }
1441        int texOffsets[GrDrawTarget::kMaxTexCoords];
1442        int colorOffset;
1443        GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1444                                                texOffsets,
1445                                                &colorOffset,
1446                                                NULL,
1447                                                NULL);
1448        void* curVertex = geo.vertices();
1449
1450        for (int i = 0; i < vertexCount; ++i) {
1451            *((GrPoint*)curVertex) = positions[i];
1452
1453            if (texOffsets[0] > 0) {
1454                *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1455            }
1456            if (colorOffset > 0) {
1457                *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1458            }
1459            curVertex = (void*)((intptr_t)curVertex + vertexSize);
1460        }
1461    } else {
1462        target->setVertexSourceToArray(layout, positions, vertexCount);
1463    }
1464
1465    // we don't currently apply offscreen AA to this path. Need improved
1466    // management of GrDrawTarget's geometry to avoid copying points per-tile.
1467
1468    if (NULL != indices) {
1469        target->setIndexSourceToArray(indices, indexCount);
1470        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1471    } else {
1472        target->drawNonIndexed(primitiveType, 0, vertexCount);
1473    }
1474}
1475
1476///////////////////////////////////////////////////////////////////////////////
1477
1478void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1479                         GrPathFill fill, const GrPoint* translate) {
1480
1481    if (path.isEmpty()) {
1482#if GR_DEBUG
1483       GrPrintf("Empty path should have been caught by canvas.\n");
1484#endif
1485       if (GrIsFillInverted(fill)) {
1486           this->drawPaint(paint);
1487       }
1488       return;
1489    }
1490
1491    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1492
1493    // An Assumption here is that path renderer would use some form of tweaking
1494    // the src color (either the input alpha or in the frag shader) to implement
1495    // aa. If we have some future driver-mojo path AA that can do the right
1496    // thing WRT to the blend then we'll need some query on the PR.
1497    if (disable_coverage_aa_for_blend(target)) {
1498#if GR_DEBUG
1499        GrPrintf("Turning off AA to correctly apply blend.\n");
1500#endif
1501        target->disableState(GrDrawTarget::kAntialias_StateBit);
1502    }
1503
1504    GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1505    if (NULL == pr) {
1506#if GR_DEBUG
1507        GrPrintf("Unable to find path renderer compatible with path.\n");
1508#endif
1509        return;
1510    }
1511
1512    GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1513    GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
1514
1515    if (!pr->supportsAA(target, path, fill) &&
1516        this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1517
1518        bool needsStencil = pr->requiresStencilPass(target, path, fill);
1519
1520        // compute bounds as intersection of rt size, clip, and path
1521        GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1522                                        target->getRenderTarget()->height());
1523        GrIRect clipIBounds;
1524        if (target->getClip().hasConservativeBounds()) {
1525            target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1526            if (!bound.intersect(clipIBounds)) {
1527                return;
1528            }
1529        }
1530
1531        GrRect pathBounds = path.getBounds();
1532        if (!pathBounds.isEmpty()) {
1533            if (NULL != translate) {
1534                pathBounds.offset(*translate);
1535            }
1536            target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1537            GrIRect pathIBounds;
1538            pathBounds.roundOut(&pathIBounds);
1539            if (!bound.intersect(pathIBounds)) {
1540                return;
1541            }
1542        }
1543        OffscreenRecord record;
1544        if (this->prepareForOffscreenAA(target, needsStencil, bound,
1545                                        pr, &record)) {
1546            for (int tx = 0; tx < record.fTileCountX; ++tx) {
1547                for (int ty = 0; ty < record.fTileCountY; ++ty) {
1548                    this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1549                    pr->drawPath(0);
1550                    this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1551                }
1552            }
1553            this->cleanupOffscreenAA(target, pr, &record);
1554            if (GrIsFillInverted(fill) && bound != clipIBounds) {
1555                GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1556                GrRect rect;
1557                if (clipIBounds.fTop < bound.fTop) {
1558                    rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1559                              clipIBounds.fRight, bound.fTop);
1560                    target->drawSimpleRect(rect, NULL, stageMask);
1561                }
1562                if (clipIBounds.fLeft < bound.fLeft) {
1563                    rect.iset(clipIBounds.fLeft, bound.fTop,
1564                              bound.fLeft, bound.fBottom);
1565                    target->drawSimpleRect(rect, NULL, stageMask);
1566                }
1567                if (clipIBounds.fRight > bound.fRight) {
1568                    rect.iset(bound.fRight, bound.fTop,
1569                              clipIBounds.fRight, bound.fBottom);
1570                    target->drawSimpleRect(rect, NULL, stageMask);
1571                }
1572                if (clipIBounds.fBottom > bound.fBottom) {
1573                    rect.iset(clipIBounds.fLeft, bound.fBottom,
1574                              clipIBounds.fRight, clipIBounds.fBottom);
1575                    target->drawSimpleRect(rect, NULL, stageMask);
1576                }
1577            }
1578            return;
1579        }
1580    }
1581    pr->drawPath(stageMask);
1582}
1583
1584////////////////////////////////////////////////////////////////////////////////
1585
1586bool GrContext::supportsShaders() const {
1587    return fGpu->getCaps().fShaderSupport;
1588}
1589
1590void GrContext::flush(int flagsBitfield) {
1591    if (kDiscard_FlushBit & flagsBitfield) {
1592        fDrawBuffer->reset();
1593    } else {
1594        flushDrawBuffer();
1595    }
1596
1597    if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
1598        fGpu->forceRenderTargetFlush();
1599    }
1600}
1601
1602void GrContext::flushText() {
1603    if (kText_DrawCategory == fLastDrawCategory) {
1604        flushDrawBuffer();
1605    }
1606}
1607
1608void GrContext::flushDrawBuffer() {
1609#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1610    if (fDrawBuffer) {
1611        fDrawBuffer->playback(fGpu);
1612        fDrawBuffer->reset();
1613    }
1614#endif
1615}
1616
1617bool GrContext::readTexturePixels(GrTexture* texture,
1618                                  int left, int top, int width, int height,
1619                                  GrPixelConfig config, void* buffer) {
1620    SK_TRACE_EVENT0("GrContext::readTexturePixels");
1621
1622    // TODO: code read pixels for textures that aren't rendertargets
1623
1624    this->flush();
1625    GrRenderTarget* target = texture->asRenderTarget();
1626    if (NULL != target) {
1627        return fGpu->readPixels(target,
1628                                left, top, width, height,
1629                                config, buffer);
1630    } else {
1631        return false;
1632    }
1633}
1634
1635bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1636                                      int left, int top, int width, int height,
1637                                      GrPixelConfig config, void* buffer) {
1638    SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
1639    uint32_t flushFlags = 0;
1640    if (NULL == target) {
1641        flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1642    }
1643
1644    this->flush(flushFlags);
1645    return fGpu->readPixels(target,
1646                            left, top, width, height,
1647                            config, buffer);
1648}
1649
1650void GrContext::writePixels(int left, int top, int width, int height,
1651                            GrPixelConfig config, const void* buffer,
1652                            size_t stride) {
1653    SK_TRACE_EVENT0("GrContext::writePixels");
1654
1655    // TODO: when underlying api has a direct way to do this we should use it
1656    // (e.g. glDrawPixels on desktop GL).
1657
1658    this->flush(true);
1659
1660    const GrTextureDesc desc = {
1661        kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
1662    };
1663    GrAutoScratchTexture ast(this, desc);
1664    GrTexture* texture = ast.texture();
1665    if (NULL == texture) {
1666        return;
1667    }
1668    texture->uploadTextureData(0, 0, width, height, buffer, stride);
1669
1670    GrDrawTarget::AutoStateRestore  asr(fGpu);
1671
1672    GrMatrix matrix;
1673    matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1674    fGpu->setViewMatrix(matrix);
1675
1676    fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1677    fGpu->disableState(GrDrawTarget::kClip_StateBit);
1678    fGpu->setAlpha(0xFF);
1679    fGpu->setBlendFunc(kOne_BlendCoeff,
1680                       kZero_BlendCoeff);
1681    fGpu->setTexture(0, texture);
1682
1683    GrSamplerState sampler;
1684    sampler.setClampNoFilter();
1685    matrix.setIDiv(texture->width(), texture->height());
1686    sampler.setMatrix(matrix);
1687    fGpu->setSamplerState(0, sampler);
1688
1689    GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1690    static const int VCOUNT = 4;
1691    // TODO: Use GrGpu::drawRect here
1692    GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1693    if (!geo.succeeded()) {
1694        GrPrintf("Failed to get space for vertices!\n");
1695        return;
1696    }
1697    ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1698    fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1699}
1700////////////////////////////////////////////////////////////////////////////////
1701
1702void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1703
1704    for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1705        int s = i + GrPaint::kFirstTextureStage;
1706        target->setTexture(s, paint.getTexture(i));
1707        target->setSamplerState(s, *paint.getTextureSampler(i));
1708    }
1709
1710    target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1711
1712    for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1713        int s = i + GrPaint::kFirstMaskStage;
1714        target->setTexture(s, paint.getMask(i));
1715        target->setSamplerState(s, *paint.getMaskSampler(i));
1716    }
1717
1718    target->setColor(paint.fColor);
1719
1720    if (paint.fDither) {
1721        target->enableState(GrDrawTarget::kDither_StateBit);
1722    } else {
1723        target->disableState(GrDrawTarget::kDither_StateBit);
1724    }
1725    if (paint.fAntiAlias) {
1726        target->enableState(GrDrawTarget::kAntialias_StateBit);
1727    } else {
1728        target->disableState(GrDrawTarget::kAntialias_StateBit);
1729    }
1730    target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1731    target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1732
1733    if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1734        GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1735    }
1736}
1737
1738GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
1739                                       DrawCategory category) {
1740    if (category != fLastDrawCategory) {
1741        flushDrawBuffer();
1742        fLastDrawCategory = category;
1743    }
1744    SetPaint(paint, fGpu);
1745    GrDrawTarget* target = fGpu;
1746    switch (category) {
1747    case kText_DrawCategory:
1748#if DEFER_TEXT_RENDERING
1749        target = fDrawBuffer;
1750        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1751#else
1752        target = fGpu;
1753#endif
1754        break;
1755    case kUnbuffered_DrawCategory:
1756        target = fGpu;
1757        break;
1758    case kBuffered_DrawCategory:
1759        target = fDrawBuffer;
1760        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1761        break;
1762    }
1763    return target;
1764}
1765
1766GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1767                                           const GrPath& path,
1768                                           GrPathFill fill) {
1769    if (NULL == fPathRendererChain) {
1770        fPathRendererChain =
1771            new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1772    }
1773    return fPathRendererChain->getPathRenderer(target, path, fill);
1774}
1775
1776////////////////////////////////////////////////////////////////////////////////
1777
1778void GrContext::setRenderTarget(GrRenderTarget* target) {
1779    this->flush(false);
1780    fGpu->setRenderTarget(target);
1781}
1782
1783GrRenderTarget* GrContext::getRenderTarget() {
1784    return fGpu->getRenderTarget();
1785}
1786
1787const GrRenderTarget* GrContext::getRenderTarget() const {
1788    return fGpu->getRenderTarget();
1789}
1790
1791const GrMatrix& GrContext::getMatrix() const {
1792    return fGpu->getViewMatrix();
1793}
1794
1795void GrContext::setMatrix(const GrMatrix& m) {
1796    fGpu->setViewMatrix(m);
1797}
1798
1799void GrContext::concatMatrix(const GrMatrix& m) const {
1800    fGpu->preConcatViewMatrix(m);
1801}
1802
1803static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1804    intptr_t mask = 1 << shift;
1805    if (pred) {
1806        bits |= mask;
1807    } else {
1808        bits &= ~mask;
1809    }
1810    return bits;
1811}
1812
1813void GrContext::resetStats() {
1814    fGpu->resetStats();
1815}
1816
1817const GrGpuStats& GrContext::getStats() const {
1818    return fGpu->getStats();
1819}
1820
1821void GrContext::printStats() const {
1822    fGpu->printStats();
1823}
1824
1825GrContext::GrContext(GrGpu* gpu) {
1826    fGpu = gpu;
1827    fGpu->ref();
1828    fGpu->setContext(this);
1829
1830    fPathRendererChain = NULL;
1831
1832    fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1833                                        MAX_TEXTURE_CACHE_BYTES);
1834    fFontCache = new GrFontCache(fGpu);
1835
1836    fLastDrawCategory = kUnbuffered_DrawCategory;
1837
1838    fDrawBuffer = NULL;
1839    fDrawBufferVBAllocPool = NULL;
1840    fDrawBufferIBAllocPool = NULL;
1841
1842    fAAFillRectIndexBuffer = NULL;
1843    fAAStrokeRectIndexBuffer = NULL;
1844
1845    int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1846    if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
1847        gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1848    }
1849    fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
1850
1851    this->setupDrawBuffer();
1852}
1853
1854void GrContext::setupDrawBuffer() {
1855
1856    GrAssert(NULL == fDrawBuffer);
1857    GrAssert(NULL == fDrawBufferVBAllocPool);
1858    GrAssert(NULL == fDrawBufferIBAllocPool);
1859
1860#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1861    fDrawBufferVBAllocPool =
1862        new GrVertexBufferAllocPool(fGpu, false,
1863                                    DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1864                                    DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1865    fDrawBufferIBAllocPool =
1866        new GrIndexBufferAllocPool(fGpu, false,
1867                                   DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1868                                   DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1869
1870    fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1871                                          fDrawBufferVBAllocPool,
1872                                          fDrawBufferIBAllocPool);
1873#endif
1874
1875#if BATCH_RECT_TO_RECT
1876    fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1877#endif
1878}
1879
1880GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1881    GrDrawTarget* target;
1882#if DEFER_TEXT_RENDERING
1883    target = prepareToDraw(paint, kText_DrawCategory);
1884#else
1885    target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1886#endif
1887    SetPaint(paint, target);
1888    return target;
1889}
1890
1891const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1892    return fGpu->getQuadIndexBuffer();
1893}
1894
1895void GrContext::convolveInX(GrTexture* texture,
1896                            const SkRect& rect,
1897                            const float* kernel,
1898                            int kernelWidth) {
1899    float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1900    convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1901}
1902
1903void GrContext::convolveInY(GrTexture* texture,
1904                            const SkRect& rect,
1905                            const float* kernel,
1906                            int kernelWidth) {
1907    float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1908    convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1909}
1910
1911void GrContext::convolve(GrTexture* texture,
1912                         const SkRect& rect,
1913                         float imageIncrement[2],
1914                         const float* kernel,
1915                         int kernelWidth) {
1916    GrDrawTarget::AutoStateRestore asr(fGpu);
1917    GrMatrix sampleM;
1918    GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1919                           GrSamplerState::kClamp_WrapMode,
1920                           GrSamplerState::kConvolution_Filter);
1921    sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
1922    sampleM.setScale(GR_Scalar1 / texture->width(),
1923                     GR_Scalar1 / texture->height());
1924    sampler.setMatrix(sampleM);
1925    fGpu->setSamplerState(0, sampler);
1926    fGpu->setViewMatrix(GrMatrix::I());
1927    fGpu->setTexture(0, texture);
1928    fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
1929    fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1930}
1931