mod.rs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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::{
  19. async_trait, AsyncEncodable, AsyncWrite, Decodable, Encodable, FutAsyncWriteExt,
  20. SerialDecodable, SerialEncodable, VarInt,
  21. };
  22. #[cfg(target_os = "android")]
  23. use miniquad::native::egl;
  24. use miniquad::{
  25. conf, window, Bindings, BufferSource, BufferType, BufferUsage, EventHandler, KeyCode, KeyMods,
  26. MouseButton, PassAction, Pipeline, RenderingBackend, TextureFormat, TextureKind, TextureParams,
  27. TextureWrap, TouchPhase, UniformType,
  28. };
  29. use std::{
  30. collections::{HashMap, HashSet},
  31. fs::File,
  32. io::Write,
  33. path::PathBuf,
  34. sync::{
  35. atomic::{AtomicU32, Ordering},
  36. Arc,
  37. },
  38. };
  39. pub mod anim;
  40. use anim::{Frame as AnimFrame, GfxSeqAnim};
  41. mod api;
  42. pub use api::{
  43. EpochIndex, GraphicsMethod, ManagedBuffer, ManagedBufferPtr, ManagedSeqAnim, ManagedSeqAnimPtr,
  44. ManagedTexture, ManagedTexturePtr, RenderApi, Renderer, RendererSync,
  45. };
  46. mod ev;
  47. pub use ev::{
  48. GraphicsEventCharSub, GraphicsEventKeyDownSub, GraphicsEventKeyUpSub,
  49. GraphicsEventMouseButtonDownSub, GraphicsEventMouseButtonUpSub, GraphicsEventMouseMoveSub,
  50. GraphicsEventMouseWheelSub, GraphicsEventPublisher, GraphicsEventPublisherPtr,
  51. GraphicsEventResizeSub, GraphicsEventTouchSub,
  52. };
  53. mod favico;
  54. mod prune;
  55. use prune::PruneMethodHeap;
  56. mod linalg;
  57. pub use linalg::{Dimension, Point, Rectangle, Segment, Vector};
  58. mod shader;
  59. mod trax;
  60. use trax::get_trax;
  61. use crate::{
  62. prop::{BatchGuardId, PropertyAtomicGuard},
  63. scene::{Pimpl, SceneNodePtr},
  64. util::unixtime,
  65. GOD,
  66. };
  67. // This is very noisy so suppress output by default
  68. const DEBUG_RENDER: bool = false;
  69. const DEBUG_GFXAPI: bool = false;
  70. const DEBUG_TRAX: bool = false;
  71. #[macro_export]
  72. macro_rules! gfxtag {
  73. ($s:expr) => {{
  74. Some($s)
  75. }};
  76. }
  77. pub use crate::gfxtag;
  78. pub type DebugTag = Option<&'static str>;
  79. macro_rules! d { ($($arg:tt)*) => { debug!(target: "gfx", $($arg)*); } }
  80. macro_rules! t { ($($arg:tt)*) => { trace!(target: "gfx", $($arg)*); } }
  81. #[cfg(target_os = "android")]
  82. pub fn get_window_size_filename() -> PathBuf {
  83. crate::android::get_appdata_path().join("window_size")
  84. }
  85. #[cfg(not(target_os = "android"))]
  86. pub fn get_window_size_filename() -> PathBuf {
  87. dirs::cache_dir().unwrap().join("darkfi/app/window_size")
  88. }
  89. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  90. #[repr(C)]
  91. pub struct Vertex {
  92. pub pos: [f32; 2],
  93. pub color: [f32; 4],
  94. pub uv: [f32; 2],
  95. }
  96. impl Vertex {
  97. pub fn pos(&self) -> Point {
  98. self.pos.into()
  99. }
  100. pub fn set_pos(&mut self, pos: &Point) {
  101. self.pos = pos.as_arr();
  102. }
  103. }
  104. pub type TextureId = u32;
  105. pub type BufferId = u32;
  106. pub type AnimId = u32;
  107. #[derive(Clone, Debug)]
  108. pub struct DrawMesh {
  109. pub vertex_buffer: ManagedBufferPtr,
  110. pub index_buffer: ManagedBufferPtr,
  111. pub textures: Option<Vec<ManagedTexturePtr>>,
  112. pub num_elements: i32,
  113. }
  114. impl DrawMesh {
  115. fn compile(
  116. self,
  117. textures: &HashMap<TextureId, miniquad::TextureId>,
  118. buffers: &HashMap<BufferId, miniquad::BufferId>,
  119. debug_str: &'static str,
  120. ) -> GfxDrawMesh {
  121. let vertex_buffer_id = self.vertex_buffer.id;
  122. let index_buffer_id = self.index_buffer.id;
  123. let _buffers_keep_alive = [self.vertex_buffer, self.index_buffer];
  124. let textures = match self.textures {
  125. Some(gfx_textures) => {
  126. let mut compiled = Vec::with_capacity(gfx_textures.len());
  127. for gfx_texture in gfx_textures {
  128. compiled.push(Self::get_texture(textures, gfx_texture, debug_str));
  129. }
  130. Some(compiled)
  131. }
  132. None => None,
  133. };
  134. GfxDrawMesh {
  135. vertex_buffer: Self::get_buffer(buffers, vertex_buffer_id, debug_str),
  136. index_buffer: Self::get_buffer(buffers, index_buffer_id, debug_str),
  137. _buffers_keep_alive,
  138. textures,
  139. num_elements: self.num_elements,
  140. }
  141. }
  142. fn get_texture(
  143. textures: &HashMap<TextureId, miniquad::TextureId>,
  144. gfx_texture: ManagedTexturePtr,
  145. debug_str: &'static str,
  146. ) -> (ManagedTexturePtr, miniquad::TextureId) {
  147. let gfx_texture_id = gfx_texture.id;
  148. let Some(_mq_texture_id) = textures.get(&gfx_texture_id) else {
  149. panic!("Missing texture ID={gfx_texture_id} debug={debug_str}")
  150. };
  151. (gfx_texture, textures[&gfx_texture_id])
  152. }
  153. fn get_buffer(
  154. buffers: &HashMap<BufferId, miniquad::BufferId>,
  155. gfx_buffer_id: BufferId,
  156. debug_str: &'static str,
  157. ) -> miniquad::BufferId {
  158. let Some(mq_buffer_id) = buffers.get(&gfx_buffer_id) else {
  159. panic!("Missing buffer ID={gfx_buffer_id} debug={debug_str}")
  160. };
  161. *mq_buffer_id
  162. }
  163. }
  164. impl Encodable for DrawMesh {
  165. fn encode<S: Write>(&self, s: &mut S) -> std::result::Result<usize, std::io::Error> {
  166. let mut len = 0;
  167. len += self.vertex_buffer.id.encode(s)?;
  168. len += self.vertex_buffer.epoch.encode(s)?;
  169. len += self.vertex_buffer.tag.encode(s)?;
  170. len += self.vertex_buffer.buftype.encode(s)?;
  171. len += self.index_buffer.id.encode(s)?;
  172. len += self.index_buffer.epoch.encode(s)?;
  173. len += self.index_buffer.tag.encode(s)?;
  174. len += self.index_buffer.buftype.encode(s)?;
  175. match &self.textures {
  176. Some(texs) => {
  177. len += 1u8.encode(s)?;
  178. len += VarInt(texs.len() as u64).encode(s)?;
  179. for t in texs {
  180. len += t.id.encode(s)?;
  181. len += t.epoch.encode(s)?;
  182. len += t.tag.encode(s)?;
  183. }
  184. }
  185. None => {
  186. len += 0u8.encode(s)?;
  187. }
  188. }
  189. len += self.num_elements.encode(s)?;
  190. Ok(len)
  191. }
  192. }
  193. #[derive(Clone, Copy, Debug, SerialEncodable)]
  194. pub enum GraphicPipeline {
  195. RGB,
  196. YUV,
  197. }
  198. #[async_trait]
  199. impl AsyncEncodable for DrawMesh {
  200. async fn encode_async<W: AsyncWrite + Unpin + Send>(
  201. &self,
  202. _: &mut W,
  203. ) -> std::io::Result<usize> {
  204. Ok(0)
  205. }
  206. }
  207. #[derive(Debug, Clone)]
  208. pub enum DrawInstruction {
  209. SetScale(f32),
  210. Move(Point),
  211. SetPos(Point),
  212. ApplyView(Rectangle),
  213. Draw(DrawMesh),
  214. Animation(ManagedSeqAnimPtr),
  215. EnableDebug,
  216. SetPipeline(GraphicPipeline),
  217. Overlay(Vec<DrawInstruction>),
  218. }
  219. impl DrawInstruction {
  220. fn compile(
  221. self,
  222. textures: &HashMap<TextureId, miniquad::TextureId>,
  223. buffers: &HashMap<BufferId, miniquad::BufferId>,
  224. debug_str: &'static str,
  225. ) -> GfxDrawInstruction {
  226. match self {
  227. Self::SetScale(scale) => GfxDrawInstruction::SetScale(scale),
  228. Self::Move(off) => GfxDrawInstruction::Move(off),
  229. Self::SetPos(pos) => GfxDrawInstruction::SetPos(pos),
  230. Self::ApplyView(view) => GfxDrawInstruction::ApplyView(view),
  231. Self::Draw(mesh) => {
  232. GfxDrawInstruction::Draw(mesh.compile(textures, buffers, debug_str))
  233. }
  234. Self::Animation(anim) => GfxDrawInstruction::Animation(anim),
  235. Self::EnableDebug => GfxDrawInstruction::EnableDebug,
  236. Self::SetPipeline(pipeline) => GfxDrawInstruction::SetPipeline(pipeline),
  237. Self::Overlay(instrs) => {
  238. let compiled =
  239. instrs.into_iter().map(|i| i.compile(textures, buffers, debug_str)).collect();
  240. GfxDrawInstruction::Overlay(compiled)
  241. }
  242. }
  243. }
  244. }
  245. #[derive(Clone, Debug, Default)]
  246. pub struct DrawCall {
  247. pub instrs: Vec<DrawInstruction>,
  248. pub dcs: Vec<DcId>,
  249. pub z_index: u32,
  250. pub debug_str: &'static str,
  251. }
  252. impl DrawCall {
  253. pub fn new(
  254. instrs: Vec<DrawInstruction>,
  255. dcs: Vec<DcId>,
  256. z_index: u32,
  257. debug_str: &'static str,
  258. ) -> Self {
  259. Self { instrs, dcs, z_index, debug_str }
  260. }
  261. fn compile(
  262. self,
  263. textures: &HashMap<TextureId, miniquad::TextureId>,
  264. buffers: &HashMap<BufferId, miniquad::BufferId>,
  265. timest: Timestamp,
  266. ) -> GfxDrawCall {
  267. GfxDrawCall {
  268. instrs: self
  269. .instrs
  270. .into_iter()
  271. .map(|i| i.compile(textures, buffers, self.debug_str))
  272. .collect(),
  273. dcs: self.dcs,
  274. z_index: self.z_index,
  275. timest,
  276. }
  277. }
  278. }
  279. #[derive(Clone, Debug)]
  280. struct GfxDrawMesh {
  281. vertex_buffer: miniquad::BufferId,
  282. index_buffer: miniquad::BufferId,
  283. /// Keeps the buffers alive for the duration of this draw call
  284. _buffers_keep_alive: [ManagedBufferPtr; 2],
  285. textures: Option<Vec<(ManagedTexturePtr, miniquad::TextureId)>>,
  286. num_elements: i32,
  287. }
  288. #[derive(Debug, Clone)]
  289. enum GfxDrawInstruction {
  290. SetScale(f32),
  291. Move(Point),
  292. SetPos(Point),
  293. ApplyView(Rectangle),
  294. Draw(GfxDrawMesh),
  295. Animation(ManagedSeqAnimPtr),
  296. EnableDebug,
  297. SetPipeline(GraphicPipeline),
  298. Overlay(Vec<GfxDrawInstruction>),
  299. }
  300. #[derive(Clone, Debug)]
  301. struct GfxDrawCall {
  302. instrs: Vec<GfxDrawInstruction>,
  303. dcs: Vec<DcId>,
  304. z_index: u32,
  305. timest: Timestamp,
  306. }
  307. struct OverlayDefer {
  308. scale: f32,
  309. pos: Point,
  310. instrs: Vec<GfxDrawInstruction>,
  311. }
  312. struct RenderContext<'a> {
  313. ctx: &'a mut Box<dyn RenderingBackend>,
  314. draw_calls: &'a HashMap<DcId, GfxDrawCall>,
  315. uniforms_data: [u8; 128],
  316. white_texture: miniquad::TextureId,
  317. loaded_pipelines: &'a [Pipeline; 2],
  318. scale: f32,
  319. view: Rectangle,
  320. cursor: Point,
  321. gfx_pipeline: GraphicPipeline,
  322. anims: &'a mut HashMap<AnimId, GfxSeqAnim>,
  323. overlays: Vec<OverlayDefer>,
  324. }
  325. impl<'a> RenderContext<'a> {
  326. fn draw(&mut self) {
  327. if DEBUG_RENDER {
  328. let screen_size = miniquad::window::screen_size();
  329. d!("RenderContext::draw() [screen_size={screen_size:?}]");
  330. }
  331. if DEBUG_TRAX {
  332. get_trax().lock().set_curr(0);
  333. }
  334. self.draw_call(&self.draw_calls[&0], 0, DEBUG_RENDER);
  335. if DEBUG_RENDER {
  336. d!("RenderContext::draw() [DONE]");
  337. }
  338. // View should be reset now so draw overlays
  339. self.draw_overlays();
  340. }
  341. fn draw_overlays(&mut self) {
  342. let (screen_w, screen_h) = miniquad::window::screen_size();
  343. let overlays = std::mem::take(&mut self.overlays);
  344. for overlay in overlays {
  345. self.view = Rectangle::new(0., 0., screen_w, screen_h);
  346. self.scale = overlay.scale;
  347. self.view.w /= self.scale;
  348. self.view.h /= self.scale;
  349. self.apply_view();
  350. self.cursor = overlay.pos;
  351. self.apply_model();
  352. for instr in overlay.instrs {
  353. match instr {
  354. GfxDrawInstruction::Move(off) => {
  355. self.cursor += off;
  356. self.apply_model();
  357. }
  358. GfxDrawInstruction::Draw(mesh) => {
  359. if DEBUG_RENDER {
  360. d!(" draw_overlay({mesh:?})");
  361. }
  362. let images = match &mesh.textures {
  363. Some(texs) => texs.iter().map(|(_, tex_id)| *tex_id).collect(),
  364. None => vec![self.white_texture],
  365. };
  366. let bindings = Bindings {
  367. vertex_buffers: vec![mesh.vertex_buffer],
  368. index_buffer: mesh.index_buffer,
  369. images,
  370. };
  371. self.ctx.apply_bindings(&bindings);
  372. self.ctx.draw(0, mesh.num_elements, 1);
  373. }
  374. _ => unimplemented!(),
  375. }
  376. }
  377. }
  378. }
  379. fn apply_view(&mut self) {
  380. // Actual physical view
  381. let view = self.view * self.scale;
  382. let (_, screen_height) = window::screen_size();
  383. let view_x = view.x.round() as i32;
  384. let view_y = screen_height - (view.y + view.h);
  385. let view_y = view_y.round() as i32;
  386. let view_w = view.w.round() as i32;
  387. let view_h = view.h.round() as i32;
  388. // OpenGL does not like negative values here
  389. if view_w <= 0 || view_h <= 0 {
  390. return
  391. }
  392. if DEBUG_RENDER {
  393. d!("=> viewport {view_x} {view_y} {view_w} {view_h}");
  394. }
  395. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  396. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  397. }
  398. fn apply_model(&mut self) {
  399. let off_x = self.cursor.x / self.view.w;
  400. let off_y = self.cursor.y / self.view.h;
  401. let scale_w = 1. / self.view.w;
  402. let scale_h = 1. / self.view.h;
  403. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  404. glam::Mat4::from_scale(glam::Vec3::new(scale_w, scale_h, 1.));
  405. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  406. self.uniforms_data[64..].copy_from_slice(&data);
  407. self.ctx.apply_uniforms_from_bytes(self.uniforms_data.as_ptr(), self.uniforms_data.len());
  408. }
  409. fn draw_call(&mut self, draw_call: &GfxDrawCall, mut indent: u32, mut is_debug: bool) {
  410. let ws = if is_debug { " ".repeat(indent as usize * 4) } else { String::new() };
  411. let old_scale = self.scale;
  412. let old_view = self.view;
  413. let old_cursor = self.cursor;
  414. let old_pipeline = self.gfx_pipeline;
  415. for (idx, instr) in draw_call.instrs.iter().enumerate() {
  416. if DEBUG_TRAX {
  417. get_trax().lock().set_instr(idx);
  418. }
  419. match instr {
  420. GfxDrawInstruction::SetScale(scale) => {
  421. self.scale = *scale;
  422. self.view.w /= self.scale;
  423. self.view.h /= self.scale;
  424. if is_debug {
  425. d!("{ws}set_scale({scale})");
  426. }
  427. }
  428. GfxDrawInstruction::Move(off) => {
  429. self.cursor += *off;
  430. if is_debug {
  431. d!(
  432. "{ws}move({off:?}) cursor={:?}, scale={}, view={:?}",
  433. self.cursor,
  434. self.scale,
  435. self.view
  436. );
  437. }
  438. self.apply_model();
  439. }
  440. GfxDrawInstruction::SetPos(pos) => {
  441. self.cursor = old_cursor + *pos;
  442. if is_debug {
  443. d!(
  444. "{ws}set_pos({pos:?}) cursor={:?}, scale={}, view={:?}",
  445. self.cursor,
  446. self.scale,
  447. self.view
  448. );
  449. }
  450. self.apply_model();
  451. }
  452. GfxDrawInstruction::ApplyView(view) => {
  453. // Adjust view relative to cursor
  454. self.view = *view + self.cursor + old_view.pos();
  455. // We could just skip drawing when clipping rect isn't visible
  456. // using an is_visible flag.
  457. match self.view.clip(&old_view) {
  458. Some(clipped) => self.view = clipped,
  459. None => self.view = Rectangle::zero(),
  460. }
  461. // Cursor resets within the view
  462. self.cursor = Point::zero();
  463. if is_debug {
  464. d!("{ws}apply_view({view:?}) scale={}, view={:?}", self.scale, self.view);
  465. }
  466. self.apply_view();
  467. self.apply_model();
  468. }
  469. GfxDrawInstruction::Draw(mesh) => {
  470. if is_debug {
  471. d!("{ws}draw({mesh:?})");
  472. }
  473. let images = match &mesh.textures {
  474. Some(texs) => texs.iter().map(|(_, tex_id)| *tex_id).collect(),
  475. None => vec![self.white_texture],
  476. };
  477. let bindings = Bindings {
  478. vertex_buffers: vec![mesh.vertex_buffer],
  479. index_buffer: mesh.index_buffer,
  480. images,
  481. };
  482. self.ctx.apply_bindings(&bindings);
  483. self.ctx.draw(0, mesh.num_elements, 1);
  484. }
  485. GfxDrawInstruction::Animation(anim) => {
  486. let gfx_anim = self.anims.get_mut(&anim.id).unwrap();
  487. gfx_anim.is_visible = true;
  488. if let Some(dc) = gfx_anim.tick() {
  489. self.draw_call(&dc, indent + 1, is_debug);
  490. }
  491. }
  492. GfxDrawInstruction::EnableDebug => {
  493. if !is_debug {
  494. indent = 0;
  495. }
  496. is_debug = true;
  497. d!("Frame start");
  498. }
  499. GfxDrawInstruction::SetPipeline(pipeline) => {
  500. self.gfx_pipeline = *pipeline;
  501. let pipeline_idx = *pipeline as usize;
  502. assert!(pipeline_idx < self.loaded_pipelines.len());
  503. self.ctx.apply_pipeline(&self.loaded_pipelines[pipeline_idx]);
  504. if is_debug {
  505. d!("{ws}set_pipeline({pipeline:?})");
  506. }
  507. }
  508. GfxDrawInstruction::Overlay(instrs) => {
  509. let pos = self.view.pos() / self.scale + self.cursor;
  510. self.overlays.push(OverlayDefer {
  511. scale: self.scale,
  512. pos,
  513. instrs: instrs.clone(),
  514. });
  515. }
  516. }
  517. }
  518. let mut draw_calls: Vec<_> =
  519. draw_call.dcs.iter().map(|key| (key, &self.draw_calls[key])).collect();
  520. draw_calls.sort_unstable_by_key(|(_, dc)| dc.z_index);
  521. for (dc_key, dc) in draw_calls {
  522. if DEBUG_TRAX {
  523. get_trax().lock().set_curr(*dc_key);
  524. }
  525. if is_debug {
  526. d!("{ws}drawcall {dc_key}");
  527. }
  528. self.draw_call(dc, indent + 1, is_debug);
  529. }
  530. self.scale = old_scale;
  531. if is_debug {
  532. d!("{ws}Frame close: cursor={old_cursor:?}, view={old_view:?}");
  533. }
  534. self.view = old_view;
  535. self.apply_view();
  536. self.cursor = old_cursor;
  537. self.gfx_pipeline = old_pipeline;
  538. let pipeline_idx = self.gfx_pipeline as usize;
  539. assert!(pipeline_idx < self.loaded_pipelines.len());
  540. self.ctx.apply_pipeline(&self.loaded_pipelines[pipeline_idx]);
  541. self.apply_model();
  542. }
  543. }
  544. type Timestamp = u64;
  545. type DcId = u64;
  546. struct Stage {
  547. ctx: Box<dyn RenderingBackend>,
  548. #[cfg(target_os = "android")]
  549. libegl: egl::LibEgl,
  550. loaded_pipelines: [Pipeline; 2],
  551. white_texture: miniquad::TextureId,
  552. draw_calls: HashMap<DcId, GfxDrawCall>,
  553. pending_batches: HashMap<BatchGuardId, Vec<GraphicsMethod>>,
  554. /// When dropping batches, we add to this set so that we keep track
  555. /// of the internal state's correctness.
  556. dropped_batches: Box<HashSet<BatchGuardId>>,
  557. textures: Box<HashMap<TextureId, miniquad::TextureId>>,
  558. buffers: Box<HashMap<BufferId, miniquad::BufferId>>,
  559. anims: Box<HashMap<AnimId, GfxSeqAnim>>,
  560. epoch: EpochIndex,
  561. method_recv: async_channel::Receiver<(EpochIndex, GraphicsMethod)>,
  562. event_pub: GraphicsEventPublisherPtr,
  563. renderer: Renderer,
  564. pruner: PruneMethodHeap,
  565. screen_state: ScreenState,
  566. /// Cached window node, looked up lazily on first touch event
  567. window_node: Option<SceneNodePtr>,
  568. }
  569. impl Stage {
  570. pub fn new() -> Self {
  571. if DEBUG_TRAX {
  572. get_trax().lock().clear();
  573. }
  574. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  575. let god = GOD.get().unwrap();
  576. // Start a new epoch. This is a brand new UI run.
  577. let renderer = god.renderer.clone();
  578. let epoch = renderer.next_epoch();
  579. // This will start the app to start. Needed since we cannot get window size for init
  580. // until window is created.
  581. god.start_app(epoch);
  582. let method_recv = god.method_recv.clone();
  583. let event_pub = god.event_pub.clone();
  584. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  585. let anims: HashMap<AnimId, GfxSeqAnim> = HashMap::new();
  586. let rgb_pipeline = shader::create_rgb_pipeline(&mut ctx);
  587. let yuv_pipeline = shader::create_yuv_pipeline(&mut ctx);
  588. #[cfg(target_os = "android")]
  589. let libegl = egl::LibEgl::try_load().expect("Cant load LibEGL");
  590. let mut self_ = Stage {
  591. ctx,
  592. #[cfg(target_os = "android")]
  593. libegl,
  594. loaded_pipelines: [rgb_pipeline, yuv_pipeline],
  595. white_texture,
  596. draw_calls: HashMap::from([(
  597. 0,
  598. GfxDrawCall { instrs: vec![], dcs: vec![], z_index: 0, timest: 0 },
  599. )]),
  600. pending_batches: HashMap::new(),
  601. dropped_batches: Box::new(HashSet::new()),
  602. textures: Box::new(HashMap::new()),
  603. buffers: Box::new(HashMap::new()),
  604. anims: Box::new(anims),
  605. epoch,
  606. method_recv,
  607. event_pub,
  608. renderer,
  609. pruner: PruneMethodHeap::new(epoch),
  610. screen_state: ScreenState::On,
  611. window_node: None,
  612. };
  613. self_.pruner.textures = &*self_.textures as *const _;
  614. self_.pruner.buffers = &*self_.buffers as *const _;
  615. self_.pruner.anims = &*self_.anims as *const _;
  616. self_.pruner.dropped_batches = &mut *self_.dropped_batches as *mut _;
  617. self_
  618. }
  619. fn process_method(&mut self, mut method: GraphicsMethod) {
  620. //d!("Received method: {method:?}");
  621. match &mut method {
  622. GraphicsMethod::NewTexture((width, height, data, fmt, gtex_id, _)) => {
  623. self.method_new_texture(*width, *height, data, *fmt, *gtex_id)
  624. }
  625. GraphicsMethod::DeleteTexture((gtex_id, _)) => self.method_delete_texture(*gtex_id),
  626. GraphicsMethod::NewVertexBuffer((verts, gbuff_id, _)) => {
  627. self.method_new_vertex_buffer(verts, *gbuff_id)
  628. }
  629. GraphicsMethod::NewIndexBuffer((indices, gbuff_id, _)) => {
  630. self.method_new_index_buffer(indices, *gbuff_id)
  631. }
  632. GraphicsMethod::DeleteBuffer((gbuff_id, _, _)) => self.method_delete_buffer(*gbuff_id),
  633. GraphicsMethod::NewSeqAnim { id, frames_len, oneshot, tag: _ } => {
  634. self.method_new_anim(*id, *frames_len, *oneshot)
  635. }
  636. GraphicsMethod::UpdateSeqAnim { id, frame_idx, frame, tag: _ } => {
  637. self.method_update_anim(*id, *frame_idx, frame.clone())
  638. }
  639. GraphicsMethod::DeleteSeqAnim((ganim_id, _)) => self.method_delete_anim(*ganim_id),
  640. GraphicsMethod::ReplaceGfxDrawCalls { batch_id, ref mut dcs } => {
  641. match batch_id {
  642. Some(bid) => {
  643. //let debug_strs: Vec<_> = dcs.iter().map(|(_, dc)| dc.debug_str).collect();
  644. //t!("Commit dc to {bid}: {debug_strs:?}");
  645. if self.dropped_batches.contains(&bid) {
  646. t!("Discarding ReplaceGfxDrawCalls from dropped {bid}");
  647. return
  648. }
  649. let Some(batch) = self.pending_batches.get_mut(&bid) else {
  650. panic!("unknown batch {bid}")
  651. };
  652. let method = std::mem::take(&mut method);
  653. batch.push(method);
  654. }
  655. None => {
  656. // Process immediately without batching
  657. let timest = unixtime();
  658. let dcs = std::mem::take(dcs);
  659. self.method_replace_draw_calls(timest, dcs);
  660. }
  661. }
  662. if DEBUG_TRAX {
  663. get_trax().lock().put_stat(0);
  664. }
  665. }
  666. GraphicsMethod::StartBatch { batch_id, tag } => {
  667. if DEBUG_GFXAPI {
  668. t!("Start batch {batch_id}: {tag:?}");
  669. }
  670. if !self.pending_batches.insert(*batch_id, vec![]).is_none() {
  671. panic!("batch {batch_id} already open!")
  672. }
  673. if DEBUG_TRAX {
  674. get_trax().lock().put_stat(0);
  675. }
  676. }
  677. GraphicsMethod::EndBatch { batch_id, timest } => {
  678. if self.dropped_batches.remove(batch_id) {
  679. if DEBUG_GFXAPI {
  680. t!("End batch {batch_id} was dropped");
  681. }
  682. return
  683. }
  684. if DEBUG_GFXAPI {
  685. t!("End batch {batch_id}");
  686. }
  687. let Some(batch) = self.pending_batches.remove(batch_id) else {
  688. panic!("unknown batch {batch_id}")
  689. };
  690. for mut method in batch {
  691. match &mut method {
  692. GraphicsMethod::ReplaceGfxDrawCalls { batch_id: _, dcs } => {
  693. let dcs = std::mem::take(dcs);
  694. self.method_replace_draw_calls(*timest, dcs)
  695. }
  696. _ => panic!("unexpected method in batch!"),
  697. }
  698. }
  699. }
  700. GraphicsMethod::Noop => panic!("noop"),
  701. }
  702. }
  703. pub(self) fn method_new_texture(
  704. &mut self,
  705. width: u16,
  706. height: u16,
  707. data: &Vec<u8>,
  708. format: TextureFormat,
  709. gfx_texture_id: TextureId,
  710. ) {
  711. let fmt_size = format.size(width as u32, height as u32) as usize;
  712. assert_eq!(
  713. fmt_size,
  714. data.len(),
  715. "Texture data size mismatch for ID={gfx_texture_id}: \
  716. expected {fmt_size}, got {} for {width}x{height} {:?}",
  717. data.len(),
  718. format
  719. );
  720. let texture = self.ctx.new_texture_from_data_and_format(
  721. data,
  722. TextureParams {
  723. kind: TextureKind::Texture2D,
  724. format,
  725. width: width as _,
  726. height: height as _,
  727. wrap: TextureWrap::Clamp,
  728. min_filter: miniquad::FilterMode::Linear,
  729. mag_filter: miniquad::FilterMode::Linear,
  730. mipmap_filter: miniquad::MipmapFilterMode::None,
  731. allocate_mipmaps: false,
  732. sample_count: 1,
  733. },
  734. );
  735. if DEBUG_GFXAPI {
  736. d!("Invoked method: new_texture({width}, {height}, ..., {gfx_texture_id}) -> {texture:?}");
  737. //d!("Invoked method: new_texture({}, {}, ..., {}) -> {:?}\n{}",
  738. // width, height, gfx_texture_id, texture,
  739. // ansi_texture(width as usize, height as usize, &data));
  740. }
  741. if let Some(_) = self.textures.insert(gfx_texture_id, texture) {
  742. if DEBUG_TRAX {
  743. get_trax().lock().put_stat(2);
  744. }
  745. panic!("Duplicate texture ID={gfx_texture_id} detected!");
  746. }
  747. if DEBUG_TRAX {
  748. get_trax().lock().put_stat(0);
  749. }
  750. }
  751. pub(self) fn method_delete_texture(&mut self, gfx_texture_id: TextureId) {
  752. let Some(texture) = self.textures.remove(&gfx_texture_id) else {
  753. if DEBUG_TRAX {
  754. get_trax().lock().put_stat(2);
  755. }
  756. panic!("unknown texture {gfx_texture_id}")
  757. };
  758. if DEBUG_GFXAPI {
  759. d!("Invoked method: delete_texture({gfx_texture_id} => {texture:?})");
  760. }
  761. self.ctx.delete_texture(texture);
  762. if DEBUG_TRAX {
  763. get_trax().lock().put_stat(0);
  764. }
  765. }
  766. pub(self) fn method_new_vertex_buffer(&mut self, verts: &[Vertex], gfx_buffer_id: BufferId) {
  767. let buffer = self.ctx.new_buffer(
  768. BufferType::VertexBuffer,
  769. BufferUsage::Immutable,
  770. BufferSource::slice(verts),
  771. );
  772. if DEBUG_GFXAPI {
  773. d!("Invoked method: new_vertex_buffer(..., {gfx_buffer_id}) -> {buffer:?}");
  774. //debug!(target: "gfx", "Invoked method: new_vertex_buffer({:?}, {}) -> {:?}",
  775. // verts, gfx_buffer_id, buffer);
  776. }
  777. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  778. if DEBUG_TRAX {
  779. get_trax().lock().put_stat(2);
  780. }
  781. panic!("Duplicate vertex buffer ID={gfx_buffer_id} detected!")
  782. }
  783. if DEBUG_TRAX {
  784. get_trax().lock().put_stat(0);
  785. }
  786. }
  787. pub(self) fn method_new_index_buffer(&mut self, indices: &[u16], gfx_buffer_id: BufferId) {
  788. let buffer = self.ctx.new_buffer(
  789. BufferType::IndexBuffer,
  790. BufferUsage::Immutable,
  791. BufferSource::slice(&indices),
  792. );
  793. if DEBUG_GFXAPI {
  794. d!("Invoked method: new_index_buffer({gfx_buffer_id}) -> {buffer:?}");
  795. //debug!(target: "gfx", "Invoked method: new_index_buffer({:?}, {}) -> {:?}",
  796. // indices, gfx_buffer_id, buffer);
  797. }
  798. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  799. if DEBUG_TRAX {
  800. get_trax().lock().put_stat(2);
  801. }
  802. panic!("Duplicate index buffer ID={gfx_buffer_id} detected!")
  803. }
  804. if DEBUG_TRAX {
  805. get_trax().lock().put_stat(0);
  806. }
  807. }
  808. pub(self) fn method_delete_buffer(&mut self, gfx_buffer_id: BufferId) {
  809. let Some(buffer) = self.buffers.remove(&gfx_buffer_id) else {
  810. if DEBUG_TRAX {
  811. get_trax().lock().put_stat(2);
  812. }
  813. panic!("unknown buffer {gfx_buffer_id}");
  814. };
  815. if DEBUG_GFXAPI {
  816. d!("Invoked method: delete_buffer({gfx_buffer_id} => {buffer:?})");
  817. }
  818. self.ctx.delete_buffer(buffer);
  819. if DEBUG_TRAX {
  820. get_trax().lock().put_stat(0);
  821. }
  822. }
  823. pub(self) fn method_new_anim(&mut self, gfx_anim_id: AnimId, frames_len: usize, oneshot: bool) {
  824. if DEBUG_GFXAPI {
  825. d!("Invoked method: new_anim({gfx_anim_id}, {frames_len}, {oneshot})");
  826. }
  827. if let Some(_) = self.anims.insert(gfx_anim_id, GfxSeqAnim::new(frames_len, oneshot)) {
  828. panic!("Duplicate anim ID={gfx_anim_id} detected!");
  829. }
  830. }
  831. pub(self) fn method_update_anim(
  832. &mut self,
  833. gfx_anim_id: AnimId,
  834. frame_idx: usize,
  835. frame: AnimFrame,
  836. ) {
  837. let Some(anim) = self.anims.get_mut(&gfx_anim_id) else {
  838. panic!("couldn't find anim {gfx_anim_id}");
  839. };
  840. if DEBUG_GFXAPI {
  841. d!("Invoked method: update_anim({gfx_anim_id}[{frame_idx}] => {frame:?})");
  842. }
  843. anim.set(frame_idx, frame, &self.textures, &self.buffers);
  844. }
  845. pub(self) fn method_delete_anim(&mut self, gfx_anim_id: AnimId) {
  846. let Some(anim) = self.anims.remove(&gfx_anim_id) else {
  847. panic!("couldn't find anim {gfx_anim_id}");
  848. };
  849. if DEBUG_GFXAPI {
  850. d!("Invoked method: delete_anim({} => {:?})", gfx_anim_id, anim);
  851. }
  852. }
  853. fn method_replace_draw_calls(&mut self, batch_timest: Timestamp, dcs: Vec<(DcId, DrawCall)>) {
  854. if DEBUG_GFXAPI {
  855. d!("Invoked method: replace_draw_calls({:?})", dcs);
  856. }
  857. // Phase 1: Check for conflicts with newer batches
  858. // If any draw call in this batch belongs to an older batch than the existing one,
  859. // reject the entire batch to maintain atomicity
  860. for (key, _) in &dcs {
  861. if let Some(old_val) = self.draw_calls.get(key) {
  862. if old_val.timest > batch_timest {
  863. // Entire batch is stale, reject all
  864. t!("Rejected stale batch {batch_timest}: conflict with newer batch {} on {key}", old_val.timest);
  865. if DEBUG_TRAX {
  866. get_trax().lock().put_stat(3); // New stat: rejected batch
  867. }
  868. return;
  869. }
  870. }
  871. }
  872. // Phase 2: Apply entire batch atomically
  873. self.apply_draw_calls(batch_timest, dcs)
  874. }
  875. pub(self) fn apply_draw_calls(&mut self, batch_timest: Timestamp, dcs: Vec<(DcId, DrawCall)>) {
  876. for (key, val) in dcs {
  877. let val = val.compile(&self.textures, &self.buffers, batch_timest);
  878. // Insert/replace draw call
  879. self.draw_calls.insert(key, val);
  880. if DEBUG_TRAX {
  881. get_trax().lock().put_stat(1); // Success
  882. }
  883. }
  884. }
  885. fn trax_method(&self, epoch: EpochIndex, method: &GraphicsMethod) {
  886. let mut trax = get_trax().lock();
  887. match method {
  888. GraphicsMethod::NewTexture((_, _, _, _, gtex_id, tag)) => {
  889. trax.put_tex(epoch, *gtex_id, *tag);
  890. }
  891. GraphicsMethod::DeleteTexture((gtex_id, tag)) => {
  892. trax.del_tex(epoch, *gtex_id, *tag);
  893. }
  894. GraphicsMethod::NewVertexBuffer((verts, gbuff_id, tag)) => {
  895. trax.put_verts(epoch, verts.clone(), *gbuff_id, *tag, 0);
  896. }
  897. GraphicsMethod::NewIndexBuffer((idxs, gbuff_id, tag)) => {
  898. trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  899. }
  900. GraphicsMethod::DeleteBuffer((gbuff_id, tag, buftype)) => {
  901. trax.del_buf(epoch, *gbuff_id, *tag, *buftype);
  902. }
  903. GraphicsMethod::NewSeqAnim { .. } => {
  904. //trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  905. }
  906. GraphicsMethod::UpdateSeqAnim { .. } => {
  907. //trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  908. }
  909. GraphicsMethod::DeleteSeqAnim(..) => {
  910. //trax.del_buf(epoch, *gbuff_id, *tag, *buftype);
  911. }
  912. GraphicsMethod::ReplaceGfxDrawCalls { batch_id, dcs } => {
  913. if let Some(bid) = batch_id {
  914. trax.put_dcs(epoch, *bid, dcs);
  915. }
  916. }
  917. GraphicsMethod::StartBatch { batch_id, tag } => {
  918. trax.put_start_batch(epoch, *batch_id, *tag);
  919. }
  920. GraphicsMethod::EndBatch { batch_id, timest: _ } => {
  921. trax.put_end_batch(epoch, *batch_id);
  922. }
  923. GraphicsMethod::Noop => panic!("noop"),
  924. };
  925. }
  926. fn egl_ctx_is_disabled(&self) -> bool {
  927. #[cfg(target_os = "android")]
  928. {
  929. let egl_ctx = unsafe { (self.libegl.eglGetCurrentContext)() };
  930. egl_ctx.is_null()
  931. }
  932. #[cfg(not(target_os = "android"))]
  933. false
  934. }
  935. #[instrument(skip_all, target = "gfx::process")]
  936. fn process_methods(&mut self) {
  937. // Process as many methods as we can
  938. while let Ok((epoch, method)) = self.method_recv.try_recv() {
  939. if DEBUG_TRAX {
  940. self.trax_method(epoch, &method);
  941. }
  942. if epoch < self.epoch {
  943. if DEBUG_TRAX {
  944. let mut trax = get_trax().lock();
  945. trax.put_stat(1);
  946. trax.flush();
  947. }
  948. // Discard old rubbish
  949. t!(
  950. "Discard method with old epoch: {epoch} curr: {} [method={method:?}]",
  951. self.epoch
  952. );
  953. continue
  954. }
  955. assert_eq!(epoch, self.epoch);
  956. self.process_method(method);
  957. if DEBUG_TRAX {
  958. get_trax().lock().flush();
  959. }
  960. }
  961. }
  962. #[instrument(skip_all, target = "gfx::pruner")]
  963. fn prime_screen(&mut self) {
  964. let methods = self.pruner.recv_all();
  965. assert!(self.pending_batches.is_empty());
  966. // Process all cached methods by the pruner from while the screen was off.
  967. for method in methods {
  968. // Stale methods will be dropped by pruner, so they will not be caught by trax
  969. // while the screen is off.
  970. if DEBUG_TRAX {
  971. self.trax_method(self.epoch, &method);
  972. }
  973. // We discard batches here but process_method uses them so implement this
  974. // workaround.
  975. match method {
  976. GraphicsMethod::NewTexture(_) |
  977. GraphicsMethod::DeleteTexture(_) |
  978. GraphicsMethod::NewVertexBuffer(_) |
  979. GraphicsMethod::NewIndexBuffer(_) |
  980. GraphicsMethod::DeleteBuffer(_) |
  981. GraphicsMethod::NewSeqAnim { .. } |
  982. GraphicsMethod::UpdateSeqAnim { .. } |
  983. GraphicsMethod::DeleteSeqAnim(_) => self.process_method(method),
  984. GraphicsMethod::ReplaceGfxDrawCalls { .. } |
  985. GraphicsMethod::StartBatch { .. } |
  986. GraphicsMethod::EndBatch { .. } => {
  987. panic!("unsupported pruned methods should be dropped!")
  988. }
  989. GraphicsMethod::Noop => panic!("noop"),
  990. }
  991. if DEBUG_TRAX {
  992. get_trax().lock().flush();
  993. }
  994. }
  995. // Trigger a full screen redraw by sending a resize event
  996. let (width, height) = miniquad::window::screen_size();
  997. self.event_pub.notify_resize(Dimension::from([width, height]));
  998. }
  999. fn close_pending_batches(&mut self) {
  1000. // Immediately apply any pending batches when the screen is switched off
  1001. let batch_ids: Vec<_> = self.pending_batches.keys().cloned().collect();
  1002. if !batch_ids.is_empty() {
  1003. t!("Force closing pending batches: {batch_ids:?}");
  1004. }
  1005. for batch_id in batch_ids {
  1006. self.process_method(GraphicsMethod::EndBatch { batch_id, timest: unixtime() });
  1007. if !self.dropped_batches.insert(batch_id) {
  1008. panic!("dropped batch {batch_id} already exits!");
  1009. }
  1010. }
  1011. assert!(self.pending_batches.is_empty());
  1012. }
  1013. }
  1014. #[derive(Copy, Clone, Debug, PartialEq)]
  1015. enum ScreenState {
  1016. // Screen is on as normal
  1017. On,
  1018. // First update since screen has gone off
  1019. SwitchOff,
  1020. // Subsequent updates after SwitchOff state
  1021. Off,
  1022. // First update when screen is on but before draw has been called
  1023. ReadyOn,
  1024. // First update and draw has been called
  1025. PrimedOn,
  1026. // Second update ready to process pruned buffered allocs
  1027. SwitchOn,
  1028. }
  1029. impl ScreenState {
  1030. fn update(&mut self, egl_is_disabled: bool) {
  1031. use ScreenState::*;
  1032. *self = if egl_is_disabled {
  1033. match self {
  1034. On | ReadyOn | PrimedOn | SwitchOn => SwitchOff,
  1035. SwitchOff => Off,
  1036. Off => Off,
  1037. }
  1038. } else {
  1039. match self {
  1040. SwitchOff | Off => ReadyOn,
  1041. ReadyOn => PrimedOn,
  1042. PrimedOn => SwitchOn,
  1043. SwitchOn => On,
  1044. On => On,
  1045. }
  1046. };
  1047. }
  1048. }
  1049. impl EventHandler for Stage {
  1050. fn update(&mut self) {
  1051. // todo: trax is all messed up in this func
  1052. let old_screen_state = self.screen_state;
  1053. self.screen_state.update(self.egl_ctx_is_disabled());
  1054. if self.screen_state != old_screen_state {
  1055. d!("Switching screen state {old_screen_state:?} => {:?}", self.screen_state);
  1056. }
  1057. match self.screen_state {
  1058. ScreenState::SwitchOff => {
  1059. self.close_pending_batches();
  1060. // Screen is off so collect all methods into the pruner
  1061. self.pruner.drain(&self.method_recv);
  1062. }
  1063. ScreenState::Off => {
  1064. assert!(self.pending_batches.is_empty());
  1065. // Screen is off so collect all methods into the pruner
  1066. self.pruner.drain(&self.method_recv);
  1067. }
  1068. ScreenState::ReadyOn => {
  1069. // We actually want to skip draining the prune queue the first time so
  1070. // miniquad draw() actually gets a chance to be called first.
  1071. // Otherwise we will see a black screen for a sec or so while update() is running.
  1072. }
  1073. ScreenState::PrimedOn => {
  1074. self.prime_screen();
  1075. }
  1076. ScreenState::SwitchOn => {
  1077. // This should have been cleared in previous PrimedOn state
  1078. let methods = self.pruner.recv_all();
  1079. assert!(methods.is_empty());
  1080. self.process_methods();
  1081. }
  1082. ScreenState::On => {
  1083. self.process_methods();
  1084. }
  1085. }
  1086. }
  1087. fn draw(&mut self) {
  1088. self.ctx.begin_default_pass(PassAction::clear_color(0., 0., 0., 1.));
  1089. // Apply default RGB pipeline
  1090. self.ctx.apply_pipeline(&self.loaded_pipelines[GraphicPipeline::RGB as usize]);
  1091. // This will make the top left (0, 0) and the bottom right (1, 1)
  1092. // Default is (-1, 1) -> (1, -1)
  1093. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  1094. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  1095. let mut uniforms_data = [0u8; 128];
  1096. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  1097. uniforms_data[0..64].copy_from_slice(&data);
  1098. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  1099. //uniforms_data[64..].copy_from_slice(&data);
  1100. assert_eq!(128, 2 * UniformType::Mat4.size());
  1101. let (screen_w, screen_h) = miniquad::window::screen_size();
  1102. // Mark all anims as invisible
  1103. for (_, anim) in self.anims.iter_mut() {
  1104. anim.is_visible = false;
  1105. }
  1106. let mut render_ctx = RenderContext {
  1107. ctx: &mut self.ctx,
  1108. draw_calls: &self.draw_calls,
  1109. uniforms_data,
  1110. white_texture: self.white_texture,
  1111. loaded_pipelines: &self.loaded_pipelines,
  1112. scale: 1.,
  1113. view: Rectangle::from([0., 0., screen_w, screen_h]),
  1114. cursor: Point::zero(),
  1115. gfx_pipeline: GraphicPipeline::RGB,
  1116. anims: &mut self.anims,
  1117. overlays: vec![],
  1118. };
  1119. render_ctx.draw();
  1120. self.ctx.end_render_pass();
  1121. self.ctx.commit_frame();
  1122. }
  1123. fn resize_event(&mut self, width: f32, height: f32) {
  1124. t!("resize_event({width}, {height})");
  1125. let filename = get_window_size_filename();
  1126. if let Some(parent) = filename.parent() {
  1127. let _ = std::fs::create_dir_all(parent);
  1128. }
  1129. if let Ok(mut file) = File::create(filename) {
  1130. (width as i32).encode(&mut file).unwrap();
  1131. (height as i32).encode(&mut file).unwrap();
  1132. }
  1133. self.event_pub.notify_resize(Dimension::from([width, height]));
  1134. }
  1135. fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
  1136. self.event_pub.notify_key_down(keycode, mods, repeat);
  1137. }
  1138. fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
  1139. self.event_pub.notify_key_up(keycode, mods);
  1140. }
  1141. fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
  1142. self.event_pub.notify_char(chr, mods, repeat);
  1143. }
  1144. fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
  1145. let pos = Point::from([x, y]);
  1146. self.event_pub.notify_mouse_btn_down(button, pos);
  1147. }
  1148. fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
  1149. let pos = Point::from([x, y]);
  1150. self.event_pub.notify_mouse_btn_up(button, pos);
  1151. }
  1152. fn mouse_motion_event(&mut self, x: f32, y: f32) {
  1153. let pos = Point::from([x, y]);
  1154. self.event_pub.notify_mouse_move(pos);
  1155. }
  1156. fn mouse_wheel_event(&mut self, x: f32, y: f32) {
  1157. let pos = Point::from([x, y]);
  1158. self.event_pub.notify_mouse_wheel(pos);
  1159. }
  1160. /// The id corresponds to multi-touch. Multiple touch events have different ids.
  1161. fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  1162. let pos = Point::from([x, y]);
  1163. // Lazy cache window on first touch event
  1164. if self.window_node.is_none() {
  1165. let god = GOD.get().unwrap();
  1166. self.window_node = god.app.sg_root.lookup_node("/window");
  1167. }
  1168. // Clone window_node to avoid borrow conflict with RenderApiSync
  1169. let window_node = self.window_node.clone();
  1170. // Create RenderApiSync for direct graphics operations
  1171. let renderer_sync = RendererSync::new(self);
  1172. // Direct call to Window's handle_touch_event_sync
  1173. if let Some(window_node) = &window_node {
  1174. match window_node.pimpl() {
  1175. Pimpl::Window(win) => {
  1176. if win.handle_touch_sync(&renderer_sync, phase, id, pos) {
  1177. return
  1178. }
  1179. }
  1180. _ => panic!(),
  1181. }
  1182. }
  1183. drop(renderer_sync);
  1184. self.event_pub.notify_touch(phase, id, pos);
  1185. }
  1186. fn quit_requested_event(&mut self) {
  1187. debug!(target: "gfx", "quit requested");
  1188. let god = GOD.get().unwrap();
  1189. god.stop_app();
  1190. }
  1191. }
  1192. pub fn run_gui(linux_backend: miniquad::conf::LinuxBackend) {
  1193. let mut window_width = 1024;
  1194. let mut window_height = 768;
  1195. if let Ok(mut file) = File::open(get_window_size_filename()) {
  1196. window_width = Decodable::decode(&mut file).unwrap();
  1197. window_height = Decodable::decode(&mut file).unwrap();
  1198. }
  1199. debug!(target: "gfx", "Window size {window_width} x {window_height}");
  1200. let mut conf = miniquad::conf::Conf {
  1201. window_title: "DarkFi".to_string(),
  1202. window_width,
  1203. window_height,
  1204. high_dpi: true,
  1205. window_resizable: true,
  1206. platform: miniquad::conf::Platform {
  1207. linux_backend,
  1208. #[cfg(target_os = "android")]
  1209. blocking_event_loop: true,
  1210. #[cfg(target_os = "android")]
  1211. sleep_interval_ms: Some(40),
  1212. android_panic_hook: false,
  1213. ..Default::default()
  1214. },
  1215. icon: Some(miniquad::conf::Icon {
  1216. small: favico::SMALL,
  1217. medium: favico::MEDIUM,
  1218. big: favico::BIG,
  1219. }),
  1220. ..Default::default()
  1221. };
  1222. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  1223. conf.platform.apple_gfx_api =
  1224. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  1225. miniquad::start(conf, || Box::new(Stage::new()));
  1226. }