blob: 53fcd1cd98d10797d238f0123eaca50da0061afa [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
8#include "DDLPromiseImageHelper.h"
9
Robert Phillips96601082018-05-29 16:13:26 -040010#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrGpu.h"
Robert Phillipse8e2bb12018-09-27 14:26:47 -040013#include "SkCachedData.h"
Robert Phillips96601082018-05-29 16:13:26 -040014#include "SkDeferredDisplayListRecorder.h"
Robert Phillipse8e2bb12018-09-27 14:26:47 -040015#include "SkImage_Base.h"
Robert Phillips66a97342018-10-04 09:10:29 -040016#include "SkYUVAIndex.h"
Jim Van Verthe24b5872018-10-29 16:26:02 -040017#include "SkYUVASizeInfo.h"
Robert Phillips96601082018-05-29 16:13:26 -040018
19DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
20 GrGpu* gpu = fContext->contextPriv().getGpu();
21
22 if (fBackendTexture.isValid()) {
23 gpu->deleteTestingOnlyBackendTexture(fBackendTexture);
24 }
25}
26
Timothy Liang036fdfe2018-06-28 15:50:36 -040027const GrCaps* DDLPromiseImageHelper::PromiseImageCallbackContext::caps() const {
28 return fContext->contextPriv().caps();
29}
30
Robert Phillips96601082018-05-29 16:13:26 -040031///////////////////////////////////////////////////////////////////////////////////////////////////
32
Robert Phillipse8e2bb12018-09-27 14:26:47 -040033DDLPromiseImageHelper::~DDLPromiseImageHelper() {}
34
Robert Phillips96601082018-05-29 16:13:26 -040035sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
36 SkSerialProcs procs;
37
38 procs.fImageCtx = this;
39 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
40 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
41
42 int id = helper->findOrDefineImage(image);
43 if (id >= 0) {
44 SkASSERT(helper->isValidID(id));
45 return SkData::MakeWithCopy(&id, sizeof(id));
46 }
47
48 return nullptr;
49 };
50
51 return inputPicture->serialize(&procs);
52}
53
54void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
55 GrGpu* gpu = context->contextPriv().getGpu();
56 SkASSERT(gpu);
57
58 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillips96601082018-05-29 16:13:26 -040059 const PromiseImageInfo& info = fImageInfo[i];
60
61 // DDL TODO: how can we tell if we need mipmapping!
Robert Phillipse8e2bb12018-09-27 14:26:47 -040062 if (info.isYUV()) {
Jim Van Verth8f11e432018-10-18 14:36:59 -040063 int numPixmaps;
64 SkAssertResult(SkYUVAIndex::AreValidIndices(info.yuvaIndices(), &numPixmaps));
65 for (int j = 0; j < numPixmaps; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040066 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -040067
Robert Phillipse8e2bb12018-09-27 14:26:47 -040068 sk_sp<PromiseImageCallbackContext> callbackContext(
69 new PromiseImageCallbackContext(context));
70 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
71 yuvPixmap.addr(),
72 yuvPixmap.width(),
73 yuvPixmap.height(),
74 yuvPixmap.colorType(),
75 false, GrMipMapped::kNo,
76 yuvPixmap.rowBytes()));
77 SkAssertResult(callbackContext->backendTexture().isValid());
78
79 fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
80 }
81 } else {
82 sk_sp<PromiseImageCallbackContext> callbackContext(
83 new PromiseImageCallbackContext(context));
84
85 const SkBitmap& bm = info.normalBitmap();
86
87 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
88 bm.getPixels(),
89 bm.width(),
90 bm.height(),
91 bm.colorType(),
92 false, GrMipMapped::kNo,
93 bm.rowBytes()));
94 // The GMs sometimes request too large an image
95 //SkAssertResult(callbackContext->backendTexture().isValid());
96
97 fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
98 }
99
Robert Phillips96601082018-05-29 16:13:26 -0400100 }
101}
102
103sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
104 SkDeferredDisplayListRecorder* recorder,
105 SkData* compressedPictureData,
106 SkTArray<sk_sp<SkImage>>* promiseImages) const {
107 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
108
109 SkDeserialProcs procs;
110 procs.fImageCtx = (void*) &perRecorderContext;
111 procs.fImageProc = PromiseImageCreator;
112
113 return SkPicture::MakeFromData(compressedPictureData, &procs);
114}
115
116// This generates promise images to replace the indices in the compressed picture. This
117// reconstitution is performed separately in each thread so we end up with multiple
118// promise images referring to the same GrBackendTexture.
119sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
120 size_t length, void* ctxIn) {
121 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
122 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
123 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
124
125 SkASSERT(length == sizeof(int));
126
127 const int* indexPtr = static_cast<const int*>(rawData);
128 SkASSERT(helper->isValidID(*indexPtr));
129
130 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
131
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400132 if (!curImage.backendTexture(0).isValid()) {
133 SkASSERT(!curImage.isYUV());
Robert Phillips96601082018-05-29 16:13:26 -0400134 // We weren't able to make a backend texture for this SkImage. In this case we create
135 // a separate bitmap-backed image for each thread.
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400136 SkASSERT(curImage.normalBitmap().isImmutable());
137 return SkImage::MakeFromBitmap(curImage.normalBitmap());
Robert Phillips96601082018-05-29 16:13:26 -0400138 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400139 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400140
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400141 const GrCaps* caps = curImage.caps();
Robert Phillips96601082018-05-29 16:13:26 -0400142
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400143 sk_sp<SkImage> image;
144 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400145 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
146 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
147 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400148 // TODO: store this value somewhere?
149 int textureCount;
150 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
151 for (int i = 0; i < textureCount; ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400152 const GrBackendTexture& backendTex = curImage.backendTexture(i);
153 backendFormats[i] = caps->createFormatFromBackendTexture(backendTex);
154
155 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400156 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400157 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400158 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400159 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400160 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000161
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400162 image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
163 backendFormats,
Jim Van Verthf9f07352018-10-24 10:32:20 -0400164 sizes,
Jim Van Verth8f11e432018-10-18 14:36:59 -0400165 curImage.yuvaIndices(),
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400166 curImage.overallWidth(),
167 curImage.overallHeight(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400168 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
169 curImage.refOverallColorSpace(),
170 DDLPromiseImageHelper::PromiseImageFulfillProc,
171 DDLPromiseImageHelper::PromiseImageReleaseProc,
172 DDLPromiseImageHelper::PromiseImageDoneProc,
173 contexts);
174
175 } else {
176 const GrBackendTexture& backendTex = curImage.backendTexture(0);
177 GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
178
179 // Each DDL recorder gets its own ref on the promise callback context for the
180 // promise images it creates.
181 // DDL TODO: sort out mipmapping
182 image = recorder->makePromiseTexture(backendFormat,
183 curImage.overallWidth(),
184 curImage.overallHeight(),
185 GrMipMapped::kNo,
186 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
187 curImage.overallColorType(),
188 curImage.overallAlphaType(),
189 curImage.refOverallColorSpace(),
190 DDLPromiseImageHelper::PromiseImageFulfillProc,
191 DDLPromiseImageHelper::PromiseImageReleaseProc,
192 DDLPromiseImageHelper::PromiseImageDoneProc,
193 (void*) curImage.refCallbackContext(0).release());
194 }
Robert Phillips96601082018-05-29 16:13:26 -0400195 perRecorderContext->fPromiseImages->push_back(image);
196 SkASSERT(image);
197 return image;
198}
199
200int DDLPromiseImageHelper::findImage(SkImage* image) const {
201 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400202 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
203 SkASSERT(fImageInfo[i].index() == i);
204 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400205 return i;
206 }
207 }
208 return -1;
209}
210
211int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400212 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400213
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400214 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
215 image->colorType(), image->alphaType(),
216 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400217
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400218 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
219 image->uniqueID(),
220 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400221
Jim Van Verthe24b5872018-10-29 16:26:02 -0400222 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400223 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400224 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400225 const void* planes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400226 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400227 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400228 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400229
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400230 // determine colortypes from index data
231 // for testing we only ever use A8 or RGBA8888
Jim Van Verthe24b5872018-10-29 16:26:02 -0400232 SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400233 kUnknown_SkColorType, kUnknown_SkColorType,
234 kUnknown_SkColorType, kUnknown_SkColorType
235 };
236 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
237 int texIdx = yuvaIndices[yuvIndex].fIndex;
238 if (texIdx < 0) {
239 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
240 continue;
241 }
242 if (kUnknown_SkColorType == colorTypes[texIdx]) {
243 colorTypes[texIdx] = kAlpha_8_SkColorType;
244 } else {
245 colorTypes[texIdx] = kRGBA_8888_SkColorType;
246 }
247 }
248
Jim Van Verthe24b5872018-10-29 16:26:02 -0400249 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400250 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
251 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400252 continue;
253 }
254
255 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
256 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400257 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400258 kUnpremul_SkAlphaType);
259 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400260 }
261 } else {
262 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
263
264 SkBitmap tmp;
265 tmp.allocPixels(overallII);
266
267 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
268 return -1;
269 }
270
271 tmp.setImmutable();
272 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400273 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400274 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400275
276 return fImageInfo.count()-1;
277}
278
279int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
280 int preExistingID = this->findImage(image);
281 if (preExistingID >= 0) {
282 SkASSERT(this->isValidID(preExistingID));
283 return preExistingID;
284 }
285
286 int newID = this->addImage(image);
287 SkASSERT(this->isValidID(newID));
288 return newID;
289}