Skip to content

Commit 80bab08

Browse files
committed
[update] buffer to fill data upon being built, implement buffer allocation inside of mesh.
1 parent c90ba3a commit 80bab08

3 files changed

Lines changed: 101 additions & 22 deletions

File tree

crates/lambda-platform/src/gfx/buffer.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use gfx_hal::{
2-
memory::SparseFlags,
2+
memory::{
3+
Segment,
4+
SparseFlags,
5+
},
36
Backend,
47
};
58

@@ -11,11 +14,14 @@ pub type Properties = gfx_hal::memory::Properties;
1114

1215
/// A buffer is a block of memory that can be used to store data that can be
1316
/// accessed by the GPU.
17+
#[derive(Debug, Clone, Copy)]
1418
pub struct Buffer<RenderBackend: super::internal::Backend> {
1519
buffer: RenderBackend::Buffer,
1620
memory: RenderBackend::Memory,
1721
}
1822

23+
impl<RenderBackend: super::internal::Backend> Buffer<RenderBackend> {}
24+
1925
pub struct BufferBuilder {
2026
buffer_length: usize,
2127
usage: Usage,
@@ -47,9 +53,12 @@ impl BufferBuilder {
4753

4854
/// Builds & binds a buffer of memory to the GPU. If the buffer cannot be
4955
/// bound to the GPU, the buffer memory is freed before the error is returned.
50-
pub fn build<RenderBackend: super::internal::Backend>(
51-
self,
56+
/// Data must represent the data that will be stored in the buffer, meaning
57+
/// it must repr C and be the same size as the buffer length.
58+
pub fn build<RenderBackend: super::internal::Backend, Data: Sized>(
59+
&self,
5260
gpu: &mut Gpu<RenderBackend>,
61+
data: Vec<Data>,
5362
) -> Result<Buffer<RenderBackend>, &'static str> {
5463
use gfx_hal::{
5564
adapter::PhysicalDevice,
@@ -98,7 +107,7 @@ impl BufferBuilder {
98107
return Err("Failed to allocate memory for buffer.");
99108
}
100109

101-
let buffer_memory = buffer_memory_allocation.unwrap();
110+
let mut buffer_memory = buffer_memory_allocation.unwrap();
102111

103112
// Bind the buffer to the GPU memory
104113
let buffer_binding = unsafe {
@@ -111,6 +120,43 @@ impl BufferBuilder {
111120
return Err("Failed to bind buffer memory.");
112121
}
113122

123+
// Get address of the buffer memory on the GPU so that we can write to it.
124+
let get_mapping_to_memory =
125+
unsafe { logical_device.map_memory(&mut buffer_memory, Segment::ALL) };
126+
127+
if get_mapping_to_memory.is_err() {
128+
unsafe { logical_device.destroy_buffer(buffer) };
129+
return Err("Failed to map memory.");
130+
}
131+
let mapped_memory = get_mapping_to_memory.unwrap();
132+
133+
// Copy the data to the GPU memory.
134+
unsafe {
135+
std::ptr::copy_nonoverlapping(
136+
data.as_ptr() as *const u8,
137+
mapped_memory,
138+
self.buffer_length,
139+
);
140+
};
141+
142+
// Flush the data to ensure it is written to the GPU memory.
143+
let memory_flush = unsafe {
144+
logical_device
145+
.flush_mapped_memory_ranges(std::iter::once((
146+
&buffer_memory,
147+
Segment::ALL,
148+
)))
149+
.map_err(|_| "Failed to flush memory.")
150+
};
151+
152+
if memory_flush.is_err() {
153+
unsafe { logical_device.destroy_buffer(buffer) };
154+
return Err("No memory available on the GPU.");
155+
}
156+
157+
// Unmap the memory now that it's no longer needed by the CPU.
158+
unsafe { logical_device.unmap_memory(&mut buffer_memory) };
159+
114160
return Ok(Buffer {
115161
buffer,
116162
memory: buffer_memory,

lambda/src/core/render/mesh.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
use super::vertex::Vertex;
1+
use lambda_platform::gfx::buffer::{
2+
Buffer,
3+
BufferBuilder,
4+
Properties,
5+
Usage,
6+
};
7+
8+
use super::{
9+
vertex::Vertex,
10+
RenderContext,
11+
};
12+
use crate::core::render::internal::mut_gpu_from_context;
213

314
// ---------------------------------- Mesh ------------------------------------
415

516
/// Collection of vertices and indices that define a 3D object.
6-
#[derive(Clone, Debug)]
17+
#[derive(Debug)]
718
pub struct Mesh {
819
vertices: Vec<Vertex>,
920
indices: Vec<u32>,
21+
buffer: Buffer<super::internal::RenderBackend>,
1022
}
1123

1224
// ------------------------------ MeshBuilder ---------------------------------
@@ -38,11 +50,38 @@ impl MeshBuilder {
3850
return self;
3951
}
4052

41-
pub fn build(&self) -> Mesh {
42-
return Mesh {
43-
vertices: self.vertices.clone(),
44-
indices: self.indices.clone(),
45-
};
53+
/// Builds a mesh from the vertices and indices that have been added to the
54+
/// builder and allocates the memory for the mesh on the GPU.
55+
pub fn build(
56+
&self,
57+
render_context: &mut RenderContext,
58+
) -> Result<Mesh, &'static str> {
59+
let gpu_memory_required =
60+
self.vertices.len() * std::mem::size_of::<Vertex>();
61+
println!(
62+
"Allocating {} bytes of GPU memory for mesh.",
63+
gpu_memory_required
64+
);
65+
66+
// Allocate memory for the mesh on the GPU.
67+
let buffer_allocation = BufferBuilder::new()
68+
.with_length(gpu_memory_required)
69+
.with_usage(Usage::VERTEX)
70+
.with_properties(Properties::CPU_VISIBLE | Properties::COHERENT)
71+
.build(mut_gpu_from_context(render_context), self.vertices.clone());
72+
73+
match buffer_allocation {
74+
Ok(buffer) => {
75+
return Ok(Mesh {
76+
vertices: self.vertices.clone(),
77+
indices: self.indices.clone(),
78+
buffer,
79+
});
80+
}
81+
Err(error) => {
82+
return Err(error);
83+
}
84+
}
4685
}
4786
}
4887

@@ -54,16 +93,9 @@ mod tests {
5493

5594
assert_eq!(mesh.vertices.len(), 0);
5695
assert_eq!(mesh.indices.len(), 0);
57-
58-
let mesh = mesh
59-
.with_capacity(10)
60-
.with_vertex(crate::core::render::vertex::VertexBuilder::new().build())
61-
.build();
62-
63-
assert_eq!(mesh.vertices.len(), 1);
64-
assert_eq!(mesh.indices.len(), 0);
65-
assert_eq!(mesh.vertices[0].position, [0.0, 0.0, 0.0]);
66-
assert_eq!(mesh.vertices[0].normal, [0.0, 0.0, 0.0]);
67-
assert_eq!(mesh.vertices[0].color, [0.0, 0.0, 0.0]);
6896
}
97+
98+
// TODO(vmarcella): Add more tests for mesh building once the render context
99+
// is mockable. As of right now, testing would require the creation of a real
100+
// render context to perform the GPU memory allocation & binding for the mesh.
69101
}

lambda/src/core/render/vertex.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[repr(C)]
12
#[derive(Clone, Copy, Debug)]
23
pub struct Vertex {
34
pub position: [f32; 3],

0 commit comments

Comments
 (0)