Skip to content

Commit

Permalink
Lower the minimum required OpenGL version to 4.1.
Browse files Browse the repository at this point in the history
Make offscreen examples compatible with WSL by removing ImageView with GTK and using gifs instead.
  • Loading branch information
Tuebel committed Feb 13, 2025
1 parent a858c32 commit b5ef92a
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SciGL"
uuid = "e33cfb9f-2574-42f7-bc46-3c25fa028886"
authors = ["Tim Redick <t.redick@irt.rwth-aachen.de>"]
version = "0.3.15"
version = "0.3.16"

[deps]
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
Expand Down
46 changes: 12 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ The primary goal is to enable efficient rendering of multiple scenes and transfe
I try to incorporate existing Julia packages wherever possible.
The next section contains a list and use cases of the packages.

For performance, I use *Persistent mapping* and `glGetTextureSubImage` to transfer data between the GPU and CPU.
These functions require **OpenGL 4.5**, but I set the minimum version to **4.1** to support WSL2.
It seems like the drivers support the functions nevertheless.

## Package Dependencies
- [CoordinateTransformations](https://github.com/JuliaGeometry/CoordinateTransformations.jl): Representing and chaining transformations like rotations, translations, and perspective transformations.
[Rotations](https://github.com/JuliaGeometry/Rotations.jl) are handled by the equally named package.
Expand All @@ -34,7 +38,6 @@ For convenience commonly used symbols are reexported:
- GLFW
- Rotations: all symbols


# HPC on Headless Server with VirtualGL
Install [TurboVNC](https://turbovnc.org/Documentation/Documentation) on the server which will be used to instantiate a render context without an attached display.
There are also good [instructions](https://github.com/JuliaGL/GLVisualize.jl/issues/146#issuecomment-289242168) on the GLVisualize github.
Expand Down Expand Up @@ -75,41 +78,16 @@ You can verify whether the NVIDIA GPU is used in a Julia program by the followin
nvidia-smi | grep julia
```

## Docker + GUI in Windows
[Install](https://docs.docker.com/docker-for-windows/wsl/) Docker with the Windows Subsystem for Linux (WSL2) backend.
Unfortunately [GPU support for WSL2](https://www.docker.com/blog/wsl-2-gpu-support-is-here/) is only available for Windows Insiders.
Thus, you will need to install an x-server, for example [VcXsrv](https://sourceforge.net/projects/vcxsrv/).

- Make sure that VcXsrv can communicate through the firewall.
- Uncheck "native opengl"
- Check "Disable Access Control"

Moreover, you will have to modify [.devcontainer/devcontainer.json] since GPU passthrough is not possible:
```json
"runArgs": [
// Graphics devices only work on native Linux host, comment on Windows
// Intel
// "--device=/dev/dri:/dev/dri",
// Comment if nvidia-docker is unavailable
// "--gpus=all",
// Write to X11 server of host
// "--volume=/tmp/.X11-unix:/tmp/.X11-unix:rw",
],
"containerEnv": {
// Native Linux host
// "DISPLAY": "${localEnv:DISPLAY}",
// Windows host
"DISPLAY": "host.docker.internal:0.0",
"LIBGL_ALWAYS_INDIRECT": "0",

"QT_X11_NO_MITSHM": "1",
// If NVIDIA Prime Profile On-Demand is active, uncomment both to use NVIDIA GPU
// Integrated graphics are used otherwise
"__NV_PRIME_RENDER_OFFLOAD": "1",
"__GLX_VENDOR_LIBRARY_NAME": "nvidia",
},
## Windows Subsystem for Linux (WSL2)
Microsoft [added](https://devblogs.microsoft.com/commandline/d3d12-gpu-video-acceleration-in-the-windows-subsystem-for-linux-now-available/) the Direct3D backend to the mesa driver in WSL2.
One drawback is that the driver version is not the latest, e.g., 4.2 for NVIDIA and 4.1 for Intel at the time of writing.
You can switch between the GPUs by setting the following environment variable:
```shell
MESA_D3D12_DEFAULT_ADAPTER_NAME=NVIDIA julia
MESA_D3D12_DEFAULT_ADAPTER_NAME=Intel julia
```


## Debug in vscode
Later versions of the Julia extension seem to have fixed the issue.

Expand Down
2 changes: 1 addition & 1 deletion examples/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
GLAbstraction = "ca6e7d0a-b0c9-59ca-8aba-aebf11497e1c"
GLFW = "f7f18e0c-5ee9-5ccd-a5bf-e8befd85ed98"
ImageView = "86fae568-95e7-573e-a6b2-d8a6b900c9ef"
MeshIO = "7269a6da-0436-5bbc-96c2-40638cbb6118"
ModernGL = "66fc600b-dfda-50eb-8b99-91cfa97b1301"
SciGL = "e33cfb9f-2574-42f7-bc46-3c25fa028886"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[sources]
GLAbstraction = {url="https://github.com/Tuebel/GLAbstraction.jl"}
# ] develop . (for SciGL)
# SciGL = {url="https://github.com/rwth-irt/SciGL.jl"}
45 changes: 18 additions & 27 deletions examples/offscreen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,47 @@
using Accessors
using CUDA
using SciGL
using ImageView
using Images

WIDTH = 801
HEIGHT = 600
DEPTH = 300

# TODO
# Compile shader program
# normal_prog = GLAbstraction.Program(SimpleVert, NormalFrag)
# silhouette_prog = GLAbstraction.Program(SimpleVert, SilhouetteFrag)
# depth_prog = GLAbstraction.Program(SimpleVert, DepthFrag)

# Create the GLFW window. This sets all the hints and makes the context current.
if cuda_interop_available()
gl_context = color_offscreen_context(WIDTH, HEIGHT, DEPTH, CuArray)
else
gl_context = color_offscreen_context(WIDTH, HEIGHT, DEPTH, Array)
end
# create ImageView
guidict = imshow(rand(HEIGHT, WIDTH))
canvas = guidict["gui"]["canvas"]

# Compile shader program
normal_prog = GLAbstraction.Program(SimpleVert, NormalFrag)
silhouette_prog = GLAbstraction.Program(SimpleVert, SilhouetteFrag)
depth_prog = GLAbstraction.Program(SimpleVert, DepthFrag)

# Init scene with normal_prog as it uses most attributes
camera = CvCamera(WIDTH, HEIGHT, 1.2 * WIDTH, 1.2 * WIDTH, WIDTH / 2, HEIGHT / 2) |> Camera
cube = upload_mesh(gl_context, "examples/meshes/cube.obj")
cube = upload_mesh(normal_prog, "examples/meshes/cube.obj")
@reset cube.pose.translation = Translation(1, 0, 0)
monkey = upload_mesh(gl_context, "examples/meshes/monkey.obj")
monkey = upload_mesh(normal_prog, "examples/meshes/monkey.obj")
@reset monkey.pose.translation = Translation(0, 0, 0)
scene = Scene(camera, [cube, monkey])

# Key callbacks GLFW.GetKey does not seem to work
GLFW.SetKeyCallback(gl_context.window, (win, key, scancode, action, mods) -> begin
key == GLFW.KEY_ESCAPE && GLFW.SetWindowShouldClose(window, true)
println("Registered $key")
end)

loops = UInt128(0)
seconds = @elapsed for _ in 1:200
# for gif
fps = 60
# for fps benchmark
n_frames = 500
images = Array{Array{RGB{N0f8},2}}(undef, n_frames)
seconds = @elapsed for frame_number in 1:n_frames
# events
GLFW.PollEvents()
# Camera rotates around mathematically positive Z
@reset scene.camera.pose.translation = Translation(1.3 * cos(2 * π * time() / 5), 1.3 * sin(2 * π * time() / 5), 0)
@reset scene.camera.pose.translation = Translation(1.3 * cos* frame_number / fps), 1.3 * sin* frame_number / fps), 0)
@reset scene.camera.pose.rotation = lookat(scene.camera, monkey, [0, 0, 1])
img = draw(gl_context, scene)
imshow(canvas, img |> Array |> transpose)
sleep(1e-6)
loops += 1
images[frame_number] = transpose(draw(gl_context, scene))
end
println("Average fps: $(loops / seconds)")
println("Average fps: $(n_frames / seconds)")
ImageShow.gif(images; fps=fps)

# needed if you're running this from the REPL
destroy_context(gl_context)
ImageView.closeall()
38 changes: 6 additions & 32 deletions examples/offscreen_depth.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

using Accessors
using SciGL
using ImageView
using Images

WIDTH = 801
HEIGHT = 600

# Create the GLFW window. This sets all the hints and makes the context current.
gl_context = depth_offscreen_context(WIDTH, HEIGHT, 3)
# create ImageView
guidict = imshow(rand(HEIGHT, WIDTH))
canvas = guidict["gui"]["canvas"]

# Init scene with normal_prog as it uses most attributes
cube = upload_mesh(gl_context, "examples/meshes/cube.obj")
Expand All @@ -31,33 +28,10 @@ scene3 = @set scene1.camera.pose.translation = Translation(1.3 * sin(3 * π / 4)
scene3 = @set scene3.camera.pose.rotation = lookat(scene3.camera, monkey, [0, 0, 1])
scenes = [scene1, scene2, scene3]

# Key callbacks GLFW.GetKey does not seem to work
GLFW.SetKeyCallback(gl_context.window, (win, key, scancode, action, mods) -> begin
key == GLFW.KEY_ESCAPE && GLFW.SetWindowShouldClose(window, true)
println("Registered $key")
end)

loops = UInt128(0)
seconds = @elapsed for _ in 1:200
# events
GLFW.PollEvents()
# draw
imgs = draw(gl_context, scenes)
if floor(Int, time() / 2) % 3 == 0
img = @view imgs[:, :, 1]
elseif floor(Int, time() / 5) % 3 == 1
img = @view imgs[:, :, 2]
else
img = @view imgs[:, :, 3]
end
# Simplified interface, performance only slightly worse
# NOTE monkey upside down is correct since OpenCV uses X=right, Y=down, Z=forward convention
imshow(canvas, img |> transpose)
sleep(1e-6)
loops += 1
end
println("Average fps: $(loops / seconds)")

imgs = draw(gl_context, scenes) .|> Gray
view(imgs, :, :, 1) |> transpose |> simshow
view(imgs, :, :, 2) |> transpose |> simshow
view(imgs, :, :, 3) |> transpose |> simshow
# Simplified interface, performance only slightly worse
# needed if you're running this from the REPL
destroy_context(gl_context)
ImageView.closeall()
5 changes: 3 additions & 2 deletions src/RenderContexts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ const default_window_hints = [
(GLFW.RESIZABLE, false),
(GLFW.FOCUSED, false),
(GLFW.CONTEXT_VERSION_MAJOR, 4),
# Persistent mapping & glGetTextureSubImage
(GLFW.CONTEXT_VERSION_MINOR, 5),
# Persistent mapping & glGetTextureSubImage requires 4.5 but some drivers will accept it with lower versions
# Using 4.1 for WSL support
(GLFW.CONTEXT_VERSION_MINOR, 1),
(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE)]

# Pipeable, set some sane defaults to avoid black screens by default
Expand Down

0 comments on commit b5ef92a

Please sign in to comment.