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