Skip to content

Commit bb025e0

Browse files
committed
[add] new module targets for implementing explicit render targets (surface & offscreen)
1 parent e8bd8e9 commit bb025e0

File tree

7 files changed

+109
-176
lines changed

7 files changed

+109
-176
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use lambda_platform::wgpu as platform;
2525

2626
use super::{
2727
instance::Instance,
28-
render_target::WindowSurface,
28+
targets::surface::WindowSurface,
2929
texture::{
3030
DepthFormat,
3131
TextureFormat,

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

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@ pub mod instance;
3838
pub mod mesh;
3939
pub mod pipeline;
4040
pub mod render_pass;
41-
pub mod render_target;
4241
pub mod scene_math;
4342
pub mod shader;
4443
pub mod surface;
45-
pub mod target;
44+
pub mod targets;
4645
pub mod texture;
4746
pub mod validation;
4847
pub mod vertex;
@@ -71,7 +70,7 @@ use self::{
7170
},
7271
pipeline::RenderPipeline,
7372
render_pass::RenderPass as RenderPassDesc,
74-
render_target::RenderTarget,
73+
targets::surface::RenderTarget,
7574
};
7675

7776
/// Builder for configuring a `RenderContext` tied to one window.
@@ -127,13 +126,13 @@ impl RenderContextBuilder {
127126
.with_label(&format!("{} Instance", name))
128127
.build();
129128

130-
let mut surface = render_target::WindowSurface::new(&instance, window)
129+
let mut surface = targets::surface::WindowSurface::new(&instance, window)
131130
.map_err(|e| {
132-
RenderContextError::SurfaceCreate(format!(
133-
"Failed to create rendering surface: {:?}",
134-
e
135-
))
136-
})?;
131+
RenderContextError::SurfaceCreate(format!(
132+
"Failed to create rendering surface: {:?}",
133+
e
134+
))
135+
})?;
137136

