1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 **************************************************************************/
26 //----------------------------------------------------------------------------------------------------------------------
27 // File: vogl_trace_file_writer.cpp
28 //----------------------------------------------------------------------------------------------------------------------
29 #include "vogl_trace_file_writer.h"
30 #include "vogl_console.h"
31 #include "vogl_file_utils.h"
32 #include "vogl_uuid.h"
34 //----------------------------------------------------------------------------------------------------------------------
35 // vogl_trace_file_writer
36 //----------------------------------------------------------------------------------------------------------------------
37 vogl_trace_file_writer::vogl_trace_file_writer(const vogl_ctypes *pCTypes)
38 : m_gl_call_counter(0),
40 m_pTrace_archive(NULL),
41 m_delete_archive(false)
46 vogl_trace_file_writer::~vogl_trace_file_writer()
53 // pTrace_archive may be NULL. Takes ownership of pTrace_archive.
54 // TODO: Get rid of the demarcation packet, etc. Make the initial sequence of packets more explicit.
55 bool vogl_trace_file_writer::open(const char *pFilename, vogl_archive_blob_manager *pTrace_archive, bool delete_archive, bool write_demarcation_packet, uint pointer_sizes)
64 m_filename = pFilename;
65 if (!m_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable, false))
67 vogl_error_printf("%s: Failed opening trace file \"%s\"\n", VOGL_METHOD_NAME, pFilename);
71 vogl_message_printf("%s: Prepping trace file \"%s\"\n", VOGL_METHOD_NAME, pFilename);
74 m_sof_packet.m_pointer_sizes = pointer_sizes;
75 m_sof_packet.m_first_packet_offset = sizeof(m_sof_packet);
77 md5_hash h(gen_uuid());
78 VOGL_ASSUME(sizeof(h) == sizeof(m_sof_packet.m_uuid));
79 memcpy(&m_sof_packet.m_uuid, &h, sizeof(h));
81 m_sof_packet.finalize();
82 VOGL_VERIFY(m_sof_packet.full_validation(sizeof(m_sof_packet)));
84 if (m_stream.write(&m_sof_packet, sizeof(m_sof_packet)) != sizeof(m_sof_packet))
86 vogl_error_printf("%s: Failed writing to trace file \"%s\"\n", VOGL_METHOD_NAME, pFilename);
92 m_pTrace_archive.reset(pTrace_archive);
93 m_delete_archive = delete_archive;
97 m_pTrace_archive.reset(vogl_new(vogl_archive_blob_manager));
98 m_delete_archive = true;
100 if (!m_pTrace_archive->init_file_temp(cBMFReadWrite, NULL))
102 vogl_error_printf("%s: Failed opening temp archive!\n", VOGL_METHOD_NAME);
104 m_pTrace_archive.reset();
110 // TODO: The trace reader records the first offset right after SOF, I would like to do this after the demarcation packet.
111 m_frame_file_offsets.reserve(10000);
112 m_frame_file_offsets.resize(0);
113 m_frame_file_offsets.push_back(m_stream.get_ofs());
115 write_ctypes_packet();
117 write_entrypoints_packet();
119 if (write_demarcation_packet)
121 vogl_write_glInternalTraceCommandRAD(m_stream, m_pCTypes, cITCRDemarcation, 0, NULL);
124 vogl_message_printf("%s: Finished opening trace file \"%s\"\n", VOGL_METHOD_NAME, pFilename);
129 bool vogl_trace_file_writer::close()
133 vogl_debug_printf("%s\n", VOGL_METHOD_NAME);
135 if (!m_stream.is_opened())
138 vogl_message_printf("%s: Flushing trace file %s (this could take some time), %u total frame file offsets\n", VOGL_METHOD_NAME, m_filename.get_ptr(), m_frame_file_offsets.size());
142 dynamic_string trace_archive_filename;
144 if (!write_eof_packet())
146 vogl_error_printf("%s: Failed writing to trace file \"%s\"\n", VOGL_METHOD_NAME, m_filename.get_ptr());
149 else if (m_pTrace_archive.get())
151 trace_archive_filename = m_pTrace_archive->get_archive_filename();
153 if ((!write_frame_file_offsets_to_archive()) || !m_pTrace_archive->deinit())
155 vogl_error_printf("%s: Failed closing trace archive \"%s\"!\n", VOGL_FUNCTION_NAME, trace_archive_filename.get_ptr());
160 if (!file_utils::get_file_size(trace_archive_filename.get_ptr(), m_sof_packet.m_archive_size))
162 vogl_error_printf("%s: Failed determining file size of archive file \"%s\"\n", VOGL_FUNCTION_NAME, trace_archive_filename.get_ptr());
165 else if (m_sof_packet.m_archive_size)
167 m_sof_packet.m_archive_offset = m_stream.get_size();
169 vogl_message_printf("Copying %" PRIu64 " archive bytes into output trace file\n", m_sof_packet.m_archive_size);
171 if (!m_stream.write_file_data(trace_archive_filename.get_ptr()))
173 vogl_error_printf("%s: Failed copying source archive \"%s\" into trace file!\n", VOGL_METHOD_NAME, trace_archive_filename.get_ptr());
177 m_sof_packet.m_archive_size = m_stream.get_size() - m_sof_packet.m_archive_offset;
183 m_sof_packet.finalize();
184 VOGL_VERIFY(m_sof_packet.full_validation(sizeof(m_sof_packet)));
186 if (!m_stream.seek(0, false) || (m_stream.write(&m_sof_packet, sizeof(m_sof_packet)) != sizeof(m_sof_packet)))
188 vogl_error_printf("%s: Failed writing to trace file \"%s\"\n", VOGL_METHOD_NAME, m_filename.get_ptr());
194 close_archive(trace_archive_filename.get_ptr());
196 uint64_t total_trace_file_size = m_stream.get_size();
198 if (!m_stream.close())
200 vogl_error_printf("Failed writing to or closing trace file!\n");
204 dynamic_string full_trace_filename(m_filename);
205 file_utils::full_path(full_trace_filename);
208 vogl_message_printf("%s: Successfully closed trace file %s, total file size: %s\n", VOGL_METHOD_NAME, full_trace_filename.get_ptr(), uint64_to_string_with_commas(total_trace_file_size).get_ptr());
210 vogl_error_printf("%s: Failed closing trace file %s! (Trace will probably not be valid.)\n", VOGL_METHOD_NAME, full_trace_filename.get_ptr());
215 void vogl_trace_file_writer::write_ctypes_packet()
219 key_value_map typemap_key_values;
220 typemap_key_values.insert("command_type", "ctypes");
221 typemap_key_values.insert("num_ctypes", VOGL_NUM_CTYPES);
222 for (uint ctype_iter = 0; ctype_iter < VOGL_NUM_CTYPES; ctype_iter++)
224 const vogl_ctype_desc_t &desc = (*m_pCTypes)[static_cast<vogl_ctype_t>(ctype_iter)];
226 uint base_index = ctype_iter << 8;
227 typemap_key_values.insert(base_index++, desc.m_pName);
228 typemap_key_values.insert(base_index++, desc.m_pCType);
229 typemap_key_values.insert(base_index++, desc.m_size);
230 typemap_key_values.insert(base_index++, desc.m_loki_type_flags);
231 typemap_key_values.insert(base_index++, desc.m_is_pointer);
232 typemap_key_values.insert(base_index++, desc.m_is_opaque_pointer);
233 typemap_key_values.insert(base_index++, desc.m_is_pointer_diff);
234 typemap_key_values.insert(base_index++, desc.m_is_opaque_type);
236 vogl_write_glInternalTraceCommandRAD(m_stream, m_pCTypes, cITCRKeyValueMap, sizeof(typemap_key_values), reinterpret_cast<const GLubyte *>(&typemap_key_values));
239 void vogl_trace_file_writer::write_entrypoints_packet()
243 key_value_map entrypoint_key_values;
244 entrypoint_key_values.insert("command_type", "entrypoints");
245 entrypoint_key_values.insert("num_entrypoints", VOGL_NUM_ENTRYPOINTS);
246 for (uint func_iter = 0; func_iter < VOGL_NUM_ENTRYPOINTS; func_iter++)
248 const gl_entrypoint_desc_t &desc = g_vogl_entrypoint_descs[func_iter];
249 entrypoint_key_values.insert(func_iter, desc.m_pName);
252 vogl_write_glInternalTraceCommandRAD(m_stream, m_pCTypes, cITCRKeyValueMap, sizeof(entrypoint_key_values), reinterpret_cast<const GLubyte *>(&entrypoint_key_values));
255 bool vogl_trace_file_writer::write_eof_packet()
259 vogl_trace_stream_packet_base eof_packet;
260 eof_packet.init(cTSPTEOF, sizeof(vogl_trace_stream_packet_base));
261 eof_packet.finalize();
262 return m_stream.write(&eof_packet, sizeof(eof_packet));
265 bool vogl_trace_file_writer::write_frame_file_offsets_to_archive()
269 if (!m_pTrace_archive.get())
272 if (m_frame_file_offsets.is_empty())
275 return m_pTrace_archive->add_buf_using_id(m_frame_file_offsets.get_ptr(), m_frame_file_offsets.size_in_bytes(), VOGL_TRACE_ARCHIVE_FRAME_FILE_OFFSETS_FILENAME).has_content();
278 void vogl_trace_file_writer::close_archive(const char *pArchive_filename)
282 if (m_pTrace_archive.get())
284 m_pTrace_archive.reset();
286 if (m_delete_archive && pArchive_filename)
288 file_utils::delete_file(pArchive_filename);
291 m_delete_archive = false;