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
+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 }
|
||||
|
||||
# --- GPU (nur mit Feature "render") ------------------------------------------
|
||||
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal). Die Linux-Backends
|
||||
# Vulkan/GLES aktiviert wgpu selbst ueber seine target-spezifischen Defaults —
|
||||
# es gibt in wgpu 22 keine expliziten `vulkan`/`gles`-Feature-Namen.
|
||||
wgpu = { version = "22", optional = true }
|
||||
# Standard-Features von wgpu (wgsl, webgpu, dx12, metal + target-spezifisch
|
||||
# Vulkan/GLES auf Linux). wgpu 30 ist bereits erschienen, aber glyphon 0.11
|
||||
# pinnt `wgpu ^29` — 29 ist damit die neueste Version, bei der beide zusammenpassen.
|
||||
wgpu = { version = "29", optional = true }
|
||||
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
|
||||
# an wgpu gekoppelt: die 0.6er-Reihe ist die zu wgpu 22 passende.
|
||||
glyphon = { version = "0.6", optional = true }
|
||||
# an wgpu gekoppelt: die 0.11er-Reihe ist die zu wgpu 29 passende.
|
||||
glyphon = { version = "0.11", optional = true }
|
||||
|
||||
# --- Headless-PNG-Export (nur mit Feature "headless") ------------------------
|
||||
# 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]
|
||||
serde_json = "1"
|
||||
# naga validiert die WGSL-Quellen headless (Parser + Validator) im Test, ohne
|
||||
# GPU/Display. Version an wgpu 22 gekoppelt (transitiv ohnehin vorhanden).
|
||||
naga = { version = "22", features = ["wgsl-in"] }
|
||||
# GPU/Display. Version an wgpu gekoppelt (transitiv ohnehin vorhanden).
|
||||
naga = { version = "29", features = ["wgsl-in"] }
|
||||
|
||||
# Der Fenster-Spike ist nur mit Feature "window" verfuegbar; ohne das Feature
|
||||
# wird das Binary aus dem Build ausgeschlossen (required-features).
|
||||
|
||||
@@ -43,15 +43,14 @@ impl GpuState {
|
||||
compatible_surface: Some(&surface),
|
||||
}))
|
||||
.expect("kein passender GPU-Adapter");
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: Some("2d.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
},
|
||||
None,
|
||||
))
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
label: Some("2d.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
trace: wgpu::Trace::Off,
|
||||
}))
|
||||
.expect("Device anfordern");
|
||||
|
||||
let caps = surface.get_capabilities(&adapter);
|
||||
@@ -96,14 +95,17 @@ impl GpuState {
|
||||
}
|
||||
|
||||
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() {
|
||||
Ok(f) => f,
|
||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
||||
wgpu::CurrentSurfaceTexture::Success(f)
|
||||
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Surface-Fehler: {e:?}");
|
||||
other => {
|
||||
eprintln!("Surface-Fehler: {other:?}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -222,8 +222,8 @@ impl Renderer {
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("2d.layout"),
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[Some(&bind_group_layout)],
|
||||
immediate_size: 0,
|
||||
});
|
||||
|
||||
// Alpha-Blending (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) wie im WebGL-Pfad.
|
||||
@@ -245,13 +245,13 @@ impl Renderer {
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &fill_module,
|
||||
entry_point: "vs_main",
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[fill_vertex_layout],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fill_module,
|
||||
entry_point: "fs_main",
|
||||
entry_point: Some("fs_main"),
|
||||
targets: &[Some(color_target.clone())],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
@@ -267,7 +267,7 @@ impl Renderer {
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@@ -282,13 +282,13 @@ impl Renderer {
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &line_module,
|
||||
entry_point: "vs_main",
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[line_vertex_layout],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &line_module,
|
||||
entry_point: "fs_main",
|
||||
entry_point: Some("fs_main"),
|
||||
targets: &[Some(color_target)],
|
||||
compilation_options: Default::default(),
|
||||
}),
|
||||
@@ -303,7 +303,7 @@ impl Renderer {
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@@ -332,8 +332,8 @@ impl Renderer {
|
||||
let arc_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("arc.pipeline.layout"),
|
||||
bind_group_layouts: &[&arc_bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
bind_group_layouts: &[Some(&arc_bind_group_layout)],
|
||||
immediate_size: 0,
|
||||
});
|
||||
// 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).
|
||||
@@ -349,13 +349,13 @@ impl Renderer {
|
||||
layout: Some(&arc_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &arc_module,
|
||||
entry_point: "vs_main",
|
||||
entry_point: Some("vs_main"),
|
||||
buffers: &[arc_instance_layout],
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &arc_module,
|
||||
entry_point: "fs_main",
|
||||
entry_point: Some("fs_main"),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: color_format,
|
||||
blend,
|
||||
@@ -374,7 +374,7 @@ impl Renderer {
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let arc_uniform = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
@@ -724,7 +724,15 @@ impl Renderer {
|
||||
);
|
||||
// Unbegrenzt: eine Zeile, kein Umbruch (Zeilen sind vorgeflacht).
|
||||
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.
|
||||
let (line_w, baseline) = buffer
|
||||
@@ -817,6 +825,8 @@ impl Renderer {
|
||||
label: Some("2d.pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: msaa_view,
|
||||
// Ziel ist eine 2D-Textur (kein 3D-Volumen) -> kein Depth-Slice.
|
||||
depth_slice: None,
|
||||
resolve_target: Some(view),
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(self.clear_color),
|
||||
@@ -826,6 +836,7 @@ impl Renderer {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
if let (Some(scene), Some(u)) = (&self.scene, &self.uniform) {
|
||||
|
||||
@@ -87,7 +87,7 @@ impl HeadlessRenderer {
|
||||
pub fn new() -> Result<Self, String> {
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::VULKAN,
|
||||
..Default::default()
|
||||
..wgpu::InstanceDescriptor::new_without_display_handle()
|
||||
});
|
||||
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||
@@ -95,16 +95,15 @@ impl HeadlessRenderer {
|
||||
// Kein Fenster -> keine kompatible Surface noetig.
|
||||
compatible_surface: None,
|
||||
}))
|
||||
.ok_or_else(|| "kein Vulkan-Adapter fuer Headless-Rendering gefunden".to_string())?;
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: Some("headless.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
},
|
||||
None,
|
||||
))
|
||||
.map_err(|e| format!("kein Vulkan-Adapter fuer Headless-Rendering gefunden: {e}"))?;
|
||||
let (device, queue) = pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor {
|
||||
label: Some("headless.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
trace: wgpu::Trace::Off,
|
||||
}))
|
||||
.map_err(|e| format!("Headless-Device anfordern fehlgeschlagen: {e}"))?;
|
||||
|
||||
let renderer = Renderer::new(&device, COLOR_FORMAT);
|
||||
@@ -178,15 +177,15 @@ impl HeadlessRenderer {
|
||||
label: Some("headless.copy"),
|
||||
});
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::ImageCopyTexture {
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::ImageCopyBuffer {
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &output_buffer,
|
||||
layout: wgpu::ImageDataLayout {
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(padded_bytes_per_row),
|
||||
rows_per_image: Some(height),
|
||||
@@ -206,8 +205,11 @@ impl HeadlessRenderer {
|
||||
let _ = tx.send(res);
|
||||
});
|
||||
// Vulkan hat keine Event-Loop wie ein Fenster -> Poll blockierend, bis
|
||||
// die Map-Callback feuert (kein busy-loop noetig, `Maintain::Wait` wartet).
|
||||
self.device.poll(wgpu::Maintain::Wait);
|
||||
// die Map-Callback feuert (kein busy-loop noetig, `PollType::Wait` wartet
|
||||
// ohne Timeout auf die juengste Submission).
|
||||
self.device
|
||||
.poll(wgpu::PollType::wait_indefinitely())
|
||||
.expect("Device-Poll fehlgeschlagen");
|
||||
rx.recv()
|
||||
.expect("Map-Callback nie aufgerufen")
|
||||
.expect("Buffer-Mapping fehlgeschlagen");
|
||||
|
||||
@@ -54,7 +54,7 @@ impl WebPlanRenderer {
|
||||
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::BROWSER_WEBGPU,
|
||||
..Default::default()
|
||||
..wgpu::InstanceDescriptor::new_without_display_handle()
|
||||
});
|
||||
let surface = instance
|
||||
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
|
||||
@@ -67,19 +67,20 @@ impl WebPlanRenderer {
|
||||
compatible_surface: Some(&surface),
|
||||
})
|
||||
.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
|
||||
.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: Some("render2d.web.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
||||
.using_resolution(adapter.limits()),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
},
|
||||
None,
|
||||
)
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
label: Some("render2d.web.device"),
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
|
||||
.using_resolution(adapter.limits()),
|
||||
experimental_features: wgpu::ExperimentalFeatures::disabled(),
|
||||
memory_hints: wgpu::MemoryHints::Performance,
|
||||
trace: wgpu::Trace::Off,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| JsValue::from_str(&format!("request_device: {e:?}")))?;
|
||||
|
||||
@@ -169,15 +170,18 @@ impl WebPlanRenderer {
|
||||
|
||||
/// Zeichnet EINEN Frame in die Surface-Textur.
|
||||
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() {
|
||||
Ok(f) => f,
|
||||
Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => {
|
||||
wgpu::CurrentSurfaceTexture::Success(f)
|
||||
| wgpu::CurrentSurfaceTexture::Suboptimal(f) => f,
|
||||
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
return;
|
||||
}
|
||||
Err(e) => {
|
||||
other => {
|
||||
web_sys::console::warn_1(&JsValue::from_str(&format!(
|
||||
"render2d Surface-Fehler: {e:?}"
|
||||
"render2d Surface-Fehler: {other:?}"
|
||||
)));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user