[1] WineD3D: Add the state dirtification infrastructure
Stefan Dösinger
stefan at codeweavers.com
Mon Dec 18 07:06:34 CST 2006
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 32a965996947d9a984c9313175b7575f6a5f29dd Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Mon, 18 Dec 2006 13:49:38 +0100
Subject: [PATCH] WineD3D: Add state dirtification infrastructure
---
dlls/wined3d/device.c | 15 ++++++++++++++-
dlls/wined3d/drawprim.c | 12 ++++++++++++
dlls/wined3d/wined3d_private.h | 20 ++++++++++++++++++++
3 files changed, 46 insertions(+), 1 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index ff3c987..94a6580 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,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 / (sizeof(DWORD) * 8);
+ shift = state - idx * sizeof(DWORD) * 8;
+ This->isStateDirty[idx] |= (1 << shift);
+}
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index a560084..0657ff7 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 / (sizeof(DWORD) * 8);
+ shift = dirtyState - idx * sizeof(DWORD) * 8;
+ 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 2f5e887..f86ce27 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 / (sizeof(DWORD) * 8);
+ BYTE shift = state - idx * sizeof(DWORD) * 8;
+ 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