New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Load engine and data concurrently #8682
Load engine and data concurrently #8682
Conversation
@@ -999,14 +999,7 @@ public void buildEnginePlatform(IProgress monitor, File buildDir, File cacheDir, | |||
|
|||
final String variant = appmanifestOptions.get("baseVariant"); | |||
|
|||
List<String> defaultNames = platform.formatBinaryName("dmengine"); | |||
List<File> exes = new ArrayList<File>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used.
@@ -203,7 +215,7 @@ void writeJson(JsonGenerator generator) throws IOException { | |||
|
|||
generator.writeFieldName("pieces"); | |||
generator.writeStartArray(); | |||
int offset = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix type because file size returns long
.
@@ -257,7 +272,6 @@ public void bundleApplication(Project project, Platform platform, File bundleDir | |||
String enginePrefix = BundleHelper.projectNameToBinaryName(title); | |||
|
|||
BundleHelper.throwIfCanceled(canceled); | |||
File projectRoot = new File(project.getRootDirectory()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used.
generator.writeEndArray(); | ||
generator.writeNumberField("total_size", totalSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calculate total game data size to avoid unnecessary calculation during runtime.
xhr.onprogress = function(e) { | ||
if (onprogress) onprogress(xhr, e); | ||
xhr.onprogress = function(event) { | ||
if (onprogress) onprogress(xhr, event, xhr._loadedSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass already loaded amount of bytes to calculate delta (use later to update progress bar).
return; | ||
} | ||
currentAttempt = currentAttempt + 1; | ||
if (onretry) onretry(xhr, event, xhr._loadedSize, currentAttempt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add onretry
callback. It uses to decrease loaded amount of bytes and update progress bar with correct values.
} | ||
request.onprogress = function(xhr, e, ls) { | ||
var delta = e.loaded - ls; | ||
onprogress(delta); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify onprogress
because we don't need to know total size from response headers (see #7039)
wasm_size: 2000000, | ||
wasmjs_size: 250000, | ||
asmjs_size: 4000000, | ||
wasm_size: {{ DEFOLD_WASM_SIZE }}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bake final size of files inside dmloader.
// load engine (asm.js or wasm.js + wasm) | ||
// left as entrypoint for backward capability | ||
// start loading archive_files.json | ||
// after receiving it - start loading engine and data concurrently | ||
load: function(appCanvasId, exeName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left EngineLoader.load
function as entrypoint because it may produce breaking change for developer.
@@ -241,9 +302,6 @@ var GameArchiveLoader = { | |||
this._onGameArchiveLoaderCompletedListeners = []; | |||
this._onAllTargetsBuiltListeners = []; | |||
this._onFileDownloadErrorListeners = []; | |||
|
|||
this._currentDownloadBytes = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to calculate it separately.
// calculate total download size of all files | ||
for(var i=0; i<this._files.length; ++i) { | ||
this._totalDownloadBytes += this._files[i].size; | ||
var isWASMSupported = Module['isWASMSupported']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Main change:
Now it starts loading game data and game engine concurrently after receiving archive_files.json
. Here it calculates total amount of bytes that need to be downloaded.
@@ -457,19 +520,6 @@ var Progress = { | |||
progress_id: "defold-progress", | |||
bar_id: "defold-progress-bar", | |||
|
|||
listeners: [], | |||
|
|||
addListener: function(callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left Progress
object only for visualization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that critical if we break something in templates, because we always can notify users and ask them to update their template (btw could you please a it into your PR message e.g. like here) but it would be nice to keep existing extensions compatible if it's possible. For example:
https://github.com/defold/extension-poki-sdk/blob/main/poki-sdk/manifests/web/engine_template.html
If it's impossible to avoid - sure, we have to notify users and probably introduce it as a breaking change, but here it feels like something only about naming. I suggest to keep Progress
for logic and create ProgressView
just for you, to keep it back compatible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left Progress object as wrapper around new ProgressView and ProgressUpdater. Let me know if such approach is ok. @AGulev
@@ -499,6 +544,50 @@ var Progress = { | |||
} | |||
}; | |||
|
|||
var ProgressUpdater = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introduce new object ProgressUpdater
. It should control and recalculate downloading progress and notify all listeners.
@@ -856,6 +890,119 @@ var Module = { | |||
}, | |||
}; | |||
|
|||
// common engine setup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part of code that was moved from engine_template.html
.
@@ -13,6 +13,7 @@ | |||
background-color: #1a72eb; | |||
text-align: center; | |||
line-height: 20px; | |||
transition: width 1s ease; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For smoother progress bar width update.
|
||
stream_wasm: false, | ||
updateWasmInstantiateProgress: function(totalDownloadedSize) { | ||
EngineLoader.wasm_instantiate_progress = totalDownloadedSize * 0.1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calculate what amount of total downloadable size is 10% and use if as part of progress that indicates wasm instantiating.
… Add dmloader.js creation during bundle process. Cleanup some unused code from Bob. Rework Progress in dmloader. Add totlaSize field to archive_list.json. Add onretry calbback. Decrease downloaded amount of bytes if request failed and retried. Add easing for base progress bar width change.
efb37f1
to
53beeb0
Compare
com.dynamo.cr/com.dynamo.cr.bob/src/com/dynamo/bob/bundle/HTML5Bundler.java
Show resolved
Hide resolved
@@ -510,6 +599,7 @@ var Module = { | |||
_archiveLoaded: false, | |||
_preLoadDone: false, | |||
_waitingForArchive: false, | |||
_isEngineLoaded: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Introduce new flag to control if engine already downloaded or not. It's need to handle case when game data loaded faster than engine binaries.
FileLoader.options.retryInterval = params["retry_time"] * 1000; | ||
if (typeof params["can_not_download_file_callback"] === "function") { | ||
GameArchiveLoader.addFileDownloadErrorListener(params["can_not_download_file_callback"]); | ||
if (Module._archiveLoaded) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If game data already loaded - call main function.
Module.noInitialRun = false; | ||
} else { | ||
Module.callMain(Module.arguments); | ||
if (Module._isEngineLoaded) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if engine binary loaded and JS runtime is initialize (it means that 'onRuntimeInitialized' was called).
Note to reviewers: |
}; | ||
request.onerror = function(xhr, e) { | ||
onerror("Error loading '" + url + "' (" + e + ")"); | ||
}; | ||
request.onload = function(xhr, e) { | ||
if (xhr.readyState === 4) { | ||
if (xhr.readyState === XMLHttpRequest.DONE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use constant instead of magic number.
@@ -457,19 +520,6 @@ var Progress = { | |||
progress_id: "defold-progress", | |||
bar_id: "defold-progress-bar", | |||
|
|||
listeners: [], | |||
|
|||
addListener: function(callback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that critical if we break something in templates, because we always can notify users and ask them to update their template (btw could you please a it into your PR message e.g. like here) but it would be nice to keep existing extensions compatible if it's possible. For example:
https://github.com/defold/extension-poki-sdk/blob/main/poki-sdk/manifests/web/engine_template.html
If it's impossible to avoid - sure, we have to notify users and probably introduce it as a breaking change, but here it feels like something only about naming. I suggest to keep Progress
for logic and create ProgressView
just for you, to keep it back compatible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! 👍
Now
dmloader.js
loads game data and game engine (wasm + js files) concurrently.Fixes #7456.
Possible fixes #7039.
Technical changes
Rework html5 loading flow. Now
dmloader.js
loadsarchive_list.json
, then loads data and engine concurrently.Additionally part of js code was moved from
engine_template.html
todmloader.js
.dmloader.js
used as template during bundle process. It means that some of project values can be used to substitute inside template (seedmloader.js
for more details).Add animation transition for progress bar width change to update progress bar more smooth. Made with transform property (thanks to @thinknathan ).
Manual update: #8682
PR checklist
Example of a well written PR description:
### Technical changes
Technical changes:
Technical notes: