Lisp HUG Maillist Archive

Using opengl in a thread?

Hi I've got a lisp project which uses Lispworks Opengl and capi to display some data. The display takes a super long time to render and then the rendering to disk, so I want to be able to continue while its processing. But when its rendering, it freezes the lispworks process until its finished. Is there any way to make it nonblocking so I can run my graphing function without it freezing lispworks?

Re: Using opengl in a thread?

Use multi-processing (see the MP package, LW user guide chapters 16 and 
35).

LW's mailboxes make this quite easy.

Look at mp:process-run-function and mp:mailbox-send (and all of its 
friends, mp:mailbox-...).

In linux (LWL) and windows (LWW), each top-level gui is a separate 
process already.  In mac (LWM), apparently, all GUI's run in the same 
process.  I have a "template" for handling these cases uniformly - ping 
me tomorrow (July 2) and I can dig it up and explain.

There are, probably, other tricks, like rendering to an off-screen 
pixmap in a process.  You would have to provide more info for us to help 
you with these options...

pt

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Using opengl in a thread?

Hi,

1. which platform do you use (OS X, Linux, Windows, all of them) ?

2. does your rendering contain/only/  OpenGL calls (glDrawElements, glBegin/glEnd, etc.) and
no other graphics related calls like CAPI (and/or Cocoa in case of OS X) ?

2.1. If yes, then it should be fairly easy: you have to create the OpenGL context in the thread which
is supposed to render.

As long as all OpenGL calls are issued in the thread where the OpenGL context is created,
you should be safe.

But if I understood the problem correctly: you are rendering (with GL), then grab the frame buffer
and write it to disk ? In that case, you can still decouple OpenGL rendering from all the rest,
but somewhere you have to queue the captured frames, since the write-to-disk will be the
slowest of all parts (esp. when compression comes into play).

HTH,
/wg


On 07/01/2013 07:25 PM, quinn jarrell wrote:
> Hi I've got a lisp project which uses Lispworks Opengl and capi to 
> display some data. The display takes a super long time to render and 
> then the rendering to disk, so I want to be able to continue while its 
> processing. But when its rendering, it freezes the lispworks process 
> until its finished. Is there any way to make it nonblocking so I can 
> run my graphing function without it freezing lispworks?

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Using opengl in a thread?


* Paul Tarvydas <51D20486.5070405@gmail.com> :
Wrote on Mon, 01 Jul 2013 18:36:54 -0400:

| In linux (LWL) and windows (LWW), each top-level gui is a separate
| process already.  In mac (LWM), apparently, all GUI's run in the same
| process.  I have a "template" for handling these cases uniformly -
| ping me tomorrow (July 2) and I can dig it up and explain.

LWL (Linux) also has a main thread "GTK Event Loop", which also appears
to have some central "serializaing" role for GUI operations. I wonder if
you special cased that; in any case I believe I'd benefit and learn from
looking your template.

I'd like to note that most of the irrecoverable freezeups I see on LWL
happen around this thread, typically with other threads waiting for
locks held by this thread, probably from some problem in the underlying
GTK C library---invariably requiring a kill -9 on the lisp process and
to restart it.  So far I haven't filed MP bug reports around GTK, on the
assumption that the fault is in the GTK layers. ---Madhu

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Using opengl in a thread?

Hi, thanks for all your replies. 

So heres some more info on what I'm trying to do.
1. I'm running on Mac and Linux.

2. I'm using only opengl calls and normal lisp calls (no capi other than define interface)

2.1 I thought I had put everything in a separate thread but i'll try again later tonight

And yeah, you've got the gist of it. I've got a graph which I just move across and after every move, I use readpixels and then put them into an image on disk using opticl. Is there a faster way of saving to disk? I'm writing to different images every move, so the best ive got right now is that once the pixels are read, it throws them off to a separate thread so I can save without blocking. 


On Wed, Jul 10, 2013 at 6:25 PM, quinn jarrell <quinnjarr@gmail.com> wrote:
Hi, thanks for all your replies. 

So heres some more info on what I'm trying to do.
1. I'm running on Mac and Linux.

2. I'm using only opengl calls and normal lisp calls (no capi other than define interface)

2.1 I thought I had put everything in a separate thread but i'll try again later tonight

And yeah, you've got the gist of it. I've got a graph which I just move across and after every move, I use readpixels and then put them into an image on disk using opticl. Is there a faster way of saving to disk? I'm writing to different images every move, so the best ive got right now is that once the pixels are read, it throws them off to a separate thread so I can save without blocking. 


On Fri, Jul 5, 2013 at 6:59 PM, Paul Tarvydas <paultarvydas@gmail.com> wrote:

On 13-07-02 10:16 AM, Madhu wrote:
you special cased that; in any case I believe I'd benefit and learn from
looking your template.

FWIW, here is a brute force, simplified example of how I run gui's in separate process, like actors / FBP, using mailboxes (in one direction only - input or output) to wire things together.  Each separate gui gets a "controller" process (that I caled "reactor"). When a button is clicked, it just fires a message to the mailbox of that gui's controller.  The reactor for "demo1" is a simple state machine, whereas the reactor for "demo2" is just an echo.  The plumbing and state are carried around as instance variables of the interfaces.  Run "main" to spin it up.  [I did succeed in folding the reactor process into the gui's process on LWW, but after Martin's suggestion (re. LWM not having separate process for each top-level gui) I re-separated them :-].  (Obviously, macro-logy, Hoyte-esque state machines, cl-actor, etc. could be employed).

