State management in D3D

Ivan Gyurdiev ivg231 at gmail.com
Sun Sep 10 19:22:49 CDT 2006


State management in D3D... is currently kind of a mess.
Stefan D. posted a message about this some time ago, but I can't find it 
right now...

- some states are applied immediately (via Set* calls)
- some are applied at draw time (like shaders, textures, transforms, ...)
- some are recorded into a stateblock structure, and applied when the 
app says apply().
- the GL code is all over the place, tightly coupled to the d3d code.

===============================
There's a number of projects going on at the moment, from what I understand:

- Roderick is working on making wined3d -> wgl
- Stefan D. has expressed concern about multithreaded d3d (where  the 
D3D device state is shared, but not necessarily the GL one - or can GL 
contexts be shared between multiple threads?)
- I'm trying to get FBOs to work, where the FBO needs to be bound once 
both the render and stencil target have been assigned (that's 2 calls 
from the app in any order) - i.e I need those states to be applied in a 
delayed fashion, before draw
- Henri Verbeet wants multiple render target support added to that 
(meaning the FBO needs to be bound once *all* render targets are 
assigned in addition to the depth/stencil one).
================================
All of the above have a common theme - better state management is 
needed, with more encapsulation, and better separation between D3D and GL.
So, let's come up with a plan, and try to implement it. How about we 
redesign the stateblock object like this:

- remove deltas. I.E. if a SetLightEnable() command is sent, fetch the 
light, enable it, then save the light back - store only state, and no 
deltas.
  This should make the recording stateblock (updateStateBlock) the same 
as the initial device stateblock, which stores states

- provide a uniform internal interface for accessing states inside the 
stateblock - like:
      SetState(stateblock, ID_XYZ, (void*) state_data);
      GetState(stateblock, ID_XYZ, (void**) state_data);
      CaptureState(stateblock, ID_XYZ);
      ApplyState(stateblock, ID_XYZ);

ID_XYZ could be an individual state, or a "trigger" keyword, which will 
refer to a whole group of states.
Those would be private functions in addition to the standard interface.

- provide a fn pointer table inside the stateblock [ which can be 
directed to OGL or WGL or AGL ],
  which, for each ID_XYZ, maps a get and set function using the same 
interface

- move all device.c GL code into those functions

- now all device.c Get* and Set* requests will do is:
       - error checking
       - recording into updateStateBlock
       - or writing to stateBlock (which may be applied later, at our 
discretion).

- apply() would just loop through all the IDs and call the corresponding 
function pointer if the states are marked dirty (we'll keep the 'dirty' 
field)

- capture() would do the same in the get* direction.

- new object can be instantiated per device, or per device per thread to 
address multithreading.
  It could have an associated glContext, and can be locked as necessary.

- it would use ideas from the d3d9 test framework for stateblock, except 
of course more competently written, and cleaner :)







More information about the wine-devel mailing list