forked from hanatos/vkdt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconnector.h
194 lines (170 loc) · 7.22 KB
/
connector.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#pragma once
#include "token.h"
#include "alloc.h"
#include <stdint.h>
#include <vulkan/vulkan.h>
// info about a region of interest.
// stores full buffer dimensions, context and roi.
typedef struct dt_roi_t
{
uint32_t full_wd, full_ht; // full input size
uint32_t wd, ht; // dimensions of scaled region
float scale; // scale: wd * scale is on input scale
}
dt_roi_t;
typedef enum dt_connector_flags_t
{
s_conn_none = 0,
s_conn_smooth = 1, // access this with a bilinear sampler during read
s_conn_clear = 2, // clear this to zero before writing
s_conn_feedback = 4, // this connection is only in between frames (written frame 1 and read frame 2)
s_conn_dynamic_array = 8, // dynamically allocated array connector, contents can change during animation
}
dt_connector_flags_t;
#if 0
// TODO: gcc can't do this either.
// TODO: so we probably want to generate these in a makefile,
// TODO: something like = 0x$(echo -n "ui16" | xxd -p -e | cut -f2 -d" ")ul
// this seems to work:
// echo "cat << EOF" > test2.sh
// cat test.h | sed 's/dt_token("\(.*\)")/0x$(echo -n "\1" | xxd -p -e | tr -s " " | cut -f2 -d" ")ul/g' >> test2.sh
// echo "EOF" >> test2.sh
// . test2.sh
// rm test2.sh
typedef enum dt_connector_format_t
{
s_format_f32 = dt_token("f32"),
s_format_f16 = dt_token("f16"),
s_format_ui32 = dt_token("ui32"),
s_format_ui16 = dt_token("ui16"),
s_format_ui8 = dt_token("ui8"),
}
dt_connector_format_t;
#endif
// shared property of nodes and modules: how many connectors do we allocate at
// max for each one of them:
#define DT_MAX_CONNECTORS 30
// connectors are used for modules as well as for nodes.
// modules:
// these have to be setup very quickly using tokens from a file
// these are only meta connections, the finest layer DAG will connect nodes
// with memory allocations for vulkan etc.
typedef struct dt_connector_t
{
dt_token_t name; // connector name
dt_token_t type; // read write source sink
dt_token_t chan; // rgb yuv.. or ssbo for storage buffers instead of images
dt_token_t format; // f32 ui16
dt_connector_flags_t flags;
// outputs (write buffers) can be connected to multiple inputs
// inputs (read buffers) can only be connected to exactly one output
// we only keep track of where inputs come from. this is also
// how we'll access it in the DAG during DFS from sinks.
int connected_mi; // pointing to connected module or node (or -1). is a reference count for write buffers.
int connected_mc; // index of the connector on the module
int associated_i; // for nodes, points back to module if repointing is needed
int associated_c;
int bypass_mi; // if set on an output, point to module input connector
int bypass_mc; // which should be used as a bypass directly.
// information about buffer dimensions transported here:
dt_roi_t roi;
// if the output/write connector holds an array and the entries have different size:
uint32_t *array_dim; // or 0 if all have the same size of the roi
dt_vkalloc_t *array_alloc; // or 0 if not needed. if the connector is flags & s_conn_dynamic_array use this.
size_t array_alloc_size; // size of the pool allocated for this dynamic texture array
dt_vkmem_t *array_mem; // memory allocated in outer mem pool, will be split for array dynamically
uint8_t *array_req; // points to flags what do do: 0 - nothing, 1 - alloc, 2 - upload, 4 - free
// buffer associated with this in case it connects nodes:
uint64_t offset_staging, size_staging;
// mem object for allocator:
// while this may seem duplicate with offset/size, it may be freed already
// and the offset and size are still valid for successive runs through the
// pipeline once it has been setup.
dt_vkmem_t *mem_staging;
// connectors can hold arrays of images, to facilitate more parallel
// processing for similar compute on small buffers.
// arrays are unsupported for: clearing, drawing, sources, and sinks.
int array_length;
// connectors can write to double-buffered output depending on animation frames.
// in the simplest case this is useful for sinks to double-buffer their data
// so drawing and computing can take place asynchronously.
int frames;
// a node's connector consumes array_length * frames buffers in the graph's
// conn_image[] pool. the location can be determined by dt_graph_connector_image()
// and makes use of the node->conn_image index list.
VkBuffer staging; // for sources and sinks
const char *tooltip; // tooltip extracted from docs
}
dt_connector_t;
// "templatised" connection functions for both modules and nodes
typedef struct dt_graph_t dt_graph_t; // fwd declare
// connect source|write (m0,c0) -> sink|read (m1,c1)
int dt_module_connect(dt_graph_t *graph, int m0, int c0, int m1, int c1);
int dt_node_connect(dt_graph_t *graph, int n0, int c0, int n1, int c1);
int dt_node_feedback(dt_graph_t *graph, int n0, int c0, int n1, int c1);
static inline int
dt_connected(const dt_connector_t *c)
{
return c->connected_mi >= 0 && c->connected_mc >= 0;
}
static inline const char*
dt_connector_error_str(const int err)
{
switch(err)
{
case 1: return "no such destination node";
case 2: return "no such destination connector";
case 3: return "destination does not read";
case 4: return "destination inconsistent";
case 5: return "destination inconsistent";
case 6: return "destination inconsistent";
case 7: return "no such source node";
case 8: return "no such source connector";
case 9: return "source does not write";
case 10: return "channels do not match";
case 11: return "format does not match";
default: return "";
}
}
#ifdef NDEBUG
#define CONN(A) (A)
#else
#define CONN(A) \
do { \
int err = (A); \
if(err) fprintf(stderr, "%s:%d connection failed: %s\n", __FILE__, __LINE__, dt_connector_error_str(err)); \
} while(0)
#endif
static inline size_t
dt_connector_bytes_per_pixel(const dt_connector_t *c)
{
if(c->format == dt_token("ui32")) return 4;
if(c->format == dt_token("f32")) return 4;
if(c->format == dt_token("atom")) return 4; // evaluates to ui32 if no float atomics are supported, f32 otherwise
if(c->format == dt_token("dspy")) return 4;
if(c->format == dt_token("ui16")) return 2;
if(c->format == dt_token("f16")) return 2;
if(c->format == dt_token("ui8")) return 1;
return 0;
}
static inline int
dt_connector_channels(const dt_connector_t *c)
{
if(c->chan == dt_token("ssbo")) return 1; // shader storage buffers have no channels
// bayer or x-trans?
if(c->chan == dt_token("rggb") || c->chan == dt_token("rgbx")) return 1;
return c->chan <= 0xff ? 1 :
(c->chan <= 0xffff ? 2 :
4);
// (c->chan <= 0xffffff ? 3 : 4)); // this is mostly padded (intel)
}
static inline size_t
dt_connector_bufsize(const dt_connector_t *c, uint32_t wd, uint32_t ht)
{
if(c->format == dt_token("bc1")) return wd/4*ht/4 * 8;
if(c->format == dt_token("yuv")) return wd*ht * 2; // XXX ??? * 2/3 is not enough here.
if(c->format == dt_token("geo")) return 14*sizeof(int16_t)*ht/3; // 14 values per triangle
const int numc = dt_connector_channels(c);
const size_t bpp = dt_connector_bytes_per_pixel(c);
return numc * bpp * wd * ht;
}