GrClipStackClip.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. /*
  2. * Copyright 2016 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/SkTo.h"
  8. #include "src/core/SkClipOpPriv.h"
  9. #include "src/core/SkMakeUnique.h"
  10. #include "src/core/SkTaskGroup.h"
  11. #include "src/core/SkTraceEvent.h"
  12. #include "src/gpu/GrAppliedClip.h"
  13. #include "src/gpu/GrClipStackClip.h"
  14. #include "src/gpu/GrContextPriv.h"
  15. #include "src/gpu/GrDeferredProxyUploader.h"
  16. #include "src/gpu/GrDrawingManager.h"
  17. #include "src/gpu/GrFixedClip.h"
  18. #include "src/gpu/GrGpuResourcePriv.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/GrStencilAttachment.h"
  24. #include "src/gpu/GrStyle.h"
  25. #include "src/gpu/GrTextureProxy.h"
  26. #include "src/gpu/effects/GrConvexPolyEffect.h"
  27. #include "src/gpu/effects/GrRRectEffect.h"
  28. #include "src/gpu/effects/GrTextureDomain.h"
  29. #include "src/gpu/geometry/GrShape.h"
  30. typedef SkClipStack::Element Element;
  31. typedef GrReducedClip::InitialState InitialState;
  32. typedef GrReducedClip::ElementList ElementList;
  33. const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
  34. bool GrClipStackClip::quickContains(const SkRect& rect) const {
  35. if (!fStack || fStack->isWideOpen()) {
  36. return true;
  37. }
  38. return fStack->quickContains(rect);
  39. }
  40. bool GrClipStackClip::quickContains(const SkRRect& rrect) const {
  41. if (!fStack || fStack->isWideOpen()) {
  42. return true;
  43. }
  44. return fStack->quickContains(rrect);
  45. }
  46. bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, GrAA* aa) const {
  47. if (!fStack) {
  48. return false;
  49. }
  50. const SkRect* rtBounds = &origRTBounds;
  51. bool isAA;
  52. if (fStack->isRRect(*rtBounds, rr, &isAA)) {
  53. *aa = GrAA(isAA);
  54. return true;
  55. }
  56. return false;
  57. }
  58. void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devResult,
  59. bool* isIntersectionOfRects) const {
  60. if (!fStack) {
  61. devResult->setXYWH(0, 0, width, height);
  62. if (isIntersectionOfRects) {
  63. *isIntersectionOfRects = true;
  64. }
  65. return;
  66. }
  67. SkRect devBounds;
  68. fStack->getConservativeBounds(0, 0, width, height, &devBounds, isIntersectionOfRects);
  69. devBounds.roundOut(devResult);
  70. }
  71. ////////////////////////////////////////////////////////////////////////////////
  72. // set up the draw state to enable the aa clipping mask.
  73. static std::unique_ptr<GrFragmentProcessor> create_fp_for_mask(sk_sp<GrTextureProxy> mask,
  74. const SkIRect& devBound) {
  75. SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
  76. return GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(mask), domainTexels,
  77. {devBound.fLeft, devBound.fTop});
  78. }
  79. // Does the path in 'element' require SW rendering? If so, return true (and,
  80. // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set
  81. // 'prOut' to the non-SW path renderer that will do the job).
  82. bool GrClipStackClip::PathNeedsSWRenderer(GrRecordingContext* context,
  83. const SkIRect& scissorRect,
  84. bool hasUserStencilSettings,
  85. const GrRenderTargetContext* renderTargetContext,
  86. const SkMatrix& viewMatrix,
  87. const Element* element,
  88. GrPathRenderer** prOut,
  89. bool needsStencil) {
  90. if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
  91. // rects can always be drawn directly w/o using the software path
  92. // TODO: skip rrects once we're drawing them directly.
  93. if (prOut) {
  94. *prOut = nullptr;
  95. }
  96. return false;
  97. } else {
  98. // We shouldn't get here with an empty clip element.
  99. SkASSERT(Element::DeviceSpaceType::kEmpty != element->getDeviceSpaceType());
  100. // the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
  101. SkPath path;
  102. element->asDeviceSpacePath(&path);
  103. if (path.isInverseFillType()) {
  104. path.toggleInverseFillType();
  105. }
  106. // We only use this method when rendering coverage clip masks.
  107. SkASSERT(renderTargetContext->numSamples() <= 1);
  108. auto aaType = (element->isAA()) ? GrAAType::kCoverage : GrAAType::kNone;
  109. GrPathRendererChain::DrawType type =
  110. needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor
  111. : GrPathRendererChain::DrawType::kColor;
  112. GrShape shape(path, GrStyle::SimpleFill());
  113. GrPathRenderer::CanDrawPathArgs canDrawArgs;
  114. canDrawArgs.fCaps = context->priv().caps();
  115. canDrawArgs.fProxy = renderTargetContext->proxy();
  116. canDrawArgs.fClipConservativeBounds = &scissorRect;
  117. canDrawArgs.fViewMatrix = &viewMatrix;
  118. canDrawArgs.fShape = &shape;
  119. canDrawArgs.fAAType = aaType;
  120. SkASSERT(!renderTargetContext->wrapsVkSecondaryCB());
  121. canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
  122. canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
  123. // the 'false' parameter disallows use of the SW path renderer
  124. GrPathRenderer* pr =
  125. context->priv().drawingManager()->getPathRenderer(canDrawArgs, false, type);
  126. if (prOut) {
  127. *prOut = pr;
  128. }
  129. return SkToBool(!pr);
  130. }
  131. }
  132. /*
  133. * This method traverses the clip stack to see if the GrSoftwarePathRenderer
  134. * will be used on any element. If so, it returns true to indicate that the
  135. * entire clip should be rendered in SW and then uploaded en masse to the gpu.
  136. */
  137. bool GrClipStackClip::UseSWOnlyPath(GrRecordingContext* context,
  138. bool hasUserStencilSettings,
  139. const GrRenderTargetContext* renderTargetContext,
  140. const GrReducedClip& reducedClip) {
  141. // TODO: right now it appears that GPU clip masks are strictly slower than software. We may
  142. // want to revisit this assumption once we can test with render target sorting.
  143. return true;
  144. // TODO: generalize this function so that when
  145. // a clip gets complex enough it can just be done in SW regardless
  146. // of whether it would invoke the GrSoftwarePathRenderer.
  147. // If we're avoiding stencils, always use SW. This includes drawing into a wrapped vulkan
  148. // secondary command buffer which can't handle stencils.
  149. if (context->priv().caps()->avoidStencilBuffers() ||
  150. renderTargetContext->wrapsVkSecondaryCB()) {
  151. return true;
  152. }
  153. // Set the matrix so that rendered clip elements are transformed to mask space from clip
  154. // space.
  155. SkMatrix translate;
  156. translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top()));
  157. for (ElementList::Iter iter(reducedClip.maskElements()); iter.get(); iter.next()) {
  158. const Element* element = iter.get();
  159. SkClipOp op = element->getOp();
  160. bool invert = element->isInverseFilled();
  161. bool needsStencil = invert ||
  162. kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op;
  163. if (PathNeedsSWRenderer(context, reducedClip.scissor(), hasUserStencilSettings,
  164. renderTargetContext, translate, element, nullptr, needsStencil)) {
  165. return true;
  166. }
  167. }
  168. return false;
  169. }
  170. ////////////////////////////////////////////////////////////////////////////////
  171. // sort out what kind of clip mask needs to be created: alpha, stencil,
  172. // scissor, or entirely software
  173. bool GrClipStackClip::apply(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext,
  174. bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out,
  175. SkRect* bounds) const {
  176. SkRect devBounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height());
  177. if (!devBounds.intersect(*bounds)) {
  178. return false;
  179. }
  180. if (!fStack || fStack->isWideOpen()) {
  181. return true;
  182. }
  183. // An default count of 4 was chosen because of the common pattern in Blink of:
  184. // isect RR
  185. // diff RR
  186. // isect convex_poly
  187. // isect convex_poly
  188. // when drawing rounded div borders.
  189. constexpr int kMaxAnalyticFPs = 4;
  190. int maxWindowRectangles = renderTargetContext->priv().maxWindowRectangles();
  191. int maxAnalyticFPs = kMaxAnalyticFPs;
  192. if (renderTargetContext->numSamples() > 1 || useHWAA || hasUserStencilSettings) {
  193. // Disable analytic clips when we have MSAA. In MSAA we never conflate coverage and opacity.
  194. maxAnalyticFPs = 0;
  195. // We disable MSAA when avoiding stencil.
  196. SkASSERT(!context->priv().caps()->avoidStencilBuffers());
  197. }
  198. auto* ccpr = context->priv().drawingManager()->getCoverageCountingPathRenderer();
  199. GrReducedClip reducedClip(*fStack, devBounds, context->priv().caps(),
  200. maxWindowRectangles, maxAnalyticFPs, ccpr ? maxAnalyticFPs : 0);
  201. if (InitialState::kAllOut == reducedClip.initialState() &&
  202. reducedClip.maskElements().isEmpty()) {
  203. return false;
  204. }
  205. if (reducedClip.hasScissor() && !GrClip::IsInsideClip(reducedClip.scissor(), devBounds)) {
  206. out->hardClip().addScissor(reducedClip.scissor(), bounds);
  207. }
  208. if (!reducedClip.windowRectangles().empty()) {
  209. out->hardClip().addWindowRectangles(reducedClip.windowRectangles(),
  210. GrWindowRectsState::Mode::kExclusive);
  211. }
  212. if (!reducedClip.maskElements().isEmpty()) {
  213. if (!this->applyClipMask(context, renderTargetContext, reducedClip, hasUserStencilSettings,
  214. out)) {
  215. return false;
  216. }
  217. }
  218. // The opList ID must not be looked up until AFTER producing the clip mask (if any). That step
  219. // can cause a flush or otherwise change which opList our draw is going into.
  220. uint32_t opListID = renderTargetContext->getOpList()->uniqueID();
  221. if (auto clipFPs = reducedClip.finishAndDetachAnalyticFPs(ccpr, opListID)) {
  222. out->addCoverageFP(std::move(clipFPs));
  223. }
  224. return true;
  225. }
  226. bool GrClipStackClip::applyClipMask(GrRecordingContext* context,
  227. GrRenderTargetContext* renderTargetContext,
  228. const GrReducedClip& reducedClip, bool hasUserStencilSettings,
  229. GrAppliedClip* out) const {
  230. #ifdef SK_DEBUG
  231. SkASSERT(reducedClip.hasScissor());
  232. SkIRect rtIBounds = SkIRect::MakeWH(renderTargetContext->width(),
  233. renderTargetContext->height());
  234. const SkIRect& scissor = reducedClip.scissor();
  235. SkASSERT(rtIBounds.contains(scissor)); // Mask shouldn't be larger than the RT.
  236. #endif
  237. // MIXED SAMPLES TODO: We may want to explore using the stencil buffer for AA clipping.
  238. if ((renderTargetContext->numSamples() <= 1 && reducedClip.maskRequiresAA()) ||
  239. context->priv().caps()->avoidStencilBuffers() ||
  240. renderTargetContext->wrapsVkSecondaryCB()) {
  241. sk_sp<GrTextureProxy> result;
  242. if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
  243. // The clip geometry is complex enough that it will be more efficient to create it
  244. // entirely in software
  245. result = this->createSoftwareClipMask(context, reducedClip, renderTargetContext);
  246. } else {
  247. result = this->createAlphaClipMask(context, reducedClip);
  248. }
  249. if (result) {
  250. // The mask's top left coord should be pinned to the rounded-out top left corner of
  251. // the clip's device space bounds.
  252. out->addCoverageFP(create_fp_for_mask(std::move(result), reducedClip.scissor()));
  253. return true;
  254. }
  255. // If alpha or software clip mask creation fails, fall through to the stencil code paths,
  256. // unless stencils are disallowed.
  257. if (context->priv().caps()->avoidStencilBuffers() ||
  258. renderTargetContext->wrapsVkSecondaryCB()) {
  259. SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
  260. "Clip will be ignored.\n");
  261. return false;
  262. }
  263. }
  264. // This relies on the property that a reduced sub-rect of the last clip will contain all the
  265. // relevant window rectangles that were in the last clip. This subtle requirement will go away
  266. // after clipping is overhauled.
  267. if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(),
  268. reducedClip.numAnalyticFPs())) {
  269. reducedClip.drawStencilClipMask(context, renderTargetContext);
  270. renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(),
  271. reducedClip.numAnalyticFPs());
  272. }
  273. // GrAppliedClip doesn't need to figure numAnalyticFPs into its key (used by operator==) because
  274. // it verifies the FPs are also equal.
  275. out->hardClip().addStencilClip(reducedClip.maskGenID());
  276. return true;
  277. }
  278. ////////////////////////////////////////////////////////////////////////////////
  279. // Create a 8-bit clip mask in alpha
  280. static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, int numAnalyticFPs,
  281. GrUniqueKey* key) {
  282. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  283. GrUniqueKey::Builder builder(key, kDomain, 4, GrClipStackClip::kMaskTestTag);
  284. builder[0] = clipGenID;
  285. // SkToS16 because image filters outset layers to a size indicated by the filter, which can
  286. // sometimes result in negative coordinates from device space.
  287. builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16);
  288. builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16);
  289. builder[3] = numAnalyticFPs;
  290. }
  291. static void add_invalidate_on_pop_message(GrRecordingContext* context,
  292. const SkClipStack& stack, uint32_t clipGenID,
  293. const GrUniqueKey& clipMaskKey) {
  294. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  295. SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
  296. while (const Element* element = iter.prev()) {
  297. if (element->getGenID() == clipGenID) {
  298. element->addResourceInvalidationMessage(proxyProvider, clipMaskKey);
  299. return;
  300. }
  301. }
  302. SkDEBUGFAIL("Gen ID was not found in stack.");
  303. }
  304. sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrRecordingContext* context,
  305. const GrReducedClip& reducedClip) const {
  306. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  307. GrUniqueKey key;
  308. create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
  309. reducedClip.numAnalyticFPs(), &key);
  310. sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey(
  311. key, kTopLeft_GrSurfaceOrigin));
  312. if (proxy) {
  313. return proxy;
  314. }
  315. auto isProtected = proxy->isProtected() ? GrProtected::kYes : GrProtected::kNo;
  316. sk_sp<GrRenderTargetContext> rtc(
  317. context->priv().makeDeferredRenderTargetContextWithFallback(SkBackingFit::kApprox,
  318. reducedClip.width(),
  319. reducedClip.height(),
  320. GrColorType::kAlpha_8,
  321. nullptr,
  322. 1,
  323. GrMipMapped::kNo,
  324. kTopLeft_GrSurfaceOrigin,
  325. nullptr,
  326. SkBudgeted::kYes,
  327. isProtected));
  328. if (!rtc) {
  329. return nullptr;
  330. }
  331. if (!reducedClip.drawAlphaClipMask(rtc.get())) {
  332. return nullptr;
  333. }
  334. sk_sp<GrTextureProxy> result(rtc->asTextureProxyRef());
  335. if (!result) {
  336. return nullptr;
  337. }
  338. SkASSERT(result->origin() == kTopLeft_GrSurfaceOrigin);
  339. proxyProvider->assignUniqueKeyToProxy(key, result.get());
  340. add_invalidate_on_pop_message(context, *fStack, reducedClip.maskGenID(), key);
  341. return result;
  342. }
  343. namespace {
  344. /**
  345. * Payload class for use with GrTDeferredProxyUploader. The clip mask code renders multiple
  346. * elements, each storing their own AA setting (and already transformed into device space). This
  347. * stores all of the information needed by the worker thread to draw all clip elements (see below,
  348. * in createSoftwareClipMask).
  349. */
  350. class ClipMaskData {
  351. public:
  352. ClipMaskData(const GrReducedClip& reducedClip)
  353. : fScissor(reducedClip.scissor())
  354. , fInitialState(reducedClip.initialState()) {
  355. for (ElementList::Iter iter(reducedClip.maskElements()); iter.get(); iter.next()) {
  356. fElements.addToTail(*iter.get());
  357. }
  358. }
  359. const SkIRect& scissor() const { return fScissor; }
  360. InitialState initialState() const { return fInitialState; }
  361. const ElementList& elements() const { return fElements; }
  362. private:
  363. SkIRect fScissor;
  364. InitialState fInitialState;
  365. ElementList fElements;
  366. };
  367. }
  368. static void draw_clip_elements_to_mask_helper(GrSWMaskHelper& helper, const ElementList& elements,
  369. const SkIRect& scissor, InitialState initialState) {
  370. // Set the matrix so that rendered clip elements are transformed to mask space from clip space.
  371. SkMatrix translate;
  372. translate.setTranslate(SkIntToScalar(-scissor.left()), SkIntToScalar(-scissor.top()));
  373. helper.clear(InitialState::kAllIn == initialState ? 0xFF : 0x00);
  374. for (ElementList::Iter iter(elements); iter.get(); iter.next()) {
  375. const Element* element = iter.get();
  376. SkClipOp op = element->getOp();
  377. GrAA aa = GrAA(element->isAA());
  378. if (kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op) {
  379. // Intersect and reverse difference require modifying pixels outside of the geometry
  380. // that is being "drawn". In both cases we erase all the pixels outside of the geometry
  381. // but leave the pixels inside the geometry alone. For reverse difference we invert all
  382. // the pixels before clearing the ones outside the geometry.
  383. if (kReverseDifference_SkClipOp == op) {
  384. SkRect temp = SkRect::Make(scissor);
  385. // invert the entire scene
  386. helper.drawRect(temp, translate, SkRegion::kXOR_Op, GrAA::kNo, 0xFF);
  387. }
  388. SkPath clipPath;
  389. element->asDeviceSpacePath(&clipPath);
  390. clipPath.toggleInverseFillType();
  391. GrShape shape(clipPath, GrStyle::SimpleFill());
  392. helper.drawShape(shape, translate, SkRegion::kReplace_Op, aa, 0x00);
  393. continue;
  394. }
  395. // The other ops (union, xor, diff) only affect pixels inside
  396. // the geometry so they can just be drawn normally
  397. if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
  398. helper.drawRect(element->getDeviceSpaceRect(), translate, (SkRegion::Op)op, aa, 0xFF);
  399. } else {
  400. SkPath path;
  401. element->asDeviceSpacePath(&path);
  402. GrShape shape(path, GrStyle::SimpleFill());
  403. helper.drawShape(shape, translate, (SkRegion::Op)op, aa, 0xFF);
  404. }
  405. }
  406. }
  407. sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
  408. GrRecordingContext* context, const GrReducedClip& reducedClip,
  409. GrRenderTargetContext* renderTargetContext) const {
  410. GrUniqueKey key;
  411. create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
  412. reducedClip.numAnalyticFPs(), &key);
  413. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  414. sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey(
  415. key, kTopLeft_GrSurfaceOrigin));
  416. if (proxy) {
  417. return proxy;
  418. }
  419. // The mask texture may be larger than necessary. We round out the clip bounds and pin the top
  420. // left corner of the resulting rect to the top left of the texture.
  421. SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
  422. SkTaskGroup* taskGroup = nullptr;
  423. if (auto direct = context->priv().asDirectContext()) {
  424. taskGroup = direct->priv().getTaskGroup();
  425. }
  426. if (taskGroup && renderTargetContext) {
  427. // Create our texture proxy
  428. GrSurfaceDesc desc;
  429. desc.fWidth = maskSpaceIBounds.width();
  430. desc.fHeight = maskSpaceIBounds.height();
  431. desc.fConfig = kAlpha_8_GrPixelConfig;
  432. GrBackendFormat format =
  433. context->priv().caps()->getBackendFormatFromColorType(GrColorType::kAlpha_8);
  434. // MDB TODO: We're going to fill this proxy with an ASAP upload (which is out of order wrt
  435. // to ops), so it can't have any pending IO.
  436. proxy = proxyProvider->createProxy(format, desc, GrRenderable::kNo, 1,
  437. kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox,
  438. SkBudgeted::kYes, GrProtected::kNo);
  439. auto uploader = skstd::make_unique<GrTDeferredProxyUploader<ClipMaskData>>(reducedClip);
  440. GrTDeferredProxyUploader<ClipMaskData>* uploaderRaw = uploader.get();
  441. auto drawAndUploadMask = [uploaderRaw, maskSpaceIBounds] {
  442. TRACE_EVENT0("skia.gpu", "Threaded SW Clip Mask Render");
  443. GrSWMaskHelper helper(uploaderRaw->getPixels());
  444. if (helper.init(maskSpaceIBounds)) {
  445. draw_clip_elements_to_mask_helper(helper, uploaderRaw->data().elements(),
  446. uploaderRaw->data().scissor(),
  447. uploaderRaw->data().initialState());
  448. } else {
  449. SkDEBUGFAIL("Unable to allocate SW clip mask.");
  450. }
  451. uploaderRaw->signalAndFreeData();
  452. };
  453. taskGroup->add(std::move(drawAndUploadMask));
  454. proxy->texPriv().setDeferredUploader(std::move(uploader));
  455. } else {
  456. GrSWMaskHelper helper;
  457. if (!helper.init(maskSpaceIBounds)) {
  458. return nullptr;
  459. }
  460. draw_clip_elements_to_mask_helper(helper, reducedClip.maskElements(), reducedClip.scissor(),
  461. reducedClip.initialState());
  462. proxy = helper.toTextureProxy(context, SkBackingFit::kApprox);
  463. }
  464. SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
  465. proxyProvider->assignUniqueKeyToProxy(key, proxy.get());
  466. add_invalidate_on_pop_message(context, *fStack, reducedClip.maskGenID(), key);
  467. return proxy;
  468. }