GrSoftwarePathRenderer.cpp 18 KB

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