|
1 |
|
2 /* |
|
3 * Copyright 2010 Google Inc. |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 |
|
11 #include "GrDrawTarget.h" |
|
12 #include "GrContext.h" |
|
13 #include "GrDrawTargetCaps.h" |
|
14 #include "GrPath.h" |
|
15 #include "GrRenderTarget.h" |
|
16 #include "GrTexture.h" |
|
17 #include "GrVertexBuffer.h" |
|
18 |
|
19 #include "SkStrokeRec.h" |
|
20 |
|
21 //////////////////////////////////////////////////////////////////////////////// |
|
22 |
|
23 GrDrawTarget::DrawInfo& GrDrawTarget::DrawInfo::operator =(const DrawInfo& di) { |
|
24 fPrimitiveType = di.fPrimitiveType; |
|
25 fStartVertex = di.fStartVertex; |
|
26 fStartIndex = di.fStartIndex; |
|
27 fVertexCount = di.fVertexCount; |
|
28 fIndexCount = di.fIndexCount; |
|
29 |
|
30 fInstanceCount = di.fInstanceCount; |
|
31 fVerticesPerInstance = di.fVerticesPerInstance; |
|
32 fIndicesPerInstance = di.fIndicesPerInstance; |
|
33 |
|
34 if (NULL != di.fDevBounds) { |
|
35 SkASSERT(di.fDevBounds == &di.fDevBoundsStorage); |
|
36 fDevBoundsStorage = di.fDevBoundsStorage; |
|
37 fDevBounds = &fDevBoundsStorage; |
|
38 } else { |
|
39 fDevBounds = NULL; |
|
40 } |
|
41 |
|
42 fDstCopy = di.fDstCopy; |
|
43 |
|
44 return *this; |
|
45 } |
|
46 |
|
47 #ifdef SK_DEBUG |
|
48 bool GrDrawTarget::DrawInfo::isInstanced() const { |
|
49 if (fInstanceCount > 0) { |
|
50 SkASSERT(0 == fIndexCount % fIndicesPerInstance); |
|
51 SkASSERT(0 == fVertexCount % fVerticesPerInstance); |
|
52 SkASSERT(fIndexCount / fIndicesPerInstance == fInstanceCount); |
|
53 SkASSERT(fVertexCount / fVerticesPerInstance == fInstanceCount); |
|
54 // there is no way to specify a non-zero start index to drawIndexedInstances(). |
|
55 SkASSERT(0 == fStartIndex); |
|
56 return true; |
|
57 } else { |
|
58 SkASSERT(!fVerticesPerInstance); |
|
59 SkASSERT(!fIndicesPerInstance); |
|
60 return false; |
|
61 } |
|
62 } |
|
63 #endif |
|
64 |
|
65 void GrDrawTarget::DrawInfo::adjustInstanceCount(int instanceOffset) { |
|
66 SkASSERT(this->isInstanced()); |
|
67 SkASSERT(instanceOffset + fInstanceCount >= 0); |
|
68 fInstanceCount += instanceOffset; |
|
69 fVertexCount = fVerticesPerInstance * fInstanceCount; |
|
70 fIndexCount = fIndicesPerInstance * fInstanceCount; |
|
71 } |
|
72 |
|
73 void GrDrawTarget::DrawInfo::adjustStartVertex(int vertexOffset) { |
|
74 fStartVertex += vertexOffset; |
|
75 SkASSERT(fStartVertex >= 0); |
|
76 } |
|
77 |
|
78 void GrDrawTarget::DrawInfo::adjustStartIndex(int indexOffset) { |
|
79 SkASSERT(this->isIndexed()); |
|
80 fStartIndex += indexOffset; |
|
81 SkASSERT(fStartIndex >= 0); |
|
82 } |
|
83 |
|
84 //////////////////////////////////////////////////////////////////////////////// |
|
85 |
|
86 #define DEBUG_INVAL_BUFFER 0xdeadcafe |
|
87 #define DEBUG_INVAL_START_IDX -1 |
|
88 |
|
89 GrDrawTarget::GrDrawTarget(GrContext* context) |
|
90 : fClip(NULL) |
|
91 , fContext(context) |
|
92 , fPushGpuTraceCount(0) { |
|
93 SkASSERT(NULL != context); |
|
94 |
|
95 fDrawState = &fDefaultDrawState; |
|
96 // We assume that fDrawState always owns a ref to the object it points at. |
|
97 fDefaultDrawState.ref(); |
|
98 GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back(); |
|
99 #ifdef SK_DEBUG |
|
100 geoSrc.fVertexCount = DEBUG_INVAL_START_IDX; |
|
101 geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER; |
|
102 geoSrc.fIndexCount = DEBUG_INVAL_START_IDX; |
|
103 geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER; |
|
104 #endif |
|
105 geoSrc.fVertexSrc = kNone_GeometrySrcType; |
|
106 geoSrc.fIndexSrc = kNone_GeometrySrcType; |
|
107 } |
|
108 |
|
109 GrDrawTarget::~GrDrawTarget() { |
|
110 SkASSERT(1 == fGeoSrcStateStack.count()); |
|
111 SkDEBUGCODE(GeometrySrcState& geoSrc = fGeoSrcStateStack.back()); |
|
112 SkASSERT(kNone_GeometrySrcType == geoSrc.fIndexSrc); |
|
113 SkASSERT(kNone_GeometrySrcType == geoSrc.fVertexSrc); |
|
114 fDrawState->unref(); |
|
115 } |
|
116 |
|
117 void GrDrawTarget::releaseGeometry() { |
|
118 int popCnt = fGeoSrcStateStack.count() - 1; |
|
119 while (popCnt) { |
|
120 this->popGeometrySource(); |
|
121 --popCnt; |
|
122 } |
|
123 this->resetVertexSource(); |
|
124 this->resetIndexSource(); |
|
125 } |
|
126 |
|
127 void GrDrawTarget::setClip(const GrClipData* clip) { |
|
128 clipWillBeSet(clip); |
|
129 fClip = clip; |
|
130 } |
|
131 |
|
132 const GrClipData* GrDrawTarget::getClip() const { |
|
133 return fClip; |
|
134 } |
|
135 |
|
136 void GrDrawTarget::setDrawState(GrDrawState* drawState) { |
|
137 SkASSERT(NULL != fDrawState); |
|
138 if (NULL == drawState) { |
|
139 drawState = &fDefaultDrawState; |
|
140 } |
|
141 if (fDrawState != drawState) { |
|
142 fDrawState->unref(); |
|
143 drawState->ref(); |
|
144 fDrawState = drawState; |
|
145 } |
|
146 } |
|
147 |
|
148 bool GrDrawTarget::reserveVertexSpace(size_t vertexSize, |
|
149 int vertexCount, |
|
150 void** vertices) { |
|
151 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
152 bool acquired = false; |
|
153 if (vertexCount > 0) { |
|
154 SkASSERT(NULL != vertices); |
|
155 this->releasePreviousVertexSource(); |
|
156 geoSrc.fVertexSrc = kNone_GeometrySrcType; |
|
157 |
|
158 acquired = this->onReserveVertexSpace(vertexSize, |
|
159 vertexCount, |
|
160 vertices); |
|
161 } |
|
162 if (acquired) { |
|
163 geoSrc.fVertexSrc = kReserved_GeometrySrcType; |
|
164 geoSrc.fVertexCount = vertexCount; |
|
165 geoSrc.fVertexSize = vertexSize; |
|
166 } else if (NULL != vertices) { |
|
167 *vertices = NULL; |
|
168 } |
|
169 return acquired; |
|
170 } |
|
171 |
|
172 bool GrDrawTarget::reserveIndexSpace(int indexCount, |
|
173 void** indices) { |
|
174 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
175 bool acquired = false; |
|
176 if (indexCount > 0) { |
|
177 SkASSERT(NULL != indices); |
|
178 this->releasePreviousIndexSource(); |
|
179 geoSrc.fIndexSrc = kNone_GeometrySrcType; |
|
180 |
|
181 acquired = this->onReserveIndexSpace(indexCount, indices); |
|
182 } |
|
183 if (acquired) { |
|
184 geoSrc.fIndexSrc = kReserved_GeometrySrcType; |
|
185 geoSrc.fIndexCount = indexCount; |
|
186 } else if (NULL != indices) { |
|
187 *indices = NULL; |
|
188 } |
|
189 return acquired; |
|
190 |
|
191 } |
|
192 |
|
193 bool GrDrawTarget::reserveVertexAndIndexSpace(int vertexCount, |
|
194 int indexCount, |
|
195 void** vertices, |
|
196 void** indices) { |
|
197 size_t vertexSize = this->drawState()->getVertexSize(); |
|
198 this->willReserveVertexAndIndexSpace(vertexCount, indexCount); |
|
199 if (vertexCount) { |
|
200 if (!this->reserveVertexSpace(vertexSize, vertexCount, vertices)) { |
|
201 if (indexCount) { |
|
202 this->resetIndexSource(); |
|
203 } |
|
204 return false; |
|
205 } |
|
206 } |
|
207 if (indexCount) { |
|
208 if (!this->reserveIndexSpace(indexCount, indices)) { |
|
209 if (vertexCount) { |
|
210 this->resetVertexSource(); |
|
211 } |
|
212 return false; |
|
213 } |
|
214 } |
|
215 return true; |
|
216 } |
|
217 |
|
218 bool GrDrawTarget::geometryHints(int32_t* vertexCount, |
|
219 int32_t* indexCount) const { |
|
220 if (NULL != vertexCount) { |
|
221 *vertexCount = -1; |
|
222 } |
|
223 if (NULL != indexCount) { |
|
224 *indexCount = -1; |
|
225 } |
|
226 return false; |
|
227 } |
|
228 |
|
229 void GrDrawTarget::releasePreviousVertexSource() { |
|
230 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
231 switch (geoSrc.fVertexSrc) { |
|
232 case kNone_GeometrySrcType: |
|
233 break; |
|
234 case kArray_GeometrySrcType: |
|
235 this->releaseVertexArray(); |
|
236 break; |
|
237 case kReserved_GeometrySrcType: |
|
238 this->releaseReservedVertexSpace(); |
|
239 break; |
|
240 case kBuffer_GeometrySrcType: |
|
241 geoSrc.fVertexBuffer->unref(); |
|
242 #ifdef SK_DEBUG |
|
243 geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER; |
|
244 #endif |
|
245 break; |
|
246 default: |
|
247 GrCrash("Unknown Vertex Source Type."); |
|
248 break; |
|
249 } |
|
250 } |
|
251 |
|
252 void GrDrawTarget::releasePreviousIndexSource() { |
|
253 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
254 switch (geoSrc.fIndexSrc) { |
|
255 case kNone_GeometrySrcType: // these two don't require |
|
256 break; |
|
257 case kArray_GeometrySrcType: |
|
258 this->releaseIndexArray(); |
|
259 break; |
|
260 case kReserved_GeometrySrcType: |
|
261 this->releaseReservedIndexSpace(); |
|
262 break; |
|
263 case kBuffer_GeometrySrcType: |
|
264 geoSrc.fIndexBuffer->unref(); |
|
265 #ifdef SK_DEBUG |
|
266 geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER; |
|
267 #endif |
|
268 break; |
|
269 default: |
|
270 GrCrash("Unknown Index Source Type."); |
|
271 break; |
|
272 } |
|
273 } |
|
274 |
|
275 void GrDrawTarget::setVertexSourceToArray(const void* vertexArray, |
|
276 int vertexCount) { |
|
277 this->releasePreviousVertexSource(); |
|
278 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
279 geoSrc.fVertexSrc = kArray_GeometrySrcType; |
|
280 geoSrc.fVertexSize = this->drawState()->getVertexSize(); |
|
281 geoSrc.fVertexCount = vertexCount; |
|
282 this->onSetVertexSourceToArray(vertexArray, vertexCount); |
|
283 } |
|
284 |
|
285 void GrDrawTarget::setIndexSourceToArray(const void* indexArray, |
|
286 int indexCount) { |
|
287 this->releasePreviousIndexSource(); |
|
288 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
289 geoSrc.fIndexSrc = kArray_GeometrySrcType; |
|
290 geoSrc.fIndexCount = indexCount; |
|
291 this->onSetIndexSourceToArray(indexArray, indexCount); |
|
292 } |
|
293 |
|
294 void GrDrawTarget::setVertexSourceToBuffer(const GrVertexBuffer* buffer) { |
|
295 this->releasePreviousVertexSource(); |
|
296 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
297 geoSrc.fVertexSrc = kBuffer_GeometrySrcType; |
|
298 geoSrc.fVertexBuffer = buffer; |
|
299 buffer->ref(); |
|
300 geoSrc.fVertexSize = this->drawState()->getVertexSize(); |
|
301 } |
|
302 |
|
303 void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) { |
|
304 this->releasePreviousIndexSource(); |
|
305 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
306 geoSrc.fIndexSrc = kBuffer_GeometrySrcType; |
|
307 geoSrc.fIndexBuffer = buffer; |
|
308 buffer->ref(); |
|
309 } |
|
310 |
|
311 void GrDrawTarget::resetVertexSource() { |
|
312 this->releasePreviousVertexSource(); |
|
313 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
314 geoSrc.fVertexSrc = kNone_GeometrySrcType; |
|
315 } |
|
316 |
|
317 void GrDrawTarget::resetIndexSource() { |
|
318 this->releasePreviousIndexSource(); |
|
319 GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
320 geoSrc.fIndexSrc = kNone_GeometrySrcType; |
|
321 } |
|
322 |
|
323 void GrDrawTarget::pushGeometrySource() { |
|
324 this->geometrySourceWillPush(); |
|
325 GeometrySrcState& newState = fGeoSrcStateStack.push_back(); |
|
326 newState.fIndexSrc = kNone_GeometrySrcType; |
|
327 newState.fVertexSrc = kNone_GeometrySrcType; |
|
328 #ifdef SK_DEBUG |
|
329 newState.fVertexCount = ~0; |
|
330 newState.fVertexBuffer = (GrVertexBuffer*)~0; |
|
331 newState.fIndexCount = ~0; |
|
332 newState.fIndexBuffer = (GrIndexBuffer*)~0; |
|
333 #endif |
|
334 } |
|
335 |
|
336 void GrDrawTarget::popGeometrySource() { |
|
337 // if popping last element then pops are unbalanced with pushes |
|
338 SkASSERT(fGeoSrcStateStack.count() > 1); |
|
339 |
|
340 this->geometrySourceWillPop(fGeoSrcStateStack.fromBack(1)); |
|
341 this->releasePreviousVertexSource(); |
|
342 this->releasePreviousIndexSource(); |
|
343 fGeoSrcStateStack.pop_back(); |
|
344 } |
|
345 |
|
346 //////////////////////////////////////////////////////////////////////////////// |
|
347 |
|
348 bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, |
|
349 int startIndex, int vertexCount, |
|
350 int indexCount) const { |
|
351 const GrDrawState& drawState = this->getDrawState(); |
|
352 #ifdef SK_DEBUG |
|
353 const GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); |
|
354 int maxVertex = startVertex + vertexCount; |
|
355 int maxValidVertex; |
|
356 switch (geoSrc.fVertexSrc) { |
|
357 case kNone_GeometrySrcType: |
|
358 GrCrash("Attempting to draw without vertex src."); |
|
359 case kReserved_GeometrySrcType: // fallthrough |
|
360 case kArray_GeometrySrcType: |
|
361 maxValidVertex = geoSrc.fVertexCount; |
|
362 break; |
|
363 case kBuffer_GeometrySrcType: |
|
364 maxValidVertex = static_cast<int>(geoSrc.fVertexBuffer->sizeInBytes() / geoSrc.fVertexSize); |
|
365 break; |
|
366 } |
|
367 if (maxVertex > maxValidVertex) { |
|
368 GrCrash("Drawing outside valid vertex range."); |
|
369 } |
|
370 if (indexCount > 0) { |
|
371 int maxIndex = startIndex + indexCount; |
|
372 int maxValidIndex; |
|
373 switch (geoSrc.fIndexSrc) { |
|
374 case kNone_GeometrySrcType: |
|
375 GrCrash("Attempting to draw indexed geom without index src."); |
|
376 case kReserved_GeometrySrcType: // fallthrough |
|
377 case kArray_GeometrySrcType: |
|
378 maxValidIndex = geoSrc.fIndexCount; |
|
379 break; |
|
380 case kBuffer_GeometrySrcType: |
|
381 maxValidIndex = static_cast<int>(geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t)); |
|
382 break; |
|
383 } |
|
384 if (maxIndex > maxValidIndex) { |
|
385 GrCrash("Index reads outside valid index range."); |
|
386 } |
|
387 } |
|
388 |
|
389 SkASSERT(NULL != drawState.getRenderTarget()); |
|
390 |
|
391 for (int s = 0; s < drawState.numColorStages(); ++s) { |
|
392 const GrEffectRef& effect = *drawState.getColorStage(s).getEffect(); |
|
393 int numTextures = effect->numTextures(); |
|
394 for (int t = 0; t < numTextures; ++t) { |
|
395 GrTexture* texture = effect->texture(t); |
|
396 SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); |
|
397 } |
|
398 } |
|
399 for (int s = 0; s < drawState.numCoverageStages(); ++s) { |
|
400 const GrEffectRef& effect = *drawState.getCoverageStage(s).getEffect(); |
|
401 int numTextures = effect->numTextures(); |
|
402 for (int t = 0; t < numTextures; ++t) { |
|
403 GrTexture* texture = effect->texture(t); |
|
404 SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); |
|
405 } |
|
406 } |
|
407 |
|
408 SkASSERT(drawState.validateVertexAttribs()); |
|
409 #endif |
|
410 if (NULL == drawState.getRenderTarget()) { |
|
411 return false; |
|
412 } |
|
413 return true; |
|
414 } |
|
415 |
|
416 bool GrDrawTarget::setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds) { |
|
417 if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDstColor()) { |
|
418 return true; |
|
419 } |
|
420 GrRenderTarget* rt = this->drawState()->getRenderTarget(); |
|
421 SkIRect copyRect; |
|
422 const GrClipData* clip = this->getClip(); |
|
423 clip->getConservativeBounds(rt, ©Rect); |
|
424 |
|
425 if (NULL != drawBounds) { |
|
426 SkIRect drawIBounds; |
|
427 drawBounds->roundOut(&drawIBounds); |
|
428 if (!copyRect.intersect(drawIBounds)) { |
|
429 #ifdef SK_DEBUG |
|
430 GrPrintf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n"); |
|
431 #endif |
|
432 return false; |
|
433 } |
|
434 } else { |
|
435 #ifdef SK_DEBUG |
|
436 //GrPrintf("No dev bounds when dst copy is made.\n"); |
|
437 #endif |
|
438 } |
|
439 |
|
440 // MSAA consideration: When there is support for reading MSAA samples in the shader we could |
|
441 // have per-sample dst values by making the copy multisampled. |
|
442 GrTextureDesc desc; |
|
443 this->initCopySurfaceDstDesc(rt, &desc); |
|
444 desc.fWidth = copyRect.width(); |
|
445 desc.fHeight = copyRect.height(); |
|
446 |
|
447 GrAutoScratchTexture ast(fContext, desc, GrContext::kApprox_ScratchTexMatch); |
|
448 |
|
449 if (NULL == ast.texture()) { |
|
450 GrPrintf("Failed to create temporary copy of destination texture.\n"); |
|
451 return false; |
|
452 } |
|
453 SkIPoint dstPoint = {0, 0}; |
|
454 if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) { |
|
455 dstCopy->setTexture(ast.texture()); |
|
456 dstCopy->setOffset(copyRect.fLeft, copyRect.fTop); |
|
457 return true; |
|
458 } else { |
|
459 return false; |
|
460 } |
|
461 } |
|
462 |
|
463 void GrDrawTarget::drawIndexed(GrPrimitiveType type, |
|
464 int startVertex, |
|
465 int startIndex, |
|
466 int vertexCount, |
|
467 int indexCount, |
|
468 const SkRect* devBounds) { |
|
469 if (indexCount > 0 && this->checkDraw(type, startVertex, startIndex, vertexCount, indexCount)) { |
|
470 DrawInfo info; |
|
471 info.fPrimitiveType = type; |
|
472 info.fStartVertex = startVertex; |
|
473 info.fStartIndex = startIndex; |
|
474 info.fVertexCount = vertexCount; |
|
475 info.fIndexCount = indexCount; |
|
476 |
|
477 info.fInstanceCount = 0; |
|
478 info.fVerticesPerInstance = 0; |
|
479 info.fIndicesPerInstance = 0; |
|
480 |
|
481 if (NULL != devBounds) { |
|
482 info.setDevBounds(*devBounds); |
|
483 } |
|
484 // TODO: We should continue with incorrect blending. |
|
485 if (!this->setupDstReadIfNecessary(&info)) { |
|
486 return; |
|
487 } |
|
488 this->onDraw(info); |
|
489 } |
|
490 } |
|
491 |
|
492 void GrDrawTarget::drawNonIndexed(GrPrimitiveType type, |
|
493 int startVertex, |
|
494 int vertexCount, |
|
495 const SkRect* devBounds) { |
|
496 if (vertexCount > 0 && this->checkDraw(type, startVertex, -1, vertexCount, -1)) { |
|
497 DrawInfo info; |
|
498 info.fPrimitiveType = type; |
|
499 info.fStartVertex = startVertex; |
|
500 info.fStartIndex = 0; |
|
501 info.fVertexCount = vertexCount; |
|
502 info.fIndexCount = 0; |
|
503 |
|
504 info.fInstanceCount = 0; |
|
505 info.fVerticesPerInstance = 0; |
|
506 info.fIndicesPerInstance = 0; |
|
507 |
|
508 if (NULL != devBounds) { |
|
509 info.setDevBounds(*devBounds); |
|
510 } |
|
511 // TODO: We should continue with incorrect blending. |
|
512 if (!this->setupDstReadIfNecessary(&info)) { |
|
513 return; |
|
514 } |
|
515 this->onDraw(info); |
|
516 } |
|
517 } |
|
518 |
|
519 void GrDrawTarget::stencilPath(const GrPath* path, SkPath::FillType fill) { |
|
520 // TODO: extract portions of checkDraw that are relevant to path stenciling. |
|
521 SkASSERT(NULL != path); |
|
522 SkASSERT(this->caps()->pathRenderingSupport()); |
|
523 SkASSERT(!SkPath::IsInverseFillType(fill)); |
|
524 this->onStencilPath(path, fill); |
|
525 } |
|
526 |
|
527 void GrDrawTarget::drawPath(const GrPath* path, SkPath::FillType fill) { |
|
528 // TODO: extract portions of checkDraw that are relevant to path rendering. |
|
529 SkASSERT(NULL != path); |
|
530 SkASSERT(this->caps()->pathRenderingSupport()); |
|
531 const GrDrawState* drawState = &getDrawState(); |
|
532 |
|
533 SkRect devBounds; |
|
534 if (SkPath::IsInverseFillType(fill)) { |
|
535 devBounds = SkRect::MakeWH(SkIntToScalar(drawState->getRenderTarget()->width()), |
|
536 SkIntToScalar(drawState->getRenderTarget()->height())); |
|
537 } else { |
|
538 devBounds = path->getBounds(); |
|
539 } |
|
540 SkMatrix viewM = drawState->getViewMatrix(); |
|
541 viewM.mapRect(&devBounds); |
|
542 |
|
543 GrDeviceCoordTexture dstCopy; |
|
544 if (!this->setupDstReadIfNecessary(&dstCopy, &devBounds)) { |
|
545 return; |
|
546 } |
|
547 |
|
548 this->onDrawPath(path, fill, dstCopy.texture() ? &dstCopy : NULL); |
|
549 } |
|
550 |
|
551 void GrDrawTarget::instantGpuTraceEvent(const char* marker) { |
|
552 if (this->caps()->gpuTracingSupport()) { |
|
553 this->onInstantGpuTraceEvent(marker); |
|
554 } |
|
555 } |
|
556 |
|
557 void GrDrawTarget::pushGpuTraceEvent(const char* marker) { |
|
558 SkASSERT(fPushGpuTraceCount >= 0); |
|
559 if (this->caps()->gpuTracingSupport()) { |
|
560 this->onPushGpuTraceEvent(marker); |
|
561 ++fPushGpuTraceCount; |
|
562 } |
|
563 } |
|
564 |
|
565 void GrDrawTarget::popGpuTraceEvent() { |
|
566 SkASSERT(fPushGpuTraceCount >= 1); |
|
567 if (this->caps()->gpuTracingSupport()) { |
|
568 this->onPopGpuTraceEvent(); |
|
569 --fPushGpuTraceCount; |
|
570 } |
|
571 } |
|
572 |
|
573 //////////////////////////////////////////////////////////////////////////////// |
|
574 |
|
575 bool GrDrawTarget::willUseHWAALines() const { |
|
576 // There is a conflict between using smooth lines and our use of premultiplied alpha. Smooth |
|
577 // lines tweak the incoming alpha value but not in a premul-alpha way. So we only use them when |
|
578 // our alpha is 0xff and tweaking the color for partial coverage is OK |
|
579 if (!this->caps()->hwAALineSupport() || |
|
580 !this->getDrawState().isHWAntialiasState()) { |
|
581 return false; |
|
582 } |
|
583 GrDrawState::BlendOptFlags opts = this->getDrawState().getBlendOpts(); |
|
584 return (GrDrawState::kDisableBlend_BlendOptFlag & opts) && |
|
585 (GrDrawState::kCoverageAsAlpha_BlendOptFlag & opts); |
|
586 } |
|
587 |
|
588 bool GrDrawTarget::canApplyCoverage() const { |
|
589 // we can correctly apply coverage if a) we have dual source blending |
|
590 // or b) one of our blend optimizations applies. |
|
591 return this->caps()->dualSourceBlendingSupport() || |
|
592 GrDrawState::kNone_BlendOpt != this->getDrawState().getBlendOpts(true); |
|
593 } |
|
594 |
|
595 //////////////////////////////////////////////////////////////////////////////// |
|
596 |
|
597 void GrDrawTarget::drawIndexedInstances(GrPrimitiveType type, |
|
598 int instanceCount, |
|
599 int verticesPerInstance, |
|
600 int indicesPerInstance, |
|
601 const SkRect* devBounds) { |
|
602 if (!verticesPerInstance || !indicesPerInstance) { |
|
603 return; |
|
604 } |
|
605 |
|
606 int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance; |
|
607 if (!maxInstancesPerDraw) { |
|
608 return; |
|
609 } |
|
610 |
|
611 DrawInfo info; |
|
612 info.fPrimitiveType = type; |
|
613 info.fStartIndex = 0; |
|
614 info.fStartVertex = 0; |
|
615 info.fIndicesPerInstance = indicesPerInstance; |
|
616 info.fVerticesPerInstance = verticesPerInstance; |
|
617 |
|
618 // Set the same bounds for all the draws. |
|
619 if (NULL != devBounds) { |
|
620 info.setDevBounds(*devBounds); |
|
621 } |
|
622 // TODO: We should continue with incorrect blending. |
|
623 if (!this->setupDstReadIfNecessary(&info)) { |
|
624 return; |
|
625 } |
|
626 |
|
627 while (instanceCount) { |
|
628 info.fInstanceCount = GrMin(instanceCount, maxInstancesPerDraw); |
|
629 info.fVertexCount = info.fInstanceCount * verticesPerInstance; |
|
630 info.fIndexCount = info.fInstanceCount * indicesPerInstance; |
|
631 |
|
632 if (this->checkDraw(type, |
|
633 info.fStartVertex, |
|
634 info.fStartIndex, |
|
635 info.fVertexCount, |
|
636 info.fIndexCount)) { |
|
637 this->onDraw(info); |
|
638 } |
|
639 info.fStartVertex += info.fVertexCount; |
|
640 instanceCount -= info.fInstanceCount; |
|
641 } |
|
642 } |
|
643 |
|
644 //////////////////////////////////////////////////////////////////////////////// |
|
645 |
|
646 namespace { |
|
647 |
|
648 // position + (optional) texture coord |
|
649 extern const GrVertexAttrib gBWRectPosUVAttribs[] = { |
|
650 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, |
|
651 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kLocalCoord_GrVertexAttribBinding} |
|
652 }; |
|
653 |
|
654 void set_vertex_attributes(GrDrawState* drawState, bool hasUVs) { |
|
655 if (hasUVs) { |
|
656 drawState->setVertexAttribs<gBWRectPosUVAttribs>(2); |
|
657 } else { |
|
658 drawState->setVertexAttribs<gBWRectPosUVAttribs>(1); |
|
659 } |
|
660 } |
|
661 |
|
662 }; |
|
663 |
|
664 void GrDrawTarget::onDrawRect(const SkRect& rect, |
|
665 const SkMatrix* matrix, |
|
666 const SkRect* localRect, |
|
667 const SkMatrix* localMatrix) { |
|
668 |
|
669 GrDrawState::AutoViewMatrixRestore avmr; |
|
670 if (NULL != matrix) { |
|
671 avmr.set(this->drawState(), *matrix); |
|
672 } |
|
673 |
|
674 set_vertex_attributes(this->drawState(), NULL != localRect); |
|
675 |
|
676 AutoReleaseGeometry geo(this, 4, 0); |
|
677 if (!geo.succeeded()) { |
|
678 GrPrintf("Failed to get space for vertices!\n"); |
|
679 return; |
|
680 } |
|
681 |
|
682 size_t vsize = this->drawState()->getVertexSize(); |
|
683 geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); |
|
684 if (NULL != localRect) { |
|
685 GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) + |
|
686 sizeof(GrPoint)); |
|
687 coords->setRectFan(localRect->fLeft, localRect->fTop, |
|
688 localRect->fRight, localRect->fBottom, |
|
689 vsize); |
|
690 if (NULL != localMatrix) { |
|
691 localMatrix->mapPointsWithStride(coords, vsize, 4); |
|
692 } |
|
693 } |
|
694 SkRect bounds; |
|
695 this->getDrawState().getViewMatrix().mapRect(&bounds, rect); |
|
696 |
|
697 this->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4, &bounds); |
|
698 } |
|
699 |
|
700 void GrDrawTarget::clipWillBeSet(const GrClipData* clipData) { |
|
701 } |
|
702 |
|
703 //////////////////////////////////////////////////////////////////////////////// |
|
704 |
|
705 GrDrawTarget::AutoStateRestore::AutoStateRestore() { |
|
706 fDrawTarget = NULL; |
|
707 } |
|
708 |
|
709 GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target, |
|
710 ASRInit init, |
|
711 const SkMatrix* vm) { |
|
712 fDrawTarget = NULL; |
|
713 this->set(target, init, vm); |
|
714 } |
|
715 |
|
716 GrDrawTarget::AutoStateRestore::~AutoStateRestore() { |
|
717 if (NULL != fDrawTarget) { |
|
718 fDrawTarget->setDrawState(fSavedState); |
|
719 fSavedState->unref(); |
|
720 } |
|
721 } |
|
722 |
|
723 void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target, ASRInit init, const SkMatrix* vm) { |
|
724 SkASSERT(NULL == fDrawTarget); |
|
725 fDrawTarget = target; |
|
726 fSavedState = target->drawState(); |
|
727 SkASSERT(fSavedState); |
|
728 fSavedState->ref(); |
|
729 if (kReset_ASRInit == init) { |
|
730 if (NULL == vm) { |
|
731 // calls the default cons |
|
732 fTempState.init(); |
|
733 } else { |
|
734 SkNEW_IN_TLAZY(&fTempState, GrDrawState, (*vm)); |
|
735 } |
|
736 } else { |
|
737 SkASSERT(kPreserve_ASRInit == init); |
|
738 if (NULL == vm) { |
|
739 fTempState.set(*fSavedState); |
|
740 } else { |
|
741 SkNEW_IN_TLAZY(&fTempState, GrDrawState, (*fSavedState, *vm)); |
|
742 } |
|
743 } |
|
744 target->setDrawState(fTempState.get()); |
|
745 } |
|
746 |
|
747 bool GrDrawTarget::AutoStateRestore::setIdentity(GrDrawTarget* target, ASRInit init) { |
|
748 SkASSERT(NULL == fDrawTarget); |
|
749 fDrawTarget = target; |
|
750 fSavedState = target->drawState(); |
|
751 SkASSERT(fSavedState); |
|
752 fSavedState->ref(); |
|
753 if (kReset_ASRInit == init) { |
|
754 // calls the default cons |
|
755 fTempState.init(); |
|
756 } else { |
|
757 SkASSERT(kPreserve_ASRInit == init); |
|
758 // calls the copy cons |
|
759 fTempState.set(*fSavedState); |
|
760 if (!fTempState.get()->setIdentityViewMatrix()) { |
|
761 // let go of any resources held by the temp |
|
762 fTempState.get()->reset(); |
|
763 fDrawTarget = NULL; |
|
764 fSavedState->unref(); |
|
765 fSavedState = NULL; |
|
766 return false; |
|
767 } |
|
768 } |
|
769 target->setDrawState(fTempState.get()); |
|
770 return true; |
|
771 } |
|
772 |
|
773 //////////////////////////////////////////////////////////////////////////////// |
|
774 |
|
775 GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry( |
|
776 GrDrawTarget* target, |
|
777 int vertexCount, |
|
778 int indexCount) { |
|
779 fTarget = NULL; |
|
780 this->set(target, vertexCount, indexCount); |
|
781 } |
|
782 |
|
783 GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry() { |
|
784 fTarget = NULL; |
|
785 } |
|
786 |
|
787 GrDrawTarget::AutoReleaseGeometry::~AutoReleaseGeometry() { |
|
788 this->reset(); |
|
789 } |
|
790 |
|
791 bool GrDrawTarget::AutoReleaseGeometry::set(GrDrawTarget* target, |
|
792 int vertexCount, |
|
793 int indexCount) { |
|
794 this->reset(); |
|
795 fTarget = target; |
|
796 bool success = true; |
|
797 if (NULL != fTarget) { |
|
798 fTarget = target; |
|
799 success = target->reserveVertexAndIndexSpace(vertexCount, |
|
800 indexCount, |
|
801 &fVertices, |
|
802 &fIndices); |
|
803 if (!success) { |
|
804 fTarget = NULL; |
|
805 this->reset(); |
|
806 } |
|
807 } |
|
808 SkASSERT(success == (NULL != fTarget)); |
|
809 return success; |
|
810 } |
|
811 |
|
812 void GrDrawTarget::AutoReleaseGeometry::reset() { |
|
813 if (NULL != fTarget) { |
|
814 if (NULL != fVertices) { |
|
815 fTarget->resetVertexSource(); |
|
816 } |
|
817 if (NULL != fIndices) { |
|
818 fTarget->resetIndexSource(); |
|
819 } |
|
820 fTarget = NULL; |
|
821 } |
|
822 fVertices = NULL; |
|
823 fIndices = NULL; |
|
824 } |
|
825 |
|
826 GrDrawTarget::AutoClipRestore::AutoClipRestore(GrDrawTarget* target, const SkIRect& newClip) { |
|
827 fTarget = target; |
|
828 fClip = fTarget->getClip(); |
|
829 fStack.init(); |
|
830 fStack.get()->clipDevRect(newClip, SkRegion::kReplace_Op); |
|
831 fReplacementClip.fClipStack = fStack.get(); |
|
832 target->setClip(&fReplacementClip); |
|
833 } |
|
834 |
|
835 namespace { |
|
836 // returns true if the read/written rect intersects the src/dst and false if not. |
|
837 bool clip_srcrect_and_dstpoint(const GrSurface* dst, |
|
838 const GrSurface* src, |
|
839 const SkIRect& srcRect, |
|
840 const SkIPoint& dstPoint, |
|
841 SkIRect* clippedSrcRect, |
|
842 SkIPoint* clippedDstPoint) { |
|
843 *clippedSrcRect = srcRect; |
|
844 *clippedDstPoint = dstPoint; |
|
845 |
|
846 // clip the left edge to src and dst bounds, adjusting dstPoint if necessary |
|
847 if (clippedSrcRect->fLeft < 0) { |
|
848 clippedDstPoint->fX -= clippedSrcRect->fLeft; |
|
849 clippedSrcRect->fLeft = 0; |
|
850 } |
|
851 if (clippedDstPoint->fX < 0) { |
|
852 clippedSrcRect->fLeft -= clippedDstPoint->fX; |
|
853 clippedDstPoint->fX = 0; |
|
854 } |
|
855 |
|
856 // clip the top edge to src and dst bounds, adjusting dstPoint if necessary |
|
857 if (clippedSrcRect->fTop < 0) { |
|
858 clippedDstPoint->fY -= clippedSrcRect->fTop; |
|
859 clippedSrcRect->fTop = 0; |
|
860 } |
|
861 if (clippedDstPoint->fY < 0) { |
|
862 clippedSrcRect->fTop -= clippedDstPoint->fY; |
|
863 clippedDstPoint->fY = 0; |
|
864 } |
|
865 |
|
866 // clip the right edge to the src and dst bounds. |
|
867 if (clippedSrcRect->fRight > src->width()) { |
|
868 clippedSrcRect->fRight = src->width(); |
|
869 } |
|
870 if (clippedDstPoint->fX + clippedSrcRect->width() > dst->width()) { |
|
871 clippedSrcRect->fRight = clippedSrcRect->fLeft + dst->width() - clippedDstPoint->fX; |
|
872 } |
|
873 |
|
874 // clip the bottom edge to the src and dst bounds. |
|
875 if (clippedSrcRect->fBottom > src->height()) { |
|
876 clippedSrcRect->fBottom = src->height(); |
|
877 } |
|
878 if (clippedDstPoint->fY + clippedSrcRect->height() > dst->height()) { |
|
879 clippedSrcRect->fBottom = clippedSrcRect->fTop + dst->height() - clippedDstPoint->fY; |
|
880 } |
|
881 |
|
882 // The above clipping steps may have inverted the rect if it didn't intersect either the src or |
|
883 // dst bounds. |
|
884 return !clippedSrcRect->isEmpty(); |
|
885 } |
|
886 } |
|
887 |
|
888 bool GrDrawTarget::copySurface(GrSurface* dst, |
|
889 GrSurface* src, |
|
890 const SkIRect& srcRect, |
|
891 const SkIPoint& dstPoint) { |
|
892 SkASSERT(NULL != dst); |
|
893 SkASSERT(NULL != src); |
|
894 |
|
895 SkIRect clippedSrcRect; |
|
896 SkIPoint clippedDstPoint; |
|
897 // If the rect is outside the src or dst then we've already succeeded. |
|
898 if (!clip_srcrect_and_dstpoint(dst, |
|
899 src, |
|
900 srcRect, |
|
901 dstPoint, |
|
902 &clippedSrcRect, |
|
903 &clippedDstPoint)) { |
|
904 SkASSERT(this->canCopySurface(dst, src, srcRect, dstPoint)); |
|
905 return true; |
|
906 } |
|
907 |
|
908 bool result = this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint); |
|
909 SkASSERT(result == this->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)); |
|
910 return result; |
|
911 } |
|
912 |
|
913 bool GrDrawTarget::canCopySurface(GrSurface* dst, |
|
914 GrSurface* src, |
|
915 const SkIRect& srcRect, |
|
916 const SkIPoint& dstPoint) { |
|
917 SkASSERT(NULL != dst); |
|
918 SkASSERT(NULL != src); |
|
919 |
|
920 SkIRect clippedSrcRect; |
|
921 SkIPoint clippedDstPoint; |
|
922 // If the rect is outside the src or dst then we're guaranteed success |
|
923 if (!clip_srcrect_and_dstpoint(dst, |
|
924 src, |
|
925 srcRect, |
|
926 dstPoint, |
|
927 &clippedSrcRect, |
|
928 &clippedDstPoint)) { |
|
929 return true; |
|
930 } |
|
931 return this->onCanCopySurface(dst, src, clippedSrcRect, clippedDstPoint); |
|
932 } |
|
933 |
|
934 bool GrDrawTarget::onCanCopySurface(GrSurface* dst, |
|
935 GrSurface* src, |
|
936 const SkIRect& srcRect, |
|
937 const SkIPoint& dstPoint) { |
|
938 // Check that the read/write rects are contained within the src/dst bounds. |
|
939 SkASSERT(!srcRect.isEmpty()); |
|
940 SkASSERT(SkIRect::MakeWH(src->width(), src->height()).contains(srcRect)); |
|
941 SkASSERT(dstPoint.fX >= 0 && dstPoint.fY >= 0); |
|
942 SkASSERT(dstPoint.fX + srcRect.width() <= dst->width() && |
|
943 dstPoint.fY + srcRect.height() <= dst->height()); |
|
944 |
|
945 return !dst->isSameAs(src) && NULL != dst->asRenderTarget() && NULL != src->asTexture(); |
|
946 } |
|
947 |
|
948 bool GrDrawTarget::onCopySurface(GrSurface* dst, |
|
949 GrSurface* src, |
|
950 const SkIRect& srcRect, |
|
951 const SkIPoint& dstPoint) { |
|
952 if (!GrDrawTarget::onCanCopySurface(dst, src, srcRect, dstPoint)) { |
|
953 return false; |
|
954 } |
|
955 |
|
956 GrRenderTarget* rt = dst->asRenderTarget(); |
|
957 GrTexture* tex = src->asTexture(); |
|
958 |
|
959 GrDrawTarget::AutoStateRestore asr(this, kReset_ASRInit); |
|
960 this->drawState()->setRenderTarget(rt); |
|
961 SkMatrix matrix; |
|
962 matrix.setTranslate(SkIntToScalar(srcRect.fLeft - dstPoint.fX), |
|
963 SkIntToScalar(srcRect.fTop - dstPoint.fY)); |
|
964 matrix.postIDiv(tex->width(), tex->height()); |
|
965 this->drawState()->addColorTextureEffect(tex, matrix); |
|
966 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, |
|
967 dstPoint.fY, |
|
968 srcRect.width(), |
|
969 srcRect.height()); |
|
970 this->drawSimpleRect(dstRect); |
|
971 return true; |
|
972 } |
|
973 |
|
974 void GrDrawTarget::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) { |
|
975 // Make the dst of the copy be a render target because the default copySurface draws to the dst. |
|
976 desc->fOrigin = kDefault_GrSurfaceOrigin; |
|
977 desc->fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; |
|
978 desc->fConfig = src->config(); |
|
979 } |
|
980 |
|
981 /////////////////////////////////////////////////////////////////////////////// |
|
982 |
|
983 void GrDrawTargetCaps::reset() { |
|
984 f8BitPaletteSupport = false; |
|
985 fMipMapSupport = false; |
|
986 fNPOTTextureTileSupport = false; |
|
987 fTwoSidedStencilSupport = false; |
|
988 fStencilWrapOpsSupport = false; |
|
989 fHWAALineSupport = false; |
|
990 fShaderDerivativeSupport = false; |
|
991 fGeometryShaderSupport = false; |
|
992 fDualSourceBlendingSupport = false; |
|
993 fBufferLockSupport = false; |
|
994 fPathRenderingSupport = false; |
|
995 fDstReadInShaderSupport = false; |
|
996 fReuseScratchTextures = true; |
|
997 fGpuTracingSupport = false; |
|
998 |
|
999 fMaxRenderTargetSize = 0; |
|
1000 fMaxTextureSize = 0; |
|
1001 fMaxSampleCount = 0; |
|
1002 |
|
1003 memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport)); |
|
1004 } |
|
1005 |
|
1006 GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) { |
|
1007 f8BitPaletteSupport = other.f8BitPaletteSupport; |
|
1008 fMipMapSupport = other.fMipMapSupport; |
|
1009 fNPOTTextureTileSupport = other.fNPOTTextureTileSupport; |
|
1010 fTwoSidedStencilSupport = other.fTwoSidedStencilSupport; |
|
1011 fStencilWrapOpsSupport = other.fStencilWrapOpsSupport; |
|
1012 fHWAALineSupport = other.fHWAALineSupport; |
|
1013 fShaderDerivativeSupport = other.fShaderDerivativeSupport; |
|
1014 fGeometryShaderSupport = other.fGeometryShaderSupport; |
|
1015 fDualSourceBlendingSupport = other.fDualSourceBlendingSupport; |
|
1016 fBufferLockSupport = other.fBufferLockSupport; |
|
1017 fPathRenderingSupport = other.fPathRenderingSupport; |
|
1018 fDstReadInShaderSupport = other.fDstReadInShaderSupport; |
|
1019 fReuseScratchTextures = other.fReuseScratchTextures; |
|
1020 fGpuTracingSupport = other.fGpuTracingSupport; |
|
1021 |
|
1022 fMaxRenderTargetSize = other.fMaxRenderTargetSize; |
|
1023 fMaxTextureSize = other.fMaxTextureSize; |
|
1024 fMaxSampleCount = other.fMaxSampleCount; |
|
1025 |
|
1026 memcpy(fConfigRenderSupport, other.fConfigRenderSupport, sizeof(fConfigRenderSupport)); |
|
1027 |
|
1028 return *this; |
|
1029 } |
|
1030 |
|
1031 SkString GrDrawTargetCaps::dump() const { |
|
1032 SkString r; |
|
1033 static const char* gNY[] = {"NO", "YES"}; |
|
1034 r.appendf("8 Bit Palette Support : %s\n", gNY[f8BitPaletteSupport]); |
|
1035 r.appendf("MIP Map Support : %s\n", gNY[fMipMapSupport]); |
|
1036 r.appendf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); |
|
1037 r.appendf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); |
|
1038 r.appendf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); |
|
1039 r.appendf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]); |
|
1040 r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); |
|
1041 r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); |
|
1042 r.appendf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]); |
|
1043 r.appendf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]); |
|
1044 r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); |
|
1045 r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); |
|
1046 r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); |
|
1047 r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); |
|
1048 r.appendf("Max Texture Size : %d\n", fMaxTextureSize); |
|
1049 r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); |
|
1050 r.appendf("Max Sample Count : %d\n", fMaxSampleCount); |
|
1051 |
|
1052 static const char* kConfigNames[] = { |
|
1053 "Unknown", // kUnknown_GrPixelConfig |
|
1054 "Alpha8", // kAlpha_8_GrPixelConfig, |
|
1055 "Index8", // kIndex_8_GrPixelConfig, |
|
1056 "RGB565", // kRGB_565_GrPixelConfig, |
|
1057 "RGBA444", // kRGBA_4444_GrPixelConfig, |
|
1058 "RGBA8888", // kRGBA_8888_GrPixelConfig, |
|
1059 "BGRA8888", // kBGRA_8888_GrPixelConfig, |
|
1060 }; |
|
1061 GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); |
|
1062 GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); |
|
1063 GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); |
|
1064 GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); |
|
1065 GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); |
|
1066 GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); |
|
1067 GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); |
|
1068 GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); |
|
1069 |
|
1070 SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); |
|
1071 SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); |
|
1072 for (size_t i = 0; i < SK_ARRAY_COUNT(kConfigNames); ++i) { |
|
1073 if (i != kUnknown_GrPixelConfig) { |
|
1074 r.appendf("%s is renderable: %s, with MSAA: %s\n", |
|
1075 kConfigNames[i], |
|
1076 gNY[fConfigRenderSupport[i][0]], |
|
1077 gNY[fConfigRenderSupport[i][1]]); |
|
1078 } |
|
1079 } |
|
1080 return r; |
|
1081 } |