Skip to content

Commit fcd1f2d

Browse files
committed
Fix issues with query change detection and writing to shared terms
1 parent f9c7c3d commit fcd1f2d

File tree

7 files changed

+744
-150
lines changed

7 files changed

+744
-150
lines changed

flecs.c

+99-72
Original file line numberDiff line numberDiff line change
@@ -56087,44 +56087,52 @@ ecs_query_table_match_t* flecs_query_cache_add(
5608756087

5608856088
typedef struct {
5608956089
ecs_table_t *table;
56090-
int32_t *dirty_state;
5609156090
int32_t column;
56092-
} table_dirty_state_t;
56091+
} flecs_table_column_t;
5609356092

5609456093
static
56095-
void flecs_query_get_dirty_state(
56094+
void flecs_query_get_column_for_term(
5609656095
ecs_query_t *query,
5609756096
ecs_query_table_match_t *match,
56098-
int32_t term,
56099-
table_dirty_state_t *out)
56097+
int32_t t,
56098+
flecs_table_column_t *out)
5610056099
{
56101-
ecs_world_t *world = query->filter.world;
56102-
ecs_entity_t src = match->sources[term];
56103-
ecs_table_t *table;
56100+
const ecs_filter_t *filter = &query->filter;
56101+
ecs_world_t *world = filter->world;
56102+
ecs_term_t *term = &filter->terms[t];
56103+
int32_t field = term->field_index;
56104+
ecs_entity_t src = match->sources[t];
56105+
ecs_table_t *table = NULL;
5610456106
int32_t column = -1;
5610556107

56106-
if (!src) {
56107-
table = match->table;
56108-
column = match->storage_columns[term];
56109-
} else {
56110-
const ecs_filter_t *filter = &query->filter;
56111-
table = ecs_get_table(world, src);
56112-
if (ecs_term_match_this(&filter->terms[term])) {
56113-
int32_t ref_index = -match->columns[term] - 1;
56114-
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
56115-
if (ref->id != 0) {
56116-
ecs_ref_update(world, ref);
56117-
column = ref->tr->column;
56118-
column = ecs_table_type_to_storage_index(table, column);
56108+
if (term->oper != EcsNot) {
56109+
if (!src) {
56110+
if (term->src.flags != EcsIsEntity) {
56111+
table = match->table;
56112+
column = match->storage_columns[field];
56113+
if (column == -2) {
56114+
/* Shared field */
56115+
column = -1;
56116+
}
5611956117
}
5612056118
} else {
56121-
column = match->columns[term];
56119+
table = ecs_get_table(world, src);
56120+
if (ecs_term_match_this(term)) {
56121+
int32_t ref_index = -match->columns[field] - 1;
56122+
ecs_ref_t *ref = ecs_vec_get_t(&match->refs, ecs_ref_t, ref_index);
56123+
if (ref->id != 0) {
56124+
ecs_ref_update(world, ref);
56125+
column = ref->tr->column;
56126+
column = ecs_table_type_to_storage_index(table, column);
56127+
}
56128+
} else {
56129+
column = -(match->columns[field] + 1);
56130+
}
5612256131
}
5612356132
}
5612456133

5612556134
out->table = table;
5612656135
out->column = column;
56127-
out->dirty_state = flecs_table_get_dirty_state(world, table);
5612856136
}
5612956137

5613056138
/* Get match monitor. Monitors are used to keep track of whether components
@@ -56144,39 +56152,38 @@ bool flecs_query_get_match_monitor(
5614456152
/* Mark terms that don't need to be monitored. This saves time when reading
5614556153
* and/or updating the monitor. */
5614656154
const ecs_filter_t *f = &query->filter;
56147-
int32_t i, t = -1, term_count = f->term_count;
56148-
table_dirty_state_t cur_dirty_state;
56155+
int32_t i, field = -1, term_count = f->term_count;
56156+
flecs_table_column_t tc;
5614956157

5615056158
for (i = 0; i < term_count; i ++) {
56151-
if (t == f->terms[i].field_index) {
56152-
if (monitor[t + 1] != -1) {
56159+
if (field == f->terms[i].field_index) {
56160+
if (monitor[field + 1] != -1) {
5615356161
continue;
5615456162
}
5615556163
}
5615656164

56157-
t = f->terms[i].field_index;
56158-
monitor[t + 1] = -1;
56165+
field = f->terms[i].field_index;
56166+
monitor[field + 1] = -1;
5615956167

5616056168
if (f->terms[i].inout != EcsIn &&
5616156169
f->terms[i].inout != EcsInOut &&
5616256170
f->terms[i].inout != EcsInOutDefault) {
5616356171
continue; /* If term isn't read, don't monitor */
5616456172
}
5616556173

56166-
int32_t column = match->columns[t];
56174+
int32_t column = match->columns[field];
5616756175
if (column == 0) {
5616856176
continue; /* Don't track terms that aren't matched */
5616956177
}
5617056178

56171-
flecs_query_get_dirty_state(query, match, t, &cur_dirty_state);
56172-
if (cur_dirty_state.column == -1) {
56179+
flecs_query_get_column_for_term(query, match, i, &tc);
56180+
if (tc.column == -1) {
5617356181
continue; /* Don't track terms that aren't stored */
5617456182
}
5617556183

56176-
monitor[t + 1] = 0;
56184+
monitor[field + 1] = 0;
5617756185
}
5617856186

56179-
5618056187
/* If matched table needs entity filter, make sure to test fields that could
5618156188
* be matched by flattened parents. */
5618256189
ecs_entity_filter_t *ef = match->entity_filter;
@@ -56219,33 +56226,33 @@ void flecs_query_sync_match_monitor(
5621956226
monitor[0] = dirty_state[0]; /* Did table gain/lose entities */
5622056227
}
5622156228

56222-
table_dirty_state_t cur;
56223-
int32_t i, term_count = query->filter.term_count;
56224-
for (i = 0; i < term_count; i ++) {
56225-
int32_t t = query->filter.terms[i].field_index;
56226-
if (monitor[t + 1] == -1) {
56227-
continue;
56228-
}
56229+
ecs_filter_t *filter = &query->filter;
56230+
{
56231+
flecs_table_column_t tc;
56232+
int32_t t, term_count = filter->term_count;
56233+
for (t = 0; t < term_count; t ++) {
56234+
int32_t field = filter->terms[t].field_index;
56235+
if (monitor[field + 1] == -1) {
56236+
continue;
56237+
}
5622956238

56230-
flecs_query_get_dirty_state(query, match, t, &cur);
56231-
if (cur.column < 0) {
56232-
// continue;
56233-
cur.column = -(cur.column + 1);
56234-
}
56239+
flecs_query_get_column_for_term(query, match, t, &tc);
5623556240

56236-
monitor[t + 1] = cur.dirty_state[cur.column + 1];
56241+
monitor[field + 1] = flecs_table_get_dirty_state(
56242+
filter->world, tc.table)[tc.column + 1];
56243+
}
5623756244
}
5623856245

5623956246
ecs_entity_filter_t *ef = match->entity_filter;
5624056247
if (ef && ef->flat_tree_column != -1) {
5624156248
flecs_flat_table_term_t *fields = ecs_vec_first(&ef->ft_terms);
56242-
int32_t field_count = ecs_vec_count(&ef->ft_terms);
56243-
for (i = 0; i < field_count; i ++) {
56244-
flecs_flat_table_term_t *field = &fields[i];
56249+
int32_t f, field_count = ecs_vec_count(&ef->ft_terms);
56250+
for (f = 0; f < field_count; f ++) {
56251+
flecs_flat_table_term_t *field = &fields[f];
5624556252
flecs_flat_monitor_t *tgt_mon = ecs_vec_first(&field->monitor);
56246-
int32_t t, tgt_count = ecs_vec_count(&field->monitor);
56247-
for (t = 0; t < tgt_count; t ++) {
56248-
tgt_mon[t].monitor = tgt_mon[t].table_state;
56253+
int32_t tgt, tgt_count = ecs_vec_count(&field->monitor);
56254+
for (tgt = 0; tgt < tgt_count; tgt ++) {
56255+
tgt_mon[tgt].monitor = tgt_mon[tgt].table_state;
5624956256
}
5625056257
}
5625156258
}
@@ -56284,11 +56291,12 @@ bool flecs_query_check_match_monitor_term(
5628456291
return false;
5628556292
}
5628656293

56287-
table_dirty_state_t cur;
56288-
flecs_query_get_dirty_state(query, match, term - 1, &cur);
56294+
flecs_table_column_t cur;
56295+
flecs_query_get_column_for_term(query, match, term - 1, &cur);
5628956296
ecs_assert(cur.column != -1, ECS_INTERNAL_ERROR, NULL);
5629056297

56291-
return monitor[term] != cur.dirty_state[cur.column + 1];
56298+
return monitor[term] != flecs_table_get_dirty_state(
56299+
query->filter.world, cur.table)[cur.column + 1];
5629256300
}
5629356301

5629456302
/* Check if any term for match has changed */
@@ -57107,7 +57115,16 @@ int flecs_query_process_signature(
5710757115
"invalid usage of Filter for query");
5710857116

5710957117
if (inout != EcsIn && inout != EcsInOutNone) {
57110-
query->flags |= EcsQueryHasOutColumns;
57118+
/* Non-this terms default to EcsIn */
57119+
if (ecs_term_match_this(term) || inout != EcsInOutDefault) {
57120+
query->flags |= EcsQueryHasOutTerms;
57121+
}
57122+
57123+
bool match_non_this = !ecs_term_match_this(term) ||
57124+
(term->src.flags & EcsUp);
57125+
if (match_non_this && inout != EcsInOutDefault) {
57126+
query->flags |= EcsQueryHasNonThisOutTerms;
57127+
}
5711157128
}
5711257129

5711357130
if (src->flags & EcsCascade) {
@@ -57994,31 +58011,41 @@ void flecs_query_mark_columns_dirty(
5799458011
ecs_query_table_match_t *qm)
5799558012
{
5799658013
ecs_table_t *table = qm->table;
57997-
if (!table) {
57998-
return;
57999-
}
58000-
58001-
int32_t *dirty_state = table->dirty_state;
58002-
if (dirty_state) {
58003-
int32_t *storage_columns = qm->storage_columns;
58004-
ecs_filter_t *filter = &query->filter;
58014+
ecs_filter_t *filter = &query->filter;
58015+
if ((table && table->dirty_state) || (query->flags & EcsQueryHasNonThisOutTerms)) {
5800558016
ecs_term_t *terms = filter->terms;
5800658017
int32_t i, count = filter->term_count;
5800758018

5800858019
for (i = 0; i < count; i ++) {
5800958020
ecs_term_t *term = &terms[i];
58010-
if (term->inout == EcsIn || term->inout == EcsInOutNone) {
58021+
ecs_inout_kind_t inout = term->inout;
58022+
if (inout == EcsIn || inout == EcsInOutNone) {
5801158023
/* Don't mark readonly terms dirty */
5801258024
continue;
5801358025
}
5801458026

58015-
int32_t field = term->field_index;
58016-
int32_t column = storage_columns[field];
58017-
if (column < 0) {
58027+
flecs_table_column_t tc;
58028+
flecs_query_get_column_for_term(query, qm, i, &tc);
58029+
58030+
if (tc.column == -1) {
58031+
continue;
58032+
}
58033+
58034+
ecs_assert(tc.table != NULL, ECS_INTERNAL_ERROR, NULL);
58035+
int32_t *dirty_state = tc.table->dirty_state;
58036+
if (!dirty_state) {
5801858037
continue;
5801958038
}
5802058039

58021-
dirty_state[column + 1] ++;
58040+
if (table != tc.table) {
58041+
if (inout == EcsInOutDefault) {
58042+
continue;
58043+
}
58044+
}
58045+
58046+
ecs_assert(tc.column >= 0, ECS_INTERNAL_ERROR, NULL);
58047+
58048+
dirty_state[tc.column + 1] ++;
5802258049
}
5802358050
}
5802458051
}
@@ -58040,7 +58067,7 @@ bool ecs_query_next_table(
5804058067
if (query->flags & EcsQueryHasMonitor) {
5804158068
flecs_query_sync_match_monitor(query, prev);
5804258069
}
58043-
if (query->flags & EcsQueryHasOutColumns) {
58070+
if (query->flags & EcsQueryHasOutTerms) {
5804458071
if (it->count) {
5804558072
flecs_query_mark_columns_dirty(query, prev);
5804658073
}
@@ -58231,7 +58258,7 @@ bool ecs_query_next_instanced(
5823158258
if (flags & EcsQueryHasMonitor) {
5823258259
flecs_query_sync_match_monitor(query, prev);
5823358260
}
58234-
if (flags & EcsQueryHasOutColumns) {
58261+
if (flags & EcsQueryHasOutTerms) {
5823558262
flecs_query_mark_columns_dirty(query, prev);
5823658263
}
5823758264
}

flecs.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ extern "C" {
447447
#define EcsQueryHasRefs (1u << 1u) /* Does query have references */
448448
#define EcsQueryIsSubquery (1u << 2u) /* Is query a subquery */
449449
#define EcsQueryIsOrphaned (1u << 3u) /* Is subquery orphaned */
450-
#define EcsQueryHasOutColumns (1u << 4u) /* Does query have out columns */
450+
#define EcsQueryHasOutTerms (1u << 4u) /* Does query have out terms */
451+
#define EcsQueryHasNonThisOutTerms (1u << 5u) /* Does query have non-this out terms */
451452
#define EcsQueryHasMonitor (1u << 5u) /* Does query track changes */
452453
#define EcsQueryTrivialIter (1u << 6u) /* Does the query require special features to iterate */
453454

@@ -8600,6 +8601,9 @@ int ecs_value_move_ctor(
86008601
#define ecs_singleton_get(world, comp)\
86018602
ecs_get(world, ecs_id(comp), comp)
86028603

8604+
#define ecs_singleton_set_ptr(world, comp, ptr)\
8605+
ecs_set_ptr(world, ecs_id(comp), comp, ptr)
8606+
86038607
#define ecs_singleton_set(world, comp, ...)\
86048608
ecs_set(world, ecs_id(comp), comp, __VA_ARGS__)
86058609

include/flecs/private/api_flags.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ extern "C" {
182182
#define EcsQueryHasRefs (1u << 1u) /* Does query have references */
183183
#define EcsQueryIsSubquery (1u << 2u) /* Is query a subquery */
184184
#define EcsQueryIsOrphaned (1u << 3u) /* Is subquery orphaned */
185-
#define EcsQueryHasOutColumns (1u << 4u) /* Does query have out columns */
185+
#define EcsQueryHasOutTerms (1u << 4u) /* Does query have out terms */
186+
#define EcsQueryHasNonThisOutTerms (1u << 5u) /* Does query have non-this out terms */
186187
#define EcsQueryHasMonitor (1u << 5u) /* Does query track changes */
187188
#define EcsQueryTrivialIter (1u << 6u) /* Does the query require special features to iterate */
188189

0 commit comments

Comments
 (0)