1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_display_list_state.cpp
27 #include "vogl_display_list_state.h"
29 vogl_display_list::vogl_display_list()
39 void vogl_display_list::clear()
51 void vogl_display_list::init_xfont(const char *pName, int glyph)
56 m_xfont_name = pName ? pName : "";
57 m_xfont_glyph = glyph;
63 void vogl_display_list::begin_gen()
71 void vogl_display_list::end_gen()
75 VOGL_ASSERT(m_generating);
80 bool vogl_display_list::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
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);
91 node.add_key_value("xfont_glyph", m_xfont_glyph);
92 node.add_key_value("xfont_name", m_xfont_name);
97 vogl_trace_packet::json_serialize_params params;
98 params.m_pBlob_manager = &blob_manager;
100 json_node &packets_array = node.add_array("packets");
101 for (uint i = 0; i < m_packets.size(); i++)
103 const uint8_vec &packet_buf = m_packets.get_packet_buf(i);
105 vogl_trace_packet packet(pCtypes);
106 if (!packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
109 if (!packet.json_serialize(packets_array.add_object(), params))
117 bool vogl_display_list::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
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");
130 m_xfont_glyph = node.value_as_int("xfont_glyph");
131 m_xfont_name = node.value_as_string("xfont_name");
134 const json_node *pPackets_array = node.find_child_array("packets");
137 if (!pPackets_array->are_all_children_objects())
143 vogl_trace_packet packet(pCtypes);
145 m_packets.resize(pPackets_array->size());
146 for (uint i = 0; i < pPackets_array->size(); i++)
148 if (!packet.json_deserialize(*pPackets_array->get_child(i), "<display_list>", &blob_manager))
154 if (!packet.serialize(m_packets.get_packet_buf(i)))
165 vogl_display_list_state::vogl_display_list_state()
170 vogl_display_list_state::vogl_display_list_state(const vogl_display_list_state &other)
177 vogl_display_list_state::~vogl_display_list_state()
182 vogl_display_list_state &vogl_display_list_state::operator=(const vogl_display_list_state &rhs)
191 m_display_lists = rhs.m_display_lists;
196 void vogl_display_list_state::clear()
200 m_display_lists.clear();
203 bool vogl_display_list_state::remap_handles(vogl_handle_remapper &remapper)
207 vogl_display_list_map new_display_lists;
209 for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
211 uint new_handle = static_cast<uint>(remapper.remap_handle(VOGL_NAMESPACE_LISTS, it->first));
213 new_display_lists[new_handle] = it->second;
216 new_display_lists.swap(m_display_lists);
221 bool vogl_display_list_state::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
225 if (m_display_lists.size())
227 json_node &lists_node = node.add_object("lists");
229 for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
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))
240 bool vogl_display_list_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
246 const json_node *pLists_node = node.find_child_object("lists");
249 if (!pLists_node->are_all_children_objects())
252 for (uint i = 0; i < pLists_node->size(); i++)
254 if (!m_display_lists[string_to_uint(pLists_node->get_key(i).get_ptr())].deserialize(*pLists_node->get_child(i), blob_manager, pCtypes))
265 bool vogl_display_list_state::define_list(GLuint trace_handle, GLuint replay_handle, const vogl_display_list &list)
269 vogl_display_list_map::insert_result res(m_display_lists.insert(trace_handle));
273 vogl_display_list_map::iterator it = res.first;
275 vogl_display_list &new_list = it->second;
277 new_list.set_handle(replay_handle);
282 void vogl_display_list_state::new_list(GLuint trace_handle, GLuint replay_handle)
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;
291 new_list.set_handle(replay_handle);
292 new_list.begin_gen();
295 bool vogl_display_list_state::end_list(GLuint trace_handle)
299 vogl_display_list_map::iterator it = m_display_lists.find(trace_handle);
300 if (it == m_display_lists.end())
303 it->second.end_gen();
307 bool vogl_display_list_state::gen_lists(GLuint first, GLsizei n, GLuint *pObject_handles)
312 for (GLsizei i = 0; i < n; i++)
314 vogl_display_list_map::insert_result res(m_display_lists.insert(first + i));
317 vogl_error_printf("%s: Failed inserting list handle %u into display list shadow!\n", VOGL_METHOD_NAME, first + i);
322 (res.first)->second.set_handle(pObject_handles ? pObject_handles[i] : first + i);
328 bool vogl_display_list_state::del_lists(GLuint first, GLsizei n)
333 for (GLsizei i = 0; i < n; i++)
335 if (!m_display_lists.erase(first + i))
341 bool vogl_display_list_state::glx_font(const char *pFont, int first, int count, int listBase)
346 for (int i = 0; i < count; i++)
348 int handle = listBase + i;
351 vogl_error_printf("%s: Invalid display list handle %i\n", VOGL_METHOD_NAME, handle);
356 vogl_display_list *pList = &m_display_lists[handle];
357 pList->init_xfont(pFont, first + i);
363 bool vogl_display_list_state::is_call_listable(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
367 if ((!g_vogl_entrypoint_descs[func].m_is_listable) || (!g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists))
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)))
381 bool vogl_display_list_state::add_packet_to_list(GLuint handle, gl_entrypoint_id_t func, const vogl_trace_packet &packet)
384 VOGL_NOTE_UNUSED(func);
386 vogl_display_list *pList = m_display_lists.find_value(handle);
390 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List %u was not genned.\n", VOGL_FUNCTION_NAME, handle);
395 if (!packet.serialize(buf))
397 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List handle %u.\n", VOGL_FUNCTION_NAME, handle);
401 pList->get_packets().push_back(buf);
405 bool vogl_display_list_state::parse_list_and_update_shadows(GLuint handle, pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
409 VOGL_ASSERT(pBind_callback);
411 const vogl_display_list *pList = find_list(handle);
415 const vogl_trace_packet_array &packets = pList->get_packets();
417 vogl_trace_packet trace_packet(&g_vogl_process_gl_ctypes);
419 for (uint packet_index = 0; packet_index < packets.size(); packet_index++)
421 if (packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
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)
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:
446 if (!trace_packet.deserialize(packets.get_packet_buf(packet_index), false))
448 vogl_error_printf("%s: Failed parsing GL entrypoint packet in display list %u\n", VOGL_FUNCTION_NAME, handle);
453 switch (trace_packet.get_entrypoint_id())
455 case VOGL_ENTRYPOINT_glBindTexture:
456 case VOGL_ENTRYPOINT_glBindTextureEXT:
458 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
461 case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
463 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), pBind_callback_opaque);
466 case VOGL_ENTRYPOINT_glBindBuffer:
468 (*pBind_callback)(VOGL_NAMESPACE_BUFFERS, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
471 case VOGL_ENTRYPOINT_glBindVertexArray:
473 (*pBind_callback)(VOGL_NAMESPACE_VERTEX_ARRAYS, GL_NONE, trace_packet.get_param_value<GLuint>(0), pBind_callback_opaque);
476 case VOGL_ENTRYPOINT_glBeginQuery:
477 case VOGL_ENTRYPOINT_glBeginQueryARB:
479 (*pBind_callback)(VOGL_NAMESPACE_QUERIES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
482 case VOGL_ENTRYPOINT_glCallList:
483 case VOGL_ENTRYPOINT_glCallLists:
485 vogl_warning_printf("%s: Recursive display lists are not currently supported\n", VOGL_METHOD_NAME);
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)
504 uint type_size = vogl_get_gl_type_size(type);
507 vogl_error_printf("%s: type is invalid\n", VOGL_FUNCTION_NAME);
513 vogl_error_printf("%s: lists param is NULL\n", VOGL_FUNCTION_NAME);
517 GLuint list_base = 0;
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));
525 const uint8 *pTrace_lists_ptr = static_cast<const uint8 *>(lists);
526 for (GLsizei i = 0; i < n; i++)
528 GLint handle = list_base;
533 handle += *reinterpret_cast<const signed char *>(pTrace_lists_ptr);
537 case GL_UNSIGNED_BYTE:
539 handle += *pTrace_lists_ptr;
545 handle += *reinterpret_cast<const int16 *>(pTrace_lists_ptr);
546 pTrace_lists_ptr += sizeof(int16);
549 case GL_UNSIGNED_SHORT:
551 handle += *reinterpret_cast<const uint16 *>(pTrace_lists_ptr);
552 pTrace_lists_ptr += sizeof(uint16);
557 handle += *reinterpret_cast<const int32 *>(pTrace_lists_ptr);
558 pTrace_lists_ptr += sizeof(int32);
561 case GL_UNSIGNED_INT:
563 handle += *reinterpret_cast<const uint32 *>(pTrace_lists_ptr);
564 pTrace_lists_ptr += sizeof(uint32);
569 handle += static_cast<GLint>(*reinterpret_cast<const float *>(pTrace_lists_ptr));
570 pTrace_lists_ptr += sizeof(float);
575 handle += ((pTrace_lists_ptr[0] << 8U) + pTrace_lists_ptr[1]);
576 pTrace_lists_ptr += 2;
581 handle += ((pTrace_lists_ptr[0] << 16U) + (pTrace_lists_ptr[1] << 8U) + pTrace_lists_ptr[2]);
582 pTrace_lists_ptr += 3;
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;
593 vogl_error_printf("%s: Invalid type parameter (0x%08X)\n", VOGL_FUNCTION_NAME, type);
600 vogl_error_printf("%s: Trace handle after adding list base is negative (%i), skipping this list index\n", VOGL_FUNCTION_NAME, handle);
605 if (!parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque))