Skip to content

Commit 5556984

Browse files
author
Ilmari Heikkinen
committed
Update README, add another example, fix URL in hello_dlopen_gh
1 parent e901d46 commit 5556984

File tree

4 files changed

+121
-22
lines changed

4 files changed

+121
-22
lines changed

README.md

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,89 @@ GLSL as a scripting language? Say no more!
44

55
Crash is a super not production-ready asynchronous IO runtime and module system for Vulkan compute shaders.
66

7+
## What does it look like?
8+
9+
```glsl
10+
#include <file.glsl>
11+
#include <parallel.glsl>
12+
13+
void main() {
14+
if (ThreadId == 0) {
15+
println("Hello from crash!");
16+
println(`We are running on ${ThreadLocalCount * ThreadGroupCount} threads across ${ThreadGroupCount} thread groups. Let me introduce the first four thread groups.`);
17+
}
18+
globalBarrier();
19+
if (ThreadGroupId < 4 && ThreadLocalId % 16 == 0) {
20+
println(`Thread ${ThreadId} from thread group ${ThreadGroupId}[${ThreadLocalId}] checking in.`);
21+
}
22+
globalBarrier();
23+
if (ThreadId == 0) {
24+
println("What's your name?");
25+
FREE_ALL(
26+
string name = awaitIO(readLine(stdin, malloc(256)));
27+
println(`Hello ${name}!`);
28+
)
29+
}
30+
}
31+
```
32+
33+
Output
34+
```
35+
Hello from crash!
36+
We are running on 16384 threads across 256 thread groups. Let me introduce the first four thread groups.
37+
Thread 0 from thread group 0[0] checking in.
38+
Thread 16 from thread group 0[16] checking in.
39+
Thread 224 from thread group 3[32] checking in.
40+
Thread 240 from thread group 3[48] checking in.
41+
Thread 160 from thread group 2[32] checking in.
42+
Thread 176 from thread group 2[48] checking in.
43+
Thread 32 from thread group 0[32] checking in.
44+
Thread 64 from thread group 1[0] checking in.
45+
Thread 48 from thread group 0[48] checking in.
46+
Thread 80 from thread group 1[16] checking in.
47+
Thread 128 from thread group 2[0] checking in.
48+
Thread 192 from thread group 3[0] checking in.
49+
Thread 144 from thread group 2[16] checking in.
50+
Thread 208 from thread group 3[16] checking in.
51+
Thread 96 from thread group 1[32] checking in.
52+
Thread 112 from thread group 1[48] checking in.
53+
What's your name?
54+
John
55+
Hello John!
56+
57+
```
58+
59+
## Features
60+
761
With crash, your compute shaders can tell your CPU to do arbitrary IO:
862

9-
* Print strings (the crash GLSL preprocessor adds strings to GLSL)
63+
* Print strings
1064
* Read from files and write to files
65+
* Run commands and await their completion
1166
* Listen on network sockets
1267
* Tell the current time
68+
* Allocate memory on the CPU side and do reads and writes to it
1369
* dlopen CPU libraries and call functions in them
14-
* Run commands and await their completion
70+
71+
Extra language features
72+
73+
* Asynchronous IO `alloc_t buf = malloc(1024); io r = read("myfile.txt", buf); awaitIO(r); awaitIO(write("mycopy.txt", buf));`
74+
* Strings `string s = "foobar"; string s2 = str(vec3(0.0, 1.0, 2.0)); string s3 = concat(s1, " = ", s2); awaitIO(println(s3));`
75+
* Multi-line template strings with backticks `` `foo ${bar}` ``
76+
* Character literals `'x'` and int32 literals `'\x89PNG'`
77+
* Dynamically allocated arrays `i32array a = i32{1,2,3}; i32array b = i32{4,5}; i32array ab = i32concat(a,b);`
78+
* String and Array libraries that mostly match JavaScript, with some Pythonic `str()` thrown in.
79+
* Hashtables `i32map h = i32hAlloc(256); i32hSet(h, 12891, 23); println(str(i32hGet(h, 12891) == 23));`
80+
* Malloc that works by bumping a heap pointer and a FREE() macro to free all memory allocated inside it `FREE(alloc_t ptr = malloc(4));`
81+
* A second heap for IO to make life complicated: `FREE(alloc_t buf = malloc(1024); FREE_IO(readSync("myfile.txt", buf)); println(buf));`
82+
* And a macro to free both heaps at the same time: `FREE_ALL(alloc_t buf = malloc(1024); readSync("myfile.txt", buf); println(buf));`
83+
* Set warp width and warp count from GLSL: `ThreadLocalCount = 64; ThreadGroupCount = 256;`
84+
* By default, crash programs run across 16384 threads. A naive hello world will fill your screen with hellos. Use ThreadId to limit it to a single thread `if (ThreadId == 0) println("Hello, World!");`
85+
* Set heap size per thread, per thread group and total program heap `HeapSize = 4096; GroupHeapSize = HeapSize * ThreadLocalCount; TotalHeapSize = GroupHeapSize * ThreadGroupCount;`
86+
* An `#include <file.glsl>` system powered by the C preprocessor.
87+
* That also loads things over HTTPS with SHA256 integrity verification `#include <https://raw.githubusercontent.com/kig/spirv-wasm/12f2554994f5b733da65e6705099e2afd160649c/spirv-io/lib/dlopen.glsl> @ 4b43671ba494238b3855c2990c2cd844573a91d15464ed8b77d2a5b98d0eb2e1`
88+
89+
## Examples
1590

