]> git.cworth.org Git - vogl/blob - src/vogleditor/vogleditor_tracereplayer.cpp
UI: separate capturing of vogl_gl_state_snapshot from allocation of the vogleditor_gl...
[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
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         vogl_warning_printf("%s: Waiting for window to resize\n", VOGL_METHOD_NAME);
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         vogl_error_printf("%s: Replay unable to apply snapshot\n", VOGL_FUNCTION_NAME);
127         bStatus = false;
128     }
129
130     return bStatus;
131 }
132
133 bool vogleditor_traceReplayer::recursive_replay_apicallTreeItem(vogleditor_apiCallTreeItem* pItem, vogleditor_gl_state_snapshot** ppNewSnapshot, uint64_t apiCallNumber)
134 {
135     bool bStatus = true;
136
137     vogleditor_apiCallItem* pApiCall = pItem->apiCallItem();
138     if (pApiCall != NULL)
139     {
140         vogl_trace_packet* pTrace_packet = pApiCall->getTracePacket();
141
142         vogl_gl_replayer::status_t status = vogl_gl_replayer::cStatusOK;
143
144         // 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.
145         while (m_pTraceReplayer->get_has_pending_window_resize() || m_pTraceReplayer->get_pending_apply_snapshot())
146         {
147             // Pump X events in case the window is resizing
148             bStatus = process_x_events();
149             if (bStatus)
150             {
151                 status = m_pTraceReplayer->process_pending_window_resize();
152                 if (status != vogl_gl_replayer::cStatusResizeWindow)
153                     break;
154             }
155             else
156             {
157                 // most likely the window wants to close, so let's return
158                 return false;
159             }
160         }
161
162         // replay the trace packet
163         if (status == vogl_gl_replayer::cStatusOK)
164             status = m_pTraceReplayer->process_next_packet(*pTrace_packet);
165
166         // if that was successful, check to see if a state snapshot is needed
167         if ((status != vogl_gl_replayer::cStatusHardFailure) && (status != vogl_gl_replayer::cStatusAtEOF))
168         {
169             if (ppNewSnapshot != NULL)
170             {
171                // get the snapshot after the selected api call
172                if ((!*ppNewSnapshot) && (m_pTraceReplayer->get_last_processed_call_counter() == static_cast<int64_t>(apiCallNumber)))
173                {
174                   vogl_printf("Taking snapshot on API call # %" PRIu64 "\n", apiCallNumber);
175
176                   vogl_gl_state_snapshot* pNewSnapshot = m_pTraceReplayer->snapshot_state();
177                   if (pNewSnapshot == NULL)
178                   {
179                       vogl_error_printf("Taking new snapshot failed!\n");
180                   }
181                   else
182                   {
183                       vogl_printf("Taking snapshot succeeded\n");
184                       *ppNewSnapshot = vogl_new(vogleditor_gl_state_snapshot, pNewSnapshot);
185                       if (*ppNewSnapshot == NULL)
186                       {
187                          vogl_error_printf("Allocating memory for snapshot container failed!\n");
188                          vogl_delete(pNewSnapshot);
189                       }
190                   }
191
192                   bStatus = false;
193                }
194             }
195         }
196         else
197         {
198             // replaying the trace packet failed, set as error
199             vogl_error_printf("%s: unable to replay gl entrypoint at call %" PRIu64 "\n", VOGL_FUNCTION_NAME, pTrace_packet->get_call_counter());
200             bStatus = false;
201         }
202     }
203
204     if (bStatus && pItem->has_snapshot() && pItem->get_snapshot()->is_edited() && pItem->get_snapshot()->is_valid())
205     {
206         bStatus = applying_snapshot_and_process_resize(pItem->get_snapshot()->get_snapshot());
207     }
208
209     if (bStatus)
210     {
211         for (int i = 0; i < pItem->childCount(); i++)
212         {
213             bStatus = recursive_replay_apicallTreeItem(pItem->child(i), ppNewSnapshot, apiCallNumber);
214
215             if (!bStatus)
216                 break;
217         }
218     }
219
220     return bStatus;
221 }
222
223 bool vogleditor_traceReplayer::replay(vogl_trace_file_reader* m_pTraceReader, vogleditor_apiCallTreeItem* pRootItem, vogleditor_gl_state_snapshot** ppNewSnapshot, uint64_t apiCallNumber, bool endlessMode)
224 {
225    // reset to beginnning of trace file.
226    m_pTraceReader->seek_to_frame(0);
227
228    int initial_window_width = 1280;
229    int initial_window_height = 1024;
230
231    if (!m_window.open(initial_window_width, initial_window_height))
232    {
233       vogl_error_printf("%s: Failed opening GL replayer window!\n", VOGL_FUNCTION_NAME);
234       return false;
235    }
236
237    uint replayer_flags = cGLReplayerForceDebugContexts;
238    if (!m_pTraceReplayer->init(replayer_flags, &m_window, m_pTraceReader->get_sof_packet(), m_pTraceReader->get_multi_blob_manager()))
239    {
240       vogl_error_printf("%s: Failed initializing GL replayer\n", VOGL_FUNCTION_NAME);
241       m_window.close();
242       return false;
243    }
244
245    XSelectInput(m_window.get_display(), m_window.get_xwindow(),
246                 EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask | StructureNotifyMask | KeymapStateMask);
247
248    m_wmDeleteMessage = XInternAtom(m_window.get_display(), "WM_DELETE_WINDOW", False);
249    XSetWMProtocols(m_window.get_display(), m_window.get_xwindow(), &m_wmDeleteMessage, 1);
250
251    timer tm;
252    tm.start();
253
254    bool bStatus = true;
255
256    for ( ; ; )
257    {
258       if (process_x_events() == false)
259       {
260           break;
261       }
262
263       if (pRootItem->childCount() > 0)
264       {
265           vogleditor_apiCallTreeItem* pFirstFrame = pRootItem->child(0);
266
267           // if the first snapshot has not been edited, then restore it here, otherwise it will get restored in the recursive call below.
268           if (pFirstFrame->has_snapshot() && !pFirstFrame->get_snapshot()->is_edited())
269           {
270               bStatus = applying_snapshot_and_process_resize(pFirstFrame->get_snapshot()->get_snapshot());
271           }
272
273           if (bStatus)
274           {
275               // replay each API call.
276               bStatus = recursive_replay_apicallTreeItem(pRootItem, ppNewSnapshot, apiCallNumber);
277
278               if (bStatus == false)
279               {
280                  vogl_error_printf("%s: Replay ending abruptly at frame index %u, global api call %" PRIu64 "\n", VOGL_FUNCTION_NAME, m_pTraceReplayer->get_frame_index(), m_pTraceReplayer->get_last_processed_call_counter());
281                  break;
282               }
283               else
284               {
285                  vogl_message_printf("%s: At trace EOF, frame index %u\n", VOGL_FUNCTION_NAME, m_pTraceReplayer->get_frame_index());
286                  if (!endlessMode)
287                  {
288                      break;
289                  }
290               }
291           }
292           else
293           {
294               break;
295           }
296       }
297    }
298
299    m_pTraceReplayer->deinit();
300    m_window.close();
301    return bStatus;
302 }
303
304 bool vogleditor_traceReplayer::pause()
305 {
306     VOGL_ASSERT(!"Not implemented");
307     return false;
308 }
309
310 bool vogleditor_traceReplayer::restart()
311 {
312     VOGL_ASSERT(!"Not implemented");
313     return false;
314 }
315
316 bool vogleditor_traceReplayer::trim()
317 {
318     VOGL_ASSERT(!"Not implemented");
319     return false;
320 }
321
322 bool vogleditor_traceReplayer::stop()
323 {
324     VOGL_ASSERT(!"Not implemented");
325     return false;
326 }