[1] WineD3D: Add the state dirtification infrastructure

Stefan Dösinger stefan at codeweavers.com
Sun Dec 17 07:45:38 CST 2006


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 7692ddd58b4ecf07a045c8887b0efa67014bef93 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sun, 17 Dec 2006 14:12:12 +0100
Subject: [PATCH] WineD3D: Add state dirtification infrastructure

---
 dlls/wined3d/device.c          |   14 +++++++++++++-
 dlls/wined3d/drawprim.c        |    9 +++++++++
 dlls/wined3d/wined3d_private.h |   15 +++++++++++++++
 3 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index ff3c987..5923634 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -568,6 +568,7 @@ static ULONG WINAPI IWineD3DDeviceImpl_R
     TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
 
     if (!refCount) {
+
         if (This->fbo) {
             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
         }
@@ -604,7 +605,6 @@ static ULONG WINAPI IWineD3DDeviceImpl_R
             dumpResources(This->resources);
         }
 
-
         IWineD3D_Release(This->wineD3D);
         This->wineD3D = NULL;
         HeapFree(GetProcessHeap(), 0, This);
@@ -7088,3 +7088,15 @@ 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;
+
+    if(!rep || This->isStateDirty[rep]) return;
+
+    This->dirtyArray[This->numDirtyEntries++] = rep;
+    /* Store the index of the dirty marker + 1 in the isStateDirty array. This will not only allow us to find out if
+     * a state is dirty, but also remove the dirty marker selectively from the list without marking everything clean.
+     */
+    This->isStateDirty[rep] = This->numDirtyEntries;
+}
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index a560084..4ec3dce 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -2129,6 +2129,7 @@ void drawPrimitive(IWineD3DDevice *iface
     IWineD3DSwapChainImpl         *swapchain;
     int                           i;
     BOOL                          fixup = FALSE;
+    DWORD                         dirtyState;
 
     BOOL lighting_changed, lighting_original = FALSE;
 
@@ -2163,6 +2164,14 @@ 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];
+        This->isStateDirty[dirtyState] = 0;
+        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 2f5e887..0d3edd2 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,23 @@ #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]; /* To find out quickly if a state is dirty */
+
 } IWineD3DDeviceImpl;
 
 extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl;
 
+void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state);
+
 /* 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