/Shader_Minifier

Minify and obfuscate GLSL or HLSL code

Primary LanguageGLSLApache License 2.0Apache-2.0

Shader Minifier

Build status

Shader Minifier is a tool that minifies and obfuscates shader code (GLSL and HLSL). Its original use-case is for the demoscene, for optimizing 4k and 64k intros. It is also suitable for reducing the size of the shaders in other applications (e.g. webgl, games).

In the context of 4kB intros, Shader Minifier help developers maintain and iterate on human-readable files, while shipping optimized code. Even when a shader is minified by hand by experienced demosceners, Shader Minifier is often able to optimize it further. See this 2010 report.

If your application uses multiple shaders, use the --preserve-externals option. Values such as the uniforms won't be renamed, which makes it easier to use in your application (at the expense of a slightly bigger shader).

Features

  • Parse and print the GLSL or HLSL code.
  • Generate a file (such as a C header) that can be embedded in an application.
  • Strip spaces, remove comments.
  • Remove useless parens.
  • Simplify constant expressions: 3.14159 * 2. becomes 6.28318.
  • Remove curly braces whenever possible: if(test){v.x=4; return b++;} is replaced with if(test)return v.x=4,b++;.
  • Squeeze definitions: float a=2.;float b; becomes float a=2.,b;.
  • Consistently rename vector fields (e.g. use foo.xy instead of foo.rg) to help the compression.
  • Rename variables, typically to one character.
  • Reuse the variable names as much as possible: a local variable may have the same name as a global variable not used in the function; two functions may have the same name using function overloading.
  • Analyze the context and make statistics to compute the variable name that will be the most compression-friendly.
  • Optionally inline variables.

Example output

/* File generated with Shader Minifier 1.1.6
 * http://www.ctrl-alt-test.fr
 */
#ifndef HEART_FRAG_EXPECTED_
# define HEART_FRAG_EXPECTED_
# define VAR_MOUSE "f"
# define VAR_RESOLUTION "y"
# define VAR_TIME "v"

const char *heart_frag =
 "uniform float v;"
 "uniform vec2 y;"
 "uniform vec4 f;"
 "void main()"
 "{"
   "vec2 f=(2.*gl_FragCoord.xy-y)/y.y;"
   "float r=mod(v,2.)/2.,a=pow(r,.2)*.5+.5;"
   "a-=a*.2*sin(r*6.2831*5.)*exp(-r*6.);"
   "f*=vec2(.5,1.5)+a*vec2(.5,-.5);"
   "float m=atan(f.x,f.y)/3.14159,x=length(f),e=abs(m),o=(13.*e-22.*e*e+10.*e*e*e)/(6.-5.*e),l=step(x,o)*pow(1.-x/o,.25);"
   "gl_FragColor=vec4(l,0.,0.,1.);"
 "}";

#endif // HEART_FRAG_EXPECTED_

Usage

Download Shader Minifier here: https://github.com/laurentlb/Shader_Minifier/releases

It is a command-line tool. Without argument, it will show the usage. If you are not on Windows, you will need mono:

$ shader_minifier.exe  # Windows
$ mono shader_minifier.exe  # Linux, Mac...
USAGE: shader_minifier.exe [--help] [-o <string>] [-v] [--hlsl] [--format <text|c-variables|c-array|js|nasm>]
                           [--field-names <rgba|xyzw|stpq>] [--preserve-externals] [--preserve-all-globals]
                           [--no-renaming] [--no-renaming-list <string>] [--no-sequence] [--smoothstep] [<filename>...]

FILENAMES:

    <filename>...         List of files to minify

OPTIONS:

    -o <string>           Set the output filename (default is shader_code.h)
    -v                    Verbose, display additional information
    --hlsl                Use HLSL (default is GLSL)
    --format <text|c-variables|c-array|js|nasm>
                          Choose to format the output (use none if you want just the shader)
    --field-names <rgba|xyzw|stpq>
                          Choose the field names for vectors: 'rgba', 'xyzw', or 'stpq'
    --preserve-externals  Do not rename external values (e.g. uniform)
    --preserve-all-globals
                          Do not rename functions and global variables
    --no-renaming         Do not rename anything
    --no-renaming-list <string>
                          Comma-separated list of functions to preserve
    --no-sequence         Do not use the comma operator trick
    --smoothstep          Use IQ's smoothstep trick
    --help                display this list of options.

