{-# LANGUAGE FlexibleContexts,TypeSynonymInstances,LiberalTypeSynonyms,TypeOperators,GADTs,RelaxedPolyRec,ConstrainedClassMethods,UndecidableInstances,IncoherentInstances,NoMonomorphismRestriction,RankNTypes,PolymorphicComponents #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} module Graphics.OpenGLES.Buffer ( -- * Buffer -- ** Constructing Mutable Buffers Buffer, GLArray, MakeArray(..), glLoad, glReload, glRead, glModify, glMap, -- ** Updating Mutable Buffers unsafeWithLen, BufferUsage, app2gl, app2glDyn, app2glStream, gl2app, gl2appDyn, gl2appStream, gl2gl, gl2glDyn, gl2glStream, -- ** Raw Buffer Operations bindBuffer, bindBufferRange, bindBufferBase, bufferData, bufferSubData, -- | /3+ | GL_OES_mapbuffer/ glUnmapBufferOES unmapBuffer, -- | /GL_OES_mapbuffer/ -- (*GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); -- define GL_WRITE_ONLY_OES 0x88B9 -- | /3+ | GL_EXT_map_buffer_range/ -- glMapBufferRangeEXT glFlushMappedBufferRangeEXT mapBufferRange, flashMappedBufferRange, map_read_bit, map_write_bit, map_invalidate_range_bit, map_invalidate_buffer_bit, map_flush_explicit_bit, map_unsynchronized_bit, -- | /3+ | GL_NV_copy_buffer/ glCopyBufferSubDataNV copyBufferSubData, BufferSlot, array_buffer, element_array_buffer, -- | /ES 3+/ pixel_pack_buffer, pixel_unpack_buffer, uniform_buffer, transform_feedback_buffer, -- | /3+ or GL_NV_copy_buffer/ copy_read_buffer, copy_write_buffer ) where import Control.Applicative import qualified Data.ByteString as B import qualified Data.ByteString.Internal as B import Data.IORef import qualified Data.Vector.Storable as V import Graphics.OpenGLES.Base import Graphics.OpenGLES.Caps import Graphics.OpenGLES.Internal import Graphics.OpenGLES.Types import Foreign -- ** Constructing Mutable Buffers class Storable (Element a) => MakeArray a where type Element a :: * makeAref :: a -> GL (Either (GLArray (Element a)) Int) makeWriter :: a -> (Ptr (Element a) -> GL (), Int) newtype Zeros a = Zeros { unZeros :: Int } class Storable a => MemZero a where memZero :: a -- zero in C lang instance MemZero Int where memZero = 0 instance MemZero Bool where memZero = False --etc instance MemZero a => MakeArray (Zeros a) where type Element (Zeros a) = a makeAref = return . Right . unZeros makeWriter (Zeros len) = (\ptr -> B.memset (castPtr ptr) 0 (fromIntegral $ len * sizeOf (undefined :: a)) >> return (), len) --instance Storable b => MakeArray Int b where -- makeAref = return . Right -- makeWriter len = (\ptr -> B.memset (castPtr ptr) 0 -- (fromIntegral $ len * sizeOf (undefined :: b)) -- >> return (), len) newtype CycleTakeN a = CycleTakeN { unCycleTakeN :: ([a], Int) } instance Storable a => MakeArray (CycleTakeN a) where type Element (CycleTakeN a) = a makeAref (CycleTakeN (xs, len)) = return . Left $ V.fromListN len (cycle xs) makeWriter (CycleTakeN (xs, len)) = (\ptr -> pokeArray ptr xs, len) --instance Storable a => MakeArray ([a], Int) a where -- makeAref (xs, len) = return . Left $ V.fromListN len (cycle xs) -- makeWriter (xs, len) = (\ptr -> pokeArray ptr xs, len) instance Storable a => MakeArray [a] where type Element [a] = a makeAref xs = return . Left $ V.fromList xs makeWriter xs = (\ptr -> pokeArray ptr xs, length xs) --instance Storable a => MakeArray [a] a where -- makeAref xs = return . Left $ V.fromList xs -- makeWriter xs = (\ptr -> pokeArray ptr xs, length xs) newtype FromBS a = FromBS { unFromBS :: B.ByteString } instance Storable a => MakeArray (FromBS a) where type Element (FromBS a) = a makeAref (FromBS bs@(B.PS foreignPtr offset len)) = do let fp | offset == 0 = foreignPtr | otherwise = case B.copy bs of (B.PS f _ _) -> f let elems = (len `div` sizeOf (undefined :: a)) let vec = V.unsafeFromForeignPtr0 (castForeignPtr fp) elems return (Left vec) makeWriter (FromBS (B.PS fp offset len)) = (\dst -> withForeignPtr fp $ \src -> B.memcpy (castPtr dst) (advancePtr (castPtr src) offset) len , len `div` sizeOf (undefined :: a)) --instance Storable b => MakeArray B.ByteString b where -- makeAref bs@(B.PS foreignPtr offset len) = do -- let fp | offset == 0 = foreignPtr -- | otherwise = case B.copy bs of (B.PS f _ _) -> f -- let elems = (len `div` sizeOf (undefined :: b)) -- let vec = V.unsafeFromForeignPtr0 (castForeignPtr fp) elems -- return (Left vec) -- makeWriter (B.PS fp offset len) = (\dst -> -- withForeignPtr fp $ \src -> -- B.memcpy (castPtr dst) (advancePtr (castPtr src) offset) len -- , len `div` sizeOf (undefined :: b)) instance Storable a => MakeArray (GLArray a) where type Element (GLArray a) = a makeAref = return . Left makeWriter vec = (\dst -> withForeignPtr fp $ \src -> B.memcpy (castPtr dst) (castPtr src) (len * sizeOf (undefined :: a)) , len) where (fp, len) = V.unsafeToForeignPtr0 vec --instance Storable a => MakeArray (GLArray a) a where -- makeAref = return . Left -- makeWriter vec = -- (\dst -> withForeignPtr fp $ \src -> -- B.memcpy (castPtr dst) (castPtr src) -- (len * sizeOf (undefined :: a)) -- , len) -- where (fp, len) = V.unsafeToForeignPtr0 vec --instance MakeArray (Buffer a) a where -- makeAref (Buffer aref glo) = return . Left =<< go =<< readIORef aref -- where -- go (Left) -- go (Right) -- | -- Create and initialize a 'Buffer' storage on GPU working memory. -- -- - Int → /O(1)/ -- New Buffer with specified number of elements initialized to zeros. -- - ([a], Int) → /O(n)/ -- New Buffer made of given list upto n th element. -- - [a] → /O(n)/ -- New Buffer made of given list. Same as (xs, length xs) -- - 'ByteString' → /head O(1) otherwise O(n)/ -- New Buffer from 'ByteString'. Might be copied when necessary. -- - 'GLArray' → __Unsafe__ /O(1)/ -- Use passed 'StorableArray' as client-side Buffer. -- -- > glLoad app2gl (10::Int) :: GL (Buffer Vec4) -- > glLoad app2gl ([V2 1 1],4::Int) :: GL (Buffer Vec2) -- > glLoad app2gl uv :: GL (Buffer (V2 Word8)) -- > glLoad app2gl bs :: GL (Buffer Float) -- > glLoad app2gl (model :: GLArray Model) :: GL (Buffer Model) glLoad :: forall a. MakeArray a => BufferUsage -> a -> GL (Buffer (Element a)) glLoad usage src = do aref <- newIORef =<< makeAref src Buffer aref <$> newBuffer (do array <- readIORef aref case array of Left vector -> unsafeWithLen vector (bufferData array_buffer usage) Right elems -> bufferData array_buffer usage (elems * unit) nullPtr void $ showError "glBufferData" ) where unit = sizeOf (undefined :: Element a) -- TODO BufferArchive newBuffer init = newGLO glGenBuffers glDeleteBuffers (\i -> glBindBuffer 0x8892 i >> init) -- GL_ARRAY_BUFFER newVector :: Storable a => Int -> Int -> IO (GLArray a) newVector elems unit = do let B.PS fp _ _ = B.replicate (elems * unit) 0 return $ V.unsafeFromForeignPtr0 (castForeignPtr fp) elems glReload :: forall a. MakeArray a => Buffer (Element a) -> Int -- ^ offset index -> a -- ^ values -> GL () glReload buf@(Buffer aref glo) offsetIx src = do bindBuffer array_buffer buf aref' <- readIORef aref let unit = sizeOf (undefined :: Element a) let (fillSubArray, size') = makeWriter src let size = size' * unit if hasES3 then do ptr <- mapBufferRange array_buffer (offsetIx * unit) size (map_write_bit + map_invalidate_range_bit + map_unsynchronized_bit) showError "glMapBufferRange" fillSubArray ptr unmapBuffer array_buffer showError "glUnmapBuffer" case aref' of Left vec -> writeIORef aref (Right (V.length vec * unit)) else do vector <- case aref' of Left array -> return array Right elems -> newVector elems unit V.unsafeWith vector $ \p -> do let ptr = advancePtr p (offsetIx * unit) fillSubArray ptr bufferSubData array_buffer (offsetIx * unit) size ptr showError "glBufferSubData" writeIORef aref (Left vector) -- | glRead :: forall a. Storable a => Buffer a -> Int -- ^ offset index -> Int -- ^ length -> GL (GLArray a) glRead buf@(Buffer aref glo) offsetIx len = do bindBuffer array_buffer buf array <- readIORef aref case array of Left vector -> return vector -- XXX Make it partial Right elems -> do vec <- newVector (min len (elems - offsetIx)) unit if hasES3 then do src <- mapBufferRange array_buffer (offsetIx * unit) (len * unit) (map_read_bit {- + map_unsynchronized_bit-}) V.unsafeWith vec $ \dst -> B.memcpy (castPtr dst) src (len * unit) unmapBuffer array_buffer writeIORef aref (Left vec) -- backup return vec else return vec where unit = sizeOf (undefined :: a) glModify :: forall a. Storable a => Buffer a -> Int -- ^ offset index -> Int -- ^ length -> (V.Vector a -> GL ()) -- ^ XXX -> GL () glModify buf@(Buffer aref glo) offsetIx len f = do bindBuffer array_buffer buf if hasES3 then do a <- readIORef aref let elems = case a of Right elems -> elems Left vector -> V.length vector ptr <- mapBufferRange array_buffer 0 (len * unit) (map_read_bit + map_write_bit {- + map_unsynchronized_bit-}) fp <- newForeignPtr_ ptr f $ V.unsafeFromForeignPtr0 fp elems unmapBuffer array_buffer writeIORef aref (Right elems) else do a <- readIORef aref case a of Left vector -> do f vector unsafeWithLen vector (bufferSubData array_buffer 0) Right elems -> do vec <- newVector elems unit f vec unsafeWithLen vec (bufferSubData array_buffer 0) where unit = sizeOf (undefined :: a) glMap :: Storable a => (a -> GL a) -> Buffer a -> Int -- ^ offset index -> Int -- ^ length -> GL () glMap f buffer off len = glModify buffer off len (V.mapM_ f) -- ** Updating Mutable Buffers unsafeWithLen :: forall a b. Storable a => GLArray a -> (Int -> Ptr a -> IO b) -> IO b unsafeWithLen vector f = do let (fp, len) = V.unsafeToForeignPtr0 vector let size = len * sizeOf (undefined :: a) withForeignPtr fp (f size) -- hasMapBufferRange = hasES3 -- GL_NV_map_buffer_range 5devices 2% -- GL_EXT_map_buffer_range 2devices 1% -- Performance hint http://www.opentk.com/node/1930 -- ** Buffer Slots -- | STATIC_DRAW (Default) app2gl = BufferUsage 0x88E4 -- | DYNAMIC_DRAW app2glDyn = BufferUsage 0x88E8 -- | STREAM_DRAW app2glStream = BufferUsage 0x88E0 -- *** GL ES 3+ -- | STATIC_READ gl2app = BufferUsage 0x88E5 -- | DYNAMIC_READ gl2appDyn = BufferUsage 0x88E9 -- | STREAM_READ gl2appStream = BufferUsage 0x88E1 -- | STATIC_COPY gl2gl = BufferUsage 0x88E6 -- | DYNAMIC_COPY gl2glDyn = BufferUsage 0x88EA -- | STREAM_COPY gl2glStream = BufferUsage 0x88E2 -- ** Raw Buffer Operations bindBuffer :: BufferSlot -> Buffer a -> GL () bindBuffer (BufferSlot target) (Buffer _ glo) = glBindBuffer target =<< getObjId glo bindBufferRange :: BufferSlot -> GLuint -> Buffer a -> Int -> Int -> GL () bindBufferRange (BufferSlot t) index (Buffer _ glo) offset size = do buf <- getObjId glo glBindBufferRange t index buf offset size bindBufferBase :: BufferSlot -> GLuint -> Buffer a -> GL () bindBufferBase (BufferSlot t) index (Buffer _ glo) = do glBindBufferBase t index =<< getObjId glo bufferData :: BufferSlot -> BufferUsage -> Int -> Ptr a -> GL () bufferData (BufferSlot target) (BufferUsage usage) size ptr = glBufferData target size (castPtr ptr) usage bufferSubData :: BufferSlot -> Int -> Int -> Ptr a -> GL () bufferSubData (BufferSlot target) offset size ptr = glBufferSubData target offset size (castPtr ptr) -- *** 3+ | GL_OES_mapbuffer glUnmapBufferOES unmapBuffer :: BufferSlot -> GL Bool unmapBuffer (BufferSlot target) = glUnmapBuffer target >>= return . (/= 0) -- *** GL_OES_mapbuffer -- (*GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); -- define GL_WRITE_ONLY_OES 0x88B9 -- *** 3+ | GL_EXT_map_buffer_range -- glMapBufferRangeEXT glFlushMappedBufferRangeEXT mapBufferRange :: BufferSlot -> Int -> Int -> GLbitfield -> GL (Ptr a) mapBufferRange (BufferSlot target) offset size access = fmap castPtr $ glMapBufferRange target offset size access flashMappedBufferRange :: BufferSlot -> Int -> Int -> GL () flashMappedBufferRange (BufferSlot target) offset size = glFlushMappedBufferRange target offset size map_read_bit = 1 :: GLbitfield map_write_bit = 2 :: GLbitfield map_invalidate_range_bit = 4 :: GLbitfield map_invalidate_buffer_bit = 8 :: GLbitfield map_flush_explicit_bit = 16 :: GLbitfield map_unsynchronized_bit = 32 :: GLbitfield -- *** 3+ | GL_NV_copy_buffer glCopyBufferSubDataNV copyBufferSubData :: BufferSlot -> BufferSlot -> Int -> Int -> Int -> GL () copyBufferSubData (BufferSlot read) (BufferSlot write) roffset woffset size = glCopyBufferSubData read write roffset woffset size array_buffer = BufferSlot 0x8892 element_array_buffer = BufferSlot 0x8893 -- *** 3+ pixel_pack_buffer = BufferSlot 0x88EB pixel_unpack_buffer = BufferSlot 0x88EC uniform_buffer = BufferSlot 0x8A11 transform_feedback_buffer = BufferSlot 0x8C8E -- *** 3+ | GL_NV_copy_buffer copy_read_buffer = BufferSlot 0x8F36 copy_write_buffer = BufferSlot 0x8F37