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