Send a bitmap from C# to C++?

Started by
7 comments, last by stottle 16 years, 2 months ago
This is my first post, be nice! I've got a C# program that runs an OpenGL window in a windows.form. I'm trying to speed up the loading of textures to OpenGL. This isn't for a game, I've got jpg's of movie covers that I show and let the user pick a movie. Everything works fine loading the images from disk to bitmaps and then to OpenGL, but I'm hoping to make it faster. What I'm looking at is having a memorystream that holds a buffer of pictures (to minimize file I/O latency) and then load the images from streams into textures. My question has to do with loading an image to a bitmap. My understanding is that lockbits is not that fast in C#, but generating a pointer to the data requires unsafe code, which may not run for some users. My thought is to pass the bitmap (or a stream with the jpg data) to unmanaged C++ to do the loading to OpenGL. Will this help my performance? If so, any pointers (no pun intended) on how to pass a bitmap or a stream to C++? In particular, I don't know how to pass a bitmap. I know how to pass an array of bytes, but if I do that, I don't know how to load a jpg as bytes into a bitmap in C++. Any suggestions appreciated. Thanks, Brett [Edited by - stottle on February 6, 2008 12:34:09 AM]
Advertisement
I think you're making this too complex.

A simple solution would be to load all the jpegs into different textures, and as required just change the texture that's used by your 3D model.
I wish that were the case. I've got ~200 movies. I started off loading the first 50, which worked fine. When I removed the limit and went to 200, it brought my system to a grinding halt - trying to swap images in and out of the graphics card. Some simple math, 200 (images) * 500*700 (dimensions) * 3 (bytes/pixel) = 210 MBytes. There are folks with a lot more than 200 movies. I detecting the GPU memory, so I there aren't too many images I will load everything directly (which I've already got working), but if that isn't the case, I need to do something different.

Brett
500*700 is a bit overkill for DVD covers. 128x256 with compression should be more than enough.
I doubt the issue here is the texture loading speed. What is slow exactly? The framerate, or the initial loading?

In either case, are you actually drawing all of the covers at once? Is mip mapping on?

If not drawing them all at once, make sure you are only making draw calls for images that are actually visible.Even if they have 500 movies, if the system only displayes 20 at a time you only need to swap in 20 textures. If the loading is what is slow, you can try experimenting with streaming in the images from the hard drive as you need them.

Anyways, more information would be helpful.
Turring Machines are better than C++ any day ^_~
Hi Brett,

try to answer some questions to make your problem more clear:

(1) Are we talking about hundreds up to thousands of images? Or will there be many more?
(2) How many of the images will be visible at once?

First of all detecting GPU memory is not the best thing to do. Reported memory depends on many factors like AGP memory usage and so on.

Most important is: It does not make sense to upload all images to the graphics board at once for each frame, since they will never be seen all at once at the highest resolution.

What you could do is some sort of LOD to not waste memory bandwidth and exploit temporal coherence (assumed that not all of the images change from one frame to the next):

(1) Identify which images will be seen in the next frame. --> save memory.

(2) No need to upload a 700x500 pixel bitmap to your graphics board if the textured object will cover only 40 pixels. Identify which images will be seen in what resolution and keep downsampled versions (preprocessing) of your images in normal RAM (you can use mipmapping-techniques for this). Upload appropriate sized versions only to your graphics memory (glTexImage(...) or some D3D equivalent). --> save bandwidth

(3) Try to guess which images will be visible in the next frame and do not upload these again. --> exploit coherence

(4) Use texture compression (very easy!).

Probably using approach (1) will solve most of your problems.
Hope this helps.

Cheers,

GuentherKrass
Instead of speeding up the loading, what will make it smooth even on a slow system is hiding the loading time by using another thread:

- On a background thread load up all the images that are visible or almost visible, and convert them to textures (jpeg decompression can be slow). I'd avoid OpenGL calls on this thread. If there's nothing to do this thread should sleep for a short delay (around 100ms) and then check again.

- On the main thread each frame:

1. Check to see if any textures have finished loading, and pass them over to OpenGL.

2. If you're running low on ram, delete the textures which are farthest off screen.

3. Draw everything. If you need textures that aren't loaded yet use a placeholder texture (or don't draw the objects using that texture at all).

To simplify the synchronization I'd create 3 HashTable.Synchronized of textures (indexed on say filename):

1. Textures that aren't loaded.
2. Textures that are loaded, and need passing to OpenGL.
3. Textures that are active.

Move them between hashtables as appropriate.
So what I thought was a reasonably clear question turned out to be not clear at all. Sorry guys. (Reminds of a quote "Sorry to write such a long letter, I didn't have time to write a short one").

Thanks for all of the advice so far, still looking for a little more help. I'm trying to do something similar to ITunes cover view. It shows ~15 covers on the screen and shifts which covers are visible as the songs change or based on user input (left/right arrows). In my case, its movies.

Not sure if I can post this URL, but here is a short clip of what I have so far:


What I meant by load the texture was the whole process from disk to opengl, not the load glTexImage2D call itself. I'm a fan of getting something to work, no matter how slow, then optimizing. The problem is that it takes about 1 sec on my system to load 50 images (again, the full process from disc). Not too bad, but not good enough for a UI.

My timing tests show that that's about 600 msec for File I/O, 300 msec to get the Image to a Bitmap ready for loading, and 80 or so msec to load the Bitmaps to OpenGL (in C#). The "Bitmap ready for loading" part is tricky, since that includes the lockbits/unlockbits part as well as the jpeg conversion. So I'm not sure how much of the 300 msec is converting jpeg to bitmap and how much is the lock/unlock.

Ok, so my heavy hitters are the File I/O and the "getting a bitmap that is ready to load" steps, right? I've already built some test code that reads the files into a BinaryStream, so I can skip the file I/O and use the jpegs stored in memory and looking for the best way to minimize that "load" time.

As I said before, I'm not sure if it will buy me anything, but I've read that C# bitmap processing with lock/unlock is slow. So I thought it was worth testing if an unmanaged function (that could easily access the bitmap data) would be faster than C#. I don't think I need to worry about unsafe code, since I will load the data to OpenGL and be done with it, I don't need to worry about C# garbage collection. My difficulty is just with this step - I'm used to Unix C++, so I've never passed anything unusual from C# to C++. I can easily create a C# bitmap, but I'm not sure how to pass that to C++ to run glTexImage2D against. I could also pass the byte stream to C++, but then I don't know how to convert that to a bitmap to load to opengl.

Any lastly, if this doesn't provide enough performance to be worth doing, that's good to know too!

As for the other tips, I haven't implemented the hashing of loaded/unloaded images yet, but I was already planning for that. I'm already using multiple threads as well. Since this part of the load is inherently serial, I'm just trying to minimize the serial time. And I will take advantage of the temporal aspects, although I need to worry about the user taking random jumps, which just makes that trickier.

I guess I'm back to that long letter part....

Thanks for the help,
Brett
Does anyone know how to pass a C# System.Drawing.Bitmap to unmanaged C++ for loading into OpenGL with glTexImage2D?

Brett

This topic is closed to new replies.

Advertisement