1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * Copyright 2017 ARM Ltd. 4cb93a386Sopenharmony_ci * 5cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 6cb93a386Sopenharmony_ci * found in the LICENSE file. 7cb93a386Sopenharmony_ci */ 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci#include "src/gpu/ops/SmallPathRenderer.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 12cb93a386Sopenharmony_ci#include "src/core/SkAutoPixmapStorage.h" 13cb93a386Sopenharmony_ci#include "src/core/SkDistanceFieldGen.h" 14cb93a386Sopenharmony_ci#include "src/core/SkDraw.h" 15cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 16cb93a386Sopenharmony_ci#include "src/core/SkMatrixProvider.h" 17cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h" 18cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 19cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrBuffer.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrDistanceFieldGenFromVector.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 25cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBitmapTextGeoProc.h" 26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDistanceFieldGeoProc.h" 27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuad.h" 28cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 29cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 30cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 31cb93a386Sopenharmony_ci#include "src/gpu/ops/SmallPathAtlasMgr.h" 32cb93a386Sopenharmony_ci#include "src/gpu/ops/SmallPathShapeData.h" 33cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_cinamespace skgpu::v1 { 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cinamespace { 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci// mip levels 40cb93a386Sopenharmony_cistatic constexpr SkScalar kIdealMinMIP = 12; 41cb93a386Sopenharmony_cistatic constexpr SkScalar kMaxMIP = 162; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistatic constexpr SkScalar kMaxDim = 73; 44cb93a386Sopenharmony_cistatic constexpr SkScalar kMinSize = SK_ScalarHalf; 45cb93a386Sopenharmony_cistatic constexpr SkScalar kMaxSize = 2*kMaxMIP; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci// padding around path bounds to allow for antialiased pixels 50cb93a386Sopenharmony_cistatic const int kAntiAliasPad = 1; 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ciclass SmallPathOp final : public GrMeshDrawOp { 53cb93a386Sopenharmony_ciprivate: 54cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_cipublic: 57cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 60cb93a386Sopenharmony_ci GrPaint&& paint, 61cb93a386Sopenharmony_ci const GrStyledShape& shape, 62cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 63cb93a386Sopenharmony_ci bool gammaCorrect, 64cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 65cb93a386Sopenharmony_ci return Helper::FactoryHelper<SmallPathOp>(context, std::move(paint), shape, viewMatrix, 66cb93a386Sopenharmony_ci gammaCorrect, stencilSettings); 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci SmallPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const GrStyledShape& shape, 70cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, bool gammaCorrect, 71cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) 72cb93a386Sopenharmony_ci : INHERITED(ClassID()) 73cb93a386Sopenharmony_ci , fHelper(processorSet, GrAAType::kCoverage, stencilSettings) { 74cb93a386Sopenharmony_ci SkASSERT(shape.hasUnstyledKey()); 75cb93a386Sopenharmony_ci // Compute bounds 76cb93a386Sopenharmony_ci this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsHairline::kNo); 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) 79cb93a386Sopenharmony_ci fUsesDistanceField = true; 80cb93a386Sopenharmony_ci#else 81cb93a386Sopenharmony_ci // only use distance fields on desktop and Android framework to save space in the atlas 82cb93a386Sopenharmony_ci fUsesDistanceField = this->bounds().width() > kMaxMIP || this->bounds().height() > kMaxMIP; 83cb93a386Sopenharmony_ci#endif 84cb93a386Sopenharmony_ci // always use distance fields if in perspective 85cb93a386Sopenharmony_ci fUsesDistanceField = fUsesDistanceField || viewMatrix.hasPerspective(); 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci fShapes.emplace_back(Entry{color, shape, viewMatrix}); 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci fGammaCorrect = gammaCorrect; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci const char* name() const override { return "SmallPathOp"; } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 95cb93a386Sopenharmony_ci fHelper.visitProxies(func); 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 101cb93a386Sopenharmony_ci GrClampType clampType) override { 102cb93a386Sopenharmony_ci return fHelper.finalizeProcessors(caps, clip, clampType, 103cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage::kSingleChannel, 104cb93a386Sopenharmony_ci &fShapes.front().fColor, &fWideColor); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ciprivate: 108cb93a386Sopenharmony_ci struct FlushInfo { 109cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fVertexBuffer; 110cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fIndexBuffer; 111cb93a386Sopenharmony_ci GrGeometryProcessor* fGeometryProcessor; 112cb93a386Sopenharmony_ci const GrSurfaceProxy** fPrimProcProxies; 113cb93a386Sopenharmony_ci int fVertexOffset; 114cb93a386Sopenharmony_ci int fInstancesToFlush; 115cb93a386Sopenharmony_ci }; 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { 118cb93a386Sopenharmony_ci // TODO [PI]: implement 119cb93a386Sopenharmony_ci return nullptr; 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps*, 123cb93a386Sopenharmony_ci SkArenaAlloc*, 124cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 125cb93a386Sopenharmony_ci bool usesMSAASurface, 126cb93a386Sopenharmony_ci GrAppliedClip&&, 127cb93a386Sopenharmony_ci const GrDstProxyView&, 128cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 129cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 130cb93a386Sopenharmony_ci // We cannot surface the SmallPathOp's programInfo at record time. As currently 131cb93a386Sopenharmony_ci // implemented, the GP is modified at flush time based on the number of pages in the 132cb93a386Sopenharmony_ci // atlas. 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci void onPrePrepareDraws(GrRecordingContext*, 136cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 137cb93a386Sopenharmony_ci GrAppliedClip*, 138cb93a386Sopenharmony_ci const GrDstProxyView&, 139cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 140cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 141cb93a386Sopenharmony_ci // TODO [PI]: implement 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 145cb93a386Sopenharmony_ci int instanceCount = fShapes.count(); 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci auto atlasMgr = target->smallPathAtlasManager(); 148cb93a386Sopenharmony_ci if (!atlasMgr) { 149cb93a386Sopenharmony_ci return; 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures; 153cb93a386Sopenharmony_ci static_assert(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures); 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci FlushInfo flushInfo; 156cb93a386Sopenharmony_ci flushInfo.fPrimProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci int numActiveProxies; 159cb93a386Sopenharmony_ci const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies); 160cb93a386Sopenharmony_ci for (int i = 0; i < numActiveProxies; ++i) { 161cb93a386Sopenharmony_ci // This op does not know its atlas proxies when it is added to a OpsTasks, so the 162cb93a386Sopenharmony_ci // proxies don't get added during the visitProxies call. Thus we add them here. 163cb93a386Sopenharmony_ci flushInfo.fPrimProcProxies[i] = views[i].proxy(); 164cb93a386Sopenharmony_ci target->sampledProxyArray()->push_back(views[i].proxy()); 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci // Setup GrGeometryProcessor 168cb93a386Sopenharmony_ci const SkMatrix& ctm = fShapes[0].fViewMatrix; 169cb93a386Sopenharmony_ci if (fUsesDistanceField) { 170cb93a386Sopenharmony_ci uint32_t flags = 0; 171cb93a386Sopenharmony_ci // Still need to key off of ctm to pick the right shader for the transformed quad 172cb93a386Sopenharmony_ci flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0; 173cb93a386Sopenharmony_ci flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; 174cb93a386Sopenharmony_ci flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0; 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci const SkMatrix* matrix; 177cb93a386Sopenharmony_ci SkMatrix invert; 178cb93a386Sopenharmony_ci if (ctm.hasPerspective()) { 179cb93a386Sopenharmony_ci matrix = &ctm; 180cb93a386Sopenharmony_ci } else if (fHelper.usesLocalCoords()) { 181cb93a386Sopenharmony_ci if (!ctm.invert(&invert)) { 182cb93a386Sopenharmony_ci return; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci matrix = &invert; 185cb93a386Sopenharmony_ci } else { 186cb93a386Sopenharmony_ci matrix = &SkMatrix::I(); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make( 189cb93a386Sopenharmony_ci target->allocator(), *target->caps().shaderCaps(), *matrix, fWideColor, 190cb93a386Sopenharmony_ci views, numActiveProxies, GrSamplerState::Filter::kLinear, 191cb93a386Sopenharmony_ci flags); 192cb93a386Sopenharmony_ci } else { 193cb93a386Sopenharmony_ci SkMatrix invert; 194cb93a386Sopenharmony_ci if (fHelper.usesLocalCoords()) { 195cb93a386Sopenharmony_ci if (!ctm.invert(&invert)) { 196cb93a386Sopenharmony_ci return; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( 201cb93a386Sopenharmony_ci target->allocator(), *target->caps().shaderCaps(), this->color(), fWideColor, 202cb93a386Sopenharmony_ci views, numActiveProxies, GrSamplerState::Filter::kNearest, 203cb93a386Sopenharmony_ci kA8_GrMaskFormat, invert, false); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci // allocate vertices 207cb93a386Sopenharmony_ci const size_t kVertexStride = flushInfo.fGeometryProcessor->vertexStride(); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci // We need to make sure we don't overflow a 32 bit int when we request space in the 210cb93a386Sopenharmony_ci // makeVertexSpace call below. 211cb93a386Sopenharmony_ci if (instanceCount > SK_MaxS32 / GrResourceProvider::NumVertsPerNonAAQuad()) { 212cb93a386Sopenharmony_ci return; 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci VertexWriter vertices{target->makeVertexSpace( 215cb93a386Sopenharmony_ci kVertexStride, GrResourceProvider::NumVertsPerNonAAQuad() * instanceCount, 216cb93a386Sopenharmony_ci &flushInfo.fVertexBuffer, &flushInfo.fVertexOffset)}; 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci flushInfo.fIndexBuffer = target->resourceProvider()->refNonAAQuadIndexBuffer(); 219cb93a386Sopenharmony_ci if (!vertices || !flushInfo.fIndexBuffer) { 220cb93a386Sopenharmony_ci SkDebugf("Could not allocate vertices\n"); 221cb93a386Sopenharmony_ci return; 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci 224cb93a386Sopenharmony_ci flushInfo.fInstancesToFlush = 0; 225cb93a386Sopenharmony_ci for (int i = 0; i < instanceCount; i++) { 226cb93a386Sopenharmony_ci const Entry& args = fShapes[i]; 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci skgpu::v1::SmallPathShapeData* shapeData; 229cb93a386Sopenharmony_ci if (fUsesDistanceField) { 230cb93a386Sopenharmony_ci // get mip level 231cb93a386Sopenharmony_ci SkScalar maxScale; 232cb93a386Sopenharmony_ci const SkRect& bounds = args.fShape.bounds(); 233cb93a386Sopenharmony_ci if (args.fViewMatrix.hasPerspective()) { 234cb93a386Sopenharmony_ci // approximate the scale since we can't get it from the matrix 235cb93a386Sopenharmony_ci SkRect xformedBounds; 236cb93a386Sopenharmony_ci args.fViewMatrix.mapRect(&xformedBounds, bounds); 237cb93a386Sopenharmony_ci maxScale = SkScalarAbs(std::max(xformedBounds.width() / bounds.width(), 238cb93a386Sopenharmony_ci xformedBounds.height() / bounds.height())); 239cb93a386Sopenharmony_ci } else { 240cb93a386Sopenharmony_ci maxScale = SkScalarAbs(args.fViewMatrix.getMaxScale()); 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci SkScalar maxDim = std::max(bounds.width(), bounds.height()); 243cb93a386Sopenharmony_ci // We try to create the DF at a 2^n scaled path resolution (1/2, 1, 2, 4, etc.) 244cb93a386Sopenharmony_ci // In the majority of cases this will yield a crisper rendering. 245cb93a386Sopenharmony_ci SkScalar mipScale = 1.0f; 246cb93a386Sopenharmony_ci // Our mipscale is the maxScale clamped to the next highest power of 2 247cb93a386Sopenharmony_ci if (maxScale <= SK_ScalarHalf) { 248cb93a386Sopenharmony_ci SkScalar log = SkScalarFloorToScalar(SkScalarLog2(SkScalarInvert(maxScale))); 249cb93a386Sopenharmony_ci mipScale = SkScalarPow(2, -log); 250cb93a386Sopenharmony_ci } else if (maxScale > SK_Scalar1) { 251cb93a386Sopenharmony_ci SkScalar log = SkScalarCeilToScalar(SkScalarLog2(maxScale)); 252cb93a386Sopenharmony_ci mipScale = SkScalarPow(2, log); 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci // Log2 isn't very precise at values close to a power of 2, 255cb93a386Sopenharmony_ci // so add a little tolerance here. A little bit of scaling up is fine. 256cb93a386Sopenharmony_ci SkASSERT(maxScale <= mipScale + SK_ScalarNearlyZero); 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci SkScalar mipSize = mipScale*SkScalarAbs(maxDim); 259cb93a386Sopenharmony_ci // For sizes less than kIdealMinMIP we want to use as large a distance field as we can 260cb93a386Sopenharmony_ci // so we can preserve as much detail as possible. However, we can't scale down more 261cb93a386Sopenharmony_ci // than a 1/4 of the size without artifacts. So the idea is that we pick the mipsize 262cb93a386Sopenharmony_ci // just bigger than the ideal, and then scale down until we are no more than 4x the 263cb93a386Sopenharmony_ci // original mipsize. 264cb93a386Sopenharmony_ci if (mipSize < kIdealMinMIP) { 265cb93a386Sopenharmony_ci SkScalar newMipSize = mipSize; 266cb93a386Sopenharmony_ci do { 267cb93a386Sopenharmony_ci newMipSize *= 2; 268cb93a386Sopenharmony_ci } while (newMipSize < kIdealMinMIP); 269cb93a386Sopenharmony_ci while (newMipSize > 4 * mipSize) { 270cb93a386Sopenharmony_ci newMipSize *= 0.25f; 271cb93a386Sopenharmony_ci } 272cb93a386Sopenharmony_ci mipSize = newMipSize; 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci SkScalar desiredDimension = std::min(mipSize, kMaxMIP); 276cb93a386Sopenharmony_ci int ceilDesiredDimension = SkScalarCeilToInt(desiredDimension); 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci // check to see if df path is cached 279cb93a386Sopenharmony_ci shapeData = atlasMgr->findOrCreate(args.fShape, ceilDesiredDimension); 280cb93a386Sopenharmony_ci if (!shapeData->fAtlasLocator.plotLocator().isValid()) { 281cb93a386Sopenharmony_ci SkScalar scale = desiredDimension / maxDim; 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci if (!this->addDFPathToAtlas(target, 284cb93a386Sopenharmony_ci &flushInfo, 285cb93a386Sopenharmony_ci atlasMgr, 286cb93a386Sopenharmony_ci shapeData, 287cb93a386Sopenharmony_ci args.fShape, 288cb93a386Sopenharmony_ci ceilDesiredDimension, 289cb93a386Sopenharmony_ci scale)) { 290cb93a386Sopenharmony_ci atlasMgr->deleteCacheEntry(shapeData); 291cb93a386Sopenharmony_ci continue; 292cb93a386Sopenharmony_ci } 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci } else { 295cb93a386Sopenharmony_ci // check to see if bitmap path is cached 296cb93a386Sopenharmony_ci shapeData = atlasMgr->findOrCreate(args.fShape, args.fViewMatrix); 297cb93a386Sopenharmony_ci if (!shapeData->fAtlasLocator.plotLocator().isValid()) { 298cb93a386Sopenharmony_ci if (!this->addBMPathToAtlas(target, 299cb93a386Sopenharmony_ci &flushInfo, 300cb93a386Sopenharmony_ci atlasMgr, 301cb93a386Sopenharmony_ci shapeData, 302cb93a386Sopenharmony_ci args.fShape, 303cb93a386Sopenharmony_ci args.fViewMatrix)) { 304cb93a386Sopenharmony_ci atlasMgr->deleteCacheEntry(shapeData); 305cb93a386Sopenharmony_ci continue; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci auto uploadTarget = target->deferredUploadTarget(); 311cb93a386Sopenharmony_ci atlasMgr->setUseToken(shapeData, uploadTarget->tokenTracker()->nextDrawToken()); 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci this->writePathVertices(vertices, GrVertexColor(args.fColor, fWideColor), 314cb93a386Sopenharmony_ci args.fViewMatrix, shapeData); 315cb93a386Sopenharmony_ci flushInfo.fInstancesToFlush++; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci this->flush(target, &flushInfo); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci bool addToAtlasWithRetry(GrMeshDrawTarget* target, 322cb93a386Sopenharmony_ci FlushInfo* flushInfo, 323cb93a386Sopenharmony_ci skgpu::v1::SmallPathAtlasMgr* atlasMgr, 324cb93a386Sopenharmony_ci int width, int height, const void* image, 325cb93a386Sopenharmony_ci const SkRect& bounds, int srcInset, 326cb93a386Sopenharmony_ci skgpu::v1::SmallPathShapeData* shapeData) const { 327cb93a386Sopenharmony_ci auto resourceProvider = target->resourceProvider(); 328cb93a386Sopenharmony_ci auto uploadTarget = target->deferredUploadTarget(); 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci auto code = atlasMgr->addToAtlas(resourceProvider, uploadTarget, width, height, 331cb93a386Sopenharmony_ci image, &shapeData->fAtlasLocator); 332cb93a386Sopenharmony_ci if (GrDrawOpAtlas::ErrorCode::kError == code) { 333cb93a386Sopenharmony_ci return false; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) { 337cb93a386Sopenharmony_ci this->flush(target, flushInfo); 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_ci code = atlasMgr->addToAtlas(resourceProvider, uploadTarget, width, height, 340cb93a386Sopenharmony_ci image, &shapeData->fAtlasLocator); 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_ci shapeData->fAtlasLocator.insetSrc(srcInset); 344cb93a386Sopenharmony_ci shapeData->fBounds = bounds; 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci return GrDrawOpAtlas::ErrorCode::kSucceeded == code; 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci 349cb93a386Sopenharmony_ci bool addDFPathToAtlas(GrMeshDrawTarget* target, 350cb93a386Sopenharmony_ci FlushInfo* flushInfo, 351cb93a386Sopenharmony_ci skgpu::v1::SmallPathAtlasMgr* atlasMgr, 352cb93a386Sopenharmony_ci skgpu::v1::SmallPathShapeData* shapeData, 353cb93a386Sopenharmony_ci const GrStyledShape& shape, 354cb93a386Sopenharmony_ci uint32_t dimension, 355cb93a386Sopenharmony_ci SkScalar scale) const { 356cb93a386Sopenharmony_ci 357cb93a386Sopenharmony_ci const SkRect& bounds = shape.bounds(); 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci // generate bounding rect for bitmap draw 360cb93a386Sopenharmony_ci SkRect scaledBounds = bounds; 361cb93a386Sopenharmony_ci // scale to mip level size 362cb93a386Sopenharmony_ci scaledBounds.fLeft *= scale; 363cb93a386Sopenharmony_ci scaledBounds.fTop *= scale; 364cb93a386Sopenharmony_ci scaledBounds.fRight *= scale; 365cb93a386Sopenharmony_ci scaledBounds.fBottom *= scale; 366cb93a386Sopenharmony_ci // subtract out integer portion of origin 367cb93a386Sopenharmony_ci // (SDF created will be placed with fractional offset burnt in) 368cb93a386Sopenharmony_ci SkScalar dx = SkScalarFloorToScalar(scaledBounds.fLeft); 369cb93a386Sopenharmony_ci SkScalar dy = SkScalarFloorToScalar(scaledBounds.fTop); 370cb93a386Sopenharmony_ci scaledBounds.offset(-dx, -dy); 371cb93a386Sopenharmony_ci // get integer boundary 372cb93a386Sopenharmony_ci SkIRect devPathBounds; 373cb93a386Sopenharmony_ci scaledBounds.roundOut(&devPathBounds); 374cb93a386Sopenharmony_ci // place devBounds at origin with padding to allow room for antialiasing 375cb93a386Sopenharmony_ci int width = devPathBounds.width() + 2 * kAntiAliasPad; 376cb93a386Sopenharmony_ci int height = devPathBounds.height() + 2 * kAntiAliasPad; 377cb93a386Sopenharmony_ci devPathBounds = SkIRect::MakeWH(width, height); 378cb93a386Sopenharmony_ci SkScalar translateX = kAntiAliasPad - dx; 379cb93a386Sopenharmony_ci SkScalar translateY = kAntiAliasPad - dy; 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci // draw path to bitmap 382cb93a386Sopenharmony_ci SkMatrix drawMatrix; 383cb93a386Sopenharmony_ci drawMatrix.setScale(scale, scale); 384cb93a386Sopenharmony_ci drawMatrix.postTranslate(translateX, translateY); 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci SkASSERT(devPathBounds.fLeft == 0); 387cb93a386Sopenharmony_ci SkASSERT(devPathBounds.fTop == 0); 388cb93a386Sopenharmony_ci SkASSERT(devPathBounds.width() > 0); 389cb93a386Sopenharmony_ci SkASSERT(devPathBounds.height() > 0); 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_ci // setup signed distance field storage 392cb93a386Sopenharmony_ci SkIRect dfBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK_DistanceFieldPad); 393cb93a386Sopenharmony_ci width = dfBounds.width(); 394cb93a386Sopenharmony_ci height = dfBounds.height(); 395cb93a386Sopenharmony_ci // TODO We should really generate this directly into the plot somehow 396cb93a386Sopenharmony_ci SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char)); 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_ci SkPath path; 399cb93a386Sopenharmony_ci shape.asPath(&path); 400cb93a386Sopenharmony_ci // Generate signed distance field directly from SkPath 401cb93a386Sopenharmony_ci bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage.get(), 402cb93a386Sopenharmony_ci path, drawMatrix, width, height, 403cb93a386Sopenharmony_ci width * sizeof(unsigned char)); 404cb93a386Sopenharmony_ci if (!succeed) { 405cb93a386Sopenharmony_ci // setup bitmap backing 406cb93a386Sopenharmony_ci SkAutoPixmapStorage dst; 407cb93a386Sopenharmony_ci if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), devPathBounds.height()))) { 408cb93a386Sopenharmony_ci return false; 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci sk_bzero(dst.writable_addr(), dst.computeByteSize()); 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci // rasterize path 413cb93a386Sopenharmony_ci SkPaint paint; 414cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 415cb93a386Sopenharmony_ci paint.setAntiAlias(true); 416cb93a386Sopenharmony_ci 417cb93a386Sopenharmony_ci SkDraw draw; 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci SkRasterClip rasterClip; 420cb93a386Sopenharmony_ci rasterClip.setRect(devPathBounds); 421cb93a386Sopenharmony_ci draw.fRC = &rasterClip; 422cb93a386Sopenharmony_ci SkSimpleMatrixProvider matrixProvider(drawMatrix); 423cb93a386Sopenharmony_ci draw.fMatrixProvider = &matrixProvider; 424cb93a386Sopenharmony_ci draw.fDst = dst; 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ci draw.drawPathCoverage(path, paint); 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci // Generate signed distance field 429cb93a386Sopenharmony_ci SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(), 430cb93a386Sopenharmony_ci (const unsigned char*)dst.addr(), 431cb93a386Sopenharmony_ci dst.width(), dst.height(), dst.rowBytes()); 432cb93a386Sopenharmony_ci } 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci SkRect drawBounds = SkRect::Make(devPathBounds).makeOffset(-translateX, -translateY); 435cb93a386Sopenharmony_ci drawBounds.fLeft /= scale; 436cb93a386Sopenharmony_ci drawBounds.fTop /= scale; 437cb93a386Sopenharmony_ci drawBounds.fRight /= scale; 438cb93a386Sopenharmony_ci drawBounds.fBottom /= scale; 439cb93a386Sopenharmony_ci 440cb93a386Sopenharmony_ci return this->addToAtlasWithRetry(target, flushInfo, atlasMgr, 441cb93a386Sopenharmony_ci width, height, dfStorage.get(), 442cb93a386Sopenharmony_ci drawBounds, SK_DistanceFieldPad, shapeData); 443cb93a386Sopenharmony_ci } 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci bool addBMPathToAtlas(GrMeshDrawTarget* target, 446cb93a386Sopenharmony_ci FlushInfo* flushInfo, 447cb93a386Sopenharmony_ci skgpu::v1::SmallPathAtlasMgr* atlasMgr, 448cb93a386Sopenharmony_ci skgpu::v1::SmallPathShapeData* shapeData, 449cb93a386Sopenharmony_ci const GrStyledShape& shape, 450cb93a386Sopenharmony_ci const SkMatrix& ctm) const { 451cb93a386Sopenharmony_ci const SkRect& bounds = shape.bounds(); 452cb93a386Sopenharmony_ci if (bounds.isEmpty()) { 453cb93a386Sopenharmony_ci return false; 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci SkMatrix drawMatrix(ctm); 456cb93a386Sopenharmony_ci SkScalar tx = ctm.getTranslateX(); 457cb93a386Sopenharmony_ci SkScalar ty = ctm.getTranslateY(); 458cb93a386Sopenharmony_ci tx -= SkScalarFloorToScalar(tx); 459cb93a386Sopenharmony_ci ty -= SkScalarFloorToScalar(ty); 460cb93a386Sopenharmony_ci drawMatrix.set(SkMatrix::kMTransX, tx); 461cb93a386Sopenharmony_ci drawMatrix.set(SkMatrix::kMTransY, ty); 462cb93a386Sopenharmony_ci SkRect shapeDevBounds; 463cb93a386Sopenharmony_ci drawMatrix.mapRect(&shapeDevBounds, bounds); 464cb93a386Sopenharmony_ci SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft); 465cb93a386Sopenharmony_ci SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop); 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci // get integer boundary 468cb93a386Sopenharmony_ci SkIRect devPathBounds; 469cb93a386Sopenharmony_ci shapeDevBounds.roundOut(&devPathBounds); 470cb93a386Sopenharmony_ci // place devBounds at origin with padding to allow room for antialiasing 471cb93a386Sopenharmony_ci int width = devPathBounds.width() + 2 * kAntiAliasPad; 472cb93a386Sopenharmony_ci int height = devPathBounds.height() + 2 * kAntiAliasPad; 473cb93a386Sopenharmony_ci devPathBounds = SkIRect::MakeWH(width, height); 474cb93a386Sopenharmony_ci SkScalar translateX = kAntiAliasPad - dx; 475cb93a386Sopenharmony_ci SkScalar translateY = kAntiAliasPad - dy; 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ci SkASSERT(devPathBounds.fLeft == 0); 478cb93a386Sopenharmony_ci SkASSERT(devPathBounds.fTop == 0); 479cb93a386Sopenharmony_ci SkASSERT(devPathBounds.width() > 0); 480cb93a386Sopenharmony_ci SkASSERT(devPathBounds.height() > 0); 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci SkPath path; 483cb93a386Sopenharmony_ci shape.asPath(&path); 484cb93a386Sopenharmony_ci // setup bitmap backing 485cb93a386Sopenharmony_ci SkAutoPixmapStorage dst; 486cb93a386Sopenharmony_ci if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), devPathBounds.height()))) { 487cb93a386Sopenharmony_ci return false; 488cb93a386Sopenharmony_ci } 489cb93a386Sopenharmony_ci sk_bzero(dst.writable_addr(), dst.computeByteSize()); 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_ci // rasterize path 492cb93a386Sopenharmony_ci SkPaint paint; 493cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 494cb93a386Sopenharmony_ci paint.setAntiAlias(true); 495cb93a386Sopenharmony_ci 496cb93a386Sopenharmony_ci SkDraw draw; 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci SkRasterClip rasterClip; 499cb93a386Sopenharmony_ci rasterClip.setRect(devPathBounds); 500cb93a386Sopenharmony_ci draw.fRC = &rasterClip; 501cb93a386Sopenharmony_ci drawMatrix.postTranslate(translateX, translateY); 502cb93a386Sopenharmony_ci SkSimpleMatrixProvider matrixProvider(drawMatrix); 503cb93a386Sopenharmony_ci draw.fMatrixProvider = &matrixProvider; 504cb93a386Sopenharmony_ci draw.fDst = dst; 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci draw.drawPathCoverage(path, paint); 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci SkRect drawBounds = SkRect::Make(devPathBounds).makeOffset(-translateX, -translateY); 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_ci return this->addToAtlasWithRetry(target, flushInfo, atlasMgr, 511cb93a386Sopenharmony_ci dst.width(), dst.height(), dst.addr(), 512cb93a386Sopenharmony_ci drawBounds, 0, shapeData); 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci void writePathVertices(VertexWriter& vertices, 516cb93a386Sopenharmony_ci const GrVertexColor& color, 517cb93a386Sopenharmony_ci const SkMatrix& ctm, 518cb93a386Sopenharmony_ci const skgpu::v1::SmallPathShapeData* shapeData) const { 519cb93a386Sopenharmony_ci SkRect translatedBounds(shapeData->fBounds); 520cb93a386Sopenharmony_ci if (!fUsesDistanceField) { 521cb93a386Sopenharmony_ci translatedBounds.offset(SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransX)), 522cb93a386Sopenharmony_ci SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransY))); 523cb93a386Sopenharmony_ci } 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci // set up texture coordinates 526cb93a386Sopenharmony_ci auto texCoords = VertexWriter::TriStripFromUVs(shapeData->fAtlasLocator.getUVs()); 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci if (fUsesDistanceField && !ctm.hasPerspective()) { 529cb93a386Sopenharmony_ci vertices.writeQuad(GrQuad::MakeFromRect(translatedBounds, ctm), 530cb93a386Sopenharmony_ci color, 531cb93a386Sopenharmony_ci texCoords); 532cb93a386Sopenharmony_ci } else { 533cb93a386Sopenharmony_ci vertices.writeQuad(VertexWriter::TriStripFromRect(translatedBounds), 534cb93a386Sopenharmony_ci color, 535cb93a386Sopenharmony_ci texCoords); 536cb93a386Sopenharmony_ci } 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci 539cb93a386Sopenharmony_ci void flush(GrMeshDrawTarget* target, FlushInfo* flushInfo) const { 540cb93a386Sopenharmony_ci auto atlasMgr = target->smallPathAtlasManager(); 541cb93a386Sopenharmony_ci if (!atlasMgr) { 542cb93a386Sopenharmony_ci return; 543cb93a386Sopenharmony_ci } 544cb93a386Sopenharmony_ci 545cb93a386Sopenharmony_ci int numActiveProxies; 546cb93a386Sopenharmony_ci const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies); 547cb93a386Sopenharmony_ci 548cb93a386Sopenharmony_ci GrGeometryProcessor* gp = flushInfo->fGeometryProcessor; 549cb93a386Sopenharmony_ci if (gp->numTextureSamplers() != numActiveProxies) { 550cb93a386Sopenharmony_ci for (int i = gp->numTextureSamplers(); i < numActiveProxies; ++i) { 551cb93a386Sopenharmony_ci flushInfo->fPrimProcProxies[i] = views[i].proxy(); 552cb93a386Sopenharmony_ci // This op does not know its atlas proxies when it is added to a OpsTasks, so the 553cb93a386Sopenharmony_ci // proxies don't get added during the visitProxies call. Thus we add them here. 554cb93a386Sopenharmony_ci target->sampledProxyArray()->push_back(views[i].proxy()); 555cb93a386Sopenharmony_ci } 556cb93a386Sopenharmony_ci // During preparation the number of atlas pages has increased. 557cb93a386Sopenharmony_ci // Update the proxies used in the GP to match. 558cb93a386Sopenharmony_ci if (fUsesDistanceField) { 559cb93a386Sopenharmony_ci reinterpret_cast<GrDistanceFieldPathGeoProc*>(gp)->addNewViews( 560cb93a386Sopenharmony_ci views, numActiveProxies, GrSamplerState::Filter::kLinear); 561cb93a386Sopenharmony_ci } else { 562cb93a386Sopenharmony_ci reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews( 563cb93a386Sopenharmony_ci views, numActiveProxies, GrSamplerState::Filter::kNearest); 564cb93a386Sopenharmony_ci } 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci if (flushInfo->fInstancesToFlush) { 568cb93a386Sopenharmony_ci GrSimpleMesh* mesh = target->allocMesh(); 569cb93a386Sopenharmony_ci mesh->setIndexedPatterned(flushInfo->fIndexBuffer, 570cb93a386Sopenharmony_ci GrResourceProvider::NumIndicesPerNonAAQuad(), 571cb93a386Sopenharmony_ci flushInfo->fInstancesToFlush, 572cb93a386Sopenharmony_ci GrResourceProvider::MaxNumNonAAQuads(), 573cb93a386Sopenharmony_ci flushInfo->fVertexBuffer, 574cb93a386Sopenharmony_ci GrResourceProvider::NumVertsPerNonAAQuad(), 575cb93a386Sopenharmony_ci flushInfo->fVertexOffset); 576cb93a386Sopenharmony_ci target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies, 577cb93a386Sopenharmony_ci GrPrimitiveType::kTriangles); 578cb93a386Sopenharmony_ci flushInfo->fVertexOffset += GrResourceProvider::NumVertsPerNonAAQuad() * 579cb93a386Sopenharmony_ci flushInfo->fInstancesToFlush; 580cb93a386Sopenharmony_ci flushInfo->fInstancesToFlush = 0; 581cb93a386Sopenharmony_ci } 582cb93a386Sopenharmony_ci } 583cb93a386Sopenharmony_ci 584cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 585cb93a386Sopenharmony_ci auto pipeline = fHelper.createPipeline(flushState); 586cb93a386Sopenharmony_ci 587cb93a386Sopenharmony_ci flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline, 588cb93a386Sopenharmony_ci fHelper.stencilSettings()); 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci 591cb93a386Sopenharmony_ci const SkPMColor4f& color() const { return fShapes[0].fColor; } 592cb93a386Sopenharmony_ci bool usesDistanceField() const { return fUsesDistanceField; } 593cb93a386Sopenharmony_ci 594cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 595cb93a386Sopenharmony_ci SmallPathOp* that = t->cast<SmallPathOp>(); 596cb93a386Sopenharmony_ci if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 597cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 598cb93a386Sopenharmony_ci } 599cb93a386Sopenharmony_ci 600cb93a386Sopenharmony_ci if (this->usesDistanceField() != that->usesDistanceField()) { 601cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_ci const SkMatrix& thisCtm = this->fShapes[0].fViewMatrix; 605cb93a386Sopenharmony_ci const SkMatrix& thatCtm = that->fShapes[0].fViewMatrix; 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_ci if (thisCtm.hasPerspective() != thatCtm.hasPerspective()) { 608cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci // We can position on the cpu unless we're in perspective, 612cb93a386Sopenharmony_ci // but also need to make sure local matrices are identical 613cb93a386Sopenharmony_ci if ((thisCtm.hasPerspective() || fHelper.usesLocalCoords()) && 614cb93a386Sopenharmony_ci !SkMatrixPriv::CheapEqual(thisCtm, thatCtm)) { 615cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 616cb93a386Sopenharmony_ci } 617cb93a386Sopenharmony_ci 618cb93a386Sopenharmony_ci // Depending on the ctm we may have a different shader for SDF paths 619cb93a386Sopenharmony_ci if (this->usesDistanceField()) { 620cb93a386Sopenharmony_ci if (thisCtm.isScaleTranslate() != thatCtm.isScaleTranslate() || 621cb93a386Sopenharmony_ci thisCtm.isSimilarity() != thatCtm.isSimilarity()) { 622cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 623cb93a386Sopenharmony_ci } 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin()); 627cb93a386Sopenharmony_ci fWideColor |= that->fWideColor; 628cb93a386Sopenharmony_ci return CombineResult::kMerged; 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_ci#if GR_TEST_UTILS 632cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 633cb93a386Sopenharmony_ci SkString string; 634cb93a386Sopenharmony_ci for (const auto& geo : fShapes) { 635cb93a386Sopenharmony_ci string.appendf("Color: 0x%08x\n", geo.fColor.toBytes_RGBA()); 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci string += fHelper.dumpInfo(); 638cb93a386Sopenharmony_ci return string; 639cb93a386Sopenharmony_ci } 640cb93a386Sopenharmony_ci#endif 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci bool fUsesDistanceField; 643cb93a386Sopenharmony_ci 644cb93a386Sopenharmony_ci struct Entry { 645cb93a386Sopenharmony_ci SkPMColor4f fColor; 646cb93a386Sopenharmony_ci GrStyledShape fShape; 647cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 648cb93a386Sopenharmony_ci }; 649cb93a386Sopenharmony_ci 650cb93a386Sopenharmony_ci SkSTArray<1, Entry> fShapes; 651cb93a386Sopenharmony_ci Helper fHelper; 652cb93a386Sopenharmony_ci bool fGammaCorrect; 653cb93a386Sopenharmony_ci bool fWideColor; 654cb93a386Sopenharmony_ci 655cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 656cb93a386Sopenharmony_ci}; 657cb93a386Sopenharmony_ci 658cb93a386Sopenharmony_ci} // anonymous namespace 659cb93a386Sopenharmony_ci 660cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 661cb93a386Sopenharmony_ci 662cb93a386Sopenharmony_ciPathRenderer::CanDrawPath SmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 663cb93a386Sopenharmony_ci if (!args.fCaps->shaderCaps()->shaderDerivativeSupport()) { 664cb93a386Sopenharmony_ci return CanDrawPath::kNo; 665cb93a386Sopenharmony_ci } 666cb93a386Sopenharmony_ci // If the shape has no key then we won't get any reuse. 667cb93a386Sopenharmony_ci if (!args.fShape->hasUnstyledKey()) { 668cb93a386Sopenharmony_ci return CanDrawPath::kNo; 669cb93a386Sopenharmony_ci } 670cb93a386Sopenharmony_ci // This only supports filled paths, however, the caller may apply the style to make a filled 671cb93a386Sopenharmony_ci // path and try again. 672cb93a386Sopenharmony_ci if (!args.fShape->style().isSimpleFill()) { 673cb93a386Sopenharmony_ci return CanDrawPath::kNo; 674cb93a386Sopenharmony_ci } 675cb93a386Sopenharmony_ci // This does non-inverse coverage-based antialiased fills. 676cb93a386Sopenharmony_ci if (GrAAType::kCoverage != args.fAAType) { 677cb93a386Sopenharmony_ci return CanDrawPath::kNo; 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci // TODO: Support inverse fill 680cb93a386Sopenharmony_ci if (args.fShape->inverseFilled()) { 681cb93a386Sopenharmony_ci return CanDrawPath::kNo; 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci SkScalar scaleFactors[2] = { 1, 1 }; 685cb93a386Sopenharmony_ci // TODO: handle perspective distortion 686cb93a386Sopenharmony_ci if (!args.fViewMatrix->hasPerspective() && !args.fViewMatrix->getMinMaxScales(scaleFactors)) { 687cb93a386Sopenharmony_ci return CanDrawPath::kNo; 688cb93a386Sopenharmony_ci } 689cb93a386Sopenharmony_ci // For affine transformations, too much shear can produce artifacts. 690cb93a386Sopenharmony_ci if (!scaleFactors[0] || scaleFactors[1]/scaleFactors[0] > 4) { 691cb93a386Sopenharmony_ci return CanDrawPath::kNo; 692cb93a386Sopenharmony_ci } 693cb93a386Sopenharmony_ci // Only support paths with bounds within kMaxDim by kMaxDim, 694cb93a386Sopenharmony_ci // scaled to have bounds within kMaxSize by kMaxSize. 695cb93a386Sopenharmony_ci // The goal is to accelerate rendering of lots of small paths that may be scaling. 696cb93a386Sopenharmony_ci SkRect bounds = args.fShape->styledBounds(); 697cb93a386Sopenharmony_ci SkScalar minDim = std::min(bounds.width(), bounds.height()); 698cb93a386Sopenharmony_ci SkScalar maxDim = std::max(bounds.width(), bounds.height()); 699cb93a386Sopenharmony_ci SkScalar minSize = minDim * SkScalarAbs(scaleFactors[0]); 700cb93a386Sopenharmony_ci SkScalar maxSize = maxDim * SkScalarAbs(scaleFactors[1]); 701cb93a386Sopenharmony_ci if (maxDim > kMaxDim || kMinSize > minSize || maxSize > kMaxSize) { 702cb93a386Sopenharmony_ci return CanDrawPath::kNo; 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_ci return CanDrawPath::kYes; 706cb93a386Sopenharmony_ci} 707cb93a386Sopenharmony_ci 708cb93a386Sopenharmony_cibool SmallPathRenderer::onDrawPath(const DrawPathArgs& args) { 709cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 710cb93a386Sopenharmony_ci "SmallPathRenderer::onDrawPath"); 711cb93a386Sopenharmony_ci 712cb93a386Sopenharmony_ci // we've already bailed on inverse filled paths, so this is safe 713cb93a386Sopenharmony_ci SkASSERT(!args.fShape->isEmpty()); 714cb93a386Sopenharmony_ci SkASSERT(args.fShape->hasUnstyledKey()); 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci GrOp::Owner op = SmallPathOp::Make( 717cb93a386Sopenharmony_ci args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, 718cb93a386Sopenharmony_ci args.fGammaCorrect, args.fUserStencilSettings); 719cb93a386Sopenharmony_ci args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op)); 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci return true; 722cb93a386Sopenharmony_ci} 723cb93a386Sopenharmony_ci 724cb93a386Sopenharmony_ci} // namespace skgpu::v1 725cb93a386Sopenharmony_ci 726cb93a386Sopenharmony_ci#if GR_TEST_UTILS 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(SmallPathOp) { 729cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrix(random); 730cb93a386Sopenharmony_ci bool gammaCorrect = random->nextBool(); 731cb93a386Sopenharmony_ci 732cb93a386Sopenharmony_ci // This path renderer only allows fill styles. 733cb93a386Sopenharmony_ci GrStyledShape shape(GrTest::TestPath(random), GrStyle::SimpleFill()); 734cb93a386Sopenharmony_ci return skgpu::v1::SmallPathOp::Make(context, std::move(paint), shape, viewMatrix, gammaCorrect, 735cb93a386Sopenharmony_ci GrGetRandomStencil(random, context)); 736cb93a386Sopenharmony_ci} 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci#endif // GR_TEST_UTILS 739