openFrameworks static linking or memory management problem?

#1

So, I’ve been using OF for some time already and there’s this issue when you compile your OF project, it is set to DLL (dynamic linking) by default if i understand correctly? (I currently work with Visual Studio, used Code::Blocks for the first versions of OF).

Tried to do a simple test sketch to confirm the horror I experienced. Is it normal that an OF app won’t load a huge image to be scrolled via ofImage.load(…) ? I’m talking about 10,8 MB png file with dimensions of 12000 x 6200 px. It can’t be a problem, because my desktop computer loads and displays it correctly (Win7 64bit), whereas my notebook (previously Win7 32bit, reinstalled into Win7 64bit) displays errors in the output window of the VS, as soon as such a large image is loaded and nothing is displayed, rather rendering the screen white (yep, pure (255,255,255) of rgb color ).
The funny part is that before I reinstalled my Windows on the notebook, it worked correctly on old win7 32bit version.

This lead me to believe that something like the infamous “DLL hell” is involved. Also tested my compiled imageTestSketch_debug.exe on my nephew’s computer (dual boot Mac with Windows 7), and the app didn’t even open, complaining about some missing DLL… (think it was some msvcp40.dll or something…)
As I have googled for a solution to this problem, I found that static linking is a versatile fix of such issues and even game development makes use of it (even though it may inflate the executable file, no matter…).
Makes some sense, for the sake of compatibility, to ensure no system .DLLs would interfere with the OF version of the libraries, making it running the same on any machine.

My question is: have you any experience with static linking of an OF project?
I want to build some (trying just a simple sketch with only main.cpp, ofApp.cpp and ofApp.h) using the static linking in preferences, but the components of the OF are not built, because the linker complains about the mismatch in the main.obj.

I’ve provided the image how I changed the runtime library in code generation from Multi-threaded Debug DLL (/MDd) to Multi-threaded Debug (/MTd) - according to the tutorials about static linking, this should tell the linker to link it statically.
And when I do the debug, output shows every ofAppRunner, ofImage, ofTesselator, etc. etc. with a mismatch error, each of them in main.obj

the last lines are:

1>openframeworksLib_debug.lib(of3dUtils.obj) : error LNK2038: mismatch detected for ‘RuntimeLibrary’: value ‘MDd_DynamicDebug’ doesn’t match value ‘MTd_StaticDebug’ in main.obj
1>LINK : fatal error LNK1104: cannot open file ‘libboost_filesystem-vc141-mt-sgd-1_64.lib’
1>Done building project “imageTestSketch.vcxproj” – FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========

Sorry, I am quite an experienced C++ coder, but never understood compiler and linker, and never bothered with the configurations, just set it up as was illustrated in tutorials…
Is there something more to do than just change the runtime library in the project properties as is shown in the image I provided?

#2

Hi there, i would think the problem you are seeing is more probably related to memory running out rather than how openFrameworks is linked.

Yes, that can happen.

If you load a png image with 12000x6200 px, this will use up lots of GPU RAM (assuming a default 4-channel image, with default 32bits(= 4 Bytes) per pixels):

12000 x 6200 x 4(=32bits/8) = 297,600,000 Bytes.

That’s ~300 MB, and it could be that some graphics cards, especially those with less VRAM, might get troubled. It’s also worth noting that some (older, mobile) graphics cards struggle with textures which are very large in terms of their dimensions - it’s worth checking your graphics card against GL_MAX_TEXTURE_SIZE in the OpenGL hardware capabilities database.

You want to use a texture dimension smaller than what it says under GL_MAX_TEXTURE_SIZE for your specific graphics card type and driver version.

If you’re running out of VRAM, you might want to consider using texture compression. If texture dimensions are the problem, consider splitting the image into two or more textures.

1 Like
#3

