News aggregator

Dimitri Sabadie: Luminance – Vertex Arrays

Planet Haskell - Mon, 08/10/2015 - 4:24am

I’ve been up working on vertex arrays in my work-in-progress graphics framework, luminance, for several days. I’m a bit slow, because I’ve been through a very hard breakup and have been struggling to recover and focus. But here I am!

So, what’s new?

OpenGL allows programmers to send vertices to the GPU through what is called a vertex array. Vertex specification is performed through several functions, operating on several objects. You need, for instance, a vertex buffer object, an index buffer object and a vertex array object. The vertex buffer stores the vertices data.


For instance, you could imagine a teapot as a set of vertices. Those vertices have several attributes. We could use, for instance, a position, a normal and a bone index. The vertex buffer would be responsible of storing those positions, normals and bone indices. There’re two ways to store them:

  1. interleaved arrays ;
  2. deinterleaved arrays.

I’ll explain those later on. The index buffer stores integral numbers – mainly set to unsigned int – that index the vertices, so that we can connect them and create lines, triangles or more complex shapes.

Finally, the vertex array object is a state object that stores links to the two buffers and makes a connection between pointers in the buffer and attribute indices. Once everything is set up, we might only use the vertex array object. The exception is when we need to change the geometry of an object. We need to access the vertex buffer and the index buffer and upload new data. However, for now, that feature is disabled so that the buffers are not exposed to the programmer. If people think that feature should be implemented, I’ll create specialized code for that very purpose.

Interleaved and deinterleaved arrays

Interleaved arrays might be the most simple to picture, because you use such arrays every day when programming. Let’s imagine you have the following type in Haskell:

data Vertex = Vertex {
vertPos :: X
, vertNor :: Y
, vertBoneID :: Z
} deriving (Eq,Show)

Now, the teapot would have several vertices. Approximately, let’s state the teapot has five vertices – yeah, ugly teapot. We can represent such vertices in an interleaved array by simply recording them in a list or an array:


As you can see, the attributes are interleaved in memory, and the whole pattern is cycling. That’s the common way to represent an array of struct in a lot of languages, and it’s very natural for a machine to do things like that.

The deinterleaved version is:


As you can see, with deinterleaved arrays, all attributes are extracted and grouped. If you want to access the third vertex, you need to read the third X, the third Y and the third Z.

Both the methods have advantages and drawbacks. The cool thing about deinterleaved arrays is that we can copy huge regions of typed memory at once whilst we cannot with interleaved arrays. However, interleaved arrays store continuous structures, so writing and reading a structure back might be faster.

An important point to keep in mind: because we plan to pass those arrays to OpenGL, there’s no alignment restriction on the structure. That is, everything is packed, and we’ll have to pass extra information to OpenGL to tell it how to advance in memory to correctly build vertices back.

Generalized tuple

I think I haven’t told you yet. I have a cool type in luminance: the (:.) type. No, you don’t have to know how to pronounce that. I like to call it the gtuple type, because it’s a generalized tuple. You can encode (a,b), (a,b,c) and all kind of tuples with (:.). You can even encode single-typed infinite tuple! – a very special kind of list, indeed.

data a :. b = a :. b

infixr 6 :.

-- a :. b is isomorphic to (a,b)
-- a :. b :. c is isomorphic to (a,b,c)

newtype Fix f = Fix (f (Fix f)) -- from Control.Monad.Fix
type Inf a = Fix ((:.) a) -- infinite tuple!

Pretty simple, but way more powerful than the regular, monomorphic tuples. As you can see, (:.) is a right-associative. That means that a :. b :. c = a :. (b :. c).

That type will be heavily used in luminance, thus you should get your fet wet with it. There’s actually nothing much to know about it. It’s a Functor. I might add other features to it later on.

The Storable trick

The cool thing about (:.) is that we can provide a Storable instance for packed memory, as OpenGL requires it. Currently, the Storable instance is implemented like this:

instance (Storable a,Storable b) => Storable (a :. b) where
sizeOf (a :. b) = sizeOf a + sizeOf b
alignment _ = 1 -- packed data
peek p = do
a <- peek $ castPtr p
b <- peek . castPtr $ p `plusPtr` sizeOf (undefined :: a)
pure $ a :. b
poke p (a :. b) = do
poke (castPtr p) a
poke (castPtr $ p `plusPtr` sizeOf (undefined :: a)) b

As you can see, the alignment is set to 1 to express the fact the memory is packed. The peek and poke functions use the size of the head of the tuple to advance the pointer so that we effectively write the whole tuple in packed memory.

Then, let’s rewrite our Vertex type in terms of (:.) to see how it’s going on:

type Vertex = X :. Y :. Z

If X, Y and Z are in Storable, we can directly poke one of our Vertex into a luminance buffer! That is, directly into the GPU buffer!

Keep in mind that the Storable instance implements packed-memory uploads and reads, and won’t work with special kinds of buffers, like shader storage ones, which require specific memory alignment. To cover them, I’ll create specific typeclasses instances. No worries.

