OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrContext.h" | |
10 | |
11 #include "GrAARectRenderer.h" | 9 #include "GrAARectRenderer.h" |
12 #include "GrAtlasTextContext.h" | |
13 #include "GrBatch.h" | 10 #include "GrBatch.h" |
14 #include "GrBatchFontCache.h" | |
15 #include "GrBatchTarget.h" | |
16 #include "GrBatchTest.h" | 11 #include "GrBatchTest.h" |
17 #include "GrCaps.h" | |
18 #include "GrContextOptions.h" | |
19 #include "GrDefaultGeoProcFactory.h" | 12 #include "GrDefaultGeoProcFactory.h" |
20 #include "GrGpuResource.h" | 13 #include "GrDrawContext.h" |
21 #include "GrGpuResourcePriv.h" | |
22 #include "GrGpu.h" | |
23 #include "GrImmediateDrawTarget.h" | |
24 #include "GrIndexBuffer.h" | |
25 #include "GrInOrderDrawBuffer.h" | |
26 #include "GrLayerCache.h" | |
27 #include "GrOvalRenderer.h" | 14 #include "GrOvalRenderer.h" |
28 #include "GrPathRenderer.h" | 15 #include "GrPathRenderer.h" |
29 #include "GrPathUtils.h" | |
30 #include "GrRenderTargetPriv.h" | |
31 #include "GrResourceCache.h" | |
32 #include "GrResourceProvider.h" | |
33 #include "GrSoftwarePathRenderer.h" | |
34 #include "GrStencilAndCoverTextContext.h" | |
35 #include "GrStrokeInfo.h" | |
36 #include "GrSurfacePriv.h" | |
37 #include "GrTextBlobCache.h" | |
38 #include "GrTexturePriv.h" | |
39 #include "GrTraceMarker.h" | |
40 #include "GrTracing.h" | |
41 #include "GrVertices.h" | |
42 #include "SkDashPathPriv.h" | |
43 #include "SkConfig8888.h" | |
44 #include "SkGr.h" | |
45 #include "SkRRect.h" | |
46 #include "SkStrokeRec.h" | |
47 #include "SkTLazy.h" | |
48 #include "SkTLS.h" | |
49 #include "SkTraceEvent.h" | |
50 | 16 |
51 #include "effects/GrConfigConversionEffect.h" | 17 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) |
52 #include "effects/GrDashingEffect.h" | 18 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } |
53 #include "effects/GrSingleTextureEffect.h" | 19 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } |
| 20 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } |
54 | 21 |
55 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) | 22 class AutoCheckFlush { |
56 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; } | |
57 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; } | |
58 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; } | |
59 | |
60 class GrContext::AutoCheckFlush { | |
61 public: | 23 public: |
62 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | 24 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} |
63 | 25 ~AutoCheckFlush() { fContext->flushIfNecessary(); } |
64 ~AutoCheckFlush() { | |
65 if (fContext->fFlushToReduceCacheSize) { | |
66 fContext->flush(); | |
67 } | |
68 } | |
69 | 26 |
70 private: | 27 private: |
71 GrContext* fContext; | 28 GrContext* fContext; |
72 }; | 29 }; |
73 | 30 |
74 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
{ | 31 GrDrawContext::GrDrawContext(GrContext* context, GrDrawTarget* drawTarget) |
75 GrContextOptions defaultOptions; | 32 : fContext(context) |
76 return Create(backend, backendContext, defaultOptions); | 33 , fDrawTarget(SkRef(drawTarget)) { |
77 } | 34 } |
78 | 35 |
79 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, | 36 void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src, |
80 const GrContextOptions& options) { | 37 const SkIRect& srcRect, const SkIPoint& dstPoint
) { |
81 GrContext* context = SkNEW(GrContext); | 38 if (!this->prepareToDraw(dst)) { |
82 | |
83 if (context->init(backend, backendContext, options)) { | |
84 return context; | |
85 } else { | |
86 context->unref(); | |
87 return NULL; | |
88 } | |
89 } | |
90 | |
91 static int32_t gNextID = 1; | |
92 static int32_t next_id() { | |
93 int32_t id; | |
94 do { | |
95 id = sk_atomic_inc(&gNextID); | |
96 } while (id == SK_InvalidGenID); | |
97 return id; | |
98 } | |
99 | |
100 GrContext::GrContext() : fUniqueID(next_id()) { | |
101 fGpu = NULL; | |
102 fResourceCache = NULL; | |
103 fResourceProvider = NULL; | |
104 fPathRendererChain = NULL; | |
105 fSoftwarePathRenderer = NULL; | |
106 fBatchFontCache = NULL; | |
107 fDrawBuffer = NULL; | |
108 fFlushToReduceCacheSize = false; | |
109 fAARectRenderer = NULL; | |
110 fOvalRenderer = NULL; | |
111 fMaxTextureSizeOverride = 1 << 20; | |
112 } | |
113 | |
114 bool GrContext::init(GrBackend backend, GrBackendContext backendContext, | |
115 const GrContextOptions& options) { | |
116 SkASSERT(NULL == fGpu); | |
117 | |
118 fGpu = GrGpu::Create(backend, backendContext, options, this); | |
119 if (NULL == fGpu) { | |
120 return false; | |
121 } | |
122 this->initCommon(); | |
123 return true; | |
124 } | |
125 | |
126 void GrContext::initCommon() { | |
127 fResourceCache = SkNEW(GrResourceCache); | |
128 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); | |
129 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); | |
130 | |
131 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); | |
132 | |
133 fAARectRenderer = SkNEW(GrAARectRenderer); | |
134 fOvalRenderer = SkNEW(GrOvalRenderer); | |
135 | |
136 fDidTestPMConversions = false; | |
137 | |
138 #ifdef IMMEDIATE_MODE | |
139 fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this)); | |
140 #else | |
141 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this)); | |
142 #endif | |
143 | |
144 // GrBatchFontCache will eventually replace GrFontCache | |
145 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); | |
146 | |
147 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB,
this))); | |
148 } | |
149 | |
150 GrContext::~GrContext() { | |
151 if (NULL == fGpu) { | |
152 return; | 39 return; |
153 } | 40 } |
154 | 41 |
155 this->flush(); | 42 fDrawTarget->copySurface(dst, src, srcRect, dstPoint); |
156 | |
157 for (int i = 0; i < fCleanUpData.count(); ++i) { | |
158 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); | |
159 } | |
160 | |
161 SkDELETE(fResourceProvider); | |
162 SkDELETE(fResourceCache); | |
163 SkDELETE(fBatchFontCache); | |
164 SkDELETE(fDrawBuffer); | |
165 | |
166 fAARectRenderer->unref(); | |
167 fOvalRenderer->unref(); | |
168 | |
169 fGpu->unref(); | |
170 SkSafeUnref(fPathRendererChain); | |
171 SkSafeUnref(fSoftwarePathRenderer); | |
172 } | 43 } |
173 | 44 |
174 void GrContext::abandonContext() { | 45 void GrDrawContext::drawText(GrPipelineBuilder* pipelineBuilder, GrBatch* batch)
{ |
175 fResourceProvider->abandon(); | 46 fDrawTarget->drawBatch(pipelineBuilder, batch); |
176 // abandon first to so destructors | |
177 // don't try to free the resources in the API. | |
178 fResourceCache->abandonAll(); | |
179 | |
180 fGpu->contextAbandoned(); | |
181 | |
182 // a path renderer may be holding onto resources that | |
183 // are now unusable | |
184 SkSafeSetNull(fPathRendererChain); | |
185 SkSafeSetNull(fSoftwarePathRenderer); | |
186 | |
187 SkDELETE(fDrawBuffer); | |
188 fDrawBuffer = NULL; | |
189 | |
190 fBatchFontCache->freeAll(); | |
191 fLayerCache->freeAll(); | |
192 fTextBlobCache->freeAll(); | |
193 } | 47 } |
194 | 48 |
195 void GrContext::resetContext(uint32_t state) { | 49 void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder, |
196 fGpu->markContextDirty(state); | 50 const GrPathProcessor* pathProc, |
| 51 const GrPathRange* pathRange, |
| 52 const void* indices, |
| 53 int /*GrDrawTarget::PathIndexType*/ indexType, |
| 54 const float transformValues[], |
| 55 int /*GrDrawTarget::PathTransformType*/ transformT
ype, |
| 56 int count, |
| 57 int /*GrPathRendering::FillType*/ fill) { |
| 58 fDrawTarget->drawPaths(pipelineBuilder, pathProc, pathRange, |
| 59 indices, (GrDrawTarget::PathIndexType) indexType, |
| 60 transformValues, |
| 61 (GrDrawTarget::PathTransformType) transformType, |
| 62 count, (GrPathRendering::FillType) fill); |
197 } | 63 } |
198 | 64 |
199 void GrContext::freeGpuResources() { | 65 void GrDrawContext::discard(GrRenderTarget* renderTarget) { |
200 this->flush(); | 66 RETURN_IF_ABANDONED |
201 | 67 SkASSERT(renderTarget); |
202 if (fDrawBuffer) { | 68 AutoCheckFlush acf(fContext); |
203 fDrawBuffer->purgeResources(); | 69 if (!this->prepareToDraw(renderTarget)) { |
| 70 return; |
204 } | 71 } |
205 | 72 fDrawTarget->discard(renderTarget); |
206 fBatchFontCache->freeAll(); | |
207 fLayerCache->freeAll(); | |
208 // a path renderer may be holding onto resources | |
209 SkSafeSetNull(fPathRendererChain); | |
210 SkSafeSetNull(fSoftwarePathRenderer); | |
211 | |
212 fResourceCache->purgeAllUnlocked(); | |
213 } | 73 } |
214 | 74 |
215 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes)
const { | 75 void GrDrawContext::clear(GrRenderTarget* renderTarget, |
216 if (resourceCount) { | 76 const SkIRect* rect, |
217 *resourceCount = fResourceCache->getBudgetedResourceCount(); | 77 const GrColor color, |
| 78 bool canIgnoreRect) { |
| 79 RETURN_IF_ABANDONED |
| 80 SkASSERT(renderTarget); |
| 81 |
| 82 AutoCheckFlush acf(fContext); |
| 83 if (!this->prepareToDraw(renderTarget)) { |
| 84 return; |
218 } | 85 } |
219 if (resourceBytes) { | 86 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget); |
220 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); | |
221 } | |
222 } | 87 } |
223 | 88 |
224 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget, | |
225 SkGpuDevice* gpuDevice, | |
226 const SkDeviceProperties& | |
227 leakyProperties, | |
228 bool enableDistanceFieldFonts) { | |
229 if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMu
ltisampled()) { | |
230 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencil
Attachment(); | |
231 if (sb) { | |
232 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr
operties); | |
233 } | |
234 } | |
235 | 89 |
236 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi
stanceFieldFonts); | 90 void GrDrawContext::drawPaint(GrRenderTarget* rt, |
237 } | 91 const GrClip& clip, |
238 | 92 const GrPaint& origPaint, |
239 //////////////////////////////////////////////////////////////////////////////// | 93 const SkMatrix& viewMatrix) { |
240 | |
241 bool GrContext::isConfigTexturable(GrPixelConfig config) const { | |
242 return fGpu->caps()->isConfigTexturable(config); | |
243 } | |
244 | |
245 bool GrContext::npotTextureTileSupport() const { | |
246 return fGpu->caps()->npotTextureTileSupport(); | |
247 } | |
248 | |
249 void GrContext::OverBudgetCB(void* data) { | |
250 SkASSERT(data); | |
251 | |
252 GrContext* context = reinterpret_cast<GrContext*>(data); | |
253 | |
254 // Flush the InOrderDrawBuffer to possibly free up some textures | |
255 context->fFlushToReduceCacheSize = true; | |
256 } | |
257 | |
258 void GrContext::TextBlobCacheOverBudgetCB(void* data) { | |
259 SkASSERT(data); | |
260 | |
261 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level,
therefore they | |
262 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The
solution is to move | |
263 // drawText calls to below the GrContext level, but this is not trivial beca
use they call | |
264 // drawPath on SkGpuDevice | |
265 GrContext* context = reinterpret_cast<GrContext*>(data); | |
266 context->flush(); | |
267 } | |
268 | |
269 int GrContext::getMaxTextureSize() const { | |
270 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride); | |
271 } | |
272 | |
273 int GrContext::getMaxRenderTargetSize() const { | |
274 return fGpu->caps()->maxRenderTargetSize(); | |
275 } | |
276 | |
277 int GrContext::getMaxSampleCount() const { | |
278 return fGpu->caps()->maxSampleCount(); | |
279 } | |
280 | |
281 /////////////////////////////////////////////////////////////////////////////// | |
282 | |
283 void GrContext::clear(const SkIRect* rect, | |
284 const GrColor color, | |
285 bool canIgnoreRect, | |
286 GrRenderTarget* renderTarget) { | |
287 RETURN_IF_ABANDONED | |
288 ASSERT_OWNED_RESOURCE(renderTarget); | |
289 SkASSERT(renderTarget); | |
290 | |
291 AutoCheckFlush acf(this); | |
292 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this); | |
293 GrDrawTarget* target = this->prepareToDraw(); | |
294 if (NULL == target) { | |
295 return; | |
296 } | |
297 target->clear(rect, color, canIgnoreRect, renderTarget); | |
298 } | |
299 | |
300 void GrContext::drawPaint(GrRenderTarget* rt, | |
301 const GrClip& clip, | |
302 const GrPaint& origPaint, | |
303 const SkMatrix& viewMatrix) { | |
304 RETURN_IF_ABANDONED | 94 RETURN_IF_ABANDONED |
305 // set rect to be big enough to fill the space, but not super-huge, so we | 95 // set rect to be big enough to fill the space, but not super-huge, so we |
306 // don't overflow fixed-point implementations | 96 // don't overflow fixed-point implementations |
307 SkRect r; | 97 SkRect r; |
308 r.setLTRB(0, 0, | 98 r.setLTRB(0, 0, |
309 SkIntToScalar(rt->width()), | 99 SkIntToScalar(rt->width()), |
310 SkIntToScalar(rt->height())); | 100 SkIntToScalar(rt->height())); |
311 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); | 101 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); |
312 | 102 |
313 // by definition this fills the entire clip, no need for AA | 103 // by definition this fills the entire clip, no need for AA |
(...skipping 14 matching lines...) Expand all Loading... |
328 } | 118 } |
329 inverse.mapRect(&r); | 119 inverse.mapRect(&r); |
330 this->drawRect(rt, clip, *paint, viewMatrix, r); | 120 this->drawRect(rt, clip, *paint, viewMatrix, r); |
331 } else { | 121 } else { |
332 SkMatrix localMatrix; | 122 SkMatrix localMatrix; |
333 if (!viewMatrix.invert(&localMatrix)) { | 123 if (!viewMatrix.invert(&localMatrix)) { |
334 SkDebugf("Could not invert matrix\n"); | 124 SkDebugf("Could not invert matrix\n"); |
335 return; | 125 return; |
336 } | 126 } |
337 | 127 |
338 AutoCheckFlush acf(this); | 128 AutoCheckFlush acf(fContext); |
339 GrPipelineBuilder pipelineBuilder; | 129 GrPipelineBuilder pipelineBuilder; |
340 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, p
aint, &acf); | 130 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, paint)) { |
341 if (NULL == target) { | |
342 return; | 131 return; |
343 } | 132 } |
344 | 133 |
345 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target); | 134 fDrawTarget->drawBWRect(&pipelineBuilder, |
346 target->drawRect(&pipelineBuilder, | 135 paint->getColor(), |
347 paint->getColor(), | 136 SkMatrix::I(), |
348 SkMatrix::I(), | 137 r, |
349 r, | 138 NULL, |
350 NULL, | 139 &localMatrix); |
351 &localMatrix); | |
352 } | 140 } |
353 } | 141 } |
354 | 142 |
355 //////////////////////////////////////////////////////////////////////////////// | |
356 | |
357 static inline bool is_irect(const SkRect& r) { | 143 static inline bool is_irect(const SkRect& r) { |
358 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && | 144 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && |
359 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); | 145 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); |
360 } | 146 } |
361 | 147 |
362 static bool apply_aa_to_rect(GrDrawTarget* target, | 148 static bool apply_aa_to_rect(GrDrawTarget* target, |
363 GrPipelineBuilder* pipelineBuilder, | 149 GrPipelineBuilder* pipelineBuilder, |
364 SkRect* devBoundRect, | 150 SkRect* devBoundRect, |
365 const SkRect& rect, | 151 const SkRect& rect, |
366 SkScalar strokeWidth, | 152 SkScalar strokeWidth, |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 bool fHairline; | 352 bool fHairline; |
567 }; | 353 }; |
568 | 354 |
569 const static int kVertsPerHairlineRect = 5; | 355 const static int kVertsPerHairlineRect = 5; |
570 const static int kVertsPerStrokeRect = 10; | 356 const static int kVertsPerStrokeRect = 10; |
571 | 357 |
572 BatchTracker fBatch; | 358 BatchTracker fBatch; |
573 SkSTArray<1, Geometry, true> fGeoData; | 359 SkSTArray<1, Geometry, true> fGeoData; |
574 }; | 360 }; |
575 | 361 |
576 void GrContext::drawRect(GrRenderTarget* rt, | 362 void GrDrawContext::drawRect(GrRenderTarget* rt, |
577 const GrClip& clip, | 363 const GrClip& clip, |
578 const GrPaint& paint, | 364 const GrPaint& paint, |
579 const SkMatrix& viewMatrix, | 365 const SkMatrix& viewMatrix, |
580 const SkRect& rect, | 366 const SkRect& rect, |
581 const GrStrokeInfo* strokeInfo) { | 367 const GrStrokeInfo* strokeInfo) { |
582 RETURN_IF_ABANDONED | 368 RETURN_IF_ABANDONED |
583 if (strokeInfo && strokeInfo->isDashed()) { | 369 if (strokeInfo && strokeInfo->isDashed()) { |
584 SkPath path; | 370 SkPath path; |
585 path.setIsVolatile(true); | 371 path.setIsVolatile(true); |
586 path.addRect(rect); | 372 path.addRect(rect); |
587 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); | 373 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); |
588 return; | 374 return; |
589 } | 375 } |
590 | 376 |
591 AutoCheckFlush acf(this); | 377 AutoCheckFlush acf(fContext); |
592 GrPipelineBuilder pipelineBuilder; | 378 GrPipelineBuilder pipelineBuilder; |
593 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 379 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
594 if (NULL == target) { | |
595 return; | 380 return; |
596 } | 381 } |
597 | 382 |
598 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target); | |
599 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); | 383 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); |
600 | 384 |
601 // Check if this is a full RT draw and can be replaced with a clear. We don'
t bother checking | 385 // Check if this is a full RT draw and can be replaced with a clear. We don'
t bother checking |
602 // cases where the RT is fully inside a stroke. | 386 // cases where the RT is fully inside a stroke. |
603 if (width < 0) { | 387 if (width < 0) { |
604 SkRect rtRect; | 388 SkRect rtRect; |
605 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); | 389 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); |
606 SkRect clipSpaceRTRect = rtRect; | 390 SkRect clipSpaceRTRect = rtRect; |
607 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); | 391 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); |
608 if (checkClip) { | 392 if (checkClip) { |
609 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), | 393 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), |
610 SkIntToScalar(clip.origin().fY)); | 394 SkIntToScalar(clip.origin().fY)); |
611 } | 395 } |
612 // Does the clip contain the entire RT? | 396 // Does the clip contain the entire RT? |
613 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { | 397 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { |
614 SkMatrix invM; | 398 SkMatrix invM; |
615 if (!viewMatrix.invert(&invM)) { | 399 if (!viewMatrix.invert(&invM)) { |
616 return; | 400 return; |
617 } | 401 } |
618 // Does the rect bound the RT? | 402 // Does the rect bound the RT? |
619 SkPoint srcSpaceRTQuad[4]; | 403 SkPoint srcSpaceRTQuad[4]; |
620 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); | 404 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); |
621 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && | 405 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && |
622 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && | 406 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && |
623 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && | 407 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && |
624 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { | 408 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { |
625 // Will it blend? | 409 // Will it blend? |
626 GrColor clearColor; | 410 GrColor clearColor; |
627 if (paint.isOpaqueAndConstantColor(&clearColor)) { | 411 if (paint.isOpaqueAndConstantColor(&clearColor)) { |
628 target->clear(NULL, clearColor, true, rt); | 412 fDrawTarget->clear(NULL, clearColor, true, rt); |
629 return; | 413 return; |
630 } | 414 } |
631 } | 415 } |
632 } | 416 } |
633 } | 417 } |
634 | 418 |
635 GrColor color = paint.getColor(); | 419 GrColor color = paint.getColor(); |
636 SkRect devBoundRect; | 420 SkRect devBoundRect; |
637 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM
ultisampled(); | 421 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM
ultisampled(); |
638 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRe
ct, rect, width, | 422 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBo
undRect, rect, |
639 viewMatrix, color); | 423 width, viewMatrix, color); |
640 | 424 |
641 if (doAA) { | 425 if (doAA) { |
642 if (width >= 0) { | 426 if (width >= 0) { |
643 fAARectRenderer->strokeAARect(target, | 427 GrAARectRenderer::StrokeAARect(fDrawTarget, |
644 &pipelineBuilder, | 428 &pipelineBuilder, |
645 color, | 429 color, |
646 viewMatrix, | 430 viewMatrix, |
647 rect, | 431 rect, |
648 devBoundRect, | 432 devBoundRect, |
649 *strokeInfo); | 433 *strokeInfo); |
650 } else { | 434 } else { |
651 // filled AA rect | 435 // filled AA rect |
652 fAARectRenderer->fillAARect(target, | 436 GrAARectRenderer::FillAARect(fDrawTarget, |
653 &pipelineBuilder, | 437 &pipelineBuilder, |
654 color, | 438 color, |
655 viewMatrix, | 439 viewMatrix, |
656 rect, | 440 rect, |
657 devBoundRect); | 441 devBoundRect); |
658 } | 442 } |
659 return; | 443 return; |
660 } | 444 } |
661 | 445 |
662 if (width >= 0) { | 446 if (width >= 0) { |
663 StrokeRectBatch::Geometry geometry; | 447 StrokeRectBatch::Geometry geometry; |
664 geometry.fViewMatrix = viewMatrix; | 448 geometry.fViewMatrix = viewMatrix; |
665 geometry.fColor = color; | 449 geometry.fColor = color; |
666 geometry.fRect = rect; | 450 geometry.fRect = rect; |
667 geometry.fStrokeWidth = width; | 451 geometry.fStrokeWidth = width; |
668 | 452 |
669 // Non-AA hairlines are snapped to pixel centers to make which pixels ar
e hit deterministic | 453 // Non-AA hairlines are snapped to pixel centers to make which pixels ar
e hit deterministic |
670 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); | 454 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); |
671 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe
lCenters)); | 455 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe
lCenters)); |
672 | 456 |
673 // Depending on sub-pixel coordinates and the particular GPU, we may los
e a corner of | 457 // Depending on sub-pixel coordinates and the particular GPU, we may los
e a corner of |
674 // hairline rects. We jam all the vertices to pixel centers to avoid thi
s, but not when MSAA | 458 // hairline rects. We jam all the vertices to pixel centers to avoid thi
s, but not when MSAA |
675 // is enabled because it can cause ugly artifacts. | 459 // is enabled because it can cause ugly artifacts. |
676 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_
Flag, | 460 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_
Flag, |
677 snapToPixelCenters); | 461 snapToPixelCenters); |
678 target->drawBatch(&pipelineBuilder, batch); | 462 fDrawTarget->drawBatch(&pipelineBuilder, batch); |
679 } else { | 463 } else { |
680 // filled BW rect | 464 // filled BW rect |
681 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect); | 465 fDrawTarget->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect); |
682 } | 466 } |
683 } | 467 } |
684 | 468 |
685 void GrContext::drawNonAARectToRect(GrRenderTarget* rt, | 469 void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt, |
686 const GrClip& clip, | 470 const GrClip& clip, |
687 const GrPaint& paint, | 471 const GrPaint& paint, |
688 const SkMatrix& viewMatrix, | 472 const SkMatrix& viewMatrix, |
689 const SkRect& rectToDraw, | 473 const SkRect& rectToDraw, |
690 const SkRect& localRect, | 474 const SkRect& localRect, |
691 const SkMatrix* localMatrix) { | 475 const SkMatrix* localMatrix) { |
692 RETURN_IF_ABANDONED | 476 RETURN_IF_ABANDONED |
693 AutoCheckFlush acf(this); | 477 AutoCheckFlush acf(fContext); |
694 GrPipelineBuilder pipelineBuilder; | 478 GrPipelineBuilder pipelineBuilder; |
695 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 479 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
696 if (NULL == target) { | |
697 return; | 480 return; |
698 } | 481 } |
699 | 482 |
700 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target); | 483 fDrawTarget->drawBWRect(&pipelineBuilder, |
701 | 484 paint.getColor(), |
702 target->drawRect(&pipelineBuilder, | 485 viewMatrix, |
703 paint.getColor(), | 486 rectToDraw, |
704 viewMatrix, | 487 &localRect, |
705 rectToDraw, | 488 localMatrix); |
706 &localRect, | |
707 localMatrix); | |
708 } | 489 } |
709 | 490 |
710 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, | 491 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, |
711 bool hasColors, | 492 bool hasColors, |
712 int* colorOffset, | 493 int* colorOffset, |
713 int* texOffset, | 494 int* texOffset, |
714 GrColor color, | 495 GrColor color, |
715 const SkMatrix& viewMatr
ix, | 496 const SkMatrix& viewMatr
ix, |
716 bool coverageIgnored) { | 497 bool coverageIgnored) { |
717 *texOffset = -1; | 498 *texOffset = -1; |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 bool fHasIndices; | 752 bool fHasIndices; |
972 bool fHasLocalCoords; | 753 bool fHasLocalCoords; |
973 int fVertexCount; | 754 int fVertexCount; |
974 int fIndexCount; | 755 int fIndexCount; |
975 }; | 756 }; |
976 | 757 |
977 BatchTracker fBatch; | 758 BatchTracker fBatch; |
978 SkSTArray<1, Geometry, true> fGeoData; | 759 SkSTArray<1, Geometry, true> fGeoData; |
979 }; | 760 }; |
980 | 761 |
981 void GrContext::drawVertices(GrRenderTarget* rt, | 762 void GrDrawContext::drawVertices(GrRenderTarget* rt, |
982 const GrClip& clip, | 763 const GrClip& clip, |
983 const GrPaint& paint, | 764 const GrPaint& paint, |
984 const SkMatrix& viewMatrix, | 765 const SkMatrix& viewMatrix, |
985 GrPrimitiveType primitiveType, | 766 GrPrimitiveType primitiveType, |
986 int vertexCount, | 767 int vertexCount, |
987 const SkPoint positions[], | 768 const SkPoint positions[], |
988 const SkPoint texCoords[], | 769 const SkPoint texCoords[], |
989 const GrColor colors[], | 770 const GrColor colors[], |
990 const uint16_t indices[], | 771 const uint16_t indices[], |
991 int indexCount) { | 772 int indexCount) { |
992 RETURN_IF_ABANDONED | 773 RETURN_IF_ABANDONED |
993 AutoCheckFlush acf(this); | 774 AutoCheckFlush acf(fContext); |
994 GrPipelineBuilder pipelineBuilder; | 775 GrPipelineBuilder pipelineBuilder; |
995 | 776 |
996 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 777 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
997 if (NULL == target) { | |
998 return; | 778 return; |
999 } | 779 } |
1000 | 780 |
1001 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target); | |
1002 | |
1003 // TODO clients should give us bounds | 781 // TODO clients should give us bounds |
1004 SkRect bounds; | 782 SkRect bounds; |
1005 if (!bounds.setBoundsCheck(positions, vertexCount)) { | 783 if (!bounds.setBoundsCheck(positions, vertexCount)) { |
1006 SkDebugf("drawVertices call empty bounds\n"); | 784 SkDebugf("drawVertices call empty bounds\n"); |
1007 return; | 785 return; |
1008 } | 786 } |
1009 | 787 |
1010 viewMatrix.mapRect(&bounds); | 788 viewMatrix.mapRect(&bounds); |
1011 | 789 |
1012 // If we don't have AA then we outset for a half pixel in each direction to
account for | 790 // If we don't have AA then we outset for a half pixel in each direction to
account for |
1013 // snapping | 791 // snapping |
1014 if (!paint.isAntiAlias()) { | 792 if (!paint.isAntiAlias()) { |
1015 bounds.outset(0.5f, 0.5f); | 793 bounds.outset(0.5f, 0.5f); |
1016 } | 794 } |
1017 | 795 |
1018 DrawVerticesBatch::Geometry geometry; | 796 DrawVerticesBatch::Geometry geometry; |
1019 geometry.fColor = paint.getColor(); | 797 geometry.fColor = paint.getColor(); |
1020 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp
e, viewMatrix, | 798 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp
e, viewMatrix, |
1021 positions, vertexCount
, indices, | 799 positions, vertexCount
, indices, |
1022 indexCount, colors, te
xCoords, | 800 indexCount, colors, te
xCoords, |
1023 bounds)); | 801 bounds)); |
1024 | 802 |
1025 target->drawBatch(&pipelineBuilder, batch); | 803 fDrawTarget->drawBatch(&pipelineBuilder, batch); |
1026 } | 804 } |
1027 | 805 |
1028 /////////////////////////////////////////////////////////////////////////////// | 806 /////////////////////////////////////////////////////////////////////////////// |
1029 | 807 |
1030 void GrContext::drawRRect(GrRenderTarget*rt, | 808 void GrDrawContext::drawRRect(GrRenderTarget*rt, |
1031 const GrClip& clip, | 809 const GrClip& clip, |
1032 const GrPaint& paint, | 810 const GrPaint& paint, |
1033 const SkMatrix& viewMatrix, | 811 const SkMatrix& viewMatrix, |
1034 const SkRRect& rrect, | 812 const SkRRect& rrect, |
1035 const GrStrokeInfo& strokeInfo) { | 813 const GrStrokeInfo& strokeInfo) { |
1036 RETURN_IF_ABANDONED | 814 RETURN_IF_ABANDONED |
1037 if (rrect.isEmpty()) { | 815 if (rrect.isEmpty()) { |
1038 return; | 816 return; |
1039 } | 817 } |
1040 | 818 |
1041 if (strokeInfo.isDashed()) { | 819 if (strokeInfo.isDashed()) { |
1042 SkPath path; | 820 SkPath path; |
1043 path.setIsVolatile(true); | 821 path.setIsVolatile(true); |
1044 path.addRRect(rrect); | 822 path.addRRect(rrect); |
1045 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | 823 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); |
1046 return; | 824 return; |
1047 } | 825 } |
1048 | 826 |
1049 AutoCheckFlush acf(this); | 827 AutoCheckFlush acf(fContext); |
1050 GrPipelineBuilder pipelineBuilder; | 828 GrPipelineBuilder pipelineBuilder; |
1051 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 829 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
1052 if (NULL == target) { | |
1053 return; | 830 return; |
1054 } | 831 } |
1055 | 832 |
1056 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target); | |
1057 | |
1058 GrColor color = paint.getColor(); | 833 GrColor color = paint.getColor(); |
1059 if (!fOvalRenderer->drawRRect(target, | 834 if (!GrOvalRenderer::DrawRRect(fDrawTarget, |
1060 &pipelineBuilder, | 835 &pipelineBuilder, |
1061 color, | 836 color, |
1062 viewMatrix, | 837 viewMatrix, |
1063 paint.isAntiAlias(), | 838 paint.isAntiAlias(), |
1064 rrect, | 839 rrect, |
1065 strokeInfo)) { | 840 strokeInfo)) { |
1066 SkPath path; | 841 SkPath path; |
1067 path.setIsVolatile(true); | 842 path.setIsVolatile(true); |
1068 path.addRRect(rrect); | 843 path.addRRect(rrect); |
1069 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | 844 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
1070 path, strokeInfo); | 845 paint.isAntiAlias(), path, strokeInfo); |
1071 } | 846 } |
1072 } | 847 } |
1073 | 848 |
1074 /////////////////////////////////////////////////////////////////////////////// | 849 /////////////////////////////////////////////////////////////////////////////// |
1075 | 850 |
1076 void GrContext::drawDRRect(GrRenderTarget* rt, | 851 void GrDrawContext::drawDRRect(GrRenderTarget* rt, |
1077 const GrClip& clip, | 852 const GrClip& clip, |
1078 const GrPaint& paint, | 853 const GrPaint& paint, |
1079 const SkMatrix& viewMatrix, | 854 const SkMatrix& viewMatrix, |
1080 const SkRRect& outer, | 855 const SkRRect& outer, |
1081 const SkRRect& inner) { | 856 const SkRRect& inner) { |
1082 RETURN_IF_ABANDONED | 857 RETURN_IF_ABANDONED |
1083 if (outer.isEmpty()) { | 858 if (outer.isEmpty()) { |
1084 return; | 859 return; |
1085 } | 860 } |
1086 | 861 |
1087 AutoCheckFlush acf(this); | 862 AutoCheckFlush acf(fContext); |
1088 GrPipelineBuilder pipelineBuilder; | 863 GrPipelineBuilder pipelineBuilder; |
1089 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 864 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
1090 | 865 return; |
1091 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target); | 866 } |
1092 | 867 |
1093 GrColor color = paint.getColor(); | 868 GrColor color = paint.getColor(); |
1094 if (!fOvalRenderer->drawDRRect(target, | 869 if (!GrOvalRenderer::DrawDRRect(fDrawTarget, |
1095 &pipelineBuilder, | 870 &pipelineBuilder, |
1096 color, | 871 color, |
1097 viewMatrix, | 872 viewMatrix, |
1098 paint.isAntiAlias(), | 873 paint.isAntiAlias(), |
1099 outer, | 874 outer, |
1100 inner)) { | 875 inner)) { |
1101 SkPath path; | 876 SkPath path; |
1102 path.setIsVolatile(true); | 877 path.setIsVolatile(true); |
1103 path.addRRect(inner); | 878 path.addRRect(inner); |
1104 path.addRRect(outer); | 879 path.addRRect(outer); |
1105 path.setFillType(SkPath::kEvenOdd_FillType); | 880 path.setFillType(SkPath::kEvenOdd_FillType); |
| 881 |
1106 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); | 882 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); |
1107 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | 883 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
1108 path, fillRec); | 884 paint.isAntiAlias(), path, fillRec); |
1109 } | 885 } |
1110 } | 886 } |
1111 | 887 |
1112 /////////////////////////////////////////////////////////////////////////////// | 888 /////////////////////////////////////////////////////////////////////////////// |
1113 | 889 |
1114 void GrContext::drawOval(GrRenderTarget* rt, | 890 void GrDrawContext::drawOval(GrRenderTarget* rt, |
1115 const GrClip& clip, | 891 const GrClip& clip, |
1116 const GrPaint& paint, | 892 const GrPaint& paint, |
1117 const SkMatrix& viewMatrix, | 893 const SkMatrix& viewMatrix, |
1118 const SkRect& oval, | 894 const SkRect& oval, |
1119 const GrStrokeInfo& strokeInfo) { | 895 const GrStrokeInfo& strokeInfo) { |
1120 RETURN_IF_ABANDONED | 896 RETURN_IF_ABANDONED |
1121 if (oval.isEmpty()) { | 897 if (oval.isEmpty()) { |
1122 return; | 898 return; |
1123 } | 899 } |
1124 | 900 |
1125 if (strokeInfo.isDashed()) { | 901 if (strokeInfo.isDashed()) { |
1126 SkPath path; | 902 SkPath path; |
1127 path.setIsVolatile(true); | 903 path.setIsVolatile(true); |
1128 path.addOval(oval); | 904 path.addOval(oval); |
1129 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | 905 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); |
1130 return; | 906 return; |
1131 } | 907 } |
1132 | 908 |
1133 AutoCheckFlush acf(this); | 909 AutoCheckFlush acf(fContext); |
1134 GrPipelineBuilder pipelineBuilder; | 910 GrPipelineBuilder pipelineBuilder; |
1135 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 911 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
1136 if (NULL == target) { | |
1137 return; | 912 return; |
1138 } | 913 } |
1139 | 914 |
1140 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target); | |
1141 | |
1142 GrColor color = paint.getColor(); | 915 GrColor color = paint.getColor(); |
1143 if (!fOvalRenderer->drawOval(target, | 916 if (!GrOvalRenderer::DrawOval(fDrawTarget, |
1144 &pipelineBuilder, | 917 &pipelineBuilder, |
1145 color, | 918 color, |
1146 viewMatrix, | 919 viewMatrix, |
1147 paint.isAntiAlias(), | 920 paint.isAntiAlias(), |
1148 oval, | 921 oval, |
1149 strokeInfo)) { | 922 strokeInfo)) { |
1150 SkPath path; | 923 SkPath path; |
1151 path.setIsVolatile(true); | 924 path.setIsVolatile(true); |
1152 path.addOval(oval); | 925 path.addOval(oval); |
1153 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | 926 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
1154 path, strokeInfo); | 927 paint.isAntiAlias(), path, strokeInfo); |
1155 } | 928 } |
1156 } | 929 } |
1157 | 930 |
1158 // Can 'path' be drawn as a pair of filled nested rectangles? | 931 // Can 'path' be drawn as a pair of filled nested rectangles? |
1159 static bool is_nested_rects(GrDrawTarget* target, | 932 static bool is_nested_rects(GrDrawTarget* target, |
1160 GrPipelineBuilder* pipelineBuilder, | 933 GrPipelineBuilder* pipelineBuilder, |
1161 GrColor color, | 934 GrColor color, |
1162 const SkMatrix& viewMatrix, | 935 const SkMatrix& viewMatrix, |
1163 const SkPath& path, | 936 const SkPath& path, |
1164 const SkStrokeRec& stroke, | 937 const SkStrokeRec& stroke, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1201 allGoE1 = false; | 974 allGoE1 = false; |
1202 } | 975 } |
1203 if (!SkScalarNearlyEqual(margin, temp)) { | 976 if (!SkScalarNearlyEqual(margin, temp)) { |
1204 allEq = false; | 977 allEq = false; |
1205 } | 978 } |
1206 } | 979 } |
1207 | 980 |
1208 return allEq || allGoE1; | 981 return allEq || allGoE1; |
1209 } | 982 } |
1210 | 983 |
1211 void GrContext::drawPath(GrRenderTarget* rt, | 984 void GrDrawContext::drawPath(GrRenderTarget* rt, |
1212 const GrClip& clip, | 985 const GrClip& clip, |
1213 const GrPaint& paint, | 986 const GrPaint& paint, |
1214 const SkMatrix& viewMatrix, | 987 const SkMatrix& viewMatrix, |
1215 const SkPath& path, | 988 const SkPath& path, |
1216 const GrStrokeInfo& strokeInfo) { | 989 const GrStrokeInfo& strokeInfo) { |
1217 RETURN_IF_ABANDONED | 990 RETURN_IF_ABANDONED |
1218 if (path.isEmpty()) { | 991 if (path.isEmpty()) { |
1219 if (path.isInverseFillType()) { | 992 if (path.isInverseFillType()) { |
1220 this->drawPaint(rt, clip, paint, viewMatrix); | 993 this->drawPaint(rt, clip, paint, viewMatrix); |
1221 } | 994 } |
1222 return; | 995 return; |
1223 } | 996 } |
1224 | 997 |
1225 GrColor color = paint.getColor(); | 998 GrColor color = paint.getColor(); |
1226 | 999 |
1227 // Note that internalDrawPath may sw-rasterize the path into a scratch textu
re. | 1000 // Note that internalDrawPath may sw-rasterize the path into a scratch textu
re. |
1228 // Scratch textures can be recycled after they are returned to the texture | 1001 // Scratch textures can be recycled after they are returned to the texture |
1229 // cache. This presents a potential hazard for buffered drawing. However, | 1002 // cache. This presents a potential hazard for buffered drawing. However, |
1230 // the writePixels that uploads to the scratch will perform a flush so we're | 1003 // the writePixels that uploads to the scratch will perform a flush so we're |
1231 // OK. | 1004 // OK. |
1232 AutoCheckFlush acf(this); | 1005 AutoCheckFlush acf(fContext); |
1233 GrPipelineBuilder pipelineBuilder; | 1006 GrPipelineBuilder pipelineBuilder; |
1234 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | 1007 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
1235 if (NULL == target) { | |
1236 return; | 1008 return; |
1237 } | 1009 } |
1238 | 1010 |
1239 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isC
onvex()); | |
1240 | |
1241 if (!strokeInfo.isDashed()) { | 1011 if (!strokeInfo.isDashed()) { |
1242 bool useCoverageAA = paint.isAntiAlias() && | 1012 bool useCoverageAA = paint.isAntiAlias() && |
1243 !pipelineBuilder.getRenderTarget()->isMultisampled(); | 1013 !pipelineBuilder.getRenderTarget()->isMultisampled(); |
1244 | 1014 |
1245 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { | 1015 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { |
1246 // Concave AA paths are expensive - try to avoid them for special ca
ses | 1016 // Concave AA paths are expensive - try to avoid them for special ca
ses |
1247 SkRect rects[2]; | 1017 SkRect rects[2]; |
1248 | 1018 |
1249 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, pat
h, strokeInfo, | 1019 if (is_nested_rects(fDrawTarget, &pipelineBuilder, color, viewMatrix
, path, strokeInfo, |
1250 rects)) { | 1020 rects)) { |
1251 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, col
or, viewMatrix, | 1021 GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilde
r, color, |
1252 rects); | 1022 viewMatrix, rects); |
1253 return; | 1023 return; |
1254 } | 1024 } |
1255 } | 1025 } |
1256 SkRect ovalRect; | 1026 SkRect ovalRect; |
1257 bool isOval = path.isOval(&ovalRect); | 1027 bool isOval = path.isOval(&ovalRect); |
1258 | 1028 |
1259 if (isOval && !path.isInverseFillType()) { | 1029 if (isOval && !path.isInverseFillType()) { |
1260 if (fOvalRenderer->drawOval(target, | 1030 if (GrOvalRenderer::DrawOval(fDrawTarget, |
1261 &pipelineBuilder, | 1031 &pipelineBuilder, |
1262 color, | 1032 color, |
1263 viewMatrix, | 1033 viewMatrix, |
1264 paint.isAntiAlias(), | 1034 paint.isAntiAlias(), |
1265 ovalRect, | 1035 ovalRect, |
1266 strokeInfo)) { | 1036 strokeInfo)) { |
1267 return; | 1037 return; |
1268 } | 1038 } |
1269 } | 1039 } |
1270 } | 1040 } |
1271 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.is
AntiAlias(), | 1041 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, pai
nt.isAntiAlias(), |
1272 path, strokeInfo); | 1042 path, strokeInfo); |
1273 } | 1043 } |
1274 | 1044 |
1275 void GrContext::internalDrawPath(GrDrawTarget* target, | 1045 void GrDrawContext::internalDrawPath(GrDrawTarget* target, |
1276 GrPipelineBuilder* pipelineBuilder, | 1046 GrPipelineBuilder* pipelineBuilder, |
1277 const SkMatrix& viewMatrix, | 1047 const SkMatrix& viewMatrix, |
1278 GrColor color, | 1048 GrColor color, |
1279 bool useAA, | 1049 bool useAA, |
1280 const SkPath& path, | 1050 const SkPath& path, |
1281 const GrStrokeInfo& strokeInfo) { | 1051 const GrStrokeInfo& strokeInfo) { |
1282 RETURN_IF_ABANDONED | 1052 RETURN_IF_ABANDONED |
1283 SkASSERT(!path.isEmpty()); | 1053 SkASSERT(!path.isEmpty()); |
1284 | 1054 |
1285 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); | |
1286 | |
1287 | 1055 |
1288 // An Assumption here is that path renderer would use some form of tweaking | 1056 // An Assumption here is that path renderer would use some form of tweaking |
1289 // the src color (either the input alpha or in the frag shader) to implement | 1057 // the src color (either the input alpha or in the frag shader) to implement |
1290 // aa. If we have some future driver-mojo path AA that can do the right | 1058 // aa. If we have some future driver-mojo path AA that can do the right |
1291 // thing WRT to the blend then we'll need some query on the PR. | 1059 // thing WRT to the blend then we'll need some query on the PR. |
1292 bool useCoverageAA = useAA && | 1060 bool useCoverageAA = useAA && |
1293 !pipelineBuilder->getRenderTarget()->isMultisampled(); | 1061 !pipelineBuilder->getRenderTarget()->isMultisampled(); |
1294 | 1062 |
1295 | 1063 |
1296 GrPathRendererChain::DrawType type = | 1064 GrPathRendererChain::DrawType type = |
1297 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : | 1065 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : |
1298 GrPathRendererChain::kColor_DrawType; | 1066 GrPathRendererChain::kColor_DrawType; |
1299 | 1067 |
1300 const SkPath* pathPtr = &path; | 1068 const SkPath* pathPtr = &path; |
1301 SkTLazy<SkPath> tmpPath; | 1069 SkTLazy<SkPath> tmpPath; |
1302 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; | 1070 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; |
1303 | 1071 |
1304 // Try a 1st time without stroking the path and without allowing the SW rend
erer | 1072 // Try a 1st time without stroking the path and without allowing the SW rend
erer |
1305 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatr
ix, *pathPtr, | 1073 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, view
Matrix, *pathPtr, |
1306 *strokeInfoPtr, false, type); | 1074 *strokeInfoPtr, false, type)
; |
1307 | 1075 |
1308 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); | 1076 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); |
1309 if (NULL == pr && strokeInfo.isDashed()) { | 1077 if (NULL == pr && strokeInfo.isDashed()) { |
1310 // It didn't work above, so try again with dashed stroke converted to a
dashless stroke. | 1078 // It didn't work above, so try again with dashed stroke converted to a
dashless stroke. |
1311 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pa
thPtr)) { | 1079 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pa
thPtr)) { |
1312 return; | 1080 return; |
1313 } | 1081 } |
1314 pathPtr = tmpPath.get(); | 1082 pathPtr = tmpPath.get(); |
1315 if (pathPtr->isEmpty()) { | 1083 if (pathPtr->isEmpty()) { |
1316 return; | 1084 return; |
1317 } | 1085 } |
1318 strokeInfoPtr = &dashlessStrokeInfo; | 1086 strokeInfoPtr = &dashlessStrokeInfo; |
1319 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | 1087 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pat
hPtr, *strokeInfoPtr, |
1320 false, type); | 1088 false, type); |
1321 } | 1089 } |
1322 | 1090 |
1323 if (NULL == pr) { | 1091 if (NULL == pr) { |
1324 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa
trix, NULL) && | 1092 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa
trix, NULL) && |
1325 !strokeInfoPtr->isFillStyle()) { | 1093 !strokeInfoPtr->isFillStyle()) { |
1326 // It didn't work above, so try again with stroke converted to a fil
l. | 1094 // It didn't work above, so try again with stroke converted to a fil
l. |
1327 if (!tmpPath.isValid()) { | 1095 if (!tmpPath.isValid()) { |
1328 tmpPath.init(); | 1096 tmpPath.init(); |
1329 } | 1097 } |
1330 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())
); | 1098 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())
); |
1331 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { | 1099 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { |
1332 return; | 1100 return; |
1333 } | 1101 } |
1334 pathPtr = tmpPath.get(); | 1102 pathPtr = tmpPath.get(); |
1335 if (pathPtr->isEmpty()) { | 1103 if (pathPtr->isEmpty()) { |
1336 return; | 1104 return; |
1337 } | 1105 } |
1338 dashlessStrokeInfo.setFillStyle(); | 1106 dashlessStrokeInfo.setFillStyle(); |
1339 strokeInfoPtr = &dashlessStrokeInfo; | 1107 strokeInfoPtr = &dashlessStrokeInfo; |
1340 } | 1108 } |
1341 | 1109 |
1342 // This time, allow SW renderer | 1110 // This time, allow SW renderer |
1343 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | 1111 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pat
hPtr, *strokeInfoPtr, |
1344 true, type); | 1112 true, type); |
1345 } | 1113 } |
1346 | 1114 |
1347 if (NULL == pr) { | 1115 if (NULL == pr) { |
1348 #ifdef SK_DEBUG | 1116 #ifdef SK_DEBUG |
1349 SkDebugf("Unable to find path renderer compatible with path.\n"); | 1117 SkDebugf("Unable to find path renderer compatible with path.\n"); |
1350 #endif | 1118 #endif |
1351 return; | 1119 return; |
1352 } | 1120 } |
1353 | 1121 |
1354 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn
foPtr, useCoverageAA); | 1122 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn
foPtr, useCoverageAA); |
1355 } | 1123 } |
1356 | 1124 |
1357 //////////////////////////////////////////////////////////////////////////////// | 1125 bool GrDrawContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder, |
| 1126 GrRenderTarget* rt, |
| 1127 const GrClip& clip, |
| 1128 const GrPaint* paint) { |
| 1129 RETURN_FALSE_IF_ABANDONED |
1358 | 1130 |
1359 void GrContext::flush(int flagsBitfield) { | 1131 ASSERT_OWNED_RESOURCE(rt); |
1360 if (NULL == fDrawBuffer) { | 1132 SkASSERT(rt && paint); |
1361 return; | 1133 pipelineBuilder->setFromPaint(*paint, rt, clip); |
1362 } | |
1363 | |
1364 if (kDiscard_FlushBit & flagsBitfield) { | |
1365 fDrawBuffer->reset(); | |
1366 } else { | |
1367 fDrawBuffer->flush(); | |
1368 } | |
1369 fResourceCache->notifyFlushOccurred(); | |
1370 fFlushToReduceCacheSize = false; | |
1371 } | |
1372 | |
1373 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t
inRowBytes, | |
1374 const void* inPixels, size_t outRowBytes, void* outPix
els) { | |
1375 SkSrcPixelInfo srcPI; | |
1376 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL))
{ | |
1377 return false; | |
1378 } | |
1379 srcPI.fAlphaType = kUnpremul_SkAlphaType; | |
1380 srcPI.fPixels = inPixels; | |
1381 srcPI.fRowBytes = inRowBytes; | |
1382 | |
1383 SkDstPixelInfo dstPI; | |
1384 dstPI.fColorType = srcPI.fColorType; | |
1385 dstPI.fAlphaType = kPremul_SkAlphaType; | |
1386 dstPI.fPixels = outPixels; | |
1387 dstPI.fRowBytes = outRowBytes; | |
1388 | |
1389 return srcPI.convertPixelsTo(&dstPI, width, height); | |
1390 } | |
1391 | |
1392 bool GrContext::writeSurfacePixels(GrSurface* surface, | |
1393 int left, int top, int width, int height, | |
1394 GrPixelConfig srcConfig, const void* buffer,
size_t rowBytes, | |
1395 uint32_t pixelOpsFlags) { | |
1396 RETURN_FALSE_IF_ABANDONED | |
1397 { | |
1398 GrTexture* texture = NULL; | |
1399 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asT
exture()) && | |
1400 fGpu->canWriteTexturePixels(texture, srcConfig)) { | |
1401 | |
1402 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && | |
1403 surface->surfacePriv().hasPendingIO()) { | |
1404 this->flush(); | |
1405 } | |
1406 return fGpu->writeTexturePixels(texture, left, top, width, height, | |
1407 srcConfig, buffer, rowBytes); | |
1408 // Don't need to check kFlushWrites_PixelOp here, we just did a dire
ct write so the | |
1409 // upload is already flushed. | |
1410 } | |
1411 } | |
1412 | |
1413 // If we didn't do a direct texture write then we upload the pixels to a tex
ture and draw. | |
1414 GrRenderTarget* renderTarget = surface->asRenderTarget(); | |
1415 if (NULL == renderTarget) { | |
1416 return false; | |
1417 } | |
1418 | |
1419 // We ignore the preferred config unless it is a R/B swap of the src config.
In that case | |
1420 // we will upload the original src data to a scratch texture but we will spo
of it as the swapped | |
1421 // config. This scratch will then have R and B swapped. We correct for this
by swapping again | |
1422 // when drawing the scratch to the dst using a conversion effect. | |
1423 bool swapRAndB = false; | |
1424 GrPixelConfig writeConfig = srcConfig; | |
1425 if (GrPixelConfigSwapRAndB(srcConfig) == | |
1426 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) { | |
1427 writeConfig = GrPixelConfigSwapRAndB(srcConfig); | |
1428 swapRAndB = true; | |
1429 } | |
1430 | |
1431 GrSurfaceDesc desc; | |
1432 desc.fWidth = width; | |
1433 desc.fHeight = height; | |
1434 desc.fConfig = writeConfig; | |
1435 SkAutoTUnref<GrTexture> texture(this->textureProvider()->refScratchTexture(d
esc, | |
1436 GrTextureProvider::kApprox_ScratchTexMatch)); | |
1437 if (!texture) { | |
1438 return false; | |
1439 } | |
1440 | |
1441 SkAutoTUnref<const GrFragmentProcessor> fp; | |
1442 SkMatrix textureMatrix; | |
1443 textureMatrix.setIDiv(texture->width(), texture->height()); | |
1444 | |
1445 // allocate a tmp buffer and sw convert the pixels to premul | |
1446 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | |
1447 | |
1448 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | |
1449 if (!GrPixelConfigIs8888(srcConfig)) { | |
1450 return false; | |
1451 } | |
1452 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | |
1453 // handle the unpremul step on the CPU if we couldn't create an effect t
o do it. | |
1454 if (NULL == fp) { | |
1455 size_t tmpRowBytes = 4 * width; | |
1456 tmpPixels.reset(width * height); | |
1457 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer
, tmpRowBytes, | |
1458 tmpPixels.get())) { | |
1459 return false; | |
1460 } | |
1461 rowBytes = tmpRowBytes; | |
1462 buffer = tmpPixels.get(); | |
1463 } | |
1464 } | |
1465 if (NULL == fp) { | |
1466 fp.reset(GrConfigConversionEffect::Create(texture, | |
1467 swapRAndB, | |
1468 GrConfigConversionEffect::kNon
e_PMConversion, | |
1469 textureMatrix)); | |
1470 } | |
1471 | |
1472 // Even if the client told us not to flush, we still flush here. The client
may have known that | |
1473 // writes to the original surface caused no data hazards, but they can't kno
w that the scratch | |
1474 // we just got is safe. | |
1475 if (texture->surfacePriv().hasPendingIO()) { | |
1476 this->flush(); | |
1477 } | |
1478 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, | |
1479 writeConfig, buffer, rowBytes)) { | |
1480 return false; | |
1481 } | |
1482 | |
1483 SkMatrix matrix; | |
1484 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | |
1485 | |
1486 // This function can be called in the midst of drawing another object (e.g.,
when uploading a | |
1487 // SW-rasterized clip while issuing a draw). So we push the current geometry
state before | |
1488 // drawing a rect to the render target. | |
1489 // The bracket ensures we pop the stack if we wind up flushing below. | |
1490 { | |
1491 GrDrawTarget* drawTarget = this->prepareToDraw(); | |
1492 if (!drawTarget) { | |
1493 return false; | |
1494 } | |
1495 | |
1496 GrPipelineBuilder pipelineBuilder; | |
1497 pipelineBuilder.addColorProcessor(fp); | |
1498 pipelineBuilder.setRenderTarget(renderTarget); | |
1499 drawTarget->drawSimpleRect(&pipelineBuilder, | |
1500 GrColor_WHITE, | |
1501 matrix, | |
1502 SkRect::MakeWH(SkIntToScalar(width), SkIntToS
calar(height))); | |
1503 } | |
1504 | |
1505 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
1506 this->flushSurfaceWrites(surface); | |
1507 } | |
1508 | |
1509 return true; | 1134 return true; |
1510 } | 1135 } |
1511 | 1136 |
1512 // toggles between RGBA and BGRA | 1137 bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) { |
1513 static SkColorType toggle_colortype32(SkColorType ct) { | 1138 RETURN_FALSE_IF_ABANDONED |
1514 if (kRGBA_8888_SkColorType == ct) { | |
1515 return kBGRA_8888_SkColorType; | |
1516 } else { | |
1517 SkASSERT(kBGRA_8888_SkColorType == ct); | |
1518 return kRGBA_8888_SkColorType; | |
1519 } | |
1520 } | |
1521 | 1139 |
1522 bool GrContext::readRenderTargetPixels(GrRenderTarget* target, | 1140 ASSERT_OWNED_RESOURCE(rt); |
1523 int left, int top, int width, int height, | 1141 SkASSERT(rt); |
1524 GrPixelConfig dstConfig, void* buffer, si
ze_t rowBytes, | |
1525 uint32_t flags) { | |
1526 RETURN_FALSE_IF_ABANDONED | |
1527 ASSERT_OWNED_RESOURCE(target); | |
1528 SkASSERT(target); | |
1529 | |
1530 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWr
ite()) { | |
1531 this->flush(); | |
1532 } | |
1533 | |
1534 // Determine which conversions have to be applied: flipY, swapRAnd, and/or u
npremul. | |
1535 | |
1536 // If fGpu->readPixels would incur a y-flip cost then we will read the pixel
s upside down. We'll | |
1537 // either do the flipY by drawing into a scratch with a matrix or on the cpu
after the read. | |
1538 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top, | |
1539 width, height, dstConfig, | |
1540 rowBytes); | |
1541 // We ignore the preferred config if it is different than our config unless
it is an R/B swap. | |
1542 // In that case we'll perform an R and B swap while drawing to a scratch tex
ture of the swapped | |
1543 // config. Then we will call readPixels on the scratch with the swapped conf
ig. The swaps during | |
1544 // the draw cancels out the fact that we call readPixels with a config that
is R/B swapped from | |
1545 // dstConfig. | |
1546 GrPixelConfig readConfig = dstConfig; | |
1547 bool swapRAndB = false; | |
1548 if (GrPixelConfigSwapRAndB(dstConfig) == | |
1549 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) { | |
1550 readConfig = GrPixelConfigSwapRAndB(readConfig); | |
1551 swapRAndB = true; | |
1552 } | |
1553 | |
1554 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); | |
1555 | |
1556 if (unpremul && !GrPixelConfigIs8888(dstConfig)) { | |
1557 // The unpremul flag is only allowed for these two configs. | |
1558 return false; | |
1559 } | |
1560 | |
1561 SkAutoTUnref<GrTexture> tempTexture; | |
1562 | |
1563 // If the src is a texture and we would have to do conversions after read pi
xels, we instead | |
1564 // do the conversions by drawing the src to a scratch texture. If we handle
any of the | |
1565 // conversions in the draw we set the corresponding bool to false so that we
don't reapply it | |
1566 // on the read back pixels. | |
1567 GrTexture* src = target->asTexture(); | |
1568 if (src && (swapRAndB || unpremul || flipY)) { | |
1569 // Make the scratch a render so we can read its pixels. | |
1570 GrSurfaceDesc desc; | |
1571 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
1572 desc.fWidth = width; | |
1573 desc.fHeight = height; | |
1574 desc.fConfig = readConfig; | |
1575 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
1576 | |
1577 // When a full read back is faster than a partial we could always make t
he scratch exactly | |
1578 // match the passed rect. However, if we see many different size rectang
les we will trash | |
1579 // our texture cache and pay the cost of creating and destroying many te
xtures. So, we only | |
1580 // request an exact match when the caller is reading an entire RT. | |
1581 GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_Sc
ratchTexMatch; | |
1582 if (0 == left && | |
1583 0 == top && | |
1584 target->width() == width && | |
1585 target->height() == height && | |
1586 fGpu->fullReadPixelsIsFasterThanPartial()) { | |
1587 match = GrTextureProvider::kExact_ScratchTexMatch; | |
1588 } | |
1589 tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match
)); | |
1590 if (tempTexture) { | |
1591 // compute a matrix to perform the draw | |
1592 SkMatrix textureMatrix; | |
1593 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); | |
1594 textureMatrix.postIDiv(src->width(), src->height()); | |
1595 | |
1596 SkAutoTUnref<const GrFragmentProcessor> fp; | |
1597 if (unpremul) { | |
1598 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix
)); | |
1599 if (fp) { | |
1600 unpremul = false; // we no longer need to do this on CPU aft
er the read back. | |
1601 } | |
1602 } | |
1603 // If we failed to create a PM->UPM effect and have no other convers
ions to perform then | |
1604 // there is no longer any point to using the scratch. | |
1605 if (fp || flipY || swapRAndB) { | |
1606 if (!fp) { | |
1607 fp.reset(GrConfigConversionEffect::Create( | |
1608 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo
nversion, | |
1609 textureMatrix)); | |
1610 } | |
1611 swapRAndB = false; // we will handle the swap in the draw. | |
1612 | |
1613 // We protect the existing geometry here since it may not be | |
1614 // clear to the caller that a draw operation (i.e., drawSimpleRe
ct) | |
1615 // can be invoked in this method | |
1616 { | |
1617 GrPipelineBuilder pipelineBuilder; | |
1618 SkASSERT(fp); | |
1619 pipelineBuilder.addColorProcessor(fp); | |
1620 | |
1621 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget(
)); | |
1622 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc
alar(height)); | |
1623 fDrawBuffer->drawSimpleRect(&pipelineBuilder, | |
1624 GrColor_WHITE, | |
1625 SkMatrix::I(), | |
1626 rect); | |
1627 // we want to read back from the scratch's origin | |
1628 left = 0; | |
1629 top = 0; | |
1630 target = tempTexture->asRenderTarget(); | |
1631 } | |
1632 this->flushSurfaceWrites(target); | |
1633 } | |
1634 } | |
1635 } | |
1636 | |
1637 if (!fGpu->readPixels(target, | |
1638 left, top, width, height, | |
1639 readConfig, buffer, rowBytes)) { | |
1640 return false; | |
1641 } | |
1642 // Perform any conversions we weren't able to perform using a scratch textur
e. | |
1643 if (unpremul || swapRAndB) { | |
1644 SkDstPixelInfo dstPI; | |
1645 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NUL
L)) { | |
1646 return false; | |
1647 } | |
1648 dstPI.fAlphaType = kUnpremul_SkAlphaType; | |
1649 dstPI.fPixels = buffer; | |
1650 dstPI.fRowBytes = rowBytes; | |
1651 | |
1652 SkSrcPixelInfo srcPI; | |
1653 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : ds
tPI.fColorType; | |
1654 srcPI.fAlphaType = kPremul_SkAlphaType; | |
1655 srcPI.fPixels = buffer; | |
1656 srcPI.fRowBytes = rowBytes; | |
1657 | |
1658 return srcPI.convertPixelsTo(&dstPI, width, height); | |
1659 } | |
1660 return true; | 1142 return true; |
1661 } | 1143 } |
1662 | 1144 |
1663 void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) { | |
1664 RETURN_IF_ABANDONED | |
1665 SkASSERT(surface); | |
1666 ASSERT_OWNED_RESOURCE(surface); | |
1667 if (surface->surfacePriv().hasPendingIO()) { | |
1668 this->flush(); | |
1669 } | |
1670 GrRenderTarget* rt = surface->asRenderTarget(); | |
1671 if (fGpu && rt) { | |
1672 fGpu->resolveRenderTarget(rt); | |
1673 } | |
1674 } | |
1675 | |
1676 void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) { | |
1677 RETURN_IF_ABANDONED | |
1678 SkASSERT(renderTarget); | |
1679 ASSERT_OWNED_RESOURCE(renderTarget); | |
1680 AutoCheckFlush acf(this); | |
1681 GrDrawTarget* target = this->prepareToDraw(); | |
1682 if (NULL == target) { | |
1683 return; | |
1684 } | |
1685 target->discard(renderTarget); | |
1686 } | |
1687 | |
1688 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe
ct, | |
1689 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { | |
1690 RETURN_IF_ABANDONED | |
1691 if (NULL == src || NULL == dst) { | |
1692 return; | |
1693 } | |
1694 ASSERT_OWNED_RESOURCE(src); | |
1695 ASSERT_OWNED_RESOURCE(dst); | |
1696 | |
1697 // Since we're going to the draw target and not GPU, no need to check kNoFlu
sh | |
1698 // here. | |
1699 | |
1700 GrDrawTarget* target = this->prepareToDraw(); | |
1701 if (NULL == target) { | |
1702 return; | |
1703 } | |
1704 target->copySurface(dst, src, srcRect, dstPoint); | |
1705 | |
1706 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
1707 this->flush(); | |
1708 } | |
1709 } | |
1710 | |
1711 void GrContext::flushSurfaceWrites(GrSurface* surface) { | |
1712 RETURN_IF_ABANDONED | |
1713 if (surface->surfacePriv().hasPendingWrite()) { | |
1714 this->flush(); | |
1715 } | |
1716 } | |
1717 | |
1718 GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder, | |
1719 GrRenderTarget* rt, | |
1720 const GrClip& clip, | |
1721 const GrPaint* paint, | |
1722 const AutoCheckFlush* acf) { | |
1723 if (NULL == fGpu || NULL == fDrawBuffer) { | |
1724 return NULL; | |
1725 } | |
1726 | |
1727 ASSERT_OWNED_RESOURCE(rt); | |
1728 SkASSERT(rt && paint && acf); | |
1729 pipelineBuilder->setFromPaint(*paint, rt, clip); | |
1730 return fDrawBuffer; | |
1731 } | |
1732 | |
1733 GrDrawTarget* GrContext::prepareToDraw() { | |
1734 if (NULL == fGpu) { | |
1735 return NULL; | |
1736 } | |
1737 return fDrawBuffer; | |
1738 } | |
1739 | |
1740 /* | |
1741 * This method finds a path renderer that can draw the specified path on | |
1742 * the provided target. | |
1743 * Due to its expense, the software path renderer has split out so it can | |
1744 * can be individually allowed/disallowed via the "allowSW" boolean. | |
1745 */ | |
1746 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, | |
1747 const GrPipelineBuilder* pipelineBuil
der, | |
1748 const SkMatrix& viewMatrix, | |
1749 const SkPath& path, | |
1750 const GrStrokeInfo& stroke, | |
1751 bool allowSW, | |
1752 GrPathRendererChain::DrawType drawTyp
e, | |
1753 GrPathRendererChain::StencilSupport*
stencilSupport) { | |
1754 | |
1755 if (NULL == fPathRendererChain) { | |
1756 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); | |
1757 } | |
1758 | |
1759 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, | |
1760 pipelineBuilder, | |
1761 viewMatrix, | |
1762 path, | |
1763 stroke, | |
1764 drawType, | |
1765 stencilSupport); | |
1766 | |
1767 if (NULL == pr && allowSW) { | |
1768 if (NULL == fSoftwarePathRenderer) { | |
1769 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); | |
1770 } | |
1771 pr = fSoftwarePathRenderer; | |
1772 } | |
1773 | |
1774 return pr; | |
1775 } | |
1776 | |
1777 //////////////////////////////////////////////////////////////////////////////// | |
1778 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { | |
1779 return fGpu->caps()->isConfigRenderable(config, withMSAA); | |
1780 } | |
1781 | |
1782 int GrContext::getRecommendedSampleCount(GrPixelConfig config, | |
1783 SkScalar dpi) const { | |
1784 if (!this->isConfigRenderable(config, true)) { | |
1785 return 0; | |
1786 } | |
1787 int chosenSampleCount = 0; | |
1788 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) { | |
1789 if (dpi >= 250.0f) { | |
1790 chosenSampleCount = 4; | |
1791 } else { | |
1792 chosenSampleCount = 16; | |
1793 } | |
1794 } | |
1795 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? | |
1796 chosenSampleCount : 0; | |
1797 } | |
1798 | |
1799 GrDrawTarget* GrContext::getTextTarget() { | |
1800 return this->prepareToDraw(); | |
1801 } | |
1802 | |
1803 namespace { | |
1804 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { | |
1805 GrConfigConversionEffect::PMConversion pmToUPM; | |
1806 GrConfigConversionEffect::PMConversion upmToPM; | |
1807 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm
ToPM); | |
1808 *pmToUPMValue = pmToUPM; | |
1809 *upmToPMValue = upmToPM; | |
1810 } | |
1811 } | |
1812 | |
1813 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, | |
1814 bool swapRAndB, | |
1815 const SkMatrix& matrix
) { | |
1816 if (!fDidTestPMConversions) { | |
1817 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); | |
1818 fDidTestPMConversions = true; | |
1819 } | |
1820 GrConfigConversionEffect::PMConversion pmToUPM = | |
1821 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); | |
1822 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { | |
1823 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, mat
rix); | |
1824 } else { | |
1825 return NULL; | |
1826 } | |
1827 } | |
1828 | |
1829 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, | |
1830 bool swapRAndB, | |
1831 const SkMatrix& matrix
) { | |
1832 if (!fDidTestPMConversions) { | |
1833 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); | |
1834 fDidTestPMConversions = true; | |
1835 } | |
1836 GrConfigConversionEffect::PMConversion upmToPM = | |
1837 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); | |
1838 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { | |
1839 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, mat
rix); | |
1840 } else { | |
1841 return NULL; | |
1842 } | |
1843 } | |
1844 | |
1845 ////////////////////////////////////////////////////////////////////////////// | |
1846 | |
1847 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes
) const { | |
1848 if (maxTextures) { | |
1849 *maxTextures = fResourceCache->getMaxResourceCount(); | |
1850 } | |
1851 if (maxTextureBytes) { | |
1852 *maxTextureBytes = fResourceCache->getMaxResourceBytes(); | |
1853 } | |
1854 } | |
1855 | |
1856 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
{ | |
1857 fResourceCache->setLimits(maxTextures, maxTextureBytes); | |
1858 } | |
1859 | |
1860 ////////////////////////////////////////////////////////////////////////////// | |
1861 | |
1862 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { | |
1863 fGpu->addGpuTraceMarker(marker); | |
1864 if (fDrawBuffer) { | |
1865 fDrawBuffer->addGpuTraceMarker(marker); | |
1866 } | |
1867 } | |
1868 | |
1869 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { | |
1870 fGpu->removeGpuTraceMarker(marker); | |
1871 if (fDrawBuffer) { | |
1872 fDrawBuffer->removeGpuTraceMarker(marker); | |
1873 } | |
1874 } | |
1875 | |
1876 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1145 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
1877 | 1146 |
1878 #ifdef GR_TEST_UTILS | 1147 #ifdef GR_TEST_UTILS |
1879 | 1148 |
1880 BATCH_TEST_DEFINE(StrokeRectBatch) { | 1149 BATCH_TEST_DEFINE(StrokeRectBatch) { |
1881 StrokeRectBatch::Geometry geometry; | 1150 StrokeRectBatch::Geometry geometry; |
1882 geometry.fViewMatrix = GrTest::TestMatrix(random); | 1151 geometry.fViewMatrix = GrTest::TestMatrix(random); |
1883 geometry.fColor = GrRandomColor(random); | 1152 geometry.fColor = GrRandomColor(random); |
1884 geometry.fRect = GrTest::TestRect(random); | 1153 geometry.fRect = GrTest::TestRect(random); |
1885 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; | 1154 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1992 geometry.fColor = GrRandomColor(random); | 1261 geometry.fColor = GrRandomColor(random); |
1993 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | 1262 return DrawVerticesBatch::Create(geometry, type, viewMatrix, |
1994 positions.begin(), vertexCount, | 1263 positions.begin(), vertexCount, |
1995 indices.begin(), hasIndices ? vertexCount :
0, | 1264 indices.begin(), hasIndices ? vertexCount :
0, |
1996 colors.begin(), | 1265 colors.begin(), |
1997 texCoords.begin(), | 1266 texCoords.begin(), |
1998 bounds); | 1267 bounds); |
1999 } | 1268 } |
2000 | 1269 |
2001 #endif | 1270 #endif |
| 1271 |
OLD | NEW |