Skip to content

Commit fddc225

Browse files
committed
renderer: Change FindNode lookup from (N²) to O(N)
1 parent 1597016 commit fddc225

2 files changed

Lines changed: 100 additions & 8 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
2+
index cca1f68fda..a415afcc67 100644
3+
--- a/thirdparty/spirv-reflect/spirv_reflect.c
4+
+++ b/thirdparty/spirv-reflect/spirv_reflect.c
5+
@@ -215,6 +215,10 @@ typedef struct SpvReflectPrvParser {
6+
const char* source_embedded;
7+
size_t node_count;
8+
SpvReflectPrvNode* nodes;
9+
+ // Maps a result id to (node index + 1); 0 means "no node". Sized by the id
10+
+ // bound from the SPIR-V header so FindNode() is O(1) instead of O(node_count).
11+
+ uint32_t id_bound;
12+
+ uint32_t* node_index_by_id;
13+
uint32_t entry_point_count;
14+
uint32_t capability_count;
15+
uint32_t function_count;
16+
@@ -511,15 +515,11 @@ static bool IsSpecConstant(const SpvReflectPrvNode* p_node) {
17+
}
18+
19+
static SpvReflectPrvNode* FindNode(SpvReflectPrvParser* p_parser, uint32_t result_id) {
20+
- SpvReflectPrvNode* p_node = NULL;
21+
- for (size_t i = 0; i < p_parser->node_count; ++i) {
22+
- SpvReflectPrvNode* p_elem = &(p_parser->nodes[i]);
23+
- if (p_elem->result_id == result_id) {
24+
- p_node = p_elem;
25+
- break;
26+
- }
27+
+ if (result_id == 0 || result_id >= p_parser->id_bound) {
28+
+ return NULL;
29+
}
30+
- return p_node;
31+
+ uint32_t index_plus_one = p_parser->node_index_by_id[result_id];
32+
+ return index_plus_one ? &(p_parser->nodes[index_plus_one - 1]) : NULL;
33+
}
34+
35+
static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id) {
36+
@@ -660,6 +660,8 @@ static void DestroyParser(SpvReflectPrvParser* p_parser) {
37+
}
38+
39+
SafeFree(p_parser->nodes);
40+
+ SafeFree(p_parser->node_index_by_id);
41+
+ p_parser->id_bound = 0;
42+
SafeFree(p_parser->strings);
43+
SafeFree(p_parser->source_embedded);
44+
SafeFree(p_parser->functions);
45+
@@ -705,6 +707,15 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) {
46+
if (IsNull(p_parser->nodes)) {
47+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
48+
}
49+
+ // Allocate the result id -> node lookup table. Word 3 of the header is the id bound.
50+
+ p_parser->id_bound = p_spirv[3];
51+
+ if (p_parser->id_bound == 0) {
52+
+ return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
53+
+ }
54+
+ p_parser->node_index_by_id = (uint32_t*)calloc(p_parser->id_bound, sizeof(*(p_parser->node_index_by_id)));
55+
+ if (IsNull(p_parser->node_index_by_id)) {
56+
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
57+
+ }
58+
// Mark all nodes with an invalid state
59+
for (uint32_t i = 0; i < node_count; ++i) {
60+
p_parser->nodes[i].op = (SpvOp)INVALID_VALUE;
61+
@@ -1008,6 +1019,13 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) {
62+
} break;
63+
}
64+
65+
+ // Register the node so FindNode() can reach it. Ids are unique, except for
66+
+ // OpTypeForwardPointer whose result id is re-assigned to the OpTypePointer
67+
+ // above, so overwriting is what we want.
68+
+ if (p_node->result_id != 0 && p_node->result_id < p_parser->id_bound) {
69+
+ p_parser->node_index_by_id[p_node->result_id] = node_index + 1;
70+
+ }
71+
+
72+
if (p_node->is_type) {
73+
++(p_parser->type_count);
74+
}

thirdparty/spirv-reflect/spirv_reflect.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ typedef struct SpvReflectPrvParser {
215215
const char* source_embedded;
216216
size_t node_count;
217217
SpvReflectPrvNode* nodes;
218+
// Maps a result id to (node index + 1); 0 means "no node". Sized by the id
219+
// bound from the SPIR-V header so FindNode() is O(1) instead of O(node_count).
220+
uint32_t id_bound;
221+
uint32_t* node_index_by_id;
218222
uint32_t entry_point_count;
219223
uint32_t capability_count;
220224
uint32_t function_count;
@@ -511,15 +515,11 @@ static bool IsSpecConstant(const SpvReflectPrvNode* p_node) {
511515
}
512516

513517
static SpvReflectPrvNode* FindNode(SpvReflectPrvParser* p_parser, uint32_t result_id) {
514-
SpvReflectPrvNode* p_node = NULL;
515-
for (size_t i = 0; i < p_parser->node_count; ++i) {
516-
SpvReflectPrvNode* p_elem = &(p_parser->nodes[i]);
517-
if (p_elem->result_id == result_id) {
518-
p_node = p_elem;
519-
break;
520-
}
518+
if (result_id == 0 || result_id >= p_parser->id_bound) {
519+
return NULL;
521520
}
522-
return p_node;
521+
uint32_t index_plus_one = p_parser->node_index_by_id[result_id];
522+
return index_plus_one ? &(p_parser->nodes[index_plus_one - 1]) : NULL;
523523
}
524524

525525
static SpvReflectTypeDescription* FindType(SpvReflectShaderModule* p_module, uint32_t type_id) {
@@ -660,6 +660,8 @@ static void DestroyParser(SpvReflectPrvParser* p_parser) {
660660
}
661661

662662
SafeFree(p_parser->nodes);
663+
SafeFree(p_parser->node_index_by_id);
664+
p_parser->id_bound = 0;
663665
SafeFree(p_parser->strings);
664666
SafeFree(p_parser->source_embedded);
665667
SafeFree(p_parser->functions);
@@ -705,6 +707,15 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) {
705707
if (IsNull(p_parser->nodes)) {
706708
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
707709
}
710+
// Allocate the result id -> node lookup table. Word 3 of the header is the id bound.
711+
p_parser->id_bound = p_spirv[3];
712+
if (p_parser->id_bound == 0) {
713+
return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ID_REFERENCE;
714+
}
715+
p_parser->node_index_by_id = (uint32_t*)calloc(p_parser->id_bound, sizeof(*(p_parser->node_index_by_id)));
716+
if (IsNull(p_parser->node_index_by_id)) {
717+
return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
718+
}
708719
// Mark all nodes with an invalid state
709720
for (uint32_t i = 0; i < node_count; ++i) {
710721
p_parser->nodes[i].op = (SpvOp)INVALID_VALUE;
@@ -1008,6 +1019,13 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser) {
10081019
} break;
10091020
}
10101021

1022+
// Register the node so FindNode() can reach it. Ids are unique, except for
1023+
// OpTypeForwardPointer whose result id is re-assigned to the OpTypePointer
1024+
// above, so overwriting is what we want.
1025+
if (p_node->result_id != 0 && p_node->result_id < p_parser->id_bound) {
1026+
p_parser->node_index_by_id[p_node->result_id] = node_index + 1;
1027+
}
1028+
10111029
if (p_node->is_type) {
10121030
++(p_parser->type_count);
10131031
}

0 commit comments

Comments
 (0)