Linux off-screen rendering with OSMesa

BlitzMax Forums/Brucey's Modules/Linux off-screen rendering with OSMesa

Brucey(Posted 2011) [#1]
Since off-screen rendering has come up occasionally, I thought it would be interesting to see if we could do it in BlitzMax.
OSMesa is a library which can render directly into memory, and is available on Linux.

In order to use it instead of the default glgraphics and glmax2d modules, it required some new ones which implement the OSMesa functionality while mirroring the current framework.

So, I've added 3 new modules to SVN :
* BaH.OSMesa
* BaH.OSMesaGraphics
* BaH.OSMesaMax2D

Also required is libOSMesa and it's dev package (for compiling).

Here's a small example included with the max2d module :

'
' OSMesa drawing example
'
'
SuperStrict

Framework BaH.OSMesaMax2D
Import BRL.PNGLoader

' create a pixmap
Local pixmap:TPixmap = CreatePixmap(400, 400, PF_RGBA8888)


'
' Note: To remain compatible with the Graphics framework, we must pass the pixel buffer
'       as an address (integer).
'
Local g:TGraphics = CreateGraphics(400, 400, 32, Int Ptr(Varptr pixmap.pixels)[0], 0)

' Set the current graphics context, so that we can do stuff.
SetGraphics(g)


' do some drawing
Cls


DrawText "OSMesa Drawing!!", 100, 200

SetColor 255, 0, 0

DrawLine 50, 50, 100, 100

SetColor 0, 255, 0
DrawLine 50, 60, 100, 110

SetColor 0, 0, 255
DrawLine 50, 70, 100, 120

' forces any buffered drawing commands to finish
Flip


' Save our pixmap!
' Graphics are drawn on an inverted Y axis, so perform a y-flip when you want to see it properly.
'
SavePixmapPNG(YFlipPixmap(pixmap), "test.png")


As you can see, everything is fairly standard, apart from the CreateGraphics call, where we also pass in the address to our image buffer. To keep it the same API, we use an address, rather than a Byte Ptr to the data itself...

Here's the resulting png from the example :


Of course, your mileage may vary (considerably).
It appears that using BRL.Graphics requires some X11 libraries because BRL.System needs them for some reason. (of all modules you'd not want to tie yourself into X11....).
But the 3 modules don't specifically do anything with X11... so you may get away with only requiring the X11 libraries to be present, and not actually using them. I haven't tried it though..

But, an interesting test anyway.
Perhaps useful for a server to render 3D to images or something :-)

Last edited 2011

Last edited 2011


BlitzSupport(Posted 2011) [#2]
Ooh. Gonna try this later, sounds much simpler than the xvfb option, thanks Brucey!


Brucey(Posted 2011) [#3]
It doesn't work... :-)

I just created a new Ubuntu 11.04 server instance, installed the required libraries, and the pre-compiled example seg-faulted... haw haw.

However, it does that because of the calls to initialising X11 stuff... which is a no-no on a server without X11 running.

So, I went back to the drawing board.
The culprit is BRL.System... so we can't have that at all... BRL.Graphics imports it... so we need a new Graphics base... and therefore we need a new Max2D base... so I've created one each of those, which remove the requirement of System, Hooks, and Polling...

I rebuilt the example, and ran it on the server. It works :-)

I'll commit the new stuff and changes now...

Last edited 2011


Brucey(Posted 2011) [#4]
Right... everything is in SVN now...

The modules are :
* BaH.OSMesa
* BaH.OSMesaGraphics
* BaH.OSMesaGraphicsBase
* BaH.OSMesaMax2D
* BaH.OSMesaMax2DBase

The "base" modules are implementations of BRL.Graphics and BRL.Max2D with support for BRL.System (mouse/keyboard) and Polling/Hooks removed.

Of course the big caveat is, that if you need BRL.System support, you cannot use these modules. If you need BRL.Graphics, or something which imports BRL.Graphics, you cannot use these modules.. or, you change your dependencies to use BaH.OSMesaGraphicsBase instead of BRL.Graphics... etc.

But, it works... so perhaps it's worth giving up a little functionality/support for greater things...


This is the result of running the app on the new Ubuntu 11.04 server instance, which doesn't have X11 running (as displayed on my mac) :



On a base Ubuntu server install, I had to run the following commands to have all the required libraries :
sudo apt-get install libgl1-mesa-dev
sudo apt-get install libglu1-mesa-dev

which also installed all the other required libraries. osmesa is part of the mesa distro.
You may not need to install the "dev" variants for your runtime binaries...

Last edited 2011


Russell(Posted 2011) [#5]
Are you a cybernetic programming machine from the future, Brucey? :)

Seriously, I can't imagine how you can find the time to do all of the programming you do and still find time in the day to eat, sleep, work (you're a programmer, right?), etc.

The BMax community would be a lesser entity if were not for your superhuman programming capabilities. Thank goodness you took an interest in BlitzMax and not Dark Basic or Free Basic or some other less-cool programming language...

Anyway...<Steps down from soapbox>, I guess the main advantage to offscreen (direct-to-memory) drawing is speed? Or are there other, less obvious advantages?

Russell


BlitzSupport(Posted 2011) [#6]
'lo Brucey, many thanks for this. Got it in place on the server now, but appear to have forgotten root password, so awaiting update from server-sharing accomplice to be able to install the dependencies! (Easy enough to reinstall from scratch if necessary, since it's not doing anything important and Linode makes it dead easy.)

This will be really cool if it works, anyway, opening up all sorts of possibilities, and I imagine it'll be better than the xvfb option since I assume that would be tied to one app rendering at a time, whereas this probably wouldn't. Anyway, thanks again! You are truly a god among men.

I'll post if/when I get it working!


BlitzSupport(Posted 2011) [#7]
After figuring out root pass... OMG OMG OMG... and... woo!

Only hiccup was that, contrary to what you said here...


which also installed all the other required libraries. osmesa is part of the mesa distro.
You may not need to install the "dev" variants for your runtime binaries...



... I had to manually do this to get it to work after installing the mesa stuff above:

apt-get install libosmesa6
apt-get install libosmesa6-dev


Brilliant! God. Among. Men.


BlitzSupport(Posted 2011) [#8]
Hmmm, still a god among men, but I can't seem to make use of LoadPixmap, SetClsColor, etc -- just getting segfaults. I'm clutching at straws now, in terms of imports. As far as I can tell, LoadPixmap doesn't depend on Graphics, but I don't think I'm getting what exactly I should be importing.

Also, will the DrawImage, etc, commands be possible, or just Pixmap stuff? I don't mind creating a separate set of customised BRL modules, but I think I'm failing on "If you need BRL.Graphics, or something which imports BRL.Graphics, you cannot use these modules.. or, you change your dependencies to use BaH.OSMesaGraphicsBase instead of BRL.Graphics... etc"... embarrasingly.

Could you show the dependencies required for the below, or for a DrawImage version, if that's even possible?




BlitzSupport(Posted 2011) [#9]
OK, so after a load of local edit/FTP/PuTTY action, I can confirm it's simply failing to load the pixmap (it's coming back Null), which is a PNG in the same directory as the source file (in BlitzMax/bin for now), both with basic filename and full path, yet BRL.PNGLoader imports BRL.Pixmap, where LoadPixmap is, so I'm not sure why it's failing there... gah!

I get the same whether root or myself... any ideas? As you can see, the files are all in place:

CENSORED@MACHINE:~/blitz/BlitzMax/bin$ ls
bcc  bmk  boing.png  docmods  fasm  makedocs  osmesa  osmesa.bmx  test.png
CENSORED@MACHINE:~/blitz/BlitzMax/bin$


Anyway, enough for tonight... fun, though!


Brucey(Posted 2011) [#10]
Very strange...

I've added another example, which loads a png and draws it with DrawImage... and also sets the background colour with SetClsColor.



Here's the output :


Last edited 2011


Brucey(Posted 2011) [#11]
I'm not sure it's a good idea to be using the pixmap you are loading, to also be the one you are going to be drawing into... especially if it is not the expected format - size/bits per pixel.

It's important that the output buffer memory size is the right size for the graphics context you are creating, otherwise you will have no end of issues when mesa is trying to write to data that it shouldn't be (because your actual buffer memory is less that it thinks it has access to)

You can also enable MESA_DEBUG before running your app. If there are any problems with the graphics context, it will show up on the console :
export MESA_DEBUG=1


:o)


Brucey(Posted 2011) [#12]
I should also add that using a Pixmap is not required for your memory output buffer. You could just as well use a MemAlloc or Bank, as long as you create a block of memory large enough to hold the image data.

One other thing, I believe the default MAX size of an OSMesa context is about 1280 x 1024.
You can, apparently, increase this by changing a .h file somewhere in the system, but I haven't looked into that. (Google is your friend, for more information ;-)


The absolute most important thing in all this appears to be the link order of libOSMesa and libGL. OSMesa lib needs to come first. If you get lots of errors when MESA_DEBUG is enabled referring to trying to perform gl commands on no context, it's likely that the link order may be broken. You can check the order by running the 'ldd' command on your executable.
However, on Ubuntu at least, the default order of Module importing that I've created should be sufficient. Your mileage on other distros may vary, if said libraries are not located in /usr/lib.

Happy coding :o)


Brucey(Posted 2011) [#13]
I guess the main advantage to offscreen (direct-to-memory) drawing is speed? Or are there other, less obvious advantages?

I don't think speed will improve rendering into main memory, since the cpu will be doing all the work.

The main advantage I see is that fact that you don't need a gfx card to do the rendering. Well, this set of modules is not intended for displaying anything on the screen, since I've gone to so much length to exclude the X11 subsystem from it.
The main purpose of these modules is to be able to create gl-rendered images on a system where you'll only be creating image files, or perhaps sending the data directly to a browser over the web...

Just another tool in the arsenal, really :-)

you're a programmer, right?

Yeah... sad, isn't it? Today I'm working on GWT/JBoss/Oracle. Who knows what surprise is in store for tomorrow!...


BlitzSupport(Posted 2011) [#14]
Ah, ya beauty! Didn't realise I was trying to use the PNG as a graphics buffer (I usually just call Graphics, me!), so that was silly. I'll have to play around with that side of things a bit, and also play with this new toy and get a little server app going!

One thing I didn't get was how this part of the CreateGraphics call works, as it represents the hertz parameter:

Int Ptr(Varptr pixmap.pixels)[0]


What's going on there?


Brucey(Posted 2011) [#15]
That would be from this bit of the original post :

As you can see, everything is fairly standard, apart from the CreateGraphics call, where we also pass in the address to our image buffer. To keep it the same API, we use an address, rather than a Byte Ptr to the data itself...



To pass in a pixel buffer instead, we would need a new function. But this way, you get to use the standard API functions. It's a bit of a hack to pass the address in as an Int, but it works, and it keeps things nice and tidy.
I'm a lazy bugger, so the less I have to change, the better ;-)

Glad you're up and running!


BlitzSupport(Posted 2011) [#16]
Ohhh... you're just borrowing the hertz field since it's not needed. Nice/nasty! I like.

Thanks again -- I'll post anything interesting I manage to do with it.

EDIT: Stupid life getting in the way! Still not set up a 'live' server, but had it render this, from the code below, on the server, which is cool.




BlitzSupport(Posted 2011) [#17]
Hi Brucey,

Did you get to try minib3d at all? I had a quick go but got stuck...

I have done this, though, which is pretty cool, running "live" at 15 FPS in the background, using only 2.5% CPU! Refresh a few times to see it move...

http://www.hi-toro.com:9080/boing.png

(Has to be copied and pasted as the forum doesn't like colons in URLs!)

You can refresh after every second (it'll deliberately disconnect if hit more than this).

This is the code, brutally hacked into my existing web server... needs boing.png from /samples/hitoro/rockout and ability to write to its local folder, where it'll dump a PNG for each IP address that connects and not tidy up after itself...

Working with this on VirtualBox/Ubuntu makes things pretty easy!




Brucey(Posted 2011) [#18]
That's cool. It moves! :-)


As for minib3d. I have got it running finally, without crashing, but the fog.bmx example only returns a blank image. Perhaps that's not a good example to try, of course....
I had to disable the call to glew init, because that does X stuff, and the ARB/VBO stuff crashes it too...
otherwise, I really dunno how it works to know what to look for next :-p


BlitzSupport(Posted 2011) [#19]
I might have a go with a really early BMX-only version of minib3d and see if that gets me anywhere -- and I think VBOs came much later. Even just having this 2D ability is a really good feature though.