| robertphillips@google.com | f4c2c52 | 2012-04-27 12:08:47 +0000 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2012 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 "GrSoftwarePathRenderer.h" | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 9 | #include "GrAuditTrail.h" | 
| Robert Phillips | be9aff2 | 2019-02-15 11:33:22 -0500 | [diff] [blame] | 10 | #include "GrCaps.h" | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 11 | #include "GrClip.h" | 
| Robert Phillips | be9aff2 | 2019-02-15 11:33:22 -0500 | [diff] [blame] | 12 | #include "GrContextPriv.h" | 
| Brian Osman | 099fa0f | 2017-10-02 16:38:32 -0400 | [diff] [blame] | 13 | #include "GrDeferredProxyUploader.h" | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 14 | #include "GrGpuResourcePriv.h" | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 15 | #include "GrOpFlushState.h" | 
|  | 16 | #include "GrOpList.h" | 
| Robert Phillips | 1afd4cd | 2018-01-08 13:40:32 -0500 | [diff] [blame] | 17 | #include "GrProxyProvider.h" | 
| Robert Phillips | 6f0e02f | 2019-02-13 11:02:28 -0500 | [diff] [blame] | 18 | #include "GrRecordingContextPriv.h" | 
| robertphillips@google.com | 58b2021 | 2012-06-27 20:44:52 +0000 | [diff] [blame] | 19 | #include "GrSWMaskHelper.h" | 
| Brian Salomon | 653f42f | 2018-07-10 10:07:31 -0400 | [diff] [blame] | 20 | #include "GrShape.h" | 
|  | 21 | #include "GrSurfaceContextPriv.h" | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 22 | #include "SkMakeUnique.h" | 
|  | 23 | #include "SkSemaphore.h" | 
|  | 24 | #include "SkTaskGroup.h" | 
|  | 25 | #include "SkTraceEvent.h" | 
| Robert Phillips | 009e9af | 2017-06-15 14:01:04 -0400 | [diff] [blame] | 26 | #include "ops/GrDrawOp.h" | 
| Michael Ludwig | 72ab346 | 2018-12-10 12:43:36 -0500 | [diff] [blame] | 27 | #include "ops/GrFillRectOp.h" | 
| robertphillips@google.com | f4c2c52 | 2012-04-27 12:08:47 +0000 | [diff] [blame] | 28 |  | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 29 | //////////////////////////////////////////////////////////////////////////////// | 
| Chris Dalton | 5ed4423 | 2017-09-07 13:22:46 -0600 | [diff] [blame] | 30 | GrPathRenderer::CanDrawPath | 
|  | 31 | GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { | 
| bsalomon | 8acedde | 2016-06-24 10:42:16 -0700 | [diff] [blame] | 32 | // Pass on any style that applies. The caller will apply the style if a suitable renderer is | 
|  | 33 | // not found and try again with the new GrShape. | 
| Robert Phillips | 1afd4cd | 2018-01-08 13:40:32 -0500 | [diff] [blame] | 34 | if (!args.fShape->style().applies() && SkToBool(fProxyProvider) && | 
| Chris Dalton | 09e5689 | 2019-03-13 00:22:01 -0600 | [diff] [blame] | 35 | ((args.fAATypeFlags & AATypeFlags::kCoverage) || args.fAATypeFlags == AATypeFlags::kNone)) { | 
| Chris Dalton | 5ed4423 | 2017-09-07 13:22:46 -0600 | [diff] [blame] | 36 | // This is the fallback renderer for when a path is too complicated for the GPU ones. | 
|  | 37 | return CanDrawPath::kAsBackup; | 
|  | 38 | } | 
|  | 39 | return CanDrawPath::kNo; | 
| robertphillips@google.com | f4c2c52 | 2012-04-27 12:08:47 +0000 | [diff] [blame] | 40 | } | 
|  | 41 |  | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 42 | //////////////////////////////////////////////////////////////////////////////// | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 43 | static bool get_unclipped_shape_dev_bounds(const GrShape& shape, const SkMatrix& matrix, | 
|  | 44 | SkIRect* devBounds) { | 
|  | 45 | SkRect shapeBounds = shape.styledBounds(); | 
|  | 46 | if (shapeBounds.isEmpty()) { | 
|  | 47 | return false; | 
|  | 48 | } | 
|  | 49 | SkRect shapeDevBounds; | 
|  | 50 | matrix.mapRect(&shapeDevBounds, shapeBounds); | 
| Brian Salomon | c1c607e | 2016-12-20 11:41:43 -0500 | [diff] [blame] | 51 | // Even though these are "unclipped" bounds we still clip to the int32_t range. | 
|  | 52 | // This is the largest int32_t that is representable exactly as a float. The next 63 larger ints | 
|  | 53 | // would round down to this value when cast to a float, but who really cares. | 
|  | 54 | // INT32_MIN is exactly representable. | 
|  | 55 | static constexpr int32_t kMaxInt = 2147483520; | 
|  | 56 | if (!shapeDevBounds.intersect(SkRect::MakeLTRB(INT32_MIN, INT32_MIN, kMaxInt, kMaxInt))) { | 
|  | 57 | return false; | 
|  | 58 | } | 
| Jim Van Verth | ba7cf29 | 2017-11-02 20:18:56 +0000 | [diff] [blame] | 59 | // Make sure that the resulting SkIRect can have representable width and height | 
|  | 60 | if (SkScalarRoundToInt(shapeDevBounds.width()) > kMaxInt || | 
|  | 61 | SkScalarRoundToInt(shapeDevBounds.height()) > kMaxInt) { | 
|  | 62 | return false; | 
|  | 63 | } | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 64 | shapeDevBounds.roundOut(devBounds); | 
|  | 65 | return true; | 
|  | 66 | } | 
|  | 67 |  | 
|  | 68 | // Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there | 
|  | 69 | // is no intersection. | 
| Robert Phillips | 20390c3 | 2018-08-17 11:01:03 -0400 | [diff] [blame] | 70 | bool GrSoftwarePathRenderer::GetShapeAndClipBounds(GrRenderTargetContext* renderTargetContext, | 
|  | 71 | const GrClip& clip, | 
|  | 72 | const GrShape& shape, | 
|  | 73 | const SkMatrix& matrix, | 
|  | 74 | SkIRect* unclippedDevShapeBounds, | 
|  | 75 | SkIRect* clippedDevShapeBounds, | 
|  | 76 | SkIRect* devClipBounds) { | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 77 | // compute bounds as intersection of rt size, clip, and path | 
| Robert Phillips | 20390c3 | 2018-08-17 11:01:03 -0400 | [diff] [blame] | 78 | clip.getConservativeBounds(renderTargetContext->width(), | 
|  | 79 | renderTargetContext->height(), | 
|  | 80 | devClipBounds); | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 81 |  | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 82 | if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) { | 
|  | 83 | *unclippedDevShapeBounds = SkIRect::EmptyIRect(); | 
|  | 84 | *clippedDevShapeBounds = SkIRect::EmptyIRect(); | 
| robertphillips@google.com | 3e11c0b | 2012-07-11 18:20:35 +0000 | [diff] [blame] | 85 | return false; | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 86 | } | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 87 | if (!clippedDevShapeBounds->intersect(*devClipBounds, *unclippedDevShapeBounds)) { | 
|  | 88 | *clippedDevShapeBounds = SkIRect::EmptyIRect(); | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 89 | return false; | 
|  | 90 | } | 
|  | 91 | return true; | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | //////////////////////////////////////////////////////////////////////////////// | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 95 |  | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 96 | void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetContext, | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 97 | GrPaint&& paint, | 
| robertphillips | d2b6d64 | 2016-07-21 08:55:08 -0700 | [diff] [blame] | 98 | const GrUserStencilSettings& userStencilSettings, | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 99 | const GrClip& clip, | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 100 | const SkMatrix& viewMatrix, | 
|  | 101 | const SkRect& rect, | 
|  | 102 | const SkMatrix& localMatrix) { | 
| Robert Phillips | 6a6de56 | 2019-02-15 15:19:15 -0500 | [diff] [blame] | 103 | auto context = renderTargetContext->surfPriv().getContext(); | 
| Brian Salomon | baaf439 | 2017-06-15 09:59:23 -0400 | [diff] [blame] | 104 | renderTargetContext->addDrawOp(clip, | 
| Michael Ludwig | 72ab346 | 2018-12-10 12:43:36 -0500 | [diff] [blame] | 105 | GrFillRectOp::MakeWithLocalMatrix( | 
|  | 106 | context, std::move(paint), GrAAType::kNone, viewMatrix, | 
|  | 107 | localMatrix, rect, &userStencilSettings)); | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 108 | } | 
|  | 109 |  | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 110 | void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext, | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 111 | GrPaint&& paint, | 
| robertphillips | d2b6d64 | 2016-07-21 08:55:08 -0700 | [diff] [blame] | 112 | const GrUserStencilSettings& userStencilSettings, | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 113 | const GrClip& clip, | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 114 | const SkMatrix& viewMatrix, | 
|  | 115 | const SkIRect& devClipBounds, | 
|  | 116 | const SkIRect& devPathBounds) { | 
| joshualitt | d27f73e | 2014-12-29 07:43:36 -0800 | [diff] [blame] | 117 | SkMatrix invert; | 
| joshualitt | 8059eb9 | 2014-12-29 15:10:07 -0800 | [diff] [blame] | 118 | if (!viewMatrix.invert(&invert)) { | 
| bsalomon@google.com | e3d3216 | 2012-07-20 13:37:06 +0000 | [diff] [blame] | 119 | return; | 
|  | 120 | } | 
| joshualitt | d27f73e | 2014-12-29 07:43:36 -0800 | [diff] [blame] | 121 |  | 
| commit-bot@chromium.org | fd03d4a | 2013-07-17 21:39:42 +0000 | [diff] [blame] | 122 | SkRect rect; | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 123 | if (devClipBounds.fTop < devPathBounds.fTop) { | 
| rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 124 | rect.iset(devClipBounds.fLeft, devClipBounds.fTop, | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 125 | devClipBounds.fRight, devPathBounds.fTop); | 
| Brian Salomon | b74ef03 | 2017-08-10 12:46:01 -0400 | [diff] [blame] | 126 | DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip, | 
|  | 127 | SkMatrix::I(), rect, invert); | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 128 | } | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 129 | if (devClipBounds.fLeft < devPathBounds.fLeft) { | 
| rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 130 | rect.iset(devClipBounds.fLeft, devPathBounds.fTop, | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 131 | devPathBounds.fLeft, devPathBounds.fBottom); | 
| Brian Salomon | b74ef03 | 2017-08-10 12:46:01 -0400 | [diff] [blame] | 132 | DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip, | 
|  | 133 | SkMatrix::I(), rect, invert); | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 134 | } | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 135 | if (devClipBounds.fRight > devPathBounds.fRight) { | 
| rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 136 | rect.iset(devPathBounds.fRight, devPathBounds.fTop, | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 137 | devClipBounds.fRight, devPathBounds.fBottom); | 
| Brian Salomon | b74ef03 | 2017-08-10 12:46:01 -0400 | [diff] [blame] | 138 | DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip, | 
|  | 139 | SkMatrix::I(), rect, invert); | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 140 | } | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 141 | if (devClipBounds.fBottom > devPathBounds.fBottom) { | 
| rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 142 | rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, | 
| robertphillips@google.com | 7b11289 | 2012-07-31 15:18:21 +0000 | [diff] [blame] | 143 | devClipBounds.fRight, devClipBounds.fBottom); | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 144 | DrawNonAARect(renderTargetContext, std::move(paint), userStencilSettings, clip, | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 145 | SkMatrix::I(), rect, invert); | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 146 | } | 
|  | 147 | } | 
|  | 148 |  | 
| Brian Osman | c7da146 | 2017-08-17 16:14:25 -0400 | [diff] [blame] | 149 | void GrSoftwarePathRenderer::DrawToTargetWithShapeMask( | 
|  | 150 | sk_sp<GrTextureProxy> proxy, | 
|  | 151 | GrRenderTargetContext* renderTargetContext, | 
|  | 152 | GrPaint&& paint, | 
|  | 153 | const GrUserStencilSettings& userStencilSettings, | 
|  | 154 | const GrClip& clip, | 
|  | 155 | const SkMatrix& viewMatrix, | 
|  | 156 | const SkIPoint& textureOriginInDeviceSpace, | 
|  | 157 | const SkIRect& deviceSpaceRectToDraw) { | 
|  | 158 | SkMatrix invert; | 
|  | 159 | if (!viewMatrix.invert(&invert)) { | 
|  | 160 | return; | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw); | 
|  | 164 |  | 
|  | 165 | // We use device coords to compute the texture coordinates. We take the device coords and apply | 
|  | 166 | // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling | 
|  | 167 | // matrix to normalized coords. | 
|  | 168 | SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX), | 
|  | 169 | SkIntToScalar(-textureOriginInDeviceSpace.fY)); | 
|  | 170 | maskMatrix.preConcat(viewMatrix); | 
|  | 171 | paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make( | 
| Brian Osman | 2240be9 | 2017-10-18 13:15:13 -0400 | [diff] [blame] | 172 | std::move(proxy), maskMatrix, GrSamplerState::Filter::kNearest)); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 173 | DrawNonAARect(renderTargetContext, std::move(paint), userStencilSettings, clip, SkMatrix::I(), | 
|  | 174 | dstRect, invert); | 
|  | 175 | } | 
|  | 176 |  | 
| Robert Phillips | 6f0e02f | 2019-02-13 11:02:28 -0500 | [diff] [blame] | 177 | static sk_sp<GrTextureProxy> make_deferred_mask_texture_proxy(GrRecordingContext* context, | 
|  | 178 | SkBackingFit fit, | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 179 | int width, int height) { | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 180 | GrProxyProvider* proxyProvider = context->priv().proxyProvider(); | 
| Robert Phillips | 0bd24dc | 2018-01-16 08:06:32 -0500 | [diff] [blame] | 181 |  | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 182 | GrSurfaceDesc desc; | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 183 | desc.fWidth = width; | 
|  | 184 | desc.fHeight = height; | 
|  | 185 | desc.fConfig = kAlpha_8_GrPixelConfig; | 
| Robert Phillips | 0bd24dc | 2018-01-16 08:06:32 -0500 | [diff] [blame] | 186 |  | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 187 | const GrBackendFormat format = | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 188 | context->priv().caps()->getBackendFormatFromColorType(kAlpha_8_SkColorType); | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 189 |  | 
| Brian Osman | d140fe9 | 2017-10-03 12:17:26 -0400 | [diff] [blame] | 190 | // MDB TODO: We're going to fill this proxy with an ASAP upload (which is out of order wrt to | 
|  | 191 | // ops), so it can't have any pending IO. | 
| Greg Daniel | 4065d45 | 2018-11-16 15:43:41 -0500 | [diff] [blame] | 192 | return proxyProvider->createProxy(format, desc, kTopLeft_GrSurfaceOrigin, fit, SkBudgeted::kYes, | 
| Robert Phillips | fe0253f | 2018-03-16 16:47:25 -0400 | [diff] [blame] | 193 | GrInternalSurfaceFlags::kNoPendingIO); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 194 | } | 
|  | 195 |  | 
|  | 196 | namespace { | 
|  | 197 |  | 
| Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 198 | /** | 
| Brian Osman | 099fa0f | 2017-10-02 16:38:32 -0400 | [diff] [blame] | 199 | * Payload class for use with GrTDeferredProxyUploader. The software path renderer only draws | 
| Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 200 | * a single path into the mask texture. This stores all of the information needed by the worker | 
|  | 201 | * thread's call to drawShape (see below, in onDrawPath). | 
|  | 202 | */ | 
|  | 203 | class SoftwarePathData { | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 204 | public: | 
| Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 205 | SoftwarePathData(const SkIRect& maskBounds, const SkMatrix& viewMatrix, const GrShape& shape, | 
|  | 206 | GrAA aa) | 
|  | 207 | : fMaskBounds(maskBounds) | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 208 | , fViewMatrix(viewMatrix) | 
|  | 209 | , fShape(shape) | 
| Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 210 | , fAA(aa) {} | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 211 |  | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 212 | const SkIRect& getMaskBounds() const { return fMaskBounds; } | 
|  | 213 | const SkMatrix* getViewMatrix() const { return &fViewMatrix; } | 
|  | 214 | const GrShape& getShape() const { return fShape; } | 
|  | 215 | GrAA getAA() const { return fAA; } | 
|  | 216 |  | 
|  | 217 | private: | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 218 | SkIRect fMaskBounds; | 
|  | 219 | SkMatrix fViewMatrix; | 
|  | 220 | GrShape fShape; | 
|  | 221 | GrAA fAA; | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 222 | }; | 
|  | 223 |  | 
| Brian Osman | e9242ca | 2017-09-26 14:05:19 -0400 | [diff] [blame] | 224 | // When the SkPathRef genID changes, invalidate a corresponding GrResource described by key. | 
|  | 225 | class PathInvalidator : public SkPathRef::GenIDChangeListener { | 
|  | 226 | public: | 
| Brian Salomon | 238069b | 2018-07-11 15:58:57 -0400 | [diff] [blame] | 227 | PathInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID) | 
|  | 228 | : fMsg(key, contextUniqueID) {} | 
|  | 229 |  | 
| Brian Osman | e9242ca | 2017-09-26 14:05:19 -0400 | [diff] [blame] | 230 | private: | 
|  | 231 | GrUniqueKeyInvalidatedMessage fMsg; | 
|  | 232 |  | 
|  | 233 | void onChange() override { | 
|  | 234 | SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | 
|  | 235 | } | 
|  | 236 | }; | 
|  | 237 |  | 
| Brian Osman | c7da146 | 2017-08-17 16:14:25 -0400 | [diff] [blame] | 238 | } | 
|  | 239 |  | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 240 | //////////////////////////////////////////////////////////////////////////////// | 
|  | 241 | // return true on success; false on failure | 
| bsalomon | 0aff2fa | 2015-07-31 06:48:27 -0700 | [diff] [blame] | 242 | bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 243 | GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), | 
| robertphillips | 976f5f0 | 2016-06-03 10:59:20 -0700 | [diff] [blame] | 244 | "GrSoftwarePathRenderer::onDrawPath"); | 
| Robert Phillips | 1afd4cd | 2018-01-08 13:40:32 -0500 | [diff] [blame] | 245 | if (!fProxyProvider) { | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 246 | return false; | 
|  | 247 | } | 
|  | 248 |  | 
| caryclark | d656200 | 2016-07-27 12:02:07 -0700 | [diff] [blame] | 249 | SkASSERT(!args.fShape->style().applies()); | 
| Robert Phillips | 20390c3 | 2018-08-17 11:01:03 -0400 | [diff] [blame] | 250 | // We really need to know if the shape will be inverse filled or not | 
| Eric Karl | 5c77975 | 2017-05-08 12:02:07 -0700 | [diff] [blame] | 251 | // If the path is hairline, ignore inverse fill. | 
| Robert Phillips | 20390c3 | 2018-08-17 11:01:03 -0400 | [diff] [blame] | 252 | bool inverseFilled = args.fShape->inverseFilled() && | 
|  | 253 | !IsStrokeHairlineOrEquivalent(args.fShape->style(), | 
|  | 254 | *args.fViewMatrix, nullptr); | 
| bsalomon | 8acedde | 2016-06-24 10:42:16 -0700 | [diff] [blame] | 255 |  | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 256 | SkIRect unclippedDevShapeBounds, clippedDevShapeBounds, devClipBounds; | 
|  | 257 | // To prevent overloading the cache with entries during animations we limit the cache of masks | 
|  | 258 | // to cases where the matrix preserves axis alignment. | 
|  | 259 | bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() && | 
| Chris Dalton | 09e5689 | 2019-03-13 00:22:01 -0600 | [diff] [blame] | 260 | args.fShape->hasUnstyledKey() && (AATypeFlags::kCoverage & args.fAATypeFlags); | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 261 |  | 
| Robert Phillips | 20390c3 | 2018-08-17 11:01:03 -0400 | [diff] [blame] | 262 | if (!GetShapeAndClipBounds(args.fRenderTargetContext, | 
|  | 263 | *args.fClip, *args.fShape, | 
|  | 264 | *args.fViewMatrix, &unclippedDevShapeBounds, | 
|  | 265 | &clippedDevShapeBounds, | 
|  | 266 | &devClipBounds)) { | 
| bsalomon | 8acedde | 2016-06-24 10:42:16 -0700 | [diff] [blame] | 267 | if (inverseFilled) { | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 268 | DrawAroundInvPath(args.fRenderTargetContext, std::move(args.fPaint), | 
|  | 269 | *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, | 
|  | 270 | devClipBounds, unclippedDevShapeBounds); | 
| bsalomon@google.com | 276c1fa | 2012-06-19 13:22:45 +0000 | [diff] [blame] | 271 | } | 
|  | 272 | return true; | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 273 | } | 
| robertphillips@google.com | 366f1c6 | 2012-06-29 21:38:47 +0000 | [diff] [blame] | 274 |  | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 275 | const SkIRect* boundsForMask = &clippedDevShapeBounds; | 
|  | 276 | if (useCache) { | 
|  | 277 | // Use the cache only if >50% of the path is visible. | 
|  | 278 | int unclippedWidth = unclippedDevShapeBounds.width(); | 
|  | 279 | int unclippedHeight = unclippedDevShapeBounds.height(); | 
| Brian Osman | 1a0ea73 | 2017-09-28 11:53:03 -0400 | [diff] [blame] | 280 | int64_t unclippedArea = sk_64_mul(unclippedWidth, unclippedHeight); | 
|  | 281 | int64_t clippedArea = sk_64_mul(clippedDevShapeBounds.width(), | 
|  | 282 | clippedDevShapeBounds.height()); | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 283 | int maxTextureSize = args.fRenderTargetContext->caps()->maxTextureSize(); | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 284 | if (unclippedArea > 2 * clippedArea || unclippedWidth > maxTextureSize || | 
|  | 285 | unclippedHeight > maxTextureSize) { | 
|  | 286 | useCache = false; | 
|  | 287 | } else { | 
|  | 288 | boundsForMask = &unclippedDevShapeBounds; | 
|  | 289 | } | 
| robertphillips@google.com | ed4155d | 2012-05-01 14:30:24 +0000 | [diff] [blame] | 290 | } | 
|  | 291 |  | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 292 | GrUniqueKey maskKey; | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 293 | if (useCache) { | 
|  | 294 | // We require the upper left 2x2 of the matrix to match exactly for a cache hit. | 
|  | 295 | SkScalar sx = args.fViewMatrix->get(SkMatrix::kMScaleX); | 
|  | 296 | SkScalar sy = args.fViewMatrix->get(SkMatrix::kMScaleY); | 
|  | 297 | SkScalar kx = args.fViewMatrix->get(SkMatrix::kMSkewX); | 
|  | 298 | SkScalar ky = args.fViewMatrix->get(SkMatrix::kMSkewY); | 
| Stan Iliev | 67cd673 | 2017-08-15 17:10:26 -0400 | [diff] [blame] | 299 | static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 
| Brian Osman | a442526 | 2018-07-26 13:37:53 -0400 | [diff] [blame] | 300 | GrUniqueKey::Builder builder(&maskKey, kDomain, 5 + args.fShape->unstyledKeySize(), | 
|  | 301 | "SW Path Mask"); | 
| Stan Iliev | 67cd673 | 2017-08-15 17:10:26 -0400 | [diff] [blame] | 302 | #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK | 
|  | 303 | // Fractional translate does not affect caching on Android. This is done for better cache | 
|  | 304 | // hit ratio and speed, but it is matching HWUI behavior, which doesn't consider the matrix | 
|  | 305 | // at all when caching paths. | 
| Brian Osman | a442526 | 2018-07-26 13:37:53 -0400 | [diff] [blame] | 306 | SkFixed fracX = 0; | 
|  | 307 | SkFixed fracY = 0; | 
| Stan Iliev | 67cd673 | 2017-08-15 17:10:26 -0400 | [diff] [blame] | 308 | #else | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 309 | SkScalar tx = args.fViewMatrix->get(SkMatrix::kMTransX); | 
|  | 310 | SkScalar ty = args.fViewMatrix->get(SkMatrix::kMTransY); | 
|  | 311 | // Allow 8 bits each in x and y of subpixel positioning. | 
|  | 312 | SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00; | 
|  | 313 | SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00; | 
| Stan Iliev | 67cd673 | 2017-08-15 17:10:26 -0400 | [diff] [blame] | 314 | #endif | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 315 | builder[0] = SkFloat2Bits(sx); | 
|  | 316 | builder[1] = SkFloat2Bits(sy); | 
|  | 317 | builder[2] = SkFloat2Bits(kx); | 
|  | 318 | builder[3] = SkFloat2Bits(ky); | 
| Brian Osman | a442526 | 2018-07-26 13:37:53 -0400 | [diff] [blame] | 319 | // Distinguish between hairline and filled paths. For hairlines, we also need to include | 
|  | 320 | // the cap. (SW grows hairlines by 0.5 pixel with round and square caps). Note that | 
|  | 321 | // stroke-and-fill of hairlines is turned into pure fill by SkStrokeRec, so this covers | 
|  | 322 | // all cases we might see. | 
|  | 323 | uint32_t styleBits = args.fShape->style().isSimpleHairline() ? | 
|  | 324 | ((args.fShape->style().strokeRec().getCap() << 1) | 1) : 0; | 
|  | 325 | builder[4] = fracX | (fracY >> 8) | (styleBits << 16); | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 326 | args.fShape->writeUnstyledKey(&builder[5]); | 
|  | 327 | } | 
|  | 328 |  | 
| Robert Phillips | d374948 | 2017-03-14 09:17:43 -0400 | [diff] [blame] | 329 | sk_sp<GrTextureProxy> proxy; | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 330 | if (useCache) { | 
| Robert Phillips | 1afd4cd | 2018-01-08 13:40:32 -0500 | [diff] [blame] | 331 | proxy = fProxyProvider->findOrCreateProxyByUniqueKey(maskKey, kTopLeft_GrSurfaceOrigin); | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 332 | } | 
| Robert Phillips | d374948 | 2017-03-14 09:17:43 -0400 | [diff] [blame] | 333 | if (!proxy) { | 
| Robert Phillips | 417b7f4 | 2016-12-14 09:12:13 -0500 | [diff] [blame] | 334 | SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox; | 
| Chris Dalton | 09e5689 | 2019-03-13 00:22:01 -0600 | [diff] [blame] | 335 | GrAA aa = GrAA(SkToBool(AATypeFlags::kCoverage & args.fAATypeFlags)); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 336 |  | 
| Robert Phillips | 6f0e02f | 2019-02-13 11:02:28 -0500 | [diff] [blame] | 337 | SkTaskGroup* taskGroup = nullptr; | 
|  | 338 | if (auto direct = args.fContext->priv().asDirectContext()) { | 
|  | 339 | taskGroup = direct->priv().getTaskGroup(); | 
|  | 340 | } | 
|  | 341 |  | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 342 | if (taskGroup) { | 
|  | 343 | proxy = make_deferred_mask_texture_proxy(args.fContext, fit, | 
|  | 344 | boundsForMask->width(), | 
|  | 345 | boundsForMask->height()); | 
|  | 346 | if (!proxy) { | 
|  | 347 | return false; | 
|  | 348 | } | 
|  | 349 |  | 
| Brian Osman | 099fa0f | 2017-10-02 16:38:32 -0400 | [diff] [blame] | 350 | auto uploader = skstd::make_unique<GrTDeferredProxyUploader<SoftwarePathData>>( | 
|  | 351 | *boundsForMask, *args.fViewMatrix, *args.fShape, aa); | 
|  | 352 | GrTDeferredProxyUploader<SoftwarePathData>* uploaderRaw = uploader.get(); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 353 |  | 
|  | 354 | auto drawAndUploadMask = [uploaderRaw] { | 
|  | 355 | TRACE_EVENT0("skia", "Threaded SW Mask Render"); | 
|  | 356 | GrSWMaskHelper helper(uploaderRaw->getPixels()); | 
| Brian Osman | 5d03474 | 2017-09-11 13:38:55 -0400 | [diff] [blame] | 357 | if (helper.init(uploaderRaw->data().getMaskBounds())) { | 
|  | 358 | helper.drawShape(uploaderRaw->data().getShape(), | 
|  | 359 | *uploaderRaw->data().getViewMatrix(), | 
|  | 360 | SkRegion::kReplace_Op, uploaderRaw->data().getAA(), 0xFF); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 361 | } else { | 
|  | 362 | SkDEBUGFAIL("Unable to allocate SW mask."); | 
|  | 363 | } | 
| Brian Osman | 099fa0f | 2017-10-02 16:38:32 -0400 | [diff] [blame] | 364 | uploaderRaw->signalAndFreeData(); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 365 | }; | 
|  | 366 | taskGroup->add(std::move(drawAndUploadMask)); | 
| Brian Osman | 099fa0f | 2017-10-02 16:38:32 -0400 | [diff] [blame] | 367 | proxy->texPriv().setDeferredUploader(std::move(uploader)); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 368 | } else { | 
|  | 369 | GrSWMaskHelper helper; | 
| Brian Salomon | 7407756 | 2017-08-30 13:55:35 -0400 | [diff] [blame] | 370 | if (!helper.init(*boundsForMask)) { | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 371 | return false; | 
|  | 372 | } | 
| Brian Salomon | 7407756 | 2017-08-30 13:55:35 -0400 | [diff] [blame] | 373 | helper.drawShape(*args.fShape, *args.fViewMatrix, SkRegion::kReplace_Op, aa, 0xFF); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 374 | proxy = helper.toTextureProxy(args.fContext, fit); | 
|  | 375 | } | 
|  | 376 |  | 
| Robert Phillips | d374948 | 2017-03-14 09:17:43 -0400 | [diff] [blame] | 377 | if (!proxy) { | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 378 | return false; | 
|  | 379 | } | 
|  | 380 | if (useCache) { | 
| Robert Phillips | e44ef10 | 2017-07-21 15:37:19 -0400 | [diff] [blame] | 381 | SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin); | 
| Robert Phillips | 1afd4cd | 2018-01-08 13:40:32 -0500 | [diff] [blame] | 382 | fProxyProvider->assignUniqueKeyToProxy(maskKey, proxy.get()); | 
| Robert Phillips | 869fe56 | 2018-09-17 14:55:49 -0400 | [diff] [blame] | 383 | args.fShape->addGenIDChangeListener( | 
| Robert Phillips | 9da87e0 | 2019-02-04 13:26:26 -0500 | [diff] [blame] | 384 | sk_make_sp<PathInvalidator>(maskKey, args.fContext->priv().contextID())); | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 385 | } | 
| bsalomon | 39ef7fb | 2016-09-21 11:16:05 -0700 | [diff] [blame] | 386 | } | 
| bsalomon | 8acedde | 2016-06-24 10:42:16 -0700 | [diff] [blame] | 387 | if (inverseFilled) { | 
| Brian Salomon | b74ef03 | 2017-08-10 12:46:01 -0400 | [diff] [blame] | 388 | DrawAroundInvPath(args.fRenderTargetContext, GrPaint::Clone(args.fPaint), | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 389 | *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, devClipBounds, | 
|  | 390 | unclippedDevShapeBounds); | 
| robertphillips@google.com | 5dfb672 | 2012-07-09 16:32:28 +0000 | [diff] [blame] | 391 | } | 
| Brian Osman | c7da146 | 2017-08-17 16:14:25 -0400 | [diff] [blame] | 392 | DrawToTargetWithShapeMask( | 
| Robert Phillips | 296b1cc | 2017-03-15 10:42:12 -0400 | [diff] [blame] | 393 | std::move(proxy), args.fRenderTargetContext, std::move(args.fPaint), | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 394 | *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, | 
|  | 395 | SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask); | 
| robertphillips@google.com | 5dfb672 | 2012-07-09 16:32:28 +0000 | [diff] [blame] | 396 |  | 
|  | 397 | return true; | 
| robertphillips@google.com | f4c2c52 | 2012-04-27 12:08:47 +0000 | [diff] [blame] | 398 | } |