-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
[3.x] Make all file access 64-bit (take 2) #47254
Conversation
5ff1db4
to
0a6ecbe
Compare
Done. As a side note, they're separate for review by @RandomShaper mostly, who is familiar with the first commit and can see the changes. For others, I'd suggest reviewing the whole PR at once instead of going through the changes twice: https://github.com/godotengine/godot/pull/47254/files |
I've tested this successfully on Linux with a 32-bit build (on a 64-bit host) which allowed me to export a PCK of 2.5 GiB, and run it with the 32-bit editor build. Needs testing on all other platforms too. A MRP would be fairly heavy (needs a project which is more than 2.1 GiB), but here's how I create one easily:
|
d8b0759
to
a170310
Compare
|
||
ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); | ||
return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int | ||
return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB. |
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 think this was a misunderstanding / the comment was bogus. This does convert bytes to megabytes, it truncates to the nearest MiB and then (supposedly) converts back to KiB.
That being said, the method seems bogus on Linux at least, but that's a separate issue.
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.
Heh interesting, the Linux 64-bit implementation seems to be broken.
On my system:
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p6 59G 46G 11G 82% /
/dev/nvme0n1p7 196G 172G 23G 89% /home
If I print the get_space_left()
for /
and /home
, I get:
32-bit:
14093373440
25898131456
Checks out taking into account reserved block count I guess? Assuming the value is in bytes and not MiB as the comment suggests.
64-bit:
1208475648
222502912
what?
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.
Also broken on macOS (it's the same shared Unix code):
> df -H
Filesystem Size Used Avail Capacity iused ifree %iused Mounted on
/dev/disk1s5s1 250G 15G 18G 47% 568975 2442362825 0% /
...
/dev/disk2s2 107G 52G 55G 49% 492742 4294474553 0% /Volumes/Windows 10
...
> get_space_left()
8983348772864 for "/"
8983348772864 for "/Volumes/Windows 10"
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 opened #47262 to keep track of it.
59f1fa4
to
58da64c
Compare
Does gdnative have problem when returning the uint64 size of an array? For example I remember Java having problems with unsigned types. I wanted to figure out the reason why other languages also don't use unsigned types like uint64_t. |
Did some testing on Windows 10 64-bit using binaries in https://downloads.tuxfamily.org/godotengine/testing/godot-3.3-rc-windows-64bit-pck-test.zip built from this PR. Exporting from 64-bit editor buildThe PCK is exported successfully (2.7 GiB in my test project), and can be run by both the 32-bit and 64-bit release export templates (didn't test debug but it should be fine too). Exporting from 32-bit editor buildThe PCK seems to be exported successfully (also 2.7 GiB, exact same size as the PCK from 64-bit editor), yet it seems to be broken. Both the 32-bit and 64-bit release export templates seem to fail running it (sounds like
File sizes are exactly identical:
But MD5 sums do differ:
|
Output from Windows
Something off around strings? |
I can reproduce the issue with the simplest MRP (new project with a main scene), it seems the PCK generation for Windows 32-bit is broken in this PR. Exporting a PCK with Windows 32-bit editor from 3.3 RC 6 works fine (same size, different MD5 sum), and can be run with the test templates from this PR. Edit: However with a local build from this branch using MSVC, it seems to work fine. So it might be something specific to the official builds compiled with MinGW-GCC. |
Or with file offset/padding, which is stored right after the strings godot/editor/editor_export.cpp Line 1072 in 94a0fc4
|
oh no. the PCK file exceed 2GB and when we run the export it doesn't work. we don't know how to reduce the import less than 2GB as this is the Godot bug in file system access. - godotengine/godot#27168 pck more than 2.1 gb error - godotengine/godot#44363 manually put an export template in root folder of this project - https://godotengine.org/qa/75329/game-over-and-not-working-what-best-handle-this-godot-stable - godotengine/godot-proposals#400 it seems that it will only fix in Godot 4.0 - https://docs.godotengine.org/en/stable/getting_started/workflow/export/exporting_pcks.html - godotengine/godot#44363 - godotengine/godot#47254 akien is fixing, but this PR here is still WIP for now unfortunately so now we added 2 export template: Windows and Linux, both 64 bit in the project root folder. simply run HexagonEngine.bat for Windows or HexagonEngine.sh for Linux respectively. those script will print "Hexagon Engine by Perkedel Technologies" then run respective export template.
58da64c
to
45d00d8
Compare
Rebased after recent codestyle changes in |
Building on Windows with both MSVC and MinGW-w64 (actually, TDM-GCC-64) I got good exports. Because of that, I just inspected the code analytically, and I found that the only possibility for the bad offsets in the PCK index is that the Something we could try is, in If that allowed it to generate good PCKs, we'd at least know that such line of investigation goes in the right direction and we could look deeper into that or do one of these: |
For the record, this table shows the offsets in a test PCK I made, compared between a good and bad build:
As you can see, the error is not constant, which, by the way, lead me to rule out some potential causes of the issue. |
Relevant commit in the MinGW: mirror/mingw-w64@edeeef2#diff-a68e7d03903adc47c8429d92fe49bc612c166bf22450f71328ba62cfde8dfa7e
|
45d00d8
to
4f3b856
Compare
With that find, it seems the PR should be good to go, as long as it's compiled with MinGW 8.0.0 or later (which I plan to do for 3.4+, and is already necessary for Vulkan support in 4.0). I squashed the two commits and amended the commit log to account for the changes I did compared to the original implementation (might need review). I added a note about the MinGW bug, but ideally if we can figure out a simple patch that works around the issue with |
4f3b856
to
3f85ab3
Compare
I made a test build of that PR for Windows 32-bit and 64-bit using mingw-w64 8.0.0 and GCC 10.3.1 from Fedora 34: https://downloads.tuxfamily.org/godotengine/testing/3.4-beta-pr47254-windows.zip Note: GitHub Actions is failing, the service is having a major outage now. Will restart the build once it's fixed, but until then we shouldn't merge. |
This changes the types of a big number of variables. General rules: - Using `uint64_t` in general. We also considered `int64_t` but eventually settled on keeping it unsigned, which is also closer to what one would expect with `size_t`/`off_t`. - We only keep `int64_t` for `seek_end` (takes a negative offset from the end) and for the `Variant` bindings, since `Variant::INT` is `int64_t`. This means we only need to guard against passing negative values in `core_bind.cpp`. - Using `uint32_t` integers for concepts not needing such a huge range, like pages, blocks, etc. In addition: - Improve usage of integer types in some related places; namely, `DirAccess`, core binds. Note: - On Windows, `_ftelli64` reports invalid values when using 32-bit MinGW with version < 8.0. This was an upstream bug fixed in 8.0. It breaks support for big files on 32-bit Windows builds made with that toolchain. We might add a workaround. Fixes godotengine#44363. Fixes godotengine/godot-proposals#400. Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
3f85ab3
to
817ffc0
Compare
Did some testing on Windows 10 Home Build 19042 with the above binaries. Exporting a big PCK (> 2.1 GiB) seems to work fine both when using the Win32 and Win64 editor binaries: The resulting export works fine (tested by playing back the webm video it contains). The MD5 and SHA256 sums for PCKs exported with the Win32 and Win64 editor binaries are identical, so that confirms that the issue outlined in #47254 (comment) is fixed (binaries built with MinGW-w64 8.0.0). I then tested loading the big PCK using the func _ready():
var file = File.new()
var err = file.open("res://EXPORT/BigProjWin32Debug.pck", File.READ)
assert(err == OK)
print(file.get_md5("res://EXPORT/BigProjWin32Debug.pck"))
var length = file.get_len()
print(length)
file.seek(length - 10)
assert(file.get_position() == length - 10)
print(file.get_32()) This confirmed that Godot can open and calculate the MD5 sum of this big file (which matches the one calculated by I did find one bug for which I'll open a dedicated bug report. Trying to get the file contents as a buffer still fails from GDScript: file.seek(0)
var buf = file.get_buffer(length)
print(buf.size())
|
The issue is that |
This is a redo of #27247 from @RandomShaper, as a draft as I intend to do some changes.
Opening against
3.x
for now as several users need support for PCK files above 2.1 GB, so they can backport this to their custom 3.3 builds. We'll probably target 3.4 for this though as it's a fairly big change, coming a bit too late for 3.3. We could consider cherry-picking for 3.3.x depending on how it goes.This will of course be forward-ported to
master
once ready.Fixes #44363.
Fixes godotengine/godot-proposals#400.
Some changes I plan to make after discussion with @reduz and others in @godotengine/core:
uint64_t
instead ofint64_t
in theFileAccess
API. That's closer tosize_t
/off_t
and should be good for all these operations.File
bindings should useint64_t
where relevant to validate that input is unsigned (as the Variant binding system only has signed ints).Directory::get_space_left()
change to bytes instead of MiB as it breaks compat. We can consider doing it for 4.0 but it shouldn't really be in the PR.I'll make changes as a separate commit for review.
This changes the types of a big number of variables.
General rules:
int64_t
in general. With 64-bit we no longer need to use unsigned type. That matchesVariant
better and avoids akward casts. Checks for negative numbers are performed where they don't make sense (seek, read/write buffer size).size_t
for file size/offsets.FileAccess::get_64/store_64
working with unsigneds. I haven't found any place where conversion to unsigned will cause trouble and saves us from having to addget/store_64_signed
or similar.int32_t
integers for concepts not needing such a huge range, like pages, blocks, etc.In addition:
DirAccess
, core binds.Directory::get_space_left()
tried to return the size in MiB, but the expression was missing parentheses, so the1024 * 1024
is removed and it keeps working as usual, returning bytes.