mod.rs 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900
  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::{
  19. async_trait, AsyncEncodable, AsyncWrite, Decodable, Encodable, FutAsyncWriteExt,
  20. SerialDecodable, SerialEncodable,
  21. };
  22. #[cfg(target_os = "android")]
  23. use miniquad::native::egl;
  24. use miniquad::{
  25. conf, window, Backend, Bindings, BlendFactor, BlendState, BlendValue, BufferLayout,
  26. BufferSource, BufferType, BufferUsage, Equation, EventHandler, KeyCode, KeyMods, MouseButton,
  27. PassAction, Pipeline, PipelineParams, RenderingBackend, ShaderMeta, ShaderSource, TouchPhase,
  28. UniformDesc, UniformType, VertexAttribute, VertexFormat,
  29. };
  30. use parking_lot::Mutex as SyncMutex;
  31. use std::{
  32. collections::{HashMap, HashSet},
  33. fs::File,
  34. io::Write,
  35. path::PathBuf,
  36. sync::{
  37. atomic::{AtomicU32, Ordering},
  38. Arc,
  39. },
  40. };
  41. pub mod anim;
  42. use anim::{Frame as AnimFrame, GfxSeqAnim};
  43. mod favico;
  44. mod linalg;
  45. pub use linalg::{Dimension, Point, Rectangle};
  46. mod shader;
  47. mod trax;
  48. use trax::get_trax;
  49. #[cfg(target_os = "android")]
  50. use crate::ExecutorPtr;
  51. use crate::{
  52. prop::{BatchGuardId, PropertyAtomicGuard},
  53. util::unixtime,
  54. GOD,
  55. };
  56. // This is very noisy so suppress output by default
  57. const DEBUG_RENDER: bool = false;
  58. const DEBUG_GFXAPI: bool = false;
  59. const DEBUG_TRAX: bool = false;
  60. #[macro_export]
  61. macro_rules! gfxtag {
  62. ($s:expr) => {{
  63. Some($s)
  64. }};
  65. }
  66. pub use crate::gfxtag;
  67. pub type DebugTag = Option<&'static str>;
  68. macro_rules! d { ($($arg:tt)*) => { debug!(target: "gfx", $($arg)*); } }
  69. macro_rules! t { ($($arg:tt)*) => { trace!(target: "gfx", $($arg)*); } }
  70. #[cfg(target_os = "android")]
  71. pub fn get_window_size_filename() -> PathBuf {
  72. crate::android::get_appdata_path().join("window_size")
  73. }
  74. #[cfg(not(target_os = "android"))]
  75. pub fn get_window_size_filename() -> PathBuf {
  76. dirs::cache_dir().unwrap().join("darkfi/app/window_size")
  77. }
  78. #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
  79. #[repr(C)]
  80. pub struct Vertex {
  81. pub pos: [f32; 2],
  82. pub color: [f32; 4],
  83. pub uv: [f32; 2],
  84. }
  85. impl Vertex {
  86. pub fn pos(&self) -> Point {
  87. self.pos.into()
  88. }
  89. pub fn set_pos(&mut self, pos: &Point) {
  90. self.pos = pos.as_arr();
  91. }
  92. }
  93. pub type TextureId = u32;
  94. pub type BufferId = u32;
  95. pub type AnimId = u32;
  96. static NEXT_BUFFER_ID: AtomicU32 = AtomicU32::new(0);
  97. static NEXT_TEXTURE_ID: AtomicU32 = AtomicU32::new(0);
  98. static NEXT_ANIM_ID: AtomicU32 = AtomicU32::new(0);
  99. pub type ManagedTexturePtr = Arc<ManagedTexture>;
  100. /// Auto-deletes texture on drop
  101. pub struct ManagedTexture {
  102. id: TextureId,
  103. epoch: u32,
  104. render_api: RenderApi,
  105. tag: DebugTag,
  106. }
  107. impl Drop for ManagedTexture {
  108. fn drop(&mut self) {
  109. self.render_api.delete_unmanaged_texture(self.id, self.epoch, self.tag);
  110. }
  111. }
  112. impl std::fmt::Debug for ManagedTexture {
  113. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  114. f.debug_struct("ManagedTexture").field("id", &self.id).finish()
  115. }
  116. }
  117. pub type ManagedBufferPtr = Arc<ManagedBuffer>;
  118. /// Auto-deletes buffer on drop
  119. pub struct ManagedBuffer {
  120. id: BufferId,
  121. epoch: u32,
  122. render_api: RenderApi,
  123. tag: DebugTag,
  124. buftype: u8,
  125. }
  126. impl Drop for ManagedBuffer {
  127. fn drop(&mut self) {
  128. self.render_api.delete_unmanaged_buffer(self.id, self.epoch, self.tag, self.buftype);
  129. }
  130. }
  131. impl std::fmt::Debug for ManagedBuffer {
  132. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  133. f.debug_struct("ManagedBuffer").field("id", &self.id).finish()
  134. }
  135. }
  136. pub type ManagedSeqAnimPtr = Arc<ManagedSeqAnim>;
  137. pub struct ManagedSeqAnim {
  138. frames_len: usize,
  139. pub id: AnimId,
  140. epoch: u32,
  141. render_api: RenderApi,
  142. tag: DebugTag,
  143. }
  144. impl ManagedSeqAnim {
  145. pub fn update(&self, frame_idx: usize, frame: AnimFrame) {
  146. assert!(frame_idx < self.frames_len);
  147. self.render_api.update_unmanaged_anim(self.id, frame_idx, frame, self.epoch, self.tag);
  148. }
  149. }
  150. impl Drop for ManagedSeqAnim {
  151. fn drop(&mut self) {
  152. self.render_api.delete_unmanaged_anim(self.id, self.epoch, self.tag);
  153. }
  154. }
  155. impl std::fmt::Debug for ManagedSeqAnim {
  156. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  157. f.debug_struct("ManagedSeqAnim").field("id", &self.id).finish()
  158. }
  159. }
  160. pub type EpochIndex = u32;
  161. #[derive(Clone)]
  162. pub struct RenderApi {
  163. /// We are abusing async_channel since it's cloneable whereas std::sync::mpsc is shit.
  164. method_send: async_channel::Sender<(EpochIndex, GraphicsMethod)>,
  165. /// Keep track of the current UI epoch
  166. epoch: Arc<AtomicU32>,
  167. }
  168. impl RenderApi {
  169. pub fn new(method_send: async_channel::Sender<(EpochIndex, GraphicsMethod)>) -> Self {
  170. Self { method_send, epoch: Arc::new(AtomicU32::new(0)) }
  171. }
  172. fn next_epoch(&self) -> EpochIndex {
  173. self.epoch.fetch_add(1, Ordering::Relaxed) + 1
  174. }
  175. fn send(&self, method: GraphicsMethod) -> EpochIndex {
  176. let epoch = self.epoch.load(Ordering::Relaxed);
  177. self.send_with_epoch(method, epoch);
  178. epoch
  179. }
  180. fn send_with_epoch(&self, method: GraphicsMethod, epoch: EpochIndex) {
  181. let _ = self.method_send.try_send((epoch, method)).unwrap();
  182. }
  183. fn new_unmanaged_texture(
  184. &self,
  185. width: u16,
  186. height: u16,
  187. data: Vec<u8>,
  188. tag: DebugTag,
  189. ) -> (TextureId, EpochIndex) {
  190. let gfx_texture_id = NEXT_TEXTURE_ID.fetch_add(1, Ordering::Relaxed);
  191. let method = GraphicsMethod::NewTexture((width, height, data, gfx_texture_id, tag));
  192. let epoch = self.send(method);
  193. (gfx_texture_id, epoch)
  194. }
  195. pub fn new_texture(
  196. &self,
  197. width: u16,
  198. height: u16,
  199. data: Vec<u8>,
  200. tag: DebugTag,
  201. ) -> ManagedTexturePtr {
  202. let (id, epoch) = self.new_unmanaged_texture(width, height, data, tag);
  203. Arc::new(ManagedTexture { id, epoch, render_api: self.clone(), tag })
  204. }
  205. fn delete_unmanaged_texture(&self, texture: TextureId, epoch: EpochIndex, tag: DebugTag) {
  206. let method = GraphicsMethod::DeleteTexture((texture, tag));
  207. self.send_with_epoch(method, epoch);
  208. }
  209. fn new_unmanaged_vertex_buffer(
  210. &self,
  211. verts: Vec<Vertex>,
  212. tag: DebugTag,
  213. ) -> (BufferId, EpochIndex) {
  214. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::Relaxed);
  215. let method = GraphicsMethod::NewVertexBuffer((verts, gfx_buffer_id, tag));
  216. let epoch = self.send(method);
  217. (gfx_buffer_id, epoch)
  218. }
  219. fn new_unmanaged_index_buffer(
  220. &self,
  221. indices: Vec<u16>,
  222. tag: DebugTag,
  223. ) -> (BufferId, EpochIndex) {
  224. let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::Relaxed);
  225. let method = GraphicsMethod::NewIndexBuffer((indices, gfx_buffer_id, tag));
  226. let epoch = self.send(method);
  227. (gfx_buffer_id, epoch)
  228. }
  229. pub fn new_vertex_buffer(&self, verts: Vec<Vertex>, tag: DebugTag) -> ManagedBufferPtr {
  230. let (id, epoch) = self.new_unmanaged_vertex_buffer(verts, tag);
  231. Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 0 })
  232. }
  233. pub fn new_index_buffer(&self, indices: Vec<u16>, tag: DebugTag) -> ManagedBufferPtr {
  234. let (id, epoch) = self.new_unmanaged_index_buffer(indices, tag);
  235. Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 1 })
  236. }
  237. fn delete_unmanaged_buffer(
  238. &self,
  239. buffer: BufferId,
  240. epoch: EpochIndex,
  241. tag: DebugTag,
  242. buftype: u8,
  243. ) {
  244. let method = GraphicsMethod::DeleteBuffer((buffer, tag, buftype));
  245. self.send_with_epoch(method, epoch);
  246. }
  247. fn new_unmanaged_anim(
  248. &self,
  249. frames_len: usize,
  250. oneshot: bool,
  251. tag: DebugTag,
  252. ) -> (AnimId, EpochIndex) {
  253. let gfx_anim_id = NEXT_ANIM_ID.fetch_add(1, Ordering::Relaxed);
  254. let method = GraphicsMethod::NewSeqAnim { id: gfx_anim_id, frames_len, oneshot, tag };
  255. let epoch = self.send(method);
  256. (gfx_anim_id, epoch)
  257. }
  258. pub fn new_anim(&self, frames_len: usize, oneshot: bool, tag: DebugTag) -> ManagedSeqAnimPtr {
  259. let (id, epoch) = self.new_unmanaged_anim(frames_len, oneshot, tag);
  260. Arc::new(ManagedSeqAnim { frames_len, id, epoch, render_api: self.clone(), tag })
  261. }
  262. pub fn update_unmanaged_anim(
  263. &self,
  264. anim: AnimId,
  265. frame_idx: usize,
  266. frame: AnimFrame,
  267. epoch: EpochIndex,
  268. tag: DebugTag,
  269. ) {
  270. let method = GraphicsMethod::UpdateSeqAnim { id: anim, frame_idx, frame, tag };
  271. self.send_with_epoch(method, epoch);
  272. }
  273. fn delete_unmanaged_anim(&self, anim: AnimId, epoch: EpochIndex, tag: DebugTag) {
  274. let method = GraphicsMethod::DeleteSeqAnim((anim, tag));
  275. self.send_with_epoch(method, epoch);
  276. }
  277. pub fn replace_draw_calls(&self, batch_id: BatchGuardId, dcs: Vec<(DcId, DrawCall)>) {
  278. let method = GraphicsMethod::ReplaceGfxDrawCalls { batch_id, dcs };
  279. self.send(method);
  280. }
  281. fn start_batch(&self, batch_id: BatchGuardId, tag: DebugTag) {
  282. let method = GraphicsMethod::StartBatch { batch_id, tag };
  283. self.send(method);
  284. }
  285. fn end_batch(&self, batch_id: BatchGuardId) {
  286. let timest = unixtime();
  287. let method = GraphicsMethod::EndBatch { batch_id, timest };
  288. self.send(method);
  289. }
  290. pub fn make_guard(&self, debug_str: Option<&'static str>) -> PropertyAtomicGuard {
  291. let r = self.clone();
  292. let start_batch = Box::new(move |bid| r.start_batch(bid, debug_str));
  293. let r = self.clone();
  294. let end_batch = Box::new(move |bid| r.end_batch(bid));
  295. PropertyAtomicGuard::new(start_batch, end_batch)
  296. }
  297. }
  298. #[derive(Clone, Debug)]
  299. pub struct DrawMesh {
  300. pub vertex_buffer: ManagedBufferPtr,
  301. pub index_buffer: ManagedBufferPtr,
  302. pub texture: Option<ManagedTexturePtr>,
  303. pub num_elements: i32,
  304. }
  305. impl DrawMesh {
  306. fn compile(
  307. self,
  308. textures: &HashMap<TextureId, miniquad::TextureId>,
  309. buffers: &HashMap<BufferId, miniquad::BufferId>,
  310. debug_str: &'static str,
  311. ) -> GfxDrawMesh {
  312. let vertex_buffer_id = self.vertex_buffer.id;
  313. let index_buffer_id = self.index_buffer.id;
  314. let _buffers_keep_alive = [self.vertex_buffer, self.index_buffer];
  315. let texture = match self.texture {
  316. Some(gfx_texture) => Some(Self::get_texture(textures, gfx_texture, debug_str)),
  317. None => None,
  318. };
  319. GfxDrawMesh {
  320. vertex_buffer: Self::get_buffer(buffers, vertex_buffer_id, debug_str),
  321. index_buffer: Self::get_buffer(buffers, index_buffer_id, debug_str),
  322. _buffers_keep_alive,
  323. texture,
  324. num_elements: self.num_elements,
  325. }
  326. }
  327. fn get_texture(
  328. textures: &HashMap<TextureId, miniquad::TextureId>,
  329. gfx_texture: ManagedTexturePtr,
  330. debug_str: &'static str,
  331. ) -> (ManagedTexturePtr, miniquad::TextureId) {
  332. let gfx_texture_id = gfx_texture.id;
  333. let Some(_mq_texture_id) = textures.get(&gfx_texture_id) else {
  334. panic!("Missing texture ID={gfx_texture_id} debug={debug_str}")
  335. };
  336. (gfx_texture, textures[&gfx_texture_id])
  337. }
  338. fn get_buffer(
  339. buffers: &HashMap<BufferId, miniquad::BufferId>,
  340. gfx_buffer_id: BufferId,
  341. debug_str: &'static str,
  342. ) -> miniquad::BufferId {
  343. let Some(mq_buffer_id) = buffers.get(&gfx_buffer_id) else {
  344. panic!("Missing buffer ID={gfx_buffer_id} debug={debug_str}")
  345. };
  346. *mq_buffer_id
  347. }
  348. }
  349. impl Encodable for DrawMesh {
  350. fn encode<S: Write>(&self, s: &mut S) -> std::result::Result<usize, std::io::Error> {
  351. let mut len = 0;
  352. len += self.vertex_buffer.id.encode(s)?;
  353. len += self.vertex_buffer.epoch.encode(s)?;
  354. len += self.vertex_buffer.tag.encode(s)?;
  355. len += self.vertex_buffer.buftype.encode(s)?;
  356. len += self.index_buffer.id.encode(s)?;
  357. len += self.index_buffer.epoch.encode(s)?;
  358. len += self.index_buffer.tag.encode(s)?;
  359. len += self.index_buffer.buftype.encode(s)?;
  360. match &self.texture {
  361. Some(t) => {
  362. len += 1u8.encode(s)?;
  363. len += t.id.encode(s)?;
  364. len += t.epoch.encode(s)?;
  365. len += t.tag.encode(s)?;
  366. }
  367. None => {
  368. len += 0u8.encode(s)?;
  369. }
  370. }
  371. len += self.num_elements.encode(s)?;
  372. Ok(len)
  373. }
  374. }
  375. #[async_trait]
  376. impl AsyncEncodable for DrawMesh {
  377. async fn encode_async<W: AsyncWrite + Unpin + Send>(
  378. &self,
  379. _: &mut W,
  380. ) -> std::io::Result<usize> {
  381. Ok(0)
  382. }
  383. }
  384. #[derive(Debug, Clone, SerialEncodable)]
  385. pub enum DrawInstruction {
  386. SetScale(f32),
  387. Move(Point),
  388. SetPos(Point),
  389. ApplyView(Rectangle),
  390. Draw(DrawMesh),
  391. Animation(AnimId),
  392. EnableDebug,
  393. }
  394. impl DrawInstruction {
  395. fn compile(
  396. self,
  397. textures: &HashMap<TextureId, miniquad::TextureId>,
  398. buffers: &HashMap<BufferId, miniquad::BufferId>,
  399. debug_str: &'static str,
  400. ) -> GfxDrawInstruction {
  401. match self {
  402. Self::SetScale(scale) => GfxDrawInstruction::SetScale(scale),
  403. Self::Move(off) => GfxDrawInstruction::Move(off),
  404. Self::SetPos(pos) => GfxDrawInstruction::SetPos(pos),
  405. Self::ApplyView(view) => GfxDrawInstruction::ApplyView(view),
  406. Self::Draw(mesh) => {
  407. GfxDrawInstruction::Draw(mesh.compile(textures, buffers, debug_str))
  408. }
  409. Self::Animation(anim) => GfxDrawInstruction::Animation(anim),
  410. Self::EnableDebug => GfxDrawInstruction::EnableDebug,
  411. }
  412. }
  413. }
  414. #[derive(Clone, Debug, Default, SerialEncodable)]
  415. pub struct DrawCall {
  416. pub instrs: Vec<DrawInstruction>,
  417. pub dcs: Vec<DcId>,
  418. pub z_index: u32,
  419. pub debug_str: &'static str,
  420. }
  421. impl DrawCall {
  422. pub fn new(
  423. instrs: Vec<DrawInstruction>,
  424. dcs: Vec<DcId>,
  425. z_index: u32,
  426. debug_str: &'static str,
  427. ) -> Self {
  428. Self { instrs, dcs, z_index, debug_str }
  429. }
  430. fn compile(
  431. self,
  432. textures: &HashMap<TextureId, miniquad::TextureId>,
  433. buffers: &HashMap<BufferId, miniquad::BufferId>,
  434. timest: Timestamp,
  435. ) -> GfxDrawCall {
  436. GfxDrawCall {
  437. instrs: self
  438. .instrs
  439. .into_iter()
  440. .map(|i| i.compile(textures, buffers, self.debug_str))
  441. .collect(),
  442. dcs: self.dcs,
  443. z_index: self.z_index,
  444. timest,
  445. }
  446. }
  447. }
  448. #[derive(Clone, Debug)]
  449. struct GfxDrawMesh {
  450. vertex_buffer: miniquad::BufferId,
  451. index_buffer: miniquad::BufferId,
  452. /// Keeps the buffers alive for the duration of this draw call
  453. _buffers_keep_alive: [ManagedBufferPtr; 2],
  454. texture: Option<(ManagedTexturePtr, miniquad::TextureId)>,
  455. num_elements: i32,
  456. }
  457. #[derive(Debug, Clone)]
  458. enum GfxDrawInstruction {
  459. SetScale(f32),
  460. Move(Point),
  461. SetPos(Point),
  462. ApplyView(Rectangle),
  463. Draw(GfxDrawMesh),
  464. Animation(AnimId),
  465. EnableDebug,
  466. }
  467. #[derive(Clone, Debug)]
  468. struct GfxDrawCall {
  469. instrs: Vec<GfxDrawInstruction>,
  470. dcs: Vec<DcId>,
  471. z_index: u32,
  472. timest: Timestamp,
  473. }
  474. struct RenderContext<'a> {
  475. ctx: &'a mut Box<dyn RenderingBackend>,
  476. draw_calls: &'a HashMap<DcId, GfxDrawCall>,
  477. uniforms_data: [u8; 128],
  478. white_texture: miniquad::TextureId,
  479. scale: f32,
  480. view: Rectangle,
  481. cursor: Point,
  482. anims: &'a mut HashMap<AnimId, GfxSeqAnim>,
  483. }
  484. impl<'a> RenderContext<'a> {
  485. fn draw(&mut self) {
  486. if DEBUG_RENDER {
  487. debug!(target: "gfx", "RenderContext::draw()");
  488. }
  489. if DEBUG_TRAX {
  490. get_trax().lock().set_curr(0);
  491. }
  492. self.draw_call(&self.draw_calls[&0], 0, DEBUG_RENDER);
  493. if DEBUG_RENDER {
  494. debug!(target: "gfx", "RenderContext::draw() [DONE]");
  495. }
  496. }
  497. fn apply_view(&mut self) {
  498. // Actual physical view
  499. let view = self.view * self.scale;
  500. let (_, screen_height) = window::screen_size();
  501. let view_x = view.x.round() as i32;
  502. let view_y = screen_height - (view.y + view.h);
  503. let view_y = view_y.round() as i32;
  504. let view_w = view.w.round() as i32;
  505. let view_h = view.h.round() as i32;
  506. // OpenGL does not like negative values here
  507. if view_w <= 0 || view_h <= 0 {
  508. return
  509. }
  510. if DEBUG_RENDER {
  511. debug!(target: "gfx", "=> viewport {view_x} {view_y} {view_w} {view_h}");
  512. }
  513. self.ctx.apply_viewport(view_x, view_y, view_w, view_h);
  514. self.ctx.apply_scissor_rect(view_x, view_y, view_w, view_h);
  515. }
  516. fn apply_model(&mut self) {
  517. let off_x = self.cursor.x / self.view.w;
  518. let off_y = self.cursor.y / self.view.h;
  519. let scale_w = 1. / self.view.w;
  520. let scale_h = 1. / self.view.h;
  521. let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
  522. glam::Mat4::from_scale(glam::Vec3::new(scale_w, scale_h, 1.));
  523. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  524. self.uniforms_data[64..].copy_from_slice(&data);
  525. self.ctx.apply_uniforms_from_bytes(self.uniforms_data.as_ptr(), self.uniforms_data.len());
  526. }
  527. fn draw_call(&mut self, draw_call: &GfxDrawCall, mut indent: u32, mut is_debug: bool) {
  528. let ws = if is_debug { " ".repeat(indent as usize * 4) } else { String::new() };
  529. let old_scale = self.scale;
  530. let old_view = self.view;
  531. let old_cursor = self.cursor;
  532. for (idx, instr) in draw_call.instrs.iter().enumerate() {
  533. if DEBUG_TRAX {
  534. get_trax().lock().set_instr(idx);
  535. }
  536. match instr {
  537. GfxDrawInstruction::SetScale(scale) => {
  538. self.scale = *scale;
  539. self.view.w /= self.scale;
  540. self.view.h /= self.scale;
  541. if is_debug {
  542. debug!(target: "gfx", "{ws}set_scale({scale})");
  543. }
  544. }
  545. GfxDrawInstruction::Move(off) => {
  546. self.cursor += *off;
  547. if is_debug {
  548. debug!(target: "gfx",
  549. "{ws}move({off:?}) cursor={:?}, scale={}, view={:?}",
  550. self.cursor, self.scale, self.view
  551. );
  552. }
  553. self.apply_model();
  554. }
  555. GfxDrawInstruction::SetPos(pos) => {
  556. self.cursor = old_cursor + *pos;
  557. if is_debug {
  558. debug!(target: "gfx",
  559. "{ws}set_pos({pos:?}) cursor={:?}, scale={}, view={:?}",
  560. self.cursor, self.scale, self.view
  561. );
  562. }
  563. self.apply_model();
  564. }
  565. GfxDrawInstruction::ApplyView(view) => {
  566. // Adjust view relative to cursor
  567. self.view = *view + self.cursor;
  568. // We could just skip drawing when clipping rect isn't visible
  569. // using an is_visible flag.
  570. match self.view.clip(&old_view) {
  571. Some(clipped) => self.view = clipped,
  572. None => self.view = Rectangle::zero(),
  573. }
  574. // Cursor resets within the view
  575. self.cursor = Point::zero();
  576. if is_debug {
  577. debug!(target: "gfx",
  578. "{ws}apply_view({view:?}) scale={}, view={:?}",
  579. self.scale, self.view
  580. );
  581. }
  582. self.apply_view();
  583. self.apply_model();
  584. }
  585. GfxDrawInstruction::Draw(mesh) => {
  586. if is_debug {
  587. debug!(target: "gfx", "{ws}draw({mesh:?})");
  588. }
  589. let texture = match mesh.texture {
  590. Some((_, texture)) => texture,
  591. None => self.white_texture,
  592. };
  593. let bindings = Bindings {
  594. vertex_buffers: vec![mesh.vertex_buffer],
  595. index_buffer: mesh.index_buffer,
  596. images: vec![texture],
  597. };
  598. self.ctx.apply_bindings(&bindings);
  599. self.ctx.draw(0, mesh.num_elements, 1);
  600. }
  601. GfxDrawInstruction::Animation(anim_id) => {
  602. let anim = self.anims.get_mut(&anim_id).unwrap();
  603. anim.is_visible = true;
  604. if let Some(dc) = anim.tick() {
  605. self.draw_call(&dc, indent + 1, is_debug);
  606. }
  607. }
  608. GfxDrawInstruction::EnableDebug => {
  609. if !is_debug {
  610. indent = 0;
  611. }
  612. is_debug = true;
  613. debug!(target: "gfx", "Frame start");
  614. }
  615. }
  616. }
  617. let mut draw_calls: Vec<_> =
  618. draw_call.dcs.iter().map(|key| (key, &self.draw_calls[key])).collect();
  619. draw_calls.sort_unstable_by_key(|(_, dc)| dc.z_index);
  620. for (dc_key, dc) in draw_calls {
  621. if DEBUG_TRAX {
  622. get_trax().lock().set_curr(*dc_key);
  623. }
  624. if is_debug {
  625. debug!(target: "gfx", "{ws}drawcall {dc_key}");
  626. }
  627. self.draw_call(dc, indent + 1, is_debug);
  628. }
  629. self.scale = old_scale;
  630. if is_debug {
  631. debug!(target: "gfx", "{ws}Frame close: cursor={old_cursor:?}, view={old_view:?}");
  632. }
  633. self.view = old_view;
  634. self.apply_view();
  635. self.cursor = old_cursor;
  636. self.apply_model();
  637. }
  638. }
  639. type Timestamp = u64;
  640. type DcId = u64;
  641. #[derive(Clone)]
  642. pub enum GraphicsMethod {
  643. NewTexture((u16, u16, Vec<u8>, TextureId, DebugTag)),
  644. DeleteTexture((TextureId, DebugTag)),
  645. NewVertexBuffer((Vec<Vertex>, BufferId, DebugTag)),
  646. NewIndexBuffer((Vec<u16>, BufferId, DebugTag)),
  647. DeleteBuffer((BufferId, DebugTag, u8)),
  648. NewSeqAnim { id: AnimId, frames_len: usize, oneshot: bool, tag: DebugTag },
  649. UpdateSeqAnim { id: AnimId, frame_idx: usize, frame: AnimFrame, tag: DebugTag },
  650. DeleteSeqAnim((AnimId, DebugTag)),
  651. ReplaceGfxDrawCalls { batch_id: BatchGuardId, dcs: Vec<(DcId, DrawCall)> },
  652. StartBatch { batch_id: BatchGuardId, tag: DebugTag },
  653. EndBatch { batch_id: BatchGuardId, timest: Timestamp },
  654. Noop,
  655. }
  656. impl std::fmt::Debug for GraphicsMethod {
  657. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  658. match self {
  659. Self::NewTexture(_) => write!(f, "NewTexture"),
  660. Self::DeleteTexture(_) => write!(f, "DeleteTexture"),
  661. Self::NewVertexBuffer(_) => write!(f, "NewVertexBuffer"),
  662. Self::NewIndexBuffer(_) => write!(f, "NewIndexBuffer"),
  663. Self::DeleteBuffer(_) => write!(f, "DeleteBuffer"),
  664. Self::NewSeqAnim { .. } => write!(f, "NewSeqAnim"),
  665. Self::UpdateSeqAnim { .. } => write!(f, "UpdateSeqAnim"),
  666. Self::DeleteSeqAnim(_) => write!(f, "DeleteSeqAnim"),
  667. Self::ReplaceGfxDrawCalls { batch_id: bid, dcs: _ } => {
  668. write!(f, "ReplaceGfxDrawCalls({bid})")
  669. }
  670. Self::StartBatch { batch_id, tag } => write!(f, "StartBatch({batch_id}, {tag:?})"),
  671. Self::EndBatch { batch_id, timest } => write!(f, "EndBatch({batch_id}, {timest})"),
  672. Self::Noop => write!(f, "Noop"),
  673. }
  674. }
  675. }
  676. impl Default for GraphicsMethod {
  677. fn default() -> Self {
  678. GraphicsMethod::Noop
  679. }
  680. }
  681. struct EventChannel<T> {
  682. sender: async_channel::Sender<T>,
  683. recvr: async_channel::Receiver<T>,
  684. }
  685. impl<T> EventChannel<T> {
  686. fn new() -> Self {
  687. let (sender, recvr) = async_channel::unbounded();
  688. Self { sender, recvr }
  689. }
  690. fn notify(&self, ev: T) {
  691. self.sender.try_send(ev).unwrap();
  692. }
  693. fn clone_recvr(&self) -> async_channel::Receiver<T> {
  694. self.recvr.clone()
  695. }
  696. }
  697. pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
  698. pub struct GraphicsEventPublisher {
  699. resize: EventChannel<Dimension>,
  700. key_down: EventChannel<(KeyCode, KeyMods, bool)>,
  701. key_up: EventChannel<(KeyCode, KeyMods)>,
  702. chr: EventChannel<(char, KeyMods, bool)>,
  703. mouse_btn_down: EventChannel<(MouseButton, Point)>,
  704. mouse_btn_up: EventChannel<(MouseButton, Point)>,
  705. mouse_move: EventChannel<Point>,
  706. mouse_wheel: EventChannel<Point>,
  707. touch: EventChannel<(TouchPhase, u64, Point)>,
  708. }
  709. pub type GraphicsEventResizeSub = async_channel::Receiver<Dimension>;
  710. pub type GraphicsEventKeyDownSub = async_channel::Receiver<(KeyCode, KeyMods, bool)>;
  711. pub type GraphicsEventKeyUpSub = async_channel::Receiver<(KeyCode, KeyMods)>;
  712. pub type GraphicsEventCharSub = async_channel::Receiver<(char, KeyMods, bool)>;
  713. pub type GraphicsEventMouseButtonDownSub = async_channel::Receiver<(MouseButton, Point)>;
  714. pub type GraphicsEventMouseButtonUpSub = async_channel::Receiver<(MouseButton, Point)>;
  715. pub type GraphicsEventMouseMoveSub = async_channel::Receiver<Point>;
  716. pub type GraphicsEventMouseWheelSub = async_channel::Receiver<Point>;
  717. pub type GraphicsEventTouchSub = async_channel::Receiver<(TouchPhase, u64, Point)>;
  718. impl GraphicsEventPublisher {
  719. pub fn new() -> Arc<Self> {
  720. Arc::new(Self {
  721. resize: EventChannel::new(),
  722. key_down: EventChannel::new(),
  723. key_up: EventChannel::new(),
  724. chr: EventChannel::new(),
  725. mouse_btn_down: EventChannel::new(),
  726. mouse_btn_up: EventChannel::new(),
  727. mouse_move: EventChannel::new(),
  728. mouse_wheel: EventChannel::new(),
  729. touch: EventChannel::new(),
  730. })
  731. }
  732. fn notify_resize(&self, screen_size: Dimension) {
  733. self.resize.notify(screen_size);
  734. }
  735. fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
  736. let ev = (key, mods, repeat);
  737. self.key_down.notify(ev);
  738. }
  739. fn notify_key_up(&self, key: KeyCode, mods: KeyMods) {
  740. let ev = (key, mods);
  741. self.key_up.notify(ev);
  742. }
  743. fn notify_char(&self, chr: char, mods: KeyMods, repeat: bool) {
  744. let ev = (chr, mods, repeat);
  745. self.chr.notify(ev);
  746. }
  747. fn notify_mouse_btn_down(&self, button: MouseButton, mouse_pos: Point) {
  748. let ev = (button, mouse_pos);
  749. self.mouse_btn_down.notify(ev);
  750. }
  751. fn notify_mouse_btn_up(&self, button: MouseButton, mouse_pos: Point) {
  752. let ev = (button, mouse_pos);
  753. self.mouse_btn_up.notify(ev);
  754. }
  755. fn notify_mouse_move(&self, mouse_pos: Point) {
  756. self.mouse_move.notify(mouse_pos);
  757. }
  758. fn notify_mouse_wheel(&self, wheel_pos: Point) {
  759. self.mouse_wheel.notify(wheel_pos);
  760. }
  761. fn notify_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) {
  762. let ev = (phase, id, touch_pos);
  763. self.touch.notify(ev);
  764. }
  765. pub fn subscribe_resize(&self) -> GraphicsEventResizeSub {
  766. self.resize.clone_recvr()
  767. }
  768. pub fn subscribe_key_down(&self) -> GraphicsEventKeyDownSub {
  769. self.key_down.clone_recvr()
  770. }
  771. pub fn subscribe_key_up(&self) -> GraphicsEventKeyUpSub {
  772. self.key_up.clone_recvr()
  773. }
  774. pub fn subscribe_char(&self) -> GraphicsEventCharSub {
  775. self.chr.clone_recvr()
  776. }
  777. pub fn subscribe_mouse_btn_down(&self) -> GraphicsEventMouseButtonDownSub {
  778. self.mouse_btn_down.clone_recvr()
  779. }
  780. pub fn subscribe_mouse_btn_up(&self) -> GraphicsEventMouseButtonUpSub {
  781. self.mouse_btn_up.clone_recvr()
  782. }
  783. pub fn subscribe_mouse_move(&self) -> GraphicsEventMouseMoveSub {
  784. self.mouse_move.clone_recvr()
  785. }
  786. pub fn subscribe_mouse_wheel(&self) -> GraphicsEventMouseWheelSub {
  787. self.mouse_wheel.clone_recvr()
  788. }
  789. pub fn subscribe_touch(&self) -> GraphicsEventTouchSub {
  790. self.touch.clone_recvr()
  791. }
  792. }
  793. struct Stage {
  794. ctx: Box<dyn RenderingBackend>,
  795. #[cfg(target_os = "android")]
  796. libegl: egl::LibEgl,
  797. pipeline: Pipeline,
  798. white_texture: miniquad::TextureId,
  799. draw_calls: HashMap<DcId, GfxDrawCall>,
  800. pending_batches: HashMap<BatchGuardId, Vec<GraphicsMethod>>,
  801. /// When dropping batches, we add to this set so that we keep track
  802. /// of the internal state's correctness.
  803. dropped_batches: Box<HashSet<BatchGuardId>>,
  804. textures: Box<HashMap<TextureId, miniquad::TextureId>>,
  805. buffers: Box<HashMap<BufferId, miniquad::BufferId>>,
  806. anims: Box<HashMap<AnimId, GfxSeqAnim>>,
  807. epoch: EpochIndex,
  808. method_queue: Arc<SyncMutex<Vec<(EpochIndex, GraphicsMethod)>>>,
  809. event_pub: GraphicsEventPublisherPtr,
  810. pruner: PruneMethodHeap,
  811. screen_state: ScreenState,
  812. #[cfg(target_os = "android")]
  813. ex: ExecutorPtr,
  814. #[cfg(target_os = "android")]
  815. refresh_task: Option<smol::Task<()>>,
  816. }
  817. impl Stage {
  818. pub fn new() -> Self {
  819. if DEBUG_TRAX {
  820. get_trax().lock().clear();
  821. }
  822. let mut ctx: Box<dyn RenderingBackend> = window::new_rendering_backend();
  823. let god = GOD.get().unwrap();
  824. // Start a new epoch. This is a brand new UI run.
  825. let epoch = god.render_api.next_epoch();
  826. // This will start the app to start. Needed since we cannot get window size for init
  827. // until window is created.
  828. god.start_app(epoch);
  829. let method_recv = god.method_recv.clone();
  830. let event_pub = god.event_pub.clone();
  831. let ex = god.fg_ex.clone();
  832. let method_queue = Arc::new(SyncMutex::new(vec![]));
  833. let method_queue2 = method_queue.clone();
  834. let sink_task = ex.spawn(async move {
  835. // Pull from render_api
  836. while let Ok((epoch, method)) = method_recv.recv().await {
  837. let is_replace_dc = matches!(method, GraphicsMethod::ReplaceGfxDrawCalls { .. });
  838. // Append to stage data
  839. method_queue2.lock().push((epoch, method));
  840. // If ReplaceGfxDrawCall then wake up miniquad
  841. if is_replace_dc {
  842. #[cfg(target_os = "android")]
  843. miniquad::window::schedule_update();
  844. }
  845. }
  846. });
  847. god.fg_runtime.push_task(sink_task);
  848. let white_texture = ctx.new_texture_from_rgba8(1, 1, &[255, 255, 255, 255]);
  849. let anims: HashMap<AnimId, GfxSeqAnim> = HashMap::new();
  850. let mut shader_meta: ShaderMeta = shader::meta();
  851. shader_meta.uniforms.uniforms.push(UniformDesc::new("Projection", UniformType::Mat4));
  852. shader_meta.uniforms.uniforms.push(UniformDesc::new("Model", UniformType::Mat4));
  853. let shader = ctx
  854. .new_shader(
  855. match ctx.info().backend {
  856. Backend::OpenGl => ShaderSource::Glsl {
  857. vertex: shader::GL_VERTEX,
  858. fragment: shader::GL_FRAGMENT,
  859. },
  860. Backend::Metal => ShaderSource::Msl { program: shader::METAL },
  861. },
  862. shader_meta,
  863. )
  864. .unwrap();
  865. let params = PipelineParams {
  866. color_blend: Some(BlendState::new(
  867. Equation::Add,
  868. BlendFactor::Value(BlendValue::SourceAlpha),
  869. BlendFactor::OneMinusValue(BlendValue::SourceAlpha),
  870. )),
  871. ..Default::default()
  872. };
  873. let pipeline = ctx.new_pipeline(
  874. &[BufferLayout::default()],
  875. &[
  876. VertexAttribute::new("in_pos", VertexFormat::Float2),
  877. VertexAttribute::new("in_color", VertexFormat::Float4),
  878. VertexAttribute::new("in_uv", VertexFormat::Float2),
  879. ],
  880. shader,
  881. params,
  882. );
  883. #[cfg(target_os = "android")]
  884. let libegl = egl::LibEgl::try_load().expect("Cant load LibEGL");
  885. let mut self_ = Stage {
  886. ctx,
  887. #[cfg(target_os = "android")]
  888. libegl,
  889. pipeline,
  890. white_texture,
  891. draw_calls: HashMap::from([(
  892. 0,
  893. GfxDrawCall { instrs: vec![], dcs: vec![], z_index: 0, timest: 0 },
  894. )]),
  895. pending_batches: HashMap::new(),
  896. dropped_batches: Box::new(HashSet::new()),
  897. textures: Box::new(HashMap::new()),
  898. buffers: Box::new(HashMap::new()),
  899. anims: Box::new(anims),
  900. epoch,
  901. method_queue,
  902. event_pub,
  903. pruner: PruneMethodHeap::new(epoch),
  904. screen_state: ScreenState::On,
  905. #[cfg(target_os = "android")]
  906. ex: ex.clone(),
  907. #[cfg(target_os = "android")]
  908. refresh_task: None,
  909. };
  910. self_.pruner.textures = &*self_.textures as *const _;
  911. self_.pruner.buffers = &*self_.buffers as *const _;
  912. self_.pruner.anims = &*self_.anims as *const _;
  913. self_.pruner.dropped_batches = &mut *self_.dropped_batches as *mut _;
  914. self_.start_refresh_task();
  915. self_
  916. }
  917. fn process_method(&mut self, mut method: GraphicsMethod) {
  918. //d!("Received method: {method:?}");
  919. match &mut method {
  920. GraphicsMethod::NewTexture((width, height, data, gtex_id, _)) => {
  921. self.method_new_texture(*width, *height, data, *gtex_id)
  922. }
  923. GraphicsMethod::DeleteTexture((gtex_id, _)) => self.method_delete_texture(*gtex_id),
  924. GraphicsMethod::NewVertexBuffer((verts, gbuff_id, _)) => {
  925. self.method_new_vertex_buffer(verts, *gbuff_id)
  926. }
  927. GraphicsMethod::NewIndexBuffer((indices, gbuff_id, _)) => {
  928. self.method_new_index_buffer(indices, *gbuff_id)
  929. }
  930. GraphicsMethod::DeleteBuffer((gbuff_id, _, _)) => self.method_delete_buffer(*gbuff_id),
  931. GraphicsMethod::NewSeqAnim { id, frames_len, oneshot, tag: _ } => {
  932. self.method_new_anim(*id, *frames_len, *oneshot)
  933. }
  934. GraphicsMethod::UpdateSeqAnim { id, frame_idx, frame, tag: _ } => {
  935. self.method_update_anim(*id, *frame_idx, frame.clone())
  936. }
  937. GraphicsMethod::DeleteSeqAnim((ganim_id, _)) => self.method_delete_anim(*ganim_id),
  938. GraphicsMethod::ReplaceGfxDrawCalls { batch_id, .. } => {
  939. //let debug_strs: Vec<_> = dcs.iter().map(|(_, dc)| dc.debug_str).collect();
  940. //t!("Commit dc to {batch_id}: {debug_strs:?}");
  941. if self.dropped_batches.contains(batch_id) {
  942. t!("Discarding ReplaceGfxDrawCalls from dropped {batch_id}");
  943. return
  944. }
  945. let Some(batch) = self.pending_batches.get_mut(batch_id) else {
  946. panic!("unknown batch {batch_id}")
  947. };
  948. let method = std::mem::take(&mut method);
  949. batch.push(method);
  950. if DEBUG_TRAX {
  951. get_trax().lock().put_stat(0);
  952. }
  953. }
  954. GraphicsMethod::StartBatch { batch_id, tag } => {
  955. if DEBUG_GFXAPI {
  956. t!("Start batch {batch_id}: {tag:?}");
  957. }
  958. if !self.pending_batches.insert(*batch_id, vec![]).is_none() {
  959. panic!("batch {batch_id} already open!")
  960. }
  961. if DEBUG_TRAX {
  962. get_trax().lock().put_stat(0);
  963. }
  964. }
  965. GraphicsMethod::EndBatch { batch_id, timest } => {
  966. if self.dropped_batches.remove(batch_id) {
  967. if DEBUG_GFXAPI {
  968. t!("End batch {batch_id} was dropped");
  969. }
  970. return
  971. }
  972. if DEBUG_GFXAPI {
  973. t!("End batch {batch_id}");
  974. }
  975. let Some(batch) = self.pending_batches.remove(batch_id) else {
  976. panic!("unknown batch {batch_id}")
  977. };
  978. for mut method in batch {
  979. match &mut method {
  980. GraphicsMethod::ReplaceGfxDrawCalls { batch_id: _, dcs } => {
  981. let dcs = std::mem::take(dcs);
  982. self.method_replace_draw_calls(*timest, dcs)
  983. }
  984. _ => panic!("unexpected method in batch!"),
  985. }
  986. }
  987. }
  988. GraphicsMethod::Noop => panic!("noop"),
  989. }
  990. }
  991. fn method_new_texture(
  992. &mut self,
  993. width: u16,
  994. height: u16,
  995. data: &Vec<u8>,
  996. gfx_texture_id: TextureId,
  997. ) {
  998. let texture = self.ctx.new_texture_from_rgba8(width, height, data);
  999. if DEBUG_GFXAPI {
  1000. d!("Invoked method: new_texture({width}, {height}, ..., {gfx_texture_id}) -> {texture:?}");
  1001. //d!("Invoked method: new_texture({}, {}, ..., {}) -> {:?}\n{}",
  1002. // width, height, gfx_texture_id, texture,
  1003. // ansi_texture(width as usize, height as usize, &data));
  1004. }
  1005. if let Some(_) = self.textures.insert(gfx_texture_id, texture) {
  1006. if DEBUG_TRAX {
  1007. get_trax().lock().put_stat(2);
  1008. }
  1009. panic!("Duplicate texture ID={gfx_texture_id} detected!");
  1010. }
  1011. if DEBUG_TRAX {
  1012. get_trax().lock().put_stat(0);
  1013. }
  1014. }
  1015. fn method_delete_texture(&mut self, gfx_texture_id: TextureId) {
  1016. let Some(texture) = self.textures.remove(&gfx_texture_id) else {
  1017. if DEBUG_TRAX {
  1018. get_trax().lock().put_stat(2);
  1019. }
  1020. panic!("unknown texture {gfx_texture_id}")
  1021. };
  1022. if DEBUG_GFXAPI {
  1023. d!("Invoked method: delete_texture({gfx_texture_id} => {texture:?})");
  1024. }
  1025. self.ctx.delete_texture(texture);
  1026. if DEBUG_TRAX {
  1027. get_trax().lock().put_stat(0);
  1028. }
  1029. }
  1030. fn method_new_vertex_buffer(&mut self, verts: &[Vertex], gfx_buffer_id: BufferId) {
  1031. let buffer = self.ctx.new_buffer(
  1032. BufferType::VertexBuffer,
  1033. BufferUsage::Immutable,
  1034. BufferSource::slice(verts),
  1035. );
  1036. if DEBUG_GFXAPI {
  1037. d!("Invoked method: new_vertex_buffer(..., {gfx_buffer_id}) -> {buffer:?}");
  1038. //debug!(target: "gfx", "Invoked method: new_vertex_buffer({:?}, {}) -> {:?}",
  1039. // verts, gfx_buffer_id, buffer);
  1040. }
  1041. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  1042. if DEBUG_TRAX {
  1043. get_trax().lock().put_stat(2);
  1044. }
  1045. panic!("Duplicate vertex buffer ID={gfx_buffer_id} detected!")
  1046. }
  1047. if DEBUG_TRAX {
  1048. get_trax().lock().put_stat(0);
  1049. }
  1050. }
  1051. fn method_new_index_buffer(&mut self, indices: &[u16], gfx_buffer_id: BufferId) {
  1052. let buffer = self.ctx.new_buffer(
  1053. BufferType::IndexBuffer,
  1054. BufferUsage::Immutable,
  1055. BufferSource::slice(&indices),
  1056. );
  1057. if DEBUG_GFXAPI {
  1058. d!("Invoked method: new_index_buffer({gfx_buffer_id}) -> {buffer:?}");
  1059. //debug!(target: "gfx", "Invoked method: new_index_buffer({:?}, {}) -> {:?}",
  1060. // indices, gfx_buffer_id, buffer);
  1061. }
  1062. if let Some(_) = self.buffers.insert(gfx_buffer_id, buffer) {
  1063. if DEBUG_TRAX {
  1064. get_trax().lock().put_stat(2);
  1065. }
  1066. panic!("Duplicate index buffer ID={gfx_buffer_id} detected!")
  1067. }
  1068. if DEBUG_TRAX {
  1069. get_trax().lock().put_stat(0);
  1070. }
  1071. }
  1072. fn method_delete_buffer(&mut self, gfx_buffer_id: BufferId) {
  1073. let Some(buffer) = self.buffers.remove(&gfx_buffer_id) else {
  1074. if DEBUG_TRAX {
  1075. get_trax().lock().put_stat(2);
  1076. }
  1077. panic!("unknown buffer {gfx_buffer_id}");
  1078. };
  1079. if DEBUG_GFXAPI {
  1080. d!("Invoked method: delete_buffer({gfx_buffer_id} => {buffer:?})");
  1081. }
  1082. self.ctx.delete_buffer(buffer);
  1083. if DEBUG_TRAX {
  1084. get_trax().lock().put_stat(0);
  1085. }
  1086. }
  1087. fn method_new_anim(&mut self, gfx_anim_id: AnimId, frames_len: usize, oneshot: bool) {
  1088. if DEBUG_GFXAPI {
  1089. d!("Invoked method: new_anim({gfx_anim_id}, {frames_len}, {oneshot})");
  1090. }
  1091. if let Some(_) = self.anims.insert(gfx_anim_id, GfxSeqAnim::new(frames_len, oneshot)) {
  1092. panic!("Duplicate anim ID={gfx_anim_id} detected!");
  1093. }
  1094. }
  1095. fn method_update_anim(&mut self, gfx_anim_id: AnimId, frame_idx: usize, frame: AnimFrame) {
  1096. let Some(anim) = self.anims.get_mut(&gfx_anim_id) else {
  1097. panic!("couldn't find anim {gfx_anim_id}");
  1098. };
  1099. if DEBUG_GFXAPI {
  1100. d!("Invoked method: update_anim({gfx_anim_id}[{frame_idx}] => {frame:?})");
  1101. }
  1102. anim.set(frame_idx, frame, &self.textures, &self.buffers);
  1103. }
  1104. fn method_delete_anim(&mut self, gfx_anim_id: AnimId) {
  1105. let Some(anim) = self.anims.remove(&gfx_anim_id) else {
  1106. panic!("couldn't find anim {gfx_anim_id}");
  1107. };
  1108. if DEBUG_GFXAPI {
  1109. d!("Invoked method: delete_anim({} => {:?})", gfx_anim_id, anim);
  1110. }
  1111. }
  1112. fn method_replace_draw_calls(&mut self, timest: Timestamp, dcs: Vec<(DcId, DrawCall)>) {
  1113. if DEBUG_GFXAPI {
  1114. d!("Invoked method: replace_draw_calls({:?})", dcs);
  1115. }
  1116. for (key, val) in dcs {
  1117. let val = val.compile(&self.textures, &self.buffers, timest);
  1118. //self.draw_calls.insert(key, val);
  1119. match self.draw_calls.get_mut(&key) {
  1120. Some(old_val) => {
  1121. // Only replace the draw call if it is more recent
  1122. if old_val.timest < timest {
  1123. if DEBUG_TRAX {
  1124. get_trax().lock().put_stat(0);
  1125. }
  1126. *old_val = val;
  1127. } else {
  1128. t!("Rejected stale draw_call {key}: {val:?}");
  1129. if DEBUG_TRAX {
  1130. get_trax().lock().put_stat(2);
  1131. }
  1132. }
  1133. }
  1134. None => {
  1135. self.draw_calls.insert(key, val);
  1136. if DEBUG_TRAX {
  1137. get_trax().lock().put_stat(1);
  1138. }
  1139. }
  1140. }
  1141. }
  1142. }
  1143. fn trax_method(&self, epoch: EpochIndex, method: &GraphicsMethod) {
  1144. let mut trax = get_trax().lock();
  1145. match method {
  1146. GraphicsMethod::NewTexture((_, _, _, gtex_id, tag)) => {
  1147. trax.put_tex(epoch, *gtex_id, *tag);
  1148. }
  1149. GraphicsMethod::DeleteTexture((gtex_id, tag)) => {
  1150. trax.del_tex(epoch, *gtex_id, *tag);
  1151. }
  1152. GraphicsMethod::NewVertexBuffer((verts, gbuff_id, tag)) => {
  1153. trax.put_verts(epoch, verts.clone(), *gbuff_id, *tag, 0);
  1154. }
  1155. GraphicsMethod::NewIndexBuffer((idxs, gbuff_id, tag)) => {
  1156. trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  1157. }
  1158. GraphicsMethod::DeleteBuffer((gbuff_id, tag, buftype)) => {
  1159. trax.del_buf(epoch, *gbuff_id, *tag, *buftype);
  1160. }
  1161. GraphicsMethod::NewSeqAnim { .. } => {
  1162. //trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  1163. }
  1164. GraphicsMethod::UpdateSeqAnim { .. } => {
  1165. //trax.put_idxs(epoch, idxs.clone(), *gbuff_id, *tag, 1);
  1166. }
  1167. GraphicsMethod::DeleteSeqAnim(..) => {
  1168. //trax.del_buf(epoch, *gbuff_id, *tag, *buftype);
  1169. }
  1170. GraphicsMethod::ReplaceGfxDrawCalls { batch_id, dcs } => {
  1171. trax.put_dcs(epoch, *batch_id, dcs);
  1172. }
  1173. GraphicsMethod::StartBatch { batch_id, tag } => {
  1174. trax.put_start_batch(epoch, *batch_id, *tag);
  1175. }
  1176. GraphicsMethod::EndBatch { batch_id, timest: _ } => {
  1177. trax.put_end_batch(epoch, *batch_id);
  1178. }
  1179. GraphicsMethod::Noop => panic!("noop"),
  1180. };
  1181. }
  1182. fn egl_ctx_is_disabled(&self) -> bool {
  1183. #[cfg(target_os = "android")]
  1184. {
  1185. let egl_ctx = unsafe { (self.libegl.eglGetCurrentContext)() };
  1186. egl_ctx.is_null()
  1187. }
  1188. #[cfg(not(target_os = "android"))]
  1189. false
  1190. }
  1191. #[instrument(skip_all, target = "gfx::process")]
  1192. fn process_methods(&mut self) {
  1193. // Process as many methods as we can
  1194. let methods = std::mem::take(&mut *self.method_queue.lock());
  1195. for (epoch, method) in methods {
  1196. if DEBUG_TRAX {
  1197. self.trax_method(epoch, &method);
  1198. }
  1199. if epoch < self.epoch {
  1200. if DEBUG_TRAX {
  1201. let mut trax = get_trax().lock();
  1202. trax.put_stat(1);
  1203. trax.flush();
  1204. }
  1205. // Discard old rubbish
  1206. t!(
  1207. "Discard method with old epoch: {epoch} curr: {} [method={method:?}]",
  1208. self.epoch
  1209. );
  1210. continue
  1211. }
  1212. assert_eq!(epoch, self.epoch);
  1213. self.process_method(method);
  1214. if DEBUG_TRAX {
  1215. get_trax().lock().flush();
  1216. }
  1217. }
  1218. }
  1219. #[instrument(skip_all, target = "gfx::pruner")]
  1220. fn prime_screen(&mut self) {
  1221. let methods = self.pruner.recv_all();
  1222. assert!(self.pending_batches.is_empty());
  1223. // Process all cached methods by the pruner from while the screen was off.
  1224. for method in methods {
  1225. // Stale methods will be dropped by pruner, so they will not be caught by trax
  1226. // while the screen is off.
  1227. if DEBUG_TRAX {
  1228. self.trax_method(self.epoch, &method);
  1229. }
  1230. // We discard batches here but process_method uses them so implement this
  1231. // workaround.
  1232. match method {
  1233. GraphicsMethod::NewTexture(_) |
  1234. GraphicsMethod::DeleteTexture(_) |
  1235. GraphicsMethod::NewVertexBuffer(_) |
  1236. GraphicsMethod::NewIndexBuffer(_) |
  1237. GraphicsMethod::DeleteBuffer(_) |
  1238. GraphicsMethod::NewSeqAnim { .. } |
  1239. GraphicsMethod::UpdateSeqAnim { .. } |
  1240. GraphicsMethod::DeleteSeqAnim(_) => self.process_method(method),
  1241. GraphicsMethod::ReplaceGfxDrawCalls { .. } |
  1242. GraphicsMethod::StartBatch { .. } |
  1243. GraphicsMethod::EndBatch { .. } => {
  1244. panic!("unsupported pruned methods should be dropped!")
  1245. }
  1246. GraphicsMethod::Noop => panic!("noop"),
  1247. }
  1248. if DEBUG_TRAX {
  1249. get_trax().lock().flush();
  1250. }
  1251. }
  1252. // Trigger a full screen redraw by sending a resize event
  1253. let (width, height) = miniquad::window::screen_size();
  1254. self.event_pub.notify_resize(Dimension::from([width, height]));
  1255. }
  1256. fn close_pending_batches(&mut self) {
  1257. // Immediately apply any pending batches when the screen is switched off
  1258. let batch_ids: Vec<_> = self.pending_batches.keys().cloned().collect();
  1259. if !batch_ids.is_empty() {
  1260. t!("Force closing pending batches: {batch_ids:?}");
  1261. }
  1262. for batch_id in batch_ids {
  1263. self.process_method(GraphicsMethod::EndBatch { batch_id, timest: unixtime() });
  1264. if !self.dropped_batches.insert(batch_id) {
  1265. panic!("dropped batch {batch_id} already exits!");
  1266. }
  1267. }
  1268. assert!(self.pending_batches.is_empty());
  1269. }
  1270. fn start_refresh_task(&mut self) {
  1271. #[cfg(target_os = "android")]
  1272. {
  1273. assert!(self.refresh_task.is_none());
  1274. // For animations do periodic refresh every 40 ms
  1275. self.refresh_task = Some(self.ex.spawn(async move {
  1276. loop {
  1277. darkfi::system::msleep(40).await;
  1278. miniquad::window::schedule_update();
  1279. }
  1280. }));
  1281. }
  1282. }
  1283. }
  1284. struct PendingAnim {
  1285. new_method: GraphicsMethod,
  1286. updates: HashMap<usize, GraphicsMethod>,
  1287. }
  1288. /// This is used to process the method queue while the screen is off to avoid the queue
  1289. /// becoming congested and using up all the memory.
  1290. /// Will drop alloc/delete pairs, and merge draw calls together.
  1291. struct PruneMethodHeap {
  1292. /// Newly allocated buffers while screen was off
  1293. new_buf: HashMap<BufferId, GraphicsMethod>,
  1294. /// Newly allocated textures while screen was off
  1295. new_tex: HashMap<TextureId, GraphicsMethod>,
  1296. /// Deleted objects
  1297. del: Vec<GraphicsMethod>,
  1298. new_anim: HashMap<AnimId, PendingAnim>,
  1299. /// Existing anim updates
  1300. anim_updates: HashMap<AnimId, HashMap<usize, GraphicsMethod>>,
  1301. /// Existing anim deletes
  1302. anim_deletes: HashSet<AnimId>,
  1303. epoch: EpochIndex,
  1304. textures: *const HashMap<TextureId, miniquad::TextureId>,
  1305. buffers: *const HashMap<BufferId, miniquad::BufferId>,
  1306. anims: *const HashMap<AnimId, GfxSeqAnim>,
  1307. dropped_batches: *mut HashSet<BatchGuardId>,
  1308. }
  1309. impl PruneMethodHeap {
  1310. fn new(epoch: EpochIndex) -> Self {
  1311. Self {
  1312. new_buf: HashMap::new(),
  1313. new_tex: HashMap::new(),
  1314. del: vec![],
  1315. new_anim: HashMap::new(),
  1316. anim_updates: HashMap::new(),
  1317. anim_deletes: HashSet::new(),
  1318. epoch,
  1319. textures: std::ptr::null(),
  1320. buffers: std::ptr::null(),
  1321. anims: std::ptr::null(),
  1322. dropped_batches: std::ptr::null_mut(),
  1323. }
  1324. }
  1325. #[instrument(skip_all, target = "gfx::pruner")]
  1326. fn drain(&mut self, methods: Vec<(EpochIndex, GraphicsMethod)>) {
  1327. // Process as many methods as we can
  1328. for (epoch, method) in methods {
  1329. if epoch < self.epoch {
  1330. // Discard old rubbish
  1331. t!(
  1332. "Discard method with old epoch: {epoch} curr: {} [method={method:?}]",
  1333. self.epoch
  1334. );
  1335. continue
  1336. }
  1337. assert_eq!(epoch, self.epoch);
  1338. self.process_method(method);
  1339. }
  1340. }
  1341. fn process_method(&mut self, mut method: GraphicsMethod) {
  1342. match &method {
  1343. GraphicsMethod::NewTexture((_, _, _, gtex_id, _)) => {
  1344. if DEBUG_GFXAPI {
  1345. t!("Prune method: new_texture(..., {gtex_id})");
  1346. }
  1347. self.new_tex.insert(*gtex_id, std::mem::take(&mut method));
  1348. }
  1349. GraphicsMethod::DeleteTexture((gtex_id, _)) => {
  1350. if DEBUG_GFXAPI {
  1351. t!("Prune method: delete_texture(..., {gtex_id})");
  1352. }
  1353. if self.new_tex.remove(&gtex_id).is_none() {
  1354. if !self.textures().contains_key(&gtex_id) {
  1355. panic!("delete_texture missing ID {gtex_id} in pruner")
  1356. }
  1357. let method = std::mem::take(&mut method);
  1358. self.del.push(method);
  1359. } else if DEBUG_GFXAPI {
  1360. t!("Discard ellided texture {gtex_id}");
  1361. }
  1362. }
  1363. GraphicsMethod::NewVertexBuffer((_, gbuff_id, _)) => {
  1364. if DEBUG_GFXAPI {
  1365. t!("Prune method: new_vertex_buffer(..., {gbuff_id})");
  1366. }
  1367. self.new_buf.insert(*gbuff_id, std::mem::take(&mut method));
  1368. }
  1369. GraphicsMethod::NewIndexBuffer((_, gbuff_id, _)) => {
  1370. if DEBUG_GFXAPI {
  1371. t!("Prune method: new_index_buffer(..., {gbuff_id})");
  1372. }
  1373. self.new_buf.insert(*gbuff_id, std::mem::take(&mut method));
  1374. }
  1375. GraphicsMethod::DeleteBuffer((gbuff_id, _, _)) => {
  1376. if DEBUG_GFXAPI {
  1377. t!("Prune method: delete_buffer(..., {gbuff_id})");
  1378. }
  1379. if self.new_buf.remove(&gbuff_id).is_none() {
  1380. if !self.buffers().contains_key(&gbuff_id) {
  1381. panic!("delete_buffer missing ID {gbuff_id} in pruner")
  1382. }
  1383. let method = std::mem::take(&mut method);
  1384. self.del.push(method);
  1385. } else if DEBUG_GFXAPI {
  1386. t!("Discard ellided buffer {gbuff_id}");
  1387. }
  1388. }
  1389. GraphicsMethod::NewSeqAnim { id, .. } => {
  1390. self.new_anim.insert(
  1391. *id,
  1392. PendingAnim {
  1393. updates: HashMap::new(),
  1394. new_method: std::mem::take(&mut method),
  1395. },
  1396. );
  1397. }
  1398. GraphicsMethod::UpdateSeqAnim { id, frame_idx, .. } => {
  1399. if let Some(pending) = self.new_anim.get_mut(id) {
  1400. pending.updates.insert(*frame_idx, method);
  1401. } else if self.anims().contains_key(id) {
  1402. self.anim_updates.entry(*id).or_default().insert(*frame_idx, method);
  1403. } else {
  1404. panic!("UpdateSeqAnim for unknown anim {id}");
  1405. }
  1406. }
  1407. GraphicsMethod::DeleteSeqAnim((id, _)) => {
  1408. if self.new_anim.remove(id).is_some() {
  1409. } else if self.anims().contains_key(id) {
  1410. self.anim_deletes.insert(*id);
  1411. self.anim_updates.remove(id);
  1412. } else {
  1413. panic!("DeleteSeqAnim for unknown anim {id}");
  1414. }
  1415. }
  1416. GraphicsMethod::ReplaceGfxDrawCalls { .. } => {}
  1417. // Discard batches since we will apply everything all at once anyway
  1418. // once the screen is switched on.
  1419. GraphicsMethod::StartBatch { batch_id, tag } => {
  1420. t!("Pruner drop start batch {batch_id} debug={tag:?}");
  1421. if !self.dropped_batches().insert(*batch_id) {
  1422. panic!("dropped batch {batch_id} already exits!");
  1423. }
  1424. }
  1425. GraphicsMethod::EndBatch { batch_id, timest: _ } => {
  1426. t!("Pruner drop end batch {batch_id}");
  1427. // Should have already been dropped previously
  1428. assert!(self.dropped_batches().contains(batch_id));
  1429. }
  1430. GraphicsMethod::Noop => panic!("noop"),
  1431. }
  1432. }
  1433. fn textures(&self) -> &HashMap<TextureId, miniquad::TextureId> {
  1434. assert!(!self.textures.is_null());
  1435. unsafe { &*self.textures }
  1436. }
  1437. fn buffers(&self) -> &HashMap<BufferId, miniquad::BufferId> {
  1438. assert!(!self.buffers.is_null());
  1439. unsafe { &*self.buffers }
  1440. }
  1441. fn anims(&self) -> &HashMap<AnimId, GfxSeqAnim> {
  1442. assert!(!self.anims.is_null());
  1443. unsafe { &*self.anims }
  1444. }
  1445. fn dropped_batches(&mut self) -> &mut HashSet<BatchGuardId> {
  1446. assert!(!self.dropped_batches.is_null());
  1447. unsafe { &mut *self.dropped_batches }
  1448. }
  1449. /// Collect everything now the screen is on
  1450. fn recv_all(&mut self) -> Vec<GraphicsMethod> {
  1451. // Inhale that smoke deep
  1452. let mut meth = Vec::with_capacity(
  1453. self.new_buf.len() +
  1454. self.new_tex.len() +
  1455. self.del.len() +
  1456. self.new_anim.len() +
  1457. self.anim_updates.len() +
  1458. self.anim_deletes.len(),
  1459. );
  1460. self.drain_resources(&mut meth);
  1461. self.drain_anims(&mut meth);
  1462. meth
  1463. }
  1464. fn drain_resources(&mut self, meth: &mut Vec<GraphicsMethod>) {
  1465. let new_buf = std::mem::take(&mut self.new_buf);
  1466. let new_tex = std::mem::take(&mut self.new_tex);
  1467. meth.extend(new_buf.into_values());
  1468. meth.extend(new_tex.into_values());
  1469. meth.append(&mut self.del);
  1470. }
  1471. fn drain_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
  1472. self.drain_pending_anims(meth);
  1473. self.drain_live_anims(meth);
  1474. }
  1475. fn drain_pending_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
  1476. for (_id, pending) in std::mem::take(&mut self.new_anim) {
  1477. meth.push(pending.new_method);
  1478. let mut updates: Vec<_> = pending.updates.into_iter().collect();
  1479. updates.sort_by_key(|(idx, _)| *idx);
  1480. for (_, update) in updates {
  1481. meth.push(update);
  1482. }
  1483. }
  1484. }
  1485. fn drain_live_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
  1486. let mut updates: Vec<_> = self
  1487. .anim_updates
  1488. .drain()
  1489. .flat_map(|(anim_id, frame_updates)| {
  1490. let mut sorted: Vec<_> = frame_updates.into_iter().collect();
  1491. sorted.sort_by_key(|(idx, _)| *idx);
  1492. sorted.into_iter().map(move |(idx, update)| (anim_id, idx, update))
  1493. })
  1494. .collect();
  1495. updates.sort_by_key(|(anim_id, idx, _)| (*anim_id, *idx));
  1496. for (_, _, update) in updates {
  1497. meth.push(update);
  1498. }
  1499. for id in std::mem::take(&mut self.anim_deletes) {
  1500. meth.push(GraphicsMethod::DeleteSeqAnim((id, None)));
  1501. }
  1502. }
  1503. }
  1504. #[derive(Copy, Clone, Debug, PartialEq)]
  1505. enum ScreenState {
  1506. // Screen is on as normal
  1507. On,
  1508. // First update since screen has gone off
  1509. SwitchOff,
  1510. // Subsequent updates after SwitchOff state
  1511. Off,
  1512. // First update when screen is on but before draw has been called
  1513. ReadyOn,
  1514. // First update and draw has been called
  1515. PrimedOn,
  1516. // Second update ready to process pruned buffered allocs
  1517. SwitchOn,
  1518. }
  1519. impl ScreenState {
  1520. fn update(&mut self, egl_is_disabled: bool) {
  1521. use ScreenState::*;
  1522. *self = if egl_is_disabled {
  1523. match self {
  1524. On | ReadyOn | PrimedOn | SwitchOn => SwitchOff,
  1525. SwitchOff => Off,
  1526. Off => Off,
  1527. }
  1528. } else {
  1529. match self {
  1530. SwitchOff | Off => ReadyOn,
  1531. ReadyOn => PrimedOn,
  1532. PrimedOn => SwitchOn,
  1533. SwitchOn => On,
  1534. On => On,
  1535. }
  1536. };
  1537. }
  1538. }
  1539. impl EventHandler for Stage {
  1540. fn update(&mut self) {
  1541. // todo: trax is all messed up in this func
  1542. let old_screen_state = self.screen_state;
  1543. self.screen_state.update(self.egl_ctx_is_disabled());
  1544. if self.screen_state != old_screen_state {
  1545. d!("Switching screen state {old_screen_state:?} => {:?}", self.screen_state);
  1546. }
  1547. match self.screen_state {
  1548. ScreenState::SwitchOff => {
  1549. #[cfg(target_os = "android")]
  1550. {
  1551. self.refresh_task = None;
  1552. }
  1553. self.close_pending_batches();
  1554. // Screen is off so collect all methods into the pruner
  1555. let methods = std::mem::take(&mut *self.method_queue.lock());
  1556. self.pruner.drain(methods);
  1557. }
  1558. ScreenState::Off => {
  1559. #[cfg(target_os = "android")]
  1560. {
  1561. assert!(self.refresh_task.is_none());
  1562. }
  1563. assert!(self.pending_batches.is_empty());
  1564. // Screen is off so collect all methods into the pruner
  1565. let methods = std::mem::take(&mut *self.method_queue.lock());
  1566. self.pruner.drain(methods);
  1567. }
  1568. ScreenState::ReadyOn => {
  1569. self.start_refresh_task();
  1570. // We actually want to skip draining the prune queue the first time so
  1571. // miniquad draw() actually gets a chance to be called first.
  1572. // Otherwise we will see a black screen for a sec or so while update() is running.
  1573. }
  1574. ScreenState::PrimedOn => {
  1575. #[cfg(target_os = "android")]
  1576. {
  1577. assert!(self.refresh_task.is_some());
  1578. }
  1579. self.prime_screen();
  1580. }
  1581. ScreenState::SwitchOn => {
  1582. #[cfg(target_os = "android")]
  1583. {
  1584. assert!(self.refresh_task.is_some());
  1585. }
  1586. // This should have been cleared in previous PrimedOn state
  1587. let methods = self.pruner.recv_all();
  1588. assert!(methods.is_empty());
  1589. self.process_methods();
  1590. }
  1591. ScreenState::On => {
  1592. #[cfg(target_os = "android")]
  1593. {
  1594. assert!(self.refresh_task.is_some());
  1595. }
  1596. self.process_methods();
  1597. }
  1598. }
  1599. }
  1600. fn draw(&mut self) {
  1601. self.ctx.begin_default_pass(PassAction::clear_color(0., 0., 0., 1.));
  1602. self.ctx.apply_pipeline(&self.pipeline);
  1603. // This will make the top left (0, 0) and the bottom right (1, 1)
  1604. // Default is (-1, 1) -> (1, -1)
  1605. let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
  1606. glam::Mat4::from_scale(glam::Vec3::new(2., -2., 1.));
  1607. let mut uniforms_data = [0u8; 128];
  1608. let data: [u8; 64] = unsafe { std::mem::transmute_copy(&proj) };
  1609. uniforms_data[0..64].copy_from_slice(&data);
  1610. //let data: [u8; 64] = unsafe { std::mem::transmute_copy(&model) };
  1611. //uniforms_data[64..].copy_from_slice(&data);
  1612. assert_eq!(128, 2 * UniformType::Mat4.size());
  1613. let (screen_w, screen_h) = miniquad::window::screen_size();
  1614. // Mark all anims as invisible
  1615. for (_, anim) in self.anims.iter_mut() {
  1616. anim.is_visible = false;
  1617. }
  1618. let mut render_ctx = RenderContext {
  1619. ctx: &mut self.ctx,
  1620. draw_calls: &self.draw_calls,
  1621. uniforms_data,
  1622. white_texture: self.white_texture,
  1623. scale: 1.,
  1624. view: Rectangle::from([0., 0., screen_w, screen_h]),
  1625. cursor: Point::from([0., 0.]),
  1626. anims: &mut self.anims,
  1627. };
  1628. render_ctx.draw();
  1629. self.ctx.end_render_pass();
  1630. self.ctx.commit_frame();
  1631. }
  1632. fn resize_event(&mut self, width: f32, height: f32) {
  1633. t!("resize_event({width}, {height})");
  1634. let filename = get_window_size_filename();
  1635. if let Some(parent) = filename.parent() {
  1636. let _ = std::fs::create_dir_all(parent);
  1637. }
  1638. if let Ok(mut file) = File::create(filename) {
  1639. (width as i32).encode(&mut file).unwrap();
  1640. (height as i32).encode(&mut file).unwrap();
  1641. }
  1642. self.event_pub.notify_resize(Dimension::from([width, height]));
  1643. }
  1644. fn key_down_event(&mut self, keycode: KeyCode, mods: KeyMods, repeat: bool) {
  1645. self.event_pub.notify_key_down(keycode, mods, repeat);
  1646. }
  1647. fn key_up_event(&mut self, keycode: KeyCode, mods: KeyMods) {
  1648. self.event_pub.notify_key_up(keycode, mods);
  1649. }
  1650. fn char_event(&mut self, chr: char, mods: KeyMods, repeat: bool) {
  1651. self.event_pub.notify_char(chr, mods, repeat);
  1652. }
  1653. fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
  1654. let pos = Point::from([x, y]);
  1655. self.event_pub.notify_mouse_btn_down(button, pos);
  1656. }
  1657. fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
  1658. let pos = Point::from([x, y]);
  1659. self.event_pub.notify_mouse_btn_up(button, pos);
  1660. }
  1661. fn mouse_motion_event(&mut self, x: f32, y: f32) {
  1662. let pos = Point::from([x, y]);
  1663. self.event_pub.notify_mouse_move(pos);
  1664. }
  1665. fn mouse_wheel_event(&mut self, x: f32, y: f32) {
  1666. let pos = Point::from([x, y]);
  1667. self.event_pub.notify_mouse_wheel(pos);
  1668. }
  1669. /// The id corresponds to multi-touch. Multiple touch events have different ids.
  1670. fn touch_event(&mut self, phase: TouchPhase, id: u64, x: f32, y: f32) {
  1671. let pos = Point::from([x, y]);
  1672. self.event_pub.notify_touch(phase, id, pos);
  1673. }
  1674. fn quit_requested_event(&mut self) {
  1675. debug!(target: "gfx", "quit requested");
  1676. let god = GOD.get().unwrap();
  1677. god.stop_app();
  1678. }
  1679. }
  1680. pub fn run_gui(linux_backend: miniquad::conf::LinuxBackend) {
  1681. let mut window_width = 1024;
  1682. let mut window_height = 768;
  1683. if let Ok(mut file) = File::open(get_window_size_filename()) {
  1684. window_width = Decodable::decode(&mut file).unwrap();
  1685. window_height = Decodable::decode(&mut file).unwrap();
  1686. }
  1687. debug!(target: "gfx", "Window size {window_width} x {window_height}");
  1688. let mut conf = miniquad::conf::Conf {
  1689. window_title: "DarkFi".to_string(),
  1690. window_width,
  1691. window_height,
  1692. high_dpi: true,
  1693. window_resizable: true,
  1694. platform: miniquad::conf::Platform {
  1695. linux_backend,
  1696. #[cfg(target_os = "android")]
  1697. blocking_event_loop: true,
  1698. android_panic_hook: false,
  1699. ..Default::default()
  1700. },
  1701. icon: Some(miniquad::conf::Icon {
  1702. small: favico::SMALL,
  1703. medium: favico::MEDIUM,
  1704. big: favico::BIG,
  1705. }),
  1706. ..Default::default()
  1707. };
  1708. let metal = std::env::args().nth(1).as_deref() == Some("metal");
  1709. conf.platform.apple_gfx_api =
  1710. if metal { conf::AppleGfxApi::Metal } else { conf::AppleGfxApi::OpenGl };
  1711. miniquad::start(conf, || Box::new(Stage::new()));
  1712. }