mod.rs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_serial::{async_trait, Decodable, Encodable, SerialDecodable, SerialEncodable};
  19. use log::debug;
  20. use miniquad::{
  21. conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferLayout,
  22. BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
  23. PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TouchPhase,
  24. UniformDesc, UniformType, VertexAttribute, VertexFormat,
  25. };
  26. use std::{
  27. collections::HashMap,
  28. fs::File,
  29. path::PathBuf,
  30. sync::{
  31. atomic::{AtomicU32, Ordering},
  32. Arc,
  33. },
  34. };
  35. mod favico;
  36. mod linalg;
  37. pub use linalg::{Dimension, Point, Rectangle};
  38. mod shader;
  39. use crate::{
  40. error::{Error, Result},
  41. GOD,
  42. };
  43. // This is very noisy so suppress output by default
  44. const DEBUG_RENDER: bool = false;
  45. const DEBUG_GFXAPI: bool = false;
  46. #[macro_export]
  47. macro_rules! gfxtag {
  48. ($s:expr) => {{
  49. Some($s)
  50. }};
  51. }
  52. pub use crate::gfxtag;
  53. pub type DebugTag = Option<&'static str>;
  54. macro_rules! t { ($($arg:tt)*) => { trace!(target: "gfx", $($arg)*); } }
  55. macro_rules! e { ($($arg:tt)*) => { error!(target: "gfx", $($arg)*); } }
  56. #[cfg(target_os = "android")]
  57. pub fn get_window_size_filename() -> PathBuf {
  58. crate::android::get_appdata_path().join("window_size")
  59. }
  60. #[cfg(not(target_os = "android"))]
  61. pub fn get_window_size_filename() -> PathBuf {
  62. dirs::cache_dir().unwrap().join("darkfi/app/window_size")
  63. }
  64. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  65. #[repr(C)]
  66. pub struct Vertex {
  67. pub pos: [f32; 2],
  68. pub color: [f32; 4],
  69. pub uv: [f32; 2],
  70. }
  71. impl Vertex {
  72. pub fn pos(&self) -> Point {
  73. self.pos.into()
  74. }
  75. pub fn set_pos(&mut self, pos: &Point) {
  76. self.pos = pos.as_arr();
  77. }
  78. }
  79. pub type GfxTextureId = u32;
  80. pub type GfxBufferId = u32;
  81. static NEXT_BUFFER_ID: AtomicU32 = AtomicU32::new(0);
  82. static NEXT_TEXTURE_ID: AtomicU32 = AtomicU32::new(0);
  83. pub type ManagedTexturePtr = Arc<ManagedTexture>;
  84. /// Auto-deletes texture on drop
  85. #[derive(Clone)]
  86. pub struct ManagedTexture {
  87. id: GfxTextureId,
  88. epoch: u32,
  89. render_api: RenderApi,
  90. tag: DebugTag,
  91. }
  92. impl Drop for ManagedTexture {
  93. fn drop(&mut self) {
  94. self.render_api.delete_unmanaged_texture(self.id, self.epoch, self.tag);
  95. }
  96. }
  97. impl std::fmt::Debug for ManagedTexture {
  98. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  99. f.debug_struct("ManagedTexture").field("id", &self.id).finish()
  100. }
  101. }
  102. pub type ManagedBufferPtr = Arc<ManagedBuffer>;
  103. /// Auto-deletes buffer on drop
  104. #[derive(Clone)]
  105. pub struct ManagedBuffer {
  106. id: GfxBufferId,
  107. epoch: u32,
  108. render_api: RenderApi,
  109. tag: DebugTag,
  110. buftype: u8,
  111. }
  112. impl Drop for ManagedBuffer {
  113. fn drop(&mut self) {
  114. self.render_api.delete_unmanaged_buffer(self.id, self.epoch, self.tag, self.buftype);
  115. }
  116. }
  117. impl std::fmt::Debug for ManagedBuffer {
  118. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  119. f.debug_struct("ManagedBuffer").field("id", &self.id).finish()
  120. }
  121. }
  122. pub type EpochIndex = u32;
  123. #[derive(Clone)]
  124. pub struct RenderApi {
  125. /// We are abusing async_channel since it's cloneable whereas std::sync::mpsc is shit.
  126. method_req: async_channel::Sender<(EpochIndex, GraphicsMethod)>,
  127. /// Keep track of the current UI epoch
  128. epoch: Arc<AtomicU32>,
  129. }
  130. impl RenderApi {
  131. pub fn new(method_req: async_channel::Sender<(EpochIndex, GraphicsMethod)>) -> Self {
  132. Self { method_req, epoch: Arc::new(AtomicU32::new(0)) }
  133. }
  134. fn next_epoch(&self) -> EpochIndex {
  135. self.epoch.fetch_add(1, Ordering::SeqCst) + 1
  136. }
  137. fn send(&self, method: GraphicsMethod) -> EpochIndex {
  138. let epoch = self.epoch.load(Ordering::Relaxed);
  139. self.send_with_epoch(method, epoch);
  140. epoch
  141. }
  142. fn send_with_epoch(&self, method: GraphicsMethod, epoch: EpochIndex) {
  143. let _ = self.method_req.try_send((epoch, method)).unwrap();
  144. }
  145. fn new_unmanaged_texture(
  146. &self,
  147. width: u16,
  148. height: u16,
  149. data: Vec<u8>,
  150. ) -> (GfxTextureId, EpochIndex) {
  151. let gfx_texture_id = NEXT_TEXTURE_ID.fetch_add(1, Ordering::SeqCst);
  152. let method = GraphicsMethod::NewTexture((width, height, data, gfx_texture_id));
  153. let epoch = self.send(method);
  154. (gfx_texture_id, epoch)
  155. }
  156. pub fn new_texture(
  157. &self,
  158. width: u16,
  159. height: u16,
  160. data: Vec<u8>,
  161. tag: DebugTag,
  162. ) -> ManagedTexturePtr {
  163. let (id, epoch) = self.new_unmanaged_texture(width, height, data);
  164. Arc::new(ManagedTexture { id, epoch, render_api: self.clone(), tag })
  165. }
  166. fn delete_unmanaged_texture(&self, texture: GfxTextureId, epoch: EpochIndex, tag: DebugTag) {
  167. let method = GraphicsMethod::DeleteTexture((texture, tag));
  168. self.send_with_epoch(method, epoch);
  169. }
  170. fn new_unmanaged_vertex_buffer(&self, verts: Vec<Vertex>) -> (GfxBufferId, EpochIndex) {
  171. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::SeqCst);
  172. let method = GraphicsMethod::NewVertexBuffer((verts, gfx_buffer_id));
  173. let epoch = self.send(method);
  174. (gfx_buffer_id, epoch)
  175. }
  176. fn new_unmanaged_index_buffer(&self, indices: Vec<u16>) -> (GfxBufferId, EpochIndex) {
  177. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::SeqCst);
  178. let method = GraphicsMethod::NewIndexBuffer((indices, gfx_buffer_id));
  179. let epoch = self.send(method);
  180. (gfx_buffer_id, epoch)
  181. }
  182. pub fn new_vertex_buffer(&self, verts: Vec<Vertex>, tag: DebugTag) -> ManagedBufferPtr {
  183. let (id, epoch) = self.new_unmanaged_vertex_buffer(verts);
  184. Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 0 })
  185. }
  186. pub fn new_index_buffer(&self, indices: Vec<u16>, tag: DebugTag) -> ManagedBufferPtr {
  187. let (id, epoch) = self.new_unmanaged_index_buffer(indices);
  188. Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 1 })
  189. }
  190. fn delete_unmanaged_buffer(
  191. &self,
  192. buffer: GfxBufferId,
  193. epoch: EpochIndex,
  194. tag: DebugTag,
  195. buftype: u8,
  196. ) {
  197. let method = GraphicsMethod::DeleteBuffer((buffer, tag, buftype));
  198. self.send_with_epoch(method, epoch);
  199. }
  200. pub fn replace_draw_calls(&self, timest: u64, dcs: Vec<(u64, GfxDrawCall)>) {
  201. let method = GraphicsMethod::ReplaceDrawCalls { timest, dcs };
  202. self.send(method);
  203. }
  204. }
  205. #[derive(Clone, Debug)]
  206. pub struct GfxDrawMesh {
  207. pub vertex_buffer: ManagedBufferPtr,
  208. pub index_buffer: ManagedBufferPtr,
  209. pub texture: Option<ManagedTexturePtr>,
  210. pub num_elements: i32,
  211. }
  212. impl GfxDrawMesh {
  213. fn compile(
  214. self,
  215. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  216. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  217. debug_str: &'static str,
  218. ) -> Option<DrawMesh> {
  219. let vertex_buffer_id = self.vertex_buffer.id;
  220. let index_buffer_id = self.index_buffer.id;
  221. let _buffers_keep_alive = [self.vertex_buffer, self.index_buffer];
  222. let texture = match self.texture {
  223. Some(gfx_texture) => Self::try_get_texture(textures, gfx_texture, debug_str),
  224. None => None,
  225. };
  226. Some(DrawMesh {
  227. vertex_buffer: Self::try_get_buffer(buffers, vertex_buffer_id, debug_str)?,
  228. index_buffer: Self::try_get_buffer(buffers, index_buffer_id, debug_str)?,
  229. _buffers_keep_alive,
  230. texture,
  231. num_elements: self.num_elements,
  232. })
  233. }
  234. fn try_get_texture(
  235. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  236. gfx_texture: ManagedTexturePtr,
  237. debug_str: &'static str,
  238. ) -> Option<(ManagedTexturePtr, miniquad::TextureId)> {
  239. let gfx_texture_id = gfx_texture.id;
  240. let Some(_mq_texture_id) = textures.get(&gfx_texture_id) else {
  241. error!(target: "gfx", "Serious error: missing texture ID={gfx_texture_id}, debug={debug_str}");
  242. error!(target: "gfx", "Dumping textures:");
  243. for (gfx_texture_id, texture_id) in textures {
  244. error!(target: "gfx", "{gfx_texture_id} => {texture_id:?}");
  245. }
  246. panic!("Missing texture ID={gfx_texture_id}")
  247. };
  248. Some((gfx_texture, textures[&gfx_texture_id]))
  249. }
  250. fn try_get_buffer(
  251. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  252. gfx_buffer_id: GfxBufferId,
  253. debug_str: &'static str,
  254. ) -> Option<miniquad::BufferId> {
  255. let Some(mq_buffer_id) = buffers.get(&gfx_buffer_id) else {
  256. error!(target: "gfx", "Serious error: missing buffer ID={gfx_buffer_id}, debug={debug_str}");
  257. error!(target: "gfx", "Dumping buffers:");
  258. for (gfx_buffer_id, buffer_id) in buffers {
  259. error!(target: "gfx", "{gfx_buffer_id} => {buffer_id:?}");
  260. }
  261. panic!("Missing buffer ID={gfx_buffer_id}")
  262. };
  263. Some(*mq_buffer_id)
  264. }
  265. }
  266. #[derive(Debug, Clone)]
  267. pub enum GfxDrawInstruction {
  268. SetScale(f32),
  269. Move(Point),
  270. SetPos(Point),
  271. ApplyView(Rectangle),
  272. Draw(GfxDrawMesh),
  273. EnableDebug,
  274. }
  275. impl GfxDrawInstruction {
  276. fn compile(
  277. self,
  278. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  279. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  280. debug_str: &'static str,
  281. ) -> Option<DrawInstruction> {
  282. let instr = match self {
  283. Self::SetScale(scale) => DrawInstruction::SetScale(scale),
  284. Self::Move(off) => DrawInstruction::Move(off),
  285. Self::SetPos(pos) => DrawInstruction::SetPos(pos),
  286. Self::ApplyView(view) => DrawInstruction::ApplyView(view),
  287. Self::Draw(mesh) => DrawInstruction::Draw(mesh.compile(textures, buffers, debug_str)?),
  288. Self::EnableDebug => DrawInstruction::EnableDebug,
  289. };
  290. Some(instr)
  291. }
  292. }
  293. #[derive(Clone, Debug, Default)]
  294. pub struct GfxDrawCall {
  295. pub instrs: Vec<GfxDrawInstruction>,
  296. pub dcs: Vec<u64>,
  297. pub z_index: u32,
  298. pub debug_str: &'static str,
  299. }
  300. impl GfxDrawCall {
  301. pub fn new(
  302. instrs: Vec<GfxDrawInstruction>,
  303. dcs: Vec<u64>,
  304. z_index: u32,
  305. debug_str: &'static str,
  306. ) -> Self {
  307. Self { instrs, dcs, z_index, debug_str }
  308. }
  309. }
  310. impl GfxDrawCall {
  311. fn compile(
  312. self,
  313. textures: &HashMap<GfxTextureId, miniquad::TextureId>,
  314. buffers: &HashMap<GfxBufferId, miniquad::BufferId>,
  315. timest: u64,
  316. ) -> Option<DrawCall> {
  317. Some(DrawCall {
  318. instrs: self
  319. .instrs
  320. .into_iter()
  321. .map(|i| i.compile(textures, buffers, self.debug_str))
  322. .collect::<Option<Vec<_>>>()?,
  323. dcs: self.dcs,
  324. z_index: self.z_index,
  325. timest,
  326. })
  327. }
  328. }
  329. #[derive(Clone, Debug)]
  330. struct DrawMesh {
  331. vertex_buffer: miniquad::BufferId,
  332. index_buffer: miniquad::BufferId,
  333. /// Keeps the buffers alive for the duration of this draw call
  334. _buffers_keep_alive: [ManagedBufferPtr; 2],
  335. texture: Option<(ManagedTexturePtr, miniquad::TextureId)>,
  336. num_elements: i32,
  337. }
  338. #[derive(Debug, Clone)]
  339. enum DrawInstruction {
  340. SetScale(f32),
  341. Move(Point),
  342. SetPos(Point),
  343. ApplyView(Rectangle),
  344. Draw(DrawMesh),
  345. EnableDebug,
  346. }
  347. #[derive(Debug)]
  348. struct DrawCall {
  349. instrs: Vec<DrawInstruction>,
  350. dcs: Vec<u64>,
  351. z_index: u32,
  352. timest: u64,
  353. }
  354. struct RenderContext<'a> {
  355. ctx: &'a mut Box<dyn RenderingBackend>,
  356. draw_calls: &'a HashMap<u64, DrawCall>,
  357. uniforms_data: [u8; 128],
  358. white_texture: miniquad::TextureId,
  359. scale: f32,
  360. view: Rectangle,
  361. cursor: Point,
  362. }
  363. impl<'a> RenderContext<'a> {
  364. fn draw(&mut self) {
  365. if DEBUG_RENDER {
  366. debug!(target: "gfx", "RenderContext::draw()");
  367. }
  368. self.draw_call(&self.draw_calls[&0], 0, DEBUG_RENDER);
  369. if DEBUG_RENDER {
  370. debug!(target: "gfx", "RenderContext::draw() [DONE]");
  371. }
  372. }
  373. fn apply_view(&mut self) {
  374. // Actual physical view
  375. let view = self.view * self.scale;
  376. let (_, screen_height) = window::screen_size();
  377. let view_x = view.x.round() as i32;
  378. let view_y = screen_height - (view.y + view.h);
  379. let view_y = view_y.round() as i32;
  380. let view_w = view.w.round() as i32;
  381. let view_h = view.h.round() as i32;
  382. // OpenGL does not like negative values here
  383. if view_w <= 0 || view_h <= 0 {
  384. return
  385. }
  386. if DEBUG_RENDER {
  387. debug!(target: "gfx", "=> viewport {view_x} {view_y} {view_w} {view_h}");
  388. }
  389. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  390. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  391. }
  392. fn apply_model(&mut self) {
  393. let off_x = self.cursor.x / self.view.w;
  394. let off_y = self.cursor.y / self.view.h;
  395. let scale_w = 1. / self.view.w;
  396. let scale_h = 1. / self.view.h;
  397. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  398. glam::Mat4::from_scale(glam::Vec3::new(scale_w, scale_h, 1.));
  399. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  400. self.uniforms_data[64..].copy_from_slice(&data);
  401. self.ctx.apply_uniforms_from_bytes(self.uniforms_data.as_ptr(), self.uniforms_data.len());
  402. }
  403. fn draw_call(&mut self, draw_call: &DrawCall, mut indent: u32, mut is_debug: bool) {
  404. let ws = if is_debug { " ".repeat(indent as usize * 4) } else { String::new() };
  405. let old_scale = self.scale;
  406. let old_view = self.view;
  407. let old_cursor = self.cursor;
  408. for instr in &draw_call.instrs {
  409. match instr {
  410. DrawInstruction::SetScale(scale) => {
  411. self.scale = *scale;
  412. self.view.w /= self.scale;
  413. self.view.h /= self.scale;
  414. if is_debug {
  415. debug!(target: "gfx", "{ws}set_scale({scale})");
  416. }
  417. }
  418. DrawInstruction::Move(off) => {
  419. self.cursor += *off;
  420. if is_debug {
  421. debug!(target: "gfx",
  422. "{ws}move({off:?}) cursor={:?}, scale={}, view={:?}",
  423. self.cursor, self.scale, self.view
  424. );
  425. }
  426. self.apply_model();
  427. }
  428. DrawInstruction::SetPos(pos) => {
  429. self.cursor = old_cursor + *pos;
  430. if is_debug {
  431. debug!(target: "gfx",
  432. "{ws}set_pos({pos:?}) cursor={:?}, scale={}, view={:?}",
  433. self.cursor, self.scale, self.view
  434. );
  435. }
  436. self.apply_model();
  437. }
  438. DrawInstruction::ApplyView(view) => {
  439. // Adjust view relative to cursor
  440. self.view = *view + self.cursor;
  441. // We could just skip drawing when clipping rect isn't visible
  442. // using an is_visible flag.
  443. match self.view.clip(&old_view) {
  444. Some(clipped) => self.view = clipped,
  445. None => self.view = Rectangle::zero(),
  446. }
  447. // Cursor resets within the view
  448. self.cursor = Point::zero();
  449. if is_debug {
  450. debug!(target: "gfx",
  451. "{ws}apply_view({view:?}) scale={}, view={:?}",
  452. self.scale, self.view
  453. );
  454. }
  455. self.apply_view();
  456. self.apply_model();
  457. }
  458. DrawInstruction::Draw(mesh) => {
  459. if is_debug {
  460. debug!(target: "gfx", "{ws}draw({mesh:?})");
  461. }
  462. let texture = match mesh.texture {
  463. Some((_, texture)) => texture,
  464. None => self.white_texture,
  465. };
  466. let bindings = Bindings {
  467. vertex_buffers: vec![mesh.vertex_buffer],
  468. index_buffer: mesh.index_buffer,
  469. images: vec![texture],
  470. };
  471. self.ctx.apply_bindings(&bindings);
  472. self.ctx.draw(0, mesh.num_elements, 1);
  473. }
  474. DrawInstruction::EnableDebug => {
  475. if !is_debug {
  476. indent = 0;
  477. }
  478. is_debug = true;
  479. debug!(target: "gfx", "Frame start");
  480. }
  481. }
  482. }
  483. let mut draw_calls: Vec<_> =
  484. draw_call.dcs.iter().map(|key| (key, &self.draw_calls[key])).collect();
  485. draw_calls.sort_unstable_by_key(|(_, dc)| dc.z_index);
  486. for (dc_key, dc) in draw_calls {
  487. if is_debug {
  488. debug!(target: "gfx", "{ws}drawcall {dc_key}");
  489. }
  490. self.draw_call(dc, indent + 1, is_debug);
  491. }
  492. self.scale = old_scale;
  493. if is_debug {
  494. debug!(target: "gfx", "{ws}Frame close: cursor={old_cursor:?}, view={old_view:?}");
  495. }
  496. self.view = old_view;
  497. self.apply_view();
  498. self.cursor = old_cursor;
  499. self.apply_model();
  500. }
  501. }
  502. #[derive(Clone)]
  503. pub enum GraphicsMethod {
  504. NewTexture((u16, u16, Vec<u8>, GfxTextureId)),
  505. DeleteTexture((GfxTextureId, DebugTag)),
  506. NewVertexBuffer((Vec<Vertex>, GfxBufferId)),
  507. NewIndexBuffer((Vec<u16>, GfxBufferId)),
  508. DeleteBuffer((GfxBufferId, DebugTag, u8)),
  509. ReplaceDrawCalls { timest: u64, dcs: Vec<(u64, GfxDrawCall)> },
  510. }
  511. impl std::fmt::Debug for GraphicsMethod {
  512. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  513. match self {
  514. Self::NewTexture(_) => write!(f, "NewTexture"),
  515. Self::DeleteTexture(_) => write!(f, "DeleteTexture"),
  516. Self::NewVertexBuffer(_) => write!(f, "NewVertexBuffer"),
  517. Self::NewIndexBuffer(_) => write!(f, "NewIndexBuffer"),
  518. Self::DeleteBuffer(_) => write!(f, "DeleteBuffer"),
  519. Self::ReplaceDrawCalls { timest: _, dcs: _ } => write!(f, "ReplaceDrawCalls"),
  520. }
  521. }
  522. }
  523. struct EventChannel<T> {
  524. sender: async_channel::Sender<T>,
  525. recvr: async_channel::Receiver<T>,
  526. }
  527. impl<T> EventChannel<T> {
  528. fn new() -> Self {
  529. let (sender, recvr) = async_channel::unbounded();
  530. Self { sender, recvr }
  531. }
  532. fn notify(&self, ev: T) {
  533. self.sender.try_send(ev).unwrap();
  534. }
  535. fn clone_recvr(&self) -> async_channel::Receiver<T> {
  536. self.recvr.clone()
  537. }
  538. }
  539. pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
  540. pub struct GraphicsEventPublisher {
  541. resize: EventChannel<Dimension>,
  542. key_down: EventChannel<(KeyCode, KeyMods, bool)>,
  543. key_up: EventChannel<(KeyCode, KeyMods)>,
  544. chr: EventChannel<(char, KeyMods, bool)>,
  545. mouse_btn_down: EventChannel<(MouseButton, Point)>,
  546. mouse_btn_up: EventChannel<(MouseButton, Point)>,
  547. mouse_move: EventChannel<Point>,
  548. mouse_wheel: EventChannel<Point>,
  549. touch: EventChannel<(TouchPhase, u64, Point)>,
  550. }
  551. pub type GraphicsEventResizeSub = async_channel::Receiver<Dimension>;
  552. pub type GraphicsEventKeyDownSub = async_channel::Receiver<(KeyCode, KeyMods, bool)>;
  553. pub type GraphicsEventKeyUpSub = async_channel::Receiver<(KeyCode, KeyMods)>;
  554. pub type GraphicsEventCharSub = async_channel::Receiver<(char, KeyMods, bool)>;
  555. pub type GraphicsEventMouseButtonDownSub = async_channel::Receiver<(MouseButton, Point)>;
  556. pub type GraphicsEventMouseButtonUpSub = async_channel::Receiver<(MouseButton, Point)>;
  557. pub type GraphicsEventMouseMoveSub = async_channel::Receiver<Point>;
  558. pub type GraphicsEventMouseWheelSub = async_channel::Receiver<Point>;
  559. pub type GraphicsEventTouchSub = async_channel::Receiver<(TouchPhase, u64, Point)>;
  560. impl GraphicsEventPublisher {
  561. pub fn new() -> Arc<Self> {
  562. Arc::new(Self {
  563. resize: EventChannel::new(),
  564. key_down: EventChannel::new(),
  565. key_up: EventChannel::new(),
  566. chr: EventChannel::new(),
  567. mouse_btn_down: EventChannel::new(),
  568. mouse_btn_up: EventChannel::new(),
  569. mouse_move: EventChannel::new(),
  570. mouse_wheel: EventChannel::new(),
  571. touch: EventChannel::new(),
  572. })
  573. }
  574. fn notify_resize(&self, screen_size: Dimension) {
  575. self.resize.notify(screen_size);
  576. }
  577. fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
  578. let ev = (key, mods, repeat);
  579. self.key_down.notify(ev);
  580. }
  581. fn notify_key_up(&self, key: KeyCode, mods: KeyMods) {
  582. let ev = (key, mods);
  583. self.key_up.notify(ev);
  584. }
  585. fn notify_char(&self, chr: char, mods: KeyMods, repeat: bool) {
  586. let ev = (chr, mods, repeat);
  587. self.chr.notify(ev);
  588. }
  589. fn notify_mouse_btn_down(&self, button: MouseButton, mouse_pos: Point) {
  590. let ev = (button, mouse_pos);
  591. self.mouse_btn_down.notify(ev);
  592. }
  593. fn notify_mouse_btn_up(&self, button: MouseButton, mouse_pos: Point) {
  594. let ev = (button, mouse_pos);
  595. self.mouse_btn_up.notify(ev);
  596. }
  597. fn notify_mouse_move(&self, mouse_pos: Point) {
  598. self.mouse_move.notify(mouse_pos);
  599. }
  600. fn notify_mouse_wheel(&self, wheel_pos: Point) {
  601. self.mouse_wheel.notify(wheel_pos);
  602. }
  603. fn notify_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) {
  604. let ev = (phase, id, touch_pos);
  605. self.touch.notify(ev);
  606. }
  607. pub fn subscribe_resize(&self) -> GraphicsEventResizeSub {
  608. self.resize.clone_recvr()
  609. }
  610. pub fn subscribe_key_down(&self) -> GraphicsEventKeyDownSub {
  611. self.key_down.clone_recvr()
  612. }
  613. pub fn subscribe_key_up(&self) -> GraphicsEventKeyUpSub {
  614. self.key_up.clone_recvr()
  615. }
  616. pub fn subscribe_char(&self) -> GraphicsEventCharSub {
  617. self.chr.clone_recvr()
  618. }
  619. pub fn subscribe_mouse_btn_down(&self) -> GraphicsEventMouseButtonDownSub {
  620. self.mouse_btn_down.clone_recvr()
  621. }
  622. pub fn subscribe_mouse_btn_up(&self) -> GraphicsEventMouseButtonUpSub {
  623. self.mouse_btn_up.clone_recvr()
  624. }
  625. pub fn subscribe_mouse_move(&self) -> GraphicsEventMouseMoveSub {
  626. self.mouse_move.clone_recvr()
  627. }
  628. pub fn subscribe_mouse_wheel(&self) -> GraphicsEventMouseWheelSub {
  629. self.mouse_wheel.clone_recvr()
  630. }
  631. pub fn subscribe_touch(&self) -> GraphicsEventTouchSub {
  632. self.touch.clone_recvr()
  633. }
  634. }
  635. struct Stage {
  636. ctx: Box<dyn RenderingBackend>,
  637. pipeline: Pipeline,
  638. white_texture: miniquad::TextureId,
  639. draw_calls: HashMap<u64, DrawCall>,
  640. textures: HashMap<GfxTextureId, miniquad::TextureId>,
  641. buffers: HashMap<GfxBufferId, miniquad::BufferId>,
  642. epoch: EpochIndex,
  643. method_rep: async_channel::Receiver<(EpochIndex, GraphicsMethod)>,
  644. event_pub: GraphicsEventPublisherPtr,
  645. }
  646. impl Stage {
  647. pub fn new() -> Self {
  648. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  649. let god = GOD.get().unwrap();
  650. // Start a new epoch. This is a brand new UI run.
  651. let epoch = god.render_api.next_epoch();
  652. // This will start the app to start. Needed since we cannot get window size for init
  653. // until window is created.
  654. god.start_app(epoch);
  655. let method_rep = god.method_rep.clone();
  656. let event_pub = god.event_pub.clone();
  657. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  658. let mut shader_meta: ShaderMeta = shader::meta();
  659. shader_meta.uniforms.uniforms.push(UniformDesc::new("Projection", UniformType::Mat4));
  660. shader_meta.uniforms.uniforms.push(UniformDesc::new("Model", UniformType::Mat4));
  661. let shader = ctx
  662. .new_shader(
  663. match ctx.info().backend {
  664. Backend::OpenGl => ShaderSource::Glsl {
  665. vertex: shader::GL_VERTEX,
  666. fragment: shader::GL_FRAGMENT,
  667. },
  668. Backend::Metal => ShaderSource::Msl { program: shader::METAL },
  669. },
  670. shader_meta,
  671. )
  672. .unwrap();
  673. let params = PipelineParams {
  674. color_blend: Some(BlendState::new(
  675. Equation::Add,
  676. BlendFactor::Value(BlendValue::SourceAlpha),
  677. BlendFactor::OneMinusValue(BlendValue::SourceAlpha),
  678. )),
  679. ..Default::default()
  680. };
  681. let pipeline = ctx.new_pipeline(
  682. &[BufferLayout::default()],
  683. &[
  684. VertexAttribute::new("in_pos", VertexFormat::Float2),
  685. VertexAttribute::new("in_color", VertexFormat::Float4),
  686. VertexAttribute::new("in_uv", VertexFormat::Float2),
  687. ],
  688. shader,
  689. params,
  690. );
  691. Stage {
  692. ctx,
  693. pipeline,
  694. white_texture,
  695. draw_calls: HashMap::from([(
  696. 0,
  697. DrawCall { instrs: vec![], dcs: vec![], z_index: 0, timest: 0 },
  698. )]),
  699. textures: HashMap::new(),
  700. buffers: HashMap::new(),
  701. epoch,
  702. method_rep,
  703. event_pub,
  704. }
  705. }
  706. fn process_method(&mut self, mut method: GraphicsMethod) {
  707. //debug!(target: "gfx", "Received method: {:?}", method);
  708. let res = match &mut method {
  709. GraphicsMethod::NewTexture((width, height, data, gfx_texture_id)) => {
  710. self.method_new_texture(*width, *height, data, *gfx_texture_id)
  711. }
  712. GraphicsMethod::DeleteTexture((texture, _)) => self.method_delete_texture(*texture),
  713. GraphicsMethod::NewVertexBuffer((verts, gbuffid)) => {
  714. self.method_new_vertex_buffer(verts, *gbuffid)
  715. }
  716. GraphicsMethod::NewIndexBuffer((indices, gbuffid)) => {
  717. self.method_new_index_buffer(indices, *gbuffid)
  718. }
  719. GraphicsMethod::DeleteBuffer((buffer, _, _)) => self.method_delete_buffer(*buffer),
  720. GraphicsMethod::ReplaceDrawCalls { timest, dcs } => {
  721. let dcs = std::mem::take(dcs);
  722. self.method_replace_draw_calls(*timest, dcs)
  723. }
  724. };
  725. if let Err(err) = res {
  726. e!("process_method(method={method:?}) failed with err: {err:?}");
  727. panic!("process_method failed!")
  728. }
  729. }
  730. fn method_new_texture(
  731. &mut self,
  732. width: u16,
  733. height: u16,
  734. data: &Vec<u8>,
  735. gfx_texture_id: GfxTextureId,
  736. ) -> Result<()> {
  737. let texture = self.ctx.new_texture_from_rgba8(width, height, data);
  738. if DEBUG_GFXAPI {
  739. debug!(target: "gfx", "Invoked method: new_texture({}, {}, ..., {}) -> {:?}",
  740. width, height, gfx_texture_id, texture);
  741. //debug!(target: "gfx", "Invoked method: new_texture({}, {}, ..., {}) -> {:?}\n{}",
  742. // width, height, gfx_texture_id, texture,
  743. // ansi_texture(width as usize, height as usize, &data));
  744. }
  745. if let Some(_) = self.textures.insert(gfx_texture_id, texture) {
  746. //panic!("Duplicate texture ID={gfx_texture_id} detected!");
  747. return Err(Error::GfxDuplicateTextureID)
  748. }
  749. Ok(())
  750. }
  751. fn method_delete_texture(&mut self, gfx_texture_id: GfxTextureId) -> Result<()> {
  752. let Some(texture) = self.textures.remove(&gfx_texture_id) else {
  753. //.expect("couldn't find gfx_texture_id");
  754. return Err(Error::GfxUnknownTextureID)
  755. };
  756. if DEBUG_GFXAPI {
  757. debug!(target: "gfx", "Invoked method: delete_texture({} => {:?})",
  758. gfx_texture_id, texture);
  759. }
  760. self.ctx.delete_texture(texture);
  761. Ok(())
  762. }
  763. fn method_new_vertex_buffer(
  764. &mut self,
  765. verts: &[Vertex],
  766. gfx_buffer_id: GfxBufferId,
  767. ) -> Result<()> {
  768. let buffer = self.ctx.new_buffer(
  769. BufferType::VertexBuffer,
  770. BufferUsage::Immutable,
  771. BufferSource::slice(verts),
  772. );
  773. if DEBUG_GFXAPI {
  774. debug!(target: "gfx", "Invoked method: new_vertex_buffer(..., {}) -> {:?}",
  775. gfx_buffer_id, buffer);
  776. //debug!(target: "gfx", "Invoked method: new_vertex_buffer({:?}, {}) -> {:?}",
  777. // verts, gfx_buffer_id, buffer);
  778. }
  779. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  780. //panic!("Duplicate vertex buffer ID={gfx_buffer_id} detected!");
  781. return Err(Error::GfxDuplicateBufferID)
  782. }
  783. Ok(())
  784. }
  785. fn method_new_index_buffer(
  786. &mut self,
  787. indices: &[u16],
  788. gfx_buffer_id: GfxBufferId,
  789. ) -> Result<()> {
  790. let buffer = self.ctx.new_buffer(
  791. BufferType::IndexBuffer,
  792. BufferUsage::Immutable,
  793. BufferSource::slice(&indices),
  794. );
  795. if DEBUG_GFXAPI {
  796. debug!(target: "gfx", "Invoked method: new_index_buffer({}) -> {:?}",
  797. gfx_buffer_id, buffer);
  798. //debug!(target: "gfx", "Invoked method: new_index_buffer({:?}, {}) -> {:?}",
  799. // indices, gfx_buffer_id, buffer);
  800. }
  801. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  802. //panic!("Duplicate index buffer ID={gfx_buffer_id} detected!");
  803. return Err(Error::GfxDuplicateBufferID)
  804. }
  805. Ok(())
  806. }
  807. fn method_delete_buffer(&mut self, gfx_buffer_id: GfxBufferId) -> Result<()> {
  808. let Some(buffer) = self.buffers.remove(&gfx_buffer_id) else {
  809. //.expect("couldn't find gfx_buffer_id");
  810. return Err(Error::GfxUnknownBufferID)
  811. };
  812. if DEBUG_GFXAPI {
  813. debug!(target: "gfx", "Invoked method: delete_buffer({} => {:?})",
  814. gfx_buffer_id, buffer);
  815. }
  816. self.ctx.delete_buffer(buffer);
  817. Ok(())
  818. }
  819. fn method_replace_draw_calls(
  820. &mut self,
  821. timest: u64,
  822. dcs: Vec<(u64, GfxDrawCall)>,
  823. ) -> Result<()> {
  824. if DEBUG_GFXAPI {
  825. debug!(target: "gfx", "Invoked method: replace_draw_calls({:?})", dcs);
  826. }
  827. for (key, val) in dcs {
  828. let Some(val) = val.compile(&self.textures, &self.buffers, timest) else {
  829. error!(target: "gfx", "fatal: replace_draw_calls({timest}, ...) failed with item ID={key}");
  830. continue
  831. };
  832. //self.draw_calls.insert(key, val);
  833. match self.draw_calls.get_mut(&key) {
  834. Some(old_val) => {
  835. // Only replace the draw call if it is more recent
  836. if old_val.timest < timest {
  837. *old_val = val;
  838. } else {
  839. trace!(target: "gfx", "Rejected stale draw_call {key}: {val:?}");
  840. }
  841. }
  842. None => {
  843. self.draw_calls.insert(key, val);
  844. }
  845. }
  846. }
  847. Ok(())
  848. }
  849. }
  850. impl EventHandler for Stage {
  851. fn update(&mut self) {
  852. // Process as many methods as we can
  853. while let Ok((epoch, method)) = self.method_rep.try_recv() {
  854. if epoch < self.epoch {
  855. // Discard old rubbish
  856. trace!(target: "gfx", "Discard method with old epoch: {epoch} curr: {} [method={method:?}]", self.epoch);
  857. continue
  858. }
  859. assert_eq!(epoch, self.epoch);
  860. self.process_method(method);
  861. }
  862. }
  863. fn draw(&mut self) {
  864. self.ctx.begin_default_pass(PassAction::clear_color(0., 0., 0., 1.));
  865. self.ctx.apply_pipeline(&self.pipeline);
  866. // This will make the top left (0, 0) and the bottom right (1, 1)
  867. // Default is (-1, 1) -> (1, -1)
  868. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  869. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  870. let mut uniforms_data = [0u8; 128];
  871. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  872. uniforms_data[0..64].copy_from_slice(&data);
  873. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  874. //uniforms_data[64..].copy_from_slice(&data);
  875. assert_eq!(128, 2 * UniformType::Mat4.size());
  876. let (screen_w, screen_h) = miniquad::window::screen_size();
  877. let mut render_ctx = RenderContext {
  878. ctx: &mut self.ctx,
  879. draw_calls: &self.draw_calls,
  880. uniforms_data,
  881. white_texture: self.white_texture,
  882. scale: 1.,
  883. view: Rectangle::from([0., 0., screen_w, screen_h]),
  884. cursor: Point::from([0., 0.]),
  885. };
  886. render_ctx.draw();
  887. self.ctx.commit_frame();
  888. }
  889. fn resize_event(&mut self, width: f32, height: f32) {
  890. t!("resize_event({width}, {height})");
  891. let filename = get_window_size_filename();
  892. if let Some(parent) = filename.parent() {
  893. let _ = std::fs::create_dir_all(parent);
  894. }
  895. if let Ok(mut file) = File::create(filename) {
  896. (width as i32).encode(&mut file).unwrap();
  897. (height as i32).encode(&mut file).unwrap();
  898. }
  899. self.event_pub.notify_resize(Dimension::from([width, height]));
  900. }
  901. fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
  902. self.event_pub.notify_key_down(keycode, mods, repeat);
  903. }
  904. fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
  905. self.event_pub.notify_key_up(keycode, mods);
  906. }
  907. fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
  908. self.event_pub.notify_char(chr, mods, repeat);
  909. }
  910. fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
  911. let pos = Point::from([x, y]);
  912. self.event_pub.notify_mouse_btn_down(button, pos);
  913. }
  914. fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
  915. let pos = Point::from([x, y]);
  916. self.event_pub.notify_mouse_btn_up(button, pos);
  917. }
  918. fn mouse_motion_event(&mut self, x: f32, y: f32) {
  919. let pos = Point::from([x, y]);
  920. self.event_pub.notify_mouse_move(pos);
  921. }
  922. fn mouse_wheel_event(&mut self, x: f32, y: f32) {
  923. let pos = Point::from([x, y]);
  924. self.event_pub.notify_mouse_wheel(pos);
  925. }
  926. /// The id corresponds to multi-touch. Multiple touch events have different ids.
  927. fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  928. let pos = Point::from([x, y]);
  929. self.event_pub.notify_touch(phase, id, pos);
  930. }
  931. fn quit_requested_event(&mut self) {
  932. debug!(target: "gfx", "quit requested");
  933. let god = GOD.get().unwrap();
  934. god.stop_app();
  935. }
  936. }
  937. pub fn run_gui() {
  938. let mut window_width = 1024;
  939. let mut window_height = 768;
  940. if let Ok(mut file) = File::open(get_window_size_filename()) {
  941. window_width = Decodable::decode(&mut file).unwrap();
  942. window_height = Decodable::decode(&mut file).unwrap();
  943. }
  944. debug!(target: "gfx", "Window size {window_width} x {window_height}");
  945. let mut conf = miniquad::conf::Conf {
  946. window_title: "DarkFi".to_string(),
  947. window_width,
  948. window_height,
  949. high_dpi: true,
  950. window_resizable: true,
  951. platform: miniquad::conf::Platform {
  952. linux_backend: miniquad::conf::LinuxBackend::WaylandWithX11Fallback,
  953. //blocking_event_loop: true,
  954. android_panic_hook: false,
  955. ..Default::default()
  956. },
  957. icon: Some(miniquad::conf::Icon {
  958. small: favico::SMALL,
  959. medium: favico::MEDIUM,
  960. big: favico::BIG,
  961. }),
  962. ..Default::default()
  963. };
  964. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  965. conf.platform.apple_gfx_api =
  966. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  967. miniquad::start(conf, || Box::new(Stage::new()));
  968. }