ComunidadAylas / PackSquash

πŸ“¦ Minecraft: Java Edition resource and data pack optimizer which aims to achieve the best possible compression, performance and protection, improving pack distribution, storage and in-game load times.
https://packsquash.aylas.org
GNU Affero General Public License v3.0
604 stars 25 forks source link

Shader parse error on working shaders #187

Closed CallumBugajski closed 1 year ago

CallumBugajski commented 1 year ago

Distribution

Linux x64 APT package

Bug description

When compiling a pack that contains Shaders from objmc (https://github.com/Godlander/objmc), I've been getting errors from Shaders that work correctly within Minecraft. Seems like they cannot be parsed but are correctly formatted.

Output:


PackSquash v0.3.1-8-g349eaf0 (release, 2022-04-14) for x86_64-unknown-linux-gnu
Minecraft resource and data pack optimizer (CLI)

This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions. Use the -v command line switch for
more details about these conditions.

- Reading options from file.toml...
- Options read. Processing pack...
- Working around automatically detected Minecraft quirks: bad_entity_eye_layer_texture_transparency_blending
! assets/minecraft/shaders/include/objmc_light.glsl: Shader parse error: error: 0: at line 5:
  if (isCustom == 0) {color *= vertexColor;}
  ^
  expected ';', found i

  1: at line 5, in Alt:
  if (isCustom == 0) {color *= vertexColor;}
  ^

  2: at line 1, in Many1:
  //objmc
  ^

! assets/minecraft/shaders/include/objmc_main.glsl: Shader parse error: error: 0: at line 4:
  isCustom = 0;
  ^
  expected ';', found i

  1: at line 4, in Alt:
  isCustom = 0;
  ^

  2: at line 1, in Many1:
  //objmc
  ^

! assets/minecraft/shaders/core/render/block.vsh: Shader parse error: error: 0: at line 43:
      #define BLOCK
      ^
  expected '}', found #

! assets/minecraft/shaders/core/render/entity_overlay.vsh: Shader parse error: error: 0: at line 52:
      #define ENTITY
      ^
  expected '}', found #

! assets/minecraft/shaders/core/render/entity.fsh: Shader parse error: error: 0: at line 36:
      #define ENTITY
      ^
  expected '}', found #

> assets/minecraft/shaders/include/fog.glsl: Minified
> assets/minecraft/shaders/core/rendertype_cutout.json: Minified
> assets/minecraft/textures/block/outworld.png: Optimized with 100% quality color quantization
> assets/minecraft/textures/block/outgui.png: Barely optimized. If not optimized externally, try tweaking options for extra savings
! assets/minecraft/shaders/core/render/entity.vsh: Shader parse error: error: 0: at line 50:
      #define ENTITY
      ^
  expected '}', found #

> assets/minecraft/shaders/core/rendertype_translucent.json: Minified
> assets/minecraft/textures/block/outhand.png: Optimized with 100% quality color quantization
> assets/minecraft/shaders/core/rendertype_item_entity_translucent_cull.json: Minified
> assets/minecraft/shaders/include/objmc_tools.glsl: Minified
> assets/minecraft/shaders/core/rendertype_solid.json: Minified
> assets/minecraft/textures/block/shuba.png: Optimized with 93% quality color quantization
> assets/minecraft/textures/block/cube.png: Optimized with 97% quality color quantization
! Pack processing error: An error occurred while processing a pack file
  Another error message with more information was emitted before. You might need to scroll up to see it.
  These troubleshooting instructions might be useful: <https://packsquash.page.link/Troubleshooting-pack-processing-errors>

Reproduction steps

  1. Download the following folder from objmc (the resource pack example): https://github.com/Godlander/objmc/tree/main/objmc
  2. Use the pack squash command on the downloaded folder with the basic config file:
    pack_directory = 'PATH_TO_PACK'
    output_file_path = 'PATH_OUTPUT'
    zip_spec_conformance_level = 'disregard'

Expected behavior

The pack should compile normally

Attached files

No response

Additional context

No response

AlexTMjugador commented 1 year ago

Hi! Thanks for reaching out to report your issue :smile:

As it happens with JSON files, the GLSL parser used by PackSquash is more strict than Minecraft. However, unlike with JSON files, I did not intend the GLSL parser to be that way, so I agree that PackSquash should improve in this regard, and understand why it may be seen as a "bug". (There is a point in enforcing strict JSON syntax, because JSON is meant to be a data exchange format, and Minecraft accepts deviations that other commonly used programs do not. However, GLSL is rather application-specific, especially when considering the fact that Mojang extended it with preprocessor directives such as #moj_import.)

The errors you experience are caused by two known limitations, described in this issue comment:

  • Preprocessor directives are only supported at the external declaration position (i.e. top level of a shader file). This means that PackSquash will spew errors if you use #moj_import inside a function, for example.
  • Included shaders (.glsl files) are parsed as translation units (i.e. standalone, normal vertex or fragment shaders). Therefore, included shaders must only contain declarations. They can't contain expressions that would only be valid inside declarations, such as var = 3. Such included shaders are only valid if they are always #moj_import'ed within a declaration (function, data type definition, etc.), which is currently not possible due to the previous point, but it's still worth keeping in mind.

Luckily, these limitations can be worked around with no functional differences (i.e., without affecting how the shaders work):

I reckon that applying these workarounds at scale can be tedious, but they should be enough to get your pack to compile for now. Sadly, I don't expect them to be fixed soon, due to current technical constraints caused by how PackSquash is designed, which will be addressed for v0.4.0.

Please let me know if this comment was helpful to you.

CallumBugajski commented 1 year ago

Hi Alex,

Thank you for your quick reply, we'll give the workarounds a try and I'll let you know if we need anything else.

Thank you, Callum

Godlander commented 1 year ago

Some preprocessor directives cannot simply be moved to the top of files, such as #ifdef, #else and #endif. These are not Mojang extensions and are part of OpenGL Specifications.

Although without the use of #moj_import these can be worked around by modifying the code in each individual shader to only use the parts that would be included after the preprocessor.

AlexTMjugador commented 1 year ago

Some preprocessor directives cannot simply be moved to the top of files, such as #ifdef, #else and #endif. These are not Mojang extensions and are part of OpenGL Specifications.

Right, I wasn't thinking on those! Indeed, they are part of the specification. And, while the specification is not crystal-clear about it, I think that PackSquash is wrong here, because the specification makes several statements that equate the GLSL preprocessor with the one you'd find on C.

The only reason for this particular limitation to exist is that the fork of the third-party GLSL parser PackSquash uses has it. Upstream has been unresponsive for quite some time now and AFAIK there are no better GLSL parsers PackSquash could use, so any fix will likely be made by me or other PackSquash contributor on that fork. Sadly, time is finite for me now, and I'm prioritizing getting v0.4.0 released, but PRs are welcome πŸ˜„

Godlander commented 1 year ago

That's understandable, and it is possible to work around the limitation so it is not a big deal.

I believe it can be resolved by keeping the newlines around any line starting with #, but that might be a suboptimal solution.

gp-Airee commented 1 year ago

Is there a way to turn off the parsing of .glsl files or exempt specific files from processing?

AlexTMjugador commented 1 year ago

Is there a way to turn off the parsing of .glsl files or exempt specific files from processing?

I'm afraid that PackSquash does not provide any options to do that, sorry. Would you mind elaborating on why are you interested in disabling such parsing? Are the discussed workarounds impractical in your scenario?

Ideally, I would like to address this issue by fixing the PackSquash GLSL parser rather than letting people sweep its problems under the rug.

Joshinn-io commented 1 year ago

I am currently in your # | packsquash support channel in discord, but we're hoping to get the minify-shaders option to work to skip trying to parse glsl files. I sent the example of how we tried to use it, but it didn't seem to work.

AlexTMjugador commented 1 year ago

Note to self (and potentially other interested parties): the naga crate offers the GLSL validation and transpilation features required by PackSquash and seems much better maintained and widely used. It might be worth switching to it to get rid of the issue of restrictive preprocessor directive positions. glsl-lang looks like another interesting alternative. glslopt may be an interesting addition, but it is abandoned and may not work fine with Minecraft or newer GLSL constructs. glsl-include may be useful as a base to implement #moj_import resolution and proper validation in this case, although it's likely it can't be used as is due to PackSquash design constraints.

UltraFaceguy commented 1 year ago

I recently wrote some shaders and was very disappointed to realize I can't release an update because of this. Definitely is "at scale" enough for the level of frustration to workaround is too high. I support an option to skip shader validation. No reason not to throw in a skip if the validator currently has known issues validating the base OpenGL Specifications, at least until it's actually accurate.

AlexTMjugador commented 1 year ago

I am aware of the disappointing reality that some shaders can't be used as-is with the current PackSquash release. I am also aware that it a fix for the situation is warranted and necessary, especially in situations where refactoring shaders is not a viable option. I'm sorry for the inconvenience it causes to some users.

However, I won't add an option to skip parsing GLSL files. I don't believe that is the proper way to approach this issue for several reasons:

That being said, while I appreciate feedback and understand that the problem can be frustrating, I'd like to kindly ask further commentors to avoid further "I'm affected by this too" comments, unless they add something new and constructive to the topic. I want to make PackSquash as good as it can be πŸ˜„

UltraFaceguy commented 1 year ago

Well I can respect having a vison and wanting things to align to it, my vision as an end-user is to compress a valid resource pack.

All the reasoning in the world can't work around that fact that I have a valid formatted resource pack with GLSL spec compliant shaders and can no longer use this project to compress it. Even if only a "subset of shaders" are affected at the end of the day preventing a project from failing to perform it's core purpose over the prospect of a temporary config boolean seems a bit silly.

Darwin1546 commented 1 year ago

This project declares itself as Minecraft: Java Edition resource and data pack optimizer Not as Minecraft: Java Edition resource and data pack parser

AlexTMjugador commented 1 year ago

I'm pleased to announce that I've just pushed a commit that allows PackSquash to support a wider variety of shaders, without resorting to changing options or throwing minification out of the window in the supported cases! :tada:

The technical details of how this was accomplished can be read at the commit description. In summary:

The new design of v0.4.0 allows removing at least the first and third classes of troublesome shaders, which means that v0.4.0 will be able to process most kinds of practical shaders automagically. (Edit: this redesign was scheduled for a later release.)

For now, I hope that these changes help at least some of you. You can try them out on the latest unstable builds. If you are using the PackSquash GitHub Action, you'll have to bring your own options file.

For those that were eager for an improvement in the situation, this represents my first concrete step forward :wink:

AlexTMjugador commented 1 year ago

As announced on Discord, the roadmap for v0.4.0 has changed, and it will be released soon with the partial fix for this issue described above.

This does not affect my plans to release a better fix in the future, once the necessary redesign originally planned for v0.4.0 lands in a future version, such as v0.5.0. With the more complete fix is in place, I'd feel comfortable adding a last-resort option to skip parsing to handle use cases that might not be feasible to support.

Thank you all for your patience :heart:

AlexTMjugador commented 1 year ago

Due to the fact that the redesign required for proper #moj_import expansion and source transformation mentioned above is taking a while, and this issue has been causing significant churn for some people, I have just reconsidered my stance on the situation.

Since the latest commits, PackSquash is now very conservative about which shaders it is willing to minify or prettify, in order to avoid unwanted parsing errors or surprises when loading the pack in-game as much as possible. This means that any shader that uses #moj_import will now not be minified or prettified, but PackSquash should work with all the problematic shader classes mentioned earlier in this issue. Parsing errors for shaders that use #moj_import are now considered tentative, meaning they show up in the output but only cause a fallback to no source transformation, to allow pack authors to decide for themselves if the error is a false positive or not.

I'll continue to work on better expansion and transformation capabilities, but I'd rather track them as separate enhancements and issues, since the shaders should at least "just work" now.

In any case, please feel free to give feedback on the latest changes! It's very welcome :smile:

UltraFaceguy commented 1 month ago

Saw this was back on the next release backlog, just as a note, v0.4.0 seems to now get tripped up on my tooltip shader, as well as some other random one that worked with the old minify_shader = false setting. Both of these shaders work fine in vanilla, and with the previous solution.

Image

Tooltip shader:

vec2 pad = vec2(3,3);
ivec3 sizes = ivec3(1,1,6);
uint base = 0x191614e2u;
uint[] tl = uint[](0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0xae7d36ffu,0xc28530ffu,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xae7d36ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xca8c32ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u);
uint[] tr = uint[](0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0xc28530ffu,0xae7d36ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xae7d36ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xcd9341ffu,0x1e0d00ffu);
uint[] bl = uint[](0x1e0d00ffu,0xc28530ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xae7d36ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x191614e2u,0x191614e2u,0x1e0d00ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0xae7d36ffu,0xc28530ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu);
uint[] br = uint[](0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xcd9341ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xae7d36ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0x191614e2u,0x191614e2u,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0xc28530ffu,0xae7d36ffu,0xf2b129ffu,0xf2b129ffu,0xf2b129ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu,0x1e0d00ffu);
uint[] t = uint[](0x1e0d00ffu,0xca8c32ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u);
uint[] l = uint[](0x1e0d00ffu,0xca8c32ffu,0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u);
uint[] r = uint[](0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xd59943ffu,0x1e0d00ffu);
uint[] b = uint[](0x191614e2u,0x191614e2u,0x191614e2u,0x191614e2u,0xca8c32ffu,0x1e0d00ffu);

Snippet from the text_effects.config.glsl shader:

TEXT_EFFECT(251, 255, 255) {
    //override_text_color(rgb(255, 255, 255));
    remove_text_shadow();
}
TEXT_EFFECT(251, 251, 255) {
    apply_skewing_movement();
    //override_text_color(rgb(255, 255, 255));
}
AlexTMjugador commented 1 month ago

Hi @UltraFaceguy, did you try the latest unstable builds? They should be more lenient when it comes to handling shader parsing errors. The issue was closed because the user-visible errors were fixed in such builds.