blob: fcda20e8bcbf183150d6c53ddf4fa6c231778f04 [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
Jim Van Verth60ac5d02018-12-06 13:11:53 -050054// needed until we have SkRG_88_ColorType;
55static GrBackendTexture create_yuva_texture(GrGpu* gpu, const SkPixmap& pm,
56 const SkYUVAIndex yuvaIndices[4], int texIndex) {
57 SkASSERT(texIndex >= 0 && texIndex <= 3);
58 int channelCount = 0;
59 for (int i = 0; i < SkYUVAIndex::kIndexCount; ++i) {
60 if (yuvaIndices[i].fIndex == texIndex) {
61 ++channelCount;
62 }
63 }
64 // Need to create an RG texture for two-channel planes
65 GrBackendTexture tex;
66 if (2 == channelCount) {
67 SkASSERT(kRGBA_8888_SkColorType == pm.colorType());
68 SkAutoTMalloc<char> pixels(2 * pm.width()*pm.height());
69 char* currPixel = pixels;
70 for (int y = 0; y < pm.height(); ++y) {
71 for (int x = 0; x < pm.width(); ++x) {
72 SkColor color = pm.getColor(x, y);
73 currPixel[0] = SkColorGetR(color);
74 currPixel[1] = SkColorGetG(color);
75 currPixel += 2;
76 }
77 }
78 tex = gpu->createTestingOnlyBackendTexture(
79 pixels,
80 pm.width(),
81 pm.height(),
82 GrColorType::kRG_88,
83 false,
84 GrMipMapped::kNo,
85 2 * pm.width());
86 } else {
87 tex = gpu->createTestingOnlyBackendTexture(
88 pm.addr(),
89 pm.width(),
90 pm.height(),
91 pm.colorType(),
92 false,
93 GrMipMapped::kNo,
94 pm.rowBytes());
95 }
96 return tex;
97}
98
Robert Phillips96601082018-05-29 16:13:26 -040099void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
100 GrGpu* gpu = context->contextPriv().getGpu();
101 SkASSERT(gpu);
102
103 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));
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400118 SkAssertResult(callbackContext->backendTexture().isValid());
119
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(
129 bm.getPixels(),
130 bm.width(),
131 bm.height(),
132 bm.colorType(),
133 false, GrMipMapped::kNo,
134 bm.rowBytes()));
135 // The GMs sometimes request too large an image
136 //SkAssertResult(callbackContext->backendTexture().isValid());
137
138 fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
139 }
140
Robert Phillips96601082018-05-29 16:13:26 -0400141 }
142}
143
144sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
145 SkDeferredDisplayListRecorder* recorder,
146 SkData* compressedPictureData,
147 SkTArray<sk_sp<SkImage>>* promiseImages) const {
148 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
149
150 SkDeserialProcs procs;
151 procs.fImageCtx = (void*) &perRecorderContext;
152 procs.fImageProc = PromiseImageCreator;
153
154 return SkPicture::MakeFromData(compressedPictureData, &procs);
155}
156
157// This generates promise images to replace the indices in the compressed picture. This
158// reconstitution is performed separately in each thread so we end up with multiple
159// promise images referring to the same GrBackendTexture.
160sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
161 size_t length, void* ctxIn) {
162 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
163 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
164 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
165
166 SkASSERT(length == sizeof(int));
167
168 const int* indexPtr = static_cast<const int*>(rawData);
169 SkASSERT(helper->isValidID(*indexPtr));
170
171 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
172
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400173 if (!curImage.backendTexture(0).isValid()) {
174 SkASSERT(!curImage.isYUV());
Robert Phillips96601082018-05-29 16:13:26 -0400175 // We weren't able to make a backend texture for this SkImage. In this case we create
176 // a separate bitmap-backed image for each thread.
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400177 SkASSERT(curImage.normalBitmap().isImmutable());
178 return SkImage::MakeFromBitmap(curImage.normalBitmap());
Robert Phillips96601082018-05-29 16:13:26 -0400179 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400180 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400181
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400182 const GrCaps* caps = curImage.caps();
Robert Phillips96601082018-05-29 16:13:26 -0400183
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400184 sk_sp<SkImage> image;
185 if (curImage.isYUV()) {
Jim Van Verthe24b5872018-10-29 16:26:02 -0400186 GrBackendFormat backendFormats[SkYUVASizeInfo::kMaxCount];
187 void* contexts[SkYUVASizeInfo::kMaxCount] = { nullptr, nullptr, nullptr, nullptr };
188 SkISize sizes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400189 // TODO: store this value somewhere?
190 int textureCount;
191 SkAssertResult(SkYUVAIndex::AreValidIndices(curImage.yuvaIndices(), &textureCount));
192 for (int i = 0; i < textureCount; ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400193 const GrBackendTexture& backendTex = curImage.backendTexture(i);
194 backendFormats[i] = caps->createFormatFromBackendTexture(backendTex);
195
196 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verthf9f07352018-10-24 10:32:20 -0400197 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400198 }
Jim Van Verthe24b5872018-10-29 16:26:02 -0400199 for (int i = textureCount; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthf9f07352018-10-24 10:32:20 -0400200 sizes[i] = SkISize::MakeEmpty();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400201 }
Jim Van Verthf99a6742018-10-18 16:13:18 +0000202
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400203 image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
204 backendFormats,
Jim Van Verthf9f07352018-10-24 10:32:20 -0400205 sizes,
Jim Van Verth8f11e432018-10-18 14:36:59 -0400206 curImage.yuvaIndices(),
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400207 curImage.overallWidth(),
208 curImage.overallHeight(),
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400209 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
210 curImage.refOverallColorSpace(),
211 DDLPromiseImageHelper::PromiseImageFulfillProc,
212 DDLPromiseImageHelper::PromiseImageReleaseProc,
213 DDLPromiseImageHelper::PromiseImageDoneProc,
214 contexts);
215
216 } else {
217 const GrBackendTexture& backendTex = curImage.backendTexture(0);
218 GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
219
220 // Each DDL recorder gets its own ref on the promise callback context for the
221 // promise images it creates.
222 // DDL TODO: sort out mipmapping
223 image = recorder->makePromiseTexture(backendFormat,
224 curImage.overallWidth(),
225 curImage.overallHeight(),
226 GrMipMapped::kNo,
227 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
228 curImage.overallColorType(),
229 curImage.overallAlphaType(),
230 curImage.refOverallColorSpace(),
231 DDLPromiseImageHelper::PromiseImageFulfillProc,
232 DDLPromiseImageHelper::PromiseImageReleaseProc,
233 DDLPromiseImageHelper::PromiseImageDoneProc,
234 (void*) curImage.refCallbackContext(0).release());
235 }
Robert Phillips96601082018-05-29 16:13:26 -0400236 perRecorderContext->fPromiseImages->push_back(image);
237 SkASSERT(image);
238 return image;
239}
240
241int DDLPromiseImageHelper::findImage(SkImage* image) const {
242 for (int i = 0; i < fImageInfo.count(); ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400243 if (fImageInfo[i].originalUniqueID() == image->uniqueID()) { // trying to dedup here
244 SkASSERT(fImageInfo[i].index() == i);
245 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].index()));
Robert Phillips96601082018-05-29 16:13:26 -0400246 return i;
247 }
248 }
249 return -1;
250}
251
252int DDLPromiseImageHelper::addImage(SkImage* image) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400253 SkImage_Base* ib = as_IB(image);
Robert Phillips96601082018-05-29 16:13:26 -0400254
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400255 SkImageInfo overallII = SkImageInfo::Make(image->width(), image->height(),
256 image->colorType(), image->alphaType(),
257 image->refColorSpace());
Robert Phillips96601082018-05-29 16:13:26 -0400258
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400259 PromiseImageInfo& newImageInfo = fImageInfo.emplace_back(fImageInfo.count(),
260 image->uniqueID(),
261 overallII);
Robert Phillips96601082018-05-29 16:13:26 -0400262
Jim Van Verthe24b5872018-10-29 16:26:02 -0400263 SkYUVASizeInfo yuvaSizeInfo;
Jim Van Verth8f11e432018-10-18 14:36:59 -0400264 SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount];
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400265 SkYUVColorSpace yuvColorSpace;
Jim Van Verthe24b5872018-10-29 16:26:02 -0400266 const void* planes[SkYUVASizeInfo::kMaxCount];
Jim Van Verth8f11e432018-10-18 14:36:59 -0400267 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvaSizeInfo, yuvaIndices, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400268 if (yuvData) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400269 newImageInfo.setYUVData(std::move(yuvData), yuvaIndices, yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400270
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400271 // determine colortypes from index data
272 // for testing we only ever use A8 or RGBA8888
Jim Van Verthe24b5872018-10-29 16:26:02 -0400273 SkColorType colorTypes[SkYUVASizeInfo::kMaxCount] = {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400274 kUnknown_SkColorType, kUnknown_SkColorType,
275 kUnknown_SkColorType, kUnknown_SkColorType
276 };
277 for (int yuvIndex = 0; yuvIndex < SkYUVAIndex::kIndexCount; ++yuvIndex) {
278 int texIdx = yuvaIndices[yuvIndex].fIndex;
279 if (texIdx < 0) {
280 SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
281 continue;
282 }
283 if (kUnknown_SkColorType == colorTypes[texIdx]) {
284 colorTypes[texIdx] = kAlpha_8_SkColorType;
285 } else {
286 colorTypes[texIdx] = kRGBA_8888_SkColorType;
287 }
288 }
289
Jim Van Verthe24b5872018-10-29 16:26:02 -0400290 for (int i = 0; i < SkYUVASizeInfo::kMaxCount; ++i) {
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400291 if (yuvaSizeInfo.fSizes[i].isEmpty()) {
292 SkASSERT(!yuvaSizeInfo.fWidthBytes[i] && kUnknown_SkColorType == colorTypes[i]);
Jim Van Verth8f11e432018-10-18 14:36:59 -0400293 continue;
294 }
295
296 SkImageInfo planeII = SkImageInfo::Make(yuvaSizeInfo.fSizes[i].fWidth,
297 yuvaSizeInfo.fSizes[i].fHeight,
Jim Van Verthb7f0b9c2018-10-22 14:12:03 -0400298 colorTypes[i],
Jim Van Verth8f11e432018-10-18 14:36:59 -0400299 kUnpremul_SkAlphaType);
300 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvaSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400301 }
302 } else {
303 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
304
305 SkBitmap tmp;
306 tmp.allocPixels(overallII);
307
308 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
309 return -1;
310 }
311
312 tmp.setImmutable();
313 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400314 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400315 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400316
317 return fImageInfo.count()-1;
318}
319
320int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
321 int preExistingID = this->findImage(image);
322 if (preExistingID >= 0) {
323 SkASSERT(this->isValidID(preExistingID));
324 return preExistingID;
325 }
326
327 int newID = this->addImage(image);
328 SkASSERT(this->isValidID(newID));
329 return newID;
330}