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