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