Private
Public Access
33-post thread, 13 PNGs, the canonical 'shader dev' walkthrough. Reads FXAA 3.11 / FSR1 / Unity STP, names the permutations pattern (32-bit / packed 16-bit / implicit mediump / MIN-MAX sampling). DXIL no bitfield ops vs SPIR-V (HLSL pre-processing on non-Xbox = fail). 16-bit perf: don't permute from 32-bit float constants (instant PC perf death), alias FP16 as UINT32 binary blobs. Designing shaders like GPU assembly, AMD RDNA2 as the design target. Defines map logic to associated instruction (fma, bitfieldExtract), all-ints-unsigned convention with SI1_I1()-style bitcast macros, 3-letter type macros. Compiler pattern-match bugs: tried always-UINT4 bitcast, didn't work; native types except waveops. Argument passing SSA state explosion: inout uint4[16] (all VGPRs) didn't end well - shader langs support globals, use them. Next level: mostly globals with type- bitcast aliasing; x86-64 union-of-structs-on-globals as the GPU calling ABI. Foundation for the SPIR-V-from-data + cart-file work (Aug 2025).
560 lines
23 KiB
JSON
560 lines
23 KiB
JSON
{
|
|
"root_post_id": "1859395250537595016",
|
|
"posts": [
|
|
{
|
|
"post_id": "1859368974351274470",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[0] Been wanting to do this for a long time, a thread on hard-core shader development. Something that digs into what I've learned and applied over the years. Along with the evolution of the strange syntax I use when writing shaders ...",
|
|
"timestamp": "2024-11-20 22:51:23",
|
|
"media_urls": [],
|
|
"reply_to_id": null,
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 22,
|
|
"like_count": 195,
|
|
"view_count": 19712
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859369992355021246",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[1] Lets start at one of the early ones, FXAA 3.11. Someone is hosting that here: https://gist.github.com/kosua20/0c506b81b3812ac900048059d2383126 ... most lines, it's an easy map to NV's arch which has predicated instructions (red is the predicate). Many lines are 1:1 mappings with physical HW instructions.",
|
|
"timestamp": "2024-11-20 22:55:26",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3OqZkWsAAeP9s?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859368974351274470",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 2,
|
|
"repost_count": 1,
|
|
"like_count": 10,
|
|
"view_count": 2078
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859372015670432237",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[2] Looking at FSR1: https://github.com/GPUOpen-Effects/FidelityFX-FSR/blob/master/ffx-fsr/ffx_fsr1.h - that had 3 permutations {32-bit, 16-bit unpacked, 16-bit packed}, where the packed one maps to how AMD's packed instructions work (everything explicitly packed)",
|
|
"timestamp": "2024-11-20 23:03:28",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3QjEiWYAADo14?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859369992355021246",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 1,
|
|
"like_count": 10,
|
|
"view_count": 1624
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859373265380069827",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[3] Onto STP: https://github.com/Unity-Technologies/Graphics/blob/27341ce4f5c8853d7f15e9420bff499f1087aceb/Packages/com.unity.render-pipelines.core/Runtime/STP/Stp.hlsl - A different set of permutations {32-bit, packed 16-bit} then {implicit mediump vs explicit} in the 32-bit (generic) permutation via types like StpMF4 which aim to allow a compiler on mobile to get some 16-bit register savings",
|
|
"timestamp": "2024-11-20 23:08:26",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3SFXTXoAEt4tX?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859372015670432237",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 4,
|
|
"view_count": 1529
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859373919146213617",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[4] Notice for 16-bit path, everything again is explicitly packed (unlike the 32-bit path). And GLSL to SPIR-V would get explicit packing to the IHV driver since SPIR-V has explicit vector types (unlike DX, which was an insane problem). Example, the reprojection filtering below.",
|
|
"timestamp": "2024-11-20 23:11:02",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3SmjPWMAEMX_d?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859373265380069827",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 5,
|
|
"view_count": 1397
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859374673953239528",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[5] Then STP had defines to work out differences in sampling capability (like supporting MIN/MAX sampling with UINT or not, or supporting immediate offsets or not). Example in the code doing {z,motion} UINT32 packed nearest dilation:",
|
|
"timestamp": "2024-11-20 23:14:02",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3TW0oWIAArDjw?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859373919146213617",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 1266
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859376826709311577",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[6] The largest portability nightmare was mixing explicit FP16 with wave ops! So many compiler bugs across vendors = so many permutations in the code. The 32-bit path had to have a conversion from 'StpMF4' (possible implicit medium precision), to 'StpF4' explicit 32-bit.",
|
|
"timestamp": "2024-11-20 23:22:35",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3UTC_WcAAyc5J?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859374673953239528",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 1237
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859377684104536314",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[7] Some of perf death problems had been that DXIL didn't have bitfield ops (unlike SPIR-V), HLSL depends on IHV compilers somehow finding and pattern matching stuff like the crap below (which is MANY OPS to 1 OPCODE). So pre-processing through HLSL on non-Xbox platforms = fail!",
|
|
"timestamp": "2024-11-20 23:26:00",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3V5wGW8AADAju?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859376826709311577",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 2,
|
|
"repost_count": 0,
|
|
"like_count": 5,
|
|
"view_count": 1310
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859378670105674093",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[8] Go into the shader which is doing wave ops, and the true nightmare of platform workarounds becomes apparent https://github.com/Unity-Technologies/Graphics/blob/27341ce4f5c8853d7f15e9420bff499f1087aceb/Packages/com.unity.render-pipelines.core/Runtime/STP/StpSetup.compute - LSD/waveop permutations, 32-bit/16-bit in 16-bit path, etc",
|
|
"timestamp": "2024-11-20 23:29:55",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3W143XEAEq6LS?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859377684104536314",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 5,
|
|
"view_count": 1289
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859380404781814109",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[9] So yeah, even in modern times you can hit paths in compilers and toolchains that well never got tested because no one had tried it and tried shipping with it. And I think this might hint that relatively few actually do this level of crazy",
|
|
"timestamp": "2024-11-20 23:36:48",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859378670105674093",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 4,
|
|
"view_count": 1827
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859381304112054632",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[10] Part of the formula for getting great gains with 16-bit is simply the register savings. It wouldn't be possible to do good 4x4 kernel lanczos inside a TAA without packed 16-bit support (it's 64 values on load without thinking about all the other mid-algorithm data) ...",
|
|
"timestamp": "2024-11-20 23:40:23",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859380404781814109",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 5,
|
|
"view_count": 901
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859381761685221605",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[11] Looking at STP again, there is a dering, which works with the {min,max} of the near 2x2. If the HW has MIN/MAX sampling, it can fetch that, which means a lot more than 64 values, and if not they need intermediate ALU min/max, which is extra state ...",
|
|
"timestamp": "2024-11-20 23:42:12",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3Ze31XAAA94Y1?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859381304112054632",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 908
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859382640534516057",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[12] Mobile hardware is so register starved (probably due to all that SRAM area going to tiles) that it wasn't possible to do good reprojection filtering PERIOD even with FP16. So STP had a crippled compromise that did bilinear in one direction, and lanczos in the other axis",
|
|
"timestamp": "2024-11-20 23:45:41",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3afacXQAAFX-c?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859381761685221605",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 883
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859383175849349534",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[13] Huge wake up call to mobile HW vendors, if you don't match VGPR capacity of PCs, you can never take on where PC workloads will get to. Now given both NV and AMD have packed 16-bit, it is a great time to push pass merging and avoid DRAM traffic by doing more in one shader",
|
|
"timestamp": "2024-11-20 23:47:49",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859382640534516057",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 728
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859383954551243222",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[14] Another part of the 16-bit perf puzzle is to not use 16-bit FP16 in constants explicitly, but only package them up as aliased as UINT32 binary blobs. And for portable systems that still need 32-bit fallbacks, always build both a packed 16-bit and 32-bit set of constants.",
|
|
"timestamp": "2024-11-20 23:50:55",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859383175849349534",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 699
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859384348249608376",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[15] So many people tried to 16-bit permute things working from 32-bit float constants, and on PC that is instant perf death. Sure some mobile hardware can do the conversions for lower cost, and some mobile HW could pre-amble the conversions if not, but that isn't perf portable",
|
|
"timestamp": "2024-11-20 23:52:28",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859383954551243222",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 678
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859385131942961199",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[16] Switching gears. So STP didn't get the most hardcore way I like to write shaders, and I've had a bunch of different permutations of ideas tried over the years ... specifically how to make the code more like GPU assembly!",
|
|
"timestamp": "2024-11-20 23:55:35",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859384348249608376",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 678
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859385497916932274",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[17] Looking like assembly as in making it exactly clear what the lines map to in HW OPCODEs, and what the variable map to in REGISTERS. So you are designing to what the hardware could do, even if the compiler cannot keep up",
|
|
"timestamp": "2024-11-20 23:57:03",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859385131942961199",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 645
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859386143663411375",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[18] Now it's true that NV and AMD HW are quite different in some respects (NV is predicated, and has generic 3 op logic ops, etc), so ultimately one has to pick their shader language abstraction based on what they want to target the most https://docs.nvidia.com/cuda/cuda-binary-utilities/index.html#instruction-set-reference (NV ISA docs)",
|
|
"timestamp": "2024-11-20 23:59:37",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859385497916932274",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 658
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859386525982527578",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[19] Since AMD's docs are more complete, and I like to make sure a console port is possible and would be as fast as possible, I prefer to think through all my shaders as if they are getting direct mapped to AMD's RDNA2 these days: https://www.amd.com/content/dam/amd/en/documents/radeon-tech-docs/instruction-set-architectures/rdna2-shader-instruction-set-architecture.pdf",
|
|
"timestamp": "2024-11-21 00:01:08",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859386143663411375",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 674
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859387770617110636",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[20] So I usually do a define that maps logic directly to what the associated instruction would be. Some of these actually map to shading language intrinsics already like fma() or bitfieldExtract(). Then write all my shader code using these defines. Example below for the defines",
|
|
"timestamp": "2024-11-21 00:06:04",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3fKzqXUAAGnBQ?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859386525982527578",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 1,
|
|
"like_count": 7,
|
|
"view_count": 861
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859388846481322425",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[21] Like to use ASM like convention for {signed, unsigned}, that all integers are unsigned, and only get converted to signed when required inside the define for a specific opcode (like signed or unsigned bitfield extract). Bit casting (aliasing) is done via SI1_I1() style macros",
|
|
"timestamp": "2024-11-21 00:10:21",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3gGUTWQAAZwyX?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859387770617110636",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 637
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859389468672680384",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[22] And I reduce all types to very simple 3 letter macros of which are described below. I use the same naming convention in CPU land as well. This helps keep code compact and easy to read IMO (highly subjective yes)",
|
|
"timestamp": "2024-11-21 00:12:49",
|
|
"media_urls": [
|
|
"https://pbs.twimg.com/media/Gc3gna_XcAA7PXx?format=png&name=orig"
|
|
],
|
|
"reply_to_id": "1859388846481322425",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 4,
|
|
"view_count": 601
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859390458293547232",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[23] One thing I struggle with to this day is compiler bitcast aliasing perf bugs. Meaning once I tried to always only use UINT4 types everywhere, and then wrap all OPCODE defines in bitcasting defines, that didn't go so well (looking at disassembly on AMD PC).",
|
|
"timestamp": "2024-11-21 00:16:45",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859389468672680384",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 542
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859390826054299714",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[24] Compilers depend a lot on pattern matching to NOP stuff, and well there are bugs, lots of bugs. So for the sake of portability, with the exception of {unsigned/signed} bitcasting, I use the native types when possible (no packed-16-bit/32-bit aliasing) exception of waveops",
|
|
"timestamp": "2024-11-21 00:18:13",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859390458293547232",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 528
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859391758817247636",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[25] Another aspect of compiler problems is argument passing to function calls causing SSA state explosions, because it's \"copy semantics\" as defined in the langs. Once I did inout uint4[16] (all VGPRs) as my only argument to all functions. Didn't end well!",
|
|
"timestamp": "2024-11-21 00:21:55",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859390826054299714",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 3,
|
|
"view_count": 518
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859392139790053772",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[26] Someone on twitter (or was it bsky or mast?) had been doing a one shader game. And addressing these kinds of problems, and reminded us, YES the shader languages support global variables. No need to pass them into function! (bingo)",
|
|
"timestamp": "2024-11-21 00:23:26",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859391758817247636",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 4,
|
|
"view_count": 522
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859392498797261032",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[27] We have been so seasoned to dislike globals in the past few decades due to well probably early mutli-window programming styles, that it is easy to forget you can just do globals, and they are fast at tool/compile time.",
|
|
"timestamp": "2024-11-21 00:24:52",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859392139790053772",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 2,
|
|
"repost_count": 1,
|
|
"like_count": 5,
|
|
"view_count": 803
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859392961294836222",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[28] I think the next level up of this design is to go to mostly global variables, but since the shader languages don't support global unions, then have different sets of globals when one needs to do type bitcast aliasing (which is very common with packed 16-bit and 64-bit logic)",
|
|
"timestamp": "2024-11-21 00:26:42",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859392498797261032",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 2,
|
|
"repost_count": 0,
|
|
"like_count": 1,
|
|
"view_count": 594
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859393537214763223",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[29] I still think the 'fix' for the shader compiler SSA state explosion mapping back to registers problem is to pass in explicit aliasing hints to the vendor compilers, so they have a better base guess at register allocation. But I doubt vendors would get on board with that",
|
|
"timestamp": "2024-11-21 00:28:59",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859392961294836222",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 1,
|
|
"view_count": 615
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859394143522521102",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[30] My personal x86-64 languages typically worked with unions of structs on globals. Where each struct in the union was a different aliased meaning to the HW registers, and functions had been associated with a given struct in the union. So no stacks or argument passing.",
|
|
"timestamp": "2024-11-21 00:31:24",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859393537214763223",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 599
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859394661518848470",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[31] That kind of setup for the GPU is ideal IMO (at least for the type of stuff I do). You can link. Because the union struct for the registers is the calling ABI, and never moves (no stack). So code sharing works amazingly well. And avoiding register state explosion is built in",
|
|
"timestamp": "2024-11-21 00:33:27",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859394143522521102",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 1,
|
|
"repost_count": 0,
|
|
"like_count": 2,
|
|
"view_count": 767
|
|
}
|
|
},
|
|
{
|
|
"post_id": "1859395250537595016",
|
|
"author": "NOTimothyLottes",
|
|
"handle": "NOTimothyLottes",
|
|
"text": "[32] oh damn [32], should probably stop now, until next time.",
|
|
"timestamp": "2024-11-21 00:35:48",
|
|
"media_urls": [],
|
|
"reply_to_id": "1859394661518848470",
|
|
"quote_of_id": null,
|
|
"metrics": {
|
|
"reply_count": 0,
|
|
"repost_count": 0,
|
|
"like_count": 8,
|
|
"view_count": 676
|
|
}
|
|
}
|
|
],
|
|
"source_url": "https://x.com/NOTimothyLottes/status/1859395250537595016"
|
|
} |