Thanks for the reply. However, this can’t really be a problem.
I mean, I used the SAME notebook with OLDER system before (Win 7 32bit) and it displayed just as on my desktop computer where it works ok. (No errors while loading)
And as I mentioned, I tested any compiled OF app I had with me on my USB key at nephew’s notebook and it didn’t even open the app because it complained about missing some .DLL file… So, as we can see, there’s not an insurance that any OF project we develop would be working on any machine - especially when it is dynamically linked by default. (System DLL files may vary from computer to computer and you can never know what might interfere…)
And even then, this is relatively NOT THAT HUGE image to load… Bitmap Editing Programs like Photoshop or GIMP have to create new/load/save even larger image files.
If graphical editors don’t complain about image size this huge, OF can’t do either I guess… (Provided that freeImage.dll that OF makes use of (this should be responsible for loading/saving images) has the capacity of these programs)
Way I see it, there’s a world of difference between loading an image and displaying it. Of course I do not draw the whole huge image going beyond the size of the screen. I use drawSubsection(…) function to draw only the portion to fit the screen.

Static linking should bake the correct libraries into the compiled program so that OS system files would just “shut up” and not possibly ruin it… :smiley:

Tried to follow @Drazinut 's post - Static linking not building needed Boost version in VS 2017?
And thank you @Drazinut, partially, for providing me the solution - didn’t know OF does rely on Boost library - boost is not mentioned anywhere in the about section of OF (I thought this isn’t my problem, but the OF components are linked towards it)…

And while I managed to copy the boost libs for static debug (that is, libboost_filesystem-vc141-mt-sgd-1_64.lib and libboost_filesystem-vc141-s-1_64.lib) , new errors occured to me while building…
This time, linker complains about unresolved external symbols and the following lines:

2>LINK : error LNK2001: unresolved external symbol __load_config_used
2>D:\Work\OpenFrameworks\of_v0.10.1_vs2017_release\libs\openFrameworksCompiled\project\vs\…\libs\boost\lib\vs\Win32\libboost_filesystem-vc141-mt-sgd-1_64.lib : warning LNK4272: library machine type ‘x64’ conflicts with target machine type ‘x86’
2>bin\imageTestSketch_debug.exe : fatal error LNK1120: 323 unresolved externals
2>Done building project “imageTestSketch.vcxproj” – FAILED.

conflict between 64bit and 32bit machine compilation… Tried changing both… this one above is when I compile MachineX86 (32bit system), and when I try to compile MachineX64, it displays this, mentioning obj\Win32\Debug\of3dPrimitives.obj

1>------ Build started: Project: openframeworksLib, Configuration: Debug Win32 ------
1>obj\Win32\Debug\of3dPrimitives.obj : fatal error LNK1112: module machine type ‘x86’ conflicts with target machine type ‘x64’
1>Done building project “openframeworksLib.vcxproj” – FAILED.
2>------ Build started: Project: imageTestSketch, Configuration: Debug Win32 ------
2>LINK : fatal error LNK1104: cannot open file ‘D:\Work\OpenFrameworks\of_v0.10.1_vs2017_release\libs\openFrameworksCompiled\lib\vs\Win32\openframeworksLib_debug.lib’
2>Done building project “imageTestSketch.vcxproj” – FAILED.
========== Build: 0 succeeded, 2 failed, 0 up-to-date, 0 skipped ==========

1 Like
#4

Dammit, you’re right after all, I must admit. Static linking didn’t solve anything in this case… I was just wondering if there’s a difference for memory to load one single huge image that would yield for example the size as the one I mentioned and to load 10 images (e.g. this one huge image divided into 10 sub-images), where in the end, the sum in total would be the same as:

1 png image (10,8 MB) = 10,8 MB
10 png images (theoretically, though not exact accurate 1,08 MB) = 10,8 MB

Is there a difference memory-wise? Like loading per-image (several of them) versus one huge image (chunks combined into one)?
I mean, even scrolling engines like google maps or game maps has to have huge (theoretically unlimited) dimensions…
But thanks for everything mentioned here.

