Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkImage_GaneshFactories.cpp
Go to the documentation of this file.
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
9
13#include "include/core/SkData.h"
19#include "include/core/SkSize.h"
25#include "include/gpu/GrTypes.h"
36#include "src/gpu/Swizzle.h"
52#include "src/gpu/ganesh/SkGr.h"
57
58#include <algorithm>
59#include <memory>
60#include <utility>
61
62enum SkColorType : int;
64
65namespace SkImages {
66
69 GrBackendTexture* backendTexture,
71 if (!image || !backendTexture || !releaseProc) {
72 return false;
73 }
74
75 auto [view, ct] = skgpu::ganesh::AsView(direct, image, skgpu::Mipmapped::kNo);
76 if (!view) {
77 return false;
78 }
79
80 // Flush any pending IO on the texture.
81 direct->priv().flushSurface(view.proxy());
82
83 GrTexture* texture = view.asTextureProxy()->peekTexture();
84 if (!texture) {
85 return false;
86 }
87 // We must make a copy of the image if the image is not unique, if the GrTexture owned by the
88 // image is not unique, or if the texture wraps an external object.
89 if (!image->unique() || !texture->unique() || texture->resourcePriv().refsWrappedObjects()) {
90 // onMakeSubset will always copy the image.
91 image = as_IB(image)->onMakeSubset(direct, image->bounds());
92 if (!image) {
93 return false;
94 }
95 return MakeBackendTextureFromImage(direct, std::move(image), backendTexture, releaseProc);
96 }
97
98 SkASSERT(!texture->resourcePriv().refsWrappedObjects());
99 SkASSERT(texture->unique());
101
102 // Take a reference to the GrTexture and release the image.
103 sk_sp<GrTexture> textureRef = sk_ref_sp(texture);
104 view.reset();
105 image = nullptr;
106 SkASSERT(textureRef->unique());
107
108 // Steal the backend texture from the GrTexture, releasing the GrTexture in the process.
109 return GrTexture::StealBackendTexture(std::move(textureRef), backendTexture, releaseProc);
110}
111
113 GrBackendTexture* outTexture,
114 bool flushPendingGrContextIO,
115 GrSurfaceOrigin* origin) {
116 if (!img) {
117 return false;
118 }
119 auto ib = as_IB(img);
120 if (ib->type() != SkImage_Base::Type::kGanesh) {
121 return false;
122 }
123 auto ig = static_cast<const SkImage_Ganesh*>(img);
124 return ig->getExistingBackendTexture(outTexture, flushPendingGrContextIO, origin);
125}
126
128 const GrBackendTexture& backendTexture,
129 GrSurfaceOrigin origin,
130 SkAlphaType alphaType,
131 sk_sp<SkColorSpace> colorSpace,
132 TextureReleaseProc textureReleaseProc,
133 ReleaseContext releaseContext) {
134 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
135
136 if (!context) {
137 return nullptr;
138 }
139
140 const GrCaps* caps = context->priv().caps();
141
142 if (!SkImage_GaneshBase::ValidateCompressedBackendTexture(caps, backendTexture, alphaType)) {
143 return nullptr;
144 }
145
146 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
148 proxyProvider->wrapCompressedBackendTexture(backendTexture,
151 std::move(releaseHelper));
152 if (!proxy) {
153 return nullptr;
154 }
155
159
160 GrSurfaceProxyView view(std::move(proxy), origin, skgpu::Swizzle::RGBA());
161 return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(context),
163 std::move(view),
164 SkColorInfo(ct, alphaType, std::move(colorSpace)));
165}
166
168 const GrBackendTexture& backendTex,
170 GrSurfaceOrigin origin,
171 SkAlphaType at,
172 sk_sp<SkColorSpace> colorSpace,
173 GrWrapOwnership ownership,
174 sk_sp<skgpu::RefCntedCallback> releaseHelper) {
175 if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) {
176 return nullptr;
177 }
178
179 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
180 sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture(
181 backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper));
182 if (!proxy) {
183 return nullptr;
184 }
185
186 skgpu::Swizzle swizzle =
187 rContext->priv().caps()->getReadSwizzle(proxy->backendFormat(), colorType);
188 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
189 SkColorInfo info(GrColorTypeToSkColorType(colorType), at, std::move(colorSpace));
190 return sk_make_sp<SkImage_Ganesh>(
191 sk_ref_sp(rContext), kNeedNewImageUniqueID, std::move(view), std::move(info));
192}
193
195 const GrBackendTexture& backendTexture,
196 GrSurfaceOrigin origin,
198 SkAlphaType alphaType,
199 sk_sp<SkColorSpace> colorSpace,
200 TextureReleaseProc textureReleaseProc,
201 ReleaseContext releaseContext) {
202 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, releaseContext);
203
204 if (!context) {
205 return nullptr;
206 }
207
208 const GrCaps* caps = context->priv().caps();
209
211 if (GrColorType::kUnknown == grColorType) {
212 return nullptr;
213 }
214
216 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
217 return nullptr;
218 }
219
220 return new_wrapped_texture_common(context,
221 backendTexture,
222 grColorType,
223 origin,
224 alphaType,
225 std::move(colorSpace),
227 std::move(releaseHelper));
228}
229
231 const GrBackendTexture& backendTexture,
232 GrSurfaceOrigin textureOrigin,
234 return AdoptTextureFrom(
235 context, backendTexture, textureOrigin, colorType, kPremul_SkAlphaType, nullptr);
236}
237
239 const GrBackendTexture& backendTexture,
240 GrSurfaceOrigin textureOrigin,
242 SkAlphaType alphaType) {
243 return AdoptTextureFrom(context, backendTexture, textureOrigin, colorType, alphaType, nullptr);
244}
245
247 const GrBackendTexture& backendTexture,
248 GrSurfaceOrigin origin,
250 SkAlphaType alphaType,
251 sk_sp<SkColorSpace> colorSpace) {
252 auto dContext = GrAsDirectContext(context);
253 if (!dContext) {
254 // We have a DDL context and we don't support adopted textures for them.
255 return nullptr;
256 }
257
258 const GrCaps* caps = dContext->priv().caps();
259
261 if (GrColorType::kUnknown == grColorType) {
262 return nullptr;
263 }
264
266 caps, backendTexture, grColorType, colorType, alphaType, colorSpace)) {
267 return nullptr;
268 }
269
270 return new_wrapped_texture_common(dContext,
271 backendTexture,
272 grColorType,
273 origin,
274 alphaType,
275 std::move(colorSpace),
277 nullptr);
278}
279
281 sk_sp<SkData> data,
282 int width,
283 int height,
285 skgpu::Mipmapped mipmapped,
286 GrProtected isProtected) {
287 if (!direct || !data) {
288 return nullptr;
289 }
290
291 GrBackendFormat beFormat = direct->compressedBackendFormat(type);
292 if (!beFormat.isValid()) {
294 if (!tmp) {
295 return nullptr;
296 }
297 return TextureFromImage(direct, tmp, mipmapped);
298 }
299
300 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
302 {width, height}, skgpu::Budgeted::kYes, mipmapped, isProtected, type, std::move(data));
303 if (!proxy) {
304 return nullptr;
305 }
306 GrSurfaceProxyView view(std::move(proxy));
307
309
310 return sk_make_sp<SkImage_Ganesh>(sk_ref_sp(direct),
312 std::move(view),
314}
315
317 const GrBackendFormat& backendFormat,
318 SkISize dimensions,
319 skgpu::Mipmapped mipmapped,
320 GrSurfaceOrigin origin,
322 SkAlphaType alphaType,
323 sk_sp<SkColorSpace> colorSpace,
324 PromiseImageTextureFulfillProc textureFulfillProc,
325 PromiseImageTextureReleaseProc textureReleaseProc,
326 PromiseImageTextureContext textureContext) {
327 // Our contract is that we will always call the release proc even on failure.
328 // We use the helper to convey the context, so we need to ensure make doesn't fail.
329 textureReleaseProc = textureReleaseProc ? textureReleaseProc : [](void*) {};
330 auto releaseHelper = skgpu::RefCntedCallback::Make(textureReleaseProc, textureContext);
331 SkImageInfo info = SkImageInfo::Make(dimensions, colorType, alphaType, colorSpace);
332 if (!SkImageInfoIsValid(info)) {
333 return nullptr;
334 }
335
336 if (!threadSafeProxy) {
337 return nullptr;
338 }
339
340 if (dimensions.isEmpty()) {
341 return nullptr;
342 }
343
345 if (GrColorType::kUnknown == grColorType) {
346 return nullptr;
347 }
348
349 if (!threadSafeProxy->priv().caps()->areColorTypeAndFormatCompatible(grColorType,
350 backendFormat)) {
351 return nullptr;
352 }
353
354 auto proxy = SkImage_GaneshBase::MakePromiseImageLazyProxy(threadSafeProxy.get(),
355 dimensions,
356 backendFormat,
357 mipmapped,
358 textureFulfillProc,
359 std::move(releaseHelper));
360 if (!proxy) {
361 return nullptr;
362 }
363 skgpu::Swizzle swizzle =
364 threadSafeProxy->priv().caps()->getReadSwizzle(backendFormat, grColorType);
365 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
366 sk_sp<GrImageContext> ctx(GrImageContextPriv::MakeForPromiseImage(std::move(threadSafeProxy)));
367 return sk_make_sp<SkImage_Ganesh>(std::move(ctx),
369 std::move(view),
370 SkColorInfo(colorType, alphaType, std::move(colorSpace)));
371}
372
374 const SkPixmap& originalPixmap,
375 bool buildMips,
376 bool limitToMaxTextureSize) {
377 // Some backends or drivers don't support (safely) moving resources between contexts
378 if (!dContext || !dContext->priv().caps()->crossContextTextureSupport()) {
379 return RasterFromPixmapCopy(originalPixmap);
380 }
381
382 // If non-power-of-two mipmapping isn't supported, ignore the client's request
383 if (!dContext->priv().caps()->mipmapSupport()) {
384 buildMips = false;
385 }
386
387 const SkPixmap* pixmap = &originalPixmap;
388 SkAutoPixmapStorage resized;
389 int maxTextureSize = dContext->priv().caps()->maxTextureSize();
390 int maxDim = std::max(originalPixmap.width(), originalPixmap.height());
391 if (limitToMaxTextureSize && maxDim > maxTextureSize) {
392 float scale = static_cast<float>(maxTextureSize) / maxDim;
393 int newWidth = std::min(static_cast<int>(originalPixmap.width() * scale), maxTextureSize);
394 int newHeight = std::min(static_cast<int>(originalPixmap.height() * scale), maxTextureSize);
395 SkImageInfo info = originalPixmap.info().makeWH(newWidth, newHeight);
397 if (!resized.tryAlloc(info) || !originalPixmap.scalePixels(resized, sampling)) {
398 return nullptr;
399 }
400 pixmap = &resized;
401 }
402 // Turn the pixmap into a GrTextureProxy
403 SkBitmap bmp;
404 bmp.installPixels(*pixmap);
405 skgpu::Mipmapped mipmapped = buildMips ? skgpu::Mipmapped::kYes : skgpu::Mipmapped::kNo;
406 auto [view, ct] = GrMakeUncachedBitmapProxyView(dContext, bmp, mipmapped);
407 if (!view) {
408 return RasterFromPixmapCopy(*pixmap);
409 }
410
411 sk_sp<GrTexture> texture = sk_ref_sp(view.proxy()->peekTexture());
412
413 // Flush any writes or uploads
414 dContext->priv().flushSurface(view.proxy());
415 GrGpu* gpu = dContext->priv().getGpu();
416
417 std::unique_ptr<GrSemaphore> sema = gpu->prepareTextureForCrossContextUsage(texture.get());
418
421 view.origin(),
422 std::move(sema),
423 skCT,
424 pixmap->alphaType(),
425 pixmap->info().refColorSpace());
426 return DeferredFromTextureGenerator(std::move(gen));
427}
428
430 const SkImage* img,
431 skgpu::Mipmapped mipmapped,
432 skgpu::Budgeted budgeted) {
433 if (!dContext || !img) {
434 return nullptr;
435 }
436 auto ib = as_IB(img);
437 if (!dContext->priv().caps()->mipmapSupport() || ib->dimensions().area() <= 1) {
438 mipmapped = skgpu::Mipmapped::kNo;
439 }
440
441 if (ib->isGaneshBacked()) {
442 if (!ib->context()->priv().matches(dContext)) {
443 return nullptr;
444 }
445
446 if (mipmapped == skgpu::Mipmapped::kNo || ib->hasMipmaps()) {
447 return sk_ref_sp(const_cast<SkImage_Base*>(ib));
448 }
449 }
450 GrImageTexGenPolicy policy = budgeted == skgpu::Budgeted::kYes
453 // TODO: Don't flatten YUVA images here. Add mips to the planes instead.
454 auto [view, ct] = skgpu::ganesh::AsView(dContext, ib, mipmapped, policy);
455 if (!view) {
456 return nullptr;
457 }
458 SkASSERT(view.asTextureProxy());
459 SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
460 view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
461 SkColorInfo colorInfo(GrColorTypeToSkColorType(ct), ib->alphaType(), ib->refColorSpace());
462 return sk_make_sp<SkImage_Ganesh>(
463 sk_ref_sp(dContext), ib->uniqueID(), std::move(view), std::move(colorInfo));
464}
465
466} // namespace SkImages
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SkTextureCompressionType GrBackendFormatToCompressionType(const GrBackendFormat &format)
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
@ kRead_GrIOType
GrWrapOwnership
Definition GrTypesPriv.h:76
@ kAdopt_GrWrapOwnership
Definition GrTypesPriv.h:81
@ kBorrow_GrWrapOwnership
Definition GrTypesPriv.h:78
static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct)
GrColorType
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
GrSurfaceOrigin
Definition GrTypes.h:147
SkAlphaType
Definition SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeUncachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
Definition SkGr.cpp:253
GrImageTexGenPolicy
Definition SkGr.h:141
static void releaseProc(const void *ptr, void *context)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static bool SkImageInfoIsValid(const SkImageInfo &info)
@ kNeedNewImageUniqueID
static SkImage_Base * as_IB(SkImage *image)
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
Type::kYUV Type::kRGBA() int(0.7 *637)
bool isValid() const
static std::unique_ptr< GrTextureGenerator > Make(const sk_sp< GrTexture > &, GrSurfaceOrigin, std::unique_ptr< GrSemaphore >, SkColorType, SkAlphaType, sk_sp< SkColorSpace >)
GrBackendFormat getBackendFormat() const
const GrCaps * caps() const
bool mipmapSupport() const
Definition GrCaps.h:72
bool crossContextTextureSupport() const
Definition GrCaps.h:411
int maxTextureSize() const
Definition GrCaps.h:229
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition GrCaps.cpp:443
SK_API GrBackendFormat compressedBackendFormat(SkTextureCompressionType) const
GrSemaphoresSubmitted flushSurface(GrSurfaceProxy *proxy, SkSurfaces::BackendSurfaceAccess access=SkSurfaces::BackendSurfaceAccess::kNoAccess, const GrFlushInfo &info={}, const skgpu::MutableTextureState *newState=nullptr)
GrDirectContextPriv priv()
Definition GrGpu.h:62
virtual std::unique_ptr< GrSemaphore > prepareTextureForCrossContextUsage(GrTexture *)=0
static sk_sp< GrImageContext > MakeForPromiseImage(sk_sp< GrContextThreadSafeProxy > tsp)
sk_sp< GrTextureProxy > wrapBackendTexture(const GrBackendTexture &, GrWrapOwnership, GrWrapCacheable, GrIOType, sk_sp< skgpu::RefCntedCallback >=nullptr)
sk_sp< GrTextureProxy > wrapCompressedBackendTexture(const GrBackendTexture &, GrWrapOwnership, GrWrapCacheable, sk_sp< skgpu::RefCntedCallback >)
sk_sp< GrTextureProxy > createCompressedTextureProxy(SkISize dimensions, skgpu::Budgeted, skgpu::Mipmapped, GrProtected, SkTextureCompressionType, sk_sp< SkData > data)
GrProxyProvider * proxyProvider()
GrRecordingContextPriv priv()
static bool StealBackendTexture(sk_sp< GrTexture >, GrBackendTexture *, SkImages::BackendTextureReleaseProc *)
Definition GrTexture.cpp:61
bool tryAlloc(const SkImageInfo &)
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition SkBitmap.cpp:323
virtual sk_sp< SkImage > onMakeSubset(GrDirectContext *, const SkIRect &) const =0
static bool ValidateBackendTexture(const GrCaps *, const GrBackendTexture &tex, GrColorType grCT, SkColorType ct, SkAlphaType at, sk_sp< SkColorSpace > cs)
static bool ValidateCompressedBackendTexture(const GrCaps *, const GrBackendTexture &tex, SkAlphaType)
static sk_sp< GrTextureProxy > MakePromiseImageLazyProxy(GrContextThreadSafeProxy *, SkISize dimensions, const GrBackendFormat &, skgpu::Mipmapped, SkImages::PromiseImageTextureFulfillProc, sk_sp< skgpu::RefCntedCallback > releaseHelper)
bool getExistingBackendTexture(GrBackendTexture *outTexture, bool flushPendingGrContextIO, GrSurfaceOrigin *origin) const
SkIRect bounds() const
Definition SkImage.h:303
bool scalePixels(const SkPixmap &dst, const SkSamplingOptions &) const
int width() const
Definition SkPixmap.h:160
const SkImageInfo & info() const
Definition SkPixmap.h:135
int height() const
Definition SkPixmap.h:166
SkAlphaType alphaType() const
Definition SkPixmap.h:175
bool unique() const
Definition SkRefCnt.h:50
T * get() const
Definition SkRefCnt.h:303
static sk_sp< RefCntedCallback > Make(Callback proc, Context ctx)
static constexpr Swizzle RGBA()
Definition Swizzle.h:66
sk_sp< SkImage > image
Definition examples.cpp:29
FlTexture * texture
SK_API sk_sp< SkImage > DeferredFromTextureGenerator(std::unique_ptr< GrTextureGenerator > gen)
void * PromiseImageTextureContext
SK_API sk_sp< SkImage > TextureFromCompressedTexture(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SK_API sk_sp< SkImage > TextureFromImage(GrDirectContext *, const SkImage *, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Budgeted=skgpu::Budgeted::kYes)
SK_API sk_sp< SkImage > AdoptTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin textureOrigin, SkColorType colorType)
SK_API sk_sp< SkImage > CrossContextTextureFromPixmap(GrDirectContext *context, const SkPixmap &pixmap, bool buildMips, bool limitToMaxTextureSize=false)
void * ReleaseContext
Definition SkImage.h:50
SK_API sk_sp< SkImage > RasterFromPixmapCopy(const SkPixmap &pixmap)
SK_API sk_sp< SkImage > TextureFromCompressedTextureData(GrDirectContext *direct, sk_sp< SkData > data, int width, int height, SkTextureCompressionType type, skgpu::Mipmapped mipmapped=skgpu::Mipmapped::kNo, GrProtected isProtected=GrProtected::kNo)
std::function< void(GrBackendTexture)> BackendTextureReleaseProc
void(*)(PromiseImageTextureContext) PromiseImageTextureReleaseProc
SK_API bool GetBackendTextureFromImage(const SkImage *img, GrBackendTexture *outTexture, bool flushPendingGrContextIO, GrSurfaceOrigin *origin=nullptr)
SK_API sk_sp< SkImage > PromiseTextureFrom(skgpu::graphite::Recorder *, SkISize dimensions, const skgpu::graphite::TextureInfo &, const SkColorInfo &, skgpu::Origin origin, skgpu::graphite::Volatile, GraphitePromiseTextureFulfillProc, GraphitePromiseImageReleaseProc, GraphitePromiseTextureReleaseProc, GraphitePromiseImageContext)
SK_API sk_sp< SkImage > BorrowTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
SK_API sk_sp< SkImage > RasterFromCompressedTextureData(sk_sp< SkData > data, int width, int height, SkTextureCompressionType type)
void(*)(ReleaseContext) TextureReleaseProc
static sk_sp< SkImage > 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)
SK_API bool MakeBackendTextureFromImage(GrDirectContext *context, sk_sp< SkImage > image, GrBackendTexture *backendTexture, BackendTextureReleaseProc *backendTextureReleaseProc)
Definition gen.py:1
std::tuple< GrSurfaceProxyView, GrColorType > AsView(GrRecordingContext *rContext, const SkImage *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
static constexpr SkColorType CompressionTypeToSkColorType(SkTextureCompressionType compression)
Budgeted
Definition GpuTypes.h:35
Mipmapped
Definition GpuTypes.h:53
Protected
Definition GpuTypes.h:61
int32_t height
int32_t width
const Scalar scale
bool isEmpty() const
Definition SkSize.h:31
SkImageInfo makeWH(int newWidth, int newHeight) const
sk_sp< SkColorSpace > refColorSpace() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)