@@ -3,34 +3,39 @@ module Sandbox where
3
3
import Prelude
4
4
5
5
import Control.Lazy (fix )
6
+ import Control.Monad.ST.Class (liftST )
6
7
import Control.Promise (toAffE )
7
8
import Control.Promise as Control.Promise
9
+ import Data.Array.ST as STArray
8
10
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 )
10
12
import Data.ArrayBuffer.Typed as Typed
11
13
import Data.ArrayBuffer.Types (ArrayView , Uint16Array , Float32Array )
12
14
import Data.Float32 (Float32 )
13
15
import Data.Foldable (traverse_ )
14
16
import Data.Int (toNumber )
15
17
import Data.Int.Bits (complement , (.&.))
16
18
import Data.JSDate (getTime , now )
17
- import Data.Maybe (Maybe (..), maybe )
19
+ import Data.Maybe (Maybe (..), fromMaybe , maybe )
18
20
import Data.Number (pi )
19
21
import Data.Number as Math
22
+ import Data.Number.Format (precision , toStringWith )
20
23
import Data.UInt (UInt )
21
24
import Effect (Effect )
22
25
import Effect.Aff (error , launchAff_ , throwError )
23
26
import Effect.Class (liftEffect )
24
27
28
+ import Effect.Ref as Ref
25
29
import Unsafe.Coerce (unsafeCoerce )
26
- import Web.DOM.Element (setAttribute )
30
+ import Web.DOM.Element (setAttribute , toNode )
31
+ import Web.DOM.Node (setTextContent )
27
32
import Web.DOM.NonElementParentNode (getElementById )
28
33
import Web.GPU.BufferSource (fromFloat32Array )
29
34
import Web.GPU.GPU (requestAdapter )
30
35
import Web.GPU.GPUAdapter (requestDevice )
31
36
import Web.GPU.GPUBindGroupEntry (GPUBufferBinding , gpuBindGroupEntry )
32
37
import Web.GPU.GPUBindGroupLayoutEntry (gpuBindGroupLayoutEntry )
33
- import Web.GPU.GPUBuffer (GPUBuffer , getMappedRange , unmap )
38
+ import Web.GPU.GPUBuffer (GPUBuffer , getMappedRange , mapAsync , unmap )
34
39
import Web.GPU.GPUBufferBindingLayout (GPUBufferBindingLayout )
35
40
import Web.GPU.GPUBufferBindingType as GPUBufferBindingType
36
41
import Web.GPU.GPUBufferUsage (GPUBufferUsageFlags )
@@ -52,7 +57,7 @@ import Web.GPU.GPUFragmentState (GPUFragmentState)
52
57
import Web.GPU.GPUFrontFace (cw )
53
58
import Web.GPU.GPUIndexFormat (uint16 )
54
59
import Web.GPU.GPULoadOp as GPULoadOp
55
-
60
+ import Web.GPU.GPUMapMode as GPUMapMode
56
61
import Web.GPU.GPUPrimitiveState (GPUPrimitiveState )
57
62
import Web.GPU.GPUPrimitiveTopology (triangleList )
58
63
import Web.GPU.GPUProgrammableStage (GPUProgrammableStage )
@@ -83,6 +88,17 @@ import Web.HTML.HTMLDocument (toNonElementParentNode)
83
88
import Web.HTML.Window (document , navigator , requestAnimationFrame )
84
89
import Web.Promise as Web.Promise
85
90
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
+
86
102
hackyFloatConv :: Array Number -> Array Float32
87
103
hackyFloatConv = unsafeCoerce
88
104
@@ -98,7 +114,7 @@ showErrorMessage :: Effect Unit
98
114
showErrorMessage = do
99
115
d <- window >>= document
100
116
getElementById " error" (toNonElementParentNode d) >>= traverse_
101
- (setAttribute " style" " display:auto;" )
117
+ (setAttribute " style" " display:auto; color: white; " )
102
118
103
119
freshIdentityMatrix :: Effect Float32Array
104
120
freshIdentityMatrix = fromArray $ hackyFloatConv
@@ -177,7 +193,16 @@ getPerspectiveMatrix = do
177
193
178
194
main :: Effect Unit
179
195
main = do
196
+ timeDeltaAverager <- averager
197
+ frameDeltaAverager <- averager
180
198
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
181
206
positions :: Float32Array <- fromArray $ hackyFloatConv
182
207
[ 1.0
183
208
, 1.0
@@ -277,22 +302,28 @@ main = do
277
302
, 0.8
278
303
, 1.0
279
304
]
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
288
318
translateZData :: Float32Array <- map identity $ freshTranslateMatrix 0.0 0.0
289
319
(-1.5 )
290
- translateZResultData :: Float32Array <- freshIdentityMatrix
320
+ let
321
+ translateZResultData = imx
291
322
perspectiveData :: Float32Array <- getPerspectiveMatrix
292
- perspectiveResultData :: Float32Array <- freshIdentityMatrix
293
- -- msdelta
294
- hackyData :: Float32Array <- freshIdentityMatrix
323
+ let
324
+ perspectiveResultData = imx
295
325
-- 📇 Index Buffer Data
326
+ outputBuffers <- liftST $ STArray .new
296
327
indices :: Uint16Array <- fromArray $ hackyIntConv
297
328
[
298
329
--
@@ -388,35 +419,36 @@ main = do
388
419
colorBuffer <- liftEffect $ createBufferF colors GPUBufferUsage .vertex
389
420
indexBuffer <- liftEffect $ createBufferF indices GPUBufferUsage .index
390
421
-- ✋ Declare buffer handles
422
+ let standardStorageFlag = GPUBufferUsage .storage
423
+ let finalStorageFlag = GPUBufferUsage .storage .|. GPUBufferUsage .copySrc
391
424
uniformBuffer <- liftEffect $ createBufferF uniformData
392
425
(GPUBufferUsage .uniform .|. GPUBufferUsage .copyDst)
393
426
timeBuffer <- liftEffect $ createBufferF timeData
394
- (GPUBufferUsage .storage .|. GPUBufferUsage .copyDst)
427
+ ( GPUBufferUsage .storage .|. GPUBufferUsage .copyDst .|.
428
+ GPUBufferUsage .copySrc
429
+ )
395
430
scaleBuffer <- liftEffect $ createBufferF scaleData
396
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
431
+ standardStorageFlag
397
432
rotateZBuffer <- liftEffect $ createBufferF rotateZData
398
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
433
+ standardStorageFlag
399
434
rotateZResultBuffer <- liftEffect $ createBufferF rotateZResultData
400
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
435
+ standardStorageFlag
401
436
rotateXBuffer <- liftEffect $ createBufferF rotateXData
402
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
437
+ standardStorageFlag
403
438
rotateXResultBuffer <- liftEffect $ createBufferF rotateXResultData
404
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
439
+ standardStorageFlag
405
440
rotateYBuffer <- liftEffect $ createBufferF rotateYData
406
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
441
+ standardStorageFlag
407
442
rotateYResultBuffer <- liftEffect $ createBufferF rotateYResultData
408
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
443
+ standardStorageFlag
409
444
translateZBuffer <- liftEffect $ createBufferF translateZData
410
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
445
+ standardStorageFlag
411
446
translateZResultBuffer <- liftEffect $ createBufferF translateZResultData
412
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
447
+ standardStorageFlag
413
448
perspectiveBuffer <- liftEffect $ createBufferF perspectiveData
414
- ( GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
449
+ standardStorageFlag
415
450
perspectiveResultBuffer <- liftEffect $ createBufferF perspectiveResultData
416
- (GPUBufferUsage .storage .|. GPUBufferUsage .copySrc)
417
- -- msdelta
418
- hackyBuffer <- liftEffect $ createBufferF hackyData
419
- (GPUBufferUsage .copyDst .|. GPUBufferUsage .mapRead)
451
+ finalStorageFlag
420
452
-- 🖍️ Shaders
421
453
let
422
454
initialScaleDesc = x
@@ -517,7 +549,7 @@ fn main(@builtin(global_invocation_id) global_id : vec3<u32>) {
517
549
}
518
550
519
551
resultMatrix[ixx*4 + ixy] = result;
520
- }"""
552
+ }"""
521
553
}
522
554
matrixMultiplicationModule <- liftEffect $ createShaderModule device
523
555
matrixMultiplicationDesc
@@ -842,16 +874,16 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
842
874
}
843
875
renderPipeline <- liftEffect $ createRenderPipeline device pipelineDesc
844
876
{ canvasWidth, canvasHeight, context } <- liftEffect do
845
- d <- window >>= document
877
+
846
878
canvas <-
847
879
( (_ >>= fromElement) <$> getElementById " gfx"
848
- (toNonElementParentNode d )
880
+ (toNonElementParentNode doc )
849
881
) >>= maybe
850
- (showErrorMessage *> throwError (error " counld not find canvas" ))
882
+ (showErrorMessage *> throwError (error " could not find canvas" ))
851
883
pure
852
884
853
885
context <- getContext canvas >>= maybe
854
- (showErrorMessage *> throwError (error " counld not find context" ))
886
+ (showErrorMessage *> throwError (error " could not find context" ))
855
887
pure
856
888
canvasWidth <- width canvas
857
889
canvasHeight <- height canvas
@@ -898,9 +930,10 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
898
930
-- 💻 Encode compute commands
899
931
scalePassEncoder <- beginComputePass commandEncoder (x {})
900
932
tn <- (getTime >>> (_ - startsAt) >>> (_ * 0.001 )) <$> now
933
+ cf <- Ref .read currentFrame
901
934
timeNowData :: Float32Array <- fromArray $ hackyFloatConv
902
- [ (tn / 2.0 ) ]
903
-
935
+ [ (tn / 2.0 ), toNumber cf ]
936
+ Ref .modify_ (add 1 ) currentFrame
904
937
writeBuffer queue timeBuffer 0 (fromFloat32Array timeNowData)
905
938
GPUComputePassEncoder .setPipeline scalePassEncoder initialScalePipeline
906
939
GPUComputePassEncoder .setBindGroup scalePassEncoder 0
@@ -1009,21 +1042,42 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
1009
1042
setIndexBuffer passEncoder indexBuffer uint16
1010
1043
setBindGroup passEncoder 0 uniformBindGroup
1011
1044
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
1012
1054
end passEncoder
1013
1055
-- ------
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
1017
1061
(4 * 16 )
1018
1062
-- 🙌 finish commandEncoder
1019
1063
toSubmit <- finish commandEncoder
1020
1064
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
1027
1081
let
1028
1082
render = unit # fix \f _ -> do
1029
1083
-- ⏭ Acquire next image from context
@@ -1034,7 +1088,6 @@ fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
1034
1088
encodeCommands colorTextureView
1035
1089
1036
1090
-- ➿ Refresh canvas
1037
- -- msdelta
1038
1091
window >>= void <<< requestAnimationFrame (f unit)
1039
1092
1040
1093
liftEffect render
0 commit comments