@@ -3,34 +3,39 @@ module Sandbox where
33import Prelude
44
55import Control.Lazy (fix )
6+ import Control.Monad.ST.Class (liftST )
67import Control.Promise (toAffE )
78import Control.Promise as Control.Promise
9+ import Data.Array.ST as STArray
810import Data.ArrayBuffer.ArrayBuffer (byteLength )
9- import Data.ArrayBuffer.Typed (class TypedArray , fromArray , setTyped , whole )
11+ import Data.ArrayBuffer.Typed (class TypedArray , fromArray , setTyped , toArray , whole )
1012import Data.ArrayBuffer.Typed as Typed
1113import Data.ArrayBuffer.Types (ArrayView , Uint16Array , Float32Array )
1214import Data.Float32 (Float32 )
1315import Data.Foldable (traverse_ )
1416import Data.Int (toNumber )
1517import Data.Int.Bits (complement , (.&.))
1618import Data.JSDate (getTime , now )
17- import Data.Maybe (Maybe (..), maybe )
19+ import Data.Maybe (Maybe (..), fromMaybe , maybe )
1820import Data.Number (pi )
1921import Data.Number as Math
22+ import Data.Number.Format (precision , toStringWith )
2023import Data.UInt (UInt )
2124import Effect (Effect )
2225import Effect.Aff (error , launchAff_ , throwError )
2326import Effect.Class (liftEffect )
2427
28+ import Effect.Ref as Ref
2529import Unsafe.Coerce (unsafeCoerce )
26- import Web.DOM.Element (setAttribute )
30+ import Web.DOM.Element (setAttribute , toNode )
31+ import Web.DOM.Node (setTextContent )
2732import Web.DOM.NonElementParentNode (getElementById )
2833import Web.GPU.BufferSource (fromFloat32Array )
2934import Web.GPU.GPU (requestAdapter )
3035import Web.GPU.GPUAdapter (requestDevice )
3136import Web.GPU.GPUBindGroupEntry (GPUBufferBinding , gpuBindGroupEntry )
3237import Web.GPU.GPUBindGroupLayoutEntry (gpuBindGroupLayoutEntry )
33- import Web.GPU.GPUBuffer (GPUBuffer , getMappedRange , unmap )
38+ import Web.GPU.GPUBuffer (GPUBuffer , getMappedRange , mapAsync , unmap )
3439import Web.GPU.GPUBufferBindingLayout (GPUBufferBindingLayout )
3540import Web.GPU.GPUBufferBindingType as GPUBufferBindingType
3641import Web.GPU.GPUBufferUsage (GPUBufferUsageFlags )
@@ -52,7 +57,7 @@ import Web.GPU.GPUFragmentState (GPUFragmentState)
5257import Web.GPU.GPUFrontFace (cw )
5358import Web.GPU.GPUIndexFormat (uint16 )
5459import Web.GPU.GPULoadOp as GPULoadOp
55-
60+ import Web.GPU.GPUMapMode as GPUMapMode
5661import Web.GPU.GPUPrimitiveState (GPUPrimitiveState )
5762import Web.GPU.GPUPrimitiveTopology (triangleList )
5863import Web.GPU.GPUProgrammableStage (GPUProgrammableStage )
@@ -83,6 +88,17 @@ import Web.HTML.HTMLDocument (toNonElementParentNode)
8388import Web.HTML.Window (document , navigator , requestAnimationFrame )
8489import Web.Promise as Web.Promise
8590
91+ averager :: forall a . EuclideanRing a => Effect (a -> Effect a )
92+ averager = do
93+ ct <- Ref .new zero
94+ val <- Ref .new zero
95+ pure \v -> do
96+ ct' <- Ref .read ct
97+ val' <- Ref .read val
98+ Ref .write (ct' + one) ct
99+ Ref .write (val' + v) val
100+ pure $ val' / ct'
101+
86102hackyFloatConv :: Array Number -> Array Float32
87103hackyFloatConv = unsafeCoerce
88104
@@ -98,7 +114,7 @@ showErrorMessage :: Effect Unit
98114showErrorMessage = do
99115 d <- window >>= document
100116 getElementById " error" (toNonElementParentNode d) >>= traverse_
101- (setAttribute " style" " display:auto;" )
117+ (setAttribute " style" " display:auto; color: white; " )
102118
103119freshIdentityMatrix :: Effect Float32Array
104120freshIdentityMatrix = fromArray $ hackyFloatConv
@@ -177,7 +193,16 @@ getPerspectiveMatrix = do
177193
178194main :: Effect Unit
179195main = do
196+ timeDeltaAverager <- averager
197+ frameDeltaAverager <- averager
180198 startsAt <- getTime <$> now
199+ doc <- window >>= document
200+ renderStats <-
201+ ( getElementById " render-stats"
202+ (toNonElementParentNode doc)
203+ ) >>= maybe
204+ (showErrorMessage *> throwError (error " could not find render-stats div" ))
205+ pure
181206 positions :: Float32Array <- fromArray $ hackyFloatConv
182207 [ 1.0
183208 , 1.0
@@ -277,22 +302,28 @@ main = do
277302 , 0.8
278303 , 1.0
279304 ]
280- scaleData :: Float32Array <- freshIdentityMatrix
281- timeData :: Float32Array <- fromArray $ hackyFloatConv [ 0.0 ]
282- rotateZData :: Float32Array <- freshIdentityMatrix
283- rotateZResultData :: Float32Array <- freshIdentityMatrix
284- rotateXData :: Float32Array <- freshIdentityMatrix
285- rotateXResultData :: Float32Array <- freshIdentityMatrix
286- rotateYData :: Float32Array <- freshIdentityMatrix
287- rotateYResultData :: Float32Array <- freshIdentityMatrix
305+ imx <- freshIdentityMatrix
306+ currentFrame <- Ref .new 0
307+ let
308+ scaleData = imx
309+ -- timestamp, currentFrame
310+ timeData :: Float32Array <- fromArray $ hackyFloatConv [ 0.0 , 0.0 ]
311+ let
312+ rotateZData = imx
313+ rotateZResultData = imx
314+ rotateXData = imx
315+ rotateXResultData = imx
316+ rotateYData = imx
317+ rotateYResultData = imx
288318 translateZData :: Float32Array <- map identity $ freshTranslateMatrix 0.0 0.0
289319 (-1.5 )
290- translateZResultData :: Float32Array <- freshIdentityMatrix
320+ let
321+ translateZResultData = imx
291322 perspectiveData :: Float32Array <- getPerspectiveMatrix
292- perspectiveResultData :: Float32Array <- freshIdentityMatrix
293- -- msdelta
294- hackyData :: Float32Array <- freshIdentityMatrix
323+ let
324+ perspectiveResultData = imx
295325 -- 📇 Index Buffer Data
326+ outputBuffers <- liftST $ STArray .new
296327 indices :: Uint16Array <- fromArray $ hackyIntConv
297328 [
298329 --
@@ -388,35 +419,36 @@ main = do
388419 colorBuffer <- liftEffect $ createBufferF colors GPUBufferUsage .vertex
389420 indexBuffer <- liftEffect $ createBufferF indices GPUBufferUsage .index
390421 -- ✋ Declare buffer handles
422+ let standardStorageFlag = GPUBufferUsage .storage
423+ let finalStorageFlag = GPUBufferUsage .storage .|. GPUBufferUsage .copySrc
391424 uniformBuffer <- liftEffect $ createBufferF uniformData
392425 (GPUBufferUsage .uniform .|. GPUBufferUsage .copyDst)
393426 timeBuffer <- liftEffect $ createBufferF timeData
394- (GPUBufferUsage .storage .|. GPUBufferUsage .copyDst)
427+ ( GPUBufferUsage .storage .|. GPUBufferUsage .copyDst .|.
428+ GPUBufferUsage .copySrc
429+ )
395430 scaleBuffer <- liftEffect $ createBufferF scaleData
396- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
431+ standardStorageFlag
397432 rotateZBuffer <- liftEffect $ createBufferF rotateZData
398- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
433+ standardStorageFlag
399434 rotateZResultBuffer <- liftEffect $ createBufferF rotateZResultData
400- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
435+ standardStorageFlag
401436 rotateXBuffer <- liftEffect $ createBufferF rotateXData
402- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
437+ standardStorageFlag
403438 rotateXResultBuffer <- liftEffect $ createBufferF rotateXResultData
404- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
439+ standardStorageFlag
405440 rotateYBuffer <- liftEffect $ createBufferF rotateYData
406- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
441+ standardStorageFlag
407442 rotateYResultBuffer <- liftEffect $ createBufferF rotateYResultData
408- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
443+ standardStorageFlag
409444 translateZBuffer <- liftEffect $ createBufferF translateZData
410- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
445+ standardStorageFlag
411446 translateZResultBuffer <- liftEffect $ createBufferF translateZResultData
412- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
447+ standardStorageFlag
413448 perspectiveBuffer <- liftEffect $ createBufferF perspectiveData
414- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
449+ standardStorageFlag
415450 perspectiveResultBuffer <- liftEffect $ createBufferF perspectiveResultData
416- (GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
417- -- msdelta
418- hackyBuffer <- liftEffect $ createBufferF hackyData
419- (GPUBufferUsage .copyDst .|. GPUBufferUsage .mapRead)
451+ finalStorageFlag
420452 -- 🖍️ Shaders
421453 let
422454 initialScaleDesc = x
@@ -517,7 +549,7 @@ fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
517549 }
518550
519551 resultMatrix[ixx*4 + ixy] = result;
520- }"""
552+ }"""
521553 }
522554 matrixMultiplicationModule <- liftEffect $ createShaderModule device
523555 matrixMultiplicationDesc
@@ -842,16 +874,16 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
842874 }
843875 renderPipeline <- liftEffect $ createRenderPipeline device pipelineDesc
844876 { canvasWidth, canvasHeight, context } <- liftEffect do
845- d <- window >>= document
877+
846878 canvas <-
847879 ( (_ >>= fromElement) <$> getElementById " gfx"
848- (toNonElementParentNode d )
880+ (toNonElementParentNode doc )
849881 ) >>= maybe
850- (showErrorMessage *> throwError (error " counld not find canvas" ))
882+ (showErrorMessage *> throwError (error " could not find canvas" ))
851883 pure
852884
853885 context <- getContext canvas >>= maybe
854- (showErrorMessage *> throwError (error " counld not find context" ))
886+ (showErrorMessage *> throwError (error " could not find context" ))
855887 pure
856888 canvasWidth <- width canvas
857889 canvasHeight <- height canvas
@@ -898,9 +930,10 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
898930 -- 💻 Encode compute commands
899931 scalePassEncoder <- beginComputePass commandEncoder (x {})
900932 tn <- (getTime >>> (_ - startsAt) >>> (_ * 0.001 )) <$> now
933+ cf <- Ref .read currentFrame
901934 timeNowData :: Float32Array <- fromArray $ hackyFloatConv
902- [ (tn / 2.0 ) ]
903-
935+ [ (tn / 2.0 ), toNumber cf ]
936+ Ref .modify_ (add 1 ) currentFrame
904937 writeBuffer queue timeBuffer 0 (fromFloat32Array timeNowData)
905938 GPUComputePassEncoder .setPipeline scalePassEncoder initialScalePipeline
906939 GPUComputePassEncoder .setBindGroup scalePassEncoder 0
@@ -1009,21 +1042,42 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
10091042 setIndexBuffer passEncoder indexBuffer uint16
10101043 setBindGroup passEncoder 0 uniformBindGroup
10111044 drawIndexedWithInstanceCount passEncoder 36 1
1045+ buf' <- liftST $ STArray .pop outputBuffers
1046+ buf <- flip fromMaybe buf'
1047+ <$> do
1048+ buffer <- createBuffer device $ x
1049+ { size: ((byteLength (Typed .buffer imx)) + 3 ) .&.
1050+ complement 3
1051+ , usage: GPUBufferUsage .copyDst .|. GPUBufferUsage .mapRead
1052+ }
1053+ pure buffer
10121054 end passEncoder
10131055 -- ------
1014- copyBufferToBuffer commandEncoder rotateXBuffer 0
1015- hackyBuffer
1016- 0
1056+ -- write to output buffer
1057+ -- we use this as a test
1058+ copyBufferToBuffer commandEncoder perspectiveResultBuffer 0
1059+ buf
1060+ 0
10171061 (4 * 16 )
10181062 -- 🙌 finish commandEncoder
10191063 toSubmit <- finish commandEncoder
10201064 submit queue [ toSubmit ]
1021- -- launchAff_ do
1022- -- toAffE $ convertPromise <$> mapAsync hackyBuffer GPUMapMode.read
1023- -- liftEffect do
1024- -- mr <- getMappedRange hackyBuffer
1025- -- arr <- (whole mr :: Effect Float32Array) >>= toArray
1026- -- logShow arr
1065+ launchAff_ do
1066+ toAffE $ convertPromise <$> mapAsync buf GPUMapMode .read
1067+ liftEffect do
1068+ mr <- getMappedRange buf
1069+ -- we don't use the mapped range, but we go through the process of
1070+ -- getting it in order to fully test the mapAsync function's timing
1071+ _ <- (whole mr :: Effect Float32Array ) >>= toArray
1072+ tnx <- (getTime >>> (_ - startsAt) >>> (_ * 0.001 )) <$> now
1073+ cfx <- Ref .read currentFrame
1074+ avgTn <- timeDeltaAverager (tnx - tn)
1075+ avgCf <- frameDeltaAverager (toNumber (cfx - cf))
1076+ setTextContent
1077+ (" Delta time: " <> show (toStringWith (precision 2 ) avgTn) <> " , Delta frames: " <> show (toStringWith (precision 2 ) avgCf))
1078+ (toNode renderStats)
1079+ unmap buf
1080+ void $ liftST $ STArray .push buf outputBuffers
10271081 let
10281082 render = unit # fix \f _ -> do
10291083 -- ⏭ Acquire next image from context
@@ -1034,7 +1088,6 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
10341088 encodeCommands colorTextureView
10351089
10361090 -- ➿ Refresh canvas
1037- -- msdelta
10381091 window >>= void <<< requestAnimationFrame (f unit)
10391092
10401093 liftEffect render
0 commit comments