today i'll start in earnest to prepare GPU compute support for LRDL:
the C++ generating backend will be generalized to use macro indirections for C++ idoms slang doesn't support
each case tagged for gpu is translated to a slang file, the slang file then translated to SPIR-V binary, the binary code embedded in the generated host code.
host code uses SDL_gpu (through macros as well) to load GPU kernels and execute them.
host table impls need to implement SDL_gpu upload/download locally; no global system.
tables accessed from gpu cases need a parallel implementation in slang; slang has limited support for generics - what i can't get to work there, i'll do with macros.
fixed a bunch of compiler bugs today, and developed some flow to modularize e.g. mouse click handling.
the abstraction below makes it possible to "listen" to mouse click events. it's just a test, i'm still figuring out how to treat system events in data flow; not happy yet.
Mouse mouse_event
time : u64
id : u32
window : u32
pos : vec2
buttons : u32
macro mouse_clicks mask :
buffer clicking u32 u32
set clicks
time : u64
id : u32
window : u32
pos : vec2
case
new mouse_event time id win pos buttons
button = band buttons mask
merge
case
button = mask
case
button = 0:u32
clicking id mask
then clicks time id win pos
cue clicking id button
label leftclicks : mouse_clicks 2:u32
label rightclicks : mouse_clicks 8:u32
case
new leftclicks.clicks _ _ _ pos
report "left"
report pos
case
new rightclicks.clicks _ _ _ pos
report "right"
report pos
# support for decorators
inline doc (text)
inline (T)
'define-symbol T
Text = text
T
# hooking pre- and post-field calls
type SuperK < Struct
inline __struct (cls T field)
inline field (...)
dump cls T ...
F := field ...
# dumps (name = type)
dump F.Type
F
struct K < SuperK
@@ doc
text = "this is foo"
foo : i32
@@ doc
text = "this is bar"
bar : Unknown = 2
Dropping a little #devlog about the actual gameplay of #Overzealous, my new solo #TTRPG of cartoonish cult devilry. This is a tactical game that revolves around five ever-changing stats.
As an outer god, you'll need enough CULTISTS and IMMINENCE to become manifest.
Your cultists generate imminence with their worship, but also
spread heretical ideas (adding DIVERGENCE)
get overexcited about bloodshed (increasing FERVOUR)
draw ancient horrors to the well of power (adding MONSTROSITY)
1/3
Stat tracker. Positive stats go to 20, negative to 13. Adorned with various Overzealous-related symbols.
In ByteBlaster there are all sorts of strange and unexplained sights and locales to explore. It’s not just random stuff around though. We believe in the power of environmental storytelling.
Erro stands near the edge of one of the many floating platforms that make up his world, looking at something just out of reach. A floating pile of debris in the shape of what appear to be pieces of a statue of someone. The viewer may make out a familiar looking helmet and sword.
Big thanks to everybody who encouraged me on this whacky gamedev journey! Today I replaced the complex cloud system with a simple shader and tuned some of the sound effects #gamedev#indiedev#devlog
🔧 Devlog: FediBuzz relay returned 400 errors. Root cause: nginx 1.18 + HTTP/2 + hyper/reqwest sent duplicate Host/:authority headers. Fixed by upgrading to nginx 1.29.4 which handles HTTP/2 headers correctly (fix from Aug 2025). #fediverse#activitypub#devlog
i'm now making some changes to the code generator to conform to NOIR semantics. rules targeting a relator will only be run when any of the inputs have been updated.
this way we can put the entire program in a single top level loop, and leave it to the low-level compiler to optimize branches.
another terminology change. renamed "relators" to "tables". has precedent, sounds familiar, describes the shape precisely - they're in fact more table-y than lua's tables.
also, if you like, you can pronounce LRDL as "lurdle".
codegen now generates code that for each case ensures that it only runs when any of its source tables bool ::changed() method returns true.
next step is to de-complexify the scheduling algo and enforce DAGness (complain about hard cycles in the hypergraph). that means i can remove SCC analysis.
i'm rewriting the execution planner, and that requires topologically sorting the program's hypergraph - so, a bipartite graph.
the problem is we have two types of vertices. how i solved it is that i number both tables and cases in the same vertex array; the reverse map (object -> vertex index) works with std::variant to resolve.
and so, for topological analysis, the graph appears no longer bipartite, and many headaches are avoided.
yesterday i only managed to do translation to a sortable graph, today i'm going to add kahn's toposort. part of it is reporting errors on hard cycles. i could auto-convert hard to soft edges, but this can still be added later.
ironically i procrastinate here not because it is hard but because it is easy and i've done this part already three times. will have to put on some music and grind through it.
tracking mouse state is presently done with a table abstraction; first pic is how it's set up; the case is triggered every time there were state changes.
unfortunately this means clicks received in the same frame get lost. so instead i'll expose mouse state updates directly as a delta table.
update: and it's done. on the user side, i only needed to swap two fields to respect field order convention.
got an idea for how to control loops better that might finally break this stalemate between me and the language.
in a nutshell: user being able to mark cases as backedges allows to organize the entire thing as nested DAGs. i really hope this is the only thing i need.
made my test case worse to break Natural Loop finding. i added edges A->C with which B no longer is a suitable loop header, and D->F so flipping all edges does not make the problem any simpler.
note that this is a dependency graph not a CFG. each edge is a task, each vertex is (accumulating) data.
but i think there's still semantic clarity
missing.
even in datalog, stratification is completely implicit. it's also very limiting - there is no support for nested strat, where a result can be considered "temporarily stratified", and then we make a change afterwards that invalidates this result so its inputs have to be recomputed again.
so for this we'd need ways to define
when the container should be reset.
when the container is considered "sufficiently complete".
these two points do look suspiciously like header and break condition for loops.
in NOIR (https://git.sr.ht/~duangle/texts/tree/master/item/NOIR.md), which has similar, more minimal semantics, (1) is decided by whether we're updating from a back- (update) or from a front-edge (init), where the front-edge has precedence, and both edges are explicitly defined as such.
(2) would apply when no back-edge sourcing our container has made updates. this means active back-edges always preempt further processing.
but handling (2) like this is not enough; say you do a 2d loop. the outer variable Y will not receive updates for a while while the inner variable X updates - but Y is not complete yet.
in NOIR, (2) is implemented through definedness; a "breaking flow" was caused when an output was defined, by making the breaking flow depend on it being defined.
here the user would need to define a "gate" that indicates whether the container is considered complete. a bit cumbersome but precise.
for (1) i would need to add the restriction that back-rules (that is, rules that modify a container after it has been sourced) need to mark their insertion as an update:
cue A x
this is also beneficial for the reason that front-rules can now safely mutate a container directly since it has not been sourced yet; while only back-rules need to mutate a temporary delta state that gets applied on the next iteration so we do not change the present container state.