Reenable threaded loading
This commit is contained in:
parent
8df54eda28
commit
ee2a207c30
|
@ -3,7 +3,7 @@ extends Node
|
||||||
signal loading_stage_updated(stage) # String
|
signal loading_stage_updated(stage) # String
|
||||||
signal rom_loaded
|
signal rom_loaded
|
||||||
|
|
||||||
const THREADED_LOADING := false
|
var THREADED_LOADING := OS.can_use_threads()
|
||||||
|
|
||||||
const STRUCT := preload('res://scripts/struct.gd')
|
const STRUCT := preload('res://scripts/struct.gd')
|
||||||
const STRUCT_SNES := preload('res://scripts/loaders/snes/structs.gd')
|
const STRUCT_SNES := preload('res://scripts/loaders/snes/structs.gd')
|
||||||
|
@ -21,7 +21,7 @@ var rom_snes := File.new()
|
||||||
var snes_data := {}
|
var snes_data := {}
|
||||||
var snes_bytes: PoolByteArray
|
var snes_bytes: PoolByteArray
|
||||||
var snes_buffer: StreamPeerBuffer
|
var snes_buffer: StreamPeerBuffer
|
||||||
var thread: Thread
|
var threads: Array # Thread
|
||||||
|
|
||||||
func load_snes_structs(buffer: StreamPeerBuffer) -> Dictionary:
|
func load_snes_structs(buffer: StreamPeerBuffer) -> Dictionary:
|
||||||
var data := {}
|
var data := {}
|
||||||
|
@ -64,8 +64,10 @@ func load_snes_structs(buffer: StreamPeerBuffer) -> Dictionary:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
var load_start_tick := 0
|
var load_start_tick := 0
|
||||||
func _on_loader_loading_stage_updated(stage: String, loader: String) -> void:
|
func _on_loader_loading_stage_updated(stage: String, loader: String, threaded: bool = false) -> void:
|
||||||
var output := '%s: %s' % [loader, stage]
|
var output := '%s: %s' % [loader, stage]
|
||||||
|
if threaded:
|
||||||
|
output += ' (background thread)'
|
||||||
#print(Time.get_time_string_from_system() + ' ' + output)
|
#print(Time.get_time_string_from_system() + ' ' + output)
|
||||||
print('@%dms - %s' % [Time.get_ticks_msec() - load_start_tick, output])
|
print('@%dms - %s' % [Time.get_ticks_msec() - load_start_tick, output])
|
||||||
emit_signal('loading_stage_updated', output)
|
emit_signal('loading_stage_updated', output)
|
||||||
|
@ -73,9 +75,25 @@ func _on_loader_loading_stage_updated(stage: String, loader: String) -> void:
|
||||||
if scenetree:
|
if scenetree:
|
||||||
yield(scenetree, 'idle_frame')
|
yield(scenetree, 'idle_frame')
|
||||||
|
|
||||||
func _load_snes_audio(data_and_buffer: Array):
|
func _unpack_threaded_args(obj_method_args: Array) -> void:
|
||||||
yield(_on_loader_loading_stage_updated('Loading sound samples and music data', 'SoundLoader'), 'completed')
|
# Thread.start() only passes one argument, totally insane API deficiency
|
||||||
SoundLoader.parse_rom(data_and_buffer[0], data_and_buffer[1])
|
var obj: Object = obj_method_args[0]
|
||||||
|
var method: String = obj_method_args[1]
|
||||||
|
var args: Array = obj_method_args[2]
|
||||||
|
obj.callv(method, args)
|
||||||
|
|
||||||
|
func _load_stage(stage: String, loader: String, obj: Object, method: String, args: Array, threaded_loading: bool = false) -> void:
|
||||||
|
yield(_on_loader_loading_stage_updated(stage, loader, threaded_loading), 'completed')
|
||||||
|
if threaded_loading:
|
||||||
|
var thread := Thread.new()
|
||||||
|
match thread.start(self, '_unpack_threaded_args', [obj, method, args]):
|
||||||
|
ERR_CANT_CREATE:
|
||||||
|
print_debug('Failed to create thread for loading %s: %s'%[loader, stage])
|
||||||
|
OS.quit(1)
|
||||||
|
OK:
|
||||||
|
self.threads.append(thread)
|
||||||
|
else:
|
||||||
|
obj.callv(method, args)
|
||||||
|
|
||||||
func load_snes_rom_from_bytes(bytes: PoolByteArray) -> void:
|
func load_snes_rom_from_bytes(bytes: PoolByteArray) -> void:
|
||||||
load_start_tick = Time.get_ticks_msec()
|
load_start_tick = Time.get_ticks_msec()
|
||||||
|
@ -85,32 +103,32 @@ func load_snes_rom_from_bytes(bytes: PoolByteArray) -> void:
|
||||||
self.snes_buffer = StreamPeerBuffer.new()
|
self.snes_buffer = StreamPeerBuffer.new()
|
||||||
self.snes_buffer.data_array = bytes
|
self.snes_buffer.data_array = bytes
|
||||||
|
|
||||||
|
# Thread anything we don't need structs loaded for
|
||||||
|
# Give threads their own buffer, avoid file pointer conflicts
|
||||||
|
self._load_stage('Loading strings', 'StringLoader', StringLoader, 'load_snes_rom', [self.snes_buffer.duplicate()], THREADED_LOADING)
|
||||||
|
|
||||||
|
# Most loaders depend on Structs being loaded, this is a bottleneck
|
||||||
yield(_on_loader_loading_stage_updated('Loading struct definitions', 'StructLoader'), 'completed')
|
yield(_on_loader_loading_stage_updated('Loading struct definitions', 'StructLoader'), 'completed')
|
||||||
self.snes_data = load_snes_structs(self.snes_buffer)
|
self.snes_data = load_snes_structs(self.snes_buffer.duplicate())
|
||||||
if THREADED_LOADING:
|
|
||||||
# Give this its own buffer if threaded, avoid file pointer conflicts
|
self._load_stage('Loading sounds', 'SoundLoader', SoundLoader, 'parse_rom', [self.snes_data, self.snes_buffer.duplicate()], THREADED_LOADING)
|
||||||
var _thread_error = thread.start(self, '_load_snes_audio', [self.snes_data, self.snes_buffer.duplicate()])
|
self._load_stage('Parsing music data', 'MusicManager', MusicManager, 'load_snes_rom', [self.snes_buffer.duplicate()], THREADED_LOADING)
|
||||||
else:
|
|
||||||
yield(self._load_snes_audio([self.snes_data, self.snes_buffer]), 'completed')
|
|
||||||
yield(_on_loader_loading_stage_updated('Loading strings', 'StringLoader'), 'completed')
|
|
||||||
yield(StringLoader.load_snes_rom(self.snes_buffer, true), 'completed')
|
|
||||||
|
|
||||||
SpriteLoader.reset()
|
SpriteLoader.reset()
|
||||||
|
self._load_stage('Loading sprites', 'SpriteLoader', SpriteLoader, 'load_from_structs', [self.snes_data])
|
||||||
|
self._load_stage('Loading enemy battle sprites', 'SpriteLoader', SpriteLoader, 'load_enemy_battle_sprites', [self.snes_data, self.snes_buffer])
|
||||||
|
self._load_stage('Loading battle backgrounds', 'SpriteLoader', SpriteLoader, 'load_battle_bgs', [self.snes_data, self.snes_buffer])
|
||||||
|
|
||||||
yield(_on_loader_loading_stage_updated('Loading sprites', 'SpriteLoader'), 'completed')
|
self._load_stage('Loading map data', 'MapLoader', MapLoader, 'load_snes_rom', [self.snes_data, self.snes_buffer])
|
||||||
SpriteLoader.load_from_structs(self.snes_data)
|
|
||||||
yield(_on_loader_loading_stage_updated('Loading enemy battle sprites', 'SpriteLoader'), 'completed')
|
for thread in self.threads:
|
||||||
SpriteLoader.load_enemy_battle_sprites(self.snes_data, self.snes_buffer)
|
thread.wait_to_finish()
|
||||||
yield(_on_loader_loading_stage_updated('Loading battle backgrounds', 'SpriteLoader'), 'completed')
|
self.threads.clear()
|
||||||
SpriteLoader.load_battle_bgs(self.snes_data, self.snes_buffer)
|
|
||||||
yield(_on_loader_loading_stage_updated('Loading map data', 'MapLoader'), 'completed')
|
|
||||||
MapLoader.load_snes_rom(self.snes_data, self.snes_buffer)
|
|
||||||
yield(_on_loader_loading_stage_updated('Parsing music data', 'MusicManager'), 'completed')
|
|
||||||
MusicManager.load_snes_rom(self.snes_buffer)
|
|
||||||
yield(_on_loader_loading_stage_updated('Finished loading!', 'RomLoader'), 'completed')
|
yield(_on_loader_loading_stage_updated('Finished loading!', 'RomLoader'), 'completed')
|
||||||
emit_signal('rom_loaded')
|
emit_signal('rom_loaded')
|
||||||
var music = load('res://scripts/loaders/snes/music_ff5.gd').new()
|
# var music = load('res://scripts/loaders/snes/music_ff5.gd').new()
|
||||||
music.disassemble_sfx(self.snes_buffer)
|
# music.disassemble_sfx(self.snes_buffer)
|
||||||
|
|
||||||
func load_snes_rom(filename: String) -> void:
|
func load_snes_rom(filename: String) -> void:
|
||||||
var error := rom_snes.open(filename, File.READ)
|
var error := rom_snes.open(filename, File.READ)
|
||||||
|
@ -140,8 +158,6 @@ func load_psx_image(filename: String):
|
||||||
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
if THREADED_LOADING:
|
|
||||||
thread = Thread.new()
|
|
||||||
structdefs.merge(STRUCT.get_base_structarraytypes())
|
structdefs.merge(STRUCT.get_base_structarraytypes())
|
||||||
STRUCT.parse_struct_definitions_from_tsv_filename('res://data/structs_SNES_stubs.tsv', structdefs)
|
STRUCT.parse_struct_definitions_from_tsv_filename('res://data/structs_SNES_stubs.tsv', structdefs)
|
||||||
STRUCT.parse_struct_definitions_from_tsv_filename('res://data/5/structs/SNES_stubs.tsv', structdefs)
|
STRUCT.parse_struct_definitions_from_tsv_filename('res://data/5/structs/SNES_stubs.tsv', structdefs)
|
||||||
|
@ -154,6 +170,5 @@ func _ready():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
pass
|
for thread in self.threads:
|
||||||
if THREADED_LOADING:
|
|
||||||
thread.wait_to_finish()
|
thread.wait_to_finish()
|
||||||
|
|
|
@ -98,10 +98,11 @@ func _load_block(block_name: String, buffer: StreamPeerBuffer, is_RPGe: bool = f
|
||||||
self.tables_raw[block_name] = raw_strings
|
self.tables_raw[block_name] = raw_strings
|
||||||
self.tables[block_name] = strings
|
self.tables[block_name] = strings
|
||||||
|
|
||||||
func load_snes_rom(buffer: StreamPeerBuffer, is_RPGe: bool = false) -> void:
|
func load_snes_rom(buffer: StreamPeerBuffer) -> void:
|
||||||
emit_signal('loading_stage_updated', 'load_snes_rom called')
|
# emit_signal('loading_stage_updated', 'load_snes_rom called')
|
||||||
|
var is_RPGe: bool = buffer.get_size() > 0x200000 # Naive check for >2MiB
|
||||||
for block_name in SNES_block_addresses:
|
for block_name in SNES_block_addresses:
|
||||||
emit_signal('loading_stage_updated', 'Loading string block "%s"'%block_name)
|
# emit_signal('loading_stage_updated', 'Loading string block "%s"'%block_name)
|
||||||
var scenetree := get_tree()
|
var scenetree := get_tree()
|
||||||
if scenetree:
|
if scenetree:
|
||||||
yield(scenetree, 'idle_frame')
|
yield(scenetree, 'idle_frame')
|
||||||
|
|
Loading…
Reference in New Issue