1
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "GrContext.h"
10
11 #include "GrAARectRenderer.h"
12 #include "GrAtlasTextContext.h"
13 #include "GrBatch.h"
14 #include "GrBatchFontCache.h"
15 #include "GrBatchTarget.h"
16 #include "GrBatchTest.h"
17 #include "GrDefaultGeoProcFactory.h"
18 #include "GrGpuResource.h"
19 #include "GrGpuResourcePriv.h"
20 #include "GrDrawTargetCaps.h"
21 #include "GrGpu.h"
22 #include "GrIndexBuffer.h"
23 #include "GrInOrderDrawBuffer.h"
24 #include "GrLayerCache.h"
25 #include "GrOvalRenderer.h"
26 #include "GrPathRenderer.h"
27 #include "GrPathUtils.h"
28 #include "GrRenderTargetPriv.h"
29 #include "GrResourceCache.h"
30 #include "GrResourceProvider.h"
31 #include "GrSoftwarePathRenderer.h"
32 #include "GrStencilAndCoverTextContext.h"
33 #include "GrStrokeInfo.h"
34 #include "GrSurfacePriv.h"
35 #include "GrTextBlobCache.h"
36 #include "GrTexturePriv.h"
37 #include "GrTraceMarker.h"
38 #include "GrTracing.h"
39 #include "GrVertices.h"
40 #include "SkDashPathPriv.h"
41 #include "SkConfig8888.h"
42 #include "SkGr.h"
43 #include "SkRRect.h"
44 #include "SkStrokeRec.h"
45 #include "SkTLazy.h"
46 #include "SkTLS.h"
47 #include "SkTraceEvent.h"
48
49 #include "effects/GrConfigConversionEffect.h"
50 #include "effects/GrDashingEffect.h"
51 #include "effects/GrSingleTextureEffect.h"
52
53 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
54 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
55 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
56 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
57
58 class GrContext::AutoCheckFlush {
59 public:
AutoCheckFlush(GrContext * context)60 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
61
~AutoCheckFlush()62 ~AutoCheckFlush() {
63 if (fContext->fFlushToReduceCacheSize) {
64 fContext->flush();
65 }
66 }
67
68 private:
69 GrContext* fContext;
70 };
71
Create(GrBackend backend,GrBackendContext backendContext,const Options * opts)72 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
73 const Options* opts) {
74 GrContext* context;
75 if (NULL == opts) {
76 context = SkNEW_ARGS(GrContext, (Options()));
77 } else {
78 context = SkNEW_ARGS(GrContext, (*opts));
79 }
80
81 if (context->init(backend, backendContext)) {
82 return context;
83 } else {
84 context->unref();
85 return NULL;
86 }
87 }
88
89 static int32_t gNextID = 1;
next_id()90 static int32_t next_id() {
91 int32_t id;
92 do {
93 id = sk_atomic_inc(&gNextID);
94 } while (id == SK_InvalidGenID);
95 return id;
96 }
97
GrContext(const Options & opts)98 GrContext::GrContext(const Options& opts) : fOptions(opts), fUniqueID(next_id()) {
99 fGpu = NULL;
100 fResourceCache = NULL;
101 fResourceProvider = NULL;
102 fPathRendererChain = NULL;
103 fSoftwarePathRenderer = NULL;
104 fBatchFontCache = NULL;
105 fDrawBuffer = NULL;
106 fFlushToReduceCacheSize = false;
107 fAARectRenderer = NULL;
108 fOvalRenderer = NULL;
109 fMaxTextureSizeOverride = 1 << 20;
110 }
111
init(GrBackend backend,GrBackendContext backendContext)112 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
113 SkASSERT(NULL == fGpu);
114
115 fGpu = GrGpu::Create(backend, backendContext, this);
116 if (NULL == fGpu) {
117 return false;
118 }
119 this->initCommon();
120 return true;
121 }
122
initCommon()123 void GrContext::initCommon() {
124 fResourceCache = SkNEW(GrResourceCache);
125 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
126 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache));
127
128 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
129
130 fAARectRenderer = SkNEW(GrAARectRenderer);
131 fOvalRenderer = SkNEW(GrOvalRenderer);
132
133 fDidTestPMConversions = false;
134
135 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this));
136
137 // GrBatchFontCache will eventually replace GrFontCache
138 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this));
139
140 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this)));
141 }
142
~GrContext()143 GrContext::~GrContext() {
144 if (NULL == fGpu) {
145 return;
146 }
147
148 this->flush();
149
150 for (int i = 0; i < fCleanUpData.count(); ++i) {
151 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
152 }
153
154 SkDELETE(fResourceProvider);
155 SkDELETE(fResourceCache);
156 SkDELETE(fBatchFontCache);
157 SkDELETE(fDrawBuffer);
158
159 fAARectRenderer->unref();
160 fOvalRenderer->unref();
161
162 fGpu->unref();
163 SkSafeUnref(fPathRendererChain);
164 SkSafeUnref(fSoftwarePathRenderer);
165 }
166
abandonContext()167 void GrContext::abandonContext() {
168 fResourceProvider->abandon();
169 // abandon first to so destructors
170 // don't try to free the resources in the API.
171 fResourceCache->abandonAll();
172
173 fGpu->contextAbandoned();
174
175 // a path renderer may be holding onto resources that
176 // are now unusable
177 SkSafeSetNull(fPathRendererChain);
178 SkSafeSetNull(fSoftwarePathRenderer);
179
180 SkDELETE(fDrawBuffer);
181 fDrawBuffer = NULL;
182
183 fBatchFontCache->freeAll();
184 fLayerCache->freeAll();
185 fTextBlobCache->freeAll();
186 }
187
resetContext(uint32_t state)188 void GrContext::resetContext(uint32_t state) {
189 fGpu->markContextDirty(state);
190 }
191
freeGpuResources()192 void GrContext::freeGpuResources() {
193 this->flush();
194
195 if (fDrawBuffer) {
196 fDrawBuffer->purgeResources();
197 }
198
199 fBatchFontCache->freeAll();
200 fLayerCache->freeAll();
201 // a path renderer may be holding onto resources
202 SkSafeSetNull(fPathRendererChain);
203 SkSafeSetNull(fSoftwarePathRenderer);
204
205 fResourceCache->purgeAllUnlocked();
206 }
207
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const208 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
209 if (resourceCount) {
210 *resourceCount = fResourceCache->getBudgetedResourceCount();
211 }
212 if (resourceBytes) {
213 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
214 }
215 }
216
createTextContext(GrRenderTarget * renderTarget,SkGpuDevice * gpuDevice,const SkDeviceProperties & leakyProperties,bool enableDistanceFieldFonts)217 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
218 SkGpuDevice* gpuDevice,
219 const SkDeviceProperties&
220 leakyProperties,
221 bool enableDistanceFieldFonts) {
222 if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
223 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
224 if (sb) {
225 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
226 }
227 }
228
229 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDistanceFieldFonts);
230 }
231
232 ////////////////////////////////////////////////////////////////////////////////
233
isConfigTexturable(GrPixelConfig config) const234 bool GrContext::isConfigTexturable(GrPixelConfig config) const {
235 return fGpu->caps()->isConfigTexturable(config);
236 }
237
npotTextureTileSupport() const238 bool GrContext::npotTextureTileSupport() const {
239 return fGpu->caps()->npotTextureTileSupport();
240 }
241
OverBudgetCB(void * data)242 void GrContext::OverBudgetCB(void* data) {
243 SkASSERT(data);
244
245 GrContext* context = reinterpret_cast<GrContext*>(data);
246
247 // Flush the InOrderDrawBuffer to possibly free up some textures
248 context->fFlushToReduceCacheSize = true;
249 }
250
TextBlobCacheOverBudgetCB(void * data)251 void GrContext::TextBlobCacheOverBudgetCB(void* data) {
252 SkASSERT(data);
253
254 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
255 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
256 // drawText calls to below the GrContext level, but this is not trivial because they call
257 // drawPath on SkGpuDevice
258 GrContext* context = reinterpret_cast<GrContext*>(data);
259 context->flush();
260 }
261
getMaxTextureSize() const262 int GrContext::getMaxTextureSize() const {
263 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
264 }
265
getMaxRenderTargetSize() const266 int GrContext::getMaxRenderTargetSize() const {
267 return fGpu->caps()->maxRenderTargetSize();
268 }
269
getMaxSampleCount() const270 int GrContext::getMaxSampleCount() const {
271 return fGpu->caps()->maxSampleCount();
272 }
273
274 ///////////////////////////////////////////////////////////////////////////////
275
clear(const SkIRect * rect,const GrColor color,bool canIgnoreRect,GrRenderTarget * renderTarget)276 void GrContext::clear(const SkIRect* rect,
277 const GrColor color,
278 bool canIgnoreRect,
279 GrRenderTarget* renderTarget) {
280 RETURN_IF_ABANDONED
281 ASSERT_OWNED_RESOURCE(renderTarget);
282 SkASSERT(renderTarget);
283
284 AutoCheckFlush acf(this);
285 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
286 GrDrawTarget* target = this->prepareToDraw();
287 if (NULL == target) {
288 return;
289 }
290 target->clear(rect, color, canIgnoreRect, renderTarget);
291 }
292
drawPaint(GrRenderTarget * rt,const GrClip & clip,const GrPaint & origPaint,const SkMatrix & viewMatrix)293 void GrContext::drawPaint(GrRenderTarget* rt,
294 const GrClip& clip,
295 const GrPaint& origPaint,
296 const SkMatrix& viewMatrix) {
297 RETURN_IF_ABANDONED
298 // set rect to be big enough to fill the space, but not super-huge, so we
299 // don't overflow fixed-point implementations
300 SkRect r;
301 r.setLTRB(0, 0,
302 SkIntToScalar(rt->width()),
303 SkIntToScalar(rt->height()));
304 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
305
306 // by definition this fills the entire clip, no need for AA
307 if (paint->isAntiAlias()) {
308 paint.writable()->setAntiAlias(false);
309 }
310
311 bool isPerspective = viewMatrix.hasPerspective();
312
313 // We attempt to map r by the inverse matrix and draw that. mapRect will
314 // map the four corners and bound them with a new rect. This will not
315 // produce a correct result for some perspective matrices.
316 if (!isPerspective) {
317 SkMatrix inverse;
318 if (!viewMatrix.invert(&inverse)) {
319 SkDebugf("Could not invert matrix\n");
320 return;
321 }
322 inverse.mapRect(&r);
323 this->drawRect(rt, clip, *paint, viewMatrix, r);
324 } else {
325 SkMatrix localMatrix;
326 if (!viewMatrix.invert(&localMatrix)) {
327 SkDebugf("Could not invert matrix\n");
328 return;
329 }
330
331 AutoCheckFlush acf(this);
332 GrPipelineBuilder pipelineBuilder;
333 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
334 if (NULL == target) {
335 return;
336 }
337
338 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
339 target->drawRect(&pipelineBuilder,
340 paint->getColor(),
341 SkMatrix::I(),
342 r,
343 NULL,
344 &localMatrix);
345 }
346 }
347
348 ////////////////////////////////////////////////////////////////////////////////
349
is_irect(const SkRect & r)350 static inline bool is_irect(const SkRect& r) {
351 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
352 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
353 }
354
apply_aa_to_rect(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,SkRect * devBoundRect,const SkRect & rect,SkScalar strokeWidth,const SkMatrix & combinedMatrix,GrColor color)355 static bool apply_aa_to_rect(GrDrawTarget* target,
356 GrPipelineBuilder* pipelineBuilder,
357 SkRect* devBoundRect,
358 const SkRect& rect,
359 SkScalar strokeWidth,
360 const SkMatrix& combinedMatrix,
361 GrColor color) {
362 if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
363 return false;
364 }
365
366 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
367 if (strokeWidth >= 0) {
368 #endif
369 if (!combinedMatrix.preservesAxisAlignment()) {
370 return false;
371 }
372
373 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
374 } else {
375 if (!combinedMatrix.preservesRightAngles()) {
376 return false;
377 }
378 }
379 #endif
380
381 combinedMatrix.mapRect(devBoundRect, rect);
382 if (!combinedMatrix.rectStaysRect()) {
383 return true;
384 }
385
386 if (strokeWidth < 0) {
387 return !is_irect(*devBoundRect);
388 }
389
390 return true;
391 }
392
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)393 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
394 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
395 point.fY >= rect.fTop && point.fY <= rect.fBottom;
396 }
397
398 class StrokeRectBatch : public GrBatch {
399 public:
400 struct Geometry {
401 GrColor fColor;
402 SkMatrix fViewMatrix;
403 SkRect fRect;
404 SkScalar fStrokeWidth;
405 };
406
Create(const Geometry & geometry,bool snapToPixelCenters)407 static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) {
408 return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters));
409 }
410
name() const411 const char* name() const override { return "StrokeRectBatch"; }
412
getInvariantOutputColor(GrInitInvariantOutput * out) const413 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
414 // When this is called on a batch, there is only one geometry bundle
415 out->setKnownFourComponents(fGeoData[0].fColor);
416 }
417
getInvariantOutputCoverage(GrInitInvariantOutput * out) const418 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
419 out->setKnownSingleComponent(0xff);
420 }
421
initBatchTracker(const GrPipelineInfo & init)422 void initBatchTracker(const GrPipelineInfo& init) override {
423 // Handle any color overrides
424 if (init.fColorIgnored) {
425 fGeoData[0].fColor = GrColor_ILLEGAL;
426 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
427 fGeoData[0].fColor = init.fOverrideColor;
428 }
429
430 // setup batch properties
431 fBatch.fColorIgnored = init.fColorIgnored;
432 fBatch.fColor = fGeoData[0].fColor;
433 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
434 fBatch.fCoverageIgnored = init.fCoverageIgnored;
435 }
436
generateGeometry(GrBatchTarget * batchTarget,const GrPipeline * pipeline)437 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
438 SkAutoTUnref<const GrGeometryProcessor> gp(
439 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
440 this->color(),
441 this->viewMatrix(),
442 SkMatrix::I()));
443
444 batchTarget->initDraw(gp, pipeline);
445
446 // TODO this is hacky, but the only way we have to initialize the GP is to use the
447 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
448 // everywhere we can remove this nastiness
449 GrPipelineInfo init;
450 init.fColorIgnored = fBatch.fColorIgnored;
451 init.fOverrideColor = GrColor_ILLEGAL;
452 init.fCoverageIgnored = fBatch.fCoverageIgnored;
453 init.fUsesLocalCoords = this->usesLocalCoords();
454 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
455
456 size_t vertexStride = gp->getVertexStride();
457
458 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
459
460 Geometry& args = fGeoData[0];
461
462 int vertexCount = kVertsPerHairlineRect;
463 if (args.fStrokeWidth > 0) {
464 vertexCount = kVertsPerStrokeRect;
465 }
466
467 const GrVertexBuffer* vertexBuffer;
468 int firstVertex;
469
470 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount,
471 &vertexBuffer, &firstVertex);
472
473 if (!verts) {
474 SkDebugf("Could not allocate vertices\n");
475 return;
476 }
477
478 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
479
480 GrPrimitiveType primType;
481
482 if (args.fStrokeWidth > 0) {;
483 primType = kTriangleStrip_GrPrimitiveType;
484 args.fRect.sort();
485 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
486 } else {
487 // hairline
488 primType = kLineStrip_GrPrimitiveType;
489 vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
490 vertex[1].set(args.fRect.fRight, args.fRect.fTop);
491 vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
492 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
493 vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
494 }
495
496 GrVertices vertices;
497 vertices.init(primType, vertexBuffer, firstVertex, vertexCount);
498 batchTarget->draw(vertices);
499 }
500
geoData()501 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
502
503 private:
StrokeRectBatch(const Geometry & geometry,bool snapToPixelCenters)504 StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) {
505 this->initClassID<StrokeRectBatch>();
506
507 fBatch.fHairline = geometry.fStrokeWidth == 0;
508
509 fGeoData.push_back(geometry);
510
511 // setup bounds
512 fBounds = geometry.fRect;
513 SkScalar rad = SkScalarHalf(geometry.fStrokeWidth);
514 fBounds.outset(rad, rad);
515 geometry.fViewMatrix.mapRect(&fBounds);
516
517 // If our caller snaps to pixel centers then we have to round out the bounds
518 if (snapToPixelCenters) {
519 fBounds.roundOut();
520 }
521 }
522
523 /* create a triangle strip that strokes the specified rect. There are 8
524 unique vertices, but we repeat the last 2 to close up. Alternatively we
525 could use an indices array, and then only send 8 verts, but not sure that
526 would be faster.
527 */
setStrokeRectStrip(SkPoint verts[10],const SkRect & rect,SkScalar width)528 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
529 const SkScalar rad = SkScalarHalf(width);
530 // TODO we should be able to enable this assert, but we'd have to filter these draws
531 // this is a bug
532 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
533
534 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
535 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
536 verts[2].set(rect.fRight - rad, rect.fTop + rad);
537 verts[3].set(rect.fRight + rad, rect.fTop - rad);
538 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
539 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
540 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
541 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
542 verts[8] = verts[0];
543 verts[9] = verts[1];
544 }
545
546
color() const547 GrColor color() const { return fBatch.fColor; }
usesLocalCoords() const548 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
colorIgnored() const549 bool colorIgnored() const { return fBatch.fColorIgnored; }
viewMatrix() const550 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
hairline() const551 bool hairline() const { return fBatch.fHairline; }
552
onCombineIfPossible(GrBatch * t)553 bool onCombineIfPossible(GrBatch* t) override {
554 // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
555
556 // NonAA stroke rects cannot batch right now
557 // TODO make these batchable
558 return false;
559 }
560
561 struct BatchTracker {
562 GrColor fColor;
563 bool fUsesLocalCoords;
564 bool fColorIgnored;
565 bool fCoverageIgnored;
566 bool fHairline;
567 };
568
569 const static int kVertsPerHairlineRect = 5;
570 const static int kVertsPerStrokeRect = 10;
571
572 BatchTracker fBatch;
573 SkSTArray<1, Geometry, true> fGeoData;
574 };
575
drawRect(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rect,const GrStrokeInfo * strokeInfo)576 void GrContext::drawRect(GrRenderTarget* rt,
577 const GrClip& clip,
578 const GrPaint& paint,
579 const SkMatrix& viewMatrix,
580 const SkRect& rect,
581 const GrStrokeInfo* strokeInfo) {
582 RETURN_IF_ABANDONED
583 if (strokeInfo && strokeInfo->isDashed()) {
584 SkPath path;
585 path.addRect(rect);
586 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
587 return;
588 }
589
590 AutoCheckFlush acf(this);
591 GrPipelineBuilder pipelineBuilder;
592 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
593 if (NULL == target) {
594 return;
595 }
596
597 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
598 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
599
600 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
601 // cases where the RT is fully inside a stroke.
602 if (width < 0) {
603 SkRect rtRect;
604 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
605 SkRect clipSpaceRTRect = rtRect;
606 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
607 if (checkClip) {
608 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
609 SkIntToScalar(clip.origin().fY));
610 }
611 // Does the clip contain the entire RT?
612 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
613 SkMatrix invM;
614 if (!viewMatrix.invert(&invM)) {
615 return;
616 }
617 // Does the rect bound the RT?
618 SkPoint srcSpaceRTQuad[4];
619 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
620 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
621 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
622 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
623 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
624 // Will it blend?
625 GrColor clearColor;
626 if (paint.isOpaqueAndConstantColor(&clearColor)) {
627 target->clear(NULL, clearColor, true, rt);
628 return;
629 }
630 }
631 }
632 }
633
634 GrColor color = paint.getColor();
635 SkRect devBoundRect;
636 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
637 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
638 viewMatrix, color);
639
640 if (doAA) {
641 if (width >= 0) {
642 const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
643 fAARectRenderer->strokeAARect(target,
644 &pipelineBuilder,
645 color,
646 viewMatrix,
647 rect,
648 devBoundRect,
649 strokeRec);
650 } else {
651 // filled AA rect
652 fAARectRenderer->fillAARect(target,
653 &pipelineBuilder,
654 color,
655 viewMatrix,
656 rect,
657 devBoundRect);
658 }
659 return;
660 }
661
662 if (width >= 0) {
663 StrokeRectBatch::Geometry geometry;
664 geometry.fViewMatrix = viewMatrix;
665 geometry.fColor = color;
666 geometry.fRect = rect;
667 geometry.fStrokeWidth = width;
668
669 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
670 bool snapToPixelCenters = (0 == width && !rt->isMultisampled());
671 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixelCenters));
672
673 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
674 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
675 // is enabled because it can cause ugly artifacts.
676 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
677 snapToPixelCenters);
678 target->drawBatch(&pipelineBuilder, batch);
679 } else {
680 // filled BW rect
681 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
682 }
683 }
684
drawNonAARectToRect(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkRect & localRect,const SkMatrix * localMatrix)685 void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
686 const GrClip& clip,
687 const GrPaint& paint,
688 const SkMatrix& viewMatrix,
689 const SkRect& rectToDraw,
690 const SkRect& localRect,
691 const SkMatrix* localMatrix) {
692 RETURN_IF_ABANDONED
693 AutoCheckFlush acf(this);
694 GrPipelineBuilder pipelineBuilder;
695 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
696 if (NULL == target) {
697 return;
698 }
699
700 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
701
702 target->drawRect(&pipelineBuilder,
703 paint.getColor(),
704 viewMatrix,
705 rectToDraw,
706 &localRect,
707 localMatrix);
708 }
709
set_vertex_attributes(bool hasLocalCoords,bool hasColors,int * colorOffset,int * texOffset,GrColor color,const SkMatrix & viewMatrix)710 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
711 bool hasColors,
712 int* colorOffset,
713 int* texOffset,
714 GrColor color,
715 const SkMatrix& viewMatrix) {
716 *texOffset = -1;
717 *colorOffset = -1;
718 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
719 if (hasLocalCoords && hasColors) {
720 *colorOffset = sizeof(SkPoint);
721 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
722 flags |= GrDefaultGeoProcFactory::kColor_GPType |
723 GrDefaultGeoProcFactory::kLocalCoord_GPType;
724 } else if (hasLocalCoords) {
725 *texOffset = sizeof(SkPoint);
726 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
727 } else if (hasColors) {
728 *colorOffset = sizeof(SkPoint);
729 flags |= GrDefaultGeoProcFactory::kColor_GPType;
730 }
731 return GrDefaultGeoProcFactory::Create(flags, color, viewMatrix, SkMatrix::I());
732 }
733
734 class DrawVerticesBatch : public GrBatch {
735 public:
736 struct Geometry {
737 GrColor fColor;
738 SkTDArray<SkPoint> fPositions;
739 SkTDArray<uint16_t> fIndices;
740 SkTDArray<GrColor> fColors;
741 SkTDArray<SkPoint> fLocalCoords;
742 };
743
Create(const Geometry & geometry,GrPrimitiveType primitiveType,const SkMatrix & viewMatrix,const SkPoint * positions,int vertexCount,const uint16_t * indices,int indexCount,const GrColor * colors,const SkPoint * localCoords,const SkRect & bounds)744 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
745 const SkMatrix& viewMatrix,
746 const SkPoint* positions, int vertexCount,
747 const uint16_t* indices, int indexCount,
748 const GrColor* colors, const SkPoint* localCoords,
749 const SkRect& bounds) {
750 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
751 vertexCount, indices, indexCount, colors,
752 localCoords, bounds));
753 }
754
name() const755 const char* name() const override { return "DrawVerticesBatch"; }
756
getInvariantOutputColor(GrInitInvariantOutput * out) const757 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
758 // When this is called on a batch, there is only one geometry bundle
759 if (this->hasColors()) {
760 out->setUnknownFourComponents();
761 } else {
762 out->setKnownFourComponents(fGeoData[0].fColor);
763 }
764 }
765
getInvariantOutputCoverage(GrInitInvariantOutput * out) const766 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
767 out->setKnownSingleComponent(0xff);
768 }
769
initBatchTracker(const GrPipelineInfo & init)770 void initBatchTracker(const GrPipelineInfo& init) override {
771 // Handle any color overrides
772 if (init.fColorIgnored) {
773 fGeoData[0].fColor = GrColor_ILLEGAL;
774 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
775 fGeoData[0].fColor = init.fOverrideColor;
776 }
777
778 // setup batch properties
779 fBatch.fColorIgnored = init.fColorIgnored;
780 fBatch.fColor = fGeoData[0].fColor;
781 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
782 fBatch.fCoverageIgnored = init.fCoverageIgnored;
783 }
784
generateGeometry(GrBatchTarget * batchTarget,const GrPipeline * pipeline)785 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
786 int colorOffset = -1, texOffset = -1;
787 SkAutoTUnref<const GrGeometryProcessor> gp(
788 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
789 &texOffset, this->color(), this->viewMatrix()));
790
791 batchTarget->initDraw(gp, pipeline);
792
793 // TODO this is hacky, but the only way we have to initialize the GP is to use the
794 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
795 // everywhere we can remove this nastiness
796 GrPipelineInfo init;
797 init.fColorIgnored = fBatch.fColorIgnored;
798 init.fOverrideColor = GrColor_ILLEGAL;
799 init.fCoverageIgnored = fBatch.fCoverageIgnored;
800 init.fUsesLocalCoords = this->usesLocalCoords();
801 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
802
803 size_t vertexStride = gp->getVertexStride();
804
805 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
806 + (this->hasColors() ? sizeof(GrColor) : 0));
807
808 int instanceCount = fGeoData.count();
809
810 const GrVertexBuffer* vertexBuffer;
811 int firstVertex;
812
813 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
814 &vertexBuffer, &firstVertex);
815
816 if (!verts) {
817 SkDebugf("Could not allocate vertices\n");
818 return;
819 }
820
821 const GrIndexBuffer* indexBuffer = NULL;
822 int firstIndex = 0;
823
824 uint16_t* indices = NULL;
825 if (this->hasIndices()) {
826 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
827
828 if (!indices) {
829 SkDebugf("Could not allocate indices\n");
830 return;
831 }
832 }
833
834 int indexOffset = 0;
835 int vertexOffset = 0;
836 for (int i = 0; i < instanceCount; i++) {
837 const Geometry& args = fGeoData[i];
838
839 // TODO we can actually cache this interleaved and then just memcopy
840 if (this->hasIndices()) {
841 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
842 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
843 }
844 }
845
846 for (int j = 0; j < args.fPositions.count(); ++j) {
847 *((SkPoint*)verts) = args.fPositions[j];
848 if (this->hasColors()) {
849 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
850 }
851 if (this->hasLocalCoords()) {
852 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
853 }
854 verts = (void*)((intptr_t)verts + vertexStride);
855 vertexOffset++;
856 }
857 }
858
859 GrVertices vertices;
860 if (this->hasIndices()) {
861 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
862 firstIndex, this->vertexCount(), this->indexCount());
863
864 } else {
865 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
866 }
867 batchTarget->draw(vertices);
868 }
869
geoData()870 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
871
872 private:
DrawVerticesBatch(const Geometry & geometry,GrPrimitiveType primitiveType,const SkMatrix & viewMatrix,const SkPoint * positions,int vertexCount,const uint16_t * indices,int indexCount,const GrColor * colors,const SkPoint * localCoords,const SkRect & bounds)873 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
874 const SkMatrix& viewMatrix,
875 const SkPoint* positions, int vertexCount,
876 const uint16_t* indices, int indexCount,
877 const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
878 this->initClassID<DrawVerticesBatch>();
879 SkASSERT(positions);
880
881 fBatch.fViewMatrix = viewMatrix;
882 Geometry& installedGeo = fGeoData.push_back(geometry);
883
884 installedGeo.fPositions.append(vertexCount, positions);
885 if (indices) {
886 installedGeo.fIndices.append(indexCount, indices);
887 fBatch.fHasIndices = true;
888 } else {
889 fBatch.fHasIndices = false;
890 }
891
892 if (colors) {
893 installedGeo.fColors.append(vertexCount, colors);
894 fBatch.fHasColors = true;
895 } else {
896 fBatch.fHasColors = false;
897 }
898
899 if (localCoords) {
900 installedGeo.fLocalCoords.append(vertexCount, localCoords);
901 fBatch.fHasLocalCoords = true;
902 } else {
903 fBatch.fHasLocalCoords = false;
904 }
905 fBatch.fVertexCount = vertexCount;
906 fBatch.fIndexCount = indexCount;
907 fBatch.fPrimitiveType = primitiveType;
908
909 this->setBounds(bounds);
910 }
911
primitiveType() const912 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
batchablePrimitiveType() const913 bool batchablePrimitiveType() const {
914 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
915 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
916 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
917 }
color() const918 GrColor color() const { return fBatch.fColor; }
usesLocalCoords() const919 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
colorIgnored() const920 bool colorIgnored() const { return fBatch.fColorIgnored; }
viewMatrix() const921 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
hasColors() const922 bool hasColors() const { return fBatch.fHasColors; }
hasIndices() const923 bool hasIndices() const { return fBatch.fHasIndices; }
hasLocalCoords() const924 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
vertexCount() const925 int vertexCount() const { return fBatch.fVertexCount; }
indexCount() const926 int indexCount() const { return fBatch.fIndexCount; }
927
onCombineIfPossible(GrBatch * t)928 bool onCombineIfPossible(GrBatch* t) override {
929 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
930
931 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
932 return false;
933 }
934
935 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
936
937 // We currently use a uniform viewmatrix for this batch
938 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
939 return false;
940 }
941
942 if (this->hasColors() != that->hasColors()) {
943 return false;
944 }
945
946 if (this->hasIndices() != that->hasIndices()) {
947 return false;
948 }
949
950 if (this->hasLocalCoords() != that->hasLocalCoords()) {
951 return false;
952 }
953
954 if (!this->hasColors() && this->color() != that->color()) {
955 return false;
956 }
957
958 if (this->color() != that->color()) {
959 fBatch.fColor = GrColor_ILLEGAL;
960 }
961 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
962 fBatch.fVertexCount += that->vertexCount();
963 fBatch.fIndexCount += that->indexCount();
964
965 this->joinBounds(that->bounds());
966 return true;
967 }
968
969 struct BatchTracker {
970 GrPrimitiveType fPrimitiveType;
971 SkMatrix fViewMatrix;
972 GrColor fColor;
973 bool fUsesLocalCoords;
974 bool fColorIgnored;
975 bool fCoverageIgnored;
976 bool fHasColors;
977 bool fHasIndices;
978 bool fHasLocalCoords;
979 int fVertexCount;
980 int fIndexCount;
981 };
982
983 BatchTracker fBatch;
984 SkSTArray<1, Geometry, true> fGeoData;
985 };
986
drawVertices(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,GrPrimitiveType primitiveType,int vertexCount,const SkPoint positions[],const SkPoint texCoords[],const GrColor colors[],const uint16_t indices[],int indexCount)987 void GrContext::drawVertices(GrRenderTarget* rt,
988 const GrClip& clip,
989 const GrPaint& paint,
990 const SkMatrix& viewMatrix,
991 GrPrimitiveType primitiveType,
992 int vertexCount,
993 const SkPoint positions[],
994 const SkPoint texCoords[],
995 const GrColor colors[],
996 const uint16_t indices[],
997 int indexCount) {
998 RETURN_IF_ABANDONED
999 AutoCheckFlush acf(this);
1000 GrPipelineBuilder pipelineBuilder;
1001
1002 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1003 if (NULL == target) {
1004 return;
1005 }
1006
1007 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
1008
1009 // TODO clients should give us bounds
1010 SkRect bounds;
1011 if (!bounds.setBoundsCheck(positions, vertexCount)) {
1012 SkDebugf("drawVertices call empty bounds\n");
1013 return;
1014 }
1015
1016 viewMatrix.mapRect(&bounds);
1017
1018 // If we don't have AA then we outset for a half pixel in each direction to account for
1019 // snapping
1020 if (!paint.isAntiAlias()) {
1021 bounds.outset(0.5f, 0.5f);
1022 }
1023
1024 DrawVerticesBatch::Geometry geometry;
1025 geometry.fColor = paint.getColor();
1026 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
1027 positions, vertexCount, indices,
1028 indexCount, colors, texCoords,
1029 bounds));
1030
1031 target->drawBatch(&pipelineBuilder, batch);
1032 }
1033
1034 ///////////////////////////////////////////////////////////////////////////////
1035
drawRRect(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStrokeInfo & strokeInfo)1036 void GrContext::drawRRect(GrRenderTarget*rt,
1037 const GrClip& clip,
1038 const GrPaint& paint,
1039 const SkMatrix& viewMatrix,
1040 const SkRRect& rrect,
1041 const GrStrokeInfo& strokeInfo) {
1042 RETURN_IF_ABANDONED
1043 if (rrect.isEmpty()) {
1044 return;
1045 }
1046
1047 if (strokeInfo.isDashed()) {
1048 SkPath path;
1049 path.addRRect(rrect);
1050 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
1051 return;
1052 }
1053
1054 AutoCheckFlush acf(this);
1055 GrPipelineBuilder pipelineBuilder;
1056 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1057 if (NULL == target) {
1058 return;
1059 }
1060
1061 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1062
1063 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1064
1065 GrColor color = paint.getColor();
1066 if (!fOvalRenderer->drawRRect(target,
1067 &pipelineBuilder,
1068 color,
1069 viewMatrix,
1070 paint.isAntiAlias(),
1071 rrect,
1072 strokeRec)) {
1073 SkPath path;
1074 path.addRRect(rrect);
1075 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1076 path, strokeInfo);
1077 }
1078 }
1079
1080 ///////////////////////////////////////////////////////////////////////////////
1081
drawDRRect(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1082 void GrContext::drawDRRect(GrRenderTarget* rt,
1083 const GrClip& clip,
1084 const GrPaint& paint,
1085 const SkMatrix& viewMatrix,
1086 const SkRRect& outer,
1087 const SkRRect& inner) {
1088 RETURN_IF_ABANDONED
1089 if (outer.isEmpty()) {
1090 return;
1091 }
1092
1093 AutoCheckFlush acf(this);
1094 GrPipelineBuilder pipelineBuilder;
1095 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1096
1097 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1098
1099 GrColor color = paint.getColor();
1100 if (!fOvalRenderer->drawDRRect(target,
1101 &pipelineBuilder,
1102 color,
1103 viewMatrix,
1104 paint.isAntiAlias(),
1105 outer,
1106 inner)) {
1107 SkPath path;
1108 path.addRRect(inner);
1109 path.addRRect(outer);
1110 path.setFillType(SkPath::kEvenOdd_FillType);
1111
1112 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
1113 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1114 path, fillRec);
1115 }
1116 }
1117
1118 ///////////////////////////////////////////////////////////////////////////////
1119
drawOval(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & oval,const GrStrokeInfo & strokeInfo)1120 void GrContext::drawOval(GrRenderTarget* rt,
1121 const GrClip& clip,
1122 const GrPaint& paint,
1123 const SkMatrix& viewMatrix,
1124 const SkRect& oval,
1125 const GrStrokeInfo& strokeInfo) {
1126 RETURN_IF_ABANDONED
1127 if (oval.isEmpty()) {
1128 return;
1129 }
1130
1131 if (strokeInfo.isDashed()) {
1132 SkPath path;
1133 path.addOval(oval);
1134 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
1135 return;
1136 }
1137
1138 AutoCheckFlush acf(this);
1139 GrPipelineBuilder pipelineBuilder;
1140 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1141 if (NULL == target) {
1142 return;
1143 }
1144
1145 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1146
1147 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1148
1149 GrColor color = paint.getColor();
1150 if (!fOvalRenderer->drawOval(target,
1151 &pipelineBuilder,
1152 color,
1153 viewMatrix,
1154 paint.isAntiAlias(),
1155 oval,
1156 strokeRec)) {
1157 SkPath path;
1158 path.addOval(oval);
1159 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1160 path, strokeInfo);
1161 }
1162 }
1163
1164 // Can 'path' be drawn as a pair of filled nested rectangles?
is_nested_rects(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,GrColor color,const SkMatrix & viewMatrix,const SkPath & path,const SkStrokeRec & stroke,SkRect rects[2])1165 static bool is_nested_rects(GrDrawTarget* target,
1166 GrPipelineBuilder* pipelineBuilder,
1167 GrColor color,
1168 const SkMatrix& viewMatrix,
1169 const SkPath& path,
1170 const SkStrokeRec& stroke,
1171 SkRect rects[2]) {
1172 SkASSERT(stroke.isFillStyle());
1173
1174 if (path.isInverseFillType()) {
1175 return false;
1176 }
1177
1178 // TODO: this restriction could be lifted if we were willing to apply
1179 // the matrix to all the points individually rather than just to the rect
1180 if (!viewMatrix.preservesAxisAlignment()) {
1181 return false;
1182 }
1183
1184 SkPath::Direction dirs[2];
1185 if (!path.isNestedFillRects(rects, dirs)) {
1186 return false;
1187 }
1188
1189 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1190 // The two rects need to be wound opposite to each other
1191 return false;
1192 }
1193
1194 // Right now, nested rects where the margin is not the same width
1195 // all around do not render correctly
1196 const SkScalar* outer = rects[0].asScalars();
1197 const SkScalar* inner = rects[1].asScalars();
1198
1199 bool allEq = true;
1200
1201 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1202 bool allGoE1 = margin >= SK_Scalar1;
1203
1204 for (int i = 1; i < 4; ++i) {
1205 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1206 if (temp < SK_Scalar1) {
1207 allGoE1 = false;
1208 }
1209 if (!SkScalarNearlyEqual(margin, temp)) {
1210 allEq = false;
1211 }
1212 }
1213
1214 return allEq || allGoE1;
1215 }
1216
drawPath(GrRenderTarget * rt,const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & strokeInfo)1217 void GrContext::drawPath(GrRenderTarget* rt,
1218 const GrClip& clip,
1219 const GrPaint& paint,
1220 const SkMatrix& viewMatrix,
1221 const SkPath& path,
1222 const GrStrokeInfo& strokeInfo) {
1223 RETURN_IF_ABANDONED
1224 if (path.isEmpty()) {
1225 if (path.isInverseFillType()) {
1226 this->drawPaint(rt, clip, paint, viewMatrix);
1227 }
1228 return;
1229 }
1230
1231 GrColor color = paint.getColor();
1232
1233 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1234 // Scratch textures can be recycled after they are returned to the texture
1235 // cache. This presents a potential hazard for buffered drawing. However,
1236 // the writePixels that uploads to the scratch will perform a flush so we're
1237 // OK.
1238 AutoCheckFlush acf(this);
1239 GrPipelineBuilder pipelineBuilder;
1240 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1241 if (NULL == target) {
1242 return;
1243 }
1244
1245 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
1246
1247 if (!strokeInfo.isDashed()) {
1248 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1249 bool useCoverageAA = paint.isAntiAlias() &&
1250 !pipelineBuilder.getRenderTarget()->isMultisampled();
1251
1252 if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
1253 // Concave AA paths are expensive - try to avoid them for special cases
1254 SkRect rects[2];
1255
1256 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec,
1257 rects)) {
1258 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix,
1259 rects);
1260 return;
1261 }
1262 }
1263 SkRect ovalRect;
1264 bool isOval = path.isOval(&ovalRect);
1265
1266 if (isOval && !path.isInverseFillType()) {
1267 if (fOvalRenderer->drawOval(target,
1268 &pipelineBuilder,
1269 color,
1270 viewMatrix,
1271 paint.isAntiAlias(),
1272 ovalRect,
1273 strokeRec)) {
1274 return;
1275 }
1276 }
1277 }
1278 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1279 path, strokeInfo);
1280 }
1281
internalDrawPath(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,const SkMatrix & viewMatrix,GrColor color,bool useAA,const SkPath & path,const GrStrokeInfo & strokeInfo)1282 void GrContext::internalDrawPath(GrDrawTarget* target,
1283 GrPipelineBuilder* pipelineBuilder,
1284 const SkMatrix& viewMatrix,
1285 GrColor color,
1286 bool useAA,
1287 const SkPath& path,
1288 const GrStrokeInfo& strokeInfo) {
1289 RETURN_IF_ABANDONED
1290 SkASSERT(!path.isEmpty());
1291
1292 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1293
1294
1295 // An Assumption here is that path renderer would use some form of tweaking
1296 // the src color (either the input alpha or in the frag shader) to implement
1297 // aa. If we have some future driver-mojo path AA that can do the right
1298 // thing WRT to the blend then we'll need some query on the PR.
1299 bool useCoverageAA = useAA &&
1300 !pipelineBuilder->getRenderTarget()->isMultisampled();
1301
1302
1303 GrPathRendererChain::DrawType type =
1304 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1305 GrPathRendererChain::kColor_DrawType;
1306
1307 const SkPath* pathPtr = &path;
1308 SkTLazy<SkPath> tmpPath;
1309 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
1310
1311 // Try a 1st time without stroking the path and without allowing the SW renderer
1312 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1313 *strokeInfoPtr, false, type);
1314
1315 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
1316 if (NULL == pr && strokeInfo.isDashed()) {
1317 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
1318 if (!strokeInfo.applyDash(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
1319 return;
1320 }
1321 pathPtr = tmpPath.get();
1322 if (pathPtr->isEmpty()) {
1323 return;
1324 }
1325 strokeInfoPtr = &dashlessStrokeInfo;
1326 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1327 false, type);
1328 }
1329
1330 if (NULL == pr) {
1331 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
1332 !strokeInfoPtr->isFillStyle()) {
1333 // It didn't work above, so try again with stroke converted to a fill.
1334 if (!tmpPath.isValid()) {
1335 tmpPath.init();
1336 }
1337 SkStrokeRec* strokeRec = dashlessStrokeInfo.getStrokeRecPtr();
1338 strokeRec->setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
1339 if (!strokeRec->applyToPath(tmpPath.get(), *pathPtr)) {
1340 return;
1341 }
1342 pathPtr = tmpPath.get();
1343 if (pathPtr->isEmpty()) {
1344 return;
1345 }
1346 strokeRec->setFillStyle();
1347 strokeInfoPtr = &dashlessStrokeInfo;
1348 }
1349
1350 // This time, allow SW renderer
1351 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1352 true, type);
1353 }
1354
1355 if (NULL == pr) {
1356 #ifdef SK_DEBUG
1357 SkDebugf("Unable to find path renderer compatible with path.\n");
1358 #endif
1359 return;
1360 }
1361
1362 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
1363 }
1364
1365 ////////////////////////////////////////////////////////////////////////////////
1366
flush(int flagsBitfield)1367 void GrContext::flush(int flagsBitfield) {
1368 if (NULL == fDrawBuffer) {
1369 return;
1370 }
1371
1372 if (kDiscard_FlushBit & flagsBitfield) {
1373 fDrawBuffer->reset();
1374 } else {
1375 fDrawBuffer->flush();
1376 }
1377 fResourceCache->notifyFlushOccurred();
1378 fFlushToReduceCacheSize = false;
1379 }
1380
sw_convert_to_premul(GrPixelConfig srcConfig,int width,int height,size_t inRowBytes,const void * inPixels,size_t outRowBytes,void * outPixels)1381 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1382 const void* inPixels, size_t outRowBytes, void* outPixels) {
1383 SkSrcPixelInfo srcPI;
1384 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
1385 return false;
1386 }
1387 srcPI.fAlphaType = kUnpremul_SkAlphaType;
1388 srcPI.fPixels = inPixels;
1389 srcPI.fRowBytes = inRowBytes;
1390
1391 SkDstPixelInfo dstPI;
1392 dstPI.fColorType = srcPI.fColorType;
1393 dstPI.fAlphaType = kPremul_SkAlphaType;
1394 dstPI.fPixels = outPixels;
1395 dstPI.fRowBytes = outRowBytes;
1396
1397 return srcPI.convertPixelsTo(&dstPI, width, height);
1398 }
1399
writeSurfacePixels(GrSurface * surface,int left,int top,int width,int height,GrPixelConfig srcConfig,const void * buffer,size_t rowBytes,uint32_t pixelOpsFlags)1400 bool GrContext::writeSurfacePixels(GrSurface* surface,
1401 int left, int top, int width, int height,
1402 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
1403 uint32_t pixelOpsFlags) {
1404 RETURN_FALSE_IF_ABANDONED
1405 {
1406 GrTexture* texture = NULL;
1407 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
1408 fGpu->canWriteTexturePixels(texture, srcConfig)) {
1409
1410 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
1411 surface->surfacePriv().hasPendingIO()) {
1412 this->flush();
1413 }
1414 return fGpu->writeTexturePixels(texture, left, top, width, height,
1415 srcConfig, buffer, rowBytes);
1416 // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
1417 // upload is already flushed.
1418 }
1419 }
1420
1421 // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
1422 GrRenderTarget* renderTarget = surface->asRenderTarget();
1423 if (NULL == renderTarget) {
1424 return false;
1425 }
1426
1427 // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1428 // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1429 // config. This scratch will then have R and B swapped. We correct for this by swapping again
1430 // when drawing the scratch to the dst using a conversion effect.
1431 bool swapRAndB = false;
1432 GrPixelConfig writeConfig = srcConfig;
1433 if (GrPixelConfigSwapRAndB(srcConfig) ==
1434 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
1435 writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1436 swapRAndB = true;
1437 }
1438
1439 GrSurfaceDesc desc;
1440 desc.fWidth = width;
1441 desc.fHeight = height;
1442 desc.fConfig = writeConfig;
1443 SkAutoTUnref<GrTexture> texture(this->textureProvider()->refScratchTexture(desc,
1444 GrTextureProvider::kApprox_ScratchTexMatch));
1445 if (!texture) {
1446 return false;
1447 }
1448
1449 SkAutoTUnref<const GrFragmentProcessor> fp;
1450 SkMatrix textureMatrix;
1451 textureMatrix.setIDiv(texture->width(), texture->height());
1452
1453 // allocate a tmp buffer and sw convert the pixels to premul
1454 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1455
1456 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
1457 if (!GrPixelConfigIs8888(srcConfig)) {
1458 return false;
1459 }
1460 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1461 // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1462 if (NULL == fp) {
1463 size_t tmpRowBytes = 4 * width;
1464 tmpPixels.reset(width * height);
1465 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
1466 tmpPixels.get())) {
1467 return false;
1468 }
1469 rowBytes = tmpRowBytes;
1470 buffer = tmpPixels.get();
1471 }
1472 }
1473 if (NULL == fp) {
1474 fp.reset(GrConfigConversionEffect::Create(texture,
1475 swapRAndB,
1476 GrConfigConversionEffect::kNone_PMConversion,
1477 textureMatrix));
1478 }
1479
1480 // Even if the client told us not to flush, we still flush here. The client may have known that
1481 // writes to the original surface caused no data hazards, but they can't know that the scratch
1482 // we just got is safe.
1483 if (texture->surfacePriv().hasPendingIO()) {
1484 this->flush();
1485 }
1486 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1487 writeConfig, buffer, rowBytes)) {
1488 return false;
1489 }
1490
1491 SkMatrix matrix;
1492 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1493
1494 // This function can be called in the midst of drawing another object (e.g., when uploading a
1495 // SW-rasterized clip while issuing a draw). So we push the current geometry state before
1496 // drawing a rect to the render target.
1497 // The bracket ensures we pop the stack if we wind up flushing below.
1498 {
1499 GrDrawTarget* drawTarget = this->prepareToDraw();
1500 if (!drawTarget) {
1501 return false;
1502 }
1503
1504 GrPipelineBuilder pipelineBuilder;
1505 pipelineBuilder.addColorProcessor(fp);
1506 pipelineBuilder.setRenderTarget(renderTarget);
1507 drawTarget->drawSimpleRect(&pipelineBuilder,
1508 GrColor_WHITE,
1509 matrix,
1510 SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
1511 }
1512
1513 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1514 this->flushSurfaceWrites(surface);
1515 }
1516
1517 return true;
1518 }
1519
1520 // toggles between RGBA and BGRA
toggle_colortype32(SkColorType ct)1521 static SkColorType toggle_colortype32(SkColorType ct) {
1522 if (kRGBA_8888_SkColorType == ct) {
1523 return kBGRA_8888_SkColorType;
1524 } else {
1525 SkASSERT(kBGRA_8888_SkColorType == ct);
1526 return kRGBA_8888_SkColorType;
1527 }
1528 }
1529
readRenderTargetPixels(GrRenderTarget * target,int left,int top,int width,int height,GrPixelConfig dstConfig,void * buffer,size_t rowBytes,uint32_t flags)1530 bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1531 int left, int top, int width, int height,
1532 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
1533 uint32_t flags) {
1534 RETURN_FALSE_IF_ABANDONED
1535 ASSERT_OWNED_RESOURCE(target);
1536 SkASSERT(target);
1537
1538 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
1539 this->flush();
1540 }
1541
1542 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
1543
1544 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1545 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1546 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
1547 width, height, dstConfig,
1548 rowBytes);
1549 // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1550 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1551 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1552 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1553 // dstConfig.
1554 GrPixelConfig readConfig = dstConfig;
1555 bool swapRAndB = false;
1556 if (GrPixelConfigSwapRAndB(dstConfig) ==
1557 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
1558 readConfig = GrPixelConfigSwapRAndB(readConfig);
1559 swapRAndB = true;
1560 }
1561
1562 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
1563
1564 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
1565 // The unpremul flag is only allowed for these two configs.
1566 return false;
1567 }
1568
1569 SkAutoTUnref<GrTexture> tempTexture;
1570
1571 // If the src is a texture and we would have to do conversions after read pixels, we instead
1572 // do the conversions by drawing the src to a scratch texture. If we handle any of the
1573 // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1574 // on the read back pixels.
1575 GrTexture* src = target->asTexture();
1576 if (src && (swapRAndB || unpremul || flipY)) {
1577 // Make the scratch a render so we can read its pixels.
1578 GrSurfaceDesc desc;
1579 desc.fFlags = kRenderTarget_GrSurfaceFlag;
1580 desc.fWidth = width;
1581 desc.fHeight = height;
1582 desc.fConfig = readConfig;
1583 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1584
1585 // When a full read back is faster than a partial we could always make the scratch exactly
1586 // match the passed rect. However, if we see many different size rectangles we will trash
1587 // our texture cache and pay the cost of creating and destroying many textures. So, we only
1588 // request an exact match when the caller is reading an entire RT.
1589 GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch;
1590 if (0 == left &&
1591 0 == top &&
1592 target->width() == width &&
1593 target->height() == height &&
1594 fGpu->fullReadPixelsIsFasterThanPartial()) {
1595 match = GrTextureProvider::kExact_ScratchTexMatch;
1596 }
1597 tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match));
1598 if (tempTexture) {
1599 // compute a matrix to perform the draw
1600 SkMatrix textureMatrix;
1601 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1602 textureMatrix.postIDiv(src->width(), src->height());
1603
1604 SkAutoTUnref<const GrFragmentProcessor> fp;
1605 if (unpremul) {
1606 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1607 if (fp) {
1608 unpremul = false; // we no longer need to do this on CPU after the read back.
1609 }
1610 }
1611 // If we failed to create a PM->UPM effect and have no other conversions to perform then
1612 // there is no longer any point to using the scratch.
1613 if (fp || flipY || swapRAndB) {
1614 if (!fp) {
1615 fp.reset(GrConfigConversionEffect::Create(
1616 src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1617 textureMatrix));
1618 }
1619 swapRAndB = false; // we will handle the swap in the draw.
1620
1621 // We protect the existing geometry here since it may not be
1622 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1623 // can be invoked in this method
1624 {
1625 GrPipelineBuilder pipelineBuilder;
1626 SkASSERT(fp);
1627 pipelineBuilder.addColorProcessor(fp);
1628
1629 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
1630 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1631 fDrawBuffer->drawSimpleRect(&pipelineBuilder,
1632 GrColor_WHITE,
1633 SkMatrix::I(),
1634 rect);
1635 // we want to read back from the scratch's origin
1636 left = 0;
1637 top = 0;
1638 target = tempTexture->asRenderTarget();
1639 }
1640 this->flushSurfaceWrites(target);
1641 }
1642 }
1643 }
1644
1645 if (!fGpu->readPixels(target,
1646 left, top, width, height,
1647 readConfig, buffer, rowBytes)) {
1648 return false;
1649 }
1650 // Perform any conversions we weren't able to perform using a scratch texture.
1651 if (unpremul || swapRAndB) {
1652 SkDstPixelInfo dstPI;
1653 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
1654 return false;
1655 }
1656 dstPI.fAlphaType = kUnpremul_SkAlphaType;
1657 dstPI.fPixels = buffer;
1658 dstPI.fRowBytes = rowBytes;
1659
1660 SkSrcPixelInfo srcPI;
1661 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1662 srcPI.fAlphaType = kPremul_SkAlphaType;
1663 srcPI.fPixels = buffer;
1664 srcPI.fRowBytes = rowBytes;
1665
1666 return srcPI.convertPixelsTo(&dstPI, width, height);
1667 }
1668 return true;
1669 }
1670
prepareSurfaceForExternalRead(GrSurface * surface)1671 void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
1672 RETURN_IF_ABANDONED
1673 SkASSERT(surface);
1674 ASSERT_OWNED_RESOURCE(surface);
1675 if (surface->surfacePriv().hasPendingIO()) {
1676 this->flush();
1677 }
1678 GrRenderTarget* rt = surface->asRenderTarget();
1679 if (fGpu && rt) {
1680 fGpu->resolveRenderTarget(rt);
1681 }
1682 }
1683
discardRenderTarget(GrRenderTarget * renderTarget)1684 void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
1685 RETURN_IF_ABANDONED
1686 SkASSERT(renderTarget);
1687 ASSERT_OWNED_RESOURCE(renderTarget);
1688 AutoCheckFlush acf(this);
1689 GrDrawTarget* target = this->prepareToDraw();
1690 if (NULL == target) {
1691 return;
1692 }
1693 target->discard(renderTarget);
1694 }
1695
copySurface(GrSurface * dst,GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint,uint32_t pixelOpsFlags)1696 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1697 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
1698 RETURN_IF_ABANDONED
1699 if (NULL == src || NULL == dst) {
1700 return;
1701 }
1702 ASSERT_OWNED_RESOURCE(src);
1703 ASSERT_OWNED_RESOURCE(dst);
1704
1705 // Since we're going to the draw target and not GPU, no need to check kNoFlush
1706 // here.
1707
1708 GrDrawTarget* target = this->prepareToDraw();
1709 if (NULL == target) {
1710 return;
1711 }
1712 target->copySurface(dst, src, srcRect, dstPoint);
1713
1714 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1715 this->flush();
1716 }
1717 }
1718
flushSurfaceWrites(GrSurface * surface)1719 void GrContext::flushSurfaceWrites(GrSurface* surface) {
1720 RETURN_IF_ABANDONED
1721 if (surface->surfacePriv().hasPendingWrite()) {
1722 this->flush();
1723 }
1724 }
1725
prepareToDraw(GrPipelineBuilder * pipelineBuilder,GrRenderTarget * rt,const GrClip & clip,const GrPaint * paint,const AutoCheckFlush * acf)1726 GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
1727 GrRenderTarget* rt,
1728 const GrClip& clip,
1729 const GrPaint* paint,
1730 const AutoCheckFlush* acf) {
1731 if (NULL == fGpu || NULL == fDrawBuffer) {
1732 return NULL;
1733 }
1734
1735 ASSERT_OWNED_RESOURCE(rt);
1736 SkASSERT(rt && paint && acf);
1737 pipelineBuilder->setFromPaint(*paint, rt, clip);
1738 return fDrawBuffer;
1739 }
1740
prepareToDraw()1741 GrDrawTarget* GrContext::prepareToDraw() {
1742 if (NULL == fGpu) {
1743 return NULL;
1744 }
1745 return fDrawBuffer;
1746 }
1747
1748 /*
1749 * This method finds a path renderer that can draw the specified path on
1750 * the provided target.
1751 * Due to its expense, the software path renderer has split out so it can
1752 * can be individually allowed/disallowed via the "allowSW" boolean.
1753 */
getPathRenderer(const GrDrawTarget * target,const GrPipelineBuilder * pipelineBuilder,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & stroke,bool allowSW,GrPathRendererChain::DrawType drawType,GrPathRendererChain::StencilSupport * stencilSupport)1754 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1755 const GrPipelineBuilder* pipelineBuilder,
1756 const SkMatrix& viewMatrix,
1757 const SkPath& path,
1758 const GrStrokeInfo& stroke,
1759 bool allowSW,
1760 GrPathRendererChain::DrawType drawType,
1761 GrPathRendererChain::StencilSupport* stencilSupport) {
1762
1763 if (NULL == fPathRendererChain) {
1764 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
1765 }
1766
1767 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
1768 pipelineBuilder,
1769 viewMatrix,
1770 path,
1771 stroke,
1772 drawType,
1773 stencilSupport);
1774
1775 if (NULL == pr && allowSW) {
1776 if (NULL == fSoftwarePathRenderer) {
1777 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
1778 }
1779 pr = fSoftwarePathRenderer;
1780 }
1781
1782 return pr;
1783 }
1784
1785 ////////////////////////////////////////////////////////////////////////////////
isConfigRenderable(GrPixelConfig config,bool withMSAA) const1786 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1787 return fGpu->caps()->isConfigRenderable(config, withMSAA);
1788 }
1789
getRecommendedSampleCount(GrPixelConfig config,SkScalar dpi) const1790 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1791 SkScalar dpi) const {
1792 if (!this->isConfigRenderable(config, true)) {
1793 return 0;
1794 }
1795 int chosenSampleCount = 0;
1796 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
1797 if (dpi >= 250.0f) {
1798 chosenSampleCount = 4;
1799 } else {
1800 chosenSampleCount = 16;
1801 }
1802 }
1803 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1804 chosenSampleCount : 0;
1805 }
1806
getTextTarget()1807 GrDrawTarget* GrContext::getTextTarget() {
1808 return this->prepareToDraw();
1809 }
1810
1811 namespace {
test_pm_conversions(GrContext * ctx,int * pmToUPMValue,int * upmToPMValue)1812 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1813 GrConfigConversionEffect::PMConversion pmToUPM;
1814 GrConfigConversionEffect::PMConversion upmToPM;
1815 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1816 *pmToUPMValue = pmToUPM;
1817 *upmToPMValue = upmToPM;
1818 }
1819 }
1820
createPMToUPMEffect(GrTexture * texture,bool swapRAndB,const SkMatrix & matrix)1821 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1822 bool swapRAndB,
1823 const SkMatrix& matrix) {
1824 if (!fDidTestPMConversions) {
1825 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1826 fDidTestPMConversions = true;
1827 }
1828 GrConfigConversionEffect::PMConversion pmToUPM =
1829 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1830 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
1831 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
1832 } else {
1833 return NULL;
1834 }
1835 }
1836
createUPMToPMEffect(GrTexture * texture,bool swapRAndB,const SkMatrix & matrix)1837 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1838 bool swapRAndB,
1839 const SkMatrix& matrix) {
1840 if (!fDidTestPMConversions) {
1841 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1842 fDidTestPMConversions = true;
1843 }
1844 GrConfigConversionEffect::PMConversion upmToPM =
1845 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1846 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
1847 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
1848 } else {
1849 return NULL;
1850 }
1851 }
1852
1853 //////////////////////////////////////////////////////////////////////////////
1854
getResourceCacheLimits(int * maxTextures,size_t * maxTextureBytes) const1855 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
1856 if (maxTextures) {
1857 *maxTextures = fResourceCache->getMaxResourceCount();
1858 }
1859 if (maxTextureBytes) {
1860 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
1861 }
1862 }
1863
setResourceCacheLimits(int maxTextures,size_t maxTextureBytes)1864 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
1865 fResourceCache->setLimits(maxTextures, maxTextureBytes);
1866 }
1867
1868 //////////////////////////////////////////////////////////////////////////////
1869
addGpuTraceMarker(const GrGpuTraceMarker * marker)1870 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1871 fGpu->addGpuTraceMarker(marker);
1872 if (fDrawBuffer) {
1873 fDrawBuffer->addGpuTraceMarker(marker);
1874 }
1875 }
1876
removeGpuTraceMarker(const GrGpuTraceMarker * marker)1877 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
1878 fGpu->removeGpuTraceMarker(marker);
1879 if (fDrawBuffer) {
1880 fDrawBuffer->removeGpuTraceMarker(marker);
1881 }
1882 }
1883
1884 ///////////////////////////////////////////////////////////////////////////////////////////////////
1885
1886 #ifdef GR_TEST_UTILS
1887
BATCH_TEST_DEFINE(StrokeRectBatch)1888 BATCH_TEST_DEFINE(StrokeRectBatch) {
1889 StrokeRectBatch::Geometry geometry;
1890 geometry.fViewMatrix = GrTest::TestMatrix(random);
1891 geometry.fColor = GrRandomColor(random);
1892 geometry.fRect = GrTest::TestRect(random);
1893 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f;
1894
1895 return StrokeRectBatch::Create(geometry, random->nextBool());
1896 }
1897
seed_vertices(GrPrimitiveType type)1898 static uint32_t seed_vertices(GrPrimitiveType type) {
1899 switch (type) {
1900 case kTriangles_GrPrimitiveType:
1901 case kTriangleStrip_GrPrimitiveType:
1902 case kTriangleFan_GrPrimitiveType:
1903 return 3;
1904 case kPoints_GrPrimitiveType:
1905 return 1;
1906 case kLines_GrPrimitiveType:
1907 case kLineStrip_GrPrimitiveType:
1908 return 2;
1909 }
1910 SkFAIL("Incomplete switch\n");
1911 return 0;
1912 }
1913
primitive_vertices(GrPrimitiveType type)1914 static uint32_t primitive_vertices(GrPrimitiveType type) {
1915 switch (type) {
1916 case kTriangles_GrPrimitiveType:
1917 return 3;
1918 case kLines_GrPrimitiveType:
1919 return 2;
1920 case kTriangleStrip_GrPrimitiveType:
1921 case kTriangleFan_GrPrimitiveType:
1922 case kPoints_GrPrimitiveType:
1923 case kLineStrip_GrPrimitiveType:
1924 return 1;
1925 }
1926 SkFAIL("Incomplete switch\n");
1927 return 0;
1928 }
1929
random_point(SkRandom * random,SkScalar min,SkScalar max)1930 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
1931 SkPoint p;
1932 p.fX = random->nextRangeScalar(min, max);
1933 p.fY = random->nextRangeScalar(min, max);
1934 return p;
1935 }
1936
randomize_params(size_t count,size_t maxVertex,SkScalar min,SkScalar max,SkRandom * random,SkTArray<SkPoint> * positions,SkTArray<SkPoint> * texCoords,bool hasTexCoords,SkTArray<GrColor> * colors,bool hasColors,SkTArray<uint16_t> * indices,bool hasIndices)1937 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
1938 SkRandom* random,
1939 SkTArray<SkPoint>* positions,
1940 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
1941 SkTArray<GrColor>* colors, bool hasColors,
1942 SkTArray<uint16_t>* indices, bool hasIndices) {
1943 for (uint32_t v = 0; v < count; v++) {
1944 positions->push_back(random_point(random, min, max));
1945 if (hasTexCoords) {
1946 texCoords->push_back(random_point(random, min, max));
1947 }
1948 if (hasColors) {
1949 colors->push_back(GrRandomColor(random));
1950 }
1951 if (hasIndices) {
1952 SkASSERT(maxVertex <= SK_MaxU16);
1953 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
1954 }
1955 }
1956 }
1957
BATCH_TEST_DEFINE(VerticesBatch)1958 BATCH_TEST_DEFINE(VerticesBatch) {
1959 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
1960 uint32_t primitiveCount = random->nextRangeU(1, 100);
1961
1962 // TODO make 'sensible' indexbuffers
1963 SkTArray<SkPoint> positions;
1964 SkTArray<SkPoint> texCoords;
1965 SkTArray<GrColor> colors;
1966 SkTArray<uint16_t> indices;
1967
1968 bool hasTexCoords = random->nextBool();
1969 bool hasIndices = random->nextBool();
1970 bool hasColors = random->nextBool();
1971
1972 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
1973
1974 static const SkScalar kMinVertExtent = -100.f;
1975 static const SkScalar kMaxVertExtent = 100.f;
1976 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1977 random,
1978 &positions,
1979 &texCoords, hasTexCoords,
1980 &colors, hasColors,
1981 &indices, hasIndices);
1982
1983 for (uint32_t i = 1; i < primitiveCount; i++) {
1984 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1985 random,
1986 &positions,
1987 &texCoords, hasTexCoords,
1988 &colors, hasColors,
1989 &indices, hasIndices);
1990 }
1991
1992 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1993 SkRect bounds;
1994 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
1995 SkASSERT(result);
1996
1997 viewMatrix.mapRect(&bounds);
1998
1999 DrawVerticesBatch::Geometry geometry;
2000 geometry.fColor = GrRandomColor(random);
2001 return DrawVerticesBatch::Create(geometry, type, viewMatrix,
2002 positions.begin(), vertexCount,
2003 indices.begin(), hasIndices ? vertexCount : 0,
2004 colors.begin(),
2005 texCoords.begin(),
2006 bounds);
2007 }
2008
2009 #endif
2010