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