diff options
author | Joe Crayne <joe@jerkface.net> | 2019-05-18 21:15:21 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-05-18 21:15:21 -0400 |
commit | fbb54c463cfd5171a582bb3d9668321d9d450f87 (patch) | |
tree | ef429d2c02f92f957cd435f83f21bbf8c2bcbca0 /MaskableStream.hs | |
parent | 5354bd2aef9607faecec1e97393b05f11e8ed2fa (diff) |
Factored lambdacube patch module from ring buffer.
Diffstat (limited to 'MaskableStream.hs')
-rw-r--r-- | MaskableStream.hs | 199 |
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 | |||
5 | module MaskableStream where | ||
6 | |||
7 | import Control.Monad | ||
8 | import Control.Monad.IO.Class | ||
9 | import Data.Foldable | ||
10 | import Data.Int | ||
11 | import Data.IORef | ||
12 | import Data.Maybe | ||
13 | import Data.Word | ||
14 | import qualified Data.Map.Strict as Map | ||
15 | import qualified Data.Vector as V | ||
16 | ;import Data.Vector as V ((!),(//)) | ||
17 | import Foreign.C.Types (CPtrdiff) | ||
18 | import Foreign.Marshal | ||
19 | import Foreign.Ptr | ||
20 | import Foreign.Storable | ||
21 | |||
22 | import LambdaCube.GL as LC | ||
23 | import LambdaCube.GL.Data -- (uploadCubeMapToGPU,uploadTextureBufferToGPU,updateTextureBuffer) | ||
24 | import LambdaCube.GL.Mesh as LC | ||
25 | import LambdaCube.GL.Type | ||
26 | import LambdaCube.IR as LC | ||
27 | import LambdaCube.GL.Util | ||
28 | import LambdaCube.GL.Input.Type | ||
29 | import LambdaCube.GL.Input hiding (createObjectCommands) | ||
30 | |||
31 | import Graphics.GL.Core33 | ||
32 | |||
33 | |||
34 | -- based on addMeshToObjectArray | ||
35 | addToObjectArray :: GLStorage | ||
36 | -> String -- ^ Slot name for a PrimitiveStream. | ||
37 | -> [String] -- ^ Uniform names. IORefs will be put in 'objUniSetup'. | ||
38 | -> GPUData | ||
39 | -> IO Object | ||
40 | addToObjectArray 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 | |||
45 | setUniformCommand :: (String -> GLUniform) | ||
46 | -> (String,GLint) | ||
47 | -> GLObjectCommand | ||
48 | setUniformCommand ulookup (n,i) = GLSetUniform i (ulookup n) | ||
49 | |||
50 | bindTextureCommand :: (String -> IORef GLint) | ||
51 | -> (String -> GLUniform) | ||
52 | -> String | ||
53 | -> GLObjectCommand | ||
54 | bindTextureCommand 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 | |||
60 | setVertexAttribCommmand :: (t -> Stream Buffer) -> (GLuint, t) -> GLObjectCommand | ||
61 | setVertexAttribCommmand 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 | |||
72 | lookupOrLookup :: (Ord k, Show k) => String -> Map.Map k a -> Map.Map k a -> k -> a | ||
73 | lookupOrLookup 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 | |||
77 | classifyStreamType :: StreamType -> ( GLint | ||
78 | , GLuint -> GLuint -> GLint -> GLenum -> Ptr () -> GLObjectCommand) | ||
79 | classifyStreamType = \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 | |||
102 | drawElementsCommand :: GLenum -> IndexStream Buffer -> GLObjectCommand | ||
103 | drawElementsCommand 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 | |||
110 | objectDrawStyle :: (GLsizei -> [(GLint,GLsizei)]) -- ^ mask, normally \x -> [(0,x)] | ||
111 | -> Object | ||
112 | -> Either [(GLint,GLsizei)] (IndexStream Buffer) | ||
113 | objectDrawStyle 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. | ||
119 | createObjectCommands :: Map.Map String (IORef GLint) -> Map.Map String GLUniform -> Object -> GLProgram -> [GLObjectCommand] | ||
120 | createObjectCommands texUnitMap topUnis obj prg = | ||
121 | createObjectCommands_ (objectEnvironment texUnitMap topUnis obj (pure . ((,) 0))) prg | ||
122 | |||
123 | data 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 | |||
131 | objectEnvironment :: Map.Map String (IORef GLint) | ||
132 | -> Map.Map String GLUniform | ||
133 | -> Object | ||
134 | -> (GLsizei -> [(GLint, GLsizei)]) | ||
135 | -> ObjectEnvironment | ||
136 | objectEnvironment 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 | |||
145 | createObjectCommands_ :: ObjectEnvironment -> GLProgram -> [GLObjectCommand] | ||
146 | createObjectCommands_ 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 | |||
155 | updateCommands :: GLStorage | ||
156 | -> Object | ||
157 | -> (GLsizei -> [(GLint,GLsizei)]) | ||
158 | -> IO Object | ||
159 | updateCommands 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. | ||
181 | uploadDynamicBuffer :: Int -> String -> IO GPUData | ||
182 | uploadDynamicBuffer 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 | |||
195 | incrementalUpdateBuffer :: MonadIO m => Buffer -> GLintptr -> GLsizeiptr -> Ptr a -> m () | ||
196 | incrementalUpdateBuffer 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 | ||