diff --git a/lib/exray/line_renderer.ex b/lib/exray/line_renderer.ex new file mode 100644 index 0000000..e3ba3b6 --- /dev/null +++ b/lib/exray/line_renderer.ex @@ -0,0 +1,18 @@ +defmodule Exray.LineRenderer do + + use GenServer + + def start_link(_), do: GenServer.start_link(__MODULE__, []) + + def render_line(worker_pid, {scene_renderer, y, scene, mx, transpose_y, viewport_width, ray, vm_u}) do + GenServer.call(worker_pid, {:render_line, scene_renderer, y, scene, mx, transpose_y, viewport_width, ray, vm_u}) + end + + def handle_call({:render_line, scene_renderer, y, scene, mx, transpose_y, viewport_width, ray, vm_u}, _from, state) do + rendered_line = Exray.Renderer.timed_render_line(scene, mx, transpose_y, viewport_width, ray, vm_u) + + send(scene_renderer, {y, rendered_line}) + + {:reply, :ok, state} + end +end diff --git a/lib/exray/renderer.ex b/lib/exray/renderer.ex index 97f6ae9..b6733e8 100644 --- a/lib/exray/renderer.ex +++ b/lib/exray/renderer.ex @@ -49,33 +49,35 @@ defmodule Exray.Renderer do num_workers = :erlang.system_info(:logical_processors) - 1 - workers = 0..num_workers |> Enum.into(%{}, fn (n) -> {n, spawn(fn -> render_lines(scene_renderer) end)} end) - # workers = %{ - # 0 => , - # 1 => spawn(fn -> render_lines(scene_renderer) end), - # 2 => spawn(fn -> render_lines(scene_renderer) end), - # #3 => spawn(fn -> render_lines(scene_renderer) end), - # } + IO.inspect "concurrent workers: #{num_workers}" - num_workers = Enum.count(workers) + {:ok, pool} = :poolboy.start( + worker_module: Exray.LineRenderer, + size: num_workers, + max_overflow: 0 + ) for y <- 0..(viewport.height-1) do - # Precalculate line-specific invariants yt = y - my transpose_y = Vec3.scale(vm_v, yt) |> Vec3.add(scene.camera.position) - # Spawn a process to render this line - # spawn fn -> - # rendered_line = timed_render_line(scene, mx, transpose_y, viewport.width, ray, vm_u) - # send scene_renderer, {y, rendered_line} - # end - worker = Dict.get(workers, rem(y, num_workers)) - send worker, {y, scene, mx, transpose_y, viewport.width, ray, vm_u} - end - - for {_, worker_pid} <- workers do - send worker_pid, :stop + spawn(fn -> + worker_pid = :poolboy.checkout( + pool, + true, # blocking + :infinity # timeout. :infinity is the standard timeout value for OTP. + # The default timeout in poolboy is 5 seconds, so we don't want + # :poolboy to kill our long and beautiful queue of tasks + ) + + :ok = Exray.LineRenderer.render_line( + worker_pid, + {scene_renderer, y, scene, mx, transpose_y, viewport.width, ray, vm_u} + ) + :poolboy.checkin(pool, worker_pid) + + end) end # Collect all rendered lines in order @@ -87,19 +89,8 @@ defmodule Exray.Renderer do end - def render_lines(scene_renderer) do - receive do - {y, scene, mx, transpose_y, width, ray, vm_u} -> - rendered_line = timed_render_line(scene, mx, transpose_y, width, ray, vm_u) - send scene_renderer, {y, rendered_line} - render_lines(scene_renderer) - :stop -> - end - end - - - defp timed_render_line(scene, mx, transpose_y, width, ray, vm_u) do + def timed_render_line(scene, mx, transpose_y, width, ray, vm_u) do {time_ns, output} = :timer.tc(fn -> render_line(scene, mx, transpose_y, width, ray, vm_u) end) diff --git a/mix.exs b/mix.exs index bbad955..5dcc735 100644 --- a/mix.exs +++ b/mix.exs @@ -25,6 +25,9 @@ defmodule Exray.Mixfile do # # Type `mix help deps` for more examples and options defp deps do - [{:ex_png, git: "https://github.com/xavier/ex_png"}] + [ + {:ex_png, github: "xavier/ex_png"}, + {:poolboy, github: "devinus/poolboy"} + ] end end diff --git a/mix.lock b/mix.lock index 5710497..0d4c63c 100644 --- a/mix.lock +++ b/mix.lock @@ -1 +1,2 @@ -%{"ex_png": {:git, "https://github.com/xavier/ex_png", "09ad85fa3ab30e2353e85fac549ed75233a00ae8", []}} +%{"ex_png": {:git, "git://github.com/xavier/ex_png.git", "09ad85fa3ab30e2353e85fac549ed75233a00ae8", []}, + "poolboy": {:git, "git://github.com/devinus/poolboy.git", "42c631720e16cd9657585c125d1e1cf3acc82c59", []}}