Skip to content

Commit 1020d1e

Browse files
committed
[add] first high level implementation for render targets and gpu.
1 parent 5b5c64f commit 1020d1e

File tree

3 files changed

+514
-0
lines changed

3 files changed

+514
-0
lines changed

crates/lambda-rs/src/render/gpu.rs

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
//! High-level GPU abstraction for resource creation and command submission.
2+
//!
3+
//! The `Gpu` type wraps the platform GPU device and queue, providing a stable
4+
//! engine-facing API for creating resources and submitting work. This
5+
//! abstraction enables future support for multiple render targets and
6+
//! backend flexibility.
7+
//!
8+
//! # Usage
9+
//!
10+
//! The `Gpu` is typically created during render context initialization and
11+
//! shared across resource builders:
12+
//!
13+
//! ```ignore
14+
//! let gpu = GpuBuilder::new()
15+
//! .with_label("My GPU")
16+
//! .build(&instance, Some(&surface))?;
17+
//!
18+
//! // Use gpu for resource creation
19+
//! let buffer = BufferBuilder::new()
20+
//! .with_size(1024)
21+
//! .build(&gpu);
22+
//! ```
23+
24+
use lambda_platform::wgpu as platform;
25+
26+
use super::texture::{
27+
DepthFormat,
28+
TextureFormat,
29+
};
30+
31+
// ---------------------------------------------------------------------------
32+
// GpuLimits
33+
// ---------------------------------------------------------------------------
34+
35+
/// Device limits exposed to the engine layer.
36+
///
37+
/// These limits are queried from the physical device and constrain resource
38+
/// creation and binding. The engine uses these to validate configurations
39+
/// before creating GPU resources.
40+
#[derive(Clone, Copy, Debug)]
41+
pub struct GpuLimits {
42+
/// Maximum bytes that can be bound for a single uniform buffer binding.
43+
pub max_uniform_buffer_binding_size: u64,
44+
/// Maximum number of bind groups that can be used by a pipeline layout.
45+
pub max_bind_groups: u32,
46+
/// Maximum number of vertex buffers that can be bound.
47+
pub max_vertex_buffers: u32,
48+
/// Maximum number of vertex attributes that can be declared.
49+
pub max_vertex_attributes: u32,
50+
/// Required alignment in bytes for dynamic uniform buffer offsets.
51+
pub min_uniform_buffer_offset_alignment: u32,
52+
}
53+
54+
impl GpuLimits {
55+
/// Create limits from the platform GPU limits.
56+
pub(crate) fn from_platform(limits: platform::gpu::GpuLimits) -> Self {
57+
return GpuLimits {
58+
max_uniform_buffer_binding_size: limits.max_uniform_buffer_binding_size,
59+
max_bind_groups: limits.max_bind_groups,
60+
max_vertex_buffers: limits.max_vertex_buffers,
61+
max_vertex_attributes: limits.max_vertex_attributes,
62+
min_uniform_buffer_offset_alignment: limits
63+
.min_uniform_buffer_offset_alignment,
64+
};
65+
}
66+
}
67+
68+
// ---------------------------------------------------------------------------
69+
// Gpu
70+
// ---------------------------------------------------------------------------
71+
72+
/// High-level GPU device and queue wrapper.
73+
///
74+
/// The `Gpu` provides a stable interface for:
75+
/// - Submitting command buffers to the GPU queue
76+
/// - Querying device limits for resource validation
77+
/// - Checking format and sample count support
78+
///
79+
/// This type does not expose platform internals directly, allowing the
80+
/// engine to evolve independently of the underlying graphics API.
81+
pub struct Gpu {
82+
inner: platform::gpu::Gpu,
83+
limits: GpuLimits,
84+
}
85+
86+
impl Gpu {
87+
/// Create a new high-level GPU from a platform GPU.
88+
pub(crate) fn from_platform(gpu: platform::gpu::Gpu) -> Self {
89+
let limits = GpuLimits::from_platform(gpu.limits());
90+
return Gpu { inner: gpu, limits };
91+
}
92+
93+
/// Borrow the underlying platform GPU for internal use.
94+
///
95+
/// This is crate-visible to allow resource builders and other internal
96+
/// code to access the platform device without exposing it publicly.
97+
#[inline]
98+
pub(crate) fn platform(&self) -> &platform::gpu::Gpu {
99+
return &self.inner;
100+
}
101+
102+
/// Query the device limits.
103+
#[inline]
104+
pub fn limits(&self) -> &GpuLimits {
105+
return &self.limits;
106+
}
107+
108+
/// Submit command buffers to the GPU queue.
109+
///
110+
/// The submitted buffers are executed in order. This method does not block;
111+
/// use fences or map callbacks for synchronization.
112+
#[inline]
113+
pub fn submit<I>(&self, buffers: I)
114+
where
115+
I: IntoIterator<Item = platform::command::CommandBuffer>,
116+
{
117+
self.inner.submit(buffers);
118+
}
119+
120+
/// Check if the GPU supports the given sample count for a texture format.
121+
///
122+
/// Returns `true` if the format can be used as a render attachment with
123+
/// the specified sample count for MSAA.
124+
pub fn supports_sample_count_for_format(
125+
&self,
126+
format: TextureFormat,
127+
sample_count: u32,
128+
) -> bool {
129+
return self
130+
.inner
131+
.supports_sample_count_for_format(format.to_platform(), sample_count);
132+
}
133+
134+
/// Check if the GPU supports the given sample count for a depth format.
135+
///
136+
/// Returns `true` if the depth format can be used as a depth/stencil
137+
/// attachment with the specified sample count for MSAA.
138+
pub fn supports_sample_count_for_depth(
139+
&self,
140+
format: DepthFormat,
141+
sample_count: u32,
142+
) -> bool {
143+
return self
144+
.inner
145+
.supports_sample_count_for_depth(format.to_platform(), sample_count);
146+
}
147+
148+
/// Maximum bytes that can be bound for a single uniform buffer binding.
149+
#[inline]
150+
pub fn limit_max_uniform_buffer_binding_size(&self) -> u64 {
151+
return self.limits.max_uniform_buffer_binding_size;
152+
}
153+
154+
/// Number of bind groups that can be used by a pipeline layout.
155+
#[inline]
156+
pub fn limit_max_bind_groups(&self) -> u32 {
157+
return self.limits.max_bind_groups;
158+
}
159+
160+
/// Maximum number of vertex buffers that can be bound.
161+
#[inline]
162+
pub fn limit_max_vertex_buffers(&self) -> u32 {
163+
return self.limits.max_vertex_buffers;
164+
}
165+
166+
/// Maximum number of vertex attributes that can be declared.
167+
#[inline]
168+
pub fn limit_max_vertex_attributes(&self) -> u32 {
169+
return self.limits.max_vertex_attributes;
170+
}
171+
172+
/// Required alignment in bytes for dynamic uniform buffer offsets.
173+
#[inline]
174+
pub fn limit_min_uniform_buffer_offset_alignment(&self) -> u32 {
175+
return self.limits.min_uniform_buffer_offset_alignment;
176+
}
177+
}
178+
179+
impl std::fmt::Debug for Gpu {
180+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181+
return f
182+
.debug_struct("Gpu")
183+
.field("limits", &self.limits)
184+
.finish_non_exhaustive();
185+
}
186+
}
187+
188+
// ---------------------------------------------------------------------------
189+
// GpuBuilder
190+
// ---------------------------------------------------------------------------
191+
192+
/// Builder for creating a `Gpu` with configurable options.
193+
///
194+
/// The builder configures adapter selection, required features, and memory
195+
/// hints before requesting the logical device.
196+
pub struct GpuBuilder {
197+
inner: platform::gpu::GpuBuilder,
198+
}
199+
200+
impl GpuBuilder {
201+
/// Create a new builder with default settings.
202+
///
203+
/// Defaults:
204+
/// - High performance power preference
205+
/// - Push constants enabled
206+
/// - Performance-oriented memory hints
207+
pub fn new() -> Self {
208+
return GpuBuilder {
209+
inner: platform::gpu::GpuBuilder::new(),
210+
};
211+
}
212+
213+
/// Attach a label for debugging and profiling.
214+
pub fn with_label(mut self, label: &str) -> Self {
215+
self.inner = self.inner.with_label(label);
216+
return self;
217+
}
218+
219+
/// Build the GPU using the provided instance and optional surface.
220+
///
221+
/// The surface is used to ensure the adapter is compatible with
222+
/// presentation. Pass `None` for headless/compute-only contexts.
223+
pub fn build(
224+
self,
225+
instance: &platform::instance::Instance,
226+
surface: Option<&platform::surface::Surface<'_>>,
227+
) -> Result<Gpu, GpuBuildError> {
228+
let platform_gpu = self
229+
.inner
230+
.build(instance, surface)
231+
.map_err(GpuBuildError::from_platform)?;
232+
return Ok(Gpu::from_platform(platform_gpu));
233+
}
234+
}
235+
236+
impl Default for GpuBuilder {
237+
fn default() -> Self {
238+
return Self::new();
239+
}
240+
}
241+
242+
// ---------------------------------------------------------------------------
243+
// GpuBuildError
244+
// ---------------------------------------------------------------------------
245+
246+
/// Errors that can occur when building a `Gpu`.
247+
#[derive(Debug)]
248+
pub enum GpuBuildError {
249+
/// No compatible GPU adapter was found.
250+
AdapterUnavailable,
251+
/// Required features are not supported by the adapter.
252+
MissingFeatures(String),
253+
/// Device creation failed.
254+
DeviceCreationFailed(String),
255+
}
256+
257+
impl GpuBuildError {
258+
fn from_platform(error: platform::gpu::GpuBuildError) -> Self {
259+
return match error {
260+
platform::gpu::GpuBuildError::AdapterUnavailable => {
261+
GpuBuildError::AdapterUnavailable
262+
}
263+
platform::gpu::GpuBuildError::MissingFeatures {
264+
requested,
265+
available,
266+
} => GpuBuildError::MissingFeatures(format!(
267+
"Requested features {:?} not available; adapter supports {:?}",
268+
requested, available
269+
)),
270+
platform::gpu::GpuBuildError::RequestDevice(msg) => {
271+
GpuBuildError::DeviceCreationFailed(msg)
272+
}
273+
};
274+
}
275+
}
276+
277+
impl std::fmt::Display for GpuBuildError {
278+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279+
return match self {
280+
GpuBuildError::AdapterUnavailable => {
281+
write!(f, "No compatible GPU adapter found")
282+
}
283+
GpuBuildError::MissingFeatures(msg) => write!(f, "{}", msg),
284+
GpuBuildError::DeviceCreationFailed(msg) => {
285+
write!(f, "Device creation failed: {}", msg)
286+
}
287+
};
288+
}
289+
}
290+
291+
impl std::error::Error for GpuBuildError {}

crates/lambda-rs/src/render/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ pub mod bind;
3333
pub mod buffer;
3434
pub mod command;
3535
pub mod encoder;
36+
pub mod gpu;
3637
pub mod mesh;
3738
pub mod pipeline;
3839
pub mod render_pass;
40+
pub mod render_target;
3941
pub mod scene_math;
4042
pub mod shader;
4143
pub mod surface;

0 commit comments

Comments
 (0)