1691
The example scripts in [examples/](examples/) show you how to do various things, such as:
1792

@@ -84,6 +159,7 @@ The GPU spins and waits for the request status flag to be set to completed. Afte
84159
buffer, sets the request status flag to handled, and goes on its merry way.
85160

86161
So far, so good. What if you couldn't trust the order of the writes and reads above? What if cache lines in your memory buffer were getting transported over UDP.
162+
What if the driver killed your compute shaders after 10 seconds. Since clearly it has hung, right? Who would wait for user input in a shader? Crash, that's who!
87163

88164

89165
## License

examples/hello_crash.glsl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <file.glsl>
2+
#include <parallel.glsl>
3+
4+
void main() {
5+
if (ThreadId == 0) {
6+
println("Hello from crash!");
7+
println(`We are running on ${ThreadLocalCount * ThreadGroupCount} threads across ${ThreadGroupCount} thread groups. Let me introduce the first four thread groups.`);
8+
}
9+
globalBarrier();
10+
if (ThreadGroupId < 4 && ThreadLocalId % 16 == 0) {
11+
println(`Thread ${ThreadId} from thread group ${ThreadGroupId}[${ThreadLocalId}] checking in.`);
12+
}
13+
globalBarrier();
14+
if (ThreadId == 0) {
15+
println("What's your name?");
16+
string name = awaitIO(readLine(stdin, malloc(256)));
17+
println(`Hello ${name}!`);
18+
}
19+
}

examples/hello_dlopen_gh.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env gls
22

33
#include <file.glsl>
4-
#include <https://raw.githubusercontent.com/kig/spirv-wasm/master/spirv-io/lib/dlopen.glsl> @ dbc62e1bd6df8765f90b9f54e72bb644e20489ad17fefae51450cdf5321ca769
4+
#include <https://raw.githubusercontent.com/kig/spirv-wasm/12f2554994f5b733da65e6705099e2afd160649c/spirv-io/lib/dlopen.glsl> @ 4b43671ba494238b3855c2990c2cd844573a91d15464ed8b77d2a5b98d0eb2e1
55

66
ThreadLocalCount = 1;
77
ThreadGroupCount = 1;

