make handles bold.
This commit is contained in:
1 parent
f577242432
commit
69b87777e5
728 files changed
+3291
-3087
No files matched your search
@@ -36,6 +36,8 @@ jobs:
|
||||
run: |
|
||||
cp publish/quartz.config.yaml site/quartz.config.yaml
|
||||
cp publish/quartz.custom.scss site/quartz/styles/custom.scss
|
||||
mkdir -p site/quartz/static
|
||||
cp publish/threadwell-reader.js site/quartz/static/threadwell-reader.js
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
+94
-94
@@ -26,291 +26,291 @@ parent_post_id: "1869436199884222515"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1869436525869724013
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(3.) If you had multiple line stores collecting on a given line with ECC, you'd have the same bottleneck as fire-and-forget atomics. A throughput of one line modification per clock.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1869436940334014771
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(4.) Note the prior assumes a read hit!
|
||||
|
||||
So at the point you get anti-atomic, you are also anti-store and anti-ECC, and anti-etc. It's the same pipelines with the same variability due to on-chip networking, different clock domain crossing, etc.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1869437450399170852
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(5.) Good GPUs have multiple ALUs doing the atomic by the last level cache. So it scales very well as a function of line collisions. Meaning if all lanes access separate addresses on a cacheline, those go in parallel.
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1869437815936979150
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(6.) Atomics and regular stores have the same memory controller base-camping behavior. If all SIMDs store to addresses that hash to the same last level cache partition, they will drop efficiency just like doing all atomics to the same address.
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1869438257983062074
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(7.) Anyway, while CPU atomics are serious design fail, GPU atomics on good GPUs are your best friend. They are actually a fantastic tool for getting more regular performance in many parallel algorithms.
|
||||
|
||||
**6/** @SebAaltonen
|
||||
**6/** **@SebAaltonen** ^1869438915679338644
|
||||
|
||||
@NOTimothyLottes @AgileJebrim @munohikari
|
||||
**@NOTimothyLottes** **@AgileJebrim** **@munohikari**
|
||||
|
||||
Indeed. Many CPU programmers have the wrong belief that GPU atomics are slow and unusable. They are fantastic. Bump allocator is your best friend on CPU side. On GPU you do atomic add to implement a bump allocator. As simple as that. It's super fast.
|
||||
|
||||
**7/** @AgileJebrim
|
||||
**7/** **@AgileJebrim** ^1869455007025946954
|
||||
|
||||
@SebAaltonen @NOTimothyLottes @munohikari
|
||||
**@SebAaltonen** **@NOTimothyLottes** **@munohikari**
|
||||
|
||||
I know NVIDIA did a really good atomicAdd, especially if you don’t use the result of the atomicAdd(). If you use it, then it forces it down a significantly slower path. But it’s all implementation-specific and different vendors will do different things yes?
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1869461633267032141
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Atomics come in two forms
|
||||
(1.) fire-and-forget (aka you don't use the return) - the compiler will flag it for no-return, so it behaves like a store
|
||||
(2.) read the return - it behaves like a {store, and read} simultaneously with layout "coherent"
|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1869462116689981465
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Good GPUs have address coalescing on writes and atomics. So a wave wide store is reduced to a cost that scales with the number of total cachelines all waves touch, with byte-write-mask so there is no read-modify-write
|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1869462778270085478
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
... atomics have the same but if any wave lane's addresses collide it will bump those to another request (for the same cacheline). Possible that some HW implements a HW reduction for collisions of some kinds of atomics locally before the requests go out, but don't assume that
|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1869463101361504275
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
... it's more likely that some compilers try to fix stupid behavior by doing a wave-reduction in software, and that causes hell for those of us who already write good code
|
||||
|
||||
**12/** @AgileJebrim
|
||||
**12/** **@AgileJebrim** ^1869463390944629143
|
||||
|
||||
@NOTimothyLottes @SebAaltonen @munohikari
|
||||
**@NOTimothyLottes** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Thoughts on atomic compare exchange? I use similar functionality on CPUs to globally synchronize threads and I figured I’d give it a shot attempting to do that on GPUs.
|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1869464512191238438
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Compare and exchange since it takes 2 values, it could have half the peak rate through on-chip network. Personally I have always used algorithms that do better things without the cmpswap atomic. You always can get the return (value pre-atomic), so cmpswap utility is less
|
||||
|
||||
**14/** @AgileJebrim
|
||||
**14/** **@AgileJebrim** ^1869465848211230840
|
||||
|
||||
@NOTimothyLottes @SebAaltonen
|
||||
**@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
My CPU sync mechanism works by stalling each thread until it reaches a multiple of the total number of threads to be synced, only incrementing an integer (swapping) when it reaches its specific thread index.
|
||||
|
||||
**15/** @NOTimothyLottes
|
||||
**15/** **@NOTimothyLottes** ^1869467172495655049
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
I assume you are using a futex then on Linux to block? But the GPU doesn't have such a thing exposed in software. Instead you'd be effectively polling using serial global memory atomic latency as your rate limiter and 'blocking'
|
||||
|
||||
**16/** @NOTimothyLottes
|
||||
**16/** **@NOTimothyLottes** ^1869467614407541225
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
Serializing workgroups on the GPU in this way has a very high latency granularity. There is also the issue of preemption on PCs, there is no guarantee of forward progress due to no guarantee all workgroups get restored
|
||||
|
||||
**17/** @NOTimothyLottes
|
||||
**17/** **@NOTimothyLottes** ^1869467785010762160
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
So you can deadlock post preemption if the workgroup that needs to do the atomic to unblock those spinning cannot get back on the machine
|
||||
|
||||
**18/** @NOTimothyLottes
|
||||
**18/** **@NOTimothyLottes** ^1869468049176506634
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
Now, the important part, there is one compromise rule that has the highest chance of being possible, that is an ask that if there is a partial restore, that it restores the oldest launched workgroups first ...
|
||||
|
||||
**19/** @NOTimothyLottes
|
||||
**19/** **@NOTimothyLottes** ^1869468322003317098
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
And with that you can have some forward progress if an algorithm only has dependencies on workgroups launched before it (like lower kernel global workgroup index), food for thought for algorithm design
|
||||
|
||||
**20/** @NOTimothyLottes
|
||||
**20/** **@NOTimothyLottes** ^1869469045357158663
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
on the CPU side, you'd futex block to get the thread off being scheduled so the dependent one could get on the machine to avoid deadlock, it isn't efficient by any means but works, the GPU's exposed only voluntary method to get off the machine is to exit the workgroup ...
|
||||
|
||||
**21/** @NOTimothyLottes
|
||||
**21/** **@NOTimothyLottes** ^1869469471892795511
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
So if you uber-task, meaning just keep launching the same dispatch, and the workgroup finds what it needs to do (instead of working off kernel global index), then you can workaround preemption that way too ...
|
||||
|
||||
**22/** @NOTimothyLottes
|
||||
**22/** **@NOTimothyLottes** ^1869469740726734946
|
||||
|
||||
@AgileJebrim @SebAaltonen
|
||||
**@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
Blocking becomes just workgroup exit. And the next workgroup gets lower schedule priority than existing active workgroups which helps solve of the scheduling issues
|
||||
|
||||
**23/** @AgileJebrim
|
||||
**23/** **@AgileJebrim** ^1869470170613461399
|
||||
|
||||
@NOTimothyLottes @SebAaltonen
|
||||
**@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
I’m not using a Linux futex. Could you look over my code here?
|
||||
|
||||
**24/** @simplex_fx
|
||||
**24/** **@simplex_fx** ^1869471291973214394
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
Hey Jeb, have you considered hitting the funny L shaped button on the right of your keyboard more frequently? 😅
|
||||
|
||||
**25/** @AgileJebrim
|
||||
**25/** **@AgileJebrim** ^1869472284156834117
|
||||
|
||||
@simplex_fx @NOTimothyLottes @SebAaltonen
|
||||
**@simplex_fx** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
Enter? Nah
|
||||
|
||||
**26/** @simplex_fx
|
||||
**26/** **@simplex_fx** ^1869474818384670790
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||

|
||||
|
||||
**27/** @AgileJebrim
|
||||
**27/** **@AgileJebrim** ^1869479130993234191
|
||||
|
||||
@simplex_fx @NOTimothyLottes @SebAaltonen
|
||||
**@simplex_fx** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
If I don’t have to scroll right…
|
||||
|
||||
**28/** @simplex_fx
|
||||
**28/** **@simplex_fx** ^1869486350074020173
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
Dude, stop with that WQHD bullshit, buy a proper tv and limit yourself to 80-120
|
||||
|
||||
**29/** @AgileJebrim
|
||||
**29/** **@AgileJebrim** ^1869486638877004115
|
||||
|
||||
@simplex_fx @NOTimothyLottes @SebAaltonen
|
||||
**@simplex_fx** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
Nty. The hell do I need a tv for? I have several monitors.
|
||||
|
||||
**30/** @simplex_fx
|
||||
**30/** **@simplex_fx** ^1869486998249185767
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
How big?
|
||||
|
||||
**31/** @AgileJebrim
|
||||
**31/** **@AgileJebrim** ^1869487741052023113
|
||||
|
||||
@simplex_fx @NOTimothyLottes @SebAaltonen
|
||||
**@simplex_fx** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
Big enough to maximize a window on each.
|
||||
|
||||
**32/** @simplex_fx
|
||||
**32/** **@simplex_fx** ^1869518005237112922
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
If you go too wide, you will just kill your neck on the long run
|
||||
|
||||
**33/** @AgileJebrim
|
||||
**33/** **@AgileJebrim** ^1869523900687864185
|
||||
|
||||
@simplex_fx @NOTimothyLottes @SebAaltonen
|
||||
**@simplex_fx** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
I have 4 monitors
|
||||
|
||||
**34/** @simplex_fx
|
||||
**34/** **@simplex_fx** ^1869529828082541035
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @SebAaltonen
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@SebAaltonen**
|
||||
|
||||
How big?
|
||||
|
||||
**35/** @NOTimothyLottes
|
||||
**35/** **@NOTimothyLottes** ^1869530109096669269
|
||||
|
||||
@simplex_fx @AgileJebrim @SebAaltonen
|
||||
**@simplex_fx** **@AgileJebrim** **@SebAaltonen**
|
||||
|
||||
Ideally one of these
|
||||
|
||||

|
||||
|
||||
**36/** @AgileJebrim
|
||||
**36/** **@AgileJebrim** ^1869530951480717429
|
||||
|
||||
@NOTimothyLottes @simplex_fx @SebAaltonen
|
||||
**@NOTimothyLottes** **@simplex_fx** **@SebAaltonen**
|
||||
|
||||
Not big enough. Evans & Sutherland still makes planetariums. We have smaller scale 360 degree domes. I think they’re about 14ft high.
|
||||
|
||||
**37/** @SebAaltonen
|
||||
**37/** **@SebAaltonen** ^1869808696366379155
|
||||
|
||||
@AgileJebrim @NOTimothyLottes
|
||||
**@AgileJebrim** **@NOTimothyLottes**
|
||||
|
||||
Same is true for everything. All memory loads on GPUs are highly vendor specific. On GTX 1080 (Pascal) your memory load goes through sampler, which is around 85 cycles of latency. While on Turing your raw load is only 28 cycles of latency (CUDA benchmarks).
|
||||
|
||||
**38/** @AgileJebrim
|
||||
**38/** **@AgileJebrim** ^1869809446437957837
|
||||
|
||||
@SebAaltonen @NOTimothyLottes
|
||||
**@SebAaltonen** **@NOTimothyLottes**
|
||||
|
||||
For sure, but my focus is more on how deterministic and predictable these are. I’ll take 85 if it’s always 85 over something that might vary unpredictably between 28 and 100.
|
||||
|
||||
**39/** @SebAaltonen
|
||||
**39/** **@SebAaltonen** ^1869810947512250536
|
||||
|
||||
@AgileJebrim @NOTimothyLottes
|
||||
**@AgileJebrim** **@NOTimothyLottes**
|
||||
|
||||
Nvidia has big L1$, so they are more predictable. Texture samplers are shared with all waves running on the same compute unit. They are not really predictable. You wait until the unit is ready. There's quite a lot of fluctuation. That's why you have 8x-10x hyperthreading per CU.
|
||||
|
||||
**40/** @SebAaltonen
|
||||
**40/** **@SebAaltonen** ^1869811242954830281
|
||||
|
||||
@AgileJebrim @NOTimothyLottes
|
||||
**@AgileJebrim** **@NOTimothyLottes**
|
||||
|
||||
The idea is to keep the SIMD running all the time. Wave execution time variance hasn't been a big optimization goal. There's always more work coming, so it's not a problem if some wave takes 10x time to execute compared to others.
|
||||
|
||||
**41/** @SebAaltonen
|
||||
**41/** **@SebAaltonen** ^1869811536547721585
|
||||
|
||||
@AgileJebrim @NOTimothyLottes
|
||||
**@AgileJebrim** **@NOTimothyLottes**
|
||||
|
||||
Basically if the SIMD is executing instructions all the time, then your workload runs at predictable amount of instructions per cycle. The problem is barriers. You wait for longest wave to finish. You can't to batch barriers to avoid turning latency into real lost SIMD cycles.
|
||||
|
||||
**42/** @AgileJebrim
|
||||
**42/** **@AgileJebrim** ^1869811840433496316
|
||||
|
||||
@SebAaltonen @NOTimothyLottes
|
||||
**@SebAaltonen** **@NOTimothyLottes**
|
||||
|
||||
If they all take the same amount of time then there shouldn’t be much idling of hardware for waiting on the longest wave.
|
||||
|
||||
**43/** @SebAaltonen
|
||||
**43/** **@SebAaltonen** ^1870002011753578827
|
||||
|
||||
@AgileJebrim @NOTimothyLottes
|
||||
**@AgileJebrim** **@NOTimothyLottes**
|
||||
|
||||
That's true. But they don't take the same amount of time due to caches. That's where the 10x hyper-threading kicks in. As long as the SIMD is fed all the time, there's no visible issue with fluctuating wave lengths. Barriers make that visible. Minimal amount of barriers = good.
|
||||
|
||||
**44/** @AgileJebrim
|
||||
**44/** **@AgileJebrim** ^1869454583191494967
|
||||
|
||||
@NOTimothyLottes @SebAaltonen @munohikari
|
||||
**@NOTimothyLottes** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Would you implement a prefix sum compaction algorithm using atomicAdd?
|
||||
|
||||
**45/** @NOTimothyLottes
|
||||
**45/** **@NOTimothyLottes** ^1869460449194037720
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Standard optimizations apply, like doing wave-reductions first.
|
||||
|
||||
**46/** @AgileJebrim
|
||||
**46/** **@AgileJebrim** ^1869460608246239720
|
||||
|
||||
@NOTimothyLottes @SebAaltonen @munohikari
|
||||
**@NOTimothyLottes** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Okay so you don’t just blanket throw an atomicAdd on it then.
|
||||
|
||||
**47/** @NOTimothyLottes
|
||||
**47/** **@NOTimothyLottes** ^1869463962322149607
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
No. For things like scanning a 1-bit value, it's a wave masked bit count op in software, followed by predicating the atomic to just lane 0 of the wave. For scanning uint32s it's a log2 wave reduction, then predicating the add to lane 0. And so on
|
||||
|
||||
|
||||
+4
-4
@@ -26,17 +26,17 @@ parent_post_id: "1869424048607993895"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SebAaltonen
|
||||
**1/** **@SebAaltonen** ^1869425726128304359
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @munohikari
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@munohikari**
|
||||
|
||||
Yes, but it's going to be MUCH slower. You can do sums and reductions in groupshared memory, but if that mobile GPU doesn't have real groupshared memory, it's going to be very slow. For example GMEM based groupshared is this slow on Qualcomm (and 730 is much better than 610):
|
||||
|
||||

|
||||
|
||||
**2/** @SebAaltonen
|
||||
**2/** **@SebAaltonen** ^1869426053002997774
|
||||
|
||||
@AgileJebrim @NOTimothyLottes @munohikari
|
||||
**@AgileJebrim** **@NOTimothyLottes** **@munohikari**
|
||||
|
||||
X1 is the brand new laptop chip. This architecture is only on latest mobile phones. Low end is Adreno 610 and similar.
|
||||
|
||||
|
||||
+24
-24
@@ -25,80 +25,80 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @AgileJebrim
|
||||
**1/** **@AgileJebrim** ^1869397269956673662
|
||||
|
||||
@munohikari @SebAaltonen
|
||||
**@munohikari** **@SebAaltonen**
|
||||
|
||||
You left out the bit where I also said no graphics pipeline. :P
|
||||
|
||||
**2/** @SebAaltonen
|
||||
**2/** **@SebAaltonen** ^1869401190653730862
|
||||
|
||||
@AgileJebrim @munohikari
|
||||
**@AgileJebrim** **@munohikari**
|
||||
|
||||
Computer shaders are a can of worms for old mobile GPUs too. Some have fast groupshared memory (could be tiny), some emulate it. Some have wave intrinsics, some don't. 64-bit atomic support is nonexistent (for MM Dreams / Native style Z+payload packing).
|
||||
|
||||
**3/** @SebAaltonen
|
||||
**3/** **@SebAaltonen** ^1869401541570179083
|
||||
|
||||
@AgileJebrim @munohikari
|
||||
**@AgileJebrim** **@munohikari**
|
||||
|
||||
Also compute shader writes are not compressed (pixel shader framebuffer writes have HW lossless compressor). You pay full memory bandwidth cost, which causes phone to heat (drain battery) and eventually throttle.
|
||||
|
||||
**4/** @AgileJebrim
|
||||
**4/** **@AgileJebrim** ^1869402067724615899
|
||||
|
||||
@SebAaltonen @munohikari
|
||||
**@SebAaltonen** **@munohikari**
|
||||
|
||||
Alternative approach is to do all rendering in screen space in a fragment shader.
|
||||
|
||||
**5/** @SebAaltonen
|
||||
**5/** **@SebAaltonen** ^1869403157530550660
|
||||
|
||||
@AgileJebrim @munohikari
|
||||
**@AgileJebrim** **@munohikari**
|
||||
|
||||
If you intend to do distance field ray-tracing using volume textures, worth noting that most mobile GPUs don't do proper 3d tiling layout for volume textures. Instead they use legacy 2d sliced layout, which results in significantly more L1$ trashing. Can 5x your mem BW use.
|
||||
|
||||
**6/** @AgileJebrim
|
||||
**6/** **@AgileJebrim** ^1869406913676660898
|
||||
|
||||
@SebAaltonen @munohikari
|
||||
**@SebAaltonen** **@munohikari**
|
||||
|
||||
Raycasting, no bouncing, using cubic textured bricks that emulate voxel surfaces via a parallax occlusion map approach measuring distances to each voxel surface.
|
||||
|
||||
If I’m writing something for an avionics cockpit, I’d be either using an Arm Mali-G78AE or NVIDIA DRIVE AGX Thor GPU.
|
||||
|
||||
**7/** @AgileJebrim
|
||||
**7/** **@AgileJebrim** ^1869408574910423473
|
||||
|
||||
@SebAaltonen @munohikari
|
||||
**@SebAaltonen** **@munohikari**
|
||||
|
||||
I’d also be using Vulkan SC, which I believe disables atomics entirely. :P
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1869423853761614046
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Disabling atomics is like chopping off both legs because someone thinks one tow has a blister when it actually doesn't.
|
||||
|
||||
**9/** @AgileJebrim
|
||||
**9/** **@AgileJebrim** ^1869424048607993895
|
||||
|
||||
@NOTimothyLottes @SebAaltonen @munohikari
|
||||
**@NOTimothyLottes** **@SebAaltonen** **@munohikari**
|
||||
|
||||
You can still implement a comparable feature yourself.
|
||||
|
||||
Branches: [[archive/threads/AgileJebrim/2024-12-18-you-left-out-the-bit-where-i-also-said-no/2024-12-18-SebAaltonen-yes-but-its-going-to-be-much-slower-you-can-do]]
|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1869434807228461111
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
No actually you cannot. No method of software (or even HW) implemented lock-line algorithm survives the kind of latency in the GPU memory system. There is a big reason atomics on GPUs are done right by the last level of cache (the coherent memory domain)
|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1869435419244527644
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
Something you really need to understand for your own benefit:
|
||||
(1.) There are a lot of more expensive things happening in the GPU memory system than atomics. For instance DCC compression. It requires metadata access (to get the state of memory just to do the compression on store).
|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1869436199884222515
|
||||
|
||||
@AgileJebrim @SebAaltonen @munohikari
|
||||
**@AgileJebrim** **@SebAaltonen** **@munohikari**
|
||||
|
||||
(2.) Think of GPU atomics as a read-modify-write op. It's effectively the same behavior as a partial cacheline write-through STORE operation on HW using ECC. Because ECC eats the bits used for byte-write-mask.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @HQuarterma43504
|
||||
**1/** **@HQuarterma43504** ^2036819288124985764
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
GameMaker introduced me to the Entity paradigm. Each entity has "events" like On Create, On Destroy, Every Step, On Draw, On Collision, Timer, and so on. And you write code for these events.
|
||||
|
||||
|
||||
+16
-16
@@ -26,15 +26,15 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Jonathan_Blow
|
||||
**1/** **@Jonathan_Blow** ^2036815488173703237
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Entities don’t have to go but having a mental framework where entities run functions is probably not helpful.
|
||||
|
||||
**2/** @anicic_filip
|
||||
**2/** **@anicic_filip** ^2037079338512769397
|
||||
|
||||
@Jonathan_Blow @BOENSAW
|
||||
**@Jonathan_Blow** **@BOENSAW**
|
||||
|
||||
Could you expand on that?
|
||||
I've seen:
|
||||
@@ -44,31 +44,31 @@ I've seen:
|
||||
|
||||
Is this what you are describing as a mental framework?
|
||||
|
||||
**3/** @Jonathan_Blow
|
||||
**3/** **@Jonathan_Blow** ^2037294870939972085
|
||||
|
||||
@anicic_filip @BOENSAW
|
||||
**@anicic_filip** **@BOENSAW**
|
||||
|
||||
My game code has evolved toward "iterate over all entities of type X, do Y on them, at the place in the code where this needs to happen". The entity does not own the function, the game engine owns the function.
|
||||
|
||||
**4/** @Jonathan_Blow
|
||||
**4/** **@Jonathan_Blow** ^2037295493085319580
|
||||
|
||||
(So instead of having a generic tick function where you switch on entity type, and then a generic pre-tick because of course you need that, and pre-pre-tick, and post-tick, etc, you just have small bits of code where you iterate over things by type and do what that type needs. If you store the entities by type in the first place (which is a very efficient way to do it due to uniform size), then these iterations are much faster than iterating over randomly-typed entities in random order.
|
||||
|
||||
**5/** @Jonathan_Blow
|
||||
**5/** **@Jonathan_Blow** ^2037295938583314583
|
||||
|
||||
@anicic_filip @BOENSAW
|
||||
**@anicic_filip** **@BOENSAW**
|
||||
|
||||
A real-world example (but most loops have more in the body; this one is chosen for readability):
|
||||
|
||||

|
||||
|
||||
**6/** @Jonathan_Blow
|
||||
**6/** **@Jonathan_Blow** ^2037296285506822315
|
||||
|
||||
@anicic_filip @BOENSAW
|
||||
**@anicic_filip** **@BOENSAW**
|
||||
|
||||
The idea of a generic tick function for entities is really not great to begin with, because in a complex game you end up caring a great deal about what order things happen in, then you need to go to great pain to impose this order. Instead, you can just say "do A, then B, ..."
|
||||
|
||||
**7/** @iquilezles
|
||||
**7/** **@iquilezles** ^2037321785008668834
|
||||
|
||||
Once I saw a project where everything was entities with a .tick(), plus a gigantic priority table intended to orchestrate the mess. Because reasoning the flow was still too hard, developers had added yield() for_rand_number_of_frames everywhere, "to give other entities some time to run their tick()s". Naturally all actions took multiple frames to execute, and they still had flow/synch bugs everywhere anyways.
|
||||
|
||||
@@ -76,15 +76,15 @@ I advised them to burn thing down and move on to just an app loop with { do_thin
|
||||
|
||||
You could say the problem was that particular team of coders, not the design per-se. But, I mean, I've seen this story repeat with different teams repeat 3 or 4 times by now...
|
||||
|
||||
**8/** @Jonathan_Blow
|
||||
**8/** **@Jonathan_Blow** ^2037322309502185845
|
||||
|
||||
@iquilezles @anicic_filip @BOENSAW
|
||||
**@iquilezles** **@anicic_filip** **@BOENSAW**
|
||||
|
||||
Everyone wants to think they are in the Matrix and doing some super cool entity simulation reality engine. In reality it is just clumsy code failing to do something simple, at great cost in complexity, speed and reliability.
|
||||
|
||||
**9/** @BOENSAW
|
||||
**9/** **@BOENSAW** ^2037340571690471473
|
||||
|
||||
@Jonathan_Blow @iquilezles @anicic_filip
|
||||
**@Jonathan_Blow** **@iquilezles** **@anicic_filip**
|
||||
|
||||
I think part of the appeal is also hiding code so that it appears simpler because you can't see all of it at once. not that that's good, lol
|
||||
|
||||
|
||||
+10
-10
@@ -26,33 +26,33 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @KnightOfTh3Wind
|
||||
**1/** **@KnightOfTh3Wind** ^2036777757875581351
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
How do you even have a functioning game without entities
|
||||
|
||||
**2/** @BOENSAW
|
||||
**2/** **@BOENSAW** ^2036779389757894720
|
||||
|
||||
@KnightOfTh3Wind
|
||||
**@KnightOfTh3Wind**
|
||||
|
||||
I'm just guessing, but over time I've realized less and less things actually need to be compartmentalized into boxes and can just be managed as a part of global state
|
||||
|
||||
**3/** @SagelessRanger
|
||||
**3/** **@SagelessRanger** ^2036781762752205009
|
||||
|
||||
@BOENSAW @KnightOfTh3Wind
|
||||
**@BOENSAW** **@KnightOfTh3Wind**
|
||||
|
||||
Can you make this expand on this idea this sounds very interesting and potentially more clear to manage
|
||||
|
||||
**4/** @BOENSAW
|
||||
**4/** **@BOENSAW** ^2036786837029863443
|
||||
|
||||
@SagelessRanger @KnightOfTh3Wind
|
||||
**@SagelessRanger** **@KnightOfTh3Wind**
|
||||
|
||||
Take a cutscene for a simple example. A naive approach might be something like "npc object spawns a textbox object and sends text from its text variable". Doesn't sound so bad but what if two NPCs activate at once, what if the textbox or npc gets destroyed somehow... error prone
|
||||
|
||||
**5/** @BOENSAW
|
||||
**5/** **@BOENSAW** ^2036787552238342282
|
||||
|
||||
@SagelessRanger @KnightOfTh3Wind
|
||||
**@SagelessRanger** **@KnightOfTh3Wind**
|
||||
|
||||
Something more along this line of thinking would be like "interaction system detects conditions to begin the cutscene state which reads from a script and draws textboxes automatically". less interdependence, no reliance on external objects, no way to muddy the state
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @MelinShioto
|
||||
**1/** **@MelinShioto** ^2036791325593379203
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Object { data stuff; function stuff }
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @MildlyNuclear
|
||||
**1/** **@MildlyNuclear** ^2036815667723166017
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
everything is just functions and variables, it's functions all the way down
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @NotHenryFonda
|
||||
**1/** **@NotHenryFonda** ^2036657302204260461
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
there's a whole book about this https://www.dataorienteddesign.com/dodbook/
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @RaykiruS
|
||||
**1/** **@RaykiruS** ^2036787677765288054
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
So, not an ecs but only a es
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Ryunocore
|
||||
**1/** **@Ryunocore** ^2036858460520755594
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Patterns are guidelines, but coding is a holistic and spiritual activity. Unironically follow your heart.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @TheWireWhiz
|
||||
**1/** **@TheWireWhiz** ^2036795872302739892
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
The only thing you ever need to think about is how the data flows, and sometimes when it flows if the paths leak. Everything else is an abstraction over that.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @_Detrend_
|
||||
**1/** **@_Detrend_** ^2036773206984470619
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Thats because entities and ECS are the new shiny thing and everyone loves to jump on the cool train.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @_flashman_harry
|
||||
**1/** **@_flashman_harry** ^2036755293187592636
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Finding out being Turing complete just requires less and not more?
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @ccallac7
|
||||
**1/** **@ccallac7** ^2036802494194729189
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
All that matters is memory and logic, everything else is a made up abstraction
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @galactix____
|
||||
**1/** **@galactix____** ^2036789325338194102
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
There are no universal pattern common to every game, especially if you are searching for efficiency. Each game have its own optimization specifics
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @mcnabbd
|
||||
**1/** **@mcnabbd** ^2036803466698674505
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
<video controls src="https://video.twimg.com/tweet_video/HEQt9MWb0AEyGm2.mp4"></video>
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @neverworksgames
|
||||
**1/** **@neverworksgames** ^2036777865643991443
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Objects, arrays, singletons. That's it.
|
||||
|
||||
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @nouriosplpolska
|
||||
**1/** **@nouriosplpolska** ^2036762408027316597
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
I feel like the actually useful patterns just emerge by themselves if you try doing something that needs them.
|
||||
|
||||
**2/** @BOENSAW
|
||||
**2/** **@BOENSAW** ^2036778414791909453
|
||||
|
||||
@nouriosplpolska
|
||||
**@nouriosplpolska**
|
||||
|
||||
That's very much been my experience. it's not that they aren't useful under certain scenarios, but they're just as often not and rather than following a rigid structure it's better just to use the right tool for the situation
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @samloeschen
|
||||
**1/** **@samloeschen** ^2036835437797396644
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
team fat struct!
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @struc_ture
|
||||
**1/** **@struc_ture** ^2036758034144510171
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Eventually you realize literally nothing matters except for love and friendship!!!!
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @HaskellEnjoyer
|
||||
**1/** **@HaskellEnjoyer** ^2036997821379822035
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Just go full haskell and realize that everything is a function
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @RafaAsor
|
||||
**1/** **@RafaAsor** ^2037115807667232798
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
This is a take for the whole software industry
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @angus_mang
|
||||
**1/** **@angus_mang** ^2037008038134006163
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
Functions that Operate on Structs/Classes/Entities/Objects makes things simple. C++ or heavy, container-ized / encapsulated Class/Structs muddies. Serves for poor organization and juggling abstract ideas instead of.
|
||||
Big ass block thing
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2036653149948424230"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @eta9499
|
||||
**1/** **@eta9499** ^2037038809129394422
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
you are almost there unc
|
||||
|
||||
|
||||
+3
-3
@@ -25,14 +25,14 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @BOENSAW
|
||||
**1/** **@BOENSAW** ^2036653149948424230
|
||||
|
||||
the more experienced I get programming games the more that I realize patterns like inheritance and components don't matter, the only thing that matters is functions and entities which run functions... entities might be the next thing to go
|
||||
|
||||
Branches: [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-NotHenryFonda-theres-a-whole-book-about-this-https-www]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-_flashman_harry-finding-out-being-turing-complete-just-requires]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-struc_ture-eventually-you-realize-literally-nothing-matters]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-nouriosplpolska-i-feel-like-the-actually-useful-patterns-just]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-_Detrend_-thats-because-entities-and-ecs-are-the-new-shiny]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-KnightOfTh3Wind-how-do-you-even-have-a-functioning-game-without]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-neverworksgames-objects-arrays-singletons-thats-it]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-RaykiruS-so-not-an-ecs-but-only-a-es]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-galactix____-there-are-no-universal-pattern-common-to-every]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-MelinShioto-object-data-stuff-function-stuff]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-TheWireWhiz-the-only-thing-you-ever-need-to-think-about-is]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-ccallac7-all-that-matters-is-memory-and-logic-everything]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-mcnabbd-thread]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-Jonathan_Blow-entities-dont-have-to-go-but-having-a-mental]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-MildlyNuclear-everything-is-just-functions-and-variables-its]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-HQuarterma43504-gamemaker-introduced-me-to-the-entity-paradigm]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-samloeschen-team-fat-struct]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-25-Ryunocore-patterns-are-guidelines-but-coding-is-a-holistic]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-26-HaskellEnjoyer-just-go-full-haskell-and-realize-that-everything]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-26-angus_mang-functions-that-operate-on-structs-classes]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-26-eta9499-you-are-almost-there-unc]], [[archive/threads/BOENSAW/2026-03-25-the-more-experienced-i-get-programming-games-the/2026-03-26-RafaAsor-this-is-a-take-for-the-whole-software-industry]]
|
||||
|
||||
**2/** @BenboQuest
|
||||
**2/** **@BenboQuest** ^2036656311367266745
|
||||
|
||||
@BOENSAW
|
||||
**@BOENSAW**
|
||||
|
||||
i only been saying this
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Alecazam123
|
||||
**1/** **@Alecazam123** ^2010391151208251442
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Hard to believe I’m still writing games in Win32 25 years later. But it runs on SteamOS, so can never be replaced now.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @BowTiedTails
|
||||
**1/** **@BowTiedTails** ^2010494359062327682
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Yep. Win32 is heaven when you see what else is out there.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @VPCOMPRESSB
|
||||
**1/** **@VPCOMPRESSB** ^2010378880209871041
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
coincidentally, i made a Vulkan Wayland compute engine yesterday in ~600 LoC.
|
||||
|
||||
|
||||
+25
-25
@@ -26,42 +26,42 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @VPCOMPRESSB
|
||||
**1/** **@VPCOMPRESSB** ^2010385913541546282
|
||||
|
||||
yeah. i actually prefer Wayland because if you implement something super simple, you get something super simple back (e.g., if i create a window, i get the bare minimum window - no decorations, no resizing, no keyboard or mouse input). with Win32, i'd have fight it and move through its weeds to force it to make something simple.
|
||||
another problem with Win32 is that it modularizes too much, and make everything seem irrelevant from each other. in Wayland, it's all unified, where if just learn 1 pattern from 1 thing, you can apply that pattern to everything else, from windows to input (e.g., all interfaces are just a simple server-client messaging model). basically, you can take a step back and look at everything as a whole, and clearly see a pattern.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^2010396312651649276
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
You didn't get the true Wayland experience until you try interfacing to Wayland without the Wayland user-space library. Meaning do it with just the kernel calls required. Then you will have taken the gold off the poop, and understood how bad it actually is.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^2010398147617640535
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
WIN32 base system DLLs are a substantially cleaner interface. I only do non-decorated full-screen (foreground or background) window. Majority of WIN32 code fits on screen grab with mostly comments. I'm not a fan of their "WndProc" but at least it is simple.
|
||||
|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^2010398743422709770
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Some like to hate on X11, but for what it was designed to do (support both local and remote displays), it is at least very well documented and actually quite easy to roll an interface for with just Linux kernel calls (no external libraries). Docs here: https://x.org/releases/X11R7.7/doc/xproto/x11protocol.html
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^2010404729633829180
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Duckduckgo Wayland protocol and you get this garbage as documentation (below). Nothing there actually explains how it works, it's just high-level OOP obfustication speak. My vomit translator cannot even process this stuff.
|
||||
|
||||

|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^2010407422272160202
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Lets continue. It's built over unix domain sockets and doesn't support remote rendering. Haha, WFT. Just because they want to transfer file descriptors between processes for "bulk data". Wayland looses network displays and is SLOWER (fail): https://www.dedoimedo.com/computers/plasma-6-4-performance-wayland-x11-power-cpu-kernel.html
|
||||
|
||||
@@ -69,47 +69,47 @@ Lets continue. It's built over unix domain sockets and doesn't support remote re
|
||||

|
||||

|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^2010411498729046449
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Don't understand why Linux people had to take what was working, X11, and instead of just improving it, they had to make something that {removed the remote desktop, made it slower, and forces an OOP garbage design}. There is nothing good here.
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^2010412846845473278
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Another great thing about X11, is that it was trivial to both write and use your own window manager, using the same stable system for DECADES. I had a 350 line minwm.c window manager. Dead easy.
|
||||
|
||||

|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^2010418524376981598
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Unix was about KISS (keep it simple stupid) then Linux user-space people transformed that into MISC {make it stupid complex}. Seen this trend with Audio, from OSS to ALSA, and so on.
|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^2010420107630330273
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
I worked in the {SunOS,Solaris,HPUX,SGI,AXI,etc} workstation era and started on Linux before ELF and before pthreads. Meaning I build things based on fork() [instead of pthreads] and SHM (shared page mappings) when doing local-only interfaces (no high kernel call granularity).
|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^2010421431105093819
|
||||
|
||||
@VPCOMPRESSB @Dispatch_Graph
|
||||
**@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
If Linux people wanted to replace X11 with a local only interface, at a minimum it should have been simple SHM for the majority, and then only go outside SHM when needing to say kick a doorbell (make wake another process), etc.
|
||||
|
||||
**12/** @o__boga
|
||||
**12/** **@o__boga** ^2010504713867870403
|
||||
|
||||
@NOTimothyLottes @VPCOMPRESSB @Dispatch_Graph
|
||||
**@NOTimothyLottes** **@VPCOMPRESSB** **@Dispatch_Graph**
|
||||
|
||||
Obfuscation is the secret for its "security!"!
|
||||
|
||||
**13/** @VPCOMPRESSB
|
||||
**13/** **@VPCOMPRESSB** ^2010498624157782265
|
||||
|
||||
@NOTimothyLottes @Dispatch_Graph
|
||||
**@NOTimothyLottes** **@Dispatch_Graph**
|
||||
|
||||
i've never actually used X11. this is much easier.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @hadal101dev
|
||||
**1/** **@hadal101dev** ^2010378989022622068
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Yea windows makes some interesting choices lol. Calling CreateFile when you want to OPEN a file? very weird lol.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @smolus
|
||||
**1/** **@smolus** ^2010450157222154626
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
one thing I appreciate about wayland is that it's just a simple protocol spec so you are not married to any particular API/library but yeah it can be a lot of work to get basic things working
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Chris_Linux
|
||||
**1/** **@Chris_Linux** ^2010676815128301753
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Apples and oranges comparison here
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @FoundryOfLies
|
||||
**1/** **@FoundryOfLies** ^2010725798114979912
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
It's KWin
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @JoaoBapt
|
||||
**1/** **@JoaoBapt** ^2010753110805979471
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
I suggest you to stick with GLFW if you’re only doing Vulkan.
|
||||
|
||||
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Oka7071
|
||||
**1/** **@Oka7071** ^2010799896866255168
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||

|
||||
|
||||
**2/** @Dispatch_Graph
|
||||
**2/** **@Dispatch_Graph** ^2010808986619298248
|
||||
|
||||
@Oka4902
|
||||
**@Oka4902**
|
||||
|
||||
if you give me 3 trillion dollars I can elaborate
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @PervWizz
|
||||
**1/** **@PervWizz** ^2010750206237651067
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Well. Win32 began as a bad API and then organically got reshaped into a worse one. Same goes for X11
|
||||
|
||||
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Rami36217810
|
||||
**1/** **@Rami36217810** ^2010799138712273238
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
What about x11
|
||||
|
||||
**2/** @Dispatch_Graph
|
||||
**2/** **@Dispatch_Graph** ^2010808862623027217
|
||||
|
||||
@Rami36217810
|
||||
**@Rami36217810**
|
||||
|
||||
its aight
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SyntaxError2505
|
||||
**1/** **@SyntaxError2505** ^2010700042080862455
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Why? Sdl works great
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @f82james
|
||||
**1/** **@f82james** ^2010735384750334453
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
fuck x11
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @linux_version
|
||||
**1/** **@linux_version** ^2010740512769404946
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Oddly enough, with how old the wine project is, Win32 might be the most stable API on Linux.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @mizanyx
|
||||
**1/** **@mizanyx** ^2010686383954800643
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Elaborate please, I'm still an X11 user
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @platonvin
|
||||
**1/** **@platonvin** ^2010728789396050001
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
windows.h is like a nightmare but real. It is so bad, that many people manually paste parts of it to avoid including entire thing
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @ruminaik
|
||||
**1/** **@ruminaik** ^2010733158996865131
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
And let us say Amen
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "2010303501851877740"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @thedarkhog
|
||||
**1/** **@thedarkhog** ^2010669573427884393
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
Get Xlibre instead. If you're using arch, btw., it's in the AUR.
|
||||
|
||||
|
||||
+5
-5
@@ -25,20 +25,20 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @Dispatch_Graph
|
||||
**1/** **@Dispatch_Graph** ^2010303501851877740
|
||||
|
||||
Ok, the Win32 API sure is something, but WOW wayland is awful
|
||||
|
||||
Branches: [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-VPCOMPRESSB-coincidentally-i-made-a-vulkan-wayland-compute]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-hadal101dev-yea-windows-makes-some-interesting-choices-lol]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-VPCOMPRESSB-yeah-i-actually-prefer-wayland-because-if-you]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-Alecazam123-hard-to-believe-im-still-writing-games-in-win32]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-smolus-one-thing-i-appreciate-about-wayland-is-that-its]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-11-BowTiedTails-yep-win32-is-heaven-when-you-see-what-else-is-out]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-thedarkhog-get-xlibre-instead-if-youre-using-arch-btw-its-in]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-Chris_Linux-apples-and-oranges-comparison-here]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-mizanyx-elaborate-please-im-still-an-x11-user]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-SyntaxError2505-why-sdl-works-great]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-FoundryOfLies-its-kwin]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-platonvin-windows-h-is-like-a-nightmare-but-real-it-is-so]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-ruminaik-and-let-us-say-amen]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-f82james-fuck-x11]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-linux_version-oddly-enough-with-how-old-the-wine-project-is]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-PervWizz-well-win32-began-as-a-bad-api-and-then]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-JoaoBapt-i-suggest-you-to-stick-with-glfw-if-youre-only]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-Rami36217810-what-about-x11]], [[archive/threads/Dispatch_Graph/2026-01-11-ok-the-win32-api-sure-is-something-but-wow/2026-01-12-Oka7071-thread]]
|
||||
|
||||
**2/** @ocarina588
|
||||
**2/** **@ocarina588** ^2010305588580974622
|
||||
|
||||
@Dispatch_Graph
|
||||
**@Dispatch_Graph**
|
||||
|
||||
😂😂😂, what are you using? Hyprland ?
|
||||
|
||||
**3/** @Dispatch_Graph
|
||||
**3/** **@Dispatch_Graph** ^2010319408045183333
|
||||
|
||||
@ocarina588
|
||||
**@ocarina588**
|
||||
|
||||
KDE Plasma
|
||||
+16
-16
@@ -26,39 +26,39 @@ parent_post_id: "1884730404587909544"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @mu_chrinovic
|
||||
**1/** **@mu_chrinovic** ^1884733082474775028
|
||||
|
||||
@FFmpeg
|
||||
**@FFmpeg**
|
||||
|
||||
I know a person with a PhD that might disagree with you
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1884744335385608455
|
||||
|
||||
@mu_chrinovic @FFmpeg
|
||||
**@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
Yeah PTX is not assembly, it's a mid level language that is closer to a 1:1 match for the HW ISA --- BUT --- the actual register allocation and management is still done by a high-level compiler ...
|
||||
|
||||
**3/** @janekm
|
||||
**3/** **@janekm** ^1884925339589038179
|
||||
|
||||
@NOTimothyLottes @mu_chrinovic @FFmpeg
|
||||
**@NOTimothyLottes** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
That's almost semantics at this point though? If you're writing x86 assembly it gets translated to microcode in the CPU as well, and will do register remapping etc. Only difference in Nvidia case that's happening in the driver, right?
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1884980252822188188
|
||||
|
||||
@janekm @mu_chrinovic @FFmpeg
|
||||
**@janekm** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
Sounds like you are trying to claim software compiler register allocation is the same as HW runtime register renaming? No. CPU register renaming maps a small set of registers to a larger set to get IPC. Compiler GPU reg allocation maps a massive SSA mess to a small set.
|
||||
|
||||
**5/** @janekm
|
||||
**5/** **@janekm** ^1884981121089257481
|
||||
|
||||
@NOTimothyLottes @mu_chrinovic @FFmpeg
|
||||
**@NOTimothyLottes** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
Fair point, my argument was merely that both cases of assembly language are really an intermediate language that gets translated to the final instructions executed by the CPU/GPU. Feels quite pedantic to claim that PTX assembly is not assembly, merely because of reg allocation 🤷♂️
|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1884985388327977299
|
||||
|
||||
@janekm @mu_chrinovic @FFmpeg
|
||||
**@janekm** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
SOFTWARE
|
||||
Assembler = human writes the physical HW instructions
|
||||
@@ -68,15 +68,15 @@ HW
|
||||
Instruction-reordering / wave-scheduling
|
||||
Register renaming
|
||||
|
||||
**7/** @janekm
|
||||
**7/** **@janekm** ^1884987565910204489
|
||||
|
||||
@NOTimothyLottes @mu_chrinovic @FFmpeg
|
||||
**@NOTimothyLottes** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
We've been calling it Assembly since at least when JVM byte code was first a thing. Doesn't matter that a JIT compiler will still do register allocation.
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1884988325049561580
|
||||
|
||||
@janekm @mu_chrinovic @FFmpeg
|
||||
**@janekm** **@mu_chrinovic** **@FFmpeg**
|
||||
|
||||
Sure people have been incorrectly labeling stuff for a long time
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @FFmpeg
|
||||
**1/** **@FFmpeg** ^1884730404587909544
|
||||
|
||||
PTX is a form of assembly language
|
||||
|
||||
Branches: [[archive/threads/FFmpeg/2025-01-29-ptx-is-a-form-of-assembly-language/2025-01-29-mu_chrinovic-i-know-a-person-with-a-phd-that-might-disagree]]
|
||||
|
||||
**2/** @FFmpeg
|
||||
**2/** **@FFmpeg** ^1884750918396051612
|
||||
|
||||
https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1781724279798686001"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @jaap_null
|
||||
**1/** **@jaap_null** ^1783039982560784428
|
||||
|
||||
@KostasAAA
|
||||
**@KostasAAA**
|
||||
|
||||
It's a silly thing on many levels. The entire arch. limitation is awkward, then the way compilers deal (or not deal) with it is just broken. Sad to see it's still around.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1781724279798686001"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @matiasgoldberg
|
||||
**1/** **@matiasgoldberg** ^1783166450733113360
|
||||
|
||||
@KostasAAA
|
||||
**@KostasAAA**
|
||||
|
||||
What's the value of shaderSampledImageArrayDynamicIndexing?
|
||||
|
||||
|
||||
+3
-3
@@ -25,19 +25,19 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @KostasAAA
|
||||
**1/** **@KostasAAA** ^1781724275159728279
|
||||
|
||||
When using arrays of resources/bindless, it's worth paying attention to index divergence. Even if using thread divergent indices, the compiler will use the index from the first active thread to access a resource, for all threads in the wave, which can cause hard to find bugs 1/3
|
||||
|
||||

|
||||
|
||||
**2/** @KostasAAA
|
||||
**2/** **@KostasAAA** ^1781724277747613724
|
||||
|
||||
This happens even when compiler knows that the index varies per thread. To fix this you need to use the NonUniformResourceIndex qualifier. The compiler will then add a waterfall loop to batch wave threads by resource index and ensure that each thread accesses the correct one. 2/3
|
||||
|
||||

|
||||
|
||||
**3/** @KostasAAA
|
||||
**3/** **@KostasAAA** ^1781724279798686001
|
||||
|
||||
This can have a performance impact though, with the worst case being each thread indexing a different resource, both in terms of thread coherence (looping over each thread individually) and texture cache. For more info https://www.asawicki.info/news_1734_which_values_are_scalar_in_a_shader 3/3
|
||||
|
||||
|
||||
+34
-34
@@ -25,101 +25,101 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @MyNameIsMJP
|
||||
**1/** **@MyNameIsMJP** ^1782636381720006711
|
||||
|
||||
@BelgianRenderer @KostasAAA @Nicolas_Lopez_
|
||||
**@BelgianRenderer** **@KostasAAA** **@Nicolas_Lopez_**
|
||||
|
||||
Apparently uniformity analysis is hard. 🙁
|
||||
|
||||
**2/** @KostasAAA
|
||||
**2/** **@KostasAAA** ^1782729117093253403
|
||||
|
||||
@MyNameIsMJP @BelgianRenderer @Nicolas_Lopez_
|
||||
**@MyNameIsMJP** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
If uniformity can't be deduced, the compiler could be conservative and assume divergence. If it guessed wrong, the waterfall loop won't be executed and all threads will use the same index. Also, the shader author could help the compiler with a UniformResourceIndex qualifier.
|
||||
|
||||
**3/** @MyNameIsMJP
|
||||
**3/** **@MyNameIsMJP** ^1782892139220766922
|
||||
|
||||
@KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
Yeah I tend to agree that assuming non-uniformity by default for descriptor indexing would have been a better path, with some better language support for explicit tagging of uniform variables. Maybe in HLSL 2027. 🙂
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1782898526512378177
|
||||
|
||||
@MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
Uniformity is the fast path, it would be horrible to tax the fast path for the sake of things designed to be slow (aka using resource divergence). The right thing to do is place in explicit uniform/nonuniform qualifiers into the languages so it's explicit.
|
||||
|
||||
**5/** @JasperBekkers
|
||||
**5/** **@JasperBekkers** ^1783022121565778346
|
||||
|
||||
@NOTimothyLottes @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@NOTimothyLottes** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
We do nuri for almost all our access (we sometimes turn it off because of badly readable Isa on amd). However the performance impact is in the noise, not all hw resolves this in the shader cores.
|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1783117204612935966
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
NV doesn't advertise this: 32-byte sector size (even with 128-byte lines) mixed with per lane IPs (so you can pipeline latency of divergent accesses) is all about shifting the perf cliff of bad behavior enough to win benchmarks, it is still a cliff (look at ALU utilization) ...
|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1783118039287771353
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
AMD never invested in pipelining divergent latency, and their compiler compounds this by serializing a lot of other things that shouldn't be serialized ...
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1783118781503459544
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
If one is already into the perf cliff, it's easy on AMD to compound perf debt to the point something can never be optimized, and maybe that's ok if time-to-market/ease-of-use/etc is the primary goal ...
|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1783121085875077596
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
There are cases where AMD's compiler is still failing hard on UNIFORM (aka wave coherent) multi-resource access: zero latency hiding -> every resource is a worst case serialization of {fetch descriptor, wait, sample} with zero pipelining ... example below
|
||||
|
||||

|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1783121769546580452
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
Or this case where the images get batched, but the descriptors accesses are serialized (below) ... so it's easy sometimes to assume NURI is not that expensive because the compiler already shot itself in the face (which is quite common in high complexity material shading).
|
||||
|
||||

|
||||
|
||||
**11/** @JasperBekkers
|
||||
**11/** **@JasperBekkers** ^1783123388375998776
|
||||
|
||||
@NOTimothyLottes @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@NOTimothyLottes** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
Most of the time for us the resource access is uniform, so the overhead is just a few waves to test this though.
|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1783124026954506679
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
If the whole shader coherently branches into uniform vs non-uniform material paths, sure that can work if the non-uniform path is almost never used, and the compiler doesn't choak on the register pressure of the non-uniform code path.
|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1783124921905778900
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
At least for the sake of learnings for others, I'll continue down the compiler rabbit hole a little more ... even serialized latency of K$ (constant) HITs (all in the cache) will destroy shader perf (a single hit is like 30 some clocks). This pattern happens on AMD today still.
|
||||
|
||||

|
||||
|
||||
**14/** @NOTimothyLottes
|
||||
**14/** **@NOTimothyLottes** ^1783126767290487066
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
And as for 'fixing' bad programmer behavior via the compiler, lets look at atomicAdd() behavior. First the compiler will burn the overhead to elect an active lane even when the compiler statically knows lane zero is active (simple example below).
|
||||
|
||||

|
||||
|
||||
**15/** @NOTimothyLottes
|
||||
**15/** **@NOTimothyLottes** ^1783128096800981138
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
Try to out smart it like this,
|
||||
|
||||
@@ -130,16 +130,16 @@ It fights back, and makes something even worse. [RED] ... see the multiply by ac
|
||||
|
||||

|
||||
|
||||
**16/** @NOTimothyLottes
|
||||
**16/** **@NOTimothyLottes** ^1783128648481951751
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
And sometimes it gets really squirrly and throws in a full wave reduction (see the DPP ops). When the good dev is just trying to do an already predicated to lane zero atomic ADD ...
|
||||
|
||||

|
||||
|
||||
**17/** @NOTimothyLottes
|
||||
**17/** **@NOTimothyLottes** ^1783129176158937434
|
||||
|
||||
@JasperBekkers @MyNameIsMJP @KostasAAA @BelgianRenderer @Nicolas_Lopez_
|
||||
**@JasperBekkers** **@MyNameIsMJP** **@KostasAAA** **@BelgianRenderer** **@Nicolas_Lopez_**
|
||||
|
||||
So if any solution depends on trusting a compiler to implicitly do the right thing, I'd be very very concerned, because they don't. Compiler size perf 'fixes' are brittle, break easy, and become massive nightmares for programmers who know what they are doing.
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1588515348223254528"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @rianflo
|
||||
**1/** **@rianflo** ^1588561182730113025
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Welcome Not Back! 🤘🏻♥️
|
||||
|
||||
|
||||
+2
-2
@@ -28,9 +28,9 @@ in_reply_to: "1588331007622930432"
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1588515348223254528
|
||||
|
||||
@rianflo
|
||||
**@rianflo**
|
||||
|
||||
Vulkan: ~1500 lines of overhead (including header src, as I don't include) for complete hotrod bind-everything-only-once compute-only gfx engine. Not a fan of VK bloatware API complexity, but frankly it can be minimized, and exposes enough to do wonderfull things to the hardware.
|
||||
|
||||
|
||||
+21
-21
@@ -25,86 +25,86 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1588902081502797826
|
||||
|
||||
GPU Programming Tip Line Thread /
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1588902190034620417
|
||||
|
||||
[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)));}'
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1588902600686329857
|
||||
|
||||
[1] PC FP16 1/denormals generates INFs which can easily eventually result in NaNs, fix positives with 'rcp(max(x,SMALLEST_NORMAL))'
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1588903127549607936
|
||||
|
||||
[2] 'spirv-opt -Os' (optimize for size) is your weapon against "back-before-its-done--getting-groceries" IHV compile times
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1588903378952007680
|
||||
|
||||
[3] Driver ignoring your '[[dont_unroll]]', 'int eatThisBuddy=1+/*hidden-zero*/constantBuffer.zero[0];for(i=0;i<1024;i+=eatThisBuddy){...'
|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1588903586721042432
|
||||
|
||||
[4] 'Ship-One-Shader' = One SPIR-V binary, use specialization constants to select shader at PSO generation time, minimizes released shader binary size
|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1588903663468437508
|
||||
|
||||
[5] 'Ship-One-Shader' requires 'spirv-opt -Os'
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1588903725783220224
|
||||
|
||||
[6] Use signed 'mask=bitfieldExtract(int(v),bit,1)' to turn bit into all 0's or 1's mask
|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1588903926510014467
|
||||
|
||||
[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));}'
|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1588904013239844870
|
||||
|
||||
[8] Use 'bitfieldInsert(,,0,compileTimeImmediate)' hits fast V_BFI_B32 on AMD, and portable to other vendors
|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1588904166269005824
|
||||
|
||||
[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)
|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1588904259265114112
|
||||
|
||||
[10] Bools as 0|1 floats '(a&b)|c' can be done via 'saturate(a*b+c)'
|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1588904325543493633
|
||||
|
||||
[11] Bools as 0|1 floats '!(a&b)' can be done via '(-a)*b+1.0'
|
||||
|
||||
**14/** @NOTimothyLottes
|
||||
**14/** **@NOTimothyLottes** ^1588904434268262400
|
||||
|
||||
[12] Convert INFs to NaNs via 'x*0.0+x'
|
||||
|
||||
**15/** @NOTimothyLottes
|
||||
**15/** **@NOTimothyLottes** ^1588904891707424768
|
||||
|
||||
[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)
|
||||
|
||||
**16/** @NOTimothyLottes
|
||||
**16/** **@NOTimothyLottes** ^1588905179449282560
|
||||
|
||||
[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
|
||||
|
||||
**17/** @NOTimothyLottes
|
||||
**17/** **@NOTimothyLottes** ^1588905286697639936
|
||||
|
||||
[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
|
||||
|
||||
**18/** @NOTimothyLottes
|
||||
**18/** **@NOTimothyLottes** ^1588905339122257921
|
||||
|
||||
[16] Merge passes to avoid round trip through DRAM, often huge wins there
|
||||
|
||||
**19/** @NOTimothyLottes
|
||||
**19/** **@NOTimothyLottes** ^1588905491027341312
|
||||
|
||||
[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
|
||||
|
||||
**20/** @NOTimothyLottes
|
||||
**20/** **@NOTimothyLottes** ^1588905764005216258
|
||||
|
||||
[18] Proper double rate "packed" 16-bit can provides gains up to 30% depending on workload/platform (except NV)
|
||||
|
||||
**21/** @NOTimothyLottes
|
||||
**21/** **@NOTimothyLottes** ^1588906002212323328
|
||||
|
||||
[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
|
||||
+1
-1
@@ -25,7 +25,7 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1589810282104524800
|
||||
|
||||
Example of "Bind-Everything-Once" Layout Aliasing in Vulkan. Storage image format by aliased name, also bound as sampled image. Choose buffer {readonly,writeonly,volatile (read uncached),atomic} access by aliased name, as either {uint,uint4,float,float4}.
|
||||
|
||||
|
||||
+2
-2
@@ -25,8 +25,8 @@ in_reply_to: "1590003266129383424"
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1590241107317002240
|
||||
|
||||
@olson_dan
|
||||
**@olson_dan**
|
||||
|
||||
If only PC vendors with open ISAs (AMD/Intel) would allow loading binary compute shaders in VK built using non-driver toolchains. If Valve enabled binary shaders on Steam Deck in Linux, that would be my new exclusive dev platform, instead of just a possible porting target
|
||||
+1
-1
@@ -25,6 +25,6 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1591646625692553216
|
||||
|
||||
My prefered method of managing application data was the 'self-modifying-binary': (a.) on launch copy binary to temp file, (b.) launch temp file, (c.) exit, (d.) now temp file execution can freely modify origional binary :)
|
||||
+5
-5
@@ -25,22 +25,22 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1651938781610508288
|
||||
|
||||
https://gpuopen.com/learn/rgp-1-15-enhanced-isa-view/ Nice Disasm View :) - However op latency isn't useful. Need to see multiwave instruction trace across time, colored by instruction type, enhanced with mark if wave is waiting to issue a given functional unit. Only then will great optimization be possible.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1651939770350678019
|
||||
|
||||
It would also be best to see overlay of board power (because !/W is the end goal), and an overlay of exactly where there are bubbles in DRAM traffic. Because anything memory bound, the goal is to minimize DRAM bubbles. Need to see how they form dynamically over time to fix ...
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1651941119075164162
|
||||
|
||||
For GPU profilers, might see say {92% ALU, 50% TEX, 21% L2}, then wonder, where is 8% I'm missing. And only way to start to understand that, is to be seeing how waves are executing instruction wise against each other. CPU-profiler-like averages per disassembly line won't cut it.
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1651945376847392769
|
||||
|
||||
Parallel machines can only be understood by seeing the parallel execution. I still have examples today of taking a vanila 32-bit shader (already designed to be fast) and getting 30% returns on all micro optimizations.
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1651946306737250304
|
||||
|
||||
Lastly, side with enabling. Remember people can learn too. And there is typically super skilled people seeded at all companies that teach others how to use advanced tools when they are available.
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @BrianKaris
|
||||
**1/** **@BrianKaris** ^1653593003368546304
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Great to see these return. Still have any of the videos?
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1653742549066973185
|
||||
|
||||
@BrianKaris
|
||||
**@BrianKaris**
|
||||
|
||||
I might, but will have to build a machine to attach the old drives. Too busy making new stuff
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @BrookeHodgman
|
||||
**1/** **@BrookeHodgman** ^1653666232749682689
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
I remember watching all of these blog entries fondly ❤
|
||||
|
||||
|
||||
+6
-6
@@ -26,21 +26,21 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Karyuutensei
|
||||
**1/** **@Karyuutensei** ^1653661020026466307
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Is the blog still up somewhere?
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1653743479032250373
|
||||
|
||||
@Karyuutensei
|
||||
**@Karyuutensei**
|
||||
|
||||
No but I have archives in pieces on old hard drives. So there is a chance I might restore it some day.
|
||||
|
||||
**3/** @Karyuutensei
|
||||
**3/** **@Karyuutensei** ^1653746161050693634
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Speaking of archives, http://archive.org has some from the blogspot here https://web.archive.org/web/20160427173127/http://timothylottes.blogspot.com/ but basically nothing from the github page :S
|
||||
|
||||
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @oconnorkg
|
||||
**1/** **@oconnorkg** ^1653842852210782209
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Did you write an engine called Atom? Talked about it on the http://OpenGL.org forum?
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1653872960455823363
|
||||
|
||||
@oconnorkg
|
||||
**@oconnorkg**
|
||||
|
||||
There was also Atomontage or something like that by another person. I had a project called Atom, but I don't remember if I was on the OGL message board
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @won3d
|
||||
**1/** **@won3d** ^1653557420805767170
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
I remember all those fondly. I also remembered the trick you did to batch logical draw calls with branching in the shader
|
||||
|
||||
|
||||
+6
-6
@@ -26,21 +26,21 @@ parent_post_id: "1653559205360553985"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @won3d
|
||||
**1/** **@won3d** ^1653573851643625480
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
My former thesis advisor was a big proponent of forth. Apparently SunOS used forth in preboot and you could do all sorts of wacky things. He interfaced with custom compute accelerators this way. I agree that concatenantive programming languages are underexplored
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1653577630229098497
|
||||
|
||||
@won3d
|
||||
**@won3d**
|
||||
|
||||
I think it is less the exact form of the language but more 'the way to make things simple' that truely important now.
|
||||
|
||||
**3/** @won3d
|
||||
**3/** **@won3d** ^1653585212628951047
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
There's something about Forth-style composition that is has a very nice appeal. It really seems to marry syntax and semantics very directly (but I can appreciate it at a distance, having not done any real work in it as you have)
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1653570742762479620"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Laxer3A
|
||||
**1/** **@Laxer3A** ^1654169796328423450
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
This is when I learned about your work and found it incredible. Nowadays with 4K / 8K, people are really craving for a very good shader/model to emulate as close as possible the CRT feel for arcade / old console etc. (I am serious)
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1653556990302470151"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @arm1n
|
||||
**1/** **@arm1n** ^1654835157789016064
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Thanks for digging those up! Great stuff, very inspiring.
|
||||
|
||||
|
||||
+16
-16
@@ -25,7 +25,7 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1653556990302470151
|
||||
|
||||
Found some of my old blogs: thread looking back an image at a time. 2007, ellipsoid l-system sprites with temporal feedback, yes temporal reprojection in 2007.
|
||||
|
||||
@@ -33,13 +33,13 @@ Found some of my old blogs: thread looking back an image at a time. 2007, ellips
|
||||
|
||||
Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-won3d-i-remember-all-those-fondly-i-also-remembered-the]], [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-BrianKaris-great-to-see-these-return-still-have-any-of-the]], [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-Karyuutensei-is-the-blog-still-up-somewhere]], [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-BrookeHodgman-i-remember-watching-all-of-these-blog-entries]], [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-oconnorkg-did-you-write-an-engine-called-atom-talked-about]], [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-06-arm1n-thanks-for-digging-those-up-great-stuff-very]]
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1653558383415271424
|
||||
|
||||
2007 particle based fluid sim mixed with spring model, this was 2D to work out ideas for later 3D implementation, rastered particle properties along particle paths into mip tree to enable high-speed collision
|
||||
|
||||

|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1653559205360553985
|
||||
|
||||
2007 crazy custom language and live editor for x86-64, color forth is like a virus of the mind, no going back once the understanding is there, and the evolutions of those ideas are ground breaking
|
||||
|
||||
@@ -47,7 +47,7 @@ Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blog
|
||||
|
||||
Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blogs-thread-looking-back-an/2023-05-03-won3d-my-former-thesis-advisor-was-a-big-proponent-of]]
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1653561084429713408
|
||||
|
||||
2010 digital photography, was compositing exposure brackets to get 16-bit tiffs with good dynamic range and did my own development tools (which had some major flaws I'd only learn about much later in life)
|
||||
|
||||
@@ -56,51 +56,51 @@ Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blog
|
||||

|
||||

|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1653563093106974728
|
||||
|
||||
2011 Was using temporal reprojection in my own engines for a while. Posted TSSAA source, an early TAA using viewport jitter for tri raster. I was mostly convinved this was a tech dead end due to the challenges of thin flicker. Decade+ later, and this story has a lot more to it ..
|
||||
|
||||

|
||||

|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1653564005888274432
|
||||
|
||||
2011 A simple GIF showing the challenges of {perceptual vs linear} filtering with temporal aliasing high frequency content with {small to large kernel windows}. No negative lobes here.
|
||||
|
||||
<video controls src="https://video.twimg.com/tweet_video/FvKi92TWcAA19un.mp4"></video>
|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1653564728440942592
|
||||
|
||||
2014 simple anti-aliased point based CS rendering engine with fisheye output using stocastic/stratified visiblity and GPU-side scene graph
|
||||
|
||||

|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1653565160605270016
|
||||
|
||||
2014 simple non-temporal spatial AA using rotated viewport to provide a good sample distribution with standard non-AA triangle rendering
|
||||
|
||||

|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1653566080235761669
|
||||
|
||||
2014 monochrome 120 hz laptop ray marcher desiged for VR, fixed cost trace, leaving scene with holes, temporal holefilling reprojection, faked 'lighting' using hierarchical + directional distance probing in lower LOD scene representations, was amazing to just fly around in there
|
||||
|
||||

|
||||

|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1653566551818207232
|
||||
|
||||
2014 was amazing how nice it was possible to get the geometry even when tracing only 1/8 the screen pixels per frame, stratified sample pattern really does wonders to neighborhood stability, no flicker at all
|
||||
|
||||

|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1653566948897062914
|
||||
|
||||
2014 still distracted by custom code generation and languages, running stuff on CRTs with custom live editors (color forth like), generating binaries with ELF header generation inside the code itself
|
||||
|
||||

|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1653567451315986432
|
||||
|
||||
2015 some more images inside the live fractal tracer
|
||||
|
||||
@@ -108,13 +108,13 @@ Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blog
|
||||

|
||||

|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1653568279271682052
|
||||
|
||||
2015 crazy mini x86 OS project (bootloader source below), using codeless binary editor with annotation. Everyone should try generating binaries with no assembler, learn alot in the process
|
||||
|
||||

|
||||
|
||||
**14/** @NOTimothyLottes
|
||||
**14/** **@NOTimothyLottes** ^1653569285048918018
|
||||
|
||||
2015 live realtime 120+ hz on laptop tracer now with spatial/temporal reconstruction on 1 shaded/sample per ray for 'fake' lit fog, did a lot of z based logic in the spatial/temporal reconstruction, realized later I was relying on the 120 Hz to hide perceptual artifacts
|
||||
|
||||
@@ -123,14 +123,14 @@ Branches: [[archive/threads/NOTimothyLottes/2023-05-03-found-some-of-my-old-blog
|
||||

|
||||

|
||||
|
||||
**15/** @NOTimothyLottes
|
||||
**15/** **@NOTimothyLottes** ^1653570073288757253
|
||||
|
||||
2015 still doing the crazy custom languages and tiny OS projects. I feel like there is a real loss in computer evolution, imagine a machine with C64 simplicity that evolved to have a massively parallel vector machine. It would be amazing. It would be approachable by one person.
|
||||
|
||||

|
||||

|
||||
|
||||
**16/** @NOTimothyLottes
|
||||
**16/** **@NOTimothyLottes** ^1653570742762479620
|
||||
|
||||
2015 did some custom CPU-side CRT shader tools for high resolution physical paper prints for someone's book. Wasn't trying to be physically accurate, but rather provide the feeling you'd get from a CRT in paper print form
|
||||
|
||||
|
||||
+42
-42
@@ -26,69 +26,69 @@ parent_post_id: "1671276990987370501"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1671279693104914434
|
||||
|
||||
Or for an APU, a way to have the storage device write direct to DRAM in pages setup for use on the GPU, because anything the CPU writes that the GPU reads is stuck on the strangled snooping bus or the strangled WC buffer limit on store.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1671288062817517570
|
||||
|
||||
If the app tried to manage GPU memory oversubscription via these strangled CPU mappings you'd literally see many second stalls. One can only assume the kernel can do storage<->DRAM DMA for managing GPU DRAM oversubscription?
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1671290467453943810
|
||||
|
||||
Even if could fill VRAM in 1 sec, just 2x oversubscription of VRAM implies 1 sec delay to context switch (assuming 2 apps accessing all meM). So classic VM multitasking is useless. Only single app focus model with pinned memory makes any useful sense. Release pin on focus change.
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1671291093860728834
|
||||
|
||||
The trend is massive res massive VRAM paired with tiny IO bus. So the case for pinned memory and bus master transfers only grows importance as things evolve.
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1671343857353515010
|
||||
|
||||
Back to SteamDeck numbers: GTT (HOST_VISIBLE) + USWC (non-HOST_CACHED) takes 1 sec for 1st 4 GiB BO alloc, but *30 sec* for 2nd 4 GiB alloc. Kernel driver time for memory allocation (maybe page table related) can be brutal (general comment for PCs too).
|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1671345575805984769
|
||||
|
||||
Related, I think Chips&Cheese CPU/GPU link DMA and Compute Bandwidths are only measured to a GTT+USWC buffer (only supporting useless uncached CPU reads). Bandwidth exceeds the CPU's bus capacity, implies it is 'garlic' or GPU bus only accesses, direct to DRAM ...
|
||||
|
||||

|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1671346590731104257
|
||||
|
||||
Since RADV+AMDVLK don't support user-space CPU mapped flush | invalidate, this implies the only supported mapping to read from DRAM direct is USWC (uncached R and write+combine W) ...
|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1671347663655018501
|
||||
|
||||
Doing GPU stores to a CPU mapped GTT without USWC would be crippingly slow (limited by the snooping bus rate). But this is unfortunately the only option available for CPU read back. So if doing a shader store, it better be only a few waves and running in parallel.
|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1671349224871436288
|
||||
|
||||
"Use GTT because it's as fast as VRAM on the Deck", could only work if GTT+USWC, as that would be only way to get Garlic (direct to DRAM high bandwidth bus). GTT without USWC would need Onion (slow snooping bus) because AMDgpu's only no-CPU map option is for VRAM!
|
||||
|
||||

|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1671357732413210629
|
||||
|
||||
Summary of the theory on best Steam Deck practices. This is the plan for my deck-compute-only driver too. Theory -> as in I haven't yet verified the GPU-side parts (my driver isn't that far along yet).
|
||||
|
||||

|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1671483638435725312
|
||||
|
||||
Possible to do better? MAYBE! CPU readback actually has 2 problems, 1st the slow GPU-side copy (4 GiB copy via snooping bus could be almost 4 sec, but direct to DRAM via USWC might be just 160 ms). Also CPU only has 4 MiB of L3, so the majority of 4 GiB will be uncached later ...
|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1671484591314464768
|
||||
|
||||
Believe UC MTYPE (uncached) forces the CPU into serialized behavior. My test was single thread 8-byte/access reads. https://uops.info/html-instr/VMOVDQA_M256_YMM.html#ZEN2 Looks like Zen2 might be able to get 32-byte/access via VMOVDQA, and going multi-threaded (8 thread), that might be a 32x speed up ..
|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1671485760141246464
|
||||
|
||||
If so might be able to approach under a GB/s for the CPU-side part (UC multithread via VMOVDQA), which would be close enough to the non-USWC running single threaded using the cache.
|
||||
|
||||
**14/** @NOTimothyLottes
|
||||
**14/** **@NOTimothyLottes** ^1671486912668880896
|
||||
|
||||
What you'd really want here as a band-aid workaround is ability for the GPU to act as if the CPU map was USWC (so go direct to DRAM), but have the CPU map act as non-USWC, so it goes through the cache. Then some kind of hack to flush the tiny 4 MiB L3 and lower caches on the CPU.
|
||||
|
||||
**15/** @NOTimothyLottes
|
||||
**15/** **@NOTimothyLottes** ^1671500657767903238
|
||||
|
||||
CPU readback (reading and summing 8-byte) GTT without USWC:
|
||||
|
||||
@@ -98,7 +98,7 @@ CPU readback (reading and summing 8-byte) GTT without USWC:
|
||||
|
||||
Going multi-core on cached readback doesn't really help much. Proper test, parked threads waiting on futex, signal, last-1st active core timing.
|
||||
|
||||
**16/** @NOTimothyLottes
|
||||
**16/** **@NOTimothyLottes** ^1671519831424729088
|
||||
|
||||
Now CPU readback GTT+USWC
|
||||
|
||||
@@ -108,11 +108,11 @@ Now CPU readback GTT+USWC
|
||||
|
||||
So measurements match theory, going multi-core with MOVNTDQA uncached read on GTT+USWC can be made to match 1 thread GTT (without USWC)
|
||||
|
||||
**17/** @NOTimothyLottes
|
||||
**17/** **@NOTimothyLottes** ^1671521432495443968
|
||||
|
||||
Both those results above had been using a pair of 4 GiB allocations. The GTT+USWC one used one 4 GiB GTT+USWC for timing, and one 4 GiB GTT (unused). And that test suffered from a 30 sec GTT BO allocation. So something was going very wrong in the page mapping ...
|
||||
|
||||
**18/** @NOTimothyLottes
|
||||
**18/** **@NOTimothyLottes** ^1671523195382374407
|
||||
|
||||
When I rerun same test with just one 4 GiB GTT+USWC allocation, the 30 sec stall is gone, and the performance also changes:
|
||||
|
||||
@@ -122,38 +122,38 @@ Oh!
|
||||
|
||||
Perhaps there is some resource limit that kills perf if too much memory gets mapped, page faults?
|
||||
|
||||
**19/** @NOTimothyLottes
|
||||
**19/** **@NOTimothyLottes** ^1671536279958302720
|
||||
|
||||
Top with thread cumulative results doesn't show anything significantly different between the 4 GiB and 8 GiB runs in terms of page faults ... suggests it must be something else
|
||||
|
||||

|
||||

|
||||
|
||||
**20/** @NOTimothyLottes
|
||||
**20/** **@NOTimothyLottes** ^1671550049359101954
|
||||
|
||||
And yet there is obviously a bug in my multi-core tests, you can tell directly from the page fault numbers, only one thread is taking all the faults. So it is back to finding my coding error (fail).
|
||||
|
||||
**21/** @NOTimothyLottes
|
||||
**21/** **@NOTimothyLottes** ^1671556087479189504
|
||||
|
||||
Lunch break and fixed the bug. Two runs now and leaving threads open to get TOP results. First run definitely soaks up the page faults, second run is page fault free (expected). Both around only 7 GB/s.
|
||||
|
||||

|
||||
|
||||
**22/** @NOTimothyLottes
|
||||
**22/** **@NOTimothyLottes** ^1671557944402378756
|
||||
|
||||
And the 8 GiB of BO mapped, but only 4 GiB used run. The first pass gets only 1 GiB/s and the second gets 7 GiB/s. Page fault number is similar to last run, can only conclude page fault costs exploded?
|
||||
|
||||

|
||||
|
||||
**23/** @NOTimothyLottes
|
||||
**23/** **@NOTimothyLottes** ^1671562574859468823
|
||||
|
||||
30 sec BO alloc time + super low bandwidth on 1st pass only (where page faults happen) suggest that Linux Kernel logic explodes in cost if too many pages are used in this way ...
|
||||
|
||||
**24/** @NOTimothyLottes
|
||||
**24/** **@NOTimothyLottes** ^1671563212368519168
|
||||
|
||||
~8K faults for 512 MiB accessed / thread = 64 KiB/fault ... X86-64 has either 4 KiB or 2 MiB for page size. So not using large pages (fail). Probably mapping 16 pages per fault. Not sure if this implies anything about GPU page size (but certainly hoping it isn't 4 KiB, ouch).
|
||||
|
||||
**25/** @NOTimothyLottes
|
||||
**25/** **@NOTimothyLottes** ^1671563873315323905
|
||||
|
||||
Some other very rough measured numbers of GTT+USWC with 8 cores splitting 4 GiB of BO.
|
||||
|
||||
@@ -163,11 +163,11 @@ Some other very rough measured numbers of GTT+USWC with 8 cores splitting 4 GiB
|
||||
|
||||
I think these seem plausable now (so maybe no more code bugs).
|
||||
|
||||
**26/** @NOTimothyLottes
|
||||
**26/** **@NOTimothyLottes** ^1671564648141684749
|
||||
|
||||
One takeaways of all this, is that you need to pre-warm the page tables for large mapped buffers (by touching all pages) when the user isn't waiting on results. And if you are doing batch jobs that {open device, send data to GPU, get data back, close device} you are screwed!
|
||||
|
||||
**27/** @NOTimothyLottes
|
||||
**27/** **@NOTimothyLottes** ^1671574993581350914
|
||||
|
||||
And lastly (maybe) comparison of GTT and GTT+USWC both 8 threads splitting streaming through 4 GiB of mapping (second pass, no page fault issues):
|
||||
|
||||
@@ -175,61 +175,61 @@ R> ~14 GiB/s (GTT) and ~7 GiB/s (GTT+USWC)
|
||||
W+R> ~14 GiB/s (GTT) and ~10 GiB/s (GTT+USWC)
|
||||
W> ~13 GiB/s (GTT) and ~15 GiB/s (GTT+USWC)
|
||||
|
||||
**28/** @NOTimothyLottes
|
||||
**28/** **@NOTimothyLottes** ^1671580078008934402
|
||||
|
||||
So an alternative option summary for those who don't want the extra GPU-side GPU to CPU mapped buffer copy step.
|
||||
|
||||

|
||||
|
||||
**29/** @NOTimothyLottes
|
||||
**29/** **@NOTimothyLottes** ^1671841381759832066
|
||||
|
||||
If anyone is looking to repro the 30 sec stall: amdgpu_bo_alloc() one 4 GiB GTT+USWC, then one 4 GiB GTT buffer, the second alloc causes the Deck to become unresponsive for 30 seconds
|
||||
|
||||
**30/** @NOTimothyLottes
|
||||
**30/** **@NOTimothyLottes** ^1671842511826952194
|
||||
|
||||
madvise() with MADV_HUGEPAGE on mapped 4 GiB region doesn't do anything (still faults at 64 KiB granularity), and none of these MADV_{WILLNEED|POPULATE_READ|POPULATE_WRITE} have any effect either (still waits until use before faulting, causing low initial effective bandwidth)
|
||||
|
||||
**31/** @NOTimothyLottes
|
||||
**31/** **@NOTimothyLottes** ^1671846815082094593
|
||||
|
||||
64KiB strided write through 4 GiB GTT+USWC (to pre-fault) costs the same as writing full 4 GiB, roughly 3 seconds. So it is quite literally massive page fault overhead for 1st access. No possible workaround found at this time for initial load time problems.
|
||||
|
||||
**32/** @NOTimothyLottes
|
||||
**32/** **@NOTimothyLottes** ^1671852339399909377
|
||||
|
||||
If doing two 4 GiB GTT+USWC allocations, there is also a 30 second BO allocate cost on the 2nd one. And this makes the initial page fault cost for access to the first 4 GiB take another 30 seconds. Effectively hangs the machine for a full minute.
|
||||
|
||||
**33/** @NOTimothyLottes
|
||||
**33/** **@NOTimothyLottes** ^1671855582632976386
|
||||
|
||||
Doing two 4 GiB GTT allocations (without USWC), doesn't incure any of the 30 second stalls. So that problem is specific to big USWC allocations. However the initial access page fault problem (extra 3 seconds) is there, so a 2ndary problem with just mapping lots of APU memory.
|
||||
|
||||
**34/** @NOTimothyLottes
|
||||
**34/** **@NOTimothyLottes** ^1671863862214250500
|
||||
|
||||
Allocation of one 4 GiB GTT first then a 4 GiB GTT+USWC doesn't see the 30 second allocation stall. Almost like anything post a big USWC alloc is poisioned. And after mapping both, then accessing the GTT only, the 30 second time for page faulting comes back.
|
||||
|
||||
**35/** @NOTimothyLottes
|
||||
**35/** **@NOTimothyLottes** ^1671864699820834821
|
||||
|
||||
Continuing from before, even if you don't map the 2nd GTT+USWC, the 30 second initial page faulting time is still there, so the act of mapping doesn't matter, simply doing the BO allocation had already doomed the Linux page management.
|
||||
|
||||
**36/** @NOTimothyLottes
|
||||
**36/** **@NOTimothyLottes** ^1671868301008314368
|
||||
|
||||
Despite header docs which imply flag only works on DOMAIN_VRAM, using DOMAIN_GTT+AMDGPU_GEM_CREATE_NO_CPU_ACCESS is apparently what you want for non-mapped GTT allocations. Mapped 4 GiB GTT with 4 GiB GTT+NO_CPU, drops the initial page fault time from 30 seconds to 3 sec.
|
||||
|
||||

|
||||
|
||||
**37/** @DaveAirlie
|
||||
**37/** **@DaveAirlie** ^1671288133680529408
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
the problem there is usually tiling, GPUs expect graphicy things in VRAM to be tiled in very specific ways, it's hard to have a storage device do that. Using a transfer engine that can tile/detile makes a lot more sense.
|
||||
|
||||
**38/** @NOTimothyLottes
|
||||
**38/** **@NOTimothyLottes** ^1671292871440314368
|
||||
|
||||
@DaveAirlie
|
||||
**@DaveAirlie**
|
||||
|
||||
The obvious elephant is an engine using only buffers for resource streaming and doing its own GPU-side decompression. This is practical NOW and portable too. But the lack of a bus master no-CPU direct storage transfer is a serious problem for throughput.
|
||||
|
||||
**39/** @NOTimothyLottes
|
||||
**39/** **@NOTimothyLottes** ^1671301204176146432
|
||||
|
||||
@DaveAirlie
|
||||
**@DaveAirlie**
|
||||
|
||||
See raw texture streaming (even with lossless compression) is way less interesting now given modern massive data tech direction, u want substantially better lossy compression simply to fit in launch constraints. So really, buffers are the way to go anyway :)
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1671276990987370501"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SheriefFYI
|
||||
**1/** **@SheriefFYI** ^1671279374622924802
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Great thread!
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1671276990987370501"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @never_released
|
||||
**1/** **@never_released** ^1671278880219447298
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
On Linux, NVIDIA has a very good UVM.
|
||||
|
||||
|
||||
+9
-9
@@ -25,55 +25,55 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1671264312516829184
|
||||
|
||||
How about a mega thread on the mechanics of CPU/GPU communication. Using AMDgpu based timing results on the SteamDeck an example, but relating to the larger picture of PC GFX APIs like Vulkan/etc. I don't claim to know all, so experts feel free to add your wisdom :)
|
||||
|
||||

|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1671266934980063239
|
||||
|
||||
Both RADV and AMDVLK: Flush/invalidate mapped memory ranges is a NOP. So bus-crossing dGPU traffic to HOST_VISIBLE is automatically snooping CPU caches. The one without HOST_CACHED, is Write+Combined [WC] on store, and Uncached [UC] on read. The one with HOST_CACHED is non-WC/UC
|
||||
|
||||

|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1671268879484571649
|
||||
|
||||
In AMDgpu (the kernel driver), likely DEVICE_LOCAL maps to AMDGPU_GEM_DOMAIN_VRAM (also the carve out on APUs) and the non-DEVICE_LOCAL maps to AMDGPU_GEM_DOMAIN_GTT
|
||||
|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1671269986588041216
|
||||
|
||||
AMD+RADV added {DEVICE_COHERENT_BIT_AMD,
|
||||
DEVICE_UNCACHED_BIT_AMD} variations to the core 4 memory types. Likely to support GPU crash debug. But also provides a way to avoid needing to write-back (flush) GPU caches before CPU read. Likely AMDgpu kernel flag mapping below.
|
||||
|
||||

|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1671271559636426754
|
||||
|
||||
This AMDGPU_GEM_CREATE_CPU_GTT_USWC appear to toggle on WriteCombine [WC] for CPU store, and Uncached [US] for CPU reads (cases of HOST_VISIBLE without HOST_CACHED)
|
||||
|
||||

|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1671273600974766081
|
||||
|
||||
For review from https://chipsandcheese.com/2023/03/05/van-gogh-amds-steam-deck-apu/ Deck bandwidths: ~71 GB/s GPU, ~43 GB/s DMA, ~34 GB/s shader copy CPU<->GPU, ~25 GB/s CPU/CPU, and damn, brutal 0.27 GB/s CPU mapped GPU buffer reads, 0.71 GB/s CPU mapped GPU buffer writes
|
||||
|
||||

|
||||

|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1671275003499757575
|
||||
|
||||
And going direct to AMDgpu instead of VK on the Deck shows these kinds of bandwidths (non-DEVICE_LOCAL, HOST_VISIBLE with HOST_CACHED and without). So using Write-Combined is amazingly painful for stores.
|
||||
|
||||

|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1671275745283301376
|
||||
|
||||
Implies that the choices one might make on dGPU PC don't necessarily port over to APUs at all. Another challenge: it takes almost 7 seconds to zero-fill using a 64-bit store for() loop the 8-GiB of mapped memory. Hints at why load times are such a challenge even in the best case.
|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1671276990987370501
|
||||
|
||||
This all hints at why PC OS derived systems are lacking in stuffing GPU VRAM. Really need some kind of bus mastered DMA (zero-copy) between non-volatile storage (disk) and GPU DRAM to avoid this CPU-touching performance tax.
|
||||
|
||||
|
||||
+4
-4
@@ -26,17 +26,17 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SebAaltonen
|
||||
**1/** **@SebAaltonen** ^1674768757867020289
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Would be nice to talk a full presentation about this topic, but people want me to show cool tech and pretty pixels instead. Maybe one day.
|
||||
|
||||
I will save your image for that day (if I get approval to use it), since Twitter search is super bad.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1674776150671781888
|
||||
|
||||
@SebAaltonen
|
||||
**@SebAaltonen**
|
||||
|
||||
"Approval", haha, sure it's covered under my favorite license
|
||||
|
||||
|
||||
+4
-4
@@ -26,16 +26,16 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @_spolsh
|
||||
**1/** **@_spolsh** ^1674839597853835285
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Once in a while people need to be reminded to stop the bloat, understand the machine guts and be self aware about productive process
|
||||
https://tonsky.me/blog/disenchantment/
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1674886711707418624
|
||||
|
||||
@_spolsh
|
||||
**@_spolsh**
|
||||
|
||||
That was a fantastic read, thanks
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @domipheus
|
||||
**1/** **@domipheus** ^1674777379414179840
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
I like this, given I never write code any more.
|
||||
sadly i am still a grumpy git.
|
||||
|
||||
+4
-4
@@ -26,16 +26,16 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @leonard_coder
|
||||
**1/** **@leonard_coder** ^1674771452799614976
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
$4e71
|
||||
if you know, you know
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1674774881093689346
|
||||
|
||||
@leonard_coder
|
||||
**@leonard_coder**
|
||||
|
||||
${EA, 1A, 3A, 5A, 7A, DA, or FA}
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @CodingFiend
|
||||
**1/** **@CodingFiend** ^1675149939759017987
|
||||
|
||||
@NOTimothyLottes @Jonathan_Blow
|
||||
**@NOTimothyLottes** **@Jonathan_Blow**
|
||||
|
||||
i designed a language Beads, which uses a graph DB, has no memory allocation, super modular, approaches this minimalism as close as humanly possible, but billable hour / job security seeking programmers refuse to try it
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @DefenceForceOrg
|
||||
**1/** **@DefenceForceOrg** ^1675059402280251395
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Many games used to be like that, at least the ones without dynamic content, mods, etc...
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @PierreTerdiman
|
||||
**1/** **@PierreTerdiman** ^1675088736621559808
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
I was calling it "disoriented programming" just the other day.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SimonNordon
|
||||
**1/** **@SimonNordon** ^1674970938234875907
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
NOP is ideal.
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @TimSweeneyEpic
|
||||
**1/** **@TimSweeneyEpic** ^1675248176498987009
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Can teach it in abstinence-only programming classes!
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @asparagiii
|
||||
**1/** **@asparagiii** ^1675123653162196992
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Looks like a koala
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @azeke1984
|
||||
**1/** **@azeke1984** ^1674996094265163782
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Best software is absense of it:
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @claudiogonzalo
|
||||
**1/** **@claudiogonzalo** ^1675054802265423872
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
c++ to √c
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @helpful_signage
|
||||
**1/** **@helpful_signage** ^1675020853862359041
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Folks, they're calling it "computer oriented programming". It's where you stop trying to impress peers and just tell the computer the best way to do things
|
||||
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @mike_acton
|
||||
**1/** **@mike_acton** ^1674962613506297857
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||

|
||||
## Related
|
||||
|
||||
+2
-2
@@ -26,9 +26,9 @@ parent_post_id: "1674757854471806977"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @wyattscarpenter
|
||||
**1/** **@wyattscarpenter** ^1678087686404595712
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
https://github.com/wyattscarpenter/wu
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1674757854471806977
|
||||
|
||||
"Nothing Oriented Programming" (NOP). Where the goal is to achieve minimal enlightenment by writing as little possible code: no dynamic memory allocation, no thousand files of glue, no includes, no objects. Write nothing, be happy. Even applied it to the logo, zero effort.
|
||||
|
||||
|
||||
+7
-7
@@ -25,38 +25,38 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1687250591813079041
|
||||
|
||||
SPC: Left off with KEY and GAMEPAD input GPU-accessable. NOP design, no functions, no API, just a fixed VA address and data format to read, dead easy.
|
||||
|
||||

|
||||
|
||||

|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1687251721032978432
|
||||
|
||||
Wrote some console data dumping to aid in bringing up HID parsers for Deck and three generations of PlayStation controllers. Apparently XBox controllers aren't HIDs so not sure how one is supposed to access those.
|
||||
|
||||

|
||||
|
||||

|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1687252813468852225
|
||||
|
||||
Supporting hot plug was a bit of a mess, just trying to open devices every second. Adding open devices to an epoll. {Product, vendor} isn't enough to ID a device, too much aliasing, so I use packet size as well.
|
||||
|
||||

|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1687253442643755008
|
||||
|
||||
Open devices with matching packet size get set in a bit array, and I collect up to 4 of those device outputs to sent to the GPU. Special logic to always place Steam Deck controls last to make docking work well.
|
||||
|
||||

|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1687254511239221249
|
||||
|
||||
I'll have to tackle audio at some point, but I'm skipping networking for version 1. But otherwise SPC is good to move on to the next step, which is to build out the GPU side assembler & data editor. Which will be written in binary at first.
|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1687255546372493313
|
||||
|
||||
Project is roughly 2000 lines of C at this point. With no includes. Anyone have any suggestions for hosting let me know. Source will be released.
|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1687257354490818561
|
||||
|
||||
For anyone tuning in now, SPC is kind of like a Pico8, but instead of being a portable fantasy console, SPC turns the Steam Deck into an actual console for exclusive GPU assembly projects. The way consoles had been done before silly portability became the only focus.
|
||||
+5
-5
@@ -25,26 +25,26 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1687062786273062912
|
||||
|
||||
SPC: Using 8 deep swap all aliasing same BO (image) fixes Game Mode crash with external display. Pipelined load gets to black screen in 2 ms. Takes 460 ms to allocate 4 GiB GTT video ram, 558 ms to copy 256 MiB cart from page cache to USWC (page faults), all in parallel.
|
||||
|
||||

|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1687065863512285185
|
||||
|
||||
Clearing page cache to simulate a cold launch: Takes 1.5 sec to read 256 MiB from the stock SSD. This is worst case load time in desktop mode. Won't be any compile/etc after this. So literally in game at this point. Speed of light. This is how it is done.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1687066126268674048
|
||||
|
||||
Forgot the timing capture ... Load from SSD.
|
||||
|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1687068433584738304
|
||||
|
||||
There are only 3 threads on load: (1.) to open X11 then spin doing present/keyboard, (2.) to open the AMDgpu device, SDMA copy after CART read, and then eventually spin doing dispatchs, (3.) one to load the CART from disk to mapped USWC GTT via read().
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1687069108355866625
|
||||
|
||||
Something I don't know: does read() since it's kernel- side automatically get some multi-core parallelism? Not a good idea to manually thread the read() because SSD needs linear reads to be fast. Not possible to know if the reads are page cache hits in advance either ...
|
||||
+4
-4
@@ -25,22 +25,22 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1688018382543597568
|
||||
|
||||
1st SPC project: to be based on vintage 640x480 render (VGA style), +fallback to 640x240 for 15 KHz arcade CRTs (PGM-esk), and CRT shader scaling on Deck and OLED/LCD. Use mix of render pixel aspect changes, running less than 480 lines, and letter-box to keep integer Y scaling.
|
||||
|
||||

|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1688019698904969216
|
||||
|
||||
My 15 KHz CRT output path when docked is HD Fury Nano (won't do <480p) doing HDMI to VGA, with a sync combiner (to workaround GBS-C bug), into GBS-C which line drops 480p ~60Hz to 240p ~60Hz and outputs component. The 640 width gets maintained even if some CRTs cannot resolve it.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1688021533904510976
|
||||
|
||||
Presents issues for UI, namely that my bitmap fonts need to look good in both 480p and 240p modes, so for editor (assembler) I'm going with a font that uses right angles and designed around 2x2 stroke width, in a 8x16 (pow2) bitmap, so 640x240p still gets a readable 8x8 (below)
|
||||
|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1688022114962374656
|
||||
|
||||
The next challenge is overscan safety, since real non-VGA CRTs will be used in development. The Y axis has an easy fix, simply keep cursor pinned in the 'safe' zone, but still print lines in the overscan area (so they can be seen when attached to non-overscan CRTs/etc too).
|
||||
@@ -25,75 +25,75 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1688275737692815360
|
||||
|
||||
SPC: RDNA2 ASSEMBLER [thread] ... Did initial design plan this weekend. The aim is a GPU-side assembler+editor, building RDNA2 binary images for Steam Deck. Live edit, live data view, etc. Assembler and editor running in massive vectorized shader code.
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1688276271619248129
|
||||
|
||||
Good reason not to use text input for assembler, instead will use a custom binary format, and treat all 32-bit words in the binary the exact same way (so massively parallel assembly step). This is parallel design 101.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1688277538571755520
|
||||
|
||||
Some basics: RDNA2 instructions are 1-N 32-bit words. Each of the 32-bit components have a bunch of fields. Will typically need 1-6 fields per 32-bit word, as will be joining some fields into one argument (like DLC/GLC) below.
|
||||
|
||||

|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1688278083684421632
|
||||
|
||||
Could argue that MIMG has the most fields, but in practice many of those fields will be joined (see example), and I'm not likely to be using NSA encoding. So still will only need maximum 6 arguments to build a 32-bit value.
|
||||
|
||||

|
||||

|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1688278959711272960
|
||||
|
||||
Custom editor, using a custom font, designed for vintage CRTs. Wanted 5-character symbol names for easy packing in 30-bit values. So setup a 6-bit character table. This is using a modified 'right-angle-only' font (like the one below). So some glyphs alias, and only upper case.
|
||||
|
||||

|
||||
|
||||
**6/** @NOTimothyLottes
|
||||
**6/** **@NOTimothyLottes** ^1688280670764756992
|
||||
|
||||
Will need some kind of symbol table, what ends up providing the arguments to the rules that build the 32-bit words that comprise the final binary. The symbol indirection provides a way to name registers for example, and then change the register mapping later.
|
||||
|
||||

|
||||
|
||||
**7/** @NOTimothyLottes
|
||||
**7/** **@NOTimothyLottes** ^1688281231954161664
|
||||
|
||||
Notice SMEM ops have 21-bit immediate offsets. I'll use 20-bits of that for an absolute positive offset from KART base. 1 MiB of easy data. The editor will relink tagged symbols that represent offsets automatically.
|
||||
|
||||

|
||||
|
||||
**8/** @NOTimothyLottes
|
||||
**8/** **@NOTimothyLottes** ^1688281975210041344
|
||||
|
||||
Next will need a collection of rules, how to join the 6 possible symbol arguments together. Rules for example for each of the RDNA2 instruction encodings (VOPC, etc). This reduces to just a 6 entry 5-bit left shift amount associated with each argument.
|
||||
|
||||

|
||||
|
||||
**9/** @NOTimothyLottes
|
||||
**9/** **@NOTimothyLottes** ^1688282613914492928
|
||||
|
||||
But will need a 7th argument, hard coded to a signed 16-bit *4 relative offset as this is how RDNA2 does all it's relative branches. This will be setup inside the editor to auto relink as source is edited.
|
||||
|
||||

|
||||
|
||||
**10/** @NOTimothyLottes
|
||||
**10/** **@NOTimothyLottes** ^1688283094049021952
|
||||
|
||||
Source then is simple, two 128-bit values per 32-bit word in the binary. One to select {RULE, SYMBOLS, RELATIVE BRANCH}, and another for {LABEL, COMMENT}.
|
||||
|
||||

|
||||
|
||||
**11/** @NOTimothyLottes
|
||||
**11/** **@NOTimothyLottes** ^1688284090129084417
|
||||
|
||||
And then the source editor, shows a line per 32-bit value (so VOP3's for example would take 2 lines). So the 'assembler' is deceptively simple, but powerful enough to do everything required to generate GPU binary code. And all the opcode generation is in the data itself :)
|
||||
|
||||

|
||||
|
||||
**12/** @NOTimothyLottes
|
||||
**12/** **@NOTimothyLottes** ^1688284962288537600
|
||||
|
||||
The editor itself will have 3 views {symbol table, rule table, source table}. The editor itself will use 2 copies of everything, so each edit, it's one entry/lane, reading prior state and updating to the new. Dead simple, dead parallel (not necessarily efficient) :)
|
||||
|
||||
**13/** @NOTimothyLottes
|
||||
**13/** **@NOTimothyLottes** ^1688286623375454208
|
||||
|
||||
Yeah, perhaps wildly alien. But for those who grew up with MOD-like trackers (like Impulse Tracker below), the interface will almost feel like home (those had simple {instrument, pattern, arangement} editors, with a very spreadsheet feel).
|
||||
|
||||
|
||||
+12
-12
@@ -26,45 +26,45 @@ parent_post_id: "1688491417109196800"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @BlurBusters
|
||||
**1/** **@BlurBusters** ^1689479056448684032
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Very interesting "crosstalk from voltage inversion" artifact. Some repeating patterns or flicker patterns can trigger crosstalk artifacts too. Behavior varies a lot between TN, IPS, and VA, but all of them have to alternate voltage polarity spatially and temporally.
|
||||
|
||||

|
||||

|
||||
|
||||
**2/** @BlurBusters
|
||||
**2/** **@BlurBusters** ^1689480058950356993
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
Related reads:
|
||||
https://www.lagom.nl/lcd-test/inversion.php
|
||||
https://forums.blurbusters.com/viewtopic.php?t=7539
|
||||
http://www.techmind.org/lcd/#:~:text=Inversion
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1689625885958127616
|
||||
|
||||
@BlurBusters
|
||||
**@BlurBusters**
|
||||
|
||||
I appreciate the links. Came to the same conclusion, for LCDs when doing low scaling like 1:2x2 'CRT' emulation, I'll have to do a stylized blue noise phosphor pattern instead.
|
||||
|
||||
**4/** @Ak4115x
|
||||
**4/** **@Ak4115x** ^1689773902241599488
|
||||
|
||||
@NOTimothyLottes @BlurBusters
|
||||
**@NOTimothyLottes** **@BlurBusters**
|
||||
|
||||
"VCOM inversion" -if wasn't line2line but frame2frame that'd "flicker" instead at half the refresh rate so that's why it's preferred& there's also another peculiarity of this scheme. Worth looking into, spent a few hours afternoon,it's late evening now maybe share another time.
|
||||
|
||||
**5/** @BlurBusters
|
||||
**5/** **@BlurBusters** ^1689815188025839616
|
||||
|
||||
@Ak4115x @NOTimothyLottes
|
||||
**@Ak4115x** **@NOTimothyLottes**
|
||||
|
||||
Inversion algorithm is both spatial and temporal on all of them, regardless of spatial pattern of voltage inversion. Line to line is also frame to frame. (lines swaps voltage polarity in next frame)
|
||||
|
||||
**6/** @Ak4115x
|
||||
**6/** **@Ak4115x** ^1689817477029535744
|
||||
|
||||
@BlurBusters @NOTimothyLottes
|
||||
**@BlurBusters** **@NOTimothyLottes**
|
||||
|
||||
LCOS has singular VCOM there's no pattern to it and no such artifact.
|
||||
|
||||
|
||||
+5
-5
@@ -25,7 +25,7 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1688491417109196800
|
||||
|
||||
CRT emulation on LCDs can be hard. For example it's often easy to generate a pattern that causes a LCD hardware bug. NOT joking. Here is an example on the Steam Deck. The pattern in the window affects the scan (Deck scan is rotated) outside the window.
|
||||
|
||||
@@ -34,22 +34,22 @@ CRT emulation on LCDs can be hard. For example it's often easy to generate a pat
|
||||
|
||||
Branches: [[archive/threads/NOTimothyLottes/2023-08-07-crt-emulation-on-lcds-can-be-hard/2023-08-10-BlurBusters-very-interesting-crosstalk-from-voltage-inversion]]
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1688492237775142912
|
||||
|
||||
The actual pattern is this (it's a 2x1 pixel checker of {G,RB}).
|
||||
|
||||

|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1688493686554849280
|
||||
|
||||
The theory: Deck's 90deg scan results in {(bottom)R, G, B (top)} sub-pixel components. So could alternate {G,RB} only per pixel in a checker pattern to generate a new sub-pixel pattern at a different resolution. In this case trying for 640x400 virtual resolution.
|
||||
|
||||

|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1688494811366506496
|
||||
|
||||
For virtual pixel, shift energy into masked virtual phosphor. So 50% brightness red, would be {100%, 0%} for {in, out} of phosphor pixels. Over 50% one starts to increase non-phosphor pixels until some maximum so mask is still visible, but brightness isn't too compromised.
|
||||
|
||||
**5/** @NOTimothyLottes
|
||||
**5/** **@NOTimothyLottes** ^1688496100460605442
|
||||
|
||||
Of course this is done in linear, so it's energy conserving in theory. But when the panel fails, it breaks down and doesn't work. I see this problem on a bunch of different devices. My personal AMD laptop has the exact same fail case (but rotated differently).
|
||||
+6
-6
@@ -26,21 +26,21 @@ parent_post_id: "1692560907988029769"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @tomcr2100
|
||||
**1/** **@tomcr2100** ^1692650176102449532
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
i am not quite sure what do you mean by subpixel scan? do you override the normal (refresh) scanout process?
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1692659851925606495
|
||||
|
||||
@tomcr2100
|
||||
**@tomcr2100**
|
||||
|
||||
It's like "clear-type" font rendering where if you know the LCD sub-pixel configuration for the RGB components of a pixel, you can do a much better job of computing and outputing the value at the specific RGB sub-pixel element. So i'm doing this for CRT-like emulation on the Deck
|
||||
|
||||
**3/** @tomcr2100
|
||||
**3/** **@tomcr2100** ^1692681369602679237
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
just curious, i started doing something similar, but this year i have focused more on rest&recover. i went with a trilinear style aperture grill approximation, and just allow prim components to leak into the two others.
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1692559239116406864
|
||||
|
||||
SPC: CRT shader on the Deck. This time not doing subpix render. Yet RGB vs BGR order matters still. One way it becomes possible to simulate even spaced aperture grill (removing scan fx), and the other more of the scan effect.
|
||||
|
||||

|
||||

|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1692559798254858259
|
||||
|
||||
Comparing all methods (grille, bad convergence scan, subpix scan)
|
||||
|
||||
@@ -40,13 +40,13 @@ Comparing all methods (grille, bad convergence scan, subpix scan)
|
||||

|
||||

|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1692560907988029769
|
||||
|
||||
The non-subpix scan has 1-pixel separation of RGB (intentional bad convergence) to help hide scaling. The subpix scan uses 1/3-pixel separation (less visible misaligned convergence). Pixel as in output pixel.
|
||||
|
||||
Branches: [[archive/threads/NOTimothyLottes/2023-08-18-spc-crt-shader-on-the-deck/2023-08-18-tomcr2100-i-am-not-quite-sure-what-do-you-mean-by-subpixel]]
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1692565070583136348
|
||||
|
||||
The subpix version is definitely better. Because of the almost 3x doubling of scanline width detail, it just perceptually feels a lot cleaner and easier to reconstruct in the mind.
|
||||
|
||||
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "1692397318471926054"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @Karyuutensei
|
||||
**1/** **@Karyuutensei** ^1692558954935550353
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
How many passes do you need to produce this result?
|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1692566718307021059
|
||||
|
||||
@Karyuutensei
|
||||
**@Karyuutensei**
|
||||
|
||||
1 pass: 12 fetches/outpix, in 2 batches. I use 6 gather4's to grab a 4-wide(x)2-line region for the {R,G,B} channels. Then 6 more fetches to do energy conserving computation of output for each {nearest 2 lines}x{R,G,B} channel based {intensity, position vertically on scan}.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ in_reply_to: ""
|
||||
|
||||
## Thread
|
||||
|
||||
**1/** @NOTimothyLottes
|
||||
**1/** **@NOTimothyLottes** ^1692395128739057844
|
||||
|
||||
SPC: Last CRT shader was broken. Corrected it. It's energy conserving now, and correctly doing sub-pixel line width raster using the individual channels. Cell camera shots below at different zooms.
|
||||
|
||||
@@ -33,16 +33,16 @@ SPC: Last CRT shader was broken. Corrected it. It's energy conserving now, and c
|
||||

|
||||

|
||||
|
||||
**2/** @NOTimothyLottes
|
||||
**2/** **@NOTimothyLottes** ^1692396538629095592
|
||||
|
||||
Each scan line is simulated with only 3 pixels. But you get 9 sub-pixels to play with, so that is where the quality comes from. It reaches 7/8th of the display peak brightness, this compromise was so there is always some amount of perceptual scan effect.
|
||||
|
||||
**3/** @NOTimothyLottes
|
||||
**3/** **@NOTimothyLottes** ^1692397318471926054
|
||||
|
||||
The scan line thickness is adaptive proportional to linear brightness. When the scan thins out it is energy conserving and increases the thin pixel brightness to compensate. When it needs to go bright, it blooms the line. Lines have some overlap in bloom.
|
||||
|
||||
Branches: [[archive/threads/NOTimothyLottes/2023-08-18-spc-last-crt-shader-was-broken/2023-08-18-Karyuutensei-how-many-passes-do-you-need-to-produce-this-result]]
|
||||
|
||||
**4/** @NOTimothyLottes
|
||||
**4/** **@NOTimothyLottes** ^1692397964151378028
|
||||
|
||||
One human perceptual reason CRTs feel like they have more contrast than they do, is because an individual scan line is super bright when in focus. So the black surround feels darker to the mind.
|
||||
+4
-4
@@ -26,15 +26,15 @@ parent_post_id: "1735631826427732305"
|
||||
|
||||
## Branch
|
||||
|
||||
**1/** @SebAaltonen
|
||||
**1/** **@SebAaltonen** ^1735671969947803827
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
They design one API for each separate use case instead of making general purpose flexible SIMD hardware and API for the developers to implement what ever algorithm they need. CPU side got this right. PS2 had correct design, but Nvidia choose hardware T&L for desktop :(
|
||||
|
||||
**2/** @SebAaltonen
|
||||
**2/** **@SebAaltonen** ^1735672402992943607
|
||||
|
||||
@NOTimothyLottes
|
||||
**@NOTimothyLottes**
|
||||
|
||||
I kind of understand hardware T&L back then because it was a new field and programmable hardware didn't exist. But now we have massive amount of wide SIMDs and bandwidth and big caches too. We can do better!
|
||||
|
||||
|
||||
Loaded 100 of 728 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user