GrYUVProvider.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright 2015 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/GrYUVProvider.h"
  8. #include "include/core/SkRefCnt.h"
  9. #include "include/core/SkYUVAIndex.h"
  10. #include "include/private/GrRecordingContext.h"
  11. #include "src/core/SkAutoMalloc.h"
  12. #include "src/core/SkCachedData.h"
  13. #include "src/core/SkResourceCache.h"
  14. #include "src/core/SkYUVPlanesCache.h"
  15. #include "src/gpu/GrCaps.h"
  16. #include "src/gpu/GrClip.h"
  17. #include "src/gpu/GrColorSpaceXform.h"
  18. #include "src/gpu/GrProxyProvider.h"
  19. #include "src/gpu/GrRecordingContextPriv.h"
  20. #include "src/gpu/GrRenderTargetContext.h"
  21. #include "src/gpu/GrTextureProxy.h"
  22. #include "src/gpu/effects/GrYUVtoRGBEffect.h"
  23. sk_sp<SkCachedData> GrYUVProvider::getPlanes(SkYUVASizeInfo* size,
  24. SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
  25. SkYUVColorSpace* colorSpace,
  26. const void* constPlanes[SkYUVASizeInfo::kMaxCount]) {
  27. sk_sp<SkCachedData> data;
  28. SkYUVPlanesCache::Info yuvInfo;
  29. data.reset(SkYUVPlanesCache::FindAndRef(this->onGetID(), &yuvInfo));
  30. void* planes[SkYUVASizeInfo::kMaxCount];
  31. if (data.get()) {
  32. planes[0] = (void*)data->data(); // we should always have at least one plane
  33. for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
  34. if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
  35. SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
  36. !yuvInfo.fSizeInfo.fSizes[i].fHeight);
  37. planes[i] = nullptr;
  38. continue;
  39. }
  40. planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
  41. yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
  42. }
  43. } else {
  44. // Fetch yuv plane sizes for memory allocation.
  45. if (!this->onQueryYUVA8(&yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, &yuvInfo.fColorSpace)) {
  46. return nullptr;
  47. }
  48. // Allocate the memory for YUVA
  49. size_t totalSize(0);
  50. for (int i = 0; i < SkYUVASizeInfo::kMaxCount; i++) {
  51. SkASSERT((yuvInfo.fSizeInfo.fWidthBytes[i] && yuvInfo.fSizeInfo.fSizes[i].fHeight) ||
  52. (!yuvInfo.fSizeInfo.fWidthBytes[i] && !yuvInfo.fSizeInfo.fSizes[i].fHeight));
  53. totalSize += yuvInfo.fSizeInfo.fWidthBytes[i] * yuvInfo.fSizeInfo.fSizes[i].fHeight;
  54. }
  55. data.reset(SkResourceCache::NewCachedData(totalSize));
  56. planes[0] = data->writable_data();
  57. for (int i = 1; i < SkYUVASizeInfo::kMaxCount; ++i) {
  58. if (!yuvInfo.fSizeInfo.fWidthBytes[i]) {
  59. SkASSERT(!yuvInfo.fSizeInfo.fWidthBytes[i] &&
  60. !yuvInfo.fSizeInfo.fSizes[i].fHeight);
  61. planes[i] = nullptr;
  62. continue;
  63. }
  64. planes[i] = (uint8_t*)planes[i-1] + (yuvInfo.fSizeInfo.fWidthBytes[i-1] *
  65. yuvInfo.fSizeInfo.fSizes[i-1].fHeight);
  66. }
  67. // Get the YUV planes.
  68. if (!this->onGetYUVA8Planes(yuvInfo.fSizeInfo, yuvInfo.fYUVAIndices, planes)) {
  69. return nullptr;
  70. }
  71. // Decoding is done, cache the resulting YUV planes
  72. SkYUVPlanesCache::Add(this->onGetID(), data.get(), &yuvInfo);
  73. }
  74. *size = yuvInfo.fSizeInfo;
  75. memcpy(yuvaIndices, yuvInfo.fYUVAIndices, sizeof(yuvInfo.fYUVAIndices));
  76. *colorSpace = yuvInfo.fColorSpace;
  77. constPlanes[0] = planes[0];
  78. constPlanes[1] = planes[1];
  79. constPlanes[2] = planes[2];
  80. constPlanes[3] = planes[3];
  81. return data;
  82. }
  83. void GrYUVProvider::YUVGen_DataReleaseProc(const void*, void* data) {
  84. SkCachedData* cachedData = static_cast<SkCachedData*>(data);
  85. SkASSERT(cachedData);
  86. cachedData->unref();
  87. }
  88. sk_sp<GrTextureProxy> GrYUVProvider::refAsTextureProxy(GrRecordingContext* ctx,
  89. const GrSurfaceDesc& desc,
  90. GrColorType colorType,
  91. SkColorSpace* srcColorSpace,
  92. SkColorSpace* dstColorSpace) {
  93. SkYUVASizeInfo yuvSizeInfo;
  94. SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
  95. SkYUVColorSpace yuvColorSpace;
  96. const void* planes[SkYUVASizeInfo::kMaxCount];
  97. sk_sp<SkCachedData> dataStorage = this->getPlanes(&yuvSizeInfo, yuvaIndices,
  98. &yuvColorSpace, planes);
  99. if (!dataStorage) {
  100. return nullptr;
  101. }
  102. sk_sp<GrTextureProxy> yuvTextureProxies[SkYUVASizeInfo::kMaxCount];
  103. for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
  104. if (yuvSizeInfo.fSizes[i].isEmpty()) {
  105. SkASSERT(!yuvSizeInfo.fWidthBytes[i]);
  106. continue;
  107. }
  108. int componentWidth = yuvSizeInfo.fSizes[i].fWidth;
  109. int componentHeight = yuvSizeInfo.fSizes[i].fHeight;
  110. // If the sizes of the components are not all the same we choose to create exact-match
  111. // textures for the smaller ones rather than add a texture domain to the draw.
  112. // TODO: revisit this decision to improve texture reuse?
  113. SkBackingFit fit =
  114. (componentWidth != yuvSizeInfo.fSizes[0].fWidth) ||
  115. (componentHeight != yuvSizeInfo.fSizes[0].fHeight)
  116. ? SkBackingFit::kExact : SkBackingFit::kApprox;
  117. SkImageInfo imageInfo = SkImageInfo::MakeA8(componentWidth, componentHeight);
  118. SkPixmap pixmap(imageInfo, planes[i], yuvSizeInfo.fWidthBytes[i]);
  119. SkCachedData* dataStoragePtr = dataStorage.get();
  120. // We grab a ref to cached yuv data. When the SkImage we create below goes away it will call
  121. // the YUVGen_DataReleaseProc which will release this ref.
  122. // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
  123. // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
  124. // life time of the proxy and not just upload. For non-DDL draws we should look into
  125. // releasing this SkImage after uploads (by deleting the lambda after instantiation).
  126. dataStoragePtr->ref();
  127. sk_sp<SkImage> yuvImage = SkImage::MakeFromRaster(pixmap, YUVGen_DataReleaseProc,
  128. dataStoragePtr);
  129. auto proxyProvider = ctx->priv().proxyProvider();
  130. yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, GrRenderable::kNo, 1,
  131. SkBudgeted::kYes, fit);
  132. SkASSERT(yuvTextureProxies[i]->width() == yuvSizeInfo.fSizes[i].fWidth);
  133. SkASSERT(yuvTextureProxies[i]->height() == yuvSizeInfo.fSizes[i].fHeight);
  134. }
  135. // TODO: investigate preallocating mip maps here
  136. sk_sp<GrRenderTargetContext> renderTargetContext(ctx->priv().makeDeferredRenderTargetContext(
  137. SkBackingFit::kExact, desc.fWidth, desc.fHeight, colorType, nullptr, 1,
  138. GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin));
  139. if (!renderTargetContext) {
  140. return nullptr;
  141. }
  142. GrPaint paint;
  143. auto yuvToRgbProcessor = GrYUVtoRGBEffect::Make(yuvTextureProxies, yuvaIndices, yuvColorSpace,
  144. GrSamplerState::Filter::kNearest);
  145. paint.addColorFragmentProcessor(std::move(yuvToRgbProcessor));
  146. // If the caller expects the pixels in a different color space than the one from the image,
  147. // apply a color conversion to do this.
  148. std::unique_ptr<GrFragmentProcessor> colorConversionProcessor =
  149. GrColorSpaceXformEffect::Make(srcColorSpace, kOpaque_SkAlphaType,
  150. dstColorSpace, kOpaque_SkAlphaType);
  151. if (colorConversionProcessor) {
  152. paint.addColorFragmentProcessor(std::move(colorConversionProcessor));
  153. }
  154. paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
  155. const SkRect r = SkRect::MakeIWH(yuvSizeInfo.fSizes[0].fWidth,
  156. yuvSizeInfo.fSizes[0].fHeight);
  157. SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height());
  158. renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, r);
  159. return renderTargetContext->asTextureProxyRef();
  160. }