SkImage_GpuBase.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /*
  2. * Copyright 2018 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/core/SkPromiseImageTexture.h"
  8. #include "include/gpu/GrBackendSurface.h"
  9. #include "include/gpu/GrContext.h"
  10. #include "include/gpu/GrTexture.h"
  11. #include "include/private/GrRecordingContext.h"
  12. #include "src/core/SkBitmapCache.h"
  13. #include "src/core/SkTLList.h"
  14. #include "src/gpu/GrClip.h"
  15. #include "src/gpu/GrContextPriv.h"
  16. #include "src/gpu/GrRecordingContextPriv.h"
  17. #include "src/gpu/GrRenderTargetContext.h"
  18. #include "src/gpu/GrTextureAdjuster.h"
  19. #include "src/gpu/effects/GrYUVtoRGBEffect.h"
  20. #include "src/image/SkImage_Gpu.h"
  21. #include "src/image/SkImage_GpuBase.h"
  22. #include "src/image/SkReadPixelsRec.h"
  23. SkImage_GpuBase::SkImage_GpuBase(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
  24. SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs)
  25. : INHERITED(SkImageInfo::Make(width, height, ct, at, std::move(cs)), uniqueID)
  26. , fContext(std::move(context)) {}
  27. SkImage_GpuBase::~SkImage_GpuBase() {}
  28. //////////////////////////////////////////////////////////////////////////////////////////////////
  29. #if GR_TEST_UTILS
  30. void SkImage_GpuBase::resetContext(sk_sp<GrContext> newContext) {
  31. SkASSERT(fContext->priv().matches(newContext.get()));
  32. fContext = newContext;
  33. }
  34. #endif
  35. bool SkImage_GpuBase::ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
  36. GrPixelConfig* config, GrColorType grCT,
  37. SkColorType ct, SkAlphaType at,
  38. sk_sp<SkColorSpace> cs) {
  39. if (!tex.isValid()) {
  40. return false;
  41. }
  42. // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
  43. // create a fake image info here.
  44. SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
  45. if (!SkImageInfoIsValid(info)) {
  46. return false;
  47. }
  48. GrBackendFormat backendFormat = tex.getBackendFormat();
  49. if (!backendFormat.isValid()) {
  50. return false;
  51. }
  52. if (!ctx->priv().caps()->areColorTypeAndFormatCompatible(grCT, backendFormat)) {
  53. return false;
  54. }
  55. *config = ctx->priv().caps()->getConfigFromBackendFormat(backendFormat, grCT);
  56. return *config != kUnknown_GrPixelConfig;
  57. }
  58. //////////////////////////////////////////////////////////////////////////////////////////////////
  59. bool SkImage_GpuBase::getROPixels(SkBitmap* dst, CachingHint chint) const {
  60. auto direct = fContext->priv().asDirectContext();
  61. if (!direct) {
  62. // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
  63. return false;
  64. }
  65. const auto desc = SkBitmapCacheDesc::Make(this);
  66. if (SkBitmapCache::Find(desc, dst)) {
  67. SkASSERT(dst->isImmutable());
  68. SkASSERT(dst->getPixels());
  69. return true;
  70. }
  71. SkBitmapCache::RecPtr rec = nullptr;
  72. SkPixmap pmap;
  73. if (kAllow_CachingHint == chint) {
  74. rec = SkBitmapCache::Alloc(desc, this->imageInfo(), &pmap);
  75. if (!rec) {
  76. return false;
  77. }
  78. } else {
  79. if (!dst->tryAllocPixels(this->imageInfo()) || !dst->peekPixels(&pmap)) {
  80. return false;
  81. }
  82. }
  83. sk_sp<GrSurfaceContext> sContext =
  84. direct->priv().makeWrappedSurfaceContext(this->asTextureProxyRef(direct),
  85. SkColorTypeToGrColorType(this->colorType()),
  86. this->alphaType(),
  87. this->refColorSpace());
  88. if (!sContext) {
  89. return false;
  90. }
  91. if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), {0, 0})) {
  92. return false;
  93. }
  94. if (rec) {
  95. SkBitmapCache::Add(std::move(rec), dst);
  96. this->notifyAddedToRasterCache();
  97. }
  98. return true;
  99. }
  100. sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(GrRecordingContext* context,
  101. const SkIRect& subset) const {
  102. if (!context || !fContext->priv().matches(context)) {
  103. return nullptr;
  104. }
  105. sk_sp<GrSurfaceProxy> proxy = this->asTextureProxyRef(context);
  106. sk_sp<GrTextureProxy> copyProxy = GrSurfaceProxy::Copy(
  107. context, proxy.get(), GrMipMapped::kNo, subset, SkBackingFit::kExact,
  108. proxy->isBudgeted());
  109. if (!copyProxy) {
  110. return nullptr;
  111. }
  112. // MDB: this call is okay bc we know 'sContext' was kExact
  113. return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, this->alphaType(),
  114. std::move(copyProxy), this->refColorSpace());
  115. }
  116. bool SkImage_GpuBase::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
  117. int srcX, int srcY, CachingHint) const {
  118. auto direct = fContext->priv().asDirectContext();
  119. if (!direct) {
  120. // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
  121. return false;
  122. }
  123. if (!SkImageInfoValidConversion(dstInfo, this->imageInfo())) {
  124. return false;
  125. }
  126. sk_sp<GrSurfaceContext> sContext = direct->priv().makeWrappedSurfaceContext(
  127. this->asTextureProxyRef(direct), SkColorTypeToGrColorType(this->colorType()),
  128. this->alphaType(), this->refColorSpace());
  129. if (!sContext) {
  130. return false;
  131. }
  132. return sContext->readPixels(dstInfo, dstPixels, dstRB, {srcX, srcY});
  133. }
  134. sk_sp<GrTextureProxy> SkImage_GpuBase::asTextureProxyRef(GrRecordingContext* context,
  135. const GrSamplerState& params,
  136. SkScalar scaleAdjust[2]) const {
  137. if (!context || !fContext->priv().matches(context)) {
  138. SkASSERT(0);
  139. return nullptr;
  140. }
  141. GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(context),
  142. SkColorTypeToGrColorType(this->colorType()), this->alphaType(),
  143. this->uniqueID(), this->colorSpace());
  144. return adjuster.refTextureProxyForParams(params, scaleAdjust);
  145. }
  146. GrBackendTexture SkImage_GpuBase::onGetBackendTexture(bool flushPendingGrContextIO,
  147. GrSurfaceOrigin* origin) const {
  148. auto direct = fContext->priv().asDirectContext();
  149. if (!direct) {
  150. // This image was created with a DDL context and cannot be instantiated.
  151. return GrBackendTexture(); // invalid
  152. }
  153. sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef(direct);
  154. SkASSERT(proxy);
  155. if (!proxy->isInstantiated()) {
  156. auto resourceProvider = direct->priv().resourceProvider();
  157. if (!proxy->instantiate(resourceProvider)) {
  158. return GrBackendTexture(); // invalid
  159. }
  160. }
  161. GrTexture* texture = proxy->peekTexture();
  162. if (texture) {
  163. if (flushPendingGrContextIO) {
  164. direct->priv().flushSurface(proxy.get());
  165. }
  166. if (origin) {
  167. *origin = proxy->origin();
  168. }
  169. return texture->getBackendTexture();
  170. }
  171. return GrBackendTexture(); // invalid
  172. }
  173. GrTexture* SkImage_GpuBase::onGetTexture() const {
  174. GrTextureProxy* proxy = this->peekProxy();
  175. if (proxy && proxy->isInstantiated()) {
  176. return proxy->peekTexture();
  177. }
  178. auto direct = fContext->priv().asDirectContext();
  179. if (!direct) {
  180. // This image was created with a DDL context and cannot be instantiated.
  181. return nullptr;
  182. }
  183. sk_sp<GrTextureProxy> proxyRef = this->asTextureProxyRef(direct);
  184. SkASSERT(proxyRef && !proxyRef->isInstantiated());
  185. if (!proxyRef->instantiate(direct->priv().resourceProvider())) {
  186. return nullptr;
  187. }
  188. return proxyRef->peekTexture();
  189. }
  190. bool SkImage_GpuBase::onIsValid(GrContext* context) const {
  191. // The base class has already checked that context isn't abandoned (if it's not nullptr)
  192. if (fContext->priv().abandoned()) {
  193. return false;
  194. }
  195. if (context && !fContext->priv().matches(context)) {
  196. return false;
  197. }
  198. return true;
  199. }
  200. bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
  201. int numTextures, const SkYUVAIndex yuvaIndices[4],
  202. GrSurfaceOrigin imageOrigin,
  203. sk_sp<GrTextureProxy> tempTextureProxies[4]) {
  204. GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
  205. const GrCaps* caps = ctx->priv().caps();
  206. // We need to make a copy of the input backend textures because we need to preserve the result
  207. // of validate_backend_texture.
  208. GrBackendTexture yuvaTexturesCopy[4];
  209. for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex) {
  210. yuvaTexturesCopy[textureIndex] = yuvaTextures[textureIndex];
  211. GrBackendFormat backendFormat = yuvaTexturesCopy[textureIndex].getBackendFormat();
  212. if (!backendFormat.isValid()) {
  213. return false;
  214. }
  215. yuvaTexturesCopy[textureIndex].fConfig =
  216. caps->getYUVAConfigFromBackendFormat(backendFormat);
  217. if (yuvaTexturesCopy[textureIndex].fConfig == kUnknown_GrPixelConfig) {
  218. return false;
  219. }
  220. GrColorType grColorType = caps->getYUVAColorTypeFromBackendFormat(backendFormat);
  221. if (GrColorType::kUnknown == grColorType) {
  222. return false;
  223. }
  224. SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
  225. tempTextureProxies[textureIndex] = proxyProvider->wrapBackendTexture(
  226. yuvaTexturesCopy[textureIndex], grColorType, imageOrigin, kBorrow_GrWrapOwnership,
  227. GrWrapCacheable::kNo, kRead_GrIOType);
  228. if (!tempTextureProxies[textureIndex]) {
  229. return false;
  230. }
  231. // Check that each texture contains the channel data for the corresponding YUVA index
  232. auto componentFlags = GrColorTypeComponentFlags(grColorType);
  233. for (int yuvaIndex = 0; yuvaIndex < SkYUVAIndex::kIndexCount; ++yuvaIndex) {
  234. if (yuvaIndices[yuvaIndex].fIndex == textureIndex) {
  235. switch (yuvaIndices[yuvaIndex].fChannel) {
  236. case SkColorChannel::kR:
  237. // TODO: Chrome needs to be patched before this can be
  238. // enforced.
  239. // if (!(kRed_SkColorTypeComponentFlag & componentFlags)) {
  240. // return false;
  241. // }
  242. break;
  243. case SkColorChannel::kG:
  244. if (!(kGreen_SkColorTypeComponentFlag & componentFlags)) {
  245. return false;
  246. }
  247. break;
  248. case SkColorChannel::kB:
  249. if (!(kBlue_SkColorTypeComponentFlag & componentFlags)) {
  250. return false;
  251. }
  252. break;
  253. case SkColorChannel::kA:
  254. if (!(kAlpha_SkColorTypeComponentFlag & componentFlags)) {
  255. return false;
  256. }
  257. break;
  258. }
  259. }
  260. }
  261. }
  262. return true;
  263. }
  264. bool SkImage_GpuBase::RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
  265. const SkRect& rect, SkYUVColorSpace yuvColorSpace,
  266. sk_sp<GrColorSpaceXform> colorSpaceXform,
  267. const sk_sp<GrTextureProxy> proxies[4],
  268. const SkYUVAIndex yuvaIndices[4]) {
  269. SkASSERT(renderTargetContext);
  270. if (!renderTargetContext->asSurfaceProxy()) {
  271. return false;
  272. }
  273. GrPaint paint;
  274. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  275. auto fp = GrYUVtoRGBEffect::Make(proxies, yuvaIndices, yuvColorSpace,
  276. GrSamplerState::Filter::kNearest);
  277. if (colorSpaceXform) {
  278. fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(colorSpaceXform));
  279. }
  280. paint.addColorFragmentProcessor(std::move(fp));
  281. renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
  282. return true;
  283. }
  284. sk_sp<GrTextureProxy> SkImage_GpuBase::MakePromiseImageLazyProxy(
  285. GrContext* context, int width, int height, GrSurfaceOrigin origin, GrColorType colorType,
  286. GrBackendFormat backendFormat, GrMipMapped mipMapped,
  287. PromiseImageTextureFulfillProc fulfillProc,
  288. PromiseImageTextureReleaseProc releaseProc,
  289. PromiseImageTextureDoneProc doneProc,
  290. PromiseImageTextureContext textureContext,
  291. PromiseImageApiVersion version) {
  292. SkASSERT(context);
  293. SkASSERT(width > 0 && height > 0);
  294. SkASSERT(doneProc);
  295. SkASSERT(colorType != GrColorType::kUnknown);
  296. if (!fulfillProc || !releaseProc) {
  297. doneProc(textureContext);
  298. return nullptr;
  299. }
  300. if (mipMapped == GrMipMapped::kYes &&
  301. GrTextureTypeHasRestrictedSampling(backendFormat.textureType())) {
  302. // It is invalid to have a GL_TEXTURE_EXTERNAL or GL_TEXTURE_RECTANGLE and have mips as
  303. // well.
  304. doneProc(textureContext);
  305. return nullptr;
  306. }
  307. /**
  308. * This class is the lazy instantiation callback for promise images. It manages calling the
  309. * client's Fulfill, Release, and Done procs. It attempts to reuse a GrTexture instance in
  310. * cases where the client provides the same SkPromiseImageTexture as Fulfill results for
  311. * multiple SkImages. The created GrTexture is given a key based on a unique ID associated with
  312. * the SkPromiseImageTexture.
  313. *
  314. * The GrTexutre idle proc mechanism is used to call the Release and Done procs. We use this
  315. * instead of the GrSurface release proc because the GrTexture is cached and therefore may
  316. * outlive the proxy into which this callback is installed.
  317. *
  318. * A key invalidation message is installed on the SkPromiseImageTexture so that the GrTexture
  319. * is deleted once it can no longer be used to instantiate a proxy.
  320. */
  321. class PromiseLazyInstantiateCallback {
  322. public:
  323. PromiseLazyInstantiateCallback(PromiseImageTextureFulfillProc fulfillProc,
  324. PromiseImageTextureReleaseProc releaseProc,
  325. PromiseImageTextureDoneProc doneProc,
  326. PromiseImageTextureContext context,
  327. GrColorType colorType,
  328. PromiseImageApiVersion version)
  329. : fFulfillProc(fulfillProc)
  330. , fReleaseProc(releaseProc)
  331. , fColorType(colorType)
  332. , fVersion(version) {
  333. fDoneCallback = sk_make_sp<GrRefCntedCallback>(doneProc, context);
  334. }
  335. PromiseLazyInstantiateCallback(PromiseLazyInstantiateCallback&&) = default;
  336. PromiseLazyInstantiateCallback(const PromiseLazyInstantiateCallback&) {
  337. // Because we get wrapped in std::function we must be copyable. But we should never
  338. // be copied.
  339. SkASSERT(false);
  340. }
  341. PromiseLazyInstantiateCallback& operator=(PromiseLazyInstantiateCallback&&) = default;
  342. PromiseLazyInstantiateCallback& operator=(const PromiseLazyInstantiateCallback&) {
  343. SkASSERT(false);
  344. return *this;
  345. }
  346. ~PromiseLazyInstantiateCallback() {
  347. // Our destructor can run on any thread. We trigger the unref of fTexture by message.
  348. if (fTexture) {
  349. SkMessageBus<GrGpuResourceFreedMessage>::Post({fTexture, fTextureContextID});
  350. }
  351. }
  352. GrSurfaceProxy::LazyInstantiationResult operator()(GrResourceProvider* resourceProvider) {
  353. // We use the unique key in a way that is unrelated to the SkImage-based key that the
  354. // proxy may receive, hence kUnsynced.
  355. static constexpr auto kKeySyncMode =
  356. GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced;
  357. // Our proxy is getting instantiated for the second+ time. We are only allowed to call
  358. // Fulfill once. So return our cached result.
  359. if (fTexture) {
  360. return {sk_ref_sp(fTexture), kKeySyncMode};
  361. } else if (fColorType == GrColorType::kUnknown) {
  362. // We've already called fulfill and it failed. Our contract says that we should only
  363. // call each callback once.
  364. return {};
  365. }
  366. SkASSERT(fDoneCallback);
  367. PromiseImageTextureContext textureContext = fDoneCallback->context();
  368. sk_sp<SkPromiseImageTexture> promiseTexture = fFulfillProc(textureContext);
  369. // From here on out our contract is that the release proc must be called, even if
  370. // the return from fulfill was invalid or we fail for some other reason.
  371. auto releaseCallback = sk_make_sp<GrRefCntedCallback>(fReleaseProc, textureContext);
  372. if (!promiseTexture) {
  373. // This records that we have failed.
  374. fColorType = GrColorType::kUnknown;
  375. return {};
  376. }
  377. auto backendTexture = promiseTexture->backendTexture();
  378. if (!backendTexture.isValid()) {
  379. return {};
  380. }
  381. // TODO: delete this block
  382. {
  383. GrPixelConfig config = resourceProvider->caps()->getConfigFromBackendFormat(
  384. backendTexture.getBackendFormat(),
  385. fColorType);
  386. SkASSERT(kUnknown_GrPixelConfig != config);
  387. backendTexture.fConfig = config;
  388. }
  389. sk_sp<GrTexture> tex;
  390. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  391. GrUniqueKey key;
  392. GrUniqueKey::Builder builder(&key, kDomain, 2, "promise");
  393. builder[0] = promiseTexture->uniqueID();
  394. builder[1] = (uint32_t) fColorType;
  395. builder.finish();
  396. // A texture with this key may already exist from a different instance of this lazy
  397. // callback. This could happen if the client fulfills a promise image with a texture
  398. // that was previously used to fulfill a different promise image.
  399. if (auto surf = resourceProvider->findByUniqueKey<GrSurface>(key)) {
  400. tex = sk_ref_sp(surf->asTexture());
  401. SkASSERT(tex);
  402. } else {
  403. if ((tex = resourceProvider->wrapBackendTexture(
  404. backendTexture, fColorType, kBorrow_GrWrapOwnership,
  405. GrWrapCacheable::kYes, kRead_GrIOType))) {
  406. tex->resourcePriv().setUniqueKey(key);
  407. } else {
  408. return {};
  409. }
  410. }
  411. auto releaseIdleState = fVersion == PromiseImageApiVersion::kLegacy
  412. ? GrTexture::IdleState::kFinished
  413. : GrTexture::IdleState::kFlushed;
  414. tex->addIdleProc(std::move(releaseCallback), releaseIdleState);
  415. tex->addIdleProc(std::move(fDoneCallback), GrTexture::IdleState::kFinished);
  416. promiseTexture->addKeyToInvalidate(tex->getContext()->priv().contextID(), key);
  417. fTexture = tex.get();
  418. // We need to hold on to the GrTexture in case our proxy gets reinstantiated. However,
  419. // we can't unref in our destructor because we may be on another thread then. So we
  420. // let the cache know it is waiting on an unref message. We will send that message from
  421. // our destructor.
  422. GrContext* context = fTexture->getContext();
  423. context->priv().getResourceCache()->insertDelayedResourceUnref(fTexture);
  424. fTextureContextID = context->priv().contextID();
  425. return {std::move(tex), kKeySyncMode};
  426. }
  427. private:
  428. PromiseImageTextureFulfillProc fFulfillProc;
  429. PromiseImageTextureReleaseProc fReleaseProc;
  430. sk_sp<GrRefCntedCallback> fDoneCallback;
  431. GrTexture* fTexture = nullptr;
  432. uint32_t fTextureContextID = SK_InvalidUniqueID;
  433. GrColorType fColorType;
  434. PromiseImageApiVersion fVersion;
  435. } callback(fulfillProc, releaseProc, doneProc, textureContext, colorType, version);
  436. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  437. GrPixelConfig config = context->priv().caps()->getConfigFromBackendFormat(
  438. backendFormat,
  439. colorType);
  440. GrSurfaceDesc desc;
  441. desc.fWidth = width;
  442. desc.fHeight = height;
  443. desc.fConfig = config;
  444. // We pass kReadOnly here since we should treat content of the client's texture as immutable.
  445. // The promise API provides no way for the client to indicated that the texture is protected.
  446. return proxyProvider->createLazyProxy(
  447. std::move(callback), backendFormat, desc, GrRenderable::kNo, 1, origin, mipMapped,
  448. GrInternalSurfaceFlags::kReadOnly, SkBackingFit::kExact, SkBudgeted::kNo,
  449. GrProtected::kNo, GrSurfaceProxy::LazyInstantiationType::kDeinstantiate);
  450. }