blob: f582cee49ad63a8ae97886fa96a89f609276d0d9 [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"
Robert Phillipse8e2bb12018-09-27 14:26:47 -040017#include "SkYUVSizeInfo.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 Verth8f11e432018-10-18 14:36:59 -0400145 GrBackendFormat backendFormats[SkYUVSizeInfo::kMaxCount];
146 void* contexts[SkYUVSizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
147 SkYUVSizeInfo sizeInfo;
148 // 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 Verth8f11e432018-10-18 14:36:59 -0400156 sizeInfo.fSizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
157 sizeInfo.fColorTypes[i] = curImage.yuvPixmap(i).colorType();
158 sizeInfo.fWidthBytes[i] = curImage.yuvPixmap(i).rowBytes();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400159 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400160 for (int i = textureCount; i < SkYUVSizeInfo::kMaxCount; ++i) {
161 sizeInfo.fSizes[i] = SkISize::MakeEmpty();
162 sizeInfo.fColorTypes[i] = kUnknown_SkColorType;
163 sizeInfo.fWidthBytes[i] = 0;
164 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000165
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400166 image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
167 backendFormats,
Jim Van Verth8f11e432018-10-18 14:36:59 -0400168 sizeInfo,
169 curImage.yuvaIndices(),
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400170 curImage.overallWidth(),
171 curImage.overallHeight(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400172 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
173 curImage.refOverallColorSpace(),
174 DDLPromiseImageHelper::PromiseImageFulfillProc,
175 DDLPromiseImageHelper::PromiseImageReleaseProc,
176 DDLPromiseImageHelper::PromiseImageDoneProc,
177 contexts);
178
179 } else {
180 const GrBackendTexture& backendTex = curImage.backendTexture(0);
181 GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
182
183 // Each DDL recorder gets its own ref on the promise callback context for the
184 // promise images it creates.
185 // DDL TODO: sort out mipmapping
186 image = recorder->makePromiseTexture(backendFormat,
187 curImage.overallWidth(),
188 curImage.overallHeight(),
189 GrMipMapped::kNo,
190 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
191 curImage.overallColorType(),
192 curImage.overallAlphaType(),
193 curImage.refOverallColorSpace(),
194 DDLPromiseImageHelper::PromiseImageFulfillProc,
195 DDLPromiseImageHelper::PromiseImageReleaseProc,
196 DDLPromiseImageHelper::PromiseImageDoneProc,
197 (void*) curImage.refCallbackContext(0).release());
198 }
Robert Phillips96601082018-05-29 16:13:26 -0400199 perRecorderContext->fPromiseImages->push_back(image);
200 SkASSERT(image);
201 return image;
202}
203
204int DDLPromiseImageHelper::findImage(SkImage* image) const {
205 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400206 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
207 SkASSERT(fImageInfo[i].index() == i);
208 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400209 return i;
210 }
211 }
212 return -1;
213}
214
215int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400216 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400217
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400218 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
219 image->colorType(), image->alphaType(),
220 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400221
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400222 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
223 image->uniqueID(),
224 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400225
Jim Van Verth8f11e432018-10-18 14:36:59 -0400226 SkYUVSizeInfo yuvaSizeInfo;
227 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400228 SkYUVColorSpace yuvColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400229 const void* planes[SkYUVSizeInfo::kMaxCount];
230 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400231 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400232 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400233
Jim Van Verth8f11e432018-10-18 14:36:59 -0400234 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
235 if (kUnknown_SkColorType == yuvaSizeInfo.fColorTypes[i]) {
236 SkASSERT(!yuvaSizeInfo.fSizes[i].fWidth &&
237 !yuvaSizeInfo.fSizes[i].fHeight &&
238 !yuvaSizeInfo.fWidthBytes[i]);
239 continue;
240 }
241
242 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
243 yuvaSizeInfo.fSizes[i].fHeight,
244 yuvaSizeInfo.fColorTypes[i],
245 kUnpremul_SkAlphaType);
246 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400247 }
248 } else {
249 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
250
251 SkBitmap tmp;
252 tmp.allocPixels(overallII);
253
254 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
255 return -1;
256 }
257
258 tmp.setImmutable();
259 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400260 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400261 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400262
263 return fImageInfo.count()-1;
264}
265
266int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
267 int preExistingID = this->findImage(image);
268 if (preExistingID >= 0) {
269 SkASSERT(this->isValidID(preExistingID));
270 return preExistingID;
271 }
272
273 int newID = this->addImage(image);
274 SkASSERT(this->isValidID(newID));
275 return newID;
276}