1
+ #[ cfg( target_os = "macos" ) ]
2
+ use std:: os:: raw:: c_void;
3
+
4
+ #[ cfg( all( feature = "accelerated_paint" , target_os = "macos" ) ) ]
5
+ use ash:: vk;
6
+ #[ cfg( all( feature = "accelerated_paint" , target_os = "macos" ) ) ]
7
+ use wgpu:: hal:: api;
8
+ #[ cfg( all( feature = "accelerated_paint" , target_os = "macos" ) ) ]
9
+ use objc2_io_surface:: { IOSurface , IOSurfaceRef } ;
10
+ #[ cfg( all( feature = "accelerated_paint" , target_os = "macos" ) ) ]
11
+ use objc2_metal:: { MTLDevice , MTLTexture , MTLTextureDescriptor , MTLPixelFormat } ;
12
+ #[ cfg( all( feature = "accelerated_paint" , target_os = "macos" ) ) ]
13
+ use core_foundation:: base:: { CFType , TCFType } ;
14
+
15
+ #[ cfg( target_os = "macos" ) ]
16
+ pub struct IOSurfaceTexture {
17
+ pub handle : * mut c_void ,
18
+ pub width : u32 ,
19
+ pub height : u32 ,
20
+ pub format : cef:: sys:: cef_color_type_t ,
21
+ }
22
+
23
+ #[ cfg( target_os = "macos" ) ]
24
+ impl IOSurfaceTexture {
25
+ pub fn import_to_wgpu ( & self , device : & wgpu:: Device ) -> Result < wgpu:: Texture , String > {
26
+ tracing:: debug!(
27
+ "IOSurface texture import requested: {}x{} handle={:p}" ,
28
+ self . width,
29
+ self . height,
30
+ self . handle
31
+ ) ;
32
+
33
+ // Try to import via Metal/Vulkan, fallback to CPU texture on failure
34
+ #[ cfg( feature = "accelerated_paint" ) ]
35
+ {
36
+ match self . import_via_vulkan ( device) {
37
+ Ok ( texture) => {
38
+ tracing:: info!( "Successfully imported IOSurface texture via Vulkan" ) ;
39
+ return Ok ( texture) ;
40
+ }
41
+ Err ( e) => {
42
+ tracing:: warn!( "Failed to import IOSurface via Vulkan: {}, falling back to CPU texture" , e) ;
43
+ }
44
+ }
45
+ }
46
+
47
+ // Fallback: create empty CPU texture with same dimensions
48
+ self . create_fallback_texture ( device)
49
+ }
50
+
51
+ #[ cfg( feature = "accelerated_paint" ) ]
52
+ fn import_via_vulkan ( & self , device : & wgpu:: Device ) -> Result < wgpu:: Texture , String > {
53
+ // Validate handle
54
+ if self . handle . is_null ( ) {
55
+ return Err ( "IOSurface handle is null" . to_string ( ) ) ;
56
+ }
57
+
58
+ // Get wgpu's Vulkan instance and device
59
+ use wgpu:: { TextureUses , wgc:: api:: Vulkan } ;
60
+ let hal_texture = unsafe {
61
+ device. as_hal :: < api:: Vulkan , _ , _ > ( |device| {
62
+ let Some ( device) = device else {
63
+ return Err ( "Device is not using Vulkan backend" . to_string ( ) ) ;
64
+ } ;
65
+
66
+ // Import IOSurface handle into Vulkan via Metal
67
+ let vk_image = self . import_iosurface_to_vulkan ( device) . map_err ( |e| format ! ( "Failed to create Vulkan image from IOSurface: {}" , e) ) ?;
68
+
69
+ // Wrap VkImage in wgpu-hal texture
70
+ let hal_texture = <api:: Vulkan as wgpu:: hal:: Api >:: Device :: texture_from_raw (
71
+ vk_image,
72
+ & wgpu:: hal:: TextureDescriptor {
73
+ label : Some ( "CEF IOSurface Texture" ) ,
74
+ size : wgpu:: Extent3d {
75
+ width : self . width ,
76
+ height : self . height ,
77
+ depth_or_array_layers : 1 ,
78
+ } ,
79
+ mip_level_count : 1 ,
80
+ sample_count : 1 ,
81
+ dimension : wgpu:: TextureDimension :: D2 ,
82
+ format : self . cef_to_hal_format ( ) ?,
83
+ usage : TextureUses :: COPY_DST | TextureUses :: RESOURCE ,
84
+ memory_flags : wgpu:: hal:: MemoryFlags :: empty ( ) ,
85
+ view_formats : vec ! [ ] ,
86
+ } ,
87
+ None , // drop_callback
88
+ ) ;
89
+
90
+ Ok ( hal_texture)
91
+ } )
92
+ } ?;
93
+
94
+ // Import hal texture into wgpu
95
+ let texture = unsafe {
96
+ device. create_texture_from_hal :: < Vulkan > (
97
+ hal_texture,
98
+ & wgpu:: TextureDescriptor {
99
+ label : Some ( "CEF IOSurface Texture" ) ,
100
+ size : wgpu:: Extent3d {
101
+ width : self . width ,
102
+ height : self . height ,
103
+ depth_or_array_layers : 1 ,
104
+ } ,
105
+ mip_level_count : 1 ,
106
+ sample_count : 1 ,
107
+ dimension : wgpu:: TextureDimension :: D2 ,
108
+ format : self . cef_to_wgpu_format ( ) ?,
109
+ usage : wgpu:: TextureUsages :: TEXTURE_BINDING ,
110
+ view_formats : & [ ] ,
111
+ } ,
112
+ )
113
+ } ;
114
+
115
+ Ok ( texture)
116
+ }
117
+
118
+ #[ cfg( feature = "accelerated_paint" ) ]
119
+ fn import_iosurface_to_vulkan ( & self , hal_device : & <api:: Vulkan as wgpu:: hal:: Api >:: Device ) -> Result < vk:: Image , String > {
120
+ // Get raw Vulkan handles
121
+ let device = hal_device. raw_device ( ) ;
122
+ let _instance = hal_device. shared_instance ( ) . raw_instance ( ) ;
123
+
124
+ // Validate dimensions
125
+ if self . width == 0 || self . height == 0 {
126
+ return Err ( "Invalid IOSurface texture dimensions" . to_string ( ) ) ;
127
+ }
128
+
129
+ // Convert handle to IOSurface
130
+ let iosurface = unsafe {
131
+ let cf_type = CFType :: wrap_under_get_rule ( self . handle as IOSurfaceRef ) ;
132
+ IOSurface :: from ( cf_type)
133
+ } ;
134
+
135
+ // Create Metal texture from IOSurface
136
+ let mtl_texture = self . create_metal_texture_from_iosurface ( & iosurface) ?;
137
+
138
+ // Import Metal texture into Vulkan using VK_EXT_metal_objects
139
+ self . import_metal_texture_to_vulkan ( device, & mtl_texture)
140
+ }
141
+
142
+ #[ cfg( feature = "accelerated_paint" ) ]
143
+ fn create_metal_texture_from_iosurface ( & self , iosurface : & IOSurface ) -> Result < MTLTexture , String > {
144
+ // Get Metal device (this would need to be obtained from wgpu-hal)
145
+ // For now, we'll create a simple fallback
146
+ tracing:: warn!( "Metal texture creation from IOSurface not fully implemented" ) ;
147
+ Err ( "Metal texture creation not available" . to_string ( ) )
148
+ }
149
+
150
+ #[ cfg( feature = "accelerated_paint" ) ]
151
+ fn import_metal_texture_to_vulkan ( & self , device : vk:: Device , _mtl_texture : & MTLTexture ) -> Result < vk:: Image , String > {
152
+ // Create external memory image info for Metal objects
153
+ let mut external_memory_info = vk:: ExternalMemoryImageCreateInfo :: default ( )
154
+ . handle_types ( vk:: ExternalMemoryHandleTypeFlags :: MTLTEXTURE_EXT ) ;
155
+
156
+ // Create image create info
157
+ let image_create_info = vk:: ImageCreateInfo :: default ( )
158
+ . image_type ( vk:: ImageType :: TYPE_2D )
159
+ . format ( self . cef_to_vk_format ( ) ?)
160
+ . extent ( vk:: Extent3D {
161
+ width : self . width ,
162
+ height : self . height ,
163
+ depth : 1 ,
164
+ } )
165
+ . mip_levels ( 1 )
166
+ . array_layers ( 1 )
167
+ . samples ( vk:: SampleCountFlags :: TYPE_1 )
168
+ . tiling ( vk:: ImageTiling :: OPTIMAL )
169
+ . usage ( vk:: ImageUsageFlags :: SAMPLED | vk:: ImageUsageFlags :: COLOR_ATTACHMENT )
170
+ . sharing_mode ( vk:: SharingMode :: EXCLUSIVE )
171
+ . push_next ( & mut external_memory_info) ;
172
+
173
+ // Create the image
174
+ let image = unsafe {
175
+ device. create_image ( & image_create_info, None )
176
+ . map_err ( |e| format ! ( "Failed to create Vulkan image: {:?}" , e) ) ?
177
+ } ;
178
+
179
+ // Note: The actual Metal-to-Vulkan import would require VK_EXT_metal_objects
180
+ // and proper Metal texture handle extraction, which is complex and not
181
+ // fully supported in the current objc2 bindings
182
+ tracing:: warn!( "Metal-to-Vulkan texture import not fully implemented" ) ;
183
+
184
+ Ok ( image)
185
+ }
186
+
187
+ fn cef_to_vk_format ( & self ) -> Result < vk:: Format , String > {
188
+ use cef:: sys:: cef_color_type_t;
189
+ match self . format {
190
+ // macOS IOSurfaces are typically BGRA
191
+ cef_color_type_t:: CEF_COLOR_TYPE_BGRA_8888 => Ok ( vk:: Format :: B8G8R8A8_UNORM ) ,
192
+ cef_color_type_t:: CEF_COLOR_TYPE_RGBA_8888 => Ok ( vk:: Format :: R8G8B8A8_UNORM ) ,
193
+ _ => Err ( format ! ( "Unsupported CEF format for Vulkan: {:?}" , self . format) ) ,
194
+ }
195
+ }
196
+
197
+ fn cef_to_hal_format ( & self ) -> Result < wgpu:: TextureFormat , String > {
198
+ use cef:: sys:: cef_color_type_t;
199
+ match self . format {
200
+ // macOS IOSurfaces are typically BGRA with sRGB
201
+ cef_color_type_t:: CEF_COLOR_TYPE_BGRA_8888 => Ok ( wgpu:: TextureFormat :: Bgra8UnormSrgb ) ,
202
+ cef_color_type_t:: CEF_COLOR_TYPE_RGBA_8888 => Ok ( wgpu:: TextureFormat :: Rgba8UnormSrgb ) ,
203
+ _ => Err ( format ! ( "Unsupported CEF format for HAL: {:?}" , self . format) ) ,
204
+ }
205
+ }
206
+
207
+ fn cef_to_wgpu_format ( & self ) -> Result < wgpu:: TextureFormat , String > {
208
+ self . cef_to_hal_format ( )
209
+ }
210
+
211
+ fn create_fallback_texture ( & self , device : & wgpu:: Device ) -> Result < wgpu:: Texture , String > {
212
+ let format = self . cef_to_wgpu_format ( ) ?;
213
+ let texture = device. create_texture ( & wgpu:: TextureDescriptor {
214
+ label : Some ( "CEF IOSurface Texture (fallback)" ) ,
215
+ size : wgpu:: Extent3d {
216
+ width : self . width ,
217
+ height : self . height ,
218
+ depth_or_array_layers : 1 ,
219
+ } ,
220
+ mip_level_count : 1 ,
221
+ sample_count : 1 ,
222
+ dimension : wgpu:: TextureDimension :: D2 ,
223
+ format,
224
+ usage : wgpu:: TextureUsages :: TEXTURE_BINDING | wgpu:: TextureUsages :: COPY_DST ,
225
+ view_formats : & [ ] ,
226
+ } ) ;
227
+
228
+ tracing:: warn!( "Using fallback CPU texture - IOSurface hardware acceleration not available" ) ;
229
+ Ok ( texture)
230
+ }
231
+ }
0 commit comments