Skip to content
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

Implement lossless WebP encoding #47835

Merged
merged 1 commit into from
Jun 11, 2021

Conversation

mortarroad
Copy link
Contributor

@mortarroad mortarroad commented Apr 12, 2021

See godotengine/godot-proposals#2593

Defaults to WebP for lossless texture compression, with a checkbox to force PNG compression.

DATA_FORMAT_LOSSY is renamed to DATA_FORMAT_WEBP and can be either lossy or lossless.
DATA_FORMAT_LOSSLESS is renamed to DATA_FORMAT_PNG.
Afaik, this does not cause a compatibility break, and no automatic re-import either. Maybe it should?

I have not yet performed performance testing, but at least in the Debug build, the slower importer performance at the default "quality" 70/100 is noticeable, but the files are definitely smaller. It is yet to be seen how much the Release build is affected.
Perhaps the "quality" setting can also be lowered.

Bugsquad edit: Closes godotengine/godot-proposals#2593

@mortarroad
Copy link
Contributor Author

mortarroad commented Apr 13, 2021

Some preliminary testing (release_debug build):

Import performance
I tested importing the ~1000 png files (most of them are tiny) from https://github.com/notapixelstudio/superstarfighter.
The times are averaged from 2 runs each; they were within 3 seconds of each other.

Time to import Imported size
WebP 64 s 10.5 MB
PNG 53 s 18.4 MB

Runtime loading performance
load() time sum for all textures in milliseconds

# Run WebP PNG
1 1484.759 1398.329
2 1040.369 1395.912
3 1041.392 1392.357
4 1048.056 1393.934
5 1019.016 1429.843
avg 1126.718 1402.075

I.e. in this test, WebP takes around 80% of the time to load, compared to PNG.

