1/*
2    Copyright 2011 Google Inc.
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8         http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15 */
16
17#include "GrContext.h"
18#include "GrGpu.h"
19#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
22#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
27
28// larger than this, and we don't AA. set to 0 for no AA
29#ifndef GR_MAX_OFFSCREEN_AA_DIM
30    #define GR_MAX_OFFSCREEN_AA_DIM    0
31#endif
32
33#define DEFER_TEXT_RENDERING 1
34
35#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
48GrContext* GrContext::Create(GrEngine engine,
49                             GrPlatform3DContext context3D) {
50    GrContext* ctx = NULL;
51    GrGpu* fGpu = GrGpu::Create(engine, context3D);
52    if (NULL != fGpu) {
53        ctx = new GrContext(fGpu);
54        fGpu->unref();
55    }
56    return ctx;
57}
58
59GrContext* GrContext::CreateGLShaderContext() {
60    return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
61}
62
63GrContext::~GrContext() {
64    this->flush();
65    delete fTextureCache;
66    delete fFontCache;
67    delete fDrawBuffer;
68    delete fDrawBufferVBAllocPool;
69    delete fDrawBufferIBAllocPool;
70    GrSafeUnref(fCustomPathRenderer);
71    GrSafeUnref(fAAFillRectIndexBuffer);
72    GrSafeUnref(fAAStrokeRectIndexBuffer);
73    fGpu->unref();
74}
75
76void GrContext::contextLost() {
77    contextDestroyed();
78    this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
82    // abandon first to so destructors
83    // don't try to free the resources in the API.
84    fGpu->abandonResources();
85
86    delete fDrawBuffer;
87    fDrawBuffer = NULL;
88
89    delete fDrawBufferVBAllocPool;
90    fDrawBufferVBAllocPool = NULL;
91
92    delete fDrawBufferIBAllocPool;
93    fDrawBufferIBAllocPool = NULL;
94
95    GrSafeSetNull(fAAFillRectIndexBuffer);
96    GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
98    fTextureCache->removeAll();
99    fFontCache->freeAll();
100    fGpu->markContextDirty();
101}
102
103void GrContext::resetContext() {
104    fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108    this->flush();
109    fTextureCache->removeAll();
110    fFontCache->freeAll();
111}
112
113////////////////////////////////////////////////////////////////////////////////
114
115int GrContext::PaintStageVertexLayoutBits(
116                            const GrPaint& paint,
117                            const bool hasTexCoords[GrPaint::kTotalStages]) {
118    int stageMask = paint.getActiveStageMask();
119    int layout = 0;
120    for (int i = 0; i < GrPaint::kTotalStages; ++i) {
121        if ((1 << i) & stageMask) {
122            if (NULL != hasTexCoords && hasTexCoords[i]) {
123                layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
124            } else {
125                layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
126            }
127        }
128    }
129    return layout;
130}
131
132
133////////////////////////////////////////////////////////////////////////////////
134
135enum {
136    kNPOTBit    = 0x1,
137    kFilterBit  = 0x2,
138    kKeylessBit = 0x4,
139};
140
141bool GrContext::finalizeTextureKey(GrTextureKey* key,
142                                   const GrSamplerState& sampler,
143                                   bool keyless) const {
144    uint32_t bits = 0;
145    uint16_t width = key->width();
146    uint16_t height = key->height();
147
148    if (!fGpu->npotTextureTileSupport()) {
149        bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
150
151        bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
152                     (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
153
154        if (tiled && !isPow2) {
155            bits |= kNPOTBit;
156            if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
157                bits |= kFilterBit;
158            }
159        }
160    }
161
162    if (keyless) {
163        bits |= kKeylessBit;
164    }
165    key->finalize(bits);
166    return 0 != bits;
167}
168
169GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170                                              const GrSamplerState& sampler) {
171    finalizeTextureKey(key, sampler, false);
172    return fTextureCache->findAndLock(*key);
173}
174
175static void stretchImage(void* dst,
176                         int dstW,
177                         int dstH,
178                         void* src,
179                         int srcW,
180                         int srcH,
181                         int bpp) {
182    GrFixed dx = (srcW << 16) / dstW;
183    GrFixed dy = (srcH << 16) / dstH;
184
185    GrFixed y = dy >> 1;
186
187    int dstXLimit = dstW*bpp;
188    for (int j = 0; j < dstH; ++j) {
189        GrFixed x = dx >> 1;
190        void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
191        void* dstRow = (uint8_t*)dst + j*dstW*bpp;
192        for (int i = 0; i < dstXLimit; i += bpp) {
193            memcpy((uint8_t*) dstRow + i,
194                   (uint8_t*) srcRow + (x>>16)*bpp,
195                   bpp);
196            x += dx;
197        }
198        y += dy;
199    }
200}
201
202GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
203                                                const GrSamplerState& sampler,
204                                                const GrTextureDesc& desc,
205                                                void* srcData, size_t rowBytes) {
206    GrAssert(key->width() == desc.fWidth);
207    GrAssert(key->height() == desc.fHeight);
208
209#if GR_DUMP_TEXTURE_UPLOAD
210    GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
211#endif
212
213    GrTextureEntry* entry = NULL;
214    bool special = finalizeTextureKey(key, sampler, false);
215    if (special) {
216        GrTextureEntry* clampEntry;
217        GrTextureKey clampKey(*key);
218        clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
219
220        if (NULL == clampEntry) {
221            clampEntry = createAndLockTexture(&clampKey,
222                                              GrSamplerState::ClampNoFilter(),
223                                              desc, srcData, rowBytes);
224            GrAssert(NULL != clampEntry);
225            if (NULL == clampEntry) {
226                return NULL;
227            }
228        }
229        GrTextureDesc rtDesc = desc;
230        rtDesc.fFlags =  rtDesc.fFlags |
231                         kRenderTarget_GrTextureFlagBit |
232                         kNoStencil_GrTextureFlagBit;
233        rtDesc.fWidth  = GrNextPow2(GrMax<int>(desc.fWidth,
234                                               fGpu->minRenderTargetWidth()));
235        rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
236                                               fGpu->minRenderTargetHeight()));
237
238        GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
239
240        if (NULL != texture) {
241            GrDrawTarget::AutoStateRestore asr(fGpu);
242            fGpu->setRenderTarget(texture->asRenderTarget());
243            fGpu->setTexture(0, clampEntry->texture());
244            fGpu->disableStencil();
245            fGpu->setViewMatrix(GrMatrix::I());
246            fGpu->setAlpha(0xff);
247            fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
248            fGpu->disableState(GrDrawTarget::kDither_StateBit |
249                               GrDrawTarget::kClip_StateBit   |
250                               GrDrawTarget::kAntialias_StateBit);
251            GrSamplerState::Filter filter;
252            // if filtering is not desired then we want to ensure all
253            // texels in the resampled image are copies of texels from
254            // the original.
255            if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
256                filter = GrSamplerState::kNearest_Filter;
257            } else {
258                filter = GrSamplerState::kBilinear_Filter;
259            }
260            GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
261                                          GrSamplerState::kClamp_WrapMode,
262                                          filter);
263            fGpu->setSamplerState(0, stretchSampler);
264
265            static const GrVertexLayout layout =
266                                GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
267            GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
268
269            if (arg.succeeded()) {
270                GrPoint* verts = (GrPoint*) arg.vertices();
271                verts[0].setIRectFan(0, 0,
272                                     texture->width(),
273                                     texture->height(),
274                                     2*sizeof(GrPoint));
275                verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
276                fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
277                                     0, 4);
278                entry = fTextureCache->createAndLock(*key, texture);
279            }
280            texture->releaseRenderTarget();
281        } else {
282            // TODO: Our CPU stretch doesn't filter. But we create separate
283            // stretched textures when the sampler state is either filtered or
284            // not. Either implement filtered stretch blit on CPU or just create
285            // one when FBO case fails.
286
287            rtDesc.fFlags = kNone_GrTextureFlags;
288            // no longer need to clamp at min RT size.
289            rtDesc.fWidth  = GrNextPow2(desc.fWidth);
290            rtDesc.fHeight = GrNextPow2(desc.fHeight);
291            int bpp = GrBytesPerPixel(desc.fFormat);
292            GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
293                                                     rtDesc.fWidth *
294                                                     rtDesc.fHeight);
295            stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
296                         srcData, desc.fWidth, desc.fHeight, bpp);
297
298            size_t stretchedRowBytes = rtDesc.fWidth * bpp;
299
300            GrTexture* texture = fGpu->createTexture(rtDesc,
301                                                     stretchedPixels.get(),
302                                                     stretchedRowBytes);
303            GrAssert(NULL != texture);
304            entry = fTextureCache->createAndLock(*key, texture);
305        }
306        fTextureCache->unlock(clampEntry);
307
308    } else {
309        GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
310        if (NULL != texture) {
311            entry = fTextureCache->createAndLock(*key, texture);
312        } else {
313            entry = NULL;
314        }
315    }
316    return entry;
317}
318
319GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
320    uint32_t p0 = desc.fFormat;
321    uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
322    GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
323    this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
324
325    GrTextureEntry* entry = fTextureCache->findAndLock(key);
326    if (NULL == entry) {
327        GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
328        if (NULL != texture) {
329            entry = fTextureCache->createAndLock(key, texture);
330        }
331    }
332    // If the caller gives us the same desc/sampler twice we don't want
333    // to return the same texture the second time (unless it was previously
334    // released). So we detach the entry from the cache and reattach at release.
335    if (NULL != entry) {
336        fTextureCache->detach(entry);
337    }
338    return entry;
339}
340
341void GrContext::unlockTexture(GrTextureEntry* entry) {
342    if (kKeylessBit & entry->key().getPrivateBits()) {
343        fTextureCache->reattachAndUnlock(entry);
344    } else {
345        fTextureCache->unlock(entry);
346    }
347}
348
349GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
350                                            void* srcData,
351                                            size_t rowBytes) {
352    return fGpu->createTexture(desc, srcData, rowBytes);
353}
354
355void GrContext::getTextureCacheLimits(int* maxTextures,
356                                      size_t* maxTextureBytes) const {
357    fTextureCache->getLimits(maxTextures, maxTextureBytes);
358}
359
360void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
361    fTextureCache->setLimits(maxTextures, maxTextureBytes);
362}
363
364int GrContext::getMaxTextureDimension() {
365    return fGpu->maxTextureDimension();
366}
367
368///////////////////////////////////////////////////////////////////////////////
369
370GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
371    // validate flags here so that GrGpu subclasses don't have to check
372    if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
373        0 != desc.fRenderTargetFlags) {
374            return NULL;
375    }
376    if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
377        (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
378            return NULL;
379    }
380    if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
381        (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
382        !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
383        return NULL;
384    }
385    return fGpu->createPlatformSurface(desc);
386}
387
388GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
389    return fGpu->createRenderTargetFrom3DApiState();
390}
391
392///////////////////////////////////////////////////////////////////////////////
393
394bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
395                                          int width, int height) {
396    if (!fGpu->supports8BitPalette()) {
397        return false;
398    }
399
400
401    bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
402
403    if (!isPow2) {
404        if (!fGpu->npotTextureSupport()) {
405            return false;
406        }
407
408        bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
409                     sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
410        if (tiled && !fGpu->npotTextureTileSupport()) {
411            return false;
412        }
413    }
414    return true;
415}
416
417////////////////////////////////////////////////////////////////////////////////
418
419const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
420
421void GrContext::setClip(const GrClip& clip) {
422    fGpu->setClip(clip);
423    fGpu->enableState(GrDrawTarget::kClip_StateBit);
424}
425
426void GrContext::setClip(const GrIRect& rect) {
427    GrClip clip;
428    clip.setFromIRect(rect);
429    fGpu->setClip(clip);
430}
431
432////////////////////////////////////////////////////////////////////////////////
433
434void GrContext::clear(const GrIRect* rect, const GrColor color) {
435    this->flush();
436    fGpu->clear(rect, color);
437}
438
439void GrContext::drawPaint(const GrPaint& paint) {
440    // set rect to be big enough to fill the space, but not super-huge, so we
441    // don't overflow fixed-point implementations
442    GrRect r;
443    r.setLTRB(0, 0,
444              GrIntToScalar(getRenderTarget()->width()),
445              GrIntToScalar(getRenderTarget()->height()));
446    GrMatrix inverse;
447    if (fGpu->getViewInverse(&inverse)) {
448        inverse.mapRect(&r);
449    } else {
450        GrPrintf("---- fGpu->getViewInverse failed\n");
451    }
452    this->drawRect(paint, r);
453}
454
455////////////////////////////////////////////////////////////////////////////////
456
457bool GrContext::doOffscreenAA(GrDrawTarget* target,
458                              const GrPaint& paint,
459                              bool isLines) const {
460#if GR_MAX_OFFSCREEN_AA_DIM==0
461    return false;
462#else
463    if (!paint.fAntiAlias) {
464        return false;
465    }
466    if (isLines && fGpu->supportsAALines()) {
467        return false;
468    }
469    if (target->getRenderTarget()->isMultisampled()) {
470        return false;
471    }
472    // we have to be sure that the blend equation is expressible
473    // as simple src / dst coeffecients when the source
474    // is already modulated by the coverage fraction.
475    // We could use dual-source blending to get the correct per-pixel
476    // dst coeffecient for the remaining cases.
477    if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
478        kOne_BlendCoeff != paint.fDstBlendCoeff &&
479        kISA_BlendCoeff != paint.fDstBlendCoeff) {
480        return false;
481    }
482    return true;
483#endif
484}
485
486bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
487                                      bool requireStencil,
488                                      const GrIRect& boundRect,
489                                      OffscreenRecord* record) {
490    GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0);
491
492    GrAssert(NULL == record->fEntry0);
493    GrAssert(NULL == record->fEntry1);
494
495    int boundW = boundRect.width();
496    int boundH = boundRect.height();
497    int size  = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
498
499    GrTextureDesc desc;
500    if (requireStencil) {
501        desc.fFlags = kRenderTarget_GrTextureFlagBit;
502    } else {
503        desc.fFlags = kRenderTarget_GrTextureFlagBit |
504                      kNoStencil_GrTextureFlagBit;
505    }
506
507    desc.fFormat = kRGBA_8888_GrPixelConfig;
508
509    int scale;
510    // Using MSAA seems to be slower for some yet unknown reason.
511    if (false && fGpu->supportsFullsceneAA()) {
512        record->fDownsample = OffscreenRecord::kFSAA_Downsample;
513        scale = GR_Scalar1;
514        desc.fAALevel = kMed_GrAALevel;
515    } else {
516        record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
517                                OffscreenRecord::k4x4SinglePass_Downsample :
518                                OffscreenRecord::k4x4TwoPass_Downsample;
519        scale = 4;
520        desc.fAALevel = kNone_GrAALevel;
521    }
522
523    desc.fWidth = scale * size;
524    desc.fHeight = scale * size;
525
526    record->fEntry0 = this->lockKeylessTexture(desc);
527
528    if (NULL == record->fEntry0) {
529        return false;
530    }
531
532    if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
533        desc.fWidth /= 2;
534        desc.fHeight /= 2;
535        record->fEntry1 = this->lockKeylessTexture(desc);
536        if (NULL == record->fEntry1) {
537            this->unlockTexture(record->fEntry0);
538            record->fEntry0 = NULL;
539            return false;
540        }
541    }
542
543    GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
544    GrAssert(NULL != offRT0);
545
546    target->saveCurrentDrawState(&record->fSavedState);
547
548    GrPaint tempPaint;
549    tempPaint.reset();
550    SetPaint(tempPaint, target);
551    target->setRenderTarget(offRT0);
552
553    GrMatrix transM;
554    transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
555    target->postConcatViewMatrix(transM);
556    GrMatrix scaleM;
557    scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
558    target->postConcatViewMatrix(scaleM);
559
560    // clip gets applied in second pass
561    target->disableState(GrDrawTarget::kClip_StateBit);
562
563    GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
564    target->clear(&clear, 0x0);
565
566    return true;
567}
568
569void GrContext::offscreenAAPass2(GrDrawTarget* target,
570                                 const GrPaint& paint,
571                                 const GrIRect& boundRect,
572                                 OffscreenRecord* record) {
573
574    GrAssert(NULL != record->fEntry0);
575
576    GrSamplerState::Filter filter;
577    if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
578        filter = GrSamplerState::k4x4Downsample_Filter;
579    } else {
580        filter = GrSamplerState::kBilinear_Filter;
581    }
582
583    GrMatrix sampleM;
584    GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
585                           GrSamplerState::kClamp_WrapMode, filter);
586
587    GrTexture* src = record->fEntry0->texture();
588    int scale;
589
590    enum {
591        kOffscreenStage = GrPaint::kTotalStages,
592    };
593
594    if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
595        GrAssert(NULL != record->fEntry1);
596        scale = 2;
597        GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
598
599        // Do 2x2 downsample from first to second
600        target->setTexture(kOffscreenStage, src);
601        target->setRenderTarget(dst);
602        target->setViewMatrix(GrMatrix::I());
603        sampleM.setScale(scale * GR_Scalar1 / src->width(),
604                         scale * GR_Scalar1 / src->height());
605        sampler.setMatrix(sampleM);
606        target->setSamplerState(kOffscreenStage, sampler);
607        GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
608                                     scale * boundRect.height());
609        target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
610
611        src = record->fEntry1->texture();
612    } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
613        scale = 1;
614        GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
615        src->asRenderTarget()->overrideResolveRect(rect);
616    } else {
617        GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
618                 record->fDownsample);
619        scale = 4;
620    }
621
622    // setup for draw back to main RT
623    int stageMask = paint.getActiveStageMask();
624
625    target->restoreDrawState(record->fSavedState);
626
627    if (stageMask) {
628        GrMatrix invVM;
629        if (target->getViewInverse(&invVM)) {
630            target->preConcatSamplerMatrices(stageMask, invVM);
631        }
632    }
633    target->setViewMatrix(GrMatrix::I());
634
635    target->setTexture(kOffscreenStage, src);
636    sampleM.setScale(scale * GR_Scalar1 / src->width(),
637                     scale * GR_Scalar1 / src->height());
638    sampler.setMatrix(sampleM);
639    sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
640    sampler.preConcatMatrix(sampleM);
641    target->setSamplerState(kOffscreenStage, sampler);
642
643    GrRect dstRect;
644    int stages = (1 << kOffscreenStage) | stageMask;
645    dstRect.set(boundRect);
646    target->drawSimpleRect(dstRect, NULL, stages);
647
648    this->unlockTexture(record->fEntry0);
649    record->fEntry0 = NULL;
650    if (NULL != record->fEntry1) {
651        this->unlockTexture(record->fEntry1);
652        record->fEntry1 = NULL;
653    }
654    target->restoreDrawState(record->fSavedState);
655}
656
657////////////////////////////////////////////////////////////////////////////////
658
659/*  create a triangle strip that strokes the specified triangle. There are 8
660 unique vertices, but we repreat the last 2 to close up. Alternatively we
661 could use an indices array, and then only send 8 verts, but not sure that
662 would be faster.
663 */
664static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
665                               GrScalar width) {
666    const GrScalar rad = GrScalarHalf(width);
667    rect.sort();
668
669    verts[0].set(rect.fLeft + rad, rect.fTop + rad);
670    verts[1].set(rect.fLeft - rad, rect.fTop - rad);
671    verts[2].set(rect.fRight - rad, rect.fTop + rad);
672    verts[3].set(rect.fRight + rad, rect.fTop - rad);
673    verts[4].set(rect.fRight - rad, rect.fBottom - rad);
674    verts[5].set(rect.fRight + rad, rect.fBottom + rad);
675    verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
676    verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
677    verts[8] = verts[0];
678    verts[9] = verts[1];
679}
680
681static GrColor getColorForMesh(const GrPaint& paint) {
682    // FIXME: This was copied from SkGpuDevice, seems like
683    // we should have already smeared a in caller if that
684    // is what is desired.
685    if (paint.hasTexture()) {
686        unsigned a = GrColorUnpackA(paint.fColor);
687        return GrColorPackRGBA(a, a, a, a);
688    } else {
689        return paint.fColor;
690    }
691}
692
693static void setInsetFan(GrPoint* pts, size_t stride,
694                        const GrRect& r, GrScalar dx, GrScalar dy) {
695    pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
696}
697
698static const uint16_t gFillAARectIdx[] = {
699    0, 1, 5, 5, 4, 0,
700    1, 2, 6, 6, 5, 1,
701    2, 3, 7, 7, 6, 2,
702    3, 0, 4, 4, 7, 3,
703    4, 5, 6, 6, 7, 4,
704};
705
706int GrContext::aaFillRectIndexCount() const {
707    return GR_ARRAY_COUNT(gFillAARectIdx);
708}
709
710GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
711    if (NULL == fAAFillRectIndexBuffer) {
712        fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
713                                                         false);
714        GrAssert(NULL != fAAFillRectIndexBuffer);
715#if GR_DEBUG
716        bool updated =
717#endif
718        fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
719                                           sizeof(gFillAARectIdx));
720        GR_DEBUGASSERT(updated);
721    }
722    return fAAFillRectIndexBuffer;
723}
724
725static const uint16_t gStrokeAARectIdx[] = {
726    0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
727    1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
728    2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
729    3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
730
731    0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
732    1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
733    2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
734    3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
735
736    0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
737    1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
738    2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
739    3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
740};
741
742int GrContext::aaStrokeRectIndexCount() const {
743    return GR_ARRAY_COUNT(gStrokeAARectIdx);
744}
745
746GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
747    if (NULL == fAAStrokeRectIndexBuffer) {
748        fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
749                                                           false);
750        GrAssert(NULL != fAAStrokeRectIndexBuffer);
751#if GR_DEBUG
752        bool updated =
753#endif
754        fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
755                                             sizeof(gStrokeAARectIdx));
756        GR_DEBUGASSERT(updated);
757    }
758    return fAAStrokeRectIndexBuffer;
759}
760
761void GrContext::fillAARect(GrDrawTarget* target,
762                           const GrPaint& paint,
763                           const GrRect& devRect) {
764
765    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
766                            GrDrawTarget::kColor_VertexLayoutBit;
767
768    size_t vsize = GrDrawTarget::VertexSize(layout);
769
770    GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
771
772    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
773
774    GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
775    GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
776
777    setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
778    setInsetFan(fan1Pos, vsize, devRect,  GR_ScalarHalf,  GR_ScalarHalf);
779
780    verts += sizeof(GrPoint);
781    for (int i = 0; i < 4; ++i) {
782        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
783    }
784
785    GrColor innerColor = getColorForMesh(paint);
786    verts += 4 * vsize;
787    for (int i = 0; i < 4; ++i) {
788        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
789    }
790
791    target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
792
793    target->drawIndexed(kTriangles_PrimitiveType, 0,
794                         0, 8, this->aaFillRectIndexCount());
795}
796
797void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
798                             const GrRect& devRect, const GrVec& devStrokeSize) {
799    const GrScalar& dx = devStrokeSize.fX;
800    const GrScalar& dy = devStrokeSize.fY;
801    const GrScalar rx = GrMul(dx, GR_ScalarHalf);
802    const GrScalar ry = GrMul(dy, GR_ScalarHalf);
803
804    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
805                            GrDrawTarget::kColor_VertexLayoutBit;
806
807    GrScalar spare;
808    {
809        GrScalar w = devRect.width() - dx;
810        GrScalar h = devRect.height() - dy;
811        spare = GrMin(w, h);
812    }
813
814    if (spare <= 0) {
815        GrRect r(devRect);
816        r.inset(-rx, -ry);
817        fillAARect(target, paint, r);
818        return;
819    }
820
821    size_t vsize = GrDrawTarget::VertexSize(layout);
822
823    GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
824
825    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
826
827    GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
828    GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
829    GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
830    GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
831
832    setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
833    setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
834    setInsetFan(fan2Pos, vsize, devRect,  rx - GR_ScalarHalf,  ry - GR_ScalarHalf);
835    setInsetFan(fan3Pos, vsize, devRect,  rx + GR_ScalarHalf,  ry + GR_ScalarHalf);
836
837    verts += sizeof(GrPoint);
838    for (int i = 0; i < 4; ++i) {
839        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
840    }
841
842    GrColor innerColor = getColorForMesh(paint);
843    verts += 4 * vsize;
844    for (int i = 0; i < 8; ++i) {
845        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
846    }
847
848    verts += 8 * vsize;
849    for (int i = 0; i < 8; ++i) {
850        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
851    }
852
853    target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
854    target->drawIndexed(kTriangles_PrimitiveType,
855                        0, 0, 16, aaStrokeRectIndexCount());
856}
857
858/**
859 * Returns true if the rects edges are integer-aligned.
860 */
861static bool isIRect(const GrRect& r) {
862    return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
863           GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
864}
865
866static bool apply_aa_to_rect(GrDrawTarget* target,
867                             GrGpu* gpu,
868                             const GrPaint& paint,
869                             const GrRect& rect,
870                             GrScalar width,
871                             const GrMatrix* matrix,
872                             GrMatrix* combinedMatrix,
873                             GrRect* devRect) {
874    // we use a simple alpha ramp to do aa on axis-aligned rects
875    // do AA with alpha ramp if the caller requested AA, the rect
876    // will be axis-aligned,the render target is not
877    // multisampled, and the rect won't land on integer coords.
878
879    if (!paint.fAntiAlias) {
880        return false;
881    }
882
883    if (target->getRenderTarget()->isMultisampled()) {
884        return false;
885    }
886
887    if (0 == width && gpu->supportsAALines()) {
888        return false;
889    }
890
891    if (!target->getViewMatrix().preservesAxisAlignment()) {
892        return false;
893    }
894
895    if (NULL != matrix &&
896        !matrix->preservesAxisAlignment()) {
897        return false;
898    }
899
900    *combinedMatrix = target->getViewMatrix();
901    if (NULL != matrix) {
902        combinedMatrix->preConcat(*matrix);
903        GrAssert(combinedMatrix->preservesAxisAlignment());
904    }
905
906    combinedMatrix->mapRect(devRect, rect);
907    devRect->sort();
908
909    if (width < 0) {
910        return !isIRect(*devRect);
911    } else {
912        return true;
913    }
914}
915
916void GrContext::drawRect(const GrPaint& paint,
917                         const GrRect& rect,
918                         GrScalar width,
919                         const GrMatrix* matrix) {
920
921
922    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
923    int stageMask = paint.getActiveStageMask();
924
925    GrRect devRect = rect;
926    GrMatrix combinedMatrix;
927    bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
928                                 &combinedMatrix, &devRect);
929
930    if (doAA) {
931        GrDrawTarget::AutoViewMatrixRestore avm(target);
932        if (stageMask) {
933            GrMatrix inv;
934            if (combinedMatrix.invert(&inv)) {
935                target->preConcatSamplerMatrices(stageMask, inv);
936            }
937        }
938        target->setViewMatrix(GrMatrix::I());
939        if (width >= 0) {
940            GrVec strokeSize;;
941            if (width > 0) {
942                strokeSize.set(width, width);
943                combinedMatrix.mapVectors(&strokeSize, 1);
944                strokeSize.setAbs(strokeSize);
945            } else {
946                strokeSize.set(GR_Scalar1, GR_Scalar1);
947            }
948            strokeAARect(target, paint, devRect, strokeSize);
949        } else {
950            fillAARect(target, paint, devRect);
951        }
952        return;
953    }
954
955    if (width >= 0) {
956        // TODO: consider making static vertex buffers for these cases.
957        // Hairline could be done by just adding closing vertex to
958        // unitSquareVertexBuffer()
959        GrVertexLayout layout =  PaintStageVertexLayoutBits(paint, NULL);
960
961        static const int worstCaseVertCount = 10;
962        GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
963
964        if (!geo.succeeded()) {
965            return;
966        }
967
968        GrPrimitiveType primType;
969        int vertCount;
970        GrPoint* vertex = geo.positions();
971
972        if (width > 0) {
973            vertCount = 10;
974            primType = kTriangleStrip_PrimitiveType;
975            setStrokeRectStrip(vertex, rect, width);
976        } else {
977            // hairline
978            vertCount = 5;
979            primType = kLineStrip_PrimitiveType;
980            vertex[0].set(rect.fLeft, rect.fTop);
981            vertex[1].set(rect.fRight, rect.fTop);
982            vertex[2].set(rect.fRight, rect.fBottom);
983            vertex[3].set(rect.fLeft, rect.fBottom);
984            vertex[4].set(rect.fLeft, rect.fTop);
985        }
986
987        GrDrawTarget::AutoViewMatrixRestore avmr;
988        if (NULL != matrix) {
989            avmr.set(target);
990            target->preConcatViewMatrix(*matrix);
991            target->preConcatSamplerMatrices(stageMask, *matrix);
992        }
993
994        target->drawNonIndexed(primType, 0, vertCount);
995    } else {
996        #if GR_STATIC_RECT_VB
997            GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
998
999            target->setVertexSourceToBuffer(layout,
1000                                            fGpu->getUnitSquareVertexBuffer());
1001            GrDrawTarget::AutoViewMatrixRestore avmr(target);
1002            GrMatrix m;
1003            m.setAll(rect.width(),    0,             rect.fLeft,
1004                        0,            rect.height(), rect.fTop,
1005                        0,            0,             GrMatrix::I()[8]);
1006
1007            if (NULL != matrix) {
1008                m.postConcat(*matrix);
1009            }
1010
1011            target->preConcatViewMatrix(m);
1012            target->preConcatSamplerMatrices(stageMask, m);
1013
1014            target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1015        #else
1016            target->drawSimpleRect(rect, matrix, stageMask);
1017        #endif
1018    }
1019}
1020
1021void GrContext::drawRectToRect(const GrPaint& paint,
1022                               const GrRect& dstRect,
1023                               const GrRect& srcRect,
1024                               const GrMatrix* dstMatrix,
1025                               const GrMatrix* srcMatrix) {
1026
1027    // srcRect refers to paint's first texture
1028    if (NULL == paint.getTexture(0)) {
1029        drawRect(paint, dstRect, -1, dstMatrix);
1030        return;
1031    }
1032
1033    GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1034
1035#if GR_STATIC_RECT_VB
1036    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1037
1038    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1039    GrDrawTarget::AutoViewMatrixRestore avmr(target);
1040
1041    GrMatrix m;
1042
1043    m.setAll(dstRect.width(), 0,                dstRect.fLeft,
1044             0,               dstRect.height(), dstRect.fTop,
1045             0,               0,                GrMatrix::I()[8]);
1046    if (NULL != dstMatrix) {
1047        m.postConcat(*dstMatrix);
1048    }
1049    target->preConcatViewMatrix(m);
1050
1051    // srcRect refers to first stage
1052    int otherStageMask = paint.getActiveStageMask() &
1053                         (~(1 << GrPaint::kFirstTextureStage));
1054    if (otherStageMask) {
1055        target->preConcatSamplerMatrices(otherStageMask, m);
1056    }
1057
1058    m.setAll(srcRect.width(), 0,                srcRect.fLeft,
1059             0,               srcRect.height(), srcRect.fTop,
1060             0,               0,                GrMatrix::I()[8]);
1061    if (NULL != srcMatrix) {
1062        m.postConcat(*srcMatrix);
1063    }
1064    target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
1065
1066    target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1067    target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1068#else
1069
1070    GrDrawTarget* target;
1071#if BATCH_RECT_TO_RECT
1072    target = this->prepareToDraw(paint, kBuffered_DrawCategory);
1073#else
1074    target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1075#endif
1076
1077    const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1078    const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1079    srcRects[0] = &srcRect;
1080    srcMatrices[0] = srcMatrix;
1081
1082    target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1083#endif
1084}
1085
1086void GrContext::drawVertices(const GrPaint& paint,
1087                             GrPrimitiveType primitiveType,
1088                             int vertexCount,
1089                             const GrPoint positions[],
1090                             const GrPoint texCoords[],
1091                             const GrColor colors[],
1092                             const uint16_t indices[],
1093                             int indexCount) {
1094
1095    GrDrawTarget::AutoReleaseGeometry geo;
1096
1097    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1098
1099    bool hasTexCoords[GrPaint::kTotalStages] = {
1100        NULL != texCoords,   // texCoordSrc provides explicit stage 0 coords
1101        0                    // remaining stages use positions
1102    };
1103
1104    GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
1105
1106    if (NULL != colors) {
1107        layout |= GrDrawTarget::kColor_VertexLayoutBit;
1108    }
1109    int vertexSize = GrDrawTarget::VertexSize(layout);
1110
1111    bool doAA = false;
1112    OffscreenRecord record;
1113    GrIRect bounds;
1114
1115    if (sizeof(GrPoint) != vertexSize) {
1116        if (!geo.set(target, layout, vertexCount, 0)) {
1117            GrPrintf("Failed to get space for vertices!");
1118            return;
1119        }
1120        int texOffsets[GrDrawTarget::kMaxTexCoords];
1121        int colorOffset;
1122        GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1123                                                texOffsets,
1124                                                &colorOffset);
1125        void* curVertex = geo.vertices();
1126
1127        for (int i = 0; i < vertexCount; ++i) {
1128            *((GrPoint*)curVertex) = positions[i];
1129
1130            if (texOffsets[0] > 0) {
1131                *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1132            }
1133            if (colorOffset > 0) {
1134                *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1135            }
1136            curVertex = (void*)((intptr_t)curVertex + vertexSize);
1137        }
1138    } else {
1139        // we don't do offscreen AA when we have per-vertex tex coords or colors
1140        if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1141            GrRect b;
1142            b.setBounds(positions, vertexCount);
1143            target->getViewMatrix().mapRect(&b);
1144            b.roundOut(&bounds);
1145
1146            if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1147                doAA = true;
1148            }
1149        }
1150        target->setVertexSourceToArray(layout, positions, vertexCount);
1151    }
1152
1153    if (NULL != indices) {
1154        target->setIndexSourceToArray(indices, indexCount);
1155    }
1156
1157    if (NULL != indices) {
1158        target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
1159    } else {
1160        target->drawNonIndexed(primitiveType, 0, vertexCount);
1161    }
1162
1163    if (doAA) {
1164        this->offscreenAAPass2(target, paint, bounds, &record);
1165    }
1166}
1167
1168
1169///////////////////////////////////////////////////////////////////////////////
1170
1171void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1172                         GrPathFill fill, const GrPoint* translate) {
1173
1174    GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1175    GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1176
1177    if (!IsFillInverted(fill) && // will be relaxed soon
1178        !pr->supportsAA(target, path, fill) &&
1179        this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
1180
1181        OffscreenRecord record;
1182        bool needsStencil = pr->requiresStencilPass(target, path, fill);
1183
1184        // compute bounds as intersection of rt size, clip, and path
1185        GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1186                                        target->getRenderTarget()->height());
1187        if (target->getClip().hasConservativeBounds()) {
1188            GrIRect clipIBounds;
1189            target->getClip().getConservativeBounds().roundOut(&clipIBounds);
1190            if (!bound.intersect(clipIBounds)) {
1191                return;
1192            }
1193        }
1194
1195        GrRect pathBounds = path.getBounds();
1196        GrIRect pathIBounds;
1197        if (!pathBounds.isEmpty()) {
1198            if (NULL != translate) {
1199                pathBounds.offset(*translate);
1200            }
1201            target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1202            pathBounds.roundOut(&pathIBounds);
1203            if (!bound.intersect(pathIBounds)) {
1204                return;
1205            }
1206        }
1207
1208        // for now, abort antialiasing if our bounds are too big, so we don't
1209        // hit the FBO size limit
1210        if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM ||
1211            pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) {
1212            goto NO_AA;
1213        }
1214
1215        if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1216            pr->drawPath(target, 0, path, fill, translate);
1217            this->offscreenAAPass2(target, paint, bound, &record);
1218            return;
1219        }
1220    }
1221
1222// we can fall out of the AA section for some reasons, and land here
1223NO_AA:
1224    GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
1225
1226    pr->drawPath(target, enabledStages, path, fill, translate);
1227}
1228
1229////////////////////////////////////////////////////////////////////////////////
1230
1231void GrContext::flush(int flagsBitfield) {
1232    if (kDiscard_FlushBit & flagsBitfield) {
1233        fDrawBuffer->reset();
1234    } else {
1235        flushDrawBuffer();
1236    }
1237
1238    if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
1239        fGpu->forceRenderTargetFlush();
1240    }
1241}
1242
1243void GrContext::flushText() {
1244    if (kText_DrawCategory == fLastDrawCategory) {
1245        flushDrawBuffer();
1246    }
1247}
1248
1249void GrContext::flushDrawBuffer() {
1250#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1251    if (fDrawBuffer) {
1252        fDrawBuffer->playback(fGpu);
1253        fDrawBuffer->reset();
1254    }
1255#endif
1256}
1257
1258bool GrContext::readTexturePixels(GrTexture* texture,
1259                                  int left, int top, int width, int height,
1260                                  GrPixelConfig config, void* buffer) {
1261
1262    // TODO: code read pixels for textures that aren't rendertargets
1263
1264    this->flush();
1265    GrRenderTarget* target = texture->asRenderTarget();
1266    if (NULL != target) {
1267        return fGpu->readPixels(target,
1268                                left, top, width, height,
1269                                config, buffer);
1270    } else {
1271        return false;
1272    }
1273}
1274
1275bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1276                                      int left, int top, int width, int height,
1277                                      GrPixelConfig config, void* buffer) {
1278    uint32_t flushFlags = 0;
1279    if (NULL == target) {
1280        flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1281    }
1282
1283    this->flush(flushFlags);
1284    return fGpu->readPixels(target,
1285                            left, top, width, height,
1286                            config, buffer);
1287}
1288
1289void GrContext::writePixels(int left, int top, int width, int height,
1290                            GrPixelConfig config, const void* buffer,
1291                            size_t stride) {
1292
1293    // TODO: when underlying api has a direct way to do this we should use it
1294    // (e.g. glDrawPixels on desktop GL).
1295
1296    const GrTextureDesc desc = {
1297        kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
1298    };
1299    GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1300    if (NULL == texture) {
1301        return;
1302    }
1303
1304    this->flush(true);
1305
1306    GrAutoUnref                     aur(texture);
1307    GrDrawTarget::AutoStateRestore  asr(fGpu);
1308
1309    GrMatrix matrix;
1310    matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1311    fGpu->setViewMatrix(matrix);
1312
1313    fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1314    fGpu->disableState(GrDrawTarget::kClip_StateBit);
1315    fGpu->setAlpha(0xFF);
1316    fGpu->setBlendFunc(kOne_BlendCoeff,
1317                       kZero_BlendCoeff);
1318    fGpu->setTexture(0, texture);
1319
1320    GrSamplerState sampler;
1321    sampler.setClampNoFilter();
1322    matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1323    sampler.setMatrix(matrix);
1324    fGpu->setSamplerState(0, sampler);
1325
1326    GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1327    static const int VCOUNT = 4;
1328
1329    GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1330    if (!geo.succeeded()) {
1331        return;
1332    }
1333    ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1334    fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1335}
1336////////////////////////////////////////////////////////////////////////////////
1337
1338void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1339
1340    for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1341        int s = i + GrPaint::kFirstTextureStage;
1342        target->setTexture(s, paint.getTexture(i));
1343        target->setSamplerState(s, *paint.getTextureSampler(i));
1344    }
1345
1346    target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1347
1348    for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1349        int s = i + GrPaint::kFirstMaskStage;
1350        target->setTexture(s, paint.getMask(i));
1351        target->setSamplerState(s, *paint.getMaskSampler(i));
1352    }
1353
1354    target->setColor(paint.fColor);
1355
1356    if (paint.fDither) {
1357        target->enableState(GrDrawTarget::kDither_StateBit);
1358    } else {
1359        target->disableState(GrDrawTarget::kDither_StateBit);
1360    }
1361    if (paint.fAntiAlias) {
1362        target->enableState(GrDrawTarget::kAntialias_StateBit);
1363    } else {
1364        target->disableState(GrDrawTarget::kAntialias_StateBit);
1365    }
1366    target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1367    target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
1368}
1369
1370GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
1371                                       DrawCategory category) {
1372    if (category != fLastDrawCategory) {
1373        flushDrawBuffer();
1374        fLastDrawCategory = category;
1375    }
1376    SetPaint(paint, fGpu);
1377    GrDrawTarget* target = fGpu;
1378    switch (category) {
1379    case kText_DrawCategory:
1380#if DEFER_TEXT_RENDERING
1381        target = fDrawBuffer;
1382        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1383#else
1384        target = fGpu;
1385#endif
1386        break;
1387    case kUnbuffered_DrawCategory:
1388        target = fGpu;
1389        break;
1390    case kBuffered_DrawCategory:
1391        target = fDrawBuffer;
1392        fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1393        break;
1394    }
1395    return target;
1396}
1397
1398////////////////////////////////////////////////////////////////////////////////
1399
1400void GrContext::setRenderTarget(GrRenderTarget* target) {
1401    this->flush(false);
1402    fGpu->setRenderTarget(target);
1403}
1404
1405GrRenderTarget* GrContext::getRenderTarget() {
1406    return fGpu->getRenderTarget();
1407}
1408
1409const GrRenderTarget* GrContext::getRenderTarget() const {
1410    return fGpu->getRenderTarget();
1411}
1412
1413const GrMatrix& GrContext::getMatrix() const {
1414    return fGpu->getViewMatrix();
1415}
1416
1417void GrContext::setMatrix(const GrMatrix& m) {
1418    fGpu->setViewMatrix(m);
1419}
1420
1421void GrContext::concatMatrix(const GrMatrix& m) const {
1422    fGpu->preConcatViewMatrix(m);
1423}
1424
1425static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1426    intptr_t mask = 1 << shift;
1427    if (pred) {
1428        bits |= mask;
1429    } else {
1430        bits &= ~mask;
1431    }
1432    return bits;
1433}
1434
1435void GrContext::resetStats() {
1436    fGpu->resetStats();
1437}
1438
1439const GrGpuStats& GrContext::getStats() const {
1440    return fGpu->getStats();
1441}
1442
1443void GrContext::printStats() const {
1444    fGpu->printStats();
1445}
1446
1447GrContext::GrContext(GrGpu* gpu) :
1448    fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1449                         gpu->supportsStencilWrapOps()) {
1450
1451    fGpu = gpu;
1452    fGpu->ref();
1453    fGpu->setContext(this);
1454
1455    fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1456    fGpu->setClipPathRenderer(fCustomPathRenderer);
1457
1458    fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1459                                       MAX_TEXTURE_CACHE_BYTES);
1460    fFontCache = new GrFontCache(fGpu);
1461
1462    fLastDrawCategory = kUnbuffered_DrawCategory;
1463
1464    fDrawBuffer = NULL;
1465    fDrawBufferVBAllocPool = NULL;
1466    fDrawBufferIBAllocPool = NULL;
1467
1468    fAAFillRectIndexBuffer = NULL;
1469    fAAStrokeRectIndexBuffer = NULL;
1470
1471    this->setupDrawBuffer();
1472}
1473
1474void GrContext::setupDrawBuffer() {
1475
1476    GrAssert(NULL == fDrawBuffer);
1477    GrAssert(NULL == fDrawBufferVBAllocPool);
1478    GrAssert(NULL == fDrawBufferIBAllocPool);
1479
1480#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1481    fDrawBufferVBAllocPool =
1482        new GrVertexBufferAllocPool(fGpu, false,
1483                                    DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1484                                    DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1485    fDrawBufferIBAllocPool =
1486        new GrIndexBufferAllocPool(fGpu, false,
1487                                   DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1488                                   DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1489
1490    fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1491                                          fDrawBufferIBAllocPool);
1492#endif
1493
1494#if BATCH_RECT_TO_RECT
1495    fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1496#endif
1497}
1498
1499GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1500    GrDrawTarget* target;
1501#if DEFER_TEXT_RENDERING
1502    target = prepareToDraw(paint, kText_DrawCategory);
1503#else
1504    target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1505#endif
1506    SetPaint(paint, target);
1507    return target;
1508}
1509
1510const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1511    return fGpu->getQuadIndexBuffer();
1512}
1513
1514GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1515                                           const GrPath& path,
1516                                           GrPathFill fill) {
1517    if (NULL != fCustomPathRenderer &&
1518        fCustomPathRenderer->canDrawPath(target, path, fill)) {
1519        return fCustomPathRenderer;
1520    } else {
1521        GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1522        return &fDefaultPathRenderer;
1523    }
1524}
1525
1526