blob: e612bc479e419990a0fc1c02991d517b58126f65 [file] [log] [blame]
Robert Phillips96601082018-05-29 16:13:26 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tools/DDLPromiseImageHelper.h"
Robert Phillips96601082018-05-29 16:13:26 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkDeferredDisplayListRecorder.h"
Robert Phillips66944402019-09-30 13:21:25 -040011#include "include/core/SkPicture.h"
12#include "include/core/SkSerialProcs.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkYUVAIndex.h"
14#include "include/core/SkYUVASizeInfo.h"
15#include "include/gpu/GrContext.h"
16#include "src/core/SkCachedData.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/image/SkImage_Base.h"
18#include "src/image/SkImage_GpuYUVA.h"
Robert Phillips96601082018-05-29 16:13:26 -040019
20DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050021 SkASSERT(fDoneCnt == fNumImages);
22 SkASSERT(!fUnreleasedFulfills);
23 SkASSERT(fTotalReleases == fTotalFulfills);
24 SkASSERT(!fTotalFulfills || fDoneCnt);
Robert Phillips96601082018-05-29 16:13:26 -040025
Brian Salomon3f4cd772019-01-11 16:03:19 -050026 if (fPromiseImageTexture) {
Robert Phillips5c7a25b2019-05-20 08:38:07 -040027 fContext->deleteBackendTexture(fPromiseImageTexture->backendTexture());
Robert Phillips96601082018-05-29 16:13:26 -040028 }
29}
30
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050031void DDLPromiseImageHelper::PromiseImageCallbackContext::setBackendTexture(
32 const GrBackendTexture& backendTexture) {
Brian Salomon7d88f312019-02-28 10:03:03 -050033 SkASSERT(!fPromiseImageTexture);
Brian Salomon3f4cd772019-01-11 16:03:19 -050034 fPromiseImageTexture = SkPromiseImageTexture::Make(backendTexture);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -050035}
36
Robert Phillips96601082018-05-29 16:13:26 -040037///////////////////////////////////////////////////////////////////////////////////////////////////
38
39sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
40 SkSerialProcs procs;
41
42 procs.fImageCtx = this;
43 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
44 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
45
46 int id = helper->findOrDefineImage(image);
Robert Phillips96601082018-05-29 16:13:26 -040047
Robert Phillips6bad7052019-12-16 15:09:57 -050048 // Even if 'id' is invalid (i.e., -1) write it to the SKP
49 return SkData::MakeWithCopy(&id, sizeof(id));
Robert Phillips96601082018-05-29 16:13:26 -040050 };
51
52 return inputPicture->serialize(&procs);
53}
54
Robert Phillipscb1adb42019-06-10 15:09:34 -040055static GrBackendTexture create_yuva_texture(GrContext* context, const SkPixmap& pm,
Jim Van Verth60ac5d02018-12-06 13:11:53 -050056 const SkYUVAIndex yuvaIndices[4], int texIndex) {
57 SkASSERT(texIndex >= 0 && texIndex <= 3);
Robert Phillipsd470e1b2019-09-04 15:05:35 -040058
59#ifdef SK_DEBUG
Jim Van Verth60ac5d02018-12-06 13:11:53 -050060 int channelCount = 0;
61 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
62 if (yuvaIndices[i].fIndex == texIndex) {
63 ++channelCount;
64 }
65 }
Jim Van Verth60ac5d02018-12-06 13:11:53 -050066 if (2 == channelCount) {
Robert Phillipsea1b30b2019-09-19 16:05:48 -040067 SkASSERT(kR8G8_unorm_SkColorType == pm.colorType());
Jim Van Verth60ac5d02018-12-06 13:11:53 -050068 }
Robert Phillipsd470e1b2019-09-04 15:05:35 -040069#endif
70
Robert Phillips66944402019-09-30 13:21:25 -040071 return context->createBackendTexture(&pm, 1, GrRenderable::kNo, GrProtected::kNo);
Jim Van Verth60ac5d02018-12-06 13:11:53 -050072}
73
Robert Phillips96601082018-05-29 16:13:26 -040074void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
Brian Salomon426ba462019-01-10 16:33:06 +000075 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -040076 const PromiseImageInfo& info = fImageInfo[i];
77
78 // DDL TODO: how can we tell if we need mipmapping!
Robert Phillipse8e2bb12018-09-27 14:26:47 -040079 if (info.isYUV()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040080 int numPixmaps;
81 SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
82 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040083 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -040084
Robert Phillipse8e2bb12018-09-27 14:26:47 -040085 sk_sp<PromiseImageCallbackContext> callbackContext(
86 new PromiseImageCallbackContext(context));
Jim Van Verth60ac5d02018-12-06 13:11:53 -050087
Robert Phillipscb1adb42019-06-10 15:09:34 -040088 callbackContext->setBackendTexture(create_yuva_texture(context, yuvPixmap,
Jim Van Verth60ac5d02018-12-06 13:11:53 -050089 info.yuvaIndices(), j));
Brian Salomon3f4cd772019-01-11 16:03:19 -050090 SkASSERT(callbackContext->promiseImageTexture());
Robert Phillipse8e2bb12018-09-27 14:26:47 -040091
92 fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
93 }
94 } else {
95 sk_sp<PromiseImageCallbackContext> callbackContext(
96 new PromiseImageCallbackContext(context));
97
98 const SkBitmap& bm = info.normalBitmap();
99
Robert Phillips66944402019-09-30 13:21:25 -0400100 GrBackendTexture backendTex = context->createBackendTexture(
Robert Phillipsda2e67a2019-07-01 15:04:06 -0400101 &bm.pixmap(), 1, GrRenderable::kNo,
102 GrProtected::kNo);
Robert Phillipscb1adb42019-06-10 15:09:34 -0400103
104 callbackContext->setBackendTexture(backendTex);
105
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400106 // The GMs sometimes request too large an image
107 //SkAssertResult(callbackContext->backendTexture().isValid());
108
109 fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
110 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500111 }
112}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400113
Robert Phillips96601082018-05-29 16:13:26 -0400114sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
115 SkDeferredDisplayListRecorder* recorder,
116 SkData* compressedPictureData,
117 SkTArray<sk_sp<SkImage>>* promiseImages) const {
118 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
119
120 SkDeserialProcs procs;
121 procs.fImageCtx = (void*) &perRecorderContext;
122 procs.fImageProc = PromiseImageCreator;
123
124 return SkPicture::MakeFromData(compressedPictureData, &procs);
125}
126
127// This generates promise images to replace the indices in the compressed picture. This
128// reconstitution is performed separately in each thread so we end up with multiple
129// promise images referring to the same GrBackendTexture.
130sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
131 size_t length, void* ctxIn) {
132 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
133 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
134 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
135
136 SkASSERT(length == sizeof(int));
137
138 const int* indexPtr = static_cast<const int*>(rawData);
Robert Phillips6bad7052019-12-16 15:09:57 -0500139 if (!helper->isValidID(*indexPtr)) {
140 return nullptr;
141 }
Robert Phillips96601082018-05-29 16:13:26 -0400142
143 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
144
Brian Salomon3f4cd772019-01-11 16:03:19 -0500145 if (!curImage.promiseTexture(0)) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400146 SkASSERT(!curImage.isYUV());
Robert Phillips96601082018-05-29 16:13:26 -0400147 // We weren't able to make a backend texture for this SkImage. In this case we create
148 // a separate bitmap-backed image for each thread.
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400149 SkASSERT(curImage.normalBitmap().isImmutable());
150 return SkImage::MakeFromBitmap(curImage.normalBitmap());
Robert Phillips96601082018-05-29 16:13:26 -0400151 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400152 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400153
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400154 sk_sp<SkImage> image;
155 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400156 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
157 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
158 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400159 // TODO: store this value somewhere?
160 int textureCount;
161 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
162 for (int i = 0; i < textureCount; ++i) {
Brian Salomon3f4cd772019-01-11 16:03:19 -0500163 const GrBackendTexture& backendTex = curImage.promiseTexture(i)->backendTexture();
Brian Salomonf391d0f2018-12-14 09:18:50 -0500164 backendFormats[i] = backendTex.getBackendFormat();
165 SkASSERT(backendFormats[i].isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400166 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400167 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400168 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400169 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400170 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400171 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000172
Brian Salomon0cc57542019-03-08 13:28:46 -0500173 image = recorder->makeYUVAPromiseTexture(
174 curImage.yuvColorSpace(),
175 backendFormats,
176 sizes,
177 curImage.yuvaIndices(),
178 curImage.overallWidth(),
179 curImage.overallHeight(),
180 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
181 curImage.refOverallColorSpace(),
182 DDLPromiseImageHelper::PromiseImageFulfillProc,
183 DDLPromiseImageHelper::PromiseImageReleaseProc,
184 DDLPromiseImageHelper::PromiseImageDoneProc,
185 contexts,
186 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500187 for (int i = 0; i < textureCount; ++i) {
188 curImage.callbackContext(i)->wasAddedToImage();
189 }
Robert Phillips193c4212019-03-04 12:18:53 -0500190
191#ifdef SK_DEBUG
192 {
193 // By the peekProxy contract this image should not have a single backing proxy so
194 // should return null. The call should also not trigger the conversion to RGBA.
195 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
196 SkASSERT(!yuva->peekProxy());
197 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
198 }
199#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400200 } else {
Brian Salomon3f4cd772019-01-11 16:03:19 -0500201 const GrBackendTexture& backendTex = curImage.promiseTexture(0)->backendTexture();
Brian Salomonf391d0f2018-12-14 09:18:50 -0500202 GrBackendFormat backendFormat = backendTex.getBackendFormat();
203 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400204
205 // Each DDL recorder gets its own ref on the promise callback context for the
206 // promise images it creates.
207 // DDL TODO: sort out mipmapping
Brian Salomon0cc57542019-03-08 13:28:46 -0500208 image = recorder->makePromiseTexture(
209 backendFormat,
210 curImage.overallWidth(),
211 curImage.overallHeight(),
212 GrMipMapped::kNo,
213 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
214 curImage.overallColorType(),
215 curImage.overallAlphaType(),
216 curImage.refOverallColorSpace(),
217 DDLPromiseImageHelper::PromiseImageFulfillProc,
218 DDLPromiseImageHelper::PromiseImageReleaseProc,
219 DDLPromiseImageHelper::PromiseImageDoneProc,
220 (void*)curImage.refCallbackContext(0).release(),
221 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500222 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400223 }
Robert Phillips96601082018-05-29 16:13:26 -0400224 perRecorderContext->fPromiseImages->push_back(image);
225 SkASSERT(image);
226 return image;
227}
228
229int DDLPromiseImageHelper::findImage(SkImage* image) const {
230 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400231 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
232 SkASSERT(fImageInfo[i].index() == i);
233 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400234 return i;
235 }
236 }
237 return -1;
238}
239
240int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400241 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400242
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400243 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400244 image->colorType() == kBGRA_8888_SkColorType
245 ? kRGBA_8888_SkColorType
246 : image->colorType(),
247 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400248 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400249
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400250 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
251 image->uniqueID(),
252 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400253
Jim Van Verthe24b5872018-10-29 16:26:02 -0400254 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400255 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400256 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400257 const void* planes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400258 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400259 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400260 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400261
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400262 // determine colortypes from index data
Robert Phillipsd470e1b2019-09-04 15:05:35 -0400263 // for testing we only ever use A8, RG_88
Jim Van Verthe24b5872018-10-29 16:26:02 -0400264 SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400265 kUnknown_SkColorType, kUnknown_SkColorType,
266 kUnknown_SkColorType, kUnknown_SkColorType
267 };
268 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
269 int texIdx = yuvaIndices[yuvIndex].fIndex;
270 if (texIdx < 0) {
271 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
272 continue;
273 }
274 if (kUnknown_SkColorType == colorTypes[texIdx]) {
275 colorTypes[texIdx] = kAlpha_8_SkColorType;
276 } else {
Robert Phillipsea1b30b2019-09-19 16:05:48 -0400277 colorTypes[texIdx] = kR8G8_unorm_SkColorType;
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400278 }
279 }
280
Jim Van Verthe24b5872018-10-29 16:26:02 -0400281 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400282 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
283 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400284 continue;
285 }
286
287 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
288 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400289 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400290 kUnpremul_SkAlphaType);
291 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400292 }
293 } else {
294 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
Robert Phillipse84bffc2019-12-16 11:22:17 -0500295 if (!rasterImage) {
296 return -1;
297 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400298
299 SkBitmap tmp;
300 tmp.allocPixels(overallII);
301
302 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
303 return -1;
304 }
305
306 tmp.setImmutable();
307 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400308 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400309 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400310
311 return fImageInfo.count()-1;
312}
313
314int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
315 int preExistingID = this->findImage(image);
316 if (preExistingID >= 0) {
317 SkASSERT(this->isValidID(preExistingID));
318 return preExistingID;
319 }
320
321 int newID = this->addImage(image);
Robert Phillips96601082018-05-29 16:13:26 -0400322 return newID;
323}