• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38 static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39 
40 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41 static 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.
45 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47 
Create(GrEngine engine,GrPlatform3DContext context3D)48 GrContext* 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 
CreateGLShaderContext()59 GrContext* GrContext::CreateGLShaderContext() {
60     return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
61 }
62 
~GrContext()63 GrContext::~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 
contextLost()76 void GrContext::contextLost() {
77     contextDestroyed();
78     this->setupDrawBuffer();
79 }
80 
contextDestroyed()81 void 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 
resetContext()103 void GrContext::resetContext() {
104     fGpu->markContextDirty();
105 }
106 
freeGpuResources()107 void GrContext::freeGpuResources() {
108     this->flush();
109     fTextureCache->removeAll();
110     fFontCache->freeAll();
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////
114 
PaintStageVertexLayoutBits(const GrPaint & paint,const bool hasTexCoords[GrPaint::kTotalStages])115 int 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 
135 enum {
136     kNPOTBit    = 0x1,
137     kFilterBit  = 0x2,
138     kKeylessBit = 0x4,
139 };
140 
finalizeTextureKey(GrTextureKey * key,const GrSamplerState & sampler,bool keyless) const141 bool 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 
findAndLockTexture(GrTextureKey * key,const GrSamplerState & sampler)169 GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170                                               const GrSamplerState& sampler) {
171     finalizeTextureKey(key, sampler, false);
172     return fTextureCache->findAndLock(*key);
173 }
174 
stretchImage(void * dst,int dstW,int dstH,void * src,int srcW,int srcH,int bpp)175 static 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 
createAndLockTexture(GrTextureKey * key,const GrSamplerState & sampler,const GrTextureDesc & desc,void * srcData,size_t rowBytes)202 GrTextureEntry* 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 
lockKeylessTexture(const GrTextureDesc & desc)319 GrTextureEntry* 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 
unlockTexture(GrTextureEntry * entry)341 void GrContext::unlockTexture(GrTextureEntry* entry) {
342     if (kKeylessBit & entry->key().getPrivateBits()) {
343         fTextureCache->reattachAndUnlock(entry);
344     } else {
345         fTextureCache->unlock(entry);
346     }
347 }
348 
createUncachedTexture(const GrTextureDesc & desc,void * srcData,size_t rowBytes)349 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
350                                             void* srcData,
351                                             size_t rowBytes) {
352     return fGpu->createTexture(desc, srcData, rowBytes);
353 }
354 
getTextureCacheLimits(int * maxTextures,size_t * maxTextureBytes) const355 void GrContext::getTextureCacheLimits(int* maxTextures,
356                                       size_t* maxTextureBytes) const {
357     fTextureCache->getLimits(maxTextures, maxTextureBytes);
358 }
359 
setTextureCacheLimits(int maxTextures,size_t maxTextureBytes)360 void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
361     fTextureCache->setLimits(maxTextures, maxTextureBytes);
362 }
363 
getMaxTextureDimension()364 int GrContext::getMaxTextureDimension() {
365     return fGpu->maxTextureDimension();
366 }
367 
368 ///////////////////////////////////////////////////////////////////////////////
369 
createPlatformSurface(const GrPlatformSurfaceDesc & desc)370 GrResource* 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 
createRenderTargetFrom3DApiState()388 GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
389     return fGpu->createRenderTargetFrom3DApiState();
390 }
391 
392 ///////////////////////////////////////////////////////////////////////////////
393 
supportsIndex8PixelConfig(const GrSamplerState & sampler,int width,int height)394 bool 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 
getClip() const419 const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
420 
setClip(const GrClip & clip)421 void GrContext::setClip(const GrClip& clip) {
422     fGpu->setClip(clip);
423     fGpu->enableState(GrDrawTarget::kClip_StateBit);
424 }
425 
setClip(const GrIRect & rect)426 void GrContext::setClip(const GrIRect& rect) {
427     GrClip clip;
428     clip.setFromIRect(rect);
429     fGpu->setClip(clip);
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 
clear(const GrIRect * rect,const GrColor color)434 void GrContext::clear(const GrIRect* rect, const GrColor color) {
435     this->flush();
436     fGpu->clear(rect, color);
437 }
438 
drawPaint(const GrPaint & paint)439 void 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 
doOffscreenAA(GrDrawTarget * target,const GrPaint & paint,bool isLines) const457 bool 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 
setupOffscreenAAPass1(GrDrawTarget * target,bool requireStencil,const GrIRect & boundRect,OffscreenRecord * record)486 bool 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 
offscreenAAPass2(GrDrawTarget * target,const GrPaint & paint,const GrIRect & boundRect,OffscreenRecord * record)569 void 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  */
setStrokeRectStrip(GrPoint verts[10],GrRect rect,GrScalar width)664 static 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 
getColorForMesh(const GrPaint & paint)681 static 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 
setInsetFan(GrPoint * pts,size_t stride,const GrRect & r,GrScalar dx,GrScalar dy)693 static 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 
698 static 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 
aaFillRectIndexCount() const706 int GrContext::aaFillRectIndexCount() const {
707     return GR_ARRAY_COUNT(gFillAARectIdx);
708 }
709 
aaFillRectIndexBuffer()710 GrIndexBuffer* 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 
725 static 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 
aaStrokeRectIndexCount() const742 int GrContext::aaStrokeRectIndexCount() const {
743     return GR_ARRAY_COUNT(gStrokeAARectIdx);
744 }
745 
aaStrokeRectIndexBuffer()746 GrIndexBuffer* 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 
fillAARect(GrDrawTarget * target,const GrPaint & paint,const GrRect & devRect)761 void 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 
strokeAARect(GrDrawTarget * target,const GrPaint & paint,const GrRect & devRect,const GrVec & devStrokeSize)797 void 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  */
isIRect(const GrRect & r)861 static bool isIRect(const GrRect& r) {
862     return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
863            GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
864 }
865 
apply_aa_to_rect(GrDrawTarget * target,GrGpu * gpu,const GrPaint & paint,const GrRect & rect,GrScalar width,const GrMatrix * matrix,GrMatrix * combinedMatrix,GrRect * devRect)866 static 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 
drawRect(const GrPaint & paint,const GrRect & rect,GrScalar width,const GrMatrix * matrix)916 void 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 
drawRectToRect(const GrPaint & paint,const GrRect & dstRect,const GrRect & srcRect,const GrMatrix * dstMatrix,const GrMatrix * srcMatrix)1021 void 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 
drawVertices(const GrPaint & paint,GrPrimitiveType primitiveType,int vertexCount,const GrPoint positions[],const GrPoint texCoords[],const GrColor colors[],const uint16_t indices[],int indexCount)1086 void 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 
drawPath(const GrPaint & paint,const GrPath & path,GrPathFill fill,const GrPoint * translate)1171 void 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
1223 NO_AA:
1224     GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
1225 
1226     pr->drawPath(target, enabledStages, path, fill, translate);
1227 }
1228 
1229 ////////////////////////////////////////////////////////////////////////////////
1230 
flush(int flagsBitfield)1231 void 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 
flushText()1243 void GrContext::flushText() {
1244     if (kText_DrawCategory == fLastDrawCategory) {
1245         flushDrawBuffer();
1246     }
1247 }
1248 
flushDrawBuffer()1249 void 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 
readTexturePixels(GrTexture * texture,int left,int top,int width,int height,GrPixelConfig config,void * buffer)1258 bool 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 
readRenderTargetPixels(GrRenderTarget * target,int left,int top,int width,int height,GrPixelConfig config,void * buffer)1275 bool 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 
writePixels(int left,int top,int width,int height,GrPixelConfig config,const void * buffer,size_t stride)1289 void 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 
SetPaint(const GrPaint & paint,GrDrawTarget * target)1338 void 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 
prepareToDraw(const GrPaint & paint,DrawCategory category)1370 GrDrawTarget* 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 
setRenderTarget(GrRenderTarget * target)1400 void GrContext::setRenderTarget(GrRenderTarget* target) {
1401     this->flush(false);
1402     fGpu->setRenderTarget(target);
1403 }
1404 
getRenderTarget()1405 GrRenderTarget* GrContext::getRenderTarget() {
1406     return fGpu->getRenderTarget();
1407 }
1408 
getRenderTarget() const1409 const GrRenderTarget* GrContext::getRenderTarget() const {
1410     return fGpu->getRenderTarget();
1411 }
1412 
getMatrix() const1413 const GrMatrix& GrContext::getMatrix() const {
1414     return fGpu->getViewMatrix();
1415 }
1416 
setMatrix(const GrMatrix & m)1417 void GrContext::setMatrix(const GrMatrix& m) {
1418     fGpu->setViewMatrix(m);
1419 }
1420 
concatMatrix(const GrMatrix & m) const1421 void GrContext::concatMatrix(const GrMatrix& m) const {
1422     fGpu->preConcatViewMatrix(m);
1423 }
1424 
setOrClear(intptr_t bits,int shift,intptr_t pred)1425 static 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 
resetStats()1435 void GrContext::resetStats() {
1436     fGpu->resetStats();
1437 }
1438 
getStats() const1439 const GrGpuStats& GrContext::getStats() const {
1440     return fGpu->getStats();
1441 }
1442 
printStats() const1443 void GrContext::printStats() const {
1444     fGpu->printStats();
1445 }
1446 
GrContext(GrGpu * gpu)1447 GrContext::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 
setupDrawBuffer()1474 void 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 
getTextTarget(const GrPaint & paint)1499 GrDrawTarget* 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 
getQuadIndexBuffer() const1510 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1511     return fGpu->getQuadIndexBuffer();
1512 }
1513 
getPathRenderer(const GrDrawTarget * target,const GrPath & path,GrPathFill fill)1514 GrPathRenderer* 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