Home | History | Annotate | Download | only in batches
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrDrawVerticesBatch.h"
      9 
     10 #include "GrBatchFlushState.h"
     11 #include "GrInvariantOutput.h"
     12 #include "GrDefaultGeoProcFactory.h"
     13 
     14 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
     15                                                         int* colorOffset,
     16                                                         int* texOffset,
     17                                                         const SkMatrix& viewMatrix,
     18                                                         bool coverageIgnored) {
     19     using namespace GrDefaultGeoProcFactory;
     20     *texOffset = -1;
     21     *colorOffset = -1;
     22 
     23     Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
     24     LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type :
     25                                              LocalCoords::kUsePosition_Type);
     26     *colorOffset = sizeof(SkPoint);
     27     if (hasLocalCoords) {
     28         *texOffset = sizeof(SkPoint) + sizeof(GrColor);
     29     }
     30     return GrDefaultGeoProcFactory::Create(Color(Color::kAttribute_Type),
     31                                            coverage, localCoords, viewMatrix);
     32 }
     33 
     34 GrDrawVerticesBatch::GrDrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
     35                                          const SkMatrix& viewMatrix,
     36                                          const SkPoint* positions, int vertexCount,
     37                                          const uint16_t* indices, int indexCount,
     38                                          const GrColor* colors, const SkPoint* localCoords,
     39                                          const SkRect& bounds)
     40     : INHERITED(ClassID()) {
     41     SkASSERT(positions);
     42 
     43     fViewMatrix = viewMatrix;
     44     Geometry& installedGeo = fGeoData.push_back(geometry);
     45 
     46     installedGeo.fPositions.append(vertexCount, positions);
     47     if (indices) {
     48         installedGeo.fIndices.append(indexCount, indices);
     49     }
     50 
     51     if (colors) {
     52         fVariableColor = true;
     53         installedGeo.fColors.append(vertexCount, colors);
     54     } else {
     55         fVariableColor = false;
     56     }
     57 
     58     if (localCoords) {
     59         installedGeo.fLocalCoords.append(vertexCount, localCoords);
     60     }
     61     fVertexCount = vertexCount;
     62     fIndexCount = indexCount;
     63     fPrimitiveType = primitiveType;
     64 
     65     this->setBounds(bounds);
     66 }
     67 
     68 void GrDrawVerticesBatch::computePipelineOptimizations(GrInitInvariantOutput* color,
     69                                                        GrInitInvariantOutput* coverage,
     70                                                        GrBatchToXPOverrides* overrides) const {
     71     // When this is called on a batch, there is only one geometry bundle
     72     if (fVariableColor) {
     73         color->setUnknownFourComponents();
     74     } else {
     75         color->setKnownFourComponents(fGeoData[0].fColor);
     76     }
     77     coverage->setKnownSingleComponent(0xff);
     78 }
     79 
     80 void GrDrawVerticesBatch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
     81     SkASSERT(fGeoData.count() == 1);
     82     GrColor overrideColor;
     83     if (overrides.getOverrideColorIfSet(&overrideColor)) {
     84         fGeoData[0].fColor = overrideColor;
     85         fGeoData[0].fColors.reset();
     86         fVariableColor = false;
     87     }
     88     fCoverageIgnored = !overrides.readsCoverage();
     89     if (!overrides.readsLocalCoords()) {
     90         fGeoData[0].fLocalCoords.reset();
     91     }
     92 }
     93 
     94 void GrDrawVerticesBatch::onPrepareDraws(Target* target) const {
     95     bool hasLocalCoords = !fGeoData[0].fLocalCoords.isEmpty();
     96     int colorOffset = -1, texOffset = -1;
     97     SkAutoTUnref<const GrGeometryProcessor> gp(
     98         set_vertex_attributes(hasLocalCoords, &colorOffset, &texOffset, fViewMatrix,
     99                               fCoverageIgnored));
    100     target->initDraw(gp, this->pipeline());
    101 
    102     size_t vertexStride = gp->getVertexStride();
    103 
    104     SkASSERT(vertexStride == sizeof(SkPoint) + (hasLocalCoords ? sizeof(SkPoint) : 0)
    105                                              + sizeof(GrColor));
    106 
    107     int instanceCount = fGeoData.count();
    108 
    109     const GrVertexBuffer* vertexBuffer;
    110     int firstVertex;
    111 
    112     void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
    113 
    114     if (!verts) {
    115         SkDebugf("Could not allocate vertices\n");
    116         return;
    117     }
    118 
    119     const GrIndexBuffer* indexBuffer = nullptr;
    120     int firstIndex = 0;
    121 
    122     uint16_t* indices = nullptr;
    123     if (!fGeoData[0].fIndices.isEmpty()) {
    124         indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
    125 
    126         if (!indices) {
    127             SkDebugf("Could not allocate indices\n");
    128             return;
    129         }
    130     }
    131 
    132     int indexOffset = 0;
    133     int vertexOffset = 0;
    134     for (int i = 0; i < instanceCount; i++) {
    135         const Geometry& args = fGeoData[i];
    136 
    137         // TODO we can actually cache this interleaved and then just memcopy
    138         if (indices) {
    139             for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
    140                 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
    141             }
    142         }
    143 
    144         for (int j = 0; j < args.fPositions.count(); ++j) {
    145             *((SkPoint*)verts) = args.fPositions[j];
    146             if (args.fColors.isEmpty()) {
    147                 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColor;
    148             } else {
    149                 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
    150             }
    151             if (hasLocalCoords) {
    152                 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
    153             }
    154             verts = (void*)((intptr_t)verts + vertexStride);
    155             vertexOffset++;
    156         }
    157     }
    158 
    159     GrVertices vertices;
    160     if (indices) {
    161         vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
    162                              firstIndex, fVertexCount, fIndexCount);
    163 
    164     } else {
    165         vertices.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
    166     }
    167     target->draw(vertices);
    168 }
    169 
    170 bool GrDrawVerticesBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
    171     GrDrawVerticesBatch* that = t->cast<GrDrawVerticesBatch>();
    172 
    173     if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
    174                                 that->bounds(), caps)) {
    175         return false;
    176     }
    177 
    178     if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
    179         return false;
    180     }
    181 
    182     // We currently use a uniform viewmatrix for this batch
    183     if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
    184         return false;
    185     }
    186 
    187     if (fGeoData[0].fIndices.isEmpty() != that->fGeoData[0].fIndices.isEmpty()) {
    188         return false;
    189     }
    190 
    191     if (fGeoData[0].fLocalCoords.isEmpty() != that->fGeoData[0].fLocalCoords.isEmpty()) {
    192         return false;
    193     }
    194 
    195     if (!fVariableColor) {
    196         if (that->fVariableColor || that->fGeoData[0].fColor != fGeoData[0].fColor) {
    197             fVariableColor = true;
    198         }
    199     }
    200 
    201     fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
    202     fVertexCount += that->fVertexCount;
    203     fIndexCount += that->fIndexCount;
    204 
    205     this->joinBounds(that->bounds());
    206     return true;
    207 }
    208 
    209 ///////////////////////////////////////////////////////////////////////////////////////////////////
    210 
    211 #ifdef GR_TEST_UTILS
    212 
    213 #include "GrBatchTest.h"
    214 
    215 static uint32_t seed_vertices(GrPrimitiveType type) {
    216     switch (type) {
    217         case kTriangles_GrPrimitiveType:
    218         case kTriangleStrip_GrPrimitiveType:
    219         case kTriangleFan_GrPrimitiveType:
    220             return 3;
    221         case kPoints_GrPrimitiveType:
    222             return 1;
    223         case kLines_GrPrimitiveType:
    224         case kLineStrip_GrPrimitiveType:
    225             return 2;
    226     }
    227     SkFAIL("Incomplete switch\n");
    228     return 0;
    229 }
    230 
    231 static uint32_t primitive_vertices(GrPrimitiveType type) {
    232     switch (type) {
    233         case kTriangles_GrPrimitiveType:
    234             return 3;
    235         case kLines_GrPrimitiveType:
    236             return 2;
    237         case kTriangleStrip_GrPrimitiveType:
    238         case kTriangleFan_GrPrimitiveType:
    239         case kPoints_GrPrimitiveType:
    240         case kLineStrip_GrPrimitiveType:
    241             return 1;
    242     }
    243     SkFAIL("Incomplete switch\n");
    244     return 0;
    245 }
    246 
    247 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
    248     SkPoint p;
    249     p.fX = random->nextRangeScalar(min, max);
    250     p.fY = random->nextRangeScalar(min, max);
    251     return p;
    252 }
    253 
    254 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
    255                              SkRandom* random,
    256                              SkTArray<SkPoint>* positions,
    257                              SkTArray<SkPoint>* texCoords, bool hasTexCoords,
    258                              SkTArray<GrColor>* colors, bool hasColors,
    259                              SkTArray<uint16_t>* indices, bool hasIndices) {
    260     for (uint32_t v = 0; v < count; v++) {
    261         positions->push_back(random_point(random, min, max));
    262         if (hasTexCoords) {
    263             texCoords->push_back(random_point(random, min, max));
    264         }
    265         if (hasColors) {
    266             colors->push_back(GrRandomColor(random));
    267         }
    268         if (hasIndices) {
    269             SkASSERT(maxVertex <= SK_MaxU16);
    270             indices->push_back(random->nextULessThan((uint16_t)maxVertex));
    271         }
    272     }
    273 }
    274 
    275 DRAW_BATCH_TEST_DEFINE(VerticesBatch) {
    276     GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
    277     uint32_t primitiveCount = random->nextRangeU(1, 100);
    278 
    279     // TODO make 'sensible' indexbuffers
    280     SkTArray<SkPoint> positions;
    281     SkTArray<SkPoint> texCoords;
    282     SkTArray<GrColor> colors;
    283     SkTArray<uint16_t> indices;
    284 
    285     bool hasTexCoords = random->nextBool();
    286     bool hasIndices = random->nextBool();
    287     bool hasColors = random->nextBool();
    288 
    289     uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
    290 
    291     static const SkScalar kMinVertExtent = -100.f;
    292     static const SkScalar kMaxVertExtent = 100.f;
    293     randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
    294                      random,
    295                      &positions,
    296                      &texCoords, hasTexCoords,
    297                      &colors, hasColors,
    298                      &indices, hasIndices);
    299 
    300     for (uint32_t i = 1; i < primitiveCount; i++) {
    301         randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
    302                          random,
    303                          &positions,
    304                          &texCoords, hasTexCoords,
    305                          &colors, hasColors,
    306                          &indices, hasIndices);
    307     }
    308 
    309     SkMatrix viewMatrix = GrTest::TestMatrix(random);
    310     SkRect bounds;
    311     SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
    312     SkASSERT(result);
    313 
    314     viewMatrix.mapRect(&bounds);
    315 
    316     GrDrawVerticesBatch::Geometry geometry;
    317     geometry.fColor = GrRandomColor(random);
    318     return GrDrawVerticesBatch::Create(geometry, type, viewMatrix,
    319                                        positions.begin(), vertexCount,
    320                                        indices.begin(), hasIndices ? vertexCount : 0,
    321                                        colors.begin(),
    322                                        texCoords.begin(),
    323                                        bounds);
    324 }
    325 
    326 #endif
    327