]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_trace_packet.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_trace_packet.cpp
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_packet.cpp
27 #include "vogl_common.h"
28 #include "vogl_trace_packet.h"
29 #include "vogl_console.h"
30 #include "vogl_file_utils.h"
31 #include "vogl_bigint128.h"
32 #include "vogl_dynamic_stream.h"
33
34 using namespace vogl;
35
36 //----------------------------------------------------------------------------------------------------------------------
37 // vogl_trace_packet::compare
38 //----------------------------------------------------------------------------------------------------------------------
39 bool vogl_trace_packet::compare(const vogl_trace_packet &other, bool deep) const
40 {
41     VOGL_FUNC_TRACER
42
43     if ((!m_is_valid) || (!other.m_is_valid))
44         return false;
45
46     if (other.get_ctypes() != get_ctypes())
47         return false;
48
49     if (m_total_params != other.m_total_params)
50         return false;
51     if (m_has_return_value != other.m_has_return_value)
52         return false;
53
54 #define CMP(x)                          \
55     if (m_packet.x != other.m_packet.x) \
56         return false;
57
58     CMP(m_entrypoint_id);
59     CMP(m_context_handle);
60     CMP(m_thread_id);
61     CMP(m_call_counter);
62
63     if (deep)
64     {
65         CMP(m_rnd);
66         CMP(m_inv_rnd);
67         CMP(m_packet_begin_rdtsc);
68         CMP(m_gl_begin_rdtsc);
69         CMP(m_gl_end_rdtsc);
70         CMP(m_backtrace_hash_index);
71         CMP(m_packet_end_rdtsc);
72
73         CMP(m_param_size);
74         CMP(m_client_memory_size);
75         CMP(m_name_value_map_size);
76     }
77 #undef CMP
78
79     const uint total_params_to_check = m_total_params + m_has_return_value;
80     for (uint i = 0; i < total_params_to_check; i++)
81     {
82         if (m_param_ctype[i] != other.m_param_ctype[i])
83             return false;
84         if (m_param_size[i] != other.m_param_size[i])
85             return false;
86
87 #if 0
88                 if ((!deep) && ((*m_pCTypes)[m_param_ctype[i]].m_is_pointer))
89                 {
90                         bool lhs_null = (m_param_data[i] != 0);
91                         bool rhs_null = (other.m_param_data[i] != 0);
92                         if (lhs_null != rhs_null)
93                                 return false;
94                 }
95                 else
96 #endif
97         {
98             if (m_param_data[i] != other.m_param_data[i])
99                 return false;
100         }
101
102         const client_memory_desc_t &desc_lhs = m_client_memory_descs[i];
103         const client_memory_desc_t &desc_rhs = other.m_client_memory_descs[i];
104
105         if (desc_lhs.m_vec_ofs >= 0)
106         {
107             if (desc_rhs.m_vec_ofs < 0)
108                 return false;
109             if ((deep) && (desc_lhs.m_vec_ofs != desc_rhs.m_vec_ofs))
110                 return false;
111             if (desc_lhs.m_data_size != desc_rhs.m_data_size)
112                 return false;
113             if (desc_lhs.m_pointee_ctype != desc_rhs.m_pointee_ctype)
114                 return false;
115             if (memcmp(m_client_memory.get_ptr() + desc_lhs.m_vec_ofs, other.m_client_memory.get_ptr() + desc_rhs.m_vec_ofs, desc_lhs.m_data_size) != 0)
116                 return false;
117         }
118         else if (desc_rhs.m_vec_ofs >= 0)
119         {
120             return false;
121         }
122     }
123
124     if (m_key_value_map != other.m_key_value_map)
125         return false;
126
127     return true;
128 }
129
130 //----------------------------------------------------------------------------------------------------------------------
131 // vogl_trace_packet::check
132 //----------------------------------------------------------------------------------------------------------------------
133 bool vogl_trace_packet::check() const
134 {
135     VOGL_FUNC_TRACER
136
137     VOGL_ASSUME(VOGL_NUM_CTYPES < cUINT8_MAX);
138
139     if (!m_is_valid)
140         return false;
141
142     if (m_packet.m_prefix != vogl_trace_stream_packet_base::cTracePacketPrefix)
143         return false;
144     if (m_packet.m_type != cTSPTGLEntrypoint)
145         return false;
146
147     const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[m_packet.m_entrypoint_id];
148
149     if (m_total_params != entrypoint_desc.m_num_params)
150         return false;
151
152     if (entrypoint_desc.m_return_ctype == VOGL_VOID)
153     {
154         if (m_has_return_value)
155             return false;
156         if (m_param_ctype[entrypoint_desc.m_num_params] != VOGL_INVALID_CTYPE)
157             return false;
158     }
159     else
160     {
161         if (!m_has_return_value)
162             return false;
163         if (m_param_ctype[entrypoint_desc.m_num_params] != entrypoint_desc.m_return_ctype)
164             return false;
165         if (m_param_size[entrypoint_desc.m_num_params] != (*m_pCTypes)[entrypoint_desc.m_return_ctype].m_size)
166             return false;
167     }
168
169     for (uint param_iter = 0; param_iter < entrypoint_desc.m_num_params; param_iter++)
170     {
171         if (m_param_ctype[param_iter] == VOGL_INVALID_CTYPE)
172             return false;
173
174         const gl_entrypoint_param_desc_t &param_desc = g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_iter];
175
176         if (m_param_ctype[param_iter] != param_desc.m_ctype)
177             return false;
178         if (m_param_size[param_iter] != (*m_pCTypes)[param_desc.m_ctype].m_size)
179             return false;
180     }
181
182     uint total_params = entrypoint_desc.m_num_params + m_has_return_value;
183     for (uint param_iter = 0; param_iter < total_params; param_iter++)
184     {
185         const client_memory_desc_t &mem_desc = m_client_memory_descs[param_iter];
186         if (mem_desc.m_vec_ofs >= 0)
187         {
188             if ((!mem_desc.m_data_size) || (mem_desc.m_data_size >= static_cast<uint32>(cINT32_MAX)))
189                 return false;
190
191             if ((mem_desc.m_vec_ofs + mem_desc.m_data_size) > m_client_memory.size())
192                 return false;
193
194             uint pointee_ctype_size = 0;
195             bool pointee_is_opaque = false;
196             bool is_opaque_ptr = false;
197             if (param_iter < entrypoint_desc.m_num_params)
198             {
199                 const gl_entrypoint_param_desc_t &param_desc = g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_iter];
200
201                 is_opaque_ptr = (*m_pCTypes)[param_desc.m_ctype].m_is_opaque_pointer;
202
203                 if (!(*m_pCTypes)[param_desc.m_ctype].m_is_pointer)
204                     return false;
205
206                 if ((*m_pCTypes)[param_desc.m_ctype].m_pointee_ctype != VOGL_VOID)
207                 {
208                     pointee_ctype_size = (*m_pCTypes)[(*m_pCTypes)[param_desc.m_ctype].m_pointee_ctype].m_size;
209                     pointee_is_opaque = (*m_pCTypes)[(*m_pCTypes)[param_desc.m_ctype].m_pointee_ctype].m_is_opaque_type;
210                 }
211             }
212             else
213             {
214                 is_opaque_ptr = (*m_pCTypes)[entrypoint_desc.m_return_ctype].m_is_opaque_pointer;
215
216                 if (!(*m_pCTypes)[entrypoint_desc.m_return_ctype].m_is_pointer)
217                     return false;
218
219                 if ((*m_pCTypes)[entrypoint_desc.m_return_ctype].m_pointee_ctype != VOGL_VOID)
220                 {
221                     pointee_ctype_size = (*m_pCTypes)[(*m_pCTypes)[entrypoint_desc.m_return_ctype].m_pointee_ctype].m_size;
222                     pointee_is_opaque = (*m_pCTypes)[(*m_pCTypes)[entrypoint_desc.m_return_ctype].m_pointee_ctype].m_is_opaque_type;
223                 }
224             }
225
226             if ((pointee_ctype_size > 1) && (!is_opaque_ptr) && (!pointee_is_opaque))
227             {
228                 if (mem_desc.m_data_size % pointee_ctype_size)
229                     return false;
230             }
231         }
232         else
233         {
234             if (mem_desc.m_vec_ofs != -1)
235                 return false;
236             if (mem_desc.m_data_size)
237                 return false;
238             if (mem_desc.m_pointee_ctype != VOGL_VOID)
239                 return false;
240         }
241     }
242
243     return true;
244 }
245
246 //----------------------------------------------------------------------------------------------------------------------
247 // vogl_trace_packet::deserialize
248 //----------------------------------------------------------------------------------------------------------------------
249 bool vogl_trace_packet::deserialize(const uint8 *pPacket_data, uint packet_data_buf_size, bool check_crc)
250 {
251     VOGL_FUNC_TRACER
252
253     reset();
254
255     const vogl_trace_gl_entrypoint_packet *pTrace_gl_entrypoint_packet = reinterpret_cast<const vogl_trace_gl_entrypoint_packet *>(pPacket_data);
256
257     if (check_crc)
258     {
259         if (!pTrace_gl_entrypoint_packet->full_validation(packet_data_buf_size))
260         {
261             vogl_error_printf("%s: Trace packet failed basic validation!\n", VOGL_METHOD_NAME);
262             return false;
263         }
264     }
265     else
266     {
267         if (!pTrace_gl_entrypoint_packet->basic_validation())
268         {
269             vogl_error_printf("%s: Trace packet failed basic validation!\n", VOGL_METHOD_NAME);
270             return false;
271         }
272     }
273
274     m_packet = *reinterpret_cast<const vogl_trace_gl_entrypoint_packet *>(pTrace_gl_entrypoint_packet);
275
276     VOGL_ASSERT(m_packet.m_type == cTSPTGLEntrypoint);
277
278     if (m_packet.m_size < sizeof(vogl_trace_gl_entrypoint_packet))
279         return false;
280
281     if (m_packet.m_entrypoint_id >= VOGL_NUM_ENTRYPOINTS)
282         return false;
283
284     uint entrypoint_index = m_packet.m_entrypoint_id;
285     const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[entrypoint_index];
286     const gl_entrypoint_param_desc_t *pParam_desc = &g_vogl_entrypoint_param_descs[entrypoint_index][0];
287
288     m_total_params = entrypoint_desc.m_num_params;
289     m_has_return_value = (entrypoint_desc.m_return_ctype != VOGL_VOID);
290
291     const uint total_params_to_deserialize = m_total_params + m_has_return_value;
292
293     const uint8 *pExtra_packet_data = pPacket_data + sizeof(vogl_trace_gl_entrypoint_packet);
294     uint num_bytes_remaining = m_packet.m_size - sizeof(vogl_trace_gl_entrypoint_packet);
295
296     if (m_packet.m_param_size)
297     {
298         if (m_packet.m_param_size > num_bytes_remaining)
299             return false;
300
301         for (uint param_index = 0; param_index < total_params_to_deserialize; ++param_index, ++pParam_desc)
302         {
303             vogl_ctype_t param_ctype = (param_index >= m_total_params) ? entrypoint_desc.m_return_ctype : pParam_desc->m_ctype;
304             uint param_size = (*m_pCTypes)[param_ctype].m_size;
305
306             if (num_bytes_remaining < param_size)
307                 return false;
308
309             m_param_ctype[param_index] = param_ctype;
310             VOGL_ASSERT(param_size <= cUINT8_MAX);
311             m_param_size[param_index] = param_size;
312
313             m_param_data[param_index] = 0;
314             memcpy(&m_param_data[param_index], pExtra_packet_data, param_size);
315
316             pExtra_packet_data += param_size;
317             num_bytes_remaining -= param_size;
318         }
319     }
320
321     if (m_packet.m_client_memory_size)
322     {
323         if (m_packet.m_client_memory_size > num_bytes_remaining)
324             return false;
325
326         uint client_memory_descs_size = (total_params_to_deserialize * sizeof(client_memory_desc_t));
327         if (num_bytes_remaining < client_memory_descs_size)
328             return false;
329
330         memcpy(m_client_memory_descs, pExtra_packet_data, client_memory_descs_size);
331         pExtra_packet_data += client_memory_descs_size;
332         num_bytes_remaining -= client_memory_descs_size;
333
334         if (client_memory_descs_size > m_packet.m_client_memory_size)
335             return false;
336
337         uint client_memory_vec_size = m_packet.m_client_memory_size - client_memory_descs_size;
338
339         m_client_memory.append(pExtra_packet_data, client_memory_vec_size);
340         pExtra_packet_data += client_memory_vec_size;
341         num_bytes_remaining -= client_memory_vec_size;
342     }
343
344     if (m_packet.m_name_value_map_size)
345     {
346         if (m_packet.m_name_value_map_size > num_bytes_remaining)
347             return false;
348
349         if (!m_key_value_map.deserialize_from_buffer(pExtra_packet_data, num_bytes_remaining, true, false))
350             return false;
351
352         pExtra_packet_data += m_packet.m_name_value_map_size;
353         num_bytes_remaining -= m_packet.m_name_value_map_size;
354     }
355
356     if (num_bytes_remaining)
357         return false;
358
359     m_is_valid = true;
360
361     VOGL_ASSERT(check());
362
363     return true;
364 }
365
366 //----------------------------------------------------------------------------------------------------------------------
367 // vogl_trace_packet::deserialize
368 //----------------------------------------------------------------------------------------------------------------------
369 bool vogl_trace_packet::deserialize(const uint8_vec &packet_buf, bool check_crc)
370 {
371     VOGL_FUNC_TRACER
372
373     return deserialize(packet_buf.get_ptr(), packet_buf.size(), check_crc);
374 }
375
376 //----------------------------------------------------------------------------------------------------------------------
377 // vogl_trace_packet::serialize
378 //----------------------------------------------------------------------------------------------------------------------
379 bool vogl_trace_packet::serialize(data_stream &stream) const
380 {
381     VOGL_FUNC_TRACER
382
383     if (!m_is_valid)
384         return false;
385
386     VOGL_ASSERT(m_packet.m_gl_begin_rdtsc <= m_packet.m_gl_end_rdtsc);
387     VOGL_ASSERT(m_packet.m_packet_begin_rdtsc <= m_packet.m_packet_end_rdtsc);
388
389     vogl_trace_gl_entrypoint_packet packet(m_packet);
390
391     uint8 param_data[512];
392
393     uint total_params_to_serialize = m_total_params + m_has_return_value;
394     uint8 *pDst_param_data = param_data;
395     for (uint i = 0; i < total_params_to_serialize; i++)
396     {
397         uint size = m_param_size[i];
398         VOGL_ASSERT(size);
399         memcpy(pDst_param_data, &m_param_data[i], size);
400         pDst_param_data += size;
401         VOGL_ASSERT((pDst_param_data - param_data) <= static_cast<long>(sizeof(param_data)));
402     }
403
404     VOGL_VERIFY((pDst_param_data - param_data) <= cUINT8_MAX);
405     packet.m_param_size = static_cast<uint8>(pDst_param_data - param_data);
406
407     uint client_memory_descs_size = (total_params_to_serialize * sizeof(client_memory_desc_t));
408     packet.m_client_memory_size = client_memory_descs_size + m_client_memory.size();
409
410     uint64_t kvm_serialize_size = m_key_value_map.get_num_key_values() ? m_key_value_map.get_serialize_size(false) : 0;
411     if (kvm_serialize_size > cUINT32_MAX)
412         return false;
413     packet.m_name_value_map_size = static_cast<uint32>(kvm_serialize_size);
414
415     uint64_t total_packet_size = sizeof(vogl_trace_gl_entrypoint_packet) + packet.m_param_size + packet.m_client_memory_size + packet.m_name_value_map_size;
416     if (total_packet_size > static_cast<uint64_t>(cINT32_MAX))
417         return false;
418
419     packet.m_size = static_cast<uint32_t>(total_packet_size);
420
421     if (!m_packet_buf.try_resize(static_cast<uint32>(total_packet_size)))
422         return false;
423
424     uint8 *pDst_buf = m_packet_buf.get_ptr();
425
426 #define APPEND_TO_DST_BUF(pSrc, n)                                         \
427     do                                                                     \
428     {                                                                      \
429         VOGL_ASSERT((int64_t)n <= (int64_t)(m_packet_buf.end() - pDst_buf)); \
430         memcpy(pDst_buf, pSrc, n);                                         \
431         pDst_buf += n;                                                     \
432     } while (0)
433
434     APPEND_TO_DST_BUF(&packet, sizeof(packet));
435
436     if (packet.m_param_size)
437     {
438         APPEND_TO_DST_BUF(param_data, packet.m_param_size);
439     }
440
441     if (packet.m_client_memory_size)
442     {
443         APPEND_TO_DST_BUF(m_client_memory_descs, client_memory_descs_size);
444         APPEND_TO_DST_BUF(m_client_memory.get_ptr(), m_client_memory.size());
445     }
446
447     if (m_key_value_map.get_num_key_values())
448     {
449         if (pDst_buf >= m_packet_buf.end())
450         {
451             VOGL_VERIFY(0);
452             return false;
453         }
454
455         uint buf_remaining = static_cast<uint>(m_packet_buf.end() - pDst_buf);
456         int result = m_key_value_map.serialize_to_buffer(pDst_buf, buf_remaining, true, false);
457         if (result != static_cast<int>(packet.m_name_value_map_size))
458             return false;
459
460         pDst_buf += result;
461     }
462
463     if (pDst_buf != m_packet_buf.end())
464         return false;
465
466 #undef APPEND_TO_DST_BUF
467
468     vogl_trace_gl_entrypoint_packet *pBuf_packet = reinterpret_cast<vogl_trace_gl_entrypoint_packet *>(m_packet_buf.get_ptr());
469     pBuf_packet->finalize();
470
471     VOGL_ASSERT(pBuf_packet->full_validation(m_packet_buf.size()));
472
473     uint n = stream.write(pBuf_packet, m_packet_buf.size());
474     if (n != m_packet_buf.size())
475         return false;
476
477     return true;
478 }
479
480 //----------------------------------------------------------------------------------------------------------------------
481 // vogl_trace_packet::serialize
482 //----------------------------------------------------------------------------------------------------------------------
483 bool vogl_trace_packet::serialize(uint8_vec &buf) const
484 {
485     VOGL_FUNC_TRACER
486
487     dynamic_stream dyn_stream;
488     if (!dyn_stream.open(128))
489         return false;
490     if (!serialize(dyn_stream))
491         return false;
492     buf.swap(dyn_stream.get_buf());
493     return true;
494 }
495
496 //----------------------------------------------------------------------------------------------------------------------
497 // vogl_trace_packet::json_serialize
498 //----------------------------------------------------------------------------------------------------------------------
499 bool vogl_trace_packet::json_serialize(json_node &node, const json_serialize_params &params) const
500 {
501     VOGL_FUNC_TRACER
502
503     const char *pFunc_name = g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_pName;
504
505     node.add_key_value("func", pFunc_name);
506
507     node.add_key_value("thread_id", dynamic_string(cVarArg, "0x%" PRIX64, m_packet.m_thread_id));
508     node.add_key_value("context", dynamic_string(cVarArg, "0x%" PRIX64, m_packet.m_context_handle));
509     node.add_key_value("call_counter", static_cast<int64_t>(m_packet.m_call_counter));
510     node.add_key_value("crc32", m_packet.m_crc);
511     node.add_key_value("begin_rdtsc", m_packet.m_packet_begin_rdtsc);
512     node.add_key_value("end_rdtsc", m_packet.m_packet_end_rdtsc);
513     node.add_key_value("gl_begin_rdtsc", m_packet.m_gl_begin_rdtsc);
514     node.add_key_value("gl_end_rdtsc", m_packet.m_gl_end_rdtsc);
515     node.add_key_value("backtrace_hash_index", m_packet.m_backtrace_hash_index);
516     node.add_key_value("rnd_check", m_packet.m_rnd);
517     node.add_key_value("inv_rnd_check", m_packet.m_inv_rnd);
518
519     json_node &gl_params_node = node.add_object("params");
520     for (uint param_index = 0; param_index < total_params(); param_index++)
521     {
522         if (!json_serialize_param(pFunc_name, gl_params_node, param_index, get_param_desc(param_index).m_pName,
523                                   get_param_data(param_index), get_param_size(param_index), get_param_ctype(param_index),
524                                   get_param_client_memory_ptr(param_index),
525                                   get_param_client_memory_data_size(param_index),
526                                   get_param_client_memory_ctype(param_index),
527                                   params))
528         {
529             return false;
530         }
531     }
532
533     if (has_return_value())
534     {
535         if (!json_serialize_param(pFunc_name, node, -1, "return",
536                                   get_return_value_data(), get_return_value_size(), get_return_value_ctype(),
537                                   get_return_client_memory_ptr(),
538                                   get_return_client_memory_data_size(),
539                                   get_return_client_memory_ctype(),
540                                   params))
541         {
542             return false;
543         }
544     }
545
546     if (m_packet.m_name_value_map_size)
547     {
548         json_node &gl_name_value_array = node.add_array("name_value_map");
549
550         dynamic_string key_str, value_str;
551
552         for (key_value_map::const_iterator it = m_key_value_map.begin(); it != m_key_value_map.end(); ++it)
553         {
554             const value &key = it->first;
555             const value &val = it->second;
556
557             json_node &entry_node = gl_name_value_array.add_object();
558
559             entry_node.add_key_value("key_type", g_value_data_type_strings[key.get_data_type()]);
560             entry_node.add_key_value("val_type", g_value_data_type_strings[val.get_data_type()]);
561
562             key.get_string(key_str, false);
563
564             if (key.get_data_type() == cDTStringHash)
565             {
566                 string_hash hash(key.get_string_hash());
567
568                 const char *pStr = find_well_known_string_hash(hash);
569                 if (pStr)
570                     key_str.set(pStr);
571             }
572
573             entry_node.add_key_value("key", key_str);
574
575             bool handle_as_blob_file = false;
576
577             if (val.is_blob())
578             {
579                 if (val.get_blob()->size() >= params.m_blob_file_size_threshold)
580                     handle_as_blob_file = true;
581                 else if (should_always_write_as_blob_file(pFunc_name))
582                     handle_as_blob_file = true;
583             }
584
585             if (handle_as_blob_file)
586             {
587                 dynamic_string id;
588
589                 uint64_t blob_crc64 = calc_crc64(CRC64_INIT, reinterpret_cast<const uint8 *>(val.get_blob()->get_ptr()), val.get_blob()->size());
590
591                 if (params.m_pBlob_manager)
592                 {
593                     //dynamic_string prefix(cVarArg, "%s_%s", params.m_output_basename.get_ptr(), pFunc_name);
594                     dynamic_string prefix(cVarArg, "%s", pFunc_name);
595
596                     id = params.m_pBlob_manager->add_buf_compute_unique_id(val.get_blob()->get_ptr(), val.get_blob()->size(), prefix, "blob", &blob_crc64);
597                     if (id.is_empty())
598                     {
599                         vogl_error_printf("%s: Failed adding blob %s to blob manager\n", VOGL_METHOD_NAME, prefix.get_ptr());
600                         return false;
601                     }
602
603                     vogl_message_printf("%s: Wrote blob id %s\n", VOGL_METHOD_NAME, id.get_ptr());
604                 }
605                 else
606                 {
607                     id = "<blob_writing_disabled>";
608                 }
609
610                 json_node &blob_node = entry_node.add_object("data");
611                 blob_node.add_key_value("blob_id", id);
612                 blob_node.add_key_value("crc64", dynamic_string(cVarArg, "0x%016" PRIX64, blob_crc64));
613                 blob_node.add_key_value("size", val.get_blob()->size());
614             }
615             else
616             {
617                 switch (val.get_data_type())
618                 {
619                     case cDTInt8:
620                     case cDTInt16:
621                     case cDTInt:
622                     case cDTInt64:
623                     {
624                         entry_node.add_key_value("data", val.get_int64());
625                         break;
626                     }
627                     case cDTUInt8:
628                     case cDTUInt16:
629                     case cDTUInt:
630                     {
631                         entry_node.add_key_value("data", val.get_uint());
632                         break;
633                     }
634                     case cDTStringHash:
635                     {
636                         string_hash hash(val.get_string_hash());
637
638                         const char *pStr = find_well_known_string_hash(hash);
639                         if (!pStr)
640                             entry_node.add_key_value("data", hash.get_hash());
641                         else
642                             entry_node.add_key_value("data", pStr);
643                         break;
644                     }
645                     case cDTFloat:
646                     {
647                         float flt_val = val.get_float();
648                         json_value &new_val = entry_node.add_key_value("data", flt_val);
649
650                         dynamic_string new_val_as_str;
651                         new_val.serialize(new_val_as_str, false);
652
653                         json_value test_val;
654                         if ((!test_val.deserialize(new_val_as_str)) || (test_val.as_float() != flt_val))
655                         {
656                             new_val.set_value(dynamic_string(cVarArg, "0x%08X", *reinterpret_cast<const uint32 *>(&flt_val)).get_ptr());
657                         }
658
659                         break;
660                     }
661                     case cDTDouble:
662                     {
663                         double dbl_val = val.get_double();
664                         json_value &new_val = entry_node.add_key_value("data", dbl_val);
665
666                         dynamic_string new_val_as_str;
667                         new_val.serialize(new_val_as_str, false);
668
669                         json_value test_val;
670                         if ((!test_val.deserialize(new_val_as_str)) || (test_val.as_double() != dbl_val))
671                         {
672                             new_val.set_value(dynamic_string(cVarArg, "0x%" PRIX64, static_cast<uint64_t>(*reinterpret_cast<const uint64_t *>(&dbl_val))).get_ptr());
673                         }
674
675                         break;
676                     }
677                     case cDTUInt64:
678                     {
679                         entry_node.add_key_value("data", dynamic_string(cVarArg, "0x%" PRIX64, val.get_uint64()).get_ptr());
680                         break;
681                     }
682                     case cDTJSONDoc:
683                     {
684                         entry_node.add_key_value("data", *val.get_json_document());
685                         break;
686                     }
687                     default:
688                     {
689                         val.get_string(value_str, false);
690                         entry_node.add_key_value("data", value_str);
691
692                         break;
693                     }
694                 }
695             }
696         }
697     }
698
699     if (params.m_write_debug_info)
700     {
701         json_node &gl_dbg_node = node.add_object("dbg");
702         gl_dbg_node.add_key_value("entrypoint_id", m_packet.m_entrypoint_id);
703         gl_dbg_node.add_key_value("total_params", total_params());
704         gl_dbg_node.add_key_value("has_return_value", has_return_value());
705         gl_dbg_node.add_key_value("is_whitelisted", get_entrypoint_desc().m_is_whitelisted);
706         gl_dbg_node.add_key_value("packet_size", m_packet.m_size);
707         gl_dbg_node.add_key_value("param_size", m_packet.m_param_size);
708         gl_dbg_node.add_key_value("client_mem_size", m_packet.m_client_memory_size);
709         gl_dbg_node.add_key_value("name_value_map_size", m_packet.m_name_value_map_size);
710     }
711
712     return true;
713 }
714
715 //----------------------------------------------------------------------------------------------------------------------
716 // print_json_context
717 //----------------------------------------------------------------------------------------------------------------------
718 static void print_json_context(const char *pDocument_filename, const json_node &node, eConsoleMessageType msg_category = cErrorConsoleMessage)
719 {
720     VOGL_FUNC_TRACER
721
722     console::printf(msg_category, "Context: JSON filename %s, on or near line %u, node path: %s\n", pDocument_filename, node.get_line(), node.get_path_to_node().get_ptr());
723 }
724
725 //----------------------------------------------------------------------------------------------------------------------
726 // print_json_context
727 //----------------------------------------------------------------------------------------------------------------------
728 static void print_json_context(const char *pDocument_filename, const json_node &node, uint node_index, eConsoleMessageType msg_category = cErrorConsoleMessage)
729 {
730     VOGL_FUNC_TRACER
731
732     console::printf(msg_category, "Context: JSON filename %s, on or near line %u, node item path: %s\n", pDocument_filename, node.get_line(), node.get_path_to_item(node_index).get_ptr());
733 }
734
735 //----------------------------------------------------------------------------------------------------------------------
736 // print_json_context
737 //----------------------------------------------------------------------------------------------------------------------
738 static void print_json_context(const char *pDocument_filename, const json_value &val, const json_node &node, eConsoleMessageType msg_category = cErrorConsoleMessage)
739 {
740     VOGL_FUNC_TRACER
741
742     console::printf(msg_category, "Context: JSON filename %s, on or near the node at line %u, on or near the value at line %u, node path: %s\n", pDocument_filename, node.get_line(), val.get_line(), node.get_path_to_node().get_ptr());
743 }
744
745 //----------------------------------------------------------------------------------------------------------------------
746 // print_json_context
747 //----------------------------------------------------------------------------------------------------------------------
748 static void print_json_context(const char *pDocument_filename, const json_value &val, const json_node &node, uint node_index, eConsoleMessageType msg_category = cErrorConsoleMessage)
749 {
750     VOGL_FUNC_TRACER
751
752     console::printf(msg_category, "Context: JSON filename %s, on or near the node at line %u, on or near the value at line %u, item path: %s\n", pDocument_filename, node.get_line(), val.get_line(), node.get_path_to_item(node_index).get_ptr());
753 }
754
755 //----------------------------------------------------------------------------------------------------------------------
756 // vogl_trace_packet::json_deserialize
757 //----------------------------------------------------------------------------------------------------------------------
758 bool vogl_trace_packet::json_deserialize(const json_node &node, const char *pDocument_filename, const vogl_blob_manager *pBlob_manager)
759 {
760     VOGL_FUNC_TRACER
761
762     reset();
763
764     const dynamic_string gl_func_name(node.value_as_string("func"));
765     if (gl_func_name.is_empty())
766     {
767         vogl_error_printf("%s: Missing \"func\" node\n", VOGL_METHOD_NAME);
768         print_json_context(pDocument_filename, node);
769         return false;
770     }
771
772     entrypoint_name_hash_map_t::const_iterator it = g_vogl_entrypoint_hashmap.find(gl_func_name);
773     if (it == g_vogl_entrypoint_hashmap.end())
774     {
775         vogl_error_printf("%s: Unknown GL function name: \"%s\"\n", VOGL_METHOD_NAME, gl_func_name.get_ptr());
776         print_json_context(pDocument_filename, node);
777         return false;
778     }
779
780     gl_entrypoint_id_t gl_entrypoint_id = it->second;
781
782     const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[gl_entrypoint_id];
783     const gl_entrypoint_param_desc_t *pEntrypoint_params = &g_vogl_entrypoint_param_descs[gl_entrypoint_id][0];
784
785     uint64_t thread_id = 0;
786     get_uint64_from_json_node(node, "thread_id", thread_id);
787
788     uint64_t context = 0;
789     if (!get_uint64_from_json_node(node, "context", context))
790         context = 1;
791
792     uint64_t call_counter = 0;
793     get_uint64_from_json_node(node, "call_counter", call_counter);
794
795     const json_node *pParams_node = node.find_child("params");
796     json_node dummy_node;
797     if (!pParams_node)
798     {
799         if (entrypoint_desc.m_num_params)
800         {
801             vogl_error_printf("%s: Failed finding params key!\n", VOGL_METHOD_NAME);
802             print_json_context(pDocument_filename, node);
803             return false;
804         }
805         else
806         {
807             vogl_warning_printf("%s: Failed finding params key! Substituting a dummy empty node and trying to deserialize anyway.\n", VOGL_METHOD_NAME);
808         }
809         dummy_node.init_object();
810         pParams_node = &dummy_node;
811     }
812
813     if (!pParams_node->is_object())
814     {
815         vogl_error_printf("%s: Failed finding params key!\n", VOGL_METHOD_NAME);
816         print_json_context(pDocument_filename, *pParams_node);
817         return false;
818     }
819
820     uint num_params = pParams_node->size();
821     if (num_params != entrypoint_desc.m_num_params)
822     {
823         vogl_error_printf("%s: Unexpected number of param keys (expected %u, found %u)\n", VOGL_METHOD_NAME, entrypoint_desc.m_num_params, num_params);
824         print_json_context(pDocument_filename, *pParams_node);
825         return false;
826     }
827
828     const bool has_return_key = node.has_key("return");
829     if (entrypoint_desc.m_return_ctype == VOGL_VOID)
830     {
831         if (has_return_key)
832         {
833             vogl_error_printf("%s: Unexpected return key\n", VOGL_METHOD_NAME);
834             print_json_context(pDocument_filename, node);
835             return false;
836         }
837     }
838     else if (!has_return_key)
839     {
840         vogl_error_printf("%s: Missing return key\n", VOGL_METHOD_NAME);
841         print_json_context(pDocument_filename, node);
842         return false;
843     }
844
845     m_packet.m_entrypoint_id = gl_entrypoint_id;
846     m_packet.m_call_counter = call_counter;
847     m_packet.m_context_handle = context;
848     m_packet.m_thread_id = thread_id;
849
850     // All of this is optional stuff
851     m_packet.m_packet_begin_rdtsc = node.value_as_uint64("begin_rdtsc");
852     m_packet.m_packet_end_rdtsc = node.value_as_uint64("end_rdtsc");
853     m_packet.m_gl_begin_rdtsc = node.value_as_uint64("gl_begin_rdtsc");
854     m_packet.m_gl_end_rdtsc = node.value_as_uint64("gl_end_rdtsc");
855     m_packet.m_backtrace_hash_index = node.value_as_uint32("backtrace_hash_index");
856
857     m_packet.m_rnd = node.value_as_uint32("rnd_check", 1);
858
859     // The rnd value can't be 0,
860     if (m_packet.m_rnd < vogl_trace_stream_packet_base::cMinimumPossibleRnd)
861     {
862         vogl_warning_printf("%s: rnd_check value cannot be 0\n", VOGL_METHOD_NAME);
863         print_json_context(pDocument_filename, node, cWarningConsoleMessage);
864         m_packet.m_rnd = vogl_trace_stream_packet_base::cMinimumPossibleRnd;
865     }
866     m_packet.m_inv_rnd = ~m_packet.m_inv_rnd;
867
868     m_total_params = num_params;
869     m_has_return_value = has_return_key;
870
871     for (uint param_iter = 0; param_iter < num_params; param_iter++)
872     {
873         const gl_entrypoint_param_desc_t &param_desc = pEntrypoint_params[param_iter];
874
875         if (!json_deserialize_param(
876                  call_counter, gl_func_name.get_ptr(),
877                  *pParams_node,
878                  param_iter, param_desc.m_pName, param_desc.m_class, (*m_pCTypes)[param_desc.m_ctype], pDocument_filename, pBlob_manager))
879         {
880             return false;
881         }
882     }
883
884     if (m_has_return_value)
885     {
886         if (!json_deserialize_param(
887                  call_counter, gl_func_name.get_ptr(),
888                  node,
889                  num_params, "return", VOGL_VALUE_PARAM, (*m_pCTypes)[entrypoint_desc.m_return_ctype], pDocument_filename, pBlob_manager))
890         {
891             return false;
892         }
893     }
894
895     const json_node *pName_value_array = node.find_child("name_value_map");
896     if (pName_value_array)
897     {
898         if (!pName_value_array->is_array())
899         {
900             vogl_error_printf("%s: name_value_map is not an array\n", VOGL_METHOD_NAME);
901             print_json_context(pDocument_filename, *pName_value_array);
902             return false;
903         }
904
905         uint64_t size = pName_value_array->size();
906         VOGL_NOTE_UNUSED(size);
907
908         uint name_value_index = 0;
909
910         for (uint name_value_node_iter = 0; name_value_node_iter < pName_value_array->size(); name_value_node_iter++)
911         {
912             const json_node *pItem_node = pName_value_array->get_value_as_object(name_value_node_iter);
913             if (!pItem_node)
914             {
915                 vogl_error_printf("%s: Expected object in name_value_map array\n", VOGL_METHOD_NAME);
916                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
917                 return false;
918             }
919             const json_node &item_node = *pItem_node;
920
921             dynamic_string key_str(item_node.value_as_string("key"));
922             if (key_str.is_empty())
923             {
924                 vogl_error_printf("%s: Expected key in name_value_map array\n", VOGL_METHOD_NAME);
925                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
926                 return false;
927             }
928
929             const char *pKey_type_str = item_node.value_as_string_ptr("key_type");
930             const char *pValue_type_str = item_node.value_as_string_ptr("val_type");
931
932             if ((!pKey_type_str) || (!pValue_type_str))
933             {
934                 vogl_error_printf("%s: Invalid data_types array in name_value_map object\n", VOGL_METHOD_NAME);
935                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
936                 return false;
937             }
938
939             value_data_type key_type = string_to_value_data_type(pKey_type_str);
940             value_data_type value_type = string_to_value_data_type(pValue_type_str);
941             if ((key_type == cDTInvalid) || (value_type == cDTInvalid))
942             {
943                 vogl_error_printf("%s: Invalid data_types array in name_value_map object\n", VOGL_METHOD_NAME);
944                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
945                 return false;
946             }
947
948             value key, val;
949             if (!key.parse(key_str.get_ptr()))
950             {
951                 vogl_error_printf("%s: Failed parsing name_value_map key string %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
952                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
953                 return false;
954             }
955
956             if (!force_value_to_type(key, key_type))
957             {
958                 vogl_error_printf("%s: Failed parsing name_value_map key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
959                 print_json_context(pDocument_filename, *pName_value_array, name_value_node_iter);
960                 return false;
961             }
962
963             const json_value &json_val = item_node.find_value("data");
964
965             if ((value_type == cDTBlob) && (json_val.is_object()))
966             {
967                 //vogl_error_printf("%s: Expected JSON object for name_value_map node key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
968                 //print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
969                 //return false;
970
971                 const json_node &blob_node = *json_val.get_node_ptr();
972
973                 dynamic_string blob_id;
974                 if (!blob_node.get_value_as_string("blob_id", blob_id))
975                 {
976                     vogl_error_printf("%s: Failed parsing blob_file key in name_value_map node key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
977                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
978                     return false;
979                 }
980
981                 uint64_t blob_crc64 = 0;
982                 if (!get_uint64_from_json_node(blob_node, "crc64", blob_crc64))
983                 {
984                     vogl_error_printf("%s: Failed parsing crc64 key in name_value_map node key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
985                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
986                     return false;
987                 }
988
989                 uint64_t blob_size = 0;
990                 if (!get_uint64_from_json_node(blob_node, "size", blob_size))
991                 {
992                     vogl_error_printf("%s: Failed parsing size key in name_value_map node key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
993                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
994                     return false;
995                 }
996
997                 if (blob_size > cUINT32_MAX)
998                 {
999                     vogl_error_printf("%s: Blob size is too large (%" PRIu64 "), blob id %s key %s\n", VOGL_METHOD_NAME, blob_size, blob_id.get_ptr(), key_str.get_ptr());
1000                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1001                     return false;
1002                 }
1003
1004                 if (!pBlob_manager)
1005                 {
1006                     vogl_error_printf("%s: Encountered data blob in packet but no blob manager was specified, blob size %" PRIu64 " blob id %s key %s\n", VOGL_METHOD_NAME, blob_size, blob_id.get_ptr(), key_str.get_ptr());
1007                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1008                     return false;
1009                 }
1010
1011                 uint8_vec blob;
1012                 if (!pBlob_manager->get(blob_id, blob))
1013                 {
1014                     vogl_error_printf("%s: Failed retrieving data blob, blob size %" PRIu64 " blob id %s key %s CRC64 0x%" PRIX64 "\n", VOGL_METHOD_NAME, blob_size, blob_id.get_ptr(), key_str.get_ptr(), blob_crc64);
1015                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1016                     return false;
1017                 }
1018
1019                 uint64_t actual_blob_size = blob.size();
1020
1021                 // TODO: We'll eventually support enormous blob files
1022                 if (actual_blob_size > cUINT32_MAX)
1023                 {
1024                     vogl_error_printf("%s: Blob size is too large (%" PRIu64 "), blob id %s key %s\n", VOGL_METHOD_NAME, actual_blob_size, blob_id.get_ptr(), key_str.get_ptr());
1025                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1026                     return false;
1027                 }
1028
1029                 if (actual_blob_size != blob_size)
1030                 {
1031                     vogl_warning_printf("%s: Unexpected size of blob id %s (should be %" PRIu64 " bytes, but is %" PRIu64 " bytes), reading all of file and hoping for the best\n", VOGL_METHOD_NAME, blob_id.get_ptr(), blob_size, actual_blob_size);
1032                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter, cWarningConsoleMessage);
1033                 }
1034
1035                 uint64_t check_crc64 = calc_crc64(CRC64_INIT, blob.get_ptr(), blob.size());
1036                 if (check_crc64 != blob_crc64)
1037                 {
1038                     vogl_warning_printf("%s: name_value_map blob file %s's CRC64 is bad (expected 0x%016" PRIX64 " got 0x%016" PRIX64 ")\n", VOGL_METHOD_NAME, blob_id.get_ptr(), blob_crc64, check_crc64);
1039                     print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter, cWarningConsoleMessage);
1040                 }
1041
1042                 val.set_blob_take_ownership(blob);
1043             }
1044             else if (value_type == cDTJSONDoc)
1045             {
1046                 *val.init_json_document() = json_val;
1047             }
1048             else
1049             {
1050                 switch (json_val.get_type())
1051                 {
1052                     case cJSONValueTypeBool:
1053                     case cJSONValueTypeInt:
1054                     {
1055                         val.set_int64(json_val.as_int64());
1056                         break;
1057                     }
1058                     case cJSONValueTypeDouble:
1059                     {
1060                         val.set_int64(json_val.as_double());
1061                         break;
1062                     }
1063                     case cJSONValueTypeString:
1064                     {
1065                         const char *pStr = json_val.as_string_ptr();
1066                         if (!pStr || !val.parse(pStr))
1067                         {
1068                             vogl_error_printf("%s: Failed parsing name_value_map value type for key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
1069                             print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1070                             return false;
1071                         }
1072                         break;
1073                     }
1074                     default:
1075                     {
1076                         // Just skip it.
1077                         vogl_error_printf("%s: Unexpected name_value_map value type for key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
1078                         print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1079                         break;
1080                     }
1081                 }
1082             }
1083
1084             if (!force_value_to_type(val, value_type))
1085             {
1086                 vogl_error_printf("%s: Failed parsing value for name_value_map key %s\n", VOGL_METHOD_NAME, key_str.get_ptr());
1087                 print_json_context(pDocument_filename, json_val, *pName_value_array, name_value_node_iter);
1088                 return false;
1089             }
1090             m_key_value_map.insert(key, val);
1091
1092             name_value_index++;
1093
1094         } // name_value_node_iter
1095     }
1096
1097     if (!fixup_manually_edited_params(gl_entrypoint_id, gl_func_name.get_ptr(), call_counter))
1098         return false;
1099
1100     m_is_valid = true;
1101
1102     VOGL_ASSERT(check());
1103
1104     return true;
1105 }
1106
1107 //----------------------------------------------------------------------------------------------------------------------
1108 // vogl_trace_packet::validate_value_conversion
1109 // Returns true if the dest type is at least large enough to hold the parameter (or the same size in bytes for floats).
1110 //----------------------------------------------------------------------------------------------------------------------
1111 bool vogl_trace_packet::validate_value_conversion(uint dest_type_size, uint dest_type_loki_type_flags, int param_index) const
1112 {
1113     VOGL_FUNC_TRACER
1114
1115     VOGL_ASSERT((dest_type_size >= 1) && (dest_type_size <= 8));
1116
1117     const vogl_ctype_desc_t &param_ctype_desc = (param_index < 0) ? get_return_value_ctype_desc() : get_param_ctype_desc(param_index);
1118     uint64_t param_data = (param_index < 0) ? get_return_value_data() : get_param_data(param_index);
1119     uint param_size = param_ctype_desc.m_size;
1120
1121     if (param_ctype_desc.m_is_pointer)
1122     {
1123         // This func is not really intended to be used with pointer types, but try to do something.
1124         return (dest_type_size >= m_pCTypes->get_pointer_size());
1125     }
1126
1127     if (param_ctype_desc.m_loki_type_flags & LOKI_TYPE_BITMASK(LOKI_IS_FLOAT))
1128     {
1129         return dest_type_size == static_cast<uint>(param_ctype_desc.m_size);
1130     }
1131
1132     // unsigned ints = unsigned char, unsigned short int,unsigned int, unsigned long int, unsigned long long int
1133     // signed ints = signed char, short int,int, long int, long long int
1134     // integral = bool, char, wchar_t, or signed/unsigned ints
1135     bool param_is_signed = (param_ctype_desc.m_loki_type_flags & (LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_INT) | LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_LONG))) != 0;
1136     bool param_is_unsigned = (param_ctype_desc.m_loki_type_flags & (LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_INT) | LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_LONG))) != 0;
1137     VOGL_NOTE_UNUSED(param_is_unsigned);
1138     bool param_is_integral = (param_ctype_desc.m_loki_type_flags & LOKI_TYPE_BITMASK(LOKI_IS_INTEGRAL)) != 0;
1139
1140     bool dest_is_signed = (dest_type_loki_type_flags & (LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_INT) | LOKI_TYPE_BITMASK(LOKI_IS_SIGNED_LONG))) != 0;
1141     bool dest_is_unsigned = (dest_type_loki_type_flags & (LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_INT) | LOKI_TYPE_BITMASK(LOKI_IS_UNSIGNED_LONG))) != 0;
1142     VOGL_NOTE_UNUSED(dest_is_unsigned);
1143     bool dest_is_integral = (dest_type_loki_type_flags & LOKI_TYPE_BITMASK(LOKI_IS_INTEGRAL)) != 0;
1144
1145     if (param_is_integral != dest_is_integral)
1146         return false;
1147
1148     bigint128 dest_min_val, dest_max_val;
1149     bigint128::get_type_range(dest_type_size, dest_is_signed, dest_min_val, dest_max_val);
1150
1151     // not endian safe
1152     bigint128 param_val(&param_data, param_size, param_is_signed);
1153
1154     if (dest_is_signed)
1155     {
1156         return (param_val >= dest_min_val) && (param_val <= dest_max_val);
1157     }
1158     else
1159     {
1160         return param_val.unsigned_less_equal(dest_max_val);
1161     }
1162 }
1163
1164 //----------------------------------------------------------------------------------------------------------------------
1165 // vogl_trace_packet::should_always_write_as_blob_file
1166 //----------------------------------------------------------------------------------------------------------------------
1167 bool vogl_trace_packet::should_always_write_as_blob_file(const char *pFunc_name)
1168 {
1169     VOGL_FUNC_TRACER
1170
1171     if ((strstr(pFunc_name, "ShaderSource") != NULL) ||
1172         (strstr(pFunc_name, "TexSubImage") != NULL) ||
1173         (strstr(pFunc_name, "TexImage") != NULL))
1174         return true;
1175     return false;
1176 }
1177
1178 //----------------------------------------------------------------------------------------------------------------------
1179 // vogl_trace_packet::ctype_to_json_string
1180 // returns false if the returned string is a valid JSON numeric (otherwise it's a string)
1181 //----------------------------------------------------------------------------------------------------------------------
1182 void vogl_trace_packet::ctype_to_json_value(json_value &val, gl_entrypoint_id_t entrypoint_id, int param_index, uint64_t data, vogl_ctype_t ctype) const
1183 {
1184     VOGL_FUNC_TRACER
1185
1186     switch (ctype)
1187     {
1188         case VOGL_BOOL:
1189         case VOGL_GLBOOLEAN:
1190         {
1191             if (data == 0)
1192             {
1193                 val.set_value(false);
1194                 return;
1195             }
1196             else if (data == 1)
1197             {
1198                 val.set_value(true);
1199                 return;
1200             }
1201
1202             break;
1203         }
1204         case VOGL_GLENUM:
1205         {
1206             const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[entrypoint_id];
1207             VOGL_NOTE_UNUSED(entrypoint_desc);
1208             VOGL_ASSERT((param_index == -1) || (static_cast<uint>(param_index) < entrypoint_desc.m_num_params));
1209
1210             const char *pName = g_gl_enums.find_name(data, entrypoint_id, param_index);
1211
1212             if (pName)
1213             {
1214                 VOGL_ASSERT(g_gl_enums.find_enum(pName) == data);
1215
1216                 val.set_value(pName);
1217                 return;
1218             }
1219
1220             break;
1221         }
1222         case VOGL_FLOAT:
1223         case VOGL_GLFLOAT:
1224         case VOGL_GLCLAMPF:
1225         {
1226             float flt_val = *reinterpret_cast<const float *>(&data);
1227             val.set_value(flt_val);
1228
1229             dynamic_string val_as_str;
1230             val.serialize(val_as_str, false);
1231
1232             json_value test_val;
1233             if ((!test_val.deserialize(val_as_str)) || (test_val.as_float() != flt_val))
1234                 break;
1235
1236             return;
1237         }
1238         case VOGL_GLDOUBLE:
1239         case VOGL_GLCLAMPD:
1240         {
1241             double dbl_val = *reinterpret_cast<const double *>(&data);
1242             val.set_value(dbl_val);
1243
1244             dynamic_string val_as_str;
1245             val.serialize(val_as_str, false);
1246
1247             json_value test_val;
1248             if ((!test_val.deserialize(val_as_str)) || (test_val.as_double() != dbl_val))
1249                 break;
1250
1251             return;
1252         }
1253         case VOGL_GLINT:
1254         case VOGL_INT:
1255         case VOGL_INT32T:
1256         case VOGL_GLSIZEI:
1257         case VOGL_GLFIXED:
1258         {
1259             val.set_value(static_cast<int32>(data));
1260             return;
1261         }
1262         case VOGL_GLSHORT:
1263         {
1264             val.set_value(static_cast<int16>(data));
1265             return;
1266         }
1267         case VOGL_GLBYTE:
1268         {
1269             val.set_value(static_cast<int8>(data));
1270             return;
1271         }
1272         case VOGL_GLINT64:
1273         case VOGL_GLINT64EXT:
1274         {
1275             val.set_value(static_cast<int64_t>(data));
1276             return;
1277         }
1278         default:
1279         {
1280             break;
1281         }
1282     }
1283
1284     val.set_value(dynamic_string(cVarArg, "0x%" PRIX64, data).get_ptr());
1285 }
1286
1287 //----------------------------------------------------------------------------------------------------------------------
1288 // vogl_trace_packet::json_serialize_param
1289 //----------------------------------------------------------------------------------------------------------------------
1290 bool vogl_trace_packet::json_serialize_param(
1291     const char *pFunc_name,
1292     json_node &gl_params_node, int param_index, const char *pName, const uint64_t param_data, const uint param_size, vogl_ctype_t param_ctype,
1293     const void *pClient_mem, uint client_mem_size, vogl_ctype_t client_mem_ctype,
1294     const json_serialize_params &params) const
1295 {
1296     VOGL_FUNC_TRACER
1297
1298     VOGL_NOTE_UNUSED(param_size);
1299     VOGL_NOTE_UNUSED(client_mem_ctype);
1300
1301     const vogl_ctype_desc_t &param_ctype_desc = (*m_pCTypes)[param_ctype];
1302
1303     const bool has_client_memory = (pClient_mem != NULL);
1304
1305     if ((param_ctype_desc.m_is_pointer) && (param_data) && (has_client_memory))
1306     {
1307         const vogl_ctype_t pointee_ctype = param_ctype_desc.m_pointee_ctype;
1308         const uint pointee_size = (*m_pCTypes)[pointee_ctype].m_size;
1309         const bool pointee_is_ptr = (*m_pCTypes)[pointee_ctype].m_is_pointer;
1310
1311         bool print_as_cstring = false;
1312         switch (param_ctype)
1313         {
1314             case VOGL_CONST_GLUBYTE_PTR:
1315             case VOGL_CONST_GLCHAR_PTR:
1316             case VOGL_GLCHARARB_PTR:
1317             case VOGL_CONST_GLBYTE_PTR:
1318             case VOGL_GLUBYTE_PTR:
1319             case VOGL_GLCHAR_PTR:
1320             case VOGL_CONST_GLCHARARB_PTR:
1321             {
1322                 if ((client_mem_size <= 8192) && (utils::is_buffer_printable(pClient_mem, client_mem_size, true, true)))
1323                 {
1324                     print_as_cstring = true;
1325                     break;
1326                 }
1327                 break;
1328             }
1329             default:
1330                 break;
1331         }
1332
1333         if (print_as_cstring)
1334         {
1335             if ((client_mem_size >= 2) && (static_cast<const char *>(pClient_mem)[0] == '0') && (static_cast<const char *>(pClient_mem)[1] == 'x'))
1336                 print_as_cstring = false;
1337             //else if (g_vogl_entrypoint_hashmap.find(static_cast<const char *>(pClient_mem)) != g_vogl_entrypoint_hashmap.end())
1338             //   print_as_cstring = false;
1339         }
1340
1341         json_node &param_node = gl_params_node.add_object(pName);
1342
1343         if (print_as_cstring)
1344         {
1345             const char *pStr = reinterpret_cast<const char *>(pClient_mem);
1346
1347             // this was causing a crash and as far as I could tell it was a clang optimizer bug?
1348             //dynamic_string str(cVarArg, "%s", pStr);
1349             dynamic_string str(pStr);
1350             param_node.add_key_value("string", str);
1351
1352             param_node.add_key_value("ptr", dynamic_string(cVarArg, "0x%016" PRIX64, param_data));
1353         }
1354         else
1355         {
1356             param_node.add_key_value("ptr", dynamic_string(cVarArg, "0x%016" PRIX64, param_data));
1357             param_node.add_key_value("mem_size", client_mem_size);
1358
1359             uint64_t client_mem_crc64 = calc_crc64(CRC64_INIT, reinterpret_cast<const uint8 *>(pClient_mem), client_mem_size);
1360             param_node.add_key_value("crc64", dynamic_string(cVarArg, "0x%016" PRIX64, client_mem_crc64));
1361
1362             if ((pointee_size >= 1) && (pointee_size <= 8) && (math::is_power_of_2(pointee_size)) && (!(client_mem_size % pointee_size)))
1363             {
1364                 json_node &param_data_values_node = param_node.add_array("values");
1365
1366                 const uint client_mem_array_size = client_mem_size / pointee_size;
1367
1368                 for (uint i = 0; i < client_mem_array_size; i++)
1369                 {
1370                     const void *p = reinterpret_cast<const uint8 *>(pClient_mem) + i * pointee_size;
1371
1372                     uint64_t data = 0;
1373                     if (pointee_size == sizeof(uint8))
1374                         data = *reinterpret_cast<const uint8 *>(p);
1375                     else if (pointee_size == sizeof(uint16))
1376                         data = *reinterpret_cast<const uint16 *>(p);
1377                     else if (pointee_size == sizeof(uint32))
1378                         data = *reinterpret_cast<const uint32 *>(p);
1379                     else if (pointee_size == sizeof(uint64_t))
1380                         data = *reinterpret_cast<const uint64_t *>(p);
1381
1382                     json_value val;
1383                     ctype_to_json_value(val, static_cast<gl_entrypoint_id_t>(m_packet.m_entrypoint_id), param_index, data, pointee_ctype);
1384
1385                     param_data_values_node.add_value(val);
1386                 }
1387             }
1388             else
1389             {
1390                 if ((!should_always_write_as_blob_file(pFunc_name)) && (client_mem_size < params.m_blob_file_size_threshold))
1391                 {
1392                     dynamic_string buf;
1393
1394                     buf.set_len(2 + client_mem_size * 2);
1395                     buf.set_char(0, '0');
1396                     buf.set_char(1, 'x');
1397
1398                     for (uint i = 0; i < client_mem_size; i++)
1399                     {
1400                         const uint8 c = reinterpret_cast<const uint8 *>(pClient_mem)[(client_mem_size - 1) - i];
1401                         buf.set_char(2 + i * 2 + 0, utils::to_hex((c >> 4) & 0xF));
1402                         buf.set_char(2 + i * 2 + 1, utils::to_hex(c & 0xF));
1403                     }
1404
1405                     param_node.add_key_value("bytes", buf);
1406                 }
1407                 else
1408                 {
1409                     dynamic_string id;
1410
1411                     if (params.m_pBlob_manager)
1412                     {
1413                         //dynamic_string prefix(cVarArg, "%s_%s_param_%i", params.m_output_basename.get_ptr(), pFunc_name, param_index);
1414                         dynamic_string prefix(cVarArg, "%s_%s", pFunc_name, g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_index].m_pName);
1415
1416                         id = params.m_pBlob_manager->add_buf_compute_unique_id(pClient_mem, client_mem_size, prefix, "blob", &client_mem_crc64);
1417                         if (id.is_empty())
1418                         {
1419                             vogl_error_printf("%s: Failed adding blob %s to blob manager\n", VOGL_METHOD_NAME, prefix.get_ptr());
1420                             return false;
1421                         }
1422
1423                         vogl_message_printf("%s: Wrote blob id %s\n", VOGL_METHOD_NAME, id.get_ptr());
1424                     }
1425                     else
1426                     {
1427                         id = "<blob_writing_disabled>";
1428                     }
1429
1430                     param_node.add_key_value("blob_id", id);
1431                 }
1432             }
1433
1434             if (params.m_write_debug_info)
1435             {
1436                 json_node &param_dbg_node = param_node.add_object("dbg");
1437                 param_dbg_node.add_key_value("ctype", (*m_pCTypes)[param_ctype].m_pCType);
1438                 param_dbg_node.add_key_value("pointee_ctype", (*m_pCTypes)[pointee_ctype].m_pCType);
1439                 param_dbg_node.add_key_value("pointee_ctype_size", (*m_pCTypes)[pointee_ctype].m_size);
1440                 param_dbg_node.add_key_value("pointee_ctype_is_opaque", (*m_pCTypes)[pointee_ctype].m_is_opaque_pointer);
1441                 param_dbg_node.add_key_value("pointee_is_ptr", pointee_is_ptr);
1442                 param_dbg_node.add_key_value("pointee_size", pointee_size);
1443             }
1444         }
1445     }
1446     else
1447     {
1448         json_value param_value;
1449         // This helper can return a hex string (beginning with 0x chars) for values that can't be losslessly converted to a JSON numeric
1450         ctype_to_json_value(param_value, static_cast<gl_entrypoint_id_t>(m_packet.m_entrypoint_id), param_index, param_data, param_ctype);
1451         gl_params_node.add_key_value(pName, param_value);
1452     }
1453
1454     return true;
1455 }
1456
1457 //----------------------------------------------------------------------------------------------------------------------
1458 // vogl_trace_packet::convert_json_value_to_ctype_data
1459 //----------------------------------------------------------------------------------------------------------------------
1460 bool vogl_trace_packet::convert_json_value_to_ctype_data(uint64_t &data, const json_value &val, vogl_ctype_t ctype, const char *pName, int param_iter, gl_entrypoint_param_class_t param_class, bool permit_client_strings, const json_node &node, const char *pDocument_filename)
1461 {
1462     VOGL_FUNC_TRACER
1463
1464     VOGL_NOTE_UNUSED(param_class);
1465
1466     const bool is_pointer = (*m_pCTypes)[ctype].m_is_pointer;
1467
1468     // could either be a pointer to a string, or pointer value with no associated client memory, or a param value
1469     data = 0;
1470
1471     double dbl_data = 0;
1472     uint parsed_size = 0;
1473     VOGL_NOTE_UNUSED(parsed_size);
1474     bool parsed_double = false;
1475     bool parsed_hex = false;
1476
1477     if (val.is_string())
1478     {
1479         dynamic_string str(val.as_string());
1480
1481         if ((str.get_len() >= 3) && (str[0] == '0') && (str[1] == 'x'))
1482         {
1483             // hex parameter data - should be <= sizeof(uint64_t)
1484             // could be a pointer to unspecified client memory, or a non-ptr param value that couldn't be serialized to a regular json type
1485
1486             const char *pBuf = str.get_ptr();
1487             if (!string_ptr_to_uint64(pBuf, data))
1488             {
1489                 vogl_error_printf("Failed parsing hex numeric value of parameter %s\n", pName);
1490                 print_json_context(pDocument_filename, val, node);
1491                 return false;
1492             }
1493             parsed_size = sizeof(uint64_t);
1494             parsed_hex = true;
1495         }
1496         else if (is_pointer)
1497         {
1498             if (!permit_client_strings)
1499             {
1500                 vogl_error_printf("Unexpected string for parameter %s\n", pName);
1501                 print_json_context(pDocument_filename, val, node);
1502                 return false;
1503             }
1504
1505             // must be a zero terminated string originally from client memory
1506             data = 0xFFFFFFFF;
1507             parsed_size = sizeof(uint32);
1508
1509             if (!is_pointer)
1510             {
1511                 vogl_error_printf("Encountered string for non-pointer parameter %s\n", pName);
1512                 print_json_context(pDocument_filename, val, node);
1513                 return false;
1514             }
1515
1516             client_memory_desc_t &mem_desc = m_client_memory_descs[param_iter];
1517             mem_desc.m_vec_ofs = m_client_memory.size();
1518             mem_desc.m_data_size = str.get_len() + 1;
1519             mem_desc.m_pointee_ctype = (*m_pCTypes)[ctype].m_pointee_ctype;
1520
1521             m_client_memory.append(reinterpret_cast<const uint8 *>(str.get_ptr()), str.get_len() + 1);
1522         }
1523         else
1524         {
1525             uint64_t gl_enum = g_gl_enums.find_enum(str);
1526             if (gl_enum == gl_enums::cUnknownEnum)
1527             {
1528                 vogl_error_printf("Unexpected string for parameter %s\n", pName);
1529                 print_json_context(pDocument_filename, val, node);
1530                 return false;
1531             }
1532
1533             // TODO - Fix this so it doesn't downcast to uint (can it safely return uint64_t?)
1534             VOGL_ASSERT(gl_enum <= cUINT32_MAX);
1535
1536             // a GL enum
1537             data = static_cast<uint>(gl_enum);
1538             parsed_size = sizeof(uint);
1539         }
1540     }
1541     else
1542     {
1543         // parameter data
1544         if (val.is_bool())
1545         {
1546             bool b = val.as_bool();
1547             memcpy(&data, &b, 1);
1548             parsed_size = 1;
1549         }
1550         else if (val.is_double())
1551         {
1552             dbl_data = val.as_double();
1553             memcpy(&data, &dbl_data, sizeof(dbl_data));
1554             parsed_size = sizeof(dbl_data);
1555             parsed_double = true;
1556         }
1557         else if (val.is_int())
1558         {
1559             int64_t v = val.as_int64();
1560             memcpy(&data, &v, sizeof(data));
1561             parsed_size = sizeof(int64_t);
1562         }
1563         else
1564         {
1565             vogl_error_printf("Invalid JSON node type for parameter %s\n", pName);
1566             print_json_context(pDocument_filename, val, node);
1567             return false;
1568         }
1569     }
1570
1571     int64_t idata = static_cast<int64_t>(data);
1572
1573     switch (ctype)
1574     {
1575         case VOGL_FLOAT:
1576         case VOGL_GLFLOAT:
1577         case VOGL_GLCLAMPF:
1578         {
1579             float v = 0;
1580             if (parsed_double)
1581                 v = static_cast<float>(dbl_data);
1582             else if (parsed_hex)
1583                 v = *reinterpret_cast<const float *>(&data);
1584             else
1585             {
1586                 v = static_cast<float>(idata);
1587                 vogl_debug_printf("Parameter %s should be a float, but a non-float value was specified in the JSON file\n", pName);
1588                 print_json_context(pDocument_filename, val, node, cDebugConsoleMessage);
1589             }
1590
1591             data = 0;
1592             memcpy(&data, &v, sizeof(v));
1593             break;
1594         }
1595         case VOGL_GLDOUBLE:
1596         case VOGL_GLCLAMPD:
1597         {
1598             double v = 0;
1599             if (parsed_double)
1600                 v = dbl_data;
1601             else if (parsed_hex)
1602                 v = *reinterpret_cast<const double *>(&data);
1603             else
1604             {
1605                 v = static_cast<double>(idata);
1606                 vogl_debug_printf("Parameter %s should be a double, but a non-double value was specified in the JSON file\n", pName);
1607                 print_json_context(pDocument_filename, val, node, cDebugConsoleMessage);
1608             }
1609             memcpy(&data, &v, sizeof(v));
1610             break;
1611         }
1612         default:
1613         {
1614             if (parsed_double)
1615             {
1616                 vogl_warning_printf("Float point value specified for non-float parameter %s, casting to integer\n", pName);
1617                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1618                 data = idata = static_cast<int64_t>(dbl_data);
1619             }
1620             break;
1621         }
1622     } // switch (ctype)
1623
1624     switch (ctype)
1625     {
1626         case VOGL_BOOL:
1627         case VOGL_GLBOOLEAN:
1628         {
1629             //if ((data != 0) && (data != 1))
1630             //   vogl_warning_printf("Expected bool value for parameter %s\n", pName);
1631             break;
1632         }
1633         case VOGL_GLBITFIELD:
1634         case VOGL_GLUINT:
1635         case VOGL_UNSIGNED_INT:
1636         case VOGL_GLENUM:
1637         case VOGL_GLHANDLEARB:
1638         {
1639             if (data > cUINT32_MAX)
1640             {
1641                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1642                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1643             }
1644             break;
1645         }
1646         case VOGL_GLINT:
1647         case VOGL_INT:
1648         case VOGL_INT32T:
1649         case VOGL_GLFIXED:
1650         case VOGL_GLSIZEI:
1651         {
1652             if ((idata < cINT32_MIN) || (idata > cINT32_MAX))
1653             {
1654                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1655                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1656             }
1657             break;
1658         }
1659         case VOGL_GLBYTE:
1660         case VOGL_GLCHARARB:
1661         {
1662             if ((idata < -cINT8_MAX) || (idata > cINT8_MAX))
1663             {
1664                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1665                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1666             }
1667             break;
1668         }
1669         case VOGL_GLCHAR:
1670         case VOGL_GLUBYTE:
1671         {
1672             if (data > cUINT8_MAX)
1673             {
1674                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1675                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1676             }
1677             break;
1678         }
1679         case VOGL_GLHALFNV:
1680         case VOGL_GLUSHORT:
1681         {
1682             if (data > cUINT16_MAX)
1683             {
1684                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1685                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1686             }
1687             break;
1688         }
1689         case VOGL_GLSHORT:
1690         {
1691             if ((idata < cINT16_MIN) || (idata > cINT16_MAX))
1692             {
1693                 vogl_warning_printf("Value out of range for parameter %s\n", pName);
1694                 print_json_context(pDocument_filename, val, node, cWarningConsoleMessage);
1695             }
1696             break;
1697         }
1698         default:
1699             break;
1700     }
1701
1702     return true;
1703 }
1704
1705 //----------------------------------------------------------------------------------------------------------------------
1706 // vogl_trace_packet::json_deserialize_param
1707 //----------------------------------------------------------------------------------------------------------------------
1708 bool vogl_trace_packet::json_deserialize_param(
1709     uint64_t cur_call_counter, const char *pFunc_name,
1710     const json_node &params_node, uint param_iter, const char *pParam_name, gl_entrypoint_param_class_t param_class, const vogl_ctype_desc_t &param_ctype_desc,
1711     const char *pDocument_filename, const vogl_blob_manager *pBlob_manager)
1712 {
1713     VOGL_FUNC_TRACER
1714
1715     VOGL_NOTE_UNUSED(cur_call_counter);
1716
1717     int param_index = params_node.find_key(pParam_name);
1718     if (param_index < 0)
1719     {
1720         vogl_error_printf("Failed finding function parameter \"%s\"\n", pParam_name);
1721         print_json_context(pDocument_filename, params_node);
1722         return false;
1723     }
1724
1725     const json_value &val = params_node.get_value(param_index);
1726     if ((val.is_null()) || (val.is_array()))
1727     {
1728         vogl_error_printf("Invalid JSON node type for parameter %s\n", pParam_name);
1729         print_json_context(pDocument_filename, params_node);
1730         return false;
1731     }
1732
1733     if (val.is_object())
1734     {
1735         // must be pointer to client memory of some sort
1736         if (!param_ctype_desc.m_is_pointer)
1737         {
1738             vogl_error_printf("A memory object was specified for parameter %s, but parameter is not a pointer to client memory\n", pParam_name);
1739             print_json_context(pDocument_filename, val, params_node);
1740             return false;
1741         }
1742
1743         vogl_ctype_t pointee_ctype = param_ctype_desc.m_pointee_ctype;
1744         VOGL_ASSERT(pointee_ctype != VOGL_INVALID_CTYPE);
1745
1746         uint pointee_ctype_size = (*m_pCTypes)[pointee_ctype].m_size;
1747
1748         const json_node *pParam_obj = val.get_node_ptr();
1749
1750         uint64_t ptr = 0;
1751         if (!get_uint64_from_json_node(*pParam_obj, "ptr", ptr, 0))
1752         {
1753             vogl_warning_printf("Failed parsing ptr field of parameter %s (the pointer is only for debugging, not replay, so this is not a hard failure)\n", pParam_name);
1754             print_json_context(pDocument_filename, *pParam_obj, cWarningConsoleMessage);
1755         }
1756
1757         if (pParam_obj->has_key("string"))
1758         {
1759             const char *pStr = pParam_obj->find_value("string").as_string_ptr();
1760             uint str_len = vogl_strlen(pStr);
1761
1762             client_memory_desc_t &mem_desc = m_client_memory_descs[param_iter];
1763             mem_desc.m_vec_ofs = m_client_memory.size();
1764             mem_desc.m_data_size = str_len + 1;
1765             mem_desc.m_pointee_ctype = pointee_ctype;
1766
1767             m_client_memory.append(reinterpret_cast<const uint8 *>(pStr), str_len + 1);
1768
1769             m_param_data[param_iter] = ptr;
1770
1771             VOGL_ASSERT(param_ctype_desc.m_size <= cUINT8_MAX);
1772             m_param_size[param_iter] = param_ctype_desc.m_size;
1773             m_param_ctype[param_iter] = param_ctype_desc.m_ctype;
1774         }
1775         else
1776         {
1777             uint64_t mem_size = 0;
1778             if (!get_uint64_from_json_node(*pParam_obj, "mem_size", mem_size, 0))
1779             {
1780                 vogl_error_printf("Failed parsing mem_size field of parameter %s\n", pParam_name);
1781                 print_json_context(pDocument_filename, *pParam_obj);
1782                 return false;
1783             }
1784
1785             if (mem_size > 0x7FFF0000)
1786             {
1787                 vogl_error_printf("Client memory blob size is too large for parameter %s\n", pParam_name);
1788                 print_json_context(pDocument_filename, *pParam_obj);
1789                 return false;
1790             }
1791
1792             uint64_t blob_crc64 = 0;
1793             bool has_blob_crc64 = get_uint64_from_json_node(*pParam_obj, "crc64", blob_crc64, 0);
1794
1795             vogl::vector<uint8> blob(static_cast<uint32>(mem_size));
1796
1797             if (pParam_obj->find_child("values"))
1798             {
1799                 if (pointee_ctype_size <= 0)
1800                 {
1801                     vogl_error_printf("Can't specify a values array for void* parameter %s\n", pParam_name);
1802                     print_json_context(pDocument_filename, *pParam_obj);
1803                     return false;
1804                 }
1805
1806                 const json_node *pValues = pParam_obj->find_child("values");
1807
1808                 if (!pValues->is_array())
1809                 {
1810                     vogl_error_printf("Expected array for values field of parameter %s\n", pParam_name);
1811                     print_json_context(pDocument_filename, *pValues);
1812                     return false;
1813                 }
1814
1815                 uint num_vals = pValues->size();
1816                 if (num_vals != (mem_size / pointee_ctype_size))
1817                 {
1818                     vogl_error_printf("Array size is invalid for parameter %s\n", pParam_name);
1819                     print_json_context(pDocument_filename, *pValues);
1820                     return false;
1821                 }
1822
1823                 if ((mem_size % pointee_ctype_size) != 0)
1824                 {
1825                     vogl_error_printf("Mem size is invalid for parameter %s\n", pParam_name);
1826                     print_json_context(pDocument_filename, *pValues);
1827                     return false;
1828                 }
1829
1830                 for (uint val_iter = 0; val_iter < num_vals; val_iter++)
1831                 {
1832                     const json_value &val = pValues->get_value(val_iter);
1833
1834                     uint64_t param_data;
1835                     if (!convert_json_value_to_ctype_data(param_data, val, pointee_ctype, "values", -1, VOGL_VALUE_PARAM, false, *pValues, pDocument_filename))
1836                         return false;
1837
1838                     memcpy(blob.get_ptr() + val_iter * pointee_ctype_size, &param_data, pointee_ctype_size);
1839                 }
1840             }
1841             else if (pParam_obj->has_key("blob_id"))
1842             {
1843                 dynamic_string blob_id;
1844                 pParam_obj->get_value_as_string("blob_id", blob_id);
1845
1846                 if (!pBlob_manager)
1847                 {
1848                     vogl_error_printf("%s: No blob manager specified, blob id %s\n", VOGL_METHOD_NAME, blob_id.get_ptr());
1849                     print_json_context(pDocument_filename, *pParam_obj);
1850                     return false;
1851                 }
1852
1853                 uint8_vec data_blob;
1854                 if (!pBlob_manager->get(blob_id, data_blob))
1855                 {
1856                     vogl_error_printf("%s: Failed retrieving data blob, blob size %" PRIu64 " blob id %s CRC64 0x%" PRIX64 "\n", VOGL_METHOD_NAME, mem_size, blob_id.get_ptr(), blob_crc64);
1857                     print_json_context(pDocument_filename, *pParam_obj);
1858                     return false;
1859                 }
1860
1861                 // TODO: We'll support uint64_t blob sizes eventually
1862                 uint64_t file_size = data_blob.size();
1863                 if (file_size > cUINT32_MAX)
1864                 {
1865                     vogl_error_printf("%s: Blob file %s is too large (%" PRIu64 ")\n", VOGL_METHOD_NAME, blob_id.get_ptr(), file_size);
1866                     print_json_context(pDocument_filename, *pParam_obj);
1867                     return false;
1868                 }
1869
1870                 blob.swap(data_blob);
1871
1872                 if (file_size != mem_size)
1873                 {
1874                     vogl_warning_printf("Unexpected size of blob file %s (should be %" PRIu64 " bytes, but is %" PRIu64 " bytes), reading all of file and hoping for the best\n", blob_id.get_ptr(), mem_size, file_size);
1875                     print_json_context(pDocument_filename, *pParam_obj, cWarningConsoleMessage);
1876                 }
1877             }
1878             else if (pParam_obj->has_key("bytes"))
1879             {
1880                 const json_value &bytes_val = pParam_obj->find_value("bytes");
1881                 const char *pByte_str = bytes_val.as_string_ptr();
1882                 if (!pByte_str)
1883                 {
1884                     vogl_error_printf("Expected bytes value string for parameter %s\n", pFunc_name);
1885                     print_json_context(pDocument_filename, *pParam_obj);
1886                     return false;
1887                 }
1888
1889                 uint bytes_len = vogl_strlen(pByte_str);
1890                 if ((bytes_len != 2 + 2 * mem_size) || (pByte_str[0] != '0') || (pByte_str[1] != 'x'))
1891                 {
1892                     vogl_error_printf("Can't parse bytes value string for parameter %s (either size is bad, or string doesn't start with 0x)\n", pFunc_name);
1893                     print_json_context(pDocument_filename, *pParam_obj);
1894                     return false;
1895                 }
1896
1897                 for (uint i = 0; i < mem_size; i++)
1898                 {
1899                     char c0 = pByte_str[2 + i * 2 + 0];
1900                     char c1 = pByte_str[2 + i * 2 + 1];
1901
1902                     int val_c0 = utils::from_hex(c0);
1903                     int val_c1 = utils::from_hex(c1);
1904
1905                     if ((val_c0 < 0) || (val_c1 < 0))
1906                     {
1907                         vogl_error_printf("Non-hex char in bytes value at byte index %u for parameter %s\n", i, pFunc_name);
1908                         print_json_context(pDocument_filename, *pParam_obj);
1909                         return false;
1910                     }
1911
1912                     blob[(static_cast<uint>(mem_size) - 1) - i] = (val_c0 << 4) | (val_c1);
1913                 }
1914             }
1915             else
1916             {
1917                 vogl_error_printf("Failed parsing array parameter %s\n", pParam_name);
1918                 print_json_context(pDocument_filename, *pParam_obj);
1919                 return false;
1920             }
1921
1922             if (has_blob_crc64)
1923             {
1924                 uint64_t check_crc64 = calc_crc64(CRC64_INIT, blob.get_ptr(), static_cast<size_t>(mem_size));
1925                 if (check_crc64 != blob_crc64)
1926                 {
1927                     vogl_warning_printf("Blob CRC64 check failed for parameter %s (expected 0x%016" PRIX64 " got 0x%016" PRIX64 ")\n", pParam_name, blob_crc64, check_crc64);
1928                     print_json_context(pDocument_filename, *pParam_obj, cWarningConsoleMessage);
1929                 }
1930             }
1931
1932             m_param_data[param_iter] = ptr;
1933
1934             VOGL_ASSERT(param_ctype_desc.m_size <= cUINT8_MAX);
1935             m_param_size[param_iter] = param_ctype_desc.m_size;
1936             m_param_ctype[param_iter] = param_ctype_desc.m_ctype;
1937
1938             client_memory_desc_t &mem_desc = m_client_memory_descs[param_iter];
1939             mem_desc.m_vec_ofs = m_client_memory.size();
1940             mem_desc.m_data_size = blob.size();
1941             mem_desc.m_pointee_ctype = pointee_ctype;
1942
1943             m_client_memory.append(blob.get_ptr(), blob.size());
1944         }
1945     }
1946     else
1947     {
1948         uint64_t param_data;
1949         if (!convert_json_value_to_ctype_data(param_data, val, param_ctype_desc.m_ctype, pParam_name, param_iter, param_class, true, params_node, pDocument_filename))
1950             return false;
1951
1952         m_param_data[param_iter] = 0;
1953         memcpy(&m_param_data[param_iter], &param_data, param_ctype_desc.m_size);
1954
1955         VOGL_ASSERT(param_ctype_desc.m_size <= cUINT8_MAX);
1956         m_param_size[param_iter] = param_ctype_desc.m_size;
1957         m_param_ctype[param_iter] = param_ctype_desc.m_ctype;
1958
1959     } // val.is_object()
1960
1961     return true;
1962 }
1963
1964 //----------------------------------------------------------------------------------------------------------------------
1965 // vogl_trace_packet::get_uint64_from_json_node
1966 // TODO: This is now outdated, we can retrieve uint64_t's directly using members in the json_node class
1967 //----------------------------------------------------------------------------------------------------------------------
1968 bool vogl_trace_packet::get_uint64_from_json_node(const json_node &node, const char *pKey, uint64_t &val, uint64_t def)
1969 {
1970     VOGL_FUNC_TRACER
1971
1972     int key_index = node.find_key(pKey);
1973     if (key_index < 0)
1974     {
1975         val = def;
1976         return false;
1977     }
1978
1979     const json_value &json_val = node.get_value(key_index);
1980
1981     if (json_val.is_string())
1982     {
1983         const char *pBuf = json_val.as_string_ptr();
1984         if (!string_ptr_to_uint64(pBuf, val))
1985         {
1986             val = def;
1987             return false;
1988         }
1989     }
1990     else
1991     {
1992         int64_t ival;
1993         if (!json_val.get_numeric(ival, static_cast<int64_t>(def)))
1994         {
1995             val = def;
1996             return false;
1997         }
1998         VOGL_ASSERT(ival >= 0);
1999         val = static_cast<uint64_t>(ival);
2000     }
2001
2002     return true;
2003 }
2004
2005 //----------------------------------------------------------------------------------------------------------------------
2006 // vogl_trace_packet::force_value_to_type
2007 //----------------------------------------------------------------------------------------------------------------------
2008 bool vogl_trace_packet::force_value_to_type(value &val, value_data_type type)
2009 {
2010     VOGL_FUNC_TRACER
2011
2012     switch (type)
2013     {
2014         case cDTBool:
2015         {
2016             val.set_bool(val.get_bool());
2017             break;
2018         }
2019         case cDTInt8:
2020         {
2021             val.set_int8(val.get_int8());
2022             break;
2023         }
2024         case cDTUInt8:
2025         {
2026             val.set_uint8(val.get_uint8());
2027             break;
2028         }
2029         case cDTInt16:
2030         {
2031             val.set_int16(val.get_int16());
2032             break;
2033         }
2034         case cDTUInt16:
2035         {
2036             val.set_uint16(val.get_uint16());
2037             break;
2038         }
2039         case cDTInt:
2040         {
2041             val.set_int(val.get_int());
2042             break;
2043         }
2044         case cDTUInt:
2045         {
2046             val.set_uint(val.get_uint());
2047             break;
2048         }
2049         case cDTInt64:
2050         {
2051             val.set_int64(val.get_int64());
2052             break;
2053         }
2054         case cDTUInt64:
2055         {
2056             val.set_uint64(val.get_uint64());
2057             break;
2058         }
2059         case cDTFloat:
2060         {
2061             val.set_float(val.get_float());
2062             break;
2063         }
2064         case cDTDouble:
2065         {
2066             val.set_double(val.get_double());
2067             break;
2068         }
2069         case cDTVoidPtr:
2070         {
2071             val.set_void_ptr((void *)val.get_uint64());
2072             break;
2073         }
2074         case cDTString:
2075         {
2076             if (val.get_data_type() != cDTString)
2077                 return false;
2078             break;
2079         }
2080         case cDTStringHash:
2081         {
2082             val.set_string_hash(val.get_string_hash());
2083             break;
2084         }
2085         case cDTBlob:
2086         {
2087             if (val.get_data_type() != cDTBlob)
2088                 return false;
2089             break;
2090         }
2091         case cDTJSONDoc:
2092         {
2093             if (val.get_data_type() != cDTJSONDoc)
2094                 return false;
2095             break;
2096         }
2097         default:
2098             return false;
2099     }
2100
2101     return true;
2102 }
2103
2104 //----------------------------------------------------------------------------------------------------------------------
2105 // vogl_trace_packet::fixup_manually_edited_params
2106 //----------------------------------------------------------------------------------------------------------------------
2107 bool vogl_trace_packet::fixup_manually_edited_params(gl_entrypoint_id_t gl_entrypoint_id, const char *pGL_func_name, uint64_t cur_call_counter)
2108 {
2109     VOGL_FUNC_TRACER
2110
2111     if ((gl_entrypoint_id == VOGL_ENTRYPOINT_glShaderSource) || (gl_entrypoint_id == VOGL_ENTRYPOINT_glShaderSourceARB))
2112     {
2113         //int count = get_param_data(1);
2114         GLsizei count = get_param_value<GLsizei>(1);
2115         if (count)
2116         {
2117             int32 *pLengths = get_param_client_memory<int32>(3);
2118             if ((pLengths) && (get_param_client_memory_data_size(3) == count * sizeof(int32)))
2119             {
2120                 for (GLsizei i = 0; i < count; i++)
2121                 {
2122                     key_value_map::const_iterator it = m_key_value_map.find(i);
2123                     if (it == m_key_value_map.end())
2124                     {
2125                         vogl_error_printf("GL func %s call counter %" PRIu64 ": Failed finding shader source blob string in GL key value map\n", pGL_func_name, cur_call_counter);
2126                         return false;
2127                     }
2128
2129                     const uint8_vec *pBlob = it->second.get_blob();
2130                     if (!pBlob)
2131                     {
2132                         vogl_error_printf("GL func %s call counter %" PRIu64 ": Failed finding shader source blob string in GL key value map\n", pGL_func_name, cur_call_counter);
2133                         return false;
2134                     }
2135
2136                     uint l = pLengths[i];
2137
2138                     if (pBlob->size() != l)
2139                     {
2140                         vogl_warning_printf("GL func %s call counter %" PRIu64 ": Shader source code line %u: blob size is %u bytes, but length field is %u bytes: Fixing up length field to match blob's size\n",
2141                                            pGL_func_name, cur_call_counter, static_cast<uint>(i), pBlob->size(), l);
2142                         pLengths[i] = pBlob->size();
2143                     }
2144                 }
2145             }
2146         }
2147     }
2148
2149     return true;
2150 }
2151
2152 //----------------------------------------------------------------------------------------------------------------------
2153 // vogl_trace_packet::pretty_print_param
2154 //----------------------------------------------------------------------------------------------------------------------
2155 bool vogl_trace_packet::pretty_print(dynamic_string &str, bool type_info) const
2156 {
2157     VOGL_FUNC_TRACER
2158
2159     if (!m_is_valid)
2160     {
2161         str.empty();
2162         return false;
2163     }
2164
2165     dynamic_string return_val;
2166     if (!pretty_print_return_value(return_val, type_info))
2167     {
2168         str.empty();
2169         return false;
2170     }
2171
2172     str.format("%s %s(", return_val.get_ptr(), get_entrypoint_desc().m_pName);
2173
2174     dynamic_string param_val;
2175     for (uint i = 0; i < m_total_params; i++)
2176     {
2177         if (!pretty_print_param(param_val, i, type_info))
2178         {
2179             str.empty();
2180             return false;
2181         }
2182
2183         str += param_val;
2184
2185         if (i != (m_total_params - 1))
2186             str += ", ";
2187     }
2188
2189     str += ")";
2190
2191     return true;
2192 }
2193
2194 //----------------------------------------------------------------------------------------------------------------------
2195 // vogl_trace_packet::pretty_print_param
2196 //----------------------------------------------------------------------------------------------------------------------
2197 bool vogl_trace_packet::pretty_print_param(dynamic_string &str, uint param_index, bool type_info) const
2198 {
2199     VOGL_FUNC_TRACER
2200
2201     str.empty();
2202
2203     if (!m_is_valid)
2204         return false;
2205
2206     const bool is_return_param = has_return_value() && (param_index == m_total_params);
2207
2208     VOGL_ASSERT((param_index < m_total_params) || is_return_param);
2209
2210     uint64_t val_data = m_param_data[param_index];
2211     //uint val_size = m_param_size[param_index];
2212
2213     const vogl_ctype_desc_t &ctype_desc = trace_ctypes()[m_param_ctype[param_index]];
2214
2215     if (type_info)
2216         str.format("(%s) ", ctype_desc.m_pCType);
2217
2218     bool handled = false;
2219
2220     if (ctype_desc.m_is_pointer)
2221     {
2222         const void *pClient_mem = NULL;
2223         uint client_mem_size = 0;
2224
2225         if (m_client_memory_descs[param_index].m_vec_ofs >= 0)
2226         {
2227             pClient_mem = &m_client_memory[m_client_memory_descs[param_index].m_vec_ofs];
2228             client_mem_size = m_client_memory_descs[param_index].m_data_size;
2229         }
2230
2231         if ((pClient_mem) && (client_mem_size))
2232         {
2233             //const vogl_ctype_t pointee_ctype = ctype_desc.m_pointee_ctype;
2234             //const uint pointee_size = (*m_pCTypes)[pointee_ctype].m_size;
2235             //const bool pointee_is_ptr = (*m_pCTypes)[pointee_ctype].m_is_pointer;
2236
2237             bool print_as_cstring = false;
2238             switch (ctype_desc.m_ctype)
2239             {
2240                 case VOGL_CONST_GLUBYTE_PTR:
2241                 case VOGL_CONST_GLCHAR_PTR:
2242                 case VOGL_GLCHARARB_PTR:
2243                 case VOGL_CONST_GLBYTE_PTR:
2244                 case VOGL_GLUBYTE_PTR:
2245                 case VOGL_GLCHAR_PTR:
2246                 case VOGL_CONST_GLCHARARB_PTR:
2247                 {
2248                     if ((client_mem_size <= 64) && (utils::is_buffer_printable(pClient_mem, client_mem_size, true, true)))
2249                     {
2250                         print_as_cstring = true;
2251                         break;
2252                     }
2253                     break;
2254                 }
2255                 default:
2256                     break;
2257             }
2258
2259             if (print_as_cstring)
2260             {
2261                 const char *pStr = reinterpret_cast<const char *>(pClient_mem);
2262                 str.format_append("\"%s\"", pStr);
2263
2264                 handled = true;
2265             }
2266         }
2267     }
2268     else
2269     {
2270         switch (ctype_desc.m_ctype)
2271         {
2272             case VOGL_BOOL:
2273             case VOGL_GLBOOLEAN:
2274             {
2275                 if (val_data == 0)
2276                 {
2277                     str += "false";
2278                     handled = true;
2279                 }
2280                 else if (val_data == 1)
2281                 {
2282                     str += "true";
2283                     handled = true;
2284                 }
2285
2286                 break;
2287             }
2288             case VOGL_GLENUM:
2289             {
2290                 const char *pName = g_gl_enums.find_name(val_data, get_entrypoint_id(), is_return_param ? -1 : param_index);
2291
2292                 if (pName)
2293                 {
2294                     VOGL_ASSERT(g_gl_enums.find_enum(pName) == val_data);
2295
2296                     str += pName;
2297                     handled = true;
2298                 }
2299
2300                 break;
2301             }
2302             case VOGL_FLOAT:
2303             case VOGL_GLFLOAT:
2304             case VOGL_GLCLAMPF:
2305             {
2306                 str.format_append("%f", *reinterpret_cast<const float *>(&val_data));
2307                 handled = true;
2308                 break;
2309             }
2310             case VOGL_GLDOUBLE:
2311             case VOGL_GLCLAMPD:
2312             {
2313                 str.format_append("%f", *reinterpret_cast<const double *>(&val_data));
2314                 handled = true;
2315                 break;
2316             }
2317             case VOGL_GLINT:
2318             case VOGL_INT:
2319             case VOGL_INT32T:
2320             case VOGL_GLSIZEI:
2321             case VOGL_GLFIXED:
2322             {
2323                 str.format_append("%i", *reinterpret_cast<const int32 *>(&val_data));
2324                 handled = true;
2325                 break;
2326             }
2327             case VOGL_GLSHORT:
2328             {
2329                 str.format_append("%i", *reinterpret_cast<const int16 *>(&val_data));
2330                 handled = true;
2331                 break;
2332             }
2333             case VOGL_GLBYTE:
2334             {
2335                 str.format_append("%i", *reinterpret_cast<const int8 *>(&val_data));
2336                 handled = true;
2337                 break;
2338             }
2339             case VOGL_GLINT64:
2340             case VOGL_GLINT64EXT:
2341             {
2342                 str.format_append("%" PRIi64, val_data);
2343                 handled = true;
2344                 break;
2345             }
2346             default:
2347                 break;
2348         }
2349     }
2350
2351     if (!handled)
2352     {
2353         if ((ctype_desc.m_is_pointer) && (!type_info))
2354             str.format_append("(%s) 0x%" PRIX64, ctype_desc.m_pCType, val_data);
2355         else
2356             str.format_append("0x%" PRIX64, val_data);
2357     }
2358
2359     return true;
2360 }
2361
2362 //----------------------------------------------------------------------------------------------------------------------
2363 // vogl_trace_packet::pretty_print_return_value
2364 //----------------------------------------------------------------------------------------------------------------------
2365 bool vogl_trace_packet::pretty_print_return_value(dynamic_string &str, bool type_info) const
2366 {
2367     VOGL_FUNC_TRACER
2368
2369     str.empty();
2370
2371     if (!m_is_valid)
2372         return false;
2373
2374     if (!has_return_value())
2375     {
2376         str = "void";
2377         return true;
2378     }
2379
2380     pretty_print_param(str, m_total_params, type_info);
2381     return true;
2382 }
2383
2384 //----------------------------------------------------------------------------------------------------------------------
2385 // vogl_does_packet_refer_to_program
2386 // This conservatively determines if a trace packet refers to a GL program or ARB program object (there may be some
2387 // false positives in here because ARB program and shader objects live in the same namespace).
2388 //----------------------------------------------------------------------------------------------------------------------
2389 bool vogl_does_packet_refer_to_program(const vogl_trace_packet &gl_packet, GLuint &program)
2390 {
2391     VOGL_FUNC_TRACER
2392
2393     program = 0;
2394
2395     gl_entrypoint_id_t entrypoint_id = gl_packet.get_entrypoint_id();
2396     const gl_entrypoint_desc_t &entrypoint_desc = gl_packet.get_entrypoint_desc();
2397
2398     if ((entrypoint_desc.m_return_namespace == VOGL_NAMESPACE_PROGRAMS) || (entrypoint_id == VOGL_ENTRYPOINT_glCreateProgramObjectARB))
2399     {
2400         program = gl_packet.get_return_value<GLuint>();
2401         return true;
2402     }
2403
2404     for (uint i = 0; i < entrypoint_desc.m_num_params; i++)
2405     {
2406         vogl_namespace_t param_namespace = g_vogl_entrypoint_param_descs[entrypoint_id][i].m_namespace;
2407
2408         if (param_namespace == VOGL_NAMESPACE_PROGRAMS)
2409         {
2410             // TODO: Make sure this never can be a ptr to an array of handles
2411             VOGL_VERIFY(!gl_packet.get_param_ctype_desc(i).m_is_pointer);
2412             program = gl_packet.get_param_value<GLuint>(i);
2413             return true;
2414         }
2415
2416         // Special case the GL_ARB_shader_objects/GL_ARB_vertex_shader GLhandleARB, which alias programs.
2417         // We want to reject handles that are clearly shader objects, and accept everything else.
2418         if ((!i) && (param_namespace == VOGL_NAMESPACE_GLHANDLEARB))
2419         {
2420             bool accept = true;
2421
2422             switch (entrypoint_id)
2423             {
2424                 case VOGL_ENTRYPOINT_glShaderSourceARB:
2425                 case VOGL_ENTRYPOINT_glCompileShaderARB:
2426                 {
2427                     accept = false;
2428                     break;
2429                 }
2430                 default:
2431                     break;
2432             }
2433
2434             if (accept)
2435             {
2436                 // TODO: Make sure this never can be a ptr to an array of handles
2437                 VOGL_VERIFY(!gl_packet.get_param_ctype_desc(i).m_is_pointer);
2438                 program = gl_packet.get_param_value<GLuint>(i);
2439                 return true;
2440             }
2441         }
2442     }
2443
2444     return false;
2445 }
2446
2447 //----------------------------------------------------------------------------------------------------------------------
2448 // vogl_write_glInternalTraceCommandRAD
2449 //----------------------------------------------------------------------------------------------------------------------
2450 bool vogl_write_glInternalTraceCommandRAD(data_stream &stream, const vogl_ctypes *pCTypes, GLuint cmd, GLuint size, const GLubyte *data)
2451 {
2452     VOGL_FUNC_TRACER
2453
2454     vogl_trace_packet packet(pCTypes);
2455
2456     packet.begin_construction(VOGL_ENTRYPOINT_glInternalTraceCommandRAD, 0, 0, 0, utils::RDTSC());
2457
2458     uint64_t cur_rdtsc = utils::RDTSC();
2459     packet.set_gl_begin_rdtsc(cur_rdtsc);
2460     packet.set_gl_end_rdtsc(cur_rdtsc + 1);
2461
2462     packet.set_param(0, VOGL_GLUINT, &cmd, sizeof(cmd));
2463     packet.set_param(1, VOGL_GLUINT, &size, sizeof(size));
2464
2465     vogl_trace_ptr_value ptr_val = reinterpret_cast<vogl_trace_ptr_value>(data);
2466     packet.set_param(2, VOGL_CONST_GLUBYTE_PTR, &ptr_val, packet.get_ctypes()->get_pointer_size());
2467
2468     switch (cmd)
2469     {
2470         case cITCRDemarcation:
2471         {
2472             break;
2473         }
2474         case cITCRKeyValueMap:
2475         {
2476             if ((size == sizeof(key_value_map)) && (data))
2477             {
2478                 // Directly jam in the key value map, so it properly serializes as readable JSON.
2479                 packet.get_key_value_map() = *reinterpret_cast<const key_value_map *>(data);
2480             }
2481             else
2482             {
2483                 VOGL_ASSERT_ALWAYS;
2484                 return false;
2485             }
2486             break;
2487         }
2488         default:
2489         {
2490             vogl_error_printf("%s: Unknown trace command type %u\n", VOGL_FUNCTION_NAME, cmd);
2491             VOGL_ASSERT_ALWAYS;
2492             return false;
2493         }
2494     }
2495
2496     packet.end_construction(utils::RDTSC());
2497
2498     return packet.serialize(stream);
2499 }