Browse Source

Shaders: fix various WebGL issues with new MeshVisualizer features.

* 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.
pull/454/head
Vladimír Vondruš 6 years ago
parent
commit
1436b7bc86
  1. 4
      doc/changelog.dox
  2. 31
      src/Magnum/Shaders/MeshVisualizer.cpp
  3. 27
      src/Magnum/Shaders/MeshVisualizer.h
  4. 2
      src/Magnum/Shaders/Test/CMakeLists.txt
  5. 9
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  6. 4
      src/Magnum/Shaders/Test/MeshVisualizerTest.cpp

4
doc/changelog.dox

@ -340,6 +340,10 @@ See also:
`Magnum/version.h` header. This header is not included by any other header `Magnum/version.h` header. This header is not included by any other header
to avoid trigerring a full rebuild when Git commit changes. If Git is not to avoid trigerring a full rebuild when Git commit changes. If Git is not
found, only the first two defines are present. found, only the first two defines are present.
- @ref Shaders::MeshVisualizer3D::Flag::Wireframe now implicitly enables
@ref Shaders::MeshVisualizer3D::Flag::NoGeometryShader also on WebGL in
addition to ES2, since this platform doesn't have a possibility to have
geometry shaders either. Same is done for @ref Shaders::MeshVisualizer2D.
@subsubsection changelog-latest-changes-audio Audio library @subsubsection changelog-latest-changes-audio Audio library

31
src/Magnum/Shaders/MeshVisualizer.cpp

