diene_engine_runtime/
lib.rs1#![forbid(unsafe_code)]
4
5use common::logging::macros::{debug, info};
6use engine_core::app::{ApplicationHost, ApplicationHostBuildError, ApplicationHostError, WindowError};
7use engine_renderer_api::{BoxedRenderer, RenderWindow, RendererFactory};
8use engine_renderer_vulkan::renderer::{VulkanRendererBuilder, VulkanRendererError};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13#[non_exhaustive]
14pub enum ApplicationError {
15 #[error("renderer failed: {0}")]
17 Renderer(#[source] VulkanRendererError),
18
19 #[error("window failed: {0}")]
21 Window(#[from] WindowError),
22
23 #[error("application build failed: {0}")]
25 Build(#[from] ApplicationHostBuildError),
26}
27
28impl From<ApplicationHostError<VulkanRendererError>> for ApplicationError {
29 fn from(error: ApplicationHostError<VulkanRendererError>) -> Self {
30 match error {
31 ApplicationHostError::Renderer(error) => Self::Renderer(error),
32 ApplicationHostError::Window(error) => Self::Window(error),
33 ApplicationHostError::Build(error) => Self::Build(error),
34 }
35 }
36}
37
38#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
40#[non_exhaustive]
41pub enum RendererBackend {
42 #[default]
44 Auto,
45
46 Vulkan,
48}
49
50#[derive(Debug)]
52pub struct Application {
53 host: RuntimeApplicationHost,
54}
55
56type RuntimeApplicationHost = ApplicationHost<RendererBackendSelector>;
57
58#[derive(Debug, Default)]
60pub struct ApplicationBuilder {
61 name: Option<String>,
62 renderer_backend: RendererBackend,
63 vsync: bool,
64}
65
66impl ApplicationBuilder {
67 #[must_use]
69 pub fn with_name(mut self, name: impl Into<String>) -> Self {
70 self.name = Some(name.into());
71 self
72 }
73
74 #[must_use]
76 pub fn with_renderer_backend(mut self, backend: RendererBackend) -> Self {
77 self.renderer_backend = backend;
78 self
79 }
80
81 #[must_use]
83 pub fn with_vsync(mut self, on: bool) -> Self {
84 self.vsync = on;
85 self
86 }
87
88 pub fn build(self) -> Result<Application, ApplicationError> {
90 debug!("building runtime application with backend {:?}", self.renderer_backend);
91
92 let selector = RendererBackendSelector { renderer_backend: self.renderer_backend, vsync: self.vsync };
93
94 let mut builder = ApplicationHost::builder(selector);
95
96 if let Some(name) = self.name {
97 builder = builder.with_name(name);
98 }
99
100 Ok(Application { host: builder.build()? })
101 }
102}
103
104impl Application {
105 pub fn builder() -> ApplicationBuilder {
107 ApplicationBuilder::default()
108 }
109
110 pub fn name(&self) -> &str {
112 self.host.name()
113 }
114
115 pub fn run(self) -> Result<(), ApplicationError> {
117 self.host.run().map_err(Into::into)
118 }
119}
120
121#[derive(Clone, Copy, Debug)]
122struct RendererBackendSelector {
123 renderer_backend: RendererBackend,
124 vsync: bool,
125}
126
127impl RendererFactory for RendererBackendSelector {
128 type Error = VulkanRendererError;
129
130 fn create_renderer(&mut self, window: &dyn RenderWindow) -> Result<BoxedRenderer<Self::Error>, Self::Error> {
131 match self.renderer_backend {
132 RendererBackend::Auto | RendererBackend::Vulkan => {
133 info!(
134 "selected renderer backend vulkan with {} policy",
135 if matches!(self.renderer_backend, RendererBackend::Auto) {
136 "auto"
137 } else {
138 "forced"
139 }
140 );
141 create_vulkan_renderer(window, self.vsync)
142 }
143 }
144 }
145}
146
147fn create_vulkan_renderer(window: &dyn RenderWindow, vsync: bool) -> Result<BoxedRenderer<VulkanRendererError>, VulkanRendererError> {
148 debug!("creating vulkan renderer");
149
150 let renderer = VulkanRendererBuilder::default().with_vsync(vsync).build(window)?;
151
152 Ok(Box::new(renderer))
153}