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/GrImageInfo.h"
34 #include "src/gpu/GrImageTextureMaker.h"
35 #include "src/gpu/GrProxyProvider.h"
36 #include "src/gpu/GrRecordingContextPriv.h"
37 #include "src/gpu/GrRenderTargetContext.h"
38 #include "src/gpu/GrSemaphore.h"
39 #include "src/gpu/GrSurfacePriv.h"
40 #include "src/gpu/GrTextureAdjuster.h"
41 #include "src/gpu/GrTextureContext.h"
42 #include "src/gpu/GrTexturePriv.h"
43 #include "src/gpu/GrTextureProxy.h"
44 #include "src/gpu/GrTextureProxyPriv.h"
45 #include "src/gpu/SkGr.h"
46 #include "src/gpu/gl/GrGLTexture.h"
47 #include "src/image/SkImage_Gpu.h"
48
proxy_color_type(GrTextureProxy * proxy)49 static SkColorType proxy_color_type(GrTextureProxy* proxy) {
50 SkColorType colorType;
51 if (!GrPixelConfigToColorType(proxy->config(), &colorType)) {
52 colorType = kUnknown_SkColorType;
53 }
54 return colorType;
55 }
56
SkImage_Gpu(sk_sp<GrContext> context,uint32_t uniqueID,SkAlphaType at,sk_sp<GrTextureProxy> proxy,sk_sp<SkColorSpace> colorSpace)57 SkImage_Gpu::SkImage_Gpu(sk_sp<GrContext> context, uint32_t uniqueID, SkAlphaType at,
58 sk_sp<GrTextureProxy> proxy, sk_sp<SkColorSpace> colorSpace)
59 : INHERITED(std::move(context), proxy->worstCaseWidth(), proxy->worstCaseHeight(), uniqueID,
60 proxy_color_type(proxy.get()), at, colorSpace)
61 , fProxy(std::move(proxy)) {}
62
~SkImage_Gpu()63 SkImage_Gpu::~SkImage_Gpu() {}
64
onFlush(GrContext * context,const GrFlushInfo & info)65 GrSemaphoresSubmitted SkImage_Gpu::onFlush(GrContext* context, const GrFlushInfo& info) {
66 if (!context || !fContext->priv().matches(context) || fContext->abandoned()) {
67 return GrSemaphoresSubmitted::kNo;
68 }
69
70 GrSurfaceProxy* p[1] = {fProxy.get()};
71 return context->priv().flushSurfaces(p, 1, info);
72 }
73
onMakeColorTypeAndColorSpace(GrRecordingContext * context,SkColorType targetCT,sk_sp<SkColorSpace> targetCS) const74 sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(GrRecordingContext* context,
75 SkColorType targetCT,
76 sk_sp<SkColorSpace> targetCS) const {
77 if (!context || !fContext->priv().matches(context)) {
78 return nullptr;
79 }
80
81 auto xform = GrColorSpaceXformEffect::Make(this->colorSpace(), this->alphaType(),
82 targetCS.get(), this->alphaType());
83 SkASSERT(xform || targetCT != this->colorType());
84
85 sk_sp<GrTextureProxy> proxy = this->asTextureProxyRef(context);
86
87 auto renderTargetContext = context->priv().makeDeferredRenderTargetContextWithFallback(
88 SkBackingFit::kExact, this->width(), this->height(), SkColorTypeToGrColorType(targetCT),
89 nullptr);
90 if (!renderTargetContext) {
91 return nullptr;
92 }
93
94 GrPaint paint;
95 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
96 paint.addColorTextureProcessor(std::move(proxy), SkColorTypeToGrColorType(this->colorType()),
97 SkMatrix::I());
98 if (xform) {
99 paint.addColorFragmentProcessor(std::move(xform));
100 }
101
102 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
103 SkRect::MakeIWH(this->width(), this->height()));
104 if (!renderTargetContext->asTextureProxy()) {
105 return nullptr;
106 }
107
108 // MDB: this call is okay bc we know 'renderTargetContext' was exact
109 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, this->alphaType(),
110 renderTargetContext->asTextureProxyRef(), std::move(targetCS));
111 }
112
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const113 sk_sp<SkImage> SkImage_Gpu::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
114 return sk_make_sp<SkImage_Gpu>(fContext, kNeedNewImageUniqueID, this->alphaType(), fProxy,
115 std::move(newCS));
116 }
117
118 ///////////////////////////////////////////////////////////////////////////////////////////////////
119
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)120 static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx,
121 const GrBackendTexture& backendTex,
122 GrColorType colorType, GrSurfaceOrigin origin,
123 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
124 GrWrapOwnership ownership,
125 SkImage::TextureReleaseProc releaseProc,
126 SkImage::ReleaseContext releaseCtx) {
127 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
128 return nullptr;
129 }
130
131 GrProxyProvider* proxyProvider = ctx->priv().proxyProvider();
132 sk_sp<GrTextureProxy> proxy =
133 proxyProvider->wrapBackendTexture(backendTex, colorType, origin, ownership,
134 GrWrapCacheable::kNo, kRead_GrIOType,
135 releaseProc, releaseCtx);
136 if (!proxy) {
137 return nullptr;
138 }
139 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at, std::move(proxy),
140 std::move(colorSpace));
141 }
142
MakeFromTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs,TextureReleaseProc releaseP,ReleaseContext releaseC)143 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx,
144 const GrBackendTexture& tex, GrSurfaceOrigin origin,
145 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs,
146 TextureReleaseProc releaseP, ReleaseContext releaseC) {
147 if (!ctx) {
148 return nullptr;
149 }
150
151 const GrCaps* caps = ctx->priv().caps();
152
153 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
154 if (GrColorType::kUnknown == grColorType) {
155 return nullptr;
156 }
157
158 if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
159 return nullptr;
160 }
161
162 return new_wrapped_texture_common(ctx, tex, grColorType, origin, at, std::move(cs),
163 kBorrow_GrWrapOwnership, releaseP, releaseC);
164 }
165
MakeFromAdoptedTexture(GrContext * ctx,const GrBackendTexture & tex,GrSurfaceOrigin origin,SkColorType ct,SkAlphaType at,sk_sp<SkColorSpace> cs)166 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx,
167 const GrBackendTexture& tex, GrSurfaceOrigin origin,
168 SkColorType ct, SkAlphaType at,
169 sk_sp<SkColorSpace> cs) {
170 if (!ctx || !ctx->priv().resourceProvider()) {
171 // We have a DDL context and we don't support adopted textures for them.
172 return nullptr;
173 }
174
175 const GrCaps* caps = ctx->priv().caps();
176
177 GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
178 if (GrColorType::kUnknown == grColorType) {
179 return nullptr;
180 }
181
182 if (!SkImage_GpuBase::ValidateBackendTexture(caps, tex, grColorType, ct, at, cs)) {
183 return nullptr;
184 }
185
186 return new_wrapped_texture_common(ctx, tex, grColorType, origin, at, std::move(cs),
187 kAdopt_GrWrapOwnership, nullptr, nullptr);
188 }
189
MakeFromCompressed(GrContext * context,sk_sp<SkData> data,int width,int height,CompressionType type)190 sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
191 int width, int height, CompressionType type) {
192 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
193 sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
194 width, height, SkBudgeted::kYes, type, std::move(data));
195
196 if (!proxy) {
197 return nullptr;
198 }
199
200 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(context), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
201 std::move(proxy), nullptr);
202 }
203
ConvertYUVATexturesToRGB(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize size,GrSurfaceOrigin origin,GrRenderTargetContext * renderTargetContext)204 sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
205 const GrBackendTexture yuvaTextures[],
206 const SkYUVAIndex yuvaIndices[4], SkISize size,
207 GrSurfaceOrigin origin,
208 GrRenderTargetContext* renderTargetContext) {
209 SkASSERT(renderTargetContext);
210
211 int numTextures;
212 if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) {
213 return nullptr;
214 }
215
216 sk_sp<GrTextureProxy> tempTextureProxies[4];
217 if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
218 origin, tempTextureProxies)) {
219 return nullptr;
220 }
221
222 const SkRect rect = SkRect::MakeIWH(size.width(), size.height());
223 if (!RenderYUVAToRGBA(ctx, renderTargetContext, rect, yuvColorSpace, nullptr,
224 tempTextureProxies, yuvaIndices)) {
225 return nullptr;
226 }
227
228 SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices);
229 // MDB: this call is okay bc we know 'renderTargetContext' was exact
230 return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at,
231 renderTargetContext->asTextureProxyRef(),
232 renderTargetContext->colorInfo().refColorSpace());
233 }
234
MakeFromYUVATexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)235 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopy(GrContext* ctx,
236 SkYUVColorSpace yuvColorSpace,
237 const GrBackendTexture yuvaTextures[],
238 const SkYUVAIndex yuvaIndices[4],
239 SkISize imageSize,
240 GrSurfaceOrigin imageOrigin,
241 sk_sp<SkColorSpace> imageColorSpace) {
242 const int width = imageSize.width();
243 const int height = imageSize.height();
244
245 // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
246 auto renderTargetContext = ctx->priv().makeDeferredRenderTargetContext(
247 SkBackingFit::kExact, width, height, GrColorType::kRGBA_8888,
248 std::move(imageColorSpace), 1, GrMipMapped::kNo, imageOrigin);
249 if (!renderTargetContext) {
250 return nullptr;
251 }
252
253 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
254 imageSize, imageOrigin, renderTargetContext.get());
255 }
256
MakeFromYUVATexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvaTextures[],const SkYUVAIndex yuvaIndices[4],SkISize imageSize,GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)257 sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend(
258 GrContext* ctx,
259 SkYUVColorSpace yuvColorSpace,
260 const GrBackendTexture yuvaTextures[],
261 const SkYUVAIndex yuvaIndices[4],
262 SkISize imageSize,
263 GrSurfaceOrigin imageOrigin,
264 const GrBackendTexture& backendTexture,
265 sk_sp<SkColorSpace> imageColorSpace,
266 TextureReleaseProc textureReleaseProc,
267 ReleaseContext releaseContext) {
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 auto renderTargetContext = ctx->priv().makeBackendTextureRenderTargetContext(
285 backendTexture, imageOrigin, 1, grColorType, std::move(imageColorSpace), nullptr,
286 textureReleaseProc, releaseContext);
287 if (!renderTargetContext) {
288 return nullptr;
289 }
290
291 return SkImage_Gpu::ConvertYUVATexturesToRGB(ctx, yuvColorSpace, yuvaTextures, yuvaIndices,
292 imageSize, imageOrigin, renderTargetContext.get());
293 }
294
MakeFromYUVTexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvTextures[3],GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)295 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
296 const GrBackendTexture yuvTextures[3],
297 GrSurfaceOrigin imageOrigin,
298 sk_sp<SkColorSpace> imageColorSpace) {
299 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
300 SkYUVAIndex yuvaIndices[4] = {
301 SkYUVAIndex{0, SkColorChannel::kR},
302 SkYUVAIndex{1, SkColorChannel::kR},
303 SkYUVAIndex{2, SkColorChannel::kR},
304 SkYUVAIndex{-1, SkColorChannel::kA}};
305 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
306 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, yuvTextures, yuvaIndices,
307 size, imageOrigin, std::move(imageColorSpace));
308 }
309
MakeFromYUVTexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture yuvTextures[3],GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace)310 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
311 GrContext* ctx, SkYUVColorSpace yuvColorSpace, const GrBackendTexture yuvTextures[3],
312 GrSurfaceOrigin imageOrigin, const GrBackendTexture& backendTexture,
313 sk_sp<SkColorSpace> imageColorSpace) {
314 SkYUVAIndex yuvaIndices[4] = {
315 SkYUVAIndex{0, SkColorChannel::kR},
316 SkYUVAIndex{1, SkColorChannel::kR},
317 SkYUVAIndex{2, SkColorChannel::kR},
318 SkYUVAIndex{-1, SkColorChannel::kA}};
319 SkISize size{yuvTextures[0].width(), yuvTextures[0].height()};
320 return SkImage_Gpu::MakeFromYUVATexturesCopyWithExternalBackend(
321 ctx, yuvColorSpace, yuvTextures, yuvaIndices, size, imageOrigin, backendTexture,
322 std::move(imageColorSpace), nullptr, nullptr);
323 }
324
MakeFromNV12TexturesCopy(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture nv12Textures[2],GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace)325 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace yuvColorSpace,
326 const GrBackendTexture nv12Textures[2],
327 GrSurfaceOrigin imageOrigin,
328 sk_sp<SkColorSpace> imageColorSpace) {
329 // TODO: SkImageSourceChannel input is being ingored right now. Setup correctly in the future.
330 SkYUVAIndex yuvaIndices[4] = {
331 SkYUVAIndex{0, SkColorChannel::kR},
332 SkYUVAIndex{1, SkColorChannel::kR},
333 SkYUVAIndex{1, SkColorChannel::kG},
334 SkYUVAIndex{-1, SkColorChannel::kA}};
335 SkISize size{nv12Textures[0].width(), nv12Textures[0].height()};
336 return SkImage_Gpu::MakeFromYUVATexturesCopy(ctx, yuvColorSpace, nv12Textures, yuvaIndices,
337 size, imageOrigin, std::move(imageColorSpace));
338 }
339
MakeFromNV12TexturesCopyWithExternalBackend(GrContext * ctx,SkYUVColorSpace yuvColorSpace,const GrBackendTexture nv12Textures[2],GrSurfaceOrigin imageOrigin,const GrBackendTexture & backendTexture,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)340 sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
341 GrContext* ctx,
342 SkYUVColorSpace yuvColorSpace,
343 const GrBackendTexture nv12Textures[2],
344 GrSurfaceOrigin imageOrigin,
345 const GrBackendTexture& backendTexture,
346 sk_sp<SkColorSpace> imageColorSpace,
347 TextureReleaseProc textureReleaseProc,
348 ReleaseContext releaseContext) {
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), textureReleaseProc, releaseContext);
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 auto 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
652 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
653 // image is not unique, or if the texture wraps an external object.
654 if (!image->unique() || !texture->unique() ||
655 texture->resourcePriv().refsWrappedObjects()) {
656 // onMakeSubset will always copy the image.
657 image = as_IB(image)->onMakeSubset(ctx, image->bounds());
658 if (!image) {
659 return false;
660 }
661
662 texture = image->getTexture();
663 if (!texture) {
664 return false;
665 }
666
667 // Flush to ensure that the copy is completed before we return the texture.
668 ctx->priv().flushSurface(as_IB(image)->peekProxy());
669 }
670
671 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
672 SkASSERT(texture->unique());
673 SkASSERT(image->unique());
674
675 // Take a reference to the GrTexture and release the image.
676 sk_sp<GrTexture> textureRef(SkSafeRef(texture));
677 image = nullptr;
678
679 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
680 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
681 }
682