Compute Shading gradually builds up memory

4.2.1

Not sure whats going on. Im running a GLSL compute shader per this document:

I have a very basic script that generates a PackedByteArray that’s 4096 bytes large, and then stores that into a dictionary of 2086 different packed byte arrays that each represent a chunk (this is a Minecraft clone)

I planned to feed the bytes into a compute shader to do some basic bit operations in parallel and update the bytes in my dictionary. I’m sure the GLSL is working properly as I’ve tested it and it works at an individual chunk level. But whenever I try to iterate through more than 50 chunks it’ll crash and give me a RAM error. I can see too that my memory is slowly building up with each iteration. I don’t understand, why is my memory increasing?

I’ve tried clearing the compute_shader using this .queue_free(), and even implemented a function inside the compute shader script that’s supposedly meant to clear up the resources:

func _cleanup_resources():
	print("Cleaning up resources.")
	if buffer.is_valid():
		RenderingServer.free_rid(buffer)
		buffer = RID()
	if uniform_set.is_valid():
		RenderingServer.free_rid(uniform_set)
		uniform_set = RID()
	if pipeline_resource_ID.is_valid():
		RenderingServer.free_rid(pipeline_resource_ID)
		pipeline_resource_ID = RID()

Here are the two scripts that I’m working with:

Compute Shader:

extends Node

class_name Compute_Shader

var rendering_device
var shader_file
var spirv_language_translator
var shader
var input_bytes : PackedByteArray
var buffer : RID
var uniform : RDUniform
var uniform_set : RID
var pipeline_resource_ID : RID
var compute_list

func _init(file_path : String, input_byte_array : PackedByteArray, workgroup : Vector3):
	input_bytes = input_byte_array
	rendering_device = RenderingServer.create_local_rendering_device()
	
	if not _load_shader_from_file(file_path):
		push_error("Failed to load shader from file.")
		return
	
	_initialize_input(workgroup)
	
func _load_shader_from_file(file_path : String) -> bool:
	shader_file = load(file_path)
	if not shader_file:
		return false
	
	spirv_language_translator = shader_file.get_spirv()
	if not spirv_language_translator:
		return false
	
	shader = rendering_device.shader_create_from_spirv(spirv_language_translator)
	if not shader:
		return false
	
	return true

func _initialize_input(workgroup):
	buffer = rendering_device.storage_buffer_create(input_bytes.size(), input_bytes)

	uniform = RDUniform.new()
	uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
	uniform.binding = 0
	uniform.add_id(buffer)
	uniform_set = rendering_device.uniform_set_create([uniform], shader, 0)
	
	_define_compute_pipeline(workgroup, 0)
	
func _define_compute_pipeline(workgroup : Vector3, index : int):
	pipeline_resource_ID = rendering_device.compute_pipeline_create(shader)
	
	compute_list = rendering_device.compute_list_begin()
	rendering_device.compute_list_bind_compute_pipeline(compute_list, pipeline_resource_ID)
	rendering_device.compute_list_bind_uniform_set(compute_list, uniform_set, index)
	rendering_device.compute_list_dispatch(compute_list, workgroup.x, workgroup.y, workgroup.z)
	rendering_device.compute_list_end()

func get_output() -> PackedByteArray:
	_execute_compute_shader()
	return rendering_device.buffer_get_data(buffer)

func _execute_compute_shader():
	rendering_device.submit()
	rendering_device.sync()  


func _cleanup_resources():
	print("Cleaning up resources.")
	if buffer.is_valid():
		RenderingServer.free_rid(buffer)
		buffer = RID()
	if uniform_set.is_valid():
		RenderingServer.free_rid(uniform_set)
		uniform_set = RID()
	if pipeline_resource_ID.is_valid():
		RenderingServer.free_rid(pipeline_resource_ID)
		pipeline_resource_ID = RID()

Test scene

extends Node3D  

var shader_path = "res://Scripts/ComputeShaders/face_info_compute_shader.glsl"

func _ready():
	pass

func on_island_generation_complete():
	print("Island generation complete signal received")
	test_with_limited_iterations(100)

func test_with_limited_iterations(iterations: int):
	var count = 0
	for chunk_key in Global.chunks.keys():
		if count >= iterations:
			break
		if not run_compute_shader(chunk_key):
			#print("Failed at chunk key: ", chunk_key)
			break
		count += 1
		print("count: ", count)

		print("Memory usage after chunk ", chunk_key, ": ", OS.get_static_memory_usage())
	print("Finished processing. Total chunks processed: ", count)

func run_compute_shader(chunk_key: Vector3) -> bool:
	var input_bytes = Global.chunks[chunk_key].get_block_values()

	var workgroup = Vector3(16, 1, 1)
	var compute_shader = Compute_Shader.new(shader_path, input_bytes, workgroup)

	var output_data = compute_shader.get_output()
	if output_data.size() != 4096:
		
		compute_shader._cleanup_resources()
		compute_shader.queue_free()
		return false


	compute_shader._cleanup_resources()
	compute_shader.queue_free()

	return true

What could I be doing wrong? Im very new at this, and just pulling my hair trying to make sense of it all.

I solved my problem.

The issue was I wasn’t clearing the rendering device properly:

func cleanup_resources():
	
	rendering_device.free_rid(buffer)
	buffer = RID()
	rendering_device.free_rid(uniform_set)
	uniform_set = RID()
	rendering_device.free_rid(pipeline_resource_ID)
	pipeline_resource_ID = RID()
	rendering_device.free_rid(shader)
	compute_list = RID()
	
	
	rendering_device.free()
	rendering_device = null