Render preview: draw within the pixel budget on 4K/5K screens (#1464) (#1477)

The product preview asked the viewport executor for the full physical
viewport, so a maximised 4K window (~8 MP) was refused against the 4 MP
limit on every frame. The preview now draws at the largest size of the
same aspect the executor admits (RenderLimits::fit, scratch included)
and filters it up into the viewport through the existing offscreen
blit. Viewports within the limits still draw at full size.

PNG setups past the image limits now say what the limits are and the
largest size at that aspect, and the image panel offers to use it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-15 15:18:00 -04:00
1 parent b6806b16cf
commit 5fbbc13885
15 files changed
+188 -12

No files matched your search

+23 -6
View File
@@ -67,13 +67,18 @@ impl Default for RenderSetup {
impl RenderSetup {
pub fn validate(&self) -> Result<()> {
let limits = RenderLimits::default();
if self.width == 0
|| self.height == 0
|| u64::from(self.width) > limits.max_dimension
|| u64::from(self.height) > limits.max_dimension
|| u64::from(self.width) * u64::from(self.height) > limits.max_pixels
let (width, height) = (u64::from(self.width), u64::from(self.height));
if width == 0 || height == 0 {
return Err(DocError::Invalid("render output must be at least 1 × 1 pixels".into()));
}
if let Some((w, h)) = limits.fit(width, height, None)
&& (w, h) != (width, height)
{
return Err(DocError::Invalid("render output exceeds the dimension/pixel limits".into()));
return Err(DocError::Invalid(format!(
"render output {width} × {height} exceeds the image limits ({} pixels per side, {} pixels in all); \
the largest image at this aspect is {w} × {h}",
limits.max_dimension, limits.max_pixels
)));
}
let camera = &self.camera;
if !camera.is_valid()
@@ -218,6 +223,18 @@ mod tests {
}
}
#[test]
fn oversized_output_names_the_limits_and_the_largest_size() {
let setup = RenderSetup { width: 4096, height: 4096, ..Default::default() };
let message = setup.validate().unwrap_err().to_string();
assert!(message.contains("4096 × 4096 exceeds the image limits (4096 pixels per side, 4194304 pixels in all)"), "{message}");
assert!(message.contains("the largest image at this aspect is 2048 × 2048"), "{message}");
let setup = RenderSetup { width: 7680, height: 4320, ..Default::default() };
let message = setup.validate().unwrap_err().to_string();
assert!(message.contains("the largest image at this aspect is 27"), "{message}");
assert!(RenderSetup { width: 2048, height: 2048, ..Default::default() }.validate().is_ok());
}
#[test]
fn invalid_saved_intent_is_rejected_at_deserialization() {
for patch in [