[1] WineD3D: Add the state dirtification infrastructure

Stefan Dösinger stefan at codeweavers.com
Mon Dec 18 12:25:45 CST 2006


Am Montag 18 Dezember 2006 14:06 schrieb Stefan Dösinger:
Another update, it fixes an spotted by Henri issue where the state was used 
instead of the representative and uses shifting and bitmasks to calculate the 
index and shift for the bitmap.

> This is another updated version, it uses bitmaps for the isStateDirty
> member.
>
> Am Sonntag 17 Dezember 2006 14:45 schrieb Stefan Dösinger:
> > Am Freitag 15 Dezember 2006 18:31 schrieb Stefan Dösinger:
> > > This patch adds the dirty list infrastructure. A dirty marker consists
> > > of a DWORD containing the state it marks dirty, and the list structure
> > > to build the list.
> > >
> > > The wined3ddevice has 3 new members:
> > > dirtyStateList: The list of dirty states. This will be moved to a
> > > per-context stucture once we add multithreading support
> > > freeListElems: A list containing unused dirty markers to avoid
> > > unnecessary HeapAlloc/HeapFree calls. I have seen D3D games spending
> > > 15% cpu time in the Heap code, we don't want to increase that.
> > > dirtyStates: An array that tells if a state is dirty. It is used to
> > > avoid double dirtification. I do not use the stateblock->changed.XXXX[]
> > > array because this is used for different purposes in the stateblock
> > > code. Ivan, do we still need it?
> >
> > Attached is an updated patch that uses an array for dirtification instead
> > of a list. Actually there are 2 arrays, one to quickly find out if a
> > specific state is dirty, and one to quickly find all dirty states.
> >
> > Checking if a state is dirty is done very often, so we need the
> > isStateDirty. A linear search on the dirtyArray would take way too much
> > time. On the other hand, my experiance so far shows that usually not more
> > than 10-20 states are dirty at the beginning of a drawprim call, so
> > iterating over all states would be a waste of time too. That's why the
> > dirtyArray is there.
> >
> > In the end there will be around 1000 states, so the size of those arrays
> > will be 8-10 kilobytes. Even oldest games load textures in the area of
> > megabytes, with recent games it's about gigabytes, so I don't think those
> > 10 kb's are an issue :-) . I could easilly change the DWORDs to shorts,
> > but all d3d states are defined as DWORDs, so I decided to use DWORDS.
> >
> > If I used a bitmap I could squeeze the same information in about 128
> > bytes + extra size for the code dealing with the bitmap + extra runtime
> > needs for bit shifting and checking all DWORDs in the bitmap. D3D games
> > are usually cpu limited, so I prefer the more memory intensive version.
> >
> > The other patches should apply cleanly over this patch, so I do not
> > resend them.
-------------- next part --------------
From 1e201d290019d5088de754e51de0d4000811a720 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Mon, 18 Dec 2006 19:23:12 +0100
Subject: [PATCH] WineD3D: Add state dirtification infrastructure

---
 dlls/wined3d/device.c          |   13 +++++++++++++
 dlls/wined3d/drawprim.c        |   12 ++++++++++++
 dlls/wined3d/wined3d_private.h |   20 ++++++++++++++++++++
 3 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 685cdf9..217f666 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -7084,3 +7084,16 @@ const DWORD SavedVertexStates_T[NUM_SAVE
 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
     WINED3DSAMP_DMAPOFFSET
 };
+
+void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
+    DWORD rep = StateTable[state].representative;
+    DWORD idx;
+    BYTE shift;
+
+    if(!rep || isStateDirty(This, rep)) return;
+
+    This->dirtyArray[This->numDirtyEntries++] = rep;
+    idx = rep >> 5;
+    shift = rep & 0x1f;
+    This->isStateDirty[idx] |= (1 << shift);
+}
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index a560084..06a86ae 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -2129,6 +2129,8 @@ void drawPrimitive(IWineD3DDevice *iface
     IWineD3DSwapChainImpl         *swapchain;
     int                           i;
     BOOL                          fixup = FALSE;
+    DWORD                         dirtyState, idx;
+    BYTE                          shift;
 
     BOOL lighting_changed, lighting_original = FALSE;
 
@@ -2163,6 +2165,16 @@ void drawPrimitive(IWineD3DDevice *iface
     /* Ok, we will be updating the screen from here onwards so grab the lock */
     ENTER_GL();
 
+    /* Apply dirty states */
+    for(i=0; i < This->numDirtyEntries; i++) {
+        dirtyState = This->dirtyArray[i];
+        idx = dirtyState >> 5;
+        shift = dirtyState & 0x1f;
+        This->isStateDirty[idx] &= ~(1 << shift);
+        StateTable[dirtyState].apply(dirtyState, This->stateBlock);
+    }
+    This->numDirtyEntries = 0; /* This makes the whole list clean */
+
     if(DrawPrimStrideData) {
 
         /* Note: this is a ddraw fixed-function code path */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index da3fbe9..97b68a0 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -413,6 +413,8 @@ typedef void (*APPLYSTATEFUNC)(DWORD sta
 #define STATE_RENDER(a) (a)
 #define STATE_IS_RENDER(a) ((a) >= STATE_RENDER(1) && (a) <= STATE_RENDER(WINEHIGHEST_RENDER_STATE))
 
+#define STATE_HIGHEST (STATE_RENDER(WINEHIGHEST_RENDER_STATE))
+
 struct StateEntry
 {
     DWORD           representative;
@@ -627,10 +629,28 @@ #define                         NEEDS_DI
 
     /* Final position fixup constant */
     float                       posFixup[4];
+
+    /* State dirtification 
+     * dirtyArray is an array that contains markers for dirty states. numDirtyEntries states are dirty, their numbers are in indices
+     * 0...numDirtyEntries - 1. isStateDirty is a redundant copy of the dirtyArray. Technically only one of them would be needed,
+     * but with the help of both it is easy to find out if a state is dirty(just check the array index), and for applying dirty states
+     * only numDirtyEntries array elements have to be checked, not STATE_HIGHEST states.
+     */
+    DWORD                   dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */
+    DWORD                   numDirtyEntries;
+    DWORD                   isStateDirty[(STATE_HIGHEST + 1) / (sizeof(DWORD) * 8)]; /* Bitmap to find out quickly if a state is dirty */
+
 } IWineD3DDeviceImpl;
 
 extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
 
+void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state);
+static inline BOOL isStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
+    DWORD idx = state >> 5;
+    BYTE shift = state & 0x1f;
+    return This->isStateDirty[idx] & (1 << shift);
+}
+
 /* Support for IWineD3DResource ::Set/Get/FreePrivateData. I don't think
  * anybody uses it for much so a good implementation is optional. */
 typedef struct PrivateData
-- 
1.4.2.4



More information about the wine-patches mailing list