(In fact these are all tested with 3.x. I can't get master to run without crashing all the time.)

@mortarroad
Copy link
Contributor Author

Meh, testing this is kind of ugly, since Directory does not support listing "res://" in exported projects.
(Even though Directory.open does not report an error, and get_current_dir() is set after...)

@fire
Copy link
Member

fire commented Apr 15, 2021

I am concerned that this is slower than png loading, is there any knob we can use to make WebP faster? It may be worth the loss.

scene/resources/texture.h Outdated Show resolved Hide resolved
@fire
Copy link
Member

fire commented Apr 15, 2021

How do I enable quality 25 for a lossless import?

@mortarroad
Copy link
Contributor Author

I did another benchmark with png files that are a bit bigger.
I chose the 500 biggest png files (most of them are still small) from https://github.com/SuperTux/supertux

The WebP presets are selected with WebPConfigLosslessPreset(), which ranges from 0 to 9.

Import time Imported size
PNG 30 s 41.2 MB
WebP (level 2) 31 s 29.8 MB
WebP (level 4) 40 s 27.7 MB
WebP (level 6) 53 s 27.4 MB

It looks like level 2 almost ties with PNG.

@Calinou
Copy link
Member

Calinou commented Apr 15, 2021

It looks like level 2 almost ties with PNG.

I think level 2 is a good default value. In the future, you could probably expose the WebP compression level in a project setting so people can tune it to their needs. We already have similar project settings for Zstandard compression.

@mortarroad
Copy link
Contributor Author

mortarroad commented Apr 15, 2021

@Calinou Are you sure? All the other texture compression settings (e.g. the VRAM compression quality) are in the import panel.

@Calinou
Copy link
Member

Calinou commented Apr 15, 2021

@Calinou Are you sure? All the other texture compression settings (e.g. the VRAM compression quality) are in the import panel.

Considering this is a "niche" setting that only needs to be changed on a global basis, I'd make it a project setting. In comparison, lossy or VRAM compression quality sometimes has to be changed on a per-texture basis.

Lossless compression is also different from lossy compression in the sense that the compression level doesn't affect visual quality, only file size.

@mortarroad
Copy link
Contributor Author

I guess I'll make the force png a project setting as well then.
Is there any mechanism that causes the import to run again when the project settings are changed, or does that not matter?

@Calinou
Copy link
Member

Calinou commented Apr 15, 2021

Is there any mechanism that causes the import to run again when the project settings are changed, or does that not matter?

There isn't a mechanism for this yet, but since this is an advanced feature, it's not that important for now.

@mortarroad
Copy link
Contributor Author

Nevermind, I found it.
You need to declare the setting via GLOBAL_DEF_RST, and then include it in get_import_settings_string().

Do you think rendering/lossless_compression/force_png and rendering/lossless_compression/webp_compression_level are fine keys?
We already have rendering/vram_compression/import_bptc, etc.

@Calinou
Copy link
Member

Calinou commented Apr 15, 2021

Do you think rendering/lossless_compression/force_png and rendering/lossless_compression/webp_compression_level are fine keys?

Sounds good to me 🙂

@mortarroad
Copy link
Contributor Author

Nevermind again, invoking a re-import by restarting would become quite ugly.
Currently the formats are only stored in the metadata if it's a vram format. I think refactoring that is out of scope for this PR.

@mortarroad mortarroad requested review from a team as code owners April 16, 2021 08:55
@mortarroad mortarroad removed request for a team April 16, 2021 09:02
@mortarroad
Copy link
Contributor Author

I think yes.

@fire fire requested a review from a team April 27, 2021 12:32
@alexfreyre
Copy link

Although isn't related to webp, I will share this graph which shows a test of some image textures loading times. Enjoy! 😄
The test was made in Openframeworks, a C++ and OpenGL creative coding open source software.

image

@mortarroad
Copy link
Contributor Author

The numbers you give look very unexpected. JPEG should generally be much faster than PNG!

I don't know if Godot has multi-threaded (and/or pipelined) resource loading (yet?).
When it has, I expect smaller (i.e. better compressed) files to give a loading speedup, even if decompression is more expensive, because the disk will be the bottleneck (- at the very least for spinning disks).

@Calinou
Copy link
Member

Calinou commented Apr 28, 2021

I don't know if Godot has multi-threaded (and/or pipelined) resource loading (yet?).

Godot has both parallel resource importing and loading in the master branch. In 3.x, neither are multi-threaded though (there's ResourceInteractiveLoader, but it's not used by the editor).

@mortarroad
Copy link
Contributor Author

Rebased to current master.
Is there any update on the review?

@fire
Copy link
Member

fire commented Jun 1, 2021

I'll start a discussion in asset-pipeline@godot chat.

Copy link
Member

@fire fire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

There were no objections. Will ask for more.

Regarding QA:

Did you try importing the TPS-DEMO from 3.x?

Does the results match what we expect? We expect there to be no difference in compression times but the entire "pak"ed repo is smaller.

@mortarroad
Copy link
Contributor Author

@fire You mean the Third Person Shooter demo? That practically uses no losslessly compressed textures, so it would hardly make any difference.

@fire
Copy link
Member

fire commented Jun 2, 2021

I was trying to think of a proper test case, and yes, modifying the TPS to go from vram to lossless is strange, and we should not do it.

Maybe there's a 2d game test candidate for the webp test.

@Calinou
Copy link
Member

Calinou commented Jun 2, 2021

Maybe there's a 2d game test candidate for the webp test.

You can use the 2D platformer demo or Jetpaca for this purpose.

Lossless compression is found in 2D projects and (correctly configured) pixel art 3D projects. In non-pixel art 3D projects, it's better to go for VRAM compression unless the base texture resolution is low enough to make non-VRAM compressed textures viable (e.g. porting an old game).

@mortarroad
Copy link
Contributor Author

The import times of Jetpaca are the same in 3.x, with and without webp.

Copy link
Member

@akien-mga akien-mga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved in PR review meeting today.

@akien-mga akien-mga merged commit 50d1e0e into godotengine:master Jun 11, 2021
@akien-mga
Copy link
Member

Thanks!

@jyrkialakuijala
Copy link

Consider exposing webp near-lossless. You will get no visible loss if you use setting 60 and still much less loss than highest quality levels of lossy codec at setting 40. Often the filesize is 40 % smaller than full lossless.

@Calinou
Copy link
Member

Calinou commented Nov 8, 2021

Consider exposing webp near-lossless. You will get no visible loss if you use setting 60 and still much less loss than highest quality levels of lossy codec at setting 40. Often the filesize is 40 % smaller than full lossless.

Godot already exposes lossy WebP encoding, while also allowing you to adjust the lossy compression quality.

Note that lossy encoding doesn't save VRAM, so it's only recommended for 2D games with heavy non-pixel art textures.

@jyrkialakuijala
Copy link

Near-lossless allows the use of yuv444 (crisper colors), and is a few db more precise than best of lossy.

@Calinou
Copy link
Member

Calinou commented Nov 8, 2021

Near-lossless allows the use of yuv444 (crisper colors), and is a few db more precise than best of lossy.

I guess near-lossless compression could be used if the lossy quality is set to 1.0 (if this isn't being done already). Feel free to open a pull request for this 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support lossless WebP for texture import
6 participants