blob: accdebdfd207294fe5e16ac15f91a3e86815c1db [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());
Jim Van Verth8f11e432018-10-18 14:36:59 -0400157 sizeInfo.fWidthBytes[i] = curImage.yuvPixmap(i).rowBytes();
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400158 }
Jim Van Verth8f11e432018-10-18 14:36:59 -0400159 for (int i = textureCount; i < SkYUVSizeInfo::kMaxCount; ++i) {
160 sizeInfo.fSizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400161 sizeInfo.fWidthBytes[i] = 0;
162 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000163
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400164 image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
165 backendFormats,
Jim Van Verth8f11e432018-10-18 14:36:59 -0400166 sizeInfo,
167 curImage.yuvaIndices(),
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400168 curImage.overallWidth(),
169 curImage.overallHeight(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400170 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
171 curImage.refOverallColorSpace(),
172 DDLPromiseImageHelper::PromiseImageFulfillProc,
173 DDLPromiseImageHelper::PromiseImageReleaseProc,
174 DDLPromiseImageHelper::PromiseImageDoneProc,
175 contexts);
176
177 } else {
178 const GrBackendTexture& backendTex = curImage.backendTexture(0);
179 GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
180
181 // Each DDL recorder gets its own ref on the promise callback context for the
182 // promise images it creates.
183 // DDL TODO: sort out mipmapping
184 image = recorder->makePromiseTexture(backendFormat,
185 curImage.overallWidth(),
186 curImage.overallHeight(),
187 GrMipMapped::kNo,
188 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
189 curImage.overallColorType(),
190 curImage.overallAlphaType(),
191 curImage.refOverallColorSpace(),
192 DDLPromiseImageHelper::PromiseImageFulfillProc,
193 DDLPromiseImageHelper::PromiseImageReleaseProc,
194 DDLPromiseImageHelper::PromiseImageDoneProc,
195 (void*) curImage.refCallbackContext(0).release());
196 }
Robert Phillips96601082018-05-29 16:13:26 -0400197 perRecorderContext->fPromiseImages->push_back(image);
198 SkASSERT(image);
199 return image;
200}
201
202int DDLPromiseImageHelper::findImage(SkImage* image) const {
203 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400204 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
205 SkASSERT(fImageInfo[i].index() == i);
206 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400207 return i;
208 }
209 }
210 return -1;
211}
212
213int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400214 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400215
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400216 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
217 image->colorType(), image->alphaType(),
218 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400219
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400220 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
221 image->uniqueID(),
222 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400223
Jim Van Verth8f11e432018-10-18 14:36:59 -0400224 SkYUVSizeInfo yuvaSizeInfo;
225 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400226 SkYUVColorSpace yuvColorSpace;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400227 const void* planes[SkYUVSizeInfo::kMaxCount];
228 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400229 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400230 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400231
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400232 // determine colortypes from index data
233 // for testing we only ever use A8 or RGBA8888
234 SkColorType colorTypes[SkYUVSizeInfo::kMaxCount] = {
235 kUnknown_SkColorType, kUnknown_SkColorType,
236 kUnknown_SkColorType, kUnknown_SkColorType
237 };
238 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
239 int texIdx = yuvaIndices[yuvIndex].fIndex;
240 if (texIdx < 0) {
241 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
242 continue;
243 }
244 if (kUnknown_SkColorType == colorTypes[texIdx]) {
245 colorTypes[texIdx] = kAlpha_8_SkColorType;
246 } else {
247 colorTypes[texIdx] = kRGBA_8888_SkColorType;
248 }
249 }
250
Jim Van Verth8f11e432018-10-18 14:36:59 -0400251 for (int i = 0; i < SkYUVSizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400252 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
253 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400254 continue;
255 }
256
257 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
258 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400259 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400260 kUnpremul_SkAlphaType);
261 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400262 }
263 } else {
264 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
265
266 SkBitmap tmp;
267 tmp.allocPixels(overallII);
268
269 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
270 return -1;
271 }
272
273 tmp.setImmutable();
274 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400275 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400276 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400277
278 return fImageInfo.count()-1;
279}
280
281int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
282 int preExistingID = this->findImage(image);
283 if (preExistingID >= 0) {
284 SkASSERT(this->isValidID(preExistingID));
285 return preExistingID;
286 }
287
288 int newID = this->addImage(image);
289 SkASSERT(this->isValidID(newID));
290 return newID;
291}