mod.rs 52 KB

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