OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 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" | 9 #include "GrContext.h" |
10 | 10 |
11 #include "GrAARectRenderer.h" | 11 #include "GrAARectRenderer.h" |
12 #include "GrAtlasTextContext.h" | 12 #include "GrAtlasTextContext.h" |
13 #include "GrBatch.h" | 13 #include "GrBatch.h" |
14 #include "GrBatchFontCache.h" | 14 #include "GrBatchFontCache.h" |
15 #include "GrBatchTarget.h" | 15 #include "GrBatchTarget.h" |
16 #include "GrBatchTest.h" | 16 #include "GrBatchTest.h" |
17 #include "GrCaps.h" | 17 #include "GrCaps.h" |
18 #include "GrContextOptions.h" | 18 #include "GrContextOptions.h" |
19 #include "GrDefaultGeoProcFactory.h" | 19 #include "GrDefaultGeoProcFactory.h" |
| 20 #include "GrDrawContext.h" |
20 #include "GrGpuResource.h" | 21 #include "GrGpuResource.h" |
21 #include "GrGpuResourcePriv.h" | 22 #include "GrGpuResourcePriv.h" |
22 #include "GrGpu.h" | 23 #include "GrGpu.h" |
23 #include "GrImmediateDrawTarget.h" | 24 #include "GrImmediateDrawTarget.h" |
24 #include "GrIndexBuffer.h" | 25 #include "GrIndexBuffer.h" |
25 #include "GrInOrderDrawBuffer.h" | 26 #include "GrInOrderDrawBuffer.h" |
26 #include "GrLayerCache.h" | 27 #include "GrLayerCache.h" |
27 #include "GrOvalRenderer.h" | 28 #include "GrOvalRenderer.h" |
28 #include "GrPathRenderer.h" | 29 #include "GrPathRenderer.h" |
29 #include "GrPathUtils.h" | 30 #include "GrPathUtils.h" |
(...skipping 16 matching lines...) Expand all Loading... |
46 #include "SkStrokeRec.h" | 47 #include "SkStrokeRec.h" |
47 #include "SkTLazy.h" | 48 #include "SkTLazy.h" |
48 #include "SkTLS.h" | 49 #include "SkTLS.h" |
49 #include "SkTraceEvent.h" | 50 #include "SkTraceEvent.h" |
50 | 51 |
51 #include "effects/GrConfigConversionEffect.h" | 52 #include "effects/GrConfigConversionEffect.h" |
52 #include "effects/GrDashingEffect.h" | 53 #include "effects/GrDashingEffect.h" |
53 #include "effects/GrSingleTextureEffect.h" | 54 #include "effects/GrSingleTextureEffect.h" |
54 | 55 |
55 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) | 56 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) |
56 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; } | 57 #define RETURN_IF_ABANDONED if (fDrawingMgr.abandoned()) { return; } |
57 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; } | 58 #define RETURN_FALSE_IF_ABANDONED if (fDrawingMgr.abandoned()) { return false; } |
58 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; } | 59 #define RETURN_NULL_IF_ABANDONED if (fDrawingMgr.abandoned()) { return NULL; } |
59 | 60 |
60 class GrContext::AutoCheckFlush { | |
61 public: | |
62 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | |
63 | 61 |
64 ~AutoCheckFlush() { | 62 //////////////////////////////////////////////////////////////////////////////// |
65 if (fContext->fFlushToReduceCacheSize) { | 63 |
66 fContext->flush(); | 64 void GrContext::DrawingMgr::init(GrContext* context) { |
67 } | 65 #ifdef IMMEDIATE_MODE |
| 66 fDrawTarget = SkNEW_ARGS(GrImmediateDrawTarget, (context)); |
| 67 #else |
| 68 fDrawTarget = SkNEW_ARGS(GrInOrderDrawBuffer, (context)); |
| 69 #endif |
| 70 |
| 71 fDrawContext = SkNEW_ARGS(GrDrawContext, (context, fDrawTarget)); |
| 72 } |
| 73 |
| 74 GrContext::DrawingMgr::~DrawingMgr() { |
| 75 SkSafeUnref(fDrawTarget); |
| 76 SkSafeUnref(fDrawContext); |
| 77 } |
| 78 |
| 79 void GrContext::DrawingMgr::abandon() { |
| 80 SkSafeSetNull(fDrawTarget); |
| 81 fDrawContext->fDrawTarget.reset(NULL); |
| 82 SkSafeSetNull(fDrawContext); |
| 83 } |
| 84 |
| 85 void GrContext::DrawingMgr::purgeResources() { |
| 86 if (fDrawTarget) { |
| 87 fDrawTarget->purgeResources(); |
68 } | 88 } |
| 89 } |
69 | 90 |
70 private: | 91 void GrContext::DrawingMgr::reset() { |
71 GrContext* fContext; | 92 if (fDrawTarget) { |
72 }; | 93 fDrawTarget->reset(); |
| 94 } |
| 95 } |
| 96 |
| 97 void GrContext::DrawingMgr::flush() { |
| 98 if (fDrawTarget) { |
| 99 fDrawTarget->flush(); |
| 100 } |
| 101 } |
| 102 |
| 103 GrDrawContext* GrContext::DrawingMgr::drawContext() { |
| 104 if (this->abandoned()) { |
| 105 return NULL; |
| 106 } |
| 107 return fDrawContext; |
| 108 } |
| 109 |
| 110 //////////////////////////////////////////////////////////////////////////////// |
| 111 |
73 | 112 |
74 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
{ | 113 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
{ |
75 GrContextOptions defaultOptions; | 114 GrContextOptions defaultOptions; |
76 return Create(backend, backendContext, defaultOptions); | 115 return Create(backend, backendContext, defaultOptions); |
77 } | 116 } |
78 | 117 |
79 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, | 118 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, |
80 const GrContextOptions& options) { | 119 const GrContextOptions& options) { |
81 GrContext* context = SkNEW(GrContext); | 120 GrContext* context = SkNEW(GrContext); |
82 | 121 |
(...skipping 14 matching lines...) Expand all Loading... |
97 return id; | 136 return id; |
98 } | 137 } |
99 | 138 |
100 GrContext::GrContext() : fUniqueID(next_id()) { | 139 GrContext::GrContext() : fUniqueID(next_id()) { |
101 fGpu = NULL; | 140 fGpu = NULL; |
102 fResourceCache = NULL; | 141 fResourceCache = NULL; |
103 fResourceProvider = NULL; | 142 fResourceProvider = NULL; |
104 fPathRendererChain = NULL; | 143 fPathRendererChain = NULL; |
105 fSoftwarePathRenderer = NULL; | 144 fSoftwarePathRenderer = NULL; |
106 fBatchFontCache = NULL; | 145 fBatchFontCache = NULL; |
107 fDrawBuffer = NULL; | |
108 fFlushToReduceCacheSize = false; | 146 fFlushToReduceCacheSize = false; |
109 fAARectRenderer = NULL; | |
110 fOvalRenderer = NULL; | |
111 fMaxTextureSizeOverride = 1 << 20; | 147 fMaxTextureSizeOverride = 1 << 20; |
112 } | 148 } |
113 | 149 |
114 bool GrContext::init(GrBackend backend, GrBackendContext backendContext, | 150 bool GrContext::init(GrBackend backend, GrBackendContext backendContext, |
115 const GrContextOptions& options) { | 151 const GrContextOptions& options) { |
116 SkASSERT(NULL == fGpu); | 152 SkASSERT(!fGpu); |
117 | 153 |
118 fGpu = GrGpu::Create(backend, backendContext, options, this); | 154 fGpu = GrGpu::Create(backend, backendContext, options, this); |
119 if (NULL == fGpu) { | 155 if (!fGpu) { |
120 return false; | 156 return false; |
121 } | 157 } |
122 this->initCommon(); | 158 this->initCommon(); |
123 return true; | 159 return true; |
124 } | 160 } |
125 | 161 |
126 void GrContext::initCommon() { | 162 void GrContext::initCommon() { |
127 fResourceCache = SkNEW(GrResourceCache); | 163 fResourceCache = SkNEW(GrResourceCache); |
128 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); | 164 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); |
129 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); | 165 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); |
130 | 166 |
131 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); | 167 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); |
132 | 168 |
133 fAARectRenderer = SkNEW(GrAARectRenderer); | |
134 fOvalRenderer = SkNEW(GrOvalRenderer); | |
135 | |
136 fDidTestPMConversions = false; | 169 fDidTestPMConversions = false; |
137 | 170 |
138 #ifdef IMMEDIATE_MODE | 171 fDrawingMgr.init(this); |
139 fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this)); | |
140 #else | |
141 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this)); | |
142 #endif | |
143 | 172 |
144 // GrBatchFontCache will eventually replace GrFontCache | 173 // GrBatchFontCache will eventually replace GrFontCache |
145 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); | 174 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); |
146 | 175 |
147 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB,
this))); | 176 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB,
this))); |
148 } | 177 } |
149 | 178 |
150 GrContext::~GrContext() { | 179 GrContext::~GrContext() { |
151 if (NULL == fGpu) { | 180 if (!fGpu) { |
152 return; | 181 return; |
153 } | 182 } |
154 | 183 |
155 this->flush(); | 184 this->flush(); |
156 | 185 |
157 for (int i = 0; i < fCleanUpData.count(); ++i) { | 186 for (int i = 0; i < fCleanUpData.count(); ++i) { |
158 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); | 187 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); |
159 } | 188 } |
160 | 189 |
161 SkDELETE(fResourceProvider); | 190 SkDELETE(fResourceProvider); |
162 SkDELETE(fResourceCache); | 191 SkDELETE(fResourceCache); |
163 SkDELETE(fBatchFontCache); | 192 SkDELETE(fBatchFontCache); |
164 SkDELETE(fDrawBuffer); | |
165 | |
166 fAARectRenderer->unref(); | |
167 fOvalRenderer->unref(); | |
168 | 193 |
169 fGpu->unref(); | 194 fGpu->unref(); |
170 SkSafeUnref(fPathRendererChain); | 195 SkSafeUnref(fPathRendererChain); |
171 SkSafeUnref(fSoftwarePathRenderer); | 196 SkSafeUnref(fSoftwarePathRenderer); |
172 } | 197 } |
173 | 198 |
174 void GrContext::abandonContext() { | 199 void GrContext::abandonContext() { |
175 fResourceProvider->abandon(); | 200 fResourceProvider->abandon(); |
176 // abandon first to so destructors | 201 // abandon first to so destructors |
177 // don't try to free the resources in the API. | 202 // don't try to free the resources in the API. |
178 fResourceCache->abandonAll(); | 203 fResourceCache->abandonAll(); |
179 | 204 |
180 fGpu->contextAbandoned(); | 205 fGpu->contextAbandoned(); |
181 | 206 |
182 // a path renderer may be holding onto resources that | 207 // a path renderer may be holding onto resources that |
183 // are now unusable | 208 // are now unusable |
184 SkSafeSetNull(fPathRendererChain); | 209 SkSafeSetNull(fPathRendererChain); |
185 SkSafeSetNull(fSoftwarePathRenderer); | 210 SkSafeSetNull(fSoftwarePathRenderer); |
186 | 211 |
187 SkDELETE(fDrawBuffer); | 212 fDrawingMgr.abandon(); |
188 fDrawBuffer = NULL; | |
189 | 213 |
190 fBatchFontCache->freeAll(); | 214 fBatchFontCache->freeAll(); |
191 fLayerCache->freeAll(); | 215 fLayerCache->freeAll(); |
192 fTextBlobCache->freeAll(); | 216 fTextBlobCache->freeAll(); |
193 } | 217 } |
194 | 218 |
195 void GrContext::resetContext(uint32_t state) { | 219 void GrContext::resetContext(uint32_t state) { |
196 fGpu->markContextDirty(state); | 220 fGpu->markContextDirty(state); |
197 } | 221 } |
198 | 222 |
199 void GrContext::freeGpuResources() { | 223 void GrContext::freeGpuResources() { |
200 this->flush(); | 224 this->flush(); |
201 | 225 |
202 if (fDrawBuffer) { | 226 fDrawingMgr.purgeResources(); |
203 fDrawBuffer->purgeResources(); | |
204 } | |
205 | 227 |
206 fBatchFontCache->freeAll(); | 228 fBatchFontCache->freeAll(); |
207 fLayerCache->freeAll(); | 229 fLayerCache->freeAll(); |
208 // a path renderer may be holding onto resources | 230 // a path renderer may be holding onto resources |
209 SkSafeSetNull(fPathRendererChain); | 231 SkSafeSetNull(fPathRendererChain); |
210 SkSafeSetNull(fSoftwarePathRenderer); | 232 SkSafeSetNull(fSoftwarePathRenderer); |
211 | 233 |
212 fResourceCache->purgeAllUnlocked(); | 234 fResourceCache->purgeAllUnlocked(); |
213 } | 235 } |
214 | 236 |
(...skipping 16 matching lines...) Expand all Loading... |
231 if (sb) { | 253 if (sb) { |
232 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr
operties); | 254 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr
operties); |
233 } | 255 } |
234 } | 256 } |
235 | 257 |
236 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi
stanceFieldFonts); | 258 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi
stanceFieldFonts); |
237 } | 259 } |
238 | 260 |
239 //////////////////////////////////////////////////////////////////////////////// | 261 //////////////////////////////////////////////////////////////////////////////// |
240 | 262 |
| 263 bool GrContext::shaderDerivativeSupport() const { |
| 264 return fGpu->caps()->shaderCaps()->shaderDerivativeSupport(); |
| 265 } |
| 266 |
241 bool GrContext::isConfigTexturable(GrPixelConfig config) const { | 267 bool GrContext::isConfigTexturable(GrPixelConfig config) const { |
242 return fGpu->caps()->isConfigTexturable(config); | 268 return fGpu->caps()->isConfigTexturable(config); |
243 } | 269 } |
244 | 270 |
245 bool GrContext::npotTextureTileSupport() const { | 271 bool GrContext::npotTextureTileSupport() const { |
246 return fGpu->caps()->npotTextureTileSupport(); | 272 return fGpu->caps()->npotTextureTileSupport(); |
247 } | 273 } |
248 | 274 |
249 void GrContext::OverBudgetCB(void* data) { | 275 void GrContext::OverBudgetCB(void* data) { |
250 SkASSERT(data); | 276 SkASSERT(data); |
(...skipping 20 matching lines...) Expand all Loading... |
271 } | 297 } |
272 | 298 |
273 int GrContext::getMaxRenderTargetSize() const { | 299 int GrContext::getMaxRenderTargetSize() const { |
274 return fGpu->caps()->maxRenderTargetSize(); | 300 return fGpu->caps()->maxRenderTargetSize(); |
275 } | 301 } |
276 | 302 |
277 int GrContext::getMaxSampleCount() const { | 303 int GrContext::getMaxSampleCount() const { |
278 return fGpu->caps()->maxSampleCount(); | 304 return fGpu->caps()->maxSampleCount(); |
279 } | 305 } |
280 | 306 |
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 | |
305 // set rect to be big enough to fill the space, but not super-huge, so we | |
306 // don't overflow fixed-point implementations | |
307 SkRect r; | |
308 r.setLTRB(0, 0, | |
309 SkIntToScalar(rt->width()), | |
310 SkIntToScalar(rt->height())); | |
311 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); | |
312 | |
313 // by definition this fills the entire clip, no need for AA | |
314 if (paint->isAntiAlias()) { | |
315 paint.writable()->setAntiAlias(false); | |
316 } | |
317 | |
318 bool isPerspective = viewMatrix.hasPerspective(); | |
319 | |
320 // We attempt to map r by the inverse matrix and draw that. mapRect will | |
321 // map the four corners and bound them with a new rect. This will not | |
322 // produce a correct result for some perspective matrices. | |
323 if (!isPerspective) { | |
324 SkMatrix inverse; | |
325 if (!viewMatrix.invert(&inverse)) { | |
326 SkDebugf("Could not invert matrix\n"); | |
327 return; | |
328 } | |
329 inverse.mapRect(&r); | |
330 this->drawRect(rt, clip, *paint, viewMatrix, r); | |
331 } else { | |
332 SkMatrix localMatrix; | |
333 if (!viewMatrix.invert(&localMatrix)) { | |
334 SkDebugf("Could not invert matrix\n"); | |
335 return; | |
336 } | |
337 | |
338 AutoCheckFlush acf(this); | |
339 GrPipelineBuilder pipelineBuilder; | |
340 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, p
aint, &acf); | |
341 if (NULL == target) { | |
342 return; | |
343 } | |
344 | |
345 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target); | |
346 target->drawRect(&pipelineBuilder, | |
347 paint->getColor(), | |
348 SkMatrix::I(), | |
349 r, | |
350 NULL, | |
351 &localMatrix); | |
352 } | |
353 } | |
354 | |
355 //////////////////////////////////////////////////////////////////////////////// | |
356 | |
357 static inline bool is_irect(const SkRect& r) { | |
358 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && | |
359 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); | |
360 } | |
361 | |
362 static bool apply_aa_to_rect(GrDrawTarget* target, | |
363 GrPipelineBuilder* pipelineBuilder, | |
364 SkRect* devBoundRect, | |
365 const SkRect& rect, | |
366 SkScalar strokeWidth, | |
367 const SkMatrix& combinedMatrix, | |
368 GrColor color) { | |
369 if (pipelineBuilder->getRenderTarget()->isMultisampled()) { | |
370 return false; | |
371 } | |
372 | |
373 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) | |
374 if (strokeWidth >= 0) { | |
375 #endif | |
376 if (!combinedMatrix.preservesAxisAlignment()) { | |
377 return false; | |
378 } | |
379 | |
380 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) | |
381 } else { | |
382 if (!combinedMatrix.preservesRightAngles()) { | |
383 return false; | |
384 } | |
385 } | |
386 #endif | |
387 | |
388 combinedMatrix.mapRect(devBoundRect, rect); | |
389 if (!combinedMatrix.rectStaysRect()) { | |
390 return true; | |
391 } | |
392 | |
393 if (strokeWidth < 0) { | |
394 return !is_irect(*devBoundRect); | |
395 } | |
396 | |
397 return true; | |
398 } | |
399 | |
400 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& po
int) { | |
401 return point.fX >= rect.fLeft && point.fX <= rect.fRight && | |
402 point.fY >= rect.fTop && point.fY <= rect.fBottom; | |
403 } | |
404 | |
405 class StrokeRectBatch : public GrBatch { | |
406 public: | |
407 struct Geometry { | |
408 GrColor fColor; | |
409 SkMatrix fViewMatrix; | |
410 SkRect fRect; | |
411 SkScalar fStrokeWidth; | |
412 }; | |
413 | |
414 static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) { | |
415 return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters)); | |
416 } | |
417 | |
418 const char* name() const override { return "StrokeRectBatch"; } | |
419 | |
420 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
421 // When this is called on a batch, there is only one geometry bundle | |
422 out->setKnownFourComponents(fGeoData[0].fColor); | |
423 } | |
424 | |
425 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
426 out->setKnownSingleComponent(0xff); | |
427 } | |
428 | |
429 void initBatchTracker(const GrPipelineInfo& init) override { | |
430 // Handle any color overrides | |
431 if (init.fColorIgnored) { | |
432 fGeoData[0].fColor = GrColor_ILLEGAL; | |
433 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
434 fGeoData[0].fColor = init.fOverrideColor; | |
435 } | |
436 | |
437 // setup batch properties | |
438 fBatch.fColorIgnored = init.fColorIgnored; | |
439 fBatch.fColor = fGeoData[0].fColor; | |
440 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
441 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
442 } | |
443 | |
444 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
445 SkAutoTUnref<const GrGeometryProcessor> gp( | |
446 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPositi
on_GPType, | |
447 this->color(), | |
448 this->usesLocalCoords(), | |
449 this->coverageIgnored(), | |
450 this->viewMatrix(), | |
451 SkMatrix::I())); | |
452 | |
453 batchTarget->initDraw(gp, pipeline); | |
454 | |
455 size_t vertexStride = gp->getVertexStride(); | |
456 | |
457 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | |
458 | |
459 Geometry& args = fGeoData[0]; | |
460 | |
461 int vertexCount = kVertsPerHairlineRect; | |
462 if (args.fStrokeWidth > 0) { | |
463 vertexCount = kVertsPerStrokeRect; | |
464 } | |
465 | |
466 const GrVertexBuffer* vertexBuffer; | |
467 int firstVertex; | |
468 | |
469 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount, | |
470 &vertexBuffer, &firstVertex); | |
471 | |
472 if (!verts) { | |
473 SkDebugf("Could not allocate vertices\n"); | |
474 return; | |
475 } | |
476 | |
477 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | |
478 | |
479 GrPrimitiveType primType; | |
480 | |
481 if (args.fStrokeWidth > 0) {; | |
482 primType = kTriangleStrip_GrPrimitiveType; | |
483 args.fRect.sort(); | |
484 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth); | |
485 } else { | |
486 // hairline | |
487 primType = kLineStrip_GrPrimitiveType; | |
488 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | |
489 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | |
490 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | |
491 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | |
492 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | |
493 } | |
494 | |
495 GrVertices vertices; | |
496 vertices.init(primType, vertexBuffer, firstVertex, vertexCount); | |
497 batchTarget->draw(vertices); | |
498 } | |
499 | |
500 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
501 | |
502 private: | |
503 StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) { | |
504 this->initClassID<StrokeRectBatch>(); | |
505 | |
506 fBatch.fHairline = geometry.fStrokeWidth == 0; | |
507 | |
508 fGeoData.push_back(geometry); | |
509 | |
510 // setup bounds | |
511 fBounds = geometry.fRect; | |
512 SkScalar rad = SkScalarHalf(geometry.fStrokeWidth); | |
513 fBounds.outset(rad, rad); | |
514 geometry.fViewMatrix.mapRect(&fBounds); | |
515 | |
516 // If our caller snaps to pixel centers then we have to round out the bo
unds | |
517 if (snapToPixelCenters) { | |
518 fBounds.roundOut(); | |
519 } | |
520 } | |
521 | |
522 /* create a triangle strip that strokes the specified rect. There are 8 | |
523 unique vertices, but we repeat the last 2 to close up. Alternatively we | |
524 could use an indices array, and then only send 8 verts, but not sure that | |
525 would be faster. | |
526 */ | |
527 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar widt
h) { | |
528 const SkScalar rad = SkScalarHalf(width); | |
529 // TODO we should be able to enable this assert, but we'd have to filter
these draws | |
530 // this is a bug | |
531 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2); | |
532 | |
533 verts[0].set(rect.fLeft + rad, rect.fTop + rad); | |
534 verts[1].set(rect.fLeft - rad, rect.fTop - rad); | |
535 verts[2].set(rect.fRight - rad, rect.fTop + rad); | |
536 verts[3].set(rect.fRight + rad, rect.fTop - rad); | |
537 verts[4].set(rect.fRight - rad, rect.fBottom - rad); | |
538 verts[5].set(rect.fRight + rad, rect.fBottom + rad); | |
539 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); | |
540 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); | |
541 verts[8] = verts[0]; | |
542 verts[9] = verts[1]; | |
543 } | |
544 | |
545 | |
546 GrColor color() const { return fBatch.fColor; } | |
547 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
548 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
549 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
550 bool hairline() const { return fBatch.fHairline; } | |
551 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
552 | |
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 | |
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.setIsVolatile(true); | |
586 path.addRect(rect); | |
587 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); | |
588 return; | |
589 } | |
590 | |
591 AutoCheckFlush acf(this); | |
592 GrPipelineBuilder pipelineBuilder; | |
593 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
594 if (NULL == target) { | |
595 return; | |
596 } | |
597 | |
598 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target); | |
599 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); | |
600 | |
601 // 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. | |
603 if (width < 0) { | |
604 SkRect rtRect; | |
605 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); | |
606 SkRect clipSpaceRTRect = rtRect; | |
607 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); | |
608 if (checkClip) { | |
609 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), | |
610 SkIntToScalar(clip.origin().fY)); | |
611 } | |
612 // Does the clip contain the entire RT? | |
613 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { | |
614 SkMatrix invM; | |
615 if (!viewMatrix.invert(&invM)) { | |
616 return; | |
617 } | |
618 // Does the rect bound the RT? | |
619 SkPoint srcSpaceRTQuad[4]; | |
620 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); | |
621 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && | |
622 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && | |
623 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && | |
624 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { | |
625 // Will it blend? | |
626 GrColor clearColor; | |
627 if (paint.isOpaqueAndConstantColor(&clearColor)) { | |
628 target->clear(NULL, clearColor, true, rt); | |
629 return; | |
630 } | |
631 } | |
632 } | |
633 } | |
634 | |
635 GrColor color = paint.getColor(); | |
636 SkRect devBoundRect; | |
637 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM
ultisampled(); | |
638 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRe
ct, rect, width, | |
639 viewMatrix, color); | |
640 | |
641 if (doAA) { | |
642 if (width >= 0) { | |
643 fAARectRenderer->strokeAARect(target, | |
644 &pipelineBuilder, | |
645 color, | |
646 viewMatrix, | |
647 rect, | |
648 devBoundRect, | |
649 *strokeInfo); | |
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 ar
e hit deterministic | |
670 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); | |
671 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe
lCenters)); | |
672 | |
673 // 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 | |
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 | |
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, &pain
t, &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 | |
710 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, | |
711 bool hasColors, | |
712 int* colorOffset, | |
713 int* texOffset, | |
714 GrColor color, | |
715 const SkMatrix& viewMatr
ix, | |
716 bool coverageIgnored) { | |
717 *texOffset = -1; | |
718 *colorOffset = -1; | |
719 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; | |
720 if (hasLocalCoords && hasColors) { | |
721 *colorOffset = sizeof(SkPoint); | |
722 *texOffset = sizeof(SkPoint) + sizeof(GrColor); | |
723 flags |= GrDefaultGeoProcFactory::kColor_GPType | | |
724 GrDefaultGeoProcFactory::kLocalCoord_GPType; | |
725 } else if (hasLocalCoords) { | |
726 *texOffset = sizeof(SkPoint); | |
727 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType; | |
728 } else if (hasColors) { | |
729 *colorOffset = sizeof(SkPoint); | |
730 flags |= GrDefaultGeoProcFactory::kColor_GPType; | |
731 } | |
732 return GrDefaultGeoProcFactory::Create(flags, color, hasLocalCoords, coverag
eIgnored, | |
733 viewMatrix, SkMatrix::I()); | |
734 } | |
735 | |
736 class DrawVerticesBatch : public GrBatch { | |
737 public: | |
738 struct Geometry { | |
739 GrColor fColor; | |
740 SkTDArray<SkPoint> fPositions; | |
741 SkTDArray<uint16_t> fIndices; | |
742 SkTDArray<GrColor> fColors; | |
743 SkTDArray<SkPoint> fLocalCoords; | |
744 }; | |
745 | |
746 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveTy
pe, | |
747 const SkMatrix& viewMatrix, | |
748 const SkPoint* positions, int vertexCount, | |
749 const uint16_t* indices, int indexCount, | |
750 const GrColor* colors, const SkPoint* localCoords, | |
751 const SkRect& bounds) { | |
752 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatri
x, positions, | |
753 vertexCount, indices, indexCount,
colors, | |
754 localCoords, bounds)); | |
755 } | |
756 | |
757 const char* name() const override { return "DrawVerticesBatch"; } | |
758 | |
759 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
760 // When this is called on a batch, there is only one geometry bundle | |
761 if (this->hasColors()) { | |
762 out->setUnknownFourComponents(); | |
763 } else { | |
764 out->setKnownFourComponents(fGeoData[0].fColor); | |
765 } | |
766 } | |
767 | |
768 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
769 out->setKnownSingleComponent(0xff); | |
770 } | |
771 | |
772 void initBatchTracker(const GrPipelineInfo& init) override { | |
773 // Handle any color overrides | |
774 if (init.fColorIgnored) { | |
775 fGeoData[0].fColor = GrColor_ILLEGAL; | |
776 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
777 fGeoData[0].fColor = init.fOverrideColor; | |
778 } | |
779 | |
780 // setup batch properties | |
781 fBatch.fColorIgnored = init.fColorIgnored; | |
782 fBatch.fColor = fGeoData[0].fColor; | |
783 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
784 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
785 } | |
786 | |
787 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
788 int colorOffset = -1, texOffset = -1; | |
789 SkAutoTUnref<const GrGeometryProcessor> gp( | |
790 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(),
&colorOffset, | |
791 &texOffset, this->color(), this->viewMatri
x(), | |
792 this->coverageIgnored())); | |
793 | |
794 batchTarget->initDraw(gp, pipeline); | |
795 | |
796 size_t vertexStride = gp->getVertexStride(); | |
797 | |
798 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? siz
eof(SkPoint) : 0) | |
799 + (this->hasColors() ? sizeof(G
rColor) : 0)); | |
800 | |
801 int instanceCount = fGeoData.count(); | |
802 | |
803 const GrVertexBuffer* vertexBuffer; | |
804 int firstVertex; | |
805 | |
806 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount
(), | |
807 &vertexBuffer, &firstVertex); | |
808 | |
809 if (!verts) { | |
810 SkDebugf("Could not allocate vertices\n"); | |
811 return; | |
812 } | |
813 | |
814 const GrIndexBuffer* indexBuffer = NULL; | |
815 int firstIndex = 0; | |
816 | |
817 uint16_t* indices = NULL; | |
818 if (this->hasIndices()) { | |
819 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuff
er, &firstIndex); | |
820 | |
821 if (!indices) { | |
822 SkDebugf("Could not allocate indices\n"); | |
823 return; | |
824 } | |
825 } | |
826 | |
827 int indexOffset = 0; | |
828 int vertexOffset = 0; | |
829 for (int i = 0; i < instanceCount; i++) { | |
830 const Geometry& args = fGeoData[i]; | |
831 | |
832 // TODO we can actually cache this interleaved and then just memcopy | |
833 if (this->hasIndices()) { | |
834 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) { | |
835 *(indices + indexOffset) = args.fIndices[j] + vertexOffset; | |
836 } | |
837 } | |
838 | |
839 for (int j = 0; j < args.fPositions.count(); ++j) { | |
840 *((SkPoint*)verts) = args.fPositions[j]; | |
841 if (this->hasColors()) { | |
842 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j]
; | |
843 } | |
844 if (this->hasLocalCoords()) { | |
845 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords
[j]; | |
846 } | |
847 verts = (void*)((intptr_t)verts + vertexStride); | |
848 vertexOffset++; | |
849 } | |
850 } | |
851 | |
852 GrVertices vertices; | |
853 if (this->hasIndices()) { | |
854 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffe
r, firstVertex, | |
855 firstIndex, this->vertexCount(), this->indexCou
nt()); | |
856 | |
857 } else { | |
858 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this
->vertexCount()); | |
859 } | |
860 batchTarget->draw(vertices); | |
861 } | |
862 | |
863 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
864 | |
865 private: | |
866 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType, | |
867 const SkMatrix& viewMatrix, | |
868 const SkPoint* positions, int vertexCount, | |
869 const uint16_t* indices, int indexCount, | |
870 const GrColor* colors, const SkPoint* localCoords, const S
kRect& bounds) { | |
871 this->initClassID<DrawVerticesBatch>(); | |
872 SkASSERT(positions); | |
873 | |
874 fBatch.fViewMatrix = viewMatrix; | |
875 Geometry& installedGeo = fGeoData.push_back(geometry); | |
876 | |
877 installedGeo.fPositions.append(vertexCount, positions); | |
878 if (indices) { | |
879 installedGeo.fIndices.append(indexCount, indices); | |
880 fBatch.fHasIndices = true; | |
881 } else { | |
882 fBatch.fHasIndices = false; | |
883 } | |
884 | |
885 if (colors) { | |
886 installedGeo.fColors.append(vertexCount, colors); | |
887 fBatch.fHasColors = true; | |
888 } else { | |
889 fBatch.fHasColors = false; | |
890 } | |
891 | |
892 if (localCoords) { | |
893 installedGeo.fLocalCoords.append(vertexCount, localCoords); | |
894 fBatch.fHasLocalCoords = true; | |
895 } else { | |
896 fBatch.fHasLocalCoords = false; | |
897 } | |
898 fBatch.fVertexCount = vertexCount; | |
899 fBatch.fIndexCount = indexCount; | |
900 fBatch.fPrimitiveType = primitiveType; | |
901 | |
902 this->setBounds(bounds); | |
903 } | |
904 | |
905 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; } | |
906 bool batchablePrimitiveType() const { | |
907 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType || | |
908 kLines_GrPrimitiveType == fBatch.fPrimitiveType || | |
909 kPoints_GrPrimitiveType == fBatch.fPrimitiveType; | |
910 } | |
911 GrColor color() const { return fBatch.fColor; } | |
912 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
913 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
914 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } | |
915 bool hasColors() const { return fBatch.fHasColors; } | |
916 bool hasIndices() const { return fBatch.fHasIndices; } | |
917 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; } | |
918 int vertexCount() const { return fBatch.fVertexCount; } | |
919 int indexCount() const { return fBatch.fIndexCount; } | |
920 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
921 | |
922 bool onCombineIfPossible(GrBatch* t) override { | |
923 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>(); | |
924 | |
925 if (!this->batchablePrimitiveType() || this->primitiveType() != that->pr
imitiveType()) { | |
926 return false; | |
927 } | |
928 | |
929 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); | |
930 | |
931 // We currently use a uniform viewmatrix for this batch | |
932 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | |
933 return false; | |
934 } | |
935 | |
936 if (this->hasColors() != that->hasColors()) { | |
937 return false; | |
938 } | |
939 | |
940 if (this->hasIndices() != that->hasIndices()) { | |
941 return false; | |
942 } | |
943 | |
944 if (this->hasLocalCoords() != that->hasLocalCoords()) { | |
945 return false; | |
946 } | |
947 | |
948 if (!this->hasColors() && this->color() != that->color()) { | |
949 return false; | |
950 } | |
951 | |
952 if (this->color() != that->color()) { | |
953 fBatch.fColor = GrColor_ILLEGAL; | |
954 } | |
955 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin())
; | |
956 fBatch.fVertexCount += that->vertexCount(); | |
957 fBatch.fIndexCount += that->indexCount(); | |
958 | |
959 this->joinBounds(that->bounds()); | |
960 return true; | |
961 } | |
962 | |
963 struct BatchTracker { | |
964 GrPrimitiveType fPrimitiveType; | |
965 SkMatrix fViewMatrix; | |
966 GrColor fColor; | |
967 bool fUsesLocalCoords; | |
968 bool fColorIgnored; | |
969 bool fCoverageIgnored; | |
970 bool fHasColors; | |
971 bool fHasIndices; | |
972 bool fHasLocalCoords; | |
973 int fVertexCount; | |
974 int fIndexCount; | |
975 }; | |
976 | |
977 BatchTracker fBatch; | |
978 SkSTArray<1, Geometry, true> fGeoData; | |
979 }; | |
980 | |
981 void GrContext::drawVertices(GrRenderTarget* rt, | |
982 const GrClip& clip, | |
983 const GrPaint& paint, | |
984 const SkMatrix& viewMatrix, | |
985 GrPrimitiveType primitiveType, | |
986 int vertexCount, | |
987 const SkPoint positions[], | |
988 const SkPoint texCoords[], | |
989 const GrColor colors[], | |
990 const uint16_t indices[], | |
991 int indexCount) { | |
992 RETURN_IF_ABANDONED | |
993 AutoCheckFlush acf(this); | |
994 GrPipelineBuilder pipelineBuilder; | |
995 | |
996 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
997 if (NULL == target) { | |
998 return; | |
999 } | |
1000 | |
1001 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target); | |
1002 | |
1003 // TODO clients should give us bounds | |
1004 SkRect bounds; | |
1005 if (!bounds.setBoundsCheck(positions, vertexCount)) { | |
1006 SkDebugf("drawVertices call empty bounds\n"); | |
1007 return; | |
1008 } | |
1009 | |
1010 viewMatrix.mapRect(&bounds); | |
1011 | |
1012 // If we don't have AA then we outset for a half pixel in each direction to
account for | |
1013 // snapping | |
1014 if (!paint.isAntiAlias()) { | |
1015 bounds.outset(0.5f, 0.5f); | |
1016 } | |
1017 | |
1018 DrawVerticesBatch::Geometry geometry; | |
1019 geometry.fColor = paint.getColor(); | |
1020 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp
e, viewMatrix, | |
1021 positions, vertexCount
, indices, | |
1022 indexCount, colors, te
xCoords, | |
1023 bounds)); | |
1024 | |
1025 target->drawBatch(&pipelineBuilder, batch); | |
1026 } | |
1027 | |
1028 /////////////////////////////////////////////////////////////////////////////// | |
1029 | |
1030 void GrContext::drawRRect(GrRenderTarget*rt, | |
1031 const GrClip& clip, | |
1032 const GrPaint& paint, | |
1033 const SkMatrix& viewMatrix, | |
1034 const SkRRect& rrect, | |
1035 const GrStrokeInfo& strokeInfo) { | |
1036 RETURN_IF_ABANDONED | |
1037 if (rrect.isEmpty()) { | |
1038 return; | |
1039 } | |
1040 | |
1041 if (strokeInfo.isDashed()) { | |
1042 SkPath path; | |
1043 path.setIsVolatile(true); | |
1044 path.addRRect(rrect); | |
1045 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | |
1046 return; | |
1047 } | |
1048 | |
1049 AutoCheckFlush acf(this); | |
1050 GrPipelineBuilder pipelineBuilder; | |
1051 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
1052 if (NULL == target) { | |
1053 return; | |
1054 } | |
1055 | |
1056 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target); | |
1057 | |
1058 GrColor color = paint.getColor(); | |
1059 if (!fOvalRenderer->drawRRect(target, | |
1060 &pipelineBuilder, | |
1061 color, | |
1062 viewMatrix, | |
1063 paint.isAntiAlias(), | |
1064 rrect, | |
1065 strokeInfo)) { | |
1066 SkPath path; | |
1067 path.setIsVolatile(true); | |
1068 path.addRRect(rrect); | |
1069 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
1070 path, strokeInfo); | |
1071 } | |
1072 } | |
1073 | |
1074 /////////////////////////////////////////////////////////////////////////////// | |
1075 | |
1076 void GrContext::drawDRRect(GrRenderTarget* rt, | |
1077 const GrClip& clip, | |
1078 const GrPaint& paint, | |
1079 const SkMatrix& viewMatrix, | |
1080 const SkRRect& outer, | |
1081 const SkRRect& inner) { | |
1082 RETURN_IF_ABANDONED | |
1083 if (outer.isEmpty()) { | |
1084 return; | |
1085 } | |
1086 | |
1087 AutoCheckFlush acf(this); | |
1088 GrPipelineBuilder pipelineBuilder; | |
1089 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
1090 | |
1091 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target); | |
1092 | |
1093 GrColor color = paint.getColor(); | |
1094 if (!fOvalRenderer->drawDRRect(target, | |
1095 &pipelineBuilder, | |
1096 color, | |
1097 viewMatrix, | |
1098 paint.isAntiAlias(), | |
1099 outer, | |
1100 inner)) { | |
1101 SkPath path; | |
1102 path.setIsVolatile(true); | |
1103 path.addRRect(inner); | |
1104 path.addRRect(outer); | |
1105 path.setFillType(SkPath::kEvenOdd_FillType); | |
1106 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); | |
1107 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
1108 path, fillRec); | |
1109 } | |
1110 } | |
1111 | |
1112 /////////////////////////////////////////////////////////////////////////////// | |
1113 | |
1114 void GrContext::drawOval(GrRenderTarget* rt, | |
1115 const GrClip& clip, | |
1116 const GrPaint& paint, | |
1117 const SkMatrix& viewMatrix, | |
1118 const SkRect& oval, | |
1119 const GrStrokeInfo& strokeInfo) { | |
1120 RETURN_IF_ABANDONED | |
1121 if (oval.isEmpty()) { | |
1122 return; | |
1123 } | |
1124 | |
1125 if (strokeInfo.isDashed()) { | |
1126 SkPath path; | |
1127 path.setIsVolatile(true); | |
1128 path.addOval(oval); | |
1129 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | |
1130 return; | |
1131 } | |
1132 | |
1133 AutoCheckFlush acf(this); | |
1134 GrPipelineBuilder pipelineBuilder; | |
1135 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
1136 if (NULL == target) { | |
1137 return; | |
1138 } | |
1139 | |
1140 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target); | |
1141 | |
1142 GrColor color = paint.getColor(); | |
1143 if (!fOvalRenderer->drawOval(target, | |
1144 &pipelineBuilder, | |
1145 color, | |
1146 viewMatrix, | |
1147 paint.isAntiAlias(), | |
1148 oval, | |
1149 strokeInfo)) { | |
1150 SkPath path; | |
1151 path.setIsVolatile(true); | |
1152 path.addOval(oval); | |
1153 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
1154 path, strokeInfo); | |
1155 } | |
1156 } | |
1157 | |
1158 // Can 'path' be drawn as a pair of filled nested rectangles? | |
1159 static bool is_nested_rects(GrDrawTarget* target, | |
1160 GrPipelineBuilder* pipelineBuilder, | |
1161 GrColor color, | |
1162 const SkMatrix& viewMatrix, | |
1163 const SkPath& path, | |
1164 const SkStrokeRec& stroke, | |
1165 SkRect rects[2]) { | |
1166 SkASSERT(stroke.isFillStyle()); | |
1167 | |
1168 if (path.isInverseFillType()) { | |
1169 return false; | |
1170 } | |
1171 | |
1172 // TODO: this restriction could be lifted if we were willing to apply | |
1173 // the matrix to all the points individually rather than just to the rect | |
1174 if (!viewMatrix.preservesAxisAlignment()) { | |
1175 return false; | |
1176 } | |
1177 | |
1178 SkPath::Direction dirs[2]; | |
1179 if (!path.isNestedFillRects(rects, dirs)) { | |
1180 return false; | |
1181 } | |
1182 | |
1183 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) { | |
1184 // The two rects need to be wound opposite to each other | |
1185 return false; | |
1186 } | |
1187 | |
1188 // Right now, nested rects where the margin is not the same width | |
1189 // all around do not render correctly | |
1190 const SkScalar* outer = rects[0].asScalars(); | |
1191 const SkScalar* inner = rects[1].asScalars(); | |
1192 | |
1193 bool allEq = true; | |
1194 | |
1195 SkScalar margin = SkScalarAbs(outer[0] - inner[0]); | |
1196 bool allGoE1 = margin >= SK_Scalar1; | |
1197 | |
1198 for (int i = 1; i < 4; ++i) { | |
1199 SkScalar temp = SkScalarAbs(outer[i] - inner[i]); | |
1200 if (temp < SK_Scalar1) { | |
1201 allGoE1 = false; | |
1202 } | |
1203 if (!SkScalarNearlyEqual(margin, temp)) { | |
1204 allEq = false; | |
1205 } | |
1206 } | |
1207 | |
1208 return allEq || allGoE1; | |
1209 } | |
1210 | |
1211 void GrContext::drawPath(GrRenderTarget* rt, | |
1212 const GrClip& clip, | |
1213 const GrPaint& paint, | |
1214 const SkMatrix& viewMatrix, | |
1215 const SkPath& path, | |
1216 const GrStrokeInfo& strokeInfo) { | |
1217 RETURN_IF_ABANDONED | |
1218 if (path.isEmpty()) { | |
1219 if (path.isInverseFillType()) { | |
1220 this->drawPaint(rt, clip, paint, viewMatrix); | |
1221 } | |
1222 return; | |
1223 } | |
1224 | |
1225 GrColor color = paint.getColor(); | |
1226 | |
1227 // 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 | |
1229 // 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 | |
1231 // OK. | |
1232 AutoCheckFlush acf(this); | |
1233 GrPipelineBuilder pipelineBuilder; | |
1234 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
1235 if (NULL == target) { | |
1236 return; | |
1237 } | |
1238 | |
1239 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isC
onvex()); | |
1240 | |
1241 if (!strokeInfo.isDashed()) { | |
1242 bool useCoverageAA = paint.isAntiAlias() && | |
1243 !pipelineBuilder.getRenderTarget()->isMultisampled(); | |
1244 | |
1245 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { | |
1246 // Concave AA paths are expensive - try to avoid them for special ca
ses | |
1247 SkRect rects[2]; | |
1248 | |
1249 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, pat
h, strokeInfo, | |
1250 rects)) { | |
1251 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, col
or, viewMatrix, | |
1252 rects); | |
1253 return; | |
1254 } | |
1255 } | |
1256 SkRect ovalRect; | |
1257 bool isOval = path.isOval(&ovalRect); | |
1258 | |
1259 if (isOval && !path.isInverseFillType()) { | |
1260 if (fOvalRenderer->drawOval(target, | |
1261 &pipelineBuilder, | |
1262 color, | |
1263 viewMatrix, | |
1264 paint.isAntiAlias(), | |
1265 ovalRect, | |
1266 strokeInfo)) { | |
1267 return; | |
1268 } | |
1269 } | |
1270 } | |
1271 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.is
AntiAlias(), | |
1272 path, strokeInfo); | |
1273 } | |
1274 | |
1275 void GrContext::internalDrawPath(GrDrawTarget* target, | |
1276 GrPipelineBuilder* pipelineBuilder, | |
1277 const SkMatrix& viewMatrix, | |
1278 GrColor color, | |
1279 bool useAA, | |
1280 const SkPath& path, | |
1281 const GrStrokeInfo& strokeInfo) { | |
1282 RETURN_IF_ABANDONED | |
1283 SkASSERT(!path.isEmpty()); | |
1284 | |
1285 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); | |
1286 | |
1287 | |
1288 // 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 | |
1290 // 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. | |
1292 bool useCoverageAA = useAA && | |
1293 !pipelineBuilder->getRenderTarget()->isMultisampled(); | |
1294 | |
1295 | |
1296 GrPathRendererChain::DrawType type = | |
1297 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : | |
1298 GrPathRendererChain::kColor_DrawType; | |
1299 | |
1300 const SkPath* pathPtr = &path; | |
1301 SkTLazy<SkPath> tmpPath; | |
1302 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; | |
1303 | |
1304 // 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, | |
1306 *strokeInfoPtr, false, type); | |
1307 | |
1308 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); | |
1309 if (NULL == pr && strokeInfo.isDashed()) { | |
1310 // 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)) { | |
1312 return; | |
1313 } | |
1314 pathPtr = tmpPath.get(); | |
1315 if (pathPtr->isEmpty()) { | |
1316 return; | |
1317 } | |
1318 strokeInfoPtr = &dashlessStrokeInfo; | |
1319 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | |
1320 false, type); | |
1321 } | |
1322 | |
1323 if (NULL == pr) { | |
1324 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa
trix, NULL) && | |
1325 !strokeInfoPtr->isFillStyle()) { | |
1326 // It didn't work above, so try again with stroke converted to a fil
l. | |
1327 if (!tmpPath.isValid()) { | |
1328 tmpPath.init(); | |
1329 } | |
1330 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())
); | |
1331 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { | |
1332 return; | |
1333 } | |
1334 pathPtr = tmpPath.get(); | |
1335 if (pathPtr->isEmpty()) { | |
1336 return; | |
1337 } | |
1338 dashlessStrokeInfo.setFillStyle(); | |
1339 strokeInfoPtr = &dashlessStrokeInfo; | |
1340 } | |
1341 | |
1342 // This time, allow SW renderer | |
1343 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | |
1344 true, type); | |
1345 } | |
1346 | |
1347 if (NULL == pr) { | |
1348 #ifdef SK_DEBUG | |
1349 SkDebugf("Unable to find path renderer compatible with path.\n"); | |
1350 #endif | |
1351 return; | |
1352 } | |
1353 | |
1354 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn
foPtr, useCoverageAA); | |
1355 } | |
1356 | |
1357 //////////////////////////////////////////////////////////////////////////////// | 307 //////////////////////////////////////////////////////////////////////////////// |
1358 | 308 |
1359 void GrContext::flush(int flagsBitfield) { | 309 void GrContext::flush(int flagsBitfield) { |
1360 if (NULL == fDrawBuffer) { | 310 RETURN_IF_ABANDONED |
1361 return; | |
1362 } | |
1363 | 311 |
1364 if (kDiscard_FlushBit & flagsBitfield) { | 312 if (kDiscard_FlushBit & flagsBitfield) { |
1365 fDrawBuffer->reset(); | 313 fDrawingMgr.reset(); |
1366 } else { | 314 } else { |
1367 fDrawBuffer->flush(); | 315 fDrawingMgr.flush(); |
1368 } | 316 } |
1369 fResourceCache->notifyFlushOccurred(); | 317 fResourceCache->notifyFlushOccurred(); |
1370 fFlushToReduceCacheSize = false; | 318 fFlushToReduceCacheSize = false; |
1371 } | 319 } |
1372 | 320 |
1373 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t
inRowBytes, | 321 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t
inRowBytes, |
1374 const void* inPixels, size_t outRowBytes, void* outPix
els) { | 322 const void* inPixels, size_t outRowBytes, void* outPix
els) { |
1375 SkSrcPixelInfo srcPI; | 323 SkSrcPixelInfo srcPI; |
1376 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL))
{ | 324 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL))
{ |
1377 return false; | 325 return false; |
(...skipping 27 matching lines...) Expand all Loading... |
1405 } | 353 } |
1406 return fGpu->writeTexturePixels(texture, left, top, width, height, | 354 return fGpu->writeTexturePixels(texture, left, top, width, height, |
1407 srcConfig, buffer, rowBytes); | 355 srcConfig, buffer, rowBytes); |
1408 // Don't need to check kFlushWrites_PixelOp here, we just did a dire
ct write so the | 356 // Don't need to check kFlushWrites_PixelOp here, we just did a dire
ct write so the |
1409 // upload is already flushed. | 357 // upload is already flushed. |
1410 } | 358 } |
1411 } | 359 } |
1412 | 360 |
1413 // If we didn't do a direct texture write then we upload the pixels to a tex
ture and draw. | 361 // 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(); | 362 GrRenderTarget* renderTarget = surface->asRenderTarget(); |
1415 if (NULL == renderTarget) { | 363 if (!renderTarget) { |
1416 return false; | 364 return false; |
1417 } | 365 } |
1418 | 366 |
1419 // We ignore the preferred config unless it is a R/B swap of the src config.
In that case | 367 // 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 | 368 // 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 | 369 // 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. | 370 // when drawing the scratch to the dst using a conversion effect. |
1423 bool swapRAndB = false; | 371 bool swapRAndB = false; |
1424 GrPixelConfig writeConfig = srcConfig; | 372 GrPixelConfig writeConfig = srcConfig; |
1425 if (GrPixelConfigSwapRAndB(srcConfig) == | 373 if (GrPixelConfigSwapRAndB(srcConfig) == |
(...skipping 18 matching lines...) Expand all Loading... |
1444 | 392 |
1445 // allocate a tmp buffer and sw convert the pixels to premul | 393 // allocate a tmp buffer and sw convert the pixels to premul |
1446 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | 394 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
1447 | 395 |
1448 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | 396 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
1449 if (!GrPixelConfigIs8888(srcConfig)) { | 397 if (!GrPixelConfigIs8888(srcConfig)) { |
1450 return false; | 398 return false; |
1451 } | 399 } |
1452 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | 400 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. | 401 // handle the unpremul step on the CPU if we couldn't create an effect t
o do it. |
1454 if (NULL == fp) { | 402 if (!fp) { |
1455 size_t tmpRowBytes = 4 * width; | 403 size_t tmpRowBytes = 4 * width; |
1456 tmpPixels.reset(width * height); | 404 tmpPixels.reset(width * height); |
1457 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer
, tmpRowBytes, | 405 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer
, tmpRowBytes, |
1458 tmpPixels.get())) { | 406 tmpPixels.get())) { |
1459 return false; | 407 return false; |
1460 } | 408 } |
1461 rowBytes = tmpRowBytes; | 409 rowBytes = tmpRowBytes; |
1462 buffer = tmpPixels.get(); | 410 buffer = tmpPixels.get(); |
1463 } | 411 } |
1464 } | 412 } |
1465 if (NULL == fp) { | 413 if (!fp) { |
1466 fp.reset(GrConfigConversionEffect::Create(texture, | 414 fp.reset(GrConfigConversionEffect::Create(texture, |
1467 swapRAndB, | 415 swapRAndB, |
1468 GrConfigConversionEffect::kNon
e_PMConversion, | 416 GrConfigConversionEffect::kNon
e_PMConversion, |
1469 textureMatrix)); | 417 textureMatrix)); |
1470 } | 418 } |
1471 | 419 |
1472 // Even if the client told us not to flush, we still flush here. The client
may have known that | 420 // 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 | 421 // writes to the original surface caused no data hazards, but they can't kno
w that the scratch |
1474 // we just got is safe. | 422 // we just got is safe. |
1475 if (texture->surfacePriv().hasPendingIO()) { | 423 if (texture->surfacePriv().hasPendingIO()) { |
1476 this->flush(); | 424 this->flush(); |
1477 } | 425 } |
1478 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, | 426 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, |
1479 writeConfig, buffer, rowBytes)) { | 427 writeConfig, buffer, rowBytes)) { |
1480 return false; | 428 return false; |
1481 } | 429 } |
1482 | 430 |
1483 SkMatrix matrix; | 431 SkMatrix matrix; |
1484 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | 432 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
1485 | 433 |
1486 // This function can be called in the midst of drawing another object (e.g.,
when uploading a | 434 GrDrawContext* drawContext = this->drawContext(); |
1487 // SW-rasterized clip while issuing a draw). So we push the current geometry
state before | 435 if (!drawContext) { |
1488 // drawing a rect to the render target. | 436 return false; |
1489 // The bracket ensures we pop the stack if we wind up flushing below. | 437 } |
1490 { | |
1491 GrDrawTarget* drawTarget = this->prepareToDraw(); | |
1492 if (!drawTarget) { | |
1493 return false; | |
1494 } | |
1495 | 438 |
1496 GrPipelineBuilder pipelineBuilder; | 439 GrPaint paint; |
1497 pipelineBuilder.addColorProcessor(fp); | 440 paint.addColorProcessor(fp); |
1498 pipelineBuilder.setRenderTarget(renderTarget); | 441 |
1499 drawTarget->drawSimpleRect(&pipelineBuilder, | 442 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); |
1500 GrColor_WHITE, | 443 |
1501 matrix, | 444 drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect,
NULL); |
1502 SkRect::MakeWH(SkIntToScalar(width), SkIntToS
calar(height))); | |
1503 } | |
1504 | 445 |
1505 if (kFlushWrites_PixelOp & pixelOpsFlags) { | 446 if (kFlushWrites_PixelOp & pixelOpsFlags) { |
1506 this->flushSurfaceWrites(surface); | 447 this->flushSurfaceWrites(surface); |
1507 } | 448 } |
1508 | 449 |
1509 return true; | 450 return true; |
1510 } | 451 } |
1511 | 452 |
1512 // toggles between RGBA and BGRA | 453 // toggles between RGBA and BGRA |
1513 static SkColorType toggle_colortype32(SkColorType ct) { | 454 static SkColorType toggle_colortype32(SkColorType ct) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1607 fp.reset(GrConfigConversionEffect::Create( | 548 fp.reset(GrConfigConversionEffect::Create( |
1608 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo
nversion, | 549 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo
nversion, |
1609 textureMatrix)); | 550 textureMatrix)); |
1610 } | 551 } |
1611 swapRAndB = false; // we will handle the swap in the draw. | 552 swapRAndB = false; // we will handle the swap in the draw. |
1612 | 553 |
1613 // We protect the existing geometry here since it may not be | 554 // We protect the existing geometry here since it may not be |
1614 // clear to the caller that a draw operation (i.e., drawSimpleRe
ct) | 555 // clear to the caller that a draw operation (i.e., drawSimpleRe
ct) |
1615 // can be invoked in this method | 556 // can be invoked in this method |
1616 { | 557 { |
1617 GrPipelineBuilder pipelineBuilder; | 558 GrDrawContext* drawContext = this->drawContext(); |
1618 SkASSERT(fp); | 559 if (!drawContext) { |
1619 pipelineBuilder.addColorProcessor(fp); | 560 return false; |
| 561 } |
1620 | 562 |
1621 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget(
)); | 563 GrPaint paint; |
| 564 paint.addColorProcessor(fp); |
| 565 |
1622 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc
alar(height)); | 566 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc
alar(height)); |
1623 fDrawBuffer->drawSimpleRect(&pipelineBuilder, | 567 |
1624 GrColor_WHITE, | 568 drawContext->drawRect(tempTexture->asRenderTarget(), GrClip:
:WideOpen(), paint, |
1625 SkMatrix::I(), | 569 SkMatrix::I(), rect, NULL);
|
1626 rect); | 570 |
1627 // we want to read back from the scratch's origin | 571 // we want to read back from the scratch's origin |
1628 left = 0; | 572 left = 0; |
1629 top = 0; | 573 top = 0; |
1630 target = tempTexture->asRenderTarget(); | 574 target = tempTexture->asRenderTarget(); |
1631 } | 575 } |
1632 this->flushSurfaceWrites(target); | 576 this->flushSurfaceWrites(target); |
1633 } | 577 } |
1634 } | 578 } |
1635 } | 579 } |
1636 | 580 |
(...skipping 29 matching lines...) Expand all Loading... |
1666 ASSERT_OWNED_RESOURCE(surface); | 610 ASSERT_OWNED_RESOURCE(surface); |
1667 if (surface->surfacePriv().hasPendingIO()) { | 611 if (surface->surfacePriv().hasPendingIO()) { |
1668 this->flush(); | 612 this->flush(); |
1669 } | 613 } |
1670 GrRenderTarget* rt = surface->asRenderTarget(); | 614 GrRenderTarget* rt = surface->asRenderTarget(); |
1671 if (fGpu && rt) { | 615 if (fGpu && rt) { |
1672 fGpu->resolveRenderTarget(rt); | 616 fGpu->resolveRenderTarget(rt); |
1673 } | 617 } |
1674 } | 618 } |
1675 | 619 |
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, | 620 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe
ct, |
1689 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { | 621 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { |
1690 RETURN_IF_ABANDONED | 622 RETURN_IF_ABANDONED |
1691 if (NULL == src || NULL == dst) { | 623 if (!src || !dst) { |
1692 return; | 624 return; |
1693 } | 625 } |
1694 ASSERT_OWNED_RESOURCE(src); | 626 ASSERT_OWNED_RESOURCE(src); |
1695 ASSERT_OWNED_RESOURCE(dst); | 627 ASSERT_OWNED_RESOURCE(dst); |
1696 | 628 |
1697 // Since we're going to the draw target and not GPU, no need to check kNoFlu
sh | 629 // Since we're going to the draw target and not GPU, no need to check kNoFlu
sh |
1698 // here. | 630 // here. |
1699 | 631 if (!dst->asRenderTarget()) { |
1700 GrDrawTarget* target = this->prepareToDraw(); | |
1701 if (NULL == target) { | |
1702 return; | 632 return; |
1703 } | 633 } |
1704 target->copySurface(dst, src, srcRect, dstPoint); | 634 |
| 635 GrDrawContext* drawContext = this->drawContext(); |
| 636 if (!drawContext) { |
| 637 return; |
| 638 } |
| 639 |
| 640 drawContext->copySurface(dst->asRenderTarget(), src, srcRect, dstPoint); |
1705 | 641 |
1706 if (kFlushWrites_PixelOp & pixelOpsFlags) { | 642 if (kFlushWrites_PixelOp & pixelOpsFlags) { |
1707 this->flush(); | 643 this->flush(); |
1708 } | 644 } |
1709 } | 645 } |
1710 | 646 |
1711 void GrContext::flushSurfaceWrites(GrSurface* surface) { | 647 void GrContext::flushSurfaceWrites(GrSurface* surface) { |
1712 RETURN_IF_ABANDONED | 648 RETURN_IF_ABANDONED |
1713 if (surface->surfacePriv().hasPendingWrite()) { | 649 if (surface->surfacePriv().hasPendingWrite()) { |
1714 this->flush(); | 650 this->flush(); |
1715 } | 651 } |
1716 } | 652 } |
1717 | 653 |
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 /* | 654 /* |
1741 * This method finds a path renderer that can draw the specified path on | 655 * This method finds a path renderer that can draw the specified path on |
1742 * the provided target. | 656 * the provided target. |
1743 * Due to its expense, the software path renderer has split out so it can | 657 * Due to its expense, the software path renderer has split out so it can |
1744 * can be individually allowed/disallowed via the "allowSW" boolean. | 658 * can be individually allowed/disallowed via the "allowSW" boolean. |
1745 */ | 659 */ |
1746 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, | 660 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, |
1747 const GrPipelineBuilder* pipelineBuil
der, | 661 const GrPipelineBuilder* pipelineBuil
der, |
1748 const SkMatrix& viewMatrix, | 662 const SkMatrix& viewMatrix, |
1749 const SkPath& path, | 663 const SkPath& path, |
1750 const GrStrokeInfo& stroke, | 664 const GrStrokeInfo& stroke, |
1751 bool allowSW, | 665 bool allowSW, |
1752 GrPathRendererChain::DrawType drawTyp
e, | 666 GrPathRendererChain::DrawType drawTyp
e, |
1753 GrPathRendererChain::StencilSupport*
stencilSupport) { | 667 GrPathRendererChain::StencilSupport*
stencilSupport) { |
1754 | 668 |
1755 if (NULL == fPathRendererChain) { | 669 if (!fPathRendererChain) { |
1756 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); | 670 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); |
1757 } | 671 } |
1758 | 672 |
1759 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, | 673 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, |
1760 pipelineBuilder, | 674 pipelineBuilder, |
1761 viewMatrix, | 675 viewMatrix, |
1762 path, | 676 path, |
1763 stroke, | 677 stroke, |
1764 drawType, | 678 drawType, |
1765 stencilSupport); | 679 stencilSupport); |
1766 | 680 |
1767 if (NULL == pr && allowSW) { | 681 if (!pr && allowSW) { |
1768 if (NULL == fSoftwarePathRenderer) { | 682 if (!fSoftwarePathRenderer) { |
1769 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); | 683 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); |
1770 } | 684 } |
1771 pr = fSoftwarePathRenderer; | 685 pr = fSoftwarePathRenderer; |
1772 } | 686 } |
1773 | 687 |
1774 return pr; | 688 return pr; |
1775 } | 689 } |
1776 | 690 |
1777 //////////////////////////////////////////////////////////////////////////////// | 691 //////////////////////////////////////////////////////////////////////////////// |
1778 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { | 692 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { |
(...skipping 10 matching lines...) Expand all Loading... |
1789 if (dpi >= 250.0f) { | 703 if (dpi >= 250.0f) { |
1790 chosenSampleCount = 4; | 704 chosenSampleCount = 4; |
1791 } else { | 705 } else { |
1792 chosenSampleCount = 16; | 706 chosenSampleCount = 16; |
1793 } | 707 } |
1794 } | 708 } |
1795 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? | 709 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? |
1796 chosenSampleCount : 0; | 710 chosenSampleCount : 0; |
1797 } | 711 } |
1798 | 712 |
1799 GrDrawTarget* GrContext::getTextTarget() { | |
1800 return this->prepareToDraw(); | |
1801 } | |
1802 | |
1803 namespace { | 713 namespace { |
1804 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { | 714 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { |
1805 GrConfigConversionEffect::PMConversion pmToUPM; | 715 GrConfigConversionEffect::PMConversion pmToUPM; |
1806 GrConfigConversionEffect::PMConversion upmToPM; | 716 GrConfigConversionEffect::PMConversion upmToPM; |
1807 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm
ToPM); | 717 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm
ToPM); |
1808 *pmToUPMValue = pmToUPM; | 718 *pmToUPMValue = pmToUPM; |
1809 *upmToPMValue = upmToPM; | 719 *upmToPMValue = upmToPM; |
1810 } | 720 } |
1811 } | 721 } |
1812 | 722 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1854 } | 764 } |
1855 | 765 |
1856 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
{ | 766 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
{ |
1857 fResourceCache->setLimits(maxTextures, maxTextureBytes); | 767 fResourceCache->setLimits(maxTextures, maxTextureBytes); |
1858 } | 768 } |
1859 | 769 |
1860 ////////////////////////////////////////////////////////////////////////////// | 770 ////////////////////////////////////////////////////////////////////////////// |
1861 | 771 |
1862 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { | 772 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { |
1863 fGpu->addGpuTraceMarker(marker); | 773 fGpu->addGpuTraceMarker(marker); |
1864 if (fDrawBuffer) { | |
1865 fDrawBuffer->addGpuTraceMarker(marker); | |
1866 } | |
1867 } | 774 } |
1868 | 775 |
1869 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { | 776 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { |
1870 fGpu->removeGpuTraceMarker(marker); | 777 fGpu->removeGpuTraceMarker(marker); |
1871 if (fDrawBuffer) { | |
1872 fDrawBuffer->removeGpuTraceMarker(marker); | |
1873 } | |
1874 } | 778 } |
1875 | 779 |
1876 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
1877 | |
1878 #ifdef GR_TEST_UTILS | |
1879 | |
1880 BATCH_TEST_DEFINE(StrokeRectBatch) { | |
1881 StrokeRectBatch::Geometry geometry; | |
1882 geometry.fViewMatrix = GrTest::TestMatrix(random); | |
1883 geometry.fColor = GrRandomColor(random); | |
1884 geometry.fRect = GrTest::TestRect(random); | |
1885 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; | |
1886 | |
1887 return StrokeRectBatch::Create(geometry, random->nextBool()); | |
1888 } | |
1889 | |
1890 static uint32_t seed_vertices(GrPrimitiveType type) { | |
1891 switch (type) { | |
1892 case kTriangles_GrPrimitiveType: | |
1893 case kTriangleStrip_GrPrimitiveType: | |
1894 case kTriangleFan_GrPrimitiveType: | |
1895 return 3; | |
1896 case kPoints_GrPrimitiveType: | |
1897 return 1; | |
1898 case kLines_GrPrimitiveType: | |
1899 case kLineStrip_GrPrimitiveType: | |
1900 return 2; | |
1901 } | |
1902 SkFAIL("Incomplete switch\n"); | |
1903 return 0; | |
1904 } | |
1905 | |
1906 static uint32_t primitive_vertices(GrPrimitiveType type) { | |
1907 switch (type) { | |
1908 case kTriangles_GrPrimitiveType: | |
1909 return 3; | |
1910 case kLines_GrPrimitiveType: | |
1911 return 2; | |
1912 case kTriangleStrip_GrPrimitiveType: | |
1913 case kTriangleFan_GrPrimitiveType: | |
1914 case kPoints_GrPrimitiveType: | |
1915 case kLineStrip_GrPrimitiveType: | |
1916 return 1; | |
1917 } | |
1918 SkFAIL("Incomplete switch\n"); | |
1919 return 0; | |
1920 } | |
1921 | |
1922 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { | |
1923 SkPoint p; | |
1924 p.fX = random->nextRangeScalar(min, max); | |
1925 p.fY = random->nextRangeScalar(min, max); | |
1926 return p; | |
1927 } | |
1928 | |
1929 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkSca
lar max, | |
1930 SkRandom* random, | |
1931 SkTArray<SkPoint>* positions, | |
1932 SkTArray<SkPoint>* texCoords, bool hasTexCoords, | |
1933 SkTArray<GrColor>* colors, bool hasColors, | |
1934 SkTArray<uint16_t>* indices, bool hasIndices) { | |
1935 for (uint32_t v = 0; v < count; v++) { | |
1936 positions->push_back(random_point(random, min, max)); | |
1937 if (hasTexCoords) { | |
1938 texCoords->push_back(random_point(random, min, max)); | |
1939 } | |
1940 if (hasColors) { | |
1941 colors->push_back(GrRandomColor(random)); | |
1942 } | |
1943 if (hasIndices) { | |
1944 SkASSERT(maxVertex <= SK_MaxU16); | |
1945 indices->push_back(random->nextULessThan((uint16_t)maxVertex)); | |
1946 } | |
1947 } | |
1948 } | |
1949 | |
1950 BATCH_TEST_DEFINE(VerticesBatch) { | |
1951 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimiti
veType + 1)); | |
1952 uint32_t primitiveCount = random->nextRangeU(1, 100); | |
1953 | |
1954 // TODO make 'sensible' indexbuffers | |
1955 SkTArray<SkPoint> positions; | |
1956 SkTArray<SkPoint> texCoords; | |
1957 SkTArray<GrColor> colors; | |
1958 SkTArray<uint16_t> indices; | |
1959 | |
1960 bool hasTexCoords = random->nextBool(); | |
1961 bool hasIndices = random->nextBool(); | |
1962 bool hasColors = random->nextBool(); | |
1963 | |
1964 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitiv
e_vertices(type); | |
1965 | |
1966 static const SkScalar kMinVertExtent = -100.f; | |
1967 static const SkScalar kMaxVertExtent = 100.f; | |
1968 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertE
xtent, | |
1969 random, | |
1970 &positions, | |
1971 &texCoords, hasTexCoords, | |
1972 &colors, hasColors, | |
1973 &indices, hasIndices); | |
1974 | |
1975 for (uint32_t i = 1; i < primitiveCount; i++) { | |
1976 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent,
kMaxVertExtent, | |
1977 random, | |
1978 &positions, | |
1979 &texCoords, hasTexCoords, | |
1980 &colors, hasColors, | |
1981 &indices, hasIndices); | |
1982 } | |
1983 | |
1984 SkMatrix viewMatrix = GrTest::TestMatrix(random); | |
1985 SkRect bounds; | |
1986 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexC
ount); | |
1987 SkASSERT(result); | |
1988 | |
1989 viewMatrix.mapRect(&bounds); | |
1990 | |
1991 DrawVerticesBatch::Geometry geometry; | |
1992 geometry.fColor = GrRandomColor(random); | |
1993 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | |
1994 positions.begin(), vertexCount, | |
1995 indices.begin(), hasIndices ? vertexCount :
0, | |
1996 colors.begin(), | |
1997 texCoords.begin(), | |
1998 bounds); | |
1999 } | |
2000 | |
2001 #endif | |
OLD | NEW |