lib/parallel.glsl

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
while (!done) {
4949
freeIO(
5050
fillLock(ReadBuffers[ActiveGroupId].status, {
51-
io r = read(file, readOffset + ActiveGroupID*readSize, readSize, ReadBuffers[ActiveGroupId].buffer);
51+
io r = read(file, readOffset + ActiveGroupId*readSize, readSize, ReadBuffers[ActiveGroupId].buffer);
5252
readOffset += ActiveGroupCount * readSize;
5353
readResult = awaitIO(r);
5454
ReadBuffers[ActiveGroupId].length = strLen(readResult);
@@ -82,7 +82,7 @@
8282
while (!done) {
8383
freeIO(
8484
drainLock(WriteBuffers[ActiveGroupId].status, {
85-
writeSync(outFile, writeOffset + ActiveGroupID*writeSize, writeSize, string(0, WriteBuffers[ActiveGroupId].length) + WriteBuffers[ActiveGroupId].buffer.x);
85+
writeSync(outFile, writeOffset + ActiveGroupId*writeSize, writeSize, string(0, WriteBuffers[ActiveGroupId].length) + WriteBuffers[ActiveGroupId].buffer.x);
8686
writeOffset += ActiveGroupCount * writeSize;
8787
done = WriteBuffers[ActiveGroupId].done;
8888
});
@@ -104,7 +104,23 @@ shared int32_t _ctx_;
104104
shared int32_t _start_group_;
105105
shared int32_t _end_group_;
106106

107-
#define GlobalBarrierLock io_pad_15
107+
#define GlobalBarrierLock io_pad_11
108+
109+
void globalBarrier() {
110+
atomicAdd(GlobalBarrierLock, 1);
111+
if (ThreadId == 0) {
112+
while (GlobalBarrierLock < ThreadCount);
113+
GlobalBarrierLock = 0;
114+
}
115+
while (GlobalBarrierLock != 0);
116+
}
117+
118+
void deviceBarrier() {
119+
controlBarrier(gl_ScopeDevice, gl_ScopeDevice, gl_StorageSemanticsBuffer | gl_StorageSemanticsShared, gl_SemanticsAcquireRelease);
120+
}
121+
122+
/*
123+
108124
#define ActiveGroupCount (_end_group_ - _start_group_)
109125
#define ActiveGroupId (ThreadGroupId - _start_group_)
110126
@@ -122,31 +138,18 @@ shared int32_t _end_group_;
122138
#define CTX_MULTIGROUP_THREADS 3
123139
124140
#define widefor(t, i, start, end) for ( \
125-
t i = t(_ctx_ == CTX_SINGLE_THREAD ? 0 : (_ctx_ == CTX_ALL_THREADS ? ThreadId : ThreadLocalID )) + (start), \
141+
t i = t(_ctx_ == CTX_SINGLE_THREAD ? 0 : (_ctx_ == CTX_ALL_THREADS ? ThreadId : ThreadLocalId )) + (start), \
126142
t _incr_ = t(_ctx_ == CTX_SINGLE_THREAD ? 1 : (_ctx_ == CTX_ALL_THREADS ? ThreadCount : ThreadLocalCount)); \
127143
i < (end); i += _incr_)
128144
129-
#define allfor(t, i, start, end) for (t i = ThreadID + start; i < end; i += ThreadCount)
130-
#define groupfor(t, i, start, end) for (t i = ThreadLocalID + start; i < end; i += ThreadLocalCount)
145+
#define allfor(t, i, start, end) for (t i = ThreadId + start; i < end; i += ThreadCount)
146+
#define groupfor(t, i, start, end) for (t i = ThreadLocalId + start; i < end; i += ThreadLocalCount)
131147
132148
void copyFromIOToHeap(ptr_t src, ptr_t dst, size_t len) {
133149
widefor(ptr_t, i, 0, len/16) i64v2heap[dst/16+i] = i64v2fromIO[src/16+i];
134150
widefor(ptr_t, i, len/16*16, len ) heap[dst+i] = fromIO[src+i];
135151
}
136152
137-
void globalBarrier() {
138-
atomicAdd(GlobalBarrierLock, 1);
139-
if (ThreadId == 0) {
140-
while (GlobalBarrierLock < ThreadCount);
141-
GlobalBarrierLock = 0;
142-
}
143-
while (GlobalBarrierLock != 0);
144-
}
145-
146-
void deviceBarrier() {
147-
controlBarrier(gl_ScopeDevice, gl_ScopeDevice, gl_StorageSemanticsBuffer | gl_StorageSemanticsShared, gl_SemanticsAcquireRelease);
148-
}
149-
150153
#define unique(f) { \
151154
atomicMax(CtxLock, 1); \
152155
if (ThreadId == 0) { \
@@ -263,3 +266,4 @@ void deviceBarrier() {
263266
// }
264267
// }
265268
//}
269+
*/

0 commit comments

Comments
 (0)