Archived

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

initial_y

What BeginScene()/EndScene() really mean?

Recommended Posts

I don''t know what DIRECTX do when BeginScene()/EndScene() were called. So I can''t decide which method is better? 1. BeginScene()/EndScene once, draw all object in the period. 2. To every object call the pair.

Share this post


Link to post
Share on other sites
Some older cards crash if you call BeginScene() twice without a present in between... So, just once.

I do a beginscene, then render all render targets, render the back buffer and present, render to all additional swapchains and present those, then I do an endscene.

Share this post


Link to post
Share on other sites
DX9 doesn''t actually DO anything until EndScene() is called. All state changes and primitives drawn between Begin/End are just queued up and then blasted out at the card in one batch, with (some, perhaps none) optimizations occurring at the driver level for things like vertex buffers, or redundant state changes.

Check the DX9 documentation on IDirect3DDevice9.

---
http://www.gapingwolf.com

Share this post


Link to post
Share on other sites
I believe BeginScene/EndScene exist mostly for the benefit of cards like PowerVR, which cache an entire scene''s worth of draw calls, and render it in small (32x32?) chunks.

xyzzy

Share this post


Link to post
Share on other sites
From the SDK doc:

Applications written in C++ notify Microsoft® Direct3D® that scene rendering is about to begin by calling the IDirect3DDevice9::BeginScene method. IDirect3DDevice9::BeginScene causes the system to check its internal data structures and the availability and validity of rendering surfaces. It also sets an internal flag to signal that a scene is in progress. After you begin a scene, you can call the various rendering methods to render the primitives or individual vertices that make up the objects in the scene. Attempts to call rendering methods when a scene is not in progress fail. For more information, see Rendering Primitives.

After you complete the scene, call the IDirect3DDevice9::EndScene method. The IDirect3DDevice9::EndScene method flushes cached data, verifies the integrity of rendering surfaces, and clears an internal flag that signals when a scene is in progress.


In fact, EndScene() is asynchronous, so it will return after it does it magic -- but the primitives might not actually be drawn on the card yet.

---
http://www.gapingwolf.com

Share this post


Link to post
Share on other sites
another way to look at it, it does end in Scene, meaning.. a group of multiple objects comprised together to make a scene/image/picture...

yeah, most examples ive ever seen draw everything between BeginScene and EndScene.. then Present!

Share this post


Link to post
Share on other sites
Just noticed:
fact, EndScene() is asynchronous, so it will return after it does it magic.

Maybe its a mistype should say immediately if this function is asynchronous.

By definition(MSDN):

Asynchronous call

A call to a function that is executed separately so that the caller can continue processing instructions without waiting for the function to return. Contrast with Synchronous call.

-------
Homepage: http://students.washington.edu/andrey

Share this post


Link to post
Share on other sites
Silly MSDN documents heh, *although* I would imagine after reading this thread that the function is actually synchronous because having it be asynchronus (do they do this with multithreading?) would be insanely difficult, but then again I''m a d3d n00b so what do I know...

Share this post


Link to post
Share on other sites
Why would it be insanely difficult? The DX driver is running in a separate thread anyway; why would this make it the slightest bit harder to implement?


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
It is async. D3D can buffer several frames worth of data, if your code is faster than your GPU. This would never happen if it didn''t return without finishing. All of D3D is async.

Also, D3D doesn''t just buffer until EndScene(). It buffers data, but also renders when there are more than a few vertices to process. EndScene will flush the buffers, but it''s not the only thing that starts rendering to occur. The benefit of a GPU is parallelism, which is lost if you just buffer everything, and then do a syncronous call at the end.

There is a cap entry for no 2d while doing 3d. On such a card, no 2d can be performed between begin and end. This makes debugging difficult, as it will use the 2D acceleration of GDI. New cards don''t have such limitations.

Now, having written this, I think I''ve tracked down a mysterious, occasional visual glitch I get when using dynamic buffers... Since I present, then endscene, I''m not flushing properly. This occurs so rarely it''s been a nightmare to try and track it down, but I think you just made something click! I''ll have to check into this at work in the morning. Thank you noobs!

Share this post


Link to post
Share on other sites
I suppose if all of Direct 3D was asynchronus it wouldn''t be harder... but doesn''t this slow it down a bit? Or did they pull a MMOJ (Mad Microsoft Optimization Job)

Share this post


Link to post
Share on other sites
The quick overview of how D3D works... kinda sorta off topic, but the previous post kinda sorta asked...

Basically all state changes, and render calls are stuffed into a queue. Rendering begins when a) the queue reaches a minimum size, b) a resource in the queue is requested by the app, or c) end scene flushes it.

Locking a resource that is in the queue, such as a VB, or surface, will wait until the resource is no longer in the queue, then return with the resource locked. These are the stalls nVidia and Microsoft talk about and plead you to try to avoid. This is why you''re not supposed to lock a static VB, or lock a texture.

The stuffing into a queue happens syncronously, but the actual rendering is async, happening when the hardware gets to that part of the queue. Switching render targets, rendering primitives, setting texture, render and sampler states, doing present, etc, are all stuffed onto a queue.

Even though the CPU just places things on a queue and returns quickly, the total time to draw a scene can be affected by HOW you place things on the queue. The GPU can draw something else pretty quickly after finishing a previous draw call, providing you don''t change anything between the two calls to draw. Changing states takes a bit more time for the GPU to process (1 state or 20 doesn''t matter, changing states causes a slight GPU stall). Changing textures, render targets, and shaders take a lot longer for the GPU to process.

This is why you''re told to sort by texture, and effect, and why CPU profiling doesn''t show a problem with ignoring this advice... the CPU just queues. The GPU is doing the work, incurring the stall. Because rendering is async, your CPU profiler doesn''t show it at all.

Also, certain drivers limit the number of queued frames (often to 3 frames). Trying to place more data in the queue will stall the CPU until the GPU catches up. In this case you''ll see a large percentage of time spent in Present. This doesn''t really mean Present is taking a long time, it just means that you''re GPU is saturated... you could add more AI, physics, etc, and not affect the frame rate in the slightest.

Share this post


Link to post
Share on other sites