Revision: 75653
          http://sourceforge.net/p/brlcad/code/75653
Author:   starseeker
Date:     2020-04-30 15:06:39 +0000 (Thu, 30 Apr 2020)
Log Message:
-----------
Get the fb and dm images updating independently.

Modified Paths:
--------------
    brlcad/trunk/src/libdm/tests/tcl_img.cpp

Modified: brlcad/trunk/src/libdm/tests/tcl_img.cpp
===================================================================
--- brlcad/trunk/src/libdm/tests/tcl_img.cpp    2020-04-30 12:42:46 UTC (rev 
75652)
+++ brlcad/trunk/src/libdm/tests/tcl_img.cpp    2020-04-30 15:06:39 UTC (rev 
75653)
@@ -51,6 +51,9 @@
     int dm_render_running;
     int dm_render_ready;
 
+    int fb_render_running;
+    int fb_render_ready;
+
     // Parent application sets this when it's time to shut
     // down all rendering
     int shutdown;
@@ -70,6 +73,9 @@
 
     // DM thread id
     Tcl_ThreadId dm_id;
+   
+    // FB thread_id 
+    Tcl_ThreadId fb_id;
 
     // Image info.  Reflects the currently requested parent image
     // size - the render thread may have a different size during
@@ -100,7 +106,7 @@
 };
 
 // Event container passed to routines triggered by events.
-struct DmRenderEvent {
+struct RenderEvent {
     Tcl_Event event;            /* Must be first */
     struct img_data *idata;
 };
@@ -126,11 +132,15 @@
 // thus be the PARENT's interp, and we have passed it through the
 // various structures to be available here.
 static int
-DmUpdateProc(Tcl_Event *evPtr, int UNUSED(mask))
+UpdateProc(Tcl_Event *evPtr, int UNUSED(mask))
 {
-    struct DmRenderEvent *DmEventPtr = (DmRenderEvent *) evPtr;
+    struct RenderEvent *DmEventPtr = (RenderEvent *) evPtr;
     struct img_data *idata = DmEventPtr->idata;
     Tcl_Interp *interp = idata->parent_interp;
+
+    Tcl_MutexLock(&dilock);
+    Tcl_MutexLock(&fblock);
+
     int width = idata->dm_bwidth;
     int height = idata->dm_bheight;
 
@@ -138,11 +148,12 @@
     // got triggered after this proc got started, and another update
     // event will eventually be triggered.
     if (idata->dm_render_running) {
+       Tcl_MutexUnlock(&dilock);
+       Tcl_MutexUnlock(&fblock);
        return 1;
     }
 
-    Tcl_MutexLock(&dilock);
-    Tcl_MutexLock(&fblock);
+    std::cout << "Window updating!\n";
 
     // Let Tcl/Tk know the photo data has changed, so it can update the visuals
     // accordingly
@@ -162,12 +173,14 @@
     Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, dm_data.width, 
dm_data.height, TK_PHOTO_COMPOSITE_SET);
 
 
-    // Now overlay the framebuffer.  We're done with dm_data, so just reuse it 
for
-    // this purpose
-    dm_data.width = idata->fb_width;
-    dm_data.height = idata->fb_height;
-    dm_data.pixelPtr = idata->fbpixel;
-    Tk_PhotoPutBlock(interp, dm_img, &dm_data, 0, 0, idata->fb_width, 
idata->fb_height, TK_PHOTO_COMPOSITE_OVERLAY);
+    // Now overlay the framebuffer.
+    Tk_PhotoImageBlock fb_data;
+    Tk_PhotoGetImage(dm_img, &fb_data);
+    fb_data.width = idata->fb_width;
+    fb_data.height = idata->fb_height;
+    fb_data.pitch = fb_data.width * 4;
+    fb_data.pixelPtr = idata->fbpixel;
+    Tk_PhotoPutBlock(interp, dm_img, &fb_data, 0, 0, idata->fb_width, 
idata->fb_height, TK_PHOTO_COMPOSITE_OVERLAY);
 
     // Render processed - reset the ready flag
     idata->dm_render_ready = 0;
@@ -218,7 +231,7 @@
 
     // Generate an event for the manager thread to let it know we need work
     Tcl_MutexLock(&threadMutex);
-    struct DmRenderEvent *threadEventPtr = (struct DmRenderEvent 
*)ckalloc(sizeof(DmRenderEvent));
+    struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
     threadEventPtr->idata = idata;
     threadEventPtr->event.proc = noop_proc;
     Tcl_ThreadQueueEvent(idata->dm_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
@@ -386,7 +399,7 @@
 
     // Generate an event for the manager thread to let it know we're done
     Tcl_MutexLock(&threadMutex);
-    struct DmRenderEvent *threadEventPtr = (struct DmRenderEvent 
*)ckalloc(sizeof(DmRenderEvent));
+    struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
     threadEventPtr->idata = idata;
     threadEventPtr->event.proc = noop_proc;
     Tcl_ThreadQueueEvent(idata->dm_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
@@ -409,6 +422,13 @@
     // information - we don't want this changing mid-render.
     Tcl_MutexLock(&fblock);
 
+    // We're now in process - don't start another frame until this one
+    // is complete.
+    idata->fb_render_running = 1;
+
+    // Until we're done, make sure nobody thinks we are ready
+    idata->fb_render_ready = 0;
+
     // Lock in this width and height - that's what we've got memory for,
     // so that's what the remainder of this rendering pass will use.
     idata->fb_width = idata->dm_width;
@@ -455,17 +475,20 @@
     
//////////////////////////////////////////////////////////////////////////////
     
//////////////////////////////////////////////////////////////////////////////
 
+    Tcl_MutexLock(&fblock);
+    idata->fb_render_running = 0;
+    idata->fb_render_ready = 1;
+    Tcl_MutexUnlock(&fblock);
+
     // Generate an event for the manager thread to let it know we're done, if 
the
     // display manager isn't already about to generate such an event
-    if (!idata->dm_render_running) {
-       Tcl_MutexLock(&threadMutex);
-       struct DmRenderEvent *threadEventPtr = (struct DmRenderEvent 
*)ckalloc(sizeof(DmRenderEvent));
-       threadEventPtr->idata = idata;
-       threadEventPtr->event.proc = noop_proc;
-       Tcl_ThreadQueueEvent(idata->dm_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
-       Tcl_ThreadAlert(idata->dm_id);
-       Tcl_MutexUnlock(&threadMutex);
-    }
+    Tcl_MutexLock(&threadMutex);
+    struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
+    threadEventPtr->idata = idata;
+    threadEventPtr->event.proc = noop_proc;
+    Tcl_ThreadQueueEvent(idata->fb_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
+    Tcl_ThreadAlert(idata->fb_id);
+    Tcl_MutexUnlock(&threadMutex);
 
     // Render complete, we're done with this thread
     Tcl_ExitThread(TCL_OK);
@@ -515,9 +538,9 @@
            // Generate an event for the parent thread - its time to update the
            // Tk_Photo in the GUI that's holding the image
            Tcl_MutexLock(&threadMutex);
-           struct DmRenderEvent *threadEventPtr = (struct DmRenderEvent 
*)ckalloc(sizeof(DmRenderEvent));
+           struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
            threadEventPtr->idata = idata;
-           threadEventPtr->event.proc = DmUpdateProc;
+           threadEventPtr->event.proc = UpdateProc;
            Tcl_ThreadQueueEvent(idata->parent_id, (Tcl_Event *) 
threadEventPtr, TCL_QUEUE_TAIL);
            Tcl_ThreadAlert(idata->parent_id);
            Tcl_MutexUnlock(&threadMutex);
@@ -545,8 +568,69 @@
        if (Tcl_CreateThread(&threadID, Dm_Render, (ClientData)idata, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {
            std::cerr << "can't create dm render thread\n";
        }
+    }
 
+    // We're well and truly done - the application is closing down - free the
+    // rendering buffer and quit the thread
+    if (idata->dmpixel) {
+       bu_free(idata->dmpixel, "free pixbuf");
+    }
+    Tcl_ExitThread(TCL_OK);
+    TCL_THREAD_CREATE_RETURN;
+}
+
+static Tcl_ThreadCreateType
+Fb_Update_Manager(ClientData clientData)
+{
+    // This thread needs to process events - give it its own interp so it can 
do so.
+    Tcl_Interp *interp = Tcl_CreateInterp();
+    Tcl_Init(interp);
+
+    // Unpack the shared data object
+    struct img_data *idata = (struct img_data *)clientData;
+
+    // Until we're shutting down, check for and process events - this thread 
will persist
+    // for the life of the application.
+    while (!idata->shutdown) {
+
+       // Events can come from either the parent (requesting a rendering, 
announcing a shutdown)
+       // or from the rendering thread (announcing completion of a rendering.)
+
+       // Eventually we'll want separate events to trigger this, but for now 
just update it at
+       // regular intervals
+       if (!idata->fb_render_ready) {
+           Tcl_Sleep(2000);
+       }
+       //Tcl_DoOneEvent(0);
+
+
+       // If anyone flipped the shutdown switch while we were waiting, don't
+       // do any more work - there's no point.
+       if (idata->shutdown) {
+           continue;
+       }
+
+       // If we have a render ready, let the parent know to update the GUI.
+       if (idata->fb_render_ready) {
+
+           // Generate an event for the parent thread - its time to update the
+           // Tk_Photo in the GUI that's holding the image
+           Tcl_MutexLock(&threadMutex);
+           struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
+           threadEventPtr->idata = idata;
+           threadEventPtr->event.proc = UpdateProc;
+           Tcl_ThreadQueueEvent(idata->parent_id, (Tcl_Event *) 
threadEventPtr, TCL_QUEUE_TAIL);
+           Tcl_ThreadAlert(idata->parent_id);
+           Tcl_MutexUnlock(&threadMutex);
+
+           // Go back to waiting.
+           idata->fb_render_ready = 0;
+           continue;
+       }
+
+       // If we need a render and aren't already running, it's time to go to 
work.
        // Start a framebuffer thread.
+       std::cout << "Framebuffer updating!\n";
        Tcl_ThreadId fbthreadID;
        if (Tcl_CreateThread(&fbthreadID, Fb_Render, (ClientData)idata, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {
            std::cerr << "can't create fb render thread\n";
@@ -556,8 +640,8 @@
 
     // We're well and truly done - the application is closing down - free the
     // rendering buffer and quit the thread
-    if (idata->dmpixel) {
-       bu_free(idata->dmpixel, "free pixbuf");
+    if (idata->fbpixel) {
+       bu_free(idata->fbpixel, "free pixbuf");
     }
     Tcl_ExitThread(TCL_OK);
     TCL_THREAD_CREATE_RETURN;
@@ -581,7 +665,9 @@
     idata->dm_render_running = 0;
     idata->dm_render_ready = 0;
     idata->shutdown = 0;
+    idata->dm_buff_size = 0;
     idata->dmpixel = NULL;
+    idata->fb_buff_size = 0;
     idata->fbpixel = NULL;
     idata->parent_id = Tcl_GetCurrentThread();
 
@@ -687,19 +773,46 @@
     }
     idata->dm_id = threadID;
 
+    Tcl_ThreadId fbthreadID;
+    if (Tcl_CreateThread(&fbthreadID, Fb_Update_Manager, (ClientData)idata, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
+       std::cerr << "can't create thread\n";
+    }
+    idata->fb_id = fbthreadID;
+
+
     // Enter the main applicatio loop - the initial image will appear, and 
Button-1 mouse
     // clicks on the window should generate and display new images
     while (1) {
        Tcl_DoOneEvent(0);
        if (!Tk_GetNumMainWindows()) {
+           int tret;
 
            // If we've closed the window, we're done - start spreading the word
-           Tcl_MutexLock(&dilock);
            idata->shutdown = 1;
 
+
+           // After setting the shutdown flag, send an event to wake up the FB 
update manager thread.
+           // It will see the change in status and proceed to shut itself down.
+           Tcl_MutexLock(&fblock);
+           struct RenderEvent *threadEventPtr = (struct RenderEvent 
*)ckalloc(sizeof(RenderEvent));
+           threadEventPtr->idata = idata;
+           threadEventPtr->event.proc = noop_proc;
+           Tcl_ThreadQueueEvent(idata->fb_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
+           Tcl_ThreadAlert(idata->fb_id);
+           Tcl_MutexUnlock(&fblock);
+
+           // Wait for the thread cleanup to complete
+           Tcl_JoinThread(idata->fb_id, &tret);
+           if (tret != TCL_OK) {
+               std::cerr << "Failed to shut down framebuffer management 
thread\n";
+           } else {
+               std::cout << "Successful framebuffer management thread 
shutdown\n";
+           }
+
            // After setting the shutdown flag, send an event to wake up the 
update manager thread.
            // It will see the change in status and proceed to shut itself down.
-           struct DmRenderEvent *threadEventPtr = (struct DmRenderEvent 
*)ckalloc(sizeof(DmRenderEvent));
+           Tcl_MutexLock(&dilock);
+           threadEventPtr = (struct RenderEvent *)ckalloc(sizeof(RenderEvent));
            threadEventPtr->idata = idata;
            threadEventPtr->event.proc = noop_proc;
            Tcl_ThreadQueueEvent(idata->dm_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
@@ -707,8 +820,7 @@
            Tcl_MutexUnlock(&dilock);
 
            // Wait for the thread cleanup to complete
-           int tret;
-           Tcl_JoinThread(threadID, &tret);
+           Tcl_JoinThread(idata->dm_id, &tret);
            if (tret != TCL_OK) {
                std::cerr << "Failed to shut down display management thread\n";
            } else {
@@ -715,6 +827,7 @@
                std::cout << "Successful display management thread shutdown\n";
            }
 
+
            // Clean up memory and exit
            BU_PUT(idata, struct img_data);
            exit(0);

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to