/ bin / app / src / gfx / trax.rs
trax.rs
  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  
 19  use darkfi_serial::Encodable;
 20  use parking_lot::Mutex as SyncMutex;
 21  use std::{fs::File, sync::OnceLock};
 22  use tracing::debug;
 23  
 24  use super::{BufferId, DebugTag, DrawCall, TextureId, Vertex};
 25  use crate::{prop::BatchGuardId, EpochIndex};
 26  
 27  macro_rules! d { ($($arg:tt)*) => { debug!(target: "gfx::trax", $($arg)*); } }
 28  
 29  pub struct Trax {
 30      file: File,
 31      buf: Vec<u8>,
 32  }
 33  
 34  impl Trax {
 35      fn new() -> Self {
 36          #[cfg(target_os = "android")]
 37          let path = crate::android::get_external_storage_path().join("trax.dat");
 38          #[cfg(not(target_os = "android"))] // FIXME:
 39          let path = std::path::PathBuf::from(std::env::var("TMPDIR").unwrap()).join("trax.dat");
 40  
 41          let file = File::create(path).unwrap();
 42          Self { file, buf: vec![] }
 43      }
 44  
 45      pub fn clear(&mut self) {
 46          d!("clear");
 47          self.file.set_len(0).unwrap();
 48      }
 49  
 50      pub fn put_dcs(
 51          &mut self,
 52          epoch: EpochIndex,
 53          batch_id: BatchGuardId,
 54          timest: u64,
 55          dcs: &Vec<(u64, DrawCall)>,
 56      ) {
 57          d!("put_dcs({epoch}, {batch_id}, {timest}, {dcs:?})");
 58          0u8.encode(&mut self.buf).unwrap();
 59          epoch.encode(&mut self.buf).unwrap();
 60          batch_id.encode(&mut self.buf).unwrap();
 61          timest.encode(&mut self.buf).unwrap();
 62          dcs.encode(&mut self.buf).unwrap();
 63      }
 64  
 65      pub fn put_start_batch(
 66          &mut self,
 67          epoch: EpochIndex,
 68          batch_id: BatchGuardId,
 69          debug_str: Option<&'static str>,
 70      ) {
 71          d!("put_start_batch({epoch}, {batch_id})");
 72          1u8.encode(&mut self.buf).unwrap();
 73          batch_id.encode(&mut self.buf).unwrap();
 74          debug_str.encode(&mut self.buf).unwrap();
 75      }
 76  
 77      pub fn put_end_batch(&mut self, epoch: EpochIndex, batch_id: BatchGuardId) {
 78          d!("put_end_batch({epoch}, {batch_id})");
 79          2u8.encode(&mut self.buf).unwrap();
 80          batch_id.encode(&mut self.buf).unwrap();
 81      }
 82  
 83      pub fn put_tex(&mut self, epoch: EpochIndex, tex: TextureId, tag: DebugTag) {
 84          d!("put_tex({epoch}, {tex}, {tag:?})");
 85          3u8.encode(&mut self.buf).unwrap();
 86          epoch.encode(&mut self.buf).unwrap();
 87          tex.encode(&mut self.buf).unwrap();
 88          tag.encode(&mut self.buf).unwrap();
 89      }
 90      pub fn put_verts(
 91          &mut self,
 92          epoch: EpochIndex,
 93          verts: Vec<Vertex>,
 94          buf: BufferId,
 95          tag: DebugTag,
 96          buftype: u8,
 97      ) {
 98          d!("put_verts({epoch}, ..., {buf}, {tag:?}, {buftype})");
 99          4u8.encode(&mut self.buf).unwrap();
100          epoch.encode(&mut self.buf).unwrap();
101          verts.encode(&mut self.buf).unwrap();
102          buf.encode(&mut self.buf).unwrap();
103          tag.encode(&mut self.buf).unwrap();
104          buftype.encode(&mut self.buf).unwrap();
105      }
106      pub fn put_idxs(
107          &mut self,
108          epoch: EpochIndex,
109          idxs: Vec<u16>,
110          buf: BufferId,
111          tag: DebugTag,
112          buftype: u8,
113      ) {
114          d!("put_idxs({epoch}, ..., {buf}, {tag:?}, {buftype})");
115          5u8.encode(&mut self.buf).unwrap();
116          epoch.encode(&mut self.buf).unwrap();
117          idxs.encode(&mut self.buf).unwrap();
118          buf.encode(&mut self.buf).unwrap();
119          tag.encode(&mut self.buf).unwrap();
120          buftype.encode(&mut self.buf).unwrap();
121      }
122      pub fn del_tex(&mut self, epoch: EpochIndex, tex: TextureId, tag: DebugTag) {
123          d!("del_tex({epoch}, {tex}, {tag:?})");
124          6u8.encode(&mut self.buf).unwrap();
125          epoch.encode(&mut self.buf).unwrap();
126          tex.encode(&mut self.buf).unwrap();
127          tag.encode(&mut self.buf).unwrap();
128      }
129      pub fn del_buf(&mut self, epoch: EpochIndex, buf: BufferId, tag: DebugTag, buftype: u8) {
130          d!("del_buf({epoch}, {buf}, {tag:?}, {buftype})");
131          7u8.encode(&mut self.buf).unwrap();
132          epoch.encode(&mut self.buf).unwrap();
133          buf.encode(&mut self.buf).unwrap();
134          tag.encode(&mut self.buf).unwrap();
135          buftype.encode(&mut self.buf).unwrap();
136      }
137  
138      pub fn set_curr(&mut self, dc: u64) {
139          d!("set_curr({dc})");
140          8u8.encode(&mut self.buf).unwrap();
141          dc.encode(&mut self.buf).unwrap();
142          self.flush();
143      }
144      pub fn set_instr(&mut self, idx: usize) {
145          d!("set_instr({idx})");
146          9u8.encode(&mut self.buf).unwrap();
147          idx.encode(&mut self.buf).unwrap();
148          self.flush();
149      }
150  
151      pub fn put_stat(&mut self, code: u8) {
152          d!("put_stat({code})");
153          code.encode(&mut self.buf).unwrap();
154      }
155  
156      pub fn flush(&mut self) {
157          d!("flush");
158          let buf = std::mem::take(&mut self.buf);
159          if buf.is_empty() {
160              d!(" -> skipping flush");
161              return
162          }
163          buf.encode(&mut self.file).unwrap();
164      }
165  }
166  
167  static TRAX: OnceLock<SyncMutex<Trax>> = OnceLock::new();
168  
169  pub(super) fn get_trax() -> &'static SyncMutex<Trax> {
170      TRAX.get_or_init(|| SyncMutex::new(Trax::new()))
171  }