blob: cc543f9d40123a22e0cb3ddc4c0402be286aa1f7 [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"
13#include "SkDeferredDisplayListRecorder.h"
14
15DDLPromiseImageHelper::PromiseImageCallbackContext::~PromiseImageCallbackContext() {
16 GrGpu* gpu = fContext->contextPriv().getGpu();
17
18 if (fBackendTexture.isValid()) {
19 gpu->deleteTestingOnlyBackendTexture(fBackendTexture);
20 }
21}
22
Timothy Liang036fdfe2018-06-28 15:50:36 -040023const GrCaps* DDLPromiseImageHelper::PromiseImageCallbackContext::caps() const {
24 return fContext->contextPriv().caps();
25}
26
Robert Phillips96601082018-05-29 16:13:26 -040027///////////////////////////////////////////////////////////////////////////////////////////////////
28
29sk_sp<SkData> DDLPromiseImageHelper::deflateSKP(const SkPicture* inputPicture) {
30 SkSerialProcs procs;
31
32 procs.fImageCtx = this;
33 procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> {
34 auto helper = static_cast<DDLPromiseImageHelper*>(ctx);
35
36 int id = helper->findOrDefineImage(image);
37 if (id >= 0) {
38 SkASSERT(helper->isValidID(id));
39 return SkData::MakeWithCopy(&id, sizeof(id));
40 }
41
42 return nullptr;
43 };
44
45 return inputPicture->serialize(&procs);
46}
47
48void DDLPromiseImageHelper::uploadAllToGPU(GrContext* context) {
49 GrGpu* gpu = context->contextPriv().getGpu();
50 SkASSERT(gpu);
51
52 for (int i = 0; i < fImageInfo.count(); ++i) {
53 sk_sp<PromiseImageCallbackContext> callbackContext(
54 new PromiseImageCallbackContext(context));
55
56 const PromiseImageInfo& info = fImageInfo[i];
57
58 // DDL TODO: how can we tell if we need mipmapping!
59 callbackContext->setBackendTexture(gpu->createTestingOnlyBackendTexture(
60 info.fBitmap.getPixels(),
61 info.fBitmap.width(),
62 info.fBitmap.height(),
63 info.fBitmap.colorType(),
Robert Phillips96601082018-05-29 16:13:26 -040064 false, GrMipMapped::kNo));
65 // The GMs sometimes request too large an image
66 //SkAssertResult(callbackContext->backendTexture().isValid());
67
68 // The fImageInfo array gets the creation ref
69 fImageInfo[i].fCallbackContext = std::move(callbackContext);
70 }
71}
72
73sk_sp<SkPicture> DDLPromiseImageHelper::reinflateSKP(
74 SkDeferredDisplayListRecorder* recorder,
75 SkData* compressedPictureData,
76 SkTArray<sk_sp<SkImage>>* promiseImages) const {
77 PerRecorderContext perRecorderContext { recorder, this, promiseImages };
78
79 SkDeserialProcs procs;
80 procs.fImageCtx = (void*) &perRecorderContext;
81 procs.fImageProc = PromiseImageCreator;
82
83 return SkPicture::MakeFromData(compressedPictureData, &procs);
84}
85
86// This generates promise images to replace the indices in the compressed picture. This
87// reconstitution is performed separately in each thread so we end up with multiple
88// promise images referring to the same GrBackendTexture.
89sk_sp<SkImage> DDLPromiseImageHelper::PromiseImageCreator(const void* rawData,
90 size_t length, void* ctxIn) {
91 PerRecorderContext* perRecorderContext = static_cast<PerRecorderContext*>(ctxIn);
92 const DDLPromiseImageHelper* helper = perRecorderContext->fHelper;
93 SkDeferredDisplayListRecorder* recorder = perRecorderContext->fRecorder;
94
95 SkASSERT(length == sizeof(int));
96
97 const int* indexPtr = static_cast<const int*>(rawData);
98 SkASSERT(helper->isValidID(*indexPtr));
99
100 const DDLPromiseImageHelper::PromiseImageInfo& curImage = helper->getInfo(*indexPtr);
101
102 if (!curImage.fCallbackContext->backendTexture().isValid()) {
103 // We weren't able to make a backend texture for this SkImage. In this case we create
104 // a separate bitmap-backed image for each thread.
105 // Note: we would like to share the same bitmap between all the threads but
106 // SkBitmap is not thread-safe.
107 return SkImage::MakeRasterCopy(curImage.fBitmap.pixmap());
108 }
109 SkASSERT(curImage.fIndex == *indexPtr);
110
Timothy Liang036fdfe2018-06-28 15:50:36 -0400111 const GrCaps* caps = curImage.fCallbackContext->caps();
112 const GrBackendTexture& backendTex = curImage.fCallbackContext->backendTexture();
113 GrBackendFormat backendFormat = caps->createFormatFromBackendTexture(backendTex);
Robert Phillips96601082018-05-29 16:13:26 -0400114
115 // Each DDL recorder gets its own ref on the promise callback context for the
116 // promise images it creates.
117 // DDL TODO: sort out mipmapping
118 sk_sp<SkImage> image = recorder->makePromiseTexture(
119 backendFormat,
120 curImage.fBitmap.width(),
121 curImage.fBitmap.height(),
122 GrMipMapped::kNo,
123 GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
124 curImage.fBitmap.colorType(),
125 curImage.fBitmap.alphaType(),
126 curImage.fBitmap.refColorSpace(),
127 DDLPromiseImageHelper::PromiseImageFulfillProc,
128 DDLPromiseImageHelper::PromiseImageReleaseProc,
129 DDLPromiseImageHelper::PromiseImageDoneProc,
130 (void*) SkSafeRef(curImage.fCallbackContext.get()));
131 perRecorderContext->fPromiseImages->push_back(image);
132 SkASSERT(image);
133 return image;
134}
135
136int DDLPromiseImageHelper::findImage(SkImage* image) const {
137 for (int i = 0; i < fImageInfo.count(); ++i) {
138 if (fImageInfo[i].fOriginalUniqueID == image->uniqueID()) { // trying to dedup here
139 SkASSERT(fImageInfo[i].fIndex == i);
140 SkASSERT(this->isValidID(i) && this->isValidID(fImageInfo[i].fIndex));
141 return i;
142 }
143 }
144 return -1;
145}
146
147int DDLPromiseImageHelper::addImage(SkImage* image) {
148 sk_sp<SkImage> rasterImage = image->makeRasterImage(); // force decoding of lazy images
149
150 SkImageInfo ii = SkImageInfo::Make(rasterImage->width(), rasterImage->height(),
151 rasterImage->colorType(), rasterImage->alphaType(),
152 rasterImage->refColorSpace());
153
154 SkBitmap bm;
155 bm.allocPixels(ii);
156
157 if (!rasterImage->readPixels(bm.pixmap(), 0, 0)) {
158 return -1;
159 }
160
161 bm.setImmutable();
162
163 PromiseImageInfo& newImageInfo = fImageInfo.push_back();
164 newImageInfo.fIndex = fImageInfo.count()-1;
165 newImageInfo.fOriginalUniqueID = image->uniqueID();
166 newImageInfo.fBitmap = bm;
167 /* fCallbackContext is filled in by uploadAllToGPU */
168
169 return fImageInfo.count()-1;
170}
171
172int DDLPromiseImageHelper::findOrDefineImage(SkImage* image) {
173 int preExistingID = this->findImage(image);
174 if (preExistingID >= 0) {
175 SkASSERT(this->isValidID(preExistingID));
176 return preExistingID;
177 }
178
179 int newID = this->addImage(image);
180 SkASSERT(this->isValidID(newID));
181 return newID;
182}