Godot Version 4.3 stable
I’m new to compute shaders in Godot, only with a slight amount of experience in Unity compute shaders. I’m trying to use a compute shader to calculate some outlines on an image, but i’m not even close to that currently. I don’t understand what i’m doing or what the engine is doing.
So just to get a little hold of it, i am now trying to count the amount of red pixels in an image. But since i want to parse data to an array of vector3’s for what i really need, i have all my output parameters in a single buffer. But it’s like the shader can’t read a variable from the buffer.
(In the GLSL shader below): I don’t think it actually increments the nCells value, why?
I want to mention that the code has gotten gradually worse, as well as my sanity. So that’s why the functions are called “createThing” and “doThing”.
GLSL code ↓:
#[compute]
#version 430
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, std430) buffer outputBuffer {
ivec3 cells[100];
int nCells;
} outBuf;
layout(set = 0, binding = 1) uniform sampler2D tex;
void main() {
if (texture(tex, vec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y)).r > 0.5) {
atomicAdd(outBuf.cells[outBuf.nCells].z, 1);
atomicAdd(outBuf.nCells, 1);
}
}
If it matters, here’s the GDscript code:
extends Node2D
@export var texture: Texture2D
var rd: RenderingDevice
var shader
var pipeline
var buffer
var buffer_uniform
var v_tex
var samp
var tex_uniform
var uniform_set
# Called when the node enters the scene tree for the first time.
func doThing() -> void:
var compute_list = rd.compute_list_begin()
rd.compute_list_bind_compute_pipeline(compute_list, pipeline)
rd.compute_list_bind_uniform_set(compute_list, uniform_set, 0)
rd.compute_list_dispatch(compute_list, texture.get_size().x/8, texture.get_size().y/8, 1)
rd.compute_list_end()
rd.submit()
rd.sync()
var byte_data = rd.buffer_get_data(buffer)
var output := byte_data.to_int32_array()
print("Output as int array: ", output)
var nCellsOut = output[output.size() - 1]
print("Number of cells: ", nCellsOut)
var cellsArray = PackedVector3Array([])
cellsArray.resize(100)
cellsArray = cellsArray.to_byte_array()
var nCells = PackedInt32Array([0]).to_byte_array()
var pbb = cellsArray+nCells
rd.buffer_update(buffer, 0, pbb.size(), pbb)
func createThing() -> void:
rd = RenderingServer.create_local_rendering_device()
var shader_file = load("res://assets/scenes/WorldGenerator/outlines.glsl")
var shader_spirv = shader_file.get_spirv()
shader = rd.shader_create_from_spirv(shader_spirv)
pipeline = rd.compute_pipeline_create(shader)
var cellsArray = PackedVector3Array([])
cellsArray.resize(100)
cellsArray = cellsArray.to_byte_array()
var nCells = PackedInt32Array([0]).to_byte_array()
var pba = cellsArray+nCells
buffer = rd.storage_buffer_create(pba.size(),pba)
buffer_uniform = RDUniform.new()
buffer_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_STORAGE_BUFFER
buffer_uniform.binding = 0
buffer_uniform.add_id(buffer)
var img = texture.get_image()
var img_pba = img.get_data()
var fmt = RDTextureFormat.new()
fmt.width = texture.get_size().x
fmt.height = texture.get_size().y
fmt.usage_bits = RenderingDevice.TEXTURE_USAGE_CAN_UPDATE_BIT | RenderingDevice.TEXTURE_USAGE_SAMPLING_BIT
fmt.format = RenderingDevice.DATA_FORMAT_R8G8B8A8_SRGB
v_tex = rd.texture_create(fmt, RDTextureView.new(), [img_pba])
var samp_state = RDSamplerState.new()
samp_state.unnormalized_uvw = true
samp = rd.sampler_create(samp_state)
tex_uniform = RDUniform.new()
tex_uniform.uniform_type = RenderingDevice.UNIFORM_TYPE_SAMPLER_WITH_TEXTURE
tex_uniform.binding = 1
tex_uniform.add_id(samp)
tex_uniform.add_id(v_tex)
uniform_set = rd.uniform_set_create([buffer_uniform,tex_uniform], shader, 0)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _ready() -> void:
createThing()
func _process(delta: float) -> void:
if Input.is_action_just_pressed("ui_accept"):
var time = Time.get_ticks_msec()
for i in 1:
doThing()
print("Done in ",str(Time.get_ticks_msec()-time)," milliseconds")