2009/07/25

Pango font rendering on an OpenGL canvas

Nowadays I’m working on the interface of the profile history manager, and I ran into the problem mentioned in the title. The problem is actually that the Gtk2Hs interface seems to have more degrees of freedom than the implementation, and even if it seemingly lets us combine various mechanisms in creative ways, most of these combinations lead to a segfault. In particular, using any incarnation of drawLayout in an OpenGL drawing area suffers from this problem.

After some sweat and tears and frantic search for solutions I decided to use Cairo for rendering. This also has the advantage that the result of the rendering can be cached in memory, so the display can be refreshed very efficiently if the text is static. All we have to do is prepare an image for later rendering.

First we need a Cairo context. As part of my goal was to preferably use the same font as the rest of the interface, I also set it to a sans serif typeface:

cctx <- cairoCreateContext Nothing
fontDesc <- contextGetFontDescription cctx
fontDescriptionSetFamily fontDesc "Sans"
contextSetFontDescription cctx fontDesc


The next step towards consistency is to set the resolution to match that of the screen. This is very important to crazy people like me, who had to change their DPI setting.

screenGetDefault >>= \s -> case s of
Nothing -> return ()
Just scr -> do
res <- Gtk.get scr screenResolution
cairoContextSetResolution cctx res


Okay, the context is sufficiently prepared for our purposes, we can create the layout:

txt <- layoutText cctx "Hello world!"


Next, we need a pixel buffer that can hold the final render. We can easily find out its dimensions by asking for the pixel extents of the layout, and it’s probably better to use the logical extents that also include some padding:

Rectangle _ _ txtWidth txtHeight <- snd <$> layoutGetPixelExtents txt
textSurface <- createImageSurface FormatARGB32 txtWidth txtHeight
textSurfacePixbuf <- pixbufFromImageSurface textSurface


And everything’s ready for rendering, so let’s do it:

renderWith textSurface $ showLayout txt


From this moment the rendering of the text is available in the pixbuf. Rendering it is a piece of cake:

withGLDrawingArea glCanvas $ \glw -> do
-- various opengl commands
gc <- gcNew glw
drawPixbuf glw gc textSurfacePixbuf 0 0 textX textY txtWidth txtHeight RgbDitherNone 0 0
-- more opengl commands
glDrawableSwapBuffers glw


When we know that we won’t need the image any more, we can free up the surface:

surfaceFinish textSurface


For more consistency we could look up the actual rendering settings (antialiasing, hinting) and fonts of the current theme and set everything before rendering. That’s left as an exercise to the reader. I’m too tired. ;)

2009/07/17

Introducing the heap profile manager

Well-well, it’s been almost two weeks since the last release, so I decided to show you the beginnings of the heap profile viewing application. After thinking about the alternatives I decided to follow in the steps of others who make core tools and use gtk2hs for the interface. Since I had a working grapher in OpenGL, it was also straightforward to keep it. I started out as a complete beginner in gtk2hs last week, and it proved to be one of the smoothest library learning experiences so far. Even getting several OpenGL drawing areas to work simultaneously went without a hitch. The UI started out as something more complex, but after some experimentation I arrived at the present design:


You can load several graphs in each column (note that multiple selection is enabled in the file open dialog), and move them left and right between columns as you wish. Columns can also be created and destroyed at will. This initial version doesn’t have any more interaction, e.g. you cannot zoom in on areas you’re interested in. Consequently, graphs with an occasional high spike can be unpleasant to look at, as illustrated by the example on the right.

The next step is obviously to add the features that make comparison easier, like displaying scales, displaying identical cost centres with identical colours, adding zooming and panning, comparing a given cost centre from separate runs on the same graph and so on. Also, the profile loader could be probably speeded up a bit by not building a map from times to samples if we convert it into a list anyway.

If all this works okay, I can also add some export plugins (e.g. ps and svg) to finally retire hp2ps.

Oh, the button next to the left arrow doesn’t do anything yet.

2009/07/06

Remote profiling at your fingertips

Yes, it’s time for another code release after a long hiatus. You can grab the source from the repository, and it should even be able to compile without any major hiccup. The grapher is now capable of connecting to a profile relay server that can broadcast the heap profile of its associated process on the fly. Stopping either the process, the server or a grapher client is handled gracefully. Thanks to decoupling the grapher and the process in the remote case, it is now possible to attach an observer to a program that was started earlier. Here’s the proof:


It’s hopefully obvious that the clients were attached at increasing times from top to bottom, and I flipped the mode of the middle one just for the fun of it.

Unfortunately, even though the code to achieve all this is quite small (hey, thanks Haskell!), getting it to work at a reasonable level of stability took longer than expected. Therefore, instead of adding remote control features to the grapher right away, I’ll start preparation for the history manager, otherwise I might not be able to get it working before the final GSoC deadline.

2009/07/03

Playing and learning

My profiling project is currently in the state where I can’t really show any pictures or code, since I’m fighting with various edge cases that one can bump into while writing a multithreaded distributed graphical application. In short, remote graphing has already been working since the beginning of the week, but there are stability issues that need to be ironed out before the next release, and it’s taking longer than I anticipated...

Until then, let me bring another program into your attention. It is a Bloxorz clone in Haskell, available through cabal in the bloxorz package. It is more limited than the original, and only features three levels, but the essence is there. This rendition was made by a student of mine, Viktor Devecseri, for a ‘practical functional programming’ class I’ve been teaching for one and a half years. This is an optional class available to students of electrical engineering and informatics (at our university, the latter involves a fair amount of both CS and IT), who don’t necessarily have any non-mainstream programming background.

The point of the class is basically to give students a wider perspective by exposing them to functional programming. The primary language of the course is Haskell, but I also talk about Hume, and the last time I dedicated a lesson to Timber too, as the official name of the course is Embedded Functional Programming for historical reasons. We even used Hume to control Mindstorms NXT robots and a Tmote Sky sensor the first time this class was held, but this proved to be a bit too complicated due to the lacking toolset for this language, so the topic slowly shifted towards general practical FP. While one might argue that Haskell is not the most practical language, it is definitely among the few languages that’s both useful for real-life purposes and can broaden one’s mind to a great extent.

I always take the time to ask everyone about their learning experience, what they found easy or hard while working on their assignment. Since students can have rather different past experiences, I let everyone choose the topic on their own, the only constraint being that the program should be interactive in some way. In other words, I don’t want to see pure data grinding, because there is another class with that focus, and it’s probably more rewarding for newcomers to see something move and respond right away.

While talking to Viktor, he had remark that the approach being ‘not object oriented enough’ (I hope I’m not misquoting him too much here) was somewhat inconvenient. Afterwards, we had a little conversation about FP being a completely different approach to modularisation than OO. Nevertheless, even if I have a few years of experience with functional languages, I still found it hard to respond to questions pertaining concrete problems. I believe it would help a lot if there was some kind of tutorial on designing real-life applications in the style of Why Functional Programming Matters. Is there such a guide somewhere, or only in the brains of experienced people and scattered everywhere across the web? My dear readers, please help me out!