cvkg_render_gpu/api/
frame.rs1use crate::renderer::GpuRenderer;
2use crate::types::{MAX_INDICES, MAX_VERTICES};
3use cvkg_core::Renderer;
4use cvkg_core::LAYOUT_DIRTY;
5use std::sync::atomic::Ordering;
6
7impl cvkg_core::FrameRenderer<wgpu::CommandEncoder> for GpuRenderer {
8 fn begin_frame(&mut self) -> wgpu::CommandEncoder {
9 cvkg_core::begin_render_phase();
10 self.frame_rendered = false;
11 self.app_drew_background = false;
12 let id = self
13 .current_window
14 .expect("No target window set for frame. Call set_target_window first.");
15 self.begin_frame(id)
16 }
17
18 fn render_frame(&mut self) {
19 if LAYOUT_DIRTY.swap(false, Ordering::AcqRel) {
22 if let Some(window_id) = self.current_window {
23 if let Some(surface_ctx) = self.surfaces.get(&window_id) {
24 let w = surface_ctx.config.width as f32;
25 let h = surface_ctx.config.height as f32;
26 let border_rect = cvkg_core::Rect {
27 x: 0.0,
28 y: 0.0,
29 width: w,
30 height: h,
31 };
32 self.stroke_rect(border_rect, [1.0, 0.0, 0.0, 1.0], 10.0);
34 }
35 }
36 }
37
38 let max_v_capacity = MAX_VERTICES * 4;
40 let grown = self.geometry_buffers.grow_vertex_buffer(
41 &self.device,
42 self.vertices.len(),
43 max_v_capacity,
44 );
45 if grown {
46 log::info!("Grew vertex buffer to fit {} vertices", self.vertices.len());
47 }
48 if self.vertices.len() > max_v_capacity {
49 log::error!("Exceeded dynamic vertex buffer max capacity! Capping geometry.");
50 self.vertices.truncate(max_v_capacity);
51 }
52
53 let max_i_capacity = MAX_INDICES * 4;
54 let grown = self.geometry_buffers.grow_index_buffer(
55 &self.device,
56 self.indices.len(),
57 max_i_capacity,
58 );
59 if grown {
60 log::info!("Grew index buffer to fit {} indices", self.indices.len());
61 }
62 if self.indices.len() > max_i_capacity {
63 log::error!("Exceeded dynamic index buffer max capacity! Capping geometry.");
64 self.indices.truncate(max_i_capacity);
65 }
66
67 let mut staging_encoder =
69 self.device
70 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
71 label: Some("Surtr Staging Encoder"),
72 });
73
74 let mut has_writes = false;
75
76 if !self.vertices.is_empty() {
77 let v_bytes = bytemuck::cast_slice(&self.vertices);
78 self.staging_belt
79 .write_buffer(
80 &mut staging_encoder,
81 &self.geometry_buffers.vertex_buffer,
82 0,
83 wgpu::BufferSize::new(v_bytes.len() as u64).unwrap(),
84 )
85 .copy_from_slice(v_bytes);
86 has_writes = true;
87 }
88
89 if !self.indices.is_empty() {
90 let i_bytes = bytemuck::cast_slice(&self.indices);
91 self.staging_belt
92 .write_buffer(
93 &mut staging_encoder,
94 &self.geometry_buffers.index_buffer,
95 0,
96 wgpu::BufferSize::new(i_bytes.len() as u64).unwrap(),
97 )
98 .copy_from_slice(i_bytes);
99 has_writes = true;
100 }
101
102 if !self.instance_data.is_empty() {
103 let inst_bytes = bytemuck::cast_slice(&self.instance_data);
104 self.staging_belt
105 .write_buffer(
106 &mut staging_encoder,
107 &self.geometry_buffers.instance_buffer,
108 0,
109 wgpu::BufferSize::new(inst_bytes.len() as u64).unwrap(),
110 )
111 .copy_from_slice(inst_bytes);
112 has_writes = true;
113 }
114
115 if has_writes {
116 self.staging_belt.finish();
117 self.staging_command_buffers.push(staging_encoder.finish());
118 }
119
120 self.current_scene.time = self.start_time.elapsed().as_secs_f32();
122 self.queue.write_buffer(
123 &self.scene_buffer,
124 0,
125 bytemuck::bytes_of(&self.current_scene),
126 );
127 self.queue.write_buffer(
128 &self.theme_buffer,
129 0,
130 bytemuck::bytes_of(&self.current_theme),
131 );
132
133 self.telemetry.draw_calls = self.draw_calls.len() as u32;
135 self.telemetry.vertices = self.vertices.len() as u32;
136 self.frame_rendered = true;
137
138 log::debug!(
139 "[Perf] draw_calls={} vertices={} instances={} staging_cmds={}",
140 self.draw_calls.len(),
141 self.vertices.len(),
142 self.instance_data.len(),
143 self.staging_command_buffers.len()
144 );
145 }
146
147 fn end_frame(&mut self, encoder: wgpu::CommandEncoder) {
148 GpuRenderer::end_frame(self, encoder);
149 cvkg_core::end_render_phase();
150 }
151}