Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: src/gpu/GrContext.cpp

Issue 1151283004: Split drawing functionality out of GrContext and into new GrDrawContext (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 fContext = context;
bsalomon 2015/05/22 20:33:57 Do we need to remember this context? I'm working h
robertphillips 2015/05/26 16:12:58 Done. Note that the GrDrawContext has its GrConte
63
64 #ifdef IMMEDIATE_MODE
65 fDrawTarget = SkNEW_ARGS(GrImmediateDrawTarget, (context));
66 #else
67 fDrawTarget = SkNEW_ARGS(GrInOrderDrawBuffer, (context));
68 #endif
69
70 fDrawContext = SkNEW_ARGS(GrDrawContext, (fContext, fDrawTarget));
71 }
72
73 GrContext::DrawingMgr::~DrawingMgr() {
74 SkSafeUnref(fDrawTarget);
75 SkSafeUnref(fDrawContext);
76 }
77
78 void GrContext::DrawingMgr::abandon() {
79 SkSafeSetNull(fDrawTarget);
80 fDrawContext->fDrawTarget.reset(NULL);
81 SkSafeSetNull(fDrawContext);
82 }
83
84 void GrContext::DrawingMgr::purgeResources() {
85 if (fDrawTarget) {
86 fDrawTarget->purgeResources();
67 } 87 }
88 }
68 89
69 private: 90 void GrContext::DrawingMgr::reset() {
70 GrContext* fContext; 91 if (fDrawTarget) {
71 }; 92 fDrawTarget->reset();
93 }
94 }
95
96 void GrContext::DrawingMgr::flush() {
97 if (fDrawTarget) {
98 fDrawTarget->flush();
99 }
100 }
101
102 GrDrawContext* GrContext::DrawingMgr::drawContext() {
103 if (this->abandoned()) {
104 return NULL;
105 }
106 return fDrawContext;
107 }
108
109 ////////////////////////////////////////////////////////////////////////////////
110
72 111
73 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, 112 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
74 const Options* opts) { 113 const Options* opts) {
75 GrContext* context; 114 GrContext* context;
76 if (NULL == opts) { 115 if (NULL == opts) {
77 context = SkNEW_ARGS(GrContext, (Options())); 116 context = SkNEW_ARGS(GrContext, (Options()));
78 } else { 117 } else {
79 context = SkNEW_ARGS(GrContext, (*opts)); 118 context = SkNEW_ARGS(GrContext, (*opts));
80 } 119 }
81 120
(...skipping 14 matching lines...) Expand all
96 return id; 135 return id;
97 } 136 }
98 137
99 GrContext::GrContext(const Options& opts) : fOptions(opts), fUniqueID(next_id()) { 138 GrContext::GrContext(const Options& opts) : fOptions(opts), fUniqueID(next_id()) {
100 fGpu = NULL; 139 fGpu = NULL;
101 fResourceCache = NULL; 140 fResourceCache = NULL;
102 fResourceProvider = NULL; 141 fResourceProvider = NULL;
103 fPathRendererChain = NULL; 142 fPathRendererChain = NULL;
104 fSoftwarePathRenderer = NULL; 143 fSoftwarePathRenderer = NULL;
105 fBatchFontCache = NULL; 144 fBatchFontCache = NULL;
106 fDrawBuffer = NULL;
107 fFlushToReduceCacheSize = false; 145 fFlushToReduceCacheSize = false;
108 fAARectRenderer = NULL;
109 fOvalRenderer = NULL;
110 fMaxTextureSizeOverride = 1 << 20; 146 fMaxTextureSizeOverride = 1 << 20;
111 } 147 }
112 148
113 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { 149 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
114 SkASSERT(NULL == fGpu); 150 SkASSERT(NULL == fGpu);
115 151
116 fGpu = GrGpu::Create(backend, backendContext, this); 152 fGpu = GrGpu::Create(backend, backendContext, this);
117 if (NULL == fGpu) { 153 if (NULL == fGpu) {
118 return false; 154 return false;
119 } 155 }
120 this->initCommon(); 156 this->initCommon();
121 return true; 157 return true;
122 } 158 }
123 159
124 void GrContext::initCommon() { 160 void GrContext::initCommon() {
125 fResourceCache = SkNEW(GrResourceCache); 161 fResourceCache = SkNEW(GrResourceCache);
126 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); 162 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
127 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); 163 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache));
128 164
129 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); 165 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
130 166
131 fAARectRenderer = SkNEW(GrAARectRenderer);
132 fOvalRenderer = SkNEW(GrOvalRenderer);
133
134 fDidTestPMConversions = false; 167 fDidTestPMConversions = false;
135 168
136 #ifdef IMMEDIATE_MODE 169 fDrawingMgr.init(this);
137 fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this));
138 #else
139 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this));
140 #endif
141 170
142 // GrBatchFontCache will eventually replace GrFontCache 171 // GrBatchFontCache will eventually replace GrFontCache
143 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); 172 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this));
144 173
145 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this))); 174 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this)));
146 } 175 }
147 176
148 GrContext::~GrContext() { 177 GrContext::~GrContext() {
149 if (NULL == fGpu) { 178 if (NULL == fGpu) {
150 return; 179 return;
151 } 180 }
152 181
153 this->flush(); 182 this->flush();
154 183
155 for (int i = 0; i < fCleanUpData.count(); ++i) { 184 for (int i = 0; i < fCleanUpData.count(); ++i) {
156 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); 185 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
157 } 186 }
158 187
159 SkDELETE(fResourceProvider); 188 SkDELETE(fResourceProvider);
160 SkDELETE(fResourceCache); 189 SkDELETE(fResourceCache);
161 SkDELETE(fBatchFontCache); 190 SkDELETE(fBatchFontCache);
162 SkDELETE(fDrawBuffer);
163
164 fAARectRenderer->unref();
165 fOvalRenderer->unref();
166 191
167 fGpu->unref(); 192 fGpu->unref();
168 SkSafeUnref(fPathRendererChain); 193 SkSafeUnref(fPathRendererChain);
169 SkSafeUnref(fSoftwarePathRenderer); 194 SkSafeUnref(fSoftwarePathRenderer);
170 } 195 }
171 196
172 void GrContext::abandonContext() { 197 void GrContext::abandonContext() {
173 fResourceProvider->abandon(); 198 fResourceProvider->abandon();
174 // abandon first to so destructors 199 // abandon first to so destructors
175 // don't try to free the resources in the API. 200 // don't try to free the resources in the API.
176 fResourceCache->abandonAll(); 201 fResourceCache->abandonAll();
177 202
178 fGpu->contextAbandoned(); 203 fGpu->contextAbandoned();
179 204
180 // a path renderer may be holding onto resources that 205 // a path renderer may be holding onto resources that
181 // are now unusable 206 // are now unusable
182 SkSafeSetNull(fPathRendererChain); 207 SkSafeSetNull(fPathRendererChain);
183 SkSafeSetNull(fSoftwarePathRenderer); 208 SkSafeSetNull(fSoftwarePathRenderer);
184 209
185 SkDELETE(fDrawBuffer); 210 fDrawingMgr.abandon();
186 fDrawBuffer = NULL;
187 211
188 fBatchFontCache->freeAll(); 212 fBatchFontCache->freeAll();
189 fLayerCache->freeAll(); 213 fLayerCache->freeAll();
190 fTextBlobCache->freeAll(); 214 fTextBlobCache->freeAll();
191 } 215 }
192 216
193 void GrContext::resetContext(uint32_t state) { 217 void GrContext::resetContext(uint32_t state) {
194 fGpu->markContextDirty(state); 218 fGpu->markContextDirty(state);
195 } 219 }
196 220
197 void GrContext::freeGpuResources() { 221 void GrContext::freeGpuResources() {
198 this->flush(); 222 this->flush();
199 223
200 if (fDrawBuffer) { 224 fDrawingMgr.purgeResources();
201 fDrawBuffer->purgeResources();
202 }
203 225
204 fBatchFontCache->freeAll(); 226 fBatchFontCache->freeAll();
205 fLayerCache->freeAll(); 227 fLayerCache->freeAll();
206 // a path renderer may be holding onto resources 228 // a path renderer may be holding onto resources
207 SkSafeSetNull(fPathRendererChain); 229 SkSafeSetNull(fPathRendererChain);
208 SkSafeSetNull(fSoftwarePathRenderer); 230 SkSafeSetNull(fSoftwarePathRenderer);
209 231
210 fResourceCache->purgeAllUnlocked(); 232 fResourceCache->purgeAllUnlocked();
211 } 233 }
212 234
(...skipping 16 matching lines...) Expand all
229 if (sb) { 251 if (sb) {
230 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr operties); 252 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr operties);
231 } 253 }
232 } 254 }
233 255
234 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi stanceFieldFonts); 256 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi stanceFieldFonts);
235 } 257 }
236 258
237 //////////////////////////////////////////////////////////////////////////////// 259 ////////////////////////////////////////////////////////////////////////////////
238 260
261 bool GrContext::shaderDerivativeSupport() const {
262 return fGpu->caps()->shaderCaps()->shaderDerivativeSupport();
263 }
264
239 bool GrContext::isConfigTexturable(GrPixelConfig config) const { 265 bool GrContext::isConfigTexturable(GrPixelConfig config) const {
240 return fGpu->caps()->isConfigTexturable(config); 266 return fGpu->caps()->isConfigTexturable(config);
241 } 267 }
242 268
243 bool GrContext::npotTextureTileSupport() const { 269 bool GrContext::npotTextureTileSupport() const {
244 return fGpu->caps()->npotTextureTileSupport(); 270 return fGpu->caps()->npotTextureTileSupport();
245 } 271 }
246 272
247 void GrContext::OverBudgetCB(void* data) { 273 void GrContext::OverBudgetCB(void* data) {
248 SkASSERT(data); 274 SkASSERT(data);
(...skipping 20 matching lines...) Expand all
269 } 295 }
270 296
271 int GrContext::getMaxRenderTargetSize() const { 297 int GrContext::getMaxRenderTargetSize() const {
272 return fGpu->caps()->maxRenderTargetSize(); 298 return fGpu->caps()->maxRenderTargetSize();
273 } 299 }
274 300
275 int GrContext::getMaxSampleCount() const { 301 int GrContext::getMaxSampleCount() const {
276 return fGpu->caps()->maxSampleCount(); 302 return fGpu->caps()->maxSampleCount();
277 } 303 }
278 304
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 //////////////////////////////////////////////////////////////////////////////// 305 ////////////////////////////////////////////////////////////////////////////////
1356 306
1357 void GrContext::flush(int flagsBitfield) { 307 void GrContext::flush(int flagsBitfield) {
1358 if (NULL == fDrawBuffer) { 308 RETURN_IF_ABANDONED
1359 return;
1360 }
1361 309
1362 if (kDiscard_FlushBit & flagsBitfield) { 310 if (kDiscard_FlushBit & flagsBitfield) {
1363 fDrawBuffer->reset(); 311 fDrawingMgr.reset();
1364 } else { 312 } else {
1365 fDrawBuffer->flush(); 313 fDrawingMgr.flush();
1366 } 314 }
1367 fResourceCache->notifyFlushOccurred(); 315 fResourceCache->notifyFlushOccurred();
1368 fFlushToReduceCacheSize = false; 316 fFlushToReduceCacheSize = false;
1369 } 317 }
1370 318
1371 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, 319 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1372 const void* inPixels, size_t outRowBytes, void* outPix els) { 320 const void* inPixels, size_t outRowBytes, void* outPix els) {
1373 SkSrcPixelInfo srcPI; 321 SkSrcPixelInfo srcPI;
1374 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) { 322 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
1375 return false; 323 return false;
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 this->flush(); 422 this->flush();
1475 } 423 }
1476 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, 424 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1477 writeConfig, buffer, rowBytes)) { 425 writeConfig, buffer, rowBytes)) {
1478 return false; 426 return false;
1479 } 427 }
1480 428
1481 SkMatrix matrix; 429 SkMatrix matrix;
1482 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 430 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1483 431
1484 // This function can be called in the midst of drawing another object (e.g., when uploading a 432 GrDrawContext* drawContext = this->drawContext();
1485 // SW-rasterized clip while issuing a draw). So we push the current geometry state before 433 if (!drawContext) {
1486 // drawing a rect to the render target. 434 return false;
1487 // The bracket ensures we pop the stack if we wind up flushing below. 435 }
1488 {
1489 GrDrawTarget* drawTarget = this->prepareToDraw();
1490 if (!drawTarget) {
1491 return false;
1492 }
1493 436
1494 GrPipelineBuilder pipelineBuilder; 437 GrPaint paint;
1495 pipelineBuilder.addColorProcessor(fp); 438 paint.addColorProcessor(fp);
1496 pipelineBuilder.setRenderTarget(renderTarget); 439
1497 drawTarget->drawSimpleRect(&pipelineBuilder, 440 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1498 GrColor_WHITE, 441
1499 matrix, 442 drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect, NULL);
1500 SkRect::MakeWH(SkIntToScalar(width), SkIntToS calar(height)));
1501 }
1502 443
1503 if (kFlushWrites_PixelOp & pixelOpsFlags) { 444 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1504 this->flushSurfaceWrites(surface); 445 this->flushSurfaceWrites(surface);
1505 } 446 }
1506 447
1507 return true; 448 return true;
1508 } 449 }
1509 450
1510 // toggles between RGBA and BGRA 451 // toggles between RGBA and BGRA
1511 static SkColorType toggle_colortype32(SkColorType ct) { 452 static SkColorType toggle_colortype32(SkColorType ct) {
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 fp.reset(GrConfigConversionEffect::Create( 546 fp.reset(GrConfigConversionEffect::Create(
1606 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo nversion, 547 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo nversion,
1607 textureMatrix)); 548 textureMatrix));
1608 } 549 }
1609 swapRAndB = false; // we will handle the swap in the draw. 550 swapRAndB = false; // we will handle the swap in the draw.
1610 551
1611 // We protect the existing geometry here since it may not be 552 // We protect the existing geometry here since it may not be
1612 // clear to the caller that a draw operation (i.e., drawSimpleRe ct) 553 // clear to the caller that a draw operation (i.e., drawSimpleRe ct)
1613 // can be invoked in this method 554 // can be invoked in this method
1614 { 555 {
1615 GrPipelineBuilder pipelineBuilder; 556 GrDrawContext* drawContext = this->drawContext();
1616 SkASSERT(fp); 557 if (!drawContext) {
1617 pipelineBuilder.addColorProcessor(fp); 558 return false;
559 }
1618 560
1619 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget( )); 561 GrPaint paint;
562 paint.addColorProcessor(fp);
563
1620 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc alar(height)); 564 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc alar(height));
1621 fDrawBuffer->drawSimpleRect(&pipelineBuilder, 565
1622 GrColor_WHITE, 566 drawContext->drawRect(tempTexture->asRenderTarget(), GrClip: :WideOpen(), paint,
1623 SkMatrix::I(), 567 SkMatrix::I(), rect, NULL);
1624 rect); 568
1625 // we want to read back from the scratch's origin 569 // we want to read back from the scratch's origin
1626 left = 0; 570 left = 0;
1627 top = 0; 571 top = 0;
1628 target = tempTexture->asRenderTarget(); 572 target = tempTexture->asRenderTarget();
1629 } 573 }
1630 this->flushSurfaceWrites(target); 574 this->flushSurfaceWrites(target);
1631 } 575 }
1632 } 576 }
1633 } 577 }
1634 578
(...skipping 29 matching lines...) Expand all
1664 ASSERT_OWNED_RESOURCE(surface); 608 ASSERT_OWNED_RESOURCE(surface);
1665 if (surface->surfacePriv().hasPendingIO()) { 609 if (surface->surfacePriv().hasPendingIO()) {
1666 this->flush(); 610 this->flush();
1667 } 611 }
1668 GrRenderTarget* rt = surface->asRenderTarget(); 612 GrRenderTarget* rt = surface->asRenderTarget();
1669 if (fGpu && rt) { 613 if (fGpu && rt) {
1670 fGpu->resolveRenderTarget(rt); 614 fGpu->resolveRenderTarget(rt);
1671 } 615 }
1672 } 616 }
1673 617
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, 618 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe ct,
1687 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { 619 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
1688 RETURN_IF_ABANDONED 620 RETURN_IF_ABANDONED
1689 if (NULL == src || NULL == dst) { 621 if (NULL == src || NULL == dst) {
1690 return; 622 return;
1691 } 623 }
1692 ASSERT_OWNED_RESOURCE(src); 624 ASSERT_OWNED_RESOURCE(src);
1693 ASSERT_OWNED_RESOURCE(dst); 625 ASSERT_OWNED_RESOURCE(dst);
1694 626
1695 // Since we're going to the draw target and not GPU, no need to check kNoFlu sh 627 // Since we're going to the draw target and not GPU, no need to check kNoFlu sh
1696 // here. 628 // here.
1697 629 if (NULL == dst->asRenderTarget()) {
bsalomon 2015/05/22 20:33:58 !dst->asRenderTarget() ?
robertphillips 2015/05/26 16:12:58 Done.
1698 GrDrawTarget* target = this->prepareToDraw();
1699 if (NULL == target) {
1700 return; 630 return;
1701 } 631 }
1702 target->copySurface(dst, src, srcRect, dstPoint); 632
633 GrDrawContext* drawContext = this->drawContext();
634 if (!drawContext) {
635 return;
636 }
637
638 drawContext->copySurface(dst->asRenderTarget(), src, srcRect, dstPoint);
1703 639
1704 if (kFlushWrites_PixelOp & pixelOpsFlags) { 640 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1705 this->flush(); 641 this->flush();
1706 } 642 }
1707 } 643 }
1708 644
1709 void GrContext::flushSurfaceWrites(GrSurface* surface) { 645 void GrContext::flushSurfaceWrites(GrSurface* surface) {
1710 RETURN_IF_ABANDONED 646 RETURN_IF_ABANDONED
1711 if (surface->surfacePriv().hasPendingWrite()) { 647 if (surface->surfacePriv().hasPendingWrite()) {
1712 this->flush(); 648 this->flush();
1713 } 649 }
1714 } 650 }
1715 651
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 /* 652 /*
1739 * This method finds a path renderer that can draw the specified path on 653 * This method finds a path renderer that can draw the specified path on
1740 * the provided target. 654 * the provided target.
1741 * Due to its expense, the software path renderer has split out so it can 655 * Due to its expense, the software path renderer has split out so it can
1742 * can be individually allowed/disallowed via the "allowSW" boolean. 656 * can be individually allowed/disallowed via the "allowSW" boolean.
1743 */ 657 */
1744 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, 658 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1745 const GrPipelineBuilder* pipelineBuil der, 659 const GrPipelineBuilder* pipelineBuil der,
1746 const SkMatrix& viewMatrix, 660 const SkMatrix& viewMatrix,
1747 const SkPath& path, 661 const SkPath& path,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1787 if (dpi >= 250.0f) { 701 if (dpi >= 250.0f) {
1788 chosenSampleCount = 4; 702 chosenSampleCount = 4;
1789 } else { 703 } else {
1790 chosenSampleCount = 16; 704 chosenSampleCount = 16;
1791 } 705 }
1792 } 706 }
1793 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? 707 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1794 chosenSampleCount : 0; 708 chosenSampleCount : 0;
1795 } 709 }
1796 710
1797 GrDrawTarget* GrContext::getTextTarget() {
1798 return this->prepareToDraw();
1799 }
1800
1801 namespace { 711 namespace {
1802 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { 712 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1803 GrConfigConversionEffect::PMConversion pmToUPM; 713 GrConfigConversionEffect::PMConversion pmToUPM;
1804 GrConfigConversionEffect::PMConversion upmToPM; 714 GrConfigConversionEffect::PMConversion upmToPM;
1805 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm ToPM); 715 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm ToPM);
1806 *pmToUPMValue = pmToUPM; 716 *pmToUPMValue = pmToUPM;
1807 *upmToPMValue = upmToPM; 717 *upmToPMValue = upmToPM;
1808 } 718 }
1809 } 719 }
1810 720
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1852 } 762 }
1853 763
1854 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { 764 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
1855 fResourceCache->setLimits(maxTextures, maxTextureBytes); 765 fResourceCache->setLimits(maxTextures, maxTextureBytes);
1856 } 766 }
1857 767
1858 ////////////////////////////////////////////////////////////////////////////// 768 //////////////////////////////////////////////////////////////////////////////
1859 769
1860 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { 770 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1861 fGpu->addGpuTraceMarker(marker); 771 fGpu->addGpuTraceMarker(marker);
1862 if (fDrawBuffer) {
1863 fDrawBuffer->addGpuTraceMarker(marker);
1864 }
1865 } 772 }
1866 773
1867 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { 774 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
1868 fGpu->removeGpuTraceMarker(marker); 775 fGpu->removeGpuTraceMarker(marker);
1869 if (fDrawBuffer) {
1870 fDrawBuffer->removeGpuTraceMarker(marker);
1871 }
1872 } 776 }
1873 777
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698