{ "root_post_id": "1588906002212323328", "posts": [ { "post_id": "1588902081502797826", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "GPU Programming Tip Line Thread /", "timestamp": "2022-11-05 14:32:31", "media_urls": [], "reply_to_id": null, "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 6, "view_count": 0 } }, { "post_id": "1588902190034620417", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[0] Normalization fail case is 'rsq(0)=INF*0=NaN', trim out intermediate INF to fix, 'normalize_safe(x){return x*min(MAX_FLOAT,rsq(dot(x,x)));}'", "timestamp": "2022-11-05 14:32:57", "media_urls": [], "reply_to_id": "1588902081502797826", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588902600686329857", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[1] PC FP16 1/denormals generates INFs which can easily eventually result in NaNs, fix positives with 'rcp(max(x,SMALLEST_NORMAL))'", "timestamp": "2022-11-05 14:34:35", "media_urls": [], "reply_to_id": "1588902190034620417", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903127549607936", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[2] 'spirv-opt -Os' (optimize for size) is your weapon against \"back-before-its-done--getting-groceries\" IHV compile times", "timestamp": "2022-11-05 14:36:40", "media_urls": [], "reply_to_id": "1588902600686329857", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903378952007680", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[3] Driver ignoring your '[[dont_unroll]]', 'int eatThisBuddy=1+/*hidden-zero*/constantBuffer.zero[0];for(i=0;i<1024;i+=eatThisBuddy){...'", "timestamp": "2022-11-05 14:37:40", "media_urls": [], "reply_to_id": "1588903127549607936", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903586721042432", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[4] 'Ship-One-Shader' = One SPIR-V binary, use specialization constants to select shader at PSO generation time, minimizes released shader binary size", "timestamp": "2022-11-05 14:38:30", "media_urls": [], "reply_to_id": "1588903378952007680", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903663468437508", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[5] 'Ship-One-Shader' requires 'spirv-opt -Os'", "timestamp": "2022-11-05 14:38:48", "media_urls": [], "reply_to_id": "1588903586721042432", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903725783220224", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[6] Use signed 'mask=bitfieldExtract(int(v),bit,1)' to turn bit into all 0's or 1's mask", "timestamp": "2022-11-05 14:39:03", "media_urls": [], "reply_to_id": "1588903663468437508", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588903926510014467", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[7] On PC for AMD's native V_BFI_B32 (to select bits based on mask) use 'Bfi(int src,int ins,int mask){return (ins&mask)|(src&(~mask));}'", "timestamp": "2022-11-05 14:39:51", "media_urls": [], "reply_to_id": "1588903725783220224", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904013239844870", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[8] Use 'bitfieldInsert(,,0,compileTimeImmediate)' hits fast V_BFI_B32 on AMD, and portable to other vendors", "timestamp": "2022-11-05 14:40:11", "media_urls": [], "reply_to_id": "1588903926510014467", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904166269005824", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[9] AMD ONLY: clamp(a,b,c) is implemented as med3(a,b,c), so can get V_MED3_* without an extension (in a non-portable way)", "timestamp": "2022-11-05 14:40:48", "media_urls": [], "reply_to_id": "1588904013239844870", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904259265114112", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[10] Bools as 0|1 floats '(a&b)|c' can be done via 'saturate(a*b+c)'", "timestamp": "2022-11-05 14:41:10", "media_urls": [], "reply_to_id": "1588904166269005824", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904325543493633", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[11] Bools as 0|1 floats '!(a&b)' can be done via '(-a)*b+1.0'", "timestamp": "2022-11-05 14:41:26", "media_urls": [], "reply_to_id": "1588904259265114112", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904434268262400", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[12] Convert INFs to NaNs via 'x*0.0+x'", "timestamp": "2022-11-05 14:41:52", "media_urls": [], "reply_to_id": "1588904325543493633", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588904891707424768", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[13] Semi-persistent workgroup opt = reusing the workgroup for more work before exit (ie processing four 8x8 tiles in a 16x16 footprint using a 64-wide group)", "timestamp": "2022-11-05 14:43:41", "media_urls": [], "reply_to_id": "1588904434268262400", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588905179449282560", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[14] Semi-persistent workgroups can be good for up to 10% perf on AMD (YMMV) ... assuming compiler doesn't fail VGPR allocation, check your disassembly", "timestamp": "2022-11-05 14:44:49", "media_urls": [], "reply_to_id": "1588904891707424768", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588905286697639936", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[15] Semi-persistent workgroups gain by keeping more local work on the same L0, by factoring out wait for store on wave exit, and better scheduling", "timestamp": "2022-11-05 14:45:15", "media_urls": [], "reply_to_id": "1588905179449282560", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588905339122257921", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[16] Merge passes to avoid round trip through DRAM, often huge wins there", "timestamp": "2022-11-05 14:45:27", "media_urls": [], "reply_to_id": "1588905286697639936", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588905491027341312", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[17] Sometimes serial dependent passes can be merged into one shader to keep work in L2 for >10% gains, requires \"unsafe you-shouldnt-do-that\" logic that works", "timestamp": "2022-11-05 14:46:04", "media_urls": [], "reply_to_id": "1588905339122257921", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588905764005216258", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[18] Proper double rate \"packed\" 16-bit can provides gains up to 30% depending on workload/platform (except NV)", "timestamp": "2022-11-05 14:47:09", "media_urls": [], "reply_to_id": "1588905491027341312", "quote_of_id": null, "metrics": { "reply_count": 1, "repost_count": 0, "like_count": 0, "view_count": 0 } }, { "post_id": "1588906002212323328", "author": "NOTimothyLottes", "handle": "NOTimothyLottes", "text": "[19] Even without double rate 16-bit, 16-bit is the most important tool for managing register pressure problems, esp with smaller HW register limits or compiler troubles", "timestamp": "2022-11-05 14:48:06", "media_urls": [], "reply_to_id": "1588905764005216258", "quote_of_id": null, "metrics": { "reply_count": 0, "repost_count": 0, "like_count": 0, "view_count": 0 } } ], "source_url": "https://x.com/NOTimothyLottes/status/1588906002212323328" }