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