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