Flutter macOS Embedder
FlutterSurface.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #import <CoreMedia/CoreMedia.h>
8 #import <Metal/Metal.h>
9 
10 #import "flutter/fml/platform/darwin/cf_utils.h"
11 
12 @interface FlutterSurface () {
13  CGSize _size;
14  fml::CFRef<IOSurfaceRef> _ioSurface;
15  id<MTLTexture> _texture;
16  // Used for testing.
18  // Whether this surface was created with wide gamut enabled.
20 }
21 @end
22 
23 @implementation FlutterSurface
24 
25 - (IOSurfaceRef)ioSurface {
26  return _ioSurface;
27 }
28 
29 - (CGSize)size {
30  return _size;
31 }
32 
33 - (int64_t)textureId {
34  return reinterpret_cast<int64_t>(_texture);
35 }
36 
37 - (BOOL)isInUse {
38  return _isInUseOverride || IOSurfaceIsInUse(_ioSurface);
39 }
40 
41 - (BOOL)isWideGamut {
42  return _isWideGamut;
43 }
44 
45 - (BOOL)isInUseOverride {
46  return _isInUseOverride;
47 }
48 
49 - (void)setIsInUseOverride:(BOOL)isInUseOverride {
50  _isInUseOverride = isInUseOverride;
51 }
52 
53 - (instancetype)initWithSize:(CGSize)size
54  device:(id<MTLDevice>)device
55  enableWideGamut:(BOOL)enableWideGamut {
56  if (self = [super init]) {
57  self->_size = size;
58  self->_isWideGamut = enableWideGamut;
59  self->_ioSurface.Reset([FlutterSurface createIOSurfaceWithSize:size
60  enableWideGamut:enableWideGamut]);
61  MTLPixelFormat pixelFormat =
62  enableWideGamut ? MTLPixelFormatBGRA10_XR : MTLPixelFormatBGRA8Unorm;
63  self->_texture = [FlutterSurface createTextureForIOSurface:_ioSurface
64  size:size
65  device:device
66  pixelFormat:pixelFormat];
67  }
68  return self;
69 }
70 
71 - (FlutterMetalTexture)asFlutterMetalTexture {
72  return FlutterMetalTexture{
73  .struct_size = sizeof(FlutterMetalTexture),
74  .texture_id = self.textureId,
75  .texture = (__bridge void*)_texture,
76  // Retain for use in [FlutterSurface fromFlutterMetalTexture]. Released in
77  // destruction_callback.
78  .user_data = (__bridge_retained void*)self,
79  .destruction_callback =
80  [](void* user_data) {
81  // Balancing release for the retain when setting user_data above.
82  FlutterSurface* surface = (__bridge_transfer FlutterSurface*)user_data;
83  surface = nil;
84  },
85  };
86 }
87 
88 + (FlutterSurface*)fromFlutterMetalTexture:(const FlutterMetalTexture*)texture {
89  return (__bridge FlutterSurface*)texture->user_data;
90 }
91 
92 + (IOSurfaceRef)createIOSurfaceWithSize:(CGSize)size enableWideGamut:(BOOL)enableWideGamut {
93  unsigned pixelFormat;
94  unsigned bytesPerElement;
95  if (enableWideGamut) {
96  // 10-bit wide gamut format (same as iOS)
97  pixelFormat = kCVPixelFormatType_40ARGBLEWideGamut;
98  bytesPerElement = 8;
99  } else {
100  pixelFormat = kCVPixelFormatType_32BGRA;
101  bytesPerElement = 4;
102  }
103 
104  size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size.width * bytesPerElement);
105  size_t totalBytes = IOSurfaceAlignProperty(kIOSurfaceAllocSize, size.height * bytesPerRow);
106  NSDictionary* options = @{
107  (id)kIOSurfaceWidth : @(size.width),
108  (id)kIOSurfaceHeight : @(size.height),
109  (id)kIOSurfacePixelFormat : @(pixelFormat),
110  (id)kIOSurfaceBytesPerElement : @(bytesPerElement),
111  (id)kIOSurfaceBytesPerRow : @(bytesPerRow),
112  (id)kIOSurfaceAllocSize : @(totalBytes),
113  };
114 
115  IOSurfaceRef res = IOSurfaceCreate((CFDictionaryRef)options);
116  if (enableWideGamut) {
117  IOSurfaceSetValue(res, kIOSurfaceColorSpace, kCGColorSpaceExtendedSRGB);
118  } else {
119  IOSurfaceSetValue(res, kIOSurfaceColorSpace, kCGColorSpaceSRGB);
120  }
121  return res;
122 }
123 
124 + (id<MTLTexture>)createTextureForIOSurface:(IOSurfaceRef)surface
125  size:(CGSize)size
126  device:(id<MTLDevice>)device
127  pixelFormat:(MTLPixelFormat)pixelFormat {
128  MTLTextureDescriptor* textureDescriptor =
129  [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat
130  width:size.width
131  height:size.height
132  mipmapped:NO];
133  textureDescriptor.usage =
134  MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsageShaderWrite;
135  // plane = 0 for BGRA.
136  return [device newTextureWithDescriptor:textureDescriptor iosurface:surface plane:0];
137 }
138 
139 @end
id< FlutterTexture > _texture
fml::CFRef< IOSurfaceRef > _ioSurface
id< MTLTexture > _texture
FlutterMetalTexture asFlutterMetalTexture()
void * user_data
int64_t texture_id