]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_display_list_state.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_display_list_state.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_display_list_state.cpp
27 #include "vogl_display_list_state.h"
28
29 vogl_display_list::vogl_display_list()
30     : m_handle(0),
31       m_xfont_glyph(0),
32       m_xfont(false),
33       m_generating(false),
34       m_valid(false)
35 {
36     VOGL_FUNC_TRACER
37 }
38
39 void vogl_display_list::clear()
40 {
41     VOGL_FUNC_TRACER
42
43     m_xfont_name.clear();
44     m_xfont_glyph = 0;
45     m_xfont = false;
46     m_packets.clear();
47     m_generating = false;
48     m_valid = false;
49 }
50
51 void vogl_display_list::init_xfont(const char *pName, int glyph)
52 {
53     VOGL_FUNC_TRACER
54
55     m_packets.clear();
56     m_xfont_name = pName ? pName : "";
57     m_xfont_glyph = glyph;
58     m_xfont = true;
59     m_generating = false;
60     m_valid = true;
61 }
62
63 void vogl_display_list::begin_gen()
64 {
65     VOGL_FUNC_TRACER
66
67     clear();
68     m_generating = true;
69 }
70
71 void vogl_display_list::end_gen()
72 {
73     VOGL_FUNC_TRACER
74
75     VOGL_ASSERT(m_generating);
76     m_generating = false;
77     m_valid = true;
78 }
79
80 bool vogl_display_list::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
81 {
82     VOGL_FUNC_TRACER
83
84     if (!m_valid)
85         return false;
86
87     node.add_key_value("handle", m_handle);
88     node.add_key_value("generating", m_generating);
89     node.add_key_value("xfont", m_xfont);
90     if (m_xfont)
91     {
92         node.add_key_value("xfont_glyph", m_xfont_glyph);
93         node.add_key_value("xfont_name", m_xfont_name);
94     }
95
96     if (m_packets.size())
97     {
98         vogl_trace_packet::json_serialize_params params;
99         params.m_pBlob_manager = &blob_manager;
100
101         json_node &packets_array = node.add_array("packets");
102         for (uint i = 0; i < m_packets.size(); i++)
103         {
104             const uint8_vec &packet_buf = m_packets.get_packet_buf(i);
105
106             vogl_trace_packet packet(pCtypes);
107             if (!packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
108                 return false;
109
110             if (!packet.json_serialize(packets_array.add_object(), params))
111                 return false;
112         }
113     }
114
115     return true;
116 }
117
118 bool vogl_display_list::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
119 {
120     VOGL_FUNC_TRACER
121
122     clear();
123
124     m_handle = node.value_as_uint32("handle");
125     m_generating = node.value_as_bool("generating");
126     m_xfont = node.value_as_bool("xfont");
127     if (m_xfont)
128     {
129         m_xfont_glyph = node.value_as_int("xfont_glyph");
130         m_xfont_name = node.value_as_string("xfont_name");
131     }
132
133     const json_node *pPackets_array = node.find_child_array("packets");
134     if (pPackets_array)
135     {
136         if (!pPackets_array->are_all_children_objects())
137         {
138             clear();
139             return false;
140         }
141
142         vogl_trace_packet packet(pCtypes);
143
144         m_packets.resize(pPackets_array->size());
145         for (uint i = 0; i < pPackets_array->size(); i++)
146         {
147             if (!packet.json_deserialize(*pPackets_array->get_child(i), "<display_list>", &blob_manager))
148             {
149                 clear();
150                 return false;
151             }
152
153             if (!packet.serialize(m_packets.get_packet_buf(i)))
154             {
155                 clear();
156                 return false;
157             }
158         }
159     }
160
161     m_valid = true;
162
163     return true;
164 }
165
166 vogl_display_list_state::vogl_display_list_state()
167 {
168     VOGL_FUNC_TRACER
169 }
170
171 vogl_display_list_state::vogl_display_list_state(const vogl_display_list_state &other)
172 {
173     VOGL_FUNC_TRACER
174
175     *this = other;
176 }
177
178 vogl_display_list_state::~vogl_display_list_state()
179 {
180     VOGL_FUNC_TRACER
181 }
182
183 vogl_display_list_state &vogl_display_list_state::operator=(const vogl_display_list_state &rhs)
184 {
185     VOGL_FUNC_TRACER
186
187     if (this == &rhs)
188         return *this;
189
190     clear();
191
192     m_display_lists = rhs.m_display_lists;
193
194     return *this;
195 }
196
197 void vogl_display_list_state::clear()
198 {
199     VOGL_FUNC_TRACER
200
201     m_display_lists.clear();
202 }
203
204 bool vogl_display_list_state::remap_handles(vogl_handle_remapper &remapper)
205 {
206     VOGL_FUNC_TRACER
207
208     vogl_display_list_map new_display_lists;
209
210     for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
211     {
212         uint new_handle = static_cast<uint>(remapper.remap_handle(VOGL_NAMESPACE_LISTS, it->first));
213
214         new_display_lists[new_handle] = it->second;
215     }
216
217     new_display_lists.swap(m_display_lists);
218
219     return true;
220 }
221
222 bool vogl_display_list_state::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
223 {
224     VOGL_FUNC_TRACER
225
226     if (m_display_lists.size())
227     {
228         json_node &lists_node = node.add_object("lists");
229
230         for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
231         {
232             if (!it->second.is_valid())
233             {
234                 vogl_warning_printf("%s: Unable to serialize display list at GL handle %u. This list is probably still being composed.\n", VOGL_METHOD_NAME, it->second.get_handle());
235                 continue;
236             }
237             if (!it->second.serialize(lists_node.add_object(uint_to_string(it->first)), blob_manager, pCtypes))
238                 return false;
239         }
240     }
241
242     return true;
243 }
244
245 bool vogl_display_list_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
246 {
247     VOGL_FUNC_TRACER
248
249     clear();
250
251     const json_node *pLists_node = node.find_child_object("lists");
252     if (pLists_node)
253     {
254         if (!pLists_node->are_all_children_objects())
255             return false;
256
257         for (uint i = 0; i < pLists_node->size(); i++)
258         {
259             if (!m_display_lists[string_to_uint(pLists_node->get_key(i).get_ptr())].deserialize(*pLists_node->get_child(i), blob_manager, pCtypes))
260             {
261                 clear();
262                 return false;
263             }
264         }
265     }
266
267     return true;
268 }
269
270 bool vogl_display_list_state::define_list(GLuint trace_handle, GLuint replay_handle, const vogl_display_list &list)
271 {
272     VOGL_FUNC_TRACER
273
274     vogl_display_list_map::insert_result res(m_display_lists.insert(trace_handle));
275     if (!res.second)
276         return false;
277
278     vogl_display_list_map::iterator it = res.first;
279
280     vogl_display_list &new_list = it->second;
281     new_list = list;
282     new_list.set_handle(replay_handle);
283
284     return true;
285 }
286
287 void vogl_display_list_state::new_list(GLuint trace_handle, GLuint replay_handle)
288 {
289     VOGL_FUNC_TRACER
290
291     vogl_display_list_map::insert_result res(m_display_lists.insert(trace_handle));
292     vogl_display_list_map::iterator it = res.first;
293     vogl_display_list &new_list = it->second;
294
295     new_list.clear();
296     new_list.set_handle(replay_handle);
297     new_list.begin_gen();
298 }
299
300 bool vogl_display_list_state::end_list(GLuint trace_handle)
301 {
302     VOGL_FUNC_TRACER
303
304     vogl_display_list_map::iterator it = m_display_lists.find(trace_handle);
305     if (it == m_display_lists.end())
306         return false;
307
308     it->second.end_gen();
309     return true;
310 }
311
312 bool vogl_display_list_state::gen_lists(GLuint first, GLsizei n, GLuint *pObject_handles)
313 {
314     VOGL_FUNC_TRACER
315
316     bool success = true;
317     for (GLsizei i = 0; i < n; i++)
318     {
319         vogl_display_list_map::insert_result res(m_display_lists.insert(first + i));
320         if (!res.second)
321         {
322             vogl_error_printf("%s: Failed inserting list handle %u into display list shadow!\n", VOGL_METHOD_NAME, first + i);
323             success = false;
324         }
325         else
326         {
327             (res.first)->second.set_handle(pObject_handles ? pObject_handles[i] : first + i);
328         }
329     }
330     return success;
331 }
332
333 bool vogl_display_list_state::del_lists(GLuint first, GLsizei n)
334 {
335     VOGL_FUNC_TRACER
336
337     bool success = true;
338     for (GLsizei i = 0; i < n; i++)
339     {
340         if (!m_display_lists.erase(first + i))
341             success = false;
342     }
343     return success;
344 }
345
346 bool vogl_display_list_state::glx_font(const char *pFont, int first, int count, int listBase)
347 {
348     VOGL_FUNC_TRACER
349
350     bool success = true;
351     for (int i = 0; i < count; i++)
352     {
353         int handle = listBase + i;
354         if (handle < 1)
355         {
356             vogl_error_printf("%s: Invalid display list handle %i\n", VOGL_METHOD_NAME, handle);
357             success = false;
358             continue;
359         }
360
361         vogl_display_list *pList = &m_display_lists[handle];
362         pList->init_xfont(pFont, first + i);
363     }
364
365     return success;
366 }
367
368 bool vogl_display_list_state::is_call_listable(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
369 {
370     VOGL_FUNC_TRACER
371
372     if ((!g_vogl_entrypoint_descs[func].m_is_listable) || (!g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists))
373         return false;
374
375     // These cases don't go into display lists, they are executed immediately.
376     if (((func == VOGL_ENTRYPOINT_glTexImage1D) && (packet.get_param_value<GLenum>(0) == GL_PROXY_TEXTURE_1D)) ||
377         ((func == VOGL_ENTRYPOINT_glTexImage2D) && (packet.get_param_value<GLenum>(0) == GL_PROXY_TEXTURE_2D)) ||
378         ((func == VOGL_ENTRYPOINT_glTexImage3D) && (packet.get_param_value<GLenum>(0) == GL_PROXY_TEXTURE_3D)))
379     {
380         return false;
381     }
382
383     return true;
384 }
385
386 bool vogl_display_list_state::add_packet_to_list(GLuint handle, gl_entrypoint_id_t func, const vogl_trace_packet &packet)
387 {
388     VOGL_FUNC_TRACER
389     VOGL_NOTE_UNUSED(func);
390
391     vogl_display_list *pList = m_display_lists.find_value(handle);
392     VOGL_ASSERT(pList);
393     if (!pList)
394     {
395         vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List %u was not genned.\n", VOGL_FUNCTION_NAME, handle);
396         return false;
397     }
398
399     uint8_vec buf;
400     if (!packet.serialize(buf))
401     {
402         vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List handle %u.\n", VOGL_FUNCTION_NAME, handle);
403         return false;
404     }
405
406     pList->get_packets().push_back(buf);
407     return true;
408 }
409
410 bool vogl_display_list_state::parse_list_and_update_shadows(GLuint handle, pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
411 {
412     VOGL_FUNC_TRACER
413
414     VOGL_ASSERT(pBind_callback);
415
416     const vogl_display_list *pList = find_list(handle);
417     if (!pList)
418         return false;
419
420     const vogl_trace_packet_array &packets = pList->get_packets();
421
422     vogl_trace_packet trace_packet(&g_vogl_process_gl_ctypes);
423
424     for (uint packet_index = 0; packet_index < packets.size(); packet_index++)
425     {
426         if (packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
427         {
428             VOGL_ASSERT_ALWAYS;
429             continue;
430         }
431
432         // Quickly skip by those packets we don't care about
433         // TODO: If display lists are used a lot we could precompute a flag for each one that indicates whether or not they should be parsed for binds.
434         const vogl_trace_gl_entrypoint_packet &gl_packet = packets.get_packet<vogl_trace_gl_entrypoint_packet>(packet_index);
435         switch (gl_packet.m_entrypoint_id)
436         {
437             case VOGL_ENTRYPOINT_glBindTexture:
438             case VOGL_ENTRYPOINT_glBindTextureEXT:
439             case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
440             case VOGL_ENTRYPOINT_glBindBuffer:
441             case VOGL_ENTRYPOINT_glBindVertexArray:
442             case VOGL_ENTRYPOINT_glBeginQuery:
443             case VOGL_ENTRYPOINT_glBeginQueryARB:
444             case VOGL_ENTRYPOINT_glCallList:
445             case VOGL_ENTRYPOINT_glCallLists:
446                 break;
447             default:
448                 continue;
449         }
450
451         if (!trace_packet.deserialize(packets.get_packet_buf(packet_index), false))
452         {
453             vogl_error_printf("%s: Failed parsing GL entrypoint packet in display list %u\n", VOGL_FUNCTION_NAME, handle);
454             VOGL_ASSERT_ALWAYS;
455             return false;
456         }
457
458         switch (trace_packet.get_entrypoint_id())
459         {
460             case VOGL_ENTRYPOINT_glBindTexture:
461             case VOGL_ENTRYPOINT_glBindTextureEXT:
462             {
463                 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
464                 break;
465             }
466             case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
467             {
468                 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), pBind_callback_opaque);
469                 break;
470             }
471             case VOGL_ENTRYPOINT_glBindBuffer:
472             {
473                 (*pBind_callback)(VOGL_NAMESPACE_BUFFERS, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
474                 break;
475             }
476             case VOGL_ENTRYPOINT_glBindVertexArray:
477             {
478                 (*pBind_callback)(VOGL_NAMESPACE_VERTEX_ARRAYS, GL_NONE, trace_packet.get_param_value<GLuint>(0), pBind_callback_opaque);
479                 break;
480             }
481             case VOGL_ENTRYPOINT_glBeginQuery:
482             case VOGL_ENTRYPOINT_glBeginQueryARB:
483             {
484                 (*pBind_callback)(VOGL_NAMESPACE_QUERIES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
485                 break;
486             }
487             case VOGL_ENTRYPOINT_glCallList:
488             case VOGL_ENTRYPOINT_glCallLists:
489             {
490                 vogl_warning_printf("%s: Recursive display lists are not currently supported\n", VOGL_METHOD_NAME);
491                 VOGL_ASSERT_ALWAYS;
492                 return false;
493             }
494             default:
495             {
496                 VOGL_ASSERT_ALWAYS;
497                 break;
498             }
499         }
500     }
501
502     return true;
503 }
504
505 bool vogl_display_list_state::parse_lists_and_update_shadows(GLsizei n, GLenum type, const GLvoid *lists, pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
506 {
507     VOGL_FUNC_TRACER
508
509     uint type_size = vogl_get_gl_type_size(type);
510     if (!type_size)
511     {
512         vogl_error_printf("%s: type is invalid\n", VOGL_FUNCTION_NAME);
513         return false;
514     }
515
516     if ((n) && (!lists))
517     {
518         vogl_error_printf("%s: lists param is NULL\n", VOGL_FUNCTION_NAME);
519         return false;
520     }
521
522     GLuint list_base = 0;
523     {
524         //vogl_scoped_gl_error_absorber gl_error_absorber(pContext); VOGL_NOTE_UNUSED(gl_error_absorber);
525         GL_ENTRYPOINT(glGetIntegerv)(GL_LIST_BASE, reinterpret_cast<GLint *>(&list_base));
526     }
527
528     bool success = true;
529
530     const uint8 *pTrace_lists_ptr = static_cast<const uint8 *>(lists);
531     for (GLsizei i = 0; i < n; i++)
532     {
533         GLint handle = list_base;
534         switch (type)
535         {
536             case GL_BYTE:
537             {
538                 handle += *reinterpret_cast<const signed char *>(pTrace_lists_ptr);
539                 pTrace_lists_ptr++;
540                 break;
541             }
542             case GL_UNSIGNED_BYTE:
543             {
544                 handle += *pTrace_lists_ptr;
545                 pTrace_lists_ptr++;
546                 break;
547             }
548             case GL_SHORT:
549             {
550                 handle += *reinterpret_cast<const int16 *>(pTrace_lists_ptr);
551                 pTrace_lists_ptr += sizeof(int16);
552                 break;
553             }
554             case GL_UNSIGNED_SHORT:
555             {
556                 handle += *reinterpret_cast<const uint16 *>(pTrace_lists_ptr);
557                 pTrace_lists_ptr += sizeof(uint16);
558                 break;
559             }
560             case GL_INT:
561             {
562                 handle += *reinterpret_cast<const int32 *>(pTrace_lists_ptr);
563                 pTrace_lists_ptr += sizeof(int32);
564                 break;
565             }
566             case GL_UNSIGNED_INT:
567             {
568                 handle += *reinterpret_cast<const uint32 *>(pTrace_lists_ptr);
569                 pTrace_lists_ptr += sizeof(uint32);
570                 break;
571             }
572             case GL_FLOAT:
573             {
574                 handle += static_cast<GLint>(*reinterpret_cast<const float *>(pTrace_lists_ptr));
575                 pTrace_lists_ptr += sizeof(float);
576                 break;
577             }
578             case GL_2_BYTES:
579             {
580                 handle += ((pTrace_lists_ptr[0] << 8U) + pTrace_lists_ptr[1]);
581                 pTrace_lists_ptr += 2;
582                 break;
583             }
584             case GL_3_BYTES:
585             {
586                 handle += ((pTrace_lists_ptr[0] << 16U) + (pTrace_lists_ptr[1] << 8U) + pTrace_lists_ptr[2]);
587                 pTrace_lists_ptr += 3;
588                 break;
589             }
590             case GL_4_BYTES:
591             {
592                 handle += ((pTrace_lists_ptr[0] << 24U) + (pTrace_lists_ptr[1] << 16U) + (pTrace_lists_ptr[2] << 8U) + pTrace_lists_ptr[3]);
593                 pTrace_lists_ptr += 4;
594                 break;
595             }
596             default:
597             {
598                 vogl_error_printf("%s: Invalid type parameter (0x%08X)\n", VOGL_FUNCTION_NAME, type);
599                 return false;
600             }
601         }
602
603         if (handle <= 0)
604         {
605             vogl_error_printf("%s: Trace handle after adding list base is negative (%i), skipping this list index\n", VOGL_FUNCTION_NAME, handle);
606             success = false;
607         }
608         else
609         {
610             if (!parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque))
611                 success = false;
612         }
613     }
614
615     return success;
616 }