mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 12:08:11 +08:00
Add the SVG Preview render mode in place of the Vello option in the preferences (#3797)
* Remove Vello from preferences * Add the Render Mode: SVG Preview radio button * Remove SVG outline renderer * Add a tooltip explaination when disabled in unsupported browsers * Fix Eyedropper tool to support Outline render mode * Use #[allow(clippy::too_many_arguments)] instead of tuple * Rerun nodegraph when max render area is changed --------- Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
co-authored by
Dennis Kobert
parent
a2d3b3f410
commit
9f2c8713ff
@@ -314,38 +314,6 @@ impl PreferencesDialogMessageHandler {
|
||||
}
|
||||
|
||||
if wgpu_available {
|
||||
let vello_description = "Auto uses Vello renderer when GPU is available.";
|
||||
let vello_renderer_label = vec![
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
TextLabel::new("Vello Renderer")
|
||||
.tooltip_label("Vello Renderer")
|
||||
.tooltip_description(vello_description)
|
||||
.widget_instance(),
|
||||
];
|
||||
let vello_preference = RadioInput::new(vec![
|
||||
RadioEntryData::new("Auto").label("Auto").on_update(move |_| {
|
||||
PreferencesMessage::VelloPreference {
|
||||
preference: graph_craft::wasm_application_io::VelloPreference::Auto,
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
RadioEntryData::new("Disabled").label("Disabled").on_update(move |_| {
|
||||
PreferencesMessage::VelloPreference {
|
||||
preference: graph_craft::wasm_application_io::VelloPreference::Disabled,
|
||||
}
|
||||
.into()
|
||||
}),
|
||||
])
|
||||
.selected_index(Some(preferences.vello_preference as u32))
|
||||
.widget_instance();
|
||||
let vello_preference = vec![
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
vello_preference,
|
||||
];
|
||||
rows.extend_from_slice(&[vello_renderer_label, vello_preference]);
|
||||
|
||||
let render_tile_resolution_description = "
|
||||
Maximum X or Y resolution per render tile. Larger tiles may improve performance but can cause flickering or missing content in complex artwork if set too high.\n\
|
||||
\n\
|
||||
|
||||
@@ -33,6 +33,7 @@ use graphene_std::math::quad::Quad;
|
||||
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
||||
use graphene_std::raster::BlendMode;
|
||||
use graphene_std::raster_types::Raster;
|
||||
use graphene_std::render_node::wgpu_available;
|
||||
use graphene_std::subpath::Subpath;
|
||||
use graphene_std::table::Table;
|
||||
use graphene_std::vector::PointId;
|
||||
@@ -2549,29 +2550,46 @@ impl DocumentMessageHandler {
|
||||
.popover_min_width(Some(320))
|
||||
.widget_instance(),
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
RadioInput::new(vec![
|
||||
RadioEntryData::new("Normal")
|
||||
.icon("RenderModeNormal")
|
||||
.tooltip_label("Render Mode: Normal")
|
||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Normal }.into()),
|
||||
RadioEntryData::new("Outline")
|
||||
.icon("RenderModeOutline")
|
||||
.tooltip_label("Render Mode: Outline")
|
||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Outline }.into()),
|
||||
// TODO: See issue #320
|
||||
// RadioEntryData::new("PixelPreview")
|
||||
// .icon("RenderModePixels")
|
||||
// .tooltip_label("Render Mode: Pixel Preview")
|
||||
// .on_update(|_| todo!()),
|
||||
// TODO: See issue #1845
|
||||
// RadioEntryData::new("SvgPreview")
|
||||
// .icon("RenderModeSvg")
|
||||
// .tooltip_label("Render Mode: SVG Preview")
|
||||
// .on_update(|_| todo!()),
|
||||
])
|
||||
.selected_index(Some(self.render_mode as u32))
|
||||
.narrow(true)
|
||||
.widget_instance(),
|
||||
{
|
||||
let disabled = cfg!(target_family = "wasm") && wgpu_available() == Some(false);
|
||||
|
||||
let mut entries = vec![
|
||||
RadioEntryData::new("Normal")
|
||||
.icon("RenderModeNormal")
|
||||
.tooltip_label("Render Mode: Normal")
|
||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Normal }.into()),
|
||||
RadioEntryData::new("Outline")
|
||||
.icon("RenderModeOutline")
|
||||
.tooltip_label("Render Mode: Outline")
|
||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::Outline }.into()),
|
||||
// TODO: See issue #320
|
||||
// RadioEntryData::new("PixelPreview")
|
||||
// .icon("RenderModePixels")
|
||||
// .tooltip_label("Render Mode: Pixel Preview")
|
||||
// .on_update(|_| todo!()),
|
||||
RadioEntryData::new("SvgPreview")
|
||||
.icon("RenderModeSvg")
|
||||
.tooltip_label("Render Mode: SVG Preview")
|
||||
.on_update(|_| DocumentMessage::SetRenderMode { render_mode: RenderMode::SvgPreview }.into()),
|
||||
];
|
||||
let mut selected_index = self.render_mode as u32;
|
||||
|
||||
if disabled {
|
||||
for entry in &mut entries {
|
||||
entry.tooltip_description = "
|
||||
*Normal* and *Outline* render modes are not available in this browser. For compatibility, *SVG Preview* mode is active as a fallback.\n\
|
||||
\n\
|
||||
This functionality requires WebGPU support. Check webgpu.org for browser implementation status.
|
||||
"
|
||||
.trim()
|
||||
.into();
|
||||
}
|
||||
|
||||
selected_index = entries.iter().position(|entry| entry.value == "SvgPreview").unwrap() as u32;
|
||||
}
|
||||
|
||||
RadioInput::new(entries).selected_index(Some(selected_index)).disabled(disabled).narrow(true).widget_instance()
|
||||
},
|
||||
Separator::new(SeparatorStyle::Unrelated).widget_instance(),
|
||||
];
|
||||
|
||||
|
||||
@@ -157,5 +157,4 @@ pub enum PortfolioMessage {
|
||||
ToggleRulers,
|
||||
UpdateDocumentWidgets,
|
||||
UpdateOpenDocumentsList,
|
||||
UpdateVelloPreference,
|
||||
}
|
||||
|
||||
@@ -407,6 +407,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||
|
||||
// TODO: Remove this when we do the SVG rendering with a separate library on desktop, thus avoiding a need for the hole punch.
|
||||
// TODO: See #3796. There is a second instance of this todo comment and code block (be sure to remove both).
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
responses.add_front(FrontendMessage::UpdateViewportHolePunch {
|
||||
active: document.render_mode != graphene_std::vector::style::RenderMode::SvgPreview,
|
||||
});
|
||||
|
||||
if let Ok(message) = self.executor.submit_node_graph_evaluation(
|
||||
self.documents.get_mut(document_id).expect("Tried to render non-existent document"),
|
||||
*document_id,
|
||||
@@ -1163,6 +1170,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
// Use exact physical dimensions from browser (via ResizeObserver's devicePixelContentBoxSize)
|
||||
let physical_resolution = viewport.size().to_physical().into_dvec2().round().as_uvec2();
|
||||
|
||||
// TODO: Remove this when we do the SVG rendering with a separate library on desktop, thus avoiding a need for the hole punch.
|
||||
// TODO: See #3796. There is a second instance of this todo comment and code block (be sure to remove both).
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
responses.add_front(FrontendMessage::UpdateViewportHolePunch {
|
||||
active: document.render_mode != graphene_std::vector::style::RenderMode::SvgPreview,
|
||||
});
|
||||
|
||||
let result = self
|
||||
.executor
|
||||
.submit_node_graph_evaluation(document, document_id, physical_resolution, scale, timing_information, node_to_inspect, ignore_hash, pointer_position);
|
||||
@@ -1197,7 +1211,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
|
||||
let result = self
|
||||
.executor
|
||||
.submit_eyedropper_preview(document_id, preview_transform, pointer_position, resolution, scale, timing_information);
|
||||
.submit_eyedropper_preview(document, document_id, preview_transform, pointer_position, resolution, scale, timing_information);
|
||||
|
||||
match result {
|
||||
Err(description) => {
|
||||
@@ -1364,13 +1378,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
||||
}
|
||||
}
|
||||
PortfolioMessage::UpdateVelloPreference => {
|
||||
// TODO: Resend this message once the GPU context is initialized to avoid having the hole punch be stuck in an invalid state
|
||||
let active = if cfg!(target_family = "wasm") { false } else { preferences.use_vello() };
|
||||
responses.add(FrontendMessage::UpdateViewportHolePunch { active });
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
self.persistent_data.use_vello = preferences.use_vello();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use graphene_std::text::{Font, FontCache};
|
||||
pub struct PersistentData {
|
||||
pub font_cache: FontCache,
|
||||
pub font_catalog: FontCatalog,
|
||||
pub use_vello: bool,
|
||||
}
|
||||
|
||||
// TODO: Should this be a BTreeMap instead?
|
||||
|
||||
@@ -10,7 +10,6 @@ pub enum PreferencesMessage {
|
||||
ResetToDefaults,
|
||||
|
||||
// Per-preference messages
|
||||
VelloPreference { preference: graph_craft::wasm_application_io::VelloPreference },
|
||||
SelectionMode { selection_mode: SelectionMode },
|
||||
BrushTool { enabled: bool },
|
||||
ModifyLayout { zoom_with_scroll: bool },
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::messages::preferences::SelectionMode;
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::utility_types::ToolType;
|
||||
use graph_craft::wasm_application_io::EditorPreferences;
|
||||
use graphene_std::application_io::GetEditorPreferences;
|
||||
|
||||
#[derive(ExtractField)]
|
||||
pub struct PreferencesMessageContext<'a> {
|
||||
@@ -17,7 +16,6 @@ pub struct PreferencesMessageContext<'a> {
|
||||
pub struct PreferencesMessageHandler {
|
||||
pub selection_mode: SelectionMode,
|
||||
pub zoom_with_scroll: bool,
|
||||
pub vello_preference: graph_craft::wasm_application_io::VelloPreference,
|
||||
pub brush_tool: bool,
|
||||
pub graph_wire_style: GraphWireStyle,
|
||||
pub viewport_zoom_wheel_rate: f64,
|
||||
@@ -37,7 +35,6 @@ impl PreferencesMessageHandler {
|
||||
|
||||
pub fn editor_preferences(&self) -> EditorPreferences {
|
||||
EditorPreferences {
|
||||
vello_preference: self.vello_preference,
|
||||
max_render_region_size: self.max_render_region_size,
|
||||
}
|
||||
}
|
||||
@@ -45,10 +42,6 @@ impl PreferencesMessageHandler {
|
||||
pub fn supports_wgpu(&self) -> bool {
|
||||
graph_craft::wasm_application_io::wgpu_available().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn use_vello(&self) -> bool {
|
||||
self.editor_preferences().use_vello()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PreferencesMessageHandler {
|
||||
@@ -56,7 +49,6 @@ impl Default for PreferencesMessageHandler {
|
||||
Self {
|
||||
selection_mode: SelectionMode::Touched,
|
||||
zoom_with_scroll: matches!(MappingVariant::default(), MappingVariant::ZoomWithScroll),
|
||||
vello_preference: EditorPreferences::default().vello_preference,
|
||||
brush_tool: false,
|
||||
graph_wire_style: GraphWireStyle::default(),
|
||||
viewport_zoom_wheel_rate: VIEWPORT_ZOOM_WHEEL_RATE,
|
||||
@@ -78,7 +70,6 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||
*self = preferences;
|
||||
|
||||
responses.add(PortfolioMessage::EditorPreferences);
|
||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
||||
responses.add(PreferencesMessage::ModifyLayout {
|
||||
zoom_with_scroll: self.zoom_with_scroll,
|
||||
});
|
||||
@@ -90,12 +81,6 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||
}
|
||||
|
||||
// Per-preference messages
|
||||
PreferencesMessage::VelloPreference { preference } => {
|
||||
self.vello_preference = preference;
|
||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
||||
responses.add(PortfolioMessage::EditorPreferences);
|
||||
responses.add(PreferencesDialogMessage::Update);
|
||||
}
|
||||
PreferencesMessage::BrushTool { enabled } => {
|
||||
self.brush_tool = enabled;
|
||||
|
||||
@@ -131,8 +116,8 @@ impl MessageHandler<PreferencesMessage, PreferencesMessageContext<'_>> for Prefe
|
||||
}
|
||||
PreferencesMessage::MaxRenderRegionSize { size } => {
|
||||
self.max_render_region_size = size;
|
||||
responses.add(PortfolioMessage::UpdateVelloPreference);
|
||||
responses.add(PortfolioMessage::EditorPreferences);
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,9 +187,11 @@ impl NodeGraphExecutor {
|
||||
self.submit_current_node_graph_evaluation(document, document_id, viewport_resolution, viewport_scale, time, pointer)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub(crate) fn submit_eyedropper_preview(
|
||||
&mut self,
|
||||
document: &DocumentMessageHandler,
|
||||
document_id: DocumentId,
|
||||
transform: DAffine2,
|
||||
pointer: DVec2,
|
||||
@@ -208,7 +210,7 @@ impl NodeGraphExecutor {
|
||||
time,
|
||||
pointer,
|
||||
export_format: graphene_std::application_io::ExportFormat::Raster,
|
||||
render_mode: graphene_std::vector::style::RenderMode::Normal,
|
||||
render_mode: document.render_mode,
|
||||
hide_artboards: false,
|
||||
for_export: false,
|
||||
for_eyedropper: true,
|
||||
|
||||
@@ -18,6 +18,7 @@ use graphene_std::table::{Table, TableRow};
|
||||
use graphene_std::text::FontCache;
|
||||
use graphene_std::transform::RenderQuality;
|
||||
use graphene_std::vector::Vector;
|
||||
use graphene_std::vector::style::RenderMode;
|
||||
use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, WasmEditorApi};
|
||||
use graphene_std::{Artboard, Context, Graphic};
|
||||
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
|
||||
@@ -243,16 +244,11 @@ impl NodeRuntime {
|
||||
self.sender.send_generation_response(CompilationResponse { result, node_graph_errors });
|
||||
}
|
||||
GraphRuntimeRequest::ExecutionRequest(ExecutionRequest { execution_id, mut render_config, .. }) => {
|
||||
// There are cases where we want to export via the svg pipeline eventhough raster was requested.
|
||||
if matches!(render_config.export_format, ExportFormat::Raster) {
|
||||
let vello_available = self.editor_api.application_io.as_ref().unwrap().gpu_executor().is_some();
|
||||
let use_vello = vello_available && self.editor_api.editor_preferences.use_vello();
|
||||
|
||||
// On web when the user has disabled vello rendering in the preferences or we are exporting.
|
||||
// And on all platforms when vello is not supposed to be used.
|
||||
if !use_vello || cfg!(target_family = "wasm") && render_config.for_export {
|
||||
render_config.export_format = ExportFormat::Svg;
|
||||
}
|
||||
// We may want to render via the SVG pipeline even though raster was requested, if SVG Preview render mode is active or WebGPU/Vello is unavailable
|
||||
if render_config.export_format == ExportFormat::Raster
|
||||
&& (render_config.render_mode == RenderMode::SvgPreview || self.editor_api.application_io.as_ref().unwrap().gpu_executor().is_none())
|
||||
{
|
||||
render_config.export_format = ExportFormat::Svg;
|
||||
}
|
||||
|
||||
let result = self.execute_network(render_config).await;
|
||||
|
||||
Reference in New Issue
Block a user