[1/10] WineD3D: Replace the light chain with a hashmap
Stefan Dösinger
stefan at codeweavers.com
Wed Feb 14 10:46:54 CST 2007
Lights are indentified by an index from 0 to MAX_DWORD, a range that is too
big for an array. On the other hand, I dislike the idea of using a linked
list because apps can define a quite huge number of lights, so I decided to
use a (primitive) hashmap. By rewriting the light organisation a few bugs
with the light list and stateblocks are fixed too.
-------------- next part --------------
From 4fff08547106025766453b4033f952d0ba950bb7 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Fri, 2 Feb 2007 12:09:31 +0100
Subject: [PATCH] WineD3D: Replace the light chain with a hashmap
---
dlls/wined3d/device.c | 360 +++++++++++----------------------------
dlls/wined3d/state.c | 12 +-
dlls/wined3d/stateblock.c | 139 +++++++++++-----
dlls/wined3d/wined3d_private.h | 11 +-
4 files changed, 210 insertions(+), 312 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 65af9ee..9a0b1b5 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -584,6 +584,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
D3DCREATEOBJECTINSTANCE(object, StateBlock)
object->blockType = Type;
+ for(i = 0; i < LIGHTMAP_SIZE; i++) {
+ list_init(&object->lightMap[i]);
+ }
+
/* Special case - Used during initialization to produce a placeholder stateblock
so other functions called can update a state block */
if (Type == WINED3DSBT_INIT) {
@@ -613,7 +617,16 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
TRACE("ALL => Pretend everything has changed\n");
stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
-
+
+ /* Lights are not part of the changed / set structure */
+ for(j = 0; j < LIGHTMAP_SIZE; j++) {
+ struct list *e;
+ LIST_FOR_EACH(e, &object->lightMap[j]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ light->changed = TRUE;
+ light->enabledChanged = TRUE;
+ }
+ }
} else if (Type == WINED3DSBT_PIXELSTATE) {
TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
@@ -673,33 +686,14 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
}
}
- /* Duplicate light chain */
- {
- PLIGHTINFOEL *src = NULL;
- PLIGHTINFOEL *dst = NULL;
- PLIGHTINFOEL *newEl = NULL;
- src = This->stateBlock->lights;
- object->lights = NULL;
-
-
- while (src) {
- newEl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
- if (newEl == NULL) return WINED3DERR_OUTOFVIDEOMEMORY;
- memcpy(newEl, src, sizeof(PLIGHTINFOEL));
- newEl->prev = dst;
- newEl->changed = TRUE;
- newEl->enabledChanged = TRUE;
- if (dst == NULL) {
- object->lights = newEl;
- } else {
- dst->next = newEl;
+ for(j = 0; j < LIGHTMAP_SIZE; j++) {
+ struct list *e;
+ LIST_FOR_EACH(e, &object->lightMap[j]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ light->changed = TRUE;
+ light->enabledChanged = TRUE;
}
- dst = newEl;
- src = src->next;
}
-
- }
-
} else {
FIXME("Unrecognized state block type %d\n", Type);
}
@@ -2329,73 +2323,30 @@ static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface
static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
float rho;
- PLIGHTINFOEL *object, *temp;
+ PLIGHTINFOEL *object = NULL;
+ UINT Hi = LIGHTMAP_HASHFUNC(Index);
+ struct list *e;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
- TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
+ TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
- /* If recording state block, just add to end of lights chain */
- if (This->isRecordingState) {
- object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
- if (NULL == object) {
- return WINED3DERR_OUTOFVIDEOMEMORY;
- }
- memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
- object->OriginalIndex = Index;
- object->glIndex = -1;
- object->changed = TRUE;
-
- /* Add to the END of the chain of lights changes to be replayed */
- if (This->updateStateBlock->lights == NULL) {
- This->updateStateBlock->lights = object;
- } else {
- temp = This->updateStateBlock->lights;
- while (temp->next != NULL) temp=temp->next;
- temp->next = object;
- }
- TRACE("Recording... not performing anything more\n");
- return WINED3D_OK;
+ LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
+ object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ if(object->OriginalIndex == Index) break;
+ object = NULL;
}
- /* Ok, not recording any longer so do real work */
- object = This->stateBlock->lights;
- while (object != NULL && object->OriginalIndex != Index) object = object->next;
-
- /* If we didn't find it in the list of lights, time to add it */
- if (object == NULL) {
- PLIGHTINFOEL *insertAt,*prevPos;
-
- object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
- if (NULL == object) {
- return WINED3DERR_OUTOFVIDEOMEMORY;
+ if(!object) {
+ TRACE("Adding new light\n");
+ object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
+ if(!object) {
+ ERR("Out of memory error when allocating a light\n");
+ return E_OUTOFMEMORY;
}
- object->OriginalIndex = Index;
+ list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
object->glIndex = -1;
-
- /* Add it to the front of list with the idea that lights will be changed as needed
- BUT after any lights currently assigned GL indexes */
- insertAt = This->stateBlock->lights;
- prevPos = NULL;
- while (insertAt != NULL && insertAt->glIndex != -1) {
- prevPos = insertAt;
- insertAt = insertAt->next;
- }
-
- if (insertAt == NULL && prevPos == NULL) { /* Start of list */
- This->stateBlock->lights = object;
- } else if (insertAt == NULL) { /* End of list */
- prevPos->next = object;
- object->prev = prevPos;
- } else { /* Middle of chain */
- if (prevPos == NULL) {
- This->stateBlock->lights = object;
- } else {
- prevPos->next = object;
- }
- object->prev = prevPos;
- object->next = insertAt;
- insertAt->prev = object;
- }
+ object->OriginalIndex = Index;
+ object->changed = TRUE;
}
/* Initialize the object */
@@ -2471,7 +2422,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I
}
/* Update the live definitions if the light is currently assigned a glIndex */
- if (object->glIndex != -1) {
+ if (object->glIndex != -1 && !This->isRecordingState) {
setup_light(iface, object->glIndex, object);
}
return WINED3D_OK;
@@ -2480,11 +2431,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I
static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ DWORD Hi = LIGHTMAP_HASHFUNC(Index);
+ struct list *e;
TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
- /* Locate the light in the live lights */
- lightInfo = This->stateBlock->lights;
- while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+ LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
+ lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ if(lightInfo->OriginalIndex == Index) break;
+ lightInfo = NULL;
+ }
if (lightInfo == NULL) {
TRACE("Light information requested but light not defined\n");
@@ -2502,38 +2457,19 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD I
static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ UINT Hi = LIGHTMAP_HASHFUNC(Index);
+ struct list *e;
TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
/* Tests show true = 128...not clear why */
-
Enable = Enable? 128: 0;
- /* If recording state block, just add to end of lights chain with changedEnable set to true */
- if (This->isRecordingState) {
- lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL));
- if (NULL == lightInfo) {
- return WINED3DERR_OUTOFVIDEOMEMORY;
- }
- lightInfo->OriginalIndex = Index;
- lightInfo->glIndex = -1;
- lightInfo->enabledChanged = TRUE;
- lightInfo->lightEnabled = Enable;
-
- /* Add to the END of the chain of lights changes to be replayed */
- if (This->updateStateBlock->lights == NULL) {
- This->updateStateBlock->lights = lightInfo;
- } else {
- PLIGHTINFOEL *temp = This->updateStateBlock->lights;
- while (temp->next != NULL) temp=temp->next;
- temp->next = lightInfo;
- }
- TRACE("Recording... not performing anything more\n");
- return WINED3D_OK;
+ LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
+ lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ if(lightInfo->OriginalIndex == Index) break;
+ lightInfo = NULL;
}
-
- /* Not recording... So, locate the light in the live lights */
- lightInfo = This->stateBlock->lights;
- while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+ TRACE("Found light: %p\n", lightInfo);
/* Special case - enabling an undefined light creates one with a strict set of parms! */
if (lightInfo == NULL) {
@@ -2542,164 +2478,62 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, D
IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
/* Search for it again! Should be fairly quick as near head of list */
- lightInfo = This->stateBlock->lights;
- while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+ LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
+ lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ if(lightInfo->OriginalIndex == Index) break;
+ lightInfo = NULL;
+ }
if (lightInfo == NULL) {
FIXME("Adding default lights has failed dismally\n");
return WINED3DERR_INVALIDCALL;
}
}
- /* OK, we now have a light... */
- if (!Enable) {
+ lightInfo->enabledChanged = TRUE;
+ if(!Enable) {
+ if(lightInfo->glIndex != -1) {
+ if(!This->isRecordingState) {
+ ENTER_GL();
+ glDisable(GL_LIGHT0 + lightInfo->glIndex);
+ checkGLcall("glDisable GL_LIGHT0+Index");
+ LEAVE_GL();
+ }
- /* If we are disabling it, check it was enabled, and
- still only do something if it has assigned a glIndex (which it should have!) */
- if ((lightInfo->lightEnabled) && (lightInfo->glIndex != -1)) {
- TRACE("Disabling light set up at gl idx %d\n", lightInfo->glIndex);
- ENTER_GL();
- glDisable(GL_LIGHT0 + lightInfo->glIndex);
- checkGLcall("glDisable GL_LIGHT0+Index");
- LEAVE_GL();
+ This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
+ lightInfo->glIndex = -1;
} else {
- TRACE("Nothing to do as light was not enabled\n");
+ TRACE("Light already disabled, nothing to do\n");
}
- lightInfo->lightEnabled = Enable;
} else {
-
- /* We are enabling it. If it is enabled, it's really simple */
- if (lightInfo->lightEnabled) {
+ if (lightInfo->glIndex != -1) {
/* nop */
TRACE("Nothing to do as light was enabled\n");
-
- /* If it already has a glIndex, it's still simple */
- } else if (lightInfo->glIndex != -1) {
- TRACE("Reusing light as already set up at gl idx %d\n", lightInfo->glIndex);
- lightInfo->lightEnabled = Enable;
- ENTER_GL();
- glEnable(GL_LIGHT0 + lightInfo->glIndex);
- checkGLcall("glEnable GL_LIGHT0+Index already setup");
- LEAVE_GL();
-
- /* Otherwise got to find space - lights are ordered gl indexes first */
} else {
- PLIGHTINFOEL *bsf = NULL;
- PLIGHTINFOEL *pos = This->stateBlock->lights;
- PLIGHTINFOEL *prev = NULL;
- int Index= 0;
- int glIndex = -1;
-
- /* Try to minimize changes as much as possible */
- while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) {
-
- /* Try to remember which index can be replaced if necessary */
- if (bsf==NULL && !pos->lightEnabled) {
- /* Found a light we can replace, save as best replacement */
- bsf = pos;
+ int i;
+ /* Find a free gl light */
+ for(i = 0; i < This->maxConcurrentLights; i++) {
+ if(This->stateBlock->activeLights[i] == NULL) {
+ This->stateBlock->activeLights[i] = lightInfo;
+ lightInfo->glIndex = i;
+ break;
}
-
- /* Step to next space */
- prev = pos;
- pos = pos->next;
- Index ++;
}
-
- /* If we have too many active lights, fail the call */
- if ((Index == This->maxConcurrentLights) && (bsf == NULL)) {
- FIXME("Program requests too many concurrent lights.\n");
+ if(lightInfo->glIndex == -1) {
+ ERR("Too many concurrently active lights\n");
return WINED3DERR_INVALIDCALL;
+ }
- /* If we have allocated all lights, but not all are enabled,
- reuse one which is not enabled */
- } else if (Index == This->maxConcurrentLights) {
- /* use bsf - Simply swap the new light and the BSF one */
- PLIGHTINFOEL *bsfNext = bsf->next;
- PLIGHTINFOEL *bsfPrev = bsf->prev;
-
- /* Sort out ends */
- if (lightInfo->next != NULL) lightInfo->next->prev = bsf;
- if (bsf->prev != NULL) {
- bsf->prev->next = lightInfo;
- } else {
- This->stateBlock->lights = lightInfo;
- }
-
- /* If not side by side, lots of chains to update */
- if (bsf->next != lightInfo) {
- lightInfo->prev->next = bsf;
- bsf->next->prev = lightInfo;
- bsf->next = lightInfo->next;
- bsf->prev = lightInfo->prev;
- lightInfo->next = bsfNext;
- lightInfo->prev = bsfPrev;
-
- } else {
- /* Simple swaps */
- bsf->prev = lightInfo;
- bsf->next = lightInfo->next;
- lightInfo->next = bsf;
- lightInfo->prev = bsfPrev;
- }
-
-
- /* Update states */
- glIndex = bsf->glIndex;
- bsf->glIndex = -1;
- lightInfo->glIndex = glIndex;
- lightInfo->lightEnabled = Enable;
-
- /* Finally set up the light in gl itself */
- TRACE("Replacing light which was set up at gl idx %d\n", lightInfo->glIndex);
- ENTER_GL();
- setup_light(iface, glIndex, lightInfo);
- glEnable(GL_LIGHT0 + glIndex);
- checkGLcall("glEnable GL_LIGHT0 new setup");
- LEAVE_GL();
-
- /* If we reached the end of the allocated lights, with space in the
- gl lights, setup a new light */
- } else if (pos->glIndex == -1) {
-
- /* We reached the end of the allocated gl lights, so already
- know the index of the next one! */
- glIndex = Index;
- lightInfo->glIndex = glIndex;
- lightInfo->lightEnabled = Enable;
-
- /* In an ideal world, it's already in the right place */
- if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) {
- /* No need to move it */
- } else {
- /* Remove this light from the list */
- lightInfo->prev->next = lightInfo->next;
- if (lightInfo->next != NULL) {
- lightInfo->next->prev = lightInfo->prev;
- }
-
- /* Add in at appropriate place (inbetween prev and pos) */
- lightInfo->prev = prev;
- lightInfo->next = pos;
- if (prev == NULL) {
- This->stateBlock->lights = lightInfo;
- } else {
- prev->next = lightInfo;
- }
- if (pos != NULL) {
- pos->prev = lightInfo;
- }
- }
-
- /* Finally set up the light in gl itself */
- TRACE("Defining new light at gl idx %d\n", lightInfo->glIndex);
+ /* i == lightInfo->glIndex */
+ if(!This->isRecordingState) {
+ setup_light(iface, i, lightInfo);
ENTER_GL();
- setup_light(iface, glIndex, lightInfo);
- glEnable(GL_LIGHT0 + glIndex);
- checkGLcall("glEnable GL_LIGHT0 new setup");
+ glEnable(GL_LIGHT0 + i);
+ checkGLcall("glEnable(GL_LIGHT0 + i)");
LEAVE_GL();
-
}
}
}
+
return WINED3D_OK;
}
@@ -2707,17 +2541,22 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, D
PLIGHTINFOEL *lightInfo = NULL;
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
+ struct list *e;
+ UINT Hi = LIGHTMAP_HASHFUNC(Index);
TRACE("(%p) : for idx(%d)\n", This, Index);
- /* Locate the light in the live lights */
- lightInfo = This->stateBlock->lights;
- while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next;
+ LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
+ lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
+ if(lightInfo->OriginalIndex == Index) break;
+ lightInfo = NULL;
+ }
if (lightInfo == NULL) {
TRACE("Light enabled state requested but light not defined\n");
return WINED3DERR_INVALIDCALL;
}
- *pEnable = lightInfo->lightEnabled;
+ /* true is 128 according to SetLightEnable */
+ *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
return WINED3D_OK;
}
@@ -4327,7 +4166,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DStateBlockImpl *object;
HRESULT temp_result;
-
+ int i;
+
TRACE("(%p)\n", This);
if (This->isRecordingState) {
@@ -4346,7 +4186,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface)
object->blockType = WINED3DSBT_ALL;
object->ref = 1;
object->lpVtbl = &IWineD3DStateBlock_Vtbl;
-
+
+ for(i = 0; i < LIGHTMAP_SIZE; i++) {
+ list_init(&object->lightMap[i]);
+ }
+
temp_result = allocate_shader_constants(object);
if (WINED3D_OK != temp_result)
return temp_result;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 9893dcb..ee898c2 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -1987,7 +1987,7 @@ static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
* NOTE2: Apparently texture transforms do NOT need reapplying
*/
- PLIGHTINFOEL *lightChain = NULL;
+ PLIGHTINFOEL *light = NULL;
glMatrixMode(GL_MODELVIEW);
checkGLcall("glMatrixMode(GL_MODELVIEW)");
@@ -1995,13 +1995,13 @@ static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
checkGLcall("glLoadMatrixf(...)");
/* Reset lights. TODO: Call light apply func */
- lightChain = stateblock->lights;
- while (lightChain && lightChain->glIndex != -1) {
- glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn);
+ for(k = 0; k < stateblock->wineD3DDevice->maxConcurrentLights; k++) {
+ light = stateblock->activeLights[k];
+ if(!light) continue;
+ glLightfv(GL_LIGHT0 + light->glIndex, GL_POSITION, light->lightPosn);
checkGLcall("glLightfv posn");
- glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn);
+ glLightfv(GL_LIGHT0 + light->glIndex, GL_SPOT_DIRECTION, light->lightDirn);
checkGLcall("glLightfv dirn");
- lightChain = lightChain->next;
}
/* Reset Clipping Planes if clipping is enabled. TODO: Call clipplane apply func */
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 093c83d..6112f59 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -140,6 +140,7 @@ void stateblock_savedstates_set(
void stateblock_copy(
IWineD3DStateBlock* destination,
IWineD3DStateBlock* source) {
+ int l;
IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)source;
IWineD3DStateBlockImpl *Dest = (IWineD3DStateBlockImpl *)destination;
@@ -164,7 +165,7 @@ void stateblock_copy(
Dest->streamIsUP = This->streamIsUP;
Dest->pIndexData = This->pIndexData;
Dest->baseVertexIndex = This->baseVertexIndex;
- Dest->lights = This->lights;
+ /* Dest->lights = This->lights; */
Dest->clip_status = This->clip_status;
Dest->viewport = This->viewport;
Dest->material = This->material;
@@ -172,6 +173,25 @@ void stateblock_copy(
Dest->glsl_program = This->glsl_program;
memcpy(&Dest->scissorRect, &This->scissorRect, sizeof(Dest->scissorRect));
+ /* Lights */
+ memset(This->activeLights, 0, sizeof(This->activeLights));
+ for(l = 0; l < LIGHTMAP_SIZE; l++) {
+ struct list *e1, *e2;
+ LIST_FOR_EACH_SAFE(e1, e2, &Dest->lightMap[l]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry);
+ list_remove(&light->entry);
+ HeapFree(GetProcessHeap(), 0, light);
+ }
+
+ LIST_FOR_EACH(e1, &This->lightMap[l]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry), *light2;
+ light2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*light));
+ memcpy(light2, light, sizeof(*light));
+ list_add_tail(&This->lightMap[l], &light2->entry);
+ if(light2->glIndex != -1) This->activeLights[light2->glIndex] = light2;
+ }
+ }
+
/* Fixed size arrays */
memcpy(Dest->vertexShaderConstantB, This->vertexShaderConstantB, sizeof(BOOL) * MAX_CONST_B);
memcpy(Dest->vertexShaderConstantI, This->vertexShaderConstantI, sizeof(INT) * MAX_CONST_I * 4);
@@ -230,10 +250,10 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
if (!refCount) {
constant_entry *constant, *constant2;
+ int counter;
/* type 0 represents the primary stateblock, so free all the resources */
if (This->blockType == WINED3DSBT_INIT) {
- int counter;
FIXME("Releasing primary stateblock\n");
/* NOTE: according to MSDN: The application is responsible for making sure the texture references are cleared down */
@@ -248,6 +268,15 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
}
+ for(counter = 0; counter < LIGHTMAP_SIZE; counter++) {
+ struct list *e1, *e2;
+ LIST_FOR_EACH_SAFE(e1, e2, &This->lightMap[counter]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry);
+ list_remove(&light->entry);
+ HeapFree(GetProcessHeap(), 0, light);
+ }
+ }
+
HeapFree(GetProcessHeap(), 0, This->vertexShaderConstantF);
HeapFree(GetProcessHeap(), 0, This->set.vertexShaderConstantsF);
HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF);
@@ -298,23 +327,27 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
/* If not recorded, then update can just recapture */
if (/*TODO: 'magic' statetype, replace with BOOL This->blockType == D3DSBT_RECORDED */ 0) {
IWineD3DStateBlockImpl* tmpBlock;
- PLIGHTINFOEL *tmp = This->lights;
+ int i;
IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)This->wineD3DDevice, This->blockType, (IWineD3DStateBlock**) &tmpBlock, NULL/*parent*/);
- /* Note just swap the light chains over so when deleting, the old one goes */
memcpy(This, tmpBlock, sizeof(IWineD3DStateBlockImpl));
- tmpBlock->lights = tmp;
- /* Delete the temporary one (which points to the old light chain though */
+ /* Move the light elements from the tmpBlock to This. No need to duplicate them, but they have to be removed from tmpBlock
+ * and the pointers updated for the base element in This.
+ *
+ * No need to update This->activeLights because the lights objects are untouched(same address)
+ */
+ for(i = 0; i < LIGHTMAP_SIZE; i++) {
+ list_init(&This->lightMap[i]); /* This element contains rubish due to the memcpy */
+ list_move_tail(&This->lightMap[i], &tmpBlock->lightMap[i]); /* Cleans the list entry in tmpBlock */
+ }
+
IWineD3DStateBlock_Release((IWineD3DStateBlock *)tmpBlock);
- /*IDirect3DDevice_DeleteStateBlock(pDevice, tmpBlock);*/
} else {
unsigned int i, j;
- PLIGHTINFOEL *src;
-
/* Recorded => Only update 'changed' values */
if (This->vertexShader != targetStateBlock->vertexShader) {
TRACE("Updating vertex shader from %p to %p\n", This->vertexShader, targetStateBlock->vertexShader);
@@ -363,37 +396,52 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->vertexShaderConstantB[i] = targetStateBlock->vertexShaderConstantB[i];
}
}
-
+
/* Lights... For a recorded state block, we just had a chain of actions to perform,
so we need to walk that chain and update any actions which differ */
- src = This->lights;
- while (src != NULL) {
- PLIGHTINFOEL *realLight = NULL;
-
- /* Locate the light in the live lights */
- realLight = targetStateBlock->lights;
- while (realLight != NULL && realLight->OriginalIndex != src->OriginalIndex) realLight = realLight->next;
-
- /* If 'changed' then its a SetLight command. Rather than comparing to see
- if the OriginalParms have changed and then copy them (twice through
- memory) just do the copy */
- if (src->changed) {
-
- /* If the light exists, copy its parameters, otherwise copy the default parameters */
- const WINED3DLIGHT* params = realLight? &realLight->OriginalParms: &WINED3D_default_light;
- TRACE("Updating lights for light %d\n", src->OriginalIndex);
- memcpy(&src->OriginalParms, params, sizeof(*params));
- }
-
- /* If 'enabledchanged' then its a LightEnable command */
- if (src->enabledChanged) {
+ for(i = 0; i < LIGHTMAP_SIZE; i++) {
+ struct list *e, *f;
+ LIST_FOR_EACH(e, &This->lightMap[i]) {
+ BOOL updated = FALSE;
+ PLIGHTINFOEL *src = LIST_ENTRY(e, PLIGHTINFOEL, entry), *realLight;
+ if(!src->changed || !src->enabledChanged) continue;
+
+ /* Look up the light in the destination */
+ LIST_FOR_EACH(f, &targetStateBlock->lightMap[i]) {
+ realLight = LIST_ENTRY(f, PLIGHTINFOEL, entry);
+ if(realLight->OriginalIndex == src->OriginalIndex) {
+ if(src->changed) {
+ memcpy(&src->OriginalParms, &realLight->OriginalParms, sizeof(src->OriginalParms));
+ }
+ if(src->enabledChanged) {
+ /* Need to double check because enabledChanged does not catch enabled -> disabled -> enabled
+ * or disabled -> enabled -> disabled changes
+ */
+ if(realLight->glIndex == -1 && src->glIndex != -1) {
+ /* Light disabled */
+ This->activeLights[src->glIndex] = NULL;
+ } else if(realLight->glIndex != -1 && src->glIndex == -1){
+ /* Light enabled */
+ This->activeLights[realLight->glIndex] = src;
+ }
+ src->glIndex = realLight->glIndex;
+ }
+ updated = TRUE;
+ break;
+ }
+ }
- /* If the light exists, check if it's enabled, otherwise default is disabled state */
- TRACE("Updating lightEnabled for light %d\n", src->OriginalIndex);
- src->lightEnabled = realLight? realLight->lightEnabled: FALSE;
+ if(updated) {
+ /* Found a light, all done, proceed with next hash entry */
+ continue;
+ } else if(src->changed) {
+ /* Otherwise assign defaul params */
+ memcpy(&src->OriginalParms, &WINED3D_default_light, sizeof(src->OriginalParms));
+ } else {
+ /* Not enabled by default */
+ src->glIndex = -1;
+ }
}
-
- src = src->next;
}
/* Recorded => Only update 'changed' values */
@@ -587,14 +635,19 @@ should really perform a delta so that only the changes get updated*/
if (/*TODO: 'magic' statetype, replace with BOOL This->blockType == D3DSBT_RECORDED || */This->blockType == WINED3DSBT_INIT || This->blockType == WINED3DSBT_ALL || This->blockType == WINED3DSBT_VERTEXSTATE) {
+ for(i = 0; i < LIGHTMAP_SIZE; i++) {
+ struct list *e;
+
+ LIST_FOR_EACH(e, &This->lightMap[i]) {
+ PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
- PLIGHTINFOEL *toDo = This->lights;
- while (toDo != NULL) {
- if (toDo->changed)
- IWineD3DDevice_SetLight(pDevice, toDo->OriginalIndex, &toDo->OriginalParms);
- if (toDo->enabledChanged)
- IWineD3DDevice_SetLightEnable(pDevice, toDo->OriginalIndex, toDo->lightEnabled);
- toDo = toDo->next;
+ if(light->changed) {
+ IWineD3DDevice_SetLight(pDevice, light->OriginalIndex, &light->OriginalParms);
+ }
+ if(light->enabledChanged) {
+ IWineD3DDevice_SetLightEnable(pDevice, light->OriginalIndex, light->glIndex != -1);
+ }
+ }
}
/* Vertex Shader */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index e21e5ce..3b30a3a 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -517,7 +517,6 @@ struct PLIGHTINFOEL {
WINED3DLIGHT OriginalParms; /* Note D3D8LIGHT == D3D9LIGHT */
DWORD OriginalIndex;
LONG glIndex;
- BOOL lightEnabled;
BOOL changed;
BOOL enabledChanged;
@@ -527,8 +526,7 @@ struct PLIGHTINFOEL {
float exponent;
float cutoff;
- PLIGHTINFOEL *next;
- PLIGHTINFOEL *prev;
+ struct list entry;
};
/* The default light parameters */
@@ -1204,8 +1202,11 @@ struct IWineD3DStateBlockImpl
/* Transform */
WINED3DMATRIX transforms[HIGHEST_TRANSFORMSTATE + 1];
- /* Lights */
- PLIGHTINFOEL *lights; /* NOTE: active GL lights must be front of the chain */
+ /* Light hashmap . Collisions are handled using standard wine double linked lists */
+#define LIGHTMAP_SIZE 43 /* Use of a prime number recommended. Set to 1 for a linked list! */
+#define LIGHTMAP_HASHFUNC(x) ((x) % LIGHTMAP_SIZE) /* Primitive and simple function */
+ struct list lightMap[LIGHTMAP_SIZE]; /* Mashmap containing the lights */
+ PLIGHTINFOEL *activeLights[MAX_ACTIVE_LIGHTS]; /* Map of opengl lights to d3d lights */
/* Clipping */
double clipplane[MAX_CLIPPLANES][4];
--
1.4.4.3
More information about the wine-patches
mailing list