pt



;; two GUI's talking to each other

(in-package "COMMON-LISP-USER")

(capi:define-interface demo1 ()
  ((my-input :accessor my-input :initarg :my-input)           ;; my input pin (mailbox)
   (other :accessor other :initarg :other)                    ;; output pin (mailbox)
   (reactor :accessor reactor :initarg :reactor)              ;; process for processing inputs
   (state :accessor state :initarg :state))
  (:panes
   (title-pane-1
    capi:title-pane
    :text ""
    :accessor title)
   (push-button-1
    capi:push-button
    :text "one"
    :callback-type :interface
    :callback #'(lambda (intf) (mp:mailbox-send (other intf) 'one)))
   (push-button-2
    capi:push-button
    :text "two"
    :callback-type :interface
    :callback #'(lambda (intf) (mp:mailbox-send (other intf) 'two)))
   (stop-button
    capi:push-button
    :text "stop"
    :callback-type :interface
    :callback #'(lambda (intf)
                  (mp:mailbox-send (other intf) 'quit)
                  (mp:mailbox-send (my-input intf) 'quit))))
  (:layouts
   (column-layout-1
    capi:column-layout
    '(title-pane-1 push-button-1 push-button-2 stop-button)))
  (:default-initargs
   :best-height 66
   :best-width 126
   :layout 'column-layout-1
   :title "demo1"))

(defun run1 (my other)
  (let ((intf (make-instance 'demo1 :my-input my :other other :reactor 'react1 :state 'idle)))
    (capi:display intf)
    (mp:process-run-function
     "demo1" ()
     #'(lambda ()
         (loop
          (let ((msg (mp:mailbox-wait-for-event my :process-other-messages-p t)))
            (when (eq msg 'quit)
              (capi:apply-in-pane-process intf 'capi:destroy intf)
              (return))
            (funcall (reactor intf) intf msg)))))))

(defun react1 (intf input-msg)
  (let (text)
    (case (state intf)
      (idle
       (case input-msg
         (eh
          (setf text "got eh, want bee")
          (setf (state intf) 'waiting-for-bee))
         (bee
          (setf text "got bee, want eh")
          (setf (state intf) 'waiting-for-eh))))
      (waiting-for-bee
       (case input-msg
         (bee
          (setf text "I'm happy")
          (setf (state intf) 'idle))
         (eh
          (setf text "send a bee!"))))
      (waiting-for-eh
       (case input-msg
         (bee
          (setf text "send me a eh!"))
         (eh
          (setf text "mmm")
          (setf (state intf) 'idle)))))
    (capi:apply-in-pane-process
     intf
     #'(setf capi:title-pane-text) text (title intf))))

(capi:define-interface demo2 ()
  ((my-input :accessor my-input :initarg :my-input)           ;; my input pin (mailbox)
   (other :accessor other :initarg :other)                    ;; output pin (mailbox)
   (reactor :accessor reactor :initarg :reactor))             ;; process for processing inputs
  (:panes
   (title-pane-1
    capi:title-pane
    :text ""
    :accessor title)
   (push-button-1
    capi:push-button
    :text "Eh"
    :callback-type :interface
    :callback #'(lambda (intf) (mp:mailbox-send (other intf) 'eh)))
   (push-button-2
    capi:push-button
    :text "Bee"
    :callback-type :interface
    :callback #'(lambda (intf) (mp:mailbox-send (other intf) 'bee))))
  (:layouts
   (column-layout-1
    capi:column-layout
    '(title-pane-1 push-button-1 push-button-2)))
  (:default-initargs
   :best-height 66
   :best-width 126
   :layout 'column-layout-1
   :title "demo2"))

(defun run2 (my other)
  (let ((intf (make-instance 'demo2 :my-input my :other other
                             :reactor #'(lambda (intf input-msg)
(capi:apply-in-pane-process
                                           intf
                                           #'(setf capi:title-pane-text)
                                           (format nil "rcvd: ~A" input-msg)
                                           (title intf))))))
    (capi:display intf)
    (mp:process-run-function "demo2" ()
                             #'(lambda ()
                                 (loop
                                  (let ((msg (mp:mailbox-wait-for-event my :process-other-messages-p t)))
                                    (when (eq msg 'quit)
                                      (capi:apply-in-pane-process intf 'capi:destroy intf)
                                      (return))
                                    (funcall (reactor intf) intf msg)))))))


(defun main ()
  (let ((mb1 (mp:make-mailbox))
        (mb2 (mp:make-mailbox)))
    (run1 mb1 mb2)
    (run2 mb2 mb1)
    #'(lambda ()  ;; (funcall *) or hit the stop button to end
        (mp:mailbox-send mb1 'quit)
        (mp:mailbox-send mb2 'quit))))


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html



Updated at: 2020-12-10 08:35 UTC