Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Nostalgia

DirectDraw Flip() woes

This topic is 5259 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

Hey all. I''ve been having a problem with Flip() forever, and no one has been able to help me. I figure I''ll try again and see if anyone has seen this problem. This is a legacy DX8 app that uses DirectDraw. The problem I''m having is, if I use Flip() to get the backbuffer surface to the front, it blocks until the next screen refresh (60hz on my monitor). This is unacceptable in my app. If I use Blt() to copy the backbuffer to the primary surface, it runs as fast as I''d like, but introduces motion artifacts, since it''s not drawing on a retrace. So, is there a way to use Flip() in such a way that it doesn''t block, but still draws on the retrace? Thanks, -Joe

Share this post


Link to post
Share on other sites
Advertisement
I''m a little hazy, but I think you can do this:

if(lpDDSPrimary->GetFlipStatus(DDGFS_CANFLIP)==DD_OK)
{
lpDDSPrimary->Flip();
}

Here is the MSDN page.

Are you trying to set up your render loop so that if the primary surface is not ready you can do AI or physics instead of waiting for vsync?

Share this post


Link to post
Share on other sites
"Are you trying to set up your render loop so that if the primary surface is not ready you can do AI or physics instead of waiting for vsync?"

Something like it. It''s a console emulator, so it''s got a set speed it should run at. The engine generates video frames at about 60hz (actually 59.something), and there''s tons of processing that needs to be done between frames. Basically I''d like to draw the scene and flip it, regardless of where in the VSYNC cycle I am. That way I can do other engine processing while it''s waiting to Flip(). I know I''m running fast enough, because when I use Blt() instead of Flip(), I get about 255 fps.

Do you think triple buffering could help me out? I haven''t done much reading on it, yet.

Thanks,

-Joe

Share this post


Link to post
Share on other sites
My experience is up to DX7, but I don''t think anything has changed much in DDraw.

The flip call shouldn''t block unless you tell it to with the DDFLIP_WAIT flag. Without that flag, it should either setup the flip and return, or return an error.

All that the flip call should do is setup the flip to occur at the next retrace. It doesn''t block until the retrace, even with the FLIP_WAIT flag. The wait flag forces it to block until the flip can be setup. I think the only real time that a flip can''t be setup immediately is when you''re trying to flip, and the previous flip is still waiting to be done (i.e. you''re program is way ahead of the flipping cycle time, which will occur if it can run at 255fps).

My memory of triple buffering is fuzzy, but I don''t think you''ll get much out of it. Its intended more for applications that are just barely missing the retrace (running too slow). As long you are doing all the program logic first in the game loop, followed by rendering to the back buffer, I think you''re running as fast as you can. But since you''re running too fast already, I don''t see the problem.

Also, you can always tell the flip call to flip immediately instead of waiting for the retrace using DDFLIP_NOVSYNC, but that will get you back to screen tearing.

Share this post


Link to post
Share on other sites
When using Flip() you can use the DDFLIP_NOVSYNC as flag to avoid it waiting for vsync, but then it can, of course, suffer from artifacts... Perhaps less severe than Blt though, because the change is instantaneous...

Like CodeMunkie said, to do this, you have to use a way to know if you can flip... There are a couple of ways:

Either you:

1. Try to flip when you know you''re ready and specify the flag DDFLIP_DONOTWAIT, and if it returns DDERR_WASSTILLDRAWING, continue your process and retry flipping until it works, because this way, it should flip when no flip is still pending or return the error, if the last flip is still not finished. It should not block your program like this.

or

2. Use CodeMunkie''s GetFlipStatus, which will, more or less, do the same thing as previous.

Share this post


Link to post
Share on other sites
I am specifying DDFLIP_DONOTWAIT. It still blocks until the retrace. How do I know? It runs 255fps with Blt(). It runs 60fps with Flip(DDFLIP_DONOTWAIT). I changed my monitor''s refresh rate to 75hz, and lo and behold, my emulator ran at 75fps.

I''ve also tried:

if (lpddsprimary->GetFlipStatus(DDGFS_CANFLIP) == DD_OK)
{
hr = lpddsprimary->Flip(NULL, DDFLIP_DONOTWAIT);
}
else
{
Log("Cannot flip");
}

And I never see "Cannot flip" in my logfile.

Could it be in the way I create the surfaces? Here''s my creation code (extensive error checking removed for clarity):

lpdd->SetDisplayMode(dwWidth, dwHeight, 16, 0, 0);

memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_VIDEOMEMORY;

lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);

ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback);

-Joe

