blob: a136c7b49c47f41b490265626868401913030b85 [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"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000018#include "GrContext.h"
Robert Phillipse2f7d182016-12-15 09:23:05 -050019#include "GrContextPriv.h"
Brian Osman2c2bc112017-02-28 10:02:49 -050020#include "GrGpu.h"
Brian Osman3b66ab62016-11-28 09:26:31 -050021#include "GrImageTextureMaker.h"
Robert Phillips0bd24dc2018-01-16 08:06:32 -050022#include "GrProxyProvider.h"
Brian Osman11052242016-10-27 14:47:55 -040023#include "GrRenderTargetContext.h"
Brian Osman32342f02017-03-04 08:12:46 -050024#include "GrResourceProvider.h"
Brian Osmanfe3b5162017-03-02 15:09:20 -050025#include "GrSemaphore.h"
Eric Karl914a36b2017-10-12 12:44:50 -070026#include "GrSurfacePriv.h"
Brian Osmane8e54582016-11-28 10:06:27 -050027#include "GrTextureAdjuster.h"
Robert Phillips646e4292017-06-13 12:44:56 -040028#include "GrTexture.h"
Eric Karl914a36b2017-10-12 12:44:50 -070029#include "GrTexturePriv.h"
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -050030#include "GrTextureProxy.h"
Brian Osman63954c92017-03-14 12:07:12 -040031#include "effects/GrNonlinearColorSpaceXformEffect.h"
Ethan Nicholas7461a4a2017-12-21 14:18:01 -050032#include "effects/GrYUVtoRGBEffect.h"
bsalomon993a4212015-05-29 11:37:25 -070033#include "SkCanvas.h"
reed262a71b2015-12-05 13:07:27 -080034#include "SkBitmapCache.h"
Brian Osman3b655982017-03-07 16:58:08 -050035#include "SkGr.h"
reed262a71b2015-12-05 13:07:27 -080036#include "SkImage_Gpu.h"
Brian Osman7992da32016-11-18 11:28:24 -050037#include "SkImageCacherator.h"
Matt Sarettcb6266b2017-01-17 10:48:53 -050038#include "SkImageInfoPriv.h"
ericrkb4da01d2016-06-13 11:18:14 -070039#include "SkMipMap.h"
reed6f1216a2015-08-04 08:10:13 -070040#include "SkPixelRef.h"
Matt Sarett03dd6d52017-01-23 12:15:09 -050041#include "SkReadPixelsRec.h"
bsalomon993a4212015-05-29 11:37:25 -070042
Robert Phillipsb726d582017-03-09 16:36:32 -050043SkImage_Gpu::SkImage_Gpu(GrContext* context, uint32_t uniqueID, SkAlphaType at,
44 sk_sp<GrTextureProxy> proxy,
45 sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
Robert Phillipsa108c922017-10-10 10:42:19 -040046 : INHERITED(proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID)
Robert Phillipsb726d582017-03-09 16:36:32 -050047 , fContext(context)
48 , fProxy(std::move(proxy))
49 , fAlphaType(at)
50 , fBudgeted(budgeted)
51 , fColorSpace(std::move(colorSpace))
52 , fAddedRasterVersionToCache(false) {
reedc9b5f8b2015-10-22 13:20:20 -070053}
piotaixrcef04f82014-07-14 07:48:04 -070054
reed6f1216a2015-08-04 08:10:13 -070055SkImage_Gpu::~SkImage_Gpu() {
56 if (fAddedRasterVersionToCache.load()) {
57 SkNotifyBitmapGenIDIsStale(this->uniqueID());
58 }
59}
60
brianosman396fcdb2016-07-22 06:26:11 -070061SkImageInfo SkImage_Gpu::onImageInfo() const {
62 SkColorType ct;
Robert Phillipsb726d582017-03-09 16:36:32 -050063 if (!GrPixelConfigToColorType(fProxy->config(), &ct)) {
brianosman396fcdb2016-07-22 06:26:11 -070064 ct = kUnknown_SkColorType;
65 }
Robert Phillipsb726d582017-03-09 16:36:32 -050066 return SkImageInfo::Make(fProxy->width(), fProxy->height(), ct, fAlphaType, fColorSpace);
brianosman396fcdb2016-07-22 06:26:11 -070067}
68
Brian Osman62517712017-04-26 16:26:39 -040069bool SkImage_Gpu::getROPixels(SkBitmap* dst, SkColorSpace*, CachingHint chint) const {
70 // The SkColorSpace parameter "dstColorSpace" is really just a hint about how/where the bitmap
71 // will be used. The client doesn't expect that we convert to that color space, it's intended
72 // for codec-backed images, to drive our decoding heuristic. In theory we *could* read directly
73 // into that color space (to save the client some effort in whatever they're about to do), but
74 // that would make our use of the bitmap cache incorrect (or much less efficient, assuming we
75 // rolled the dstColorSpace into the key).
Mike Reed5fa3d6d2017-03-25 09:51:00 -040076 const auto desc = SkBitmapCacheDesc::Make(this);
77 if (SkBitmapCache::Find(desc, dst)) {
reed6f1216a2015-08-04 08:10:13 -070078 SkASSERT(dst->getGenerationID() == this->uniqueID());
79 SkASSERT(dst->isImmutable());
80 SkASSERT(dst->getPixels());
81 return true;
82 }
83
Mike Reed7a542c52017-04-11 12:03:44 -040084 SkBitmapCache::RecPtr rec = nullptr;
85 SkPixmap pmap;
86 if (kAllow_CachingHint == chint) {
Brian Osman62517712017-04-26 16:26:39 -040087 rec = SkBitmapCache::Alloc(desc, this->onImageInfo(), &pmap);
Mike Reed7a542c52017-04-11 12:03:44 -040088 if (!rec) {
89 return false;
90 }
91 } else {
Brian Osman62517712017-04-26 16:26:39 -040092 if (!dst->tryAllocPixels(this->onImageInfo()) || !dst->peekPixels(&pmap)) {
Mike Reed7a542c52017-04-11 12:03:44 -040093 return false;
94 }
reed8b26b992015-05-07 15:36:17 -070095 }
Robert Phillipsb726d582017-03-09 16:36:32 -050096
Brian Salomon2084ffa2017-03-27 17:32:18 -040097 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
98 fProxy,
99 fColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500100 if (!sContext) {
101 return false;
102 }
103
Mike Reed7a542c52017-04-11 12:03:44 -0400104 if (!sContext->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), 0, 0)) {
reed8b26b992015-05-07 15:36:17 -0700105 return false;
106 }
reed6f1216a2015-08-04 08:10:13 -0700107
Mike Reed7a542c52017-04-11 12:03:44 -0400108 if (rec) {
109 SkBitmapCache::Add(std::move(rec), dst);
reed09553032015-11-23 12:32:16 -0800110 fAddedRasterVersionToCache.store(true);
111 }
reed8b26b992015-05-07 15:36:17 -0700112 return true;
113}
114
Robert Phillipsb726d582017-03-09 16:36:32 -0500115sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400116 const GrSamplerState& params,
Robert Phillipsb726d582017-03-09 16:36:32 -0500117 SkColorSpace* dstColorSpace,
118 sk_sp<SkColorSpace>* texColorSpace,
119 SkScalar scaleAdjust[2]) const {
Robert Phillips30a38ff2017-03-22 10:31:11 -0400120 if (context != fContext) {
Robert Phillipsb726d582017-03-09 16:36:32 -0500121 SkASSERT(0);
122 return nullptr;
123 }
124
Brian Osman7992da32016-11-18 11:28:24 -0500125 if (texColorSpace) {
126 *texColorSpace = this->fColorSpace;
127 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500128
Greg Danielc77085d2017-11-01 16:38:48 -0400129 GrTextureAdjuster adjuster(fContext, fProxy, this->alphaType(), this->uniqueID(),
130 this->fColorSpace.get());
Greg Daniel4faa0402017-09-29 15:21:28 -0400131 return adjuster.refTextureProxySafeForParams(params, scaleAdjust);
reed85d91782015-09-10 14:33:38 -0700132}
133
reed8b26b992015-05-07 15:36:17 -0700134static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
135 switch (info.colorType()) {
136 case kRGBA_8888_SkColorType:
137 case kBGRA_8888_SkColorType:
138 break;
139 default:
140 return; // nothing to do
141 }
142
143 // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
144 // and in either case, the alpha-byte is always in the same place, so we can safely call
145 // SkPreMultiplyColor()
146 //
147 SkColor* row = (SkColor*)pixels;
148 for (int y = 0; y < info.height(); ++y) {
149 for (int x = 0; x < info.width(); ++x) {
150 row[x] = SkPreMultiplyColor(row[x]);
151 }
152 }
153}
154
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400155GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
156 GrSurfaceOrigin* origin) const {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400157 SkASSERT(fProxy);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400158
Greg Danielf2336e42018-01-23 16:38:14 -0500159 if (!fContext->contextPriv().resourceProvider() && !fProxy->priv().isInstantiated()) {
160 // This image was created with a DDL context and cannot be instantiated. Thus we return 0
161 // here which is considered invalid for all backends.
162 return 0;
163 }
164
165 if (GrSurfaceProxy::LazyState::kNot != fProxy->lazyInstantiationState()) {
166 SkASSERT(fContext->contextPriv().resourceProvider());
167 fProxy->priv().doLazyInstantiation(fContext->contextPriv().resourceProvider());
168 if (!fProxy->priv().isInstantiated()) {
169 // We failed to instantiate the lazy proxy. Thus we return 0 here which is considered
170 // invalid for all backends.
171 return 0;
172 }
173 }
174
Robert Phillips6be756b2018-01-16 15:07:54 -0500175 if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400176 return 0;
177 }
178
179 GrTexture* texture = fProxy->priv().peekTexture();
180
181 if (texture) {
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400182 if (flushPendingGrContextIO) {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400183 fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400184 }
185 if (origin) {
Robert Phillips7ee385e2017-03-30 08:02:11 -0400186 *origin = fProxy->origin();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400187 }
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400188 return texture->getTextureHandle();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400189 }
190 return 0;
191}
192
193GrTexture* SkImage_Gpu::onGetTexture() const {
194 GrTextureProxy* proxy = this->peekProxy();
195 if (!proxy) {
196 return nullptr;
197 }
198
Robert Phillips6be756b2018-01-16 15:07:54 -0500199 if (!proxy->instantiate(fContext->contextPriv().resourceProvider())) {
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400200 return nullptr;
201 }
202
203 return proxy->priv().peekTexture();
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400204}
205
Matt Sarett03dd6d52017-01-23 12:15:09 -0500206bool SkImage_Gpu::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
reed09553032015-11-23 12:32:16 -0800207 int srcX, int srcY, CachingHint) const {
Matt Sarett03dd6d52017-01-23 12:15:09 -0500208 if (!SkImageInfoValidConversion(dstInfo, this->onImageInfo())) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500209 return false;
210 }
211
Matt Sarett03dd6d52017-01-23 12:15:09 -0500212 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, srcX, srcY);
213 if (!rec.trim(this->width(), this->height())) {
214 return false;
215 }
216
Robert Phillipsb726d582017-03-09 16:36:32 -0500217 // TODO: this seems to duplicate code in GrTextureContext::onReadPixels and
218 // GrRenderTargetContext::onReadPixels
reed8b26b992015-05-07 15:36:17 -0700219 uint32_t flags = 0;
Matt Sarett03dd6d52017-01-23 12:15:09 -0500220 if (kUnpremul_SkAlphaType == rec.fInfo.alphaType() && kPremul_SkAlphaType == fAlphaType) {
reed8b26b992015-05-07 15:36:17 -0700221 // let the GPU perform this transformation for us
Robert Phillipse78b7252017-04-06 07:59:41 -0400222 flags = GrContextPriv::kUnpremul_PixelOpsFlag;
reed8b26b992015-05-07 15:36:17 -0700223 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500224
Brian Osmana8ac9242017-09-07 10:19:08 -0400225 // This hack allows us to call makeNonTextureImage on images with arbitrary color spaces.
226 // Otherwise, we'll be unable to create a render target context.
227 // TODO: This shouldn't be necessary - we need more robust support for images (and surfaces)
228 // with arbitrary color spaces. Unfortunately, this is one spot where we go from image to
229 // surface (rather than the opposite), and our lenient image rules break our (currently) more
230 // strict surface rules.
Mike Klein98e38e22018-01-12 15:59:53 +0000231 // We treat null-dst color space as always equal to fColorSpace for this kind of read-back.
Brian Osmana8ac9242017-09-07 10:19:08 -0400232 sk_sp<SkColorSpace> surfaceColorSpace = fColorSpace;
Mike Klein98e38e22018-01-12 15:59:53 +0000233 if (!flags) {
234 if (!dstInfo.colorSpace() ||
235 SkColorSpace::Equals(fColorSpace.get(), dstInfo.colorSpace())) {
236 surfaceColorSpace = nullptr;
237 }
Brian Osmana8ac9242017-09-07 10:19:08 -0400238 }
239
Brian Salomon2084ffa2017-03-27 17:32:18 -0400240 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeWrappedSurfaceContext(
Brian Osmana8ac9242017-09-07 10:19:08 -0400241 fProxy, surfaceColorSpace);
Robert Phillipsb726d582017-03-09 16:36:32 -0500242 if (!sContext) {
reed8b26b992015-05-07 15:36:17 -0700243 return false;
244 }
Robert Phillipsb726d582017-03-09 16:36:32 -0500245
246 if (!sContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, flags)) {
247 return false;
248 }
249
reed8b26b992015-05-07 15:36:17 -0700250 // do we have to manually fix-up the alpha channel?
251 // src dst
252 // unpremul premul fix manually
253 // premul unpremul done by kUnpremul_PixelOpsFlag
254 // all other combos need to change.
255 //
256 // Should this be handled by Ganesh? todo:?
257 //
Matt Sarett03dd6d52017-01-23 12:15:09 -0500258 if (kPremul_SkAlphaType == rec.fInfo.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
259 apply_premul(rec.fInfo, rec.fPixels, rec.fRowBytes);
reed8b26b992015-05-07 15:36:17 -0700260 }
261 return true;
262}
263
reed7fb4f8b2016-03-11 04:33:52 -0800264sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
Brian Salomon63e79732017-05-15 21:23:13 -0400265 GrSurfaceDesc desc;
Robert Phillips16d8ec62017-07-27 16:16:25 -0400266 desc.fOrigin = fProxy->origin();
reed7b6945b2015-09-24 00:50:58 -0700267 desc.fWidth = subset.width();
268 desc.fHeight = subset.height();
Robert Phillips16d8ec62017-07-27 16:16:25 -0400269 desc.fConfig = fProxy->config();
reed7b6945b2015-09-24 00:50:58 -0700270
Robert Phillipsb726d582017-03-09 16:36:32 -0500271 sk_sp<GrSurfaceContext> sContext(fContext->contextPriv().makeDeferredSurfaceContext(
Robert Phillipse2f7d182016-12-15 09:23:05 -0500272 desc,
Greg Daniel65c7f662017-10-30 13:39:09 -0400273 GrMipMapped::kNo,
Robert Phillipse2f7d182016-12-15 09:23:05 -0500274 SkBackingFit::kExact,
275 fBudgeted));
276 if (!sContext) {
277 return nullptr;
278 }
279
Robert Phillipsb726d582017-03-09 16:36:32 -0500280 if (!sContext->copy(fProxy.get(), subset, SkIPoint::Make(0, 0))) {
Robert Phillipse2f7d182016-12-15 09:23:05 -0500281 return nullptr;
282 }
283
Robert Phillipsb726d582017-03-09 16:36:32 -0500284 // MDB: this call is okay bc we know 'sContext' was kExact
285 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
286 fAlphaType, sContext->asTextureProxyRef(),
Robert Phillipse2f7d182016-12-15 09:23:05 -0500287 fColorSpace, fBudgeted);
reed7b6945b2015-09-24 00:50:58 -0700288}
289
reed8b26b992015-05-07 15:36:17 -0700290///////////////////////////////////////////////////////////////////////////////////////////////////
291
Greg Daniel7ef28f32017-04-20 16:41:55 +0000292static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
293 const GrBackendTexture& backendTex,
294 GrSurfaceOrigin origin,
brianosmandddbe382016-07-20 13:55:39 -0700295 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
296 GrWrapOwnership ownership,
reed7fb4f8b2016-03-11 04:33:52 -0800297 SkImage::TextureReleaseProc releaseProc,
298 SkImage::ReleaseContext releaseCtx) {
Greg Daniel7ef28f32017-04-20 16:41:55 +0000299 if (backendTex.width() <= 0 || backendTex.height() <= 0) {
halcanary96fcdcc2015-08-27 07:41:13 -0700300 return nullptr;
reed8b26b992015-05-07 15:36:17 -0700301 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400302
Robert Phillipsadbe1322018-01-17 13:35:46 -0500303 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
304 sk_sp<GrTextureProxy> proxy = proxyProvider->createWrappedTextureProxy(
305 backendTex, origin, ownership, releaseProc, releaseCtx);
306 if (!proxy) {
Robert Phillipse201ebc2018-01-17 18:12:50 +0000307 return nullptr;
308 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500309
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400310 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500311 at, std::move(proxy), std::move(colorSpace), SkBudgeted::kNo);
bsalomon6dc6f5f2015-06-18 09:12:16 -0700312}
313
Greg Daniel94403452017-04-18 15:52:36 -0400314sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
315 const GrBackendTexture& tex, GrSurfaceOrigin origin,
316 SkAlphaType at, sk_sp<SkColorSpace> cs,
317 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500318 if (!ctx) {
319 return nullptr;
320 }
Greg Daniel7ef28f32017-04-20 16:41:55 +0000321 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kBorrow_GrWrapOwnership,
322 releaseP, releaseC);
Greg Daniel94403452017-04-18 15:52:36 -0400323}
324
Greg Danielfaa095e2017-12-19 13:15:02 -0500325bool validate_backend_texture(GrContext* ctx, const GrBackendTexture& tex, GrPixelConfig* config,
Greg Danielf5d87582017-12-18 14:48:15 -0500326 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs) {
327 // TODO: Create a SkImageColorInfo struct for color, alpha, and color space so we don't need to
328 // create a fake image info here.
329 SkImageInfo info = SkImageInfo::Make(1, 1, ct, at, cs);
330 if (!SkImageInfoIsValidAllowNumericalCS(info)) {
331 return false;
332 }
333
Greg Danielfaa095e2017-12-19 13:15:02 -0500334 return ctx->caps()->validateBackendTexture(tex, ct, config);
Greg Danielf5d87582017-12-18 14:48:15 -0500335}
336
337sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
338 const GrBackendTexture& tex, GrSurfaceOrigin origin,
339 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
340 TextureReleaseProc releaseP, ReleaseContext releaseC) {
Greg Danielfaa095e2017-12-19 13:15:02 -0500341 if (!ctx) {
342 return nullptr;
343 }
Greg Danielf5d87582017-12-18 14:48:15 -0500344 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500345 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500346 return nullptr;
347 }
348 return MakeFromTexture(ctx, texCopy, origin, at, cs, releaseP, releaseC);
349}
350
Greg Daniel94403452017-04-18 15:52:36 -0400351sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
352 const GrBackendTexture& tex, GrSurfaceOrigin origin,
353 SkAlphaType at, sk_sp<SkColorSpace> cs) {
Greg Danielf2336e42018-01-23 16:38:14 -0500354 if (!ctx->contextPriv().resourceProvider()) {
355 // We have a DDL context and we don't support adopted textures for them.
356 return nullptr;
357 }
Greg Daniel7ef28f32017-04-20 16:41:55 +0000358 return new_wrapped_texture_common(ctx, tex, origin, at, std::move(cs), kAdopt_GrWrapOwnership,
359 nullptr, nullptr);
360}
361
Greg Danielf5d87582017-12-18 14:48:15 -0500362sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
363 const GrBackendTexture& tex, GrSurfaceOrigin origin,
364 SkColorType ct, SkAlphaType at,
365 sk_sp<SkColorSpace> cs) {
366 GrBackendTexture texCopy = tex;
Greg Danielfaa095e2017-12-19 13:15:02 -0500367 if (!validate_backend_texture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
Greg Danielf5d87582017-12-18 14:48:15 -0500368 return nullptr;
369 }
370 return MakeFromAdoptedTexture(ctx, texCopy, origin, at, cs);
371}
372
Greg Daniel7ef28f32017-04-20 16:41:55 +0000373static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
374 int width, int height,
375 GrPixelConfig config,
376 GrBackendObject handle) {
Brian Salomon8fe24272017-07-07 12:56:11 -0400377 switch (backend) {
378 case kOpenGL_GrBackend: {
379 const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle);
380 return GrBackendTexture(width, height, config, *glInfo);
381 }
Mike Reedd20b5c42017-06-14 06:03:10 -0400382#ifdef SK_VULKAN
Brian Salomon8fe24272017-07-07 12:56:11 -0400383 case kVulkan_GrBackend: {
384 const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle);
385 return GrBackendTexture(width, height, *vkInfo);
386 }
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000387#endif
Brian Salomon8fe24272017-07-07 12:56:11 -0400388 case kMock_GrBackend: {
389 const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle);
390 return GrBackendTexture(width, height, config, *mockInfo);
391 }
392 default:
393 return GrBackendTexture();
394 }
Greg Daniel94403452017-04-18 15:52:36 -0400395}
396
Robert Phillipsc25db632017-12-13 09:22:45 -0500397static bool are_yuv_sizes_valid(const SkISize yuvSizes[], bool nv12) {
398 if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 ||
399 yuvSizes[1].fWidth <= 0 || yuvSizes[1].fHeight <= 0) {
400 return false;
401 }
402 if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
403 return false;
404 }
405
406 return true;
407}
408
jbaumanb445a572016-06-09 13:24:48 -0700409static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
410 bool nv12,
Robert Phillipsc25db632017-12-13 09:22:45 -0500411 const GrBackendTexture yuvBackendTextures[],
jbaumanb445a572016-06-09 13:24:48 -0700412 const SkISize yuvSizes[],
brianosmandddbe382016-07-20 13:55:39 -0700413 GrSurfaceOrigin origin,
414 sk_sp<SkColorSpace> imageColorSpace) {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500415 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
416
Robert Phillipsc25db632017-12-13 09:22:45 -0500417 if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
jbaumanb445a572016-06-09 13:24:48 -0700418 return nullptr;
419 }
420
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500421 sk_sp<GrTextureProxy> yProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[0],
422 origin);
423 sk_sp<GrTextureProxy> uProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[1],
424 origin);
Greg Daniel7ef28f32017-04-20 16:41:55 +0000425 sk_sp<GrTextureProxy> vProxy;
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500426
jbaumanb445a572016-06-09 13:24:48 -0700427 if (nv12) {
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500428 vProxy = uProxy;
jbaumanb445a572016-06-09 13:24:48 -0700429 } else {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500430 vProxy = proxyProvider->createWrappedTextureProxy(yuvBackendTextures[2], origin);
jbaumanb445a572016-06-09 13:24:48 -0700431 }
Robert Phillipsbc7a4fb2017-01-23 15:30:35 -0500432 if (!yProxy || !uProxy || !vProxy) {
halcanary96fcdcc2015-08-27 07:41:13 -0700433 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700434 }
435
robertphillipsd4c741e2016-04-28 09:55:15 -0700436 const int width = yuvSizes[0].fWidth;
437 const int height = yuvSizes[0].fHeight;
robertphillipsaa19a5f2016-04-28 06:21:55 -0700438
robertphillipsd4c741e2016-04-28 09:55:15 -0700439 // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
Robert Phillipsdd3b3f42017-04-24 10:57:28 -0400440 sk_sp<GrRenderTargetContext> renderTargetContext(ctx->makeDeferredRenderTargetContext(
Brian Salomond0d72702018-02-01 14:16:02 -0500441 SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
442 std::move(imageColorSpace), 1, GrMipMapped::kNo, origin));
Brian Osman11052242016-10-27 14:47:55 -0400443 if (!renderTargetContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700444 return nullptr;
bsalomon993a4212015-05-29 11:37:25 -0700445 }
446
447 GrPaint paint;
Mike Reed7d954ad2016-10-28 15:42:34 -0400448 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Ethan Nicholas7461a4a2017-12-21 14:18:01 -0500449 paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(yProxy, uProxy, vProxy,
450 yuvSizes, colorSpace, nv12));
bsalomon993a4212015-05-29 11:37:25 -0700451
Robert Phillipsb726d582017-03-09 16:36:32 -0500452 const SkRect rect = SkRect::MakeIWH(width, height);
robertphillipsc9a37062015-09-01 08:34:28 -0700453
Brian Salomon82f44312017-01-11 13:42:54 -0500454 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
Robert Phillipse60ad622016-11-17 10:22:48 -0500455
Robert Phillips7ee385e2017-03-30 08:02:11 -0400456 if (!renderTargetContext->asSurfaceProxy()) {
Robert Phillipse60ad622016-11-17 10:22:48 -0500457 return nullptr;
458 }
Robert Phillips7ee385e2017-03-30 08:02:11 -0400459 ctx->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());
Robert Phillipsb726d582017-03-09 16:36:32 -0500460
461 // MDB: this call is okay bc we know 'renderTargetContext' was exact
Brian Salomonf3569f02017-10-24 12:52:33 -0400462 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, kOpaque_SkAlphaType,
463 renderTargetContext->asTextureProxyRef(),
Robert Phillipsc25db632017-12-13 09:22:45 -0500464 renderTargetContext->colorSpaceInfo().refColorSpace(),
465 SkBudgeted::kYes);
466}
467
468static sk_sp<SkImage> make_from_yuv_objects_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
469 bool nv12,
470 const GrBackendObject yuvTextureHandles[],
471 const SkISize yuvSizes[],
472 GrSurfaceOrigin origin,
473 sk_sp<SkColorSpace> imageColorSpace) {
474 if (!are_yuv_sizes_valid(yuvSizes, nv12)) {
475 return nullptr;
476 }
477
478 GrBackendTexture backendTextures[3];
479
480 const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
481
482 GrBackend backend = ctx->contextPriv().getBackend();
483 backendTextures[0] = make_backend_texture_from_handle(backend,
484 yuvSizes[0].fWidth,
485 yuvSizes[0].fHeight,
486 kConfig,
487 yuvTextureHandles[0]);
488 backendTextures[1] = make_backend_texture_from_handle(backend,
489 yuvSizes[1].fWidth,
490 yuvSizes[1].fHeight,
491 kConfig,
492 yuvTextureHandles[1]);
493
494 if (!nv12) {
495 backendTextures[2] = make_backend_texture_from_handle(backend,
496 yuvSizes[2].fWidth,
497 yuvSizes[2].fHeight,
498 kConfig,
499 yuvTextureHandles[2]);
500 }
501
502 return make_from_yuv_textures_copy(ctx, colorSpace, nv12,
503 backendTextures, yuvSizes, origin,
504 std::move(imageColorSpace));
bsalomon993a4212015-05-29 11:37:25 -0700505}
reed56179002015-07-07 06:11:19 -0700506
jbaumanb445a572016-06-09 13:24:48 -0700507sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
508 const GrBackendObject yuvTextureHandles[3],
brianosmandddbe382016-07-20 13:55:39 -0700509 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
510 sk_sp<SkColorSpace> imageColorSpace) {
Robert Phillipsc25db632017-12-13 09:22:45 -0500511 return make_from_yuv_objects_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
512 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700513}
514
515sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
516 const GrBackendObject yuvTextureHandles[2],
517 const SkISize yuvSizes[2],
brianosmandddbe382016-07-20 13:55:39 -0700518 GrSurfaceOrigin origin,
519 sk_sp<SkColorSpace> imageColorSpace) {
Robert Phillipsc25db632017-12-13 09:22:45 -0500520 return make_from_yuv_objects_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
521 std::move(imageColorSpace));
522}
523
524sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
525 const GrBackendTexture yuvBackendTextures[3],
526 const SkISize yuvSizes[3], GrSurfaceOrigin origin,
527 sk_sp<SkColorSpace> imageColorSpace) {
528 return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvBackendTextures, yuvSizes, origin,
529 std::move(imageColorSpace));
530}
531
532sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
533 const GrBackendTexture yuvBackendTextures[2],
534 const SkISize yuvSizes[2],
535 GrSurfaceOrigin origin,
536 sk_sp<SkColorSpace> imageColorSpace) {
537 return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvBackendTextures, yuvSizes, origin,
brianosmandddbe382016-07-20 13:55:39 -0700538 std::move(imageColorSpace));
jbaumanb445a572016-06-09 13:24:48 -0700539}
540
Robert Phillips3798c862017-03-27 11:08:16 -0400541static sk_sp<SkImage> create_image_from_maker(GrContext* context, GrTextureMaker* maker,
542 SkAlphaType at, uint32_t id,
Brian Osman041f7df2017-02-07 11:23:28 -0500543 SkColorSpace* dstColorSpace) {
544 sk_sp<SkColorSpace> texColorSpace;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400545 sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(
546 GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr));
Robert Phillips3798c862017-03-27 11:08:16 -0400547 if (!proxy) {
Brian Osman041f7df2017-02-07 11:23:28 -0500548 return nullptr;
549 }
Robert Phillips3798c862017-03-27 11:08:16 -0400550 return sk_make_sp<SkImage_Gpu>(context, id, at,
551 std::move(proxy), std::move(texColorSpace), SkBudgeted::kNo);
Brian Osman041f7df2017-02-07 11:23:28 -0500552}
553
Brian Osman2c2bc112017-02-28 10:02:49 -0500554sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const {
Brian Osman041f7df2017-02-07 11:23:28 -0500555 if (!context) {
556 return nullptr;
557 }
Robert Phillips87444052017-06-23 14:09:30 -0400558 if (GrContext* incumbent = as_IB(this)->context()) {
559 return incumbent == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
Brian Osman041f7df2017-02-07 11:23:28 -0500560 }
561
Brian Osmandf7e0752017-04-26 16:20:28 -0400562 if (this->isLazyGenerated()) {
563 GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400564 return create_image_from_maker(context, &maker, this->alphaType(),
565 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500566 }
567
568 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
569 GrBitmapTextureMaker maker(context, *bmp);
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400570 return create_image_from_maker(context, &maker, this->alphaType(),
571 this->uniqueID(), dstColorSpace);
Brian Osman041f7df2017-02-07 11:23:28 -0500572 }
573 return nullptr;
574}
575
Brian Osman13dddce2017-05-09 13:19:50 -0400576sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
577 bool buildMips, SkColorSpace* dstColorSpace) {
578 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
579 if (!codecImage) {
580 return nullptr;
581 }
582
583 // Some backends or drivers don't support (safely) moving resources between contexts
584 if (!context || !context->caps()->crossContextTextureSupport()) {
585 return codecImage;
586 }
587
588 // Turn the codec image into a GrTextureProxy
589 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
590 sk_sp<SkColorSpace> texColorSpace;
Brian Salomon2bbdcc42017-09-07 12:36:34 -0400591 GrSamplerState samplerState(
592 GrSamplerState::WrapMode::kClamp,
593 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
594 sk_sp<GrTextureProxy> proxy(
595 maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
Brian Osman13dddce2017-05-09 13:19:50 -0400596 if (!proxy) {
597 return codecImage;
598 }
599
Robert Phillips6be756b2018-01-16 15:07:54 -0500600 if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
Brian Osman13dddce2017-05-09 13:19:50 -0400601 return codecImage;
602 }
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400603 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
Brian Osman13dddce2017-05-09 13:19:50 -0400604
605 // Flush any writes or uploads
606 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
607
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500608 GrGpu* gpu = context->contextPriv().getGpu();
609 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman13dddce2017-05-09 13:19:50 -0400610
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400611 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
Robert Phillips16d8ec62017-07-27 16:16:25 -0400612 std::move(sema), codecImage->alphaType(),
Brian Osman13dddce2017-05-09 13:19:50 -0400613 std::move(texColorSpace));
614 return SkImage::MakeFromGenerator(std::move(gen));
615}
616
Brian Osman63bc48d2017-11-07 10:37:00 -0500617sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
618 bool buildMips, SkColorSpace* dstColorSpace) {
619 // Some backends or drivers don't support (safely) moving resources between contexts
620 if (!context || !context->caps()->crossContextTextureSupport()) {
621 return SkImage::MakeRasterCopy(pixmap);
622 }
623
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500624 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
Brian Osman63bc48d2017-11-07 10:37:00 -0500625 // Turn the pixmap into a GrTextureProxy
626 sk_sp<GrTextureProxy> proxy;
627 if (buildMips) {
628 SkBitmap bmp;
629 bmp.installPixels(pixmap);
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500630 proxy = GrGenerateMipMapsAndUploadToTextureProxy(proxyProvider, bmp, dstColorSpace);
Brian Osman63bc48d2017-11-07 10:37:00 -0500631 } else {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500632 proxy = GrUploadPixmapToTextureProxy(proxyProvider, pixmap, SkBudgeted::kYes,
633 dstColorSpace);
Brian Osman63bc48d2017-11-07 10:37:00 -0500634 }
635
636 if (!proxy) {
637 return SkImage::MakeRasterCopy(pixmap);
638 }
639
640 sk_sp<GrTexture> texture = sk_ref_sp(proxy->priv().peekTexture());
641
642 // Flush any writes or uploads
643 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500644 GrGpu* gpu = context->contextPriv().getGpu();
Brian Osman63bc48d2017-11-07 10:37:00 -0500645
Robert Phillipsf35fd8d2018-01-22 10:48:15 -0500646 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
Brian Osman63bc48d2017-11-07 10:37:00 -0500647
648 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
649 std::move(sema), pixmap.alphaType(),
650 pixmap.info().refColorSpace());
651 return SkImage::MakeFromGenerator(std::move(gen));
652}
653
Derek Sollenberger7a869872017-06-27 15:37:25 -0400654#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
Stan Iliev7e910df2017-06-02 10:29:21 -0400655sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
656 sk_sp<SkColorSpace> cs) {
657 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs);
658 return SkImage::MakeFromGenerator(std::move(gen));
659}
660#endif
661
reed56179002015-07-07 06:11:19 -0700662///////////////////////////////////////////////////////////////////////////////////////////////////
663
Eric Karlaae533e2017-12-15 23:37:45 +0000664namespace {
665struct MipMapLevelData {
666 void* fPixelData;
667 size_t fRowBytes;
668};
669
670struct DeferredTextureImage {
671 uint32_t fContextUniqueID;
672 // Right now, the destination color mode is only considered when generating mipmaps
673 SkDestinationSurfaceColorMode fColorMode;
674 // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
675 int fWidth;
676 int fHeight;
677 SkColorType fColorType;
678 SkAlphaType fAlphaType;
679 void* fColorSpace;
680 size_t fColorSpaceSize;
681 int fMipMapLevelCount;
682 // The fMipMapLevelData array may contain more than 1 element.
683 // It contains fMipMapLevelCount elements.
684 // That means this struct's size is not known at compile-time.
685 MipMapLevelData fMipMapLevelData[1];
686};
687} // anonymous namespace
688
689static bool should_use_mip_maps(const SkImage::DeferredTextureImageUsageParams & param) {
690 // There is a bug in the mipmap pre-generation logic in use in getDeferredTextureImageData.
691 // This can cause runaway memory leaks, so we are disabling this path until we can
692 // investigate further. crbug.com/669775
693 return false;
694}
695
696namespace {
697
698class DTIBufferFiller
699{
700public:
701 explicit DTIBufferFiller(char* bufferAsCharPtr)
702 : bufferAsCharPtr_(bufferAsCharPtr) {}
703
704 void fillMember(const void* source, size_t memberOffset, size_t size) {
705 memcpy(bufferAsCharPtr_ + memberOffset, source, size);
706 }
707
708private:
709
710 char* bufferAsCharPtr_;
711};
712}
713
714#define FILL_MEMBER(bufferFiller, member, source) \
715 bufferFiller.fillMember(source, \
716 offsetof(DeferredTextureImage, member), \
717 sizeof(DeferredTextureImage::member));
718
719static bool SupportsColorSpace(SkColorType colorType) {
720 switch (colorType) {
721 case kRGBA_8888_SkColorType:
722 case kBGRA_8888_SkColorType:
723 case kRGBA_F16_SkColorType:
724 return true;
725 default:
726 return false;
727 }
728}
729
730size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
731 const DeferredTextureImageUsageParams params[],
732 int paramCnt, void* buffer,
733 SkColorSpace* dstColorSpace,
734 SkColorType dstColorType) const {
735 // Some quick-rejects where is makes no sense to return CPU data
736 // e.g.
737 // - texture backed
738 // - picture backed
739 //
740 if (this->isTextureBacked()) {
741 return 0;
742 }
743 if (as_IB(this)->onCanLazyGenerateOnGPU()) {
744 return 0;
745 }
746
747 bool supportsColorSpace = SupportsColorSpace(dstColorType);
748 // Quick reject if the caller requests a color space with an unsupported color type.
749 if (SkToBool(dstColorSpace) && !supportsColorSpace) {
750 return 0;
751 }
752
753 // Extract relevant min/max values from the params array.
754 int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
755 SkFilterQuality highestFilterQuality = params[0].fQuality;
756 bool useMipMaps = should_use_mip_maps(params[0]);
757 for (int i = 1; i < paramCnt; ++i) {
758 if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
759 lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
760 if (highestFilterQuality < params[i].fQuality)
761 highestFilterQuality = params[i].fQuality;
762 useMipMaps |= should_use_mip_maps(params[i]);
763 }
764
765 const bool fillMode = SkToBool(buffer);
766 if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
767 return 0;
768 }
769
770 // Calculate scaling parameters.
771 bool isScaled = lowestPreScaleMipLevel != 0;
772
773 SkISize scaledSize;
774 if (isScaled) {
775 // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
776 // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
777 scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
778 lowestPreScaleMipLevel - 1);
779 } else {
780 scaledSize = SkISize::Make(this->width(), this->height());
781 }
782
783 // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
784 SkFilterQuality scaleFilterQuality = highestFilterQuality;
785 if (scaleFilterQuality > kMedium_SkFilterQuality) {
786 scaleFilterQuality = kMedium_SkFilterQuality;
787 }
788
789 const int maxTextureSize = proxy.fCaps->maxTextureSize();
790 if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
791 return 0;
792 }
793
794 SkAutoPixmapStorage pixmap;
795 SkImageInfo info;
796 size_t pixelSize = 0;
797 if (!isScaled && this->peekPixels(&pixmap) && pixmap.info().colorType() == dstColorType) {
798 info = pixmap.info();
799 pixelSize = SkAlign8(pixmap.computeByteSize());
800 if (!dstColorSpace) {
801 pixmap.setColorSpace(nullptr);
802 info = info.makeColorSpace(nullptr);
803 }
804 } else {
805 if (!this->isLazyGenerated() && !this->peekPixels(nullptr)) {
806 return 0;
807 }
808 if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
809 // Generator backed image. Tweak info to trigger correct kind of decode.
810 SkImageCacherator::CachedFormat cacheFormat = cacher->chooseCacheFormat(
811 dstColorSpace, proxy.fCaps.get());
812 info = cacher->buildCacheInfo(cacheFormat).makeWH(scaledSize.width(),
813 scaledSize.height());
814 } else {
815 info = as_IB(this)->onImageInfo().makeWH(scaledSize.width(), scaledSize.height());
816 if (!dstColorSpace) {
817 info = info.makeColorSpace(nullptr);
818 }
819 }
820 // Force color type to be the requested type.
821 info = info.makeColorType(dstColorType);
822 pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
823 if (fillMode) {
824 // Always decode to N32 and convert to the requested type if necessary.
825 SkImageInfo decodeInfo = info.makeColorType(kN32_SkColorType);
826 SkAutoPixmapStorage decodePixmap;
827 decodePixmap.alloc(decodeInfo);
828
829 if (isScaled) {
830 if (!this->scalePixels(decodePixmap, scaleFilterQuality,
831 SkImage::kDisallow_CachingHint)) {
832 return 0;
833 }
834 } else {
835 if (!this->readPixels(decodePixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
836 return 0;
837 }
838 }
839
840 if (decodeInfo.colorType() != info.colorType()) {
841 pixmap.alloc(info);
842 // Convert and copy the decoded pixmap to the target pixmap.
843 decodePixmap.readPixels(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes(), 0,
844 0);
845 } else {
846 pixmap = std::move(decodePixmap);
847 }
848 }
849 }
850 int mipMapLevelCount = 1;
851 if (useMipMaps) {
852 // SkMipMap only deals with the mipmap levels it generates, which does
853 // not include the base level.
854 // That means it generates and holds levels 1-x instead of 0-x.
855 // So the total mipmap level count is 1 more than what
856 // SkMipMap::ComputeLevelCount returns.
857 mipMapLevelCount = SkMipMap::ComputeLevelCount(scaledSize.width(), scaledSize.height()) + 1;
858
859 // We already initialized pixelSize to the size of the base level.
860 // SkMipMap will generate the extra mipmap levels. Their sizes need to
861 // be added to the total.
862 // Index 0 here does not refer to the base mipmap level -- it is
863 // SkMipMap's first generated mipmap level (level 1).
864 for (int currentMipMapLevelIndex = mipMapLevelCount - 2; currentMipMapLevelIndex >= 0;
865 currentMipMapLevelIndex--) {
866 SkISize mipSize = SkMipMap::ComputeLevelSize(scaledSize.width(), scaledSize.height(),
867 currentMipMapLevelIndex);
868 SkImageInfo mipInfo = info.makeWH(mipSize.fWidth, mipSize.fHeight);
869 pixelSize += SkAlign8(SkAutoPixmapStorage::AllocSize(mipInfo, nullptr));
870 }
871 }
872 size_t size = 0;
873 size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
874 size += dtiSize;
875 size += (mipMapLevelCount - 1) * sizeof(MipMapLevelData);
876 // We subtract 1 because DeferredTextureImage already includes the base
877 // level in its size
878 size_t pixelOffset = size;
879 size += pixelSize;
880 size_t colorSpaceOffset = 0;
881 size_t colorSpaceSize = 0;
882 SkColorSpaceTransferFn fn;
883 if (info.colorSpace()) {
884 SkASSERT(dstColorSpace);
885 SkASSERT(supportsColorSpace);
886 colorSpaceOffset = size;
887 colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
888 size += colorSpaceSize;
889 } else if (supportsColorSpace && this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn)) {
890 // In legacy mode, preserve the color space tag on the SkImage. This is only
891 // supported if the color space has a parametric transfer function.
892 SkASSERT(!dstColorSpace);
893 colorSpaceOffset = size;
894 colorSpaceSize = this->colorSpace()->writeToMemory(nullptr);
895 size += colorSpaceSize;
896 }
897 if (!fillMode) {
898 return size;
899 }
900 char* bufferAsCharPtr = reinterpret_cast<char*>(buffer);
901 char* pixelsAsCharPtr = bufferAsCharPtr + pixelOffset;
902 void* pixels = pixelsAsCharPtr;
903
904 memcpy(reinterpret_cast<void*>(SkAlign8(reinterpret_cast<uintptr_t>(pixelsAsCharPtr))),
905 pixmap.addr(), pixmap.computeByteSize());
906
907 // If the context has sRGB support, and we're intending to render to a surface with an attached
908 // color space, and the image has an sRGB-like color space attached, then use our gamma (sRGB)
909 // aware mip-mapping.
910 SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
911 if (proxy.fCaps->srgbSupport() && SkToBool(dstColorSpace) &&
912 info.colorSpace() && info.colorSpace()->gammaCloseToSRGB()) {
913 SkASSERT(supportsColorSpace);
914 colorMode = SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware;
915 }
916
917 SkASSERT(info == pixmap.info());
918 size_t rowBytes = pixmap.rowBytes();
919 static_assert(std::is_standard_layout<DeferredTextureImage>::value,
920 "offsetof, which we use below, requires the type have standard layout");
921 auto dtiBufferFiller = DTIBufferFiller{bufferAsCharPtr};
922 FILL_MEMBER(dtiBufferFiller, fColorMode, &colorMode);
923 FILL_MEMBER(dtiBufferFiller, fContextUniqueID, &proxy.fContextUniqueID);
924 int width = info.width();
925 FILL_MEMBER(dtiBufferFiller, fWidth, &width);
926 int height = info.height();
927 FILL_MEMBER(dtiBufferFiller, fHeight, &height);
928 SkColorType colorType = info.colorType();
929 FILL_MEMBER(dtiBufferFiller, fColorType, &colorType);
930 SkAlphaType alphaType = info.alphaType();
931 FILL_MEMBER(dtiBufferFiller, fAlphaType, &alphaType);
932 FILL_MEMBER(dtiBufferFiller, fMipMapLevelCount, &mipMapLevelCount);
933 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fPixelData),
934 &pixels, sizeof(pixels));
935 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData[0].fRowBytes),
936 &rowBytes, sizeof(rowBytes));
937 if (colorSpaceSize) {
938 void* colorSpace = bufferAsCharPtr + colorSpaceOffset;
939 FILL_MEMBER(dtiBufferFiller, fColorSpace, &colorSpace);
940 FILL_MEMBER(dtiBufferFiller, fColorSpaceSize, &colorSpaceSize);
941 if (info.colorSpace()) {
942 info.colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
943 } else {
944 SkASSERT(this->colorSpace() && this->colorSpace()->isNumericalTransferFn(&fn));
945 SkASSERT(!dstColorSpace);
946 this->colorSpace()->writeToMemory(bufferAsCharPtr + colorSpaceOffset);
947 }
948 } else {
949 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpace),
950 0, sizeof(DeferredTextureImage::fColorSpace));
951 memset(bufferAsCharPtr + offsetof(DeferredTextureImage, fColorSpaceSize),
952 0, sizeof(DeferredTextureImage::fColorSpaceSize));
953 }
954
955 // Fill in the mipmap levels if they exist
956 char* mipLevelPtr = pixelsAsCharPtr + SkAlign8(pixmap.computeByteSize());
957
958 if (useMipMaps) {
959 static_assert(std::is_standard_layout<MipMapLevelData>::value,
960 "offsetof, which we use below, requires the type have a standard layout");
961
962 std::unique_ptr<SkMipMap> mipmaps(SkMipMap::Build(pixmap, colorMode, nullptr));
963 // SkMipMap holds only the mipmap levels it generates.
964 // A programmer can use the data they provided to SkMipMap::Build as level 0.
965 // So the SkMipMap provides levels 1-x but it stores them in its own
966 // range 0-(x-1).
967 for (int generatedMipLevelIndex = 0; generatedMipLevelIndex < mipMapLevelCount - 1;
968 generatedMipLevelIndex++) {
969 SkMipMap::Level mipLevel;
970 mipmaps->getLevel(generatedMipLevelIndex, &mipLevel);
971
972 // Make sure the mipmap data is after the start of the buffer
973 SkASSERT(mipLevelPtr > bufferAsCharPtr);
974 // Make sure the mipmap data starts before the end of the buffer
975 SkASSERT(mipLevelPtr < bufferAsCharPtr + pixelOffset + pixelSize);
976 // Make sure the mipmap data ends before the end of the buffer
977 SkASSERT(mipLevelPtr + mipLevel.fPixmap.computeByteSize() <=
978 bufferAsCharPtr + pixelOffset + pixelSize);
979
980 memcpy(mipLevelPtr, mipLevel.fPixmap.addr(), mipLevel.fPixmap.computeByteSize());
981
982 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
983 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
984 offsetof(MipMapLevelData, fPixelData), &mipLevelPtr, sizeof(void*));
985 size_t rowBytes = mipLevel.fPixmap.rowBytes();
986 memcpy(bufferAsCharPtr + offsetof(DeferredTextureImage, fMipMapLevelData) +
987 sizeof(MipMapLevelData) * (generatedMipLevelIndex + 1) +
988 offsetof(MipMapLevelData, fRowBytes), &rowBytes, sizeof(rowBytes));
989
990 mipLevelPtr += SkAlign8(mipLevel.fPixmap.computeByteSize());
991 }
992 }
993 return size;
994}
995
996sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
997 SkBudgeted budgeted) {
998 if (!data) {
999 return nullptr;
1000 }
1001 const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
1002
1003 if (!context || context->uniqueID() != dti->fContextUniqueID || context->abandoned()) {
1004 return nullptr;
1005 }
1006 int mipLevelCount = dti->fMipMapLevelCount;
1007 SkASSERT(mipLevelCount >= 1);
1008 sk_sp<SkColorSpace> colorSpace;
1009 if (dti->fColorSpaceSize) {
1010 colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
1011 }
1012 SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
1013 dti->fColorType, dti->fAlphaType, colorSpace);
1014 if (mipLevelCount == 1) {
1015 SkPixmap pixmap;
1016 pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData, dti->fMipMapLevelData[0].fRowBytes);
1017
1018 // Pass nullptr for the |dstColorSpace|. This opts in to more lenient color space
1019 // verification. This is ok because we've already verified the color space in
1020 // getDeferredTextureImageData().
1021 sk_sp<GrTextureProxy> proxy(GrUploadPixmapToTextureProxy(
Robert Phillips1afd4cd2018-01-08 13:40:32 -05001022 context->contextPriv().proxyProvider(), pixmap, budgeted, nullptr));
Eric Karlaae533e2017-12-15 23:37:45 +00001023 if (!proxy) {
1024 return nullptr;
1025 }
1026 return sk_make_sp<SkImage_Gpu>(context, kNeedNewImageUniqueID, pixmap.alphaType(),
1027 std::move(proxy), std::move(colorSpace), budgeted);
1028 } else {
1029 std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
1030 for (int i = 0; i < mipLevelCount; i++) {
1031 texels[i].fPixels = dti->fMipMapLevelData[i].fPixelData;
1032 texels[i].fRowBytes = dti->fMipMapLevelData[i].fRowBytes;
1033 }
1034
1035 return SkImage::MakeTextureFromMipMap(context, info, texels.get(),
1036 mipLevelCount, SkBudgeted::kYes,
1037 dti->fColorMode);
1038 }
1039}
1040
1041///////////////////////////////////////////////////////////////////////////////////////////////////
1042
Eric Karl914a36b2017-10-12 12:44:50 -07001043bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
1044 sk_sp<SkImage> image,
1045 GrBackendTexture* backendTexture,
1046 BackendTextureReleaseProc* releaseProc) {
1047 if (!image || !ctx || !backendTexture || !releaseProc) {
1048 return false;
1049 }
1050
1051 // Ensure we have a texture backed image.
1052 if (!image->isTextureBacked()) {
1053 image = image->makeTextureImage(ctx, nullptr);
1054 if (!image) {
1055 return false;
1056 }
1057 }
1058 GrTexture* texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -08001059 if (!texture) {
1060 // In context-loss cases, we may not have a texture.
1061 return false;
1062 }
Eric Karl914a36b2017-10-12 12:44:50 -07001063
1064 // If the image's context doesn't match the provided context, fail.
1065 if (texture->getContext() != ctx) {
1066 return false;
1067 }
1068
1069 // Flush any pending IO on the texture.
1070 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
1071 SkASSERT(!texture->surfacePriv().hasPendingIO());
1072
1073 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
1074 // image is not unique, or if the texture wraps an external object.
1075 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
1076 texture->resourcePriv().refsWrappedObjects()) {
1077 // onMakeSubset will always copy the image.
1078 image = as_IB(image)->onMakeSubset(image->bounds());
1079 if (!image) {
1080 return false;
1081 }
1082
1083 texture = image->getTexture();
Eric Karl36591e52018-01-19 13:45:02 -08001084 if (!texture) {
1085 return false;
1086 }
Eric Karl914a36b2017-10-12 12:44:50 -07001087
1088 // Flush to ensure that the copy is completed before we return the texture.
1089 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
1090 SkASSERT(!texture->surfacePriv().hasPendingIO());
1091 }
1092
1093 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
1094 SkASSERT(texture->surfacePriv().hasUniqueRef());
1095 SkASSERT(image->unique());
1096
1097 // Take a reference to the GrTexture and release the image.
1098 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
1099 image = nullptr;
1100
1101 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
1102 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
1103}
1104
1105///////////////////////////////////////////////////////////////////////////////////////////////////
1106
cblume186d2d42016-06-03 11:17:42 -07001107sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
Robert Phillips590533f2017-07-11 14:22:35 -04001108 const GrMipLevel texels[], int mipLevelCount,
cblume33e0cb52016-08-30 12:09:23 -07001109 SkBudgeted budgeted,
Brian Osman7b8400d2016-11-08 17:08:54 -05001110 SkDestinationSurfaceColorMode colorMode) {
Robert Phillips1119dc32017-04-11 12:54:57 -04001111 SkASSERT(mipLevelCount >= 1);
cblume186d2d42016-06-03 11:17:42 -07001112 if (!ctx) {
1113 return nullptr;
1114 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -05001115 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
1116
Greg Daniel55afd6d2017-09-29 09:32:44 -04001117 // For images where the client is passing the mip data we require that all the mip levels have
1118 // valid data.
1119 for (int i = 0; i < mipLevelCount; ++i) {
1120 if (!texels[i].fPixels) {
1121 return nullptr;
1122 }
1123 }
Robert Phillips0bd24dc2018-01-16 08:06:32 -05001124 sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(proxyProvider, info,
1125 texels, mipLevelCount, colorMode));
Robert Phillips0ae6faa2017-03-21 16:22:00 -04001126 if (!proxy) {
cblume186d2d42016-06-03 11:17:42 -07001127 return nullptr;
1128 }
Robert Phillips0ae6faa2017-03-21 16:22:00 -04001129
1130 SkASSERT(proxy->priv().isExact());
1131 return sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
1132 info.alphaType(), std::move(proxy),
1133 info.refColorSpace(), budgeted);
cblume186d2d42016-06-03 11:17:42 -07001134}
Brian Osman63954c92017-03-14 12:07:12 -04001135
Matt Sarettd3df9ec2017-06-05 10:45:30 -04001136sk_sp<SkImage> SkImage_Gpu::onMakeColorSpace(sk_sp<SkColorSpace> target, SkColorType,
Matt Sarett9f3dcb32017-05-04 08:53:32 -04001137 SkTransferFunctionBehavior premulBehavior) const {
1138 if (SkTransferFunctionBehavior::kRespect == premulBehavior) {
1139 // TODO: Implement this.
1140 return nullptr;
1141 }
1142
Matt Sarettd3df9ec2017-06-05 10:45:30 -04001143 sk_sp<SkColorSpace> srcSpace = fColorSpace;
1144 if (!fColorSpace) {
1145 if (target->isSRGB()) {
1146 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this));
1147 }
1148
1149 srcSpace = SkColorSpace::MakeSRGB();
1150 }
1151
1152 auto xform = GrNonlinearColorSpaceXformEffect::Make(srcSpace.get(), target.get());
Brian Osman63954c92017-03-14 12:07:12 -04001153 if (!xform) {
1154 return sk_ref_sp(const_cast<SkImage_Gpu*>(this));
1155 }
1156
Robert Phillipsdd3b3f42017-04-24 10:57:28 -04001157 sk_sp<GrRenderTargetContext> renderTargetContext(fContext->makeDeferredRenderTargetContext(
Brian Osman63954c92017-03-14 12:07:12 -04001158 SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig, nullptr));
1159 if (!renderTargetContext) {
1160 return nullptr;
1161 }
1162
1163 GrPaint paint;
1164 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Osman2240be92017-10-18 13:15:13 -04001165 paint.addColorTextureProcessor(fProxy, SkMatrix::I());
Brian Osman63954c92017-03-14 12:07:12 -04001166 paint.addColorFragmentProcessor(std::move(xform));
1167
1168 const SkRect rect = SkRect::MakeIWH(this->width(), this->height());
1169
1170 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);
1171
Robert Phillips7ee385e2017-03-30 08:02:11 -04001172 if (!renderTargetContext->asTextureProxy()) {
Brian Osman63954c92017-03-14 12:07:12 -04001173 return nullptr;
1174 }
1175
1176 // MDB: this call is okay bc we know 'renderTargetContext' was exact
1177 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID,
1178 fAlphaType, renderTargetContext->asTextureProxyRef(),
Matt Sarettd3df9ec2017-06-05 10:45:30 -04001179 std::move(target), fBudgeted);
Brian Osman63954c92017-03-14 12:07:12 -04001180
1181}
Brian Osman5bbd0762017-05-08 11:07:42 -04001182
1183bool SkImage_Gpu::onIsValid(GrContext* context) const {
1184 // The base class has already checked that context isn't abandoned (if it's not nullptr)
1185 if (fContext->abandoned()) {
1186 return false;
1187 }
1188
1189 if (context && context != fContext) {
1190 return false;
1191 }
1192
1193 return true;
1194}