138137
let gpu = gpu::GpuBuilder::new()
139138
.with_label(&format!("{} Device", name))
@@ -225,7 +224,7 @@ impl RenderContextBuilder {
225224
pub struct RenderContext {
226225
label: String,
227226
instance: instance::Instance,
228-
surface: render_target::WindowSurface,
227+
surface: targets::surface::WindowSurface,
229228
gpu: gpu::Gpu,
230229
config: surface::SurfaceConfig,
231230
texture_usage: texture::TextureUsages,
@@ -235,7 +234,7 @@ pub struct RenderContext {
235234
depth_sample_count: u32,
236235
msaa_color: Option<texture::ColorAttachmentTexture>,
237236
msaa_sample_count: u32,
238-
offscreen_targets: Vec<target::OffscreenTarget>,
237+
offscreen_targets: Vec<targets::offscreen::OffscreenTarget>,
239238
render_passes: Vec<RenderPassDesc>,
240239
render_pipelines: Vec<RenderPipeline>,
241240
bind_group_layouts: Vec<bind::BindGroupLayout>,
@@ -276,7 +275,7 @@ impl RenderContext {
276275
/// Attach an offscreen target and return a handle for use in destinations.
277276
pub fn attach_offscreen_target(
278277
&mut self,
279-
target: target::OffscreenTarget,
278+
target: targets::offscreen::OffscreenTarget,
280279
) -> ResourceId {
281280
let id = self.offscreen_targets.len();
282281
self.offscreen_targets.push(target);
@@ -290,7 +289,7 @@ impl RenderContext {
290289
pub fn replace_offscreen_target(
291290
&mut self,
292291
id: ResourceId,
293-
target: target::OffscreenTarget,
292+
target: targets::offscreen::OffscreenTarget,
294293
) -> Result<(), String> {
295294
let slot = match self.offscreen_targets.get_mut(id) {
296295
Some(slot) => slot,
@@ -411,7 +410,7 @@ impl RenderContext {
411410
pub fn get_offscreen_target(
412411
&self,
413412
id: ResourceId,
414-
) -> &target::OffscreenTarget {
413+
) -> &targets::offscreen::OffscreenTarget {
415414
return &self.offscreen_targets[id];
416415
}
417416

@@ -780,17 +779,6 @@ impl RenderContext {
780779
));
781780
}
782781

783-
#[cfg(any(debug_assertions, feature = "render-validation-render-targets",))]
784-
{
785-
if target.defaulted_from_surface_size() && target.size() != self.size {
786-
logging::warn!(
787-
"Offscreen target size {:?} does not match surface size {:?}; rebuild the target to match the new surface size",
788-
target.size(),
789-
self.size
790-
);
791-
}
792-
}
793-
794782
let depth_texture_ref = if want_depth_attachment {
795783
target.depth_texture()
796784
} else {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//! Render targets for surface presentation and offscreen rendering.
2+
//!
3+
//! This module owns the engine-level APIs for:
4+
//! - Surface presentation (`targets::surface`)
5+
//! - Offscreen render-to-texture (`targets::offscreen`)
6+
7+
pub mod offscreen;
8+
pub mod surface;

crates/lambda-rs/src/render/target.rs renamed to crates/lambda-rs/src/render/targets/offscreen.rs

Lines changed: 20 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
//! Provides `OffscreenTarget` and `OffscreenTargetBuilder` for render‑to‑texture
44
//! workflows without exposing platform texture types at call sites.
55
6-
use logging;
7-
8-
use super::{
6+
use crate::render::{
7+
gpu::Gpu,
98
surface,
109
texture,
10+
validation,
1111
RenderContext,
1212
};
13-
use crate::render::validation;
1413

1514
#[derive(Debug)]
1615
/// Offscreen render target with color and optional depth attachments.
@@ -27,7 +26,6 @@ pub struct OffscreenTarget {
2726
depth_format: Option<texture::DepthFormat>,
2827
sample_count: u32,
2928
label: Option<String>,
30-
defaulted_from_surface_size: bool,
3129
}
3230

3331
impl OffscreenTarget {
@@ -81,10 +79,6 @@ impl OffscreenTarget {
8179
return self.label.as_deref();
8280
}
8381

84-
pub(crate) fn defaulted_from_surface_size(&self) -> bool {
85-
return self.defaulted_from_surface_size;
86-
}
87-
8882
/// Explicitly destroy this render target.
8983
///
9084
/// Dropping the value also releases the underlying GPU resources; this
@@ -97,7 +91,7 @@ impl OffscreenTarget {
9791
pub enum OffscreenTargetError {
9892
/// Color attachment was not configured.
9993
MissingColorAttachment,
100-
/// Width or height was zero after resolving defaults.
94+
/// Width or height was zero.
10195
InvalidSize { width: u32, height: u32 },
10296
/// Sample count is not supported for the chosen format or device limits.
10397
UnsupportedSampleCount { requested: u32 },
@@ -131,10 +125,6 @@ impl OffscreenTargetBuilder {
131125
}
132126

133127
/// Configure the color attachment format and size.
134-
///
135-
/// When `width` or `height` is zero, the builder falls back to the current
136-
/// `RenderContext` surface size during `build`. A resolved size of zero in
137-
/// either dimension is treated as an error.
138128
pub fn with_color(
139129
mut self,
140130
format: texture::TextureFormat,
@@ -154,7 +144,6 @@ impl OffscreenTargetBuilder {
154144
}
155145

156146
/// Configure multi‑sampling for this target.
157-
///
158147
pub fn with_multi_sample(mut self, samples: u32) -> Self {
159148
self.sample_count = samples.max(1);
160149
return self;
@@ -169,16 +158,14 @@ impl OffscreenTargetBuilder {
169158
/// Create the render target color (and optional depth) attachments.
170159
pub fn build(
171160
self,
172-
render_context: &mut RenderContext,
161+
gpu: &Gpu,
173162
) -> Result<OffscreenTarget, OffscreenTargetError> {
174163
let format = match self.color_format {
175164
Some(format) => format,
176165
None => return Err(OffscreenTargetError::MissingColorAttachment),
177166
};
178167

179-
let surface_size = render_context.surface_size();
180-
let defaulted_from_surface_size = self.width == 0 || self.height == 0;
181-
let (width, height) = self.resolve_size(surface_size)?;
168+
let (width, height) = self.resolve_size()?;
182169

183170
let sample_count = self.sample_count.max(1);
184171
if let Err(_) = validation::validate_sample_count(sample_count) {
@@ -188,9 +175,7 @@ impl OffscreenTargetBuilder {
188175
}
189176

190177
if sample_count > 1
191-
&& !render_context
192-
.gpu()
193-
.supports_sample_count_for_format(format, sample_count)
178+
&& !gpu.supports_sample_count_for_format(format, sample_count)
194179
{
195180
return Err(OffscreenTargetError::UnsupportedSampleCount {
196181
requested: sample_count,
@@ -199,9 +184,7 @@ impl OffscreenTargetBuilder {
199184

200185
if let Some(depth_format) = self.depth_format {
201186
if sample_count > 1
202-
&& !render_context
203-
.gpu()
204-
.supports_sample_count_for_depth(depth_format, sample_count)
187+
&& !gpu.supports_sample_count_for_depth(depth_format, sample_count)
205188
{
206189
return Err(OffscreenTargetError::UnsupportedSampleCount {
207190
requested: sample_count,
@@ -221,7 +204,7 @@ impl OffscreenTargetBuilder {
221204
}
222205
}
223206

224-
let resolve_texture = match color_builder.build(render_context.gpu()) {
207+
let resolve_texture = match color_builder.build(gpu) {
225208
Ok(texture) => texture,
226209
Err(message) => {
227210
return Err(OffscreenTargetError::DeviceError(message.to_string()));
@@ -236,7 +219,7 @@ impl OffscreenTargetBuilder {
236219
if let Some(ref label) = self.label {
237220
msaa_builder = msaa_builder.with_label(&format!("{}-msaa", label));
238221
}
239-
Some(msaa_builder.build(render_context.gpu()))
222+
Some(msaa_builder.build(gpu))
240223
} else {
241224
None
242225
};
@@ -251,7 +234,7 @@ impl OffscreenTargetBuilder {
251234
depth_builder = depth_builder.with_label(&format!("{}-depth", label));
252235
}
253236

254-
Some(depth_builder.build(render_context.gpu()))
237+
Some(depth_builder.build(gpu))
255238
} else {
256239
None
257240
};
@@ -265,26 +248,14 @@ impl OffscreenTargetBuilder {
265248
depth_format: self.depth_format,
266249
sample_count,
267250
label: self.label,
268-
defaulted_from_surface_size,
269251
});
270252
}
271253

272-
/// Resolve the final size using an optional explicit size and surface default.
273-
///
274-
/// When no explicit size was provided, the builder falls back to
275-
/// `surface_size`. A resolved size with zero width or height is treated as
276-
/// an error.
277254
pub(crate) fn resolve_size(
278255
&self,
279-
surface_size: (u32, u32),
280256
) -> Result<(u32, u32), OffscreenTargetError> {
281-
let mut width = self.width;
282-
let mut height = self.height;
283-
if width == 0 || height == 0 {
284-
width = surface_size.0;
285-
height = surface_size.1;
286-
}
287-
257+
let width = self.width;
258+
let height = self.height;
288259
if width == 0 || height == 0 {
289260
return Err(OffscreenTargetError::InvalidSize { width, height });
290261
}
@@ -294,47 +265,34 @@ impl OffscreenTargetBuilder {
294265
}
295266

296267
#[deprecated(
297-
note = "Use `lambda::render::target::OffscreenTarget` to avoid confusion with `lambda::render::render_target::RenderTarget`."
268+
note = "Use `lambda::render::targets::offscreen::OffscreenTarget` to avoid confusion with `lambda::render::targets::surface::RenderTarget`."
298269
)]
299270
pub type RenderTarget = OffscreenTarget;
300271

301272
#[deprecated(
302-
note = "Use `lambda::render::target::OffscreenTargetBuilder` to avoid confusion with `lambda::render::render_target::RenderTarget`."
273+
note = "Use `lambda::render::targets::offscreen::OffscreenTargetBuilder` to avoid confusion with `lambda::render::targets::surface::RenderTarget`."
303274
)]
304275
pub type RenderTargetBuilder = OffscreenTargetBuilder;
305276

306-
#[deprecated(note = "Use `lambda::render::target::OffscreenTargetError`.")]
277+
#[deprecated(
278+
note = "Use `lambda::render::targets::offscreen::OffscreenTargetError`."
279+
)]
307280
pub type RenderTargetError = OffscreenTargetError;
308281

309282
#[cfg(test)]
310283
mod tests {
311284
use super::*;
312285

313-
/// Defaults size to the surface when no explicit dimensions are provided.
314-
#[test]
315-
fn resolve_size_defaults_to_surface_size() {
316-
let builder = OffscreenTargetBuilder::new().with_color(
317-
texture::TextureFormat::Rgba8Unorm,
318-
0,
319-
0,
320-
);
321-
let surface_size = (800, 600);
322-
323-
let resolved = builder.resolve_size(surface_size).unwrap();
324-
assert_eq!(resolved, surface_size);
325-
}
326-
327-
/// Fails when the resolved size has a zero dimension.
286+
/// Fails when the builder has a zero dimension.
328287
#[test]
329288
fn resolve_size_rejects_zero_dimensions() {
330289
let builder = OffscreenTargetBuilder::new().with_color(
331290
texture::TextureFormat::Rgba8Unorm,
332291
0,
333292
0,
334293
);
335-
let surface_size = (0, 0);
336294

337-
let resolved = builder.resolve_size(surface_size);
295+
let resolved = builder.resolve_size();
338296
assert_eq!(
339297
resolved,
340298
Err(OffscreenTargetError::InvalidSize {

0 commit comments

Comments
 (0)