@ -125,7 +125,6 @@ GL::Version MeshVisualizerBase::setupShaders(GL::Shader& vert, GL::Shader& frag,
#endif #endif
; ;
frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "") frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(_flags & FlagBase::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "")
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
.addSource(_flags & FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") .addSource(_flags & FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
.addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "") .addSource(_flags & FlagBase::VertexId ? "#define VERTEX_ID\n" : "")
@ -200,12 +199,18 @@ MeshVisualizer2D::MeshVisualizer2D(const Flags flags): Implementation::MeshVisua
vert.addSource("#define TWO_DIMENSIONS\n") vert.addSource("#define TWO_DIMENSIONS\n")
/* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when /* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when
nothing actually needs it, as that makes checks much simpler in nothing actually needs it, as that makes checks much simpler in
the vertex shader code */ the shader code */
.addSource((flags & Flag::NoGeometryShader) || !(flags & Flag::Wireframe) ? .addSource((flags & Flag::NoGeometryShader) || !(flags & Flag::Wireframe) ?
"#define NO_GEOMETRY_SHADER\n" : "") "#define NO_GEOMETRY_SHADER\n" : "")
.addSource(rs.get("generic.glsl")) .addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.vert")); .addSource(rs.get("MeshVisualizer.vert"));
frag.addSource(rs.get("generic.glsl")) frag
/* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when
nothing actually needs it, as that makes checks much simpler in
the shader code */
.addSource((flags & Flag::NoGeometryShader) || !(flags & Flag::Wireframe) ?
"#define NO_GEOMETRY_SHADER\n" : "")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.frag")); .addSource(rs.get("MeshVisualizer.frag"));
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -292,7 +297,7 @@ MeshVisualizer2D::MeshVisualizer2D(const Flags flags): Implementation::MeshVisua
setTransformationProjectionMatrix({}); setTransformationProjectionMatrix({});
if(flags & (Flag::Wireframe if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::PrimitiveIdFromVertexId |Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif #endif
)) ))
setColor(Color3(1.0f)); setColor(Color3(1.0f));
@ -340,7 +345,7 @@ MeshVisualizer3D::MeshVisualizer3D(const Flags flags): Implementation::MeshVisua
CORRADE_ASSERT(!(flags & Flag::BitangentDirection && flags & Flag::BitangentFromTangentDirection), CORRADE_ASSERT(!(flags & Flag::BitangentDirection && flags & Flag::BitangentFromTangentDirection),
"Shaders::MeshVisualizer3D: Flag::BitangentDirection and Flag::BitangentFromTangentDirection are mutually exclusive", ); "Shaders::MeshVisualizer3D: Flag::BitangentDirection and Flag::BitangentFromTangentDirection are mutually exclusive", );
#elif !defined(MAGNUM_TARGET_GLES2) #elif !defined(MAGNUM_TARGET_GLES2)
CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::InstancedObjectId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader), CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader),
"Shaders::MeshVisualizer3D: at least one visualization feature has to be enabled", ); "Shaders::MeshVisualizer3D: at least one visualization feature has to be enabled", );
#else #else
CORRADE_ASSERT(flags & (Flag::Wireframe & ~Flag::NoGeometryShader), CORRADE_ASSERT(flags & (Flag::Wireframe & ~Flag::NoGeometryShader),
@ -377,6 +382,14 @@ MeshVisualizer3D::MeshVisualizer3D(const Flags flags): Implementation::MeshVisua
.addSource(rs.get("generic.glsl")) .addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.vert")); .addSource(rs.get("MeshVisualizer.vert"));
frag frag
/* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when
nothing actually needs it, as that makes checks much simpler in
the vertex shader code */
.addSource((flags & Flag::NoGeometryShader) || !(flags & (Flag::Wireframe
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
|Flag::TangentDirection|Flag::BitangentDirection|Flag::BitangentFromTangentDirection|Flag::NormalDirection
#endif
)) ? "#define NO_GEOMETRY_SHADER\n" : "")
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
.addSource(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection) ? "#define TBN_DIRECTION\n" : "") .addSource(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection) ? "#define TBN_DIRECTION\n" : "")
#endif #endif
@ -504,7 +517,7 @@ MeshVisualizer3D::MeshVisualizer3D(const Flags flags): Implementation::MeshVisua
setProjectionMatrix({}); setProjectionMatrix({});
if(flags & (Flag::Wireframe if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::PrimitiveIdFromVertexId |Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif #endif
)) ))
setColor(Color3(1.0f)); setColor(Color3(1.0f));
@ -652,7 +665,8 @@ Debug& operator<<(Debug& debug, const MeshVisualizer3D::Flag value) {
Debug& operator<<(Debug& debug, const MeshVisualizer2D::Flags value) { Debug& operator<<(Debug& debug, const MeshVisualizer2D::Flags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer2D::Flags{}", { return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer2D::Flags{}", {
MeshVisualizer2D::Flag::Wireframe, MeshVisualizer2D::Flag::Wireframe,
/* Wireframe contains this on ES2 so it's not reported there */ /* Wireframe contains this on ES2 and WebGL 1 so it's not reported
there */
MeshVisualizer2D::Flag::NoGeometryShader, MeshVisualizer2D::Flag::NoGeometryShader,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
MeshVisualizer2D::Flag::InstancedObjectId, MeshVisualizer2D::Flag::InstancedObjectId,
@ -668,7 +682,8 @@ Debug& operator<<(Debug& debug, const MeshVisualizer2D::Flags value) {
Debug& operator<<(Debug& debug, const MeshVisualizer3D::Flags value) { Debug& operator<<(Debug& debug, const MeshVisualizer3D::Flags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer3D::Flags{}", { return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer3D::Flags{}", {
MeshVisualizer3D::Flag::Wireframe, MeshVisualizer3D::Flag::Wireframe,
/* Wireframe contains this on ES2 so it's not reported there */ /* Wireframe contains this on ES2 and WebGL 1 so it's not reported
there */
MeshVisualizer3D::Flag::NoGeometryShader, MeshVisualizer3D::Flag::NoGeometryShader,
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
MeshVisualizer3D::Flag::TangentDirection, MeshVisualizer3D::Flag::TangentDirection,

27
src/Magnum/Shaders/MeshVisualizer.h

@ -43,11 +43,10 @@ namespace Implementation {
class MAGNUM_SHADERS_EXPORT MeshVisualizerBase: public GL::AbstractShaderProgram { class MAGNUM_SHADERS_EXPORT MeshVisualizerBase: public GL::AbstractShaderProgram {
protected: protected:
enum class FlagBase: UnsignedShort { enum class FlagBase: UnsignedShort {
#ifndef MAGNUM_TARGET_GLES2 /* Unlike the public Wireframe flag, this one doesn't include
NoGeometryShader on ES2 as that would make the checks too
complex */
Wireframe = 1 << 0, Wireframe = 1 << 0,
#else
Wireframe = (1 << 0) | (1 << 1),
#endif
NoGeometryShader = 1 << 1, NoGeometryShader = 1 << 1,
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
InstancedObjectId = 1 << 2, InstancedObjectId = 1 << 2,
@ -169,10 +168,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer2D: public Implementation::MeshVisuali
*/ */
enum class Flag: UnsignedShort { enum class Flag: UnsignedShort {
/** /**
* Visualize wireframe. On OpenGL ES 2.0 this also enables * Visualize wireframe. On OpenGL ES 2.0 and WebGL this also
* @ref Flag::NoGeometryShader. * enables @ref Flag::NoGeometryShader.
*/ */
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
Wireframe = 1 << 0, Wireframe = 1 << 0,
#else #else
Wireframe = (1 << 0) | (1 << 1), Wireframe = (1 << 0) | (1 << 1),
@ -181,8 +180,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer2D: public Implementation::MeshVisuali
/** /**
* Don't use a geometry shader for wireframe visualization. If * Don't use a geometry shader for wireframe visualization. If
* enabled, you might need to provide also the @ref VertexIndex * enabled, you might need to provide also the @ref VertexIndex
* attribute in the mesh. In OpenGL ES 2.0 enabled alongside * attribute in the mesh. On OpenGL ES 2.0 and WebGL enabled
* @ref Flag::Wireframe. * alongside @ref Flag::Wireframe.
*/ */
NoGeometryShader = 1 << 1, NoGeometryShader = 1 << 1,
@ -589,10 +588,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer3D: public Implementation::MeshVisuali
*/ */
enum class Flag: UnsignedShort { enum class Flag: UnsignedShort {
/** /**
* Visualize wireframe. On OpenGL ES 2.0 this also enables * Visualize wireframe. On OpenGL ES 2.0 and WebGL this also
* @ref Flag::NoGeometryShader. * enables @ref Flag::NoGeometryShader.
*/ */
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
Wireframe = 1 << 0, Wireframe = 1 << 0,
#else #else
Wireframe = (1 << 0) | (1 << 1), Wireframe = (1 << 0) | (1 << 1),
@ -601,8 +600,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer3D: public Implementation::MeshVisuali
/** /**
* Don't use a geometry shader for wireframe visualization. If * Don't use a geometry shader for wireframe visualization. If
* enabled, you might need to provide also the @ref VertexIndex * enabled, you might need to provide also the @ref VertexIndex
* attribute in the mesh. In OpenGL ES 2.0 enabled alongside * attribute in the mesh. On OpenGL ES 2.0 and WebGL enabled
* @ref Flag::Wireframe. * alongside @ref Flag::Wireframe.
* *
* Mutually exclusive with @ref Flag::TangentDirection, * Mutually exclusive with @ref Flag::TangentDirection,
* @ref Flag::BitangentFromTangentDirection, * @ref Flag::BitangentFromTangentDirection,

2
src/Magnum/Shaders/Test/CMakeLists.txt

@ -174,6 +174,8 @@ if(BUILD_GL_TESTS)
MeshVisualizerTestFiles/vertexid3D.tga MeshVisualizerTestFiles/vertexid3D.tga
MeshVisualizerTestFiles/wireframe-nogeo2D.tga MeshVisualizerTestFiles/wireframe-nogeo2D.tga
MeshVisualizerTestFiles/wireframe-nogeo3D.tga MeshVisualizerTestFiles/wireframe-nogeo3D.tga
MeshVisualizerTestFiles/wireframe-objectid2D.tga
MeshVisualizerTestFiles/wireframe-objectid3D.tga
MeshVisualizerTestFiles/wireframe-nogeo-objectid2D.tga MeshVisualizerTestFiles/wireframe-nogeo-objectid2D.tga
MeshVisualizerTestFiles/wireframe-nogeo-objectid3D.tga MeshVisualizerTestFiles/wireframe-nogeo-objectid3D.tga
MeshVisualizerTestFiles/wireframe-perspective.tga MeshVisualizerTestFiles/wireframe-perspective.tga

9
src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp

@ -207,7 +207,7 @@ constexpr struct {
} ConstructInvalidData2D[] { } ConstructInvalidData2D[] {
{"no feature enabled", {"no feature enabled",
MeshVisualizer2D::Flag::NoGeometryShader, /* not a feature flag */ MeshVisualizer2D::Flag::NoGeometryShader, /* not a feature flag */
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #ifndef MAGNUM_TARGET_GLES2
"2D: at least one visualization feature has to be enabled" "2D: at least one visualization feature has to be enabled"
#else #else
"2D: at least Flag::Wireframe has to be enabled" "2D: at least Flag::Wireframe has to be enabled"
@ -230,7 +230,7 @@ constexpr struct {
} ConstructInvalidData3D[] { } ConstructInvalidData3D[] {
{"no feature enabled", {"no feature enabled",
MeshVisualizer3D::Flag::NoGeometryShader, /* not a feature flag */ MeshVisualizer3D::Flag::NoGeometryShader, /* not a feature flag */
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #ifndef MAGNUM_TARGET_GLES2
"3D: at least one visualization feature has to be enabled" "3D: at least one visualization feature has to be enabled"
#else #else
"3D: at least Flag::Wireframe has to be enabled" "3D: at least Flag::Wireframe has to be enabled"
@ -1583,8 +1583,11 @@ void MeshVisualizerGLTest::renderObjectVertexPrimitiveId2D() {
if(data.flags2D >= MeshVisualizer2D::Flag::PrimitiveIdFromVertexId) if(data.flags2D >= MeshVisualizer2D::Flag::PrimitiveIdFromVertexId)
circleData = MeshTools::generateIndices(circleData); circleData = MeshTools::generateIndices(circleData);
if(data.flags2D >= MeshVisualizer2D::Flag::PrimitiveIdFromVertexId || if(data.flags2D >= MeshVisualizer2D::Flag::PrimitiveIdFromVertexId ||
data.flags2D & MeshVisualizer2D::Flag::NoGeometryShader) data.flags2D & MeshVisualizer2D::Flag::NoGeometryShader) {
if(circleData.primitive() != MeshPrimitive::Triangles)
circleData = MeshTools::generateIndices(circleData);
circleData = MeshTools::duplicate(circleData); circleData = MeshTools::duplicate(circleData);
}
GL::Mesh circle = MeshTools::compile(circleData); GL::Mesh circle = MeshTools::compile(circleData);

4
src/Magnum/Shaders/Test/MeshVisualizerTest.cpp

@ -124,7 +124,7 @@ void MeshVisualizerTest::debugFlags2D() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << (MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader) << MeshVisualizer2D::Flags{}; Debug{&out} << (MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader) << MeshVisualizer2D::Flags{};
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe|Shaders::MeshVisualizer2D::Flag::NoGeometryShader Shaders::MeshVisualizer2D::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe|Shaders::MeshVisualizer2D::Flag::NoGeometryShader Shaders::MeshVisualizer2D::Flags{}\n");
#else #else
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe Shaders::MeshVisualizer2D::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe Shaders::MeshVisualizer2D::Flags{}\n");
@ -135,7 +135,7 @@ void MeshVisualizerTest::debugFlags3D() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << (MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader) << MeshVisualizer3D::Flags{}; Debug{&out} << (MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader) << MeshVisualizer3D::Flags{};
#ifndef MAGNUM_TARGET_GLES2 #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe|Shaders::MeshVisualizer3D::Flag::NoGeometryShader Shaders::MeshVisualizer3D::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe|Shaders::MeshVisualizer3D::Flag::NoGeometryShader Shaders::MeshVisualizer3D::Flags{}\n");
#else #else
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe Shaders::MeshVisualizer3D::Flags{}\n"); CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe Shaders::MeshVisualizer3D::Flags{}\n");

Loading…
Cancel
Save