[PATCH 5/6] ddraw: Use a less offensive handle table implementation for materials.

Henri Verbeet hverbeet at codeweavers.com
Thu Jul 29 05:56:57 CDT 2010


IDirect3DDeviceImpl_CreateHandle() is particular is just awful.
---
 dlls/ddraw/ddraw_private.h |   30 +++++++++++-
 dlls/ddraw/device.c        |   63 ++++++++++++-------------
 dlls/ddraw/direct3d.c      |   10 ++++
 dlls/ddraw/executebuffer.c |   26 ++++------
 dlls/ddraw/main.c          |  111 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/material.c      |   13 ++---
 dlls/ddraw/viewport.c      |   34 ++++++--------
 7 files changed, 213 insertions(+), 74 deletions(-)

diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index 789c163..e5e6ff4 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -326,7 +326,6 @@ typedef enum
 {
     DDrawHandle_Unknown       = 0,
     DDrawHandle_Texture       = 1,
-    DDrawHandle_Material      = 2,
     DDrawHandle_Matrix        = 3,
     DDrawHandle_StateBlock    = 4
 } DDrawHandleTypes;
@@ -337,6 +336,34 @@ struct HandleEntry
     DDrawHandleTypes      type;
 };
 
+#define DDRAW_INVALID_HANDLE ~0U
+
+enum ddraw_handle_type
+{
+    DDRAW_HANDLE_FREE,
+    DDRAW_HANDLE_MATERIAL,
+};
+
+struct ddraw_handle_entry
+{
+    void *object;
+    enum ddraw_handle_type type;
+};
+
+struct ddraw_handle_table
+{
+    struct ddraw_handle_entry *entries;
+    struct ddraw_handle_entry *free_entries;
+    UINT table_size;
+    UINT entry_count;
+};
+
+BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size) DECLSPEC_HIDDEN;
+void ddraw_handle_table_destroy(struct ddraw_handle_table *t) DECLSPEC_HIDDEN;
+DWORD ddraw_allocate_handle(struct ddraw_handle_table *t, void *object, enum ddraw_handle_type type) DECLSPEC_HIDDEN;
+void *ddraw_free_handle(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type) DECLSPEC_HIDDEN;
+void *ddraw_get_object(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type) DECLSPEC_HIDDEN;
+
 struct IDirect3DDeviceImpl
 {
     /* IUnknown */
@@ -376,6 +403,7 @@ struct IDirect3DDeviceImpl
     /* Handle management */
     struct HandleEntry      *Handles;
     DWORD                    numHandles;
+    struct ddraw_handle_table handle_table;
     D3DMATRIXHANDLE          world, proj, view;
 };
 
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index f120bf3..fee434e 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -382,14 +382,6 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
                     }
                     break;
 
-                    case DDrawHandle_Material:
-                    {
-                        IDirect3DMaterialImpl *mat = This->Handles[i].ptr;
-                        FIXME("Material handle %d not unset properly\n", i + 1);
-                        mat->Handle = 0;
-                    }
-                    break;
-
                     case DDrawHandle_Matrix:
                     {
                         /* No fixme here because this might happen because of sloppy apps */
@@ -414,6 +406,31 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
 
         HeapFree(GetProcessHeap(), 0, This->Handles);
 
+        for (i = 0; i < This->handle_table.entry_count; ++i)
+        {
+            struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
+
+            switch (entry->type)
+            {
+                case DDRAW_HANDLE_FREE:
+                    break;
+
+                case DDRAW_HANDLE_MATERIAL:
+                {
+                    IDirect3DMaterialImpl *m = entry->object;
+                    FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
+                    m->Handle = 0;
+                    break;
+                }
+
+                default:
+                    FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
+                    break;
+            }
+        }
+
+        ddraw_handle_table_destroy(&This->handle_table);
+
         TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target);
         /* Release the render target and the WineD3D render target
          * (See IDirect3D7::CreateDevice for more comments on this)
@@ -3048,35 +3065,17 @@ IDirect3DDeviceImpl_3_SetLightState(IDirect3DDevice3 *iface,
     EnterCriticalSection(&ddraw_cs);
     if (LightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */)
     {
-        IDirect3DMaterialImpl *mat;
-
-        if(Value == 0) mat = NULL;
-        else if(Value > This->numHandles)
-        {
-            ERR("Material handle out of range(%d)\n", Value);
-            LeaveCriticalSection(&ddraw_cs);
-            return DDERR_INVALIDPARAMS;
-        }
-        else if(This->Handles[Value - 1].type != DDrawHandle_Material)
+        IDirect3DMaterialImpl *m = ddraw_get_object(&This->handle_table, Value - 1, DDRAW_HANDLE_MATERIAL);
+        if (!m)
         {
-            ERR("Invalid handle %d\n", Value);
+            WARN("Invalid material handle.\n");
             LeaveCriticalSection(&ddraw_cs);
             return DDERR_INVALIDPARAMS;
         }
-        else
-        {
-            mat = This->Handles[Value - 1].ptr;
-        }
 
-        if (mat != NULL)
-        {
-            TRACE(" activating material %p.\n", mat);
-            mat->activate(mat);
-        }
-        else
-        {
-            FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
-        }
+        TRACE(" activating material %p.\n", m);
+        m->activate(m);
+
         This->material = Value;
     }
     else if (LightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */)
diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c
index a95965e..e213e24 100644
--- a/dlls/ddraw/direct3d.c
+++ b/dlls/ddraw/direct3d.c
@@ -808,6 +808,14 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 *iface,
     object->Handles = NULL;
     object->numHandles = 0;
 
+    if (!ddraw_handle_table_init(&object->handle_table, 64))
+    {
+        ERR("Failed to initialize handle table.\n");
+        HeapFree(GetProcessHeap(), 0, object);
+        LeaveCriticalSection(&ddraw_cs);
+        return DDERR_OUTOFMEMORY;
+    }
+
     object->legacyTextureBlending = FALSE;
 
     /* This is for convenience */
@@ -818,6 +826,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 *iface,
     if(!IndexBufferParent)
     {
         ERR("Allocating memory for an index buffer parent failed\n");
+        ddraw_handle_table_destroy(&object->handle_table);
         HeapFree(GetProcessHeap(), 0, object);
         LeaveCriticalSection(&ddraw_cs);
         return DDERR_OUTOFMEMORY;
@@ -837,6 +846,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 *iface,
     if(FAILED(hr))
     {
         ERR("Failed to create an index buffer\n");
+        ddraw_handle_table_destroy(&object->handle_table);
         HeapFree(GetProcessHeap(), 0, object);
         LeaveCriticalSection(&ddraw_cs);
         return hr;
diff --git a/dlls/ddraw/executebuffer.c b/dlls/ddraw/executebuffer.c
index 29fd65e..40b586f 100644
--- a/dlls/ddraw/executebuffer.c
+++ b/dlls/ddraw/executebuffer.c
@@ -251,22 +251,18 @@ IDirect3DExecuteBufferImpl_Execute(IDirect3DExecuteBufferImpl *This,
 
 		    if (!ci->u1.dlstLightStateType || (ci->u1.dlstLightStateType > D3DLIGHTSTATE_COLORVERTEX))
 			ERR("Unexpected Light State Type %d\n", ci->u1.dlstLightStateType);
-		    else if (ci->u1.dlstLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */) {
-			DWORD matHandle = ci->u2.dwArg[0];
-
-			if (!matHandle) {
-			    FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
-			} else if (matHandle >= lpDevice->numHandles) {
-			    WARN("Material handle %d is invalid\n", matHandle);
-			} else if (lpDevice->Handles[matHandle - 1].type != DDrawHandle_Material) {
-			    WARN("Handle %d is not a material handle\n", matHandle);
-			} else {
-			    IDirect3DMaterialImpl *mat =
-                                lpDevice->Handles[matHandle - 1].ptr;
-
-			    mat->activate(mat);
-			}
-		    } else if (ci->u1.dlstLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */) {
+                    else if (ci->u1.dlstLightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */)
+                    {
+                        IDirect3DMaterialImpl *m;
+
+                        m = ddraw_get_object(&lpDevice->handle_table, ci->u2.dwArg[0] - 1, DDRAW_HANDLE_MATERIAL);
+                        if (!m)
+                            ERR("Invalid material handle %#x.\n", ci->u2.dwArg[0]);
+                        else
+                            m->activate(m);
+                    }
+                    else if (ci->u1.dlstLightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */)
+                    {
 			switch (ci->u2.dwArg[0]) {
 			    case D3DCOLOR_MONO:
 				ERR("DDCOLOR_MONO should not happen!\n");
diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c
index 45a156f..7292ed8 100644
--- a/dlls/ddraw/main.c
+++ b/dlls/ddraw/main.c
@@ -70,6 +70,117 @@ CRITICAL_SECTION ddraw_cs = { &ddraw_cs_debug, -1, 0, 0, 0, 0 };
 /* value of ForceRefreshRate */
 DWORD force_refresh_rate = 0;
 
+/* Handle table functions */
+BOOL ddraw_handle_table_init(struct ddraw_handle_table *t, UINT initial_size)
+{
+    t->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, initial_size * sizeof(*t->entries));
+    if (!t->entries)
+    {
+        ERR("Failed to allocate handle table memory.\n");
+        return FALSE;
+    }
+    t->free_entries = NULL;
+    t->table_size = initial_size;
+    t->entry_count = 0;
+
+    return TRUE;
+}
+
+void ddraw_handle_table_destroy(struct ddraw_handle_table *t)
+{
+    HeapFree(GetProcessHeap(), 0, t->entries);
+    memset(t, 0, sizeof(*t));
+}
+
+DWORD ddraw_allocate_handle(struct ddraw_handle_table *t, void *object, enum ddraw_handle_type type)
+{
+    struct ddraw_handle_entry *entry;
+
+    if (t->free_entries)
+    {
+        DWORD idx = t->free_entries - t->entries;
+        /* Use a free handle */
+        entry = t->free_entries;
+        if (entry->type != DDRAW_HANDLE_FREE)
+        {
+            ERR("Handle %#x (%p) is in the free list, but has type %#x.\n", idx, entry->object, entry->type);
+            return DDRAW_INVALID_HANDLE;
+        }
+        t->free_entries = entry->object;
+        entry->object = object;
+        entry->type = type;
+
+        return idx;
+    }
+
+    if (!(t->entry_count < t->table_size))
+    {
+        /* Grow the table */
+        UINT new_size = t->table_size + (t->table_size >> 1);
+        struct ddraw_handle_entry *new_entries = HeapReAlloc(GetProcessHeap(),
+                0, t->entries, new_size * sizeof(*t->entries));
+        if (!new_entries)
+        {
+            ERR("Failed to grow the handle table.\n");
+            return DDRAW_INVALID_HANDLE;
+        }
+        t->entries = new_entries;
+        t->table_size = new_size;
+    }
+
+    entry = &t->entries[t->entry_count];
+    entry->object = object;
+    entry->type = type;
+
+    return t->entry_count++;
+}
+
+void *ddraw_free_handle(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
+{
+    struct ddraw_handle_entry *entry;
+    void *object;
+
+    if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
+    {
+        WARN("Invalid handle %#x passed.\n", handle);
+        return NULL;
+    }
+
+    entry = &t->entries[handle];
+    if (entry->type != type)
+    {
+        WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
+        return NULL;
+    }
+
+    object = entry->object;
+    entry->object = t->free_entries;
+    entry->type = DDRAW_HANDLE_FREE;
+    t->free_entries = entry;
+
+    return object;
+}
+
+void *ddraw_get_object(struct ddraw_handle_table *t, DWORD handle, enum ddraw_handle_type type)
+{
+    struct ddraw_handle_entry *entry;
+
+    if (handle == DDRAW_INVALID_HANDLE || handle >= t->entry_count)
+    {
+        WARN("Invalid handle %#x passed.\n", handle);
+        return NULL;
+    }
+
+    entry = &t->entries[handle];
+    if (entry->type != type)
+    {
+        WARN("Handle %#x (%p) is not of type %#x.\n", handle, entry->object, type);
+        return NULL;
+    }
+
+    return entry->object;
+}
+
 /*
  * Helper Function for DDRAW_Create and DirectDrawCreateClipper for
  * lazy loading of the Wine D3D driver.
diff --git a/dlls/ddraw/material.c b/dlls/ddraw/material.c
index d75501e..3c5dc1d 100644
--- a/dlls/ddraw/material.c
+++ b/dlls/ddraw/material.c
@@ -160,8 +160,7 @@ IDirect3DMaterialImpl_Release(IDirect3DMaterial3 *iface)
         if(This->Handle)
         {
             EnterCriticalSection(&ddraw_cs);
-            This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
-            This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
+            ddraw_free_handle(&This->ddraw->d3ddevice->handle_table, This->Handle - 1, DDRAW_HANDLE_MATERIAL);
             LeaveCriticalSection(&ddraw_cs);
         }
 
@@ -328,15 +327,15 @@ IDirect3DMaterialImpl_GetHandle(IDirect3DMaterial3 *iface,
     This->active_device = device;
     if(!This->Handle)
     {
-        This->Handle = IDirect3DDeviceImpl_CreateHandle(device);
-        if(!This->Handle)
+        DWORD h = ddraw_allocate_handle(&device->handle_table, This, DDRAW_HANDLE_MATERIAL);
+        if (h == DDRAW_INVALID_HANDLE)
         {
-            ERR("Error creating a handle\n");
+            ERR("Failed to allocate a material handle.\n");
             LeaveCriticalSection(&ddraw_cs);
             return DDERR_INVALIDPARAMS;   /* Unchecked */
         }
-        device->Handles[This->Handle - 1].ptr = This;
-        device->Handles[This->Handle - 1].type = DDrawHandle_Material;
+
+        This->Handle = h + 1;
     }
     *lpHandle = This->Handle;
     TRACE(" returning handle %08x.\n", *lpHandle);
diff --git a/dlls/ddraw/viewport.c b/dlls/ddraw/viewport.c
index b637df1..5e17bd0 100644
--- a/dlls/ddraw/viewport.c
+++ b/dlls/ddraw/viewport.c
@@ -529,36 +529,32 @@ IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface,
                                     D3DMATERIALHANDLE hMat)
 {
     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
+    IDirect3DMaterialImpl *m;
+
     TRACE("(%p)->(%d)\n", This, hMat);
 
     EnterCriticalSection(&ddraw_cs);
-    if(hMat && hMat > This->ddraw->d3ddevice->numHandles)
+
+    if (!hMat)
     {
-        WARN("Specified Handle %d out of range\n", hMat);
+        This->background = NULL;
+        TRACE("Setting background to NULL\n");
         LeaveCriticalSection(&ddraw_cs);
-        return DDERR_INVALIDPARAMS;
+        return D3D_OK;
     }
-    else if(hMat && This->ddraw->d3ddevice->Handles[hMat - 1].type != DDrawHandle_Material)
+
+    m = ddraw_get_object(&This->ddraw->d3ddevice->handle_table, hMat - 1, DDRAW_HANDLE_MATERIAL);
+    if (!m)
     {
-        WARN("Handle %d is not a material handle\n", hMat);
+        WARN("Invalid material handle.\n");
         LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
     }
 
-    if(hMat)
-    {
-        This->background = This->ddraw->d3ddevice->Handles[hMat - 1].ptr;
-        TRACE(" setting background color : %f %f %f %f\n",
-              This->background->mat.u.diffuse.u1.r,
-              This->background->mat.u.diffuse.u2.g,
-              This->background->mat.u.diffuse.u3.b,
-              This->background->mat.u.diffuse.u4.a);
-    }
-    else
-    {
-        This->background = NULL;
-        TRACE("Setting background to NULL\n");
-    }
+    TRACE("Setting background color : %.8e %.8e %.8e %.8e.\n",
+            m->mat.u.diffuse.u1.r, m->mat.u.diffuse.u2.g,
+            m->mat.u.diffuse.u3.b, m->mat.u.diffuse.u4.a);
+    This->background = m;
 
     LeaveCriticalSection(&ddraw_cs);
     return D3D_OK;
-- 
1.7.1




More information about the wine-patches mailing list