1

ゲーム開発にlwjglをclojureで使用しようとしています。

私の最初のステップは、REPL から OpenGL 画面に何かを表示しようとすることです。lein repl で repl を起動した後、これまでに行ったことは次のとおりです。

(import org.lwjgl.opengl GL11 Display DisplayMode
(Display/setDisplayMode (DisplayMode. 800 600))
(Display/create) ; This shows a black 800x600 window as expected
(GL11/glClearColor 1.0 0.0 0.0 1.0) 
(GL11/glClear (bit-or GL11/GL_COLOR_BUFFER_BIT GL11/GL_DEPTH_BUFFER_BIT))
(Display/update)

十分に迅速に実行すれば、これは機能することに注意してください。しかし、しばらくすると (ただ待っていても)、現在の OpenGL コンテキストが現在のスレッドにバインドされていないというエラーが発生し始めます。

(Display/update)
IllegalStateException No context is current  org.lwjgl.opengl.LinuxContextImplementation.swapBuffers (LinuxContextImplementation.java:72)

(GL11/glClear ...) 
RuntimeException No OpenGL context found in the current thread.  org.lwjgl.opengl.GLContext.getCapabilities (GLContext.java:124)

しかし、おそらく最も興味深いエラーは、Display/destroy を呼び出そうとしたときに発生します。

(Display/destroy)
IllegalStateException From thread Thread[nREPL-worker-4,5,main]: Thread[nREPL-worker-0,5,] already has the context current  org.lwjgl.opengl.ContextGL.checkAccess (ContextGL.java:184)

しばらく非アクティブ状態が続いた後、repl がランダムに別のスレッドを生成したように見えます。私が読むことができたように、LWJGL では、最初に作成されたスレッドからのみ OpenGL 呼び出しを行うことができるため、これがこれらのエラーを引き起こしているに違いありません。

しかし、REPL がランダムにスレッドを切り替えるにはどうすればよいでしょうか? 特に私が何もしていない場合は、ただ待っているだけです。

4

1 に答える 1

3

これは既知の問題であり、nREPL プロジェクトに対して既に報告されています( Clojure Google Group で議論されています)。nREPL は、アイドル状態のスレッドを終了するスレッド プールを使用しているようです (おそらくkeepalive設定による)。

修正されるまで、これに対する回避策を使用できます (少しぎこちなく、私は認めます):

(import '(java.util.concurrent Executors))

(def opengl-executor (Executors/newSingleThreadExecutor))

(defmacro with-executor [executor & body]
  `(.submit ~executor (fn [] ~@body)))

(on-executor opengl-executor
  (println (.getId (Thread/currentThread))))

独自のエグゼキュータを使用すると、ラップされたすべてのコードon-executorがそのスレッドで実行されます。ドキュメントによると、現在のスレッドが例外のために失敗した場合にのみそれを置き換えるnewSingleThreadExecutor単一のスレッドを作成します。長い遅延で最後の式を実行しようとすると、出力されるスレッド ID は同じままになるはずです。

shutdownアプリケーションを停止するときは、executorを使用する必要があることに注意してください。

于 2016-03-23T19:55:43.297 に答える