State management in D3D

Stefan Dösinger stefandoesinger at gmx.at
Mon Sep 11 11:03:04 CDT 2006


Hi,
> Ok, so the main idea is to separate the applying of GL state from the
> tracking of D3D state. Looks like a good idea.
Fully agreed

> What I would like to 
> add to that is something BBrox mentioned on IRC a while back...
> grouping related states together and marking that group dirty / clean.
> That way we would get a tree like structure for the states, which
> would make checking what states changed and need to be applied
> somewhat faster. While it would be possible to add that afterwards, I
> think it would be easier to just take it into account when designing
> the new stateblock structure.
I think we should do the change quicky, even if we risk regressions. I do not 
think that we should add comments stating "if you add new gl stuff add it to 
<new file.c>". But I think none of you wants that :-) What we can do for sure 
is to move render states, sampler states, matriced and bound shaders 
seperately, which we should do to keep patches small :-)

> > I don't like the way things are done right now - Set* functions can do
> > one of two things - record to a stateblock, or apply state. Then the
> > stateblock calls the Set* functions itself when it's applied - seems
> > very ugly to me [ and also in certain places we're forced to disable
> > recording to get a state applied immediately using a Set* function ].
>
> You always record to a stateblock, be it the main device stateblock or
> the update stateblock, but yes, it's pretty ugly.

Let me illustrate my idea:

* Move out the GL calls from Set*State. Set*State writes the values to the 
update stateblock and updates the refcounts(maybe we should kick internal 
refcounting from wined3d altogether)

* Keep the stateblock and update stateblock structure as they are now. I think 
for recording stateblocks the idea is quite good

* Keep a list of dirty states for each gl context in use: We don't need 
something as fancy as trees for that, a little array can do the job, like 
this(example for render states, but can be used for all other stuff too):

WINED3DRENDERSTATETYPE updatedStates[WINEHIGHEST_RENDER_STATE]
DWORD numDirtyStates;

SetRenderState(device, state, newValue) sets updatedStates[numDirtyStates] = 
state for each context and increments numDirtyStates. It doesn't store the 
value of the state.

In drawprim we have a loop
for(i = 0; i < numDirtyStates; i++)
{
	set_render_state(updatedStates[i]);
}
numDirtyStates = 0;

set_render_state does the opengl stuff. We can put that function into 
drawprim.c or a new file, e.g. opengl_utils.c like in old ddraw.

This concept can be optimized a bit: To group common states we can do that:

static const WINED3DRENDERSTATETYPE stategroup[] =
{
	/*0*/				0,
	/*WINED3DRS_TEXTUREHANDLE*/	0,
	/*WINED3DRS_ANTIALIAS*/		WINED3DRS_ANTIALIAS,
	...
	/*WINED3DRS_TEXTUREMAPBLEND*/	0,
	...
	/*WINED3DRS_FOGENABLE*/		WINED3DRS_FOGENABLE,
	...
	/*WINED3DRS_FOGCOLOR*/		WINED3DRS_FOGCOLOR,
	/*WINED3DRS_FOGTABLEMODE*/	WINED3DRS_FOGTABLEMODE
	/*WINED3DRS_FOGSTART*/		WINED3DRS_FOGTABLEMODE
	/*WINED3DRS_FOGEND*/		WINED3DRS_FOGTABLEMODE
	/*WINED3DRS_FOGDENSITY*/	WINED3DRS_FOGDENSITY,
	...
	/*WINED3DRS_FOGVERTEXMODE*/	WINED3DRS_FOGTABLEMODE
	...
	/*WINED3DRS_BLENDOPALPHA*/	WINED3DRS_BLENDOPALPHA
};
	
The current code applies FOGVERTEXMODE and FOGTABLEMODE in the same code, 
because the resulting gl values depend on both states. Also the applied fog 
range is important for this, even if we do not have it in the same group 
right now. (How come? looks buggy to me. Well, I was the one who did that). 
WINED3DRS_TEXTUREHANDLE and WINED3DRS_TEXTUREMAPPEDBLEND are legacy states 
which are wrapped to SetTexture and SetTextureStageState in ddraw.dll, so 
wined3d doesn't have to deal with them. We set them to 0 and cry bloody 
murder if such a state is applied.

With this modification SetRenderState would set updatedStates[numDirtyStates] 
= stategroup[state]; The little drawback is that we have 209 DWORDs hanging 
around, with some of them beeing plain useless. Well, that are 836 Bytes, and 
we safe some of them because set_render_state needs less case WINED3DRS_FOO: 
marks.

The above optimization doesn't bring much yet. Instead of applying 4 different 
fog states we apply FOGENABLE 4 times. But we can change the .changed field 
for each state in the stateblock to a changed[num contexts] array(dynamically 
allocated preferably). It is set to true when the state is changed the first 
time, and set to 0 when set_render_state applies the gl state. When it is 
TRUE already for the context then SetRenderState doesn't have to put the 
state again onto the change list. This way we can limit the size of the 
changed state array to WINEHIGHEST_RENDER_STATE too :-)

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20060911/80f77659/attachment-0001.pgp


More information about the wine-devel mailing list