wgpu 22 → 29, glyphon 0.6 → 0.11: requestDevice-Shim entfällt
glyphon 0.11 ist die neueste zu wgpu 29 passende Version (wgpu 30 existiert bereits, glyphon pinnt aber ^29). Das 22er-Limit maxInterStageShaderComponents wird von 29 nicht mehr in requiredLimits gesendet — src/engine/requestDeviceShim.ts komplett entfernt, beide Hook-Importstellen (useWasmPlanRenderer, useWasm3dRenderer) angepasst. pollster 0.3→0.4, naga 22→29 mitgezogen. Alle Draw-/Text-Pfade (draw_sequence, glyphon ColorMode::Web, widthScreen-Polylinien, Headless/Golden) unverändert funktionsfähig. Verifiziert: cargo check nativ (render2d/render3d/src-tauri) grün, cargo test render2d 17/17 + Golden bit-exakt, render3d 29/29, wasm32 --features web für beide grün, npx tsc -b + npm run build grün.
This commit is contained in:
Generated
+386
-368
File diff suppressed because it is too large
Load Diff
@@ -47,5 +47,5 @@ render2d = { path = "render2d", features = ["window"], optional = true }
|
|||||||
render3d = { path = "render3d", features = ["window"], optional = true }
|
render3d = { path = "render3d", features = ["window"], optional = true }
|
||||||
# Versionen an render2d gekoppelt (identische raw-window-handle 0.6-Kette).
|
# Versionen an render2d gekoppelt (identische raw-window-handle 0.6-Kette).
|
||||||
winit = { version = "0.30", optional = true }
|
winit = { version = "0.30", optional = true }
|
||||||
wgpu = { version = "22", optional = true }
|
wgpu = { version = "29", optional = true }
|
||||||
pollster = { version = "0.3", optional = true }
|
pollster = { version = "0.4", optional = true }
|
||||||
|
|||||||
Generated
+795
-288
File diff suppressed because it is too large
Load Diff
@@ -66,15 +66,15 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
serde_json = { version = "1", optional = true }
|
serde_json = { version = "1", optional = true }
|
||||||
|
|
||||||
# --- GPU (nur mit Feature "render") ------------------------------------------
|
# --- GPU (nur mit Feature "render") ------------------------------------------
|
||||||
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal). Die Linux-Backends
|
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal + target-spezifisch
|
||||||
# Vulkan/GLES aktiviert wgpu selbst ueber seine target-spezifischen Defaults —
|
# Vulkan/GLES auf Linux). wgpu 30 ist bereits erschienen, aber glyphon 0.11
|
||||||
# es gibt in wgpu 22 keine expliziten `vulkan`/`gles`-Feature-Namen.
|
# pinnt `wgpu ^29` — 29 ist damit die neueste Version, bei der beide zusammenpassen.
|
||||||
wgpu = { version = "22", optional = true }
|
wgpu = { version = "29", optional = true }
|
||||||
bytemuck = { version = "1", optional = true, features = ["derive"] }
|
bytemuck = { version = "1", optional = true, features = ["derive"] }
|
||||||
pollster = { version = "0.3", optional = true }
|
pollster = { version = "0.4", optional = true }
|
||||||
# Echte TrueType-Glyphen ueber einen GPU-Atlas (cosmic-text + etagere). Version
|
# Echte TrueType-Glyphen ueber einen GPU-Atlas (cosmic-text + etagere). Version
|
||||||
# an wgpu gekoppelt: die 0.6er-Reihe ist die zu wgpu 22 passende.
|
# an wgpu gekoppelt: die 0.11er-Reihe ist die zu wgpu 29 passende.
|
||||||
glyphon = { version = "0.6", optional = true }
|
glyphon = { version = "0.11", optional = true }
|
||||||
|
|
||||||
# --- Headless-PNG-Export (nur mit Feature "headless") ------------------------
|
# --- Headless-PNG-Export (nur mit Feature "headless") ------------------------
|
||||||
# Nur der PNG-Codec noetig (kein volles Format-Universum) -> default-features aus.
|
# Nur der PNG-Codec noetig (kein volles Format-Universum) -> default-features aus.
|
||||||
@@ -103,8 +103,8 @@ web-sys = { version = "0.3", optional = true, features = [
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
# naga validiert die WGSL-Quellen headless (Parser + Validator) im Test, ohne
|
# naga validiert die WGSL-Quellen headless (Parser + Validator) im Test, ohne
|
||||||
# GPU/Display. Version an wgpu 22 gekoppelt (transitiv ohnehin vorhanden).
|
# GPU/Display. Version an wgpu gekoppelt (transitiv ohnehin vorhanden).
|
||||||
naga = { version = "22", features = ["wgsl-in"] }
|
naga = { version = "29", features = ["wgsl-in"] }
|
||||||
|
|
||||||
# Der Fenster-Spike ist nur mit Feature "window" verfuegbar; ohne das Feature
|
# Der Fenster-Spike ist nur mit Feature "window" verfuegbar; ohne das Feature
|
||||||
# wird das Binary aus dem Build ausgeschlossen (required-features).
|
# wird das Binary aus dem Build ausgeschlossen (required-features).
|
||||||
|
|||||||
@@ -43,15 +43,14 @@ impl GpuState {
|
|||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
}))
|
}))
|
||||||
.expect("kein passender GPU-Adapter");
|
.expect("kein passender GPU-Adapter");
|
||||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some("2d.device"),
|
||||||
label: Some("2d.device"),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::default(),
|
||||||
required_limits: wgpu::Limits::default(),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
}))
|
||||||
))
|
|
||||||
.expect("Device anfordern");
|
.expect("Device anfordern");
|
||||||
|
|
||||||
let caps = surface.get_capabilities(&adapter);
|
let caps = surface.get_capabilities(&adapter);
|
||||||
@@ -96,14 +95,17 @@ impl GpuState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, view_box: ViewBox) {
|
fn render(&mut self, view_box: ViewBox) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
eprintln!("Surface-Fehler: {e:?}");
|
eprintln!("Surface-Fehler: {other:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -222,8 +222,8 @@ impl Renderer {
|
|||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("2d.layout"),
|
label: Some("2d.layout"),
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
bind_group_layouts: &[Some(&bind_group_layout)],
|
||||||
push_constant_ranges: &[],
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Alpha-Blending (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) wie im WebGL-Pfad.
|
// Alpha-Blending (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) wie im WebGL-Pfad.
|
||||||
@@ -245,13 +245,13 @@ impl Renderer {
|
|||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &fill_module,
|
module: &fill_module,
|
||||||
entry_point: "vs_main",
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[fill_vertex_layout],
|
buffers: &[fill_vertex_layout],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &fill_module,
|
module: &fill_module,
|
||||||
entry_point: "fs_main",
|
entry_point: Some("fs_main"),
|
||||||
targets: &[Some(color_target.clone())],
|
targets: &[Some(color_target.clone())],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
}),
|
}),
|
||||||
@@ -267,7 +267,7 @@ impl Renderer {
|
|||||||
mask: !0,
|
mask: !0,
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
multiview: None,
|
multiview_mask: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -282,13 +282,13 @@ impl Renderer {
|
|||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &line_module,
|
module: &line_module,
|
||||||
entry_point: "vs_main",
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[line_vertex_layout],
|
buffers: &[line_vertex_layout],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &line_module,
|
module: &line_module,
|
||||||
entry_point: "fs_main",
|
entry_point: Some("fs_main"),
|
||||||
targets: &[Some(color_target)],
|
targets: &[Some(color_target)],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
}),
|
}),
|
||||||
@@ -303,7 +303,7 @@ impl Renderer {
|
|||||||
mask: !0,
|
mask: !0,
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
multiview: None,
|
multiview_mask: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -332,8 +332,8 @@ impl Renderer {
|
|||||||
let arc_pipeline_layout =
|
let arc_pipeline_layout =
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("arc.pipeline.layout"),
|
label: Some("arc.pipeline.layout"),
|
||||||
bind_group_layouts: &[&arc_bind_group_layout],
|
bind_group_layouts: &[Some(&arc_bind_group_layout)],
|
||||||
push_constant_ranges: &[],
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
// Instanz-Layout: [center vec2, geom vec4, color vec4, wdash vec4, dash vec4],
|
// Instanz-Layout: [center vec2, geom vec4, color vec4, wdash vec4, dash vec4],
|
||||||
// stride 18*4, step_mode Instance. Das Quad kommt aus @builtin(vertex_index).
|
// stride 18*4, step_mode Instance. Das Quad kommt aus @builtin(vertex_index).
|
||||||
@@ -349,13 +349,13 @@ impl Renderer {
|
|||||||
layout: Some(&arc_pipeline_layout),
|
layout: Some(&arc_pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &arc_module,
|
module: &arc_module,
|
||||||
entry_point: "vs_main",
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[arc_instance_layout],
|
buffers: &[arc_instance_layout],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &arc_module,
|
module: &arc_module,
|
||||||
entry_point: "fs_main",
|
entry_point: Some("fs_main"),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: color_format,
|
format: color_format,
|
||||||
blend,
|
blend,
|
||||||
@@ -374,7 +374,7 @@ impl Renderer {
|
|||||||
mask: !0,
|
mask: !0,
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
},
|
},
|
||||||
multiview: None,
|
multiview_mask: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
let arc_uniform = device.create_buffer(&wgpu::BufferDescriptor {
|
let arc_uniform = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
@@ -724,7 +724,15 @@ impl Renderer {
|
|||||||
);
|
);
|
||||||
// Unbegrenzt: eine Zeile, kein Umbruch (Zeilen sind vorgeflacht).
|
// Unbegrenzt: eine Zeile, kein Umbruch (Zeilen sind vorgeflacht).
|
||||||
buffer.set_size(&mut ts.font_system, None, None);
|
buffer.set_size(&mut ts.font_system, None, None);
|
||||||
buffer.set_text(&mut ts.font_system, &t.content, attrs, glyphon::Shaping::Advanced);
|
// Kein Align-Override (None): die Ausrichtung rechnet der
|
||||||
|
// Platzierungscode unten selbst ueber die gemessene Zeilenbreite.
|
||||||
|
buffer.set_text(
|
||||||
|
&mut ts.font_system,
|
||||||
|
&t.content,
|
||||||
|
&attrs,
|
||||||
|
glyphon::Shaping::Advanced,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
// Gemessene Breite + Baseline fuer Ausrichtung/Anker.
|
// Gemessene Breite + Baseline fuer Ausrichtung/Anker.
|
||||||
let (line_w, baseline) = buffer
|
let (line_w, baseline) = buffer
|
||||||
@@ -817,6 +825,8 @@ impl Renderer {
|
|||||||
label: Some("2d.pass"),
|
label: Some("2d.pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view: msaa_view,
|
view: msaa_view,
|
||||||
|
// Ziel ist eine 2D-Textur (kein 3D-Volumen) -> kein Depth-Slice.
|
||||||
|
depth_slice: None,
|
||||||
resolve_target: Some(view),
|
resolve_target: Some(view),
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(self.clear_color),
|
load: wgpu::LoadOp::Clear(self.clear_color),
|
||||||
@@ -826,6 +836,7 @@ impl Renderer {
|
|||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
|
multiview_mask: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
if let (Some(scene), Some(u)) = (&self.scene, &self.uniform) {
|
if let (Some(scene), Some(u)) = (&self.scene, &self.uniform) {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ impl HeadlessRenderer {
|
|||||||
pub fn new() -> Result<Self, String> {
|
pub fn new() -> Result<Self, String> {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: wgpu::Backends::VULKAN,
|
backends: wgpu::Backends::VULKAN,
|
||||||
..Default::default()
|
..wgpu::InstanceDescriptor::new_without_display_handle()
|
||||||
});
|
});
|
||||||
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
@@ -95,16 +95,15 @@ impl HeadlessRenderer {
|
|||||||
// Kein Fenster -> keine kompatible Surface noetig.
|
// Kein Fenster -> keine kompatible Surface noetig.
|
||||||
compatible_surface: None,
|
compatible_surface: None,
|
||||||
}))
|
}))
|
||||||
.ok_or_else(|| "kein Vulkan-Adapter fuer Headless-Rendering gefunden".to_string())?;
|
.map_err(|e| format!("kein Vulkan-Adapter fuer Headless-Rendering gefunden: {e}"))?;
|
||||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some("headless.device"),
|
||||||
label: Some("headless.device"),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::default(),
|
||||||
required_limits: wgpu::Limits::default(),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
}))
|
||||||
))
|
|
||||||
.map_err(|e| format!("Headless-Device anfordern fehlgeschlagen: {e}"))?;
|
.map_err(|e| format!("Headless-Device anfordern fehlgeschlagen: {e}"))?;
|
||||||
|
|
||||||
let renderer = Renderer::new(&device, COLOR_FORMAT);
|
let renderer = Renderer::new(&device, COLOR_FORMAT);
|
||||||
@@ -178,15 +177,15 @@ impl HeadlessRenderer {
|
|||||||
label: Some("headless.copy"),
|
label: Some("headless.copy"),
|
||||||
});
|
});
|
||||||
encoder.copy_texture_to_buffer(
|
encoder.copy_texture_to_buffer(
|
||||||
wgpu::ImageCopyTexture {
|
wgpu::TexelCopyTextureInfo {
|
||||||
texture,
|
texture,
|
||||||
mip_level: 0,
|
mip_level: 0,
|
||||||
origin: wgpu::Origin3d::ZERO,
|
origin: wgpu::Origin3d::ZERO,
|
||||||
aspect: wgpu::TextureAspect::All,
|
aspect: wgpu::TextureAspect::All,
|
||||||
},
|
},
|
||||||
wgpu::ImageCopyBuffer {
|
wgpu::TexelCopyBufferInfo {
|
||||||
buffer: &output_buffer,
|
buffer: &output_buffer,
|
||||||
layout: wgpu::ImageDataLayout {
|
layout: wgpu::TexelCopyBufferLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row: Some(padded_bytes_per_row),
|
bytes_per_row: Some(padded_bytes_per_row),
|
||||||
rows_per_image: Some(height),
|
rows_per_image: Some(height),
|
||||||
@@ -206,8 +205,11 @@ impl HeadlessRenderer {
|
|||||||
let _ = tx.send(res);
|
let _ = tx.send(res);
|
||||||
});
|
});
|
||||||
// Vulkan hat keine Event-Loop wie ein Fenster -> Poll blockierend, bis
|
// Vulkan hat keine Event-Loop wie ein Fenster -> Poll blockierend, bis
|
||||||
// die Map-Callback feuert (kein busy-loop noetig, `Maintain::Wait` wartet).
|
// die Map-Callback feuert (kein busy-loop noetig, `PollType::Wait` wartet
|
||||||
self.device.poll(wgpu::Maintain::Wait);
|
// ohne Timeout auf die juengste Submission).
|
||||||
|
self.device
|
||||||
|
.poll(wgpu::PollType::wait_indefinitely())
|
||||||
|
.expect("Device-Poll fehlgeschlagen");
|
||||||
rx.recv()
|
rx.recv()
|
||||||
.expect("Map-Callback nie aufgerufen")
|
.expect("Map-Callback nie aufgerufen")
|
||||||
.expect("Buffer-Mapping fehlgeschlagen");
|
.expect("Buffer-Mapping fehlgeschlagen");
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ impl WebPlanRenderer {
|
|||||||
|
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: wgpu::Backends::BROWSER_WEBGPU,
|
backends: wgpu::Backends::BROWSER_WEBGPU,
|
||||||
..Default::default()
|
..wgpu::InstanceDescriptor::new_without_display_handle()
|
||||||
});
|
});
|
||||||
let surface = instance
|
let surface = instance
|
||||||
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
|
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
|
||||||
@@ -67,19 +67,20 @@ impl WebPlanRenderer {
|
|||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| JsValue::from_str("kein WebGPU-Adapter (navigator.gpu?)"))?;
|
.map_err(|e| {
|
||||||
|
JsValue::from_str(&format!("kein WebGPU-Adapter (navigator.gpu?): {e}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
let (device, queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(
|
.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some("render2d.web.device"),
|
||||||
label: Some("render2d.web.device"),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
||||||
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
.using_resolution(adapter.limits()),
|
||||||
.using_resolution(adapter.limits()),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
})
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| JsValue::from_str(&format!("request_device: {e:?}")))?;
|
.map_err(|e| JsValue::from_str(&format!("request_device: {e:?}")))?;
|
||||||
|
|
||||||
@@ -169,15 +170,18 @@ impl WebPlanRenderer {
|
|||||||
|
|
||||||
/// Zeichnet EINEN Frame in die Surface-Textur.
|
/// Zeichnet EINEN Frame in die Surface-Textur.
|
||||||
pub fn render(&mut self) {
|
pub fn render(&mut self) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
web_sys::console::warn_1(&JsValue::from_str(&format!(
|
web_sys::console::warn_1(&JsValue::from_str(&format!(
|
||||||
"render2d Surface-Fehler: {e:?}"
|
"render2d Surface-Fehler: {other:?}"
|
||||||
)));
|
)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+449
-302
File diff suppressed because it is too large
Load Diff
@@ -59,12 +59,12 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
serde_json = { version = "1", optional = true }
|
serde_json = { version = "1", optional = true }
|
||||||
|
|
||||||
# --- GPU (nur mit Feature "render") ------------------------------------------
|
# --- GPU (nur mit Feature "render") ------------------------------------------
|
||||||
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal). Die Linux-Backends
|
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal + target-spezifisch
|
||||||
# Vulkan/GLES aktiviert wgpu selbst ueber seine target-spezifischen Defaults —
|
# Vulkan/GLES auf Linux). Version im Gleichschritt mit render2d: wgpu 29, weil
|
||||||
# es gibt in wgpu 22 keine expliziten `vulkan`/`gles`-Feature-Namen.
|
# glyphon (dort) noch keine 30 unterstuetzt — beide Crates teilen den Stand.
|
||||||
wgpu = { version = "22", optional = true }
|
wgpu = { version = "29", optional = true }
|
||||||
bytemuck = { version = "1", optional = true, features = ["derive"] }
|
bytemuck = { version = "1", optional = true, features = ["derive"] }
|
||||||
pollster = { version = "0.3", optional = true }
|
pollster = { version = "0.4", optional = true }
|
||||||
|
|
||||||
# --- Fenster (nur mit Feature "window") --------------------------------------
|
# --- Fenster (nur mit Feature "window") --------------------------------------
|
||||||
winit = { version = "0.30", optional = true }
|
winit = { version = "0.30", optional = true }
|
||||||
@@ -87,8 +87,8 @@ web-sys = { version = "0.3", optional = true, features = [
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
# naga validiert die WGSL-Quellen headless (Parser + Validator) im Test, ohne
|
# naga validiert die WGSL-Quellen headless (Parser + Validator) im Test, ohne
|
||||||
# GPU/Display. Version an wgpu 22 gekoppelt (transitiv ohnehin vorhanden).
|
# GPU/Display. Version an wgpu gekoppelt (transitiv ohnehin vorhanden).
|
||||||
naga = { version = "22", features = ["wgsl-in"] }
|
naga = { version = "29", features = ["wgsl-in"] }
|
||||||
|
|
||||||
# Der Fenster-Spike ist nur mit Feature "window" verfuegbar; ohne das Feature
|
# Der Fenster-Spike ist nur mit Feature "window" verfuegbar; ohne das Feature
|
||||||
# wird das Binary aus dem Build ausgeschlossen (required-features).
|
# wird das Binary aus dem Build ausgeschlossen (required-features).
|
||||||
|
|||||||
@@ -76,15 +76,14 @@ impl GpuState {
|
|||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
}))
|
}))
|
||||||
.expect("kein passender GPU-Adapter");
|
.expect("kein passender GPU-Adapter");
|
||||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some("3d.device"),
|
||||||
label: Some("3d.device"),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::default(),
|
||||||
required_limits: wgpu::Limits::default(),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
}))
|
||||||
))
|
|
||||||
.expect("Device anfordern");
|
.expect("Device anfordern");
|
||||||
|
|
||||||
let caps = surface.get_capabilities(&adapter);
|
let caps = surface.get_capabilities(&adapter);
|
||||||
@@ -129,14 +128,17 @@ impl GpuState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, camera: &Camera) {
|
fn render(&mut self, camera: &Camera) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
eprintln!("Surface-Fehler: {e:?}");
|
eprintln!("Surface-Fehler: {other:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ impl Renderer {
|
|||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("3d.layout"),
|
label: Some("3d.layout"),
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
bind_group_layouts: &[Some(&bind_group_layout)],
|
||||||
push_constant_ranges: &[],
|
immediate_size: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Vertex-Layout: [pos vec3, normal vec3, color vec3], stride 9*4.
|
// Vertex-Layout: [pos vec3, normal vec3, color vec3], stride 9*4.
|
||||||
@@ -124,13 +124,13 @@ impl Renderer {
|
|||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &module,
|
module: &module,
|
||||||
entry_point: "vs_main",
|
entry_point: Some("vs_main"),
|
||||||
buffers: &[vertex_layout],
|
buffers: &[vertex_layout],
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
},
|
},
|
||||||
fragment: Some(wgpu::FragmentState {
|
fragment: Some(wgpu::FragmentState {
|
||||||
module: &module,
|
module: &module,
|
||||||
entry_point: "fs_main",
|
entry_point: Some("fs_main"),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: color_format,
|
format: color_format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
@@ -147,13 +147,13 @@ impl Renderer {
|
|||||||
},
|
},
|
||||||
depth_stencil: Some(wgpu::DepthStencilState {
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
format: DEPTH_FORMAT,
|
format: DEPTH_FORMAT,
|
||||||
depth_write_enabled: true,
|
depth_write_enabled: Some(true),
|
||||||
depth_compare: wgpu::CompareFunction::Less,
|
depth_compare: Some(wgpu::CompareFunction::Less),
|
||||||
stencil: wgpu::StencilState::default(),
|
stencil: wgpu::StencilState::default(),
|
||||||
bias: wgpu::DepthBiasState::default(),
|
bias: wgpu::DepthBiasState::default(),
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
multiview: None,
|
multiview_mask: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -292,6 +292,8 @@ impl Renderer {
|
|||||||
label: Some("3d.pass"),
|
label: Some("3d.pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
view,
|
view,
|
||||||
|
// Ziel ist eine 2D-Textur (kein 3D-Volumen) -> kein Depth-Slice.
|
||||||
|
depth_slice: None,
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(self.clear_color),
|
load: wgpu::LoadOp::Clear(self.clear_color),
|
||||||
@@ -308,6 +310,7 @@ impl Renderer {
|
|||||||
}),
|
}),
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
|
multiview_mask: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(m) = &self.mesh {
|
if let Some(m) = &self.mesh {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ impl WebModelRenderer {
|
|||||||
|
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: wgpu::Backends::BROWSER_WEBGPU,
|
backends: wgpu::Backends::BROWSER_WEBGPU,
|
||||||
..Default::default()
|
..wgpu::InstanceDescriptor::new_without_display_handle()
|
||||||
});
|
});
|
||||||
let surface = instance
|
let surface = instance
|
||||||
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
|
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
|
||||||
@@ -76,19 +76,20 @@ impl WebModelRenderer {
|
|||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| JsValue::from_str("kein WebGPU-Adapter (navigator.gpu?)"))?;
|
.map_err(|e| {
|
||||||
|
JsValue::from_str(&format!("kein WebGPU-Adapter (navigator.gpu?): {e}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
let (device, queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(
|
.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some("render3d.web.device"),
|
||||||
label: Some("render3d.web.device"),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
||||||
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
.using_resolution(adapter.limits()),
|
||||||
.using_resolution(adapter.limits()),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
})
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| JsValue::from_str(&format!("request_device: {e:?}")))?;
|
.map_err(|e| JsValue::from_str(&format!("request_device: {e:?}")))?;
|
||||||
|
|
||||||
@@ -192,15 +193,18 @@ impl WebModelRenderer {
|
|||||||
|
|
||||||
/// Zeichnet EINEN Frame in die Surface-Textur.
|
/// Zeichnet EINEN Frame in die Surface-Textur.
|
||||||
pub fn render(&mut self) {
|
pub fn render(&mut self) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
web_sys::console::warn_1(&JsValue::from_str(&format!(
|
web_sys::console::warn_1(&JsValue::from_str(&format!(
|
||||||
"render3d Surface-Fehler: {e:?}"
|
"render3d Surface-Fehler: {other:?}"
|
||||||
)));
|
)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-17
@@ -139,14 +139,17 @@ impl GpuState2d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, view_box: ViewBox) {
|
fn render(&mut self, view_box: ViewBox) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
eprintln!("native2d Surface-Fehler: {e:?}");
|
eprintln!("native2d Surface-Fehler: {other:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -274,14 +277,17 @@ impl GpuState3d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, camera: &Camera) {
|
fn render(&mut self, camera: &Camera) {
|
||||||
|
// wgpu 29: `get_current_texture` liefert ein Enum statt eines Results —
|
||||||
|
// Suboptimal ist weiterhin praesentierbar, Lost/Outdated -> rekonfigurieren.
|
||||||
let frame = match self.surface.get_current_texture() {
|
let frame = match self.surface.get_current_texture() {
|
||||||
Ok(f) => f,
|
wgpu::CurrentSurfaceTexture::Success(f)
|
||||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||||
|
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||||
self.surface.configure(&self.device, &self.config);
|
self.surface.configure(&self.device, &self.config);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
other => {
|
||||||
eprintln!("native3d Surface-Fehler: {e:?}");
|
eprintln!("native3d Surface-Fehler: {other:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -332,6 +338,7 @@ fn demo_walls() -> Vec<WallInput> {
|
|||||||
height: ht,
|
height: ht,
|
||||||
base_elevation: 0.0,
|
base_elevation: 0.0,
|
||||||
color: grey,
|
color: grey,
|
||||||
|
openings: vec![],
|
||||||
};
|
};
|
||||||
vec![
|
vec![
|
||||||
mk([0.0, 0.0], [6.0, 0.0]),
|
mk([0.0, 0.0], [6.0, 0.0]),
|
||||||
@@ -443,15 +450,14 @@ fn configure_surface(
|
|||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
}))
|
}))
|
||||||
.expect("kein passender GPU-Adapter");
|
.expect("kein passender GPU-Adapter");
|
||||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||||
&wgpu::DeviceDescriptor {
|
label: Some(device_label),
|
||||||
label: Some(device_label),
|
required_features: wgpu::Features::empty(),
|
||||||
required_features: wgpu::Features::empty(),
|
required_limits: wgpu::Limits::default(),
|
||||||
required_limits: wgpu::Limits::default(),
|
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||||
memory_hints: wgpu::MemoryHints::Performance,
|
memory_hints: wgpu::MemoryHints::Performance,
|
||||||
},
|
trace: wgpu::Trace::Off,
|
||||||
None,
|
}))
|
||||||
))
|
|
||||||
.expect("Device anfordern");
|
.expect("Device anfordern");
|
||||||
|
|
||||||
let caps = surface.get_capabilities(&adapter);
|
let caps = surface.get_capabilities(&adapter);
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Kompatibilitäts-Shim für die WASM-Engines (render2d/render3d, beide wgpu 22):
|
|
||||||
* wgpu 22 sendet in `requestDevice` noch das Limit `maxInterStageShaderComponents`,
|
|
||||||
* das AUS DER WebGPU-Spec ENTFERNT wurde. Neuere Chromium-Builds lehnen einen
|
|
||||||
* nicht-`undefined`-Wert dafür mit `OperationError` ab (→ Device-Erzeugung
|
|
||||||
* schlägt fehl). Wir entfernen den Schlüssel EINMAL global aus dem Descriptor,
|
|
||||||
* bevor wgpu ihn stellt. Entfällt, sobald die Engines auf ein wgpu (+ glyphon)
|
|
||||||
* hochgezogen werden, das dieses Limit nicht mehr mitschickt.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let requestDevicePatched = false;
|
|
||||||
|
|
||||||
export function patchRequestDeviceLimits(): void {
|
|
||||||
if (requestDevicePatched) return;
|
|
||||||
const AdapterCtor = (globalThis as any).GPUAdapter;
|
|
||||||
if (!AdapterCtor?.prototype?.requestDevice) return;
|
|
||||||
const orig = AdapterCtor.prototype.requestDevice;
|
|
||||||
AdapterCtor.prototype.requestDevice = function (
|
|
||||||
this: unknown,
|
|
||||||
desc?: any,
|
|
||||||
) {
|
|
||||||
if (desc?.requiredLimits && "maxInterStageShaderComponents" in desc.requiredLimits) {
|
|
||||||
const requiredLimits = { ...desc.requiredLimits };
|
|
||||||
delete requiredLimits.maxInterStageShaderComponents;
|
|
||||||
desc = { ...desc, requiredLimits };
|
|
||||||
}
|
|
||||||
return orig.call(this, desc);
|
|
||||||
};
|
|
||||||
requestDevicePatched = true;
|
|
||||||
}
|
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import type { Plan } from "./generatePlan";
|
import type { Plan } from "./generatePlan";
|
||||||
import { planToRenderScene } from "./toRenderScene";
|
import { planToRenderScene } from "./toRenderScene";
|
||||||
// wgpu-22-Limit-Shim (maxInterStageShaderComponents), geteilt mit useWasm3dRenderer.
|
|
||||||
import { patchRequestDeviceLimits } from "../engine/requestDeviceShim";
|
|
||||||
|
|
||||||
interface ViewBox {
|
interface ViewBox {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -64,7 +62,6 @@ function getRenderer(canvas: HTMLCanvasElement): Promise<WebPlanRendererLike> {
|
|||||||
let p = rendererCache.get(canvas);
|
let p = rendererCache.get(canvas);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = (async () => {
|
p = (async () => {
|
||||||
patchRequestDeviceLimits(); // wgpu-22-Limit-Shim (src/engine/requestDeviceShim)
|
|
||||||
const mod = await loadEngine();
|
const mod = await loadEngine();
|
||||||
// Canvas VOR dem Surface-Erzeugen auf die Zielpixel (DPR) bringen.
|
// Canvas VOR dem Surface-Erzeugen auf die Zielpixel (DPR) bringen.
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import type { Project } from "../model/types";
|
import type { Project } from "../model/types";
|
||||||
import { projectToModel3d } from "../plan/toWalls3d";
|
import { projectToModel3d } from "../plan/toWalls3d";
|
||||||
// wgpu-22-Limit-Shim (maxInterStageShaderComponents), geteilt mit useWasmPlanRenderer.
|
|
||||||
import { patchRequestDeviceLimits } from "../engine/requestDeviceShim";
|
|
||||||
|
|
||||||
/** Fertige Kamera für einen Frame (world-Meter, Y-up — wie render3d::types::Camera). */
|
/** Fertige Kamera für einen Frame (world-Meter, Y-up — wie render3d::types::Camera). */
|
||||||
export interface Camera3d {
|
export interface Camera3d {
|
||||||
@@ -84,7 +82,6 @@ function getRenderer(canvas: HTMLCanvasElement): Promise<WebModelRendererLike> {
|
|||||||
let p = rendererCache.get(canvas);
|
let p = rendererCache.get(canvas);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = (async () => {
|
p = (async () => {
|
||||||
patchRequestDeviceLimits(); // wgpu-22-Limit-Shim (src/engine/requestDeviceShim)
|
|
||||||
const mod = await loadEngine();
|
const mod = await loadEngine();
|
||||||
// Canvas VOR dem Surface-Erzeugen auf die Zielpixel (DPR) bringen.
|
// Canvas VOR dem Surface-Erzeugen auf die Zielpixel (DPR) bringen.
|
||||||
const rect = canvas.getBoundingClientRect();
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
|||||||
Reference in New Issue
Block a user