Creating a vertex array

Creating a vertex array is done through the function createVertexArray. I might change the name of that object – it’s ugly, right? Maybe Shape, or something cooler!

createVertexArray :: (Foldable f,MonadIO m,MonadResource m,Storable v,Traversable t,Vertex v)
=> t v
-> f Word32
-> m VertexArray

As you can see, the type signature is highly polymorphic. t and f represent foldable structures storing the vertices and the indices. And that’s all. Nothing else to feed the function with! As you can see, there’s a typeclass constraint on v, the inner vertex type, Vertex. That constraint ensures the vertex type is representable on the OpenGL side and has a known vertex format.

Disclaimer: the Traversable constraint might be relaxed to be Foldable very soon.

Once tested, I’ll move all that code from the unstable branch to the master branch so that you guys can test it. :)

About OpenGL…

I eventually came to the realization that I needed to inform you about the OpenGL prerequisites. Because I want the framework to be as modern and well-designed as possible, you’ll need… OpenGL 4.5. The latest version, indeed. You might also need an extension, ARB_bindless_texture. That would enable the framework to pass textures to shader in a very stateless way, which is our objective!

I’ll let you know what I decide about that. I don’t want to use an extension that is not implemented almost everywhere.

What’s next?

Well, tests! I need to be sure everything is correctly done on the GPU side, especially the vertex format specification. I’m pretty confident though.

Once the vertex arrays are tested, I’ll start defining a render interface as stateless as I can. As always, I’ll keep you informed!

Categories: Offsite Blogs

Pattern guards in comprehensions