In short:

  • List the shaders you want to minify on the command-line.

  • Use -o to choose the output file (by default, it will use shader_code.h). If you pass - for the output, it will be printed on stdout.

  • Use --format to control the output format. By default, it will create a C header. There are other options to get only the shader, or have it in a .js or nasm file.

Tips

4kB intros

4kB intros typically use a single shader file. The default flags should work well:

shader_minifier.exe -o shader_code.h fragment.glsl

We recommend that you frequently check the output of Shader Minifier to make sure there are no obvious problems. Use inlining where possible.

If you desperately need to save a few bytes, try another value of --field-names. It can affect the size after compression.

64kB intros

The recommandation is to use:

shader_minifier.exe --format c-array --preserve-externals *.frag -o shaders.h

Then, in your C or C++ code, include the file:

const char* shaderSources[] = {
#include shaders.h
};

Since the uniforms are not renamed, prefer shorter names when possible. Hopefully a future version of Shader Minifier will improve this.

Javascript

Use --format js. It will define a variable for each shader, the variable name being derived from the input file. We expect you to run a Javascript minifier on the output file.

Other applications

The simplest solution is to minify each file separately:

shader_minifier.exe --format text --preserve-externals file.glsl -o file_opt.glsl

The output may be used as a drop-in replacement for your original shaders.

Macros

Shader Minifier will preserve the preprocessor directives (the lines starting with #), except that it strips the spaces.

If you define a macro, Shader Minifier will notice the name of the macro and won't rename the occurrences of the macro. It also doesn't rename variables used inside the macro. Clever macros are discouraged and can break the shader.

Verbatim

If you want to temporary turn off the minifier, use the //[ and //] comments. This can be useful as a workaround if you get a parser error.

Variables inside the region won't be renamed. Spaces will be stripped.

//[
[maxvertexcount(3)]
//]
void GSScene( triangleadj GSSceneIn input[6], inout TriangleStream<PSSceneIn> OutputStream )
{   
    PSSceneIn output = (PSSceneIn)0;
    ...
}

Inlining

Shader Minifier will inline any variable that starts with i_. Inlining can allow the Minifier to simplify the code further.

For example, this input:

bool i_debug = false;
int i_level = 5;

int foo(int x, int y) {
  if (i_debug) {
    x++;
  }

  return 2 * i_level * x;
}

will be simplified into:

int foo(int x,int y)
{
  return 10*x;
}

It's often a good idea to inline the variables that are used only once. The minifier currently doesn't this trick automatically because this can be unsafe (in presence of side effects).

If you want to aggressively reduce the size of your shader, try inlining other variables. Inlining can have performance implications though (if the variable stored the result of a computation), so be careful with it.

Inlining can lead to repetition in the shader code, which may make the shader longer (but the output may be more compression-friendly).

Overloading

At this time, do not use overloaded functions (two functions with the same name but different arguments) in the input. The output probably won't compile.

On the other hand, Shader Minifier will aggressively use function overloading in the output. If two functions have a different number of arguments, they may have the same name in the output. This reduces the number of identifiers used by the shader and make it more compression friendly.

Bugs and limitations

  • The parser is not complete. Some constructs are not yet supported.
  • Don't use overloaded functions.
  • Avoid macros that contain references to other variables.

Please give feedback in the bugtracker. If something is blocking you, you can file a bug or update an existing bug. We rely on your feedback to prioritize the work.


Slightly outdated user manual: http://www.ctrl-alt-test.fr/?page_id=7

Contributions are welcome.

Created by Laurent Le Brun (LLB / Ctrl-Alt-Test).

http://laurent.le-brun.eu http://ctrl-alt-test.fr