GrContext.cpp revision 289533ada623f2238a83771eec977f204f75994f
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::kHWAntialias_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    // Line primitves are always rasterized as 1 pixel wide.
668    // Super-sampling would make them too thin but MSAA would be OK.
669    if (isHairLines &&
670        (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
671        return false;
672    }
673    if (target->getRenderTarget()->isMultisampled()) {
674        return false;
675    }
676    if (disable_coverage_aa_for_blend(target)) {
677#if GR_DEBUG
678        GrPrintf("Turning off AA to correctly apply blend.\n");
679#endif
680        return false;
681    }
682    return true;
683#endif
684}
685
686bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
687                                      bool requireStencil,
688                                      const GrIRect& boundRect,
689                                      GrPathRenderer* pr,
690                                      OffscreenRecord* record) {
691
692    GrAssert(GR_USE_OFFSCREEN_AA);
693
694    GrAssert(NULL == record->fOffscreen0.texture());
695    GrAssert(NULL == record->fOffscreen1.texture());
696    GrAssert(!boundRect.isEmpty());
697
698    int boundW = boundRect.width();
699    int boundH = boundRect.height();
700
701    GrTextureDesc desc;
702
703    desc.fWidth  = GrMin(fMaxOffscreenAASize, boundW);
704    desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
705
706    if (requireStencil) {
707        desc.fFlags = kRenderTarget_GrTextureFlagBit;
708    } else {
709        desc.fFlags = kRenderTarget_GrTextureFlagBit |
710                      kNoStencil_GrTextureFlagBit;
711    }
712
713    desc.fFormat = kRGBA_8888_GrPixelConfig;
714
715    if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
716        record->fDownsample = OffscreenRecord::kFSAA_Downsample;
717        record->fScale = 1;
718        desc.fAALevel = kMed_GrAALevel;
719    } else {
720        record->fDownsample = fGpu->getCaps().fShaderSupport ?
721                                OffscreenRecord::k4x4SinglePass_Downsample :
722                                OffscreenRecord::k4x4TwoPass_Downsample;
723        record->fScale = OFFSCREEN_SSAA_SCALE;
724        // both downsample paths assume this
725        GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
726        desc.fAALevel = kNone_GrAALevel;
727    }
728
729    desc.fWidth *= record->fScale;
730    desc.fHeight *= record->fScale;
731    record->fOffscreen0.set(this, desc);
732    if (NULL == record->fOffscreen0.texture()) {
733        return false;
734    }
735    // the approximate lookup might have given us some slop space, might as well
736    // use it when computing the tiles size.
737    // these are scale values, will adjust after considering
738    // the possible second offscreen.
739    record->fTileSizeX = record->fOffscreen0.texture()->width();
740    record->fTileSizeY = record->fOffscreen0.texture()->height();
741
742    if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
743        desc.fWidth /= 2;
744        desc.fHeight /= 2;
745        record->fOffscreen1.set(this, desc);
746        if (NULL == record->fOffscreen1.texture()) {
747            return false;
748        }
749        record->fTileSizeX = GrMin(record->fTileSizeX,
750                                   2 * record->fOffscreen0.texture()->width());
751        record->fTileSizeY = GrMin(record->fTileSizeY,
752                                   2 * record->fOffscreen0.texture()->height());
753    }
754    record->fTileSizeX /= record->fScale;
755    record->fTileSizeY /= record->fScale;
756
757    record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
758    record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
759
760    record->fClip = target->getClip();
761
762    target->saveCurrentDrawState(&record->fSavedState);
763    return true;
764}
765
766void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
767                                      const GrIRect& boundRect,
768                                      int tileX, int tileY,
769                                      OffscreenRecord* record) {
770
771    GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
772    GrAssert(NULL != offRT0);
773
774    GrPaint tempPaint;
775    tempPaint.reset();
776    SetPaint(tempPaint, target);
777    target->setRenderTarget(offRT0);
778#if PREFER_MSAA_OFFSCREEN_AA
779    target->enableState(GrDrawTarget::kHWAntialias_StateBit);
780#endif
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, and the rect won't land on integer coords.
1170
1171    // we are keeping around the "tweak the alpha" trick because
1172    // it is our only hope for the fixed-pipe implementation.
1173    // In a shader implementation we can give a separate coverage input
1174    // TODO: remove this ugliness when we drop the fixed-pipe impl
1175    *useVertexCoverage = false;
1176    if (!target->canTweakAlphaForCoverage()) {
1177        if (target->getCaps().fSupportPerVertexCoverage) {
1178            if (disable_coverage_aa_for_blend(target)) {
1179#if GR_DEBUG
1180                GrPrintf("Turning off AA to correctly apply blend.\n");
1181#endif
1182                return false;
1183            } else {
1184                *useVertexCoverage = true;
1185            }
1186        } else {
1187            GrPrintf("Rect AA dropped because no support for coverage.\n");
1188            return false;
1189        }
1190    }
1191
1192    if (target->getRenderTarget()->isMultisampled()) {
1193        return false;
1194    }
1195
1196    if (0 == width && target->willUseHWAALines()) {
1197        return false;
1198    }
1199
1200    if (!target->getViewMatrix().preservesAxisAlignment()) {
1201        return false;
1202    }
1203
1204    if (NULL != matrix &&
1205        !matrix->preservesAxisAlignment()) {
1206        return false;
1207    }
1208
1209    *combinedMatrix = target->getViewMatrix();
1210    if (NULL != matrix) {
1211        combinedMatrix->preConcat(*matrix);
1212        GrAssert(combinedMatrix->preservesAxisAlignment());
1213    }
1214
1215    combinedMatrix->mapRect(devRect, rect);
1216    devRect->sort();
1217
1218    if (width < 0) {
1219        return !isIRect(*devRect);
1220    } else {
1221        return true;
1222    }
1223}
1224
1225void GrContext::drawRect(const GrPaint& paint,
1226                         const GrRect& rect,
1227                         GrScalar width,
1228                         const GrMatrix* matrix) {
1229    SK_TRACE_EVENT0("GrContext::drawRect");
1230
1231    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1232    int stageMask = paint.getActiveStageMask();
1233
1234    GrRect devRect = rect;
1235    GrMatrix combinedMatrix;
1236    bool useVertexCoverage;
1237    bool needAA = paint.fAntiAlias &&
1238                  !this->getRenderTarget()->isMultisampled();
1239    bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1240                                           &combinedMatrix, &devRect,
1241                                           &useVertexCoverage);
1242
1243    if (doAA) {
1244        GrDrawTarget::AutoViewMatrixRestore avm(target);
1245        if (stageMask) {
1246            GrMatrix inv;
1247            if (combinedMatrix.invert(&inv)) {
1248                target->preConcatSamplerMatrices(stageMask, inv);
1249            }
1250        }
1251        target->setViewMatrix(GrMatrix::I());
1252        if (width >= 0) {
1253            GrVec strokeSize;;
1254            if (width > 0) {
1255                strokeSize.set(width, width);
1256                combinedMatrix.mapVectors(&strokeSize, 1);
1257                strokeSize.setAbs(strokeSize);
1258            } else {
1259                strokeSize.set(GR_Scalar1, GR_Scalar1);
1260            }
1261            strokeAARect(target, devRect, strokeSize, useVertexCoverage);
1262        } else {
1263            fillAARect(target, devRect, useVertexCoverage);
1264        }
1265        return;
1266    }
1267
1268    if (width >= 0) {
1269        // TODO: consider making static vertex buffers for these cases.
1270        // Hairline could be done by just adding closing vertex to
1271        // unitSquareVertexBuffer()
1272        GrVertexLayout layout =  PaintStageVertexLayoutBits(paint, NULL);
1273
1274        static const int worstCaseVertCount = 10;
1275        GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1276
1277        if (!geo.succeeded()) {
1278            GrPrintf("Failed to get space for vertices!\n");
1279            return;
1280        }
1281
1282        GrPrimitiveType primType;
1283        int vertCount;
1284        GrPoint* vertex = geo.positions();
1285
1286        if (width > 0) {
1287            vertCount = 10;
1288            primType = kTriangleStrip_PrimitiveType;
1289            setStrokeRectStrip(vertex, rect, width);
1290        } else {
1291            // hairline
1292            vertCount = 5;
1293            primType = kLineStrip_PrimitiveType;
1294            vertex[0].set(rect.fLeft, rect.fTop);
1295            vertex[1].set(rect.fRight, rect.fTop);
1296            vertex[2].set(rect.fRight, rect.fBottom);
1297            vertex[3].set(rect.fLeft, rect.fBottom);
1298            vertex[4].set(rect.fLeft, rect.fTop);
1299        }
1300
1301        GrDrawTarget::AutoViewMatrixRestore avmr;
1302        if (NULL != matrix) {
1303            avmr.set(target);
1304            target->preConcatViewMatrix(*matrix);
1305            target->preConcatSamplerMatrices(stageMask, *matrix);
1306        }
1307
1308        target->drawNonIndexed(primType, 0, vertCount);
1309    } else {
1310        #if GR_STATIC_RECT_VB
1311            GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1312            const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1313            if (NULL == sqVB) {
1314                GrPrintf("Failed to create static rect vb.\n");
1315                return;
1316            }
1317            target->setVertexSourceToBuffer(layout, sqVB);
1318            GrDrawTarget::AutoViewMatrixRestore avmr(target);
1319            GrMatrix m;
1320            m.setAll(rect.width(),    0,             rect.fLeft,
1321                        0,            rect.height(), rect.fTop,
1322                        0,            0,             GrMatrix::I()[8]);
1323
1324            if (NULL != matrix) {
1325                m.postConcat(*matrix);
1326            }
1327
1328            target->preConcatViewMatrix(m);
1329            target->preConcatSamplerMatrices(stageMask, m);
1330
1331            target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1332        #else
1333            target->drawSimpleRect(rect, matrix, stageMask);
1334        #endif
1335    }
1336}
1337
1338void GrContext::drawRectToRect(const GrPaint& paint,
1339                               const GrRect& dstRect,
1340                               const GrRect& srcRect,
1341                               const GrMatrix* dstMatrix,
1342                               const GrMatrix* srcMatrix) {
1343    SK_TRACE_EVENT0("GrContext::drawRectToRect");
1344
1345    // srcRect refers to paint's first texture
1346    if (NULL == paint.getTexture(0)) {
1347        drawRect(paint, dstRect, -1, dstMatrix);
1348        return;
1349    }
1350
1351    GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1352
1353#if GR_STATIC_RECT_VB
1354    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1355
1356    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1357    GrDrawTarget::AutoViewMatrixRestore avmr(target);
1358
1359    GrMatrix m;
1360
1361    m.setAll(dstRect.width(), 0,                dstRect.fLeft,
1362             0,               dstRect.height(), dstRect.fTop,
1363             0,               0,                GrMatrix::I()[8]);
1364    if (NULL != dstMatrix) {
1365        m.postConcat(*dstMatrix);
1366    }
1367    target->preConcatViewMatrix(m);
1368
1369    // srcRect refers to first stage
1370    int otherStageMask = paint.getActiveStageMask() &
1371                         (~(1 << GrPaint::kFirstTextureStage));
1372    if (otherStageMask) {
1373        target->preConcatSamplerMatrices(otherStageMask, m);
1374    }
1375
1376    m.setAll(srcRect.width(), 0,                srcRect.fLeft,
1377             0,               srcRect.height(), srcRect.fTop,
1378             0,               0,                GrMatrix::I()[8]);
1379    if (NULL != srcMatrix) {
1380        m.postConcat(*srcMatrix);
1381    }
1382    target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
1383
1384    const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1385    if (NULL == sqVB) {
1386        GrPrintf("Failed to create static rect vb.\n");
1387        return;
1388    }
1389    target->setVertexSourceToBuffer(layout, sqVB);
1390    target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1391#else
1392
1393    GrDrawTarget* target;
1394#if BATCH_RECT_TO_RECT
1395    target = this->prepareToDraw(paint, kBuffered_DrawCategory);
1396#else
1397    target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1398#endif
1399
1400    const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1401    const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1402    srcRects[0] = &srcRect;
1403    srcMatrices[0] = srcMatrix;
1404
1405    target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1406#endif
1407}
1408
1409void GrContext::drawVertices(const GrPaint& paint,
1410                             GrPrimitiveType primitiveType,
1411                             int vertexCount,
1412                             const GrPoint positions[],
1413                             const GrPoint texCoords[],
1414                             const GrColor colors[],
1415                             const uint16_t indices[],
1416                             int indexCount) {
1417    SK_TRACE_EVENT0("GrContext::drawVertices");
1418
1419    GrDrawTarget::AutoReleaseGeometry geo;
1420
1421    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1422
1423    bool hasTexCoords[GrPaint::kTotalStages] = {
1424        NULL != texCoords,   // texCoordSrc provides explicit stage 0 coords
1425        0                    // remaining stages use positions
1426    };
1427
1428    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
1429
1430    if (NULL != colors) {
1431        layout |= GrDrawTarget::kColor_VertexLayoutBit;
1432    }
1433    int vertexSize = GrDrawTarget::VertexSize(layout);
1434
1435    if (sizeof(GrPoint) != vertexSize) {
1436        if (!geo.set(target, layout, vertexCount, 0)) {
1437            GrPrintf("Failed to get space for vertices!\n");
1438            return;
1439        }
1440        int texOffsets[GrDrawTarget::kMaxTexCoords];
1441        int colorOffset;
1442        GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1443                                                texOffsets,
1444                                                &colorOffset,
1445                                                NULL,
1446                                                NULL);
1447        void* curVertex = geo.vertices();
1448
1449        for (int i = 0; i < vertexCount; ++i) {
1450            *((GrPoint*)curVertex) = positions[i];
1451
1452            if (texOffsets[0] > 0) {
1453                *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1454            }
1455            if (colorOffset > 0) {
1456                *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1457            }
1458            curVertex = (void*)((intptr_t)curVertex + vertexSize);
1459        }
1460    } else {
1461        target->setVertexSourceToArray(layout, positions, vertexCount);
1462    }
1463
1464    // we don't currently apply offscreen AA to this path. Need improved
1465    // management of GrDrawTarget's geometry to avoid copying points per-tile.
1466
1467    if (NULL != indices) {
1468        target->setIndexSourceToArray(indices, indexCount);
1469        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1470    } else {
1471        target->drawNonIndexed(primitiveType, 0, vertexCount);
1472    }
1473}
1474
1475///////////////////////////////////////////////////////////////////////////////
1476
1477void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1478                         GrPathFill fill, const GrPoint* translate) {
1479
1480    if (path.isEmpty()) {
1481#if GR_DEBUG
1482       GrPrintf("Empty path should have been caught by canvas.\n");
1483#endif
1484       if (GrIsFillInverted(fill)) {
1485           this->drawPaint(paint);
1486       }
1487       return;
1488    }
1489
1490    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1491
1492    bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1493
1494    // An Assumption here is that path renderer would use some form of tweaking
1495    // the src color (either the input alpha or in the frag shader) to implement
1496    // aa. If we have some future driver-mojo path AA that can do the right
1497    // thing WRT to the blend then we'll need some query on the PR.
1498    if (disable_coverage_aa_for_blend(target)) {
1499#if GR_DEBUG
1500        GrPrintf("Turning off AA to correctly apply blend.\n");
1501#endif
1502        prAA = false;
1503    }
1504
1505    bool doOSAA = false;
1506    GrPathRenderer* pr = NULL;
1507    if (prAA) {
1508        pr = this->getPathRenderer(path, fill, true);
1509        if (NULL == pr) {
1510            prAA = false;
1511            doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1512            pr = this->getPathRenderer(path, fill, false);
1513        }
1514    } else {
1515        pr = this->getPathRenderer(path, fill, false);
1516    }
1517
1518    if (NULL == pr) {
1519#if GR_DEBUG
1520        GrPrintf("Unable to find path renderer compatible with path.\n");
1521#endif
1522        return;
1523    }
1524
1525    GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
1526    GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
1527
1528    if (doOSAA) {
1529        bool needsStencil = pr->requiresStencilPass(target, path, fill);
1530
1531        // compute bounds as intersection of rt size, clip, and path
1532        GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1533                                        target->getRenderTarget()->height());
1534        GrIRect clipIBounds;
1535        if (target->getClip().hasConservativeBounds()) {
1536            target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1537            if (!bound.intersect(clipIBounds)) {
1538                return;
1539            }
1540        }
1541
1542        GrRect pathBounds = path.getBounds();
1543        if (!pathBounds.isEmpty()) {
1544            if (NULL != translate) {
1545                pathBounds.offset(*translate);
1546            }
1547            target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1548            GrIRect pathIBounds;
1549            pathBounds.roundOut(&pathIBounds);
1550            if (!bound.intersect(pathIBounds)) {
1551                return;
1552            }
1553        }
1554        OffscreenRecord record;
1555        if (this->prepareForOffscreenAA(target, needsStencil, bound,
1556                                        pr, &record)) {
1557            for (int tx = 0; tx < record.fTileCountX; ++tx) {
1558                for (int ty = 0; ty < record.fTileCountY; ++ty) {
1559                    this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1560                    pr->drawPath(0);
1561                    this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1562                }
1563            }
1564            this->cleanupOffscreenAA(target, pr, &record);
1565            if (GrIsFillInverted(fill) && bound != clipIBounds) {
1566                GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1567                GrRect rect;
1568                if (clipIBounds.fTop < bound.fTop) {
1569                    rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1570                              clipIBounds.fRight, bound.fTop);
1571                    target->drawSimpleRect(rect, NULL, stageMask);
1572                }
1573                if (clipIBounds.fLeft < bound.fLeft) {
1574                    rect.iset(clipIBounds.fLeft, bound.fTop,
1575                              bound.fLeft, bound.fBottom);
1576                    target->drawSimpleRect(rect, NULL, stageMask);
1577                }
1578                if (clipIBounds.fRight > bound.fRight) {
1579                    rect.iset(bound.fRight, bound.fTop,
1580                              clipIBounds.fRight, bound.fBottom);
1581                    target->drawSimpleRect(rect, NULL, stageMask);
1582                }
1583                if (clipIBounds.fBottom > bound.fBottom) {
1584                    rect.iset(clipIBounds.fLeft, bound.fBottom,
1585                              clipIBounds.fRight, clipIBounds.fBottom);
1586                    target->drawSimpleRect(rect, NULL, stageMask);
1587                }
1588            }
1589            return;
1590        }
1591    }
1592    pr->drawPath(stageMask);
1593}
1594
1595////////////////////////////////////////////////////////////////////////////////
1596
1597bool GrContext::supportsShaders() const {
1598    return fGpu->getCaps().fShaderSupport;
1599}
1600
1601void GrContext::flush(int flagsBitfield) {
1602    if (kDiscard_FlushBit & flagsBitfield) {
1603        fDrawBuffer->reset();
1604    } else {
1605        flushDrawBuffer();
1606    }
1607
1608    if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
1609        fGpu->forceRenderTargetFlush();
1610    }
1611}
1612
1613void GrContext::flushText() {
1614    if (kText_DrawCategory == fLastDrawCategory) {
1615        flushDrawBuffer();
1616    }
1617}
1618
1619void GrContext::flushDrawBuffer() {
1620#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1621    if (fDrawBuffer) {
1622        fDrawBuffer->playback(fGpu);
1623        fDrawBuffer->reset();
1624    }
1625#endif
1626}
1627
1628bool GrContext::readTexturePixels(GrTexture* texture,
1629                                  int left, int top, int width, int height,
1630                                  GrPixelConfig config, void* buffer) {
1631    SK_TRACE_EVENT0("GrContext::readTexturePixels");
1632
1633    // TODO: code read pixels for textures that aren't rendertargets
1634
1635    this->flush();
1636    GrRenderTarget* target = texture->asRenderTarget();
1637    if (NULL != target) {
1638        return fGpu->readPixels(target,
1639                                left, top, width, height,
1640                                config, buffer);
1641    } else {
1642        return false;
1643    }
1644}
1645
1646bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1647                                      int left, int top, int width, int height,
1648                                      GrPixelConfig config, void* buffer) {
1649    SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
1650    uint32_t flushFlags = 0;
1651    if (NULL == target) {
1652        flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1653    }
1654
1655    this->flush(flushFlags);
1656    return fGpu->readPixels(target,
1657                            left, top, width, height,
1658                            config, buffer);
1659}
1660
1661void GrContext::writePixels(int left, int top, int width, int height,
1662                            GrPixelConfig config, const void* buffer,
1663                            size_t stride) {
1664    SK_TRACE_EVENT0("GrContext::writePixels");
1665
1666    // TODO: when underlying api has a direct way to do this we should use it
1667    // (e.g. glDrawPixels on desktop GL).
1668
1669    this->flush(true);
1670
1671    const GrTextureDesc desc = {
1672        kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
1673    };
1674    GrAutoScratchTexture ast(this, desc);
1675    GrTexture* texture = ast.texture();
1676    if (NULL == texture) {
1677        return;
1678    }
1679    texture->uploadTextureData(0, 0, width, height, buffer, stride);
1680
1681    GrDrawTarget::AutoStateRestore  asr(fGpu);
1682
1683    GrMatrix matrix;
1684    matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1685    fGpu->setViewMatrix(matrix);
1686
1687    fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1688    fGpu->disableState(GrDrawTarget::kClip_StateBit);
1689    fGpu->setAlpha(0xFF);
1690    fGpu->setBlendFunc(kOne_BlendCoeff,
1691                       kZero_BlendCoeff);
1692    fGpu->setTexture(0, texture);
1693
1694    GrSamplerState sampler;
1695    sampler.setClampNoFilter();
1696    matrix.setIDiv(texture->width(), texture->height());
1697    sampler.setMatrix(matrix);
1698    fGpu->setSamplerState(0, sampler);
1699
1700    GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1701    static const int VCOUNT = 4;
1702    // TODO: Use GrGpu::drawRect here
1703    GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1704    if (!geo.succeeded()) {
1705        GrPrintf("Failed to get space for vertices!\n");
1706        return;
1707    }
1708    ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1709    fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1710}
1711////////////////////////////////////////////////////////////////////////////////
1712
1713void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1714
1715    for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1716        int s = i + GrPaint::kFirstTextureStage;
1717        target->setTexture(s, paint.getTexture(i));
1718        target->setSamplerState(s, *paint.getTextureSampler(i));
1719    }
1720
1721    target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1722
1723    for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1724        int s = i + GrPaint::kFirstMaskStage;
1725        target->setTexture(s, paint.getMask(i));
1726        target->setSamplerState(s, *paint.getMaskSampler(i));
1727    }
1728
1729    target->setColor(paint.fColor);
1730
1731    if (paint.fDither) {
1732        target->enableState(GrDrawTarget::kDither_StateBit);
1733    } else {
1734        target->disableState(GrDrawTarget::kDither_StateBit);
1735    }
1736    if (paint.fAntiAlias) {
1737        target->enableState(GrDrawTarget::kHWAntialias_StateBit);
1738    } else {
1739        target->disableState(GrDrawTarget::kHWAntialias_StateBit);
1740    }
1741    target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1742    target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1743
1744    if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1745        GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1746    }
1747}
1748
1749GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
1750                                       DrawCategory category) {
1751    if (category != fLastDrawCategory) {
1752        flushDrawBuffer();
1753        fLastDrawCategory = category;
1754    }
1755    SetPaint(paint, fGpu);
1756    GrDrawTarget* target = fGpu;
1757    switch (category) {
1758    case kText_DrawCategory:
1759#if DEFER_TEXT_RENDERING
1760        target = fDrawBuffer;
1761        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1762#else
1763        target = fGpu;
1764#endif
1765        break;
1766    case kUnbuffered_DrawCategory:
1767        target = fGpu;
1768        break;
1769    case kBuffered_DrawCategory:
1770        target = fDrawBuffer;
1771        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1772        break;
1773    }
1774    return target;
1775}
1776
1777GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1778                                           GrPathFill fill,
1779                                           bool antiAlias) {
1780    if (NULL == fPathRendererChain) {
1781        fPathRendererChain =
1782            new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1783    }
1784    return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1785                                               fill, antiAlias);
1786}
1787
1788////////////////////////////////////////////////////////////////////////////////
1789
1790void GrContext::setRenderTarget(GrRenderTarget* target) {
1791    this->flush(false);
1792    fGpu->setRenderTarget(target);
1793}
1794
1795GrRenderTarget* GrContext::getRenderTarget() {
1796    return fGpu->getRenderTarget();
1797}
1798
1799const GrRenderTarget* GrContext::getRenderTarget() const {
1800    return fGpu->getRenderTarget();
1801}
1802
1803const GrMatrix& GrContext::getMatrix() const {
1804    return fGpu->getViewMatrix();
1805}
1806
1807void GrContext::setMatrix(const GrMatrix& m) {
1808    fGpu->setViewMatrix(m);
1809}
1810
1811void GrContext::concatMatrix(const GrMatrix& m) const {
1812    fGpu->preConcatViewMatrix(m);
1813}
1814
1815static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1816    intptr_t mask = 1 << shift;
1817    if (pred) {
1818        bits |= mask;
1819    } else {
1820        bits &= ~mask;
1821    }
1822    return bits;
1823}
1824
1825void GrContext::resetStats() {
1826    fGpu->resetStats();
1827}
1828
1829const GrGpuStats& GrContext::getStats() const {
1830    return fGpu->getStats();
1831}
1832
1833void GrContext::printStats() const {
1834    fGpu->printStats();
1835}
1836
1837GrContext::GrContext(GrGpu* gpu) {
1838    fGpu = gpu;
1839    fGpu->ref();
1840    fGpu->setContext(this);
1841
1842    fPathRendererChain = NULL;
1843
1844    fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1845                                        MAX_TEXTURE_CACHE_BYTES);
1846    fFontCache = new GrFontCache(fGpu);
1847
1848    fLastDrawCategory = kUnbuffered_DrawCategory;
1849
1850    fDrawBuffer = NULL;
1851    fDrawBufferVBAllocPool = NULL;
1852    fDrawBufferIBAllocPool = NULL;
1853
1854    fAAFillRectIndexBuffer = NULL;
1855    fAAStrokeRectIndexBuffer = NULL;
1856
1857    int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1858    if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
1859        gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1860    }
1861    fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
1862
1863    this->setupDrawBuffer();
1864}
1865
1866void GrContext::setupDrawBuffer() {
1867
1868    GrAssert(NULL == fDrawBuffer);
1869    GrAssert(NULL == fDrawBufferVBAllocPool);
1870    GrAssert(NULL == fDrawBufferIBAllocPool);
1871
1872#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1873    fDrawBufferVBAllocPool =
1874        new GrVertexBufferAllocPool(fGpu, false,
1875                                    DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1876                                    DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1877    fDrawBufferIBAllocPool =
1878        new GrIndexBufferAllocPool(fGpu, false,
1879                                   DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1880                                   DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1881
1882    fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1883                                          fDrawBufferVBAllocPool,
1884                                          fDrawBufferIBAllocPool);
1885#endif
1886
1887#if BATCH_RECT_TO_RECT
1888    fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1889#endif
1890}
1891
1892GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1893    GrDrawTarget* target;
1894#if DEFER_TEXT_RENDERING
1895    target = prepareToDraw(paint, kText_DrawCategory);
1896#else
1897    target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1898#endif
1899    SetPaint(paint, target);
1900    return target;
1901}
1902
1903const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1904    return fGpu->getQuadIndexBuffer();
1905}
1906
1907void GrContext::convolveInX(GrTexture* texture,
1908                            const SkRect& rect,
1909                            const float* kernel,
1910                            int kernelWidth) {
1911    float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1912    convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1913}
1914
1915void GrContext::convolveInY(GrTexture* texture,
1916                            const SkRect& rect,
1917                            const float* kernel,
1918                            int kernelWidth) {
1919    float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1920    convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1921}
1922
1923void GrContext::convolve(GrTexture* texture,
1924                         const SkRect& rect,
1925                         float imageIncrement[2],
1926                         const float* kernel,
1927                         int kernelWidth) {
1928    GrDrawTarget::AutoStateRestore asr(fGpu);
1929    GrMatrix sampleM;
1930    GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1931                           GrSamplerState::kClamp_WrapMode,
1932                           GrSamplerState::kConvolution_Filter);
1933    sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
1934    sampleM.setScale(GR_Scalar1 / texture->width(),
1935                     GR_Scalar1 / texture->height());
1936    sampler.setMatrix(sampleM);
1937    fGpu->setSamplerState(0, sampler);
1938    fGpu->setViewMatrix(GrMatrix::I());
1939    fGpu->setTexture(0, texture);
1940    fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
1941    fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1942}
1943