NZDN 2024: Day 4 – Shaders + HW decoding working

It took some time, but with the help of the Discord members I was able to get everything working properly without issues (on my machine at least). The test builds are shared to the testers so now it’s waiting for feedback, if everybody gives a green light, I’ll be releasing version 4 of GDE GoZen. 😀

The shaders

The shaders are rather simple and really nothing complicated, the shader for converting YUV420P to RGB:

shader_type canvas_item;

uniform sampler2D y_data;
uniform sampler2D u_data;
uniform sampler2D v_data;

void fragment() {
	vec2 uv = UV;

    float Y = texture(y_data, uv).r;
    float U = texture(u_data, uv).r - 0.5;
    float V = texture(v_data, uv).r - 0.5;

    float R = Y + 1.402 * V;
    float G = Y - 0.344136 * U - 0.714136 * V;
    float B = Y + 1.772 * U;

    COLOR = vec4(R, G, B, 1.0);
}

The shader for the hardware pixel format NV12:

shader_type canvas_item;

uniform sampler2D y_data;
uniform sampler2D uv_data;

void fragment() {
	vec2 uv = UV;

    float Y = texture(y_data, uv).r;
    float U = texture(uv_data, uv).r - 0.5;
    float V = texture(uv_data, uv).g - 0.5;

    float R = Y + 1.402 * V;
    float G = Y - 0.344136 * U - 0.714136 * V;
    float B = Y + 1.772 * U;

    COLOR = vec4(R, G, B, 1.0);
}

The most difficult part was figuring out how to send the data to the shader and I got stuck on this part for some time, all because of ONE thing I did wrong. Send a TextureImage and not an Image … this took soo long to solve and kept me up at night. ^^”

The GDScript code:

func _set_frame_image() -> void:
	if hardware_conversion:
		if video.get_pixel_format() == "nv12":
			_shader_material.set_shader_parameter("y_data", ImageTexture.create_from_image(Image.create_from_data(_resolution.x, _resolution.y, false, Image.FORMAT_R8, video.get_y_data())))
			_shader_material.set_shader_parameter("uv_data", ImageTexture.create_from_image(Image.create_from_data(_uv_resolution.x, _uv_resolution.y, false, Image.FORMAT_RG8, video.get_u_data())))
		else:
			_shader_material.set_shader_parameter("y_data", ImageTexture.create_from_image(Image.create_from_data(_resolution.x, _resolution.y, false, Image.FORMAT_L8, video.get_y_data())))
			_shader_material.set_shader_parameter("u_data", ImageTexture.create_from_image(Image.create_from_data(_uv_resolution.x, _uv_resolution.y, false, Image.FORMAT_R8, video.get_u_data())))
			_shader_material.set_shader_parameter("v_data", ImageTexture.create_from_image(Image.create_from_data(_uv_resolution.x, _uv_resolution.y, false, Image.FORMAT_R8, video.get_v_data())))
	else:
		texture_rect.texture.set_image(video.get_frame_image())

So I’m still taking in mind the normal software conversion as for some people their GPU just won’t be able to do it, or the hardware pixel format of their GPU may not have any support yet. I do intend on adding pixel format support if there would be need for this in the future.

Tomorrow’s plans

As for tomorrow, I’ll finally tackle audio encoding as this is something I have not been able to figure out yet. I did find some interesting things in the Godot wiki which I should try, but that will be for tomorrow, I may do a live-stream tomorrow to see if I can figure this out or not. If not … then I’ll have a difficult couple of day’s ahead of me hahah. But I am running one day ahead of schedule, which feels good. ^^

As always a big thank you to all my ko-fi supporters, really can’t thank you all enough for the support, can’t do this without all of you.