blob: ff07a5101f6be3e8ccd85f9ae9604403f3244b40 [file] [log] [blame]
Jim Van Verth8026ccc2018-10-04 13:10:39 -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 "GrBackendSurface.h"
9#include "GrClip.h"
10#include "GrContext.h"
11#include "GrContextPriv.h"
12#include "GrRenderTargetContext.h"
13#include "GrTexture.h"
14#include "GrTextureAdjuster.h"
15#include "SkBitmapCache.h"
16#include "SkImage_Gpu.h"
17#include "SkImage_GpuBase.h"
Jim Van Verth8bbce0e2018-10-08 14:34:52 -040018#include "SkReadPixelsRec.h"
Jim Van Verth8026ccc2018-10-04 13:10:39 -040019
20SkImage_GpuBase::SkImage_GpuBase(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
21 SkAlphaType at, SkBudgeted budgeted, sk_sp<SkColorSpace> cs)
22 : INHERITED(width, height, uniqueID)
23 , fContext(std::move(context))
24 , fAlphaType(at)
25 , fBudgeted(budgeted)
26 , fColorSpace(std::move(cs)) {}
27
28SkImage_GpuBase::~SkImage_GpuBase() {}
29
30//////////////////////////////////////////////////////////////////////////////////////////////////
31
32bool SkImage_GpuBase::ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
33 GrPixelConfig* config, SkColorType ct, SkAlphaType at,
34 sk_sp<SkColorSpace> cs) {
35 if (!tex.isValid()) {
36 return false;
37 }
38 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
39 // create a fake image info here.
40 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
41 if (!SkImageInfoIsValid(info)) {
42 return false;
43 }
44
45 return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
46}
47
48//////////////////////////////////////////////////////////////////////////////////////////////////
49
Brian Osmane50cdf02018-10-19 13:02:14 -040050bool SkImage_GpuBase::getROPixels(SkBitmap* dst, CachingHint chint) const {
Jim Van Verth8026ccc2018-10-04 13:10:39 -040051 if (!fContext->contextPriv().resourceProvider()) {
52 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
53 return false;
54 }
55
Jim Van Verth8026ccc2018-10-04 13:10:39 -040056 const auto desc = SkBitmapCacheDesc::Make(this);
57 if (SkBitmapCache::Find(desc, dst)) {
Jim Van Verth8026ccc2018-10-04 13:10:39 -040058 SkASSERT(dst->isImmutable());
59 SkASSERT(dst->getPixels());
60 return true;
61 }
62
63 SkBitmapCache::RecPtr rec = nullptr;
64 SkPixmap pmap;
65 if (kAllow_CachingHint == chint) {
66 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
67 if (!rec) {
68 return false;
69 }
70 } else {
71 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
72 return false;
73 }
74 }
75
76 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
77 this->asTextureProxyRef(),
78 fColorSpace);
79 if (!sContext) {
80 return false;
81 }
82
83 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
84 return false;
85 }
86
87 if (rec) {
88 SkBitmapCache::Add(std::move(rec), dst);
89 this->notifyAddedToRasterCache();
90 }
91 return true;
92}
93
94sk_sp<SkImage> SkImage_GpuBase::onMakeSubset(const SkIRect& subset) const {
95 sk_sp<GrSurfaceProxy> proxy = this->asTextureProxyRef();
96
97 GrSurfaceDesc desc;
98 desc.fWidth = subset.width();
99 desc.fHeight = subset.height();
100 desc.fConfig = proxy->config();
101
102 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
103 desc, proxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, fBudgeted));
104 if (!sContext) {
105 return nullptr;
106 }
107
108 if (!sContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
109 return nullptr;
110 }
111
112 // MDB: this call is okay bc we know 'sContext' was kExact
113 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
114 fAlphaType, sContext->asTextureProxyRef(),
115 fColorSpace, fBudgeted);
116}
117
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400118static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
119 switch (info.colorType()) {
120 case kRGBA_8888_SkColorType:
121 case kBGRA_8888_SkColorType:
122 break;
123 default:
124 return; // nothing to do
125 }
126
127 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
128 // and in either case, the alpha-byte is always in the same place, so we can safely call
129 // SkPreMultiplyColor()
130 //
131 SkColor* row = (SkColor*)pixels;
132 for (int y = 0; y < info.height(); ++y) {
133 for (int x = 0; x < info.width(); ++x) {
134 row[x] = SkPreMultiplyColor(row[x]);
135 }
136 row = (SkColor*)((char*)(row)+rowBytes);
137 }
138}
139
140bool SkImage_GpuBase::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
141 int srcX, int srcY, CachingHint) const {
142 if (!fContext->contextPriv().resourceProvider()) {
143 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
144 return false;
145 }
146
147 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
148 return false;
149 }
150
151 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
152 if (!rec.trim(this->width(), this->height())) {
153 return false;
154 }
155
156 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
157 // GrRenderTargetContext::onReadPixels
158 uint32_t flags = 0;
159 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
160 // let the GPU perform this transformation for us
161 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
162 }
163
164 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
165 this->asTextureProxyRef(), fColorSpace);
166 if (!sContext) {
167 return false;
168 }
169
170 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
171 return false;
172 }
173
174 // do we have to manually fix-up the alpha channel?
175 // src dst
176 // unpremul premul fix manually
177 // premul unpremul done by kUnpremul_PixelOpsFlag
178 // all other combos need to change.
179 //
180 // Should this be handled by Ganesh? todo:?
181 //
182 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
183 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
184 }
185 return true;
186}
187
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400188sk_sp<GrTextureProxy> SkImage_GpuBase::asTextureProxyRef(GrContext* context,
189 const GrSamplerState& params,
190 SkColorSpace* dstColorSpace,
191 sk_sp<SkColorSpace>* texColorSpace,
192 SkScalar scaleAdjust[2]) const {
193 if (context->uniqueID() != fContext->uniqueID()) {
194 SkASSERT(0);
195 return nullptr;
196 }
197
198 GrTextureAdjuster adjuster(fContext.get(), this->asTextureProxyRef(), fAlphaType,
199 this->uniqueID(), fColorSpace.get());
200 return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
201}
202
203GrBackendTexture SkImage_GpuBase::onGetBackendTexture(bool flushPendingGrContextIO,
204 GrSurfaceOrigin* origin) const {
205 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
206 SkASSERT(proxy);
207
208 if (!fContext->contextPriv().resourceProvider() && !proxy->isInstantiated()) {
209 // This image was created with a DDL context and cannot be instantiated.
210 return GrBackendTexture();
211}
212
213 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
214 return GrBackendTexture(); // invalid
215 }
216
217 GrTexture* texture = proxy->peekTexture();
218
219 if (texture) {
220 if (flushPendingGrContextIO) {
221 fContext->contextPriv().prepareSurfaceForExternalIO(proxy.get());
222 }
223 if (origin) {
224 *origin = proxy->origin();
225 }
226 return texture->getBackendTexture();
227 }
228 return GrBackendTexture(); // invalid
229}
230
231GrTexture* SkImage_GpuBase::onGetTexture() const {
232 GrTextureProxy* proxy = this->peekProxy();
233 if (!proxy) {
234 return nullptr;
235 }
236
237 sk_sp<GrTextureProxy> proxyRef = this->asTextureProxyRef();
238 if (!fContext->contextPriv().resourceProvider() && !proxyRef->isInstantiated()) {
239 // This image was created with a DDL context and cannot be instantiated.
240 return nullptr;
241 }
242
243 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
244 return nullptr;
245 }
246
247 return proxy->peekTexture();
248}
249
250sk_sp<SkImage> SkImage_GpuBase::onMakeColorSpace(sk_sp<SkColorSpace> target) const {
Brian Osmanbe686f02018-10-12 11:18:02 -0400251 auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
252 target.get(), fAlphaType);
Brian Osmanb4ae4992018-10-18 11:16:14 -0400253 SkASSERT(xform);
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400254
Brian Osman9c111352018-10-16 10:18:26 -0400255 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
256
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400257 sk_sp<GrRenderTargetContext> renderTargetContext(
Brian Osman9c111352018-10-16 10:18:26 -0400258 fContext->contextPriv().makeDeferredRenderTargetContextWithFallback(
259 SkBackingFit::kExact, this->width(), this->height(), proxy->config(), nullptr));
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400260 if (!renderTargetContext) {
261 return nullptr;
262 }
263
264 GrPaint paint;
265 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Osman9c111352018-10-16 10:18:26 -0400266 paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I());
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400267 paint.addColorFragmentProcessor(std::move(xform));
268
Brian Osmanb4ae4992018-10-18 11:16:14 -0400269 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
270 SkRect::MakeIWH(this->width(), this->height()));
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400271 if (!renderTargetContext->asTextureProxy()) {
272 return nullptr;
273 }
274
275 // MDB: this call is okay bc we know 'renderTargetContext' was exact
276 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
Brian Osmanbe686f02018-10-12 11:18:02 -0400277 fAlphaType, renderTargetContext->asTextureProxyRef(),
Jim Van Verth8026ccc2018-10-04 13:10:39 -0400278 std::move(target), fBudgeted);
279}
280
281bool SkImage_GpuBase::onIsValid(GrContext* context) const {
282 // The base class has already checked that context isn't abandoned (if it's not nullptr)
283 if (fContext->abandoned()) {
284 return false;
285 }
286
287 if (context && context != fContext.get()) {
288 return false;
289 }
290
291 return true;
292}
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400293
294/////////////////////////////////////////////////////////////////////////////////////////////////
295sk_sp<GrTexture> SkPromiseImageHelper::getTexture(GrResourceProvider* resourceProvider,
296 GrPixelConfig config) {
297 // Releases the promise helper if there are no outstanding hard refs. This means that we
298 // don't have any ReleaseProcs waiting to be called so we will need to do a fulfill.
299 if (fReleaseHelper && fReleaseHelper->weak_expired()) {
300 this->resetReleaseHelper();
301 }
302
303 sk_sp<GrTexture> tex;
304 if (!fReleaseHelper) {
305 fFulfillProc(fContext, &fBackendTex);
306 fBackendTex.fConfig = config;
307 if (!fBackendTex.isValid()) {
308 // Even though the GrBackendTexture is not valid, we must call the release
309 // proc to keep our contract of always calling Fulfill and Release in pairs.
310 fReleaseProc(fContext);
311 return sk_sp<GrTexture>();
312 }
313
314 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
315 if (!tex) {
316 // Even though the GrBackendTexture is not valid, we must call the release
317 // proc to keep our contract of always calling Fulfill and Release in pairs.
318 fReleaseProc(fContext);
319 return sk_sp<GrTexture>();
320 }
321 fReleaseHelper = new SkPromiseReleaseProcHelper(fReleaseProc, fContext, fDoneHelper);
322 // Take a weak ref
323 fReleaseHelper->weak_ref();
324 } else {
325 SkASSERT(fBackendTex.isValid());
326 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
327 if (!tex) {
328 // We weren't able to make a texture here, but since we are in this branch
329 // of the calls (promiseHelper.fReleaseHelper is valid) there is already a
330 // texture out there which will call the release proc so we don't need to
331 // call it here.
332 return sk_sp<GrTexture>();
333 }
334
335 SkAssertResult(fReleaseHelper->try_ref());
336 }
337 SkASSERT(tex);
338 // Pass the hard ref off to the texture
339 tex->setRelease(sk_sp<GrReleaseProcHelper>(fReleaseHelper));
340 return tex;
341}