1use makepad_objc_sys::{msg_send};
7use makepad_objc_sys::runtime::YES;
8use crate::cx_apple::*;
10use crate::cx_cocoa::*;
11use crate::cx::*;
12
13impl Cx {
14
15 pub fn render_view(
16 &mut self,
17 pass_id: usize,
18 view_id: usize,
19 scroll: Vec2,
20 clip: (Vec2, Vec2),
21 zbias: &mut f32,
22 zbias_step: f32,
23 encoder: id,
24 metal_cx: &MetalCx,
25 ) {
26 let draw_calls_len = self.views[view_id].draw_calls_len;
28 self.views[view_id].uniform_view_transform(&Mat4::identity());
30 self.views[view_id].parent_scroll = scroll;
31 let local_scroll = self.views[view_id].get_local_scroll();
32 let clip = self.views[view_id].intersect_clip(clip);
33
34 for draw_call_id in 0..draw_calls_len {
35 let sub_view_id = self.views[view_id].draw_calls[draw_call_id].sub_view_id;
36 if sub_view_id != 0 {
37 self.render_view(
38 pass_id,
39 sub_view_id,
40 Vec2 {x: local_scroll.x + scroll.x, y: local_scroll.y + scroll.y},
41 clip,
42 zbias,
43 zbias_step,
44 encoder,
45 metal_cx,
46 );
47 }
48 else {
49 let cxview = &mut self.views[view_id];
50 let draw_call = &mut cxview.draw_calls[draw_call_id];
52 let sh = &self.shaders[draw_call.shader_id];
53 let shp = sh.platform.as_ref().unwrap();
54
55 if draw_call.instance_dirty {
56 draw_call.instance_dirty = false;
57 self.platform.bytes_written += draw_call.instance.len() * 4;
59 draw_call.platform.inst_vbuf.update_with_f32_data(metal_cx, &draw_call.instance);
60 }
61
62 draw_call.set_zbias(*zbias);
64 draw_call.set_local_scroll(scroll, local_scroll);
65 draw_call.set_clip(clip);
66 *zbias += zbias_step;
67
68 if draw_call.uniforms_dirty {
69 draw_call.uniforms_dirty = false;
70 }
71
72 let instances = (draw_call.instance.len() / sh.mapping.instance_slots) as u64;
74 if instances == 0 {
75 continue;
76 }
77 let pipeline_state = shp.pipeline_state;
78 unsafe {let () = msg_send![encoder, setRenderPipelineState: pipeline_state];}
79
80 if let Some(buf) = shp.geom_vbuf.multi_buffer_read().buffer {
81 unsafe {msg_send![
82 encoder,
83 setVertexBuffer: buf
84 offset: 0
85 atIndex: 0
86 ]}
87 }
88 else {println!("Drawing error: geom_vbuf None")}
89
90 if let Some(buf) = draw_call.platform.inst_vbuf.multi_buffer_read().buffer {
91 unsafe {msg_send![
92 encoder,
93 setVertexBuffer: buf
94 offset: 0
95 atIndex: 1
96 ]}
97 }
98 else {println!("Drawing error: inst_vbuf None")}
99
100 let pass_uniforms = self.passes[pass_id].pass_uniforms.as_slice();
101 let view_uniforms = cxview.view_uniforms.as_slice();
102 let draw_uniforms = draw_call.draw_uniforms.as_slice();
103
104 unsafe {
105 let () = msg_send![encoder, setVertexBytes: pass_uniforms.as_ptr() as *const std::ffi::c_void length: (pass_uniforms.len() * 4) as u64 atIndex: 2u64];
106 let () = msg_send![encoder, setVertexBytes: view_uniforms.as_ptr() as *const std::ffi::c_void length: (view_uniforms.len() * 4) as u64 atIndex: 3u64];
107 let () = msg_send![encoder, setVertexBytes: draw_uniforms.as_ptr() as *const std::ffi::c_void length: (draw_uniforms.len() * 4) as u64 atIndex: 4u64];
108 let () = msg_send![encoder, setVertexBytes: draw_call.uniforms.as_ptr() as *const std::ffi::c_void length: (draw_call.uniforms.len() * 4) as u64 atIndex: 5u64];
109 let () = msg_send![encoder, setFragmentBytes: pass_uniforms.as_ptr() as *const std::ffi::c_void length: (pass_uniforms.len() * 4) as u64 atIndex: 0u64];
110 let () = msg_send![encoder, setFragmentBytes: view_uniforms.as_ptr() as *const std::ffi::c_void length: (view_uniforms.len() * 4) as u64 atIndex: 1u64];
111 let () = msg_send![encoder, setFragmentBytes: draw_uniforms.as_ptr() as *const std::ffi::c_void length: (draw_uniforms.len() * 4) as u64 atIndex: 2u64];
112 let () = msg_send![encoder, setFragmentBytes: draw_call.uniforms.as_ptr() as *const std::ffi::c_void length: (draw_call.uniforms.len() * 4) as u64 atIndex: 3u64];
113 }
114 for (i, texture_id) in draw_call.textures_2d.iter().enumerate() {
124 let cxtexture = &mut self.textures[*texture_id as usize];
125 if cxtexture.update_image {
126 metal_cx.update_platform_texture_image2d(cxtexture);
127 }
128 if let Some(mtl_texture) = cxtexture.platform.mtl_texture {
129 let () = unsafe {msg_send![
130 encoder,
131 setFragmentTexture: mtl_texture
132 atIndex: i as u64
133 ]};
134 let () = unsafe {msg_send![
135 encoder,
136 setVertexTexture: mtl_texture
137 atIndex: i as u64
138 ]};
139 }
140 }
141 self.platform.draw_calls_done += 1;
142 if let Some(buf) = shp.geom_ibuf.multi_buffer_read().buffer {
143
144 let () = unsafe {msg_send![
145 encoder,
146 drawIndexedPrimitives: MTLPrimitiveType::Triangle
147 indexCount: sh.shader_gen.geometry_indices.len() as u64
148 indexType: MTLIndexType::UInt32
149 indexBuffer: buf
150 indexBufferOffset: 0
151 instanceCount: instances
152 ]};
153 }
154 else {println!("Drawing error: geom_ibuf None")}
155 }
156 }
157 }
158
159 pub fn setup_render_pass_descriptor(&mut self, render_pass_descriptor: id, pass_id: usize, inherit_dpi_factor: f32, first_texture: Option<id>, metal_cx: &MetalCx) {
160 let pass_size = self.passes[pass_id].pass_size;
161
162 self.passes[pass_id].set_ortho_matrix(Vec2::default(), pass_size);
163 self.passes[pass_id].uniform_camera_view(&Mat4::identity());
164 self.passes[pass_id].paint_dirty = false;
165 let dpi_factor = if let Some(override_dpi_factor) = self.passes[pass_id].override_dpi_factor {
166 override_dpi_factor
167 }
168 else {
169 inherit_dpi_factor
170 };
171 self.passes[pass_id].set_dpi_factor(dpi_factor);
172
173 for (index, color_texture) in self.passes[pass_id].color_textures.iter().enumerate() {
174 let color_attachments: id = unsafe {msg_send![render_pass_descriptor, colorAttachments]};
175 let color_attachment: id = unsafe {msg_send![color_attachments, objectAtIndexedSubscript: 0]};
176 let is_initial;
179 if index == 0 && first_texture.is_some() {
180 let () = unsafe {msg_send![
181 color_attachment,
182 setTexture: first_texture.unwrap()
183 ]};
184 is_initial = true;
185 }
186 else {
187 let cxtexture = &mut self.textures[color_texture.texture_id];
188 is_initial = metal_cx.update_platform_render_target(cxtexture, dpi_factor, pass_size, false);
189
190 if let Some(mtl_texture) = cxtexture.platform.mtl_texture {
191 let () = unsafe {msg_send![
192 color_attachment,
193 setTexture: mtl_texture
194 ]};
195 }
196 else {
197 println!("draw_pass_to_texture invalid render target");
198 }
199
200 }
201 unsafe {msg_send![color_attachment, setStoreAction: MTLStoreAction::Store]}
202
203 match color_texture.clear_color {
204 ClearColor::InitWith(color) => {
205 if is_initial {
206 unsafe {
207 let () = msg_send![color_attachment, setLoadAction: MTLLoadAction::Clear];
208 let () = msg_send![color_attachment, setClearColor: MTLClearColor {
209 red: color.r as f64,
210 green: color.g as f64,
211 blue: color.b as f64,
212 alpha: color.a as f64
213 }];
214 }
215 }
216 else {
217 unsafe {let () = msg_send![color_attachment, setLoadAction: MTLLoadAction::Load];}
218 }
219 },
220 ClearColor::ClearWith(color) => {
221 unsafe {
222 let () = msg_send![color_attachment, setLoadAction: MTLLoadAction::Clear];
223 let () = msg_send![color_attachment, setClearColor: MTLClearColor {
224 red: color.r as f64,
225 green: color.g as f64,
226 blue: color.b as f64,
227 alpha: color.a as f64
228 }];
229 }
230 }
231 }
232 }
233 if let Some(depth_texture_id) = self.passes[pass_id].depth_texture {
235 let cxtexture = &mut self.textures[depth_texture_id];
236 let is_initial = metal_cx.update_platform_render_target(cxtexture, dpi_factor, pass_size, true);
237
238 let depth_attachment: id = unsafe {msg_send![render_pass_descriptor, depthAttachment]};
239
240 if let Some(mtl_texture) = cxtexture.platform.mtl_texture {
241 unsafe {msg_send![depth_attachment, setTexture: mtl_texture]}
242 }
243 else {
244 println!("draw_pass_to_texture invalid render target");
245 }
246 let () = unsafe {msg_send![depth_attachment, setStoreAction: MTLStoreAction::Store]};
247
248 match self.passes[pass_id].clear_depth {
249 ClearDepth::InitWith(depth) => {
250 if is_initial {
251 let () = unsafe {msg_send![depth_attachment, setLoadAction: MTLLoadAction::Clear]};
252 let () = unsafe {msg_send![depth_attachment, setClearDepth: depth as f64]};
253 }
254 else {
255 let () = unsafe {msg_send![depth_attachment, setLoadAction: MTLLoadAction::Load]};
256 }
257 },
258 ClearDepth::ClearWith(depth) => {
259 let () = unsafe {msg_send![depth_attachment, setLoadAction: MTLLoadAction::Clear]};
260 let () = unsafe {msg_send![depth_attachment, setClearDepth: depth as f64]};
261 }
262 }
263 if self.passes[pass_id].platform.mtl_depth_state.is_none() {
265
266 let desc: id = unsafe {msg_send![class!(MTLDepthStencilDescriptor), new]};
267 let () = unsafe {msg_send![desc, setDepthCompareFunction: MTLCompareFunction::LessEqual]};
268 let () = unsafe {msg_send![desc, setDepthWriteEnabled: true]};
269 let depth_stencil_state: id = unsafe {msg_send![metal_cx.device, newDepthStencilStateWithDescriptor: desc]};
270 self.passes[pass_id].platform.mtl_depth_state = Some(depth_stencil_state);
271 }
272 }
273 }
274
275 pub fn draw_pass_to_layer(
276 &mut self,
277 pass_id: usize,
278 dpi_factor: f32,
279 layer: id,
280 metal_cx: &mut MetalCx,
281 ) {
282 self.platform.bytes_written = 0;
283 self.platform.draw_calls_done = 0;
284 let view_id = self.passes[pass_id].main_view_id.unwrap();
285
286 let pool: id = unsafe {msg_send![class!(NSAutoreleasePool), new]};
287
288 let drawable: id = unsafe {msg_send![layer, nextDrawable]};
290 if drawable != nil {
291 let render_pass_descriptor: id = unsafe {msg_send![class!(MTLRenderPassDescriptorInternal), renderPassDescriptor]};
292
293 let texture: id = unsafe {msg_send![drawable, texture]};
294
295 self.setup_render_pass_descriptor(render_pass_descriptor, pass_id, dpi_factor, Some(texture), metal_cx);
296
297 let command_buffer: id = unsafe {msg_send![metal_cx.command_queue, commandBuffer]};
298 let encoder: id = unsafe {msg_send![command_buffer, renderCommandEncoderWithDescriptor: render_pass_descriptor]};
299
300 unsafe {msg_send![encoder, textureBarrier]}
301
302 if let Some(depth_state) = self.passes[pass_id].platform.mtl_depth_state {
303 let () = unsafe {msg_send![encoder, setDepthStencilState: depth_state]};
304 }
305 let mut zbias = 0.0;
306 let zbias_step = self.passes[pass_id].zbias_step;
307
308 self.render_view(
309 pass_id,
310 view_id,
311 Vec2::default(),
312 (Vec2 {x: -50000., y: -50000.}, Vec2 {x: 50000., y: 50000.}),
313 &mut zbias,
314 zbias_step,
315 encoder,
316 &metal_cx,
317 );
318
319 let () = unsafe {msg_send![encoder, endEncoding]};
320 let () = unsafe {msg_send![command_buffer, presentDrawable: drawable]};
321 let () = unsafe {msg_send![command_buffer, commit]};
322 }
324 let () = unsafe {msg_send![pool, release]};
325 }
326
327 pub fn draw_pass_to_texture(
328 &mut self,
329 pass_id: usize,
330 dpi_factor: f32,
331 metal_cx: &MetalCx,
332 ) {
333 let view_id = self.passes[pass_id].main_view_id.unwrap();
334
335 let pool: id = unsafe {msg_send![class!(NSAutoreleasePool), new]};
336 let render_pass_descriptor: id = unsafe {msg_send![class!(MTLRenderPassDescriptorInternal), renderPassDescriptor]};
337
338 self.setup_render_pass_descriptor(render_pass_descriptor, pass_id, dpi_factor, None, metal_cx);
339
340 let command_buffer: id = unsafe {msg_send![metal_cx.command_queue, commandBuffer]};
341 let encoder: id = unsafe {msg_send![command_buffer, renderCommandEncoderWithDescriptor: render_pass_descriptor]};
342
343 if let Some(depth_state) = self.passes[pass_id].platform.mtl_depth_state {
344 let () = unsafe {msg_send![encoder, setDepthStencilState: depth_state]};
345 }
346
347 let mut zbias = 0.0;
348 let zbias_step = self.passes[pass_id].zbias_step;
349 self.render_view(
350 pass_id,
351 view_id,
352 Vec2::default(),
353 (Vec2 {x: -50000., y: -50000.}, Vec2 {x: 50000., y: 50000.}),
354 &mut zbias,
355 zbias_step,
356 encoder,
357 &metal_cx,
358 );
359 let () = unsafe {msg_send![encoder, textureBarrier]};
360 let () = unsafe {msg_send![encoder, endEncoding]};
361 let () = unsafe {msg_send![command_buffer, commit]};
362 let () = unsafe {msg_send![pool, release]};
364 }
365}
366
367pub struct MetalCx {
368 pub device: id,
369 pub command_queue: id
370}
371
372impl MetalCx {
373
374 pub fn new() -> MetalCx {
375 let devices = get_all_metal_devices();
376 for device in devices {
377 let is_low_power: BOOL = unsafe {msg_send![device, isLowPower]};
378 let command_queue: id = unsafe {msg_send![device, newCommandQueue]};
379 if is_low_power == YES {
380 return MetalCx {
381 command_queue: command_queue,
382 device: device
383 }
384 }
385 }
386 let device = get_default_metal_device().expect("Cannot get default metal device");
387 MetalCx {
388 command_queue: unsafe {msg_send![device, newCommandQueue]},
389 device: device
390 }
391 }
392
393 pub fn update_platform_render_target(&self, cxtexture: &mut CxTexture, dpi_factor: f32, size: Vec2, is_depth: bool) -> bool {
394
395 let width = if let Some(width) = cxtexture.desc.width {width as u64} else {(size.x * dpi_factor) as u64};
396 let height = if let Some(height) = cxtexture.desc.height {height as u64} else {(size.y * dpi_factor) as u64};
397
398 if cxtexture.platform.width == width && cxtexture.platform.height == height && cxtexture.platform.alloc_desc == cxtexture.desc {
399 return false
400 }
401 cxtexture.platform.mtl_texture = None;
402
403 let mdesc: id = unsafe {msg_send![class!(MTLTextureDescriptor), new]};
404 if !is_depth {
405 match cxtexture.desc.format {
406 TextureFormat::Default | TextureFormat::RenderBGRA => {
407 unsafe {
408 let () = msg_send![mdesc, setPixelFormat: MTLPixelFormat::BGRA8Unorm];
409 let () = msg_send![mdesc, setTextureType: MTLTextureType::D2];
410 let () = msg_send![mdesc, setStorageMode: MTLStorageMode::Private];
411 let () = msg_send![mdesc, setUsage: MTLTextureUsage::RenderTarget];
412 }
413 },
414 _ => {
415 println!("update_platform_render_target unsupported texture format");
416 return false;
417 }
418 }
419 }
420 else {
421 match cxtexture.desc.format {
422 TextureFormat::Default | TextureFormat::Depth32Stencil8 => {
423 unsafe {
424 let () = msg_send![mdesc, setPixelFormat: MTLPixelFormat::Depth32Float_Stencil8];
425 let () = msg_send![mdesc, setTextureType: MTLTextureType::D2];
426 let () = msg_send![mdesc, setStorageMode: MTLStorageMode::Private];
427 let () = msg_send![mdesc, setUsage: MTLTextureUsage::RenderTarget];
428 }
429 },
430 _ => {
431 println!("update_platform_render_targete unsupported texture format");
432 return false;
433 }
434 }
435 }
436 let () = unsafe {msg_send![mdesc, setWidth: width as u64]};
437 let () = unsafe {msg_send![mdesc, setHeight: height as u64]};
438 let () = unsafe {msg_send![mdesc, setDepth: 1u64]};
439
440 let tex: id = unsafe {msg_send![self.device, newTextureWithDescriptor: mdesc]};
441
442 cxtexture.platform.width = width;
443 cxtexture.platform.height = height;
444 cxtexture.platform.alloc_desc = cxtexture.desc.clone();
445 cxtexture.platform.mtl_texture = Some(tex);
446 return true
447 }
448
449 pub fn update_platform_texture_image2d(&self, cxtexture: &mut CxTexture) {
450
451 if cxtexture.desc.width.is_none() || cxtexture.desc.height.is_none() {
452 println!("update_platform_texture_image2d without width/height");
453 return;
454 }
455
456 let width = cxtexture.desc.width.unwrap();
457 let height = cxtexture.desc.height.unwrap();
458
459 if cxtexture.platform.alloc_desc != cxtexture.desc {
461 cxtexture.platform.mtl_texture = None;
462
463 let mdesc: id = unsafe {msg_send![class!(MTLTextureDescriptor), new]};
464 unsafe {
465 let () = msg_send![mdesc, setTextureType: MTLTextureType::D2];
466 let () = msg_send![mdesc, setStorageMode: MTLStorageMode::Managed];
467 let () = msg_send![mdesc, setUsage: MTLTextureUsage::RenderTarget];
468 let () = msg_send![mdesc, setWidth: width as u64];
469 let () = msg_send![mdesc, setHeight: height as u64];
470 }
471
472 match cxtexture.desc.format {
473 TextureFormat::Default | TextureFormat::ImageBGRA => {
474 let () = unsafe {msg_send![mdesc, setPixelFormat: MTLPixelFormat::BGRA8Unorm]};
475
476 let tex: id = unsafe {msg_send![self.device, newTextureWithDescriptor: mdesc]};
477
478 cxtexture.platform.mtl_texture = Some(tex);
479
480 if cxtexture.image_u32.len() != width * height {
481 println!("update_platform_texture_image2d with wrong buffer_u32 size!");
482 cxtexture.platform.mtl_texture = None;
483 return;
484 }
485 let region = MTLRegion {
486 origin: MTLOrigin {x: 0, y: 0, z: 0},
487 size: MTLSize {width: width as u64, height: height as u64, depth: 1}
488 };
489 if let Some(mtl_texture) = cxtexture.platform.mtl_texture {
490 let () = unsafe {msg_send![
491 mtl_texture,
492 replaceRegion: region
493 mipmapLevel: 0
494 withBytes: cxtexture.image_u32.as_ptr() as *const std::ffi::c_void
495 bytesPerRow: (width * std::mem::size_of::<u32>()) as u64
496 ]};
497 }
498 },
499 _ => {
500 println!("update_platform_texture_image2d with unsupported format");
501 return;
502 }
503 }
504 cxtexture.platform.alloc_desc = cxtexture.desc.clone();
505 cxtexture.platform.width = width as u64;
506 cxtexture.platform.height = height as u64;
507 }
508
509 cxtexture.update_image = false;
510 }
511}
512
513#[derive(Clone)]
514pub struct MetalWindow {
515 pub window_id: usize,
516 pub first_draw: bool,
517 pub window_geom: WindowGeom,
518 pub cal_size: Vec2,
519 pub ca_layer: id,
520 pub cocoa_window: CocoaWindow,
521}
522
523impl MetalWindow {
524 pub fn new(window_id: usize, metal_cx: &MetalCx, cocoa_app: &mut CocoaApp, inner_size: Vec2, position: Option<Vec2>, title: &str) -> MetalWindow {
525
526 let ca_layer: id = unsafe {msg_send![class!(CAMetalLayer), new]};
527
528 let mut cocoa_window = CocoaWindow::new(cocoa_app, window_id);
529
530 cocoa_window.init(title, inner_size, position);
531
532 unsafe {
533 let () = msg_send![ca_layer, setDevice: metal_cx.device];
534 let () = msg_send![ca_layer, setPixelFormat: MTLPixelFormat::BGRA8Unorm];
535 let () = msg_send![ca_layer, setPresentsWithTransaction: NO];
536 let () = msg_send![ca_layer, setMaximumDrawableCount: 3];
537 let () = msg_send![ca_layer, setDisplaySyncEnabled: NO];
538 let () = msg_send![ca_layer, setNeedsDisplayOnBoundsChange: YES];
539 let () = msg_send![ca_layer, setAutoresizingMask: (1 << 4) | (1 << 1)];
540 let () = msg_send![ca_layer, setAllowsNextDrawableTimeout: NO];
541 let () = msg_send![ca_layer, setDelegate: cocoa_window.view];
542 let () = msg_send![ca_layer, setBackgroundColor: CGColorCreateGenericRGB(0.0, 0.0, 0.0, 1.0)];
543
544 let view = cocoa_window.view;
545 let () = msg_send![view, setWantsBestResolutionOpenGLSurface: YES];
546 let () = msg_send![view, setWantsLayer: YES];
547 let () = msg_send![view, setLayerContentsPlacement: 11];
548 let () = msg_send![view, setLayer: ca_layer];
549 }
550
551 MetalWindow {
552 first_draw: true,
553 window_id,
554 cal_size: Vec2::default(),
555 ca_layer,
556 window_geom: cocoa_window.get_window_geom(),
557 cocoa_window
558 }
559 }
560
561 pub fn set_vsync_enable(&mut self, enable: bool) {
562 let () = unsafe {msg_send![self.ca_layer, setDisplaySyncEnabled: enable]};
563 }
564
565 pub fn set_buffer_count(&mut self, _count: u64) {
566 let () = unsafe {msg_send![self.ca_layer, setMaximumDrawableCount: 3]};
567 }
568
569 pub fn resize_core_animation_layer(&mut self, _metal_cx: &MetalCx) -> bool {
570 let cal_size = Vec2 {
571 x: self.window_geom.inner_size.x * self.window_geom.dpi_factor,
572 y: self.window_geom.inner_size.y * self.window_geom.dpi_factor
573 };
574 if self.cal_size != cal_size {
575 self.cal_size = cal_size;
576 unsafe {
577 let () = msg_send![self.ca_layer, setDrawableSize: CGSize {width: cal_size.x as f64, height: cal_size.y as f64}];
578 let () = msg_send![self.ca_layer, setContentsScale: self.window_geom.dpi_factor as f64];
579 }
580 true
582 }
583 else {
584 false
585 }
586 }
587
588}
589
590#[derive(Clone, Default)]
591pub struct CxPlatformView {
592}
593
594#[derive(Default, Clone)]
595pub struct CxPlatformDrawCall {
596 pub inst_vbuf: MetalBuffer
598}
599
600#[derive(Default, Clone)]
601pub struct CxPlatformTexture {
602 pub alloc_desc: TextureDesc,
603 pub width: u64,
604 pub height: u64,
605 pub mtl_texture: Option<id>
606}
607
608#[derive(Default, Clone)]
609pub struct CxPlatformPass {
610 pub mtl_depth_state: Option<id>
611}
612
613#[derive(Default, Clone)]
614pub struct MultiMetalBuffer {
615 pub buffer: Option<id>,
616 pub size: usize,
617 pub used: usize
618}
619
620#[derive(Default, Clone)]
621pub struct MetalBuffer {
622 pub last_written: usize,
623 pub multi1: MultiMetalBuffer,
624 pub multi2: MultiMetalBuffer,
625 pub multi3: MultiMetalBuffer,
626 pub multi4: MultiMetalBuffer,
627 pub multi5: MultiMetalBuffer,
628 pub multi6: MultiMetalBuffer,
629 pub multi7: MultiMetalBuffer,
630 pub multi8: MultiMetalBuffer,
631 pub multi9: MultiMetalBuffer,
632 pub multi10: MultiMetalBuffer,
633}
634
635impl MetalBuffer {
636 pub fn multi_buffer_read(&self) -> &MultiMetalBuffer {
637 match self.last_written {
638 0 => &self.multi1,
639 1 => &self.multi2,
640 2 => &self.multi3,
641 3 => &self.multi4,
642 _ => &self.multi5,
643 }
644 }
645
646 pub fn multi_buffer_write(&mut self) -> &mut MultiMetalBuffer {
647 self.last_written = (self.last_written + 1) % 5;
648 match self.last_written {
649 0 => &mut self.multi1,
650 1 => &mut self.multi2,
651 2 => &mut self.multi3,
652 3 => &mut self.multi4,
653 _ => &mut self.multi5,
654 }
655 }
656
657 pub fn update_with_f32_data(&mut self, metal_cx: &MetalCx, data: &Vec<f32>) {
658 let elem = self.multi_buffer_write();
659 if elem.size < data.len() {
660 elem.buffer = None;
661 }
662 if let None = elem.buffer {
663 let buffer: id = unsafe {msg_send![
664 metal_cx.device,
665 newBufferWithLength: (data.len() * std::mem::size_of::<f32>()) as u64
666 options: MTLResourceOptions::StorageModeShared
667 ]};
668 if buffer == nil {elem.buffer = None} else {elem.buffer = Some(buffer)}
669 elem.size = data.len()
670 }
671
672 if let Some(buffer) = elem.buffer {
673 unsafe {
674 let p: *mut std::ffi::c_void = msg_send![buffer, contents];
675 std::ptr::copy(data.as_ptr(), p as *mut f32, data.len());
676 let () = msg_send![
677 buffer,
678 didModifyRange: NSRange {
679 location: 0,
680 length: (data.len() * std::mem::size_of::<f32>()) as u64
681 }
682 ];
683 }
684 }
685 elem.used = data.len()
686 }
687
688 pub fn update_with_u32_data(&mut self, metal_cx: &MetalCx, data: &Vec<u32>) {
689 let elem = self.multi_buffer_write();
690 if elem.size < data.len() {
691 elem.buffer = None;
692 }
693 if let None = elem.buffer {
694 let buffer: id = unsafe {msg_send![
695 metal_cx.device,
696 newBufferWithLength: (data.len() * std::mem::size_of::<u32>()) as u64
697 options: MTLResourceOptions::StorageModeShared
698 ]};
699 if buffer == nil {elem.buffer = None} else {elem.buffer = Some(buffer)}
700 elem.size = data.len()
701 }
702 if let Some(buffer) = elem.buffer {
703 unsafe {
704 let p: *mut std::ffi::c_void = msg_send![buffer, contents];
705 std::ptr::copy(data.as_ptr(), p as *mut u32, data.len());
706 let () = msg_send![
707 buffer,
708 didModifyRange: NSRange {
709 location: 0,
710 length: (data.len() * std::mem::size_of::<f32>()) as u64
711 }
712 ];
713 }
714 }
715 elem.used = data.len()
716 }
717}