Home | History | Annotate | Download | only in ops
      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 "GrDrawVerticesOp.h"
      9 #include "GrDefaultGeoProcFactory.h"
     10 #include "GrOpFlushState.h"
     11 #include "SkGr.h"
     12 
     13 std::unique_ptr<GrMeshDrawOp> GrDrawVerticesOp::Make(
     14         GrColor color, GrPrimitiveType primitiveType, const SkMatrix& viewMatrix,
     15         const SkPoint* positions, int vertexCount, const uint16_t* indices, int indexCount,
     16         const uint32_t* colors, const SkPoint* localCoords, const SkRect& bounds,
     17         GrRenderTargetContext::ColorArrayType colorArrayType) {
     18     static constexpr SkCanvas::VertexMode kIgnoredMode = SkCanvas::kTriangles_VertexMode;
     19     SkASSERT(positions);
     20     if (!colors) {
     21         // When we tessellate we will fill a color array with the GrColor value passed above as
     22         // 'color'.
     23         colorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor;
     24     }
     25     sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, vertexCount, positions,
     26                                                       localCoords, colors, indexCount, indices);
     27     if (!vertices) {
     28         return nullptr;
     29     }
     30     return std::unique_ptr<GrMeshDrawOp>(new GrDrawVerticesOp(std::move(vertices), primitiveType,
     31                                                               color, colorArrayType, viewMatrix));
     32 }
     33 
     34 std::unique_ptr<GrMeshDrawOp> GrDrawVerticesOp::Make(GrColor color, sk_sp<SkVertices> vertices,
     35                                                      const SkMatrix& viewMatrix) {
     36     SkASSERT(vertices);
     37     GrPrimitiveType primType = SkVertexModeToGrPrimitiveType(vertices->mode());
     38     return std::unique_ptr<GrMeshDrawOp>(new GrDrawVerticesOp(
     39             std::move(vertices), primType, color, GrRenderTargetContext::ColorArrayType::kSkColor,
     40             viewMatrix));
     41 }
     42 
     43 GrDrawVerticesOp::GrDrawVerticesOp(sk_sp<SkVertices> vertices, GrPrimitiveType primitiveType,
     44                                    GrColor color,
     45                                    GrRenderTargetContext::ColorArrayType colorArrayType,
     46                                    const SkMatrix& viewMatrix, uint32_t flags)
     47         : INHERITED(ClassID()), fColorArrayType(colorArrayType) {
     48     SkASSERT(vertices);
     49 
     50     fVertexCount = vertices->vertexCount();
     51     fIndexCount = vertices->indexCount();
     52     fPrimitiveType = primitiveType;
     53 
     54     Mesh& mesh = fMeshes.push_back();
     55     mesh.fColor = color;
     56     mesh.fViewMatrix = viewMatrix;
     57     mesh.fVertices = std::move(vertices);
     58     mesh.fFlags = flags;
     59 
     60     fFlags = 0;
     61     if (mesh.hasPerVertexColors()) {
     62         fFlags |= kRequiresPerVertexColors_Flag;
     63     }
     64     if (mesh.hasExplicitLocalCoords()) {
     65         fFlags |= kAnyMeshHasExplicitLocalCoords;
     66     }
     67 
     68     IsZeroArea zeroArea;
     69     if (GrIsPrimTypeLines(primitiveType) || kPoints_GrPrimitiveType == primitiveType) {
     70         zeroArea = IsZeroArea::kYes;
     71     } else {
     72         zeroArea = IsZeroArea::kNo;
     73     }
     74     this->setTransformedBounds(mesh.fVertices->bounds(), viewMatrix, HasAABloat::kNo, zeroArea);
     75 }
     76 
     77 void GrDrawVerticesOp::getFragmentProcessorAnalysisInputs(
     78         GrPipelineAnalysisColor* color, GrPipelineAnalysisCoverage* coverage) const {
     79     if (this->requiresPerVertexColors()) {
     80         color->setToUnknown();
     81     } else {
     82         color->setToConstant(fMeshes[0].fColor);
     83     }
     84     *coverage = GrPipelineAnalysisCoverage::kNone;
     85 }
     86 
     87 void GrDrawVerticesOp::applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) {
     88     SkASSERT(fMeshes.count() == 1);
     89     GrColor overrideColor;
     90     if (optimizations.getOverrideColorIfSet(&overrideColor)) {
     91         fMeshes[0].fColor = overrideColor;
     92         fMeshes[0].fFlags |= kIgnoreColors_VerticesFlag;
     93         fFlags &= ~kRequiresPerVertexColors_Flag;
     94         fColorArrayType = GrRenderTargetContext::ColorArrayType::kPremulGrColor;
     95     }
     96     if (optimizations.readsLocalCoords()) {
     97         fFlags |= kPipelineRequiresLocalCoords_Flag;
     98     } else {
     99         fFlags |= kIgnoreTexCoords_VerticesFlag;
    100         fFlags &= ~kAnyMeshHasExplicitLocalCoords;
    101     }
    102 }
    103 
    104 sk_sp<GrGeometryProcessor> GrDrawVerticesOp::makeGP(bool* hasColorAttribute,
    105                                                     bool* hasLocalCoordAttribute) const {
    106     using namespace GrDefaultGeoProcFactory;
    107     LocalCoords::Type localCoordsType;
    108     if (this->pipelineRequiresLocalCoords()) {
    109         // If we have multiple view matrices we will transform the positions into device space. We
    110         // must then also provide untransformed positions as local coords.
    111         if (this->anyMeshHasExplicitLocalCoords() || this->hasMultipleViewMatrices()) {
    112             *hasLocalCoordAttribute = true;
    113             localCoordsType = LocalCoords::kHasExplicit_Type;
    114         } else {
    115             *hasLocalCoordAttribute = false;
    116             localCoordsType = LocalCoords::kUsePosition_Type;
    117         }
    118     } else {
    119         localCoordsType = LocalCoords::kUnused_Type;
    120         *hasLocalCoordAttribute = false;
    121     }
    122 
    123     Color color(fMeshes[0].fColor);
    124     if (this->requiresPerVertexColors()) {
    125         color.fType = (fColorArrayType == GrRenderTargetContext::ColorArrayType::kPremulGrColor)
    126                               ? Color::kPremulGrColorAttribute_Type
    127                               : Color::kUnpremulSkColorAttribute_Type;
    128         *hasColorAttribute = true;
    129     } else {
    130         *hasColorAttribute = false;
    131     };
    132     const SkMatrix& vm = this->hasMultipleViewMatrices() ? SkMatrix::I() : fMeshes[0].fViewMatrix;
    133     return GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType, vm);
    134 }
    135 
    136 void GrDrawVerticesOp::onPrepareDraws(Target* target) const {
    137     bool hasColorAttribute;
    138     bool hasLocalCoordsAttribute;
    139     sk_sp<GrGeometryProcessor> gp = this->makeGP(&hasColorAttribute, &hasLocalCoordsAttribute);
    140     size_t vertexStride = gp->getVertexStride();
    141 
    142     SkASSERT(vertexStride == sizeof(SkPoint) + (hasColorAttribute ? sizeof(uint32_t) : 0) +
    143                                      (hasLocalCoordsAttribute ? sizeof(SkPoint) : 0));
    144 
    145     int instanceCount = fMeshes.count();
    146 
    147     const GrBuffer* vertexBuffer;
    148     int firstVertex;
    149 
    150     void* verts = target->makeVertexSpace(vertexStride, fVertexCount, &vertexBuffer, &firstVertex);
    151 
    152     if (!verts) {
    153         SkDebugf("Could not allocate vertices\n");
    154         return;
    155     }
    156 
    157     const GrBuffer* indexBuffer = nullptr;
    158     int firstIndex = 0;
    159 
    160     uint16_t* indices = nullptr;
    161     if (this->isIndexed()) {
    162         indices = target->makeIndexSpace(fIndexCount, &indexBuffer, &firstIndex);
    163 
    164         if (!indices) {
    165             SkDebugf("Could not allocate indices\n");
    166             return;
    167         }
    168     }
    169 
    170     int vertexOffset = 0;
    171     // We have a fast case below for uploading the vertex data when the matrix is translate
    172     // only and there are colors but not local coords.
    173     bool fastAttrs = hasColorAttribute && !hasLocalCoordsAttribute;
    174     for (int i = 0; i < instanceCount; i++) {
    175         const Mesh& mesh = fMeshes[i];
    176         if (indices) {
    177             int indexCount = mesh.fVertices->indexCount();
    178             for (int j = 0; j < indexCount; ++j) {
    179                 *indices++ = mesh.fVertices->indices()[j] + vertexOffset;
    180             }
    181         }
    182         int vertexCount = mesh.fVertices->vertexCount();
    183         const SkPoint* positions = mesh.fVertices->positions();
    184         const SkColor* colors = mesh.fVertices->colors();
    185         const SkPoint* localCoords = mesh.fVertices->texCoords();
    186         bool fastMesh = (!this->hasMultipleViewMatrices() ||
    187                          mesh.fViewMatrix.getType() <= SkMatrix::kTranslate_Mask) &&
    188                         mesh.hasPerVertexColors();
    189         if (fastAttrs && fastMesh) {
    190             struct V {
    191                 SkPoint fPos;
    192                 uint32_t fColor;
    193             };
    194             SkASSERT(sizeof(V) == vertexStride);
    195             V* v = (V*)verts;
    196             Sk2f t(0, 0);
    197             if (this->hasMultipleViewMatrices()) {
    198                 t = Sk2f(mesh.fViewMatrix.getTranslateX(), mesh.fViewMatrix.getTranslateY());
    199             }
    200             for (int j = 0; j < vertexCount; ++j) {
    201                 Sk2f p = Sk2f::Load(positions++) + t;
    202                 p.store(&v[j].fPos);
    203                 v[j].fColor = colors[j];
    204             }
    205             verts = v + vertexCount;
    206         } else {
    207             static constexpr size_t kColorOffset = sizeof(SkPoint);
    208             size_t localCoordOffset =
    209                     hasColorAttribute ? kColorOffset + sizeof(uint32_t) : kColorOffset;
    210 
    211             for (int j = 0; j < vertexCount; ++j) {
    212                 if (this->hasMultipleViewMatrices()) {
    213                     mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
    214                 } else {
    215                     *((SkPoint*)verts) = positions[j];
    216                 }
    217                 if (hasColorAttribute) {
    218                     if (mesh.hasPerVertexColors()) {
    219                         *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
    220                     } else {
    221                         *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
    222                     }
    223                 }
    224                 if (hasLocalCoordsAttribute) {
    225                     if (mesh.hasExplicitLocalCoords()) {
    226                         *(SkPoint*)((intptr_t)verts + localCoordOffset) = localCoords[j];
    227                     } else {
    228                         *(SkPoint*)((intptr_t)verts + localCoordOffset) = positions[j];
    229                     }
    230                 }
    231                 verts = (void*)((intptr_t)verts + vertexStride);
    232             }
    233         }
    234         vertexOffset += vertexCount;
    235     }
    236 
    237     GrMesh mesh;
    238     if (indices) {
    239         mesh.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex, firstIndex,
    240                          fVertexCount, fIndexCount);
    241 
    242     } else {
    243         mesh.init(this->primitiveType(), vertexBuffer, firstVertex, fVertexCount);
    244     }
    245     target->draw(gp.get(), mesh);
    246 }
    247 
    248 bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
    249     GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
    250 
    251     if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
    252                                 that->bounds(), caps)) {
    253         return false;
    254     }
    255 
    256     if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
    257         return false;
    258     }
    259 
    260     if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
    261         return false;
    262     }
    263 
    264     if (fColorArrayType != that->fColorArrayType) {
    265         return false;
    266     }
    267 
    268     if (fVertexCount + that->fVertexCount > SK_MaxU16) {
    269         return false;
    270     }
    271 
    272     // If either op required explicit local coords or per-vertex colors the combined mesh does. Same
    273     // with multiple view matrices.
    274     fFlags |= that->fFlags;
    275 
    276     if (!this->requiresPerVertexColors() && this->fMeshes[0].fColor != that->fMeshes[0].fColor) {
    277         fFlags |= kRequiresPerVertexColors_Flag;
    278     }
    279     // Check whether we are about to acquire a mesh with a different view matrix.
    280     if (!this->hasMultipleViewMatrices() &&
    281         !this->fMeshes[0].fViewMatrix.cheapEqualTo(that->fMeshes[0].fViewMatrix)) {
    282         fFlags |= kHasMultipleViewMatrices_Flag;
    283     }
    284 
    285     fMeshes.push_back_n(that->fMeshes.count(), that->fMeshes.begin());
    286     fVertexCount += that->fVertexCount;
    287     fIndexCount += that->fIndexCount;
    288 
    289     this->joinBounds(*that);
    290     return true;
    291 }
    292 
    293 ///////////////////////////////////////////////////////////////////////////////////////////////////
    294 
    295 #if GR_TEST_UTILS
    296 
    297 #include "GrDrawOpTest.h"
    298 
    299 static uint32_t seed_vertices(GrPrimitiveType type) {
    300     switch (type) {
    301         case kTriangles_GrPrimitiveType:
    302         case kTriangleStrip_GrPrimitiveType:
    303         case kTriangleFan_GrPrimitiveType:
    304             return 3;
    305         case kPoints_GrPrimitiveType:
    306             return 1;
    307         case kLines_GrPrimitiveType:
    308         case kLineStrip_GrPrimitiveType:
    309             return 2;
    310     }
    311     SkFAIL("Incomplete switch\n");
    312     return 0;
    313 }
    314 
    315 static uint32_t primitive_vertices(GrPrimitiveType type) {
    316     switch (type) {
    317         case kTriangles_GrPrimitiveType:
    318             return 3;
    319         case kLines_GrPrimitiveType:
    320             return 2;
    321         case kTriangleStrip_GrPrimitiveType:
    322         case kTriangleFan_GrPrimitiveType:
    323         case kPoints_GrPrimitiveType:
    324         case kLineStrip_GrPrimitiveType:
    325             return 1;
    326     }
    327     SkFAIL("Incomplete switch\n");
    328     return 0;
    329 }
    330 
    331 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
    332     SkPoint p;
    333     p.fX = random->nextRangeScalar(min, max);
    334     p.fY = random->nextRangeScalar(min, max);
    335     return p;
    336 }
    337 
    338 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
    339                              SkRandom* random, SkTArray<SkPoint>* positions,
    340                              SkTArray<SkPoint>* texCoords, bool hasTexCoords,
    341                              SkTArray<uint32_t>* colors, bool hasColors,
    342                              SkTArray<uint16_t>* indices, bool hasIndices) {
    343     for (uint32_t v = 0; v < count; v++) {
    344         positions->push_back(random_point(random, min, max));
    345         if (hasTexCoords) {
    346             texCoords->push_back(random_point(random, min, max));
    347         }
    348         if (hasColors) {
    349             colors->push_back(GrRandomColor(random));
    350         }
    351         if (hasIndices) {
    352             SkASSERT(maxVertex <= SK_MaxU16);
    353             indices->push_back(random->nextULessThan((uint16_t)maxVertex));
    354         }
    355     }
    356 }
    357 
    358 DRAW_OP_TEST_DEFINE(VerticesOp) {
    359     GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
    360     uint32_t primitiveCount = random->nextRangeU(1, 100);
    361 
    362     // TODO make 'sensible' indexbuffers
    363     SkTArray<SkPoint> positions;
    364     SkTArray<SkPoint> texCoords;
    365     SkTArray<uint32_t> colors;
    366     SkTArray<uint16_t> indices;
    367 
    368     bool hasTexCoords = random->nextBool();
    369     bool hasIndices = random->nextBool();
    370     bool hasColors = random->nextBool();
    371 
    372     uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
    373 
    374     static const SkScalar kMinVertExtent = -100.f;
    375     static const SkScalar kMaxVertExtent = 100.f;
    376     randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent, random,
    377                      &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
    378                      hasIndices);
    379 
    380     for (uint32_t i = 1; i < primitiveCount; i++) {
    381         randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
    382                          random, &positions, &texCoords, hasTexCoords, &colors, hasColors, &indices,
    383                          hasIndices);
    384     }
    385 
    386     GrRenderTargetContext::ColorArrayType colorArrayType =
    387             random->nextBool() ? GrRenderTargetContext::ColorArrayType::kPremulGrColor
    388                                : GrRenderTargetContext::ColorArrayType::kSkColor;
    389     SkMatrix viewMatrix = GrTest::TestMatrix(random);
    390     SkRect bounds;
    391     SkDEBUGCODE(bool result =) bounds.setBoundsCheck(positions.begin(), vertexCount);
    392     SkASSERT(result);
    393 
    394     GrColor color = GrRandomColor(random);
    395     return GrDrawVerticesOp::Make(color, type, viewMatrix, positions.begin(), vertexCount,
    396                                   indices.begin(), hasIndices ? indices.count() : 0, colors.begin(),
    397                                   texCoords.begin(), bounds, colorArrayType);
    398 }
    399 
    400 #endif
    401