I'm struggling to figure out RenderingServer calls on a 2D game in Godot 4.2. I've exhausted Google and the documentation, so I'm hoping the community can help.

What I'm trying to achieve

Given there is currently no depth buffer in 2D, I'm creating it myself. This involves rendering the world twice, setting a global variable RENDER_PASS as 0 for the depth pass and 1 for the game view. Each sprite has a custom shader; if global uniform RENDER_PASS is 0, the shader renders the sprite in a solid color based on the sprite's worldY position; if RENDER_PASS is 1 then the sprite is rendered in color as normal. The output of render pass 0 should be a grayscale image representing depth.

I first attempted this with viewport nodes in the tree, and it worked albeit flickering between the two frames. So I know the creation of the depth image works as intended, but I need manual control over the rendering to perform both renders within the same frame, hence a migration to RenderingServer. Here's what the depth frame looked like (the black is a TileMap) :-

As a side note, I need the depth texture to compare position of lights within the scene for shadow calculation, after hitting the (Vulkan) limit of lights per surface with Godot's Light2D (even after increasing it).

What I'm struggling with

I can't determine which RenderingServer commands to use, and whether I need to copy world2D and global transforms over to the new viewports. Right now the viewports aren't rendering anything; the game just runs behind a black screen. I'm also not convinced I can pass the RID of the depthTexture directly into the shader even though the documentation suggests I can. All funcs are being entered as and when expected.

The solution avoids copying data from the GPU to CPU per frame to avoid killing performance. Hence the use of RIDs and not copying texture data.

Code

# non-ready vars
var camera: Camera2D

var viewportDepth: RID
var viewportGame: RID
var depthTexture: RID
var viewSize: Vector2i
var isInitialized: bool

static var _instance: RenderManager = null

static var instance: RenderManager :
	get:
		return _instance

func _ready():
	Debug.logInfo("RenderManager::_ready()")
	_instance = self if _instance == null else _instance

	viewSize = get_viewport().size # which is 3840x2054

func _process(delta: float) -> void:
	if not isInitialized:
		return

	RenderingServer.call_on_render_thread(onRender)
	
func initialize() -> void:
	camera = WorldManager.instance.ui.camera
	
	viewportDepth = RenderingServer.viewport_create()
	RenderingServer.viewport_attach_camera(viewportDepth, camera)
	RenderingServer.viewport_set_size(viewportDepth, viewSize.x, viewSize.y)
	RenderingServer.viewport_set_clear_mode(viewportDepth, RenderingServer.VIEWPORT_CLEAR_ALWAYS)
	RenderingServer.viewport_set_update_mode(viewportDepth, RenderingServer.VIEWPORT_UPDATE_ALWAYS)
	
	viewportGame = RenderingServer.viewport_create()
	RenderingServer.viewport_attach_camera(viewportGame, camera)
	RenderingServer.viewport_set_size(viewportGame, viewSize.x, viewSize.y)
	RenderingServer.viewport_set_clear_mode(viewportGame, RenderingServer.VIEWPORT_CLEAR_ALWAYS)
	RenderingServer.viewport_set_update_mode(viewportGame, RenderingServer.VIEWPORT_UPDATE_ALWAYS)
	RenderingServer.viewport_set_render_direct_to_screen(viewportGame, true)
	RenderingServer.viewport_set_active(viewportGame, true)
	
	RenderingServer.render_loop_enabled = false

	isInitialized = true

func onRender() -> void:
	RenderingServer.global_shader_parameter_set("RENDER_PASS", 0)
	RenderingServer.viewport_set_active(viewportDepth, true)
	# RenderingServer.viewport_set_active(viewportGame, false)
	RenderingServer.force_draw(false)
	depthTexture = RenderingServer.viewport_get_texture(viewportDepth) # passed into shader elsewhere as set_shader_parameter("depth_texture", RenderManager.instance.depthTexture)
	
	RenderingServer.global_shader_parameter_set("RENDER_PASS", 1)
	RenderingServer.viewport_set_active(viewportDepth, false)
	# RenderingServer.viewport_set_active(viewportGame, true)
	RenderingServer.force_draw(false)
	RenderingServer.viewport_attach_to_screen(viewportGame, Rect2(0, 0, viewSize.x, viewSize.y))

This is a stab in the dark, I don't see a call to attach a canvas like the docs say if your are doing a custom render.

@pennyloafers I've taken a different route for now, and once I have it fully working I'll try using RenderingServer again hopefully with a deeper understanding.