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