Skip to content

Commit 8deef52

Browse files
author
Mike Solomon
committed
Adds information about the frame and time delay
1 parent 470bd39 commit 8deef52

File tree

3 files changed

+105
-51
lines changed

3 files changed

+105
-51
lines changed

sandbox-dev.dhall

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ let conf = ./spago.dhall
22

33
in conf
44
// { sources = conf.sources # [ "sandbox/**/*.purs" ]
5-
, dependencies = conf.dependencies # [ "aff", "console", "js-date", "gl-matrix", "numbers", "aff-promise", "arraybuffer", "control", "float32", "foldable-traversable", "uint", "web-dom" ]
5+
, dependencies = conf.dependencies # [ "aff", "arrays", "refs", "st", "console", "js-date", "gl-matrix", "numbers", "aff-promise", "arraybuffer", "control", "float32", "foldable-traversable", "uint", "web-dom" ]
66
}

sandbox/Sandbox.purs

Lines changed: 103 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,39 @@ module Sandbox where
33
import Prelude
44

55
import Control.Lazy (fix)
6+
import Control.Monad.ST.Class (liftST)
67
import Control.Promise (toAffE)
78
import Control.Promise as Control.Promise
9+
import Data.Array.ST as STArray
810
import 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)
1012
import Data.ArrayBuffer.Typed as Typed
1113
import Data.ArrayBuffer.Types (ArrayView, Uint16Array, Float32Array)
1214
import Data.Float32 (Float32)
1315
import Data.Foldable (traverse_)
1416
import Data.Int (toNumber)
1517
import Data.Int.Bits (complement, (.&.))
1618
import Data.JSDate (getTime, now)
17-
import Data.Maybe (Maybe(..), maybe)
19+
import Data.Maybe (Maybe(..), fromMaybe, maybe)
1820
import Data.Number (pi)
1921
import Data.Number as Math
22+
import Data.Number.Format (precision, toStringWith)
2023
import Data.UInt (UInt)
2124
import Effect (Effect)
2225
import Effect.Aff (error, launchAff_, throwError)
2326
import Effect.Class (liftEffect)
2427

28+
import Effect.Ref as Ref
2529
import Unsafe.Coerce (unsafeCoerce)
26-
import Web.DOM.Element (setAttribute)
30+
import Web.DOM.Element (setAttribute, toNode)
31+
import Web.DOM.Node (setTextContent)
2732
import Web.DOM.NonElementParentNode (getElementById)
2833
import Web.GPU.BufferSource (fromFloat32Array)
2934
import Web.GPU.GPU (requestAdapter)
3035
import Web.GPU.GPUAdapter (requestDevice)
3136
import Web.GPU.GPUBindGroupEntry (GPUBufferBinding, gpuBindGroupEntry)
3237
import Web.GPU.GPUBindGroupLayoutEntry (gpuBindGroupLayoutEntry)
33-
import Web.GPU.GPUBuffer (GPUBuffer, getMappedRange, unmap)
38+
import Web.GPU.GPUBuffer (GPUBuffer, getMappedRange, mapAsync, unmap)
3439
import Web.GPU.GPUBufferBindingLayout (GPUBufferBindingLayout)
3540
import Web.GPU.GPUBufferBindingType as GPUBufferBindingType
3641
import Web.GPU.GPUBufferUsage (GPUBufferUsageFlags)
@@ -52,7 +57,7 @@ import Web.GPU.GPUFragmentState (GPUFragmentState)
5257
import Web.GPU.GPUFrontFace (cw)
5358
import Web.GPU.GPUIndexFormat (uint16)
5459
import Web.GPU.GPULoadOp as GPULoadOp
55-
60+
import Web.GPU.GPUMapMode as GPUMapMode
5661
import Web.GPU.GPUPrimitiveState (GPUPrimitiveState)
5762
import Web.GPU.GPUPrimitiveTopology (triangleList)
5863
import Web.GPU.GPUProgrammableStage (GPUProgrammableStage)
@@ -83,6 +88,17 @@ import Web.HTML.HTMLDocument (toNonElementParentNode)
8388
import Web.HTML.Window (document, navigator, requestAnimationFrame)
8489
import 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+
86102
hackyFloatConv :: Array Number -> Array Float32
87103
hackyFloatConv = unsafeCoerce
88104

@@ -98,7 +114,7 @@ showErrorMessage :: Effect Unit
98114
showErrorMessage = do
99115
d <- window >>= document
100116
getElementById "error" (toNonElementParentNode d) >>= traverse_
101-
(setAttribute "style" "display:auto;")
117+
(setAttribute "style" "display:auto; color: white;")
102118

103119
freshIdentityMatrix :: Effect Float32Array
104120
freshIdentityMatrix = fromArray $ hackyFloatConv
@@ -177,7 +193,16 @@ getPerspectiveMatrix = do
177193

178194
main :: Effect Unit
179195
main = 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

sandbox/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<body>
2626
<div id="error" style="display:none;">Your device does not support webgpu.</div>
2727
<canvas width="640" height="640" id="gfx"></canvas>
28+
<div style="color:white;" id="render-stats"></div>
2829
<script type="module" src="./index.js" defer></script>
2930
</body>
3031
</html>

0 commit comments

Comments
 (0)