diff options
Diffstat (limited to 'Backend/GL/Input.hs')
-rw-r--r-- | Backend/GL/Input.hs | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/Backend/GL/Input.hs b/Backend/GL/Input.hs new file mode 100644 index 0000000..6d4f40f --- /dev/null +++ b/Backend/GL/Input.hs | |||
@@ -0,0 +1,381 @@ | |||
1 | module Backend.GL.Input where | ||
2 | |||
3 | import Control.Applicative | ||
4 | import Control.Exception | ||
5 | import Control.Monad | ||
6 | import Data.ByteString.Char8 (ByteString,pack) | ||
7 | import Data.IORef | ||
8 | import Data.IntMap (IntMap) | ||
9 | import Data.Trie (Trie) | ||
10 | import Data.Trie.Convenience as T | ||
11 | import Data.Vector (Vector,(//),(!)) | ||
12 | import Data.Word | ||
13 | import Foreign | ||
14 | import qualified Data.ByteString.Char8 as SB | ||
15 | import qualified Data.IntMap as IM | ||
16 | import qualified Data.Set as S | ||
17 | import qualified Data.Map as Map | ||
18 | import qualified Data.Trie as T | ||
19 | import qualified Data.Vector as V | ||
20 | import qualified Data.Vector.Algorithms.Intro as I | ||
21 | |||
22 | import Graphics.Rendering.OpenGL.Raw.Core33 | ||
23 | |||
24 | import IR as IR | ||
25 | import Backend.GL.Type as T | ||
26 | import Backend.GL.Util | ||
27 | |||
28 | import qualified IR as IR | ||
29 | |||
30 | schemaFromPipeline :: IR.Pipeline -> PipelineSchema | ||
31 | schemaFromPipeline a = PipelineSchema (T.fromList sl) (foldl T.unionL T.empty ul) | ||
32 | where | ||
33 | (sl,ul) = unzip [((pack n,SlotSchema p (fmap cvt (toTrie s))),toTrie u) | IR.Slot n u s p _ <- V.toList $ IR.slots a] | ||
34 | cvt a = case toStreamType a of | ||
35 | Just v -> v | ||
36 | Nothing -> error "internal error (schemaFromPipeline)" | ||
37 | |||
38 | mkUniform :: [(ByteString,InputType)] -> IO (Trie InputSetter, Trie GLUniform) | ||
39 | mkUniform l = do | ||
40 | unisAndSetters <- forM l $ \(n,t) -> do | ||
41 | (uni, setter) <- mkUniformSetter t | ||
42 | return ((n,uni),(n,setter)) | ||
43 | let (unis,setters) = unzip unisAndSetters | ||
44 | return (T.fromList setters, T.fromList unis) | ||
45 | |||
46 | mkGLPipelineInput :: PipelineSchema -> IO GLPipelineInput | ||
47 | mkGLPipelineInput sch = do | ||
48 | let sm = T.fromList $ zip (T.keys $ T.slots sch) [0..] | ||
49 | len = T.size sm | ||
50 | (setters,unis) <- mkUniform $ T.toList $ uniforms sch | ||
51 | seed <- newIORef 0 | ||
52 | slotV <- V.replicateM len $ newIORef (GLSlot IM.empty V.empty Ordered) | ||
53 | size <- newIORef (0,0) | ||
54 | ppls <- newIORef $ V.singleton Nothing | ||
55 | return $ GLPipelineInput | ||
56 | { schema = sch | ||
57 | , slotMap = sm | ||
58 | , slotVector = slotV | ||
59 | , objSeed = seed | ||
60 | , uniformSetter = setters | ||
61 | , uniformSetup = unis | ||
62 | , screenSize = size | ||
63 | , pipelines = ppls | ||
64 | } | ||
65 | |||
66 | -- object | ||
67 | addObject :: GLPipelineInput -> ByteString -> Primitive -> Maybe (IndexStream Buffer) -> Trie (Stream Buffer) -> [ByteString] -> IO Object | ||
68 | addObject input slotName prim indices attribs uniformNames = do | ||
69 | let sch = schema input | ||
70 | forM_ uniformNames $ \n -> case T.lookup n (uniforms sch) of | ||
71 | Nothing -> throw $ userError $ "Unknown uniform: " ++ show n | ||
72 | _ -> return () | ||
73 | case T.lookup slotName (T.slots sch) of | ||
74 | Nothing -> throw $ userError $ "Unknown slot: " ++ show slotName | ||
75 | Just (SlotSchema sPrim sAttrs) -> do | ||
76 | when (sPrim /= (primitiveToFetchPrimitive prim)) $ throw $ userError $ | ||
77 | "Primitive mismatch for slot (" ++ show slotName ++ ") expected " ++ show sPrim ++ " but got " ++ show prim | ||
78 | let sType = fmap streamToStreamType attribs | ||
79 | when (sType /= sAttrs) $ throw $ userError $ unlines $ | ||
80 | [ "Attribute stream mismatch for slot (" ++ show slotName ++ ") expected " | ||
81 | , show sAttrs | ||
82 | , " but got " | ||
83 | , show sType | ||
84 | ] | ||
85 | |||
86 | let slotIdx = case slotName `T.lookup` slotMap input of | ||
87 | Nothing -> error "internal error (slot index)" | ||
88 | Just i -> i | ||
89 | seed = objSeed input | ||
90 | order <- newIORef 0 | ||
91 | enabled <- newIORef True | ||
92 | index <- readIORef seed | ||
93 | modifyIORef seed (1+) | ||
94 | (setters,unis) <- mkUniform [(n,t) | n <- uniformNames, let Just t = T.lookup n (uniforms sch)] | ||
95 | cmdsRef <- newIORef (V.singleton V.empty) | ||
96 | let obj = Object | ||
97 | { objSlot = slotIdx | ||
98 | , objPrimitive = prim | ||
99 | , objIndices = indices | ||
100 | , objAttributes = attribs | ||
101 | , objUniSetter = setters | ||
102 | , objUniSetup = unis | ||
103 | , objOrder = order | ||
104 | , objEnabled = enabled | ||
105 | , objId = index | ||
106 | , objCommands = cmdsRef | ||
107 | } | ||
108 | |||
109 | modifyIORef (slotVector input ! slotIdx) $ \(GLSlot objs _ _) -> GLSlot (IM.insert index obj objs) V.empty Generate | ||
110 | |||
111 | -- generate GLObjectCommands for the new object | ||
112 | {- | ||
113 | foreach pipeline: | ||
114 | foreach realted program: | ||
115 | generate commands | ||
116 | -} | ||
117 | ppls <- readIORef $ pipelines input | ||
118 | let topUnis = uniformSetup input | ||
119 | cmds <- V.forM ppls $ \mp -> case mp of | ||
120 | Nothing -> return V.empty | ||
121 | Just p -> do | ||
122 | Just ic <- readIORef $ glInput p | ||
123 | case icSlotMapInputToPipeline ic ! slotIdx of | ||
124 | Nothing -> do | ||
125 | putStrLn $ " ** slot is not used!" | ||
126 | return V.empty -- this slot is not used in that pipeline | ||
127 | Just pSlotIdx -> do | ||
128 | putStrLn "slot is used!" | ||
129 | --where | ||
130 | let emptyV = V.replicate (V.length $ glPrograms p) [] | ||
131 | return $ emptyV // [(prgIdx,createObjectCommands (glTexUnitMapping p) topUnis obj (glPrograms p ! prgIdx))| prgIdx <- glSlotPrograms p ! pSlotIdx] | ||
132 | writeIORef cmdsRef cmds | ||
133 | return obj | ||
134 | |||
135 | removeObject :: GLPipelineInput -> Object -> IO () | ||
136 | removeObject p obj = modifyIORef (slotVector p ! objSlot obj) $ \(GLSlot objs _ _) -> GLSlot (IM.delete (objId obj) objs) V.empty Generate | ||
137 | |||
138 | enableObject :: Object -> Bool -> IO () | ||
139 | enableObject obj b = writeIORef (objEnabled obj) b | ||
140 | |||
141 | setObjectOrder :: GLPipelineInput -> Object -> Int -> IO () | ||
142 | setObjectOrder p obj i = do | ||
143 | writeIORef (objOrder obj) i | ||
144 | modifyIORef (slotVector p ! objSlot obj) $ \(GLSlot objs sorted _) -> GLSlot objs sorted Reorder | ||
145 | |||
146 | objectUniformSetter :: Object -> Trie InputSetter | ||
147 | objectUniformSetter = objUniSetter | ||
148 | |||
149 | setScreenSize :: GLPipelineInput -> Word -> Word -> IO () | ||
150 | setScreenSize p w h = writeIORef (screenSize p) (w,h) | ||
151 | |||
152 | sortSlotObjects :: GLPipelineInput -> IO () | ||
153 | sortSlotObjects p = V.forM_ (slotVector p) $ \slotRef -> do | ||
154 | GLSlot objMap sortedV ord <- readIORef slotRef | ||
155 | let cmpFun (a,_) (b,_) = a `compare` b | ||
156 | doSort objs = do | ||
157 | ordObjsM <- V.thaw objs | ||
158 | I.sortBy cmpFun ordObjsM | ||
159 | ordObjs <- V.freeze ordObjsM | ||
160 | writeIORef slotRef (GLSlot objMap ordObjs Ordered) | ||
161 | case ord of | ||
162 | Ordered -> return () | ||
163 | Generate -> do | ||
164 | objs <- V.forM (V.fromList $ IM.elems objMap) $ \obj -> do | ||
165 | ord <- readIORef $ objOrder obj | ||
166 | return (ord,obj) | ||
167 | doSort objs | ||
168 | Reorder -> do | ||
169 | objs <- V.forM sortedV $ \(_,obj) -> do | ||
170 | ord <- readIORef $ objOrder obj | ||
171 | return (ord,obj) | ||
172 | doSort objs | ||
173 | |||
174 | createObjectCommands :: Trie (IORef GLint) -> Trie GLUniform -> Object -> GLProgram -> [GLObjectCommand] | ||
175 | createObjectCommands texUnitMap topUnis obj prg = objUniCmds ++ objStreamCmds ++ [objDrawCmd] | ||
176 | where | ||
177 | -- object draw command | ||
178 | objDrawCmd = case objIndices obj of | ||
179 | Nothing -> GLDrawArrays prim 0 (fromIntegral count) | ||
180 | Just (IndexStream (Buffer arrs bo) arrIdx start idxCount) -> GLDrawElements prim (fromIntegral idxCount) idxType bo ptr | ||
181 | where | ||
182 | ArrayDesc arrType arrLen arrOffs arrSize = arrs ! arrIdx | ||
183 | idxType = arrayTypeToGLType arrType | ||
184 | ptr = intPtrToPtr $! fromIntegral (arrOffs + start * sizeOfArrayType arrType) | ||
185 | where | ||
186 | objAttrs = objAttributes obj | ||
187 | prim = primitiveToGLType $ objPrimitive obj | ||
188 | count = head [c | Stream _ _ _ _ c <- T.elems objAttrs] | ||
189 | |||
190 | -- object uniform commands | ||
191 | -- texture slot setup commands | ||
192 | objUniCmds = uniCmds ++ texCmds | ||
193 | where | ||
194 | uniCmds = [GLSetUniform i u | (n,i) <- uniMap, let u = T.lookupWithDefault (topUni n) n objUnis] | ||
195 | uniMap = T.toList $ inputUniforms prg | ||
196 | topUni n = T.lookupWithDefault (error "internal error (createObjectCommands)!") n topUnis | ||
197 | objUnis = objUniSetup obj | ||
198 | texUnis = S.toList $ inputTextureUniforms prg | ||
199 | texCmds = [ GLBindTexture (inputTypeToTextureTarget $ uniInputType u) texUnit u | ||
200 | | n <- texUnis | ||
201 | , let u = T.lookupWithDefault (topUni n) n objUnis | ||
202 | , let texUnit = T.lookupWithDefault (error "internal error (createObjectCommands - Texture Unit)") n texUnitMap | ||
203 | ] | ||
204 | uniInputType (GLUniform ty _) = ty | ||
205 | |||
206 | -- object attribute stream commands | ||
207 | objStreamCmds = [attrCmd i s | (i,name) <- T.elems attrMap, let Just s = T.lookup name objAttrs] | ||
208 | where | ||
209 | attrMap = inputStreams prg | ||
210 | objAttrs = objAttributes obj | ||
211 | attrCmd i s = case s of | ||
212 | Stream ty (Buffer arrs bo) arrIdx start len -> case ty of | ||
213 | TWord -> setIntAttrib 1 | ||
214 | TV2U -> setIntAttrib 2 | ||
215 | TV3U -> setIntAttrib 3 | ||
216 | TV4U -> setIntAttrib 4 | ||
217 | TInt -> setIntAttrib 1 | ||
218 | TV2I -> setIntAttrib 2 | ||
219 | TV3I -> setIntAttrib 3 | ||
220 | TV4I -> setIntAttrib 4 | ||
221 | TFloat -> setFloatAttrib 1 | ||
222 | TV2F -> setFloatAttrib 2 | ||
223 | TV3F -> setFloatAttrib 3 | ||
224 | TV4F -> setFloatAttrib 4 | ||
225 | TM22F -> setFloatAttrib 4 | ||
226 | TM23F -> setFloatAttrib 6 | ||
227 | TM24F -> setFloatAttrib 8 | ||
228 | TM32F -> setFloatAttrib 6 | ||
229 | TM33F -> setFloatAttrib 9 | ||
230 | TM34F -> setFloatAttrib 12 | ||
231 | TM42F -> setFloatAttrib 8 | ||
232 | TM43F -> setFloatAttrib 12 | ||
233 | TM44F -> setFloatAttrib 16 | ||
234 | where | ||
235 | setFloatAttrib n = GLSetVertexAttribArray i bo n glType (ptr n) | ||
236 | setIntAttrib n = GLSetVertexAttribIArray i bo n glType (ptr n) | ||
237 | ArrayDesc arrType arrLen arrOffs arrSize = arrs ! arrIdx | ||
238 | glType = arrayTypeToGLType arrType | ||
239 | ptr compCnt = intPtrToPtr $! fromIntegral (arrOffs + start * fromIntegral compCnt * sizeOfArrayType arrType) | ||
240 | |||
241 | -- constant generic attribute | ||
242 | constAttr -> GLSetVertexAttrib i constAttr | ||
243 | |||
244 | nullSetter :: ByteString -> String -> a -> IO () | ||
245 | nullSetter n t _ = return () -- Prelude.putStrLn $ "WARNING: unknown uniform: " ++ SB.unpack n ++ " :: " ++ t | ||
246 | |||
247 | uniformBool :: ByteString -> Trie InputSetter -> SetterFun Bool | ||
248 | uniformV2B :: ByteString -> Trie InputSetter -> SetterFun V2B | ||
249 | uniformV3B :: ByteString -> Trie InputSetter -> SetterFun V3B | ||
250 | uniformV4B :: ByteString -> Trie InputSetter -> SetterFun V4B | ||
251 | |||
252 | uniformWord :: ByteString -> Trie InputSetter -> SetterFun Word32 | ||
253 | uniformV2U :: ByteString -> Trie InputSetter -> SetterFun V2U | ||
254 | uniformV3U :: ByteString -> Trie InputSetter -> SetterFun V3U | ||
255 | uniformV4U :: ByteString -> Trie InputSetter -> SetterFun V4U | ||
256 | |||
257 | uniformInt :: ByteString -> Trie InputSetter -> SetterFun Int32 | ||
258 | uniformV2I :: ByteString -> Trie InputSetter -> SetterFun V2I | ||
259 | uniformV3I :: ByteString -> Trie InputSetter -> SetterFun V3I | ||
260 | uniformV4I :: ByteString -> Trie InputSetter -> SetterFun V4I | ||
261 | |||
262 | uniformFloat :: ByteString -> Trie InputSetter -> SetterFun Float | ||
263 | uniformV2F :: ByteString -> Trie InputSetter -> SetterFun V2F | ||
264 | uniformV3F :: ByteString -> Trie InputSetter -> SetterFun V3F | ||
265 | uniformV4F :: ByteString -> Trie InputSetter -> SetterFun V4F | ||
266 | |||
267 | uniformM22F :: ByteString -> Trie InputSetter -> SetterFun M22F | ||
268 | uniformM23F :: ByteString -> Trie InputSetter -> SetterFun M23F | ||
269 | uniformM24F :: ByteString -> Trie InputSetter -> SetterFun M24F | ||
270 | uniformM32F :: ByteString -> Trie InputSetter -> SetterFun M32F | ||
271 | uniformM33F :: ByteString -> Trie InputSetter -> SetterFun M33F | ||
272 | uniformM34F :: ByteString -> Trie InputSetter -> SetterFun M34F | ||
273 | uniformM42F :: ByteString -> Trie InputSetter -> SetterFun M42F | ||
274 | uniformM43F :: ByteString -> Trie InputSetter -> SetterFun M43F | ||
275 | uniformM44F :: ByteString -> Trie InputSetter -> SetterFun M44F | ||
276 | |||
277 | uniformFTexture2D :: ByteString -> Trie InputSetter -> SetterFun TextureData | ||
278 | |||
279 | uniformBool n is = case T.lookup n is of | ||
280 | Just (SBool fun) -> fun | ||
281 | _ -> nullSetter n "Bool" | ||
282 | |||
283 | uniformV2B n is = case T.lookup n is of | ||
284 | Just (SV2B fun) -> fun | ||
285 | _ -> nullSetter n "V2B" | ||
286 | |||
287 | uniformV3B n is = case T.lookup n is of | ||
288 | Just (SV3B fun) -> fun | ||
289 | _ -> nullSetter n "V3B" | ||
290 | |||
291 | uniformV4B n is = case T.lookup n is of | ||
292 | Just (SV4B fun) -> fun | ||
293 | _ -> nullSetter n "V4B" | ||
294 | |||
295 | uniformWord n is = case T.lookup n is of | ||
296 | Just (SWord fun) -> fun | ||
297 | _ -> nullSetter n "Word" | ||
298 | |||
299 | uniformV2U n is = case T.lookup n is of | ||
300 | Just (SV2U fun) -> fun | ||
301 | _ -> nullSetter n "V2U" | ||
302 | |||
303 | uniformV3U n is = case T.lookup n is of | ||
304 | Just (SV3U fun) -> fun | ||
305 | _ -> nullSetter n "V3U" | ||
306 | |||
307 | uniformV4U n is = case T.lookup n is of | ||
308 | Just (SV4U fun) -> fun | ||
309 | _ -> nullSetter n "V4U" | ||
310 | |||
311 | uniformInt n is = case T.lookup n is of | ||
312 | Just (SInt fun) -> fun | ||
313 | _ -> nullSetter n "Int" | ||
314 | |||
315 | uniformV2I n is = case T.lookup n is of | ||
316 | Just (SV2I fun) -> fun | ||
317 | _ -> nullSetter n "V2I" | ||
318 | |||
319 | uniformV3I n is = case T.lookup n is of | ||
320 | Just (SV3I fun) -> fun | ||
321 | _ -> nullSetter n "V3I" | ||
322 | |||
323 | uniformV4I n is = case T.lookup n is of | ||
324 | Just (SV4I fun) -> fun | ||
325 | _ -> nullSetter n "V4I" | ||
326 | |||
327 | uniformFloat n is = case T.lookup n is of | ||
328 | Just (SFloat fun) -> fun | ||
329 | _ -> nullSetter n "Float" | ||
330 | |||
331 | uniformV2F n is = case T.lookup n is of | ||
332 | Just (SV2F fun) -> fun | ||
333 | _ -> nullSetter n "V2F" | ||
334 | |||
335 | uniformV3F n is = case T.lookup n is of | ||
336 | Just (SV3F fun) -> fun | ||
337 | _ -> nullSetter n "V3F" | ||
338 | |||
339 | uniformV4F n is = case T.lookup n is of | ||
340 | Just (SV4F fun) -> fun | ||
341 | _ -> nullSetter n "V4F" | ||
342 | |||
343 | uniformM22F n is = case T.lookup n is of | ||
344 | Just (SM22F fun) -> fun | ||
345 | _ -> nullSetter n "M22F" | ||
346 | |||
347 | uniformM23F n is = case T.lookup n is of | ||
348 | Just (SM23F fun) -> fun | ||
349 | _ -> nullSetter n "M23F" | ||
350 | |||
351 | uniformM24F n is = case T.lookup n is of | ||
352 | Just (SM24F fun) -> fun | ||
353 | _ -> nullSetter n "M24F" | ||
354 | |||
355 | uniformM32F n is = case T.lookup n is of | ||
356 | Just (SM32F fun) -> fun | ||
357 | _ -> nullSetter n "M32F" | ||
358 | |||
359 | uniformM33F n is = case T.lookup n is of | ||
360 | Just (SM33F fun) -> fun | ||
361 | _ -> nullSetter n "M33F" | ||
362 | |||
363 | uniformM34F n is = case T.lookup n is of | ||
364 | Just (SM34F fun) -> fun | ||
365 | _ -> nullSetter n "M34F" | ||
366 | |||
367 | uniformM42F n is = case T.lookup n is of | ||
368 | Just (SM42F fun) -> fun | ||
369 | _ -> nullSetter n "M42F" | ||
370 | |||
371 | uniformM43F n is = case T.lookup n is of | ||
372 | Just (SM43F fun) -> fun | ||
373 | _ -> nullSetter n "M43F" | ||
374 | |||
375 | uniformM44F n is = case T.lookup n is of | ||
376 | Just (SM44F fun) -> fun | ||
377 | _ -> nullSetter n "M44F" | ||
378 | |||
379 | uniformFTexture2D n is = case T.lookup n is of | ||
380 | Just (SFTexture2D fun) -> fun | ||
381 | _ -> nullSetter n "FTexture2D" | ||