-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathGPUClearExample.hs
More file actions
139 lines (121 loc) · 5.04 KB
/
GPUClearExample.hs
File metadata and controls
139 lines (121 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
{-# LANGUAGE RecordWildCards #-}
-- |
-- Example : SDL.GPUClear
-- Description : SDL Window, Event, and Basic GPU Rendering Example
-- Copyright : (c) Kyle Lukaszek, 2025
-- License : BSD3
--
-- Based on the examples from: https://github.com/TheSpydog/SDL_gpu_examples/
-- |
module Main where
import Control.Monad (unless, when)
-- For shader format flags
import Data.IORef
import Data.Word (Word64)
import GPUCommon
import SDL3
import System.Exit (exitFailure, exitSuccess)
import Text.Printf (printf)
main :: IO ()
main = do
sdlLog $ "Compiled SDL Version: " ++ show sdlVersion
linkedVersion <- sdlGetVersion
sdlLog $ "Linked SDL Version: " ++ show linkedVersion
-- Use withContext for initialization and cleanup
maybeResult <- withContext "SDL3 Haskell GPU Example" [SDL_WINDOW_RESIZABLE] runAppGPU
case maybeResult of
Nothing -> do
sdlLog "Application initialization failed."
exitFailure
Just _ -> do
sdlLog "Application finished successfully."
exitSuccess
-- | Application logic, now receives the Context
runAppGPU :: Context -> IO ()
runAppGPU context@Context {} = do
-- Deconstruct context
-- Start event loop with initial time
startTime <- sdlGetPerformanceCounter
freq <- sdlGetPerformanceFrequency
deltaTimeRef <- newIORef 0.0
eventLoopGPU context startTime freq deltaTimeRef
-- Cleanup is handled by withContext
-- | Main event loop
eventLoopGPU :: Context -> Word64 -> Word64 -> IORef Double -> IO ()
eventLoopGPU context@Context {} lastTime freq deltaTimeRef = do
currentTime <- sdlGetPerformanceCounter
let deltaTime = fromIntegral (currentTime - lastTime) / fromIntegral freq
writeIORef deltaTimeRef (deltaTime * 1000.0)
sdlPumpEvents
shouldQuitRef <- newIORef False
processEventsGPU shouldQuitRef deltaTimeRef
shouldQuit <- readIORef shouldQuitRef
unless shouldQuit $ do
-- \*** GPU Rendering ***
renderFrameGPU context -- Pass context
-- Continue loop
eventLoopGPU context currentTime freq deltaTimeRef
-- | Process all pending events (simplified for GPU example)
processEventsGPU :: IORef Bool -> IORef Double -> IO ()
processEventsGPU shouldQuitRef deltaTimeRef = do
maybeEvent <- sdlPollEvent
case maybeEvent of
Nothing -> return () -- No more events
Just event -> do
quit <- handleEventGPU event deltaTimeRef
when quit $ writeIORef shouldQuitRef True
processEventsGPU shouldQuitRef deltaTimeRef -- Process next event
-- | Handle a single SDL event (simplified for GPU example)
handleEventGPU :: SDLEvent -> IORef Double -> IO Bool
handleEventGPU event deltaTimeRef = case event of
SDLEventQuit _ -> do
sdlLog "Quit event received."
return True
SDLEventKeyboard (SDLKeyboardEvent _ _ _ _ scancode _ _ _ down _) | down -> do
dtMs <- readIORef deltaTimeRef
sdlLog $ printf "Key '%s' pressed. Delta Time: %.3f ms" (show scancode) dtMs
return $ scancode == SDL_SCANCODE_Q -- Quit on Q
_ -> return False
renderFrameGPU :: Context -> IO ()
renderFrameGPU Context {..} = do
-- Deconstruct context
-- 1. Acquire Command Buffer
maybeCmdbuf <- sdlAcquireGPUCommandBuffer contextDevice
case maybeCmdbuf of
Nothing -> sdlLog "Error: Failed to acquire command buffer"
Just cmdbuf -> do
-- 2. Acquire Swapchain Texture
maybeSwapchain <- sdlWaitAndAcquireGPUSwapchainTexture cmdbuf contextWindow
case maybeSwapchain of
Nothing -> sdlLog "Warning: Failed to acquire swapchain texture"
Just (swapchainTexture, _w, _h) -> do
-- 3. Define Color Target Info
let clearColor = SDLFColor 0.3 0.4 0.5 1.0
let colorTargetInfo =
SDLGPUColorTargetInfo
{ texture = swapchainTexture,
mipLevel = 0, -- Use base level
layerOrDepthPlane = 0, -- Use base layer
clearColor = clearColor,
loadOp = SDL_GPU_LOADOP_CLEAR, -- Clear the target
storeOp = SDL_GPU_STOREOP_STORE, -- Store the result
resolveTexture = Nothing, -- No MSAA resolve needed
resolveMipLevel = 0,
resolveLayer = 0,
targetCycle = False, -- Don't cycle (relevant for multi-buffer resources)
targetCycleResolve = False
}
-- 4. Begin Render Pass
maybeRenderPass <- sdlBeginGPURenderPass cmdbuf [colorTargetInfo] Nothing -- Only one color target, no depth/stencil
case maybeRenderPass of
Nothing -> sdlLog "Error: Failed to begin render pass"
Just renderPass -> do
-- \*** Insert Drawing Commands Here (in the future) ***
-- For now, we just clear via the LoadOp.
-- 5. End Render Pass
sdlEndGPURenderPass renderPass
-- 6. Submit Command Buffer (regardless of whether texture was acquired, buffer might have other commands)
submitted <- sdlSubmitGPUCommandBuffer cmdbuf
unless submitted $ do
err <- sdlGetError
sdlLog $ "Error: Failed to submit command buffer: " ++ err