DDLPromiseImageHelper.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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 "tools/DDLPromiseImageHelper.h"
  8. #include "include/core/SkDeferredDisplayListRecorder.h"
  9. #include "include/core/SkYUVAIndex.h"
  10. #include "include/core/SkYUVASizeInfo.h"
  11. #include "include/gpu/GrContext.h"
  12. #include "src/core/SkCachedData.h"
  13. #include "src/gpu/GrContextPriv.h"
  14. #include "src/gpu/GrGpu.h"
  15. #include "src/image/SkImage_Base.h"
  16. #include "src/image/SkImage_GpuYUVA.h"
  17. DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
  18. SkASSERT(fDoneCnt == fNumImages);
  19. SkASSERT(!fUnreleasedFulfills);
  20. SkASSERT(fTotalReleases == fTotalFulfills);
  21. SkASSERT(!fTotalFulfills || fDoneCnt);
  22. if (fPromiseImageTexture) {
  23. fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
  24. }
  25. }
  26. void DDLPromiseImageHelper::PromiseImageCallbackContext::setBackendTexture(
  27. const GrBackendTexture& backendTexture) {
  28. SkASSERT(!fPromiseImageTexture);
  29. fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
  30. }
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
  33. SkSerialProcs procs;
  34. procs.fImageCtx = this;
  35. procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
  36. auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
  37. int id = helper->findOrDefineImage(image);
  38. if (id >= 0) {
  39. SkASSERT(helper->isValidID(id));
  40. return SkData::MakeWithCopy(&id, sizeof(id));
  41. }
  42. return nullptr;
  43. };
  44. return inputPicture->serialize(&procs);
  45. }
  46. // needed until we have SkRG_88_ColorType;
  47. static GrBackendTexture create_yuva_texture(GrContext* context, const SkPixmap& pm,
  48. const SkYUVAIndex yuvaIndices[4], int texIndex) {
  49. SkASSERT(texIndex >= 0 && texIndex <= 3);
  50. int channelCount = 0;
  51. for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
  52. if (yuvaIndices[i].fIndex == texIndex) {
  53. ++channelCount;
  54. }
  55. }
  56. // Need to create an RG texture for two-channel planes
  57. GrBackendTexture tex;
  58. if (2 == channelCount) {
  59. const GrCaps* caps = context->priv().caps();
  60. GrGpu* gpu = context->priv().getGpu();
  61. SkASSERT(kRGBA_8888_SkColorType == pm.colorType());
  62. SkAutoTMalloc<char> pixels(2 * pm.width()*pm.height());
  63. char* currPixel = pixels;
  64. for (int y = 0; y < pm.height(); ++y) {
  65. for (int x = 0; x < pm.width(); ++x) {
  66. SkColor color = pm.getColor(x, y);
  67. currPixel[0] = SkColorGetR(color);
  68. currPixel[1] = SkColorGetG(color);
  69. currPixel += 2;
  70. }
  71. }
  72. GrBackendFormat format = caps->getBackendFormatFromColorType(GrColorType::kRG_88);
  73. tex = gpu->createBackendTexture(pm.width(), pm.height(), format,
  74. GrMipMapped::kNo, GrRenderable::kNo,
  75. pixels, 2 * pm.width(), nullptr, GrProtected::kNo);
  76. } else {
  77. tex = context->priv().createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo);
  78. }
  79. return tex;
  80. }
  81. void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
  82. for (int i = 0; i < fImageInfo.count(); ++i) {
  83. const PromiseImageInfo& info = fImageInfo[i];
  84. // DDL TODO: how can we tell if we need mipmapping!
  85. if (info.isYUV()) {
  86. int numPixmaps;
  87. SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
  88. for (int j = 0; j < numPixmaps; ++j) {
  89. const SkPixmap& yuvPixmap = info.yuvPixmap(j);
  90. sk_sp<PromiseImageCallbackContext> callbackContext(
  91. new PromiseImageCallbackContext(context));
  92. callbackContext->setBackendTexture(create_yuva_texture(context, yuvPixmap,
  93. info.yuvaIndices(), j));
  94. SkASSERT(callbackContext->promiseImageTexture());
  95. fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
  96. }
  97. } else {
  98. sk_sp<PromiseImageCallbackContext> callbackContext(
  99. new PromiseImageCallbackContext(context));
  100. const SkBitmap& bm = info.normalBitmap();
  101. GrBackendTexture backendTex = context->priv().createBackendTexture(
  102. &bm.pixmap(), 1, GrRenderable::kNo,
  103. GrProtected::kNo);
  104. callbackContext->setBackendTexture(backendTex);
  105. // The GMs sometimes request too large an image
  106. //SkAssertResult(callbackContext->backendTexture().isValid());
  107. fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
  108. }
  109. }
  110. }
  111. sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
  112. SkDeferredDisplayListRecorder* recorder,
  113. SkData* compressedPictureData,
  114. SkTArray<sk_sp<SkImage>>* promiseImages) const {
  115. PerRecorderContext perRecorderContext { recorder, this, promiseImages };
  116. SkDeserialProcs procs;
  117. procs.fImageCtx = (void*) &perRecorderContext;
  118. procs.fImageProc = PromiseImageCreator;
  119. return SkPicture::MakeFromData(compressedPictureData, &procs);
  120. }
  121. // This generates promise images to replace the indices in the compressed picture. This
  122. // reconstitution is performed separately in each thread so we end up with multiple
  123. // promise images referring to the same GrBackendTexture.
  124. sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
  125. size_t length, void* ctxIn) {
  126. PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
  127. const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
  128. SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
  129. SkASSERT(length == sizeof(int));
  130. const int* indexPtr = static_cast<const int*>(rawData);
  131. SkASSERT(helper->isValidID(*indexPtr));
  132. const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
  133. if (!curImage.promiseTexture(0)) {
  134. SkASSERT(!curImage.isYUV());
  135. // We weren't able to make a backend texture for this SkImage. In this case we create
  136. // a separate bitmap-backed image for each thread.
  137. SkASSERT(curImage.normalBitmap().isImmutable());
  138. return SkImage::MakeFromBitmap(curImage.normalBitmap());
  139. }
  140. SkASSERT(curImage.index() == *indexPtr);
  141. sk_sp<SkImage> image;
  142. if (curImage.isYUV()) {
  143. GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
  144. void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
  145. SkISize sizes[SkYUVASizeInfo::kMaxCount];
  146. // TODO: store this value somewhere?
  147. int textureCount;
  148. SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
  149. for (int i = 0; i < textureCount; ++i) {
  150. const GrBackendTexture& backendTex = curImage.promiseTexture(i)->backendTexture();
  151. backendFormats[i] = backendTex.getBackendFormat();
  152. SkASSERT(backendFormats[i].isValid());
  153. contexts[i] = curImage.refCallbackContext(i).release();
  154. sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
  155. }
  156. for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
  157. sizes[i] = SkISize::MakeEmpty();
  158. }
  159. image = recorder->makeYUVAPromiseTexture(
  160. curImage.yuvColorSpace(),
  161. backendFormats,
  162. sizes,
  163. curImage.yuvaIndices(),
  164. curImage.overallWidth(),
  165. curImage.overallHeight(),
  166. GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
  167. curImage.refOverallColorSpace(),
  168. DDLPromiseImageHelper::PromiseImageFulfillProc,
  169. DDLPromiseImageHelper::PromiseImageReleaseProc,
  170. DDLPromiseImageHelper::PromiseImageDoneProc,
  171. contexts,
  172. SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
  173. for (int i = 0; i < textureCount; ++i) {
  174. curImage.callbackContext(i)->wasAddedToImage();
  175. }
  176. #ifdef SK_DEBUG
  177. {
  178. // By the peekProxy contract this image should not have a single backing proxy so
  179. // should return null. The call should also not trigger the conversion to RGBA.
  180. SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
  181. SkASSERT(!yuva->peekProxy());
  182. SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
  183. }
  184. #endif
  185. } else {
  186. const GrBackendTexture& backendTex = curImage.promiseTexture(0)->backendTexture();
  187. GrBackendFormat backendFormat = backendTex.getBackendFormat();
  188. SkASSERT(backendFormat.isValid());
  189. // Each DDL recorder gets its own ref on the promise callback context for the
  190. // promise images it creates.
  191. // DDL TODO: sort out mipmapping
  192. image = recorder->makePromiseTexture(
  193. backendFormat,
  194. curImage.overallWidth(),
  195. curImage.overallHeight(),
  196. GrMipMapped::kNo,
  197. GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
  198. curImage.overallColorType(),
  199. curImage.overallAlphaType(),
  200. curImage.refOverallColorSpace(),
  201. DDLPromiseImageHelper::PromiseImageFulfillProc,
  202. DDLPromiseImageHelper::PromiseImageReleaseProc,
  203. DDLPromiseImageHelper::PromiseImageDoneProc,
  204. (void*)curImage.refCallbackContext(0).release(),
  205. SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
  206. curImage.callbackContext(0)->wasAddedToImage();
  207. }
  208. perRecorderContext->fPromiseImages->push_back(image);
  209. SkASSERT(image);
  210. return image;
  211. }
  212. int DDLPromiseImageHelper::findImage(SkImage* image) const {
  213. for (int i = 0; i < fImageInfo.count(); ++i) {
  214. if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
  215. SkASSERT(fImageInfo[i].index() == i);
  216. SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
  217. return i;
  218. }
  219. }
  220. return -1;
  221. }
  222. int DDLPromiseImageHelper::addImage(SkImage* image) {
  223. SkImage_Base* ib = as_IB(image);
  224. SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
  225. image->colorType() == kBGRA_8888_SkColorType
  226. ? kRGBA_8888_SkColorType
  227. : image->colorType(),
  228. image->alphaType(),
  229. image->refColorSpace());
  230. PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
  231. image->uniqueID(),
  232. overallII);
  233. SkYUVASizeInfo yuvaSizeInfo;
  234. SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
  235. SkYUVColorSpace yuvColorSpace;
  236. const void* planes[SkYUVASizeInfo::kMaxCount];
  237. sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
  238. if (yuvData) {
  239. newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
  240. // determine colortypes from index data
  241. // for testing we only ever use A8 or RGBA8888
  242. SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
  243. kUnknown_SkColorType, kUnknown_SkColorType,
  244. kUnknown_SkColorType, kUnknown_SkColorType
  245. };
  246. for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
  247. int texIdx = yuvaIndices[yuvIndex].fIndex;
  248. if (texIdx < 0) {
  249. SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
  250. continue;
  251. }
  252. if (kUnknown_SkColorType == colorTypes[texIdx]) {
  253. colorTypes[texIdx] = kAlpha_8_SkColorType;
  254. } else {
  255. colorTypes[texIdx] = kRGBA_8888_SkColorType;
  256. }
  257. }
  258. for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
  259. if (yuvaSizeInfo.fSizes[i].isEmpty()) {
  260. SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
  261. continue;
  262. }
  263. SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
  264. yuvaSizeInfo.fSizes[i].fHeight,
  265. colorTypes[i],
  266. kUnpremul_SkAlphaType);
  267. newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
  268. }
  269. } else {
  270. sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
  271. SkBitmap tmp;
  272. tmp.allocPixels(overallII);
  273. if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
  274. return -1;
  275. }
  276. tmp.setImmutable();
  277. newImageInfo.setNormalBitmap(tmp);
  278. }
  279. // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
  280. return fImageInfo.count()-1;
  281. }
  282. int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
  283. int preExistingID = this->findImage(image);
  284. if (preExistingID >= 0) {
  285. SkASSERT(this->isValidID(preExistingID));
  286. return preExistingID;
  287. }
  288. int newID = this->addImage(image);
  289. SkASSERT(this->isValidID(newID));
  290. return newID;
  291. }