wined3d: Use RB tree for storing lights.

This commit is contained in:
Paul Gofman 2023-05-16 21:12:24 -06:00 committed by Alexandre Julliard
parent debe2bd632
commit 71da110b46
4 changed files with 100 additions and 134 deletions

View file

@ -1998,7 +1998,7 @@ static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
{ {
const struct wined3d_cs_set_light *op = data; const struct wined3d_cs_set_light *op = data;
struct wined3d_light_info *light_info; struct wined3d_light_info *light_info;
unsigned int light_idx, hash_idx; unsigned int light_idx;
light_idx = op->light.OriginalIndex; light_idx = op->light.OriginalIndex;
@ -2011,10 +2011,9 @@ static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data)
return; return;
} }
hash_idx = LIGHTMAP_HASHFUNC(light_idx);
list_add_head(&cs->state.light_state.light_map[hash_idx], &light_info->entry);
light_info->glIndex = -1; light_info->glIndex = -1;
light_info->OriginalIndex = light_idx; light_info->OriginalIndex = light_idx;
rb_put(&cs->state.light_state.lights_tree, (void *)(ULONG_PTR)light_idx, &light_info->entry);
} }
if (light_info->glIndex != -1) if (light_info->glIndex != -1)

View file

@ -1907,7 +1907,7 @@ void CDECL wined3d_device_context_reset_state(struct wined3d_device_context *con
void CDECL wined3d_device_context_set_state(struct wined3d_device_context *context, struct wined3d_state *state) void CDECL wined3d_device_context_set_state(struct wined3d_device_context *context, struct wined3d_state *state)
{ {
const struct wined3d_light_info *light; struct wined3d_light_info *light;
unsigned int i, j; unsigned int i, j;
TRACE("context %p, state %p.\n", context, state); TRACE("context %p, state %p.\n", context, state);
@ -1991,13 +1991,10 @@ void CDECL wined3d_device_context_set_state(struct wined3d_device_context *conte
wined3d_device_context_emit_set_viewports(context, state->viewport_count, state->viewports); wined3d_device_context_emit_set_viewports(context, state->viewport_count, state->viewports);
wined3d_device_context_emit_set_scissor_rects(context, state->scissor_rect_count, state->scissor_rects); wined3d_device_context_emit_set_scissor_rects(context, state->scissor_rect_count, state->scissor_rects);
for (i = 0; i < LIGHTMAP_SIZE; ++i) RB_FOR_EACH_ENTRY(light, &state->light_state.lights_tree, struct wined3d_light_info, entry)
{ {
LIST_FOR_EACH_ENTRY(light, &state->light_state.light_map[i], struct wined3d_light_info, entry) wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms);
{ wined3d_device_context_emit_set_light_enable(context, light->OriginalIndex, light->glIndex != -1);
wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms);
wined3d_device_context_emit_set_light_enable(context, light->OriginalIndex, light->glIndex != -1);
}
} }
for (i = 0; i < WINEHIGHEST_RENDER_STATE + 1; ++i) for (i = 0; i < WINEHIGHEST_RENDER_STATE + 1; ++i)
@ -3074,6 +3071,7 @@ static void init_transformed_lights(struct lights_settings *ls,
{ {
const struct wined3d_light_info *lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS]; const struct wined3d_light_info *lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS];
const struct wined3d_light_info *light_info; const struct wined3d_light_info *light_info;
struct wined3d_light_info *light_iter;
struct light_transformed *light; struct light_transformed *light;
struct wined3d_vec4 vec4; struct wined3d_vec4 vec4;
unsigned int light_count; unsigned int light_count;
@ -3105,39 +3103,37 @@ static void init_transformed_lights(struct lights_settings *ls,
ls->normalise = !!state->render_states[WINED3D_RS_NORMALIZENORMALS]; ls->normalise = !!state->render_states[WINED3D_RS_NORMALIZENORMALS];
ls->localviewer = !!state->render_states[WINED3D_RS_LOCALVIEWER]; ls->localviewer = !!state->render_states[WINED3D_RS_LOCALVIEWER];
for (i = 0, index = 0; i < LIGHTMAP_SIZE && index < ARRAY_SIZE(lights); ++i) index = 0;
RB_FOR_EACH_ENTRY(light_iter, &state->light_state.lights_tree, struct wined3d_light_info, entry)
{ {
LIST_FOR_EACH_ENTRY(light_info, &state->light_state.light_map[i], struct wined3d_light_info, entry) if (!light_iter->enabled)
continue;
switch (light_iter->OriginalParms.type)
{ {
if (!light_info->enabled) case WINED3D_LIGHT_DIRECTIONAL:
continue; ++ls->directional_light_count;
switch (light_info->OriginalParms.type)
{
case WINED3D_LIGHT_DIRECTIONAL:
++ls->directional_light_count;
break;
case WINED3D_LIGHT_POINT:
++ls->point_light_count;
break;
case WINED3D_LIGHT_SPOT:
++ls->spot_light_count;
break;
case WINED3D_LIGHT_PARALLELPOINT:
++ls->parallel_point_light_count;
break;
default:
FIXME("Unhandled light type %#x.\n", light_info->OriginalParms.type);
continue;
}
lights[index++] = light_info;
if (index == WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS)
break; break;
case WINED3D_LIGHT_POINT:
++ls->point_light_count;
break;
case WINED3D_LIGHT_SPOT:
++ls->spot_light_count;
break;
case WINED3D_LIGHT_PARALLELPOINT:
++ls->parallel_point_light_count;
break;
default:
FIXME("Unhandled light type %#x.\n", light_iter->OriginalParms.type);
continue;
} }
lights[index++] = light_iter;
if (index == WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS)
break;
} }
light_count = index; light_count = index;

View file

@ -340,24 +340,19 @@ void CDECL wined3d_stateblock_init_contained_states(struct wined3d_stateblock *s
} }
} }
static void stateblock_init_lights(struct wined3d_stateblock *stateblock, const struct list *src_map) static void stateblock_init_lights(struct wined3d_stateblock *stateblock, const struct rb_tree *src_tree)
{ {
struct list *dst_map = stateblock->stateblock_state.light_state->light_map; struct rb_tree *dst_tree = &stateblock->stateblock_state.light_state->lights_tree;
unsigned int i; struct wined3d_light_info *src_light;
for (i = 0; i < LIGHTMAP_SIZE; ++i) RB_FOR_EACH_ENTRY(src_light, src_tree, struct wined3d_light_info, entry)
{ {
const struct wined3d_light_info *src_light; struct wined3d_light_info *dst_light = heap_alloc(sizeof(*dst_light));
LIST_FOR_EACH_ENTRY(src_light, &src_map[i], struct wined3d_light_info, entry) *dst_light = *src_light;
{ rb_put(dst_tree, (void *)(ULONG_PTR)dst_light->OriginalIndex, &dst_light->entry);
struct wined3d_light_info *dst_light = heap_alloc(sizeof(*dst_light)); dst_light->changed = true;
list_add_tail(&stateblock->changed.changed_lights, &dst_light->changed_entry);
*dst_light = *src_light;
list_add_tail(&dst_map[i], &dst_light->entry);
dst_light->changed = true;
list_add_tail(&stateblock->changed.changed_lights, &dst_light->changed_entry);
}
} }
} }
@ -544,41 +539,34 @@ void wined3d_stateblock_state_cleanup(struct wined3d_stateblock_state *state)
} }
} }
for (i = 0; i < LIGHTMAP_SIZE; ++i) RB_FOR_EACH_ENTRY_DESTRUCTOR(light, cursor, &state->light_state->lights_tree, struct wined3d_light_info, entry)
{ {
LIST_FOR_EACH_ENTRY_SAFE(light, cursor, &state->light_state->light_map[i], struct wined3d_light_info, entry) if (light->changed)
{ list_remove(&light->changed_entry);
if (light->changed) rb_remove(&state->light_state->lights_tree, &light->entry);
list_remove(&light->changed_entry); heap_free(light);
list_remove(&light->entry);
heap_free(light);
}
} }
} }
void state_cleanup(struct wined3d_state *state) void state_cleanup(struct wined3d_state *state)
{ {
unsigned int counter; struct wined3d_light_info *light, *cursor;
unsigned int i;
if (!(state->flags & WINED3D_STATE_NO_REF)) if (!(state->flags & WINED3D_STATE_NO_REF))
state_unbind_resources(state); state_unbind_resources(state);
for (counter = 0; counter < WINED3D_MAX_ACTIVE_LIGHTS; ++counter) for (i = 0; i < WINED3D_MAX_ACTIVE_LIGHTS; ++i)
{ {
state->light_state.lights[counter] = NULL; state->light_state.lights[i] = NULL;
} }
for (counter = 0; counter < LIGHTMAP_SIZE; ++counter) RB_FOR_EACH_ENTRY_DESTRUCTOR(light, cursor, &state->light_state.lights_tree, struct wined3d_light_info, entry)
{ {
struct list *e1, *e2; if (light->changed)
LIST_FOR_EACH_SAFE(e1, e2, &state->light_state.light_map[counter]) list_remove(&light->changed_entry);
{ rb_remove(&state->light_state.lights_tree, &light->entry);
struct wined3d_light_info *light = LIST_ENTRY(e1, struct wined3d_light_info, entry); heap_free(light);
list_remove(&light->entry);
if (light->changed)
list_remove(&light->changed_entry);
heap_free(light);
}
} }
} }
@ -601,17 +589,12 @@ ULONG CDECL wined3d_stateblock_decref(struct wined3d_stateblock *stateblock)
struct wined3d_light_info *wined3d_light_state_get_light(const struct wined3d_light_state *state, unsigned int idx) struct wined3d_light_info *wined3d_light_state_get_light(const struct wined3d_light_state *state, unsigned int idx)
{ {
struct wined3d_light_info *light_info; struct rb_entry *entry;
unsigned int hash_idx;
hash_idx = LIGHTMAP_HASHFUNC(idx); if (!(entry = rb_get(&state->lights_tree, (void *)(ULONG_PTR)idx)))
LIST_FOR_EACH_ENTRY(light_info, &state->light_map[hash_idx], struct wined3d_light_info, entry) return NULL;
{
if (light_info->OriginalIndex == idx)
return light_info;
}
return NULL; return RB_ENTRY_VALUE(entry, struct wined3d_light_info, entry);
} }
static void set_light_changed(struct wined3d_stateblock *stateblock, struct wined3d_light_info *light_info) static void set_light_changed(struct wined3d_stateblock *stateblock, struct wined3d_light_info *light_info)
@ -628,7 +611,6 @@ HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD l
const struct wined3d_light *params, struct wined3d_light_info **light_info) const struct wined3d_light *params, struct wined3d_light_info **light_info)
{ {
struct wined3d_light_info *object; struct wined3d_light_info *object;
unsigned int hash_idx;
if (!(object = wined3d_light_state_get_light(state, light_idx))) if (!(object = wined3d_light_state_get_light(state, light_idx)))
{ {
@ -639,10 +621,9 @@ HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD l
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
} }
hash_idx = LIGHTMAP_HASHFUNC(light_idx);
list_add_head(&state->light_map[hash_idx], &object->entry);
object->glIndex = -1; object->glIndex = -1;
object->OriginalIndex = light_idx; object->OriginalIndex = light_idx;
rb_put(&state->lights_tree, (void *)(ULONG_PTR)light_idx, &object->entry);
} }
object->OriginalParms = *params; object->OriginalParms = *params;
@ -702,44 +683,40 @@ static void wined3d_state_record_lights(struct wined3d_light_state *dst_state,
{ {
const struct wined3d_light_info *src; const struct wined3d_light_info *src;
struct wined3d_light_info *dst; struct wined3d_light_info *dst;
UINT i;
/* Lights... For a recorded state block, we just had a chain of actions /* 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 * to perform, so we need to walk that chain and update any actions which
* differ. */ * differ. */
for (i = 0; i < LIGHTMAP_SIZE; ++i) RB_FOR_EACH_ENTRY(dst, &dst_state->lights_tree, struct wined3d_light_info, entry)
{ {
LIST_FOR_EACH_ENTRY(dst, &dst_state->light_map[i], struct wined3d_light_info, entry) if ((src = wined3d_light_state_get_light(src_state, dst->OriginalIndex)))
{ {
if ((src = wined3d_light_state_get_light(src_state, dst->OriginalIndex))) dst->OriginalParms = src->OriginalParms;
{
dst->OriginalParms = src->OriginalParms;
if (src->glIndex == -1 && dst->glIndex != -1) if (src->glIndex == -1 && dst->glIndex != -1)
{ {
/* Light disabled. */ /* Light disabled. */
dst_state->lights[dst->glIndex] = NULL; dst_state->lights[dst->glIndex] = NULL;
}
else if (src->glIndex != -1 && dst->glIndex == -1)
{
/* Light enabled. */
dst_state->lights[src->glIndex] = dst;
}
dst->glIndex = src->glIndex;
} }
else else if (src->glIndex != -1 && dst->glIndex == -1)
{ {
/* This can happen if the light was originally created as a /* Light enabled. */
* default light for SetLightEnable() while recording. */ dst_state->lights[src->glIndex] = dst;
WARN("Light %u in dst_state %p does not exist in src_state %p.\n", }
dst->OriginalIndex, dst_state, src_state); dst->glIndex = src->glIndex;
}
else
{
/* This can happen if the light was originally created as a
* default light for SetLightEnable() while recording. */
WARN("Light %u in dst_state %p does not exist in src_state %p.\n",
dst->OriginalIndex, dst_state, src_state);
dst->OriginalParms = WINED3D_default_light; dst->OriginalParms = WINED3D_default_light;
if (dst->glIndex != -1) if (dst->glIndex != -1)
{ {
dst_state->lights[dst->glIndex] = NULL; dst_state->lights[dst->glIndex] = NULL;
dst->glIndex = -1; dst->glIndex = -1;
}
} }
} }
} }
@ -1895,18 +1872,21 @@ static void state_init_default(struct wined3d_state *state, const struct wined3d
} }
} }
static int lights_compare(const void *key, const struct rb_entry *entry)
{
const struct wined3d_light_info *light = RB_ENTRY_VALUE(entry, struct wined3d_light_info, entry);
unsigned int original_index = (ULONG_PTR)key;
return wined3d_uint32_compare(light->OriginalIndex, original_index);
}
void state_init(struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info, void state_init(struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info,
uint32_t flags, enum wined3d_feature_level feature_level) uint32_t flags, enum wined3d_feature_level feature_level)
{ {
unsigned int i;
state->feature_level = feature_level; state->feature_level = feature_level;
state->flags = flags; state->flags = flags;
for (i = 0; i < LIGHTMAP_SIZE; i++) rb_init(&state->light_state.lights_tree, lights_compare);
{
list_init(&state->light_state.light_map[i]);
}
if (flags & WINED3D_STATE_INIT_DEFAULT) if (flags & WINED3D_STATE_INIT_DEFAULT)
state_init_default(state, d3d_info); state_init_default(state, d3d_info);
@ -2001,12 +1981,7 @@ static void stateblock_state_init_default(struct wined3d_stateblock_state *state
void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state, void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state,
const struct wined3d_device *device, uint32_t flags) const struct wined3d_device *device, uint32_t flags)
{ {
unsigned int i; rb_init(&state->light_state->lights_tree, lights_compare);
for (i = 0; i < ARRAY_SIZE(state->light_state->light_map); i++)
{
list_init(&state->light_state->light_map[i]);
}
if (flags & WINED3D_STATE_INIT_DEFAULT) if (flags & WINED3D_STATE_INIT_DEFAULT)
stateblock_state_init_default(state, &device->adapter->d3d_info); stateblock_state_init_default(state, &device->adapter->d3d_info);
@ -2035,7 +2010,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru
switch (type) switch (type)
{ {
case WINED3D_SBT_ALL: case WINED3D_SBT_ALL:
stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); stateblock_init_lights(stateblock, &device_state->stateblock_state.light_state->lights_tree);
stateblock_savedstates_set_all(&stateblock->changed, stateblock_savedstates_set_all(&stateblock->changed,
d3d_info->limits.vs_uniform_count, d3d_info->limits.ps_uniform_count); d3d_info->limits.vs_uniform_count, d3d_info->limits.ps_uniform_count);
break; break;
@ -2046,7 +2021,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru
break; break;
case WINED3D_SBT_VERTEX_STATE: case WINED3D_SBT_VERTEX_STATE:
stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); stateblock_init_lights(stateblock, &device_state->stateblock_state.light_state->lights_tree);
stateblock_savedstates_set_vertex(&stateblock->changed, stateblock_savedstates_set_vertex(&stateblock->changed,
d3d_info->limits.vs_uniform_count); d3d_info->limits.vs_uniform_count);
break; break;

View file

@ -2991,7 +2991,7 @@ struct wined3d_light_info
float exponent; float exponent;
float cutoff; float cutoff;
struct list entry; struct rb_entry entry;
struct list changed_entry; struct list changed_entry;
bool changed; bool changed;
}; };
@ -3880,13 +3880,9 @@ struct wined3d_rasterizer_state
struct wine_rb_entry entry; struct wine_rb_entry entry;
}; };
#define LIGHTMAP_SIZE 43
#define LIGHTMAP_HASHFUNC(x) ((x) % LIGHTMAP_SIZE)
struct wined3d_light_state struct wined3d_light_state
{ {
/* Light hashmap. Collisions are handled using linked lists. */ struct rb_tree lights_tree;
struct list light_map[LIGHTMAP_SIZE];
const struct wined3d_light_info *lights[WINED3D_MAX_ACTIVE_LIGHTS]; const struct wined3d_light_info *lights[WINED3D_MAX_ACTIVE_LIGHTS];
}; };