14#include "third_party/skia/include/core/SkColorSpace.h"
15#include "third_party/skia/include/core/SkImage.h"
16#include "third_party/skia/include/core/SkYUVAInfo.h"
17#include "third_party/skia/include/gpu/GpuTypes.h"
18#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
19#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
20#include "third_party/skia/include/gpu/ganesh/GrYUVABackendTextures.h"
21#include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h"
22#include "third_party/skia/include/gpu/ganesh/mtl/GrMtlBackendSurface.h"
23#include "third_party/skia/include/gpu/ganesh/mtl/GrMtlTypes.h"
24#include "third_party/skia/include/ports/SkCFObject.h"
38- (instancetype)initWithTextureCache:(nonnull CVMetalTextureCacheRef)textureCache
39 textureID:(int64_t)textureID
41 enableImpeller:(
BOOL)enableImpeller {
42 if (
self = [super init]) {
43 _textureCache.Retain(textureCache);
55 CVMetalTextureCacheFlush(_textureCache, 0);
59- (void)paintContext:(
flutter::Texture::PaintContext&)context
60 bounds:(const SkRect&)bounds
65 if (needsUpdatedTexture) {
66 [
self onNeedsUpdatedTexture:context];
70 context.canvas->DrawImageRect(
81- (void)onNeedsUpdatedTexture:(
flutter::Texture::PaintContext&)context {
82 CVPixelBufferRef pixelBuffer = [_externalTexture copyPixelBuffer];
91 sk_sp<flutter::DlImage>
image = [
self wrapExternalPixelBuffer:_lastPixelBuffer context:context];
98- (void)onGrContextCreated {
104- (void)onGrContextDestroyed {
111 CVMetalTextureCacheFlush(_textureCache, 0);
115- (void)markNewFrameAvailable {
119- (void)onTextureUnregistered {
120 if ([
_externalTexture respondsToSelector:@selector(onTextureUnregistered:)]) {
121 [_externalTexture onTextureUnregistered:_externalTexture];
125#pragma mark - External texture skia wrapper methods.
127- (sk_sp<
flutter::DlImage>)wrapExternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
128 context:(
flutter::Texture::PaintContext&)context {
133 sk_sp<flutter::DlImage>
image =
nullptr;
134 if (
_pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
135 _pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
136 image = [
self wrapNV12ExternalPixelBuffer:pixelBuffer context:context];
138 image = [
self wrapBGRAExternalPixelBuffer:pixelBuffer context:context];
145 FML_DLOG(ERROR) <<
"Could not wrap Metal texture as a display list image.";
151- (sk_sp<
flutter::DlImage>)wrapNV12ExternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
152 context:(
flutter::Texture::PaintContext&)context {
153 SkISize textureSize =
154 SkISize::Make(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));
155 CVMetalTextureRef yMetalTexture =
nullptr;
158 CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
162 MTLPixelFormatR8Unorm,
164 textureSize.height(),
168 if (cvReturn != kCVReturnSuccess) {
169 FML_DLOG(ERROR) <<
"Could not create Metal texture from pixel buffer: CVReturn " << cvReturn;
174 CVMetalTextureRef uvMetalTexture =
nullptr;
177 CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
181 MTLPixelFormatRG8Unorm,
182 textureSize.width() / 2,
183 textureSize.height() / 2,
187 if (cvReturn != kCVReturnSuccess) {
188 FML_DLOG(ERROR) <<
"Could not create Metal texture from pixel buffer: CVReturn " << cvReturn;
193 id<MTLTexture> yTex = CVMetalTextureGetTexture(yMetalTexture);
194 CVBufferRelease(yMetalTexture);
196 id<MTLTexture> uvTex = CVMetalTextureGetTexture(uvMetalTexture);
197 CVBufferRelease(uvMetalTexture);
201 _pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
210 SkYUVColorSpace colorSpace =
_pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
211 ? kRec601_Limited_SkYUVColorSpace
212 : kJPEG_Full_SkYUVColorSpace;
217 width:textureSize.width()
218 height:textureSize.height()];
227- (sk_sp<
flutter::DlImage>)wrapBGRAExternalPixelBuffer:(CVPixelBufferRef)pixelBuffer
228 context:(
flutter::Texture::PaintContext&)context {
229 SkISize textureSize =
230 SkISize::Make(CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer));
231 CVMetalTextureRef metalTexture =
nullptr;
233 CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
237 MTLPixelFormatBGRA8Unorm,
239 textureSize.height(),
243 if (cvReturn != kCVReturnSuccess) {
244 FML_DLOG(ERROR) <<
"Could not create Metal texture from pixel buffer: CVReturn " << cvReturn;
248 id<MTLTexture> rgbaTex = CVMetalTextureGetTexture(metalTexture);
249 CVBufferRelease(metalTexture);
258 width:textureSize.width()
259 height:textureSize.height()];
272+ (sk_sp<SkImage>)wrapYUVATexture:(
id<MTLTexture>)yTex
273 UVTex:(
id<MTLTexture>)uvTex
274 YUVColorSpace:(SkYUVColorSpace)colorSpace
275 grContext:(nonnull GrDirectContext*)grContext
277 height:(
size_t)height {
281 GrMtlTextureInfo ySkiaTextureInfo;
282 ySkiaTextureInfo.fTexture.retain((__bridge GrMTLHandle)yTex);
284 GrBackendTexture skiaBackendTextures[2];
285 skiaBackendTextures[0] =
286 GrBackendTextures::MakeMtl(
width,
height, skgpu::Mipmapped::kNo, ySkiaTextureInfo);
288 GrMtlTextureInfo uvSkiaTextureInfo;
289 uvSkiaTextureInfo.fTexture.retain((__bridge GrMTLHandle)uvTex);
291 skiaBackendTextures[1] =
292 GrBackendTextures::MakeMtl(
width,
height, skgpu::Mipmapped::kNo, uvSkiaTextureInfo);
293 SkYUVAInfo yuvaInfo(skiaBackendTextures[0].dimensions(), SkYUVAInfo::PlaneConfig::kY_UV,
294 SkYUVAInfo::Subsampling::k444, colorSpace);
295 GrYUVABackendTextures yuvaBackendTextures(yuvaInfo, skiaBackendTextures,
296 kTopLeft_GrSurfaceOrigin);
298 return SkImages::TextureFromYUVATextures(grContext, yuvaBackendTextures,
304+ (sk_sp<SkImage>)wrapRGBATexture:(
id<MTLTexture>)rgbaTex
305 grContext:(nonnull GrDirectContext*)grContext
307 height:(
size_t)height {
312 GrMtlTextureInfo skiaTextureInfo;
313 skiaTextureInfo.fTexture.retain((__bridge GrMTLHandle)rgbaTex);
315 GrBackendTexture skiaBackendTexture =
316 GrBackendTextures::MakeMtl(
width,
height, skgpu::Mipmapped ::kNo, skiaTextureInfo);
318 return SkImages::BorrowTextureFrom(grContext, skiaBackendTexture, kTopLeft_GrSurfaceOrigin,
319 kBGRA_8888_SkColorType, kPremul_SkAlphaType,
328+ (sk_sp<
flutter::DlImage>)wrapYUVATexture:(
id<MTLTexture>)yTex
329 UVTex:(
id<MTLTexture>)uvTex
331 aiksContext:(nonnull
impeller::AiksContext*)aiks_context {
353+ (sk_sp<
flutter::DlImage>)wrapRGBATexture:(
id<MTLTexture>)rgbaTex
354 aiksContext:(nonnull
impeller::AiksContext*)aiks_context {
sk_sp< flutter::DlImage > _externalImage
NSObject< FlutterTexture > * _externalTexture
CVPixelBufferRef _lastPixelBuffer
BOOL _textureFrameAvailable
static sk_sp< DlImage > Make(const SkImage *image)
static sk_sp< DlImageImpeller > MakeFromYUVTextures(AiksContext *aiks_context, std::shared_ptr< Texture > y_texture, std::shared_ptr< Texture > uv_texture, YUVColorSpace yuv_color_space)
static sk_sp< DlImageImpeller > Make(std::shared_ptr< Texture > texture, OwningContext owning_context=OwningContext::kIO)
static std::shared_ptr< TextureMTL > Wrapper(TextureDescriptor desc, id< MTLTexture > texture, std::function< void()> deletion_proc=nullptr)
FlutterVulkanImage * image
#define FML_DLOG(severity)
#define FML_LOG(severity)
sk_sp< flutter::DlImage > wrapRGBATexture:aiksContext:(nonnull id< MTLTexture > rgbaTex,[aiksContext] nonnull impeller::AiksContext *aiks_context)
sk_sp< flutter::DlImage > wrapYUVATexture:UVTex:YUVColorSpace:aiksContext:(nonnull id< MTLTexture > yTex,[UVTex] nonnull id< MTLTexture > uvTex,[YUVColorSpace] impeller::YUVColorSpace colorSpace,[aiksContext] nonnull impeller::AiksContext *aiksContext)
sk_sp< SkImage > wrapRGBATexture:grContext:width:height:(nonnull id< MTLTexture > rgbaTex,[grContext] nonnull GrDirectContext *grContext,[width] size_t width,[height] size_t height)
sk_sp< SkImage > wrapYUVATexture:UVTex:YUVColorSpace:grContext:width:height:(nonnull id< MTLTexture > yTex,[UVTex] nonnull id< MTLTexture > uvTex,[YUVColorSpace] SkYUVColorSpace colorSpace,[grContext] nonnull GrDirectContext *grContext,[width] size_t width,[height] size_t height)
const DlRect & ToDlRect(const SkRect &rect)
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...