fix: Raise max iterations limit
This commit is contained in:
@@ -128,7 +128,13 @@ pixel is a handful of `f32` complex multiplies.
|
|||||||
passes near 0 at a deep minibrot. `has_scaled()` then forces the deep
|
passes near 0 at a deep minibrot. `has_scaled()` then forces the deep
|
||||||
pipeline, the only one that reads `exps`. Requests are made with 1.5×
|
pipeline, the only one that reads `exps`. Requests are made with 1.5×
|
||||||
iteration headroom (`reference_iterations` in `app.rs`), so auto-iterations
|
iteration headroom (`reference_iterations` in `app.rs`), so auto-iterations
|
||||||
creeping up during a zoom doesn't recompute the orbit every frame.
|
creeping up during a zoom doesn't recompute the orbit every frame. The
|
||||||
|
interactive reference buffers start at 2^17 points and grow on demand
|
||||||
|
(`FractalRenderer::ensure_ref_capacity`) up to `MAX_REF_POINTS` (2^24, the
|
||||||
|
128 MiB WebGPU default binding size). That is also the hard iteration
|
||||||
|
ceiling (`app.rs::MAX_ITERATIONS`), because the shader treats an exhausted
|
||||||
|
reference as escaped. The UI slider only goes to 100k when dragged; typed
|
||||||
|
values can go higher.
|
||||||
- `src/shaders/*.wgsl` — none of these are standalone WGSL modules; WGSL has
|
- `src/shaders/*.wgsl` — none of these are standalone WGSL modules; WGSL has
|
||||||
no `#include`, so each is compiled by concatenating plain-text fragments
|
no `#include`, so each is compiled by concatenating plain-text fragments
|
||||||
with `concat!`/`include_str!` at the `create_shader_module` call site (see
|
with `concat!`/`include_str!` at the `create_shader_module` call site (see
|
||||||
|
|||||||
+21
-13
@@ -43,6 +43,10 @@ fn bailout_sq(kind: FractalKind, power: u32) -> f32 {
|
|||||||
}
|
}
|
||||||
/// Cap on exported image dimension (px), to stay within GPU texture limits.
|
/// Cap on exported image dimension (px), to stay within GPU texture limits.
|
||||||
const MAX_EXPORT_DIM: u32 = 8192 * 16;
|
const MAX_EXPORT_DIM: u32 = 8192 * 16;
|
||||||
|
/// Hard ceiling on the iteration count: the longest reference orbit the GPU
|
||||||
|
/// buffer holds (past it, the shader would read pixels as escaped).
|
||||||
|
const MAX_ITERATIONS: u32 = MAX_REF_POINTS as u32 - 1;
|
||||||
|
|
||||||
/// While the user is actively panning/zooming, the fractal is rendered into a
|
/// While the user is actively panning/zooming, the fractal is rendered into a
|
||||||
/// cache texture downscaled by this factor per axis (and with AA forced off), so
|
/// cache texture downscaled by this factor per axis (and with AA forced off), so
|
||||||
/// each interacting frame is cheap; the linear blit upsamples it to the widget.
|
/// each interacting frame is cheap; the linear blit upsamples it to the widget.
|
||||||
@@ -827,7 +831,7 @@ impl FractalApp {
|
|||||||
}
|
}
|
||||||
if let Some(iterations) = cli.iterations {
|
if let Some(iterations) = cli.iterations {
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = iterations;
|
self.max_iterations = iterations.clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
if let Some(half_height) = cli.half_height {
|
if let Some(half_height) = cli.half_height {
|
||||||
self.apply_half_height_spec(&half_height);
|
self.apply_half_height_spec(&half_height);
|
||||||
@@ -858,7 +862,7 @@ impl FractalApp {
|
|||||||
self.view = view;
|
self.view = view;
|
||||||
if let Some(v) = iterations {
|
if let Some(v) = iterations {
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = v.clamp(32, MAX_REF_POINTS as u32 - 1);
|
self.max_iterations = v.clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -912,7 +916,7 @@ impl FractalApp {
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub(crate) fn set_max_iterations(&mut self, i: u32) {
|
pub(crate) fn set_max_iterations(&mut self, i: u32) {
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = i;
|
self.max_iterations = i.clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-kind constants `(julia_c, phoenix_p, lambda_l, complex_power)`.
|
/// Per-kind constants `(julia_c, phoenix_p, lambda_l, complex_power)`.
|
||||||
@@ -1004,7 +1008,7 @@ impl FractalApp {
|
|||||||
self.morph = None;
|
self.morph = None;
|
||||||
// Presets carry a hand-tuned count; don't let the auto-scaler clobber it.
|
// Presets carry a hand-tuned count; don't let the auto-scaler clobber it.
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = iterations.clamp(32, MAX_REF_POINTS as u32 - 1);
|
self.max_iterations = iterations.clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,7 +1018,7 @@ impl FractalApp {
|
|||||||
fn auto_iteration_count(&self) -> u32 {
|
fn auto_iteration_count(&self) -> u32 {
|
||||||
let decades = self.view.magnification_log10().max(0.0);
|
let decades = self.view.magnification_log10().max(0.0);
|
||||||
let iters = 400.0 + 900.0 * decades;
|
let iters = 400.0 + 900.0 * decades;
|
||||||
(iters.round() as u32).clamp(200, MAX_REF_POINTS as u32 - 1)
|
(iters.round() as u32).clamp(200, MAX_ITERATIONS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Snapshot the current view as a shareable state.
|
/// Snapshot the current view as a shareable state.
|
||||||
@@ -1061,7 +1065,7 @@ impl FractalApp {
|
|||||||
// The link carries an explicit iteration count; honor it rather than
|
// The link carries an explicit iteration count; honor it rather than
|
||||||
// letting the auto-scaler immediately overwrite it.
|
// letting the auto-scaler immediately overwrite it.
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = s.iterations.clamp(32, MAX_REF_POINTS as u32 - 1);
|
self.max_iterations = s.iterations.clamp(32, MAX_ITERATIONS);
|
||||||
let bits = precision_for(s.half_height);
|
let bits = precision_for(s.half_height);
|
||||||
if let (Some(re), Some(im)) = (
|
if let (Some(re), Some(im)) = (
|
||||||
big_from_decimal_str(&s.center_re, bits),
|
big_from_decimal_str(&s.center_re, bits),
|
||||||
@@ -1157,7 +1161,7 @@ impl FractalApp {
|
|||||||
// while auto-iterations creep up during a zoom (the shader clamps
|
// while auto-iterations creep up during a zoom (the shader clamps
|
||||||
// to `max_iterations`); only recompute once it's too short, or
|
// to `max_iterations`); only recompute once it's too short, or
|
||||||
// far longer than needed.
|
// far longer than needed.
|
||||||
|| self.max_iterations > key.iter
|
|| self.max_iterations.min(MAX_ITERATIONS) > key.iter
|
||||||
|| self.max_iterations.saturating_mul(4) < key.iter
|
|| self.max_iterations.saturating_mul(4) < key.iter
|
||||||
|| key.kind != self.kind
|
|| key.kind != self.kind
|
||||||
|| key.power != self.power
|
|| key.power != self.power
|
||||||
@@ -2209,7 +2213,7 @@ impl FractalApp {
|
|||||||
for &(name, re, im, iterations, phoenix) in JULIA_PRESETS[self.kind as usize] {
|
for &(name, re, im, iterations, phoenix) in JULIA_PRESETS[self.kind as usize] {
|
||||||
if ui.small_button(name).clicked() {
|
if ui.small_button(name).clicked() {
|
||||||
self.julia_c = (re, im);
|
self.julia_c = (re, im);
|
||||||
self.max_iterations = iterations.clamp(32, MAX_REF_POINTS as u32 - 1);
|
self.max_iterations = iterations.clamp(32, MAX_ITERATIONS);
|
||||||
|
|
||||||
if let Some(phoenix) = phoenix {
|
if let Some(phoenix) = phoenix {
|
||||||
self.phoenix_p = phoenix;
|
self.phoenix_p = phoenix;
|
||||||
@@ -2266,11 +2270,15 @@ impl FractalApp {
|
|||||||
if self.auto_iterations {
|
if self.auto_iterations {
|
||||||
ui.label(format!("iterations: {} (auto)", self.max_iterations));
|
ui.label(format!("iterations: {} (auto)", self.max_iterations));
|
||||||
} else {
|
} else {
|
||||||
|
// Dragging stays within the slider's range, but a typed value
|
||||||
|
// isn't clamped to it: only to what the reference buffer can hold.
|
||||||
ui.add(
|
ui.add(
|
||||||
egui::Slider::new(&mut self.max_iterations, 32..=100_000)
|
egui::Slider::new(&mut self.max_iterations, 32..=100_000)
|
||||||
.text("iterations")
|
.text("iterations")
|
||||||
.logarithmic(true),
|
.logarithmic(true)
|
||||||
|
.clamping(egui::SliderClamping::Never),
|
||||||
);
|
);
|
||||||
|
self.max_iterations = self.max_iterations.clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
ui.checkbox(&mut self.antialias, "Antialiasing (2×2)")
|
ui.checkbox(&mut self.antialias, "Antialiasing (2×2)")
|
||||||
.on_hover_text("Supersample each pixel for smoother edges (~4× slower).");
|
.on_hover_text("Supersample each pixel for smoother edges (~4× slower).");
|
||||||
@@ -2812,13 +2820,13 @@ impl FractalApp {
|
|||||||
}
|
}
|
||||||
if ui.input(|i| i.key_pressed(egui::Key::Plus) || i.key_pressed(egui::Key::Equals)) {
|
if ui.input(|i| i.key_pressed(egui::Key::Plus) || i.key_pressed(egui::Key::Equals)) {
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = ((self.max_iterations as f64 * 1.25).round() as u32)
|
self.max_iterations =
|
||||||
.clamp(32, MAX_REF_POINTS as u32 - 1);
|
((self.max_iterations as f64 * 1.25).round() as u32).clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
if ui.input(|i| i.key_pressed(egui::Key::Minus)) {
|
if ui.input(|i| i.key_pressed(egui::Key::Minus)) {
|
||||||
self.auto_iterations = false;
|
self.auto_iterations = false;
|
||||||
self.max_iterations = ((self.max_iterations as f64 / 1.25).round() as u32)
|
self.max_iterations =
|
||||||
.clamp(32, MAX_REF_POINTS as u32 - 1);
|
((self.max_iterations as f64 / 1.25).round() as u32).clamp(32, MAX_ITERATIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ pub struct RefOrbit {
|
|||||||
|
|
||||||
impl RefOrbit {
|
impl RefOrbit {
|
||||||
fn with_capacity(n: usize) -> Self {
|
fn with_capacity(n: usize) -> Self {
|
||||||
|
// Most orbits escape long before `max_iter`; don't reserve hundreds of
|
||||||
|
// MB up front for a multi-million iteration request.
|
||||||
|
let n = n.min(1 << 17);
|
||||||
Self {
|
Self {
|
||||||
points: Vec::with_capacity(n),
|
points: Vec::with_capacity(n),
|
||||||
exps: Vec::with_capacity(n),
|
exps: Vec::with_capacity(n),
|
||||||
|
|||||||
+104
-29
@@ -19,9 +19,15 @@ use super::kind::FractalKind;
|
|||||||
use super::reference::RefOrbit;
|
use super::reference::RefOrbit;
|
||||||
use crate::lights::{GpuLight, Light, MAX_LIGHT_COUNT, gpu_lights};
|
use crate::lights::{GpuLight, Light, MAX_LIGHT_COUNT, gpu_lights};
|
||||||
|
|
||||||
/// Maximum reference-orbit length (points) the storage buffer can hold. Also
|
/// Maximum reference-orbit length (points), and so the hard ceiling on the
|
||||||
/// bounds the iteration count. 128k points * 8 bytes = 1 MiB.
|
/// iteration count (the shader treats an exhausted reference as escaped).
|
||||||
pub const MAX_REF_POINTS: usize = 1 << 17;
|
/// 16M points * 8 bytes = 128 MiB, WebGPU's default
|
||||||
|
/// `max_storage_buffer_binding_size`, so every device can bind it.
|
||||||
|
pub const MAX_REF_POINTS: usize = 1 << 24;
|
||||||
|
|
||||||
|
/// Initial capacity (points) of the interactive reference buffers; they grow
|
||||||
|
/// (by powers of two, up to `MAX_REF_POINTS`) when a longer orbit arrives.
|
||||||
|
const INITIAL_REF_POINTS: usize = 1 << 17;
|
||||||
|
|
||||||
/// Format of the intermediate iteration-data texture holding, per pixel,
|
/// Format of the intermediate iteration-data texture holding, per pixel,
|
||||||
/// `(ci, DE factor, interior fraction)`. 32-bit float keeps the smooth iteration
|
/// `(ci, DE factor, interior fraction)`. 32-bit float keeps the smooth iteration
|
||||||
@@ -233,7 +239,15 @@ impl Lipschitz {
|
|||||||
immediate_size: 0,
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
let pipeline = |label, entry| {
|
let pipeline = |label, entry| {
|
||||||
fullscreen_pipeline(device, label, &module, &pipeline_layout, entry, DATA_FORMAT, &[])
|
fullscreen_pipeline(
|
||||||
|
device,
|
||||||
|
label,
|
||||||
|
&module,
|
||||||
|
&pipeline_layout,
|
||||||
|
entry,
|
||||||
|
DATA_FORMAT,
|
||||||
|
&[],
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let mut contents = vec![0u8; (LIPSCHITZ_STRIDE * LIPSCHITZ_SLOTS) as usize];
|
let mut contents = vec![0u8; (LIPSCHITZ_STRIDE * LIPSCHITZ_SLOTS) as usize];
|
||||||
for k in 0..LIPSCHITZ_SLOTS {
|
for k in 0..LIPSCHITZ_SLOTS {
|
||||||
@@ -380,7 +394,13 @@ impl Envelope {
|
|||||||
pass(encoder, &self.views[0], &lp.seed, &self.inputs[1], 0);
|
pass(encoder, &self.views[0], &lp.seed, &self.inputs[1], 0);
|
||||||
// Pass i reads seeds i % 2 and writes the other.
|
// Pass i reads seeds i % 2 and writes the other.
|
||||||
for (i, &slot) in self.slots.iter().enumerate() {
|
for (i, &slot) in self.slots.iter().enumerate() {
|
||||||
pass(encoder, &self.views[(i + 1) % 2], &lp.jump, &self.inputs[i % 2], slot);
|
pass(
|
||||||
|
encoder,
|
||||||
|
&self.views[(i + 1) % 2],
|
||||||
|
&lp.jump,
|
||||||
|
&self.inputs[i % 2],
|
||||||
|
slot,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let last = self.slots.len() % 2;
|
let last = self.slots.len() % 2;
|
||||||
pass(encoder, &self.views[2], &lp.compose, &self.inputs[last], 0);
|
pass(encoder, &self.views[2], &lp.compose, &self.inputs[last], 0);
|
||||||
@@ -531,6 +551,8 @@ pub struct FractalRenderer {
|
|||||||
uniform_buffer: wgpu::Buffer,
|
uniform_buffer: wgpu::Buffer,
|
||||||
ref_buffer: wgpu::Buffer,
|
ref_buffer: wgpu::Buffer,
|
||||||
ref_exp_buffer: wgpu::Buffer,
|
ref_exp_buffer: wgpu::Buffer,
|
||||||
|
/// Points `ref_buffer` / `ref_exp_buffer` can hold (see `ensure_ref_capacity`).
|
||||||
|
ref_capacity: usize,
|
||||||
lights_buffer: wgpu::Buffer,
|
lights_buffer: wgpu::Buffer,
|
||||||
bind_group: wgpu::BindGroup,
|
bind_group: wgpu::BindGroup,
|
||||||
target_format: wgpu::TextureFormat,
|
target_format: wgpu::TextureFormat,
|
||||||
@@ -562,6 +584,37 @@ pub struct FractalRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FractalRenderer {
|
impl FractalRenderer {
|
||||||
|
/// Grow the reference buffers (and rebuild the bind group pointing at
|
||||||
|
/// them) so they hold at least `needed` points. The caller re-uploads the
|
||||||
|
/// orbit right after, so the old contents aren't copied over.
|
||||||
|
fn ensure_ref_capacity(&mut self, device: &wgpu::Device, needed: usize) {
|
||||||
|
if needed <= self.ref_capacity {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let capacity = needed.next_power_of_two().min(MAX_REF_POINTS);
|
||||||
|
self.ref_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("reference orbit"),
|
||||||
|
size: (capacity * std::mem::size_of::<[f32; 2]>()) as u64,
|
||||||
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
self.ref_exp_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("reference orbit exponents"),
|
||||||
|
size: (capacity * std::mem::size_of::<i32>()) as u64,
|
||||||
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
self.bind_group = iterate_bind_group(
|
||||||
|
device,
|
||||||
|
&self.bind_group_layout,
|
||||||
|
&self.uniform_buffer,
|
||||||
|
&self.ref_buffer,
|
||||||
|
&self.lights_buffer,
|
||||||
|
&self.ref_exp_buffer,
|
||||||
|
);
|
||||||
|
self.ref_capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(device: &wgpu::Device, target_format: wgpu::TextureFormat) -> Self {
|
pub fn new(device: &wgpu::Device, target_format: wgpu::TextureFormat) -> Self {
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: Some("mandelbrot"),
|
label: Some("mandelbrot"),
|
||||||
@@ -584,7 +637,7 @@ impl FractalRenderer {
|
|||||||
|
|
||||||
let ref_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let ref_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("reference orbit"),
|
label: Some("reference orbit"),
|
||||||
size: (MAX_REF_POINTS * std::mem::size_of::<[f32; 2]>()) as u64,
|
size: (INITIAL_REF_POINTS * std::mem::size_of::<[f32; 2]>()) as u64,
|
||||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
@@ -593,7 +646,7 @@ impl FractalRenderer {
|
|||||||
// read by deep pipelines.
|
// read by deep pipelines.
|
||||||
let ref_exp_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let ref_exp_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("reference orbit exponents"),
|
label: Some("reference orbit exponents"),
|
||||||
size: (MAX_REF_POINTS * std::mem::size_of::<i32>()) as u64,
|
size: (INITIAL_REF_POINTS * std::mem::size_of::<i32>()) as u64,
|
||||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
@@ -654,28 +707,14 @@ impl FractalRenderer {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group = iterate_bind_group(
|
||||||
label: Some("fractal bind group"),
|
device,
|
||||||
layout: &bind_group_layout,
|
&bind_group_layout,
|
||||||
entries: &[
|
&uniform_buffer,
|
||||||
wgpu::BindGroupEntry {
|
&ref_buffer,
|
||||||
binding: 0,
|
&lights_buffer,
|
||||||
resource: uniform_buffer.as_entire_binding(),
|
&ref_exp_buffer,
|
||||||
},
|
);
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: ref_buffer.as_entire_binding(),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 2,
|
|
||||||
resource: lights_buffer.as_entire_binding(),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 3,
|
|
||||||
resource: ref_exp_buffer.as_entire_binding(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("fractal pipeline layout"),
|
label: Some("fractal pipeline layout"),
|
||||||
@@ -872,6 +911,7 @@ impl FractalRenderer {
|
|||||||
uniform_buffer,
|
uniform_buffer,
|
||||||
ref_buffer,
|
ref_buffer,
|
||||||
ref_exp_buffer,
|
ref_exp_buffer,
|
||||||
|
ref_capacity: INITIAL_REF_POINTS,
|
||||||
lights_buffer,
|
lights_buffer,
|
||||||
bind_group,
|
bind_group,
|
||||||
target_format,
|
target_format,
|
||||||
@@ -1648,6 +1688,40 @@ pub fn encode_png_with_progress(
|
|||||||
|
|
||||||
/// Colourise pass input: the uniforms, the data texture `data` to colour and
|
/// Colourise pass input: the uniforms, the data texture `data` to colour and
|
||||||
/// the lights.
|
/// the lights.
|
||||||
|
/// Group 0 of the iterate/refine pipelines: uniforms, reference orbit,
|
||||||
|
/// lights, reference exponents.
|
||||||
|
fn iterate_bind_group(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
layout: &wgpu::BindGroupLayout,
|
||||||
|
uniform_buffer: &wgpu::Buffer,
|
||||||
|
ref_buffer: &wgpu::Buffer,
|
||||||
|
lights_buffer: &wgpu::Buffer,
|
||||||
|
ref_exp_buffer: &wgpu::Buffer,
|
||||||
|
) -> wgpu::BindGroup {
|
||||||
|
device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("fractal bind group"),
|
||||||
|
layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: uniform_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: ref_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 2,
|
||||||
|
resource: lights_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 3,
|
||||||
|
resource: ref_exp_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn colorize_bind_group(
|
fn colorize_bind_group(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
layout: &wgpu::BindGroupLayout,
|
layout: &wgpu::BindGroupLayout,
|
||||||
@@ -1779,6 +1853,7 @@ impl egui_wgpu::CallbackTrait for FractalCallback {
|
|||||||
&& !self.reference.is_empty()
|
&& !self.reference.is_empty()
|
||||||
{
|
{
|
||||||
let count = self.reference.len().min(MAX_REF_POINTS);
|
let count = self.reference.len().min(MAX_REF_POINTS);
|
||||||
|
renderer.ensure_ref_capacity(device, count);
|
||||||
queue.write_buffer(
|
queue.write_buffer(
|
||||||
&renderer.ref_buffer,
|
&renderer.ref_buffer,
|
||||||
0,
|
0,
|
||||||
|
|||||||
Reference in New Issue
Block a user