Skip to content

Instantly share code, notes, and snippets.

@paniq
Created April 28, 2024 08:31
Show Gist options
  • Save paniq/3ee7e1d5651057acfe7e3c2848308ec7 to your computer and use it in GitHub Desktop.
Save paniq/3ee7e1d5651057acfe7e3c2848308ec7 to your computer and use it in GitHub Desktop.
sdl wgpu := do
using import backport
use-backport-globals;
import sdl wgpu
using import print String glm slice
using import compiler.target.SPIR-V
inline typeinit@ (...)
implies (T)
static-assert (T < pointer)
imply (& (local := (elementof T) ...)) T
inline chained@ (K ...)
using wgpu
chaintypename := K
K := getattr wgpu K
chaintype := static-try (getattr SType chaintypename)
else
(getattr NativeSType chaintypename) as (storageof SType) as SType
typeinit@
nextInChain = as
&
local := K
chain = typeinit
sType = chaintype
...
mutable@ ChainedStruct
inline arrayfieldinit (field countof ...)
pass
key field
implies (T)
imply (arrayof& (elementof T) ...) T
key countof
va-countof ...
MSAA_COUNT := 4
SURFACE_FORMAT := wgpu.TextureFormat.BGRA8UnormSrgb
fn install-wgpu-logger ()
using wgpu
SetLogCallback
fn (log-level message userdata)
print2 "wgpu:" message
null
SetLogLevel LogLevel.Error
fn create-instance ()
using wgpu
CreateInstance
chained@ 'InstanceExtras
backends = InstanceBackend.Primary
fn create-surface (window instance)
using wgpu
local info : sdl.SysWMinfo
sdl.SDL_VERSION &info.version
assert (storagecast (sdl.GetWindowWMInfo window &info))
let info = info.info
static-match operating-system
case 'linux
let x11-display x11-window = info.x11.display info.x11.window
InstanceCreateSurface instance
chained@ 'SurfaceDescriptorFromXlibWindow
display = x11-display as voidstar
window = x11-window as u32
case 'windows
let hinstance hwnd = info.win.hinstance info.win.window
InstanceCreateSurface instance
chained@ 'SurfaceDescriptorFromWindowsHWND
hinstance = hinstance
hwnd = hwnd
default
static-error "unsupported operating system"
fn get-adapter (instance surface)
using wgpu
local adapter : Adapter
InstanceRequestAdapter instance
typeinit@
compatibleSurface = surface
powerPreference = PowerPreference.HighPerformance
fn (status result msg userdata)
#assert (status == 0:u32)
assert (status == RequestAdapterStatus.Success)
@ (userdata as (mutable @Adapter)) = result
;
&adapter as voidstar
adapter
fn get-device (adapter)
using wgpu
#
local adapter-limits : SupportedLimits
AdapterGetLimits adapter &adapter-limits
local device : Device
AdapterRequestDevice adapter
typeinit@
requiredLimits = typeinit@
limits = Limits
va-map
inline (T)
static-match (unqualified T)
case u32 WGPU_LIMIT_U32_UNDEFINED
case u64 WGPU_LIMIT_U64_UNDEFINED
default
dump T
static-error "unhandled limit type"
elementsof Limits
fn (status result msg userdata)
if (status != RequestDeviceStatus.Success)
print2 "error while requesting device:" msg
assert false
@ (userdata as (mutable @Device)) = result
;
&device as voidstar
#do
local device-limits : SupportedLimits
DeviceGetLimits device &device-limits
print2 device-limits.limits
DeviceSetUncapturedErrorCallback device
fn (errtype msg userdata)
print2 "device error:" msg
;
null
device
fn verify-surface-format-available (surface adapter required-format)
using wgpu
local capabilities : SurfaceCapabilities
SurfaceGetCapabilities surface adapter &capabilities
capabilities.formats = alloca-array TextureFormat capabilities.formatCount
capabilities.presentModes = alloca-array PresentMode capabilities.presentModeCount
capabilities.alphaModes = alloca-array CompositeAlphaMode capabilities.alphaModeCount
SurfaceGetCapabilities surface adapter &capabilities
for i in (range capabilities.formatCount)
format := capabilities.formats @ i
if (format == required-format)
break;
else
assert false
"surface format not available on this platform"
fn create-swapchain (window surface adapter device format)
using wgpu
local width : u32
local height : u32
sdl.GetWindowSizeInPixels window
&width as (mutable @i32)
&height as (mutable @i32)
DeviceCreateSwapChain device surface
typeinit@
label = "swapchain"
usage = TextureUsage.RenderAttachment
format = format
width = width
height = height
presentMode = PresentMode.Fifo
fn create-rendertarget (window surface adapter device format)
using wgpu
local width : u32
local height : u32
sdl.GetWindowSizeInPixels window
&width as (mutable @i32)
&height as (mutable @i32)
DeviceCreateTexture device
typeinit@
label = "rendertarget"
usage = |
TextureUsage.CopyDst
TextureUsage.TextureBinding
TextureUsage.RenderAttachment
dimension = '2D
size = typeinit width height 1
format = format
mipLevelCount = 1
sampleCount = MSAA_COUNT
inline create-shader-module (device target shader-main)
using import wgpu
code := static-compile-spirv SPV_ENV_VULKAN_1_1_SPIRV_1_4 target
static-typify shader-main
ptr sz := 'data code
DeviceCreateShaderModule device
chained@ 'ShaderModuleSPIRVDescriptor
codeSize = (sz // (sizeof u32)) as u32
code = ptr as @u32
inline run (init render)
raising noreturn
using sdl
if (operating-system == 'windows)
SetHint SDL_HINT_WINDOWS_DPI_AWARENESS "permonitorv2"
SetHint SDL_HINT_WINDOWS_DPI_SCALING "0"
if
>= 0
Init
| SDL_INIT_VIDEO
SDL_INIT_TIMER
#
SDL_INIT_AUDIO
SDL_INIT_VIDEO
SDL_INIT_GAMECONTROLLER
window := CreateWindow "scopes sdl & webgpu demo"
SDL_WINDOWPOS_UNDEFINED
SDL_WINDOWPOS_UNDEFINED
\ 1280 720
| SDL_WINDOW_SHOWN
SDL_WINDOW_RESIZABLE
install-wgpu-logger;
instance := (create-instance)
surface := create-surface window instance
adapter := get-adapter instance surface
device := get-device adapter
rtformat := SURFACE_FORMAT
verify-surface-format-available surface adapter rtformat
local swapchain = create-swapchain window surface adapter device rtformat
local rendertarget = create-rendertarget window surface adapter device rtformat
local rtview = wgpu.TextureCreateView rendertarget null
queue := wgpu.DeviceGetQueue device
ctx := init
instance = instance
surface = surface
adapter = adapter
device = device
swapchain = swapchain
queue = queue
format = rtformat
local event : Event
loop ()
quit? := loop (quit? = false)
if ((PollEvent &event) == 0)
break quit?
if (event.type == SDL_QUIT)
repeat true
elseif
&
event.type == SDL_WINDOWEVENT
event.window.event == (SDL_WINDOWEVENT_CLOSE as integer)
event.window.windowID == (GetWindowID window)
repeat true
quit?
if quit?
break;
using wgpu
surfaceview := SwapChainGetCurrentTextureView swapchain
surfaceview := if (surfaceview == null)
SwapChainRelease swapchain
TextureViewRelease rtview
TextureRelease rendertarget
# reallocate swapchain and msaa texture
swapchain = create-swapchain window surface adapter device rtformat
rendertarget = create-rendertarget window surface adapter device rtformat
rtview = TextureCreateView rendertarget null
SwapChainGetCurrentTextureView swapchain
else surfaceview
assert (surfaceview != null)
cmds := DeviceCreateCommandEncoder device
typeinit@;
rp := CommandEncoderBeginRenderPass cmds
typeinit@
label = "clear screen"
arrayfieldinit 'colorAttachments
countof = 'colorAttachmentCount
typeinit
view = rtview
resolveTarget = null
loadOp = 'Clear
storeOp = 'Store
clearValue = Color (unpack (vec4 0 0 0.5 1))
RenderPassEncoderEnd rp
render ctx
instance = instance
surface = surface
adapter = adapter
device = device
swapchain = swapchain
queue = queue
format = rtformat
cmds = cmds
rtview = rtview
surfaceview = surfaceview
local cmds = CommandEncoderFinish cmds null
QueueSubmit queue 1 &cmds
SwapChainPresent swapchain
;
DestroyWindow window
Quit;
;
################################################################################
fn vertex-shader ()
using import glsl glm
out vcolor : vec4
location = 0
@if false
local vertices =
arrayof vec3
vec3 -1 -1 0
vec3 3 -1 0
vec3 -1 3 0
local colors =
arrayof vec4
vec4 0 0 0 1
vec4 2 0 0 1
vec4 0 2 0 1
@else
local vertices =
arrayof vec3
vec3 0.0 0.5 0.0
vec3 -0.5 -0.5 0.0
vec3 0.5 -0.5 0.0
local colors =
arrayof vec4
vec4 1.0 0.0 0.0 1.0
vec4 0.0 1.0 0.0 1.0
vec4 0.0 0.0 1.0 1.0
@endif
idx := gl_VertexIndex
vcolor = colors @ idx
gl_Position = vec4 (vertices @ idx) 1.0
fn fragment-shader ()
using import glsl glm
in vcolor : vec4
location = 0
out fcolor : vec4
location = 0
fcolor = vcolor
fn init (device format ...)
using wgpu
local pipeline : RenderPipeline
vertex-module := create-shader-module device 'vertex vertex-shader
fragment-module := create-shader-module device 'fragment fragment-shader
pipeline := DeviceCreateRenderPipeline device
typeinit@
label = "rasterize triangle"
layout = DeviceCreatePipelineLayout device
typeinit@
label = "rasterize triangle layout"
arrayfieldinit 'bindGroupLayouts
countof = 'bindGroupLayoutCount
vertex = typeinit
module = vertex-module
entryPoint = "main"
primitive = typeinit
topology = 'TriangleList
frontFace = 'CCW
multisample = typeinit
count = MSAA_COUNT
mask = ~0:u32
alphaToCoverageEnabled = false
fragment = typeinit@
module = fragment-module
entryPoint = "main"
arrayfieldinit 'targets
countof = 'targetCount
typeinit
format = format
writeMask = ColorWriteMask.All
blend = typeinit@
color = typeinit
operation = 'Add
srcFactor = 'SrcAlpha
dstFactor = 'OneMinusSrcAlpha
alpha = typeinit
operation = 'Add
srcFactor = 'One
dstFactor = 'OneMinusSrcAlpha
pipeline
fn render (pipeline rtview surfaceview cmds ...)
using wgpu
rp := CommandEncoderBeginRenderPass cmds
typeinit@
label = "msaa mixdown"
arrayfieldinit 'colorAttachments
countof = 'colorAttachmentCount
typeinit
view = rtview
resolveTarget = surfaceview
loadOp = 'Load
storeOp = 'Store
RenderPassEncoderSetPipeline rp pipeline
RenderPassEncoderDraw rp
3 # vertex count
1:u32 # instance-count
0:u32 # first vertex
0:u32 # first instance
RenderPassEncoderEnd rp
fn main ()
run init render
main;
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment