1 /*
2 * Copyright 2023 Google LLC
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 "include/gpu/ganesh/SkImageGanesh.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPixmap.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkSamplingOptions.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkYUVAInfo.h"
21 #include "include/core/SkYUVAPixmaps.h"
22 #include "include/gpu/GpuTypes.h"
23 #include "include/gpu/ganesh/GrBackendSurface.h"
24 #include "include/gpu/ganesh/GrContextThreadSafeProxy.h"
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "include/gpu/ganesh/GrExternalTextureGenerator.h"
27 #include "include/gpu/ganesh/GrRecordingContext.h"
28 #include "include/gpu/ganesh/GrTypes.h"
29 #include "include/gpu/ganesh/GrYUVABackendTextures.h"
30 #include "include/private/base/SkAssert.h"
31 #include "include/private/chromium/SkImageChromium.h"
32 #include "include/private/gpu/ganesh/GrImageContext.h"
33 #include "include/private/gpu/ganesh/GrTextureGenerator.h"
34 #include "include/private/gpu/ganesh/GrTypesPriv.h"
35 #include "src/core/SkAutoPixmapStorage.h"
36 #include "src/core/SkImageInfoPriv.h"
37 #include "src/gpu/GpuTypesPriv.h"
38 #include "src/gpu/RefCntedCallback.h"
39 #include "src/gpu/Swizzle.h"
40 #include "src/gpu/ganesh/GrBackendTextureImageGenerator.h"
41 #include "src/gpu/ganesh/GrBackendUtils.h"
42 #include "src/gpu/ganesh/GrCaps.h"
43 #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h"
44 #include "src/gpu/ganesh/GrDirectContextPriv.h"
45 #include "src/gpu/ganesh/GrGpu.h"
46 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
47 #include "src/gpu/ganesh/GrImageContextPriv.h"
48 #include "src/gpu/ganesh/GrProxyProvider.h"
49 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
50 #include "src/gpu/ganesh/GrSemaphore.h"
51 #include "src/gpu/ganesh/GrSurfaceProxy.h"
52 #include "src/gpu/ganesh/GrSurfaceProxyView.h"
53 #include "src/gpu/ganesh/GrTexture.h"
54 #include "src/gpu/ganesh/GrTextureProxy.h"
55 #include "src/gpu/ganesh/GrYUVATextureProxies.h"
56 #include "src/gpu/ganesh/SkGr.h"
57 #include "src/gpu/ganesh/image/GrImageUtils.h"
58 #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
59 #include "src/gpu/ganesh/image/SkImage_GaneshBase.h"
60 #include "src/gpu/ganesh/image/SkImage_GaneshYUVA.h"
61 #include "src/image/SkImage_Base.h"
62
63 #include <algorithm>
64 #include <memory>
65 #include <tuple>
66 #include <utility>
67
68 enum SkColorType : int;
69 enum class SkTextureCompressionType;
70
71 namespace SkImages {
72
MakeBackendTextureFromImage(GrDirectContext * direct,sk_sp<SkImage> image,GrBackendTexture * backendTexture,BackendTextureReleaseProc * releaseProc)73 bool MakeBackendTextureFromImage(GrDirectContext* direct,
74 sk_sp<SkImage> image,
75 GrBackendTexture* backendTexture,
76 BackendTextureReleaseProc* releaseProc) {
77 if (!image || !backendTexture || !releaseProc) {
78 return false;
79 }
80
81 auto [view, ct] = skgpu::ganesh::AsView(direct, image, skgpu::Mipmapped::kNo);
82 if (!view) {
83 return false;
84 }
85
86 // Flush any pending IO on the texture.
87 direct->priv().flushSurface(view.proxy());
88
89 GrTexture* texture = view.asTextureProxy()->peekTexture();
90 if (!texture) {
91 return false;
92 }
93 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
94 // image is not unique, or if the texture wraps an external object.
95 if (!image->unique() || !texture->unique() || texture->resourcePriv().refsWrappedObjects()) {
96 // onMakeSubset will always copy the image.
97 image = as_IB(image)->onMakeSubset(direct, image->bounds());
98 if (!image) {
99 return false;
100 }
101 return MakeBackendTextureFromImage(direct, std::move(image), backendTexture, releaseProc);
102 }
103
104 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
105 SkASSERT(texture->unique());
106 SkASSERT(image->unique());
107
108 // Take a reference to the GrTexture and release the image.
109 sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
110 view.reset();
111 image = nullptr;
112 SkASSERT(textureRef->unique());
113
114 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
115 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
116 }
117
GetBackendTextureFromImage(const SkImage * img,GrBackendTexture * outTexture,bool flushPendingGrContextIO,GrSurfaceOrigin * origin)118 bool GetBackendTextureFromImage(const SkImage* img,
119 GrBackendTexture* outTexture,
120 bool flushPendingGrContextIO,
121 GrSurfaceOrigin* origin) {
122 if (!img) {
123 return false;
124 }
125 auto ib = as_IB(img);
126 if (ib->type() != SkImage_Base::Type::kGanesh) {
127 return false;
128 }
129 auto ig = static_cast<const SkImage_Ganesh*>(img);
130 return ig->getExistingBackendTexture(outTexture, flushPendingGrContextIO, origin);
131 }
132
TextureFromCompressedTexture(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)133 sk_sp<SkImage> TextureFromCompressedTexture(GrRecordingContext* context,
134 const GrBackendTexture& backendTexture,
135 GrSurfaceOrigin origin,
136 SkAlphaType alphaType,
137 sk_sp<SkColorSpace> colorSpace,
138 TextureReleaseProc textureReleaseProc,
139 ReleaseContext releaseContext) {
140 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
141
142 if (!context) {
143 return nullptr;
144 }
145
146 const GrCaps* caps = context->priv().caps();
147
148 if (!SkImage_GaneshBase::ValidateCompressedBackendTexture(caps, backendTexture, alphaType)) {
149 return nullptr;
150 }
151
152 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
153 sk_sp<GrTextureProxy> proxy =
154 proxyProvider->wrapCompressedBackendTexture(backendTexture,
155 kBorrow_GrWrapOwnership,
156 GrWrapCacheable::kNo,
157 std::move(releaseHelper));
158 if (!proxy) {
159 return nullptr;
160 }
161
162 SkTextureCompressionType type =
163 GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
164 SkColorType ct = skgpu::CompressionTypeToSkColorType(type);
165
166 GrSurfaceProxyView view(std::move(proxy), origin, skgpu::Swizzle::RGBA());
167 return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(context),
168 kNeedNewImageUniqueID,
169 std::move(view),
170 SkColorInfo(ct, alphaType, std::move(colorSpace)));
171 }
172
new_wrapped_texture_common(GrRecordingContext * rContext,const GrBackendTexture & backendTex,GrColorType colorType,GrSurfaceOrigin origin,SkAlphaType at,sk_sp<SkColorSpace> colorSpace,GrWrapOwnership ownership,sk_sp<skgpu::RefCntedCallback> releaseHelper)173 static sk_sp<SkImage> new_wrapped_texture_common(GrRecordingContext* rContext,
174 const GrBackendTexture& backendTex,
175 GrColorType colorType,
176 GrSurfaceOrigin origin,
177 SkAlphaType at,
178 sk_sp<SkColorSpace> colorSpace,
179 GrWrapOwnership ownership,
180 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
181 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
182 return nullptr;
183 }
184
185 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
186 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
187 backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
188 if (!proxy) {
189 return nullptr;
190 }
191
192 skgpu::Swizzle swizzle =
193 rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), colorType);
194 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
195 SkColorInfo info(GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
196 return sk_make_sp<SkImage_Ganesh>(
197 sk_ref_sp(rContext), kNeedNewImageUniqueID, std::move(view), std::move(info));
198 }
199
BorrowTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)200 sk_sp<SkImage> BorrowTextureFrom(GrRecordingContext* context,
201 const GrBackendTexture& backendTexture,
202 GrSurfaceOrigin origin,
203 SkColorType colorType,
204 SkAlphaType alphaType,
205 sk_sp<SkColorSpace> colorSpace,
206 TextureReleaseProc textureReleaseProc,
207 ReleaseContext releaseContext) {
208 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
209
210 if (!context) {
211 return nullptr;
212 }
213
214 const GrCaps* caps = context->priv().caps();
215
216 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
217 if (GrColorType::kUnknown == grColorType) {
218 return nullptr;
219 }
220
221 if (!SkImage_GaneshBase::ValidateBackendTexture(
222 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
223 return nullptr;
224 }
225
226 return new_wrapped_texture_common(context,
227 backendTexture,
228 grColorType,
229 origin,
230 alphaType,
231 std::move(colorSpace),
232 kBorrow_GrWrapOwnership,
233 std::move(releaseHelper));
234 }
235
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType)236 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
237 const GrBackendTexture& backendTexture,
238 GrSurfaceOrigin textureOrigin,
239 SkColorType colorType) {
240 return AdoptTextureFrom(
241 context, backendTexture, textureOrigin, colorType, kPremul_SkAlphaType, nullptr);
242 }
243
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin textureOrigin,SkColorType colorType,SkAlphaType alphaType)244 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
245 const GrBackendTexture& backendTexture,
246 GrSurfaceOrigin textureOrigin,
247 SkColorType colorType,
248 SkAlphaType alphaType) {
249 return AdoptTextureFrom(context, backendTexture, textureOrigin, colorType, alphaType, nullptr);
250 }
251
AdoptTextureFrom(GrRecordingContext * context,const GrBackendTexture & backendTexture,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)252 sk_sp<SkImage> AdoptTextureFrom(GrRecordingContext* context,
253 const GrBackendTexture& backendTexture,
254 GrSurfaceOrigin origin,
255 SkColorType colorType,
256 SkAlphaType alphaType,
257 sk_sp<SkColorSpace> colorSpace) {
258 auto dContext = GrAsDirectContext(context);
259 if (!dContext) {
260 // We have a DDL context and we don't support adopted textures for them.
261 return nullptr;
262 }
263
264 const GrCaps* caps = dContext->priv().caps();
265
266 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
267 if (GrColorType::kUnknown == grColorType) {
268 return nullptr;
269 }
270
271 if (!SkImage_GaneshBase::ValidateBackendTexture(
272 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
273 return nullptr;
274 }
275
276 return new_wrapped_texture_common(dContext,
277 backendTexture,
278 grColorType,
279 origin,
280 alphaType,
281 std::move(colorSpace),
282 kAdopt_GrWrapOwnership,
283 nullptr);
284 }
285
TextureFromCompressedTextureData(GrDirectContext * direct,sk_sp<SkData> data,int width,int height,SkTextureCompressionType type,skgpu::Mipmapped mipmapped,GrProtected isProtected,sk_sp<SkColorSpace> colorSpace)286 sk_sp<SkImage> TextureFromCompressedTextureData(GrDirectContext* direct,
287 sk_sp<SkData> data,
288 int width,
289 int height,
290 SkTextureCompressionType type,
291 skgpu::Mipmapped mipmapped,
292 GrProtected isProtected,
293 sk_sp<SkColorSpace> colorSpace) {
294 if (!direct || !data) {
295 return nullptr;
296 }
297
298 GrBackendFormat beFormat = direct->compressedBackendFormat(type);
299 if (!beFormat.isValid()) {
300 sk_sp<SkImage> tmp = RasterFromCompressedTextureData(std::move(data), width, height, type);
301 if (!tmp) {
302 return nullptr;
303 }
304 return TextureFromImage(direct, tmp, mipmapped);
305 }
306
307 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
308 sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
309 {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
310 if (!proxy) {
311 return nullptr;
312 }
313 GrSurfaceProxyView view(std::move(proxy));
314
315 SkColorType colorType = skgpu::CompressionTypeToSkColorType(type);
316
317 // modify for support astc texture format
318 SkAlphaType alphaType = skgpu::CompressionTypeToSkAlphaType(type);
319
320 return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(direct),
321 kNeedNewImageUniqueID,
322 std::move(view),
323 SkColorInfo(colorType, alphaType, colorSpace));
324 }
325
PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrBackendFormat & backendFormat,SkISize dimensions,skgpu::Mipmapped mipmapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContext)326 sk_sp<SkImage> PromiseTextureFrom(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
327 const GrBackendFormat& backendFormat,
328 SkISize dimensions,
329 skgpu::Mipmapped mipmapped,
330 GrSurfaceOrigin origin,
331 SkColorType colorType,
332 SkAlphaType alphaType,
333 sk_sp<SkColorSpace> colorSpace,
334 PromiseImageTextureFulfillProc textureFulfillProc,
335 PromiseImageTextureReleaseProc textureReleaseProc,
336 PromiseImageTextureContext textureContext) {
337 // Our contract is that we will always call the release proc even on failure.
338 // We use the helper to convey the context, so we need to ensure make doesn't fail.
339 textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
340 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
341 SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
342 if (!SkImageInfoIsValid(info)) {
343 return nullptr;
344 }
345
346 if (!threadSafeProxy) {
347 return nullptr;
348 }
349
350 if (dimensions.isEmpty()) {
351 return nullptr;
352 }
353
354 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
355 if (GrColorType::kUnknown == grColorType) {
356 return nullptr;
357 }
358
359 if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
360 backendFormat)) {
361 return nullptr;
362 }
363
364 auto proxy = SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
365 dimensions,
366 backendFormat,
367 mipmapped,
368 textureFulfillProc,
369 std::move(releaseHelper));
370 if (!proxy) {
371 return nullptr;
372 }
373 skgpu::Swizzle swizzle =
374 threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
375 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
376 sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
377 return sk_make_sp<SkImage_Ganesh>(std::move(ctx),
378 kNeedNewImageUniqueID,
379 std::move(view),
380 SkColorInfo(colorType, alphaType, std::move(colorSpace)));
381 }
382
CrossContextTextureFromPixmap(GrDirectContext * dContext,const SkPixmap & originalPixmap,bool buildMips,bool limitToMaxTextureSize)383 sk_sp<SkImage> CrossContextTextureFromPixmap(GrDirectContext* dContext,
384 const SkPixmap& originalPixmap,
385 bool buildMips,
386 bool limitToMaxTextureSize) {
387 // Some backends or drivers don't support (safely) moving resources between contexts
388 if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
389 return RasterFromPixmapCopy(originalPixmap);
390 }
391
392 // If non-power-of-two mipmapping isn't supported, ignore the client's request
393 if (!dContext->priv().caps()->mipmapSupport()) {
394 buildMips = false;
395 }
396
397 const SkPixmap* pixmap = &originalPixmap;
398 SkAutoPixmapStorage resized;
399 int maxTextureSize = dContext->priv().caps()->maxTextureSize();
400 int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
401 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
402 float scale = static_cast<float>(maxTextureSize) / maxDim;
403 int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
404 int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
405 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
406 SkSamplingOptions sampling(SkFilterMode::kLinear);
407 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
408 return nullptr;
409 }
410 pixmap = &resized;
411 }
412 // Turn the pixmap into a GrTextureProxy
413 SkBitmap bmp;
414 bmp.installPixels(*pixmap);
415 skgpu::Mipmapped mipmapped = buildMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
416 auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
417 if (!view) {
418 return RasterFromPixmapCopy(*pixmap);
419 }
420
421 sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
422
423 // Flush any writes or uploads
424 dContext->priv().flushSurface(view.proxy());
425 GrGpu* gpu = dContext->priv().getGpu();
426
427 std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
428
429 SkColorType skCT = GrColorTypeToSkColorType(ct);
430 auto gen = GrBackendTextureImageGenerator::Make(std::move(texture),
431 view.origin(),
432 std::move(sema),
433 skCT,
434 pixmap->alphaType(),
435 pixmap->info().refColorSpace());
436 return DeferredFromTextureGenerator(std::move(gen));
437 }
438
TextureFromImage(GrDirectContext * dContext,const SkImage * img,skgpu::Mipmapped mipmapped,skgpu::Budgeted budgeted)439 sk_sp<SkImage> TextureFromImage(GrDirectContext* dContext,
440 const SkImage* img,
441 skgpu::Mipmapped mipmapped,
442 skgpu::Budgeted budgeted) {
443 if (!dContext || !img) {
444 return nullptr;
445 }
446 auto ib = as_IB(img);
447 if (!dContext->priv().caps()->mipmapSupport() || ib->dimensions().area() <= 1) {
448 mipmapped = skgpu::Mipmapped::kNo;
449 }
450
451 if (ib->isGaneshBacked()) {
452 if (!ib->context()->priv().matches(dContext)) {
453 return nullptr;
454 }
455
456 if (mipmapped == skgpu::Mipmapped::kNo || ib->hasMipmaps()) {
457 return sk_ref_sp(const_cast<SkImage_Base*>(ib));
458 }
459 }
460 GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
461 ? GrImageTexGenPolicy::kNew_Uncached_Budgeted
462 : GrImageTexGenPolicy::kNew_Uncached_Unbudgeted;
463 // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
464 auto [view, ct] = skgpu::ganesh::AsView(dContext, ib, mipmapped, policy);
465 if (!view) {
466 return nullptr;
467 }
468 SkASSERT(view.asTextureProxy());
469 SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
470 view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
471 SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), ib->alphaType(), ib->refColorSpace());
472 return sk_make_sp<SkImage_Ganesh>(
473 sk_ref_sp(dContext), ib->uniqueID(), std::move(view), std::move(colorInfo));
474 }
475
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures)476 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
477 const GrYUVABackendTextures& yuvaTextures) {
478 return TextureFromYUVATextures(context, yuvaTextures, nullptr, nullptr, nullptr);
479 }
480
TextureFromYUVATextures(GrRecordingContext * context,const GrYUVABackendTextures & yuvaTextures,sk_sp<SkColorSpace> imageColorSpace,TextureReleaseProc textureReleaseProc,ReleaseContext releaseContext)481 sk_sp<SkImage> TextureFromYUVATextures(GrRecordingContext* context,
482 const GrYUVABackendTextures& yuvaTextures,
483 sk_sp<SkColorSpace> imageColorSpace,
484 TextureReleaseProc textureReleaseProc,
485 ReleaseContext releaseContext) {
486 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
487
488 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
489 int numPlanes = yuvaTextures.yuvaInfo().numPlanes();
490 sk_sp<GrSurfaceProxy> proxies[SkYUVAInfo::kMaxPlanes];
491 for (int plane = 0; plane < numPlanes; ++plane) {
492 proxies[plane] = proxyProvider->wrapBackendTexture(yuvaTextures.texture(plane),
493 kBorrow_GrWrapOwnership,
494 GrWrapCacheable::kNo,
495 kRead_GrIOType,
496 releaseHelper);
497 if (!proxies[plane]) {
498 return {};
499 }
500 }
501 GrYUVATextureProxies yuvaProxies(
502 yuvaTextures.yuvaInfo(), proxies, yuvaTextures.textureOrigin());
503
504 if (!yuvaProxies.isValid()) {
505 return nullptr;
506 }
507
508 return sk_make_sp<SkImage_GaneshYUVA>(
509 sk_ref_sp(context), kNeedNewImageUniqueID, yuvaProxies, imageColorSpace);
510 }
511
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize)512 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
513 const SkYUVAPixmaps& pixmaps,
514 skgpu::Mipmapped buildMips,
515 bool limitToMaxTextureSize) {
516 return TextureFromYUVAPixmaps(context, pixmaps, buildMips, limitToMaxTextureSize, nullptr);
517 }
518
TextureFromYUVAPixmaps(GrRecordingContext * context,const SkYUVAPixmaps & pixmaps,skgpu::Mipmapped buildMips,bool limitToMaxTextureSize,sk_sp<SkColorSpace> imageColorSpace)519 sk_sp<SkImage> TextureFromYUVAPixmaps(GrRecordingContext* context,
520 const SkYUVAPixmaps& pixmaps,
521 skgpu::Mipmapped buildMips,
522 bool limitToMaxTextureSize,
523 sk_sp<SkColorSpace> imageColorSpace) {
524 if (!context) {
525 return nullptr;
526 }
527
528 if (!pixmaps.isValid()) {
529 return nullptr;
530 }
531
532 if (!context->priv().caps()->mipmapSupport()) {
533 buildMips = skgpu::Mipmapped::kNo;
534 }
535
536 // Resize the pixmaps if necessary.
537 int numPlanes = pixmaps.numPlanes();
538 int maxTextureSize = context->priv().caps()->maxTextureSize();
539 int maxDim = std::max(pixmaps.yuvaInfo().width(), pixmaps.yuvaInfo().height());
540
541 SkYUVAPixmaps tempPixmaps;
542 const SkYUVAPixmaps* pixmapsToUpload = &pixmaps;
543 // We assume no plane is larger than the image size (and at least one plane is as big).
544 if (maxDim > maxTextureSize) {
545 if (!limitToMaxTextureSize) {
546 return nullptr;
547 }
548 float scale = static_cast<float>(maxTextureSize) / maxDim;
549 SkISize newDimensions = {
550 std::min(static_cast<int>(pixmaps.yuvaInfo().width() * scale), maxTextureSize),
551 std::min(static_cast<int>(pixmaps.yuvaInfo().height() * scale), maxTextureSize)};
552 SkYUVAInfo newInfo = pixmaps.yuvaInfo().makeDimensions(newDimensions);
553 SkYUVAPixmapInfo newPixmapInfo(newInfo, pixmaps.dataType(), /*row bytes*/ nullptr);
554 tempPixmaps = SkYUVAPixmaps::Allocate(newPixmapInfo);
555 SkSamplingOptions sampling(SkFilterMode::kLinear);
556 if (!tempPixmaps.isValid()) {
557 return nullptr;
558 }
559 for (int i = 0; i < numPlanes; ++i) {
560 if (!pixmaps.plane(i).scalePixels(tempPixmaps.plane(i), sampling)) {
561 return nullptr;
562 }
563 }
564 pixmapsToUpload = &tempPixmaps;
565 }
566
567 // Convert to texture proxies.
568 GrSurfaceProxyView views[SkYUVAInfo::kMaxPlanes];
569 GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
570 for (int i = 0; i < numPlanes; ++i) {
571 // Turn the pixmap into a GrTextureProxy
572 SkBitmap bmp;
573 bmp.installPixels(pixmapsToUpload->plane(i));
574 std::tie(views[i], std::ignore) = GrMakeUncachedBitmapProxyView(context, bmp, buildMips);
575 if (!views[i]) {
576 return nullptr;
577 }
578 pixmapColorTypes[i] = SkColorTypeToGrColorType(bmp.colorType());
579 }
580
581 GrYUVATextureProxies yuvaProxies(pixmapsToUpload->yuvaInfo(), views, pixmapColorTypes);
582 SkASSERT(yuvaProxies.isValid());
583 return sk_make_sp<SkImage_GaneshYUVA>(sk_ref_sp(context),
584 kNeedNewImageUniqueID,
585 std::move(yuvaProxies),
586 std::move(imageColorSpace));
587 }
588
PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,const GrYUVABackendTextureInfo & backendTextureInfo,sk_sp<SkColorSpace> imageColorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureContext textureContexts[])589 sk_sp<SkImage> PromiseTextureFromYUVA(sk_sp<GrContextThreadSafeProxy> threadSafeProxy,
590 const GrYUVABackendTextureInfo& backendTextureInfo,
591 sk_sp<SkColorSpace> imageColorSpace,
592 PromiseImageTextureFulfillProc textureFulfillProc,
593 PromiseImageTextureReleaseProc textureReleaseProc,
594 PromiseImageTextureContext textureContexts[]) {
595 if (!backendTextureInfo.isValid()) {
596 return nullptr;
597 }
598
599 SkISize planeDimensions[SkYUVAInfo::kMaxPlanes];
600 int n = backendTextureInfo.yuvaInfo().planeDimensions(planeDimensions);
601
602 // Our contract is that we will always call the release proc even on failure.
603 // We use the helper to convey the context, so we need to ensure make doesn't fail.
604 textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
605 sk_sp<skgpu::RefCntedCallback> releaseHelpers[4];
606 for (int i = 0; i < n; ++i) {
607 releaseHelpers[i] = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContexts[i]);
608 }
609
610 if (!threadSafeProxy) {
611 return nullptr;
612 }
613
614 SkAlphaType at =
615 backendTextureInfo.yuvaInfo().hasAlpha() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
616 SkImageInfo info = SkImageInfo::Make(
617 backendTextureInfo.yuvaInfo().dimensions(), SkImage_GaneshYUVA::kAssumedColorType, at,
618 imageColorSpace);
619 if (!SkImageInfoIsValid(info)) {
620 return nullptr;
621 }
622
623 // Make a lazy proxy for each plane
624 sk_sp<GrSurfaceProxy> proxies[4];
625 for (int i = 0; i < n; ++i) {
626 proxies[i] =
627 SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
628 planeDimensions[i],
629 backendTextureInfo.planeFormat(i),
630 skgpu::Mipmapped::kNo,
631 textureFulfillProc,
632 std::move(releaseHelpers[i]));
633 if (!proxies[i]) {
634 return nullptr;
635 }
636 }
637 GrYUVATextureProxies yuvaTextureProxies(
638 backendTextureInfo.yuvaInfo(), proxies, backendTextureInfo.textureOrigin());
639 SkASSERT(yuvaTextureProxies.isValid());
640 sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
641 return sk_make_sp<SkImage_GaneshYUVA>(std::move(ctx),
642 kNeedNewImageUniqueID,
643 std::move(yuvaTextureProxies),
644 std::move(imageColorSpace));
645 }
646
647 } // namespace SkImages
648