Sign in to follow this  

Getting raw pixel data onto the screen

This topic is 4861 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've written a software triangle rasterizer that draws into a buffer I've allocated myself. I'm currently using SDL to create my window and get this buffer onto the screen. Unfortunatly, even when all I do is blit the backbuffer to the screen without even drawing anything on it, all I get is 20 FPS. I'm looking for a solution that will get my pixels on the screen as fast as posible. I've poked at DirectDraw, but without knowing the API I wasn't able to actually get anything working. I'm looking for a solution that will get my pixels on the screen as fast as possible, preferably without getting too complicated. Any ideas are welcomed; but please, if you suggest a specific API, tell me a little about it! This structure stores all the information about the pixel buffer.
struct RenderTarget
{
	unsigned int * pixels; //Only 32 bit.
	unsigned int pitch; //In words, not bytes, assuming 1 word = 4 bytes.
	unsigned int width;
	unsigned int height;
};

Share this post


Link to post
Share on other sites
In openGL, which you can use in SDL, there is a function called glDrawPixels, or something like that. It is for drawing raw buffers on to the screen. You'll also have to make some preparatory function calls at the beginning of the program to set the pixel format and such. I don't know if that will be any faster, but it is something else to try.

Share this post


Link to post
Share on other sites
i have no idea how SDL managed to be so slow... as in old days of i486 80mz... maybe you're using SDL_OPENGLBLIT ? It's especially slow.
edit:also make sure your bits-per-pixel are equal on the screen and in SDL so it will not convert (conversion must be faster anyway,but it may be done in really stupid way). Fullscreen SDL might work faster...

In normal winapi, you can draw raw data on the screen using SetDIBitsToDevice .

Share this post


Link to post
Share on other sites
If your backbuffer is in video memory along with your primary surface, it will be that slow, because you are effectively reading every single pixel from vram, wich is the slowest operation in computer history, and then writing them back to vram, all over the bus.

The only right way to do this is to create all your buffers in system memory, and do all your drawing from system memory to system memory. and the last thing you do each frame is to copy the finished back buffer to video memory using whatever API you chose.
This cancels all hardware acceleration, but it is the only possible way if you want to do software rendering and have any kind of fast direct access to the pixel data.

[edit]
oh, and a WORD is two bytes, at least on the win32 platform, four bytes would be a DWORD.

Share this post


Link to post
Share on other sites
My buffer is in system memory (Remember, I newed it myself) and the video buffer has the SDL_SWSURFACE flag. Regardless; I'm on a machine with shared video memory.
All buffers are already the same pixel format: ARGB.
If I remove the blit, and do nothing but invalidate the screen every frame, I can only get to about 80 FPS.

I'm going to look into the windows GDI tonight. Hopefully, I'll be able to just grab a DC from the SDL window.

Share this post


Link to post
Share on other sites
it's unclear for me what's exactly you are doing...
maybe you can try to
SDL_LockSurface(screen);
copy your buffer to the screen yourself
SDL_UnlockSurface(screen);
SDL_Flip(screen);

or maybe

SDL_LockSurface(screen);
if(screen->pitch & 3)return;
YourCurrentRenderTarget.pitch=screen->pitch/4;//edit:stupid typo. * instead of / .
YourCurrentRenderTarget.pixels=screen->pixels;
YourCurrentRenderTarget.width=screen->w;
YourCurrentRenderTarget.height=screen->h;
RenderYourFrame;
SDL_UnlockSurface(screen);
SDL_Flip(screen);

It's really bad that now it's not simpler to draw on the screen fast than in old times.
You can try using directX; in directX you can get pointer directly to video ram,and copy your buffer yourself.

edit:some time ago i somehow hax0red some DirectDraw examples and was somehow able to copy image directly into videoram. Can't remember exact commands... it wasn't hard.

[Edited by - Dmytry on August 21, 2004 3:37:37 PM]

Share this post


Link to post
Share on other sites
This is very straight forward with D3D. After you have created your Direct3DDevice9 ( you can look at the tutorials included with the SDK to get to this step ) you simply need to:

UnlockVideoBuffer
{
pd3dDevice->GetBackBuffer(...);
pBackBuffer->LockRect(...);
pBackBufferData = (DWORD*)(lockedRect.pBits);
return pBackBufferData;
}

