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