GrSurfaceContext.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  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 "src/gpu/GrSurfaceContext.h"
  8. #include "include/private/GrRecordingContext.h"
  9. #include "src/core/SkAutoPixmapStorage.h"
  10. #include "src/gpu/GrAuditTrail.h"
  11. #include "src/gpu/GrClip.h"
  12. #include "src/gpu/GrContextPriv.h"
  13. #include "src/gpu/GrDataUtils.h"
  14. #include "src/gpu/GrDrawingManager.h"
  15. #include "src/gpu/GrGpu.h"
  16. #include "src/gpu/GrOpList.h"
  17. #include "src/gpu/GrRecordingContextPriv.h"
  18. #include "src/gpu/GrRenderTargetContext.h"
  19. #include "src/gpu/GrSurfaceContextPriv.h"
  20. #include "src/gpu/GrSurfacePriv.h"
  21. #include "src/gpu/GrTextureContext.h"
  22. #include "src/gpu/SkGr.h"
  23. #include "src/gpu/effects/GrBicubicEffect.h"
  24. #define ASSERT_SINGLE_OWNER \
  25. SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
  26. #define RETURN_FALSE_IF_ABANDONED if (this->fContext->priv().abandoned()) { return false; }
  27. // In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
  28. // GrOpLists to be picked up and added to by renderTargetContexts lower in the call
  29. // stack. When this occurs with a closed GrOpList, a new one will be allocated
  30. // when the renderTargetContext attempts to use it (via getOpList).
  31. GrSurfaceContext::GrSurfaceContext(GrRecordingContext* context,
  32. GrColorType colorType,
  33. SkAlphaType alphaType,
  34. sk_sp<SkColorSpace> colorSpace)
  35. : fContext(context), fColorSpaceInfo(colorType, alphaType, std::move(colorSpace)) {}
  36. GrAuditTrail* GrSurfaceContext::auditTrail() {
  37. return fContext->priv().auditTrail();
  38. }
  39. GrDrawingManager* GrSurfaceContext::drawingManager() {
  40. return fContext->priv().drawingManager();
  41. }
  42. const GrDrawingManager* GrSurfaceContext::drawingManager() const {
  43. return fContext->priv().drawingManager();
  44. }
  45. #ifdef SK_DEBUG
  46. GrSingleOwner* GrSurfaceContext::singleOwner() {
  47. return fContext->priv().singleOwner();
  48. }
  49. #endif
  50. bool GrSurfaceContext::readPixels(const GrPixelInfo& origDstInfo, void* dst, size_t rowBytes,
  51. SkIPoint pt, GrContext* direct) {
  52. ASSERT_SINGLE_OWNER
  53. RETURN_FALSE_IF_ABANDONED
  54. SkDEBUGCODE(this->validate();)
  55. GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::readPixels");
  56. if (!direct && !(direct = fContext->priv().asDirectContext())) {
  57. return false;
  58. }
  59. if (!dst) {
  60. return false;
  61. }
  62. size_t tightRowBytes = origDstInfo.minRowBytes();
  63. if (!rowBytes) {
  64. rowBytes = tightRowBytes;
  65. } else if (rowBytes < tightRowBytes) {
  66. return false;
  67. }
  68. if (!origDstInfo.isValid()) {
  69. return false;
  70. }
  71. GrSurfaceProxy* srcProxy = this->asSurfaceProxy();
  72. // MDB TODO: delay this instantiation until later in the method
  73. if (!srcProxy->instantiate(direct->priv().resourceProvider())) {
  74. return false;
  75. }
  76. GrSurface* srcSurface = srcProxy->peekSurface();
  77. auto dstInfo = origDstInfo;
  78. if (!dstInfo.clip(this->width(), this->height(), &pt, &dst, rowBytes)) {
  79. return false;
  80. }
  81. // Our tight row bytes may have been changed by clipping.
  82. tightRowBytes = dstInfo.minRowBytes();
  83. bool premul = this->colorSpaceInfo().alphaType() == kUnpremul_SkAlphaType &&
  84. dstInfo.alphaType() == kPremul_SkAlphaType;
  85. bool unpremul = this->colorSpaceInfo().alphaType() == kPremul_SkAlphaType &&
  86. dstInfo.alphaType() == kUnpremul_SkAlphaType;
  87. bool needColorConversion = SkColorSpaceXformSteps::Required(this->colorSpaceInfo().colorSpace(),
  88. dstInfo.colorSpace());
  89. const GrCaps* caps = direct->priv().caps();
  90. // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't
  91. // care so much about getImageData performance. However, in order to ensure putImageData/
  92. // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary
  93. // unpremul step to writeSurfacePixels's premul step (which is determined empirically in
  94. // fContext->vaildaPMUPMConversionExists()).
  95. bool canvas2DFastPath = unpremul && !needColorConversion &&
  96. (GrColorType::kRGBA_8888 == dstInfo.colorType() ||
  97. GrColorType::kBGRA_8888 == dstInfo.colorType()) &&
  98. SkToBool(srcProxy->asTextureProxy()) &&
  99. (srcProxy->config() == kRGBA_8888_GrPixelConfig ||
  100. srcProxy->config() == kBGRA_8888_GrPixelConfig) &&
  101. caps->isConfigRenderable(kRGBA_8888_GrPixelConfig) &&
  102. direct->priv().validPMUPMConversionExists();
  103. auto readFlag = caps->surfaceSupportsReadPixels(srcSurface);
  104. if (readFlag == GrCaps::SurfaceReadPixelsSupport::kUnsupported) {
  105. return false;
  106. }
  107. if (readFlag == GrCaps::SurfaceReadPixelsSupport::kCopyToTexture2D || canvas2DFastPath) {
  108. GrColorType colorType = canvas2DFastPath ? GrColorType::kRGBA_8888
  109. : this->colorSpaceInfo().colorType();
  110. sk_sp<SkColorSpace> cs = canvas2DFastPath ? nullptr
  111. : this->colorSpaceInfo().refColorSpace();
  112. sk_sp<GrRenderTargetContext> tempCtx = direct->priv().makeDeferredRenderTargetContext(
  113. SkBackingFit::kApprox, dstInfo.width(), dstInfo.height(), colorType, std::move(cs),
  114. 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, nullptr, SkBudgeted::kYes);
  115. if (!tempCtx) {
  116. return false;
  117. }
  118. std::unique_ptr<GrFragmentProcessor> fp;
  119. if (canvas2DFastPath) {
  120. fp = direct->priv().createPMToUPMEffect(
  121. GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()),
  122. SkMatrix::I()));
  123. if (dstInfo.colorType() == GrColorType::kBGRA_8888) {
  124. fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
  125. dstInfo = dstInfo.makeColorType(GrColorType::kRGBA_8888);
  126. }
  127. // The render target context is incorrectly tagged as kPremul even though we're writing
  128. // unpremul data thanks to the PMToUPM effect. Fake out the dst alpha type so we don't
  129. // double unpremul.
  130. dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
  131. } else {
  132. fp = GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()), SkMatrix::I());
  133. }
  134. if (!fp) {
  135. return false;
  136. }
  137. GrPaint paint;
  138. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  139. paint.addColorFragmentProcessor(std::move(fp));
  140. tempCtx->asRenderTargetContext()->fillRectToRect(
  141. GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
  142. SkRect::MakeWH(dstInfo.width(), dstInfo.height()),
  143. SkRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height()));
  144. return tempCtx->readPixels(dstInfo, dst, rowBytes, {0, 0}, direct);
  145. }
  146. bool flip = srcProxy->origin() == kBottomLeft_GrSurfaceOrigin;
  147. auto supportedRead = caps->supportedReadPixelsColorType(
  148. this->colorSpaceInfo().colorType(), srcProxy->backendFormat(), dstInfo.colorType());
  149. bool makeTight = !caps->readPixelsRowBytesSupport() && tightRowBytes != rowBytes;
  150. bool convert = unpremul || premul || needColorConversion || flip || makeTight ||
  151. (dstInfo.colorType() != supportedRead.fColorType) ||
  152. supportedRead.fSwizzle != GrSwizzle::RGBA();
  153. std::unique_ptr<char[]> tmpPixels;
  154. GrPixelInfo tmpInfo;
  155. void* readDst = dst;
  156. size_t readRB = rowBytes;
  157. if (convert) {
  158. tmpInfo = {supportedRead.fColorType, this->colorSpaceInfo().alphaType(),
  159. this->colorSpaceInfo().refColorSpace(), dstInfo.width(), dstInfo.height()};
  160. size_t tmpRB = tmpInfo.minRowBytes();
  161. size_t size = tmpRB * tmpInfo.height();
  162. // Chrome MSAN bots require the data to be initialized (hence the ()).
  163. tmpPixels.reset(new char[size]());
  164. readDst = tmpPixels.get();
  165. readRB = tmpRB;
  166. pt.fY = flip ? srcSurface->height() - pt.fY - dstInfo.height() : pt.fY;
  167. }
  168. direct->priv().flushSurface(srcProxy);
  169. if (!direct->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dstInfo.width(),
  170. dstInfo.height(), supportedRead.fColorType, readDst,
  171. readRB)) {
  172. return false;
  173. }
  174. if (convert) {
  175. return GrConvertPixels(dstInfo, dst, rowBytes, tmpInfo, readDst, readRB, flip,
  176. supportedRead.fSwizzle);
  177. }
  178. return true;
  179. }
  180. bool GrSurfaceContext::writePixels(const GrPixelInfo& origSrcInfo, const void* src, size_t rowBytes,
  181. SkIPoint pt, GrContext* direct) {
  182. ASSERT_SINGLE_OWNER
  183. RETURN_FALSE_IF_ABANDONED
  184. SkDEBUGCODE(this->validate();)
  185. GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContext::writePixels");
  186. if (!direct && !(direct = fContext->priv().asDirectContext())) {
  187. return false;
  188. }
  189. if (this->asSurfaceProxy()->readOnly()) {
  190. return false;
  191. }
  192. if (!src) {
  193. return false;
  194. }
  195. size_t tightRowBytes = origSrcInfo.minRowBytes();
  196. if (!rowBytes) {
  197. rowBytes = tightRowBytes;
  198. } else if (rowBytes < tightRowBytes) {
  199. return false;
  200. }
  201. if (!origSrcInfo.isValid()) {
  202. return false;
  203. }
  204. GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
  205. if (!dstProxy->instantiate(direct->priv().resourceProvider())) {
  206. return false;
  207. }
  208. GrSurface* dstSurface = dstProxy->peekSurface();
  209. auto srcInfo = origSrcInfo;
  210. if (!srcInfo.clip(this->width(), this->height(), &pt, &src, rowBytes)) {
  211. return false;
  212. }
  213. // Our tight row bytes may have been changed by clipping.
  214. tightRowBytes = srcInfo.minRowBytes();
  215. bool premul = this->colorSpaceInfo().alphaType() == kPremul_SkAlphaType &&
  216. srcInfo.alphaType() == kUnpremul_SkAlphaType;
  217. bool unpremul = this->colorSpaceInfo().alphaType() == kUnpremul_SkAlphaType &&
  218. srcInfo.alphaType() == kPremul_SkAlphaType;
  219. bool needColorConversion = SkColorSpaceXformSteps::Required(
  220. srcInfo.colorSpace(), this->colorSpaceInfo().colorSpace());
  221. const GrCaps* caps = direct->priv().caps();
  222. // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs
  223. // that are premultiplied on the GPU. This is kept as narrow as possible for now.
  224. bool canvas2DFastPath = !caps->avoidWritePixelsFastPath() && premul && !needColorConversion &&
  225. (srcInfo.colorType() == GrColorType::kRGBA_8888 ||
  226. srcInfo.colorType() == GrColorType::kBGRA_8888) &&
  227. SkToBool(this->asRenderTargetContext()) &&
  228. (dstProxy->config() == kRGBA_8888_GrPixelConfig ||
  229. dstProxy->config() == kBGRA_8888_GrPixelConfig) &&
  230. direct->priv().caps()->isConfigTexturable(kRGBA_8888_GrPixelConfig) &&
  231. direct->priv().validPMUPMConversionExists();
  232. if (!caps->surfaceSupportsWritePixels(dstSurface) || canvas2DFastPath) {
  233. GrSurfaceDesc desc;
  234. desc.fWidth = srcInfo.width();
  235. desc.fHeight = srcInfo.height();
  236. GrColorType colorType;
  237. GrBackendFormat format;
  238. SkAlphaType alphaType;
  239. if (canvas2DFastPath) {
  240. desc.fConfig = kRGBA_8888_GrPixelConfig;
  241. colorType = GrColorType::kRGBA_8888;
  242. format = caps->getBackendFormatFromColorType(colorType);
  243. alphaType = kUnpremul_SkAlphaType;
  244. } else {
  245. desc.fConfig = dstProxy->config();
  246. colorType = this->colorSpaceInfo().colorType();
  247. format = dstProxy->backendFormat().makeTexture2D();
  248. if (!format.isValid()) {
  249. return false;
  250. }
  251. alphaType = this->colorSpaceInfo().alphaType();
  252. }
  253. // It is more efficient for us to write pixels into a top left origin so we prefer that.
  254. // However, if the final proxy isn't a render target then we must use a copy to move the
  255. // data into it which requires the origins to match. If the final proxy is a render target
  256. // we can use a draw instead which doesn't have this origin restriction. Thus for render
  257. // targets we will use top left and otherwise we will make the origins match.
  258. GrSurfaceOrigin tempOrigin =
  259. this->asRenderTargetContext() ? kTopLeft_GrSurfaceOrigin : dstProxy->origin();
  260. auto tempProxy = direct->priv().proxyProvider()->createProxy(
  261. format, desc, GrRenderable::kNo, 1, tempOrigin, SkBackingFit::kApprox,
  262. SkBudgeted::kYes, GrProtected::kNo);
  263. if (!tempProxy) {
  264. return false;
  265. }
  266. auto tempCtx = direct->priv().drawingManager()->makeTextureContext(
  267. tempProxy, colorType, alphaType, this->colorSpaceInfo().refColorSpace());
  268. if (!tempCtx) {
  269. return false;
  270. }
  271. // In the fast path we always write the srcData to the temp context as though it were RGBA.
  272. // When the data is really BGRA the write will cause the R and B channels to be swapped in
  273. // the intermediate surface which gets corrected by a swizzle effect when drawing to the
  274. // dst.
  275. if (canvas2DFastPath) {
  276. srcInfo = srcInfo.makeColorType(GrColorType::kRGBA_8888);
  277. }
  278. if (!tempCtx->writePixels(srcInfo, src, rowBytes, {0, 0}, direct)) {
  279. return false;
  280. }
  281. if (this->asRenderTargetContext()) {
  282. std::unique_ptr<GrFragmentProcessor> fp;
  283. if (canvas2DFastPath) {
  284. fp = direct->priv().createUPMToPMEffect(
  285. GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I()));
  286. // Important: check the original src color type here!
  287. if (origSrcInfo.colorType() == GrColorType::kBGRA_8888) {
  288. fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
  289. }
  290. } else {
  291. fp = GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I());
  292. }
  293. if (!fp) {
  294. return false;
  295. }
  296. GrPaint paint;
  297. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  298. paint.addColorFragmentProcessor(std::move(fp));
  299. this->asRenderTargetContext()->fillRectToRect(
  300. GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
  301. SkRect::MakeXYWH(pt.fX, pt.fY, srcInfo.width(), srcInfo.height()),
  302. SkRect::MakeWH(srcInfo.width(), srcInfo.height()));
  303. } else {
  304. SkIRect srcRect = SkIRect::MakeWH(srcInfo.width(), srcInfo.height());
  305. SkIPoint dstPoint = SkIPoint::Make(pt.fX, pt.fY);
  306. if (!this->copy(tempProxy.get(), srcRect, dstPoint)) {
  307. return false;
  308. }
  309. }
  310. return true;
  311. }
  312. GrColorType allowedColorType =
  313. caps->supportedWritePixelsColorType(dstProxy->config(), srcInfo.colorType());
  314. bool flip = dstProxy->origin() == kBottomLeft_GrSurfaceOrigin;
  315. bool makeTight = !caps->writePixelsRowBytesSupport() && rowBytes != tightRowBytes;
  316. bool convert = premul || unpremul || needColorConversion || makeTight ||
  317. (srcInfo.colorType() != allowedColorType) || flip;
  318. std::unique_ptr<char[]> tmpPixels;
  319. GrColorType srcColorType = srcInfo.colorType();
  320. if (convert) {
  321. GrPixelInfo tmpInfo(allowedColorType, this->colorSpaceInfo().alphaType(),
  322. this->colorSpaceInfo().refColorSpace(), srcInfo.width(),
  323. srcInfo.height());
  324. auto tmpRB = tmpInfo.minRowBytes();
  325. tmpPixels.reset(new char[tmpRB * tmpInfo.height()]);
  326. GrConvertPixels(tmpInfo, tmpPixels.get(), tmpRB, srcInfo, src, rowBytes, flip);
  327. srcColorType = tmpInfo.colorType();
  328. rowBytes = tmpRB;
  329. src = tmpPixels.get();
  330. pt.fY = flip ? dstSurface->height() - pt.fY - tmpInfo.height() : pt.fY;
  331. }
  332. // On platforms that prefer flushes over VRAM use (i.e., ANGLE) we're better off forcing a
  333. // complete flush here. On platforms that prefer VRAM use over flushes we're better off
  334. // giving the drawing manager the chance of skipping the flush (i.e., by passing in the
  335. // destination proxy)
  336. // TODO: should this policy decision just be moved into the drawing manager?
  337. direct->priv().flushSurface(caps->preferVRAMUseOverFlushes() ? dstProxy : nullptr);
  338. return direct->priv().getGpu()->writePixels(dstSurface, pt.fX, pt.fY, srcInfo.width(),
  339. srcInfo.height(), srcColorType, src, rowBytes);
  340. }
  341. bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
  342. ASSERT_SINGLE_OWNER
  343. RETURN_FALSE_IF_ABANDONED
  344. SkDEBUGCODE(this->validate();)
  345. GR_AUDIT_TRAIL_AUTO_FRAME(this->auditTrail(), "GrSurfaceContextPriv::copy");
  346. const GrCaps* caps = fContext->priv().caps();
  347. SkASSERT(src->backendFormat().textureType() != GrTextureType::kExternal);
  348. SkASSERT(src->origin() == this->asSurfaceProxy()->origin());
  349. SkASSERT(caps->makeConfigSpecific(src->config(), src->backendFormat()) ==
  350. caps->makeConfigSpecific(this->asSurfaceProxy()->config(),
  351. this->asSurfaceProxy()->backendFormat()));
  352. GrSurfaceProxy* dst = this->asSurfaceProxy();
  353. if (!caps->canCopySurface(dst, src, srcRect, dstPoint)) {
  354. return false;
  355. }
  356. return this->getOpList()->copySurface(fContext, dst, src, srcRect, dstPoint);
  357. }
  358. sk_sp<GrRenderTargetContext> GrSurfaceContext::rescale(const SkImageInfo& info,
  359. const SkIRect& srcRect,
  360. SkSurface::RescaleGamma rescaleGamma,
  361. SkFilterQuality rescaleQuality) {
  362. auto direct = fContext->priv().asDirectContext();
  363. if (!direct) {
  364. return nullptr;
  365. }
  366. auto rtProxy = this->asRenderTargetProxy();
  367. if (rtProxy && rtProxy->wrapsVkSecondaryCB()) {
  368. return nullptr;
  369. }
  370. // We rescale by drawing and don't currently support drawing to a kUnpremul destination.
  371. if (info.alphaType() == kUnpremul_SkAlphaType) {
  372. return nullptr;
  373. }
  374. int srcW = srcRect.width();
  375. int srcH = srcRect.height();
  376. int srcX = srcRect.fLeft;
  377. int srcY = srcRect.fTop;
  378. sk_sp<GrTextureProxy> texProxy = sk_ref_sp(this->asTextureProxy());
  379. SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
  380. if (!texProxy) {
  381. texProxy = GrSurfaceProxy::Copy(fContext, this->asSurfaceProxy(), GrMipMapped::kNo, srcRect,
  382. SkBackingFit::kApprox, SkBudgeted::kNo);
  383. if (!texProxy) {
  384. return nullptr;
  385. }
  386. srcX = 0;
  387. srcY = 0;
  388. constraint = SkCanvas::kFast_SrcRectConstraint;
  389. }
  390. float sx = (float)info.width() / srcW;
  391. float sy = (float)info.height() / srcH;
  392. // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
  393. int stepsX;
  394. int stepsY;
  395. if (rescaleQuality > kNone_SkFilterQuality) {
  396. stepsX = static_cast<int>((sx > 1.f) ? ceil(log2f(sx)) : floor(log2f(sx)));
  397. stepsY = static_cast<int>((sy > 1.f) ? ceil(log2f(sy)) : floor(log2f(sy)));
  398. } else {
  399. stepsX = sx != 1.f;
  400. stepsY = sy != 1.f;
  401. }
  402. SkASSERT(stepsX || stepsY);
  403. auto currCtx = sk_ref_sp(this);
  404. // Assume we should ignore the rescale linear request if the surface has no color space since
  405. // it's unclear how we'd linearize from an unknown color space.
  406. if (rescaleGamma == SkSurface::kLinear && this->colorSpaceInfo().colorSpace() &&
  407. !this->colorSpaceInfo().colorSpace()->gammaIsLinear()) {
  408. auto cs = this->colorSpaceInfo().colorSpace()->makeLinearGamma();
  409. auto xform = GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(),
  410. this->colorSpaceInfo().alphaType(), cs.get(),
  411. kPremul_SkAlphaType);
  412. // We'll fall back to kRGBA_8888 if half float not supported.
  413. auto linearRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
  414. SkBackingFit::kExact, srcW, srcH, GrColorType::kRGBA_F16, cs, 1, GrMipMapped::kNo,
  415. kTopLeft_GrSurfaceOrigin);
  416. if (!linearRTC) {
  417. return nullptr;
  418. }
  419. linearRTC->drawTexture(GrNoClip(), texProxy, GrSamplerState::Filter::kNearest,
  420. SkBlendMode::kSrc, SK_PMColor4fWHITE, SkRect::Make(srcRect),
  421. SkRect::MakeWH(srcW, srcH), GrAA::kNo, GrQuadAAFlags::kNone,
  422. constraint, SkMatrix::I(), std::move(xform));
  423. texProxy = linearRTC->asTextureProxyRef();
  424. currCtx = std::move(linearRTC);
  425. srcX = 0;
  426. srcY = 0;
  427. constraint = SkCanvas::kFast_SrcRectConstraint;
  428. }
  429. while (stepsX || stepsY) {
  430. int nextW = info.width();
  431. int nextH = info.height();
  432. if (stepsX < 0) {
  433. nextW = info.width() << (-stepsX - 1);
  434. stepsX++;
  435. } else if (stepsX != 0) {
  436. if (stepsX > 1) {
  437. nextW = srcW * 2;
  438. }
  439. --stepsX;
  440. }
  441. if (stepsY < 0) {
  442. nextH = info.height() << (-stepsY - 1);
  443. stepsY++;
  444. } else if (stepsY != 0) {
  445. if (stepsY > 1) {
  446. nextH = srcH * 2;
  447. }
  448. --stepsY;
  449. }
  450. GrColorType colorType = currCtx->colorSpaceInfo().colorType();
  451. auto cs = currCtx->colorSpaceInfo().refColorSpace();
  452. sk_sp<GrColorSpaceXform> xform;
  453. auto prevAlphaType = currCtx->colorSpaceInfo().alphaType();
  454. if (!stepsX && !stepsY) {
  455. // Might as well fold conversion to final info in the last step.
  456. cs = info.refColorSpace();
  457. colorType = SkColorTypeToGrColorType(info.colorType());
  458. xform = GrColorSpaceXform::Make(currCtx->colorSpaceInfo().colorSpace(),
  459. currCtx->colorSpaceInfo().alphaType(), cs.get(),
  460. info.alphaType());
  461. }
  462. auto currRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
  463. SkBackingFit::kExact, nextW, nextH, colorType, std::move(cs), 1, GrMipMapped::kNo,
  464. kTopLeft_GrSurfaceOrigin);
  465. currCtx = currRTC;
  466. if (!currCtx) {
  467. return nullptr;
  468. }
  469. auto dstRect = SkRect::MakeWH(nextW, nextH);
  470. if (rescaleQuality == kHigh_SkFilterQuality) {
  471. SkMatrix matrix;
  472. matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY);
  473. std::unique_ptr<GrFragmentProcessor> fp;
  474. auto dir = GrBicubicEffect::Direction::kXY;
  475. if (nextW == srcW) {
  476. dir = GrBicubicEffect::Direction::kY;
  477. } else if (nextH == srcH) {
  478. dir = GrBicubicEffect::Direction::kX;
  479. }
  480. if (srcW != texProxy->width() || srcH != texProxy->height()) {
  481. auto domain = GrTextureDomain::MakeTexelDomain(
  482. SkIRect::MakeXYWH(srcX, srcY, srcW, srcH), GrTextureDomain::kClamp_Mode);
  483. fp = GrBicubicEffect::Make(texProxy, matrix, domain, dir, prevAlphaType);
  484. } else {
  485. fp = GrBicubicEffect::Make(texProxy, matrix, dir, prevAlphaType);
  486. }
  487. if (xform) {
  488. fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
  489. }
  490. GrPaint paint;
  491. paint.addColorFragmentProcessor(std::move(fp));
  492. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  493. currRTC->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
  494. dstRect);
  495. } else {
  496. auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
  497. : GrSamplerState::Filter::kBilerp;
  498. auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
  499. currRTC->drawTexture(GrNoClip(), texProxy, filter, SkBlendMode::kSrc, SK_PMColor4fWHITE,
  500. srcSubset, dstRect, GrAA::kNo, GrQuadAAFlags::kNone, constraint,
  501. SkMatrix::I(), std::move(xform));
  502. }
  503. texProxy = currCtx->asTextureProxyRef();
  504. srcX = srcY = 0;
  505. srcW = nextW;
  506. srcH = nextH;
  507. constraint = SkCanvas::kFast_SrcRectConstraint;
  508. }
  509. SkASSERT(currCtx);
  510. return sk_ref_sp(currCtx->asRenderTargetContext());
  511. }