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