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 "GrDrawPathOp.h"
      9 #include "GrAppliedClip.h"
     10 #include "GrRenderTargetContext.h"
     11 #include "GrRenderTargetPriv.h"
     12 #include "SkTemplates.h"
     13 
     14 GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
     15                                    GrPathRendering::FillType fill, GrAAType aaType)
     16         : INHERITED(classID)
     17         , fViewMatrix(viewMatrix)
     18         , fInputColor(paint.getColor())
     19         , fFillType(fill)
     20         , fAAType(aaType)
     21         , fPipelineSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint))
     22         , fProcessorSet(std::move(paint)) {}
     23 
     24 SkString GrDrawPathOp::dumpInfo() const {
     25     SkString string;
     26     string.printf("PATH: 0x%p", fPath.get());
     27     string.append(INHERITED::dumpInfo());
     28     return string;
     29 }
     30 
     31 GrPipeline::InitArgs GrDrawPathOpBase::pipelineInitArgs(const GrOpFlushState& state) {
     32     static constexpr GrUserStencilSettings kCoverPass{
     33             GrUserStencilSettings::StaticInit<
     34                     0x0000,
     35                     GrUserStencilTest::kNotEqual,
     36                     0xffff,
     37                     GrUserStencilOp::kZero,
     38                     GrUserStencilOp::kKeep,
     39                     0xffff>()
     40     };
     41     GrPipeline::InitArgs args;
     42     args.fFlags = fPipelineSRGBFlags;
     43     if (GrAATypeIsHW(fAAType)) {
     44         args.fFlags |= GrPipeline::kHWAntialias_Flag;
     45     }
     46     args.fUserStencil = &kCoverPass;
     47     args.fProxy = state.drawOpArgs().fProxy;
     48     args.fCaps = &state.caps();
     49     args.fResourceProvider = state.resourceProvider();
     50     args.fDstProxy = state.drawOpArgs().fDstProxy;
     51     return args;
     52 }
     53 
     54 //////////////////////////////////////////////////////////////////////////////
     55 
     56 void init_stencil_pass_settings(const GrOpFlushState& flushState,
     57                                 GrPathRendering::FillType fillType, GrStencilSettings* stencil) {
     58     const GrAppliedClip* appliedClip = flushState.drawOpArgs().fAppliedClip;
     59     bool stencilClip = appliedClip && appliedClip->hasStencilClip();
     60     stencil->reset(GrPathRendering::GetStencilPassSettings(fillType), stencilClip,
     61                    flushState.drawOpArgs().renderTarget()->renderTargetPriv().numStencilBits());
     62 }
     63 
     64 //////////////////////////////////////////////////////////////////////////////
     65 
     66 void GrDrawPathOp::onExecute(GrOpFlushState* state) {
     67     GrPipeline pipeline(this->pipelineInitArgs(*state), this->detachProcessors(),
     68                         state->detachAppliedClip());
     69     sk_sp<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(), this->viewMatrix()));
     70 
     71     GrStencilSettings stencil;
     72     init_stencil_pass_settings(*state, this->fillType(), &stencil);
     73     state->gpu()->pathRendering()->drawPath(pipeline, *pathProc, stencil, fPath.get());
     74 }
     75 
     76 //////////////////////////////////////////////////////////////////////////////
     77 
     78 SkString GrDrawPathRangeOp::dumpInfo() const {
     79     SkString string;
     80     string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
     81     for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
     82         string.appendf("%d, ", iter.get()->fInstanceData->count());
     83     }
     84     string.remove(string.size() - 2, 2);
     85     string.append("]");
     86     string.append(INHERITED::dumpInfo());
     87     return string;
     88 }
     89 
     90 GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
     91                                      SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill,
     92                                      GrAAType aaType, GrPathRange* range,
     93                                      const InstanceData* instanceData, const SkRect& bounds)
     94         : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aaType)
     95         , fPathRange(range)
     96         , fTotalPathCount(instanceData->count())
     97         , fScale(scale) {
     98     fDraws.addToHead()->set(instanceData, x, y);
     99     this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
    100 }
    101 
    102 static void pre_translate_transform_values(const float* xforms,
    103                                            GrPathRendering::PathTransformType type, int count,
    104                                            SkScalar x, SkScalar y, float* dst);
    105 
    106 bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
    107     GrDrawPathRangeOp* that = t->cast<GrDrawPathRangeOp>();
    108     if (this->fPathRange.get() != that->fPathRange.get() ||
    109         this->transformType() != that->transformType() || this->fScale != that->fScale ||
    110         this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
    111         return false;
    112     }
    113     if (this->processors() != that->processors()) {
    114         return false;
    115     }
    116     if (this->pipelineSRGBFlags() != that->pipelineSRGBFlags()) {
    117         return false;
    118     }
    119     switch (fDraws.head()->fInstanceData->transformType()) {
    120         case GrPathRendering::kNone_PathTransformType:
    121             if (this->fDraws.head()->fX != that->fDraws.head()->fX ||
    122                 this->fDraws.head()->fY != that->fDraws.head()->fY) {
    123                 return false;
    124             }
    125             break;
    126         case GrPathRendering::kTranslateX_PathTransformType:
    127             if (this->fDraws.head()->fY != that->fDraws.head()->fY) {
    128                 return false;
    129             }
    130             break;
    131         case GrPathRendering::kTranslateY_PathTransformType:
    132             if (this->fDraws.head()->fX != that->fDraws.head()->fX) {
    133                 return false;
    134             }
    135             break;
    136         default:
    137             break;
    138     }
    139     // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...)
    140     // Try to combine this call with the previous DrawPaths. We do this by stenciling all the
    141     // paths together and then covering them in a single pass. This is not equivalent to two
    142     // separate draw calls, so we can only do it if there is no blending (no overlap would also
    143     // work). Note that it's also possible for overlapping paths to cancel each other's winding
    144     // numbers, and we only partially account for this by not allowing even/odd paths to be
    145     // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.)
    146 
    147     if (GrPathRendering::kWinding_FillType != this->fillType() ||
    148         GrPathRendering::kWinding_FillType != that->fillType()) {
    149         return false;
    150     }
    151     if (!this->processorAnalysis().canCombineOverlappedStencilAndCover()) {
    152         return false;
    153     }
    154     fTotalPathCount += that->fTotalPathCount;
    155     while (Draw* head = that->fDraws.head()) {
    156         Draw* draw = fDraws.addToTail();
    157         draw->fInstanceData.reset(head->fInstanceData.release());
    158         draw->fX = head->fX;
    159         draw->fY = head->fY;
    160         that->fDraws.popHead();
    161     }
    162     this->joinBounds(*that);
    163     return true;
    164 }
    165 
    166 void GrDrawPathRangeOp::onExecute(GrOpFlushState* state) {
    167     const Draw& head = *fDraws.head();
    168 
    169     SkMatrix drawMatrix(this->viewMatrix());
    170     drawMatrix.preScale(fScale, fScale);
    171     drawMatrix.preTranslate(head.fX, head.fY);
    172 
    173     SkMatrix localMatrix;
    174     localMatrix.setScale(fScale, fScale);
    175     localMatrix.preTranslate(head.fX, head.fY);
    176 
    177     sk_sp<GrPathProcessor> pathProc(
    178             GrPathProcessor::Create(this->color(), drawMatrix, localMatrix));
    179 
    180     GrPipeline pipeline(this->pipelineInitArgs(*state), this->detachProcessors(),
    181                         state->detachAppliedClip());
    182     GrStencilSettings stencil;
    183     init_stencil_pass_settings(*state, this->fillType(), &stencil);
    184     if (fDraws.count() == 1) {
    185         const InstanceData& instances = *head.fInstanceData;
    186         state->gpu()->pathRendering()->drawPaths(pipeline,
    187                                                  *pathProc,
    188                                                  stencil,
    189                                                  fPathRange.get(),
    190                                                  instances.indices(),
    191                                                  GrPathRange::kU16_PathIndexType,
    192                                                  instances.transformValues(),
    193                                                  instances.transformType(),
    194                                                  instances.count());
    195     } else {
    196         int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
    197         SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
    198         SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
    199         int idx = 0;
    200         for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
    201             const Draw& draw = *iter.get();
    202             const InstanceData& instances = *draw.fInstanceData;
    203             memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t));
    204             pre_translate_transform_values(instances.transformValues(), this->transformType(),
    205                                            instances.count(), draw.fX - head.fX, draw.fY - head.fY,
    206                                            &transformStorage[floatsPerTransform * idx]);
    207             idx += instances.count();
    208 
    209             // TODO: Support mismatched transform types if we start using more types other than 2D.
    210             SkASSERT(instances.transformType() == this->transformType());
    211         }
    212         SkASSERT(idx == fTotalPathCount);
    213 
    214         state->gpu()->pathRendering()->drawPaths(pipeline,
    215                                                  *pathProc,
    216                                                  stencil,
    217                                                  fPathRange.get(),
    218                                                  indexStorage,
    219                                                  GrPathRange::kU16_PathIndexType,
    220                                                  transformStorage,
    221                                                  this->transformType(),
    222                                                  fTotalPathCount);
    223     }
    224 }
    225 
    226 inline void pre_translate_transform_values(const float* xforms,
    227                                            GrPathRendering::PathTransformType type, int count,
    228                                            SkScalar x, SkScalar y, float* dst) {
    229     if (0 == x && 0 == y) {
    230         memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
    231         return;
    232     }
    233     switch (type) {
    234         case GrPathRendering::kNone_PathTransformType:
    235             SK_ABORT("Cannot pre-translate kNone_PathTransformType.");
    236             break;
    237         case GrPathRendering::kTranslateX_PathTransformType:
    238             SkASSERT(0 == y);
    239             for (int i = 0; i < count; i++) {
    240                 dst[i] = xforms[i] + x;
    241             }
    242             break;
    243         case GrPathRendering::kTranslateY_PathTransformType:
    244             SkASSERT(0 == x);
    245             for (int i = 0; i < count; i++) {
    246                 dst[i] = xforms[i] + y;
    247             }
    248             break;
    249         case GrPathRendering::kTranslate_PathTransformType:
    250             for (int i = 0; i < 2 * count; i += 2) {
    251                 dst[i] = xforms[i] + x;
    252                 dst[i + 1] = xforms[i + 1] + y;
    253             }
    254             break;
    255         case GrPathRendering::kAffine_PathTransformType:
    256             for (int i = 0; i < 6 * count; i += 6) {
    257                 dst[i] = xforms[i];
    258                 dst[i + 1] = xforms[i + 1];
    259                 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
    260                 dst[i + 3] = xforms[i + 3];
    261                 dst[i + 4] = xforms[i + 4];
    262                 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
    263             }
    264             break;
    265         default:
    266             SK_ABORT("Unknown transform type.");
    267             break;
    268     }
    269 }
    270