haskell-cafe - Mon, 08/10/2015 - 1:48am
I propose we add pattern guards in comprehensions, but I'm not sure what syntax would work. Consider this function: allMinus :: [Natural] -> [Natural] allMinus m = mapMaybe (-? m) where n -? m | m > n = Nothing | True = Just (n-m) One may wish to write such as a list comprehension, but it is cumbersome: allMinus m ns = [n' | n< at >((-? m) -> Just n') <- ns] This would be clearer with pattern guards, fictitious syntax here: allMinus m ns = [n' | n <- ns, Just n' <- n -? m] Alas, this conflicts with the other part of list comprehension syntax. Try we this, actual syntax now: allMinus m ns = [n' | n <- ns, let Just n' = n -? m] Nope, that's an error if (any (< m) ns). I recognize in this case the one in terms of mapMaybe is quite clear, but in the case of some other code I'm writing it's much more complicated. Ideas: 1. Modify semantics of let in comprehension to skip that element on pattern mismatch 2. Use another keyword, e.g. [n' | n <- ns where Just n' <- n -? m] Thoughts?
Categories: Offsite Discussion

Appropriate location for list of language suggestions

haskell-cafe - Mon, 08/10/2015 - 12:49am
This email is in response to the (ongoing) Haskell-cafe discussion about type declaration syntax. There are a number of hypothetical changes to Haskell that could be aesthetically pleasing or convenient if implemented, but not to such a degree that the added convenience outweighs the added complexity of a pragma-gated feature or the cost of breaking existing code. (Case in point: renaming type/newtype/data to be less confusing to first-time users) However, there may be better opportunities to implement such changes in the future, and it would be a shame if every good (but perhaps somewhat trivial) idea was lost to the annals of the mailing list. Therefore, I proposed that we might maintain a list of nitpicks, which could be used to inform future decisions about breaking changes to the Haskell specification. I'm not sure what the most appropriate forum is for such a list. The mailing list is sub-optimal, because we might end up with a huge email chain littered with bikeshedding reply-alls. I would be
Categories: Offsite Discussion


haskell-cafe - Sun, 08/09/2015 - 2:58pm
Hi there, I just wanted to ask whether I just missed this years HAL (Haskell in Halle/Leipzig) or if it was canceled this year. Cheers Pascal _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe< at >
Categories: Offsite Discussion


Haskell on Reddit - Sun, 08/09/2015 - 2:00pm
Categories: Incoming News

Deploying Haskell (standalone, yesod, snap…) in Openshift fails

Haskell on Reddit - Sun, 08/09/2015 - 9:24am

I'm posting this in /r/haskell because I didn't get any responses in /r/haskellquestions. Is this an error on my end, or is it something known?

Whenever I try to create an application based on the Haskell cartridge, it results in the a variant of the following error:

The initial build for the application failed: Shell command '/sbin/runuser -s /bin/sh 55c67c940c1e6694ac000017 -c "exec /usr/bin/runcon 'unconfined_u:system_r:openshift_t:s0:c5,c753' /bin/sh -c \"gear postreceive --init >> /tmp/initial-build.log 2>&1\""' returned an error. rc=137 .Last 10 kB of build output: The server is not running, nothing to stop. Repairing links for 1 deployments Building git ref 'master', commit 6b8beb4 Downloading the latest package list from

This happens for predefined cartridges in the Openshift hub, such as Snap, Yesod, Scotty, and for the cartridges defined in the wiki (

I'm requesting help because he application never gets created thus I can't check the logs, and I can't make much from the error message. I tried other cartridge types than Haskell, and they get created just fine.

submitted by Skyeam
[link] [7 comments]
Categories: Incoming News

an idea for modifiyng data/newtype syntax: use `::=`instead of `=`

haskell-cafe - Sat, 08/08/2015 - 12:09pm
Hello, i would like to suggest an idea for modifying the basic data/newtype syntax in Haskell: replace the equality sign `=` with `::=`. When i started learning Haskell, the most confusing part of the syntax for me was the equality sign in `data` definition. I could not even guess what the `data` definition meant without reading a chapter or two about types in Haskell, and i think it was partially due to the equality sign. I still find this notation inconsistent with other uses of the equality sign in Haskell and in general. For example, in type Name = String data Date = Date Int Int Int data Anniversary = Birthday Name Date | Wedding Name Name Date the second line is particularly disorienting IMO because on two sides of the equality, `Date` denotes different things. As far as i understand, in all contexts except those of `data` and `newtype` definitions, the equality sign in Haskell denotes the actual equality for all purposes: if a line foo x y = bar y x is present in a program, `
Categories: Offsite Discussion

monads, memoization etc

haskell-cafe - Sat, 08/08/2015 - 2:11am
Hi everyone, I'm new to Haskell and decided to learn a bit about monads and their utility. Actually, what worked nicely for me was: to read first several pages from "Computational lambda-calculus and monads", then do exercises from, and then map these exercises to actual functions in the standard library. Then, I decided to implement memoization to practice a bit with ST, HashTable's and such. Here is what I managed to get: . This code computes Fibonacci numbers while caching the intermediate values in a hash table. I tried to make the code as fast as possible (it runs in under 15 seconds, when computing 1M'th Fibonacci number modulo 999983). It uses the package hashtables. I have several question about all this. First, is there a cheap way to speed this code up? Note that I'm interested in a universal memoization strategy, that is I don't want to use arrays instead of hash tables etc. Second, is this
Categories: Offsite Discussion

More concise code using phantom types

haskell-cafe - Sat, 08/08/2015 - 12:28am
Hello! Consider the following code: module Units where data Units a = U Double deriving Eq units :: Double -> a -> Units a units value _ = U value data Meters data Yards meters = undefined :: Meters yards = undefined :: Yards instance Show Meters where show _ = "meters" instance Show Yards where show _ = "yards" extractA :: Units a -> a extractA = undefined instance Show a => Show (Units a) where show u< at >(U value) = show value ++ " " ++ show $ extractA u main = (print $ units 5 yards) >> (print $ units 5 meters) Is it possible to use something instead extractA function here? For example, substitute "extractA u” with “undefined :: a”? GHC disallows it, so is there a way to explain that I only need a token with type a? Also, with highlighting on lpaste: With regards, Nikita Kartashov _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe< at >
Categories: Offsite Discussion

ANN: happstack-server-tls-cryptonite

haskell-cafe - Sat, 08/08/2015 - 12:12am
Hi, I'd like to announce happstack-server-tls-cryptonite, package adding native TLS support to happstack, utilizing hs-tls and cryptonite packages by Vincent Hanquez. You can now run secure web server without using OpenSSL or other foreign libraries. This package is almost drop-in replacement for happstack-server-tls, just change Happstack.Server.SimpleHTTPS to Happstack.Server.SimpleTLS in imports. Regards, Andrey
Categories: Offsite Discussion

simultaneous ghc versions

glasgow-user - Fri, 07/31/2015 - 7:10pm
The recent release of ghc 7.10.2 reminded me of something I meant to ask about a long time ago. Most of the binaries ghc installs are versioned (x linked to x-7.10.2), with some exceptions (hpc and hsc2hs). Shouldn't they all be versioned? Also, 'haddock' is inconsistent with all the rest, in that it's haddock linked to haddock-ghc-7.10.2. I've long used a few shell scripts (recently upgraded to python) to manage ghc installs. A 'set' which creates symlinks to make a particular version current, and an 'rm' to remove all traces of a version. But due to the inconsistency, I have to remember to run "fix" first, which moves the unversioned binaries to versioned names. As an aside, I have three scripts I use all the time: set version, remove version, and remove library. Come to think of it, shouldn't ghc include this, instead of everyone creating their own shell scripts by hand?
Categories: Offsite Discussion

broken source link

glasgow-user - Fri, 07/24/2015 - 8:59am
Hi, when trying to look up the original definition for Data.List.transpose in I found that the source link does not work. Could this be fixed? Or should I look elsewhere for the sources? Cheers Christian P.S. my looking up transpose was inspired by
Categories: Offsite Discussion

New gtk2hs 0.12.4 release

gtk2hs - Wed, 11/21/2012 - 12:56pm

Thanks to John Lato and Duncan Coutts for the latest bugfix release! The latest packages should be buildable on GHC 7.6, and the cairo package should behave a bit nicer in ghci on Windows. Thanks to all!


Categories: Incoming News