]> git.cworth.org Git - vogl/blob - src/vogleditor/vogleditor_tracereplayer.cpp
UI: vogleditor_tracereplayer now outputs messages regarding success of replaying...
[vogl] / src / vogleditor / vogleditor_tracereplayer.cpp
1
2 #include "vogleditor_apicalltreeitem.h"
3
4 #include "vogleditor_tracereplayer.h"
5
6 #include "vogl_find_files.h"
7 #include "vogl_file_utils.h"
8 #include "vogl_gl_replayer.h"
9 #include "vogleditor_output.h"
10
11 vogleditor_traceReplayer::vogleditor_traceReplayer()
12     : m_pTraceReplayer(vogl_new(vogl_gl_replayer))
13 {
14
15 }
16
17 vogleditor_traceReplayer::~vogleditor_traceReplayer()
18 {
19     if (m_pTraceReplayer != NULL)
20     {
21         vogl_delete(m_pTraceReplayer);
22         m_pTraceReplayer = NULL;
23     }
24 }
25
26 //----------------------------------------------------------------------------------------------------------------------
27 // X11_Pending - from SDL
28 //----------------------------------------------------------------------------------------------------------------------
29 static int X11_Pending(Display *display)
30 {
31    VOGL_FUNC_TRACER
32
33    /* Flush the display connection and look to see if events are queued */
34    XFlush(display);
35    if (XEventsQueued(display, QueuedAlready))
36    {
37       return(1);
38    }
39
40    /* More drastic measures are required -- see if X is ready to talk */
41    {
42       static struct timeval zero_time;  /* static == 0 */
43       int x11_fd;
44       fd_set fdset;
45
46       x11_fd = ConnectionNumber(display);
47       FD_ZERO(&fdset);
48       FD_SET(x11_fd, &fdset);
49       if (select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1)
50       {
51          return(XPending(display));
52       }
53    }
54
55    /* Oh well, nothing is ready .. */
56    return(0);
57 }
58
59 bool vogleditor_traceReplayer::process_x_events()
60 {
61     while (X11_Pending(m_window.get_display()))
62     {
63        XEvent newEvent;
64
65        // Watch for new X events
66        XNextEvent(m_window.get_display(), &newEvent);
67
68        switch (newEvent.type)
69        {
70           case MapNotify:
71           {
72              m_pTraceReplayer->update_window_dimensions();
73              break;
74           }
75           case ConfigureNotify:
76           {
77              m_pTraceReplayer->update_window_dimensions();
78              break;
79           }
80           case DestroyNotify:
81           {
82              vogl_message_printf("Exiting\n");
83              return false;
84              break;
85           }
86           case ClientMessage:
87           {
88              if(newEvent.xclient.data.l[0] == (int)m_wmDeleteMessage)
89              {
90                 vogl_message_printf("Exiting\n");
91                 return false;
92              }
93
94              break;
95           }
96           default: break;
97        }
98     }
99
100     return true;
101 }
102
103 bool vogleditor_traceReplayer::applying_snapshot_and_process_resize(const vogl_gl_state_snapshot* pSnapshot)
104 {
105     vogl_gl_replayer::status_t status = m_pTraceReplayer->begin_applying_snapshot(pSnapshot, false);
106
107     bool bStatus = true;
108     while (status == vogl_gl_replayer::cStatusResizeWindow)
109     {
110         vogleditor_output_message("Waiting for replay window to resize.");
111
112         // Pump X events in case the window is resizing
113         if (process_x_events())
114         {
115             status = m_pTraceReplayer->process_pending_window_resize();
116         }
117         else
118         {
119             bStatus = false;
120             break;
121         }
122     }
123
124     if (bStatus && status != vogl_gl_replayer::cStatusOK)
125     {
126         vogleditor_output_error("Replay unable to apply snapshot");
127         bStatus = false;
128     }
129
130     return bStatus;
131 }
132
133 vogleditor_tracereplayer_result vogleditor_traceReplayer::recursive_replay_apicallTreeItem(vogleditor_apiCallTreeItem* pItem, vogleditor_gl_state_snapshot** ppNewSnapshot, uint64_t apiCallNumber)
134 {
135     vogleditor_tracereplayer_result result = VOGLEDITOR_TRR_SUCCESS;
136     vogleditor_apiCallItem* pApiCall = pItem->apiCallItem();
137     if (pApiCall != NULL)
138     {
139         vogl_trace_packet* pTrace_packet = pApiCall->getTracePacket();
140
141         vogl_gl_replayer::status_t status = vogl_gl_replayer::cStatusOK;
142
143         // 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.
144         while (m_pTraceReplayer->get_has_pending_window_resize() || m_pTraceReplayer->get_pending_apply_snapshot())
145         {
146             // Pump X events in case the window is resizing
147             if (process_x_events())
148             {
149                 status = m_pTraceReplayer->process_pending_window_resize();
150                 if (status != vogl_gl_replayer::cStatusResizeWindow)
151                     break;
152             }
153             else
154             {
155                 // most likely the window wants to close, so let's return
156                 return VOGLEDITOR_TRR_USER_EXIT;
157             }
158         }
159
160         // replay the trace packet
161         if (status == vogl_gl_replayer::cStatusOK)
162             status = m_pTraceReplayer->process_next_packet(*pTrace_packet);
163
164         // if that was successful, check to see if a state snapshot is needed
165         if ((status != vogl_gl_replayer::cStatusHardFailure) && (status != vogl_gl_replayer::cStatusAtEOF))
166         {
167             if (ppNewSnapshot != NULL)
168             {
169                // get the snapshot after the selected api call
170                if ((!*ppNewSnapshot) && (m_pTraceReplayer->get_last_processed_call_counter() == static_cast<int64_t>(apiCallNumber)))
171                {
172                   dynamic_string info;
173                   vogleditor_output_message(info.format("Taking snapshot on API call # %" PRIu64 "...", apiCallNumber).c_str());
174
175                   vogl_gl_state_snapshot* pNewSnapshot = m_pTraceReplayer->snapshot_state();
176                   if (pNewSnapshot == NULL)
177                   {
178                       result = VOGLEDITOR_TRR_ERROR;
179                       vogleditor_output_error("... snapshot failed!");
180                   }
181                   else
182                   {
183                       result = VOGLEDITOR_TRR_SNAPSHOT_SUCCESS;
184                       vogleditor_output_message("... snapshot succeeded!\n");
185                       *ppNewSnapshot = vogl_new(vogleditor_gl_state_snapshot, pNewSnapshot);
186                       if (*ppNewSnapshot == NULL)
187                       {
188                          result = VOGLEDITOR_TRR_ERROR;
189                          vogleditor_output_error("Allocating memory for snapshot container failed!");
190                          vogl_delete(pNewSnapshot);
191                       }
192                   }
193                }
194             }
195         }
196         else
197         {
198             // replaying the trace packet failed, set as error
199             result = VOGLEDITOR_TRR_ERROR;
200             dynamic_string info;
201             vogleditor_output_error(info.format("Unable to replay gl entrypoint at call %" PRIu64, pTrace_packet->get_call_counter()).c_str());
202         }
203     }
204
205     if (result == VOGLEDITOR_TRR_SUCCESS && pItem->has_snapshot() && pItem->get_snapshot()->is_edited() && pItem->get_snapshot()->is_valid())
206     {
207         if(applying_snapshot_and_process_resize(pItem->get_snapshot()->get_snapshot()))
208         {
209             result = VOGLEDITOR_TRR_SUCCESS;
210         }
211     }
212
213     if (result == VOGLEDITOR_TRR_SUCCESS)
214     {
215         for (int i = 0; i < pItem->childCount(); i++)
216         {
217             result = recursive_replay_apicallTreeItem(pItem->child(i), ppNewSnapshot, apiCallNumber);
218
219             if (result != VOGLEDITOR_TRR_SUCCESS)
220                 break;
221
222             // Pump X events in case the window is resizing
223             if (process_x_events() == false)
224             {
225                 // most likely the window wants to close, so let's return
226                 return VOGLEDITOR_TRR_USER_EXIT;
227             }
228         }
229     }
230
231     return result;
232 }
233
234 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)
235 {
236    // reset to beginnning of trace file.
237    m_pTraceReader->seek_to_frame(0);
238
239    int initial_window_width = 1280;
240    int initial_window_height = 1024;
241
242    if (!m_window.open(initial_window_width, initial_window_height))
243    {
244       vogleditor_output_error("Failed opening GL replayer window!");
245       return VOGLEDITOR_TRR_ERROR;
246    }
247
248    uint replayer_flags = cGLReplayerForceDebugContexts;
249    if (!m_pTraceReplayer->init(replayer_flags, &m_window, m_pTraceReader->get_sof_packet(), m_pTraceReader->get_multi_blob_manager()))
250    {
251       vogleditor_output_error("Failed initializing GL replayer!");
252       m_window.close();
253       return VOGLEDITOR_TRR_ERROR;
254    }
255
256    XSelectInput(m_window.get_display(), m_window.get_xwindow(),
257                 EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask | StructureNotifyMask | KeymapStateMask);
258
259    m_wmDeleteMessage = XInternAtom(m_window.get_display(), "WM_DELETE_WINDOW", False);
260    XSetWMProtocols(m_window.get_display(), m_window.get_xwindow(), &m_wmDeleteMessage, 1);
261
262    timer tm;
263    tm.start();
264
265    vogleditor_tracereplayer_result result = VOGLEDITOR_TRR_SUCCESS;
266
267    for ( ; ; )
268    {
269       if (process_x_events() == false)
270       {
271           result = VOGLEDITOR_TRR_USER_EXIT;
272           break;
273       }
274
275       if (pRootItem->childCount() > 0)
276       {
277           vogleditor_apiCallTreeItem* pFirstFrame = pRootItem->child(0);
278
279           bool bStatus = true;
280           // if the first snapshot has not been edited, then restore it here, otherwise it will get restored in the recursive call below.
281           if (pFirstFrame->has_snapshot() && !pFirstFrame->get_snapshot()->is_edited())
282           {
283               bStatus = applying_snapshot_and_process_resize(pFirstFrame->get_snapshot()->get_snapshot());
284           }
285
286           if (bStatus)
287           {
288               // replay each API call.
289               result = recursive_replay_apicallTreeItem(pRootItem, ppNewSnapshot, apiCallNumber);
290
291               if (result == VOGLEDITOR_TRR_ERROR)
292               {
293                   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());
294                   vogleditor_output_error(msg.toStdString().c_str());
295                   break;
296               }
297               else if (result == VOGLEDITOR_TRR_SNAPSHOT_SUCCESS)
298               {
299                   break;
300               }
301               else if (result == VOGLEDITOR_TRR_USER_EXIT)
302               {
303                   vogleditor_output_message("Replay stopped");
304                   break;
305               }
306               else
307               {
308                   QString msg = QString("At trace EOF, frame index %1").arg(m_pTraceReplayer->get_frame_index());
309                   vogleditor_output_message(msg.toStdString().c_str());
310                   if (!endlessMode)
311                   {
312                       break;
313                   }
314               }
315           }
316           else
317           {
318               break;
319           }
320       }
321    }
322
323    m_pTraceReplayer->deinit();
324    m_window.close();
325    return result;
326 }
327
328 bool vogleditor_traceReplayer::pause()
329 {
330     VOGL_ASSERT(!"Not implemented");
331     return false;
332 }
333
334 bool vogleditor_traceReplayer::restart()
335 {
336     VOGL_ASSERT(!"Not implemented");
337     return false;
338 }
339
340 bool vogleditor_traceReplayer::trim()
341 {
342     VOGL_ASSERT(!"Not implemented");
343     return false;
344 }
345
346 bool vogleditor_traceReplayer::stop()
347 {
348     VOGL_ASSERT(!"Not implemented");
349     return false;
350 }