1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/ops/SoftwarePathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 11cb93a386Sopenharmony_ci#include "include/private/SkSemaphore.h" 12cb93a386Sopenharmony_ci#include "src/core/SkTaskGroup.h" 13cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrDeferredProxyUploader.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrGpuResourcePriv.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrProxyProvider.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrSWMaskHelper.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrUtil.h" 25cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 28cb93a386Sopenharmony_ci#include "src/gpu/ops/GrDrawOp.h" 29cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_cinamespace { 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci/** 34cb93a386Sopenharmony_ci * Payload class for use with GrTDeferredProxyUploader. The software path renderer only draws 35cb93a386Sopenharmony_ci * a single path into the mask texture. This stores all of the information needed by the worker 36cb93a386Sopenharmony_ci * thread's call to drawShape (see below, in onDrawPath). 37cb93a386Sopenharmony_ci */ 38cb93a386Sopenharmony_ciclass SoftwarePathData { 39cb93a386Sopenharmony_cipublic: 40cb93a386Sopenharmony_ci SoftwarePathData(const SkIRect& maskBounds, const SkMatrix& viewMatrix, 41cb93a386Sopenharmony_ci const GrStyledShape& shape, GrAA aa) 42cb93a386Sopenharmony_ci : fMaskBounds(maskBounds) 43cb93a386Sopenharmony_ci , fViewMatrix(viewMatrix) 44cb93a386Sopenharmony_ci , fShape(shape) 45cb93a386Sopenharmony_ci , fAA(aa) {} 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci const SkIRect& getMaskBounds() const { return fMaskBounds; } 48cb93a386Sopenharmony_ci const SkMatrix* getViewMatrix() const { return &fViewMatrix; } 49cb93a386Sopenharmony_ci const GrStyledShape& getShape() const { return fShape; } 50cb93a386Sopenharmony_ci GrAA getAA() const { return fAA; } 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ciprivate: 53cb93a386Sopenharmony_ci SkIRect fMaskBounds; 54cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 55cb93a386Sopenharmony_ci GrStyledShape fShape; 56cb93a386Sopenharmony_ci GrAA fAA; 57cb93a386Sopenharmony_ci}; 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_cibool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkMatrix& matrix, 60cb93a386Sopenharmony_ci SkIRect* devBounds) { 61cb93a386Sopenharmony_ci SkRect shapeBounds = shape.styledBounds(); 62cb93a386Sopenharmony_ci if (shapeBounds.isEmpty()) { 63cb93a386Sopenharmony_ci return false; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci SkRect shapeDevBounds; 66cb93a386Sopenharmony_ci matrix.mapRect(&shapeDevBounds, shapeBounds); 67cb93a386Sopenharmony_ci // Even though these are "unclipped" bounds we still clip to the int32_t range. 68cb93a386Sopenharmony_ci // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints 69cb93a386Sopenharmony_ci // would round down to this value when cast to a float, but who really cares. 70cb93a386Sopenharmony_ci // INT32_MIN is exactly representable. 71cb93a386Sopenharmony_ci static constexpr int32_t kMaxInt = 2147483520; 72cb93a386Sopenharmony_ci if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) { 73cb93a386Sopenharmony_ci return false; 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci // Make sure that the resulting SkIRect can have representable width and height 76cb93a386Sopenharmony_ci if (SkScalarRoundToInt(shapeDevBounds.width()) > kMaxInt || 77cb93a386Sopenharmony_ci SkScalarRoundToInt(shapeDevBounds.height()) > kMaxInt) { 78cb93a386Sopenharmony_ci return false; 79cb93a386Sopenharmony_ci } 80cb93a386Sopenharmony_ci shapeDevBounds.roundOut(devBounds); 81cb93a386Sopenharmony_ci return true; 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ciGrSurfaceProxyView make_deferred_mask_texture_view(GrRecordingContext* rContext, 85cb93a386Sopenharmony_ci SkBackingFit fit, 86cb93a386Sopenharmony_ci SkISize dimensions) { 87cb93a386Sopenharmony_ci GrProxyProvider* proxyProvider = rContext->priv().proxyProvider(); 88cb93a386Sopenharmony_ci const GrCaps* caps = rContext->priv().caps(); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kAlpha_8, 91cb93a386Sopenharmony_ci GrRenderable::kNo); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci GrSwizzle swizzle = caps->getReadSwizzle(format, GrColorType::kAlpha_8); 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci auto proxy = 96cb93a386Sopenharmony_ci proxyProvider->createProxy(format, dimensions, GrRenderable::kNo, 1, GrMipmapped::kNo, 97cb93a386Sopenharmony_ci fit, SkBudgeted::kYes, GrProtected::kNo); 98cb93a386Sopenharmony_ci return {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci} // anonymous namespace 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_cinamespace skgpu::v1 { 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 107cb93a386Sopenharmony_ciPathRenderer::CanDrawPath SoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 108cb93a386Sopenharmony_ci // Pass on any style that applies. The caller will apply the style if a suitable renderer is 109cb93a386Sopenharmony_ci // not found and try again with the new GrStyledShape. 110cb93a386Sopenharmony_ci if (!args.fShape->style().applies() && SkToBool(fProxyProvider) && 111cb93a386Sopenharmony_ci (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone)) { 112cb93a386Sopenharmony_ci // This is the fallback renderer for when a path is too complicated for the GPU ones. 113cb93a386Sopenharmony_ci return CanDrawPath::kAsBackup; 114cb93a386Sopenharmony_ci } 115cb93a386Sopenharmony_ci return CanDrawPath::kNo; 116cb93a386Sopenharmony_ci} 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci// Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there 121cb93a386Sopenharmony_ci// is no intersection. 122cb93a386Sopenharmony_cibool SoftwarePathRenderer::GetShapeAndClipBounds(SurfaceDrawContext* sdc, 123cb93a386Sopenharmony_ci const GrClip* clip, 124cb93a386Sopenharmony_ci const GrStyledShape& shape, 125cb93a386Sopenharmony_ci const SkMatrix& matrix, 126cb93a386Sopenharmony_ci SkIRect* unclippedDevShapeBounds, 127cb93a386Sopenharmony_ci SkIRect* clippedDevShapeBounds, 128cb93a386Sopenharmony_ci SkIRect* devClipBounds) { 129cb93a386Sopenharmony_ci // compute bounds as intersection of rt size, clip, and path 130cb93a386Sopenharmony_ci *devClipBounds = clip ? clip->getConservativeBounds() 131cb93a386Sopenharmony_ci : SkIRect::MakeWH(sdc->width(), sdc->height()); 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) { 134cb93a386Sopenharmony_ci *unclippedDevShapeBounds = SkIRect::MakeEmpty(); 135cb93a386Sopenharmony_ci *clippedDevShapeBounds = SkIRect::MakeEmpty(); 136cb93a386Sopenharmony_ci return false; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci if (!clippedDevShapeBounds->intersect(*devClipBounds, *unclippedDevShapeBounds)) { 139cb93a386Sopenharmony_ci *clippedDevShapeBounds = SkIRect::MakeEmpty(); 140cb93a386Sopenharmony_ci return false; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci return true; 143cb93a386Sopenharmony_ci} 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawNonAARect(SurfaceDrawContext* sdc, 148cb93a386Sopenharmony_ci GrPaint&& paint, 149cb93a386Sopenharmony_ci const GrUserStencilSettings& userStencilSettings, 150cb93a386Sopenharmony_ci const GrClip* clip, 151cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 152cb93a386Sopenharmony_ci const SkRect& rect, 153cb93a386Sopenharmony_ci const SkMatrix& localMatrix) { 154cb93a386Sopenharmony_ci sdc->stencilRect(clip, &userStencilSettings, std::move(paint), GrAA::kNo, 155cb93a386Sopenharmony_ci viewMatrix, rect, &localMatrix); 156cb93a386Sopenharmony_ci} 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawAroundInvPath(SurfaceDrawContext* sdc, 159cb93a386Sopenharmony_ci GrPaint&& paint, 160cb93a386Sopenharmony_ci const GrUserStencilSettings& userStencilSettings, 161cb93a386Sopenharmony_ci const GrClip* clip, 162cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 163cb93a386Sopenharmony_ci const SkIRect& devClipBounds, 164cb93a386Sopenharmony_ci const SkIRect& devPathBounds) { 165cb93a386Sopenharmony_ci SkMatrix invert; 166cb93a386Sopenharmony_ci if (!viewMatrix.invert(&invert)) { 167cb93a386Sopenharmony_ci return; 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci SkRect rect; 171cb93a386Sopenharmony_ci if (devClipBounds.fTop < devPathBounds.fTop) { 172cb93a386Sopenharmony_ci rect.setLTRB(SkIntToScalar(devClipBounds.fLeft), SkIntToScalar(devClipBounds.fTop), 173cb93a386Sopenharmony_ci SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devPathBounds.fTop)); 174cb93a386Sopenharmony_ci DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip, 175cb93a386Sopenharmony_ci SkMatrix::I(), rect, invert); 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci if (devClipBounds.fLeft < devPathBounds.fLeft) { 178cb93a386Sopenharmony_ci rect.setLTRB(SkIntToScalar(devClipBounds.fLeft), SkIntToScalar(devPathBounds.fTop), 179cb93a386Sopenharmony_ci SkIntToScalar(devPathBounds.fLeft), SkIntToScalar(devPathBounds.fBottom)); 180cb93a386Sopenharmony_ci DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip, 181cb93a386Sopenharmony_ci SkMatrix::I(), rect, invert); 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci if (devClipBounds.fRight > devPathBounds.fRight) { 184cb93a386Sopenharmony_ci rect.setLTRB(SkIntToScalar(devPathBounds.fRight), SkIntToScalar(devPathBounds.fTop), 185cb93a386Sopenharmony_ci SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devPathBounds.fBottom)); 186cb93a386Sopenharmony_ci DrawNonAARect(sdc, GrPaint::Clone(paint), userStencilSettings, clip, 187cb93a386Sopenharmony_ci SkMatrix::I(), rect, invert); 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci if (devClipBounds.fBottom > devPathBounds.fBottom) { 190cb93a386Sopenharmony_ci rect.setLTRB(SkIntToScalar(devClipBounds.fLeft), SkIntToScalar(devPathBounds.fBottom), 191cb93a386Sopenharmony_ci SkIntToScalar(devClipBounds.fRight), SkIntToScalar(devClipBounds.fBottom)); 192cb93a386Sopenharmony_ci DrawNonAARect(sdc, std::move(paint), userStencilSettings, clip, 193cb93a386Sopenharmony_ci SkMatrix::I(), rect, invert); 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci} 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_civoid SoftwarePathRenderer::DrawToTargetWithShapeMask( 198cb93a386Sopenharmony_ci GrSurfaceProxyView view, 199cb93a386Sopenharmony_ci SurfaceDrawContext* sdc, 200cb93a386Sopenharmony_ci GrPaint&& paint, 201cb93a386Sopenharmony_ci const GrUserStencilSettings& userStencilSettings, 202cb93a386Sopenharmony_ci const GrClip* clip, 203cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 204cb93a386Sopenharmony_ci const SkIPoint& textureOriginInDeviceSpace, 205cb93a386Sopenharmony_ci const SkIRect& deviceSpaceRectToDraw) { 206cb93a386Sopenharmony_ci SkMatrix invert; 207cb93a386Sopenharmony_ci if (!viewMatrix.invert(&invert)) { 208cb93a386Sopenharmony_ci return; 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_ci view.concatSwizzle(GrSwizzle("aaaa")); 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw); 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci // We use device coords to compute the texture coordinates. We take the device coords and apply 216cb93a386Sopenharmony_ci // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling 217cb93a386Sopenharmony_ci // matrix to normalized coords. 218cb93a386Sopenharmony_ci SkMatrix maskMatrix = SkMatrix::Translate(SkIntToScalar(-textureOriginInDeviceSpace.fX), 219cb93a386Sopenharmony_ci SkIntToScalar(-textureOriginInDeviceSpace.fY)); 220cb93a386Sopenharmony_ci maskMatrix.preConcat(viewMatrix); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci paint.setCoverageFragmentProcessor(GrTextureEffect::Make( 223cb93a386Sopenharmony_ci std::move(view), kPremul_SkAlphaType, maskMatrix, GrSamplerState::Filter::kNearest)); 224cb93a386Sopenharmony_ci DrawNonAARect(sdc, std::move(paint), userStencilSettings, clip, SkMatrix::I(), 225cb93a386Sopenharmony_ci dstRect, invert); 226cb93a386Sopenharmony_ci} 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 229cb93a386Sopenharmony_ci// return true on success; false on failure 230cb93a386Sopenharmony_cibool SoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { 231cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 232cb93a386Sopenharmony_ci "SoftwarePathRenderer::onDrawPath"); 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci if (!fProxyProvider) { 235cb93a386Sopenharmony_ci return false; 236cb93a386Sopenharmony_ci } 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci SkASSERT(!args.fShape->style().applies()); 239cb93a386Sopenharmony_ci // We really need to know if the shape will be inverse filled or not 240cb93a386Sopenharmony_ci // If the path is hairline, ignore inverse fill. 241cb93a386Sopenharmony_ci bool inverseFilled = args.fShape->inverseFilled() && 242cb93a386Sopenharmony_ci !GrIsStrokeHairlineOrEquivalent(args.fShape->style(), 243cb93a386Sopenharmony_ci *args.fViewMatrix, nullptr); 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_ci SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds; 246cb93a386Sopenharmony_ci // To prevent overloading the cache with entries during animations we limit the cache of masks 247cb93a386Sopenharmony_ci // to cases where the matrix preserves axis alignment. 248cb93a386Sopenharmony_ci bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() && 249cb93a386Sopenharmony_ci args.fShape->hasUnstyledKey() && (GrAAType::kCoverage == args.fAAType); 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci if (!GetShapeAndClipBounds(args.fSurfaceDrawContext, 252cb93a386Sopenharmony_ci args.fClip, *args.fShape, 253cb93a386Sopenharmony_ci *args.fViewMatrix, &unclippedDevShapeBounds, 254cb93a386Sopenharmony_ci &clippedDevShapeBounds, 255cb93a386Sopenharmony_ci &devClipBounds)) { 256cb93a386Sopenharmony_ci if (inverseFilled) { 257cb93a386Sopenharmony_ci DrawAroundInvPath(args.fSurfaceDrawContext, std::move(args.fPaint), 258cb93a386Sopenharmony_ci *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, 259cb93a386Sopenharmony_ci devClipBounds, unclippedDevShapeBounds); 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci return true; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci const SkIRect* boundsForMask = &clippedDevShapeBounds; 265cb93a386Sopenharmony_ci if (useCache) { 266cb93a386Sopenharmony_ci // Use the cache only if >50% of the path is visible. 267cb93a386Sopenharmony_ci int unclippedWidth = unclippedDevShapeBounds.width(); 268cb93a386Sopenharmony_ci int unclippedHeight = unclippedDevShapeBounds.height(); 269cb93a386Sopenharmony_ci int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight); 270cb93a386Sopenharmony_ci int64_t clippedArea = sk_64_mul(clippedDevShapeBounds.width(), 271cb93a386Sopenharmony_ci clippedDevShapeBounds.height()); 272cb93a386Sopenharmony_ci int maxTextureSize = args.fSurfaceDrawContext->caps()->maxTextureSize(); 273cb93a386Sopenharmony_ci if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize || 274cb93a386Sopenharmony_ci unclippedHeight > maxTextureSize) { 275cb93a386Sopenharmony_ci useCache = false; 276cb93a386Sopenharmony_ci } else { 277cb93a386Sopenharmony_ci boundsForMask = &unclippedDevShapeBounds; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci 281cb93a386Sopenharmony_ci GrUniqueKey maskKey; 282cb93a386Sopenharmony_ci if (useCache) { 283cb93a386Sopenharmony_ci // We require the upper left 2x2 of the matrix to match exactly for a cache hit. 284cb93a386Sopenharmony_ci SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX); 285cb93a386Sopenharmony_ci SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY); 286cb93a386Sopenharmony_ci SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX); 287cb93a386Sopenharmony_ci SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY); 288cb93a386Sopenharmony_ci static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 289cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(&maskKey, kDomain, 7 + args.fShape->unstyledKeySize(), 290cb93a386Sopenharmony_ci "SW Path Mask"); 291cb93a386Sopenharmony_ci builder[0] = boundsForMask->width(); 292cb93a386Sopenharmony_ci builder[1] = boundsForMask->height(); 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 295cb93a386Sopenharmony_ci // Fractional translate does not affect caching on Android. This is done for better cache 296cb93a386Sopenharmony_ci // hit ratio and speed, but it is matching HWUI behavior, which doesn't consider the matrix 297cb93a386Sopenharmony_ci // at all when caching paths. 298cb93a386Sopenharmony_ci SkFixed fracX = 0; 299cb93a386Sopenharmony_ci SkFixed fracY = 0; 300cb93a386Sopenharmony_ci#else 301cb93a386Sopenharmony_ci SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX); 302cb93a386Sopenharmony_ci SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY); 303cb93a386Sopenharmony_ci // Allow 8 bits each in x and y of subpixel positioning. 304cb93a386Sopenharmony_ci SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00; 305cb93a386Sopenharmony_ci SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00; 306cb93a386Sopenharmony_ci#endif 307cb93a386Sopenharmony_ci builder[2] = SkFloat2Bits(sx); 308cb93a386Sopenharmony_ci builder[3] = SkFloat2Bits(sy); 309cb93a386Sopenharmony_ci builder[4] = SkFloat2Bits(kx); 310cb93a386Sopenharmony_ci builder[5] = SkFloat2Bits(ky); 311cb93a386Sopenharmony_ci // Distinguish between hairline and filled paths. For hairlines, we also need to include 312cb93a386Sopenharmony_ci // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that 313cb93a386Sopenharmony_ci // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers 314cb93a386Sopenharmony_ci // all cases we might see. 315cb93a386Sopenharmony_ci uint32_t styleBits = args.fShape->style().isSimpleHairline() ? 316cb93a386Sopenharmony_ci ((args.fShape->style().strokeRec().getCap() << 1) | 1) : 0; 317cb93a386Sopenharmony_ci builder[6] = fracX | (fracY >> 8) | (styleBits << 16); 318cb93a386Sopenharmony_ci args.fShape->writeUnstyledKey(&builder[7]); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci GrSurfaceProxyView view; 322cb93a386Sopenharmony_ci if (useCache) { 323cb93a386Sopenharmony_ci sk_sp<GrTextureProxy> proxy = fProxyProvider->findOrCreateProxyByUniqueKey(maskKey); 324cb93a386Sopenharmony_ci if (proxy) { 325cb93a386Sopenharmony_ci GrSwizzle swizzle = args.fSurfaceDrawContext->caps()->getReadSwizzle( 326cb93a386Sopenharmony_ci proxy->backendFormat(), GrColorType::kAlpha_8); 327cb93a386Sopenharmony_ci view = {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; 328cb93a386Sopenharmony_ci args.fContext->priv().stats()->incNumPathMasksCacheHits(); 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci } 331cb93a386Sopenharmony_ci if (!view) { 332cb93a386Sopenharmony_ci SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox; 333cb93a386Sopenharmony_ci GrAA aa = GrAA(GrAAType::kCoverage == args.fAAType); 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci SkTaskGroup* taskGroup = nullptr; 336cb93a386Sopenharmony_ci if (auto direct = args.fContext->asDirectContext()) { 337cb93a386Sopenharmony_ci taskGroup = direct->priv().getTaskGroup(); 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci if (taskGroup) { 341cb93a386Sopenharmony_ci view = make_deferred_mask_texture_view(args.fContext, fit, boundsForMask->size()); 342cb93a386Sopenharmony_ci if (!view) { 343cb93a386Sopenharmony_ci return false; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci auto uploader = std::make_unique<GrTDeferredProxyUploader<SoftwarePathData>>( 347cb93a386Sopenharmony_ci *boundsForMask, *args.fViewMatrix, *args.fShape, aa); 348cb93a386Sopenharmony_ci GrTDeferredProxyUploader<SoftwarePathData>* uploaderRaw = uploader.get(); 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci auto drawAndUploadMask = [uploaderRaw] { 351cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", "Threaded SW Mask Render"); 352cb93a386Sopenharmony_ci GrSWMaskHelper helper(uploaderRaw->getPixels()); 353cb93a386Sopenharmony_ci if (helper.init(uploaderRaw->data().getMaskBounds())) { 354cb93a386Sopenharmony_ci helper.drawShape(uploaderRaw->data().getShape(), 355cb93a386Sopenharmony_ci *uploaderRaw->data().getViewMatrix(), 356cb93a386Sopenharmony_ci SkRegion::kReplace_Op, uploaderRaw->data().getAA(), 0xFF); 357cb93a386Sopenharmony_ci } else { 358cb93a386Sopenharmony_ci SkDEBUGFAIL("Unable to allocate SW mask."); 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci uploaderRaw->signalAndFreeData(); 361cb93a386Sopenharmony_ci }; 362cb93a386Sopenharmony_ci taskGroup->add(std::move(drawAndUploadMask)); 363cb93a386Sopenharmony_ci view.asTextureProxy()->texPriv().setDeferredUploader(std::move(uploader)); 364cb93a386Sopenharmony_ci } else { 365cb93a386Sopenharmony_ci GrSWMaskHelper helper; 366cb93a386Sopenharmony_ci if (!helper.init(*boundsForMask)) { 367cb93a386Sopenharmony_ci return false; 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci helper.drawShape(*args.fShape, *args.fViewMatrix, SkRegion::kReplace_Op, aa, 0xFF); 370cb93a386Sopenharmony_ci view = helper.toTextureView(args.fContext, fit); 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci 373cb93a386Sopenharmony_ci if (!view) { 374cb93a386Sopenharmony_ci return false; 375cb93a386Sopenharmony_ci } 376cb93a386Sopenharmony_ci if (useCache) { 377cb93a386Sopenharmony_ci SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin); 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci // We will add an invalidator to the path so that if the path goes away we will 380cb93a386Sopenharmony_ci // delete or recycle the mask texture. 381cb93a386Sopenharmony_ci auto listener = GrMakeUniqueKeyInvalidationListener(&maskKey, 382cb93a386Sopenharmony_ci args.fContext->priv().contextID()); 383cb93a386Sopenharmony_ci fProxyProvider->assignUniqueKeyToProxy(maskKey, view.asTextureProxy()); 384cb93a386Sopenharmony_ci args.fShape->addGenIDChangeListener(std::move(listener)); 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci args.fContext->priv().stats()->incNumPathMasksGenerated(); 388cb93a386Sopenharmony_ci } 389cb93a386Sopenharmony_ci SkASSERT(view); 390cb93a386Sopenharmony_ci if (inverseFilled) { 391cb93a386Sopenharmony_ci DrawAroundInvPath(args.fSurfaceDrawContext, GrPaint::Clone(args.fPaint), 392cb93a386Sopenharmony_ci *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, devClipBounds, 393cb93a386Sopenharmony_ci unclippedDevShapeBounds); 394cb93a386Sopenharmony_ci } 395cb93a386Sopenharmony_ci DrawToTargetWithShapeMask(std::move(view), args.fSurfaceDrawContext, std::move(args.fPaint), 396cb93a386Sopenharmony_ci *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, 397cb93a386Sopenharmony_ci SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask); 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci return true; 400cb93a386Sopenharmony_ci} 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci} // namespace skgpu::v1 403