Stop doing this:
GL20.glUniformMatrix4(
GL20.glGetUniformLocation(getProgram(), "projectionMatrix"),
[...]
Uniform locations do not change after you link your program, and querying anything from OpenGL is a great way to kill performance.
This particular Get
function is particularly expensive because it uses a string to identify the location you are searching for. String comparisons are slow unless optimized into something like a trie, hash tables, etc... and the expense grows as you add more potential matches to the set of searched strings. Neither OpenGL nor GLSL defines how this function has to be implemented, but you should assume that your implementation is as stupid as they come if you are concerned about performance.
Keep a GLint
handy for your frequently used named uniforms. I would honestly suggest writing a class that encapsulates a GLSL program object, and then subclass this for any specialization. The specialized classes would store all of the uniform locations they need and you would never have to query GL for uniform locations.