summaryrefslogtreecommitdiff
path: root/MaskableStream.hs
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2019-05-18 21:15:21 -0400
committerJoe Crayne <joe@jerkface.net>2019-05-18 21:15:21 -0400
commitfbb54c463cfd5171a582bb3d9668321d9d450f87 (patch)
treeef429d2c02f92f957cd435f83f21bbf8c2bcbca0 /MaskableStream.hs
parent5354bd2aef9607faecec1e97393b05f11e8ed2fa (diff)
Factored lambdacube patch module from ring buffer.
Diffstat (limited to 'MaskableStream.hs')
-rw-r--r--MaskableStream.hs199
1 files changed, 199 insertions, 0 deletions
diff --git a/MaskableStream.hs b/MaskableStream.hs
new file mode 100644
index 0000000..c023998
--- /dev/null
+++ b/MaskableStream.hs
@@ -0,0 +1,199 @@
1{-# LANGUAGE LambdaCase, RecordWildCards #-}
2
3-- TODO: Formulate this module as a patch against lambdacube-gl.
4
5module MaskableStream where
6
7import Control.Monad
8import Control.Monad.IO.Class
9import Data.Foldable
10import Data.Int
11import Data.IORef
12import Data.Maybe
13import Data.Word
14import qualified Data.Map.Strict as Map
15import qualified Data.Vector as V
16 ;import Data.Vector as V ((!),(//))
17import Foreign.C.Types (CPtrdiff)
18import Foreign.Marshal
19import Foreign.Ptr
20import Foreign.Storable
21
22import LambdaCube.GL as LC
23import LambdaCube.GL.Data -- (uploadCubeMapToGPU,uploadTextureBufferToGPU,updateTextureBuffer)
24import LambdaCube.GL.Mesh as LC
25import LambdaCube.GL.Type
26import LambdaCube.IR as LC
27import LambdaCube.GL.Util
28import LambdaCube.GL.Input.Type
29import LambdaCube.GL.Input hiding (createObjectCommands)
30
31import Graphics.GL.Core33
32
33
34-- based on addMeshToObjectArray
35addToObjectArray :: GLStorage
36 -> String -- ^ Slot name for a PrimitiveStream.
37 -> [String] -- ^ Uniform names. IORefs will be put in 'objUniSetup'.
38 -> GPUData
39 -> IO Object
40addToObjectArray input slotName objUniNames (GPUData prim streams indices _) = do
41 let ObjectArraySchema _ slotStreams = fromMaybe (error $ "addMeshToObjectArray - missing object array: " ++ slotName)
42 $ Map.lookup slotName $! objectArrays $! schema input
43 addObject input slotName prim indices (Map.intersection streams slotStreams) objUniNames
44
45setUniformCommand :: (String -> GLUniform)
46 -> (String,GLint)
47 -> GLObjectCommand
48setUniformCommand ulookup (n,i) = GLSetUniform i (ulookup n)
49
50bindTextureCommand :: (String -> IORef GLint)
51 -> (String -> GLUniform)
52 -> String
53 -> GLObjectCommand
54bindTextureCommand tlookup ulookup n = GLBindTexture (inputTypeToTextureTarget $ uniInputType u) (tlookup n) u
55 where
56 u = ulookup n
57 uniInputType (GLTypedUniform ty _) = unwitnessType ty
58 uniInputType (GLUniform r) = objectType r
59
60setVertexAttribCommmand :: (t -> Stream Buffer) -> (GLuint, t) -> GLObjectCommand
61setVertexAttribCommmand alookup (i,name) = case alookup name of
62 Stream ty (Buffer arrs bo) arrIdx start len -> mkAttrCmd i bo n (arrayTypeToGLType arrType) (intPtrToPtr $! offset)
63 where
64 (n, mkAttrCmd) = classifyStreamType ty
65 ArrayDesc arrType arrLen arrOffs arrSize = arrs ! arrIdx
66 offset = fromIntegral (arrOffs + start * fromIntegral n * sizeOfArrayType arrType)
67
68 -- constant generic attribute
69 constAttr -> GLSetVertexAttrib i constAttr
70
71
72lookupOrLookup :: (Ord k, Show k) => String -> Map.Map k a -> Map.Map k a -> k -> a
73lookupOrLookup callsite objUnis topUnis n = Map.findWithDefault (topUni n) n objUnis
74 where
75 topUni n = Map.findWithDefault (error $ "internal error ("++callsite++"): " ++ show n) n topUnis
76
77classifyStreamType :: StreamType -> ( GLint
78 , GLuint -> GLuint -> GLint -> GLenum -> Ptr () -> GLObjectCommand)
79classifyStreamType = \case
80 Attribute_Word -> ( 1 , GLSetVertexAttribIArray )
81 Attribute_V2U -> ( 2 , GLSetVertexAttribIArray )
82 Attribute_V3U -> ( 3 , GLSetVertexAttribIArray )
83 Attribute_V4U -> ( 4 , GLSetVertexAttribIArray )
84 Attribute_Int -> ( 1 , GLSetVertexAttribIArray )
85 Attribute_V2I -> ( 2 , GLSetVertexAttribIArray )
86 Attribute_V3I -> ( 3 , GLSetVertexAttribIArray )
87 Attribute_V4I -> ( 4 , GLSetVertexAttribIArray )
88 Attribute_Float -> ( 1 , GLSetVertexAttribArray )
89 Attribute_V2F -> ( 2 , GLSetVertexAttribArray )
90 Attribute_V3F -> ( 3 , GLSetVertexAttribArray )
91 Attribute_V4F -> ( 4 , GLSetVertexAttribArray )
92 Attribute_M22F -> ( 4 , GLSetVertexAttribArray )
93 Attribute_M23F -> ( 6 , GLSetVertexAttribArray )
94 Attribute_M24F -> ( 8 , GLSetVertexAttribArray )
95 Attribute_M32F -> ( 6 , GLSetVertexAttribArray )
96 Attribute_M33F -> ( 9 , GLSetVertexAttribArray )
97 Attribute_M34F -> ( 12 , GLSetVertexAttribArray )
98 Attribute_M42F -> ( 8 , GLSetVertexAttribArray )
99 Attribute_M43F -> ( 12 , GLSetVertexAttribArray )
100 Attribute_M44F -> ( 16 , GLSetVertexAttribArray )
101
102drawElementsCommand :: GLenum -> IndexStream Buffer -> GLObjectCommand
103drawElementsCommand prim (IndexStream (Buffer arrs bo) arrIdx start idxCount)
104 = GLDrawElements prim (fromIntegral idxCount) idxType bo ptr
105 where
106 ArrayDesc arrType arrLen arrOffs arrSize = arrs ! arrIdx
107 idxType = arrayTypeToGLType arrType
108 ptr = intPtrToPtr $! fromIntegral (arrOffs + start * sizeOfArrayType arrType)
109
110objectDrawStyle :: (GLsizei -> [(GLint,GLsizei)]) -- ^ mask, normally \x -> [(0,x)]
111 -> Object
112 -> Either [(GLint,GLsizei)] (IndexStream Buffer)
113objectDrawStyle streamMask obj = case objIndices obj of
114 Nothing -> Left $ let cnt = head [c | Stream _ _ _ _ c <- Map.elems (objAttributes obj)]
115 in streamMask $ fromIntegral cnt
116 Just idxStream -> Right idxStream
117
118-- backward-compatible non-masking interface.
119createObjectCommands :: Map.Map String (IORef GLint) -> Map.Map String GLUniform -> Object -> GLProgram -> [GLObjectCommand]
120createObjectCommands texUnitMap topUnis obj prg =
121 createObjectCommands_ (objectEnvironment texUnitMap topUnis obj (pure . ((,) 0))) prg
122
123data ObjectEnvironment = ObjectEnvironment
124 { envPrim :: GLenum
125 , envDrawStyle :: Either [(GLint,GLsizei)] (IndexStream Buffer)
126 , tlookup :: String -> IORef GLint
127 , ulookup :: String -> GLUniform
128 , alookup :: String -> Stream Buffer
129 }
130
131objectEnvironment :: Map.Map String (IORef GLint)
132 -> Map.Map String GLUniform
133 -> Object
134 -> (GLsizei -> [(GLint, GLsizei)])
135 -> ObjectEnvironment
136objectEnvironment texUnitMap topUnis obj streamMask = ObjectEnvironment
137 { envPrim = primitiveToGLType $ objPrimitive obj
138 , envDrawStyle = objectDrawStyle streamMask obj
139 , tlookup = \n -> Map.findWithDefault (error $ "missing texture unit: " ++ show n) n texUnitMap
140 , ulookup = lookupOrLookup "missing uniform: " (objUniSetup obj) topUnis
141 , alookup = \n -> Map.findWithDefault (error $ "missing attribute: " ++ n) n $ objAttributes obj
142 }
143
144
145createObjectCommands_ :: ObjectEnvironment -> GLProgram -> [GLObjectCommand]
146createObjectCommands_ ObjectEnvironment{..} prg = concat
147 [ map (setUniformCommand ulookup) $ Map.toList (inputUniforms prg)
148 , map (bindTextureCommand tlookup ulookup) $ toList (inputTextureUniforms prg)
149 , map (setVertexAttribCommmand alookup) $ Map.elems (inputStreams prg)
150 , case envDrawStyle of
151 Left ranges -> map (uncurry $ GLDrawArrays envPrim) ranges
152 Right indexed -> pure $ drawElementsCommand envPrim indexed
153 ]
154
155updateCommands :: GLStorage
156 -> Object
157 -> (GLsizei -> [(GLint,GLsizei)])
158 -> IO Object
159updateCommands input obj mask = do
160 let cmdsRef = objCommands obj :: IORef (V.Vector (V.Vector [GLObjectCommand]))
161 slotIdx = objSlot obj :: Int
162 ppls <- readIORef $ pipelines input
163 cmds <- V.forM (ppls :: V.Vector (Maybe GLRenderer)) $ \mp -> case mp of
164 Nothing -> return V.empty
165 Just p -> do
166 let env = objectEnvironment (glTexUnitMapping p) (uniformSetup input) obj mask
167 Just ic <- readIORef $ glInput p
168 case icSlotMapInputToPipeline ic ! slotIdx of
169 Nothing -> return V.empty -- this slot is not used in that pipeline
170 Just pSlotIdx -> do
171 let emptyV = V.replicate (V.length $ glPrograms p) []
172 return $ emptyV // [(prgIdx,createObjectCommands_ env (glPrograms p ! prgIdx))
173 | prgIdx <- glSlotPrograms p ! pSlotIdx]
174 writeIORef cmdsRef cmds
175 return obj
176
177
178-- TODO: Add flexibility.
179-- Currently this allocates a buffer consisting of a single named vertex attribute that
180-- must be of type V3F.
181uploadDynamicBuffer :: Int -> String -> IO GPUData
182uploadDynamicBuffer sz attrname = do
183 bo <- alloca $! \pbo -> glGenBuffers 1 pbo >> peek pbo
184 glBindBuffer GL_ARRAY_BUFFER bo
185 let bufsize = 3 * fromIntegral sz
186 byteCount = 4 * bufsize
187 glBufferData GL_ARRAY_BUFFER byteCount nullPtr GL_DYNAMIC_DRAW
188 glBindBuffer GL_ARRAY_BUFFER 0
189 let buffer = Buffer (V.singleton $ ArrayDesc ArrFloat (fromIntegral bufsize) 0 (fromIntegral byteCount))
190 bo
191 gd = GPUData PointList (Map.singleton attrname $ Stream Attribute_V3F buffer 0 0 sz) Nothing [buffer]
192 return gd
193
194
195incrementalUpdateBuffer :: MonadIO m => Buffer -> GLintptr -> GLsizeiptr -> Ptr a -> m ()
196incrementalUpdateBuffer b byteoffset bytecount ptr = do
197 glBindBuffer GL_ARRAY_BUFFER (bufGLObj b)
198 glBufferSubData GL_ARRAY_BUFFER byteoffset bytecount ptr
199 glBindBuffer GL_ARRAY_BUFFER 0