浏览代码

Multiple-threads loading (#425)

Add Multiple-threads loading demo
Vitaliy 5 年之前
父节点
当前提交
5f7072a18d
共有 49 个文件被更改,包括 525 次插入0 次删除
  1. 15 0
      loading/multiple_threads_loading/README.md
  2. 18 0
      loading/multiple_threads_loading/default_env.tres
  3. 二进制
      loading/multiple_threads_loading/icon.png
  4. 二进制
      loading/multiple_threads_loading/images/icon_1.png
  5. 二进制
      loading/multiple_threads_loading/images/icon_10.png
  6. 二进制
      loading/multiple_threads_loading/images/icon_11.png
  7. 二进制
      loading/multiple_threads_loading/images/icon_12.png
  8. 二进制
      loading/multiple_threads_loading/images/icon_13.png
  9. 二进制
      loading/multiple_threads_loading/images/icon_14.png
  10. 二进制
      loading/multiple_threads_loading/images/icon_15.png
  11. 二进制
      loading/multiple_threads_loading/images/icon_16.png
  12. 二进制
      loading/multiple_threads_loading/images/icon_17.png
  13. 二进制
      loading/multiple_threads_loading/images/icon_18.png
  14. 二进制
      loading/multiple_threads_loading/images/icon_19.png
  15. 二进制
      loading/multiple_threads_loading/images/icon_2.png
  16. 二进制
      loading/multiple_threads_loading/images/icon_20.png
  17. 二进制
      loading/multiple_threads_loading/images/icon_21.png
  18. 二进制
      loading/multiple_threads_loading/images/icon_22.png
  19. 二进制
      loading/multiple_threads_loading/images/icon_23.png
  20. 二进制
      loading/multiple_threads_loading/images/icon_24.png
  21. 二进制
      loading/multiple_threads_loading/images/icon_25.png
  22. 二进制
      loading/multiple_threads_loading/images/icon_26.png
  23. 二进制
      loading/multiple_threads_loading/images/icon_27.png
  24. 二进制
      loading/multiple_threads_loading/images/icon_28.png
  25. 二进制
      loading/multiple_threads_loading/images/icon_29.png
  26. 二进制
      loading/multiple_threads_loading/images/icon_3.png
  27. 二进制
      loading/multiple_threads_loading/images/icon_30.png
  28. 二进制
      loading/multiple_threads_loading/images/icon_31.png
  29. 二进制
      loading/multiple_threads_loading/images/icon_32.png
  30. 二进制
      loading/multiple_threads_loading/images/icon_33.png
  31. 二进制
      loading/multiple_threads_loading/images/icon_34.png
  32. 二进制
      loading/multiple_threads_loading/images/icon_35.png
  33. 二进制
      loading/multiple_threads_loading/images/icon_36.png
  34. 二进制
      loading/multiple_threads_loading/images/icon_37.png
  35. 二进制
      loading/multiple_threads_loading/images/icon_38.png
  36. 二进制
      loading/multiple_threads_loading/images/icon_39.png
  37. 二进制
      loading/multiple_threads_loading/images/icon_4.png
  38. 二进制
      loading/multiple_threads_loading/images/icon_40.png
  39. 二进制
      loading/multiple_threads_loading/images/icon_5.png
  40. 二进制
      loading/multiple_threads_loading/images/icon_6.png
  41. 二进制
      loading/multiple_threads_loading/images/icon_7.png
  42. 二进制
      loading/multiple_threads_loading/images/icon_8.png
  43. 二进制
      loading/multiple_threads_loading/images/icon_9.png
  44. 219 0
      loading/multiple_threads_loading/main.tscn
  45. 33 0
      loading/multiple_threads_loading/preload.gd
  46. 70 0
      loading/multiple_threads_loading/preload.tscn
  47. 25 0
      loading/multiple_threads_loading/project.godot
  48. 145 0
      loading/multiple_threads_loading/resource_queue.gd
  49. 二进制
      loading/multiple_threads_loading/screenshots/screenshot.png

+ 15 - 0
loading/multiple_threads_loading/README.md

@@ -0,0 +1,15 @@
+# Multiple-threads loading demo
+
+This demo shows how you can organize background loading using multiple threads.
+
+Language: GDScript
+
+Renderer: GLES 2
+
+## How does it work?
+
+[Official documentation - Using multiple threads](http://docs.godotengine.org/en/3.2/tutorials/io/background_loading.html#using-multiple-threads)
+
+## Screenshots
+
+![Screenshot](screenshots/screenshot.png)

+ 18 - 0
loading/multiple_threads_loading/default_env.tres

@@ -0,0 +1,18 @@
+[gd_resource type="Environment" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+radiance_size = 4
+sky_top_color = Color( 0.0470588, 0.454902, 0.976471, 1 )
+sky_horizon_color = Color( 0.556863, 0.823529, 0.909804, 1 )
+sky_curve = 0.25
+ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
+ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
+ground_curve = 0.01
+sun_energy = 16.0
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )
+fog_height_min = 0.0
+fog_height_max = 100.0
+ssao_quality = 0

二进制
loading/multiple_threads_loading/icon.png


二进制
loading/multiple_threads_loading/images/icon_1.png


二进制
loading/multiple_threads_loading/images/icon_10.png


二进制
loading/multiple_threads_loading/images/icon_11.png


二进制
loading/multiple_threads_loading/images/icon_12.png


二进制
loading/multiple_threads_loading/images/icon_13.png


二进制
loading/multiple_threads_loading/images/icon_14.png


二进制
loading/multiple_threads_loading/images/icon_15.png


二进制
loading/multiple_threads_loading/images/icon_16.png


二进制
loading/multiple_threads_loading/images/icon_17.png


二进制
loading/multiple_threads_loading/images/icon_18.png


二进制
loading/multiple_threads_loading/images/icon_19.png


二进制
loading/multiple_threads_loading/images/icon_2.png


二进制
loading/multiple_threads_loading/images/icon_20.png


二进制
loading/multiple_threads_loading/images/icon_21.png


二进制
loading/multiple_threads_loading/images/icon_22.png


二进制
loading/multiple_threads_loading/images/icon_23.png


二进制
loading/multiple_threads_loading/images/icon_24.png


二进制
loading/multiple_threads_loading/images/icon_25.png


二进制
loading/multiple_threads_loading/images/icon_26.png


二进制
loading/multiple_threads_loading/images/icon_27.png


二进制
loading/multiple_threads_loading/images/icon_28.png


二进制
loading/multiple_threads_loading/images/icon_29.png


二进制
loading/multiple_threads_loading/images/icon_3.png


二进制
loading/multiple_threads_loading/images/icon_30.png


二进制
loading/multiple_threads_loading/images/icon_31.png


二进制
loading/multiple_threads_loading/images/icon_32.png


二进制
loading/multiple_threads_loading/images/icon_33.png


二进制
loading/multiple_threads_loading/images/icon_34.png


二进制
loading/multiple_threads_loading/images/icon_35.png


二进制
loading/multiple_threads_loading/images/icon_36.png


二进制
loading/multiple_threads_loading/images/icon_37.png


二进制
loading/multiple_threads_loading/images/icon_38.png


二进制
loading/multiple_threads_loading/images/icon_39.png


二进制
loading/multiple_threads_loading/images/icon_4.png


二进制
loading/multiple_threads_loading/images/icon_40.png


二进制
loading/multiple_threads_loading/images/icon_5.png


二进制
loading/multiple_threads_loading/images/icon_6.png


二进制
loading/multiple_threads_loading/images/icon_7.png


二进制
loading/multiple_threads_loading/images/icon_8.png


二进制
loading/multiple_threads_loading/images/icon_9.png


+ 219 - 0
loading/multiple_threads_loading/main.tscn

@@ -0,0 +1,219 @@
+[gd_scene load_steps=41 format=2]
+
+[ext_resource path="res://images/icon_1.png" type="Texture" id=1]
+[ext_resource path="res://images/icon_2.png" type="Texture" id=2]
+[ext_resource path="res://images/icon_3.png" type="Texture" id=3]
+[ext_resource path="res://images/icon_4.png" type="Texture" id=4]
+[ext_resource path="res://images/icon_5.png" type="Texture" id=5]
+[ext_resource path="res://images/icon_6.png" type="Texture" id=6]
+[ext_resource path="res://images/icon_7.png" type="Texture" id=7]
+[ext_resource path="res://images/icon_8.png" type="Texture" id=8]
+[ext_resource path="res://images/icon_9.png" type="Texture" id=9]
+[ext_resource path="res://images/icon_10.png" type="Texture" id=10]
+[ext_resource path="res://images/icon_11.png" type="Texture" id=11]
+[ext_resource path="res://images/icon_12.png" type="Texture" id=12]
+[ext_resource path="res://images/icon_13.png" type="Texture" id=13]
+[ext_resource path="res://images/icon_14.png" type="Texture" id=14]
+[ext_resource path="res://images/icon_15.png" type="Texture" id=15]
+[ext_resource path="res://images/icon_16.png" type="Texture" id=16]
+[ext_resource path="res://images/icon_17.png" type="Texture" id=17]
+[ext_resource path="res://images/icon_18.png" type="Texture" id=18]
+[ext_resource path="res://images/icon_19.png" type="Texture" id=19]
+[ext_resource path="res://images/icon_20.png" type="Texture" id=20]
+[ext_resource path="res://images/icon_21.png" type="Texture" id=21]
+[ext_resource path="res://images/icon_22.png" type="Texture" id=22]
+[ext_resource path="res://images/icon_23.png" type="Texture" id=23]
+[ext_resource path="res://images/icon_24.png" type="Texture" id=24]
+[ext_resource path="res://images/icon_25.png" type="Texture" id=25]
+[ext_resource path="res://images/icon_26.png" type="Texture" id=26]
+[ext_resource path="res://images/icon_27.png" type="Texture" id=27]
+[ext_resource path="res://images/icon_28.png" type="Texture" id=28]
+[ext_resource path="res://images/icon_29.png" type="Texture" id=29]
+[ext_resource path="res://images/icon_30.png" type="Texture" id=30]
+[ext_resource path="res://images/icon_31.png" type="Texture" id=31]
+[ext_resource path="res://images/icon_32.png" type="Texture" id=32]
+[ext_resource path="res://images/icon_33.png" type="Texture" id=33]
+[ext_resource path="res://images/icon_34.png" type="Texture" id=34]
+[ext_resource path="res://images/icon_35.png" type="Texture" id=35]
+[ext_resource path="res://images/icon_36.png" type="Texture" id=36]
+[ext_resource path="res://images/icon_37.png" type="Texture" id=37]
+[ext_resource path="res://images/icon_38.png" type="Texture" id=38]
+[ext_resource path="res://images/icon_39.png" type="Texture" id=39]
+[ext_resource path="res://images/icon_40.png" type="Texture" id=40]
+
+[node name="Node" type="Node"]
+
+[node name="ColorRect" type="ColorRect" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+color = Color( 0, 0, 0, 1 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="Label" type="Label" parent="."]
+margin_left = 452.0
+margin_top = 272.0
+margin_right = 572.0
+margin_bottom = 286.0
+text = "Main scene loaded"
+
+[node name="Sprite1" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 1 )
+
+[node name="Sprite2" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 2 )
+
+[node name="Sprite3" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 3 )
+
+[node name="Sprite4" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 4 )
+
+[node name="Sprite5" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 5 )
+
+[node name="Sprite6" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 6 )
+
+[node name="Sprite7" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 7 )
+
+[node name="Sprite8" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 8 )
+
+[node name="Sprite9" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 9 )
+
+[node name="Sprite10" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 10 )
+
+[node name="Sprite11" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 11 )
+
+[node name="Sprite12" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 12 )
+
+[node name="Sprite13" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 13 )
+
+[node name="Sprite14" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 14 )
+
+[node name="Sprite15" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 15 )
+
+[node name="Sprite16" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 16 )
+
+[node name="Sprite17" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 17 )
+
+[node name="Sprite18" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 18 )
+
+[node name="Sprite19" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 19 )
+
+[node name="Sprite20" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 20 )
+
+[node name="Sprite21" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 21 )
+
+[node name="Sprite22" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 22 )
+
+[node name="Sprite23" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 23 )
+
+[node name="Sprite24" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 24 )
+
+[node name="Sprite25" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 25 )
+
+[node name="Sprite26" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 26 )
+
+[node name="Sprite27" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 27 )
+
+[node name="Sprite28" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 28 )
+
+[node name="Sprite29" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 29 )
+
+[node name="Sprite30" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 30 )
+
+[node name="Sprite31" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 31 )
+
+[node name="Sprite32" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 32 )
+
+[node name="Sprite33" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 33 )
+
+[node name="Sprite34" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 34 )
+
+[node name="Sprite35" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 35 )
+
+[node name="Sprite36" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 36 )
+
+[node name="Sprite37" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 37 )
+
+[node name="Sprite38" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 38 )
+
+[node name="Sprite39" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 39 )
+
+[node name="Sprite40" type="Sprite" parent="."]
+visible = false
+texture = ExtResource( 40 )

+ 33 - 0
loading/multiple_threads_loading/preload.gd

@@ -0,0 +1,33 @@
+extends Node
+
+
+var Queue
+
+
+func _ready():
+	# Initialize
+	Queue = preload("res://resource_queue.gd").new()
+	# Call after you instance the class to start the thread.
+	Queue.start()
+
+
+func _process(_delta):
+	# Returns true if a resource is done loading and ready to be retrieved
+	if Queue.is_ready("res://main.tscn"):
+		set_process(false)
+		# Returns the fully loaded resource
+		var next_scene = Queue.get_resource("res://main.tscn").instance()
+		get_node("/root").add_child(next_scene)
+		get_node("/root").remove_child(self)
+		queue_free()
+	else:
+		# Get the progress of a resource
+		var progress = round(Queue.get_progress("res://main.tscn")*100)
+		get_node("ProgressBar").set_value(progress)
+
+
+func _on_Button_button_up():
+	get_node("Button").hide()
+	set_process(true)
+	# Queue a resource
+	Queue.queue_resource("res://main.tscn", true)

+ 70 - 0
loading/multiple_threads_loading/preload.tscn

@@ -0,0 +1,70 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://preload.gd" type="Script" id=1]
+
+[sub_resource type="GDScript" id=1]
+script/source = "extends LinkButton
+
+func _on_LinkButton_button_up():
+	OS.shell_open(\"http://docs.godotengine.org/en/3.2/tutorials/io/background_loading.html#using-multiple-threads\")
+"
+
+[node name="Node" type="Node"]
+script = ExtResource( 1 )
+
+[node name="ColorRect" type="ColorRect" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+color = Color( 0.00390625, 0, 0, 1 )
+
+[node name="ProgressBar" type="ProgressBar" parent="."]
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+margin_left = -225.0
+margin_top = -66.0
+margin_right = 225.0
+margin_bottom = 66.0
+step = 1.0
+
+[node name="Button" type="Button" parent="."]
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+margin_left = -223.0
+margin_top = -193.0
+margin_right = 224.0
+margin_bottom = -84.0
+text = "Load next scene"
+
+[node name="Label" type="Label" parent="."]
+anchor_left = 0.5
+anchor_right = 0.5
+margin_left = -267.0
+margin_top = 12.0
+margin_right = 267.0
+margin_bottom = 82.0
+text = "Multiple-treads loading demo
+The next scene contains 40 resource files. Loading is done using multiple threads.
+The download speed depends on the performance of your device.
+For more information, see:"
+__meta__ = {
+"_edit_use_anchors_": false
+}
+
+[node name="LinkButton" type="LinkButton" parent="."]
+anchor_left = 0.5
+anchor_right = 0.5
+margin_left = -233.0
+margin_top = 80.0
+margin_right = 233.0
+margin_bottom = 94.0
+text = "http://docs.godotengine.org/en/3.2/tutorials/io/background_loading.html"
+script = SubResource( 1 )
+__meta__ = {
+"_edit_use_anchors_": false
+}
+[connection signal="button_up" from="Button" to="." method="_on_Button_button_up"]
+[connection signal="button_up" from="LinkButton" to="LinkButton" method="_on_LinkButton_button_up"]

+ 25 - 0
loading/multiple_threads_loading/project.godot

@@ -0,0 +1,25 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=4
+
+_global_script_classes=[  ]
+_global_script_class_icons={
+
+}
+
+[application]
+
+config/name="Multiple threads loading"
+run/main_scene="res://preload.tscn"
+config/icon="res://icon.png"
+
+[rendering]
+
+quality/driver/driver_name="GLES2"
+environment/default_environment="res://default_env.tres"

+ 145 - 0
loading/multiple_threads_loading/resource_queue.gd

@@ -0,0 +1,145 @@
+var thread
+var mutex
+var sem
+
+var time_max = 100 # Milliseconds.
+
+var queue = []
+var pending = {}
+
+func _lock(_caller):
+	mutex.lock()
+
+
+func _unlock(_caller):
+	mutex.unlock()
+
+
+func _post(_caller):
+	sem.post()
+
+
+func _wait(_caller):
+	sem.wait()
+
+
+func queue_resource(path, p_in_front = false):
+	_lock("queue_resource")
+	if path in pending:
+		_unlock("queue_resource")
+		return
+	elif ResourceLoader.has_cached(path):
+		var res = ResourceLoader.load(path)
+		pending[path] = res
+		_unlock("queue_resource")
+		return
+	else:
+		var res = ResourceLoader.load_interactive(path)
+		res.set_meta("path", path)
+		if p_in_front:
+			queue.insert(0, res)
+		else:
+			queue.push_back(res)
+		pending[path] = res
+		_post("queue_resource")
+		_unlock("queue_resource")
+		return
+
+
+func cancel_resource(path):
+	_lock("cancel_resource")
+	if path in pending:
+		if pending[path] is ResourceInteractiveLoader:
+			queue.erase(pending[path])
+		pending.erase(path)
+	_unlock("cancel_resource")
+
+
+func get_progress(path):
+	_lock("get_progress")
+	var ret = -1
+	if path in pending:
+		if pending[path] is ResourceInteractiveLoader:
+			ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count())
+		else:
+			ret = 1.0
+	_unlock("get_progress")
+	return ret
+
+
+func is_ready(path):
+	var ret
+	_lock("is_ready")
+	if path in pending:
+		ret = !(pending[path] is ResourceInteractiveLoader)
+	else:
+		ret = false
+	_unlock("is_ready")
+	return ret
+
+
+func _wait_for_resource(res, path):
+	_unlock("wait_for_resource")
+	while true:
+		VisualServer.sync()
+		OS.delay_usec(16000) # Wait approximately 1 frame.
+		_lock("wait_for_resource")
+		if queue.size() == 0 || queue[0] != res:
+			return pending[path]
+		_unlock("wait_for_resource")
+
+
+func get_resource(path):
+	_lock("get_resource")
+	if path in pending:
+		if pending[path] is ResourceInteractiveLoader:
+			var res = pending[path]
+			if res != queue[0]:
+				var pos = queue.find(res)
+				queue.remove(pos)
+				queue.insert(0, res)
+			
+			res = _wait_for_resource(res, path)
+			pending.erase(path)
+			_unlock("return")
+			return res
+		else:
+			var res = pending[path]
+			pending.erase(path)
+			_unlock("return")
+			return res
+	else:
+		_unlock("return")
+		return ResourceLoader.load(path)
+
+
+func thread_process():
+	_wait("thread_process")
+	_lock("process")
+	
+	while queue.size() > 0:
+		var res = queue[0]
+		_unlock("process_poll")
+		var ret = res.poll()
+		_lock("process_check_queue")
+		
+		if ret == ERR_FILE_EOF || ret != OK:
+			var path = res.get_meta("path")
+			if path in pending: # Else, it was already retrieved.
+				pending[res.get_meta("path")] = res.get_resource()
+			# Something might have been put at the front of the queue while
+			# we polled, so use erase instead of remove.
+			queue.erase(res)
+	_unlock("process")
+
+
+func thread_func(_u):
+	while true:
+		thread_process()
+
+
+func start():
+	mutex = Mutex.new()
+	sem = Semaphore.new()
+	thread = Thread.new()
+	thread.start(self, "thread_func", 0)

二进制
loading/multiple_threads_loading/screenshots/screenshot.png