[BGM Shader] Batching improvements

Make it easier to change framebuffer size
This commit is contained in:
Luke Hubmayer-Werner 2024-07-15 00:45:10 +09:30
parent 87739d57f4
commit 313872f115
4 changed files with 39 additions and 29 deletions

View File

@ -3,9 +3,8 @@
// Unfortunately, this loses type-checking on [0.0, 1.0] vs [0,255] etc. so a lot of this will involve comments declaring ranges.
shader_type canvas_item;
render_mode blend_premul_alpha;
const int INT_TEX_SIZE = 4096;
const float TEX_SIZE = 4096.0;
const float UV_QUANTIZE = TEX_SIZE;
uniform int INT_TEX_WIDTH = 4096;
uniform vec2 TEX_SIZE = vec2(4096.0, 4096.0);
// I feel like these magic numbers are a bit more intuitive in hex
const float x00FF = float(0x00FF); // 255.0
const float x0100 = float(0x0100); // 256.0
@ -60,16 +59,16 @@ vec2 pack_float_to_int16(float value) {
return vec2(LSB, MSB);
}
vec4 test_writeback(sampler2D tex, vec2 uv) {
// Test importing and exporting the samples,
// and exporting a value derived from the UV
vec4 output;
float sample_1 = rescale_int16(unpack_int16(texture(tex, uv).xw));
float sample_2 = rescale_int16(dot(trunc(uv*TEX_SIZE), vec2(1.0, TEX_SIZE)));
output.xy = pack_float_to_int16(sample_1);
output.zw = pack_float_to_int16(sample_2);
return output;
}
// vec4 test_writeback(sampler2D tex, vec2 uv) {
// // Test importing and exporting the samples,
// // and exporting a value derived from the UV
// vec4 output;
// float sample_1 = rescale_int16(unpack_int16(texture(tex, uv).xw));
// float sample_2 = rescale_int16(dot(trunc(uv*TEX_SIZE), vec2(1.0, TEX_SIZE)));
// output.xy = pack_float_to_int16(sample_1);
// output.zw = pack_float_to_int16(sample_2);
// return output;
// }
// ============================================================= LOGIC =============================================================
@ -153,7 +152,6 @@ float get_instrument_sample(float instrument_index, float note, float t) {
const int NUM_CHANNELS = 8;
const int MAX_CHANNEL_NOTE_EVENTS = 2048;
const int NUM_CHANNEL_NOTE_PROBES = 11; // log2(MAX_CHANNEL_NOTE_EVENTS)
// uniform sampler2D midi_events : hint_normal;
uniform vec2 midi_events_size = vec2(2048.0, 32.0);
vec4 get_midi_texel(sampler2D tex, float x, float y) {
return texture(tex, vec2(x, y)/midi_events_size).xyzw;
@ -211,8 +209,8 @@ vec4 render_song(sampler2D tex, int smp) {
void fragment() {
// GLES2
vec2 uv = vec2(UV.x, 1.0-UV.y);
// uv = (trunc(uv*UV_QUANTIZE)+0.5)/UV_QUANTIZE;
// uv = (trunc(uv*TEX_SIZE)+0.5)/TEX_SIZE;
// COLOR.xyzw = test_writeback(TEXTURE, uv);
ivec2 xy = ivec2(trunc(uv*TEX_SIZE));
COLOR.xyzw = render_song(TEXTURE, xy.x + (xy.y*INT_TEX_SIZE));
COLOR.xyzw = render_song(TEXTURE, xy.x + (xy.y*INT_TEX_WIDTH));
}

View File

@ -4,8 +4,9 @@ const INPUT_TEX_WIDTH := 2048
const INPUT_FORMAT := Image.FORMAT_RGBA8 # Image.FORMAT_LA8
const INPUT_BYTES_PER_TEXEL := 4 # 2
const OUTPUT_BYTES_PER_TEXEL := 4
const OUTPUT_WIDTH := 4096
const OUTPUT_HEIGHT := 4096
const OUTPUT_FRAMEBUFFER_SIZE := Vector2(4096, 4096)
const OUTPUT_WIDTH := int(OUTPUT_FRAMEBUFFER_SIZE.x)
const OUTPUT_HEIGHT := int(OUTPUT_FRAMEBUFFER_SIZE.y)
const QUAD_COLOR := PoolColorArray([Color.white, Color.white, Color.white, Color.white])
var viewport: Viewport
var render_queue: Array # of Images
@ -21,19 +22,27 @@ func _ready() -> void:
self.waiting_for_viewport = []
self.done_first_draw = false
self.current_textures = []
self.get_parent().size = OUTPUT_FRAMEBUFFER_SIZE
self.material.set_shader_param('OUTPUT_FRAMEBUFFER_SIZE', OUTPUT_FRAMEBUFFER_SIZE)
self.material.set_shader_param('INT_OUTPUT_WIDTH', OUTPUT_WIDTH)
func push_image(img: Image, uv_rows: int = 4096, desc: String = '') -> void:
self.render_queue.append([img, uv_rows, desc])
func push_image(img: Image, target_samples: int = -1, desc: String = '') -> void:
var target_rows = ceil(target_samples/float(OUTPUT_WIDTH))
if target_samples <= 0:
target_rows = int(img.get_size().y)
self.render_queue.append([img, target_rows, desc])
func push_bytes(data: PoolByteArray, uv_rows: int = 4096, desc: String = '') -> void:
# print(data.subarray(0, 15))
func push_bytes(data: PoolByteArray, target_samples: int = -1, desc: String = '') -> void:
var rows = int(pow(2, ceil(log((len(data)/INPUT_BYTES_PER_TEXEL) / INPUT_TEX_WIDTH)/log(2))))
var target_length = rows * INPUT_BYTES_PER_TEXEL * INPUT_FORMAT
while len(data) < target_length: # This is inefficient, but this function should be called with pre-padded data anyway
data.append(0)
var image := Image.new()
image.create_from_data(INPUT_TEX_WIDTH, rows, false, INPUT_FORMAT, data)
self.render_queue.append([image, uv_rows, desc])
var target_rows = ceil(target_samples/float(OUTPUT_WIDTH))
if target_samples <= 0:
target_rows = rows
self.render_queue.append([image, target_rows, desc])
func _process(_delta) -> void:
update()
@ -67,11 +76,10 @@ func _draw() -> void:
self.current_textures.append(ImageTexture.new())
var tex: ImageTexture = self.current_textures[i]
tex.create_from_image(image_and_uv_rows_and_desc[0], 0)
# self.material.set_shader_param('midi_events', tex)
self.material.set_shader_param('midi_events_size', tex.get_size())
var y_top: int = OUTPUT_HEIGHT - rows_drawn
var y_bot: int = y_top + draw_rows
var uv_inv_v: float = 1 - (draw_rows / float(OUTPUT_WIDTH))
var uv_inv_v: float = 1 - (draw_rows / OUTPUT_FRAMEBUFFER_SIZE.y)
var uvs := PoolVector2Array([Vector2(0, uv_inv_v), Vector2(1, uv_inv_v), Vector2(1, 1), Vector2(0, 1)])
var points := PoolVector2Array([Vector2(0, y_top), Vector2(OUTPUT_WIDTH, y_top), Vector2(OUTPUT_WIDTH, y_bot), Vector2(0, y_bot)])
draw_primitive(points, QUAD_COLOR, uvs, tex)

View File

@ -180,14 +180,13 @@ func queue_prerender_bgm(bgm_id: int) -> void:
var data = data_and_target_time_and_loops[0]
var target_time = data_and_target_time_and_loops[1]
var target_samples = target_time * 32000
var target_rows = ceil(target_samples/4096.0)
var bgm_key := 'BGM%02d'%bgm_id
audio_renderer.push_bytes(data, target_rows, bgm_key)
audio_renderer.push_bytes(data, target_samples, bgm_key)
self.prerendered_bgm_start_and_end_loops[bgm_key] = data_and_target_time_and_loops[2]
func render_all_bgm(bgms_to_render: int = 64) -> void:
func render_all_bgm(bgms_to_render: int = 70) -> void:
self.initialize_instrument_texture()
for bgm_id in bgms_to_render:
self.queue_prerender_bgm(bgm_id)
@ -199,6 +198,7 @@ func render_all_bgm(bgms_to_render: int = 64) -> void:
const save_prerendered_audio := false
func _get_prerendered_audio():
audio_renderer.get_result()
var tracks_rendered := ''
while audio_renderer.result_queue:
var result = audio_renderer.result_queue.pop_front()
var desc = result[0]
@ -216,11 +216,13 @@ func _get_prerendered_audio():
var error = rendered_audio.save_to_wav('output/rendered_%s.wav'%desc)
print('@%dms - Saved render of %s (error code %s)' % [get_ms(), desc, globals.ERROR_CODE_STRINGS[error]])
else:
print('@%dms - Rendered %s without saving' % [get_ms(), desc])
# print('@%dms - Rendered %s without saving' % [get_ms(), desc])
tracks_rendered = '%s, %s'%[tracks_rendered, desc]
if self.queued_bgm_playback == desc:
self.audio_player.stream = rendered_audio
self.audio_player.play()
self.queued_bgm_playback = ''
print('@%dms - Rendered %s without saving' % [get_ms(), tracks_rendered.right(2)])
func get_shader_test_pattern() -> PoolByteArray:

View File

@ -6,6 +6,8 @@
[sub_resource type="ShaderMaterial" id=2]
shader = ExtResource( 4 )
shader_param/INT_TEX_WIDTH = 4096
shader_param/TEX_SIZE = Vector2( 4096, 4096 )
shader_param/instrument_samples_size = Vector2( 2048, 128 )
shader_param/reference_note = 71.0
shader_param/output_mixrate = 32000.0