Re: State management in D3D

2006-09-12 Thread Stefan Dösinger
Am Montag 11 September 2006 23:36 schrieb H. Verbeet:
 On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
  Am Montag 11 September 2006 19:56 schrieb H. Verbeet:
   On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
That's what I'd use the state.changed field for. Set it to TRUE when
the state is first modified and to FALSE when it it applied to gl. Do
not add the state to the list of changes whn state.changed == TRUE
  
   Well, sure, that's what the constants loading code does as well, but I
   still like a list better :-)
 
  What would the list look like? Lionel was talking about some tree.

 That's not related to the trees thing, but your proposal with a list
 instead of a fixed size array.

 (the changed marker
  can store the position + 1)

 Instead of a boolean dirty flag, you could store a pointer to the list
 element :-)
Yeah, but we still can't remove the entry. Or wait, set it to 0 and implement 
state 0 as a nop-apply :-)


pgpSq5oMrrJBb.pgp
Description: PGP signature



Re: State management in D3D

2006-09-12 Thread H. Verbeet

On 12/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:

Yeah, but we still can't remove the entry. Or wait, set it to 0 and implement
state 0 as a nop-apply :-)

Why wouldn't you be able to remove an entry from a list?




Re: State management in D3D

2006-09-12 Thread Stefan Dösinger
Am Dienstag 12 September 2006 18:13 schrieb H. Verbeet:
 On 12/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
  Yeah, but we still can't remove the entry. Or wait, set it to 0 and
  implement state 0 as a nop-apply :-)

 Why wouldn't you be able to remove an entry from a list?
With the array, we can only truly remove a single element by moving all other 
entries by one, reducing the total amount of entries and adjusting all values 
that specify a list index. This is possible, but the amount of work needed is 
growing linearly with the numbers of elements in the list.

However, we can set the to delete value to 0, and if our apply function hits 
the state 0 to apply, it just continues with the next state :-) It is not 
truly removed then, but this works too and is much cheaper.


pgpx4F4SyzWve.pgp
Description: PGP signature



Re: State management in D3D

2006-09-12 Thread H. Verbeet

On 12/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:

 Why wouldn't you be able to remove an entry from a list?
With the array, we can only truly remove a single element by moving all other
entries by one, reducing the total amount of entries and adjusting all values
that specify a list index. This is possible, but the amount of work needed is
growing linearly with the numbers of elements in the list.

An array is not the same as a list... :-)




Re: State management in D3D

2006-09-11 Thread H. Verbeet

On 11/09/06, Ivan Gyurdiev [EMAIL PROTECTED] wrote:

I guess that seems like a large undertaking, and those are all doomed to
failure.. but it doesn't have to be.

The key idea that I care about seems to be to move GL code from device.c
into the data structure object, and figure out a way to apply a set of
delayed states at draw time. We don't have to replace everything right
now - we could have 2 coexisting data structures and slowly move things
from one to the other, but I wanted to see if people agree with that idea.

Ok, so the main idea is to separate the applying of GL state from the
tracking of D3D state. Looks like a good idea. 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 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.




Re: State management in D3D

2006-09-11 Thread Stefan Dösinger
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 :-)



pgpu3pUbq7xI9.pgp
Description: PGP signature



Re: State management in D3D

2006-09-11 Thread H. Verbeet

On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:

* 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):

You would at least need to use a proper list. Consider an application
that sets the same state multiple times. Note that what you're
proposing is pretty similar (in basis) to the way we currently handle
shader constants loading.




Re: State management in D3D

2006-09-11 Thread Stefan Dösinger
Am Montag 11 September 2006 18:41 schrieb H. Verbeet:
 On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
  * 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):

 You would at least need to use a proper list. Consider an application
 that sets the same state multiple times. Note that what you're
 proposing is pretty similar (in basis) to the way we currently handle
 shader constants loading.
That's what I'd use the state.changed field for. Set it to TRUE when the state 
is first modified and to FALSE when it it applied to gl. Do not add the state 
to the list of changes whn state.changed == TRUE


pgpSgKUirPgao.pgp
Description: PGP signature



Re: State management in D3D

2006-09-11 Thread H. Verbeet

On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:

That's what I'd use the state.changed field for. Set it to TRUE when the state
is first modified and to FALSE when it it applied to gl. Do not add the state
to the list of changes whn state.changed == TRUE

Well, sure, that's what the constants loading code does as well, but I
still like a list better :-)




Re: State management in D3D

2006-09-11 Thread Stefan Dösinger
Am Montag 11 September 2006 19:56 schrieb H. Verbeet:
 On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
  That's what I'd use the state.changed field for. Set it to TRUE when the
  state is first modified and to FALSE when it it applied to gl. Do not add
  the state to the list of changes whn state.changed == TRUE

 Well, sure, that's what the constants loading code does as well, but I
 still like a list better :-)
What would the list look like? Lionel was talking about some tree.

How would the complexity of the various operations compare? With an array and 
the chaned marker we have constant complexity for adding an element, 
determining if the list is empty, finding an element(the changed marker can 
store the position + 1) and emptiying the list. That is, I think, everything 
we need. We can't cheaply remove a single state from the dirty list, but I 
don't think we need this.


pgpxWBeb6IW3G.pgp
Description: PGP signature



Re: State management in D3D

2006-09-11 Thread H. Verbeet

On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:

Am Montag 11 September 2006 19:56 schrieb H. Verbeet:
 On 11/09/06, Stefan Dösinger [EMAIL PROTECTED] wrote:
  That's what I'd use the state.changed field for. Set it to TRUE when the
  state is first modified and to FALSE when it it applied to gl. Do not add
  the state to the list of changes whn state.changed == TRUE

 Well, sure, that's what the constants loading code does as well, but I
 still like a list better :-)
What would the list look like? Lionel was talking about some tree.

That's not related to the trees thing, but your proposal with a list
instead of a fixed size array.


How would the complexity of the various operations compare? With an array and
the chaned marker we have constant complexity for adding an element,
determining if the list is empty, finding an element(the changed marker can
store the position + 1) and emptiying the list. That is, I think, everything
we need. We can't cheaply remove a single state from the dirty list, but I
don't think we need this.

Instead of a boolean dirty flag, you could store a pointer to the list
element :-)




Re: State management in D3D

2006-09-10 Thread Ivan Gyurdiev
I guess that seems like a large undertaking, and those are all doomed to 
failure.. but it doesn't have to be.


The key idea that I care about seems to be to move GL code from device.c 
into the data structure object, and figure out a way to apply a set of 
delayed states at draw time. We don't have to replace everything right 
now - we could have 2 coexisting data structures and slowly move things 
from one to the other, but I wanted to see if people agree with that idea.


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 ].