blob: 63369cc219b1e3e0d2416e98455f422ee1ef9961 [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 Verthf99a6742018-10-18 16:13:18 +000063 for (int j = 0; j < 3; ++j) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -040064 const SkPixmap& yuvPixmap = info.yuvPixmap(j);
Robert Phillips96601082018-05-29 16:13:26 -040065
Robert Phillipse8e2bb12018-09-27 14:26:47 -040066 sk_sp<PromiseImageCallbackContext> callbackContext(
67 new PromiseImageCallbackContext(context));
68 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
69 yuvPixmap.addr(),
70 yuvPixmap.width(),
71 yuvPixmap.height(),
72 yuvPixmap.colorType(),
73 false, GrMipMapped::kNo,
74 yuvPixmap.rowBytes()));
75 SkAssertResult(callbackContext->backendTexture().isValid());
76
77 fImageInfo[i].setCallbackContext(j, std::move(callbackContext));
78 }
79 } else {
80 sk_sp<PromiseImageCallbackContext> callbackContext(
81 new PromiseImageCallbackContext(context));
82
83 const SkBitmap& bm = info.normalBitmap();
84
85 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
86 bm.getPixels(),
87 bm.width(),
88 bm.height(),
89 bm.colorType(),
90 false, GrMipMapped::kNo,
91 bm.rowBytes()));
92 // The GMs sometimes request too large an image
93 //SkAssertResult(callbackContext->backendTexture().isValid());
94
95 fImageInfo[i].setCallbackContext(0, std::move(callbackContext));
96 }
97
Robert Phillips96601082018-05-29 16:13:26 -040098 }
99}
100
101sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
102 SkDeferredDisplayListRecorder* recorder,
103 SkData* compressedPictureData,
104 SkTArray<sk_sp<SkImage>>* promiseImages) const {
105 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
106
107 SkDeserialProcs procs;
108 procs.fImageCtx = (void*) &perRecorderContext;
109 procs.fImageProc = PromiseImageCreator;
110
111 return SkPicture::MakeFromData(compressedPictureData, &procs);
112}
113
114// This generates promise images to replace the indices in the compressed picture. This
115// reconstitution is performed separately in each thread so we end up with multiple
116// promise images referring to the same GrBackendTexture.
117sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
118 size_t length, void* ctxIn) {
119 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
120 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
121 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
122
123 SkASSERT(length == sizeof(int));
124
125 const int* indexPtr = static_cast<const int*>(rawData);
126 SkASSERT(helper->isValidID(*indexPtr));
127
128 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
129
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400130 if (!curImage.backendTexture(0).isValid()) {
131 SkASSERT(!curImage.isYUV());
Robert Phillips96601082018-05-29 16:13:26 -0400132 // We weren't able to make a backend texture for this SkImage. In this case we create
133 // a separate bitmap-backed image for each thread.
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400134 SkASSERT(curImage.normalBitmap().isImmutable());
135 return SkImage::MakeFromBitmap(curImage.normalBitmap());
Robert Phillips96601082018-05-29 16:13:26 -0400136 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400137 SkASSERT(curImage.index() == *indexPtr);
Robert Phillips96601082018-05-29 16:13:26 -0400138
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400139 const GrCaps* caps = curImage.caps();
Robert Phillips96601082018-05-29 16:13:26 -0400140
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400141 sk_sp<SkImage> image;
142 if (curImage.isYUV()) {
Jim Van Verthf99a6742018-10-18 16:13:18 +0000143 GrBackendFormat backendFormats[4];
144 void* contexts[4] = { nullptr, nullptr, nullptr, nullptr };
145 SkISize sizes[4];
146
147 for (int i = 0; i < 3; ++i) {
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400148 const GrBackendTexture& backendTex = curImage.backendTexture(i);
149 backendFormats[i] = caps->createFormatFromBackendTexture(backendTex);
150
151 contexts[i] = curImage.refCallbackContext(i).release();
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400152 sizes[i].set(curImage.yuvPixmap(i).width(), curImage.yuvPixmap(i).height());
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400153 }
154
Jim Van Verthf99a6742018-10-18 16:13:18 +0000155 SkYUVAIndex yuvaIndices[4] = {
156 SkYUVAIndex{0, SkColorChannel::kA},
157 SkYUVAIndex{1, SkColorChannel::kA},
158 SkYUVAIndex{2, SkColorChannel::kA},
159 SkYUVAIndex{-1, SkColorChannel::kA} // TODO: enable this
160 };
161
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400162 image = recorder->makeYUVAPromiseTexture(curImage.yuvColorSpace(),
163 backendFormats,
Jim Van Verth21bd60d2018-10-12 15:00:20 -0400164 sizes,
Jim Van Verthf99a6742018-10-18 16:13:18 +0000165 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 Verthf99a6742018-10-18 16:13:18 +0000222 SkYUVSizeInfo yuvSizeInfo;
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400223 SkYUVColorSpace yuvColorSpace;
Jim Van Verthf99a6742018-10-18 16:13:18 +0000224 const void* planes[3];
225 sk_sp<SkCachedData> yuvData = ib->getPlanes(&yuvSizeInfo, &yuvColorSpace, planes);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400226 if (yuvData) {
Jim Van Verthf99a6742018-10-18 16:13:18 +0000227 newImageInfo.setYUVData(std::move(yuvData), yuvColorSpace);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400228
Jim Van Verthf99a6742018-10-18 16:13:18 +0000229 for (int i = 0; i < 3; ++i) {
230 SkImageInfo planeII = SkImageInfo::MakeA8(yuvSizeInfo.fSizes[i].fWidth,
231 yuvSizeInfo.fSizes[i].fHeight);
232 newImageInfo.addYUVPlane(i, planeII, planes[i], yuvSizeInfo.fWidthBytes[i]);
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400233 }
234 } else {
235 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
236
237 SkBitmap tmp;
238 tmp.allocPixels(overallII);
239
240 if (!rasterImage->readPixels(tmp.pixmap(), 0, 0)) {
241 return -1;
242 }
243
244 tmp.setImmutable();
245 newImageInfo.setNormalBitmap(tmp);
Robert Phillips96601082018-05-29 16:13:26 -0400246 }
Robert Phillipse8e2bb12018-09-27 14:26:47 -0400247 // In either case newImageInfo's PromiseImageCallbackContext is filled in by uploadAllToGPU
Robert Phillips96601082018-05-29 16:13:26 -0400248
249 return fImageInfo.count()-1;
250}
251
252int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
253 int preExistingID = this->findImage(image);
254 if (preExistingID >= 0) {
255 SkASSERT(this->isValidID(preExistingID));
256 return preExistingID;
257 }
258
259 int newID = this->addImage(image);
260 SkASSERT(this->isValidID(newID));
261 return newID;
262}