blob: 0b3868d3fee0eaaece15d750c96641e32ed8fbff [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)
Mike Reed30301c42018-07-19 09:39:21 -040054 , fColorSpace(std::move(colorSpace)) {}
piotaixrcef04f82014-07-14 07:48:04 -070055
Mike Reed30301c42018-07-19 09:39:21 -040056SkImage_Gpu::~SkImage_Gpu() {}
reed6f1216a2015-08-04 08:10:13 -070057
brianosman396fcdb2016-07-22 06:26:11 -070058SkImageInfo SkImage_Gpu::onImageInfo() const {
Greg Daniel56008aa2018-03-14 15:33:42 -040059 return SkImageInfo::Make(fProxy->width(), fProxy->height(), this->onColorType(), fAlphaType,
60 fColorSpace);
61}
62
63SkColorType SkImage_Gpu::onColorType() const {
brianosman396fcdb2016-07-22 06:26:11 -070064 SkColorType ct;
Robert Phillipsb726d582017-03-09 16:36:32 -050065 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
brianosman396fcdb2016-07-22 06:26:11 -070066 ct = kUnknown_SkColorType;
67 }
Greg Daniel56008aa2018-03-14 15:33:42 -040068 return ct;
brianosman396fcdb2016-07-22 06:26:11 -070069}
70
Brian Osman62517712017-04-26 16:26:39 -040071bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
Robert Phillipsa6aef2a2018-04-11 10:41:20 -040072 if (!fContext->contextPriv().resourceProvider()) {
73 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
74 return false;
75 }
76
Brian Osman62517712017-04-26 16:26:39 -040077 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
78 // will be used. The client doesn't expect that we convert to that color space, it's intended
79 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
80 // into that color space (to save the client some effort in whatever they're about to do), but
81 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
82 // rolled the dstColorSpace into the key).
Mike Reed5fa3d6d2017-03-25 09:51:00 -040083 const auto desc = SkBitmapCacheDesc::Make(this);
84 if (SkBitmapCache::Find(desc, dst)) {
reed6f1216a2015-08-04 08:10:13 -070085 SkASSERT(dst->getGenerationID() == this->uniqueID());
86 SkASSERT(dst->isImmutable());
87 SkASSERT(dst->getPixels());
88 return true;
89 }
90
Mike Reed7a542c52017-04-11 12:03:44 -040091 SkBitmapCache::RecPtr rec = nullptr;
92 SkPixmap pmap;
93 if (kAllow_CachingHint == chint) {
Brian Osman62517712017-04-26 16:26:39 -040094 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
Mike Reed7a542c52017-04-11 12:03:44 -040095 if (!rec) {
96 return false;
97 }
98 } else {
Brian Osman62517712017-04-26 16:26:39 -040099 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
Mike Reed7a542c52017-04-11 12:03:44 -0400100 return false;
101 }
reed8b26b992015-05-07 15:36:17 -0700102 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500103
Brian Salomon2084ffa2017-03-27 17:32:18 -0400104 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
105 fProxy,
106 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500107 if (!sContext) {
108 return false;
109 }
110
Mike Reed7a542c52017-04-11 12:03:44 -0400111 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
reed8b26b992015-05-07 15:36:17 -0700112 return false;
113 }
reed6f1216a2015-08-04 08:10:13 -0700114
Mike Reed7a542c52017-04-11 12:03:44 -0400115 if (rec) {
116 SkBitmapCache::Add(std::move(rec), dst);
Mike Reed30301c42018-07-19 09:39:21 -0400117 this->notifyAddedToRasterCache();
reed09553032015-11-23 12:32:16 -0800118 }
reed8b26b992015-05-07 15:36:17 -0700119 return true;
120}
121
Robert Phillipsb726d582017-03-09 16:36:32 -0500122sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400123 const GrSamplerState& params,
Robert Phillipsb726d582017-03-09 16:36:32 -0500124 SkColorSpace* dstColorSpace,
125 sk_sp<SkColorSpace>* texColorSpace,
126 SkScalar scaleAdjust[2]) const {
Brian Salomon8a8dd332018-05-24 14:08:31 -0400127 if (context != fContext.get()) {
Robert Phillipsb726d582017-03-09 16:36:32 -0500128 SkASSERT(0);
129 return nullptr;
130 }
131
Brian Salomon8a8dd332018-05-24 14:08:31 -0400132 GrTextureAdjuster adjuster(fContext.get(), fProxy, this->alphaType(), this->uniqueID(),
Greg Danielc77085d2017-11-01 16:38:48 -0400133 this->fColorSpace.get());
Brian Salomon2a943df2018-05-04 13:43:19 -0400134 return adjuster.refTextureProxyForParams(params, dstColorSpace, texColorSpace, scaleAdjust);
reed85d91782015-09-10 14:33:38 -0700135}
136
reed8b26b992015-05-07 15:36:17 -0700137static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
138 switch (info.colorType()) {
139 case kRGBA_8888_SkColorType:
140 case kBGRA_8888_SkColorType:
141 break;
142 default:
143 return; // nothing to do
144 }
145
146 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
147 // and in either case, the alpha-byte is always in the same place, so we can safely call
148 // SkPreMultiplyColor()
149 //
150 SkColor* row = (SkColor*)pixels;
151 for (int y = 0; y < info.height(); ++y) {
152 for (int x = 0; x < info.width(); ++x) {
153 row[x] = SkPreMultiplyColor(row[x]);
154 }
Brian Salomon9708af82018-02-05 12:57:10 -0500155 row = (SkColor*)((char*)(row) + rowBytes);
reed8b26b992015-05-07 15:36:17 -0700156 }
157}
158
Robert Phillipsc5509952018-04-04 15:54:55 -0400159GrBackendTexture SkImage_Gpu::onGetBackendTexture(bool flushPendingGrContextIO,
160 GrSurfaceOrigin* origin) const {
161 SkASSERT(fProxy);
162
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400163 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
164 // This image was created with a DDL context and cannot be instantiated.
165 return GrBackendTexture();
166 }
167
Robert Phillipsc5509952018-04-04 15:54:55 -0400168 if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
169 return GrBackendTexture(); // invalid
170 }
171
172 GrTexture* texture = fProxy->priv().peekTexture();
173
174 if (texture) {
175 if (flushPendingGrContextIO) {
176 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
177 }
178 if (origin) {
179 *origin = fProxy->origin();
180 }
181 return texture->getBackendTexture();
182 }
183 return GrBackendTexture(); // invalid
184}
185
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400186GrTexture* SkImage_Gpu::onGetTexture() const {
187 GrTextureProxy* proxy = this->peekProxy();
188 if (!proxy) {
189 return nullptr;
190 }
191
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400192 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
193 // This image was created with a DDL context and cannot be instantiated.
194 return nullptr;
195 }
196
Robert Phillips6be756b2018-01-16 15:07:54 -0500197 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400198 return nullptr;
199 }
200
201 return proxy->priv().peekTexture();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400202}
203
Matt Sarett03dd6d52017-01-23 12:15:09 -0500204bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
reed09553032015-11-23 12:32:16 -0800205 int srcX, int srcY, CachingHint) const {
Robert Phillipsa6aef2a2018-04-11 10:41:20 -0400206 if (!fContext->contextPriv().resourceProvider()) {
207 // DDL TODO: buffer up the readback so it occurs when the DDL is drawn?
208 return false;
209 }
210
Matt Sarett03dd6d52017-01-23 12:15:09 -0500211 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500212 return false;
213 }
214
Matt Sarett03dd6d52017-01-23 12:15:09 -0500215 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
216 if (!rec.trim(this->width(), this->height())) {
217 return false;
218 }
219
Robert Phillipsb726d582017-03-09 16:36:32 -0500220 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
221 // GrRenderTargetContext::onReadPixels
reed8b26b992015-05-07 15:36:17 -0700222 uint32_t flags = 0;
Matt Sarett03dd6d52017-01-23 12:15:09 -0500223 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
reed8b26b992015-05-07 15:36:17 -0700224 // let the GPU perform this transformation for us
Robert Phillipse78b7252017-04-06 07:59:41 -0400225 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
reed8b26b992015-05-07 15:36:17 -0700226 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500227
Brian Salomon2084ffa2017-03-27 17:32:18 -0400228 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
Brian Osman9aa30c62018-07-02 15:21:46 -0400229 fProxy, fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500230 if (!sContext) {
reed8b26b992015-05-07 15:36:17 -0700231 return false;
232 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500233
234 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
235 return false;
236 }
237
reed8b26b992015-05-07 15:36:17 -0700238 // do we have to manually fix-up the alpha channel?
239 // src dst
240 // unpremul premul fix manually
241 // premul unpremul done by kUnpremul_PixelOpsFlag
242 // all other combos need to change.
243 //
244 // Should this be handled by Ganesh? todo:?
245 //
Matt Sarett03dd6d52017-01-23 12:15:09 -0500246 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
247 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
reed8b26b992015-05-07 15:36:17 -0700248 }
249 return true;
250}
251
reed7fb4f8b2016-03-11 04:33:52 -0800252sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
Brian Salomon63e79732017-05-15 21:23:13 -0400253 GrSurfaceDesc desc;
reed7b6945b2015-09-24 00:50:58 -0700254 desc.fWidth = subset.width();
255 desc.fHeight = subset.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400256 desc.fConfig = fProxy->config();
reed7b6945b2015-09-24 00:50:58 -0700257
Robert Phillipsb726d582017-03-09 16:36:32 -0500258 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
Brian Salomon2a4f9832018-03-03 22:43:43 -0500259 desc, fProxy->origin(), GrMipMapped::kNo, SkBackingFit::kExact, fBudgeted));
Robert Phillipse2f7d182016-12-15 09:23:05 -0500260 if (!sContext) {
261 return nullptr;
262 }
263
Robert Phillipsb726d582017-03-09 16:36:32 -0500264 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500265 return nullptr;
266 }
267
Robert Phillipsb726d582017-03-09 16:36:32 -0500268 // MDB: this call is okay bc we know 'sContext' was kExact
269 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
270 fAlphaType, sContext->asTextureProxyRef(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500271 fColorSpace, fBudgeted);
reed7b6945b2015-09-24 00:50:58 -0700272}
273
reed8b26b992015-05-07 15:36:17 -0700274///////////////////////////////////////////////////////////////////////////////////////////////////
275
Greg Daniel7ef28f32017-04-20 16:41:55 +0000276static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
277 const GrBackendTexture& backendTex,
278 GrSurfaceOrigin origin,
brianosmandddbe382016-07-20 13:55:39 -0700279 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
280 GrWrapOwnership ownership,
reed7fb4f8b2016-03-11 04:33:52 -0800281 SkImage::TextureReleaseProc releaseProc,
282 SkImage::ReleaseContext releaseCtx) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400283 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700284 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700285 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400286
Robert Phillipsadbe1322018-01-17 13:35:46 -0500287 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
Brian Salomon7578f3e2018-03-07 14:39:54 -0500288 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(backendTex, origin, ownership,
289 releaseProc, releaseCtx);
Robert Phillipsadbe1322018-01-17 13:35:46 -0500290 if (!proxy) {
Robert Phillipse201ebc2018-01-17 18:12:50 +0000291 return nullptr;
292 }
Brian Salomon94575462018-06-21 17:00:26 -0400293#if 1
294 // Temporary fix for crbug.com/850617 that can be cleanly merged back to older branches. Assume
295 // any MIP levels on the incoming texture are dirty. The proper fix is to make them clean on
296 // export. See #if 0'ed out code in GrDrawingManager::prepareSurfaceForExternalIO().
297 SkASSERT(proxy->priv().isInstantiated());
298 if (auto* tex = proxy->priv().peekTexture()) {
299 if (tex->texturePriv().mipMapped() == GrMipMapped::kYes) {
300 proxy->priv().peekTexture()->texturePriv().markMipMapsDirty();
301 }
302 }
303#endif
Brian Salomon8a8dd332018-05-24 14:08:31 -0400304 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy),
305 std::move(colorSpace), SkBudgeted::kNo);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700306}
307
Greg Danielfaa095e2017-12-19 13:15:02 -0500308bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
Greg Danielf5d87582017-12-18 14:48:15 -0500309 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) {
Greg Daniel66aebf32018-04-09 09:15:56 -0400310 if (!tex.isValid()) {
311 return false;
312 }
Greg Danielf5d87582017-12-18 14:48:15 -0500313 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
314 // create a fake image info here.
315 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
Brian Osmane1adc3a2018-06-04 09:21:17 -0400316 if (!SkImageInfoIsValid(info)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500317 return false;
318 }
319
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400320 return ctx->contextPriv().caps()->validateBackendTexture(tex, ct, config);
Greg Danielf5d87582017-12-18 14:48:15 -0500321}
322
323sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
324 const GrBackendTexture& tex, GrSurfaceOrigin origin,
325 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
326 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500327 if (!ctx) {
328 return nullptr;
329 }
Greg Danielf5d87582017-12-18 14:48:15 -0500330 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500331 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500332 return nullptr;
333 }
Brian Salomonbfd27492018-03-19 14:08:51 -0400334 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
335 kBorrow_GrWrapOwnership, releaseP, releaseC);
Greg Danielf5d87582017-12-18 14:48:15 -0500336}
337
Greg Daniel94403452017-04-18 15:52:36 -0400338sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
339 const GrBackendTexture& tex, GrSurfaceOrigin origin,
Brian Salomon42409c22018-03-20 13:48:41 -0400340 SkColorType ct, SkAlphaType at,
341 sk_sp<SkColorSpace> cs) {
342 if (!ctx || !ctx->contextPriv().resourceProvider()) {
Greg Danielf2336e42018-01-23 16:38:14 -0500343 // We have a DDL context and we don't support adopted textures for them.
344 return nullptr;
345 }
Greg Danielf5d87582017-12-18 14:48:15 -0500346 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500347 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500348 return nullptr;
349 }
Brian Salomon42409c22018-03-20 13:48:41 -0400350 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
351 kAdopt_GrWrapOwnership, nullptr, nullptr);
Greg Danielf5d87582017-12-18 14:48:15 -0500352}
353
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400354sk_sp<SkImage> SkImage_Gpu::MakeFromYUVATexturesCopyImpl(GrContext* ctx,
355 SkYUVColorSpace colorSpace,
356 const GrBackendTexture yuvaTextures[],
357 SkYUVAIndex yuvaIndices[4],
358 SkISize size,
359 GrSurfaceOrigin origin,
360 sk_sp<SkColorSpace> imageColorSpace) {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500361 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
362
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400363 // Right now this still only deals with YUV and NV12 formats. Assuming that YUV has different
364 // textures for U and V planes, while NV12 uses same texture for U and V planes.
365 bool nv12 = (yuvaIndices[1].fIndex == yuvaIndices[2].fIndex);
Brian Salomon6a426c12018-03-15 12:16:02 -0400366 auto ct = nv12 ? kRGBA_8888_SkColorType : kAlpha_8_SkColorType;
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400367
Greg Daniel108bb232018-07-03 16:18:29 -0400368 // We need to make a copy of the input backend textures because we need to preserve the result
369 // of validate_backend_texture.
370 GrBackendTexture yuvaTexturesCopy[4];
371
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400372 for (int i = 0; i < 4; ++i) {
373 // Validate that the yuvaIndices refer to valid backend textures.
374 SkYUVAIndex& yuvaIndex = yuvaIndices[i];
375 if (i == 3 && yuvaIndex.fIndex == -1) {
376 // Meaning the A plane isn't passed in.
377 continue;
378 }
379 if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
380 // Y plane, U plane, and V plane must refer to image sources being passed in. There are
381 // at most 4 images sources being passed in, could not have a index more than 3.
Brian Salomon3afdab12018-03-19 16:29:37 -0400382 return nullptr;
Brian Salomon6a426c12018-03-15 12:16:02 -0400383 }
Greg Daniel108bb232018-07-03 16:18:29 -0400384 if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
385 yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
386 // TODO: Instead of using assumption about whether it is NV12 format to guess colorType,
387 // actually use channel information here.
388 if (!validate_backend_texture(ctx, yuvaTexturesCopy[i], &yuvaTexturesCopy[i].fConfig,
389 ct, kPremul_SkAlphaType, nullptr)) {
390 return nullptr;
391 }
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400392 }
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500393
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400394 // TODO: Check that for each plane, the channel actually exist in the image source we are
395 // reading from.
jbaumanb445a572016-06-09 13:24:48 -0700396 }
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400397
398 sk_sp<GrTextureProxy> tempTextureProxies[4];
399 for (int i = 0; i < 4; ++i) {
400 // Fill in tempTextureProxies to avoid duplicate texture proxies.
401 int textureIndex = yuvaIndices[i].fIndex;
402
403 // Safely ignore since this means we are missing the A plane.
404 if (textureIndex == -1) {
405 SkASSERT(3 == i);
406 continue;
407 }
408
409 if (!tempTextureProxies[textureIndex]) {
Greg Daniel108bb232018-07-03 16:18:29 -0400410 SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400411 tempTextureProxies[textureIndex] =
Greg Daniel108bb232018-07-03 16:18:29 -0400412 proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400413 }
414 }
415 sk_sp<GrTextureProxy> yProxy = tempTextureProxies[yuvaIndices[0].fIndex];
416 sk_sp<GrTextureProxy> uProxy = tempTextureProxies[yuvaIndices[1].fIndex];
417 sk_sp<GrTextureProxy> vProxy = tempTextureProxies[yuvaIndices[2].fIndex];
418
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500419 if (!yProxy || !uProxy || !vProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700420 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700421 }
422
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400423 const int width = size.width();
424 const int height = size.height();
robertphillipsaa19a5f2016-04-28 06:21:55 -0700425
robertphillipsd4c741e2016-04-28 09:55:15 -0700426 // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500427 sk_sp<GrRenderTargetContext> renderTargetContext(
428 ctx->contextPriv().makeDeferredRenderTargetContext(
429 SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
430 std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
Brian Osman11052242016-10-27 14:47:55 -0400431 if (!renderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700432 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700433 }
434
435 GrPaint paint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400436 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400437 // TODO: Modify the fragment processor to sample from different channel instead of taking nv12
438 // bool.
Brian Salomon6a426c12018-03-15 12:16:02 -0400439 paint.addColorFragmentProcessor(
Weiliang Chen3e95e572018-05-30 15:15:23 -0400440 GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy, colorSpace, nv12));
bsalomon993a4212015-05-29 11:37:25 -0700441
Robert Phillipsb726d582017-03-09 16:36:32 -0500442 const SkRect rect = SkRect::MakeIWH(width, height);
robertphillipsc9a37062015-09-01 08:34:28 -0700443
Brian Salomon82f44312017-01-11 13:42:54 -0500444 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
Robert Phillipse60ad622016-11-17 10:22:48 -0500445
Robert Phillips7ee385e2017-03-30 08:02:11 -0400446 if (!renderTargetContext->asSurfaceProxy()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500447 return nullptr;
448 }
Robert Phillips7ee385e2017-03-30 08:02:11 -0400449 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
Robert Phillipsb726d582017-03-09 16:36:32 -0500450
451 // MDB: this call is okay bc we know 'renderTargetContext' was exact
Brian Salomon8a8dd332018-05-24 14:08:31 -0400452 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
Brian Salomonf3569f02017-10-24 12:52:33 -0400453 renderTargetContext->asTextureProxyRef(),
Robert Phillipsc25db632017-12-13 09:22:45 -0500454 renderTargetContext->colorSpaceInfo().refColorSpace(),
455 SkBudgeted::kYes);
456}
457
Brian Salomon6a426c12018-03-15 12:16:02 -0400458sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
459 const GrBackendTexture yuvTextures[3],
460 GrSurfaceOrigin origin,
461 sk_sp<SkColorSpace> imageColorSpace) {
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400462 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
463 SkYUVAIndex yuvaIndices[4] = {
464 SkYUVAIndex{0, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
465 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
466 SkYUVAIndex{2, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
467 SkYUVAIndex{-1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel}};
468 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
469 return SkImage_Gpu::MakeFromYUVATexturesCopyImpl(ctx, colorSpace, yuvTextures, yuvaIndices,
470 size, origin, std::move(imageColorSpace));
bsalomon993a4212015-05-29 11:37:25 -0700471}
reed56179002015-07-07 06:11:19 -0700472
jbaumanb445a572016-06-09 13:24:48 -0700473sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
Brian Salomon6a426c12018-03-15 12:16:02 -0400474 const GrBackendTexture nv12Textures[2],
brianosmandddbe382016-07-20 13:55:39 -0700475 GrSurfaceOrigin origin,
476 sk_sp<SkColorSpace> imageColorSpace) {
Weiliang Chenbed9d5e2018-05-22 18:44:02 -0400477 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
478 SkYUVAIndex yuvaIndices[4] = {
479 SkYUVAIndex{0, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
480 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
481 SkYUVAIndex{1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel},
482 SkYUVAIndex{-1, SkImageSourceChannel::kLastEnum_SkImageSourceChannel}};
483 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
484 return SkImage_Gpu::MakeFromYUVATexturesCopyImpl(ctx, colorSpace, nv12Textures, yuvaIndices,
485 size, origin, std::move(imageColorSpace));
Robert Phillipsc25db632017-12-13 09:22:45 -0500486}
487
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400488static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
489 SkAlphaType at, uint32_t id,
490 SkColorSpace* dstColorSpace,
491 GrMipMapped mipMapped) {
Brian Osman041f7df2017-02-07 11:23:28 -0500492 sk_sp<SkColorSpace> texColorSpace;
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400493 sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped, dstColorSpace,
494 &texColorSpace));
Robert Phillips3798c862017-03-27 11:08:16 -0400495 if (!proxy) {
Brian Osman041f7df2017-02-07 11:23:28 -0500496 return nullptr;
497 }
Brian Salomon8a8dd332018-05-24 14:08:31 -0400498 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, at, std::move(proxy),
499 std::move(texColorSpace), SkBudgeted::kNo);
Brian Osman041f7df2017-02-07 11:23:28 -0500500}
501
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400502sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
503 GrMipMapped mipMapped) const {
Brian Osman041f7df2017-02-07 11:23:28 -0500504 if (!context) {
505 return nullptr;
506 }
Robert Phillips87444052017-06-23 14:09:30 -0400507 if (GrContext* incumbent = as_IB(this)->context()) {
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400508 if (incumbent != context) {
509 return nullptr;
510 }
511 sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef();
512 SkASSERT(proxy);
513 if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) {
514 return sk_ref_sp(const_cast<SkImage*>(this));
515 }
516 GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(),
517 this->uniqueID(), this->colorSpace());
518 return create_image_from_producer(context, &adjuster, this->alphaType(),
519 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500520 }
521
Brian Osmandf7e0752017-04-26 16:20:28 -0400522 if (this->isLazyGenerated()) {
523 GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400524 return create_image_from_producer(context, &maker, this->alphaType(),
525 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500526 }
527
528 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
529 GrBitmapTextureMaker maker(context, *bmp);
Greg Daniel5f4b09d2018-06-12 16:39:59 -0400530 return create_image_from_producer(context, &maker, this->alphaType(),
531 this->uniqueID(), dstColorSpace, mipMapped);
Brian Osman041f7df2017-02-07 11:23:28 -0500532 }
533 return nullptr;
534}
535
Greg Daniel7278d682018-03-16 14:57:21 -0400536///////////////////////////////////////////////////////////////////////////////////////////////////
537
538/**
539 * This helper holds the normal hard ref for the Release proc as well as a hard ref on the DoneProc.
540 * Thus when a GrTexture is being released, it will unref both the ReleaseProc and DoneProc.
541 */
542class PromiseReleaseProcHelper : public GrReleaseProcHelper {
543public:
544 PromiseReleaseProcHelper(SkImage_Gpu::TextureReleaseProc releaseProc,
545 SkImage_Gpu::TextureContext context,
546 sk_sp<GrReleaseProcHelper> doneHelper)
547 : INHERITED(releaseProc, context)
548 , fDoneProcHelper(std::move(doneHelper)) {}
549
550 void weak_dispose() const override {
551 // Call the inherited weak_dispose first so that we call the ReleaseProc before the DoneProc
552 // if we hold the last ref to the DoneProc.
553 INHERITED::weak_dispose();
554 fDoneProcHelper.reset();
555 }
556
557private:
558 mutable sk_sp<GrReleaseProcHelper> fDoneProcHelper;
559
560 typedef GrReleaseProcHelper INHERITED;
561};
562
563/**
564 * This helper class manages the ref counting for the the ReleaseProc and DoneProc for promise
565 * images. It holds a weak ref on the ReleaseProc (hard refs are owned by GrTextures). The weak ref
566 * allows us to reuse an outstanding ReleaseProc (because we dropped our GrTexture but the GrTexture
567 * isn't done on the GPU) without needing to call FulfillProc again. It also holds a hard ref on the
568 * DoneProc. The idea is that after every flush we may call the ReleaseProc so that the client can
569 * free up their GPU memory if they want to. The life time of the DoneProc matches that of any
570 * outstanding ReleaseProc as well as the PromiseImageHelper. Thus we won't call the DoneProc until
571 * all ReleaseProcs are finished and we are finished with the PromiseImageHelper (i.e. won't call
572 * FulfillProc again).
573 */
Greg Daniela8d92112018-03-09 12:05:04 -0500574class PromiseImageHelper {
575public:
576 PromiseImageHelper(SkImage_Gpu::TextureFulfillProc fulFillProc,
577 SkImage_Gpu::TextureReleaseProc releaseProc,
Greg Daniel7278d682018-03-16 14:57:21 -0400578 SkImage_Gpu::PromiseDoneProc doneProc,
Greg Daniela8d92112018-03-09 12:05:04 -0500579 SkImage_Gpu::TextureContext context)
580 : fFulfillProc(fulFillProc)
581 , fReleaseProc(releaseProc)
Greg Daniel7278d682018-03-16 14:57:21 -0400582 , fContext(context)
583 , fDoneHelper(new GrReleaseProcHelper(doneProc, context)) {}
Greg Daniela8d92112018-03-09 12:05:04 -0500584
585 void reset() {
586 this->resetReleaseHelper();
Greg Daniel7278d682018-03-16 14:57:21 -0400587 fDoneHelper.reset();
Greg Daniela8d92112018-03-09 12:05:04 -0500588 }
589
Greg Daniel057627f2018-03-14 15:51:58 -0400590 sk_sp<GrTexture> getTexture(GrResourceProvider* resourceProvider, GrPixelConfig config) {
Greg Daniela8d92112018-03-09 12:05:04 -0500591 // Releases the promise helper if there are no outstanding hard refs. This means that we
592 // don't have any ReleaseProcs waiting to be called so we will need to do a fulfill.
593 if (fReleaseHelper && fReleaseHelper->weak_expired()) {
594 this->resetReleaseHelper();
595 }
596
597 sk_sp<GrTexture> tex;
598 if (!fReleaseHelper) {
599 fFulfillProc(fContext, &fBackendTex);
Greg Daniel057627f2018-03-14 15:51:58 -0400600 fBackendTex.fConfig = config;
Greg Daniela8d92112018-03-09 12:05:04 -0500601 if (!fBackendTex.isValid()) {
602 // Even though the GrBackendTexture is not valid, we must call the release
603 // proc to keep our contract of always calling Fulfill and Release in pairs.
604 fReleaseProc(fContext);
605 return sk_sp<GrTexture>();
606 }
607
608 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
609 if (!tex) {
610 // Even though the GrBackendTexture is not valid, we must call the release
611 // proc to keep our contract of always calling Fulfill and Release in pairs.
612 fReleaseProc(fContext);
613 return sk_sp<GrTexture>();
614 }
Greg Daniel7278d682018-03-16 14:57:21 -0400615 fReleaseHelper = new PromiseReleaseProcHelper(fReleaseProc, fContext, fDoneHelper);
Greg Daniela8d92112018-03-09 12:05:04 -0500616 // Take a weak ref
617 fReleaseHelper->weak_ref();
618 } else {
619 SkASSERT(fBackendTex.isValid());
620 tex = resourceProvider->wrapBackendTexture(fBackendTex, kBorrow_GrWrapOwnership);
621 if (!tex) {
622 // We weren't able to make a texture here, but since we are in this branch
623 // of the calls (promiseHelper.fReleaseHelper is valid) there is already a
624 // texture out there which will call the release proc so we don't need to
625 // call it here.
626 return sk_sp<GrTexture>();
627 }
628
629 SkAssertResult(fReleaseHelper->try_ref());
630 }
631 SkASSERT(tex);
632 // Pass the hard ref off to the texture
633 tex->setRelease(sk_sp<GrReleaseProcHelper>(fReleaseHelper));
634 return tex;
635 }
636
637private:
638 // Weak unrefs fReleaseHelper and sets it to null
639 void resetReleaseHelper() {
640 if (fReleaseHelper) {
641 fReleaseHelper->weak_unref();
642 fReleaseHelper = nullptr;
643 }
644 }
645
646 SkImage_Gpu::TextureFulfillProc fFulfillProc;
647 SkImage_Gpu::TextureReleaseProc fReleaseProc;
648 SkImage_Gpu::TextureContext fContext;
649
650 // We cache the GrBackendTexture so that if we deleted the GrTexture but the the release proc
651 // has yet not been called (this can happen on Vulkan), then we can create a new texture without
652 // needing to call the fulfill proc again.
653 GrBackendTexture fBackendTex;
654 // The fReleaseHelper is used to track a weak ref on the release proc. This helps us make sure
655 // we are always pairing fulfill and release proc calls correctly.
Greg Daniel7278d682018-03-16 14:57:21 -0400656 PromiseReleaseProcHelper* fReleaseHelper = nullptr;
657 // We don't want to call the fDoneHelper until we are done with the PromiseImageHelper and all
658 // ReleaseHelpers are finished. Thus we hold a hard ref here and we will pass a hard ref to each
659 // fReleaseHelper we make.
660 sk_sp<GrReleaseProcHelper> fDoneHelper;
Greg Daniela8d92112018-03-09 12:05:04 -0500661};
662
Robert Phillipsabf7b762018-03-21 12:13:37 -0400663static GrInternalSurfaceFlags get_flags_from_format(const GrBackendFormat& backendFormat) {
664 if (const GrGLenum* target = backendFormat.getGLTarget()) {
665 if (GR_GL_TEXTURE_RECTANGLE == *target || GR_GL_TEXTURE_EXTERNAL == *target) {
Greg Daniel09c94002018-06-08 22:11:51 +0000666 return GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal;
Robert Phillipsabf7b762018-03-21 12:13:37 -0400667 }
668 }
669
670 return GrInternalSurfaceFlags::kNone;
671}
672
Greg Daniela8d92112018-03-09 12:05:04 -0500673sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
674 const GrBackendFormat& backendFormat,
675 int width,
676 int height,
677 GrMipMapped mipMapped,
678 GrSurfaceOrigin origin,
679 SkColorType colorType,
680 SkAlphaType alphaType,
681 sk_sp<SkColorSpace> colorSpace,
682 TextureFulfillProc textureFulfillProc,
683 TextureReleaseProc textureReleaseProc,
Greg Daniel7278d682018-03-16 14:57:21 -0400684 PromiseDoneProc promiseDoneProc,
Greg Daniela8d92112018-03-09 12:05:04 -0500685 TextureContext textureContext) {
686 if (!context) {
687 return nullptr;
688 }
689
690 if (width <= 0 || height <= 0) {
691 return nullptr;
692 }
693
Greg Daniel7278d682018-03-16 14:57:21 -0400694 if (!textureFulfillProc || !textureReleaseProc || !promiseDoneProc) {
Greg Daniela8d92112018-03-09 12:05:04 -0500695 return nullptr;
696 }
697
698 SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
Brian Osmane1adc3a2018-06-04 09:21:17 -0400699 if (!SkImageInfoIsValid(info)) {
Greg Daniela8d92112018-03-09 12:05:04 -0500700 return nullptr;
701 }
702 GrPixelConfig config = kUnknown_GrPixelConfig;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400703 if (!context->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, colorType,
704 &config)) {
Greg Daniela8d92112018-03-09 12:05:04 -0500705 return nullptr;
706 }
707
Greg Daniel09c94002018-06-08 22:11:51 +0000708 GrInternalSurfaceFlags formatFlags = get_flags_from_format(backendFormat);
709
710 if (mipMapped == GrMipMapped::kYes &&
711 SkToBool(formatFlags & GrInternalSurfaceFlags::kIsGLTextureRectangleOrExternal)) {
712 // It is invalid to have a GL_TEXTURE_EXTERNAL or GL_TEXTURE_RECTANGLE and have mips as
713 // well.
714 return nullptr;
715 }
716
Greg Daniela8d92112018-03-09 12:05:04 -0500717 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
718
719 GrSurfaceDesc desc;
720 desc.fWidth = width;
721 desc.fHeight = height;
722 desc.fConfig = config;
723
Greg Daniel7278d682018-03-16 14:57:21 -0400724 PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, promiseDoneProc,
725 textureContext);
Greg Daniela8d92112018-03-09 12:05:04 -0500726
727 sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
Greg Daniel057627f2018-03-14 15:51:58 -0400728 [promiseHelper, config] (GrResourceProvider* resourceProvider) mutable {
Greg Daniela8d92112018-03-09 12:05:04 -0500729 if (!resourceProvider) {
730 promiseHelper.reset();
731 return sk_sp<GrTexture>();
732 }
733
Greg Daniel057627f2018-03-14 15:51:58 -0400734 return promiseHelper.getTexture(resourceProvider, config);
Robert Phillipsabf7b762018-03-21 12:13:37 -0400735 }, desc, origin, mipMapped, formatFlags, SkBackingFit::kExact,
Greg Daniela8d92112018-03-09 12:05:04 -0500736 SkBudgeted::kNo, GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
737
738 if (!proxy) {
739 return nullptr;
740 }
741
Brian Salomon8a8dd332018-05-24 14:08:31 -0400742 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType,
743 std::move(proxy), std::move(colorSpace), SkBudgeted::kNo);
Greg Daniela8d92112018-03-09 12:05:04 -0500744}
745
Greg Daniel7278d682018-03-16 14:57:21 -0400746///////////////////////////////////////////////////////////////////////////////////////////////////
747
Brian Osman13dddce2017-05-09 13:19:50 -0400748sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
Brian Osman584b5012018-04-13 15:48:26 -0400749 bool buildMips, SkColorSpace* dstColorSpace,
750 bool limitToMaxTextureSize) {
Brian Osman13dddce2017-05-09 13:19:50 -0400751 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
752 if (!codecImage) {
753 return nullptr;
754 }
755
756 // Some backends or drivers don't support (safely) moving resources between contexts
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400757 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
Brian Osman13dddce2017-05-09 13:19:50 -0400758 return codecImage;
759 }
760
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400761 auto maxTextureSize = context->contextPriv().caps()->maxTextureSize();
762 if (limitToMaxTextureSize &&
763 (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) {
Brian Osman584b5012018-04-13 15:48:26 -0400764 SkAutoPixmapStorage pmap;
765 SkImageInfo info = as_IB(codecImage)->onImageInfo();
766 if (!dstColorSpace) {
767 info = info.makeColorSpace(nullptr);
768 }
769 if (!pmap.tryAlloc(info) || !codecImage->readPixels(pmap, 0, 0, kDisallow_CachingHint)) {
770 return nullptr;
771 }
772 return MakeCrossContextFromPixmap(context, pmap, buildMips, dstColorSpace, true);
773 }
774
Brian Osman13dddce2017-05-09 13:19:50 -0400775 // Turn the codec image into a GrTextureProxy
776 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
777 sk_sp<SkColorSpace> texColorSpace;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400778 GrSamplerState samplerState(
779 GrSamplerState::WrapMode::kClamp,
780 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
781 sk_sp<GrTextureProxy> proxy(
782 maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
Brian Osman13dddce2017-05-09 13:19:50 -0400783 if (!proxy) {
784 return codecImage;
785 }
786
Robert Phillips6be756b2018-01-16 15:07:54 -0500787 if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
Brian Osman13dddce2017-05-09 13:19:50 -0400788 return codecImage;
789 }
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400790 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
Brian Osman13dddce2017-05-09 13:19:50 -0400791
792 // Flush any writes or uploads
793 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
794
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500795 GrGpu* gpu = context->contextPriv().getGpu();
796 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman13dddce2017-05-09 13:19:50 -0400797
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400798 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
Brian Osman052ef692018-03-27 09:56:31 -0400799 std::move(sema),
800 as_IB(codecImage)->onImageInfo().colorType(),
801 codecImage->alphaType(),
Brian Osman13dddce2017-05-09 13:19:50 -0400802 std::move(texColorSpace));
803 return SkImage::MakeFromGenerator(std::move(gen));
804}
805
Brian Osman584b5012018-04-13 15:48:26 -0400806sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context,
807 const SkPixmap& originalPixmap, bool buildMips,
808 SkColorSpace* dstColorSpace,
809 bool limitToMaxTextureSize) {
Brian Osman63bc48d2017-11-07 10:37:00 -0500810 // Some backends or drivers don't support (safely) moving resources between contexts
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400811 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
Brian Osman584b5012018-04-13 15:48:26 -0400812 return SkImage::MakeRasterCopy(originalPixmap);
Brian Osman63bc48d2017-11-07 10:37:00 -0500813 }
814
Greg Daniel9e788112018-02-08 14:29:37 -0500815 // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not
816 // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy
817 // instead.
818 if (!context->contextPriv().resourceProvider()) {
Brian Osman584b5012018-04-13 15:48:26 -0400819 return SkImage::MakeRasterCopy(originalPixmap);
Greg Daniel9e788112018-02-08 14:29:37 -0500820 }
821
Brian Osman584b5012018-04-13 15:48:26 -0400822 const SkPixmap* pixmap = &originalPixmap;
823 SkAutoPixmapStorage resized;
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400824 int maxTextureSize = context->contextPriv().caps()->maxTextureSize();
Brian Osman584b5012018-04-13 15:48:26 -0400825 int maxDim = SkTMax(originalPixmap.width(), originalPixmap.height());
826 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
827 float scale = static_cast<float>(maxTextureSize) / maxDim;
828 int newWidth = SkTMin(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
829 int newHeight = SkTMin(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
830 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
831 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) {
832 return nullptr;
833 }
834 pixmap = &resized;
835 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500836 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
Brian Osman63bc48d2017-11-07 10:37:00 -0500837 // Turn the pixmap into a GrTextureProxy
838 sk_sp<GrTextureProxy> proxy;
839 if (buildMips) {
840 SkBitmap bmp;
Brian Osman584b5012018-04-13 15:48:26 -0400841 bmp.installPixels(*pixmap);
Brian Osman2b23c4b2018-06-01 12:25:08 -0400842 proxy = proxyProvider->createMipMapProxyFromBitmap(bmp);
Brian Osman63bc48d2017-11-07 10:37:00 -0500843 } else {
Brian Osman2b23c4b2018-06-01 12:25:08 -0400844 if (SkImageInfoIsValid(pixmap->info())) {
Brian Osman584b5012018-04-13 15:48:26 -0400845 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap->width(), pixmap->height());
Greg Danielabadbee2018-03-20 12:09:09 -0400846 // We don't need a release proc on the data in pixmap since we know we are in a
847 // GrContext that has a resource provider. Thus the createTextureProxy call will
848 // immediately upload the data.
Brian Osman584b5012018-04-13 15:48:26 -0400849 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
Greg Danielabadbee2018-03-20 12:09:09 -0400850 proxy = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
851 SkBudgeted::kYes, SkBackingFit::kExact);
Greg Danielbc54fad2018-02-09 16:40:32 -0500852 }
Brian Osman63bc48d2017-11-07 10:37:00 -0500853 }
854
855 if (!proxy) {
Brian Osman584b5012018-04-13 15:48:26 -0400856 return SkImage::MakeRasterCopy(*pixmap);
Brian Osman63bc48d2017-11-07 10:37:00 -0500857 }
858
859 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
860
861 // Flush any writes or uploads
862 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500863 GrGpu* gpu = context->contextPriv().getGpu();
Brian Osman63bc48d2017-11-07 10:37:00 -0500864
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500865 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman63bc48d2017-11-07 10:37:00 -0500866
867 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
Brian Osman584b5012018-04-13 15:48:26 -0400868 std::move(sema), pixmap->colorType(),
869 pixmap->alphaType(),
870 pixmap->info().refColorSpace());
Brian Osman63bc48d2017-11-07 10:37:00 -0500871 return SkImage::MakeFromGenerator(std::move(gen));
872}
873
Derek Sollenberger7a869872017-06-27 15:37:25 -0400874#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
Stan Iliev7e910df2017-06-02 10:29:21 -0400875sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
876 sk_sp<SkColorSpace> cs) {
877 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
878 return SkImage::MakeFromGenerator(std::move(gen));
879}
880#endif
881
reed56179002015-07-07 06:11:19 -0700882///////////////////////////////////////////////////////////////////////////////////////////////////
883
Eric Karl914a36b2017-10-12 12:44:50 -0700884bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
885 sk_sp<SkImage> image,
886 GrBackendTexture* backendTexture,
887 BackendTextureReleaseProc* releaseProc) {
888 if (!image || !ctx || !backendTexture || !releaseProc) {
889 return false;
890 }
891
892 // Ensure we have a texture backed image.
893 if (!image->isTextureBacked()) {
894 image = image->makeTextureImage(ctx, nullptr);
895 if (!image) {
896 return false;
897 }
898 }
899 GrTexture* texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -0800900 if (!texture) {
901 // In context-loss cases, we may not have a texture.
902 return false;
903 }
Eric Karl914a36b2017-10-12 12:44:50 -0700904
905 // If the image's context doesn't match the provided context, fail.
906 if (texture->getContext() != ctx) {
907 return false;
908 }
909
910 // Flush any pending IO on the texture.
911 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
912 SkASSERT(!texture->surfacePriv().hasPendingIO());
913
914 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
915 // image is not unique, or if the texture wraps an external object.
916 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
917 texture->resourcePriv().refsWrappedObjects()) {
918 // onMakeSubset will always copy the image.
919 image = as_IB(image)->onMakeSubset(image->bounds());
920 if (!image) {
921 return false;
922 }
923
924 texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -0800925 if (!texture) {
926 return false;
927 }
Eric Karl914a36b2017-10-12 12:44:50 -0700928
929 // Flush to ensure that the copy is completed before we return the texture.
930 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
931 SkASSERT(!texture->surfacePriv().hasPendingIO());
932 }
933
934 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
935 SkASSERT(texture->surfacePriv().hasUniqueRef());
936 SkASSERT(image->unique());
937
938 // Take a reference to the GrTexture and release the image.
939 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
940 image = nullptr;
941
942 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
943 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
944}
945
946///////////////////////////////////////////////////////////////////////////////////////////////////
947
Brian Osmanb62f50c2018-07-12 14:44:27 -0400948sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType) const {
Matt Sarettd3df9ec2017-06-05 10:45:30 -0400949 sk_sp<SkColorSpace> srcSpace = fColorSpace;
950 if (!fColorSpace) {
951 if (target->isSRGB()) {
952 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
953 }
954
955 srcSpace = SkColorSpace::MakeSRGB();
956 }
957
Brian Osman47c27512018-06-18 10:58:51 -0400958 auto xform = GrColorSpaceXformEffect::Make(srcSpace.get(), target.get());
Brian Osman63954c92017-03-14 12:07:12 -0400959 if (!xform) {
960 return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
961 }
962
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500963 sk_sp<GrRenderTargetContext> renderTargetContext(
964 fContext->contextPriv().makeDeferredRenderTargetContext(
965 SkBackingFit::kExact, this->width(), this->height(),
966 kRGBA_8888_GrPixelConfig, nullptr));
Brian Osman63954c92017-03-14 12:07:12 -0400967 if (!renderTargetContext) {
968 return nullptr;
969 }
970
971 GrPaint paint;
972 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Osman2240be92017-10-18 13:15:13 -0400973 paint.addColorTextureProcessor(fProxy, SkMatrix::I());
Brian Osman63954c92017-03-14 12:07:12 -0400974 paint.addColorFragmentProcessor(std::move(xform));
975
976 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
977
978 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
979
Robert Phillips7ee385e2017-03-30 08:02:11 -0400980 if (!renderTargetContext->asTextureProxy()) {
Brian Osman63954c92017-03-14 12:07:12 -0400981 return nullptr;
982 }
983
984 // MDB: this call is okay bc we know 'renderTargetContext' was exact
985 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
986 fAlphaType, renderTargetContext->asTextureProxyRef(),
Matt Sarettd3df9ec2017-06-05 10:45:30 -0400987 std::move(target), fBudgeted);
Brian Osman63954c92017-03-14 12:07:12 -0400988
989}
Brian Osman5bbd0762017-05-08 11:07:42 -0400990
991bool SkImage_Gpu::onIsValid(GrContext* context) const {
992 // The base class has already checked that context isn't abandoned (if it's not nullptr)
Khushalc421ca12018-06-26 14:38:34 -0700993 if (fContext->abandoned()) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400994 return false;
995 }
996
Brian Salomon8a8dd332018-05-24 14:08:31 -0400997 if (context && context != fContext.get()) {
Brian Osman5bbd0762017-05-08 11:07:42 -0400998 return false;
999 }
1000
1001 return true;
1002}