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