#5

Hi @mr.Bitmap,

there is no difference in total memory needed for 1 large vs. 10 smaller images, but there is a subtle difference in how robust (meaning fail-safe) the application will be.

I’ll explain why this is in a moment, but first, I feel it’s important to get on the same page in finding out how much memory is actually needed:

The file size of a PNG does not really tell us anything about how much memory the GPU will need to display this image. That’s because PNGs can be super compressed and GPUs usually only deal with uncompressed image memory.

Uncompressed memory is relatively simple. For the most common type of image, a 4 (RGB + Alpha) channel image, each pixel is stored as a group of 4 bytes (that’s one byte for each of r,g,b and one byte for alpha).

This means, to calculate the amount of memory needed on the GPU to sample an image you can use the formula:

width * height * (number of bytes per pixel=4)

Which is the formula I used in my first answer, and it gave about ~300MB for the PNG you described.

Now, this is a large image, and you are correct, a Desktop GPU can deal with such images, usually. Until it runs out of RAM. Or maybe, it can’t find a chunk of free RAM big enough to fit the image. This problem is called memory fragmentation, and it can be nasty to debug because it will only show up after some time…

Sometimes I like to think of RAM as a giant supermarket car park:

At the beginning of the day it is empty, and then, as shoppers come, it fills up with more and more cars. Of course shoppers don’t stay forever, so some cars leave, leaving parking lots free. By afternoon, the parking situation might look pretty patchy: there’s a big irregular jumble of free and taken parking lots, and sometimes a leftover shopping trolley blocking an otherwise free space…

And now imagine someone with a massive delivery truck comes in, and they are looking for 8 parking lots next to each other, because nothing else will fit their truck. They probably should have shown up earlier in the morning, when the whole car park was still free. Or they should have taken smaller trucks.

Sometimes, graphics cards drivers will do some magic in the background to re-organise memory automatically, and to consolidate free space. Nearly all of them do it, but banking on it is a bit risky, because we can’t know when and how these things happen.

I would suggest breaking it down into smaller images - the nice thing with that is also that you will see at which point (after how many images) things start to break down - and at the end of the day you will have a robust application that works on both larger, and smaller computers.

2 Likes
#6

Yeah, even while searching for this issue in game scrolling engines, it seems like this has been a traditional approach since the first computers’ era… From 8bits (ZX Spectrum, C64 (provided they had sufficient memory capabilities), Amiga (my childhood :slight_smile: ) ) until today…
The example and idea I found is to divide the screen into 9 chunks (subsections of one huge image map) that are actively used (drawn) - and thus, currently in the memory.
As the huge and huge maps are scrolled in any direction, 3 chunks of the opposite direction always come out of scope and can be replaced - loaded with another 3 chunk images.

quoting from this reference:
http://www.oldschool-gaming.com/view_article.php?art=map_compression

CHUNK COMPRESSION
Chunk compression is, as the name suggests, a method to take a series of pre-defined chunks of map data and expand it out as the scrolling needs it; this is far simpler than tile compression (of which more later) but bears some similarities. As we’ve already seen, storing a map straight into RAM isn’t particularly efficient on space and, if we were to assume that, for vertical scrolling, we’d need to stack up a large block of data in the RAM and shift it through the actual screen a line at a time. As also noted previously, that can be very memory intensive and for our theoretical machine, 32K of data will generate a mere 34 screens of scrolling, a paltry two minutes of landscape assuming a fixed speed of one pixel per frame. So instead we store chunks of landscape and have a running order that tells the scrolling routine which chunk to work it’s way through next, where a chunk is the full 40 bytes wide but can be any size vertically we require. This means that, should the need arise, the same landscape feature (or group of features) can be repeated two, three or many more times in a row or throughout a larger map to drastically increase the length of the landscape and the chunks themselves can vary in size from a couple of bytes high to a complete screen of data as the detail dictates.

2 Likes