You can pass data from a compute shader to other shaders without needing to sync to the CPU. This is what a Texture2DRD can be used for. Put a sampler2D uniform in a material’s shader, set it to a Texture2DRD in the shader parameters section, and assign it the RID of the texture your compute shader writes to, which works if the compute shader is on the main render thread.
The stuff about not running compute shaders on the main render thread is more about for when you’re doing longer-running compute-heavy tasks that aren’t immediately relevant to your next frame, but you can totally use them for real-time purposes, before the rest of the render pipeline.
This demo project is what I’ve been referencing when trying this stuff out. They’re using spatial shaders but it works with CanvasItem shaders too.
In any case, writing to viewports might be a bit of a clunky workflow but it’s a perfectly valid approach. Compute shaders come with their own issues, tbh, setting them up can be verbose and finicky with quite a bit of boilerplate.