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
87 node.add_key_value("handle", m_handle);
88 node.add_key_value("generating", m_generating);
89 node.add_key_value("xfont", m_xfont);
92 node.add_key_value("xfont_glyph", m_xfont_glyph);
93 node.add_key_value("xfont_name", m_xfont_name);
98 vogl_trace_packet::json_serialize_params params;
99 params.m_pBlob_manager = &blob_manager;
101 json_node &packets_array = node.add_array("packets");
102 for (uint i = 0; i < m_packets.size(); i++)
104 const uint8_vec &packet_buf = m_packets.get_packet_buf(i);
106 vogl_trace_packet packet(pCtypes);
107 if (!packet.deserialize(packet_buf.get_ptr(), packet_buf.size(), true))
110 if (!packet.json_serialize(packets_array.add_object(), params))
118 bool vogl_display_list::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
124 m_handle = node.value_as_uint32("handle");
125 m_generating = node.value_as_bool("generating");
126 m_xfont = node.value_as_bool("xfont");
129 m_xfont_glyph = node.value_as_int("xfont_glyph");
130 m_xfont_name = node.value_as_string("xfont_name");
133 const json_node *pPackets_array = node.find_child_array("packets");
136 if (!pPackets_array->are_all_children_objects())
142 vogl_trace_packet packet(pCtypes);
144 m_packets.resize(pPackets_array->size());
145 for (uint i = 0; i < pPackets_array->size(); i++)
147 if (!packet.json_deserialize(*pPackets_array->get_child(i), "<display_list>", &blob_manager))
153 if (!packet.serialize(m_packets.get_packet_buf(i)))
166 vogl_display_list_state::vogl_display_list_state()
171 vogl_display_list_state::vogl_display_list_state(const vogl_display_list_state &other)
178 vogl_display_list_state::~vogl_display_list_state()
183 vogl_display_list_state &vogl_display_list_state::operator=(const vogl_display_list_state &rhs)
192 m_display_lists = rhs.m_display_lists;
197 void vogl_display_list_state::clear()
201 m_display_lists.clear();
204 bool vogl_display_list_state::remap_handles(vogl_handle_remapper &remapper)
208 vogl_display_list_map new_display_lists;
210 for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
212 uint new_handle = static_cast<uint>(remapper.remap_handle(VOGL_NAMESPACE_LISTS, it->first));
214 new_display_lists[new_handle] = it->second;
217 new_display_lists.swap(m_display_lists);
222 bool vogl_display_list_state::serialize(json_node &node, vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes) const
226 if (m_display_lists.size())
228 json_node &lists_node = node.add_object("lists");
230 for (vogl_display_list_map::const_iterator it = m_display_lists.begin(); it != m_display_lists.end(); ++it)
232 if (!it->second.is_valid())
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());
237 if (!it->second.serialize(lists_node.add_object(uint_to_string(it->first)), blob_manager, pCtypes))
245 bool vogl_display_list_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager, const vogl_ctypes *pCtypes)
251 const json_node *pLists_node = node.find_child_object("lists");
254 if (!pLists_node->are_all_children_objects())
257 for (uint i = 0; i < pLists_node->size(); i++)
259 if (!m_display_lists[string_to_uint(pLists_node->get_key(i).get_ptr())].deserialize(*pLists_node->get_child(i), blob_manager, pCtypes))
270 bool vogl_display_list_state::define_list(GLuint trace_handle, GLuint replay_handle, const vogl_display_list &list)
274 vogl_display_list_map::insert_result res(m_display_lists.insert(trace_handle));
278 vogl_display_list_map::iterator it = res.first;
280 vogl_display_list &new_list = it->second;
282 new_list.set_handle(replay_handle);
287 void vogl_display_list_state::new_list(GLuint trace_handle, GLuint replay_handle)
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;
296 new_list.set_handle(replay_handle);
297 new_list.begin_gen();
300 bool vogl_display_list_state::end_list(GLuint trace_handle)
304 vogl_display_list_map::iterator it = m_display_lists.find(trace_handle);
305 if (it == m_display_lists.end())
308 it->second.end_gen();
312 bool vogl_display_list_state::gen_lists(GLuint first, GLsizei n, GLuint *pObject_handles)
317 for (GLsizei i = 0; i < n; i++)
319 vogl_display_list_map::insert_result res(m_display_lists.insert(first + i));
322 vogl_error_printf("%s: Failed inserting list handle %u into display list shadow!\n", VOGL_METHOD_NAME, first + i);
327 (res.first)->second.set_handle(pObject_handles ? pObject_handles[i] : first + i);
333 bool vogl_display_list_state::del_lists(GLuint first, GLsizei n)
338 for (GLsizei i = 0; i < n; i++)
340 if (!m_display_lists.erase(first + i))
346 bool vogl_display_list_state::glx_font(const char *pFont, int first, int count, int listBase)
351 for (int i = 0; i < count; i++)
353 int handle = listBase + i;
356 vogl_error_printf("%s: Invalid display list handle %i\n", VOGL_METHOD_NAME, handle);
361 vogl_display_list *pList = &m_display_lists[handle];
362 pList->init_xfont(pFont, first + i);
368 bool vogl_display_list_state::is_call_listable(gl_entrypoint_id_t func, const vogl_trace_packet &packet)
372 if ((!g_vogl_entrypoint_descs[func].m_is_listable) || (!g_vogl_entrypoint_descs[func].m_whitelisted_for_displaylists))
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)))
386 bool vogl_display_list_state::add_packet_to_list(GLuint handle, gl_entrypoint_id_t func, const vogl_trace_packet &packet)
389 VOGL_NOTE_UNUSED(func);
391 vogl_display_list *pList = m_display_lists.find_value(handle);
395 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List %u was not genned.\n", VOGL_FUNCTION_NAME, handle);
400 if (!packet.serialize(buf))
402 vogl_error_printf("%s: Failed serializing trace packet into display list shadow! List handle %u.\n", VOGL_FUNCTION_NAME, handle);
406 pList->get_packets().push_back(buf);
410 bool vogl_display_list_state::parse_list_and_update_shadows(GLuint handle, pBind_callback_func_ptr pBind_callback, void *pBind_callback_opaque)
414 VOGL_ASSERT(pBind_callback);
416 const vogl_display_list *pList = find_list(handle);
420 const vogl_trace_packet_array &packets = pList->get_packets();
422 vogl_trace_packet trace_packet(&g_vogl_process_gl_ctypes);
424 for (uint packet_index = 0; packet_index < packets.size(); packet_index++)
426 if (packets.get_packet_type(packet_index) != cTSPTGLEntrypoint)
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)
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:
451 if (!trace_packet.deserialize(packets.get_packet_buf(packet_index), false))
453 vogl_error_printf("%s: Failed parsing GL entrypoint packet in display list %u\n", VOGL_FUNCTION_NAME, handle);
458 switch (trace_packet.get_entrypoint_id())
460 case VOGL_ENTRYPOINT_glBindTexture:
461 case VOGL_ENTRYPOINT_glBindTextureEXT:
463 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
466 case VOGL_ENTRYPOINT_glBindMultiTextureEXT:
468 (*pBind_callback)(VOGL_NAMESPACE_TEXTURES, trace_packet.get_param_value<GLenum>(1), trace_packet.get_param_value<GLuint>(2), pBind_callback_opaque);
471 case VOGL_ENTRYPOINT_glBindBuffer:
473 (*pBind_callback)(VOGL_NAMESPACE_BUFFERS, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
476 case VOGL_ENTRYPOINT_glBindVertexArray:
478 (*pBind_callback)(VOGL_NAMESPACE_VERTEX_ARRAYS, GL_NONE, trace_packet.get_param_value<GLuint>(0), pBind_callback_opaque);
481 case VOGL_ENTRYPOINT_glBeginQuery:
482 case VOGL_ENTRYPOINT_glBeginQueryARB:
484 (*pBind_callback)(VOGL_NAMESPACE_QUERIES, trace_packet.get_param_value<GLenum>(0), trace_packet.get_param_value<GLuint>(1), pBind_callback_opaque);
487 case VOGL_ENTRYPOINT_glCallList:
488 case VOGL_ENTRYPOINT_glCallLists:
490 vogl_warning_printf("%s: Recursive display lists are not currently supported\n", VOGL_METHOD_NAME);
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)
509 uint type_size = vogl_get_gl_type_size(type);
512 vogl_error_printf("%s: type is invalid\n", VOGL_FUNCTION_NAME);
518 vogl_error_printf("%s: lists param is NULL\n", VOGL_FUNCTION_NAME);
522 GLuint list_base = 0;
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));
530 const uint8 *pTrace_lists_ptr = static_cast<const uint8 *>(lists);
531 for (GLsizei i = 0; i < n; i++)
533 GLint handle = list_base;
538 handle += *reinterpret_cast<const signed char *>(pTrace_lists_ptr);
542 case GL_UNSIGNED_BYTE:
544 handle += *pTrace_lists_ptr;
550 handle += *reinterpret_cast<const int16 *>(pTrace_lists_ptr);
551 pTrace_lists_ptr += sizeof(int16);
554 case GL_UNSIGNED_SHORT:
556 handle += *reinterpret_cast<const uint16 *>(pTrace_lists_ptr);
557 pTrace_lists_ptr += sizeof(uint16);
562 handle += *reinterpret_cast<const int32 *>(pTrace_lists_ptr);
563 pTrace_lists_ptr += sizeof(int32);
566 case GL_UNSIGNED_INT:
568 handle += *reinterpret_cast<const uint32 *>(pTrace_lists_ptr);
569 pTrace_lists_ptr += sizeof(uint32);
574 handle += static_cast<GLint>(*reinterpret_cast<const float *>(pTrace_lists_ptr));
575 pTrace_lists_ptr += sizeof(float);
580 handle += ((pTrace_lists_ptr[0] << 8U) + pTrace_lists_ptr[1]);
581 pTrace_lists_ptr += 2;
586 handle += ((pTrace_lists_ptr[0] << 16U) + (pTrace_lists_ptr[1] << 8U) + pTrace_lists_ptr[2]);
587 pTrace_lists_ptr += 3;
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;
598 vogl_error_printf("%s: Invalid type parameter (0x%08X)\n", VOGL_FUNCTION_NAME, type);
605 vogl_error_printf("%s: Trace handle after adding list base is negative (%i), skipping this list index\n", VOGL_FUNCTION_NAME, handle);
610 if (!parse_list_and_update_shadows(handle, pBind_callback, pBind_callback_opaque))