mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-01 03:18:02 +03:00
init
This commit is contained in:
12511 files changed
+6156641
No files matched your search
+286
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright © 2019 Broadcom
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "util/set.h"
|
||||
#include "util/dag.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
append_edge(struct dag_node *parent, struct dag_node *child, uintptr_t data)
|
||||
{
|
||||
/* Remove the child as a DAG head. */
|
||||
list_delinit(&child->link);
|
||||
|
||||
struct dag_edge edge = {
|
||||
.child = child,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
util_dynarray_append(&parent->edges, edge);
|
||||
child->parent_count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a directed edge from the parent node to the child.
|
||||
*
|
||||
* Both nodes should have been initialized with dag_init_node(). The edge
|
||||
* list may contain multiple edges to the same child with different data.
|
||||
*/
|
||||
void
|
||||
dag_add_edge(struct dag_node *parent, struct dag_node *child, uintptr_t data)
|
||||
{
|
||||
util_dynarray_foreach(&parent->edges, struct dag_edge, edge) {
|
||||
if (edge->child == child && edge->data == data)
|
||||
return;
|
||||
}
|
||||
|
||||
append_edge(parent, child, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a directed edge from the parent node to the child.
|
||||
*
|
||||
* Both nodes should have been initialized with dag_init_node(). If there is
|
||||
* already an existing edge, the data is updated to the maximum of the
|
||||
* previous data and the new data. This is useful if the data represents a
|
||||
* delay.
|
||||
*/
|
||||
void
|
||||
dag_add_edge_max_data(struct dag_node *parent, struct dag_node *child,
|
||||
uintptr_t data)
|
||||
{
|
||||
util_dynarray_foreach(&parent->edges, struct dag_edge, edge) {
|
||||
if (edge->child == child) {
|
||||
edge->data = MAX2(edge->data, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
append_edge(parent, child, data);
|
||||
}
|
||||
|
||||
/* Removes a single edge from the graph, promoting the child to a DAG head.
|
||||
*
|
||||
* Note that calling this other than through dag_prune_head() means that you
|
||||
* need to be careful when iterating the edges of remaining nodes for NULL
|
||||
* children.
|
||||
*/
|
||||
void
|
||||
dag_remove_edge(struct dag *dag, struct dag_edge *edge)
|
||||
{
|
||||
if (!edge->child)
|
||||
return;
|
||||
|
||||
struct dag_node *child = edge->child;
|
||||
child->parent_count--;
|
||||
if (child->parent_count == 0)
|
||||
list_addtail(&child->link, &dag->heads);
|
||||
|
||||
edge->child = NULL;
|
||||
edge->data = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a DAG head from the graph, and moves any new dag heads into the
|
||||
* heads list.
|
||||
*/
|
||||
void
|
||||
dag_prune_head(struct dag *dag, struct dag_node *node)
|
||||
{
|
||||
assert(!node->parent_count);
|
||||
|
||||
list_delinit(&node->link);
|
||||
|
||||
util_dynarray_foreach(&node->edges, struct dag_edge, edge) {
|
||||
dag_remove_edge(dag, edge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes DAG node (probably embedded in some other datastructure in the
|
||||
* user).
|
||||
*/
|
||||
void
|
||||
dag_init_node(struct dag *dag, struct dag_node *node)
|
||||
{
|
||||
util_dynarray_init(&node->edges, dag);
|
||||
list_addtail(&node->link, &dag->heads);
|
||||
}
|
||||
|
||||
struct dag_traverse_bottom_up_state {
|
||||
struct set *seen;
|
||||
void (*cb)(struct dag_node *node, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
dag_traverse_bottom_up_node(struct dag_node *node,
|
||||
struct dag_traverse_bottom_up_state *state)
|
||||
{
|
||||
if (_mesa_set_search(state->seen, node))
|
||||
return;
|
||||
|
||||
struct util_dynarray stack = UTIL_DYNARRAY_INIT;
|
||||
|
||||
do {
|
||||
assert(node);
|
||||
|
||||
while (node->edges.size != 0) {
|
||||
util_dynarray_append(&stack, node);
|
||||
|
||||
/* Push unprocessed children onto stack in reverse order. Note that
|
||||
* it's possible for any of the children nodes to already be on the
|
||||
* stack.
|
||||
*/
|
||||
util_dynarray_foreach_reverse(&node->edges, struct dag_edge, edge) {
|
||||
if (!_mesa_set_search(state->seen, edge->child)) {
|
||||
util_dynarray_append(&stack, edge->child);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get last element pushed: either left-most child or current node.
|
||||
* If it's the current node, that means that we've processed all its
|
||||
* children already.
|
||||
*/
|
||||
struct dag_node *top = util_dynarray_pop(&stack, struct dag_node *);
|
||||
if (top == node)
|
||||
break;
|
||||
node = top;
|
||||
}
|
||||
|
||||
/* Process the node */
|
||||
state->cb(node, state->data);
|
||||
_mesa_set_add(state->seen, node);
|
||||
|
||||
/* Find the next unprocessed node in the stack */
|
||||
do {
|
||||
node = NULL;
|
||||
if (stack.size == 0)
|
||||
break;
|
||||
|
||||
node = util_dynarray_pop(&stack, struct dag_node *);
|
||||
} while (_mesa_set_search(state->seen, node));
|
||||
} while (node);
|
||||
|
||||
util_dynarray_fini(&stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the DAG from leaves to the root, ensuring that each node is only seen
|
||||
* once its children have been, and each node is only traversed once.
|
||||
*/
|
||||
void
|
||||
dag_traverse_bottom_up(struct dag *dag, void (*cb)(struct dag_node *node,
|
||||
void *data), void *data)
|
||||
{
|
||||
struct dag_traverse_bottom_up_state state = {
|
||||
.seen = _mesa_pointer_set_create(NULL),
|
||||
.data = data,
|
||||
.cb = cb,
|
||||
};
|
||||
|
||||
list_for_each_entry(struct dag_node, node, &dag->heads, link) {
|
||||
dag_traverse_bottom_up_node(node, &state);
|
||||
}
|
||||
|
||||
ralloc_free(state.seen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty DAG datastructure.
|
||||
*/
|
||||
struct dag *
|
||||
dag_create(void *mem_ctx)
|
||||
{
|
||||
struct dag *dag = rzalloc(mem_ctx, struct dag);
|
||||
|
||||
list_inithead(&dag->heads);
|
||||
|
||||
return dag;
|
||||
}
|
||||
|
||||
struct dag_validate_state {
|
||||
struct util_dynarray stack;
|
||||
struct set *stack_set;
|
||||
struct set *seen;
|
||||
void (*cb)(const struct dag_node *node, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void
|
||||
dag_validate_node(struct dag_node *node,
|
||||
struct dag_validate_state *state)
|
||||
{
|
||||
if (_mesa_set_search(state->stack_set, node)) {
|
||||
fprintf(stderr, "DAG validation failed at:\n");
|
||||
fprintf(stderr, " %p: ", node);
|
||||
state->cb(node, state->data);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Nodes in stack:\n");
|
||||
util_dynarray_foreach(&state->stack, struct dag_node *, nodep) {
|
||||
struct dag_node *node = *nodep;
|
||||
fprintf(stderr, " %p: ", node);
|
||||
state->cb(node, state->data);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
if (_mesa_set_search(state->seen, node))
|
||||
return;
|
||||
|
||||
_mesa_set_add(state->stack_set, node);
|
||||
_mesa_set_add(state->seen, node);
|
||||
util_dynarray_append(&state->stack, node);
|
||||
|
||||
util_dynarray_foreach(&node->edges, struct dag_edge, edge) {
|
||||
dag_validate_node(edge->child, state);
|
||||
}
|
||||
|
||||
(void)util_dynarray_pop(&state->stack, struct dag_node *);
|
||||
_mesa_set_remove_key(state->stack_set, node);
|
||||
}
|
||||
|
||||
void
|
||||
dag_validate(struct dag *dag, void (*cb)(const struct dag_node *node,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
void *mem_ctx = ralloc_context(NULL);
|
||||
struct dag_validate_state state = {
|
||||
.stack_set = _mesa_pointer_set_create(mem_ctx),
|
||||
.seen = _mesa_pointer_set_create(mem_ctx),
|
||||
.cb = cb,
|
||||
.data = data,
|
||||
};
|
||||
|
||||
util_dynarray_init(&state.stack, mem_ctx);
|
||||
|
||||
list_validate(&dag->heads);
|
||||
|
||||
list_for_each_entry(struct dag_node, node, &dag->heads, link) {
|
||||
dag_validate_node(node, &state);
|
||||
}
|
||||
|
||||
ralloc_free(mem_ctx);
|
||||
}
|
||||
Reference in new issue
Block a user