Mainly important for Shader::addSource() to prevent it from creating a
needless copy, but doesn't hurt to do the same also for
uniformLocation(), bindAttributeLocation() etc. -- it'll avoid a runtime
strlen() in that case at least.
Same as in the previous commit, most cases are inputs so a StringStl.h
compatibility include will do, the only breaking change is
GL::Shader::sources() which now returns a StringIterable instead of a
std::vector<std::string> (ew).
Awesome about this whole thing is that The Shader API now allows
creating a shader from sources coming either from string view literals
or Utility::Resource completely without having to allocate any strings
internally, because all those can be just non-owning references wrapped
with String::nullTerminatedGlobalView(). The only parts which aren't
references are the #line markers, but (especially on 64bit) those can
easily fit into the 22-byte (or 10-byte on 32bit) SSO storage.
Also, various Shader constructors and assignment operators had to be
deinlined in order to avoid having to include the String header, which
would be needed for Array destruction during a move.
Co-authored-by: Hugo Amiard <hugo.amiard@wonderlandengine.com>
It's not a GL error, and allows the application to compile just a single
shader for all skinned meshes, not one for each skeleton size. Together
with the dynamic per-vertex joint count this means the app only needs a
single shader for all skinned meshes, which is nice.
High-level docs with examples will be written once there's corresponding
support in MeshTools::compile() *and* in importer plugins, as skinned
meshes are usually brought in from files, never set up directly.
Co-authored-by: Squareys <squareys@googlemail.com>
* No need to repeat the type for all variables, unnecessary redundancy.
* Reducing the amount of redundant local variables and if they stay
making their definitions more localized to where they get used.
* All uniform setters used the "initial value is" phrase instead of
"default is", this one didn't.
Because it was no longer bearable with three UnsignedInt arguments in a
row, especially when some of them are only available on a subset of
platforms. And it would get even worse with introduction of planned
features such as multiview or skinning.
Backwards compatibility is in place, as always. To ensure nothing
breaks, this commit still has all tests and snippets using the old API.
Consistently with checkLink(), this avoids having to explicitly include
both Iterable and Reference in shader code. Alsod allowing people to
have direct arrays of shaders, runtime-sized lists of shaders etc.
A compat include is provided on a deprecated build to avoid breaking
existing code.
The class is rather heavy (strings, STL vector) and it'll stay heavier
than strictly needed even after the planned STL cleanup -- shader users
should not bear the overhead of Array, StringView etc. that it needs in
order to compile the shader sources.
I might eventually come to a different conclusion (maybe separating
GL::Shader population and usage like doing in Vulkan with CreateInfos),
but right now this commit has the best available solution -- converting
the instance to a lightweight class containing just ID and type, and
then converting that back to a GL::Shader upon checking compilation/link
status.
While at it, also removed the not-strictly-needed Optional usage from
the header. It wouldn't work with forward-declared GL::Shader anyway.
The new async APIs were just checking the link status, and printing the
linker error. Because drivers commonly do all that in a single step,
without really separating compilation from linking (or at least that's
what I thought?), I assumed the linker error would contain *also* the
compilation error, if any.
But on a quick check with Mesa that's not the case, I only get "error:
linking with uncompiled/unspecialized shader", which is very useless.
Which means, to get proper error output, the checkLink() function now
explicitly takes a list of the input shaders. It will unconditionally go
through them at the beginning and call checkCompile() on each.
To further encourage the shaders to be passed, there's no default
argument -- so if the application calls checkCompile() on its own for
some reason, it has to pass an empty list to checkLink().
Hah this took a while, as there was no texture scaffolding in place at
all. Thus all this had to be added and tested for the first time:
* 2D textures
* 2D texture arrays
* Texture transformation uniforms
* Texture transformation UBOs
* Instanced texture offset
This also means that MeshVisualizer can be used to visualize arbitrary
(single-channel) integer textures now, not just render meshes with
object ID textures. Yay for feature parity!
Mainly to have feature parity with Flat and Phong -- otherwise switching
to draw a wireframe on an instanced mesh would be too annoying. Also, if
we have multidraw there already, why not instancing as well.
Originally the uniform wasn't present with the assumption that users
could easily adjust color map offset to achieve the same effect. That
was however unnecessarily annoying and error-prone in cases where it's
essential to have the same object IDs from multiple draws have a
matching color, and it was complicating multidraw workflows as the color
map offset was not a part of per-draw data, but rather material data.
This is always true in the single-draw case, since setDrawOffset()
asserts on this. In the multi-draw case this optimization doesn't make
sense, because it doesn't make sense to create a multidraw shader with
just one draw.
On an Intel 630 GPU this resulted in single-draw single-material Phong
to go from 550 ms to 440, which is roughly a 20% improvement. For the
simpler shaders the difference is even higher. The multidraw numbers
stayed the same as before, obviously.
These deliberately share the same binding (because there's very little
space), but the shader wasn't guarding that. Discovered completely by
accident when adding tests for "multidraw with all the things" -- Mesa
gives just a warning, but ANGLE straight out fails the shader
compilation, so better have an assert there.
I just put this aside when I discovered the error, thinking it was a
Mesa bug. Now that ARM Mali yelled about the same, I realized it wasn't
just Mesa.
Note to self: Mesa has no bugs. Can you just finally accept that?!
It probably didn't matter as much as the only platform without
ARB_explicit_uniform_location is Mac, which doesn't have
ARB_shading_language_420pack either.
* Shader compilation failed with vertex, object and primitive ID
enabled due to the NO_GEOMETRY_SHADER define not being correctly
propagated
* Enabling just vertex ID visualization on WebGL caused an assert in
constructor, complaining that "at least one visualization feature has
to be enabled", which is wrong
* Defaults were not correctly set up for vertex ID rendering, causing
all-black render when setColor() wasn't called
* Forgot to list/bundle some ground truth test images for the test
case, causing the test to fail due to files not found
* The test asserted when generating mesh data due to an unhandled
corner case
* The test expected an ES2 assertion message on WebGL 2
* Flag::Wireframe now implicitly enables Flag::NoGeometryShader also on
WebGL. This was done only for ES2 previously, but WebGL doesn't have
(and won't have) geometry shaders, so it makes sense to do the same
there.
It was rendering everything with a plain color, which is rather useless.
Moreover it wasn't consistent with TBN visualization where you might
actually want only the lines rendered and not the triangle.
Bloaty says it saved 10 kB in Debug build of MagnumGL:
VM SIZE FILE SIZE
-------------- --------------
[ = ] 0 .debug_info +1.59Ki +0.0%
+0.4% +1.50Ki .text +1.50Ki +0.4%
[ = ] 0 .debug_str +409 +0.0%
[ = ] 0 .debug_line +276 +0.1%
[ = ] 0 .debug_abbrev +20 +0.0%
-28.6% -2 [LOAD [RX]] -2 -28.6%
[ = ] 0 [Unmapped] -4.28Ki -41.0%
-22.7% -9.23Ki .rodata -9.23Ki -22.7%
-0.8% -7.73Ki TOTAL -9.73Ki -0.1%
And 4 kB in Release:
VM SIZE FILE SIZE
-------------- --------------
+1.1% +3.44Ki .text +3.44Ki +1.1%
+1.7% +1.39Ki .eh_frame +1.39Ki +1.7%
[ = ] 0 [Unmapped] +656 +51%
-25.5% -9.47Ki .rodata -9.47Ki -25.5%
-0.7% -4.64Ki TOTAL -4.00Ki -0.4%
That's not negative, so I guess that's good. This change is of course
more significant in the context of a minimal WebGL build, where the exe
can be as little as 50 kB -- there 4 kB is almost 10% of the size.
This only generates code that will be never executed. Tested with Flat
and Phong, the other shaders don't have rendering tests yet but since
the change is the same, I assume it will work there as well.