GrDrawTarget.cpp revision e9c0fc616d2a1632c285885b9b656b68ca8d4f24
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#include "GrDrawTarget.h"
10
11#include "GrBatch.h"
12#include "GrBufferAllocPool.h"
13#include "GrContext.h"
14#include "GrDrawTargetCaps.h"
15#include "GrPath.h"
16#include "GrPipeline.h"
17#include "GrMemoryPool.h"
18#include "GrRenderTarget.h"
19#include "GrRenderTargetPriv.h"
20#include "GrSurfacePriv.h"
21#include "GrTemplates.h"
22#include "GrTexture.h"
23#include "GrVertexBuffer.h"
24
25#include "SkStrokeRec.h"
26
27////////////////////////////////////////////////////////////////////////////////
28
29GrDrawTarget::DrawInfo& GrDrawTarget::DrawInfo::operator =(const DrawInfo& di) {
30    fPrimitiveType  = di.fPrimitiveType;
31    fStartVertex    = di.fStartVertex;
32    fStartIndex     = di.fStartIndex;
33    fVertexCount    = di.fVertexCount;
34    fIndexCount     = di.fIndexCount;
35
36    fInstanceCount          = di.fInstanceCount;
37    fVerticesPerInstance    = di.fVerticesPerInstance;
38    fIndicesPerInstance     = di.fIndicesPerInstance;
39
40    if (di.fDevBounds) {
41        SkASSERT(di.fDevBounds == &di.fDevBoundsStorage);
42        fDevBoundsStorage = di.fDevBoundsStorage;
43        fDevBounds = &fDevBoundsStorage;
44    } else {
45        fDevBounds = NULL;
46    }
47
48    this->setVertexBuffer(di.vertexBuffer());
49    this->setIndexBuffer(di.indexBuffer());
50
51    return *this;
52}
53
54////////////////////////////////////////////////////////////////////////////////
55
56#define DEBUG_INVAL_BUFFER 0xdeadcafe
57#define DEBUG_INVAL_START_IDX -1
58
59GrDrawTarget::GrDrawTarget(GrContext* context,
60                           GrVertexBufferAllocPool* vpool,
61                           GrIndexBufferAllocPool* ipool)
62    : fContext(context)
63    , fCaps(SkRef(context->getGpu()->caps()))
64    , fGpuTraceMarkerCount(0)
65    , fVertexPool(vpool)
66    , fIndexPool(ipool)
67    , fFlushing(false) {
68    SkASSERT(context);
69}
70
71////////////////////////////////////////////////////////////////////////////////
72
73bool GrDrawTarget::setupDstReadIfNecessary(const GrPipelineBuilder& pipelineBuilder,
74                                           const GrProcOptInfo& colorPOI,
75                                           const GrProcOptInfo& coveragePOI,
76                                           GrDeviceCoordTexture* dstCopy,
77                                           const SkRect* drawBounds) {
78    if (!pipelineBuilder.willXPNeedDstCopy(*this->caps(), colorPOI, coveragePOI)) {
79        return true;
80    }
81    SkIRect copyRect;
82    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
83    pipelineBuilder.clip().getConservativeBounds(rt, &copyRect);
84
85    if (drawBounds) {
86        SkIRect drawIBounds;
87        drawBounds->roundOut(&drawIBounds);
88        if (!copyRect.intersect(drawIBounds)) {
89#ifdef SK_DEBUG
90            SkDebugf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n");
91#endif
92            return false;
93        }
94    } else {
95#ifdef SK_DEBUG
96        //SkDebugf("No dev bounds when dst copy is made.\n");
97#endif
98    }
99
100    // MSAA consideration: When there is support for reading MSAA samples in the shader we could
101    // have per-sample dst values by making the copy multisampled.
102    GrSurfaceDesc desc;
103    if (!this->getGpu()->initCopySurfaceDstDesc(rt, &desc)) {
104        desc.fOrigin = kDefault_GrSurfaceOrigin;
105        desc.fFlags = kRenderTarget_GrSurfaceFlag;
106        desc.fConfig = rt->config();
107    }
108
109
110    desc.fWidth = copyRect.width();
111    desc.fHeight = copyRect.height();
112
113    SkAutoTUnref<GrTexture> copy(
114        fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
115
116    if (!copy) {
117        SkDebugf("Failed to create temporary copy of destination texture.\n");
118        return false;
119    }
120    SkIPoint dstPoint = {0, 0};
121    if (this->copySurface(copy, rt, copyRect, dstPoint)) {
122        dstCopy->setTexture(copy);
123        dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
124        return true;
125    } else {
126        return false;
127    }
128}
129
130void GrDrawTarget::reset() {
131    fVertexPool->reset();
132    fIndexPool->reset();
133
134    this->onReset();
135}
136
137void GrDrawTarget::flush() {
138    if (fFlushing) {
139        return;
140    }
141    fFlushing = true;
142
143    this->getGpu()->saveActiveTraceMarkers();
144
145    this->onFlush();
146
147    this->getGpu()->restoreActiveTraceMarkers();
148
149    fFlushing = false;
150    this->reset();
151}
152
153void GrDrawTarget::drawBatch(GrPipelineBuilder* pipelineBuilder,
154                             GrBatch* batch,
155                             const SkRect* devBounds) {
156    SkASSERT(pipelineBuilder);
157    // TODO some kind of checkdraw, but not at this level
158
159    // Setup clip
160    GrScissorState scissorState;
161    GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
162    GrPipelineBuilder::AutoRestoreStencil ars;
163    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, devBounds)) {
164        return;
165    }
166
167    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, batch, devBounds, this);
168    if (pipelineInfo.mustSkipDraw()) {
169        return;
170    }
171
172    this->onDrawBatch(batch, pipelineInfo);
173}
174
175static const GrStencilSettings& winding_path_stencil_settings() {
176    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
177        kIncClamp_StencilOp,
178        kIncClamp_StencilOp,
179        kAlwaysIfInClip_StencilFunc,
180        0xFFFF, 0xFFFF, 0xFFFF);
181    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
182}
183
184static const GrStencilSettings& even_odd_path_stencil_settings() {
185    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
186        kInvert_StencilOp,
187        kInvert_StencilOp,
188        kAlwaysIfInClip_StencilFunc,
189        0xFFFF, 0xFFFF, 0xFFFF);
190    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
191}
192
193void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,
194                                                     const GrStencilAttachment* sb,
195                                                     GrStencilSettings* outStencilSettings) {
196
197    switch (fill) {
198        default:
199            SkFAIL("Unexpected path fill.");
200        case GrPathRendering::kWinding_FillType:
201            *outStencilSettings = winding_path_stencil_settings();
202            break;
203        case GrPathRendering::kEvenOdd_FillType:
204            *outStencilSettings = even_odd_path_stencil_settings();
205            break;
206    }
207    this->clipMaskManager()->adjustPathStencilParams(sb, outStencilSettings);
208}
209
210void GrDrawTarget::stencilPath(GrPipelineBuilder* pipelineBuilder,
211                               const GrPathProcessor* pathProc,
212                               const GrPath* path,
213                               GrPathRendering::FillType fill) {
214    // TODO: extract portions of checkDraw that are relevant to path stenciling.
215    SkASSERT(path);
216    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
217    SkASSERT(pipelineBuilder);
218
219    // Setup clip
220    GrScissorState scissorState;
221    GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
222    GrPipelineBuilder::AutoRestoreStencil ars;
223    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, NULL)) {
224        return;
225    }
226
227    // set stencil settings for path
228    GrStencilSettings stencilSettings;
229    GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
230    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
231    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
232
233    this->onStencilPath(*pipelineBuilder, pathProc, path, scissorState, stencilSettings);
234}
235
236void GrDrawTarget::drawPath(GrPipelineBuilder* pipelineBuilder,
237                            const GrPathProcessor* pathProc,
238                            const GrPath* path,
239                            GrPathRendering::FillType fill) {
240    // TODO: extract portions of checkDraw that are relevant to path rendering.
241    SkASSERT(path);
242    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
243    SkASSERT(pipelineBuilder);
244
245    SkRect devBounds = path->getBounds();
246    pathProc->viewMatrix().mapRect(&devBounds);
247
248    // Setup clip
249    GrScissorState scissorState;
250    GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
251    GrPipelineBuilder::AutoRestoreStencil ars;
252    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, &devBounds)) {
253       return;
254    }
255
256    // set stencil settings for path
257    GrStencilSettings stencilSettings;
258    GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
259    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
260    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
261
262    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, &devBounds,
263                                            this);
264    if (pipelineInfo.mustSkipDraw()) {
265        return;
266    }
267
268    this->onDrawPath(pathProc, path, stencilSettings, pipelineInfo);
269}
270
271void GrDrawTarget::drawPaths(GrPipelineBuilder* pipelineBuilder,
272                             const GrPathProcessor* pathProc,
273                             const GrPathRange* pathRange,
274                             const void* indices,
275                             PathIndexType indexType,
276                             const float transformValues[],
277                             PathTransformType transformType,
278                             int count,
279                             GrPathRendering::FillType fill) {
280    SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
281    SkASSERT(pathRange);
282    SkASSERT(indices);
283    SkASSERT(0 == reinterpret_cast<long>(indices) % GrPathRange::PathIndexSizeInBytes(indexType));
284    SkASSERT(transformValues);
285    SkASSERT(pipelineBuilder);
286
287    // Setup clip
288    GrScissorState scissorState;
289    GrPipelineBuilder::AutoRestoreFragmentProcessors arfp;
290    GrPipelineBuilder::AutoRestoreStencil ars;
291
292    if (!this->setupClip(pipelineBuilder, &arfp, &ars, &scissorState, NULL)) {
293        return;
294    }
295
296    // set stencil settings for path
297    GrStencilSettings stencilSettings;
298    GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
299    GrStencilAttachment* sb = rt->renderTargetPriv().attachStencilAttachment();
300    this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
301
302    // Don't compute a bounding box for dst copy texture, we'll opt
303    // instead for it to just copy the entire dst. Realistically this is a moot
304    // point, because any context that supports NV_path_rendering will also
305    // support NV_blend_equation_advanced.
306    GrDrawTarget::PipelineInfo pipelineInfo(pipelineBuilder, &scissorState, pathProc, NULL, this);
307    if (pipelineInfo.mustSkipDraw()) {
308        return;
309    }
310
311    this->onDrawPaths(pathProc, pathRange, indices, indexType, transformValues,
312                      transformType, count, stencilSettings, pipelineInfo);
313}
314
315void GrDrawTarget::clear(const SkIRect* rect,
316                         GrColor color,
317                         bool canIgnoreRect,
318                         GrRenderTarget* renderTarget) {
319    if (fCaps->useDrawInsteadOfClear()) {
320        // This works around a driver bug with clear by drawing a rect instead.
321        // The driver will ignore a clear if it is the only thing rendered to a
322        // target before the target is read.
323        SkIRect rtRect = SkIRect::MakeWH(renderTarget->width(), renderTarget->height());
324        if (NULL == rect || canIgnoreRect || rect->contains(rtRect)) {
325            rect = &rtRect;
326            // We first issue a discard() since that may help tilers.
327            this->discard(renderTarget);
328        }
329
330        GrPipelineBuilder pipelineBuilder;
331        pipelineBuilder.setRenderTarget(renderTarget);
332
333        this->drawSimpleRect(&pipelineBuilder, color, SkMatrix::I(), *rect);
334    } else {
335        this->onClear(rect, color, canIgnoreRect, renderTarget);
336    }
337}
338
339typedef GrTraceMarkerSet::Iter TMIter;
340void GrDrawTarget::saveActiveTraceMarkers() {
341    if (this->caps()->gpuTracingSupport()) {
342        SkASSERT(0 == fStoredTraceMarkers.count());
343        fStoredTraceMarkers.addSet(fActiveTraceMarkers);
344        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
345            this->removeGpuTraceMarker(&(*iter));
346        }
347    }
348}
349
350void GrDrawTarget::restoreActiveTraceMarkers() {
351    if (this->caps()->gpuTracingSupport()) {
352        SkASSERT(0 == fActiveTraceMarkers.count());
353        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
354            this->addGpuTraceMarker(&(*iter));
355        }
356        for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) {
357            this->fStoredTraceMarkers.remove(*iter);
358        }
359    }
360}
361
362void GrDrawTarget::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
363    if (this->caps()->gpuTracingSupport()) {
364        SkASSERT(fGpuTraceMarkerCount >= 0);
365        this->fActiveTraceMarkers.add(*marker);
366        ++fGpuTraceMarkerCount;
367    }
368}
369
370void GrDrawTarget::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
371    if (this->caps()->gpuTracingSupport()) {
372        SkASSERT(fGpuTraceMarkerCount >= 1);
373        this->fActiveTraceMarkers.remove(*marker);
374        --fGpuTraceMarkerCount;
375    }
376}
377
378////////////////////////////////////////////////////////////////////////////////
379
380namespace {
381// returns true if the read/written rect intersects the src/dst and false if not.
382bool clip_srcrect_and_dstpoint(const GrSurface* dst,
383                               const GrSurface* src,
384                               const SkIRect& srcRect,
385                               const SkIPoint& dstPoint,
386                               SkIRect* clippedSrcRect,
387                               SkIPoint* clippedDstPoint) {
388    *clippedSrcRect = srcRect;
389    *clippedDstPoint = dstPoint;
390
391    // clip the left edge to src and dst bounds, adjusting dstPoint if necessary
392    if (clippedSrcRect->fLeft < 0) {
393        clippedDstPoint->fX -= clippedSrcRect->fLeft;
394        clippedSrcRect->fLeft = 0;
395    }
396    if (clippedDstPoint->fX < 0) {
397        clippedSrcRect->fLeft -= clippedDstPoint->fX;
398        clippedDstPoint->fX = 0;
399    }
400
401    // clip the top edge to src and dst bounds, adjusting dstPoint if necessary
402    if (clippedSrcRect->fTop < 0) {
403        clippedDstPoint->fY -= clippedSrcRect->fTop;
404        clippedSrcRect->fTop = 0;
405    }
406    if (clippedDstPoint->fY < 0) {
407        clippedSrcRect->fTop -= clippedDstPoint->fY;
408        clippedDstPoint->fY = 0;
409    }
410
411    // clip the right edge to the src and dst bounds.
412    if (clippedSrcRect->fRight > src->width()) {
413        clippedSrcRect->fRight = src->width();
414    }
415    if (clippedDstPoint->fX + clippedSrcRect->width() > dst->width()) {
416        clippedSrcRect->fRight = clippedSrcRect->fLeft + dst->width() - clippedDstPoint->fX;
417    }
418
419    // clip the bottom edge to the src and dst bounds.
420    if (clippedSrcRect->fBottom > src->height()) {
421        clippedSrcRect->fBottom = src->height();
422    }
423    if (clippedDstPoint->fY + clippedSrcRect->height() > dst->height()) {
424        clippedSrcRect->fBottom = clippedSrcRect->fTop + dst->height() - clippedDstPoint->fY;
425    }
426
427    // The above clipping steps may have inverted the rect if it didn't intersect either the src or
428    // dst bounds.
429    return !clippedSrcRect->isEmpty();
430}
431}
432
433bool GrDrawTarget::copySurface(GrSurface* dst,
434                               GrSurface* src,
435                               const SkIRect& srcRect,
436                               const SkIPoint& dstPoint) {
437    SkASSERT(dst);
438    SkASSERT(src);
439
440    SkIRect clippedSrcRect;
441    SkIPoint clippedDstPoint;
442    // If the rect is outside the src or dst then we've already succeeded.
443    if (!clip_srcrect_and_dstpoint(dst,
444                                   src,
445                                   srcRect,
446                                   dstPoint,
447                                   &clippedSrcRect,
448                                   &clippedDstPoint)) {
449        return true;
450    }
451
452    if (this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint)) {
453        this->onCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
454        return true;
455    }
456
457    GrRenderTarget* rt = dst->asRenderTarget();
458    GrTexture* tex = src->asTexture();
459
460    if ((dst == src) || !rt || !tex) {
461        return false;
462    }
463
464    GrPipelineBuilder pipelineBuilder;
465    pipelineBuilder.setRenderTarget(rt);
466    SkMatrix matrix;
467    matrix.setTranslate(SkIntToScalar(clippedSrcRect.fLeft - clippedDstPoint.fX),
468                        SkIntToScalar(clippedSrcRect.fTop - clippedDstPoint.fY));
469    matrix.postIDiv(tex->width(), tex->height());
470    pipelineBuilder.addColorTextureProcessor(tex, matrix);
471    SkIRect dstRect = SkIRect::MakeXYWH(clippedDstPoint.fX,
472                                        clippedDstPoint.fY,
473                                        clippedSrcRect.width(),
474                                        clippedSrcRect.height());
475    this->drawSimpleRect(&pipelineBuilder, GrColor_WHITE, SkMatrix::I(), dstRect);
476    return true;
477}
478
479bool GrDrawTarget::canCopySurface(const GrSurface* dst,
480                                  const GrSurface* src,
481                                  const SkIRect& srcRect,
482                                  const SkIPoint& dstPoint) {
483    SkASSERT(dst);
484    SkASSERT(src);
485
486    SkIRect clippedSrcRect;
487    SkIPoint clippedDstPoint;
488    // If the rect is outside the src or dst then we're guaranteed success
489    if (!clip_srcrect_and_dstpoint(dst,
490                                   src,
491                                   srcRect,
492                                   dstPoint,
493                                   &clippedSrcRect,
494                                   &clippedDstPoint)) {
495        return true;
496    }
497    return ((dst != src) && dst->asRenderTarget() && src->asTexture()) ||
498           this->getGpu()->canCopySurface(dst, src, clippedSrcRect, clippedDstPoint);
499}
500
501void GrDrawTarget::setupPipeline(const PipelineInfo& pipelineInfo,
502                                 GrPipeline* pipeline) {
503    SkNEW_PLACEMENT_ARGS(pipeline, GrPipeline, (*pipelineInfo.fPipelineBuilder,
504                                                pipelineInfo.fColorPOI,
505                                                pipelineInfo.fCoveragePOI,
506                                                *this->caps(),
507                                                *pipelineInfo.fScissor,
508                                                &pipelineInfo.fDstCopy));
509}
510///////////////////////////////////////////////////////////////////////////////
511
512GrDrawTarget::PipelineInfo::PipelineInfo(GrPipelineBuilder* pipelineBuilder,
513                                         GrScissorState* scissor,
514                                         const GrPrimitiveProcessor* primProc,
515                                         const SkRect* devBounds,
516                                         GrDrawTarget* target)
517    : fPipelineBuilder(pipelineBuilder)
518    , fScissor(scissor) {
519    fColorPOI = fPipelineBuilder->colorProcInfo(primProc);
520    fCoveragePOI = fPipelineBuilder->coverageProcInfo(primProc);
521    if (!target->setupDstReadIfNecessary(*fPipelineBuilder, fColorPOI, fCoveragePOI,
522                                         &fDstCopy, devBounds)) {
523        fPipelineBuilder = NULL;
524    }
525}
526
527GrDrawTarget::PipelineInfo::PipelineInfo(GrPipelineBuilder* pipelineBuilder,
528                                         GrScissorState* scissor,
529                                         const GrBatch* batch,
530                                         const SkRect* devBounds,
531                                         GrDrawTarget* target)
532    : fPipelineBuilder(pipelineBuilder)
533    , fScissor(scissor) {
534    fColorPOI = fPipelineBuilder->colorProcInfo(batch);
535    fCoveragePOI = fPipelineBuilder->coverageProcInfo(batch);
536    if (!target->setupDstReadIfNecessary(*fPipelineBuilder, fColorPOI, fCoveragePOI,
537                                         &fDstCopy, devBounds)) {
538        fPipelineBuilder = NULL;
539    }
540}
541
542///////////////////////////////////////////////////////////////////////////////
543
544void GrShaderCaps::reset() {
545    fShaderDerivativeSupport = false;
546    fGeometryShaderSupport = false;
547    fPathRenderingSupport = false;
548    fDstReadInShaderSupport = false;
549    fDualSourceBlendingSupport = false;
550
551    fShaderPrecisionVaries = false;
552}
553
554GrShaderCaps& GrShaderCaps::operator=(const GrShaderCaps& other) {
555    fShaderDerivativeSupport = other.fShaderDerivativeSupport;
556    fGeometryShaderSupport = other.fGeometryShaderSupport;
557    fPathRenderingSupport = other.fPathRenderingSupport;
558    fDstReadInShaderSupport = other.fDstReadInShaderSupport;
559    fDualSourceBlendingSupport = other.fDualSourceBlendingSupport;
560
561    fShaderPrecisionVaries = other.fShaderPrecisionVaries;
562    for (int s = 0; s < kGrShaderTypeCount; ++s) {
563        for (int p = 0; p < kGrSLPrecisionCount; ++p) {
564            fFloatPrecisions[s][p] = other.fFloatPrecisions[s][p];
565        }
566    }
567    return *this;
568}
569
570static const char* shader_type_to_string(GrShaderType type) {
571    switch (type) {
572    case kVertex_GrShaderType:
573        return "vertex";
574    case kGeometry_GrShaderType:
575        return "geometry";
576    case kFragment_GrShaderType:
577        return "fragment";
578    }
579    return "";
580}
581
582static const char* precision_to_string(GrSLPrecision p) {
583    switch (p) {
584    case kLow_GrSLPrecision:
585        return "low";
586    case kMedium_GrSLPrecision:
587        return "medium";
588    case kHigh_GrSLPrecision:
589        return "high";
590    }
591    return "";
592}
593
594SkString GrShaderCaps::dump() const {
595    SkString r;
596    static const char* gNY[] = { "NO", "YES" };
597    r.appendf("Shader Derivative Support          : %s\n", gNY[fShaderDerivativeSupport]);
598    r.appendf("Geometry Shader Support            : %s\n", gNY[fGeometryShaderSupport]);
599    r.appendf("Path Rendering Support             : %s\n", gNY[fPathRenderingSupport]);
600    r.appendf("Dst Read In Shader Support         : %s\n", gNY[fDstReadInShaderSupport]);
601    r.appendf("Dual Source Blending Support       : %s\n", gNY[fDualSourceBlendingSupport]);
602
603    r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]);
604
605    for (int s = 0; s < kGrShaderTypeCount; ++s) {
606        GrShaderType shaderType = static_cast<GrShaderType>(s);
607        r.appendf("\t%s:\n", shader_type_to_string(shaderType));
608        for (int p = 0; p < kGrSLPrecisionCount; ++p) {
609            if (fFloatPrecisions[s][p].supported()) {
610                GrSLPrecision precision = static_cast<GrSLPrecision>(p);
611                r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n",
612                    precision_to_string(precision),
613                    fFloatPrecisions[s][p].fLogRangeLow,
614                    fFloatPrecisions[s][p].fLogRangeHigh,
615                    fFloatPrecisions[s][p].fBits);
616            }
617        }
618    }
619
620    return r;
621}
622
623///////////////////////////////////////////////////////////////////////////////
624
625void GrDrawTargetCaps::reset() {
626    fMipMapSupport = false;
627    fNPOTTextureTileSupport = false;
628    fTwoSidedStencilSupport = false;
629    fStencilWrapOpsSupport = false;
630    fDiscardRenderTargetSupport = false;
631    fReuseScratchTextures = true;
632    fGpuTracingSupport = false;
633    fCompressedTexSubImageSupport = false;
634    fOversizedStencilSupport = false;
635    fTextureBarrierSupport = false;
636
637    fUseDrawInsteadOfClear = false;
638
639    fMapBufferFlags = kNone_MapFlags;
640
641    fMaxRenderTargetSize = 0;
642    fMaxTextureSize = 0;
643    fMaxSampleCount = 0;
644
645    memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport));
646    memset(fConfigTextureSupport, 0, sizeof(fConfigTextureSupport));
647}
648
649GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) {
650    fMipMapSupport = other.fMipMapSupport;
651    fNPOTTextureTileSupport = other.fNPOTTextureTileSupport;
652    fTwoSidedStencilSupport = other.fTwoSidedStencilSupport;
653    fStencilWrapOpsSupport = other.fStencilWrapOpsSupport;
654    fDiscardRenderTargetSupport = other.fDiscardRenderTargetSupport;
655    fReuseScratchTextures = other.fReuseScratchTextures;
656    fGpuTracingSupport = other.fGpuTracingSupport;
657    fCompressedTexSubImageSupport = other.fCompressedTexSubImageSupport;
658    fOversizedStencilSupport = other.fOversizedStencilSupport;
659    fTextureBarrierSupport = other.fTextureBarrierSupport;
660
661    fUseDrawInsteadOfClear = other.fUseDrawInsteadOfClear;
662
663    fMapBufferFlags = other.fMapBufferFlags;
664
665    fMaxRenderTargetSize = other.fMaxRenderTargetSize;
666    fMaxTextureSize = other.fMaxTextureSize;
667    fMaxSampleCount = other.fMaxSampleCount;
668
669    memcpy(fConfigRenderSupport, other.fConfigRenderSupport, sizeof(fConfigRenderSupport));
670    memcpy(fConfigTextureSupport, other.fConfigTextureSupport, sizeof(fConfigTextureSupport));
671
672    return *this;
673}
674
675static SkString map_flags_to_string(uint32_t flags) {
676    SkString str;
677    if (GrDrawTargetCaps::kNone_MapFlags == flags) {
678        str = "none";
679    } else {
680        SkASSERT(GrDrawTargetCaps::kCanMap_MapFlag & flags);
681        SkDEBUGCODE(flags &= ~GrDrawTargetCaps::kCanMap_MapFlag);
682        str = "can_map";
683
684        if (GrDrawTargetCaps::kSubset_MapFlag & flags) {
685            str.append(" partial");
686        } else {
687            str.append(" full");
688        }
689        SkDEBUGCODE(flags &= ~GrDrawTargetCaps::kSubset_MapFlag);
690    }
691    SkASSERT(0 == flags); // Make sure we handled all the flags.
692    return str;
693}
694
695SkString GrDrawTargetCaps::dump() const {
696    SkString r;
697    static const char* gNY[] = {"NO", "YES"};
698    r.appendf("MIP Map Support                    : %s\n", gNY[fMipMapSupport]);
699    r.appendf("NPOT Texture Tile Support          : %s\n", gNY[fNPOTTextureTileSupport]);
700    r.appendf("Two Sided Stencil Support          : %s\n", gNY[fTwoSidedStencilSupport]);
701    r.appendf("Stencil Wrap Ops  Support          : %s\n", gNY[fStencilWrapOpsSupport]);
702    r.appendf("Discard Render Target Support      : %s\n", gNY[fDiscardRenderTargetSupport]);
703    r.appendf("Reuse Scratch Textures             : %s\n", gNY[fReuseScratchTextures]);
704    r.appendf("Gpu Tracing Support                : %s\n", gNY[fGpuTracingSupport]);
705    r.appendf("Compressed Update Support          : %s\n", gNY[fCompressedTexSubImageSupport]);
706    r.appendf("Oversized Stencil Support          : %s\n", gNY[fOversizedStencilSupport]);
707    r.appendf("Texture Barrier Support            : %s\n", gNY[fTextureBarrierSupport]);
708    r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]);
709
710    r.appendf("Max Texture Size                   : %d\n", fMaxTextureSize);
711    r.appendf("Max Render Target Size             : %d\n", fMaxRenderTargetSize);
712    r.appendf("Max Sample Count                   : %d\n", fMaxSampleCount);
713
714    r.appendf("Map Buffer Support                 : %s\n",
715              map_flags_to_string(fMapBufferFlags).c_str());
716
717    static const char* kConfigNames[] = {
718        "Unknown",  // kUnknown_GrPixelConfig
719        "Alpha8",   // kAlpha_8_GrPixelConfig,
720        "Index8",   // kIndex_8_GrPixelConfig,
721        "RGB565",   // kRGB_565_GrPixelConfig,
722        "RGBA444",  // kRGBA_4444_GrPixelConfig,
723        "RGBA8888", // kRGBA_8888_GrPixelConfig,
724        "BGRA8888", // kBGRA_8888_GrPixelConfig,
725        "SRGBA8888",// kSRGBA_8888_GrPixelConfig,
726        "ETC1",     // kETC1_GrPixelConfig,
727        "LATC",     // kLATC_GrPixelConfig,
728        "R11EAC",   // kR11_EAC_GrPixelConfig,
729        "ASTC12x12",// kASTC_12x12_GrPixelConfig,
730        "RGBAFloat",// kRGBA_float_GrPixelConfig
731        "AlphaHalf",// kAlpha_half_GrPixelConfig
732    };
733    GR_STATIC_ASSERT(0  == kUnknown_GrPixelConfig);
734    GR_STATIC_ASSERT(1  == kAlpha_8_GrPixelConfig);
735    GR_STATIC_ASSERT(2  == kIndex_8_GrPixelConfig);
736    GR_STATIC_ASSERT(3  == kRGB_565_GrPixelConfig);
737    GR_STATIC_ASSERT(4  == kRGBA_4444_GrPixelConfig);
738    GR_STATIC_ASSERT(5  == kRGBA_8888_GrPixelConfig);
739    GR_STATIC_ASSERT(6  == kBGRA_8888_GrPixelConfig);
740    GR_STATIC_ASSERT(7  == kSRGBA_8888_GrPixelConfig);
741    GR_STATIC_ASSERT(8  == kETC1_GrPixelConfig);
742    GR_STATIC_ASSERT(9  == kLATC_GrPixelConfig);
743    GR_STATIC_ASSERT(10  == kR11_EAC_GrPixelConfig);
744    GR_STATIC_ASSERT(11 == kASTC_12x12_GrPixelConfig);
745    GR_STATIC_ASSERT(12 == kRGBA_float_GrPixelConfig);
746    GR_STATIC_ASSERT(13 == kAlpha_half_GrPixelConfig);
747    GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt);
748
749    SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]);
750    SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]);
751
752    for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i)  {
753        r.appendf("%s is renderable: %s, with MSAA: %s\n",
754                  kConfigNames[i],
755                  gNY[fConfigRenderSupport[i][0]],
756                  gNY[fConfigRenderSupport[i][1]]);
757    }
758
759    SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]);
760
761    for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i)  {
762        r.appendf("%s is uploadable to a texture: %s\n",
763                  kConfigNames[i],
764                  gNY[fConfigTextureSupport[i]]);
765    }
766
767    return r;
768}
769
770///////////////////////////////////////////////////////////////////////////////////////////////////
771
772bool GrClipTarget::setupClip(GrPipelineBuilder* pipelineBuilder,
773                             GrPipelineBuilder::AutoRestoreFragmentProcessors* arfp,
774                             GrPipelineBuilder::AutoRestoreStencil* ars,
775                             GrScissorState* scissorState,
776                             const SkRect* devBounds) {
777    return fClipMaskManager.setupClipping(pipelineBuilder,
778                                          arfp,
779                                          ars,
780                                          scissorState,
781                                          devBounds);
782}
783