Skip to content

Commit

Permalink
Linux support
Browse files Browse the repository at this point in the history
- Loading `so` dynamic library and surface creation.
- Updated triangle example to resize swapchain on window resize.
- Added Getting Started instructions for Linux.
- Added `ubuntu-latest` to CI workflow.
  • Loading branch information
lancelet committed Aug 24, 2021
1 parent ced259a commit 9edd272
Show file tree
Hide file tree
Showing 13 changed files with 184 additions and 20 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macOS-latest, windows-latest] # ubuntu-latest
os: [macOS-latest, ubuntu-latest, windows-latest]
cabal: ["3.2"]
ghc:
- "8.10.5"

steps:
- uses: actions/checkout@v2

- name: Install Ubuntu Dependencies
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt-get update
sudo apt-get install libglfw3-dev libxi-dev libxrandr-dev libxxf86vm-dev libxcursor-dev libxinerama-dev -y
- uses: haskell/actions/setup@v1
id: setup-haskell-cabal
name: Setup Haskell
Expand Down
80 changes: 78 additions & 2 deletions GettingStarted.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Getting Started

Please see the platform-specific guides below:
- [Apple macOS](#macOS)
- [Microsoft Windows](#windows)
- [Apple macOS](#apple-macos)
- [Microsoft Windows](#microsoft-windows)
- [Ubuntu Linux](#ubuntu-linux)

## Apple macOS

Expand Down Expand Up @@ -112,3 +113,78 @@ of Windows 10 on 2021-08-21.
```powershell
cabal run triangle
```

## Ubuntu Linux

These instructions are only a suggestion. Other setup options are possible.
These instructions were tested manually in a fresh installation of Ubuntu Linux
20.04.3 LTS on 2021-08-24.

### Toolchain Installation

1. Make sure your Linux graphics drivers are up-to-date, and that they
support Vulkan.

1. Install the required development tools supplied in the Ubuntu
repositories:

```sh
sudo apt-get update
sudo apt-get install \
build-essential \
clang \
curl \
git \
libffi-dev \
libffi7 \
libgmp-dev \
libncurses-dev \
libncurses5 \
libtinfo5 \
libglfw3-dev \
libxi-dev \
libxxf86vm-dev \
libxcursor-dev \
libxinerama-dev \
-y
```

(NB: `libglfw3-dev` will als bring in `libvulkan-dev`.)

1. Install the
[Rust toolchain](https://www.rust-lang.org/tools/install) using `rustup`.

1. Install the [Haskell toolchain](https://www.haskell.org/ghcup/) using
`ghcup`. You may need to use `ghcup tui` to select an appropriate GHC
version (GHC 8.10.5).

### Build and Run an Example

1. Clone the repository. In a terminal:

```sh
git clone https://github.com/lancelet/wgpu-hs.git
cd wgpu-hs
git submodule update --init --recursive
```

1. Build the Rust library `libwgpu_native.so`:

```sh
pushd wgpu-raw-hs-codegen/wgpu-native
WGPU_NATIVE_VERSION='v0.9.2.2' make lib-native
popd
```

1. Set `LD_LIBRARY_PATH` to include the Rust dynamic library that was just
built:

```sh
export LD_LIBRARY_PATH=$(pwd)/wgpu-raw-hs-codegen/wgpu-native/target/debug/:$LD_LIBRARY_PATH
```

1. Build and run the `triangle` example:

```sh
cabal run triangle
```
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
[![Hackage][hackage-shield]][hackage]
[![CI Build][github-ci-shield]][github-ci]
[![License BSD-3-Clause][license-shield]][license]
![Platforms][platform-shield]

[hackage]: http://hackage.haskell.org/package/wgpu-hs
[hackage-shield]: https://img.shields.io/hackage/v/wgpu-hs.svg?logo=haskell
[github-ci]: https://github.com/lancelet/wgpu-hs/actions
[github-ci-shield]: https://github.com/lancelet/wgpu-hs/actions/workflows/ci.yml/badge.svg
[license]: https://github.com/lancelet/wgpu-hs/blob/master/LICENSE
[license-shield]: https://img.shields.io/badge/license-BSD--3--Clause-green.svg
[platform-shield]: https://img.shields.io/badge/platform-macos%20%7C%20linux%20%7C%20windows-blue

This repository contains Haskell bindings for
[wgpu-native](https://github.com/gfx-rs/wgpu-native).

Currently, only macOS and Windows are supported by these Haskell bindings.
Adding Linux is on the roadmap.
macOS, Windows and Linux are supported.

To get started, please read the [Getting Started](GettingStarted.md)
instructions.
5 changes: 5 additions & 0 deletions wgpu-hs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Revision history for wgpu-hs

## 0.2.0.1 -- 2021-08-24

- Added Linux support for surfaces and DLL loading.
- Updated `triangle` example to reallocate SwapChain correctly on resize.

## 0.2.0.0 -- 2021-08-22

- Added MS Windows support for surfaces and DLL loading.
Expand Down
43 changes: 36 additions & 7 deletions wgpu-hs/examples/triangle/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
-- | Let's draw a triangle!
module Main (main) where

import Control.Monad (unless)
import Control.Monad (unless, when)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (runExceptT)
import Control.Monad.Trans.Maybe (MaybeT (MaybeT), maybeToExceptT)
import Data.Default (def)
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as TextIO
Expand All @@ -28,12 +29,10 @@ main = do
exitFailure

-- create the GLFW window without a "client API"
let initWidth, initHeight :: Int
initWidth = 640
initHeight = 480
windowSzRef <- newIORef (640, 480)
GLFW.windowHint (GLFW.WindowHint'ClientAPI GLFW.ClientAPI'NoAPI)
window <- do
mWin <- GLFW.createWindow initWidth initHeight "Triangle" Nothing Nothing
mWin <- GLFW.createWindow 640 480 "Triangle" Nothing Nothing
case mWin of
Just w -> pure w
Nothing -> do
Expand Down Expand Up @@ -61,10 +60,11 @@ main = do
{ swapChainLabel = "SwapChain",
usage = WGPU.TextureUsageRenderAttachment,
swapChainFormat = swapChainFormat,
width = fromIntegral initWidth,
height = fromIntegral initHeight,
width = 640,
height = 480,
presentMode = WGPU.PresentModeFifo
}
swapChainRef <- newIORef swapChain
pipelineLayout <-
WGPU.createPipelineLayout
device
Expand Down Expand Up @@ -92,6 +92,8 @@ main = do
}

let loop = do
-- update swapchain if the window size is different
updateSwapChain device surface window swapChainFormat windowSzRef swapChainRef
-- render
nextTexture <- WGPU.getSwapChainCurrentTextureView swapChain
encoder <- WGPU.createCommandEncoder device "Command Encoder"
Expand Down Expand Up @@ -171,6 +173,33 @@ getResources inst window = runExceptT $ do

pure Resources {..}

updateSwapChain ::
WGPU.Device ->
WGPU.Surface ->
GLFW.Window ->
WGPU.TextureFormat ->
IORef (Int, Int) ->
IORef WGPU.SwapChain ->
IO ()
updateSwapChain device surface window textureFormat szRef swapChainRef = do
oldSz <- readIORef szRef
curSz <- GLFW.getWindowSize window
when (curSz /= oldSz) $ do
writeIORef szRef curSz
swapChain <-
WGPU.createSwapChain
device
surface
WGPU.SwapChainDescriptor
{ swapChainLabel = "SwapChain",
usage = WGPU.TextureUsageRenderAttachment,
swapChainFormat = textureFormat,
width = fromIntegral . fst $ curSz,
height = fromIntegral . snd $ curSz,
presentMode = WGPU.PresentModeFifo
}
writeIORef swapChainRef swapChain

shaderSrc :: WGPU.WGSL
shaderSrc =
WGPU.WGSL $
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hs/src-internal/WGPU/Internal/Instance.hs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ platformDylibName =
case System.Info.os of
"darwin" -> "libwgpu_native.dylib"
"mingw32" -> "wgpu_native.dll"
"linux" -> "libwgpu_native.dylib"
"linux" -> "libwgpu_native.so"
other ->
error $ "platformDylibName: unknown / unhandled platform: " <> other

Expand Down
4 changes: 2 additions & 2 deletions wgpu-hs/src/WGPU.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
-- Copyright : Copyright (C) Jonathan Merritt 2021
-- Maintainer : Jonathan Merritt <[email protected]>
-- Stability : experimental
-- Portability : macOS
-- Portability : macOS, Linux, Windows
--
-- Layout of this module should be guided by the evolving
-- <https://www.w3.org/TR/webgpu/ WebGPU Specification>.
Expand Down Expand Up @@ -212,7 +212,7 @@ import WGPU.Internal.Texture
--
-- === Platform Support
--
-- Currently, macOS (Metal) and Windows are supported. Linux support is planned.
-- Currently, macOS (Metal), Windows and Linux are supported.
--
-- === Dependence on GLFW-b
--
Expand Down
4 changes: 2 additions & 2 deletions wgpu-hs/wgpu-hs.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: wgpu-hs
version: 0.2.0.0
version: 0.2.0.1
synopsis: WGPU
description: A high-level binding to WGPU.
bug-reports: https://github.com/lancelet/wgpu-hs/issues
Expand Down Expand Up @@ -70,7 +70,7 @@ library
, transformers ^>=0.5.6
, vector ^>=0.12.3
, wgpu-hs-internal
, wgpu-raw-hs ==0.2.0.0
, wgpu-raw-hs ==0.2.0.1

exposed-modules: WGPU

Expand Down
Binary file removed wgpu-hs/wgpu_native.dll
Binary file not shown.
4 changes: 4 additions & 0 deletions wgpu-raw-hs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Revision history for wgpu-raw-hs

## 0.2.0.1 -- 2021-08-24

- Linux support.

## 0.2.0.0 -- 2021-08-22

- Microsoft Windows support.
Expand Down
4 changes: 3 additions & 1 deletion wgpu-raw-hs/src/WGPU/Raw/Dynamic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import WGPU.Raw.Generated.Fun (WGPUHsInstance, loadDynamicInstance)

#ifdef WGPUHS_UNIX
import System.Posix.DynamicLinker (withDL, dlsym)
import System.Posix.DynamicLinker.Prim (RTLDFlags(RTLD_NOW))

-- | Load WGPU from a dynamic library and run a program using an instance.
withWGPU ::
Expand All @@ -20,7 +21,8 @@ withWGPU ::
-- | Completed IO action.
IO a
withWGPU dynlibFile action = do
withDL dynlibFile [] $ \dl -> loadDynamicInstance (dlsym dl) >>= action
withDL
dynlibFile [RTLD_NOW] $ \dl -> loadDynamicInstance (dlsym dl) >>= action
#endif

#ifdef WGPUHS_WINDOWS
Expand Down
43 changes: 42 additions & 1 deletion wgpu-raw-hs/src/WGPU/Raw/GLFWSurface.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,52 @@ foreign import ccall "wgpuhs_metal_layer"

#ifdef WGPUHS_TARGET_LINUX

import WGPU.Raw.Generated.Struct.WGPUSurfaceDescriptorFromXlib

createSurface ::
WGPUHsInstance ->
GLFW.Window ->
IO WGPUSurface
createSurface inst window = error "Linux: not yet implemented."
createSurface inst glfwWin = do
x11Display <- GLFW.getX11Display glfwWin
x11Window <- GLFW.getX11Window glfwWin

alloca $ \ptr_surfaceDescriptor -> do
alloca $ \ptr_chainedStruct -> do
alloca $ \ptr_surfaceDescriptorFromXlib -> do

let surfaceDescriptorFromXlib =
WGPUSurfaceDescriptorFromXlib
{ chain =
WGPUChainedStruct
{ next = nullPtr,
sType = WGPUSType.SurfaceDescriptorFromXlib
},
display = x11Display,
window = fromIntegral x11Window
}
poke
ptr_surfaceDescriptorFromXlib
surfaceDescriptorFromXlib

let chainedStruct =
WGPUChainedStruct
{ next = castPtr ptr_surfaceDescriptorFromXlib,
sType = WGPUSType.SurfaceDescriptorFromXlib
}
poke ptr_chainedStruct chainedStruct

let surfaceDescriptor =
WGPUSurfaceDescriptor
{ nextInChain = ptr_chainedStruct,
label = nullPtr
}
poke ptr_surfaceDescriptor surfaceDescriptor

wgpuInstanceCreateSurface
inst
(WGPUInstance nullPtr)
ptr_surfaceDescriptor

#endif

Expand Down
2 changes: 1 addition & 1 deletion wgpu-raw-hs/wgpu-raw-hs.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: wgpu-raw-hs
version: 0.2.0.0
version: 0.2.0.1
synopsis: WGPU Raw
description:
A very low-level WGPU binding.
Expand Down

0 comments on commit 9edd272

Please sign in to comment.