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 }