bool vogleditor_traceReplayer::applying_snapshot_and_process_resize(const vogl_gl_state_snapshot* pSnapshot) { vogl_gl_replayer::status_t status = m_pTraceReplayer->begin_applying_snapshot(pSnapshot, false); bool bStatus = true; while (status == vogl_gl_replayer::cStatusResizeWindow) { vogleditor_output_message("Waiting for replay window to resize."); // Pump X events in case the window is resizing if (process_x_events()) { status = m_pTraceReplayer->process_pending_window_resize(); } else { bStatus = false; break; } } if (bStatus && status != vogl_gl_replayer::cStatusOK) { vogleditor_output_error("Replay unable to apply snapshot"); bStatus = false; } return bStatus; }
bool vogleditor_QApiCallTreeModel::init(vogl_trace_file_reader* pTrace_reader) { vogleditor_apiCallTreeItem* parent = m_rootItem; const vogl_trace_stream_start_of_file_packet &sof_packet = pTrace_reader->get_sof_packet(); VOGL_NOTE_UNUSED(sof_packet); uint64_t total_swaps = 0; bool found_eof_packet = false; // make a PendingFrame node to hold the api calls // this will remain in the pending state until the first // api call is seen, then it will be made the CurFrame and // appended to the parent vogleditor_frameItem* pCurFrame = NULL; vogleditor_apiCallTreeItem* pCurParent = parent; // Make a PendingSnapshot that may or may not be populated when reading the trace. // This snapshot will be assigned to the next API call that occurs. vogleditor_gl_state_snapshot* pPendingSnapshot = NULL; m_trace_ctypes.init(pTrace_reader->get_sof_packet().m_pointer_sizes); for ( ; ; ) { vogl_trace_file_reader::trace_file_reader_status_t read_status = pTrace_reader->read_next_packet(); if ((read_status != vogl_trace_file_reader::c*K) && (read_status != vogl_trace_file_reader::cEOF)) { vogleditor_output_error("Failed reading from trace file!"); return false; } if (read_status == vogl_trace_file_reader::cEOF) { vogl_printf("At trace file EOF on swap %" PRIu64 "\n", total_swaps); return false; } const vogl::vector<uint8_t> &packet_buf = pTrace_reader->get_packet_buf(); VOGL_NOTE_UNUSED(packet_buf); const vogl_trace_stream_packet_base &base_packet = pTrace_reader->get_base_packet(); VOGL_NOTE_UNUSED(base_packet); const vogl_trace_gl_entrypoint_packet *pGL_packet = NULL; if (pTrace_reader->get_packet_type() == cTSPTGLEntrypoint) { vogl_trace_packet* pTrace_packet = vogl_new(vogl_trace_packet, &m_trace_ctypes); if (!pTrace_packet->deserialize(pTrace_reader->get_packet_buf().get_ptr(), pTrace_reader->get_packet_buf().size(), false)) { vogleditor_output_error("Failed parsing GL entrypoint packet."); return false; } if (!pTrace_packet->check()) { vogleditor_output_error("GL entrypoint packet failed consistency check. Please make sure the trace was made with the most recent version of VOGL."); return false; } pGL_packet = &pTrace_reader->get_packet<vogl_trace_gl_entrypoint_packet>(); gl_entrypoint_id_t entrypoint_id = static_cast<gl_entrypoint_id_t>(pGL_packet->m_entrypoint_id); if (entrypoint_id == VOGL_ENTRYPOINT_glInternalTraceCommandRAD) { // Check if this is a state snapshot. // This is entirely optional since the client is designed to dynamically get new snapshots // if they don't exist. GLuint cmd = pTrace_packet->get_param_value<GLuint>(0); GLuint size = pTrace_packet->get_param_value<GLuint>(1); VOGL_NOTE_UNUSED(size); if (cmd == cITCRKeyValueMap) { key_value_map &kvm = pTrace_packet->get_key_value_map(); dynamic_string cmd_type(kvm.get_string("command_type")); if (cmd_type == "state_snapshot") { dynamic_string id(kvm.get_string("binary_id")); if (id.is_empty()) { vogl_warning_printf("%s: Missing binary_id field in glInternalTraceCommandRAD key_value_map command type: \"%s\"\n", VOGL_FUNCTION_INFO_CSTR, cmd_type.get_ptr()); continue; } uint8_vec snapshot_data; { timed_scope ts("get_multi_blob_manager().get"); if (!pTrace_reader->get_multi_blob_manager().get(id, snapshot_data) || (snapshot_data.is_empty())) { vogl_warning_printf("%s: Failed reading snapshot blob data \"%s\"!\n", VOGL_FUNCTION_INFO_CSTR, id.get_ptr()); continue; } } json_document doc; { timed_scope ts("doc.binary_deserialize"); if (!doc.binary_deserialize(snapshot_data) || (!doc.get_root())) { vogl_warning_printf("%s: Failed deserializing JSON snapshot blob data \"%s\"!\n", VOGL_FUNCTION_INFO_CSTR, id.get_ptr()); continue; } } vogl_gl_state_snapshot* pGLSnapshot = vogl_new(vogl_gl_state_snapshot); pPendingSnapshot = vogl_new(vogleditor_gl_state_snapshot, pGLSnapshot); timed_scope ts("pPendingSnapshot->deserialize"); if (!pPendingSnapshot->get_snapshot()->deserialize(*doc.get_root(), pTrace_reader->get_multi_blob_manager(), &m_trace_ctypes)) { vogl_delete(pPendingSnapshot); pPendingSnapshot = NULL; vogl_warning_printf("%s: Failed deserializing snapshot blob data \"%s\"!\n", VOGL_FUNCTION_INFO_CSTR, id.get_ptr()); } } } continue; } const gl_entrypoint_desc_t &entrypoint_desc = g_vogl_entrypoint_descs[entrypoint_id]; QString funcCall = entrypoint_desc.m_pName; // format parameters funcCall.append("( "); dynamic_string paramStr; for (uint param_index = 0; param_index < pTrace_packet->total_params(); param_index++) { if (param_index != 0) funcCall.append(", "); paramStr.clear(); pTrace_packet->pretty_print_param(paramStr, param_index, false); funcCall.append(paramStr.c_str()); } funcCall.append(" )"); if (pTrace_packet->has_return_value()) { funcCall.append(" = "); paramStr.clear(); pTrace_packet->pretty_print_return_value(paramStr, false); funcCall.append(paramStr.c_str()); } // if we don't have a current frame, make a new frame node // and append it to the parent if (pCurFrame == NULL) { pCurFrame = vogl_new(vogleditor_frameItem, total_swaps); vogleditor_apiCallTreeItem* pNewFrameNode = vogl_new(vogleditor_apiCallTreeItem, pCurFrame, pCurParent); pCurParent->appendChild(pNewFrameNode); m_itemList.append(pNewFrameNode); if (pPendingSnapshot != NULL) { pCurFrame->set_snapshot(pPendingSnapshot); pPendingSnapshot = NULL; } // update current parent pCurParent = pNewFrameNode; } // make item and node for the api call vogleditor_apiCallItem* pCallItem = vogl_new(vogleditor_apiCallItem, pCurFrame, pTrace_packet, *pGL_packet); pCurFrame->appendCall(pCallItem); if (pPendingSnapshot != NULL) { pCallItem->set_snapshot(pPendingSnapshot); pPendingSnapshot = NULL; } vogleditor_apiCallTreeItem* item = vogl_new(vogleditor_apiCallTreeItem, funcCall, pCallItem, pCurParent); pCurParent->appendChild(item); m_itemList.append(item); if (vogl_is_swap_buffers_entrypoint(entrypoint_id)) { total_swaps++; // reset the CurParent back to the original parent so that the next frame will be at the root level pCurParent = parent; // reset the CurFrame so that a new frame node will be created on the next api call pCurFrame = NULL; } else if (vogl_is_start_nested_entrypoint(entrypoint_id)) { // Nest logically paired blocks of gl calls including terminating // nest call pCurParent = item; } else if (vogl_is_end_nested_entrypoint(entrypoint_id)) { // move the parent back one level of the hierarchy, to its own parent // (but not past Frame parent [e.g., unpaired "end" operation]) if (pCurParent->parent() != parent) pCurParent = pCurParent->parent(); } } if (pTrace_reader->get_packet_type() == cTSPTEOF) { found_eof_packet = true; vogl_printf("Found trace file EOF packet on swap %" PRIu64 "\n", total_swaps); break; } } return found_eof_packet; }
vogleditor_tracereplayer_result vogleditor_traceReplayer::replay(vogl_trace_file_reader* m_pTraceReader, vogleditor_apiCallTreeItem* pRootItem, vogleditor_gl_state_snapshot** ppNewSnapshot, uint64_t apiCallNumber, bool endlessMode) { // reset to beginnning of trace file. m_pTraceReader->seek_to_frame(0); int initial_window_width = 1280; int initial_window_height = 1024; if (!m_window.open(initial_window_width, initial_window_height)) { vogleditor_output_error("Failed opening GL replayer window!"); return VOGLEDITOR_TRR_ERROR; } uint replayer_flags = cGLReplayerForceDebugContexts; if (!m_pTraceReplayer->init(replayer_flags, &m_window, m_pTraceReader->get_sof_packet(), m_pTraceReader->get_multi_blob_manager())) { vogleditor_output_error("Failed initializing GL replayer!"); m_window.close(); return VOGLEDITOR_TRR_ERROR; } XSelectInput(m_window.get_display(), m_window.get_xwindow(), EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask | StructureNotifyMask | KeymapStateMask); m_wmDeleteMessage = XInternAtom(m_window.get_display(), "WM_DELETE_WINDOW", False); XSetWMProtocols(m_window.get_display(), m_window.get_xwindow(), &m_wmDeleteMessage, 1); timer tm; tm.start(); vogleditor_tracereplayer_result result = VOGLEDITOR_TRR_SUCCESS; for ( ; ; ) { if (process_x_events() == false) { result = VOGLEDITOR_TRR_USER_EXIT; break; } if (pRootItem->childCount() > 0) { vogleditor_apiCallTreeItem* pFirstFrame = pRootItem->child(0); bool bStatus = true; // if the first snapshot has not been edited, then restore it here, otherwise it will get restored in the recursive call below. if (pFirstFrame->has_snapshot() && !pFirstFrame->get_snapshot()->is_edited()) { bStatus = applying_snapshot_and_process_resize(pFirstFrame->get_snapshot()->get_snapshot()); } if (bStatus) { // replay each API call. result = recursive_replay_apicallTreeItem(pRootItem, ppNewSnapshot, apiCallNumber); if (result == VOGLEDITOR_TRR_ERROR) { QString msg = QString("Replay ending abruptly at frame index %1, global api call %2").arg(m_pTraceReplayer->get_frame_index()).arg(m_pTraceReplayer->get_last_processed_call_counter()); vogleditor_output_error(msg.toStdString().c_str()); break; } else if (result == VOGLEDITOR_TRR_SNAPSHOT_SUCCESS) { break; } else if (result == VOGLEDITOR_TRR_USER_EXIT) { vogleditor_output_message("Replay stopped"); break; } else { QString msg = QString("At trace EOF, frame index %1").arg(m_pTraceReplayer->get_frame_index()); vogleditor_output_message(msg.toStdString().c_str()); if (!endlessMode) { break; } } } else { break; } } } m_pTraceReplayer->deinit(); m_window.close(); return result; }
vogleditor_tracereplayer_result vogleditor_traceReplayer::recursive_replay_apicallTreeItem(vogleditor_apiCallTreeItem* pItem, vogleditor_gl_state_snapshot** ppNewSnapshot, uint64_t apiCallNumber) { vogleditor_tracereplayer_result result = VOGLEDITOR_TRR_SUCCESS; vogleditor_apiCallItem* pApiCall = pItem->apiCallItem(); if (pApiCall != NULL) { vogl_trace_packet* pTrace_packet = pApiCall->getTracePacket(); vogl_gl_replayer::status_t status = vogl_gl_replayer::cStatusOK; // See if a window resize or snapshot is pending. If a window resize is pending we must delay a while and pump X events until the window is resized. while (m_pTraceReplayer->get_has_pending_window_resize() || m_pTraceReplayer->get_pending_apply_snapshot()) { // Pump X events in case the window is resizing if (process_x_events()) { status = m_pTraceReplayer->process_pending_window_resize(); if (status != vogl_gl_replayer::cStatusResizeWindow) break; } else { // most likely the window wants to close, so let's return return VOGLEDITOR_TRR_USER_EXIT; } } // replay the trace packet if (status == vogl_gl_replayer::cStatusOK) status = m_pTraceReplayer->process_next_packet(*pTrace_packet); // if that was successful, check to see if a state snapshot is needed if ((status != vogl_gl_replayer::cStatusHardFailure) && (status != vogl_gl_replayer::cStatusAtEOF)) { if (ppNewSnapshot != NULL) { // get the snapshot after the selected api call if ((!*ppNewSnapshot) && (m_pTraceReplayer->get_last_processed_call_counter() == static_cast<int64_t>(apiCallNumber))) { dynamic_string info; vogleditor_output_message(info.format("Taking snapshot on API call # %" PRIu64 "...", apiCallNumber).c_str()); vogl_gl_state_snapshot* pNewSnapshot = m_pTraceReplayer->snapshot_state(); if (pNewSnapshot == NULL) { result = VOGLEDITOR_TRR_ERROR; vogleditor_output_error("... snapshot failed!"); } else { result = VOGLEDITOR_TRR_SNAPSHOT_SUCCESS; vogleditor_output_message("... snapshot succeeded!\n"); *ppNewSnapshot = vogl_new(vogleditor_gl_state_snapshot, pNewSnapshot); if (*ppNewSnapshot == NULL) { result = VOGLEDITOR_TRR_ERROR; vogleditor_output_error("Allocating memory for snapshot container failed!"); vogl_delete(pNewSnapshot); } } } } } else { // replaying the trace packet failed, set as error result = VOGLEDITOR_TRR_ERROR; dynamic_string info; vogleditor_output_error(info.format("Unable to replay gl entrypoint at call %" PRIu64, pTrace_packet->get_call_counter()).c_str()); } } if (result == VOGLEDITOR_TRR_SUCCESS && pItem->has_snapshot() && pItem->get_snapshot()->is_edited() && pItem->get_snapshot()->is_valid()) { if(applying_snapshot_and_process_resize(pItem->get_snapshot()->get_snapshot())) { result = VOGLEDITOR_TRR_SUCCESS; } } if (result == VOGLEDITOR_TRR_SUCCESS) { for (int i = 0; i < pItem->childCount(); i++) { result = recursive_replay_apicallTreeItem(pItem->child(i), ppNewSnapshot, apiCallNumber); if (result != VOGLEDITOR_TRR_SUCCESS) break; // Pump X events in case the window is resizing if (process_x_events() == false) { // most likely the window wants to close, so let's return return VOGLEDITOR_TRR_USER_EXIT; } } } return result; }