Commit 0cb4de45 authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

ddraw: Use a less offensive handle table implementation for materials.

parent 7b3d200a
......@@ -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;
};
......
......@@ -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 */)
......
......@@ -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;
......
......@@ -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");
......
......@@ -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.
......
......@@ -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);
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment