GrContext.cpp revision 733c062c09bfe3ec4a32658510136fc5850a6e2c
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/GrConvolutionEffect.h"
13#include "effects/GrSingleTextureEffect.h"
14#include "effects/GrConfigConversionEffect.h"
15
16#include "GrBufferAllocPool.h"
17#include "GrGpu.h"
18#include "GrDrawTargetCaps.h"
19#include "GrIndexBuffer.h"
20#include "GrInOrderDrawBuffer.h"
21#include "GrOvalRenderer.h"
22#include "GrPathRenderer.h"
23#include "GrPathUtils.h"
24#include "GrResourceCache.h"
25#include "GrSoftwarePathRenderer.h"
26#include "GrStencilBuffer.h"
27#include "GrTextStrike.h"
28#include "SkRTConf.h"
29#include "SkStrokeRec.h"
30#include "SkTLazy.h"
31#include "SkTLS.h"
32#include "SkTrace.h"
33
34SK_DEFINE_INST_COUNT(GrContext)
35SK_DEFINE_INST_COUNT(GrDrawState)
36
37// It can be useful to set this to false to test whether a bug is caused by using the
38// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make
39// debugging simpler.
40SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true,
41                "Defers rendering in GrContext via GrInOrderDrawBuffer.");
42
43#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw)
44
45#define MAX_BLUR_SIGMA 4.0f
46
47// When we're using coverage AA but the blend is incompatible (given gpu
48// limitations) should we disable AA or draw wrong?
49#define DISABLE_COVERAGE_AA_FOR_BLEND 1
50
51#if GR_DEBUG
52    // change this to a 1 to see notifications when partial coverage fails
53    #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
54#else
55    #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0
56#endif
57
58static const size_t MAX_TEXTURE_CACHE_COUNT = 2048;
59static const size_t MAX_TEXTURE_CACHE_BYTES = GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT * 1024 * 1024;
60
61static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
62static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
63
64static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
65static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
66
67#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
68
69GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
70    GrContext* context = SkNEW(GrContext);
71    if (context->init(backend, backendContext)) {
72        return context;
73    } else {
74        context->unref();
75        return NULL;
76    }
77}
78
79namespace {
80void* CreateThreadInstanceCount() {
81    return SkNEW_ARGS(int, (0));
82}
83void DeleteThreadInstanceCount(void* v) {
84    delete reinterpret_cast<int*>(v);
85}
86#define THREAD_INSTANCE_COUNT \
87    (*reinterpret_cast<int*>(SkTLS::Get(CreateThreadInstanceCount, DeleteThreadInstanceCount)))
88}
89
90GrContext::GrContext() {
91    ++THREAD_INSTANCE_COUNT;
92    fDrawState = NULL;
93    fGpu = NULL;
94    fPathRendererChain = NULL;
95    fSoftwarePathRenderer = NULL;
96    fTextureCache = NULL;
97    fFontCache = NULL;
98    fDrawBuffer = NULL;
99    fDrawBufferVBAllocPool = NULL;
100    fDrawBufferIBAllocPool = NULL;
101    fAARectRenderer = NULL;
102    fOvalRenderer = NULL;
103}
104
105bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
106    GrAssert(NULL == fGpu);
107
108    fGpu = GrGpu::Create(backend, backendContext, this);
109    if (NULL == fGpu) {
110        return false;
111    }
112
113    fDrawState = SkNEW(GrDrawState);
114    fGpu->setDrawState(fDrawState);
115
116
117    fTextureCache = SkNEW_ARGS(GrResourceCache,
118                               (MAX_TEXTURE_CACHE_COUNT,
119                                MAX_TEXTURE_CACHE_BYTES));
120    fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
121
122    fLastDrawWasBuffered = kNo_BufferedDraw;
123
124    fAARectRenderer = SkNEW(GrAARectRenderer);
125    fOvalRenderer = SkNEW(GrOvalRenderer);
126
127    fDidTestPMConversions = false;
128
129    this->setupDrawBuffer();
130
131    return true;
132}
133
134int GrContext::GetThreadInstanceCount() {
135    return THREAD_INSTANCE_COUNT;
136}
137
138GrContext::~GrContext() {
139    for (int i = 0; i < fCleanUpData.count(); ++i) {
140        (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
141    }
142
143    if (NULL == fGpu) {
144        return;
145    }
146
147    this->flush();
148
149    // Since the gpu can hold scratch textures, give it a chance to let go
150    // of them before freeing the texture cache
151    fGpu->purgeResources();
152
153    delete fTextureCache;
154    fTextureCache = NULL;
155    delete fFontCache;
156    delete fDrawBuffer;
157    delete fDrawBufferVBAllocPool;
158    delete fDrawBufferIBAllocPool;
159
160    fAARectRenderer->unref();
161    fOvalRenderer->unref();
162
163    fGpu->unref();
164    GrSafeUnref(fPathRendererChain);
165    GrSafeUnref(fSoftwarePathRenderer);
166    fDrawState->unref();
167
168    --THREAD_INSTANCE_COUNT;
169}
170
171void GrContext::contextLost() {
172    this->contextDestroyed();
173    this->setupDrawBuffer();
174}
175
176void GrContext::contextDestroyed() {
177    // abandon first to so destructors
178    // don't try to free the resources in the API.
179    fGpu->abandonResources();
180
181    // a path renderer may be holding onto resources that
182    // are now unusable
183    GrSafeSetNull(fPathRendererChain);
184    GrSafeSetNull(fSoftwarePathRenderer);
185
186    delete fDrawBuffer;
187    fDrawBuffer = NULL;
188
189    delete fDrawBufferVBAllocPool;
190    fDrawBufferVBAllocPool = NULL;
191
192    delete fDrawBufferIBAllocPool;
193    fDrawBufferIBAllocPool = NULL;
194
195    fAARectRenderer->reset();
196
197    fTextureCache->purgeAllUnlocked();
198    fFontCache->freeAll();
199    fGpu->markContextDirty();
200}
201
202void GrContext::resetContext() {
203    fGpu->markContextDirty();
204}
205
206void GrContext::freeGpuResources() {
207    this->flush();
208
209    fGpu->purgeResources();
210
211    fAARectRenderer->reset();
212
213    fTextureCache->purgeAllUnlocked();
214    fFontCache->freeAll();
215    // a path renderer may be holding onto resources
216    GrSafeSetNull(fPathRendererChain);
217    GrSafeSetNull(fSoftwarePathRenderer);
218}
219
220size_t GrContext::getGpuTextureCacheBytes() const {
221  return fTextureCache->getCachedResourceBytes();
222}
223
224////////////////////////////////////////////////////////////////////////////////
225
226namespace {
227
228void scale_rect(SkRect* rect, float xScale, float yScale) {
229    rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale));
230    rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale));
231    rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale));
232    rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale));
233}
234
235float adjust_sigma(float sigma, int *scaleFactor, int *radius) {
236    *scaleFactor = 1;
237    while (sigma > MAX_BLUR_SIGMA) {
238        *scaleFactor *= 2;
239        sigma *= 0.5f;
240    }
241    *radius = static_cast<int>(ceilf(sigma * 3.0f));
242    GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius);
243    return sigma;
244}
245
246void convolve_gaussian(GrDrawTarget* target,
247                       GrTexture* texture,
248                       const SkRect& rect,
249                       float sigma,
250                       int radius,
251                       Gr1DKernelEffect::Direction direction) {
252    GrRenderTarget* rt = target->drawState()->getRenderTarget();
253    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit);
254    GrDrawState* drawState = target->drawState();
255    drawState->setRenderTarget(rt);
256    SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture,
257                                                                       direction,
258                                                                       radius,
259                                                                       sigma));
260    drawState->setEffect(0, conv);
261    target->drawSimpleRect(rect, NULL);
262}
263
264}
265
266////////////////////////////////////////////////////////////////////////////////
267
268GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
269                                        const GrCacheID& cacheID,
270                                        const GrTextureParams* params) {
271    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
272    GrResource* resource = fTextureCache->find(resourceKey);
273    SkSafeRef(resource);
274    return static_cast<GrTexture*>(resource);
275}
276
277bool GrContext::isTextureInCache(const GrTextureDesc& desc,
278                                 const GrCacheID& cacheID,
279                                 const GrTextureParams* params) const {
280    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
281    return fTextureCache->hasKey(resourceKey);
282}
283
284void GrContext::addStencilBuffer(GrStencilBuffer* sb) {
285    ASSERT_OWNED_RESOURCE(sb);
286
287    GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(),
288                                                            sb->height(),
289                                                            sb->numSamples());
290    fTextureCache->addResource(resourceKey, sb);
291}
292
293GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
294                                              int sampleCnt) {
295    GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width,
296                                                            height,
297                                                            sampleCnt);
298    GrResource* resource = fTextureCache->find(resourceKey);
299    return static_cast<GrStencilBuffer*>(resource);
300}
301
302static void stretchImage(void* dst,
303                         int dstW,
304                         int dstH,
305                         void* src,
306                         int srcW,
307                         int srcH,
308                         int bpp) {
309    GrFixed dx = (srcW << 16) / dstW;
310    GrFixed dy = (srcH << 16) / dstH;
311
312    GrFixed y = dy >> 1;
313
314    int dstXLimit = dstW*bpp;
315    for (int j = 0; j < dstH; ++j) {
316        GrFixed x = dx >> 1;
317        void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
318        void* dstRow = (uint8_t*)dst + j*dstW*bpp;
319        for (int i = 0; i < dstXLimit; i += bpp) {
320            memcpy((uint8_t*) dstRow + i,
321                   (uint8_t*) srcRow + (x>>16)*bpp,
322                   bpp);
323            x += dx;
324        }
325        y += dy;
326    }
327}
328
329namespace {
330
331// position + local coordinate
332extern const GrVertexAttrib gVertexAttribs[] = {
333    {kVec2f_GrVertexAttribType, 0,               kPosition_GrVertexAttribBinding},
334    {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding}
335};
336
337};
338
339// The desired texture is NPOT and tiled but that isn't supported by
340// the current hardware. Resize the texture to be a POT
341GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc,
342                                           const GrCacheID& cacheID,
343                                           void* srcData,
344                                           size_t rowBytes,
345                                           bool needsFiltering) {
346    SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, cacheID, NULL));
347    if (NULL == clampedTexture) {
348        clampedTexture.reset(this->createTexture(NULL, desc, cacheID, srcData, rowBytes));
349
350        if (NULL == clampedTexture) {
351            return NULL;
352        }
353    }
354
355    GrTextureDesc rtDesc = desc;
356    rtDesc.fFlags =  rtDesc.fFlags |
357                     kRenderTarget_GrTextureFlagBit |
358                     kNoStencil_GrTextureFlagBit;
359    rtDesc.fWidth  = GrNextPow2(GrMax(desc.fWidth, 64));
360    rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
361
362    GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
363
364    if (NULL != texture) {
365        GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
366        GrDrawState* drawState = fGpu->drawState();
367        drawState->setRenderTarget(texture->asRenderTarget());
368
369        // if filtering is not desired then we want to ensure all
370        // texels in the resampled image are copies of texels from
371        // the original.
372        GrTextureParams params(SkShader::kClamp_TileMode, needsFiltering);
373        drawState->createTextureEffect(0, clampedTexture, SkMatrix::I(), params);
374
375        drawState->setVertexAttribs<gVertexAttribs>(SK_ARRAY_COUNT(gVertexAttribs));
376
377        GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
378
379        if (arg.succeeded()) {
380            GrPoint* verts = (GrPoint*) arg.vertices();
381            verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(GrPoint));
382            verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(GrPoint));
383            fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
384        }
385    } else {
386        // TODO: Our CPU stretch doesn't filter. But we create separate
387        // stretched textures when the texture params is either filtered or
388        // not. Either implement filtered stretch blit on CPU or just create
389        // one when FBO case fails.
390
391        rtDesc.fFlags = kNone_GrTextureFlags;
392        // no longer need to clamp at min RT size.
393        rtDesc.fWidth  = GrNextPow2(desc.fWidth);
394        rtDesc.fHeight = GrNextPow2(desc.fHeight);
395        int bpp = GrBytesPerPixel(desc.fConfig);
396        SkAutoSMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight);
397        stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
398                     srcData, desc.fWidth, desc.fHeight, bpp);
399
400        size_t stretchedRowBytes = rtDesc.fWidth * bpp;
401
402        SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(),
403                                                              stretchedRowBytes);
404        GrAssert(NULL != texture);
405    }
406
407    return texture;
408}
409
410GrTexture* GrContext::createTexture(const GrTextureParams* params,
411                                    const GrTextureDesc& desc,
412                                    const GrCacheID& cacheID,
413                                    void* srcData,
414                                    size_t rowBytes) {
415    SK_TRACE_EVENT0("GrContext::createTexture");
416
417    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID);
418
419    GrTexture* texture;
420    if (GrTexture::NeedsResizing(resourceKey)) {
421        texture = this->createResizedTexture(desc, cacheID,
422                                             srcData, rowBytes,
423                                             GrTexture::NeedsFiltering(resourceKey));
424    } else {
425        texture= fGpu->createTexture(desc, srcData, rowBytes);
426    }
427
428    if (NULL != texture) {
429        fTextureCache->addResource(resourceKey, texture);
430    }
431
432    return texture;
433}
434
435GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) {
436    GrTextureDesc desc = inDesc;
437
438    GrAssert((desc.fFlags & kRenderTarget_GrTextureFlagBit) ||
439             !(desc.fFlags & kNoStencil_GrTextureFlagBit));
440
441    if (kApprox_ScratchTexMatch == match) {
442        // bin by pow2 with a reasonable min
443        static const int MIN_SIZE = 16;
444        desc.fWidth  = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
445        desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
446    }
447
448    // Renderable A8 targets are not universally supported (e.g., not on ANGLE)
449    GrAssert(this->isConfigRenderable(kAlpha_8_GrPixelConfig) ||
450             !(desc.fFlags & kRenderTarget_GrTextureFlagBit) ||
451             (desc.fConfig != kAlpha_8_GrPixelConfig));
452
453    GrResource* resource = NULL;
454    int origWidth = desc.fWidth;
455    int origHeight = desc.fHeight;
456
457    do {
458        GrResourceKey key = GrTexture::ComputeScratchKey(desc);
459        // Ensure we have exclusive access to the texture so future 'find' calls don't return it
460        resource = fTextureCache->find(key, GrResourceCache::kHide_OwnershipFlag);
461        if (NULL != resource) {
462            resource->ref();
463            break;
464        }
465        if (kExact_ScratchTexMatch == match) {
466            break;
467        }
468        // We had a cache miss and we are in approx mode, relax the fit of the flags.
469
470        // We no longer try to reuse textures that were previously used as render targets in
471        // situations where no RT is needed; doing otherwise can confuse the video driver and
472        // cause significant performance problems in some cases.
473        if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
474            desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
475        } else {
476            break;
477        }
478
479    } while (true);
480
481    if (NULL == resource) {
482        desc.fFlags = inDesc.fFlags;
483        desc.fWidth = origWidth;
484        desc.fHeight = origHeight;
485        GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
486        if (NULL != texture) {
487            GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc());
488            // Make the resource exclusive so future 'find' calls don't return it
489            fTextureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag);
490            resource = texture;
491        }
492    }
493
494    return static_cast<GrTexture*>(resource);
495}
496
497void GrContext::addExistingTextureToCache(GrTexture* texture) {
498
499    if (NULL == texture) {
500        return;
501    }
502
503    // This texture should already have a cache entry since it was once
504    // attached
505    GrAssert(NULL != texture->getCacheEntry());
506
507    // Conceptually, the cache entry is going to assume responsibility
508    // for the creation ref.
509    GrAssert(1 == texture->getRefCnt());
510
511    // Since this texture came from an AutoScratchTexture it should
512    // still be in the exclusive pile
513    fTextureCache->makeNonExclusive(texture->getCacheEntry());
514
515    this->purgeCache();
516}
517
518
519void GrContext::unlockScratchTexture(GrTexture* texture) {
520    ASSERT_OWNED_RESOURCE(texture);
521    GrAssert(NULL != texture->getCacheEntry());
522
523    // If this is a scratch texture we detached it from the cache
524    // while it was locked (to avoid two callers simultaneously getting
525    // the same texture).
526    if (texture->getCacheEntry()->key().isScratch()) {
527        fTextureCache->makeNonExclusive(texture->getCacheEntry());
528    }
529
530    this->purgeCache();
531}
532
533void GrContext::purgeCache() {
534    if (NULL != fTextureCache) {
535        fTextureCache->purgeAsNeeded();
536    }
537}
538
539GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn,
540                                            void* srcData,
541                                            size_t rowBytes) {
542    GrTextureDesc descCopy = descIn;
543    return fGpu->createTexture(descCopy, srcData, rowBytes);
544}
545
546void GrContext::getTextureCacheLimits(int* maxTextures,
547                                      size_t* maxTextureBytes) const {
548    fTextureCache->getLimits(maxTextures, maxTextureBytes);
549}
550
551void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
552    fTextureCache->setLimits(maxTextures, maxTextureBytes);
553}
554
555int GrContext::getMaxTextureSize() const {
556    return fGpu->caps()->maxTextureSize();
557}
558
559int GrContext::getMaxRenderTargetSize() const {
560    return fGpu->caps()->maxRenderTargetSize();
561}
562
563int GrContext::getMaxSampleCount() const {
564    return fGpu->caps()->maxSampleCount();
565}
566
567///////////////////////////////////////////////////////////////////////////////
568
569GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
570    return fGpu->wrapBackendTexture(desc);
571}
572
573GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
574    return fGpu->wrapBackendRenderTarget(desc);
575}
576
577///////////////////////////////////////////////////////////////////////////////
578
579bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
580                                          int width, int height) const {
581    const GrDrawTargetCaps* caps = fGpu->caps();
582    if (!caps->eightBitPaletteSupport()) {
583        return false;
584    }
585
586    bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
587
588    if (!isPow2) {
589        bool tiled = NULL != params && params->isTiled();
590        if (tiled && !caps->npotTextureTileSupport()) {
591            return false;
592        }
593    }
594    return true;
595}
596
597////////////////////////////////////////////////////////////////////////////////
598
599const GrClipData* GrContext::getClip() const {
600    return fGpu->getClip();
601}
602
603void GrContext::setClip(const GrClipData* clipData) {
604    fGpu->setClip(clipData);
605
606    fDrawState->setState(GrDrawState::kClip_StateBit,
607                         clipData && clipData->fClipStack && !clipData->fClipStack->isWideOpen());
608}
609
610////////////////////////////////////////////////////////////////////////////////
611
612void GrContext::clear(const GrIRect* rect,
613                      const GrColor color,
614                      GrRenderTarget* target) {
615    this->prepareToDraw(NULL, BUFFERED_DRAW)->clear(rect, color, target);
616}
617
618void GrContext::drawPaint(const GrPaint& origPaint) {
619    // set rect to be big enough to fill the space, but not super-huge, so we
620    // don't overflow fixed-point implementations
621    GrRect r;
622    r.setLTRB(0, 0,
623              SkIntToScalar(getRenderTarget()->width()),
624              SkIntToScalar(getRenderTarget()->height()));
625    SkMatrix inverse;
626    SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
627    AutoMatrix am;
628
629    // We attempt to map r by the inverse matrix and draw that. mapRect will
630    // map the four corners and bound them with a new rect. This will not
631    // produce a correct result for some perspective matrices.
632    if (!this->getMatrix().hasPerspective()) {
633        if (!fDrawState->getViewInverse(&inverse)) {
634            GrPrintf("Could not invert matrix\n");
635            return;
636        }
637        inverse.mapRect(&r);
638    } else {
639        if (!am.setIdentity(this, paint.writable())) {
640            GrPrintf("Could not invert matrix\n");
641            return;
642        }
643    }
644    // by definition this fills the entire clip, no need for AA
645    if (paint->isAntiAlias()) {
646        paint.writable()->setAntiAlias(false);
647    }
648    this->drawRect(*paint, r);
649}
650
651////////////////////////////////////////////////////////////////////////////////
652
653namespace {
654inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
655    return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
656}
657}
658
659////////////////////////////////////////////////////////////////////////////////
660
661/*  create a triangle strip that strokes the specified triangle. There are 8
662 unique vertices, but we repreat the last 2 to close up. Alternatively we
663 could use an indices array, and then only send 8 verts, but not sure that
664 would be faster.
665 */
666static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
667                               SkScalar width) {
668    const SkScalar rad = SkScalarHalf(width);
669    rect.sort();
670
671    verts[0].set(rect.fLeft + rad, rect.fTop + rad);
672    verts[1].set(rect.fLeft - rad, rect.fTop - rad);
673    verts[2].set(rect.fRight - rad, rect.fTop + rad);
674    verts[3].set(rect.fRight + rad, rect.fTop - rad);
675    verts[4].set(rect.fRight - rad, rect.fBottom - rad);
676    verts[5].set(rect.fRight + rad, rect.fBottom + rad);
677    verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
678    verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
679    verts[8] = verts[0];
680    verts[9] = verts[1];
681}
682
683/**
684 * Returns true if the rects edges are integer-aligned.
685 */
686static bool isIRect(const GrRect& r) {
687    return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
688           SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
689}
690
691static bool apply_aa_to_rect(GrDrawTarget* target,
692                             const GrRect& rect,
693                             SkScalar strokeWidth,
694                             const SkMatrix* matrix,
695                             SkMatrix* combinedMatrix,
696                             GrRect* devRect,
697                             bool* useVertexCoverage) {
698    // we use a simple coverage ramp to do aa on axis-aligned rects
699    // we check if the rect will be axis-aligned, and the rect won't land on
700    // integer coords.
701
702    // we are keeping around the "tweak the alpha" trick because
703    // it is our only hope for the fixed-pipe implementation.
704    // In a shader implementation we can give a separate coverage input
705    // TODO: remove this ugliness when we drop the fixed-pipe impl
706    *useVertexCoverage = false;
707    if (!target->getDrawState().canTweakAlphaForCoverage()) {
708        if (disable_coverage_aa_for_blend(target)) {
709#if GR_DEBUG
710            //GrPrintf("Turning off AA to correctly apply blend.\n");
711#endif
712            return false;
713        } else {
714            *useVertexCoverage = true;
715        }
716    }
717    const GrDrawState& drawState = target->getDrawState();
718    if (drawState.getRenderTarget()->isMultisampled()) {
719        return false;
720    }
721
722    if (0 == strokeWidth && target->willUseHWAALines()) {
723        return false;
724    }
725
726#ifdef SHADER_AA_FILL_RECT
727    if (strokeWidth >= 0) {
728#endif
729        if (!drawState.getViewMatrix().preservesAxisAlignment()) {
730            return false;
731        }
732
733        if (NULL != matrix && !matrix->preservesAxisAlignment()) {
734            return false;
735        }
736#ifdef SHADER_AA_FILL_RECT
737    } else {
738        if (!drawState.getViewMatrix().preservesAxisAlignment() &&
739            !drawState.getViewMatrix().preservesRightAngles()) {
740            return false;
741        }
742
743        if (NULL != matrix && !matrix->preservesRightAngles()) {
744            return false;
745        }
746    }
747#endif
748
749    *combinedMatrix = drawState.getViewMatrix();
750    if (NULL != matrix) {
751        combinedMatrix->preConcat(*matrix);
752
753#if GR_DEBUG
754#ifdef SHADER_AA_FILL_RECT
755        if (strokeWidth >= 0) {
756#endif
757            GrAssert(combinedMatrix->preservesAxisAlignment());
758#ifdef SHADER_AA_FILL_RECT
759        } else {
760            GrAssert(combinedMatrix->preservesRightAngles());
761        }
762#endif
763#endif
764    }
765
766    combinedMatrix->mapRect(devRect, rect);
767    devRect->sort();
768
769    if (strokeWidth < 0) {
770        return !isIRect(*devRect);
771    } else {
772        return true;
773    }
774}
775
776void GrContext::drawRect(const GrPaint& paint,
777                         const GrRect& rect,
778                         SkScalar width,
779                         const SkMatrix* matrix) {
780    SK_TRACE_EVENT0("GrContext::drawRect");
781
782    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
783    GrDrawState::AutoStageDisable atr(fDrawState);
784
785    GrRect devRect = rect;
786    SkMatrix combinedMatrix;
787    bool useVertexCoverage;
788    bool needAA = paint.isAntiAlias() &&
789                  !this->getRenderTarget()->isMultisampled();
790    bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
791                                           &combinedMatrix, &devRect,
792                                           &useVertexCoverage);
793    if (doAA) {
794        GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
795        if (!adcd.succeeded()) {
796            return;
797        }
798        if (width >= 0) {
799            GrVec strokeSize;
800            if (width > 0) {
801                strokeSize.set(width, width);
802                combinedMatrix.mapVectors(&strokeSize, 1);
803                strokeSize.setAbs(strokeSize);
804            } else {
805                strokeSize.set(SK_Scalar1, SK_Scalar1);
806            }
807            fAARectRenderer->strokeAARect(this->getGpu(), target, devRect,
808                                          strokeSize, useVertexCoverage);
809        } else {
810            // filled AA rect
811#ifdef SHADER_AA_FILL_RECT
812            fAARectRenderer->shaderFillAARect(this->getGpu(), target,
813                                              rect, combinedMatrix, devRect,
814                                              useVertexCoverage);
815#else
816            fAARectRenderer->fillAARect(this->getGpu(), target,
817                                        devRect, useVertexCoverage);
818#endif
819        }
820        return;
821    }
822
823    if (width >= 0) {
824        // TODO: consider making static vertex buffers for these cases.
825        // Hairline could be done by just adding closing vertex to
826        // unitSquareVertexBuffer()
827
828        static const int worstCaseVertCount = 10;
829        target->drawState()->setDefaultVertexAttribs();
830        GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0);
831
832        if (!geo.succeeded()) {
833            GrPrintf("Failed to get space for vertices!\n");
834            return;
835        }
836
837        GrPrimitiveType primType;
838        int vertCount;
839        GrPoint* vertex = geo.positions();
840
841        if (width > 0) {
842            vertCount = 10;
843            primType = kTriangleStrip_GrPrimitiveType;
844            setStrokeRectStrip(vertex, rect, width);
845        } else {
846            // hairline
847            vertCount = 5;
848            primType = kLineStrip_GrPrimitiveType;
849            vertex[0].set(rect.fLeft, rect.fTop);
850            vertex[1].set(rect.fRight, rect.fTop);
851            vertex[2].set(rect.fRight, rect.fBottom);
852            vertex[3].set(rect.fLeft, rect.fBottom);
853            vertex[4].set(rect.fLeft, rect.fTop);
854        }
855
856        GrDrawState::AutoViewMatrixRestore avmr;
857        if (NULL != matrix) {
858            GrDrawState* drawState = target->drawState();
859            avmr.set(drawState, *matrix);
860        }
861
862        target->drawNonIndexed(primType, 0, vertCount);
863    } else {
864        // filled BW rect
865        target->drawSimpleRect(rect, matrix);
866    }
867}
868
869void GrContext::drawRectToRect(const GrPaint& paint,
870                               const GrRect& dstRect,
871                               const GrRect& localRect,
872                               const SkMatrix* dstMatrix,
873                               const SkMatrix* localMatrix) {
874    SK_TRACE_EVENT0("GrContext::drawRectToRect");
875
876    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
877    GrDrawState::AutoStageDisable atr(fDrawState);
878
879    target->drawRect(dstRect, dstMatrix, &localRect, localMatrix);
880}
881
882namespace {
883
884extern const GrVertexAttrib gPosUVColorAttribs[] = {
885    {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding },
886    {kVec2f_GrVertexAttribType,  sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding },
887    {kVec4ub_GrVertexAttribType, 2*sizeof(GrPoint), kColor_GrVertexAttribBinding}
888};
889
890extern const GrVertexAttrib gPosColorAttribs[] = {
891    {kVec2f_GrVertexAttribType,  0, kPosition_GrVertexAttribBinding},
892    {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
893};
894
895static void set_vertex_attributes(GrDrawState* drawState,
896                                  const GrPoint* texCoords,
897                                  const GrColor* colors,
898                                  int* colorOffset,
899                                  int* texOffset) {
900    *texOffset = -1;
901    *colorOffset = -1;
902
903    if (NULL != texCoords && NULL != colors) {
904        *texOffset = sizeof(GrPoint);
905        *colorOffset = 2*sizeof(GrPoint);
906        drawState->setVertexAttribs<gPosUVColorAttribs>(3);
907    } else if (NULL != texCoords) {
908        *texOffset = sizeof(GrPoint);
909        drawState->setVertexAttribs<gPosUVColorAttribs>(2);
910    } else if (NULL != colors) {
911        *colorOffset = sizeof(GrPoint);
912        drawState->setVertexAttribs<gPosColorAttribs>(2);
913    } else {
914        drawState->setVertexAttribs<gPosColorAttribs>(1);
915    }
916}
917
918};
919
920void GrContext::drawVertices(const GrPaint& paint,
921                             GrPrimitiveType primitiveType,
922                             int vertexCount,
923                             const GrPoint positions[],
924                             const GrPoint texCoords[],
925                             const GrColor colors[],
926                             const uint16_t indices[],
927                             int indexCount) {
928    SK_TRACE_EVENT0("GrContext::drawVertices");
929
930    GrDrawTarget::AutoReleaseGeometry geo;
931
932    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
933    GrDrawState::AutoStageDisable atr(fDrawState);
934
935    GrDrawState* drawState = target->drawState();
936
937    int colorOffset = -1, texOffset = -1;
938    set_vertex_attributes(drawState, texCoords, colors, &colorOffset, &texOffset);
939
940    size_t vertexSize = drawState->getVertexSize();
941    if (sizeof(GrPoint) != vertexSize) {
942        if (!geo.set(target, vertexCount, 0)) {
943            GrPrintf("Failed to get space for vertices!\n");
944            return;
945        }
946        void* curVertex = geo.vertices();
947
948        for (int i = 0; i < vertexCount; ++i) {
949            *((GrPoint*)curVertex) = positions[i];
950
951            if (texOffset >= 0) {
952                *(GrPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
953            }
954            if (colorOffset >= 0) {
955                *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
956            }
957            curVertex = (void*)((intptr_t)curVertex + vertexSize);
958        }
959    } else {
960        target->setVertexSourceToArray(positions, vertexCount);
961    }
962
963    // we don't currently apply offscreen AA to this path. Need improved
964    // management of GrDrawTarget's geometry to avoid copying points per-tile.
965
966    if (NULL != indices) {
967        target->setIndexSourceToArray(indices, indexCount);
968        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
969        target->resetIndexSource();
970    } else {
971        target->drawNonIndexed(primitiveType, 0, vertexCount);
972    }
973}
974
975///////////////////////////////////////////////////////////////////////////////
976
977void GrContext::drawOval(const GrPaint& paint,
978                         const GrRect& oval,
979                         const SkStrokeRec& stroke) {
980
981    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
982    GrDrawState::AutoStageDisable atr(fDrawState);
983
984    if (!fOvalRenderer->drawOval(target, this, paint, oval, stroke)) {
985        SkPath path;
986        path.addOval(oval);
987        this->internalDrawPath(target, paint, path, stroke);
988    }
989}
990
991void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) {
992
993    if (path.isEmpty()) {
994       if (path.isInverseFillType()) {
995           this->drawPaint(paint);
996       }
997       return;
998    }
999
1000    // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1001    // Scratch textures can be recycled after they are returned to the texture
1002    // cache. This presents a potential hazard for buffered drawing. However,
1003    // the writePixels that uploads to the scratch will perform a flush so we're
1004    // OK.
1005    GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
1006    GrDrawState::AutoStageDisable atr(fDrawState);
1007
1008    SkRect ovalRect;
1009    bool isOval = path.isOval(&ovalRect);
1010
1011    if (!isOval || path.isInverseFillType()
1012        || !fOvalRenderer->drawOval(target, this, paint, ovalRect, stroke)) {
1013        this->internalDrawPath(target, paint, path, stroke);
1014    }
1015}
1016
1017void GrContext::internalDrawPath(GrDrawTarget* target, const GrPaint& paint, const SkPath& path,
1018                                 const SkStrokeRec& stroke) {
1019
1020    bool prAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled();
1021
1022    // An Assumption here is that path renderer would use some form of tweaking
1023    // the src color (either the input alpha or in the frag shader) to implement
1024    // aa. If we have some future driver-mojo path AA that can do the right
1025    // thing WRT to the blend then we'll need some query on the PR.
1026    if (disable_coverage_aa_for_blend(target)) {
1027#if GR_DEBUG
1028        //GrPrintf("Turning off AA to correctly apply blend.\n");
1029#endif
1030        prAA = false;
1031    }
1032
1033    GrPathRendererChain::DrawType type = prAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1034                                                GrPathRendererChain::kColor_DrawType;
1035
1036    const SkPath* pathPtr = &path;
1037    SkPath tmpPath;
1038    SkStrokeRec strokeRec(stroke);
1039
1040    // Try a 1st time without stroking the path and without allowing the SW renderer
1041    GrPathRenderer* pr = this->getPathRenderer(*pathPtr, strokeRec, target, false, type);
1042
1043    if (NULL == pr) {
1044        if (!strokeRec.isHairlineStyle()) {
1045            // It didn't work the 1st time, so try again with the stroked path
1046            if (strokeRec.applyToPath(&tmpPath, *pathPtr)) {
1047                pathPtr = &tmpPath;
1048                strokeRec.setFillStyle();
1049            }
1050        }
1051        // This time, allow SW renderer
1052        pr = this->getPathRenderer(*pathPtr, strokeRec, target, true, type);
1053    }
1054
1055    if (NULL == pr) {
1056#if GR_DEBUG
1057        GrPrintf("Unable to find path renderer compatible with path.\n");
1058#endif
1059        return;
1060    }
1061
1062    pr->drawPath(*pathPtr, strokeRec, target, prAA);
1063}
1064
1065////////////////////////////////////////////////////////////////////////////////
1066
1067void GrContext::flush(int flagsBitfield) {
1068    if (kDiscard_FlushBit & flagsBitfield) {
1069        fDrawBuffer->reset();
1070    } else {
1071        this->flushDrawBuffer();
1072    }
1073    if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
1074        fGpu->forceRenderTargetFlush();
1075    }
1076}
1077
1078void GrContext::flushDrawBuffer() {
1079    if (NULL != fDrawBuffer && !fDrawBuffer->isFlushing()) {
1080        fDrawBuffer->flush();
1081    }
1082}
1083
1084bool GrContext::writeTexturePixels(GrTexture* texture,
1085                                   int left, int top, int width, int height,
1086                                   GrPixelConfig config, const void* buffer, size_t rowBytes,
1087                                   uint32_t flags) {
1088    SK_TRACE_EVENT0("GrContext::writeTexturePixels");
1089    ASSERT_OWNED_RESOURCE(texture);
1090
1091    if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) {
1092        if (NULL != texture->asRenderTarget()) {
1093            return this->writeRenderTargetPixels(texture->asRenderTarget(),
1094                                                 left, top, width, height,
1095                                                 config, buffer, rowBytes, flags);
1096        } else {
1097            return false;
1098        }
1099    }
1100
1101    if (!(kDontFlush_PixelOpsFlag & flags)) {
1102        this->flush();
1103    }
1104
1105    return fGpu->writeTexturePixels(texture, left, top, width, height,
1106                                    config, buffer, rowBytes);
1107}
1108
1109bool GrContext::readTexturePixels(GrTexture* texture,
1110                                  int left, int top, int width, int height,
1111                                  GrPixelConfig config, void* buffer, size_t rowBytes,
1112                                  uint32_t flags) {
1113    SK_TRACE_EVENT0("GrContext::readTexturePixels");
1114    ASSERT_OWNED_RESOURCE(texture);
1115
1116    // TODO: code read pixels for textures that aren't also rendertargets
1117    GrRenderTarget* target = texture->asRenderTarget();
1118    if (NULL != target) {
1119        return this->readRenderTargetPixels(target,
1120                                            left, top, width, height,
1121                                            config, buffer, rowBytes,
1122                                            flags);
1123    } else {
1124        return false;
1125    }
1126}
1127
1128#include "SkConfig8888.h"
1129
1130namespace {
1131/**
1132 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1133 * formats are representable as Config8888 and so the function returns false
1134 * if the GrPixelConfig has no equivalent Config8888.
1135 */
1136bool grconfig_to_config8888(GrPixelConfig config,
1137                            bool unpremul,
1138                            SkCanvas::Config8888* config8888) {
1139    switch (config) {
1140        case kRGBA_8888_GrPixelConfig:
1141            if (unpremul) {
1142                *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1143            } else {
1144                *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1145            }
1146            return true;
1147        case kBGRA_8888_GrPixelConfig:
1148            if (unpremul) {
1149                *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1150            } else {
1151                *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1152            }
1153            return true;
1154        default:
1155            return false;
1156    }
1157}
1158
1159// It returns a configuration with where the byte position of the R & B components are swapped in
1160// relation to the input config. This should only be called with the result of
1161// grconfig_to_config8888 as it will fail for other configs.
1162SkCanvas::Config8888 swap_config8888_red_and_blue(SkCanvas::Config8888 config8888) {
1163    switch (config8888) {
1164        case SkCanvas::kBGRA_Premul_Config8888:
1165            return SkCanvas::kRGBA_Premul_Config8888;
1166        case SkCanvas::kBGRA_Unpremul_Config8888:
1167            return SkCanvas::kRGBA_Unpremul_Config8888;
1168        case SkCanvas::kRGBA_Premul_Config8888:
1169            return SkCanvas::kBGRA_Premul_Config8888;
1170        case SkCanvas::kRGBA_Unpremul_Config8888:
1171            return SkCanvas::kBGRA_Unpremul_Config8888;
1172        default:
1173            GrCrash("Unexpected input");
1174            return SkCanvas::kBGRA_Unpremul_Config8888;;
1175    }
1176}
1177}
1178
1179bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1180                                       int left, int top, int width, int height,
1181                                       GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
1182                                       uint32_t flags) {
1183    SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
1184    ASSERT_OWNED_RESOURCE(target);
1185
1186    if (NULL == target) {
1187        target = fDrawState->getRenderTarget();
1188        if (NULL == target) {
1189            return false;
1190        }
1191    }
1192
1193    if (!(kDontFlush_PixelOpsFlag & flags)) {
1194        this->flush();
1195    }
1196
1197    // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
1198
1199    // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1200    // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1201    bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
1202                                                 width, height, dstConfig,
1203                                                 rowBytes);
1204    // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1205    // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1206    // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1207    // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1208    // dstConfig.
1209    GrPixelConfig readConfig = dstConfig;
1210    bool swapRAndB = false;
1211    if (GrPixelConfigSwapRAndB(dstConfig) == fGpu->preferredReadPixelsConfig(dstConfig)) {
1212        readConfig = GrPixelConfigSwapRAndB(readConfig);
1213        swapRAndB = true;
1214    }
1215
1216    bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
1217
1218    if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
1219        // The unpremul flag is only allowed for these two configs.
1220        return false;
1221    }
1222
1223    // If the src is a texture and we would have to do conversions after read pixels, we instead
1224    // do the conversions by drawing the src to a scratch texture. If we handle any of the
1225    // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1226    // on the read back pixels.
1227    GrTexture* src = target->asTexture();
1228    GrAutoScratchTexture ast;
1229    if (NULL != src && (swapRAndB || unpremul || flipY)) {
1230        // Make the scratch a render target because we don't have a robust readTexturePixels as of
1231        // yet. It calls this function.
1232        GrTextureDesc desc;
1233        desc.fFlags = kRenderTarget_GrTextureFlagBit;
1234        desc.fWidth = width;
1235        desc.fHeight = height;
1236        desc.fConfig = readConfig;
1237        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1238
1239        // When a full read back is faster than a partial we could always make the scratch exactly
1240        // match the passed rect. However, if we see many different size rectangles we will trash
1241        // our texture cache and pay the cost of creating and destroying many textures. So, we only
1242        // request an exact match when the caller is reading an entire RT.
1243        ScratchTexMatch match = kApprox_ScratchTexMatch;
1244        if (0 == left &&
1245            0 == top &&
1246            target->width() == width &&
1247            target->height() == height &&
1248            fGpu->fullReadPixelsIsFasterThanPartial()) {
1249            match = kExact_ScratchTexMatch;
1250        }
1251        ast.set(this, desc, match);
1252        GrTexture* texture = ast.texture();
1253        if (texture) {
1254            // compute a matrix to perform the draw
1255            SkMatrix textureMatrix;
1256            textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1257            textureMatrix.postIDiv(src->width(), src->height());
1258
1259            SkAutoTUnref<const GrEffectRef> effect;
1260            if (unpremul) {
1261                effect.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1262                if (NULL != effect) {
1263                    unpremul = false; // we no longer need to do this on CPU after the read back.
1264                }
1265            }
1266            // If we failed to create a PM->UPM effect and have no other conversions to perform then
1267            // there is no longer any point to using the scratch.
1268            if (NULL != effect || flipY || swapRAndB) {
1269                if (!effect) {
1270                    effect.reset(GrConfigConversionEffect::Create(
1271                                                    src,
1272                                                    swapRAndB,
1273                                                    GrConfigConversionEffect::kNone_PMConversion,
1274                                                    textureMatrix));
1275                }
1276                swapRAndB = false; // we will handle the swap in the draw.
1277
1278                // We protect the existing geometry here since it may not be
1279                // clear to the caller that a draw operation (i.e., drawSimpleRect)
1280                // can be invoked in this method
1281                GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
1282                GrDrawState* drawState = fGpu->drawState();
1283                GrAssert(effect);
1284                drawState->setEffect(0, effect);
1285
1286                drawState->setRenderTarget(texture->asRenderTarget());
1287                GrRect rect = GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1288                fGpu->drawSimpleRect(rect, NULL);
1289                // we want to read back from the scratch's origin
1290                left = 0;
1291                top = 0;
1292                target = texture->asRenderTarget();
1293            }
1294        }
1295    }
1296    if (!fGpu->readPixels(target,
1297                          left, top, width, height,
1298                          readConfig, buffer, rowBytes)) {
1299        return false;
1300    }
1301    // Perform any conversions we weren't able to perform using a scratch texture.
1302    if (unpremul || swapRAndB) {
1303        // These are initialized to suppress a warning
1304        SkCanvas::Config8888 srcC8888 = SkCanvas::kNative_Premul_Config8888;
1305        SkCanvas::Config8888 dstC8888 = SkCanvas::kNative_Premul_Config8888;
1306
1307        SkDEBUGCODE(bool c8888IsValid =) grconfig_to_config8888(dstConfig, false, &srcC8888);
1308        grconfig_to_config8888(dstConfig, unpremul, &dstC8888);
1309
1310        if (swapRAndB) {
1311            GrAssert(c8888IsValid); // we should only do r/b swap on 8888 configs
1312            srcC8888 = swap_config8888_red_and_blue(srcC8888);
1313        }
1314        GrAssert(c8888IsValid);
1315        uint32_t* b32 = reinterpret_cast<uint32_t*>(buffer);
1316        SkConvertConfig8888Pixels(b32, rowBytes, dstC8888,
1317                                  b32, rowBytes, srcC8888,
1318                                  width, height);
1319    }
1320    return true;
1321}
1322
1323void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1324    GrAssert(target);
1325    ASSERT_OWNED_RESOURCE(target);
1326    // In the future we may track whether there are any pending draws to this
1327    // target. We don't today so we always perform a flush. We don't promise
1328    // this to our clients, though.
1329    this->flush();
1330    fGpu->resolveRenderTarget(target);
1331}
1332
1333void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) {
1334    if (NULL == src || NULL == dst) {
1335        return;
1336    }
1337    ASSERT_OWNED_RESOURCE(src);
1338
1339    // Writes pending to the source texture are not tracked, so a flush
1340    // is required to ensure that the copy captures the most recent contents
1341    // of the source texture. See similar behavior in
1342    // GrContext::resolveRenderTarget.
1343    this->flush();
1344
1345    GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
1346    GrDrawState* drawState = fGpu->drawState();
1347    drawState->setRenderTarget(dst);
1348    SkMatrix sampleM;
1349    sampleM.setIDiv(src->width(), src->height());
1350    SkIRect srcRect = SkIRect::MakeWH(dst->width(), dst->height());
1351    if (NULL != topLeft) {
1352        srcRect.offset(*topLeft);
1353    }
1354    SkIRect srcBounds = SkIRect::MakeWH(src->width(), src->height());
1355    if (!srcRect.intersect(srcBounds)) {
1356        return;
1357    }
1358    sampleM.preTranslate(SkIntToScalar(srcRect.fLeft), SkIntToScalar(srcRect.fTop));
1359    drawState->createTextureEffect(0, src, sampleM);
1360    SkRect dstR = SkRect::MakeWH(SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height()));
1361    fGpu->drawSimpleRect(dstR, NULL);
1362}
1363
1364bool GrContext::writeRenderTargetPixels(GrRenderTarget* target,
1365                                        int left, int top, int width, int height,
1366                                        GrPixelConfig srcConfig,
1367                                        const void* buffer,
1368                                        size_t rowBytes,
1369                                        uint32_t flags) {
1370    SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
1371    ASSERT_OWNED_RESOURCE(target);
1372
1373    if (NULL == target) {
1374        target = fDrawState->getRenderTarget();
1375        if (NULL == target) {
1376            return false;
1377        }
1378    }
1379
1380    // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on
1381    // desktop GL).
1382
1383    // We will always call some form of writeTexturePixels and we will pass our flags on to it.
1384    // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't
1385    // set.)
1386
1387    // If the RT is also a texture and we don't have to premultiply then take the texture path.
1388    // We expect to be at least as fast or faster since it doesn't use an intermediate texture as
1389    // we do below.
1390
1391#if !GR_MAC_BUILD
1392    // At least some drivers on the Mac get confused when glTexImage2D is called on a texture
1393    // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or
1394    // HW is affected.
1395    if (NULL != target->asTexture() && !(kUnpremul_PixelOpsFlag & flags) &&
1396        fGpu->canWriteTexturePixels(target->asTexture(), srcConfig)) {
1397        return this->writeTexturePixels(target->asTexture(),
1398                                        left, top, width, height,
1399                                        srcConfig, buffer, rowBytes, flags);
1400    }
1401#endif
1402
1403    // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1404    // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1405    // config. This scratch will then have R and B swapped. We correct for this by swapping again
1406    // when drawing the scratch to the dst using a conversion effect.
1407    bool swapRAndB = false;
1408    GrPixelConfig writeConfig = srcConfig;
1409    if (fGpu->preferredWritePixelsConfig(srcConfig) == GrPixelConfigSwapRAndB(srcConfig)) {
1410        writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1411        swapRAndB = true;
1412    }
1413
1414    GrTextureDesc desc;
1415    desc.fWidth = width;
1416    desc.fHeight = height;
1417    desc.fConfig = writeConfig;
1418    GrAutoScratchTexture ast(this, desc);
1419    GrTexture* texture = ast.texture();
1420    if (NULL == texture) {
1421        return false;
1422    }
1423
1424    SkAutoTUnref<const GrEffectRef> effect;
1425    SkMatrix textureMatrix;
1426    textureMatrix.setIDiv(texture->width(), texture->height());
1427
1428    // allocate a tmp buffer and sw convert the pixels to premul
1429    SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1430
1431    if (kUnpremul_PixelOpsFlag & flags) {
1432        if (!GrPixelConfigIs8888(srcConfig)) {
1433            return false;
1434        }
1435        effect.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1436        // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1437        if (NULL == effect) {
1438            SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1439            GR_DEBUGCODE(bool success = )
1440            grconfig_to_config8888(srcConfig, true, &srcConfig8888);
1441            GrAssert(success);
1442            GR_DEBUGCODE(success = )
1443            grconfig_to_config8888(srcConfig, false, &dstConfig8888);
1444            GrAssert(success);
1445            const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1446            tmpPixels.reset(width * height);
1447            SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1448                                      src, rowBytes, srcConfig8888,
1449                                      width, height);
1450            buffer = tmpPixels.get();
1451            rowBytes = 4 * width;
1452        }
1453    }
1454    if (NULL == effect) {
1455        effect.reset(GrConfigConversionEffect::Create(texture,
1456                                                      swapRAndB,
1457                                                      GrConfigConversionEffect::kNone_PMConversion,
1458                                                      textureMatrix));
1459    }
1460
1461    if (!this->writeTexturePixels(texture,
1462                                  0, 0, width, height,
1463                                  writeConfig, buffer, rowBytes,
1464                                  flags & ~kUnpremul_PixelOpsFlag)) {
1465        return false;
1466    }
1467
1468    // writeRenderTargetPixels can be called in the midst of drawing another
1469    // object (e.g., when uploading a SW path rendering to the gpu while
1470    // drawing a rect) so preserve the current geometry.
1471    GrDrawTarget::AutoGeometryAndStatePush agasp(fGpu, GrDrawTarget::kReset_ASRInit);
1472    GrDrawState* drawState = fGpu->drawState();
1473    GrAssert(effect);
1474    drawState->setEffect(0, effect);
1475
1476    SkMatrix matrix;
1477    matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1478    drawState->setViewMatrix(matrix);
1479    drawState->setRenderTarget(target);
1480
1481    fGpu->drawSimpleRect(GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), NULL);
1482    return true;
1483}
1484////////////////////////////////////////////////////////////////////////////////
1485
1486GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, BufferedDraw buffered) {
1487    if (kNo_BufferedDraw == buffered && kYes_BufferedDraw == fLastDrawWasBuffered) {
1488        this->flushDrawBuffer();
1489        fLastDrawWasBuffered = kNo_BufferedDraw;
1490    }
1491    if (NULL != paint) {
1492        GrAssert(fDrawState->stagesDisabled());
1493        fDrawState->setFromPaint(*paint);
1494#if GR_DEBUG_PARTIAL_COVERAGE_CHECK
1495        if ((paint->hasMask() || 0xff != paint->fCoverage) &&
1496            !fGpu->canApplyCoverage()) {
1497            GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1498        }
1499#endif
1500    }
1501    if (kYes_BufferedDraw == buffered) {
1502        fDrawBuffer->setClip(fGpu->getClip());
1503        fLastDrawWasBuffered = kYes_BufferedDraw;
1504        return fDrawBuffer;
1505    } else {
1506        GrAssert(kNo_BufferedDraw == buffered);
1507        return fGpu;
1508    }
1509}
1510
1511/*
1512 * This method finds a path renderer that can draw the specified path on
1513 * the provided target.
1514 * Due to its expense, the software path renderer has split out so it can
1515 * can be individually allowed/disallowed via the "allowSW" boolean.
1516 */
1517GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
1518                                           const SkStrokeRec& stroke,
1519                                           const GrDrawTarget* target,
1520                                           bool allowSW,
1521                                           GrPathRendererChain::DrawType drawType,
1522                                           GrPathRendererChain::StencilSupport* stencilSupport) {
1523
1524    if (NULL == fPathRendererChain) {
1525        fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
1526    }
1527
1528    GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
1529                                                             stroke,
1530                                                             target,
1531                                                             drawType,
1532                                                             stencilSupport);
1533
1534    if (NULL == pr && allowSW) {
1535        if (NULL == fSoftwarePathRenderer) {
1536            fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
1537        }
1538        pr = fSoftwarePathRenderer;
1539    }
1540
1541    return pr;
1542}
1543
1544////////////////////////////////////////////////////////////////////////////////
1545
1546void GrContext::setRenderTarget(GrRenderTarget* target) {
1547    ASSERT_OWNED_RESOURCE(target);
1548    fDrawState->setRenderTarget(target);
1549}
1550
1551GrRenderTarget* GrContext::getRenderTarget() {
1552    return fDrawState->getRenderTarget();
1553}
1554
1555const GrRenderTarget* GrContext::getRenderTarget() const {
1556    return fDrawState->getRenderTarget();
1557}
1558
1559bool GrContext::isConfigRenderable(GrPixelConfig config) const {
1560    return fGpu->isConfigRenderable(config);
1561}
1562
1563const SkMatrix& GrContext::getMatrix() const {
1564    return fDrawState->getViewMatrix();
1565}
1566
1567void GrContext::setMatrix(const SkMatrix& m) {
1568    fDrawState->setViewMatrix(m);
1569}
1570
1571void GrContext::setIdentityMatrix() {
1572    fDrawState->viewMatrix()->reset();
1573}
1574
1575void GrContext::concatMatrix(const SkMatrix& m) const {
1576    fDrawState->preConcatViewMatrix(m);
1577}
1578
1579static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1580    intptr_t mask = 1 << shift;
1581    if (pred) {
1582        bits |= mask;
1583    } else {
1584        bits &= ~mask;
1585    }
1586    return bits;
1587}
1588
1589void GrContext::setupDrawBuffer() {
1590
1591    GrAssert(NULL == fDrawBuffer);
1592    GrAssert(NULL == fDrawBufferVBAllocPool);
1593    GrAssert(NULL == fDrawBufferIBAllocPool);
1594
1595    fDrawBufferVBAllocPool =
1596        SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
1597                                    DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1598                                    DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
1599    fDrawBufferIBAllocPool =
1600        SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
1601                                   DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1602                                   DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
1603
1604    fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
1605                                                   fDrawBufferVBAllocPool,
1606                                                   fDrawBufferIBAllocPool));
1607
1608    fDrawBuffer->setDrawState(fDrawState);
1609}
1610
1611GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1612    return this->prepareToDraw(&paint, BUFFERED_DRAW);
1613}
1614
1615const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1616    return fGpu->getQuadIndexBuffer();
1617}
1618
1619namespace {
1620void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1621    GrConfigConversionEffect::PMConversion pmToUPM;
1622    GrConfigConversionEffect::PMConversion upmToPM;
1623    GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1624    *pmToUPMValue = pmToUPM;
1625    *upmToPMValue = upmToPM;
1626}
1627}
1628
1629const GrEffectRef* GrContext::createPMToUPMEffect(GrTexture* texture,
1630                                                  bool swapRAndB,
1631                                                  const SkMatrix& matrix) {
1632    if (!fDidTestPMConversions) {
1633        test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1634        fDidTestPMConversions = true;
1635    }
1636    GrConfigConversionEffect::PMConversion pmToUPM =
1637        static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1638    if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
1639        return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
1640    } else {
1641        return NULL;
1642    }
1643}
1644
1645const GrEffectRef* GrContext::createUPMToPMEffect(GrTexture* texture,
1646                                                  bool swapRAndB,
1647                                                  const SkMatrix& matrix) {
1648    if (!fDidTestPMConversions) {
1649        test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1650        fDidTestPMConversions = true;
1651    }
1652    GrConfigConversionEffect::PMConversion upmToPM =
1653        static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1654    if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
1655        return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
1656    } else {
1657        return NULL;
1658    }
1659}
1660
1661GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture,
1662                                   bool canClobberSrc,
1663                                   const SkRect& rect,
1664                                   float sigmaX, float sigmaY) {
1665    ASSERT_OWNED_RESOURCE(srcTexture);
1666
1667    AutoRenderTarget art(this);
1668
1669    AutoMatrix am;
1670    am.setIdentity(this);
1671
1672    SkIRect clearRect;
1673    int scaleFactorX, radiusX;
1674    int scaleFactorY, radiusY;
1675    sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX);
1676    sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY);
1677
1678    SkRect srcRect(rect);
1679    scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
1680    srcRect.roundOut();
1681    scale_rect(&srcRect, static_cast<float>(scaleFactorX),
1682                         static_cast<float>(scaleFactorY));
1683
1684    AutoClip acs(this, srcRect);
1685
1686    GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() ||
1687             kRGBA_8888_GrPixelConfig == srcTexture->config() ||
1688             kAlpha_8_GrPixelConfig == srcTexture->config());
1689
1690    GrTextureDesc desc;
1691    desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
1692    desc.fWidth = SkScalarFloorToInt(srcRect.width());
1693    desc.fHeight = SkScalarFloorToInt(srcRect.height());
1694    desc.fConfig = srcTexture->config();
1695
1696    GrAutoScratchTexture temp1, temp2;
1697    GrTexture* dstTexture = temp1.set(this, desc);
1698    GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(this, desc);
1699    if (NULL == dstTexture || NULL == tempTexture) {
1700        return NULL;
1701    }
1702
1703    GrPaint paint;
1704    paint.reset();
1705
1706    for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
1707        SkMatrix matrix;
1708        matrix.setIDiv(srcTexture->width(), srcTexture->height());
1709        this->setRenderTarget(dstTexture->asRenderTarget());
1710        SkRect dstRect(srcRect);
1711        scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
1712                             i < scaleFactorY ? 0.5f : 1.0f);
1713
1714        paint.colorStage(0)->setEffect(GrSimpleTextureEffect::Create(srcTexture,
1715                                                                     matrix,
1716                                                                     true))->unref();
1717        this->drawRectToRect(paint, dstRect, srcRect);
1718        srcRect = dstRect;
1719        srcTexture = dstTexture;
1720        SkTSwap(dstTexture, tempTexture);
1721    }
1722
1723    SkIRect srcIRect;
1724    srcRect.roundOut(&srcIRect);
1725
1726    if (sigmaX > 0.0f) {
1727        if (scaleFactorX > 1) {
1728            // Clear out a radius to the right of the srcRect to prevent the
1729            // X convolution from reading garbage.
1730            clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
1731                                          radiusX, srcIRect.height());
1732            this->clear(&clearRect, 0x0);
1733        }
1734
1735        this->setRenderTarget(dstTexture->asRenderTarget());
1736        GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW);
1737        convolve_gaussian(target, srcTexture, srcRect, sigmaX, radiusX,
1738                          Gr1DKernelEffect::kX_Direction);
1739        srcTexture = dstTexture;
1740        SkTSwap(dstTexture, tempTexture);
1741    }
1742
1743    if (sigmaY > 0.0f) {
1744        if (scaleFactorY > 1 || sigmaX > 0.0f) {
1745            // Clear out a radius below the srcRect to prevent the Y
1746            // convolution from reading garbage.
1747            clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
1748                                          srcIRect.width(), radiusY);
1749            this->clear(&clearRect, 0x0);
1750        }
1751
1752        this->setRenderTarget(dstTexture->asRenderTarget());
1753        GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW);
1754        convolve_gaussian(target, srcTexture, srcRect, sigmaY, radiusY,
1755                          Gr1DKernelEffect::kY_Direction);
1756        srcTexture = dstTexture;
1757        SkTSwap(dstTexture, tempTexture);
1758    }
1759
1760    if (scaleFactorX > 1 || scaleFactorY > 1) {
1761        // Clear one pixel to the right and below, to accommodate bilinear
1762        // upsampling.
1763        clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
1764                                      srcIRect.width() + 1, 1);
1765        this->clear(&clearRect, 0x0);
1766        clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
1767                                      1, srcIRect.height());
1768        this->clear(&clearRect, 0x0);
1769        SkMatrix matrix;
1770        // FIXME:  This should be mitchell, not bilinear.
1771        matrix.setIDiv(srcTexture->width(), srcTexture->height());
1772        this->setRenderTarget(dstTexture->asRenderTarget());
1773        paint.colorStage(0)->setEffect(GrSimpleTextureEffect::Create(srcTexture,
1774                                                                     matrix,
1775                                                                     true))->unref();
1776        SkRect dstRect(srcRect);
1777        scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY);
1778        this->drawRectToRect(paint, dstRect, srcRect);
1779        srcRect = dstRect;
1780        srcTexture = dstTexture;
1781        SkTSwap(dstTexture, tempTexture);
1782    }
1783    if (srcTexture == temp1.texture()) {
1784        return temp1.detach();
1785    } else if (srcTexture == temp2.texture()) {
1786        return temp2.detach();
1787    } else {
1788        srcTexture->ref();
1789        return srcTexture;
1790    }
1791}
1792
1793///////////////////////////////////////////////////////////////////////////////
1794#if GR_CACHE_STATS
1795void GrContext::printCacheStats() const {
1796    fTextureCache->printStats();
1797}
1798#endif
1799