GrBackendTextureImageGenerator.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright 2017 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/gpu/GrContext.h"
  8. #include "include/gpu/GrTexture.h"
  9. #include "include/private/GrRecordingContext.h"
  10. #include "src/core/SkMessageBus.h"
  11. #include "src/gpu/GrBackendTextureImageGenerator.h"
  12. #include "src/gpu/GrContextPriv.h"
  13. #include "src/gpu/GrGpu.h"
  14. #include "src/gpu/GrProxyProvider.h"
  15. #include "src/gpu/GrRecordingContextPriv.h"
  16. #include "src/gpu/GrRenderTargetContext.h"
  17. #include "src/gpu/GrResourceCache.h"
  18. #include "src/gpu/GrResourceProvider.h"
  19. #include "src/gpu/GrResourceProviderPriv.h"
  20. #include "src/gpu/GrSemaphore.h"
  21. #include "src/gpu/GrTexturePriv.h"
  22. #include "src/gpu/GrTextureProxyPriv.h"
  23. #include "src/gpu/SkGr.h"
  24. #include "src/gpu/gl/GrGLTexture.h"
  25. GrBackendTextureImageGenerator::RefHelper::RefHelper(GrTexture* texture, uint32_t owningContextID)
  26. : fOriginalTexture(texture)
  27. , fOwningContextID(owningContextID)
  28. , fBorrowingContextReleaseProc(nullptr)
  29. , fBorrowingContextID(SK_InvalidGenID) {}
  30. GrBackendTextureImageGenerator::RefHelper::~RefHelper() {
  31. SkASSERT(fBorrowingContextID == SK_InvalidUniqueID);
  32. // Generator has been freed, and no one is borrowing the texture. Notify the original cache
  33. // that it can free the last ref, so it happens on the correct thread.
  34. GrGpuResourceFreedMessage msg { fOriginalTexture, fOwningContextID };
  35. SkMessageBus<GrGpuResourceFreedMessage>::Post(msg);
  36. }
  37. std::unique_ptr<SkImageGenerator>
  38. GrBackendTextureImageGenerator::Make(sk_sp<GrTexture> texture, GrSurfaceOrigin origin,
  39. sk_sp<GrSemaphore> semaphore, SkColorType colorType,
  40. SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
  41. GrContext* context = texture->getContext();
  42. // Attach our texture to this context's resource cache. This ensures that deletion will happen
  43. // in the correct thread/context. This adds the only ref to the texture that will persist from
  44. // this point. That ref will be released when the generator's RefHelper is freed.
  45. context->priv().getResourceCache()->insertDelayedResourceUnref(texture.get());
  46. GrBackendTexture backendTexture = texture->getBackendTexture();
  47. // TODO: delete this block
  48. {
  49. GrBackendFormat backendFormat = backendTexture.getBackendFormat();
  50. if (!backendFormat.isValid()) {
  51. return nullptr;
  52. }
  53. backendTexture.fConfig = context->priv().caps()->getConfigFromBackendFormat(
  54. backendFormat,
  55. SkColorTypeToGrColorType(colorType));
  56. if (backendTexture.fConfig == kUnknown_GrPixelConfig) {
  57. return nullptr;
  58. }
  59. }
  60. SkImageInfo info = SkImageInfo::Make(texture->width(), texture->height(), colorType, alphaType,
  61. std::move(colorSpace));
  62. return std::unique_ptr<SkImageGenerator>(new GrBackendTextureImageGenerator(
  63. info, texture.get(), origin, context->priv().contextID(),
  64. std::move(semaphore), backendTexture));
  65. }
  66. GrBackendTextureImageGenerator::GrBackendTextureImageGenerator(const SkImageInfo& info,
  67. GrTexture* texture,
  68. GrSurfaceOrigin origin,
  69. uint32_t owningContextID,
  70. sk_sp<GrSemaphore> semaphore,
  71. const GrBackendTexture& backendTex)
  72. : INHERITED(info)
  73. , fRefHelper(new RefHelper(texture, owningContextID))
  74. , fSemaphore(std::move(semaphore))
  75. , fBackendTexture(backendTex)
  76. , fSurfaceOrigin(origin) {}
  77. GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator() {
  78. fRefHelper->unref();
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////
  81. void GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* ctx) {
  82. RefHelper* refHelper = static_cast<RefHelper*>(ctx);
  83. SkASSERT(refHelper);
  84. refHelper->fBorrowingContextReleaseProc = nullptr;
  85. refHelper->fBorrowingContextID = SK_InvalidGenID;
  86. refHelper->unref();
  87. }
  88. sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
  89. GrRecordingContext* context, const SkImageInfo& info,
  90. const SkIPoint& origin, bool willNeedMipMaps) {
  91. SkASSERT(context);
  92. if (context->backend() != fBackendTexture.backend()) {
  93. return nullptr;
  94. }
  95. if (info.colorType() != this->getInfo().colorType()) {
  96. return nullptr;
  97. }
  98. auto proxyProvider = context->priv().proxyProvider();
  99. const GrCaps* caps = context->priv().caps();
  100. fBorrowingMutex.acquire();
  101. sk_sp<GrRefCntedCallback> releaseProcHelper;
  102. if (SK_InvalidGenID != fRefHelper->fBorrowingContextID) {
  103. if (fRefHelper->fBorrowingContextID != context->priv().contextID()) {
  104. fBorrowingMutex.release();
  105. return nullptr;
  106. } else {
  107. SkASSERT(fRefHelper->fBorrowingContextReleaseProc);
  108. // Ref the release proc to be held by the proxy we make below
  109. releaseProcHelper = sk_ref_sp(fRefHelper->fBorrowingContextReleaseProc);
  110. }
  111. } else {
  112. SkASSERT(!fRefHelper->fBorrowingContextReleaseProc);
  113. // The ref we add to fRefHelper here will be passed into and owned by the
  114. // GrRefCntedCallback.
  115. fRefHelper->ref();
  116. releaseProcHelper.reset(
  117. new GrRefCntedCallback(ReleaseRefHelper_TextureReleaseProc, fRefHelper));
  118. fRefHelper->fBorrowingContextReleaseProc = releaseProcHelper.get();
  119. }
  120. fRefHelper->fBorrowingContextID = context->priv().contextID();
  121. if (!fRefHelper->fBorrowedTextureKey.isValid()) {
  122. static const auto kDomain = GrUniqueKey::GenerateDomain();
  123. GrUniqueKey::Builder builder(&fRefHelper->fBorrowedTextureKey, kDomain, 1);
  124. builder[0] = this->uniqueID();
  125. }
  126. fBorrowingMutex.release();
  127. SkASSERT(fRefHelper->fBorrowingContextID == context->priv().contextID());
  128. GrBackendFormat backendFormat = fBackendTexture.getBackendFormat();
  129. SkASSERT(backendFormat.isValid());
  130. GrColorType grColorType = SkColorTypeToGrColorType(info.colorType());
  131. GrPixelConfig config = caps->getConfigFromBackendFormat(backendFormat, grColorType);
  132. if (kUnknown_GrPixelConfig == config) {
  133. return nullptr;
  134. }
  135. SkASSERT(GrCaps::AreConfigsCompatible(fBackendTexture.config(), config));
  136. GrSurfaceDesc desc;
  137. desc.fWidth = fBackendTexture.width();
  138. desc.fHeight = fBackendTexture.height();
  139. desc.fConfig = config;
  140. GrMipMapped mipMapped = fBackendTexture.hasMipMaps() ? GrMipMapped::kYes : GrMipMapped::kNo;
  141. // Must make copies of member variables to capture in the lambda since this image generator may
  142. // be deleted before we actually execute the lambda.
  143. sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
  144. [refHelper = fRefHelper, releaseProcHelper, semaphore = fSemaphore,
  145. backendTexture = fBackendTexture, grColorType](GrResourceProvider* resourceProvider)
  146. -> GrSurfaceProxy::LazyInstantiationResult {
  147. if (semaphore) {
  148. resourceProvider->priv().gpu()->waitSemaphore(semaphore);
  149. }
  150. // If a client re-draws the same image multiple times, the texture we return
  151. // will be cached and re-used. If they draw a subset, though, we may be
  152. // re-called. In that case, we want to re-use the borrowed texture we've
  153. // previously created.
  154. sk_sp<GrTexture> tex;
  155. SkASSERT(refHelper->fBorrowedTextureKey.isValid());
  156. auto surf = resourceProvider->findByUniqueKey<GrSurface>(
  157. refHelper->fBorrowedTextureKey);
  158. if (surf) {
  159. SkASSERT(surf->asTexture());
  160. tex = sk_ref_sp(surf->asTexture());
  161. } else {
  162. // We just gained access to the texture. If we're on the original context, we
  163. // could use the original texture, but we'd have no way of detecting that it's
  164. // no longer in-use. So we always make a wrapped copy, where the release proc
  165. // informs us that the context is done with it. This is unfortunate - we'll have
  166. // two texture objects referencing the same GPU object. However, no client can
  167. // ever see the original texture, so this should be safe.
  168. // We make the texture uncacheable so that the release proc is called ASAP.
  169. tex = resourceProvider->wrapBackendTexture(
  170. backendTexture, grColorType, kBorrow_GrWrapOwnership,
  171. GrWrapCacheable::kNo, kRead_GrIOType);
  172. if (!tex) {
  173. return {};
  174. }
  175. tex->setRelease(releaseProcHelper);
  176. tex->resourcePriv().setUniqueKey(refHelper->fBorrowedTextureKey);
  177. }
  178. // We use keys to avoid re-wrapping the GrBackendTexture in a GrTexture. This is
  179. // unrelated to the whatever SkImage key may be assigned to the proxy.
  180. return {std::move(tex), GrSurfaceProxy::LazyInstantiationKeyMode::kUnsynced};
  181. },
  182. backendFormat, desc, GrRenderable::kNo, 1, fSurfaceOrigin, mipMapped,
  183. GrInternalSurfaceFlags::kReadOnly, SkBackingFit::kExact, SkBudgeted::kNo,
  184. GrProtected::kNo);
  185. if (!proxy) {
  186. return nullptr;
  187. }
  188. if (0 == origin.fX && 0 == origin.fY &&
  189. info.width() == fBackendTexture.width() && info.height() == fBackendTexture.height() &&
  190. (!willNeedMipMaps || GrMipMapped::kYes == proxy->mipMapped())) {
  191. // If the caller wants the entire texture and we have the correct mip support, we're done
  192. return proxy;
  193. } else {
  194. // Otherwise, make a copy of the requested subset. Make sure our temporary is renderable,
  195. // because Vulkan will want to do the copy as a draw. All other copies would require a
  196. // layout change in Vulkan and we do not change the layout of borrowed images.
  197. GrMipMapped mipMapped = willNeedMipMaps ? GrMipMapped::kYes : GrMipMapped::kNo;
  198. SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height());
  199. return GrSurfaceProxy::Copy(context, proxy.get(), mipMapped, subset, SkBackingFit::kExact,
  200. SkBudgeted::kYes);
  201. }
  202. }