blob: 7b24858c2f3ea00c91d0a33a3289833090508bf7 [file] [log] [blame]
reed@google.com5d4ba882012-07-31 15:45:27 +00001/*
2 * Copyright 2012 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
cblume33e0cb52016-08-30 12:09:23 -07008#include <cstddef>
9#include <cstring>
10#include <type_traits>
11
robertphillipsc5035e72016-03-17 06:58:39 -070012#include "SkAutoPixmapStorage.h"
Greg Daniel7ef28f32017-04-20 16:41:55 +000013#include "GrBackendSurface.h"
Brian Osman13dddce2017-05-09 13:19:50 -040014#include "GrBackendTextureImageGenerator.h"
Stan Iliev7e910df2017-06-02 10:29:21 -040015#include "GrAHardwareBufferImageGenerator.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050016#include "GrBitmapTextureMaker.h"
reed856e9d92015-09-30 12:21:45 -070017#include "GrCaps.h"
Brian Osman47c27512018-06-18 10:58:51 -040018#include "GrColorSpaceXform.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000019#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050020#include "GrContextPriv.h"
Brian Osman2c2bc112017-02-28 10:02:49 -050021#include "GrGpu.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050022#include "GrImageTextureMaker.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050023#include "GrProxyProvider.h"
Brian Osman11052242016-10-27 14:47:55 -040024#include "GrRenderTargetContext.h"
Brian Osman32342f02017-03-04 08:12:46 -050025#include "GrResourceProvider.h"
Brian Osmanfe3b5162017-03-02 15:09:20 -050026#include "GrSemaphore.h"
Eric Karl914a36b2017-10-12 12:44:50 -070027#include "GrSurfacePriv.h"
Brian Osmane8e54582016-11-28 10:06:27 -050028#include "GrTextureAdjuster.h"
Robert Phillips646e4292017-06-13 12:44:56 -040029#include "GrTexture.h"
Eric Karl914a36b2017-10-12 12:44:50 -070030#include "GrTexturePriv.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050031#include "GrTextureProxy.h"
Greg Daniele3204862018-04-16 11:24:10 -040032#include "GrTextureProxyPriv.h"
Robert Phillipsabf7b762018-03-21 12:13:37 -040033#include "gl/GrGLDefines.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050034#include "effects/GrYUVtoRGBEffect.h"
bsalomon993a4212015-05-29 11:37:25 -070035#include "SkCanvas.h"
reed262a71b2015-12-05 13:07:27 -080036#include "SkBitmapCache.h"
Brian Osman3b655982017-03-07 16:58:08 -050037#include "SkGr.h"
reed262a71b2015-12-05 13:07:27 -080038#include "SkImage_Gpu.h"
Brian Osman7992da32016-11-18 11:28:24 -050039#include "SkImageCacherator.h"
Matt Sarettcb6266b2017-01-17 10:48:53 -050040#include "SkImageInfoPriv.h"
ericrkb4da01d2016-06-13 11:18:14 -070041#include "SkMipMap.h"
reed6f1216a2015-08-04 08:10:13 -070042#include "SkPixelRef.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050043#include "SkReadPixelsRec.h"
Greg Danielbc54fad2018-02-09 16:40:32 -050044#include "SkTraceEvent.h"
bsalomon993a4212015-05-29 11:37:25 -070045
Brian Salomon8a8dd332018-05-24 14:08:31 -040046SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
47 sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace,
48 SkBudgeted budgeted)
49 : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID)
50 , fContext(std::move(context))
51 , fProxy(std::move(proxy))
52 , fAlphaType(at)
53 , fBudgeted(budgeted)
54 , fColorSpace(std::move(colorSpace))
55 , fAddedRasterVersionToCache(false) {}
piotaixrcef04f82014-07-14 07:48:04 -070056
reed6f1216a2015-08-04 08:10:13 -070057SkImage_Gpu::~SkImage_Gpu() {
58 if (fAddedRasterVersionToCache.load()) {
59 SkNotifyBitmapGenIDIsStale(this->uniqueID());
60 }
61}
62
brianosman396fcdb2016-07-22 06:26:11 -070063SkImageInfo SkImage_Gpu::onImageInfo() const {
Greg Daniel56008aa2018-03-14 15:33:42 -040064 return SkImageInfo::Make(fProxy->width(), fProxy->height(), this->onColorType(), fAlphaType,
65 fColorSpace);
66}
67
68SkColorType SkImage_Gpu::onColorType() const {
brianosman396fcdb2016-07-22 06:26:11 -070069 SkColorType ct;
Robert Phillipsb726d582017-03-09 16:36:32 -050070 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
brianosman396fcdb2016-07-22 06:26:11 -070071 ct = kUnknown_SkColorType;
72 }
Greg Daniel56008aa2018-03-14 15:33:42 -040073 return ct;
brianosman396fcdb2016-07-22 06:26:11 -070074}
75
Brian Osman62517712017-04-26 16:26:39 -040076bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
Robert Phillipsa6aef2a2018-04-11 10:41:20 -040077 if (!fContext->contextPriv().resourceProvider()) {
78 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
79 return false;
80 }
81
Brian Osman62517712017-04-26 16:26:39 -040082 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
83 // will be used. The client doesn't expect that we convert to that color space, it's intended
84 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
85 // into that color space (to save the client some effort in whatever they're about to do), but
86 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
87 // rolled the dstColorSpace into the key).
Mike Reed5fa3d6d2017-03-25 09:51:00 -040088 const auto desc = SkBitmapCacheDesc::Make(this);
89 if (SkBitmapCache::Find(desc, dst)) {
reed6f1216a2015-08-04 08:10:13 -070090 SkASSERT(dst->getGenerationID() == this->uniqueID());
91 SkASSERT(dst->isImmutable());
92 SkASSERT(dst->getPixels());
93 return true;
94 }
95
Mike Reed7a542c52017-04-11 12:03:44 -040096 SkBitmapCache::RecPtr rec = nullptr;
97 SkPixmap pmap;
98 if (kAllow_CachingHint == chint) {
Brian Osman62517712017-04-26 16:26:39 -040099 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
Mike Reed7a542c52017-04-11 12:03:44 -0400100 if (!rec) {
101 return false;
102 }
103 } else {
Brian Osman62517712017-04-26 16:26:39 -0400104 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
Mike Reed7a542c52017-04-11 12:03:44 -0400105 return false;
106 }
reed8b26b992015-05-07 15:36:17 -0700107 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500108
Brian Salomon2084ffa2017-03-27 17:32:18 -0400109 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
110 fProxy,
111 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500112 if (!sContext) {
113 return false;
114 }
115
Mike Reed7a542c52017-04-11 12:03:44 -0400116 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
reed8b26b992015-05-07 15:36:17 -0700117 return false;
118 }
reed6f1216a2015-08-04 08:10:13 -0700119
Mike Reed7a542c52017-04-11 12:03:44 -0400120 if (rec) {
121 SkBitmapCache::Add(std::move(rec), dst);
reed09553032015-11-23 12:32:16 -0800122 fAddedRasterVersionToCache.store(true);
123 }
reed8b26b992015-05-07 15:36:17 -0700124 return true;
125}
126
Robert Phillipsb726d582017-03-09 16:36:32 -0500127sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400128 const GrSamplerState& params,
Robert Phillipsb726d582017-03-09 16:36:32 -0500129 SkColorSpace* dstColorSpace,
130 sk_sp<SkColorSpace>* texColorSpace,
131 SkScalar scaleAdjust[2]) const {
Brian Salomon8a8dd332018-05-24 14:08:31 -0400132 if (context != fContext.get()) {
Robert Phillipsb726d582017-03-09 16:36:32 -0500133 SkASSERT(0);
134 return nullptr;
135 }
136
Brian Salomon8a8dd332018-05-24 14:08:31 -0400137 GrTextureAdjuster adjuster(fContext.get(), fProxy, this->alphaType(), this->uniqueID(),
Greg Danielc77085d2017-11-01 16:38:48 -0400138 this->fColorSpace.get());
Brian Salomon2a943df2018-05-04 13:43:19 -0400139 return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
reed85d91782015-09-10 14:33:38 -0700140}
141
reed8b26b992015-05-07 15:36:17 -0700142static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
143 switch (info.colorType()) {
144 case kRGBA_8888_SkColorType:
145 case kBGRA_8888_SkColorType:
146 break;
147 default:
148 return; // nothing to do
149 }
150
151 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
152 // and in either case, the alpha-byte is always in the same place, so we can safely call
153 // SkPreMultiplyColor()
154 //
155 SkColor* row = (SkColor*)pixels;
156 for (int y = 0; y < info.height(); ++y) {
157 for (int x = 0; x < info.width(); ++x) {
158 row[x] = SkPreMultiplyColor(row[x]);
159 }
Brian Salomon9708af82018-02-05 12:57:10 -0500160 row = (SkColor*)((char*)(row) + rowBytes);
reed8b26b992015-05-07 15:36:17 -0700161 }
162}
163
Robert Phillipsc5509952018-04-04 15:54:55 -0400164GrBackendTexture SkImage_Gpu::onGetBackendTexture(bool flushPendingGrContextIO,
165 GrSurfaceOrigin* origin) const {
166 SkASSERT(fProxy);
167
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400168 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
169 // This image was created with a DDL context and cannot be instantiated.
170 return GrBackendTexture();
171 }
172
Robert Phillipsc5509952018-04-04 15:54:55 -0400173 if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
174 return GrBackendTexture(); // invalid
175 }
176
177 GrTexture* texture = fProxy->priv().peekTexture();
178
179 if (texture) {
180 if (flushPendingGrContextIO) {
181 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
182 }
183 if (origin) {
184 *origin = fProxy->origin();
185 }
186 return texture->getBackendTexture();
187 }
188 return GrBackendTexture(); // invalid
189}
190
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400191GrTexture* SkImage_Gpu::onGetTexture() const {
192 GrTextureProxy* proxy = this->peekProxy();
193 if (!proxy) {
194 return nullptr;
195 }
196
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400197 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
198 // This image was created with a DDL context and cannot be instantiated.
199 return nullptr;
200 }
201
Robert Phillips6be756b2018-01-16 15:07:54 -0500202 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400203 return nullptr;
204 }
205
206 return proxy->priv().peekTexture();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400207}
208
Matt Sarett03dd6d52017-01-23 12:15:09 -0500209bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
reed09553032015-11-23 12:32:16 -0800210 int srcX, int srcY, CachingHint) const {
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400211 if (!fContext->contextPriv().resourceProvider()) {
212 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
213 return false;
214 }
215
Matt Sarett03dd6d52017-01-23 12:15:09 -0500216 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500217 return false;
218 }
219
Matt Sarett03dd6d52017-01-23 12:15:09 -0500220 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
221 if (!rec.trim(this->width(), this->height())) {
222 return false;
223 }
224
Robert Phillipsb726d582017-03-09 16:36:32 -0500225 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
226 // GrRenderTargetContext::onReadPixels
reed8b26b992015-05-07 15:36:17 -0700227 uint32_t flags = 0;
Matt Sarett03dd6d52017-01-23 12:15:09 -0500228 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
reed8b26b992015-05-07 15:36:17 -0700229 // let the GPU perform this transformation for us
Robert Phillipse78b7252017-04-06 07:59:41 -0400230 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
reed8b26b992015-05-07 15:36:17 -0700231 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500232
Brian Salomon2084ffa2017-03-27 17:32:18 -0400233 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
Brian Osman9aa30c62018-07-02 15:21:46 -0400234 fProxy, fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500235 if (!sContext) {
reed8b26b992015-05-07 15:36:17 -0700236 return false;
237 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500238
239 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
240 return false;
241 }
242
reed8b26b992015-05-07 15:36:17 -0700243 // do we have to manually fix-up the alpha channel?
244 // src dst
245 // unpremul premul fix manually
246 // premul unpremul done by kUnpremul_PixelOpsFlag
247 // all other combos need to change.
248 //
249 // Should this be handled by Ganesh? todo:?
250 //
Matt Sarett03dd6d52017-01-23 12:15:09 -0500251 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
252 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
reed8b26b992015-05-07 15:36:17 -0700253 }
254 return true;
255}
256
reed7fb4f8b2016-03-11 04:33:52 -0800257sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
Brian Salomon63e79732017-05-15 21:23:13 -0400258 GrSurfaceDesc desc;
reed7b6945b2015-09-24 00:50:58 -0700259 desc.fWidth = subset.width();
260 desc.fHeight = subset.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400261 desc.fConfig = fProxy->config();
reed7b6945b2015-09-24 00:50:58 -0700262
Robert Phillipsb726d582017-03-09 16:36:32 -0500263 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
Brian Salomon2a4f9832018-03-03 22:43:43 -0500264 desc, fProxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, fBudgeted));
Robert Phillipse2f7d182016-12-15 09:23:05 -0500265 if (!sContext) {
266 return nullptr;
267 }
268
Robert Phillipsb726d582017-03-09 16:36:32 -0500269 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500270 return nullptr;
271 }
272
Robert Phillipsb726d582017-03-09 16:36:32 -0500273 // MDB: this call is okay bc we know 'sContext' was kExact
274 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
275 fAlphaType, sContext->asTextureProxyRef(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500276 fColorSpace, fBudgeted);
reed7b6945b2015-09-24 00:50:58 -0700277}
278
reed8b26b992015-05-07 15:36:17 -0700279///////////////////////////////////////////////////////////////////////////////////////////////////
280
Greg Daniel7ef28f32017-04-20 16:41:55 +0000281static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
282 const GrBackendTexture& backendTex,
283 GrSurfaceOrigin origin,
brianosmandddbe382016-07-20 13:55:39 -0700284 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
285 GrWrapOwnership ownership,
reed7fb4f8b2016-03-11 04:33:52 -0800286 SkImage::TextureReleaseProc releaseProc,
287 SkImage::ReleaseContext releaseCtx) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400288 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700289 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700290 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400291
Robert Phillipsadbe1322018-01-17 13:35:46 -0500292 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
Brian Salomon7578f3e2018-03-07 14:39:54 -0500293 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(backendTex, origin, ownership,
294 releaseProc, releaseCtx);
Robert Phillipsadbe1322018-01-17 13:35:46 -0500295 if (!proxy) {
Robert Phillipse201ebc2018-01-17 18:12:50 +0000296 return nullptr;
297 }
Brian Salomon94575462018-06-21 17:00:26 -0400298#if 1
299 // Temporary fix for crbug.com/850617 that can be cleanly merged back to older branches. Assume
300 // any MIP levels on the incoming texture are dirty. The proper fix is to make them clean on
301 // export. See #if 0'ed out code in GrDrawingManager::prepareSurfaceForExternalIO().
302 SkASSERT(proxy->priv().isInstantiated());
303 if (auto* tex = proxy->priv().peekTexture()) {
304 if (tex->texturePriv().mipMapped() == GrMipMapped::kYes) {
305 proxy->priv().peekTexture()->texturePriv().markMipMapsDirty();
306 }
307 }
308#endif
Brian Salomon8a8dd332018-05-24 14:08:31 -0400309 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy),
310 std::move(colorSpace), SkBudgeted::kNo);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700311}
312
Greg Danielfaa095e2017-12-19 13:15:02 -0500313bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
Greg Danielf5d87582017-12-18 14:48:15 -0500314 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400315 if (!tex.isValid()) {
316 return false;
317 }
Greg Danielf5d87582017-12-18 14:48:15 -0500318 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
319 // create a fake image info here.
320 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
Brian Osmane1adc3a2018-06-04 09:21:17 -0400321 if (!SkImageInfoIsValid(info)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500322 return false;
323 }
324
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400325 return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
Greg Danielf5d87582017-12-18 14:48:15 -0500326}
327
328sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
329 const GrBackendTexture& tex, GrSurfaceOrigin origin,
330 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
331 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500332 if (!ctx) {
333 return nullptr;
334 }
Greg Danielf5d87582017-12-18 14:48:15 -0500335 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500336 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500337 return nullptr;
338 }
Brian Salomonbfd27492018-03-19 14:08:51 -0400339 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
340 kBorrow_GrWrapOwnership, releaseP, releaseC);
Greg Danielf5d87582017-12-18 14:48:15 -0500341}
342
Greg Daniel94403452017-04-18 15:52:36 -0400343sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
344 const GrBackendTexture& tex, GrSurfaceOrigin origin,
Brian Salomon42409c22018-03-20 13:48:41 -0400345 SkColorType ct, SkAlphaType at,
346 sk_sp<SkColorSpace> cs) {
347 if (!ctx || !ctx->contextPriv().resourceProvider()) {
Greg Danielf2336e42018-01-23 16:38:14 -0500348 // We have a DDL context and we don't support adopted textures for them.
349 return nullptr;
350 }
Greg Danielf5d87582017-12-18 14:48:15 -0500351 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500352 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500353 return nullptr;
354 }
Brian Salomon42409c22018-03-20 13:48:41 -0400355 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
356 kAdopt_GrWrapOwnership, nullptr, nullptr);
Greg Danielf5d87582017-12-18 14:48:15 -0500357}
358
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400359sk_sp<SkImage> SkImage_Gpu::MakeFromYUVATexturesCopyImpl(GrContext* ctx,
360 SkYUVColorSpace colorSpace,
361 const GrBackendTexture yuvaTextures[],
362 SkYUVAIndex yuvaIndices[4],
363 SkISize size,
364 GrSurfaceOrigin origin,
365 sk_sp<SkColorSpace> imageColorSpace) {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500366 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
367
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400368 // Right now this still only deals with YUV and NV12 formats. Assuming that YUV has different
369 // textures for U and V planes, while NV12 uses same texture for U and V planes.
370 bool nv12 = (yuvaIndices[1].fIndex == yuvaIndices[2].fIndex);
Brian Salomon6a426c12018-03-15 12:16:02 -0400371 auto ct = nv12 ? kRGBA_8888_SkColorType : kAlpha_8_SkColorType;
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400372
Greg Daniel108bb232018-07-03 16:18:29 -0400373 // We need to make a copy of the input backend textures because we need to preserve the result
374 // of validate_backend_texture.
375 GrBackendTexture yuvaTexturesCopy[4];
376
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400377 for (int i = 0; i < 4; ++i) {
378 // Validate that the yuvaIndices refer to valid backend textures.
379 SkYUVAIndex& yuvaIndex = yuvaIndices[i];
380 if (i == 3 && yuvaIndex.fIndex == -1) {
381 // Meaning the A plane isn't passed in.
382 continue;
383 }
384 if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
385 // Y plane, U plane, and V plane must refer to image sources being passed in. There are
386 // at most 4 images sources being passed in, could not have a index more than 3.
Brian Salomon3afdab12018-03-19 16:29:37 -0400387 return nullptr;
Brian Salomon6a426c12018-03-15 12:16:02 -0400388 }
Greg Daniel108bb232018-07-03 16:18:29 -0400389 if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
390 yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
391 // TODO: Instead of using assumption about whether it is NV12 format to guess colorType,
392 // actually use channel information here.
393 if (!validate_backend_texture(ctx, yuvaTexturesCopy[i], &yuvaTexturesCopy[i].fConfig,
394 ct, kPremul_SkAlphaType, nullptr)) {
395 return nullptr;
396 }
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400397 }
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500398
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400399 // TODO: Check that for each plane, the channel actually exist in the image source we are
400 // reading from.
jbaumanb445a572016-06-09 13:24:48 -0700401 }
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400402
403 sk_sp<GrTextureProxy> tempTextureProxies[4];
404 for (int i = 0; i < 4; ++i) {
405 // Fill in tempTextureProxies to avoid duplicate texture proxies.
406 int textureIndex = yuvaIndices[i].fIndex;
407
408 // Safely ignore since this means we are missing the A plane.
409 if (textureIndex == -1) {
410 SkASSERT(3 == i);
411 continue;
412 }
413
414 if (!tempTextureProxies[textureIndex]) {
Greg Daniel108bb232018-07-03 16:18:29 -0400415 SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400416 tempTextureProxies[textureIndex] =
Greg Daniel108bb232018-07-03 16:18:29 -0400417 proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400418 }
419 }
420 sk_sp<GrTextureProxy> yProxy = tempTextureProxies[yuvaIndices[0].fIndex];
421 sk_sp<GrTextureProxy> uProxy = tempTextureProxies[yuvaIndices[1].fIndex];
422 sk_sp<GrTextureProxy> vProxy = tempTextureProxies[yuvaIndices[2].fIndex];
423
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500424 if (!yProxy || !uProxy || !vProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700425 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700426 }
427
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400428 const int width = size.width();
429 const int height = size.height();
robertphillipsaa19a5f2016-04-28 06:21:55 -0700430
robertphillipsd4c741e2016-04-28 09:55:15 -0700431 // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500432 sk_sp<GrRenderTargetContext> renderTargetContext(
433 ctx->contextPriv().makeDeferredRenderTargetContext(
434 SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
435 std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
Brian Osman11052242016-10-27 14:47:55 -0400436 if (!renderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700437 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700438 }
439
440 GrPaint paint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400441 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400442 // TODO: Move the sizes into GrYUVtoRGBEffect since this can just be done there.
443 SkISize sizes[] = {{yProxy->width(), yProxy->height()},
444 {uProxy->width(), uProxy->height()},
445 {vProxy->width(), vProxy->height()}};
446 // TODO: Modify the fragment processor to sample from different channel instead of taking nv12
447 // bool.
Brian Salomon6a426c12018-03-15 12:16:02 -0400448 paint.addColorFragmentProcessor(
449 GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy, sizes, colorSpace, nv12));
bsalomon993a4212015-05-29 11:37:25 -0700450
Robert Phillipsb726d582017-03-09 16:36:32 -0500451 const SkRect rect = SkRect::MakeIWH(width, height);
robertphillipsc9a37062015-09-01 08:34:28 -0700452
Brian Salomon82f44312017-01-11 13:42:54 -0500453 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
Robert Phillipse60ad622016-11-17 10:22:48 -0500454
Robert Phillips7ee385e2017-03-30 08:02:11 -0400455 if (!renderTargetContext->asSurfaceProxy()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500456 return nullptr;
457 }
Robert Phillips7ee385e2017-03-30 08:02:11 -0400458 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
Robert Phillipsb726d582017-03-09 16:36:32 -0500459
460 // MDB: this call is okay bc we know 'renderTargetContext' was exact
Brian Salomon8a8dd332018-05-24 14:08:31 -0400461 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
Brian Salomonf3569f02017-10-24 12:52:33 -0400462 renderTargetContext->asTextureProxyRef(),
Robert Phillipsc25db632017-12-13 09:22:45 -0500463 renderTargetContext->colorSpaceInfo().refColorSpace(),
464 SkBudgeted::kYes);
465}
466
Brian Salomon6a426c12018-03-15 12:16:02 -0400467sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
468 const GrBackendTexture yuvTextures[3],
469 GrSurfaceOrigin origin,
470 sk_sp<SkColorSpace> imageColorSpace) {
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400471 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
472 SkYUVAIndex yuvaIndices[4] = {
473 SkYUVAIndex{0, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
474 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
475 SkYUVAIndex{2, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
476 SkYUVAIndex{-1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel}};
477 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
478 return SkImage_Gpu::MakeFromYUVATexturesCopyImpl(ctx, colorSpace, yuvTextures, yuvaIndices,
479 size, origin, std::move(imageColorSpace));
bsalomon993a4212015-05-29 11:37:25 -0700480}
reed56179002015-07-07 06:11:19 -0700481
jbaumanb445a572016-06-09 13:24:48 -0700482sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
Brian Salomon6a426c12018-03-15 12:16:02 -0400483 const GrBackendTexture nv12Textures[2],
brianosmandddbe382016-07-20 13:55:39 -0700484 GrSurfaceOrigin origin,
485 sk_sp<SkColorSpace> imageColorSpace) {
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400486 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
487 SkYUVAIndex yuvaIndices[4] = {
488 SkYUVAIndex{0, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
489 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
490 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
491 SkYUVAIndex{-1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel}};
492 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
493 return SkImage_Gpu::MakeFromYUVATexturesCopyImpl(ctx, colorSpace, nv12Textures, yuvaIndices,
494 size, origin, std::move(imageColorSpace));
Robert Phillipsc25db632017-12-13 09:22:45 -0500495}
496
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400497static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
498 SkAlphaType at, uint32_t id,
499 SkColorSpace* dstColorSpace,
500 GrMipMapped mipMapped) {
Brian Osman041f7df2017-02-07 11:23:28 -0500501 sk_sp<SkColorSpace> texColorSpace;
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400502 sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped, dstColorSpace,
503 &texColorSpace));
Robert Phillips3798c862017-03-27 11:08:16 -0400504 if (!proxy) {
Brian Osman041f7df2017-02-07 11:23:28 -0500505 return nullptr;
506 }
Brian Salomon8a8dd332018-05-24 14:08:31 -0400507 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, at, std::move(proxy),
508 std::move(texColorSpace), SkBudgeted::kNo);
Brian Osman041f7df2017-02-07 11:23:28 -0500509}
510
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400511sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
512 GrMipMapped mipMapped) const {
Brian Osman041f7df2017-02-07 11:23:28 -0500513 if (!context) {
514 return nullptr;
515 }
Robert Phillips87444052017-06-23 14:09:30 -0400516 if (GrContext* incumbent = as_IB(this)->context()) {
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400517 if (incumbent != context) {
518 return nullptr;
519 }
520 sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef();
521 SkASSERT(proxy);
522 if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) {
523 return sk_ref_sp(const_cast<SkImage*>(this));
524 }
525 GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(),
526 this->uniqueID(), this->colorSpace());
527 return create_image_from_producer(context, &adjuster, this->alphaType(),
528 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500529 }
530
Brian Osmandf7e0752017-04-26 16:20:28 -0400531 if (this->isLazyGenerated()) {
532 GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400533 return create_image_from_producer(context, &maker, this->alphaType(),
534 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500535 }
536
537 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
538 GrBitmapTextureMaker maker(context, *bmp);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400539 return create_image_from_producer(context, &maker, this->alphaType(),
540 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500541 }
542 return nullptr;
543}
544
Greg Daniel7278d682018-03-16 14:57:21 -0400545///////////////////////////////////////////////////////////////////////////////////////////////////
546
547/**
548 * This helper holds the normal hard ref for the Release proc as well as a hard ref on the DoneProc.
549 * Thus when a GrTexture is being released, it will unref both the ReleaseProc and DoneProc.
550 */
551class PromiseReleaseProcHelper : public GrReleaseProcHelper {
552public:
553 PromiseReleaseProcHelper(SkImage_Gpu::TextureReleaseProc releaseProc,
554 SkImage_Gpu::TextureContext context,
555 sk_sp<GrReleaseProcHelper> doneHelper)
556 : INHERITED(releaseProc, context)
557 , fDoneProcHelper(std::move(doneHelper)) {}
558
559 void weak_dispose() const override {
560 // Call the inherited weak_dispose first so that we call the ReleaseProc before the DoneProc
561 // if we hold the last ref to the DoneProc.
562 INHERITED::weak_dispose();
563 fDoneProcHelper.reset();
564 }
565
566private:
567 mutable sk_sp<GrReleaseProcHelper> fDoneProcHelper;
568
569 typedef GrReleaseProcHelper INHERITED;
570};
571
572/**
573 * This helper class manages the ref counting for the the ReleaseProc and DoneProc for promise
574 * images. It holds a weak ref on the ReleaseProc (hard refs are owned by GrTextures). The weak ref
575 * allows us to reuse an outstanding ReleaseProc (because we dropped our GrTexture but the GrTexture
576 * isn't done on the GPU) without needing to call FulfillProc again. It also holds a hard ref on the
577 * DoneProc. The idea is that after every flush we may call the ReleaseProc so that the client can
578 * free up their GPU memory if they want to. The life time of the DoneProc matches that of any
579 * outstanding ReleaseProc as well as the PromiseImageHelper. Thus we won't call the DoneProc until
580 * all ReleaseProcs are finished and we are finished with the PromiseImageHelper (i.e. won't call
581 * FulfillProc again).
582 */
Greg Daniela8d92112018-03-09 12:05:04 -0500583class PromiseImageHelper {
584public:
585 PromiseImageHelper(SkImage_Gpu::TextureFulfillProc fulFillProc,
586 SkImage_Gpu::TextureReleaseProc releaseProc,
Greg Daniel7278d682018-03-16 14:57:21 -0400587 SkImage_Gpu::PromiseDoneProc doneProc,
Greg Daniela8d92112018-03-09 12:05:04 -0500588 SkImage_Gpu::TextureContext context)
589 : fFulfillProc(fulFillProc)
590 , fReleaseProc(releaseProc)
Greg Daniel7278d682018-03-16 14:57:21 -0400591 , fContext(context)
592 , fDoneHelper(new GrReleaseProcHelper(doneProc, context)) {}
Greg Daniela8d92112018-03-09 12:05:04 -0500593
594 void reset() {
595 this->resetReleaseHelper();
Greg Daniel7278d682018-03-16 14:57:21 -0400596 fDoneHelper.reset();
Greg Daniela8d92112018-03-09 12:05:04 -0500597 }
598
Greg Daniel057627f2018-03-14 15:51:58 -0400599 sk_sp<GrTexture> getTexture(GrResourceProvider* resourceProvider, GrPixelConfig config) {
Greg Daniela8d92112018-03-09 12:05:04 -0500600 // Releases the promise helper if there are no outstanding hard refs. This means that we
601 // don't have any ReleaseProcs waiting to be called so we will need to do a fulfill.
602 if (fReleaseHelper && fReleaseHelper->weak_expired()) {
603 this->resetReleaseHelper();
604 }
605
606 sk_sp<GrTexture> tex;
607 if (!fReleaseHelper) {
608 fFulfillProc(fContext, &fBackendTex);
Greg Daniel057627f2018-03-14 15:51:58 -0400609 fBackendTex.fConfig = config;
Greg Daniela8d92112018-03-09 12:05:04 -0500610 if (!fBackendTex.isValid()) {
611 // Even though the GrBackendTexture is not valid, we must call the release
612 // proc to keep our contract of always calling Fulfill and Release in pairs.
613 fReleaseProc(fContext);
614 return sk_sp<GrTexture>();
615 }
616
617 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
618 if (!tex) {
619 // Even though the GrBackendTexture is not valid, we must call the release
620 // proc to keep our contract of always calling Fulfill and Release in pairs.
621 fReleaseProc(fContext);
622 return sk_sp<GrTexture>();
623 }
Greg Daniel7278d682018-03-16 14:57:21 -0400624 fReleaseHelper = new PromiseReleaseProcHelper(fReleaseProc, fContext, fDoneHelper);
Greg Daniela8d92112018-03-09 12:05:04 -0500625 // Take a weak ref
626 fReleaseHelper->weak_ref();
627 } else {
628 SkASSERT(fBackendTex.isValid());
629 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
630 if (!tex) {
631 // We weren't able to make a texture here, but since we are in this branch
632 // of the calls (promiseHelper.fReleaseHelper is valid) there is already a
633 // texture out there which will call the release proc so we don't need to
634 // call it here.
635 return sk_sp<GrTexture>();
636 }
637
638 SkAssertResult(fReleaseHelper->try_ref());
639 }
640 SkASSERT(tex);
641 // Pass the hard ref off to the texture
642 tex->setRelease(sk_sp<GrReleaseProcHelper>(fReleaseHelper));
643 return tex;
644 }
645
646private:
647 // Weak unrefs fReleaseHelper and sets it to null
648 void resetReleaseHelper() {
649 if (fReleaseHelper) {
650 fReleaseHelper->weak_unref();
651 fReleaseHelper = nullptr;
652 }
653 }
654
655 SkImage_Gpu::TextureFulfillProc fFulfillProc;
656 SkImage_Gpu::TextureReleaseProc fReleaseProc;
657 SkImage_Gpu::TextureContext fContext;
658
659 // We cache the GrBackendTexture so that if we deleted the GrTexture but the the release proc
660 // has yet not been called (this can happen on Vulkan), then we can create a new texture without
661 // needing to call the fulfill proc again.
662 GrBackendTexture fBackendTex;
663 // The fReleaseHelper is used to track a weak ref on the release proc. This helps us make sure
664 // we are always pairing fulfill and release proc calls correctly.
Greg Daniel7278d682018-03-16 14:57:21 -0400665 PromiseReleaseProcHelper* fReleaseHelper = nullptr;
666 // We don't want to call the fDoneHelper until we are done with the PromiseImageHelper and all
667 // ReleaseHelpers are finished. Thus we hold a hard ref here and we will pass a hard ref to each
668 // fReleaseHelper we make.
669 sk_sp<GrReleaseProcHelper> fDoneHelper;
Greg Daniela8d92112018-03-09 12:05:04 -0500670};
671
Robert Phillipsabf7b762018-03-21 12:13:37 -0400672static GrInternalSurfaceFlags get_flags_from_format(const GrBackendFormat& backendFormat) {
673 if (const GrGLenum* target = backendFormat.getGLTarget()) {
674 if (GR_GL_TEXTURE_RECTANGLE == *target || GR_GL_TEXTURE_EXTERNAL == *target) {
Greg Daniel09c94002018-06-08 22:11:51 +0000675 return GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
Robert Phillipsabf7b762018-03-21 12:13:37 -0400676 }
677 }
678
679 return GrInternalSurfaceFlags::kNone;
680}
681
Greg Daniela8d92112018-03-09 12:05:04 -0500682sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
683 const GrBackendFormat& backendFormat,
684 int width,
685 int height,
686 GrMipMapped mipMapped,
687 GrSurfaceOrigin origin,
688 SkColorType colorType,
689 SkAlphaType alphaType,
690 sk_sp<SkColorSpace> colorSpace,
691 TextureFulfillProc textureFulfillProc,
692 TextureReleaseProc textureReleaseProc,
Greg Daniel7278d682018-03-16 14:57:21 -0400693 PromiseDoneProc promiseDoneProc,
Greg Daniela8d92112018-03-09 12:05:04 -0500694 TextureContext textureContext) {
695 if (!context) {
696 return nullptr;
697 }
698
699 if (width <= 0 || height <= 0) {
700 return nullptr;
701 }
702
Greg Daniel7278d682018-03-16 14:57:21 -0400703 if (!textureFulfillProc || !textureReleaseProc || !promiseDoneProc) {
Greg Daniela8d92112018-03-09 12:05:04 -0500704 return nullptr;
705 }
706
707 SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
Brian Osmane1adc3a2018-06-04 09:21:17 -0400708 if (!SkImageInfoIsValid(info)) {
Greg Daniela8d92112018-03-09 12:05:04 -0500709 return nullptr;
710 }
711 GrPixelConfig config = kUnknown_GrPixelConfig;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400712 if (!context->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, colorType,
713 &config)) {
Greg Daniela8d92112018-03-09 12:05:04 -0500714 return nullptr;
715 }
716
Greg Daniel09c94002018-06-08 22:11:51 +0000717 GrInternalSurfaceFlags formatFlags = get_flags_from_format(backendFormat);
718
719 if (mipMapped == GrMipMapped::kYes &&
720 SkToBool(formatFlags & GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal)) {
721 // It is invalid to have a GL_TEXTURE_EXTERNAL or GL_TEXTURE_RECTANGLE and have mips as
722 // well.
723 return nullptr;
724 }
725
Greg Daniela8d92112018-03-09 12:05:04 -0500726 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
727
728 GrSurfaceDesc desc;
729 desc.fWidth = width;
730 desc.fHeight = height;
731 desc.fConfig = config;
732
Greg Daniel7278d682018-03-16 14:57:21 -0400733 PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, promiseDoneProc,
734 textureContext);
Greg Daniela8d92112018-03-09 12:05:04 -0500735
736 sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
Greg Daniel057627f2018-03-14 15:51:58 -0400737 [promiseHelper, config] (GrResourceProvider* resourceProvider) mutable {
Greg Daniela8d92112018-03-09 12:05:04 -0500738 if (!resourceProvider) {
739 promiseHelper.reset();
740 return sk_sp<GrTexture>();
741 }
742
Greg Daniel057627f2018-03-14 15:51:58 -0400743 return promiseHelper.getTexture(resourceProvider, config);
Robert Phillipsabf7b762018-03-21 12:13:37 -0400744 }, desc, origin, mipMapped, formatFlags, SkBackingFit::kExact,
Greg Daniela8d92112018-03-09 12:05:04 -0500745 SkBudgeted::kNo, GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
746
747 if (!proxy) {
748 return nullptr;
749 }
750
Brian Salomon8a8dd332018-05-24 14:08:31 -0400751 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType,
752 std::move(proxy), std::move(colorSpace), SkBudgeted::kNo);
Greg Daniela8d92112018-03-09 12:05:04 -0500753}
754
Greg Daniel7278d682018-03-16 14:57:21 -0400755///////////////////////////////////////////////////////////////////////////////////////////////////
756
Brian Osman13dddce2017-05-09 13:19:50 -0400757sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
Brian Osman584b5012018-04-13 15:48:26 -0400758 bool buildMips, SkColorSpace* dstColorSpace,
759 bool limitToMaxTextureSize) {
Brian Osman13dddce2017-05-09 13:19:50 -0400760 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
761 if (!codecImage) {
762 return nullptr;
763 }
764
765 // Some backends or drivers don't support (safely) moving resources between contexts
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400766 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
Brian Osman13dddce2017-05-09 13:19:50 -0400767 return codecImage;
768 }
769
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400770 auto maxTextureSize = context->contextPriv().caps()->maxTextureSize();
771 if (limitToMaxTextureSize &&
772 (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) {
Brian Osman584b5012018-04-13 15:48:26 -0400773 SkAutoPixmapStorage pmap;
774 SkImageInfo info = as_IB(codecImage)->onImageInfo();
775 if (!dstColorSpace) {
776 info = info.makeColorSpace(nullptr);
777 }
778 if (!pmap.tryAlloc(info) || !codecImage->readPixels(pmap, 0, 0, kDisallow_CachingHint)) {
779 return nullptr;
780 }
781 return MakeCrossContextFromPixmap(context, pmap, buildMips, dstColorSpace, true);
782 }
783
Brian Osman13dddce2017-05-09 13:19:50 -0400784 // Turn the codec image into a GrTextureProxy
785 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
786 sk_sp<SkColorSpace> texColorSpace;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400787 GrSamplerState samplerState(
788 GrSamplerState::WrapMode::kClamp,
789 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
790 sk_sp<GrTextureProxy> proxy(
791 maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
Brian Osman13dddce2017-05-09 13:19:50 -0400792 if (!proxy) {
793 return codecImage;
794 }
795
Robert Phillips6be756b2018-01-16 15:07:54 -0500796 if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
Brian Osman13dddce2017-05-09 13:19:50 -0400797 return codecImage;
798 }
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400799 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
Brian Osman13dddce2017-05-09 13:19:50 -0400800
801 // Flush any writes or uploads
802 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
803
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500804 GrGpu* gpu = context->contextPriv().getGpu();
805 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman13dddce2017-05-09 13:19:50 -0400806
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400807 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
Brian Osman052ef692018-03-27 09:56:31 -0400808 std::move(sema),
809 as_IB(codecImage)->onImageInfo().colorType(),
810 codecImage->alphaType(),
Brian Osman13dddce2017-05-09 13:19:50 -0400811 std::move(texColorSpace));
812 return SkImage::MakeFromGenerator(std::move(gen));
813}
814
Brian Osman584b5012018-04-13 15:48:26 -0400815sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context,
816 const SkPixmap& originalPixmap, bool buildMips,
817 SkColorSpace* dstColorSpace,
818 bool limitToMaxTextureSize) {
Brian Osman63bc48d2017-11-07 10:37:00 -0500819 // Some backends or drivers don't support (safely) moving resources between contexts
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400820 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
Brian Osman584b5012018-04-13 15:48:26 -0400821 return SkImage::MakeRasterCopy(originalPixmap);
Brian Osman63bc48d2017-11-07 10:37:00 -0500822 }
823
Greg Daniel9e788112018-02-08 14:29:37 -0500824 // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not
825 // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy
826 // instead.
827 if (!context->contextPriv().resourceProvider()) {
Brian Osman584b5012018-04-13 15:48:26 -0400828 return SkImage::MakeRasterCopy(originalPixmap);
Greg Daniel9e788112018-02-08 14:29:37 -0500829 }
830
Brian Osman584b5012018-04-13 15:48:26 -0400831 const SkPixmap* pixmap = &originalPixmap;
832 SkAutoPixmapStorage resized;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400833 int maxTextureSize = context->contextPriv().caps()->maxTextureSize();
Brian Osman584b5012018-04-13 15:48:26 -0400834 int maxDim = SkTMax(originalPixmap.width(), originalPixmap.height());
835 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
836 float scale = static_cast<float>(maxTextureSize) / maxDim;
837 int newWidth = SkTMin(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
838 int newHeight = SkTMin(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
839 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
840 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) {
841 return nullptr;
842 }
843 pixmap = &resized;
844 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500845 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
Brian Osman63bc48d2017-11-07 10:37:00 -0500846 // Turn the pixmap into a GrTextureProxy
847 sk_sp<GrTextureProxy> proxy;
848 if (buildMips) {
849 SkBitmap bmp;
Brian Osman584b5012018-04-13 15:48:26 -0400850 bmp.installPixels(*pixmap);
Brian Osman2b23c4b2018-06-01 12:25:08 -0400851 proxy = proxyProvider->createMipMapProxyFromBitmap(bmp);
Brian Osman63bc48d2017-11-07 10:37:00 -0500852 } else {
Brian Osman2b23c4b2018-06-01 12:25:08 -0400853 if (SkImageInfoIsValid(pixmap->info())) {
Brian Osman584b5012018-04-13 15:48:26 -0400854 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap->width(), pixmap->height());
Greg Danielabadbee2018-03-20 12:09:09 -0400855 // We don't need a release proc on the data in pixmap since we know we are in a
856 // GrContext that has a resource provider. Thus the createTextureProxy call will
857 // immediately upload the data.
Brian Osman584b5012018-04-13 15:48:26 -0400858 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
Greg Danielabadbee2018-03-20 12:09:09 -0400859 proxy = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
860 SkBudgeted::kYes, SkBackingFit::kExact);
Greg Danielbc54fad2018-02-09 16:40:32 -0500861 }
Brian Osman63bc48d2017-11-07 10:37:00 -0500862 }
863
864 if (!proxy) {
Brian Osman584b5012018-04-13 15:48:26 -0400865 return SkImage::MakeRasterCopy(*pixmap);
Brian Osman63bc48d2017-11-07 10:37:00 -0500866 }
867
868 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
869
870 // Flush any writes or uploads
871 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500872 GrGpu* gpu = context->contextPriv().getGpu();
Brian Osman63bc48d2017-11-07 10:37:00 -0500873
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500874 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman63bc48d2017-11-07 10:37:00 -0500875
876 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
Brian Osman584b5012018-04-13 15:48:26 -0400877 std::move(sema), pixmap->colorType(),
878 pixmap->alphaType(),
879 pixmap->info().refColorSpace());
Brian Osman63bc48d2017-11-07 10:37:00 -0500880 return SkImage::MakeFromGenerator(std::move(gen));
881}
882
Derek Sollenberger7a869872017-06-27 15:37:25 -0400883#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
Stan Iliev7e910df2017-06-02 10:29:21 -0400884sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
885 sk_sp<SkColorSpace> cs) {
886 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
887 return SkImage::MakeFromGenerator(std::move(gen));
888}
889#endif
890
reed56179002015-07-07 06:11:19 -0700891///////////////////////////////////////////////////////////////////////////////////////////////////
892
Eric Karl914a36b2017-10-12 12:44:50 -0700893bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
894 sk_sp<SkImage> image,
895 GrBackendTexture* backendTexture,
896 BackendTextureReleaseProc* releaseProc) {
897 if (!image || !ctx || !backendTexture || !releaseProc) {
898 return false;
899 }
900
901 // Ensure we have a texture backed image.
902 if (!image->isTextureBacked()) {
903 image = image->makeTextureImage(ctx, nullptr);
904 if (!image) {
905 return false;
906 }
907 }
908 GrTexture* texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -0800909 if (!texture) {
910 // In context-loss cases, we may not have a texture.
911 return false;
912 }
Eric Karl914a36b2017-10-12 12:44:50 -0700913
914 // If the image's context doesn't match the provided context, fail.
915 if (texture->getContext() != ctx) {
916 return false;
917 }
918
919 // Flush any pending IO on the texture.
920 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
921 SkASSERT(!texture->surfacePriv().hasPendingIO());
922
923 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
924 // image is not unique, or if the texture wraps an external object.
925 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
926 texture->resourcePriv().refsWrappedObjects()) {
927 // onMakeSubset will always copy the image.
928 image = as_IB(image)->onMakeSubset(image->bounds());
929 if (!image) {
930 return false;
931 }
932
933 texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -0800934 if (!texture) {
935 return false;
936 }
Eric Karl914a36b2017-10-12 12:44:50 -0700937
938 // Flush to ensure that the copy is completed before we return the texture.
939 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
940 SkASSERT(!texture->surfacePriv().hasPendingIO());
941 }
942
943 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
944 SkASSERT(texture->surfacePriv().hasUniqueRef());
945 SkASSERT(image->unique());
946
947 // Take a reference to the GrTexture and release the image.
948 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
949 image = nullptr;
950
951 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
952 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
953}
954
955///////////////////////////////////////////////////////////////////////////////////////////////////
956
Matt Sarettd3df9ec2017-06-05 10:45:30 -0400957sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType,
Matt Sarett9f3dcb32017-05-04 08:53:32 -0400958 SkTransferFunctionBehavior premulBehavior) const {
959 if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
960 // TODO: Implement this.
961 return nullptr;
962 }
963
Matt Sarettd3df9ec2017-06-05 10:45:30 -0400964 sk_sp<SkColorSpace> srcSpace = fColorSpace;
965 if (!fColorSpace) {
966 if (target->isSRGB()) {
967 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
968 }
969
970 srcSpace = SkColorSpace::MakeSRGB();
971 }
972
Brian Osman47c27512018-06-18 10:58:51 -0400973 auto xform = GrColorSpaceXformEffect::Make(srcSpace.get(), target.get());
Brian Osman63954c92017-03-14 12:07:12 -0400974 if (!xform) {
975 return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
976 }
977
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500978 sk_sp<GrRenderTargetContext> renderTargetContext(
979 fContext->contextPriv().makeDeferredRenderTargetContext(
980 SkBackingFit::kExact, this->width(), this->height(),
981 kRGBA_8888_GrPixelConfig, nullptr));
Brian Osman63954c92017-03-14 12:07:12 -0400982 if (!renderTargetContext) {
983 return nullptr;
984 }
985
986 GrPaint paint;
987 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Osman2240be92017-10-18 13:15:13 -0400988 paint.addColorTextureProcessor(fProxy, SkMatrix::I());
Brian Osman63954c92017-03-14 12:07:12 -0400989 paint.addColorFragmentProcessor(std::move(xform));
990
991 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
992
993 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
994
Robert Phillips7ee385e2017-03-30 08:02:11 -0400995 if (!renderTargetContext->asTextureProxy()) {
Brian Osman63954c92017-03-14 12:07:12 -0400996 return nullptr;
997 }
998
999 // MDB: this call is okay bc we know 'renderTargetContext' was exact
1000 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
1001 fAlphaType, renderTargetContext->asTextureProxyRef(),
Matt Sarettd3df9ec2017-06-05 10:45:30 -04001002 std::move(target), fBudgeted);
Brian Osman63954c92017-03-14 12:07:12 -04001003
1004}
Brian Osman5bbd0762017-05-08 11:07:42 -04001005
1006bool SkImage_Gpu::onIsValid(GrContext* context) const {
1007 // The base class has already checked that context isn't abandoned (if it's not nullptr)
Khushalc421ca12018-06-26 14:38:34 -07001008 if (fContext->abandoned()) {
Brian Osman5bbd0762017-05-08 11:07:42 -04001009 return false;
1010 }
1011
Brian Salomon8a8dd332018-05-24 14:08:31 -04001012 if (context && context != fContext.get()) {
Brian Osman5bbd0762017-05-08 11:07:42 -04001013 return false;
1014 }
1015
1016 return true;
1017}