LockVideoBuffer
{
pBackBuffer->UnlockRect();
pBackBuffer->Release();
}

pBackBuffer = LPDIRECT3DSURFACE9
pBackBufferData = DWORD*
lockedRect = D3DLOCKED_RECT

You may also need to add the following to your presentation parameters:
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER

Unlock the video buffer before you write to it, lock it after you're done and then use pd3dDevice->Present(...) as usual.

Share this post


Link to post
Share on other sites
Here is a classic plasma effect I wrote using D3D and software rendering if you want to see it in action. You can alt+tab to the console window to see the FPS. Alt+f4 to exit the program. As you might guess, this wasn't made to be released, although I would like to know the FPS other people get. I get about 120 fps on a 2.4ghz P4 with 768mb ram.

Share this post


Link to post
Share on other sites
Hmm... just so you know, I already tried my software blitter on a Celeron P4 which had only cheap on-board video and it would only go to 28fps... which is slower than anything I got with discrete video cards. It *may* just be normal, since shared memory is really slow, especially when also moving from within memory to shared memory, or at least it seems :)

Share this post


Link to post
Share on other sites
Here is a starfield effect done with the same software engine. The stars have to move so quickly since I didn't do subpixel blending - you'd see massive 'hopping' effects if they changed position less than ~45fps. I pick up about 1500 fps on my same system.

Share this post


Link to post
Share on other sites
Quote:
Original post by persil
Hmm... just so you know, I already tried my software blitter on a Celeron P4 which had only cheap on-board video and it would only go to 28fps... which is slower than anything I got with discrete video cards. It *may* just be normal, since shared memory is really slow, especially when also moving from within memory to shared memory, or at least it seems :)


Have you tried either of the demo's I put up? You can check the FPS since I know those run relatively fast. I am almost positive that this is not a hardware problem.

Share this post


Link to post
Share on other sites
My software library can do full screen alpha blending in 640x480 at around 200 fps on a celeron laptop with shared memory... I know it's possible, the only thing I can think of that would make it that slow is if one of your surfaces is in video memory.
And making your video buffer SDL_SWSURFACE still puts it in video memory. can't really have a primary surfae anywhere else than video memory.

Otherwise I can't help I'm afraid, except keep trying, it is possible.

Share this post


Link to post
Share on other sites
I was able to get slightly more performance out of SDL. DirectDraw, however, blows it away. A sample in the DirectX8.1 SDK called 'DirectSurfaceWrite' gave me everything I needed to get my renderer drawing directly to a DirectDraw surface. Without drawing (A full-screen blit and a buffer flip) I get several hundred FPS.
It seems my plans to write a series of articles on software rendering may go ahead, but they will include a rather long diatribe explaining why the people who design these MS interfaces are on crack.

The software rasterizer is still horribly slow. I'll get around to optimizing it eventually.

Share this post


Link to post
Share on other sites
Yeah, I use DirectDraw too, for giving me direct access to the surfaces only.

Some points of advice:
Skip the flipping, and copy straight from your system ram back buffer to the primary video surface. But add a manual check for vsync. That will increase your fps a bit.

Also, use a GDI BitBlt to copy your back buffer to vram. Get DC's for the back buffer and primary surface with GetDC() and use BitBlt. GDI can use hardware accelleration when copying across the bus, so this will be literally twice as fast as using DDraw Blt or doing it in software.

Good luck. =)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by haro
... although I would like to know the FPS other people get. I get about 120 fps on a 2.4ghz P4 with 768mb ram.


Plasma: 128 fps
Starfield: 900 fps

AMD athlon xp 2000
512 mb ram
Geforce3 Ti200




Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by haro
... although I would like to know the FPS other people get. I get about 120 fps on a 2.4ghz P4 with 768mb ram.


Plasma: 128 fps
Starfield: 900 fps

AMD athlon xp 2000
512 mb ram
Geforce3 Ti200


Thanks. That's interesting you have slightly better performance than my setup on the Plasma demo, but significantly less performance on the starfield demo. I have no idea how to explain that.

Share this post


Link to post
Share on other sites

This topic is 4861 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this