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