blob: 790699c58c7901aac438c146d5294f65cdfe1d2c [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"
11#include "include/core/SkYUVAIndex.h"
12#include "include/core/SkYUVASizeInfo.h"
13#include "include/gpu/GrContext.h"
14#include "src/core/SkCachedData.h"
15#include "src/gpu/GrContextPriv.h"
16#include "src/gpu/GrGpu.h"
17#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);
47 if (id >= 0) {
48 SkASSERT(helper->isValidID(id));
49 return SkData::MakeWithCopy(&id, sizeof(id));
50 }
51
52 return nullptr;
53 };
54
55 return inputPicture->serialize(&procs);
56}
57
Jim Van Verth60ac5d02018-12-06 13:11:53 -050058// needed until we have SkRG_88_ColorType;
59static GrBackendTexture create_yuva_texture(GrGpu* gpu, const SkPixmap& pm,
60 const SkYUVAIndex yuvaIndices[4], int texIndex) {
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040061 const GrCaps* caps = gpu->caps();
62
Jim Van Verth60ac5d02018-12-06 13:11:53 -050063 SkASSERT(texIndex >= 0 && texIndex <= 3);
64 int channelCount = 0;
65 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
66 if (yuvaIndices[i].fIndex == texIndex) {
67 ++channelCount;
68 }
69 }
70 // Need to create an RG texture for two-channel planes
71 GrBackendTexture tex;
72 if (2 == channelCount) {
73 SkASSERT(kRGBA_8888_SkColorType == pm.colorType());
74 SkAutoTMalloc<char> pixels(2 * pm.width()*pm.height());
75 char* currPixel = pixels;
76 for (int y = 0; y < pm.height(); ++y) {
77 for (int x = 0; x < pm.width(); ++x) {
78 SkColor color = pm.getColor(x, y);
79 currPixel[0] = SkColorGetR(color);
80 currPixel[1] = SkColorGetG(color);
81 currPixel += 2;
82 }
83 }
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040084
85 GrBackendFormat format = caps->getBackendFormatFromGrColorType(GrColorType::kRG_88,
86 GrSRGBEncoded::kNo);
Robert Phillipsf0313ee2019-05-21 13:51:11 -040087 tex = gpu->createBackendTexture(pm.width(), pm.height(), format,
88 GrMipMapped::kNo, GrRenderable::kNo,
Robert Phillipsd1d869d2019-06-07 14:21:31 -040089 pixels, 2 * pm.width(), nullptr);
Jim Van Verth60ac5d02018-12-06 13:11:53 -050090 } else {
91 tex = gpu->createTestingOnlyBackendTexture(
Robert Phillips9dbcdcc2019-05-13 10:40:06 -040092 pm.width(), pm.height(), pm.colorType(),
93 GrMipMapped::kNo, GrRenderable::kNo,
Robert Phillipsd1d869d2019-06-07 14:21:31 -040094 pm.addr(), pm.rowBytes(), nullptr);
Jim Van Verth60ac5d02018-12-06 13:11:53 -050095 }
96 return tex;
97}
98
Robert Phillips96601082018-05-29 16:13:26 -040099void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
Robert Phillips9da87e02019-02-04 13:26:26 -0500100 GrGpu* gpu = context->priv().getGpu();
Robert Phillips96601082018-05-29 16:13:26 -0400101 SkASSERT(gpu);
102
Brian Salomon426ba462019-01-10 16:33:06 +0000103 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -0400104 const PromiseImageInfo& info = fImageInfo[i];
105
106 // DDL TODO: how can we tell if we need mipmapping!
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400107 if (info.isYUV()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400108 int numPixmaps;
109 SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
110 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400111 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -0400112
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400113 sk_sp<PromiseImageCallbackContext> callbackContext(
114 new PromiseImageCallbackContext(context));
Jim Van Verth60ac5d02018-12-06 13:11:53 -0500115
116 callbackContext->setBackendTexture(create_yuva_texture(gpu, yuvPixmap,
117 info.yuvaIndices(), j));
Brian Salomon3f4cd772019-01-11 16:03:19 -0500118 SkASSERT(callbackContext->promiseImageTexture());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400119
120 fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
121 }
122 } else {
123 sk_sp<PromiseImageCallbackContext> callbackContext(
124 new PromiseImageCallbackContext(context));
125
126 const SkBitmap& bm = info.normalBitmap();
127
128 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400129 bm.width(), bm.height(), bm.colorType(),
130 GrMipMapped::kNo, GrRenderable::kNo,
Robert Phillipsd1d869d2019-06-07 14:21:31 -0400131 bm.getPixels(), bm.rowBytes(), nullptr));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400132 // The GMs sometimes request too large an image
133 //SkAssertResult(callbackContext->backendTexture().isValid());
134
135 fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
136 }
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500137 }
138}
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400139
Robert Phillips96601082018-05-29 16:13:26 -0400140sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
141 SkDeferredDisplayListRecorder* recorder,
142 SkData* compressedPictureData,
143 SkTArray<sk_sp<SkImage>>* promiseImages) const {
144 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
145
146 SkDeserialProcs procs;
147 procs.fImageCtx = (void*) &perRecorderContext;
148 procs.fImageProc = PromiseImageCreator;
149
150 return SkPicture::MakeFromData(compressedPictureData, &procs);
151}
152
153// This generates promise images to replace the indices in the compressed picture. This
154// reconstitution is performed separately in each thread so we end up with multiple
155// promise images referring to the same GrBackendTexture.
156sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
157 size_t length, void* ctxIn) {
158 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
159 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
160 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
161
162 SkASSERT(length == sizeof(int));
163
164 const int* indexPtr = static_cast<const int*>(rawData);
165 SkASSERT(helper->isValidID(*indexPtr));
166
167 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
168
Brian Salomon3f4cd772019-01-11 16:03:19 -0500169 if (!curImage.promiseTexture(0)) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400170 SkASSERT(!curImage.isYUV());
Robert Phillips96601082018-05-29 16:13:26 -0400171 // We weren't able to make a backend texture for this SkImage. In this case we create
172 // a separate bitmap-backed image for each thread.
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400173 SkASSERT(curImage.normalBitmap().isImmutable());
174 return SkImage::MakeFromBitmap(curImage.normalBitmap());
Robert Phillips96601082018-05-29 16:13:26 -0400175 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400176 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400177
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400178 sk_sp<SkImage> image;
179 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400180 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
181 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
182 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400183 // TODO: store this value somewhere?
184 int textureCount;
185 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
186 for (int i = 0; i < textureCount; ++i) {
Brian Salomon3f4cd772019-01-11 16:03:19 -0500187 const GrBackendTexture& backendTex = curImage.promiseTexture(i)->backendTexture();
Brian Salomonf391d0f2018-12-14 09:18:50 -0500188 backendFormats[i] = backendTex.getBackendFormat();
189 SkASSERT(backendFormats[i].isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400190 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400191 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400192 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400193 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400194 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400195 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000196
Brian Salomon0cc57542019-03-08 13:28:46 -0500197 image = recorder->makeYUVAPromiseTexture(
198 curImage.yuvColorSpace(),
199 backendFormats,
200 sizes,
201 curImage.yuvaIndices(),
202 curImage.overallWidth(),
203 curImage.overallHeight(),
204 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
205 curImage.refOverallColorSpace(),
206 DDLPromiseImageHelper::PromiseImageFulfillProc,
207 DDLPromiseImageHelper::PromiseImageReleaseProc,
208 DDLPromiseImageHelper::PromiseImageDoneProc,
209 contexts,
210 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500211 for (int i = 0; i < textureCount; ++i) {
212 curImage.callbackContext(i)->wasAddedToImage();
213 }
Robert Phillips193c4212019-03-04 12:18:53 -0500214
215#ifdef SK_DEBUG
216 {
217 // By the peekProxy contract this image should not have a single backing proxy so
218 // should return null. The call should also not trigger the conversion to RGBA.
219 SkImage_GpuYUVA* yuva = reinterpret_cast<SkImage_GpuYUVA*>(image.get());
220 SkASSERT(!yuva->peekProxy());
221 SkASSERT(!yuva->peekProxy()); // the first call didn't force a conversion to RGBA
222 }
223#endif
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400224 } else {
Brian Salomon3f4cd772019-01-11 16:03:19 -0500225 const GrBackendTexture& backendTex = curImage.promiseTexture(0)->backendTexture();
Brian Salomonf391d0f2018-12-14 09:18:50 -0500226 GrBackendFormat backendFormat = backendTex.getBackendFormat();
227 SkASSERT(backendFormat.isValid());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400228
229 // Each DDL recorder gets its own ref on the promise callback context for the
230 // promise images it creates.
231 // DDL TODO: sort out mipmapping
Brian Salomon0cc57542019-03-08 13:28:46 -0500232 image = recorder->makePromiseTexture(
233 backendFormat,
234 curImage.overallWidth(),
235 curImage.overallHeight(),
236 GrMipMapped::kNo,
237 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
238 curImage.overallColorType(),
239 curImage.overallAlphaType(),
240 curImage.refOverallColorSpace(),
241 DDLPromiseImageHelper::PromiseImageFulfillProc,
242 DDLPromiseImageHelper::PromiseImageReleaseProc,
243 DDLPromiseImageHelper::PromiseImageDoneProc,
244 (void*)curImage.refCallbackContext(0).release(),
245 SkDeferredDisplayListRecorder::PromiseImageApiVersion::kNew);
Brian Salomoncdd8a0a2019-01-10 12:09:52 -0500246 curImage.callbackContext(0)->wasAddedToImage();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400247 }
Robert Phillips96601082018-05-29 16:13:26 -0400248 perRecorderContext->fPromiseImages->push_back(image);
249 SkASSERT(image);
250 return image;
251}
252
253int DDLPromiseImageHelper::findImage(SkImage* image) const {
254 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400255 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
256 SkASSERT(fImageInfo[i].index() == i);
257 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400258 return i;
259 }
260 }
261 return -1;
262}
263
264int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400265 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400266
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400267 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
Robert Phillips13371a12019-05-13 15:59:10 -0400268 image->colorType() == kBGRA_8888_SkColorType
269 ? kRGBA_8888_SkColorType
270 : image->colorType(),
271 image->alphaType(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400272 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400273
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400274 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
275 image->uniqueID(),
276 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400277
Jim Van Verthe24b5872018-10-29 16:26:02 -0400278 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400279 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400280 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400281 const void* planes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400282 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400283 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400284 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400285
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400286 // determine colortypes from index data
287 // for testing we only ever use A8 or RGBA8888
Jim Van Verthe24b5872018-10-29 16:26:02 -0400288 SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400289 kUnknown_SkColorType, kUnknown_SkColorType,
290 kUnknown_SkColorType, kUnknown_SkColorType
291 };
292 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
293 int texIdx = yuvaIndices[yuvIndex].fIndex;
294 if (texIdx < 0) {
295 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
296 continue;
297 }
298 if (kUnknown_SkColorType == colorTypes[texIdx]) {
299 colorTypes[texIdx] = kAlpha_8_SkColorType;
300 } else {
301 colorTypes[texIdx] = kRGBA_8888_SkColorType;
302 }
303 }
304
Jim Van Verthe24b5872018-10-29 16:26:02 -0400305 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400306 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
307 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400308 continue;
309 }
310
311 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
312 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400313 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400314 kUnpremul_SkAlphaType);
315 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400316 }
317 } else {
318 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
319
320 SkBitmap tmp;
321 tmp.allocPixels(overallII);
322
323 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
324 return -1;
325 }
326
327 tmp.setImmutable();
328 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400329 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400330 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400331
332 return fImageInfo.count()-1;
333}
334
335int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
336 int preExistingID = this->findImage(image);
337 if (preExistingID >= 0) {
338 SkASSERT(this->isValidID(preExistingID));
339 return preExistingID;
340 }
341
342 int newID = this->addImage(image);
343 SkASSERT(this->isValidID(newID));
344 return newID;
345}