]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_trace_packet.h
Initial vogl checkin
[vogl] / src / voglcommon / vogl_trace_packet.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 #ifndef VOGL_TRACE_PACKET_H
27 #define VOGL_TRACE_PACKET_H
28
29 #include "vogl_core.h"
30 #include "vogl_data_stream.h"
31 #include "vogl_value.h"
32 #include "vogl_console.h"
33
34 #include "vogl_trace_stream_types.h"
35 #include "vogl_common.h"
36 #include "vogl_blob_manager.h"
37
38 #include "TypeTraits.h"
39
40 //----------------------------------------------------------------------------------------------------------------------
41 // class vogl_client_memory_array
42 //----------------------------------------------------------------------------------------------------------------------
43 class vogl_client_memory_array
44 {
45 public:
46     inline vogl_client_memory_array(vogl_ctype_t element_ctype, const void *p, uint element_size, uint num_elements)
47         : m_element_ctype(element_ctype), m_pPtr(static_cast<const uint8 *>(p)), m_element_size(element_size), m_num_elements(num_elements)
48     {
49         VOGL_FUNC_TRACER
50     }
51
52     inline vogl_ctype_t get_element_ctype() const
53     {
54         return m_element_ctype;
55     }
56
57     inline const void *get_ptr() const
58     {
59         return m_pPtr;
60     }
61
62     template <typename T>
63     inline const T *get_value_ptr() const
64     {
65         return reinterpret_cast<const T *>(m_pPtr);
66     }
67
68     inline uint size() const
69     {
70         return m_num_elements;
71     }
72     inline uint get_element_size() const
73     {
74         return m_element_size;
75     }
76     inline uint get_size_in_bytes() const
77     {
78         return m_element_size * m_num_elements;
79     }
80
81     template <typename T>
82     inline T get_element(uint index) const
83     {
84         VOGL_FUNC_TRACER
85
86         VOGL_ASSERT(index < m_num_elements);
87         T result;
88         if ((!m_pPtr) || (!m_num_elements))
89         {
90             VOGL_ASSERT_ALWAYS;
91             utils::zero_object(result);
92         }
93         else
94         {
95             uint n = math::minimum<uint>(sizeof(T), m_element_size);
96             if (n < sizeof(T))
97                 utils::zero_object(result);
98             memcpy(&result, m_pPtr + m_element_size * index, n);
99         }
100         return result;
101     }
102
103     vogl_ctype_t m_element_ctype;
104
105     const uint8 *m_pPtr;
106     uint m_element_size;
107     uint m_num_elements;
108 };
109
110 //----------------------------------------------------------------------------------------------------------------------
111 // class vogl_trace_packet
112 // Keep this in sync with class vogl_entrypoint_serializer
113 // This object is somewhat expensive to construct - so keep it around!
114 //----------------------------------------------------------------------------------------------------------------------
115 class vogl_trace_packet
116 {
117 public:
118     inline vogl_trace_packet(const vogl_ctypes *pCtypes)
119         : m_pCTypes(pCtypes),
120           m_total_params(0),
121           m_has_return_value(false),
122           m_is_valid(false)
123     {
124         VOGL_FUNC_TRACER
125
126         VOGL_ASSUME(VOGL_INVALID_CTYPE == 0);
127
128         utils::zero_object(m_packet);
129     }
130
131     inline void clear()
132     {
133         VOGL_FUNC_TRACER
134
135         reset();
136     }
137
138     // reset() tries its best to not free any memory.
139     inline void reset()
140     {
141         VOGL_FUNC_TRACER
142
143         m_is_valid = false;
144         m_total_params = 0;
145         m_has_return_value = false;
146
147         utils::zero_object(m_packet);
148
149         m_packet.init();
150
151         utils::zero_object(m_param_ctype);
152         utils::zero_object(m_param_data);
153         utils::zero_object(m_param_size);
154
155         for (uint i = 0; i < cMaxParams; i++)
156             m_client_memory_descs[i].clear();
157
158         m_client_memory.resize(0);
159         m_key_value_map.reset();
160     }
161
162     void set_ctypes(const vogl_ctypes *pCtypes)
163     {
164         VOGL_FUNC_TRACER
165
166         m_pCTypes = pCtypes;
167     }
168
169     const vogl_ctypes *get_ctypes() const
170     {
171         VOGL_FUNC_TRACER
172
173         return m_pCTypes;
174     }
175
176     bool compare(const vogl_trace_packet &other, bool deep) const;
177
178     bool check() const;
179
180     bool pretty_print(dynamic_string &str, bool type_info) const;
181
182     // serialization/deserialization
183     bool serialize(data_stream &stream) const;
184     bool serialize(uint8_vec &buf) const;
185
186     bool deserialize(const uint8 *pPacket_data, uint packet_data_buf_size, bool check_crc);
187     bool deserialize(const uint8_vec &packet_buf, bool check_crc);
188
189     class json_serialize_params
190     {
191     public:
192         json_serialize_params()
193         {
194             VOGL_FUNC_TRACER
195
196             clear();
197         }
198
199         void clear()
200         {
201             VOGL_FUNC_TRACER
202
203             m_pBlob_manager = NULL;
204             m_cur_frame = 0;
205             m_blob_file_size_threshold = 2048;
206             m_write_debug_info = false;
207         }
208
209         dynamic_string m_output_basename;
210         vogl_blob_manager *m_pBlob_manager;
211
212         uint m_cur_frame;
213         uint m_blob_file_size_threshold;
214         bool m_write_debug_info;
215     };
216
217     bool json_serialize(json_node &node, const json_serialize_params &params) const;
218
219     // pDocument_filename is used to print context of warnings/errors
220     bool json_deserialize(const json_node &node, const char *pDocument_filename, const vogl_blob_manager *pBlob_manager);
221
222     inline const vogl_trace_gl_entrypoint_packet &get_entrypoint_packet() const
223     {
224         return m_packet;
225     }
226     inline vogl_trace_gl_entrypoint_packet &get_entrypoint_packet()
227     {
228         return m_packet;
229     }
230
231     inline gl_entrypoint_id_t get_entrypoint_id() const
232     {
233         return static_cast<gl_entrypoint_id_t>(m_packet.m_entrypoint_id);
234     }
235     inline const gl_entrypoint_desc_t &get_entrypoint_desc() const
236     {
237         return g_vogl_entrypoint_descs[m_packet.m_entrypoint_id];
238     }
239
240     inline uint64_t get_context_handle() const
241     {
242         return m_packet.m_context_handle;
243     }
244     inline uint64_t get_call_counter() const
245     {
246         return m_packet.m_call_counter;
247     }
248     inline uint64_t get_thread_id() const
249     {
250         return m_packet.m_thread_id;
251     }
252
253     inline bool is_valid() const
254     {
255         return m_is_valid;
256     }
257     inline uint total_params() const
258     {
259         return m_total_params;
260     }
261     inline bool has_return_value() const
262     {
263         return m_has_return_value;
264     }
265
266     inline const key_value_map &get_key_value_map() const
267     {
268         return m_key_value_map;
269     }
270     inline key_value_map &get_key_value_map()
271     {
272         return m_key_value_map;
273     }
274
275     // packet construction
276     inline void begin_construction(gl_entrypoint_id_t id, uint64_t context_handle, uint64_t call_counter, uint64_t thread_id, uint64_t begin_rdtsc)
277     {
278         VOGL_FUNC_TRACER
279
280         VOGL_ASSERT(id < VOGL_NUM_ENTRYPOINTS);
281
282         m_total_params = 0;
283         m_has_return_value = false;
284
285         VOGL_ASSUME(VOGL_INVALID_CTYPE == 0);
286         utils::zero_object(m_param_ctype);
287
288         const uint total_params_to_serialize = g_vogl_entrypoint_descs[id].m_num_params + (g_vogl_entrypoint_descs[id].m_return_ctype != VOGL_VOID);
289         for (uint i = 0; i < total_params_to_serialize; ++i)
290             m_client_memory_descs[i].clear();
291
292         m_client_memory.resize(0);
293         m_key_value_map.reset();
294
295         m_packet.init();
296         m_packet.init_rnd();
297         m_packet.m_packet_begin_rdtsc = begin_rdtsc;
298         m_packet.m_entrypoint_id = id;
299         m_packet.m_context_handle = context_handle;
300         m_packet.m_call_counter = call_counter;
301         m_packet.m_thread_id = thread_id;
302         m_packet.m_backtrace_hash_index = 0;
303
304         m_is_valid = true;
305     }
306
307     inline void set_begin_rdtsc(uint64_t val)
308     {
309         m_packet.m_packet_begin_rdtsc = val;
310     }
311
312     inline void set_gl_begin_rdtsc(uint64_t val)
313     {
314         m_packet.m_gl_begin_rdtsc = val;
315     }
316     inline void set_gl_end_rdtsc(uint64_t val)
317     {
318         m_packet.m_gl_end_rdtsc = val;
319     }
320
321     inline void set_backtrace_hash_index(uint32 hash_index)
322     {
323         m_packet.m_backtrace_hash_index = hash_index;
324     }
325     inline uint32 get_backtrace_hash_index() const
326     {
327         return m_packet.m_backtrace_hash_index;
328     }
329
330     inline void end_construction(uint64_t end_rdtsc)
331     {
332         VOGL_FUNC_TRACER
333
334         VOGL_ASSERT(m_is_valid);
335         VOGL_ASSERT(m_total_params == get_entrypoint_desc().m_num_params);
336         VOGL_ASSERT(m_has_return_value == (get_entrypoint_desc().m_return_ctype != VOGL_VOID));
337
338         m_packet.m_packet_end_rdtsc = end_rdtsc;
339     }
340
341     // composition
342     inline void set_return_param(vogl_ctype_t ctype, const void *pParam, uint param_size)
343     {
344         VOGL_FUNC_TRACER
345
346         VOGL_ASSERT(m_is_valid);
347         VOGL_ASSERT(ctype != VOGL_INVALID_CTYPE);
348         VOGL_ASSERT((uint)trace_ctypes()[ctype].m_size == param_size);
349         VOGL_ASSERT((param_size >= sizeof(uint8)) && (param_size <= sizeof(uint64_t)));
350         VOGL_ASSERT(g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_return_ctype == ctype);
351
352         uint param_index = g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params;
353         memcpy(&m_param_data[param_index], pParam, param_size);
354         m_param_ctype[param_index] = ctype;
355         m_param_size[param_index] = static_cast<uint8>(param_size);
356
357         m_has_return_value = true;
358     }
359
360     inline void set_param(uint8_t param_id, vogl_ctype_t ctype, const void *pParam, uint param_size)
361     {
362         VOGL_FUNC_TRACER
363
364         if (param_id == VOGL_RETURN_PARAM_INDEX)
365         {
366             set_return_param(ctype, pParam, param_size);
367             return;
368         }
369
370         VOGL_ASSERT(m_is_valid);
371         VOGL_ASSERT(ctype != VOGL_INVALID_CTYPE);
372         VOGL_ASSERT(param_id < g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params);
373         VOGL_ASSERT(g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params < cMaxParams);
374         VOGL_ASSERT((uint)trace_ctypes()[ctype].m_size == param_size);
375         VOGL_ASSERT((param_size >= sizeof(uint8)) && (param_size <= sizeof(uint64_t)));
376         VOGL_ASSERT(g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_id].m_ctype == ctype);
377
378         m_total_params += (m_param_ctype[param_id] == VOGL_INVALID_CTYPE);
379         VOGL_ASSERT(m_total_params <= g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params);
380
381         memcpy(&m_param_data[param_id], pParam, param_size);
382         m_param_ctype[param_id] = ctype;
383         m_param_size[param_id] = static_cast<uint8>(param_size);
384     }
385
386     inline void set_array_client_memory(uint8_t param_id, vogl_ctype_t pointee_ctype, uint64_t array_size, const void *pData, uint64_t data_size)
387     {
388         VOGL_FUNC_TRACER
389
390         VOGL_NOTE_UNUSED(array_size);
391
392         VOGL_ASSERT(m_is_valid);
393         //VOGL_ASSERT(param_id <= cUINT8_MAX);
394         VOGL_ASSERT(static_cast<int>(pointee_ctype) <= cUINT8_MAX);
395         if (trace_ctypes()[pointee_ctype].m_size > 0)
396         {
397             VOGL_ASSERT((data_size % trace_ctypes()[pointee_ctype].m_size) == 0);
398         }
399         if (data_size >= static_cast<uint64_t>(cINT32_MAX))
400         {
401             VOGL_FAIL("vogl_entrypoint_serializer::add_param_client_memory: Need to support streaming more than 2GB of client memory per call!\n");
402         }
403
404         uint param_index = param_id;
405         if (param_id == VOGL_RETURN_PARAM_INDEX)
406         {
407             VOGL_ASSERT(trace_ctypes()[g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_return_ctype].m_is_pointer);
408             param_index = g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params;
409         }
410         else
411         {
412             VOGL_ASSERT(trace_ctypes()[g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_id].m_ctype].m_is_pointer);
413         }
414
415         uint32 data_size32 = static_cast<uint32>(data_size);
416
417         m_client_memory_descs[param_index].m_pointee_ctype = pointee_ctype;
418
419         if ((m_client_memory_descs[param_index].m_vec_ofs >= 0) && (data_size32 <= m_client_memory_descs[param_index].m_data_size))
420         {
421             memcpy(&m_client_memory[m_client_memory_descs[param_index].m_vec_ofs], pData, static_cast<size_t>(data_size));
422         }
423         else
424         {
425             m_client_memory_descs[param_index].m_vec_ofs = m_client_memory.size();
426             m_client_memory_descs[param_index].m_data_size = data_size32;
427             m_client_memory.append(static_cast<const uint8 *>(pData), data_size32);
428         }
429     }
430
431     inline void set_ref_client_memory(uint8_t param_id, vogl_ctype_t pointee_ctype, const void *pData, uint64_t data_size)
432     {
433         VOGL_FUNC_TRACER
434
435         set_array_client_memory(param_id, pointee_ctype, 1U, pData, data_size);
436     }
437
438     inline bool set_key_value(const value &key, const value &value)
439     {
440         VOGL_FUNC_TRACER
441
442         VOGL_ASSERT(m_is_valid);
443         return m_key_value_map.insert(key, value).second;
444     }
445
446     // ownership of blob's buffer is taken
447     inline bool set_key_value_blob_take_ownership(const value &key, uint8_vec &blob)
448     {
449         VOGL_FUNC_TRACER
450
451         VOGL_ASSERT(m_is_valid);
452         value_to_value_hash_map::insert_result res(m_key_value_map.insert(key, value()));
453         (res.first)->second.set_blob_take_ownership(blob);
454         return res.second;
455     }
456
457     inline bool set_key_value_blob(const value &key, const void *pData, uint data_size)
458     {
459         VOGL_FUNC_TRACER
460
461         VOGL_ASSERT(m_is_valid);
462         value_to_value_hash_map::insert_result res(m_key_value_map.insert(key, value()));
463         (res.first)->second.set_blob(static_cast<const uint8 *>(pData), data_size);
464         return res.second;
465     }
466
467     inline bool set_key_value_json_document(const value &key, const json_document &doc)
468     {
469         VOGL_FUNC_TRACER
470
471         VOGL_ASSERT(m_is_valid);
472         value_to_value_hash_map::insert_result res(m_key_value_map.insert(key, value()));
473         (res.first)->second.set_json_document(doc);
474         return res.second;
475     }
476
477     // param accessors
478     inline const uint64_t &get_param_data(uint param_index) const
479     {
480         VOGL_ASSERT(param_index < m_total_params);
481         return m_param_data[param_index];
482     }
483     inline uint get_param_size(uint param_index) const
484     {
485         VOGL_ASSERT(param_index < m_total_params);
486         return m_param_size[param_index];
487     }
488     inline vogl_ctype_t get_param_ctype(uint param_index) const
489     {
490         VOGL_ASSERT(param_index < m_total_params);
491         return m_param_ctype[param_index];
492     }
493     inline const gl_entrypoint_param_desc_t &get_param_desc(uint param_index) const
494     {
495         VOGL_ASSERT(param_index < m_total_params);
496         return g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][param_index];
497     }
498     inline const vogl_ctype_desc_t &get_param_ctype_desc(uint param_index) const
499     {
500         VOGL_ASSERT(param_index < m_total_params);
501         return trace_ctypes()[m_param_ctype[param_index]];
502     }
503     inline vogl_namespace_t get_param_namespace(uint param_index) const
504     {
505         return get_param_desc(param_index).m_namespace;
506     }
507
508     // It's acceptable to call this on params which have sizeof's less than T, the upper bytes are 0's.
509     template <typename T>
510     inline T get_param_value(uint param_index) const
511     {
512         VOGL_FUNC_TRACER
513
514         VOGL_ASSERT(sizeof(T) <= sizeof(uint64_t));
515         VOGL_ASSUME(!Loki::type_is_ptr<T>::result);
516         VOGL_ASSERT(sizeof(T) >= static_cast<uint>(get_param_ctype_desc(param_index).m_size));
517         VOGL_ASSERT(!get_param_ctype_desc(param_index).m_is_pointer);
518
519         if (sizeof(T) != get_param_size(param_index))
520         {
521             if (!validate_value_conversion(sizeof(T), Loki::TypeTraits<T>::typeFlags, param_index))
522             {
523                 console::warning("%s: Parameter value conversion of call counter %llu func %s parameter \"%s %s\" to dest type size %u will fail, size %u value=0x%08llx\n", VOGL_METHOD_NAME,
524                                  (unsigned long long)m_packet.m_call_counter,
525                                  get_entrypoint_desc().m_pName,
526                                  get_param_ctype_desc(param_index).m_pName, get_param_desc(param_index).m_pName,
527                                  (uint)sizeof(T),
528                                  get_param_size(param_index),
529                                  (unsigned long long)get_param_data(param_index));
530             }
531         }
532
533         return *reinterpret_cast<const T *>(&get_param_data(param_index));
534     }
535
536     inline vogl_trace_ptr_value get_param_ptr_value(uint param_index) const
537     {
538         VOGL_FUNC_TRACER
539
540         VOGL_ASSUME(sizeof(vogl_trace_ptr_value) <= sizeof(uint64_t));
541         VOGL_ASSERT(get_param_ctype_desc(param_index).m_is_pointer);
542         return *reinterpret_cast<const vogl_trace_ptr_value *>(&get_param_data(param_index));
543     }
544
545     // Returns cInvalidIndex if not found
546     inline int find_param_index(const char *pName) const
547     {
548         VOGL_FUNC_TRACER
549
550         const gl_entrypoint_param_desc_t *pParams = &g_vogl_entrypoint_param_descs[m_packet.m_entrypoint_id][0];
551         VOGL_ASSERT(g_vogl_entrypoint_descs[m_packet.m_entrypoint_id].m_num_params == m_total_params);
552
553         for (uint i = 0; i < m_total_params; i++)
554             if (vogl_strcmp(pName, pParams->m_pName) == 0)
555                 return i;
556
557         return cInvalidIndex;
558     }
559
560     bool pretty_print_param(dynamic_string &str, uint param_index, bool type_info) const;
561     bool pretty_print_return_value(dynamic_string &str, bool type_info) const;
562
563     // return value
564     inline const uint64_t &get_return_value_data() const
565     {
566         VOGL_ASSERT(m_has_return_value);
567         return m_param_data[m_total_params];
568     }
569     inline uint get_return_value_size() const
570     {
571         VOGL_ASSERT(m_has_return_value);
572         return m_param_size[m_total_params];
573     }
574     inline vogl_ctype_t get_return_value_ctype() const
575     {
576         VOGL_ASSERT(m_has_return_value);
577         return m_param_ctype[m_total_params];
578     }
579     inline const vogl_ctype_desc_t &get_return_value_ctype_desc() const
580     {
581         return trace_ctypes()[get_return_value_ctype()];
582     }
583     inline vogl_namespace_t get_return_value_namespace() const
584     {
585         return get_entrypoint_desc().m_return_namespace;
586     }
587
588     // It's acceptable to call this on params which have sizeof's less than T, the upper bytes are 0's.
589     template <typename T>
590     inline T get_return_value() const
591     {
592         VOGL_FUNC_TRACER
593
594         VOGL_ASSERT(sizeof(T) <= sizeof(uint64_t));
595         VOGL_ASSUME(!Loki::type_is_ptr<T>::result);
596         VOGL_ASSERT(sizeof(T) >= static_cast<uint>(get_return_value_ctype_desc().m_size));
597         VOGL_ASSERT(!get_return_value_ctype_desc().m_is_pointer);
598
599         if (sizeof(T) != get_return_value_size())
600         {
601             if (!validate_value_conversion(sizeof(T), Loki::TypeTraits<T>::typeFlags, -1))
602             {
603                 console::warning("%s: Return value conversion of call counter %llu func %s return value type \"%s\" to dest type size %u will fail, size %u value=0x%08llx\n", VOGL_METHOD_NAME,
604                                  (unsigned long long)m_packet.m_call_counter,
605                                  get_entrypoint_desc().m_pName,
606                                  get_return_value_ctype_desc().m_pName,
607                                  (uint)sizeof(T),
608                                  get_return_value_size(),
609                                  (unsigned long long)get_return_value_data());
610             }
611         }
612
613         return *reinterpret_cast<const T *>(&get_return_value_data());
614     }
615
616     inline vogl_trace_ptr_value get_return_ptr_value() const
617     {
618         VOGL_FUNC_TRACER
619
620         VOGL_ASSUME(sizeof(vogl_trace_ptr_value) <= sizeof(uint64_t));
621         VOGL_ASSERT(get_return_value_ctype_desc().m_is_pointer);
622         return *reinterpret_cast<const vogl_trace_ptr_value *>(&get_return_value_data());
623     }
624
625     // param client memory accessors
626     inline bool has_param_client_memory(uint param_index) const
627     {
628         VOGL_ASSERT(param_index < m_total_params);
629         return m_client_memory_descs[param_index].m_vec_ofs != -1;
630     }
631     inline const void *get_param_client_memory_ptr(uint param_index) const
632     {
633         VOGL_ASSERT(param_index < m_total_params);
634         int ofs = m_client_memory_descs[param_index].m_vec_ofs;
635         return (ofs < 0) ? NULL : &m_client_memory[ofs];
636     }
637     inline void *get_param_client_memory_ptr(uint param_index)
638     {
639         VOGL_ASSERT(param_index < m_total_params);
640         int ofs = m_client_memory_descs[param_index].m_vec_ofs;
641         return (ofs < 0) ? NULL : &m_client_memory[ofs];
642     }
643     inline uint get_param_client_memory_data_size(uint param_index) const
644     {
645         VOGL_ASSERT(param_index < m_total_params);
646         return m_client_memory_descs[param_index].m_data_size;
647     }
648     inline vogl_ctype_t get_param_client_memory_ctype(uint param_index) const
649     {
650         VOGL_ASSERT(param_index < m_total_params);
651         return static_cast<vogl_ctype_t>(m_client_memory_descs[param_index].m_pointee_ctype);
652     }
653     inline const vogl_ctype_desc_t &get_param_client_memory_ctype_desc(uint param_index) const
654     {
655         return trace_ctypes()[get_param_client_memory_ctype(param_index)];
656     }
657
658     template <typename T>
659     inline const T *get_param_client_memory(uint param_index) const
660     {
661         VOGL_FUNC_TRACER
662
663         VOGL_ASSUME(!Loki::type_is_ptr<T>::result);
664         return static_cast<const T *>(get_param_client_memory_ptr(param_index));
665     };
666
667     template <typename T>
668     inline T *get_param_client_memory(uint param_index)
669     {
670         VOGL_FUNC_TRACER
671
672         VOGL_ASSUME(!Loki::type_is_ptr<T>::result);
673         return static_cast<T *>(get_param_client_memory_ptr(param_index));
674     };
675
676     inline const vogl_client_memory_array get_param_client_memory_array(uint param_index) const
677     {
678         VOGL_FUNC_TRACER
679
680         const vogl_ctype_desc_t &ctype_desc = get_param_client_memory_ctype_desc(param_index);
681         uint element_size = ctype_desc.m_size;
682         uint data_size = get_param_client_memory_data_size(param_index);
683         if (element_size <= 0)
684             return vogl_client_memory_array(get_param_client_memory_ctype(param_index), get_param_client_memory_ptr(param_index), data_size, 1);
685         else
686         {
687             VOGL_ASSERT((data_size % element_size) == 0);
688             return vogl_client_memory_array(get_param_client_memory_ctype(param_index), get_param_client_memory_ptr(param_index), element_size, data_size / element_size);
689         }
690     }
691
692     // return client memory accessors
693     inline bool has_return_client_memory() const
694     {
695         VOGL_ASSERT(m_has_return_value);
696         return m_client_memory_descs[m_total_params].m_vec_ofs != -1;
697     }
698     inline const void *get_return_client_memory_ptr() const
699     {
700         VOGL_ASSERT(m_has_return_value);
701         int ofs = m_client_memory_descs[m_total_params].m_vec_ofs;
702         return (ofs < 0) ? NULL : &m_client_memory[ofs];
703     }
704     inline int get_return_client_memory_data_size() const
705     {
706         VOGL_ASSERT(m_has_return_value);
707         return m_client_memory_descs[m_total_params].m_data_size;
708     }
709     inline vogl_ctype_t get_return_client_memory_ctype() const
710     {
711         VOGL_ASSERT(m_has_return_value);
712         return static_cast<vogl_ctype_t>(m_client_memory_descs[m_total_params].m_pointee_ctype);
713     }
714     inline const vogl_ctype_desc_t &get_return_client_memory_ctype_desc() const
715     {
716         return trace_ctypes()[get_return_client_memory_ctype()];
717     }
718
719     inline const vogl_client_memory_array get_return_client_memory_array() const
720     {
721         VOGL_FUNC_TRACER
722
723         const vogl_ctype_desc_t &ctype_desc = get_return_client_memory_ctype_desc();
724         uint element_size = ctype_desc.m_size;
725         uint data_size = get_return_client_memory_data_size();
726         if (element_size <= 0)
727             return vogl_client_memory_array(get_return_client_memory_ctype(), get_return_client_memory_ptr(), data_size, 1);
728         else
729         {
730             VOGL_ASSERT((data_size % element_size) == 0);
731             return vogl_client_memory_array(get_return_client_memory_ctype(), get_return_client_memory_ptr(), element_size, data_size / element_size);
732         }
733     }
734
735 private:
736     const vogl_ctypes *m_pCTypes;
737
738     inline const vogl_ctypes &trace_ctypes() const
739     {
740         return *m_pCTypes;
741     }
742
743     // the "_size" fields in m_packet are not valid until binary serialization
744     vogl_trace_gl_entrypoint_packet m_packet;
745
746     uint m_total_params;
747     bool m_has_return_value;
748     bool m_is_valid;
749
750     enum
751     {
752         cMaxParams = 32
753     };
754     uint64_t m_param_data[cMaxParams];
755     uint8 m_param_size[cMaxParams];
756     vogl_ctype_t m_param_ctype[cMaxParams];
757
758     uint8_vec m_client_memory;
759
760     key_value_map m_key_value_map;
761
762 #pragma pack(push)
763 #pragma pack(1)
764     struct client_memory_desc_t
765     {
766         int32 m_vec_ofs;
767         uint32 m_data_size;
768         uint8 m_pointee_ctype; // vogl_ctype_t
769
770         inline void clear()
771         {
772             m_vec_ofs = -1;
773             m_data_size = 0;
774             m_pointee_ctype = VOGL_VOID;
775         }
776     };
777 #pragma pack(pop)
778
779     client_memory_desc_t m_client_memory_descs[cMaxParams];
780
781     mutable uint8_vec m_packet_buf;
782
783     bool validate_value_conversion(uint dest_type_size, uint dest_type_loki_type_flags, int param_index) const;
784
785     static bool should_always_write_as_blob_file(const char *pFunc_name);
786
787     void ctype_to_json_value(json_value &val, gl_entrypoint_id_t entrypoint_id, int param_index, uint64_t data, vogl_ctype_t ctype) const;
788
789     bool json_serialize_param(
790         const char *pFunc_name,
791         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,
792         const void *pClient_mem, uint client_mem_size, vogl_ctype_t client_mem_ctype,
793         const json_serialize_params &params) const;
794
795     bool 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);
796
797     bool json_deserialize_param(
798         uint64_t cur_call_counter, const char *pFunc_name,
799         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,
800         const char *pDocument_filename, const vogl_blob_manager *pBlob_manager);
801
802     static bool get_uint64_from_json_node(const json_node &node, const char *pKey, uint64_t &val, uint64_t def = 0);
803
804     static bool force_value_to_type(value &val, value_data_type type);
805
806     bool fixup_manually_edited_params(gl_entrypoint_id_t gl_entrypoint_id, const char *pGL_func_name, uint64_t cur_call_counter);
807 };
808
809 bool vogl_does_packet_refer_to_program(const vogl_trace_packet &gl_packet, GLuint &program);
810 bool vogl_write_glInternalTraceCommandRAD(data_stream &stream, const vogl_ctypes *pCTypes, GLuint cmd, GLuint size, const GLubyte *data);
811
812 #endif // VOGL_TRACE_PACKET_H