]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_trace_file_reader.h
Initial vogl checkin
[vogl] / src / voglcommon / vogl_trace_file_reader.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_trace_file_reader.h
27 #ifndef VOGL_TRACE_FILE_READER_H
28 #define VOGL_TRACE_FILE_READER_H
29
30 #include "vogl_common.h"
31 #include "vogl_trace_stream_types.h"
32 #include "vogl_trace_packet.h"
33 #include "vogl_cfile_stream.h"
34 #include "vogl_dynamic_stream.h"
35 #include "vogl_json.h"
36
37 //----------------------------------------------------------------------------------------------------------------------
38 // class vogl_trace_packet_array
39 //----------------------------------------------------------------------------------------------------------------------
40 typedef vogl::vector<uint8_vec> vogl_packet_buf_vec;
41
42 class vogl_trace_packet_array
43 {
44 public:
45     vogl_trace_packet_array()
46     {
47     }
48
49     void clear()
50     {
51         m_packets.clear();
52     }
53
54     void resize(uint new_size)
55     {
56         m_packets.resize(new_size);
57     }
58     void reserve(uint new_capacity)
59     {
60         m_packets.reserve(new_capacity);
61     }
62
63     uint size() const
64     {
65         return m_packets.size();
66     }
67     bool is_empty() const
68     {
69         return m_packets.is_empty();
70     }
71
72     void push_back(const uint8_vec &packet)
73     {
74         m_packets.push_back(packet);
75     }
76
77     void insert(uint index, const uint8_vec &packet)
78     {
79         m_packets.insert(index, packet);
80     }
81
82     void erase(uint index)
83     {
84         m_packets.erase(index);
85     }
86
87     void swap(vogl_trace_packet_array &other)
88     {
89         m_packets.swap(other.m_packets);
90     }
91
92     const vogl_packet_buf_vec &get_vec() const
93     {
94         return m_packets;
95     }
96     vogl_packet_buf_vec &get_vec()
97     {
98         return m_packets;
99     }
100
101     const uint8_vec &get_packet_buf(uint index) const
102     {
103         return m_packets[index];
104     }
105     uint8_vec &get_packet_buf(uint index)
106     {
107         return m_packets[index];
108     }
109
110     template <typename T>
111     inline const T &get_packet(uint index) const
112     {
113         VOGL_ASSERT(m_packets[index].size() >= sizeof(T));
114         return *reinterpret_cast<const T *>(m_packets[index].get_ptr());
115     }
116
117     inline const vogl_trace_stream_packet_base &get_base_packet(uint index) const
118     {
119         return get_packet<vogl_trace_stream_packet_base>(index);
120     }
121
122     inline vogl_trace_stream_packet_types_t get_packet_type(uint index) const
123     {
124         return static_cast<vogl_trace_stream_packet_types_t>(get_base_packet(index).m_type);
125     }
126     inline uint get_packet_size(uint index) const
127     {
128         return m_packets[index].size();
129     }
130
131     inline bool is_eof_packet(uint index) const
132     {
133         VOGL_FUNC_TRACER
134
135         return (get_packet_type(index) == cTSPTEOF);
136     }
137
138     inline bool is_swap_buffers_packet(uint index) const
139     {
140         VOGL_FUNC_TRACER
141
142         if (get_packet_type(index) == cTSPTGLEntrypoint)
143         {
144             const vogl_trace_gl_entrypoint_packet &gl_packet = get_packet<vogl_trace_gl_entrypoint_packet>(index);
145             return vogl_is_swap_buffers_entrypoint(static_cast<gl_entrypoint_id_t>(gl_packet.m_entrypoint_id));
146         }
147         return false;
148     }
149
150 private:
151     vogl_packet_buf_vec m_packets;
152 };
153
154 //----------------------------------------------------------------------------------------------------------------------
155 // enum trace_file_reader_type_t
156 //----------------------------------------------------------------------------------------------------------------------
157 enum vogl_trace_file_reader_type_t
158 {
159     cINVALID_TRACE_FILE_READER,
160     cBINARY_TRACE_FILE_READER,
161     cJSON_TRACE_FILE_READER,
162     cTOTAL_TRACE_FILE_READERS
163 };
164
165 //----------------------------------------------------------------------------------------------------------------------
166 // class trace_file_reader
167 //----------------------------------------------------------------------------------------------------------------------
168 class vogl_trace_file_reader
169 {
170     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_trace_file_reader);
171
172 public:
173     vogl_trace_file_reader()
174     {
175         VOGL_FUNC_TRACER
176
177         utils::zero_object(m_sof_packet);
178
179         m_multi_blob_manager.init(cBMFReadable | cBMFOpenExisting);
180
181         m_multi_blob_manager.add_blob_manager(&m_loose_file_blob_manager);
182         m_multi_blob_manager.add_blob_manager(&m_archive_blob_manager);
183     }
184
185     virtual ~vogl_trace_file_reader()
186     {
187     }
188
189     virtual bool open(const char *pFilename, const char *pLoose_file_path) = 0;
190
191     virtual bool is_opened() = 0;
192     virtual const char *get_filename() = 0;
193
194     virtual void close()
195     {
196         VOGL_FUNC_TRACER
197
198         utils::zero_object(m_sof_packet);
199         m_packet_buf.clear();
200         m_loose_file_blob_manager.deinit();
201         m_archive_blob_manager.deinit();
202     }
203
204     virtual vogl_trace_file_reader_type_t get_type() const = 0;
205
206     virtual const vogl_trace_stream_start_of_file_packet &get_sof_packet() const
207     {
208         VOGL_FUNC_TRACER return m_sof_packet;
209     }
210
211     virtual bool is_at_eof() = 0;
212
213     virtual bool can_quickly_seek_forward() const = 0;
214
215     virtual uint get_cur_frame() const = 0;
216
217     // Allows random seeking, but it can be very slow to seek forward in binary traces.
218     virtual bool seek_to_frame(uint frame_index) = 0;
219
220     virtual int64_t get_max_frame_index() = 0;
221
222     virtual bool push_location() = 0;
223     virtual bool pop_location() = 0;
224
225     enum trace_file_reader_status_t
226     {
227         cFailed = -1,
228         cOK,
229         cEOF
230     };
231
232     // Notes: Be careful handling cEOF/eof packets.
233     // The last packet MAY be an EOF packet, or not if the trace terminated before it could be flushed.
234     // So you need to check for both the cEOF return status and if the packet is EOF.
235     // Be sure to test with both JSON and binary readers because with JSON files you'll always just get a cEOF return
236     // status at EOF (and never see an actual EOF packet), while with binary you can get both types of behavior.
237     // Also, for binary traces: just because you get an EOF packet doesn't necessarily mean that cEOF will be returned next (the file could somehow be corrupted).
238     virtual trace_file_reader_status_t read_next_packet() = 0;
239
240     virtual trace_file_reader_status_t read_frame_packets(uint frame_index, uint num_frames, vogl_trace_packet_array &packets, uint &actual_frames_read);
241
242     // packet helpers
243
244     const uint8_vec &get_packet_buf() const
245     {
246         return m_packet_buf;
247     }
248
249     template <typename T>
250     inline const T &get_packet() const
251     {
252         VOGL_ASSERT(m_packet_buf.size() >= sizeof(T));
253         return *reinterpret_cast<const T *>(m_packet_buf.get_ptr());
254     }
255
256     inline const vogl_trace_stream_packet_base &get_base_packet() const
257     {
258         return get_packet<vogl_trace_stream_packet_base>();
259     }
260
261     inline vogl_trace_stream_packet_types_t get_packet_type() const
262     {
263         return static_cast<vogl_trace_stream_packet_types_t>(get_base_packet().m_type);
264     }
265     inline uint get_packet_size() const
266     {
267         return m_packet_buf.size();
268     }
269
270     inline bool is_eof_packet() const
271     {
272         VOGL_FUNC_TRACER
273
274         return (get_packet_type() == cTSPTEOF);
275     }
276
277     inline bool is_swap_buffers_packet() const
278     {
279         VOGL_FUNC_TRACER
280
281         if (get_packet_type() == cTSPTGLEntrypoint)
282         {
283             const vogl_trace_gl_entrypoint_packet &gl_packet = get_packet<vogl_trace_gl_entrypoint_packet>();
284             return vogl_is_swap_buffers_entrypoint(static_cast<gl_entrypoint_id_t>(gl_packet.m_entrypoint_id));
285         }
286         return false;
287     }
288
289     const vogl_multi_blob_manager &get_multi_blob_manager() const
290     {
291         return m_multi_blob_manager;
292     }
293     vogl_multi_blob_manager &get_multi_blob_manager()
294     {
295         return m_multi_blob_manager;
296     }
297
298     const vogl_loose_file_blob_manager &get_loose_file_blob_manager() const
299     {
300         return m_loose_file_blob_manager;
301     }
302     vogl_loose_file_blob_manager &get_loose_file_blob_manager()
303     {
304         return m_loose_file_blob_manager;
305     }
306
307     const vogl_archive_blob_manager &get_archive_blob_manager() const
308     {
309         return m_archive_blob_manager;
310     }
311     vogl_archive_blob_manager &get_archive_blob_manager()
312     {
313         return m_archive_blob_manager;
314     }
315
316 protected:
317     vogl_trace_stream_start_of_file_packet m_sof_packet;
318
319     uint8_vec m_packet_buf;
320
321     vogl_loose_file_blob_manager m_loose_file_blob_manager;
322     vogl_archive_blob_manager m_archive_blob_manager;
323     vogl_multi_blob_manager m_multi_blob_manager;
324
325     void create_eof_packet();
326     bool init_loose_file_blob_manager(const char *pTrace_filename, const char *pLoose_file_path);
327 };
328
329 //----------------------------------------------------------------------------------------------------------------------
330 // class vogl_scoped_location_saver
331 //----------------------------------------------------------------------------------------------------------------------
332 class vogl_scoped_location_saver
333 {
334     vogl_trace_file_reader &m_reader;
335
336 public:
337     vogl_scoped_location_saver(vogl_trace_file_reader &reader)
338         : m_reader(reader)
339     {
340         m_reader.push_location();
341     }
342     ~vogl_scoped_location_saver()
343     {
344         m_reader.pop_location();
345     }
346 };
347
348 //----------------------------------------------------------------------------------------------------------------------
349 // class binary_trace_file_reader
350 //----------------------------------------------------------------------------------------------------------------------
351 class vogl_binary_trace_file_reader : public vogl_trace_file_reader
352 {
353     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_binary_trace_file_reader);
354
355 public:
356     vogl_binary_trace_file_reader();
357
358     const data_stream &get_stream() const
359     {
360         return m_trace_stream;
361     }
362     data_stream &get_stream()
363     {
364         return m_trace_stream;
365     }
366
367     virtual ~vogl_binary_trace_file_reader();
368
369     virtual bool open(const char *pFilename, const char *pLoose_file_path);
370
371     virtual bool is_opened();
372     virtual const char *get_filename();
373
374     virtual void close();
375
376     virtual vogl_trace_file_reader_type_t get_type() const
377     {
378         return cBINARY_TRACE_FILE_READER;
379     }
380
381     virtual bool is_at_eof();
382
383     virtual bool can_quickly_seek_forward() const
384     {
385         return m_found_frame_file_offsets_packet;
386     }
387
388     virtual uint get_cur_frame() const
389     {
390         return m_cur_frame_index;
391     }
392
393     virtual bool seek_to_frame(uint frame_index);
394
395     virtual int64_t get_max_frame_index();
396
397     virtual bool push_location();
398     virtual bool pop_location();
399
400     uint64_t get_trace_file_size() const
401     {
402         return m_trace_file_size;
403     }
404     inline uint64_t get_cur_file_ofs()
405     {
406         return m_trace_stream.get_ofs();
407     }
408     inline bool seek(uint64_t new_ofs)
409     {
410         return m_trace_stream.seek(new_ofs, false);
411     }
412
413     virtual trace_file_reader_status_t read_next_packet();
414
415 private:
416     cfile_stream m_trace_stream;
417     uint64_t m_trace_file_size;
418
419     uint m_cur_frame_index;
420     int64_t m_max_frame_index;
421     vogl::vector<uint64_t> m_frame_file_offsets;
422
423     struct saved_location
424     {
425         uint m_cur_frame_index;
426         uint64_t m_cur_ofs;
427     };
428
429     vogl::vector<saved_location> m_saved_location_stack;
430
431     bool read_frame_file_offsets();
432
433     bool m_found_frame_file_offsets_packet;
434 };
435
436 //----------------------------------------------------------------------------------------------------------------------
437 // class json_trace_file_reader
438 //----------------------------------------------------------------------------------------------------------------------
439 class vogl_json_trace_file_reader : public vogl_trace_file_reader
440 {
441     VOGL_NO_COPY_OR_ASSIGNMENT_OP(vogl_json_trace_file_reader);
442
443 public:
444     vogl_json_trace_file_reader();
445
446     virtual ~vogl_json_trace_file_reader();
447
448     virtual bool open(const char *pFilename, const char *pLoose_file_path);
449
450     virtual bool is_opened();
451     virtual const char *get_filename();
452
453     virtual void close();
454
455     virtual vogl_trace_file_reader_type_t get_type() const
456     {
457         return cJSON_TRACE_FILE_READER;
458     }
459
460     virtual bool is_at_eof();
461
462     virtual bool can_quickly_seek_forward() const
463     {
464         return true;
465     }
466
467     virtual uint get_cur_frame() const
468     {
469         return m_cur_frame_index;
470     }
471
472     virtual int64_t get_max_frame_index()
473     {
474         return m_max_frame_index;
475     }
476
477     virtual bool seek_to_frame(uint frame_index);
478
479     virtual trace_file_reader_status_t read_next_packet();
480
481     virtual bool push_location();
482     virtual bool pop_location();
483
484 private:
485     dynamic_string m_filename;
486     dynamic_string m_base_filename;
487     bool m_filename_exists;
488     bool m_filename_is_in_multiframe_form;
489
490     dynamic_string m_drive;
491     dynamic_string m_dir;
492     dynamic_string m_fname;
493     dynamic_string m_ext;
494
495     dynamic_string m_cur_frame_filename;
496
497     cfile_stream m_trace_stream;
498
499     uint m_cur_frame_index;
500     uint m_max_frame_index;
501
502     json_document m_cur_doc;
503     const json_node *m_pPackets_array;
504     uint m_cur_packet_node_index;
505     uint m_packet_node_size;
506     int m_doc_eof_key_value;
507
508     bool m_at_eof;
509
510     vogl_ctypes m_trace_ctypes;
511     vogl_trace_packet m_trace_packet;
512     dynamic_stream m_dyn_stream;
513
514     struct saved_location
515     {
516         dynamic_string m_cur_frame_filename;
517         uint m_cur_frame_index;
518         uint m_cur_packet_node_index;
519         bool m_at_eof;
520     };
521
522     vogl::vector<saved_location> m_saved_location_stack;
523
524     dynamic_string compose_frame_filename();
525     bool read_document(const dynamic_string &filename);
526     bool open_first_document();
527 };
528
529 bool vogl_is_multiframe_json_trace_filename(const char *pFilename);
530 vogl_trace_file_reader_type_t vogl_determine_trace_file_type(const dynamic_string &orig_filename, dynamic_string &filename_to_use);
531 vogl_trace_file_reader *vogl_create_trace_file_reader(vogl_trace_file_reader_type_t trace_type);
532 vogl_trace_file_reader *vogl_open_trace_file(dynamic_string &orig_filename, dynamic_string &actual_filename, const char *pLoose_file_path);
533
534 #endif // VOGL_TRACE_FILE_READER_H