Share this post


Link to post
Share on other sites
Well, no matter what, if you don't include the DDFLIP_NOVSYNC flag, the most fps you'll get is the monitor refresh rate, so that's no mystery. I wouldn't immediately assume the flip is blocking though. Stick a timer around it to see how long the call takes. It should not block.

Maybe a blitting call is blocking. If you tell the primary to flip, and then go and try to draw to the back surface, it will either block there or return an error (depending on what flag you use there I believe), because since the back buffer you want to draw to is still the primary (being displayed), DX won't let you draw to it. So that could block until the first flip physically occurs, and then you would draw to the back buffer and the next flip call would return OK immediately. You could use triple buffering to get one more frame ahead, but I don't see how that would really help any.

I still don't see what you are trying to accomplish. You are running way faster then the refresh already. Without turning off vertical syncing, you can't improve the framerate anymore. And therefore somewhere along the line you're program will need to wait for the retrace before continuing, whether you let DX block or do it in your app.

[edited by - Rock2000 on March 25, 2004 12:02:06 AM]

Share this post


Link to post
Share on other sites
Rock:

Well, the problem is, the emulator''s engine spits out just about 60 video frames per second. This means if Flip() is waiting for VSYNC, that leaves me very little time to do the engine processing between frames. This particular engine runs 14000 cpu cycles per video frame. That''s quite a bit of processing that needs to be done. In addition, the controllers are polled each video frame as well. So, when using Flip(), the emulator is noticeably slowed down.

What I''m trying to accomplish exactly is for the Flip() to just fail if it''s busy, or get performed asynchronously. I wouldn''t mind dropping 2 or 3 frames per second to get the performance I need. So, I''m not trying to get a faster frame rate, I''m trying to buy myself more time to process between frames.

Interesting point about the Blt(). I''m not too sure, though. The only time I perform a Blt() is *immediately* before Flipping the surface. The rest of my processing is done on a memory buffer. All my blts are performed DDBLT_ASYNC, as well.

Thanks for the suggestions,

-Joe

Share this post


Link to post
Share on other sites
As long as you are performing all non-ddraw logic after the flip, which it sounds like you are, I think you''re good. The only times I can think of that you will hit a wall and have to wait are when calling a Blt func, Lock, or Flip. And generally the Blt/Lock will want to block rather then the flip when using vsync, since they''re done first. In your case, I think triple buffers might help get a fraction ahead. In that case, after the Flip call, you should still be able to render to the new Back buffer, since that 3rd buffer isn''t being displayed, and isn''t queued to be displayed, its available. But when you go to Flip that one and the last flip is still waiting, you''ll have to wait there. So you can get get the extra performance of rendering to the back buffer earlier, which you couldn''t with just 2 buffers. At 60fps it shouldn''t be a problem, but just be aware that this increases the input latency a LITTLE, since the user is seeing a frame that you built 2 frames ago with the input they entered 2 frames ago, or something like that.

There are comparable wait flags for Blt (not sure if waiting or not waiting is the default) you can use. I''m not really sure what the ASYNC flag does. I don''t know what DX is supposed to do if you don''t specify it, but it isn''t meant as a wait flag. And I THINK the Blt error you''ll get when trying to render to the back buffer that is still being displayed is SURFACE_BUSY, which doesn''t look like its covered by the wait flags anyways. Make sure you check the return codes.

Like I said, I doubt the flip is blocking, but if you want to be sure who is blocking, but a few timers around some functions and log the time they take to return. That will clearly show who the culprit it. My only guess is Blt or Lock.

Share this post


Link to post
Share on other sites
I''ll try the timing thing, since I''m curious. I''ll post some results this evening, if I can get some time to work on it.

I''m using the DDBLT_DONOTWAIT and DDBLT_ASYNC flags on all my Blt()s. The DDBLT_ASYNC flag, according to MSDN:
"Performs this blit asynchronously through the first in, first out (FIFO) hardware in the order received. If no room is available in the FIFO hardware, the call fails."

I''m also using the DDLOCK_DONOTWAIT flag on my Lock() call.

I check return values on everything. According to my logfile, none of the DD functions are returning anything but DD_OK. Very strange. I''ll check the timings tonight, and double check my error handling logic, and we''ll be sure. There''s only 1 lock, 2 blts and a flip, so shouldn''t be too hard.

Is it possible for DirectDraw to affect DirectSound? I wouldn''t think so, but I''ve been surprised before.

-Joe

Nostalgia, an Intellivision Emulator
http://www.gotmaille.com/nostalgia/

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!