[1] WineD3D: Add the state dirtification infrastructure

Stefan Dösinger stefan at codeweavers.com
Fri Dec 15 11:31:52 CST 2006


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?
-------------- next part --------------
From e1e113df65c888a14d8a54bc073a15858b4fd986 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Fri, 15 Dec 2006 17:46:47 +0100
Subject: [PATCH] WineD3D: Add state dirtification infrastructure

---
 dlls/wined3d/device.c          |   36 ++++++++++++++++++++++++++++++++++++
 dlls/wined3d/directx.c         |    3 +++
 dlls/wined3d/drawprim.c        |   10 ++++++++++
 dlls/wined3d/wined3d_private.h |   17 +++++++++++++++++
 4 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index ff3c987..af6876a 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -568,6 +568,8 @@ static ULONG WINAPI IWineD3DDeviceImpl_R
     TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
 
     if (!refCount) {
+        struct list *entry, *entry2;
+
         if (This->fbo) {
             GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
         }
@@ -604,6 +606,19 @@ static ULONG WINAPI IWineD3DDeviceImpl_R
             dumpResources(This->resources);
         }
 
+        /* Free the dirty state list and the free elem list */
+        LIST_FOR_EACH_SAFE(entry, entry2, &This->dirtyStateList)
+        {
+            struct dirtyMarker *marker = LIST_ENTRY(entry, struct dirtyMarker, entry);
+            list_remove(&marker->entry);
+            HeapFree(GetProcessHeap(), 0, marker);
+        }
+        LIST_FOR_EACH_SAFE(entry, entry2, &This->freeListElems)
+        {
+            struct dirtyMarker *marker = LIST_ENTRY(entry, struct dirtyMarker, entry);
+            list_remove(&marker->entry);
+            HeapFree(GetProcessHeap(), 0, marker);
+        }
 
         IWineD3D_Release(This->wineD3D);
         This->wineD3D = NULL;
@@ -7088,3 +7103,24 @@ 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;
+    struct list *ret;
+    struct dirtyMarker *marker;
+
+    if(!rep || This->dirtyStates[rep]) return;
+
+    /* Look if there is an element in our free elem list, otherwise alloc a new one */
+    ret = list_head(&This->freeListElems);
+    if(!ret) {
+        TRACE("creating new elem\n");
+        marker = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dirtyMarker));
+    } else {
+        list_remove(ret);
+        marker = LIST_ENTRY(ret, struct dirtyMarker, entry);
+    }
+    marker->state = rep;
+    list_add_tail(&This->dirtyStateList, &marker->entry);
+    This->dirtyStates[rep] = TRUE;
+}
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 6e97cc3..b592c01 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2458,6 +2458,9 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     object->ddraw_format = pixelformat_for_depth(GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES));
     DeleteDC(hDC);
 
+    list_init(&object->dirtyStateList);
+    list_init(&object->freeListElems);
+
     return WINED3D_OK;
 create_device_error:
 
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index a560084..38042ec 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;
+    struct list                   *entry;
+    struct dirtyMarker            *dirtyState;
 
     BOOL lighting_changed, lighting_original = FALSE;
 
@@ -2163,6 +2165,14 @@ void drawPrimitive(IWineD3DDevice *iface
     /* Ok, we will be updating the screen from here onwards so grab the lock */
     ENTER_GL();
 
+    /* Apply dirty states */
+    LIST_FOR_EACH(entry, &This->dirtyStateList) {
+        dirtyState = LIST_ENTRY(entry, struct dirtyMarker, entry);
+        This->dirtyStates[dirtyState->state] = 0;
+        StateTable[dirtyState->state].apply(dirtyState->state, This->stateBlock);
+    }
+    list_move_tail(&This->freeListElems, &This->dirtyStateList);
+
     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..5025fd0 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;
@@ -422,6 +424,13 @@ struct StateEntry
 /* Global state table */
 extern const struct StateEntry StateTable[];
 
+/* Functions for state dirtification */
+struct dirtyMarker
+{
+    struct list entry;
+    DWORD state;
+};
+
 /* Routine to fill gl caps for swapchains and IWineD3D */
 BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display);
 
@@ -627,10 +636,18 @@ #define                         NEEDS_DI
 
     /* Final position fixup constant */
     float                       posFixup[4];
+
+    /* State dirtification. */
+    struct list             dirtyStateList; /* TODO: Move this into the ctx */
+    struct list             freeListElems;  /* To avoid too much alloc / free calls */
+    DWORD                   dirtyStates[STATE_HIGHEST + 1];
+
 } 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