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 "GrContext.h"
11
12#include "effects/GrConfigConversionEffect.h"
13#include "effects/GrDashingEffect.h"
14#include "effects/GrSingleTextureEffect.h"
15
16#include "GrAARectRenderer.h"
17#include "GrBufferAllocPool.h"
18#include "GrGpu.h"
19#include "GrDistanceFieldTextContext.h"
20#include "GrDrawTargetCaps.h"
21#include "GrIndexBuffer.h"
22#include "GrInOrderDrawBuffer.h"
23#include "GrLayerCache.h"
24#include "GrOvalRenderer.h"
25#include "GrPathRenderer.h"
26#include "GrPathUtils.h"
27#include "GrResourceCache.h"
28#include "GrResourceCache2.h"
29#include "GrSoftwarePathRenderer.h"
30#include "GrStencilBuffer.h"
31#include "GrStencilAndCoverTextContext.h"
32#include "GrStrokeInfo.h"
33#include "GrTextStrike.h"
34#include "GrTraceMarker.h"
35#include "GrTracing.h"
36#include "SkDashPathPriv.h"
37#include "SkGr.h"
38#include "SkRTConf.h"
39#include "SkRRect.h"
40#include "SkStrokeRec.h"
41#include "SkTLazy.h"
42#include "SkTLS.h"
43#include "SkTraceEvent.h"
44
45// It can be useful to set this to false to test whether a bug is caused by using the
46// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
47// debugging simpler.
48SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
49                "Defers rendering in GrContext via GrInOrderDrawBuffer.");
50
51#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
52
53#ifdef SK_DEBUG
54    // change this to a 1 to see notifications when partial coverage fails
55    #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
56#else
57    #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
58#endif
59
60static const size_t MAX_RESOURCE_CACHE_COUNT = GR_DEFAULT_RESOURCE_CACHE_COUNT_LIMIT;
61static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMIT * 1024 * 1024;
62
63static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
64static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
65
66static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
67static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
68
69#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
70
71// Glorified typedef to avoid including GrDrawState.h in GrContext.h
72class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {};
73
74class GrContext::AutoCheckFlush {
75public:
76    AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
77
78    ~AutoCheckFlush() {
79        if (fContext->fFlushToReduceCacheSize) {
80            fContext->flush();
81        }
82    }
83
84private:
85    GrContext* fContext;
86};
87
88GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
89                             const Options* opts) {
90    GrContext* context;
91    if (NULL == opts) {
92        context = SkNEW_ARGS(GrContext, (Options()));
93    } else {
94        context = SkNEW_ARGS(GrContext, (*opts));
95    }
96
97    if (context->init(backend, backendContext)) {
98        return context;
99    } else {
100        context->unref();
101        return NULL;
102    }
103}
104
105GrContext::GrContext(const Options& opts) : fOptions(opts) {
106    fDrawState = NULL;
107    fGpu = NULL;
108    fClip = NULL;
109    fPathRendererChain = NULL;
110    fSoftwarePathRenderer = NULL;
111    fResourceCache = NULL;
112    fResourceCache2 = NULL;
113    fFontCache = NULL;
114    fDrawBuffer = NULL;
115    fDrawBufferVBAllocPool = NULL;
116    fDrawBufferIBAllocPool = NULL;
117    fFlushToReduceCacheSize = false;
118    fAARectRenderer = NULL;
119    fOvalRenderer = NULL;
120    fViewMatrix.reset();
121    fMaxTextureSizeOverride = 1 << 20;
122}
123
124bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
125    SkASSERT(NULL == fGpu);
126
127    fGpu = GrGpu::Create(backend, backendContext, this);
128    if (NULL == fGpu) {
129        return false;
130    }
131
132    fDrawState = SkNEW(GrDrawState);
133    fGpu->setDrawState(fDrawState);
134
135    fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT,
136                                                  MAX_RESOURCE_CACHE_BYTES));
137    fResourceCache->setOverbudgetCallback(OverbudgetCB, this);
138    fResourceCache2 = SkNEW(GrResourceCache2);
139
140    fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
141
142    fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
143
144    fLastDrawWasBuffered = kNo_BufferedDraw;
145
146    fAARectRenderer = SkNEW(GrAARectRenderer);
147    fOvalRenderer = SkNEW(GrOvalRenderer);
148
149    fDidTestPMConversions = false;
150
151    this->setupDrawBuffer();
152
153    return true;
154}
155
156GrContext::~GrContext() {
157    if (NULL == fGpu) {
158        return;
159    }
160
161    this->flush();
162
163    for (int i = 0; i < fCleanUpData.count(); ++i) {
164        (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
165    }
166
167    delete fResourceCache2;
168    fResourceCache2 = NULL;
169    delete fResourceCache;
170    fResourceCache = NULL;
171    delete fFontCache;
172    delete fDrawBuffer;
173    delete fDrawBufferVBAllocPool;
174    delete fDrawBufferIBAllocPool;
175
176    fAARectRenderer->unref();
177    fOvalRenderer->unref();
178
179    fGpu->unref();
180    SkSafeUnref(fPathRendererChain);
181    SkSafeUnref(fSoftwarePathRenderer);
182    fDrawState->unref();
183}
184
185void GrContext::abandonContext() {
186    // abandon first to so destructors
187    // don't try to free the resources in the API.
188    fResourceCache2->abandonAll();
189
190    fGpu->contextAbandoned();
191
192    // a path renderer may be holding onto resources that
193    // are now unusable
194    SkSafeSetNull(fPathRendererChain);
195    SkSafeSetNull(fSoftwarePathRenderer);
196
197    delete fDrawBuffer;
198    fDrawBuffer = NULL;
199
200    delete fDrawBufferVBAllocPool;
201    fDrawBufferVBAllocPool = NULL;
202
203    delete fDrawBufferIBAllocPool;
204    fDrawBufferIBAllocPool = NULL;
205
206    fAARectRenderer->reset();
207    fOvalRenderer->reset();
208
209    fResourceCache->purgeAllUnlocked();
210
211    fFontCache->freeAll();
212    fLayerCache->freeAll();
213}
214
215void GrContext::resetContext(uint32_t state) {
216    fGpu->markContextDirty(state);
217}
218
219void GrContext::freeGpuResources() {
220    this->flush();
221
222    fGpu->purgeResources();
223    if (fDrawBuffer) {
224        fDrawBuffer->purgeResources();
225    }
226
227    fAARectRenderer->reset();
228    fOvalRenderer->reset();
229
230    fResourceCache->purgeAllUnlocked();
231    fFontCache->freeAll();
232    fLayerCache->freeAll();
233    // a path renderer may be holding onto resources
234    SkSafeSetNull(fPathRendererChain);
235    SkSafeSetNull(fSoftwarePathRenderer);
236}
237
238void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
239  if (resourceCount) {
240    *resourceCount = fResourceCache->getCachedResourceCount();
241  }
242  if (resourceBytes) {
243    *resourceBytes = fResourceCache->getCachedResourceBytes();
244  }
245}
246
247GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
248                                            const SkDeviceProperties&
249                                            leakyProperties,
250                                            bool enableDistanceFieldFonts) {
251    if (fGpu->caps()->pathRenderingSupport()) {
252        if (renderTarget->getStencilBuffer() && renderTarget->isMultisampled()) {
253            return SkNEW_ARGS(GrStencilAndCoverTextContext, (this, leakyProperties));
254        }
255    }
256    return SkNEW_ARGS(GrDistanceFieldTextContext, (this, leakyProperties,
257                                                   enableDistanceFieldFonts));
258}
259
260////////////////////////////////////////////////////////////////////////////////
261
262GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
263                                        const GrCacheID& cacheID,
264                                        const GrTextureParams* params) {
265    GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
266    GrGpuResource* resource = fResourceCache->find(resourceKey);
267    SkSafeRef(resource);
268    return static_cast<GrTexture*>(resource);
269}
270
271bool GrContext::isTextureInCache(const GrTextureDesc& desc,
272                                 const GrCacheID& cacheID,
273                                 const GrTextureParams* params) const {
274    GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
275    return fResourceCache->hasKey(resourceKey);
276}
277
278void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
279    ASSERT_OWNED_RESOURCE(sb);
280
281    GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
282                                                            sb->height(),
283                                                            sb->numSamples());
284    fResourceCache->addResource(resourceKey, sb);
285}
286
287GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
288                                              int sampleCnt) {
289    GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
290                                                            height,
291                                                            sampleCnt);
292    GrGpuResource* resource = fResourceCache->find(resourceKey);
293    return static_cast<GrStencilBuffer*>(resource);
294}
295
296static void stretch_image(void* dst,
297                          int dstW,
298                          int dstH,
299                          const void* src,
300                          int srcW,
301                          int srcH,
302                          size_t bpp) {
303    SkFixed dx = (srcW << 16) / dstW;
304    SkFixed dy = (srcH << 16) / dstH;
305
306    SkFixed y = dy >> 1;
307
308    size_t dstXLimit = dstW*bpp;
309    for (int j = 0; j < dstH; ++j) {
310        SkFixed x = dx >> 1;
311        const uint8_t* srcRow = reinterpret_cast<const uint8_t *>(src) + (y>>16)*srcW*bpp;
312        uint8_t* dstRow = reinterpret_cast<uint8_t *>(dst) + j*dstW*bpp;
313        for (size_t i = 0; i < dstXLimit; i += bpp) {
314            memcpy(dstRow + i, srcRow + (x>>16)*bpp, bpp);
315            x += dx;
316        }
317        y += dy;
318    }
319}
320
321namespace {
322
323// position + local coordinate
324extern const GrVertexAttrib gVertexAttribs[] = {
325    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
326    {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
327};
328
329};
330
331// The desired texture is NPOT and tiled but that isn't supported by
332// the current hardware. Resize the texture to be a POT
333GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
334                                           const GrCacheID& cacheID,
335                                           const void* srcData,
336                                           size_t rowBytes,
337                                           bool filter) {
338    SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, cacheID, NULL));
339    if (NULL == clampedTexture) {
340        clampedTexture.reset(this->createTexture(NULL, desc, cacheID, srcData, rowBytes));
341
342        if (NULL == clampedTexture) {
343            return NULL;
344        }
345    }
346
347    GrTextureDesc rtDesc = desc;
348    rtDesc.fFlags =  rtDesc.fFlags |
349                     kRenderTarget_GrTextureFlagBit |
350                     kNoStencil_GrTextureFlagBit;
351    rtDesc.fWidth  = GrNextPow2(desc.fWidth);
352    rtDesc.fHeight = GrNextPow2(desc.fHeight);
353
354    GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356    if (texture) {
357        GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
358        GrDrawState* drawState = fGpu->drawState();
359        drawState->setRenderTarget(texture->asRenderTarget());
360
361        // if filtering is not desired then we want to ensure all
362        // texels in the resampled image are copies of texels from
363        // the original.
364        GrTextureParams params(SkShader::kClamp_TileMode, filter ? GrTextureParams::kBilerp_FilterMode :
365                                                                   GrTextureParams::kNone_FilterMode);
366        drawState->addColorTextureProcessor(clampedTexture, SkMatrix::I(), params);
367
368        drawState->setVertexAttribs<gVertexAttribs>(SK_ARRAY_COUNT(gVertexAttribs),
369                                                    2 * sizeof(SkPoint));
370
371        GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
372
373        if (arg.succeeded()) {
374            SkPoint* verts = (SkPoint*) arg.vertices();
375            verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(SkPoint));
376            verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(SkPoint));
377            fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
378        }
379    } else {
380        // TODO: Our CPU stretch doesn't filter. But we create separate
381        // stretched textures when the texture params is either filtered or
382        // not. Either implement filtered stretch blit on CPU or just create
383        // one when FBO case fails.
384
385        rtDesc.fFlags = kNone_GrTextureFlags;
386        // no longer need to clamp at min RT size.
387        rtDesc.fWidth  = GrNextPow2(desc.fWidth);
388        rtDesc.fHeight = GrNextPow2(desc.fHeight);
389
390        // We shouldn't be resizing a compressed texture.
391        SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
392
393        size_t bpp = GrBytesPerPixel(desc.fConfig);
394        GrAutoMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight);
395        stretch_image(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
396                      srcData, desc.fWidth, desc.fHeight, bpp);
397
398        size_t stretchedRowBytes = rtDesc.fWidth * bpp;
399
400        texture = fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes);
401        SkASSERT(texture);
402    }
403
404    return texture;
405}
406
407GrTexture* GrContext::createTexture(const GrTextureParams* params,
408                                    const GrTextureDesc& desc,
409                                    const GrCacheID& cacheID,
410                                    const void* srcData,
411                                    size_t rowBytes,
412                                    GrResourceKey* cacheKey) {
413    GrResourceKey resourceKey = GrTextureImpl::ComputeKey(fGpu, params, desc, cacheID);
414
415    GrTexture* texture;
416    if (GrTextureImpl::NeedsResizing(resourceKey)) {
417        // We do not know how to resize compressed textures.
418        SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
419
420        texture = this->createResizedTexture(desc, cacheID,
421                                             srcData, rowBytes,
422                                             GrTextureImpl::NeedsBilerp(resourceKey));
423    } else {
424        texture = fGpu->createTexture(desc, srcData, rowBytes);
425    }
426
427    if (texture) {
428        // Adding a resource could put us overbudget. Try to free up the
429        // necessary space before adding it.
430        fResourceCache->purgeAsNeeded(1, texture->gpuMemorySize());
431        fResourceCache->addResource(resourceKey, texture);
432
433        if (cacheKey) {
434            *cacheKey = resourceKey;
435        }
436    }
437
438    return texture;
439}
440
441static GrTexture* create_scratch_texture(GrGpu* gpu,
442                                         GrResourceCache* resourceCache,
443                                         const GrTextureDesc& desc) {
444    GrTexture* texture = gpu->createTexture(desc, NULL, 0);
445    if (texture) {
446        GrResourceKey key = GrTextureImpl::ComputeScratchKey(texture->desc());
447        // Adding a resource could put us overbudget. Try to free up the
448        // necessary space before adding it.
449        resourceCache->purgeAsNeeded(1, texture->gpuMemorySize());
450        // Make the resource exclusive so future 'find' calls don't return it
451        resourceCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
452    }
453    return texture;
454}
455
456GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
457
458    SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
459             !(inDesc.fFlags & kNoStencil_GrTextureFlagBit));
460
461    // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
462    SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt > 0) ||
463             !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) ||
464             (inDesc.fConfig != kAlpha_8_GrPixelConfig));
465
466    if (!fGpu->caps()->reuseScratchTextures() &&
467        !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) {
468        // If we're never recycling this texture we can always make it the right size
469        return create_scratch_texture(fGpu, fResourceCache, inDesc);
470    }
471
472    GrTextureDesc desc = inDesc;
473
474    if (kApprox_ScratchTexMatch == match) {
475        // bin by pow2 with a reasonable min
476        static const int MIN_SIZE = 16;
477        desc.fWidth  = SkTMax(MIN_SIZE, GrNextPow2(desc.fWidth));
478        desc.fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc.fHeight));
479    }
480
481    GrGpuResource* resource = NULL;
482    int origWidth = desc.fWidth;
483    int origHeight = desc.fHeight;
484
485    do {
486        GrResourceKey key = GrTextureImpl::ComputeScratchKey(desc);
487        // Ensure we have exclusive access to the texture so future 'find' calls don't return it
488        resource = fResourceCache->find(key, GrResourceCache::kHide_OwnershipFlag);
489        if (resource) {
490            resource->ref();
491            break;
492        }
493        if (kExact_ScratchTexMatch == match) {
494            break;
495        }
496        // We had a cache miss and we are in approx mode, relax the fit of the flags.
497
498        // We no longer try to reuse textures that were previously used as render targets in
499        // situations where no RT is needed; doing otherwise can confuse the video driver and
500        // cause significant performance problems in some cases.
501        if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
502            desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
503        } else {
504            break;
505        }
506
507    } while (true);
508
509    if (NULL == resource) {
510        desc.fFlags = inDesc.fFlags;
511        desc.fWidth = origWidth;
512        desc.fHeight = origHeight;
513        resource = create_scratch_texture(fGpu, fResourceCache, desc);
514    }
515
516    return static_cast<GrTexture*>(resource);
517}
518
519void GrContext::addExistingTextureToCache(GrTexture* texture) {
520
521    if (NULL == texture) {
522        return;
523    }
524
525    // This texture should already have a cache entry since it was once
526    // attached
527    SkASSERT(texture->getCacheEntry());
528
529    // Conceptually, the cache entry is going to assume responsibility
530    // for the creation ref. Assert refcnt == 1.
531    // Except that this also gets called when the texture is prematurely
532    // abandoned. In that case the ref count may be > 1.
533    // SkASSERT(texture->unique());
534
535    if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) {
536        // Since this texture came from an AutoScratchTexture it should
537        // still be in the exclusive pile. Recycle it.
538        fResourceCache->makeNonExclusive(texture->getCacheEntry());
539        this->purgeCache();
540    } else {
541        // When we aren't reusing textures we know this scratch texture
542        // will never be reused and would be just wasting time in the cache
543        fResourceCache->makeNonExclusive(texture->getCacheEntry());
544        fResourceCache->deleteResource(texture->getCacheEntry());
545    }
546}
547
548void GrContext::unlockScratchTexture(GrTexture* texture) {
549    if (texture->wasDestroyed()) {
550        if (texture->getCacheEntry()->key().isScratch()) {
551            // This texture was detached from the cache but the cache still had a ref to it but
552            // not a pointer to it. This will unref the texture and delete its resource cache
553            // entry.
554            delete texture->getCacheEntry();
555        }
556        return;
557    }
558
559    ASSERT_OWNED_RESOURCE(texture);
560    SkASSERT(texture->getCacheEntry());
561
562    // If this is a scratch texture we detached it from the cache
563    // while it was locked (to avoid two callers simultaneously getting
564    // the same texture).
565    if (texture->getCacheEntry()->key().isScratch()) {
566        if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) {
567            fResourceCache->makeNonExclusive(texture->getCacheEntry());
568            this->purgeCache();
569        } else if (texture->unique()) {
570            // Only the cache now knows about this texture. Since we're never
571            // reusing scratch textures (in this code path) it would just be
572            // wasting time sitting in the cache.
573            fResourceCache->makeNonExclusive(texture->getCacheEntry());
574            fResourceCache->deleteResource(texture->getCacheEntry());
575        } else {
576            // In this case (there is still a non-cache ref) but we don't really
577            // want to readd it to the cache (since it will never be reused).
578            // Instead, give up the cache's ref and leave the decision up to
579            // addExistingTextureToCache once its ref count reaches 0. For
580            // this to work we need to leave it in the exclusive list.
581            texture->impl()->setFlag((GrTextureFlags) GrTextureImpl::kReturnToCache_FlagBit);
582            // Give up the cache's ref to the texture
583            texture->unref();
584        }
585    }
586}
587
588void GrContext::purgeCache() {
589    if (fResourceCache) {
590        fResourceCache->purgeAsNeeded();
591    }
592}
593
594bool GrContext::OverbudgetCB(void* data) {
595    SkASSERT(data);
596
597    GrContext* context = reinterpret_cast<GrContext*>(data);
598
599    // Flush the InOrderDrawBuffer to possibly free up some textures
600    context->fFlushToReduceCacheSize = true;
601
602    return true;
603}
604
605
606GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn,
607                                            void* srcData,
608                                            size_t rowBytes) {
609    GrTextureDesc descCopy = descIn;
610    return fGpu->createTexture(descCopy, srcData, rowBytes);
611}
612
613void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
614    fResourceCache->getLimits(maxTextures, maxTextureBytes);
615}
616
617void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
618    fResourceCache->setLimits(maxTextures, maxTextureBytes);
619}
620
621int GrContext::getMaxTextureSize() const {
622    return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
623}
624
625int GrContext::getMaxRenderTargetSize() const {
626    return fGpu->caps()->maxRenderTargetSize();
627}
628
629int GrContext::getMaxSampleCount() const {
630    return fGpu->caps()->maxSampleCount();
631}
632
633///////////////////////////////////////////////////////////////////////////////
634
635GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
636    return fGpu->wrapBackendTexture(desc);
637}
638
639GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
640    return fGpu->wrapBackendRenderTarget(desc);
641}
642
643///////////////////////////////////////////////////////////////////////////////
644
645bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
646                                          int width, int height) const {
647    const GrDrawTargetCaps* caps = fGpu->caps();
648    if (!caps->isConfigTexturable(kIndex_8_GrPixelConfig)) {
649        return false;
650    }
651
652    bool isPow2 = SkIsPow2(width) && SkIsPow2(height);
653
654    if (!isPow2) {
655        bool tiled = params && params->isTiled();
656        if (tiled && !caps->npotTextureTileSupport()) {
657            return false;
658        }
659    }
660    return true;
661}
662
663
664////////////////////////////////////////////////////////////////////////////////
665
666void GrContext::clear(const SkIRect* rect,
667                      const GrColor color,
668                      bool canIgnoreRect,
669                      GrRenderTarget* renderTarget) {
670    ASSERT_OWNED_RESOURCE(renderTarget);
671    AutoRestoreEffects are;
672    AutoCheckFlush acf(this);
673    GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
674    GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf);
675    if (NULL == target) {
676        return;
677    }
678    target->clear(rect, color, canIgnoreRect, renderTarget);
679}
680
681void GrContext::drawPaint(const GrPaint& origPaint) {
682    // set rect to be big enough to fill the space, but not super-huge, so we
683    // don't overflow fixed-point implementations
684    SkRect r;
685    r.setLTRB(0, 0,
686              SkIntToScalar(getRenderTarget()->width()),
687              SkIntToScalar(getRenderTarget()->height()));
688    SkMatrix inverse;
689    SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
690    AutoMatrix am;
691    GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::drawPaint", this);
692
693    // We attempt to map r by the inverse matrix and draw that. mapRect will
694    // map the four corners and bound them with a new rect. This will not
695    // produce a correct result for some perspective matrices.
696    if (!this->getMatrix().hasPerspective()) {
697        if (!fViewMatrix.invert(&inverse)) {
698            GrPrintf("Could not invert matrix\n");
699            return;
700        }
701        inverse.mapRect(&r);
702    } else {
703        if (!am.setIdentity(this, paint.writable())) {
704            GrPrintf("Could not invert matrix\n");
705            return;
706        }
707    }
708    // by definition this fills the entire clip, no need for AA
709    if (paint->isAntiAlias()) {
710        paint.writable()->setAntiAlias(false);
711    }
712    this->drawRect(*paint, r);
713}
714
715#ifdef SK_DEVELOPER
716void GrContext::dumpFontCache() const {
717    fFontCache->dump();
718}
719#endif
720
721////////////////////////////////////////////////////////////////////////////////
722
723/*  create a triangle strip that strokes the specified triangle. There are 8
724 unique vertices, but we repreat the last 2 to close up. Alternatively we
725 could use an indices array, and then only send 8 verts, but not sure that
726 would be faster.
727 */
728static void setStrokeRectStrip(SkPoint verts[10], SkRect rect,
729                               SkScalar width) {
730    const SkScalar rad = SkScalarHalf(width);
731    rect.sort();
732
733    verts[0].set(rect.fLeft + rad, rect.fTop + rad);
734    verts[1].set(rect.fLeft - rad, rect.fTop - rad);
735    verts[2].set(rect.fRight - rad, rect.fTop + rad);
736    verts[3].set(rect.fRight + rad, rect.fTop - rad);
737    verts[4].set(rect.fRight - rad, rect.fBottom - rad);
738    verts[5].set(rect.fRight + rad, rect.fBottom + rad);
739    verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
740    verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
741    verts[8] = verts[0];
742    verts[9] = verts[1];
743}
744
745static inline bool is_irect(const SkRect& r) {
746  return SkScalarIsInt(r.fLeft)  && SkScalarIsInt(r.fTop) &&
747         SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
748}
749
750static bool apply_aa_to_rect(GrDrawTarget* target,
751                             const SkRect& rect,
752                             SkScalar strokeWidth,
753                             const SkMatrix& combinedMatrix,
754                             SkRect* devBoundRect) {
755    if (!target->getDrawState().canTweakAlphaForCoverage() &&
756        target->shouldDisableCoverageAAForBlend()) {
757#ifdef SK_DEBUG
758        //GrPrintf("Turning off AA to correctly apply blend.\n");
759#endif
760        return false;
761    }
762    const GrDrawState& drawState = target->getDrawState();
763    if (drawState.getRenderTarget()->isMultisampled()) {
764        return false;
765    }
766
767#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
768    if (strokeWidth >= 0) {
769#endif
770        if (!combinedMatrix.preservesAxisAlignment()) {
771            return false;
772        }
773
774#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
775    } else {
776        if (!combinedMatrix.preservesRightAngles()) {
777            return false;
778        }
779    }
780#endif
781
782    combinedMatrix.mapRect(devBoundRect, rect);
783    if (strokeWidth < 0) {
784        return !is_irect(*devBoundRect);
785    }
786
787    return true;
788}
789
790static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
791    return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
792           point.fY >= rect.fTop && point.fY <= rect.fBottom;
793}
794
795void GrContext::drawRect(const GrPaint& paint,
796                         const SkRect& rect,
797                         const GrStrokeInfo* strokeInfo) {
798    if (strokeInfo && strokeInfo->isDashed()) {
799        SkPath path;
800        path.addRect(rect);
801        this->drawPath(paint, path, *strokeInfo);
802        return;
803    }
804
805    AutoRestoreEffects are;
806    AutoCheckFlush acf(this);
807    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
808    if (NULL == target) {
809        return;
810    }
811
812    GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
813    SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
814    SkMatrix matrix = target->drawState()->getViewMatrix();
815
816    // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
817    // cases where the RT is fully inside a stroke.
818    if (width < 0) {
819        SkRect rtRect;
820        target->getDrawState().getRenderTarget()->getBoundsRect(&rtRect);
821        SkRect clipSpaceRTRect = rtRect;
822        bool checkClip = false;
823        if (this->getClip()) {
824            checkClip = true;
825            clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX),
826                                   SkIntToScalar(this->getClip()->fOrigin.fY));
827        }
828        // Does the clip contain the entire RT?
829        if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) {
830            SkMatrix invM;
831            if (!matrix.invert(&invM)) {
832                return;
833            }
834            // Does the rect bound the RT?
835            SkPoint srcSpaceRTQuad[4];
836            invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
837            if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
838                rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
839                rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
840                rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
841                // Will it blend?
842                GrColor clearColor;
843                if (paint.isOpaqueAndConstantColor(&clearColor)) {
844                    target->clear(NULL, clearColor, true);
845                    return;
846                }
847            }
848        }
849    }
850
851    SkRect devBoundRect;
852    bool needAA = paint.isAntiAlias() &&
853                  !target->getDrawState().getRenderTarget()->isMultisampled();
854    bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, &devBoundRect);
855
856    const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
857
858    if (doAA) {
859        GrDrawState::AutoViewMatrixRestore avmr;
860        if (!avmr.setIdentity(target->drawState())) {
861            return;
862        }
863        if (width >= 0) {
864            fAARectRenderer->strokeAARect(this->getGpu(), target, rect,
865                                          matrix, devBoundRect,
866                                          strokeRec);
867        } else {
868            // filled AA rect
869            fAARectRenderer->fillAARect(this->getGpu(), target,
870                                        rect, matrix, devBoundRect);
871        }
872        return;
873    }
874
875    if (width >= 0) {
876        // TODO: consider making static vertex buffers for these cases.
877        // Hairline could be done by just adding closing vertex to
878        // unitSquareVertexBuffer()
879
880        static const int worstCaseVertCount = 10;
881        target->drawState()->setDefaultVertexAttribs();
882        GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0);
883
884        if (!geo.succeeded()) {
885            GrPrintf("Failed to get space for vertices!\n");
886            return;
887        }
888
889        GrPrimitiveType primType;
890        int vertCount;
891        SkPoint* vertex = geo.positions();
892
893        if (width > 0) {
894            vertCount = 10;
895            primType = kTriangleStrip_GrPrimitiveType;
896            setStrokeRectStrip(vertex, rect, width);
897        } else {
898            // hairline
899            vertCount = 5;
900            primType = kLineStrip_GrPrimitiveType;
901            vertex[0].set(rect.fLeft, rect.fTop);
902            vertex[1].set(rect.fRight, rect.fTop);
903            vertex[2].set(rect.fRight, rect.fBottom);
904            vertex[3].set(rect.fLeft, rect.fBottom);
905            vertex[4].set(rect.fLeft, rect.fTop);
906        }
907
908        target->drawNonIndexed(primType, 0, vertCount);
909    } else {
910        // filled BW rect
911        target->drawSimpleRect(rect);
912    }
913}
914
915void GrContext::drawRectToRect(const GrPaint& paint,
916                               const SkRect& dstRect,
917                               const SkRect& localRect,
918                               const SkMatrix* localMatrix) {
919    AutoRestoreEffects are;
920    AutoCheckFlush acf(this);
921    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
922    if (NULL == target) {
923        return;
924    }
925
926    GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
927
928    target->drawRect(dstRect, &localRect, localMatrix);
929}
930
931namespace {
932
933extern const GrVertexAttrib gPosUVColorAttribs[] = {
934    {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding },
935    {kVec2f_GrVertexAttribType,  sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding },
936    {kVec4ub_GrVertexAttribType, 2*sizeof(SkPoint), kColor_GrVertexAttribBinding}
937};
938
939static const size_t kPosUVAttribsSize = 2 * sizeof(SkPoint);
940static const size_t kPosUVColorAttribsSize = 2 * sizeof(SkPoint) + sizeof(GrColor);
941
942extern const GrVertexAttrib gPosColorAttribs[] = {
943    {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding},
944    {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
945};
946
947static const size_t kPosAttribsSize = sizeof(SkPoint);
948static const size_t kPosColorAttribsSize = sizeof(SkPoint) + sizeof(GrColor);
949
950static void set_vertex_attributes(GrDrawState* drawState,
951                                  const SkPoint* texCoords,
952                                  const GrColor* colors,
953                                  int* colorOffset,
954                                  int* texOffset) {
955    *texOffset = -1;
956    *colorOffset = -1;
957
958    if (texCoords && colors) {
959        *texOffset = sizeof(SkPoint);
960        *colorOffset = 2*sizeof(SkPoint);
961        drawState->setVertexAttribs<gPosUVColorAttribs>(3, kPosUVColorAttribsSize);
962    } else if (texCoords) {
963        *texOffset = sizeof(SkPoint);
964        drawState->setVertexAttribs<gPosUVColorAttribs>(2, kPosUVAttribsSize);
965    } else if (colors) {
966        *colorOffset = sizeof(SkPoint);
967        drawState->setVertexAttribs<gPosColorAttribs>(2, kPosColorAttribsSize);
968    } else {
969        drawState->setVertexAttribs<gPosColorAttribs>(1, kPosAttribsSize);
970    }
971}
972
973};
974
975void GrContext::drawVertices(const GrPaint& paint,
976                             GrPrimitiveType primitiveType,
977                             int vertexCount,
978                             const SkPoint positions[],
979                             const SkPoint texCoords[],
980                             const GrColor colors[],
981                             const uint16_t indices[],
982                             int indexCount) {
983    AutoRestoreEffects are;
984    AutoCheckFlush acf(this);
985    GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
986
987    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
988    if (NULL == target) {
989        return;
990    }
991    GrDrawState* drawState = target->drawState();
992
993    GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
994
995    int colorOffset = -1, texOffset = -1;
996    set_vertex_attributes(drawState, texCoords, colors, &colorOffset, &texOffset);
997
998    size_t VertexStride = drawState->getVertexStride();
999    if (sizeof(SkPoint) != VertexStride) {
1000        if (!geo.set(target, vertexCount, 0)) {
1001            GrPrintf("Failed to get space for vertices!\n");
1002            return;
1003        }
1004        void* curVertex = geo.vertices();
1005
1006        for (int i = 0; i < vertexCount; ++i) {
1007            *((SkPoint*)curVertex) = positions[i];
1008
1009            if (texOffset >= 0) {
1010                *(SkPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
1011            }
1012            if (colorOffset >= 0) {
1013                *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1014            }
1015            curVertex = (void*)((intptr_t)curVertex + VertexStride);
1016        }
1017    } else {
1018        target->setVertexSourceToArray(positions, vertexCount);
1019    }
1020
1021    // we don't currently apply offscreen AA to this path. Need improved
1022    // management of GrDrawTarget's geometry to avoid copying points per-tile.
1023
1024    if (indices) {
1025        target->setIndexSourceToArray(indices, indexCount);
1026        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1027        target->resetIndexSource();
1028    } else {
1029        target->drawNonIndexed(primitiveType, 0, vertexCount);
1030    }
1031}
1032
1033///////////////////////////////////////////////////////////////////////////////
1034
1035void GrContext::drawRRect(const GrPaint& paint,
1036                          const SkRRect& rrect,
1037                          const GrStrokeInfo& strokeInfo) {
1038    if (rrect.isEmpty()) {
1039       return;
1040    }
1041
1042    if (strokeInfo.isDashed()) {
1043        SkPath path;
1044        path.addRRect(rrect);
1045        this->drawPath(paint, path, strokeInfo);
1046        return;
1047    }
1048
1049    AutoRestoreEffects are;
1050    AutoCheckFlush acf(this);
1051    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1052    if (NULL == target) {
1053        return;
1054    }
1055
1056    GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1057
1058    const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1059
1060    if (!fOvalRenderer->drawRRect(target, this, paint.isAntiAlias(), rrect, strokeRec)) {
1061        SkPath path;
1062        path.addRRect(rrect);
1063        this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1064    }
1065}
1066
1067///////////////////////////////////////////////////////////////////////////////
1068
1069void GrContext::drawDRRect(const GrPaint& paint,
1070                           const SkRRect& outer,
1071                           const SkRRect& inner) {
1072    if (outer.isEmpty()) {
1073       return;
1074    }
1075
1076    AutoRestoreEffects are;
1077    AutoCheckFlush acf(this);
1078    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1079
1080    GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1081
1082    if (!fOvalRenderer->drawDRRect(target, this, paint.isAntiAlias(), outer, inner)) {
1083        SkPath path;
1084        path.addRRect(inner);
1085        path.addRRect(outer);
1086        path.setFillType(SkPath::kEvenOdd_FillType);
1087
1088        GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
1089        this->internalDrawPath(target, paint.isAntiAlias(), path, fillRec);
1090    }
1091}
1092
1093///////////////////////////////////////////////////////////////////////////////
1094
1095void GrContext::drawOval(const GrPaint& paint,
1096                         const SkRect& oval,
1097                         const GrStrokeInfo& strokeInfo) {
1098    if (oval.isEmpty()) {
1099       return;
1100    }
1101
1102    if (strokeInfo.isDashed()) {
1103        SkPath path;
1104        path.addOval(oval);
1105        this->drawPath(paint, path, strokeInfo);
1106        return;
1107    }
1108
1109    AutoRestoreEffects are;
1110    AutoCheckFlush acf(this);
1111    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1112    if (NULL == target) {
1113        return;
1114    }
1115
1116    GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1117
1118    const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1119
1120
1121    if (!fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), oval, strokeRec)) {
1122        SkPath path;
1123        path.addOval(oval);
1124        this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1125    }
1126}
1127
1128// Can 'path' be drawn as a pair of filled nested rectangles?
1129static bool is_nested_rects(GrDrawTarget* target,
1130                            const SkPath& path,
1131                            const SkStrokeRec& stroke,
1132                            SkRect rects[2]) {
1133    SkASSERT(stroke.isFillStyle());
1134
1135    if (path.isInverseFillType()) {
1136        return false;
1137    }
1138
1139    const GrDrawState& drawState = target->getDrawState();
1140
1141    // TODO: this restriction could be lifted if we were willing to apply
1142    // the matrix to all the points individually rather than just to the rect
1143    if (!drawState.getViewMatrix().preservesAxisAlignment()) {
1144        return false;
1145    }
1146
1147    if (!target->getDrawState().canTweakAlphaForCoverage() &&
1148        target->shouldDisableCoverageAAForBlend()) {
1149        return false;
1150    }
1151
1152    SkPath::Direction dirs[2];
1153    if (!path.isNestedRects(rects, dirs)) {
1154        return false;
1155    }
1156
1157    if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1158        // The two rects need to be wound opposite to each other
1159        return false;
1160    }
1161
1162    // Right now, nested rects where the margin is not the same width
1163    // all around do not render correctly
1164    const SkScalar* outer = rects[0].asScalars();
1165    const SkScalar* inner = rects[1].asScalars();
1166
1167    SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1168    for (int i = 1; i < 4; ++i) {
1169        SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1170        if (!SkScalarNearlyEqual(margin, temp)) {
1171            return false;
1172        }
1173    }
1174
1175    return true;
1176}
1177
1178void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const GrStrokeInfo& strokeInfo) {
1179
1180    if (path.isEmpty()) {
1181       if (path.isInverseFillType()) {
1182           this->drawPaint(paint);
1183       }
1184       return;
1185    }
1186
1187    if (strokeInfo.isDashed()) {
1188        SkPoint pts[2];
1189        if (path.isLine(pts)) {
1190            AutoRestoreEffects are;
1191            AutoCheckFlush acf(this);
1192            GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1193            if (NULL == target) {
1194                return;
1195            }
1196            GrDrawState* drawState = target->drawState();
1197
1198            SkMatrix origViewMatrix = drawState->getViewMatrix();
1199            GrDrawState::AutoViewMatrixRestore avmr;
1200            if (avmr.setIdentity(target->drawState())) {
1201                if (GrDashingEffect::DrawDashLine(pts, paint, strokeInfo, fGpu, target,
1202                                                  origViewMatrix)) {
1203                    return;
1204                }
1205            }
1206        }
1207
1208        // Filter dashed path into new path with the dashing applied
1209        const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
1210        SkTLazy<SkPath> effectPath;
1211        GrStrokeInfo newStrokeInfo(strokeInfo, false);
1212        SkStrokeRec* stroke = newStrokeInfo.getStrokeRecPtr();
1213        if (SkDashPath::FilterDashPath(effectPath.init(), path, stroke, NULL, info)) {
1214            this->drawPath(paint, *effectPath.get(), newStrokeInfo);
1215            return;
1216        }
1217
1218        this->drawPath(paint, path, newStrokeInfo);
1219        return;
1220    }
1221
1222    // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1223    // Scratch textures can be recycled after they are returned to the texture
1224    // cache. This presents a potential hazard for buffered drawing. However,
1225    // the writePixels that uploads to the scratch will perform a flush so we're
1226    // OK.
1227    AutoRestoreEffects are;
1228    AutoCheckFlush acf(this);
1229    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are, &acf);
1230    if (NULL == target) {
1231        return;
1232    }
1233    GrDrawState* drawState = target->drawState();
1234
1235    GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
1236
1237    const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1238
1239    bool useCoverageAA = paint.isAntiAlias() && !drawState->getRenderTarget()->isMultisampled();
1240
1241    if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
1242        // Concave AA paths are expensive - try to avoid them for special cases
1243        SkRect rects[2];
1244
1245        if (is_nested_rects(target, path, strokeRec, rects)) {
1246            SkMatrix origViewMatrix = drawState->getViewMatrix();
1247            GrDrawState::AutoViewMatrixRestore avmr;
1248            if (!avmr.setIdentity(target->drawState())) {
1249                return;
1250            }
1251
1252            fAARectRenderer->fillAANestedRects(this->getGpu(), target, rects, origViewMatrix);
1253            return;
1254        }
1255    }
1256
1257    SkRect ovalRect;
1258    bool isOval = path.isOval(&ovalRect);
1259
1260    if (!isOval || path.isInverseFillType()
1261        || !fOvalRenderer->drawOval(target, this, paint.isAntiAlias(), ovalRect, strokeRec)) {
1262        this->internalDrawPath(target, paint.isAntiAlias(), path, strokeInfo);
1263    }
1264}
1265
1266void GrContext::internalDrawPath(GrDrawTarget* target, bool useAA, const SkPath& path,
1267                                 const GrStrokeInfo& strokeInfo) {
1268    SkASSERT(!path.isEmpty());
1269
1270    GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1271
1272
1273    // An Assumption here is that path renderer would use some form of tweaking
1274    // the src color (either the input alpha or in the frag shader) to implement
1275    // aa. If we have some future driver-mojo path AA that can do the right
1276    // thing WRT to the blend then we'll need some query on the PR.
1277    bool useCoverageAA = useAA &&
1278        !target->getDrawState().getRenderTarget()->isMultisampled() &&
1279        !target->shouldDisableCoverageAAForBlend();
1280
1281
1282    GrPathRendererChain::DrawType type =
1283        useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1284                           GrPathRendererChain::kColor_DrawType;
1285
1286    const SkPath* pathPtr = &path;
1287    SkTLazy<SkPath> tmpPath;
1288    SkTCopyOnFirstWrite<SkStrokeRec> stroke(strokeInfo.getStrokeRec());
1289
1290    // Try a 1st time without stroking the path and without allowing the SW renderer
1291    GrPathRenderer* pr = this->getPathRenderer(*pathPtr, *stroke, target, false, type);
1292
1293    if (NULL == pr) {
1294        if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, this->getMatrix(), NULL)) {
1295            // It didn't work the 1st time, so try again with the stroked path
1296            if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
1297                pathPtr = tmpPath.get();
1298                stroke.writable()->setFillStyle();
1299                if (pathPtr->isEmpty()) {
1300                    return;
1301                }
1302            }
1303        }
1304
1305        // This time, allow SW renderer
1306        pr = this->getPathRenderer(*pathPtr, *stroke, target, true, type);
1307    }
1308
1309    if (NULL == pr) {
1310#ifdef SK_DEBUG
1311        GrPrintf("Unable to find path renderer compatible with path.\n");
1312#endif
1313        return;
1314    }
1315
1316    pr->drawPath(*pathPtr, *stroke, target, useCoverageAA);
1317}
1318
1319////////////////////////////////////////////////////////////////////////////////
1320
1321void GrContext::flush(int flagsBitfield) {
1322    if (NULL == fDrawBuffer) {
1323        return;
1324    }
1325
1326    if (kDiscard_FlushBit & flagsBitfield) {
1327        fDrawBuffer->reset();
1328    } else {
1329        fDrawBuffer->flush();
1330    }
1331    fFlushToReduceCacheSize = false;
1332}
1333
1334bool GrContext::writeTexturePixels(GrTexture* texture,
1335                                   int left, int top, int width, int height,
1336                                   GrPixelConfig config, const void* buffer, size_t rowBytes,
1337                                   uint32_t flags) {
1338    ASSERT_OWNED_RESOURCE(texture);
1339
1340    if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) {
1341        if (texture->asRenderTarget()) {
1342            return this->writeRenderTargetPixels(texture->asRenderTarget(),
1343                                                 left, top, width, height,
1344                                                 config, buffer, rowBytes, flags);
1345        } else {
1346            return false;
1347        }
1348    }
1349
1350    if (!(kDontFlush_PixelOpsFlag & flags) && texture->hasPendingIO()) {
1351        this->flush();
1352    }
1353
1354    return fGpu->writeTexturePixels(texture, left, top, width, height,
1355                                    config, buffer, rowBytes);
1356}
1357
1358bool GrContext::readTexturePixels(GrTexture* texture,
1359                                  int left, int top, int width, int height,
1360                                  GrPixelConfig config, void* buffer, size_t rowBytes,
1361                                  uint32_t flags) {
1362    ASSERT_OWNED_RESOURCE(texture);
1363
1364    GrRenderTarget* target = texture->asRenderTarget();
1365    if (target) {
1366        return this->readRenderTargetPixels(target,
1367                                            left, top, width, height,
1368                                            config, buffer, rowBytes,
1369                                            flags);
1370    } else {
1371        // TODO: make this more efficient for cases where we're reading the entire
1372        //       texture, i.e., use GetTexImage() instead
1373
1374        // create scratch rendertarget and read from that
1375        GrAutoScratchTexture ast;
1376        GrTextureDesc desc;
1377        desc.fFlags = kRenderTarget_GrTextureFlagBit;
1378        desc.fWidth = width;
1379        desc.fHeight = height;
1380        desc.fConfig = config;
1381        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1382        ast.set(this, desc, kExact_ScratchTexMatch);
1383        GrTexture* dst = ast.texture();
1384        if (dst && (target = dst->asRenderTarget())) {
1385            this->copyTexture(texture, target, NULL);
1386            return this->readRenderTargetPixels(target,
1387                                                left, top, width, height,
1388                                                config, buffer, rowBytes,
1389                                                flags);
1390        }
1391
1392        return false;
1393    }
1394}
1395
1396#include "SkConfig8888.h"
1397
1398// toggles between RGBA and BGRA
1399static SkColorType toggle_colortype32(SkColorType ct) {
1400    if (kRGBA_8888_SkColorType == ct) {
1401        return kBGRA_8888_SkColorType;
1402    } else {
1403        SkASSERT(kBGRA_8888_SkColorType == ct);
1404        return kRGBA_8888_SkColorType;
1405    }
1406}
1407
1408bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1409                                       int left, int top, int width, int height,
1410                                       GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
1411                                       uint32_t flags) {
1412    ASSERT_OWNED_RESOURCE(target);
1413
1414    if (NULL == target) {
1415        target = fRenderTarget.get();
1416        if (NULL == target) {
1417            return false;
1418        }
1419    }
1420
1421    if (!(kDontFlush_PixelOpsFlag & flags) && target->hasPendingWrite()) {
1422        this->flush();
1423    }
1424
1425    // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
1426
1427    // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1428    // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1429    bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
1430                                                 width, height, dstConfig,
1431                                                 rowBytes);
1432    // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1433    // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1434    // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1435    // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1436    // dstConfig.
1437    GrPixelConfig readConfig = dstConfig;
1438    bool swapRAndB = false;
1439    if (GrPixelConfigSwapRAndB(dstConfig) ==
1440        fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
1441        readConfig = GrPixelConfigSwapRAndB(readConfig);
1442        swapRAndB = true;
1443    }
1444
1445    bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
1446
1447    if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
1448        // The unpremul flag is only allowed for these two configs.
1449        return false;
1450    }
1451
1452    // If the src is a texture and we would have to do conversions after read pixels, we instead
1453    // do the conversions by drawing the src to a scratch texture. If we handle any of the
1454    // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1455    // on the read back pixels.
1456    GrTexture* src = target->asTexture();
1457    GrAutoScratchTexture ast;
1458    if (src && (swapRAndB || unpremul || flipY)) {
1459        // Make the scratch a render target because we don't have a robust readTexturePixels as of
1460        // yet. It calls this function.
1461        GrTextureDesc desc;
1462        desc.fFlags = kRenderTarget_GrTextureFlagBit;
1463        desc.fWidth = width;
1464        desc.fHeight = height;
1465        desc.fConfig = readConfig;
1466        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1467
1468        // When a full read back is faster than a partial we could always make the scratch exactly
1469        // match the passed rect. However, if we see many different size rectangles we will trash
1470        // our texture cache and pay the cost of creating and destroying many textures. So, we only
1471        // request an exact match when the caller is reading an entire RT.
1472        ScratchTexMatch match = kApprox_ScratchTexMatch;
1473        if (0 == left &&
1474            0 == top &&
1475            target->width() == width &&
1476            target->height() == height &&
1477            fGpu->fullReadPixelsIsFasterThanPartial()) {
1478            match = kExact_ScratchTexMatch;
1479        }
1480        ast.set(this, desc, match);
1481        GrTexture* texture = ast.texture();
1482        if (texture) {
1483            // compute a matrix to perform the draw
1484            SkMatrix textureMatrix;
1485            textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1486            textureMatrix.postIDiv(src->width(), src->height());
1487
1488            SkAutoTUnref<const GrFragmentProcessor> fp;
1489            if (unpremul) {
1490                fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1491                if (fp) {
1492                    unpremul = false; // we no longer need to do this on CPU after the read back.
1493                }
1494            }
1495            // If we failed to create a PM->UPM effect and have no other conversions to perform then
1496            // there is no longer any point to using the scratch.
1497            if (fp || flipY || swapRAndB) {
1498                if (!fp) {
1499                    fp.reset(GrConfigConversionEffect::Create(
1500                            src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1501                            textureMatrix));
1502                }
1503                swapRAndB = false; // we will handle the swap in the draw.
1504
1505                // We protect the existing geometry here since it may not be
1506                // clear to the caller that a draw operation (i.e., drawSimpleRect)
1507                // can be invoked in this method
1508                GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
1509                GrDrawState* drawState = fGpu->drawState();
1510                SkASSERT(fp);
1511                drawState->addColorProcessor(fp);
1512
1513                drawState->setRenderTarget(texture->asRenderTarget());
1514                SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1515                fGpu->drawSimpleRect(rect);
1516                // we want to read back from the scratch's origin
1517                left = 0;
1518                top = 0;
1519                target = texture->asRenderTarget();
1520            }
1521        }
1522    }
1523    if (!fGpu->readPixels(target,
1524                          left, top, width, height,
1525                          readConfig, buffer, rowBytes)) {
1526        return false;
1527    }
1528    // Perform any conversions we weren't able to perform using a scratch texture.
1529    if (unpremul || swapRAndB) {
1530        SkDstPixelInfo dstPI;
1531        if (!GrPixelConfig2ColorType(dstConfig, &dstPI.fColorType)) {
1532            return false;
1533        }
1534        dstPI.fAlphaType = kUnpremul_SkAlphaType;
1535        dstPI.fPixels = buffer;
1536        dstPI.fRowBytes = rowBytes;
1537
1538        SkSrcPixelInfo srcPI;
1539        srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1540        srcPI.fAlphaType = kPremul_SkAlphaType;
1541        srcPI.fPixels = buffer;
1542        srcPI.fRowBytes = rowBytes;
1543
1544        return srcPI.convertPixelsTo(&dstPI, width, height);
1545    }
1546    return true;
1547}
1548
1549void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1550    SkASSERT(target);
1551    ASSERT_OWNED_RESOURCE(target);
1552    // In the future we may track whether there are any pending draws to this
1553    // target. We don't today so we always perform a flush. We don't promise
1554    // this to our clients, though.
1555    this->flush();
1556    if (fGpu) {
1557        fGpu->resolveRenderTarget(target);
1558    }
1559}
1560
1561void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
1562    SkASSERT(renderTarget);
1563    ASSERT_OWNED_RESOURCE(renderTarget);
1564    AutoRestoreEffects are;
1565    AutoCheckFlush acf(this);
1566    GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, &are, &acf);
1567    if (NULL == target) {
1568        return;
1569    }
1570    target->discard(renderTarget);
1571}
1572
1573void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) {
1574    if (NULL == src || NULL == dst) {
1575        return;
1576    }
1577    ASSERT_OWNED_RESOURCE(src);
1578
1579    SkIRect srcRect = SkIRect::MakeWH(dst->width(), dst->height());
1580    if (topLeft) {
1581        srcRect.offset(*topLeft);
1582    }
1583    SkIRect srcBounds = SkIRect::MakeWH(src->width(), src->height());
1584    if (!srcRect.intersect(srcBounds)) {
1585        return;
1586    }
1587
1588    GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW, NULL, NULL);
1589    if (NULL == target) {
1590        return;
1591    }
1592    SkIPoint dstPoint;
1593    dstPoint.setZero();
1594    target->copySurface(dst, src, srcRect, dstPoint);
1595}
1596
1597bool GrContext::writeRenderTargetPixels(GrRenderTarget* target,
1598                                        int left, int top, int width, int height,
1599                                        GrPixelConfig srcConfig,
1600                                        const void* buffer,
1601                                        size_t rowBytes,
1602                                        uint32_t flags) {
1603    ASSERT_OWNED_RESOURCE(target);
1604
1605    if (NULL == target) {
1606        target = fRenderTarget.get();
1607        if (NULL == target) {
1608            return false;
1609        }
1610    }
1611
1612    // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on
1613    // desktop GL).
1614
1615    // We will always call some form of writeTexturePixels and we will pass our flags on to it.
1616    // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't
1617    // set.)
1618
1619    // If the RT is also a texture and we don't have to premultiply then take the texture path.
1620    // We expect to be at least as fast or faster since it doesn't use an intermediate texture as
1621    // we do below.
1622
1623#if !defined(SK_BUILD_FOR_MAC)
1624    // At least some drivers on the Mac get confused when glTexImage2D is called on a texture
1625    // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or
1626    // HW is affected.
1627    if (target->asTexture() && !(kUnpremul_PixelOpsFlag & flags) &&
1628        fGpu->canWriteTexturePixels(target->asTexture(), srcConfig)) {
1629        return this->writeTexturePixels(target->asTexture(),
1630                                        left, top, width, height,
1631                                        srcConfig, buffer, rowBytes, flags);
1632    }
1633#endif
1634
1635    // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1636    // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1637    // config. This scratch will then have R and B swapped. We correct for this by swapping again
1638    // when drawing the scratch to the dst using a conversion effect.
1639    bool swapRAndB = false;
1640    GrPixelConfig writeConfig = srcConfig;
1641    if (GrPixelConfigSwapRAndB(srcConfig) ==
1642        fGpu->preferredWritePixelsConfig(srcConfig, target->config())) {
1643        writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1644        swapRAndB = true;
1645    }
1646
1647    GrTextureDesc desc;
1648    desc.fWidth = width;
1649    desc.fHeight = height;
1650    desc.fConfig = writeConfig;
1651    GrAutoScratchTexture ast(this, desc);
1652    GrTexture* texture = ast.texture();
1653    if (NULL == texture) {
1654        return false;
1655    }
1656
1657    SkAutoTUnref<const GrFragmentProcessor> fp;
1658    SkMatrix textureMatrix;
1659    textureMatrix.setIDiv(texture->width(), texture->height());
1660
1661    // allocate a tmp buffer and sw convert the pixels to premul
1662    SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1663
1664    if (kUnpremul_PixelOpsFlag & flags) {
1665        if (!GrPixelConfigIs8888(srcConfig)) {
1666            return false;
1667        }
1668        fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1669        // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1670        if (NULL == fp) {
1671            SkSrcPixelInfo srcPI;
1672            if (!GrPixelConfig2ColorType(srcConfig, &srcPI.fColorType)) {
1673                return false;
1674            }
1675            srcPI.fAlphaType = kUnpremul_SkAlphaType;
1676            srcPI.fPixels = buffer;
1677            srcPI.fRowBytes = rowBytes;
1678
1679            tmpPixels.reset(width * height);
1680
1681            SkDstPixelInfo dstPI;
1682            dstPI.fColorType = srcPI.fColorType;
1683            dstPI.fAlphaType = kPremul_SkAlphaType;
1684            dstPI.fPixels = tmpPixels.get();
1685            dstPI.fRowBytes = 4 * width;
1686
1687            if (!srcPI.convertPixelsTo(&dstPI, width, height)) {
1688                return false;
1689            }
1690
1691            buffer = tmpPixels.get();
1692            rowBytes = 4 * width;
1693        }
1694    }
1695    if (NULL == fp) {
1696        fp.reset(GrConfigConversionEffect::Create(texture,
1697                                                      swapRAndB,
1698                                                      GrConfigConversionEffect::kNone_PMConversion,
1699                                                      textureMatrix));
1700    }
1701
1702    if (!this->writeTexturePixels(texture,
1703                                  0, 0, width, height,
1704                                  writeConfig, buffer, rowBytes,
1705                                  flags & ~kUnpremul_PixelOpsFlag)) {
1706        return false;
1707    }
1708
1709    // TODO: Usually this could go to fDrawBuffer but currently
1710    // writeRenderTargetPixels can be called in the midst of drawing another
1711    // object (e.g., when uploading a SW path rendering to the gpu while
1712    // drawing a rect). So we always draw directly to GrGpu and preserve the current geometry.
1713    // But that means we also have to flush the draw buffer if there is a pending IO operation to
1714    // the render target.
1715    if (!(kDontFlush_PixelOpsFlag & flags) && target->hasPendingIO()) {
1716        this->flush();
1717    }
1718    SkMatrix matrix;
1719    matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1720    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit, &matrix);
1721    GrDrawState* drawState = fGpu->drawState();
1722    SkASSERT(fp);
1723    drawState->addColorProcessor(fp);
1724
1725    drawState->setRenderTarget(target);
1726
1727    fGpu->drawSimpleRect(SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
1728    return true;
1729}
1730////////////////////////////////////////////////////////////////////////////////
1731
1732GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint,
1733                                       BufferedDraw buffered,
1734                                       AutoRestoreEffects* are,
1735                                       AutoCheckFlush* acf) {
1736    // All users of this draw state should be freeing up all effects when they're done.
1737    // Otherwise effects that own resources may keep those resources alive indefinitely.
1738    SkASSERT(0 == fDrawState->numColorStages() && 0 == fDrawState->numCoverageStages() &&
1739             !fDrawState->hasGeometryProcessor());
1740
1741    if (NULL == fGpu) {
1742        return NULL;
1743    }
1744
1745    if (kNo_BufferedDraw == buffered && kYes_BufferedDraw == fLastDrawWasBuffered) {
1746        fDrawBuffer->flush();
1747        fLastDrawWasBuffered = kNo_BufferedDraw;
1748    }
1749    ASSERT_OWNED_RESOURCE(fRenderTarget.get());
1750    if (paint) {
1751        SkASSERT(are);
1752        SkASSERT(acf);
1753        are->set(fDrawState);
1754        fDrawState->setFromPaint(*paint, fViewMatrix, fRenderTarget.get());
1755#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
1756        if ((paint->hasMask() || 0xff != paint->fCoverage) &&
1757            !fDrawState->couldApplyCoverage(fGpu->caps())) {
1758            GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1759        }
1760#endif
1761        // Clear any vertex attributes configured for the previous use of the
1762        // GrDrawState which can effect which blend optimizations are in effect.
1763        fDrawState->setDefaultVertexAttribs();
1764    } else {
1765        fDrawState->reset(fViewMatrix);
1766        fDrawState->setRenderTarget(fRenderTarget.get());
1767    }
1768    GrDrawTarget* target;
1769    if (kYes_BufferedDraw == buffered) {
1770        fLastDrawWasBuffered = kYes_BufferedDraw;
1771        target = fDrawBuffer;
1772    } else {
1773        SkASSERT(kNo_BufferedDraw == buffered);
1774        fLastDrawWasBuffered = kNo_BufferedDraw;
1775        target = fGpu;
1776    }
1777    fDrawState->setState(GrDrawState::kClip_StateBit, fClip &&
1778                                                     !fClip->fClipStack->isWideOpen());
1779    target->setClip(fClip);
1780    SkASSERT(fDrawState == target->drawState());
1781    return target;
1782}
1783
1784/*
1785 * This method finds a path renderer that can draw the specified path on
1786 * the provided target.
1787 * Due to its expense, the software path renderer has split out so it can
1788 * can be individually allowed/disallowed via the "allowSW" boolean.
1789 */
1790GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
1791                                           const SkStrokeRec& stroke,
1792                                           const GrDrawTarget* target,
1793                                           bool allowSW,
1794                                           GrPathRendererChain::DrawType drawType,
1795                                           GrPathRendererChain::StencilSupport* stencilSupport) {
1796
1797    if (NULL == fPathRendererChain) {
1798        fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
1799    }
1800
1801    GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
1802                                                             stroke,
1803                                                             target,
1804                                                             drawType,
1805                                                             stencilSupport);
1806
1807    if (NULL == pr && allowSW) {
1808        if (NULL == fSoftwarePathRenderer) {
1809            fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
1810        }
1811        pr = fSoftwarePathRenderer;
1812    }
1813
1814    return pr;
1815}
1816
1817////////////////////////////////////////////////////////////////////////////////
1818bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1819    return fGpu->caps()->isConfigRenderable(config, withMSAA);
1820}
1821
1822int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1823                                         SkScalar dpi) const {
1824    if (!this->isConfigRenderable(config, true)) {
1825        return 0;
1826    }
1827    int chosenSampleCount = 0;
1828    if (fGpu->caps()->pathRenderingSupport()) {
1829        if (dpi >= 250.0f) {
1830            chosenSampleCount = 4;
1831        } else {
1832            chosenSampleCount = 16;
1833        }
1834    }
1835    return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1836        chosenSampleCount : 0;
1837}
1838
1839void GrContext::setupDrawBuffer() {
1840    SkASSERT(NULL == fDrawBuffer);
1841    SkASSERT(NULL == fDrawBufferVBAllocPool);
1842    SkASSERT(NULL == fDrawBufferIBAllocPool);
1843
1844    fDrawBufferVBAllocPool =
1845        SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
1846                                    DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1847                                    DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
1848    fDrawBufferIBAllocPool =
1849        SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
1850                                   DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1851                                   DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
1852
1853    fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
1854                                                   fDrawBufferVBAllocPool,
1855                                                   fDrawBufferIBAllocPool));
1856
1857    fDrawBuffer->setDrawState(fDrawState);
1858}
1859
1860GrDrawTarget* GrContext::getTextTarget() {
1861    return this->prepareToDraw(NULL, BUFFERED_DRAW, NULL, NULL);
1862}
1863
1864const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1865    return fGpu->getQuadIndexBuffer();
1866}
1867
1868namespace {
1869void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1870    GrConfigConversionEffect::PMConversion pmToUPM;
1871    GrConfigConversionEffect::PMConversion upmToPM;
1872    GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1873    *pmToUPMValue = pmToUPM;
1874    *upmToPMValue = upmToPM;
1875}
1876}
1877
1878const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1879                                                          bool swapRAndB,
1880                                                          const SkMatrix& matrix) {
1881    if (!fDidTestPMConversions) {
1882        test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1883        fDidTestPMConversions = true;
1884    }
1885    GrConfigConversionEffect::PMConversion pmToUPM =
1886        static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1887    if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
1888        return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
1889    } else {
1890        return NULL;
1891    }
1892}
1893
1894const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1895                                                          bool swapRAndB,
1896                                                          const SkMatrix& matrix) {
1897    if (!fDidTestPMConversions) {
1898        test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1899        fDidTestPMConversions = true;
1900    }
1901    GrConfigConversionEffect::PMConversion upmToPM =
1902        static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1903    if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
1904        return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
1905    } else {
1906        return NULL;
1907    }
1908}
1909
1910void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResource* resource) {
1911    fResourceCache->purgeAsNeeded(1, resource->gpuMemorySize());
1912    fResourceCache->addResource(resourceKey, resource);
1913}
1914
1915GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resourceKey) {
1916    GrGpuResource* resource = fResourceCache->find(resourceKey);
1917    SkSafeRef(resource);
1918    return resource;
1919}
1920
1921void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1922    fGpu->addGpuTraceMarker(marker);
1923    if (fDrawBuffer) {
1924        fDrawBuffer->addGpuTraceMarker(marker);
1925    }
1926}
1927
1928void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
1929    fGpu->removeGpuTraceMarker(marker);
1930    if (fDrawBuffer) {
1931        fDrawBuffer->removeGpuTraceMarker(marker);
1932    }
1933}
1934
1935///////////////////////////////////////////////////////////////////////////////
1936#if GR_CACHE_STATS
1937void GrContext::printCacheStats() const {
1938    fResourceCache->printStats();
1939}
1940#endif
1941
1942#if GR_GPU_STATS
1943const GrContext::GPUStats* GrContext::gpuStats() const {
1944    return fGpu->gpuStats();
1945}
1946#endif
1947
1948