1 /*
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
8 #include <cstddef>
9 #include <cstring>
10 #include <type_traits>
11
12 #include "GrAHardwareBufferImageGenerator.h"
13 #include "GrBackendSurface.h"
14 #include "GrBackendTextureImageGenerator.h"
15 #include "GrBitmapTextureMaker.h"
16 #include "GrCaps.h"
17 #include "GrClip.h"
18 #include "GrColorSpaceXform.h"
19 #include "GrContext.h"
20 #include "GrContextPriv.h"
21 #include "GrGpu.h"
22 #include "GrImageTextureMaker.h"
23 #include "GrProxyProvider.h"
24 #include "GrRenderTargetContext.h"
25 #include "GrResourceProvider.h"
26 #include "GrResourceProviderPriv.h"
27 #include "GrSemaphore.h"
28 #include "GrSurfacePriv.h"
29 #include "GrTexture.h"
30 #include "GrTextureAdjuster.h"
31 #include "GrTexturePriv.h"
32 #include "GrTextureProxy.h"
33 #include "GrTextureProxyPriv.h"
34 #include "SkAutoPixmapStorage.h"
35 #include "SkBitmapCache.h"
36 #include "SkCanvas.h"
37 #include "SkGr.h"
38 #include "SkImageInfoPriv.h"
39 #include "SkImage_Gpu.h"
40 #include "SkMipMap.h"
41 #include "SkScopeExit.h"
42 #include "SkTraceEvent.h"
43 #include "effects/GrYUVtoRGBEffect.h"
44 #include "gl/GrGLTexture.h"
45
SkImage_Gpu(sk_sp<GrContext> context,uint32_t uniqueID,SkAlphaType at,sk_sp<GrTextureProxy> proxy,sk_sp<SkColorSpace> colorSpace)46 SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
47 sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace)
48 : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID,
49 at, colorSpace)
50 , fProxy(std::move(proxy)) {}
51
~SkImage_Gpu()52 SkImage_Gpu::~SkImage_Gpu() {}
53
onImageInfo() const54 SkImageInfo SkImage_Gpu::onImageInfo() const {
55 SkColorType colorType;
56 if (!GrPixelConfigToColorType(fProxy->config(), &colorType)) {
57 colorType = kUnknown_SkColorType;
58 }
59
60 return SkImageInfo::Make(fProxy->width(), fProxy->height(), colorType, fAlphaType, fColorSpace);
61 }
62
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS) const63 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(SkColorType targetCT,
64 sk_sp<SkColorSpace> targetCS) const {
65 auto xform = GrColorSpaceXformEffect::Make(fColorSpace.get(), fAlphaType,
66 targetCS.get(), fAlphaType);
67 SkASSERT(xform || targetCT != this->colorType());
68
69 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef();
70
71 GrBackendFormat format = proxy->backendFormat().makeTexture2D();
72 if (!format.isValid()) {
73 return nullptr;
74 }
75
76 sk_sp<GrRenderTargetContext> renderTargetContext(
77 fContext->contextPriv().makeDeferredRenderTargetContextWithFallback(
78 format, SkBackingFit::kExact, this->width(), this->height(),
79 SkColorType2GrPixelConfig(targetCT), nullptr));
80 if (!renderTargetContext) {
81 return nullptr;
82 }
83
84 GrPaint paint;
85 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
86 paint.addColorTextureProcessor(std::move(proxy), SkMatrix::I());
87 if (xform) {
88 paint.addColorFragmentProcessor(std::move(xform));
89 }
90
91 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
92 SkRect::MakeIWH(this->width(), this->height()));
93 if (!renderTargetContext->asTextureProxy()) {
94 return nullptr;
95 }
96
97 // MDB: this call is okay bc we know 'renderTargetContext' was exact
98 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, fAlphaType,
99 renderTargetContext->asTextureProxyRef(), std::move(targetCS));
100 }
101
102 ///////////////////////////////////////////////////////////////////////////////////////////////////
103
new_wrapped_texture_common(GrContext * ctx,const GrBackendTexture & backendTex,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,GrWrapOwnership ownership,SkImage::TextureReleaseProc releaseProc,SkImage::ReleaseContext releaseCtx)104 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
105 const GrBackendTexture& backendTex,
106 GrSurfaceOrigin origin,
107 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
108 GrWrapOwnership ownership,
109 SkImage::TextureReleaseProc releaseProc,
110 SkImage::ReleaseContext releaseCtx) {
111 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
112 return nullptr;
113 }
114
115 GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
116 sk_sp<GrTextureProxy> proxy =
117 proxyProvider->wrapBackendTexture(backendTex, origin, ownership, GrWrapCacheable::kNo,
118 kRead_GrIOType, releaseProc, releaseCtx);
119 if (!proxy) {
120 return nullptr;
121 }
122 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy),
123 std::move(colorSpace));
124 }
125
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)126 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
127 const GrBackendTexture& tex, GrSurfaceOrigin origin,
128 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
129 TextureReleaseProc releaseP, ReleaseContext releaseC) {
130 if (!ctx) {
131 return nullptr;
132 }
133 GrBackendTexture texCopy = tex;
134 if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
135 return nullptr;
136 }
137 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
138 kBorrow_GrWrapOwnership, releaseP, releaseC);
139 }
140
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)141 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
142 const GrBackendTexture& tex, GrSurfaceOrigin origin,
143 SkColorType ct, SkAlphaType at,
144 sk_sp<SkColorSpace> cs) {
145 if (!ctx || !ctx->contextPriv().resourceProvider()) {
146 // We have a DDL context and we don't support adopted textures for them.
147 return nullptr;
148 }
149 GrBackendTexture texCopy = tex;
150 if (!SkImage_GpuBase::ValidateBackendTexture(ctx, texCopy, &texCopy.fConfig, ct, at, cs)) {
151 return nullptr;
152 }
153 return new_wrapped_texture_common(ctx, texCopy, origin, at, std::move(cs),
154 kAdopt_GrWrapOwnership, nullptr, nullptr);
155 }
156
MakeFromCompressed(GrContext * context,sk_sp<SkData> data,int width,int height,CompressionType type)157 sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
158 int width, int height, CompressionType type) {
159 // create the backing texture
160 GrSurfaceDesc desc;
161 desc.fFlags = kNone_GrSurfaceFlags;
162 desc.fWidth = width;
163 desc.fHeight = height;
164 switch (type) {
165 case kETC1_CompressionType:
166 desc.fConfig = kRGB_ETC1_GrPixelConfig;
167 break;
168 default:
169 desc.fConfig = kUnknown_GrPixelConfig;
170 break;
171 }
172 desc.fSampleCnt = 1;
173
174 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
175 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(std::move(data), desc);
176
177 if (!proxy) {
178 return nullptr;
179 }
180
181 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
182 std::move(proxy), nullptr);
183 }
184
ConvertYUVATexturesToRGB(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize size,GrSurfaceOrigin origin,GrRenderTargetContext * renderTargetContext)185 sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
186 const GrBackendTexture yuvaTextures[],
187 const SkYUVAIndex yuvaIndices[4], SkISize size,
188 GrSurfaceOrigin origin,
189 GrRenderTargetContext* renderTargetContext) {
190 SkASSERT(renderTargetContext);
191
192 int numTextures;
193 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
194 return nullptr;
195 }
196
197 sk_sp<GrTextureProxy> tempTextureProxies[4];
198 if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
199 origin, tempTextureProxies)) {
200 return nullptr;
201 }
202
203 const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
204 if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace,
205 tempTextureProxies, yuvaIndices)) {
206 return nullptr;
207 }
208
209 SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices);
210 // MDB: this call is okay bc we know 'renderTargetContext' was exact
211 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at,
212 renderTargetContext->asTextureProxyRef(),
213 renderTargetContext->colorSpaceInfo().refColorSpace());
214 }
215
MakeFromYUVATexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)216 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* ctx,
217 SkYUVColorSpace yuvColorSpace,
218 const GrBackendTexture yuvaTextures[],
219 const SkYUVAIndex yuvaIndices[4],
220 SkISize imageSize,
221 GrSurfaceOrigin imageOrigin,
222 sk_sp<SkColorSpace> imageColorSpace) {
223 const int width = imageSize.width();
224 const int height = imageSize.height();
225
226 const GrBackendFormat format =
227 ctx->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
228
229 // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
230 sk_sp<GrRenderTargetContext> renderTargetContext(
231 ctx->contextPriv().makeDeferredRenderTargetContext(
232 format, SkBackingFit::kExact, width, height, kRGBA_8888_GrPixelConfig,
233 std::move(imageColorSpace), 1, GrMipMapped::kNo, imageOrigin));
234 if (!renderTargetContext) {
235 return nullptr;
236 }
237
238 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
239 imageSize, imageOrigin, renderTargetContext.get());
240 }
241
MakeFromYUVATexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace)242 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
243 GrContext* ctx,
244 SkYUVColorSpace yuvColorSpace,
245 const GrBackendTexture yuvaTextures[],
246 const SkYUVAIndex yuvaIndices[4],
247 SkISize imageSize,
248 GrSurfaceOrigin imageOrigin,
249 const GrBackendTexture& backendTexture,
250 sk_sp<SkColorSpace> imageColorSpace) {
251 GrBackendTexture backendTextureCopy = backendTexture;
252
253 SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices);
254 if (!SkImage_Gpu::ValidateBackendTexture(ctx, backendTextureCopy, &backendTextureCopy.fConfig,
255 kRGBA_8888_SkColorType, at, nullptr)) {
256 return nullptr;
257 }
258
259 // Needs to create a render target with external texture
260 // in order to draw to it for the yuv->rgb conversion.
261 sk_sp<GrRenderTargetContext> renderTargetContext(
262 ctx->contextPriv().makeBackendTextureRenderTargetContext(backendTextureCopy,
263 imageOrigin, 1,
264 std::move(imageColorSpace)));
265
266 if (!renderTargetContext) {
267 return nullptr;
268 }
269
270 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
271 imageSize, imageOrigin, renderTargetContext.get());
272 }
273
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvTextures[3],GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)274 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
275 const GrBackendTexture yuvTextures[3],
276 GrSurfaceOrigin imageOrigin,
277 sk_sp<SkColorSpace> imageColorSpace) {
278 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
279 SkYUVAIndex yuvaIndices[4] = {
280 SkYUVAIndex{0, SkColorChannel::kR},
281 SkYUVAIndex{1, SkColorChannel::kR},
282 SkYUVAIndex{2, SkColorChannel::kR},
283 SkYUVAIndex{-1, SkColorChannel::kA}};
284 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
285 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, yuvTextures, yuvaIndices,
286 size, imageOrigin, std::move(imageColorSpace));
287 }
288
MakeFromYUVTexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvTextures[3],GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace)289 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
290 GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
291 GrSurfaceOrigin imageOrigin, const GrBackendTexture& backendTexture,
292 sk_sp<SkColorSpace> imageColorSpace) {
293 SkYUVAIndex yuvaIndices[4] = {
294 SkYUVAIndex{0, SkColorChannel::kR},
295 SkYUVAIndex{1, SkColorChannel::kR},
296 SkYUVAIndex{2, SkColorChannel::kR},
297 SkYUVAIndex{-1, SkColorChannel::kA}};
298 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
299 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
300 ctx, yuvColorSpace, yuvTextures, yuvaIndices, size, imageOrigin, backendTexture,
301 std::move(imageColorSpace));
302 }
303
MakeFromNV12TexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture nv12Textures[2],GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)304 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
305 const GrBackendTexture nv12Textures[2],
306 GrSurfaceOrigin imageOrigin,
307 sk_sp<SkColorSpace> imageColorSpace) {
308 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
309 SkYUVAIndex yuvaIndices[4] = {
310 SkYUVAIndex{0, SkColorChannel::kR},
311 SkYUVAIndex{1, SkColorChannel::kR},
312 SkYUVAIndex{1, SkColorChannel::kG},
313 SkYUVAIndex{-1, SkColorChannel::kA}};
314 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
315 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, nv12Textures, yuvaIndices,
316 size, imageOrigin, std::move(imageColorSpace));
317 }
318
MakeFromNV12TexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture nv12Textures[2],GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace)319 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
320 GrContext* ctx,
321 SkYUVColorSpace yuvColorSpace,
322 const GrBackendTexture nv12Textures[2],
323 GrSurfaceOrigin imageOrigin,
324 const GrBackendTexture& backendTexture,
325 sk_sp<SkColorSpace> imageColorSpace) {
326 SkYUVAIndex yuvaIndices[4] = {
327 SkYUVAIndex{0, SkColorChannel::kR},
328 SkYUVAIndex{1, SkColorChannel::kR},
329 SkYUVAIndex{1, SkColorChannel::kG},
330 SkYUVAIndex{-1, SkColorChannel::kA}};
331 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
332 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
333 ctx, yuvColorSpace, nv12Textures, yuvaIndices, size, imageOrigin, backendTexture,
334 std::move(imageColorSpace));
335 }
336
create_image_from_producer(GrContext * context,GrTextureProducer * producer,SkAlphaType at,uint32_t id,GrMipMapped mipMapped)337 static sk_sp<SkImage> create_image_from_producer(GrContext* context, GrTextureProducer* producer,
338 SkAlphaType at, uint32_t id,
339 GrMipMapped mipMapped) {
340 sk_sp<GrTextureProxy> proxy(producer->refTextureProxy(mipMapped));
341 if (!proxy) {
342 return nullptr;
343 }
344 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), id, at, std::move(proxy),
345 sk_ref_sp(producer->colorSpace()));
346 }
347
makeTextureImage(GrContext * context,SkColorSpace * dstColorSpace,GrMipMapped mipMapped) const348 sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
349 GrMipMapped mipMapped) const {
350 if (!context) {
351 return nullptr;
352 }
353 if (uint32_t incumbentID = as_IB(this)->contextID()) {
354 if (incumbentID != context->contextPriv().contextID()) {
355 return nullptr;
356 }
357 sk_sp<GrTextureProxy> proxy = as_IB(this)->asTextureProxyRef();
358 SkASSERT(proxy);
359 if (GrMipMapped::kNo == mipMapped || proxy->mipMapped() == mipMapped) {
360 return sk_ref_sp(const_cast<SkImage*>(this));
361 }
362 GrTextureAdjuster adjuster(context, std::move(proxy), this->alphaType(),
363 this->uniqueID(), this->colorSpace());
364 return create_image_from_producer(context, &adjuster, this->alphaType(),
365 this->uniqueID(), mipMapped);
366 }
367
368 if (this->isLazyGenerated()) {
369 GrImageTextureMaker maker(context, this, kDisallow_CachingHint);
370 return create_image_from_producer(context, &maker, this->alphaType(),
371 this->uniqueID(), mipMapped);
372 }
373
374 if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
375 GrBitmapTextureMaker maker(context, *bmp);
376 return create_image_from_producer(context, &maker, this->alphaType(),
377 this->uniqueID(), mipMapped);
378 }
379 return nullptr;
380 }
381
382 ///////////////////////////////////////////////////////////////////////////////////////////////////
383
MakePromiseTexture(GrContext * context,const GrBackendFormat & backendFormat,int width,int height,GrMipMapped mipMapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureDoneProc textureDoneProc,PromiseImageTextureContext textureContext,DelayReleaseCallback delayReleaseCallback)384 sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
385 const GrBackendFormat& backendFormat,
386 int width,
387 int height,
388 GrMipMapped mipMapped,
389 GrSurfaceOrigin origin,
390 SkColorType colorType,
391 SkAlphaType alphaType,
392 sk_sp<SkColorSpace> colorSpace,
393 PromiseImageTextureFulfillProc textureFulfillProc,
394 PromiseImageTextureReleaseProc textureReleaseProc,
395 PromiseImageTextureDoneProc textureDoneProc,
396 PromiseImageTextureContext textureContext,
397 DelayReleaseCallback delayReleaseCallback) {
398 // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
399 // even if creation of the SkImage fails. Once we call MakePromiseImageLazyProxy it takes
400 // responsibility for calling the done proc.
401 if (!textureDoneProc) {
402 return nullptr;
403 }
404 SkScopeExit callDone([textureDoneProc, textureContext]() { textureDoneProc(textureContext); });
405
406 SkImageInfo info = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
407 if (!SkImageInfoIsValid(info)) {
408 return nullptr;
409 }
410
411 if (!context) {
412 return nullptr;
413 }
414
415 if (width <= 0 || height <= 0) {
416 return nullptr;
417 }
418
419 GrPixelConfig config =
420 context->contextPriv().caps()->getConfigFromBackendFormat(backendFormat, colorType);
421 if (config == kUnknown_GrPixelConfig) {
422 return nullptr;
423 }
424
425 callDone.clear();
426 auto proxy = MakePromiseImageLazyProxy(context, width, height, origin, config, backendFormat,
427 mipMapped, textureFulfillProc, textureReleaseProc,
428 textureDoneProc, textureContext, delayReleaseCallback);
429 if (!proxy) {
430 return nullptr;
431 }
432 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, alphaType,
433 std::move(proxy), std::move(colorSpace));
434 }
435
436 ///////////////////////////////////////////////////////////////////////////////////////////////////
437
MakeCrossContextFromEncoded(GrContext * context,sk_sp<SkData> encoded,bool buildMips,SkColorSpace * dstColorSpace,bool limitToMaxTextureSize)438 sk_sp<SkImage> SkImage::MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> encoded,
439 bool buildMips, SkColorSpace* dstColorSpace,
440 bool limitToMaxTextureSize) {
441 sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded));
442 if (!codecImage) {
443 return nullptr;
444 }
445
446 // Some backends or drivers don't support (safely) moving resources between contexts
447 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
448 return codecImage;
449 }
450
451 auto maxTextureSize = context->contextPriv().caps()->maxTextureSize();
452 if (limitToMaxTextureSize &&
453 (codecImage->width() > maxTextureSize || codecImage->height() > maxTextureSize)) {
454 SkAutoPixmapStorage pmap;
455 SkImageInfo info = as_IB(codecImage)->onImageInfo();
456 if (!dstColorSpace) {
457 info = info.makeColorSpace(nullptr);
458 }
459 if (!pmap.tryAlloc(info) || !codecImage->readPixels(pmap, 0, 0, kDisallow_CachingHint)) {
460 return nullptr;
461 }
462 return MakeCrossContextFromPixmap(context, pmap, buildMips, dstColorSpace, true);
463 }
464
465 // Turn the codec image into a GrTextureProxy
466 GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
467 GrSamplerState samplerState(
468 GrSamplerState::WrapMode::kClamp,
469 buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
470 sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(samplerState, nullptr));
471 if (!proxy) {
472 return codecImage;
473 }
474
475 if (!proxy->instantiate(context->contextPriv().resourceProvider())) {
476 return codecImage;
477 }
478 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
479
480 // Flush any writes or uploads
481 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
482
483 GrGpu* gpu = context->contextPriv().getGpu();
484 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
485
486 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
487 std::move(sema),
488 as_IB(codecImage)->onImageInfo().colorType(),
489 codecImage->alphaType(),
490 codecImage->refColorSpace());
491 return SkImage::MakeFromGenerator(std::move(gen));
492 }
493
MakeCrossContextFromPixmap(GrContext * context,const SkPixmap & originalPixmap,bool buildMips,SkColorSpace * dstColorSpace,bool limitToMaxTextureSize)494 sk_sp<SkImage> SkImage::MakeCrossContextFromPixmap(GrContext* context,
495 const SkPixmap& originalPixmap, bool buildMips,
496 SkColorSpace* dstColorSpace,
497 bool limitToMaxTextureSize) {
498 // Some backends or drivers don't support (safely) moving resources between contexts
499 if (!context || !context->contextPriv().caps()->crossContextTextureSupport()) {
500 return SkImage::MakeRasterCopy(originalPixmap);
501 }
502
503 // If we don't have access to the resource provider and gpu (i.e. in a DDL context) we will not
504 // be able to make everything needed for a GPU CrossContext image. Thus return a raster copy
505 // instead.
506 if (!context->contextPriv().resourceProvider()) {
507 return SkImage::MakeRasterCopy(originalPixmap);
508 }
509
510 const SkPixmap* pixmap = &originalPixmap;
511 SkAutoPixmapStorage resized;
512 int maxTextureSize = context->contextPriv().caps()->maxTextureSize();
513 int maxDim = SkTMax(originalPixmap.width(), originalPixmap.height());
514 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
515 float scale = static_cast<float>(maxTextureSize) / maxDim;
516 int newWidth = SkTMin(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
517 int newHeight = SkTMin(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
518 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
519 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, kLow_SkFilterQuality)) {
520 return nullptr;
521 }
522 pixmap = &resized;
523 }
524 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
525 // Turn the pixmap into a GrTextureProxy
526 sk_sp<GrTextureProxy> proxy;
527 if (buildMips) {
528 SkBitmap bmp;
529 bmp.installPixels(*pixmap);
530 proxy = proxyProvider->createMipMapProxyFromBitmap(bmp);
531 } else {
532 if (SkImageInfoIsValid(pixmap->info())) {
533 ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap->width(), pixmap->height());
534 // We don't need a release proc on the data in pixmap since we know we are in a
535 // GrContext that has a resource provider. Thus the createTextureProxy call will
536 // immediately upload the data.
537 sk_sp<SkImage> image = SkImage::MakeFromRaster(*pixmap, nullptr, nullptr);
538 proxy = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
539 SkBudgeted::kYes, SkBackingFit::kExact);
540 }
541 }
542
543 if (!proxy) {
544 return SkImage::MakeRasterCopy(*pixmap);
545 }
546
547 sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
548
549 // Flush any writes or uploads
550 context->contextPriv().prepareSurfaceForExternalIO(proxy.get());
551 GrGpu* gpu = context->contextPriv().getGpu();
552
553 sk_sp<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
554
555 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture), proxy->origin(),
556 std::move(sema), pixmap->colorType(),
557 pixmap->alphaType(),
558 pixmap->info().refColorSpace());
559 return SkImage::MakeFromGenerator(std::move(gen));
560 }
561
562 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
MakeFromAHardwareBuffer(AHardwareBuffer * graphicBuffer,SkAlphaType at,sk_sp<SkColorSpace> cs,GrSurfaceOrigin surfaceOrigin)563 sk_sp<SkImage> SkImage::MakeFromAHardwareBuffer(AHardwareBuffer* graphicBuffer, SkAlphaType at,
564 sk_sp<SkColorSpace> cs,
565 GrSurfaceOrigin surfaceOrigin) {
566 auto gen = GrAHardwareBufferImageGenerator::Make(graphicBuffer, at, cs, surfaceOrigin);
567 return SkImage::MakeFromGenerator(std::move(gen));
568 }
569 #endif
570
571 ///////////////////////////////////////////////////////////////////////////////////////////////////
572
MakeBackendTextureFromSkImage(GrContext * ctx,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)573 bool SkImage::MakeBackendTextureFromSkImage(GrContext* ctx,
574 sk_sp<SkImage> image,
575 GrBackendTexture* backendTexture,
576 BackendTextureReleaseProc* releaseProc) {
577 if (!image || !ctx || !backendTexture || !releaseProc) {
578 return false;
579 }
580
581 // Ensure we have a texture backed image.
582 if (!image->isTextureBacked()) {
583 image = image->makeTextureImage(ctx, nullptr);
584 if (!image) {
585 return false;
586 }
587 }
588 GrTexture* texture = image->getTexture();
589 if (!texture) {
590 // In context-loss cases, we may not have a texture.
591 return false;
592 }
593
594 // If the image's context doesn't match the provided context, fail.
595 if (texture->getContext() != ctx) {
596 return false;
597 }
598
599 // Flush any pending IO on the texture.
600 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
601 SkASSERT(!texture->surfacePriv().hasPendingIO());
602
603 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
604 // image is not unique, or if the texture wraps an external object.
605 if (!image->unique() || !texture->surfacePriv().hasUniqueRef() ||
606 texture->resourcePriv().refsWrappedObjects()) {
607 // onMakeSubset will always copy the image.
608 image = as_IB(image)->onMakeSubset(image->bounds());
609 if (!image) {
610 return false;
611 }
612
613 texture = image->getTexture();
614 if (!texture) {
615 return false;
616 }
617
618 // Flush to ensure that the copy is completed before we return the texture.
619 ctx->contextPriv().prepareSurfaceForExternalIO(as_IB(image)->peekProxy());
620 SkASSERT(!texture->surfacePriv().hasPendingIO());
621 }
622
623 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
624 SkASSERT(texture->surfacePriv().hasUniqueRef());
625 SkASSERT(image->unique());
626
627 // Take a reference to the GrTexture and release the image.
628 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
629 image = nullptr;
630
631 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
632 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
633 }
634