From a95fdb55981e78f4200b2a0a0dd7ab7143f31bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 2 Oct 2024 21:09:42 +0200 Subject: [PATCH] GL: implement EXT_clip_control and WEBGL_polygon_mode on Emscripten. Following the spirit of extension-based functionality, the entrypoints are available always but do something (i.e., call the actual WebGL API) only if the extension is advertised. Which it is only on Emscripten 3.1.66+ because older versions don't have the corresponding entrypoints, so there it's marked as disabled. Additionally, EXT_polygon_offset_clamp is now also working on 3.1.66+, but there's no wrapper for it yet. --- doc/changelog.dox | 16 +++--- doc/opengl-support.dox | 4 +- .../GL/Implementation/RendererState.cpp | 23 +++++++- src/Magnum/GL/Implementation/RendererState.h | 2 +- .../GL/Implementation/driverSpecific.cpp | 10 ++++ src/Magnum/GL/Renderer.cpp | 20 +++++-- src/Magnum/GL/Renderer.h | 55 ++++++++++++------- src/Magnum/GL/Test/RendererGLTest.cpp | 20 ++----- 8 files changed, 99 insertions(+), 51 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index ed2b3cf1e..9b5fb6b28 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -129,8 +129,9 @@ See also: extensions on GLES 3.1+, exposed as @ref GL::Texture::view() and similar APIs on other texture types - Implemented the GL 4.5 @gl_extension{ARB,clip_control} extension and - matching @gl_extension{EXT,clip_control} extension on GLES, exposed as - @ref GL::Renderer::setClipControl(). See also [mosra/magnum#543](https://github.com/mosra/magnum/issues/543). + matching @gl_extension{EXT,clip_control} and + @webgl_extension{WEBGL,clip_control} extension on GLES and WebGL, exposed + as @ref GL::Renderer::setClipControl(). See also [mosra/magnum#543](https://github.com/mosra/magnum/issues/543). - Implemented @gl_extension{EXT,texture_norm16} and @webgl_extension{EXT,texture_norm16} ES and WebGL extensions, making normalized 16-bit texture and renderbuffer formats available on all @@ -156,18 +157,19 @@ See also: WebGL extensions, making @ref GL::SamplerWrapping::MirrorClampToEdge available on all platforms - Implemented the @m_class{m-doc-external} [ANGLE_provoking_vertex](https://chromium.googlesource.com/angle/angle/+/main/extensions/ANGLE_provoking_vertex.txt) - and @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt) - ES extensions. Recognized also on WebGL as - @webgl_extension{WEBGL,provoking_vertex} and - @webgl_extension{WEBGL,polygon_mode} but with no implementation as + ES extension. Recognized also on WebGL as + @webgl_extension{WEBGL,provoking_vertex} but with no implementation as Emscripten doesn't have the required entrypoints yet. +- Implemented the @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt) + and @webgl_extension{WEBGL,polygon_mode} ES and WebGL extension. - Implemented the @m_class{m-doc-external} [ANGLE_stencil_texturing](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_stencil_texturing.txt) ES and @webgl_extension{WEBGL,stencil_texturing} WebGL extensions - Implemented the @gl_extension{EXT,blend_func_extended} ES and @webgl_extension{WEBGL,blend_func_extended} WebGL extensions - Implemented the @gl_extension{INTEL,blackhole_render} desktop and ES extension -- Recognizing @webgl_extension{EXT,float_blend} and +- Recognizing @webgl_extension{EXT,float_blend}, + @webgl_extension{EXT,polygon_offset_clamp} and @webgl_extension{WEBGL,debug_shaders} WebGL extensions, no implementation done yet - Implemented @ref GL-AbstractShaderProgram-async "Async shader compilation and linking" diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 82941abaa..5502a3ec9 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -576,7 +576,7 @@ Extension | Status @webgl_extension{EXT,texture_compression_bptc} | done @webgl_extension{EXT,texture_norm16} | done @webgl_extension{EXT,polygon_offset_clamp} | | -@webgl_extension{EXT,clip_control} | | +@webgl_extension{EXT,clip_control} | done @webgl_extension{EXT,depth_clamp} | done @webgl_extension{EXT,texture_mirror_clamp_to_edge} | done @webgl_extension{KHR,parallel_shader_compile} | done @@ -598,7 +598,7 @@ Extension | Status @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} | done @webgl_extension{WEBGL,multi_draw_instanced_base_vertex_base_instance} | done @webgl_extension{WEBGL,provoking_vertex} | missing support in Emscripten -@webgl_extension{WEBGL,polygon_mode} | | +@webgl_extension{WEBGL,polygon_mode} | done @webgl_extension{WEBGL,blend_func_extended} | done @webgl_extension{WEBGL,stencil_texturing} | done diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index c9dc95ebd..03ee24bd8 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/src/Magnum/GL/Implementation/RendererState.cpp @@ -31,6 +31,16 @@ #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" +/* The __EMSCRIPTEN_major__ etc macros used to be passed implicitly, version + 3.1.4 moved them to a version header and version 3.1.23 dropped the + backwards compatibility. To work consistently on all versions, including the + header only if the version macros aren't present. + https://github.com/emscripten-core/emscripten/commit/f99af02045357d3d8b12e63793cef36dfde4530a + https://github.com/emscripten-core/emscripten/commit/f76ddc702e4956aeedb658c49790cc352f892e4c */ +#if defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(__EMSCRIPTEN_major__) +#include +#endif + namespace Magnum { namespace GL { namespace Implementation { using namespace Containers::Literals; @@ -206,7 +216,8 @@ RendererState::RendererState(Context& context, ContextState& contextState, Conta #endif #endif - #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + #ifdef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_WEBGL if(context.isExtensionSupported()) { extensions[Extensions::NV::polygon_mode::Index] = Extensions::NV::polygon_mode::string(); @@ -215,7 +226,15 @@ RendererState::RendererState(Context& context, ContextState& contextState, Conta extensions[Extensions::ANGLE::polygon_mode::Index] = Extensions::ANGLE::polygon_mode::string(); polygonModeImplementation = glPolygonModeANGLE; - } else { + } else + #elif __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30166 + if(context.isExtensionSupported()) { + extensions[Extensions::WEBGL::polygon_mode::Index] = + Extensions::WEBGL::polygon_mode::string(); + polygonModeImplementation = glPolygonModeWEBGL; + } else + #endif + { polygonModeImplementation = nullptr; } #endif diff --git a/src/Magnum/GL/Implementation/RendererState.h b/src/Magnum/GL/Implementation/RendererState.h index 3ff0ab954..a27bb44d5 100644 --- a/src/Magnum/GL/Implementation/RendererState.h +++ b/src/Magnum/GL/Implementation/RendererState.h @@ -59,7 +59,7 @@ struct RendererState { void(APIENTRY *blendFuncSeparateiImplementation)(GLuint, GLenum, GLenum, GLenum, GLenum); void(APIENTRY *colorMaskiImplementation)(GLuint, GLboolean, GLboolean, GLboolean, GLboolean); #endif - #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + #ifdef MAGNUM_TARGET_GLES void(APIENTRY *polygonModeImplementation)(GLenum, GLenum); #endif #ifndef MAGNUM_TARGET_WEBGL diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index c0b99b200..35147cc5c 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -732,6 +732,16 @@ void Context::setupDriverWorkarounds() { #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ < 20000 _setRequiredVersion(WEBGL::multi_draw, None); #endif + /* EXT_clip_control, EXT_polygon_offset_clamp and WEBGL_polygon_mode + entrypoints are only available since Emscripten 3.1.66: + https://github.com/emscripten-core/emscripten/pull/20841 + However, the extension is advertised even on older versions and we have + no way to link to those entrypoints there. */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ < 30166 + _setRequiredVersion(EXT::clip_control, None); + _setRequiredVersion(EXT::polygon_offset_clamp, None); + _setRequiredVersion(WEBGL::polygon_mode, None); + #endif #ifndef MAGNUM_TARGET_GLES2 /* WEBGL_multi_draw_instanced_base_vertex_base_instance only since Emscripten 2.0.5: https://github.com/emscripten-core/emscripten/pull/12282 */ diff --git a/src/Magnum/GL/Renderer.cpp b/src/Magnum/GL/Renderer.cpp index a128b3127..fc44dc76c 100644 --- a/src/Magnum/GL/Renderer.cpp +++ b/src/Magnum/GL/Renderer.cpp @@ -33,6 +33,16 @@ #include "Magnum/GL/Implementation/State.h" #include "Magnum/GL/Implementation/RendererState.h" +/* The __EMSCRIPTEN_major__ etc macros used to be passed implicitly, version + 3.1.4 moved them to a version header and version 3.1.23 dropped the + backwards compatibility. To work consistently on all versions, including the + header only if the version macros aren't present. + https://github.com/emscripten-core/emscripten/commit/f99af02045357d3d8b12e63793cef36dfde4530a + https://github.com/emscripten-core/emscripten/commit/f76ddc702e4956aeedb658c49790cc352f892e4c */ +#if defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(__EMSCRIPTEN_major__) +#include +#endif + namespace Magnum { namespace GL { Range1D Renderer::lineWidthRange() { @@ -137,7 +147,6 @@ void Renderer::setProvokingVertex(const ProvokingVertex mode) { } #endif -#ifndef MAGNUM_TARGET_WEBGL void Renderer::setPolygonMode(const PolygonMode mode) { #ifndef MAGNUM_TARGET_GLES glPolygonMode @@ -146,7 +155,6 @@ void Renderer::setPolygonMode(const PolygonMode mode) { #endif (GL_FRONT_AND_BACK, GLenum(mode)); } -#endif void Renderer::setPolygonOffset(const Float factor, const Float units) { glPolygonOffset(factor, units); @@ -331,15 +339,17 @@ void Renderer::depthRangefImplementationDefault(const Float near, const Float fa } #endif -#ifndef MAGNUM_TARGET_WEBGL void Renderer::setClipControl(const ClipOrigin origin, const ClipDepth depth) { #ifndef MAGNUM_TARGET_GLES glClipControl(GLenum(origin), GLenum(depth)); - #else + #elif !defined(MAGNUM_TARGET_WEBGL) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 30166 glClipControlEXT(GLenum(origin), GLenum(depth)); + #else + static_cast(origin); + static_cast(depth); + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); #endif } -#endif void Renderer::setColorMask(const GLboolean allowRed, const GLboolean allowGreen, const GLboolean allowBlue, const GLboolean allowAlpha) { glColorMask(allowRed, allowGreen, allowBlue, allowAlpha); diff --git a/src/Magnum/GL/Renderer.h b/src/Magnum/GL/Renderer.h index 61efb62df..ef5d7fcd3 100644 --- a/src/Magnum/GL/Renderer.h +++ b/src/Magnum/GL/Renderer.h @@ -417,7 +417,6 @@ class MAGNUM_GL_EXPORT Renderer { */ PolygonOffsetFill = GL_POLYGON_OFFSET_FILL, - #ifndef MAGNUM_TARGET_WEBGL /** * Offset lines. Note that this affects only filled polygons * rendered with @ref setPolygonMode() set to @@ -426,15 +425,20 @@ class MAGNUM_GL_EXPORT Renderer { * @ref setPolygonOffset() * @requires_es_extension Extension @gl_extension{NV,polygon_offset} * or @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt) - * @requires_gles Only @ref Feature::PolygonOffsetFill is available - * in WebGL. + * @requires_webgl_extension Extension @webgl_extension{WEBGL,polygon_mode}. + * Note that this extension is only implemented since + * Emscripten 3.1.66 and thus it's not even advertised on + * older versions. */ #ifndef MAGNUM_TARGET_GLES PolygonOffsetLine = GL_POLYGON_OFFSET_LINE, - #else + #elif !defined(MAGNUM_TARGET_WEBGL) PolygonOffsetLine = GL_POLYGON_OFFSET_LINE_NV, + #else + PolygonOffsetLine = GL_POLYGON_OFFSET_LINE_WEBGL, #endif + #ifndef MAGNUM_TARGET_WEBGL /** * Offset points. Note that this affects only filled polygons * rendered with @ref setPolygonMode() set to @@ -442,8 +446,8 @@ class MAGNUM_GL_EXPORT Renderer { * @see @ref Feature::PolygonOffsetFill, @ref Feature::PolygonOffsetLine, * @ref setPolygonOffset() * @requires_es_extension Extension @gl_extension{NV,polygon_offset} - * @requires_gles Only @ref Feature::PolygonOffsetFill is available - * in WebGL. + * @requires_gles Only @ref Feature::PolygonOffsetFill and + * @ref Feature::PolygonOffsetPoint is available in WebGL. */ #ifndef MAGNUM_TARGET_GLES PolygonOffsetPoint = GL_POLYGON_OFFSET_POINT, @@ -856,7 +860,6 @@ class MAGNUM_GL_EXPORT Renderer { static void setProvokingVertex(ProvokingVertex mode); #endif - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Polygon mode * @@ -866,7 +869,10 @@ class MAGNUM_GL_EXPORT Renderer { * @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt). * Otherwise behaves always like @ref PolygonMode::Fill. See * @ref Mesh::setPrimitive() for a possible workaround. - * @requires_gles WebGL behaves always like @ref PolygonMode::Fill. See + * @requires_webgl_extension Extension @webgl_extension{WEBGL,polygon_mode}. + * Note that this extension is only implemented since Emscripten + * 3.1.66 and thus it's not even advertised on older versions. + * Otherwise behaves always like @ref PolygonMode::Fill. See * @ref Mesh::setPrimitive() for a possible workaround. */ enum class PolygonMode: GLenum { @@ -875,8 +881,10 @@ class MAGNUM_GL_EXPORT Renderer { */ #ifndef MAGNUM_TARGET_GLES Fill = GL_FILL, - #else + #elif !defined(MAGNUM_TARGET_WEBGL) Fill = GL_FILL_NV, + #else + Fill = GL_FILL_WEBGL, #endif /** @@ -884,21 +892,26 @@ class MAGNUM_GL_EXPORT Renderer { */ #ifndef MAGNUM_TARGET_GLES Line = GL_LINE, - #else + #elif !defined(MAGNUM_TARGET_WEBGL) Line = GL_LINE_NV, + #else + Line = GL_LINE_WEBGL, #endif + #ifndef MAGNUM_TARGET_WEBGL /** * Starts of boundary edges are drawn as points. See also * @ref setPointSize(). * @requires_es_extension Extension @gl_extension{NV,polygon_mode}, * not available with @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt) + * @requires_gles Not available in @webgl_extension{WEBGL,polygon_mode} */ #ifndef MAGNUM_TARGET_GLES Point = GL_POINT #else Point = GL_POINT_NV #endif + #endif }; /** @@ -910,11 +923,13 @@ class MAGNUM_GL_EXPORT Renderer { * @m_class{m-doc-external} [ANGLE_polygon_mode](https://chromium.googlesource.com/angle/angle/+/HEAD/extensions/ANGLE_polygon_mode.txt). * Otherwise behaves always like the default. See * @ref Mesh::setPrimitive() for possible workaround. - * @requires_gles WebGL behaves always like the default. See + * @requires_webgl_extension Extension @webgl_extension{WEBGL,polygon_mode}. + * Note that this extension is only implemented since Emscripten + * 3.1.66 and thus it's not even advertised on older versions. + * Otherwise behaves always like the default. See * @ref Mesh::setPrimitive() for possible workaround. */ static void setPolygonMode(PolygonMode mode); - #endif /** * @brief Set polygon offset @@ -1234,7 +1249,6 @@ class MAGNUM_GL_EXPORT Renderer { /** @{ @name Depth testing and clip control */ - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Clip origin * @m_since_latest @@ -1243,7 +1257,9 @@ class MAGNUM_GL_EXPORT Renderer { * @m_enum_values_as_keywords * @requires_gl45 Extension @gl_extension{ARB,clip_control} * @requires_es_extension Extension @gl_extension{EXT,clip_control} - * @requires_gles Clip control is not available in WebGL. + * @requires_webgl_extension Extension @webgl_extension{EXT,clip_control}. + * Note that this extension is only implemented since Emscripten + * 3.1.66 and thus it's not even advertised on older versions. */ enum class ClipOrigin: GLenum { /** Lower left */ @@ -1269,7 +1285,9 @@ class MAGNUM_GL_EXPORT Renderer { * @m_enum_values_as_keywords * @requires_gl45 Extension @gl_extension{ARB,clip_control} * @requires_es_extension Extension @gl_extension{EXT,clip_control} - * @requires_gles Clip control is not available in WebGL. + * @requires_webgl_extension Extension @webgl_extension{EXT,clip_control}. + * Note that this extension is only implemented since Emscripten + * 3.1.66 and thus it's not even advertised on older versions. */ enum class ClipDepth: GLenum { /** -1 to 1 */ @@ -1286,7 +1304,6 @@ class MAGNUM_GL_EXPORT Renderer { ZeroToOne = GL_ZERO_TO_ONE_EXT, #endif }; - #endif /** * @brief Depth function @@ -1335,7 +1352,6 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setDepthRange(Float near, Float far); - #ifndef MAGNUM_TARGET_WEBGL /** * @brief Set clipping behavior * @m_since_latest @@ -1345,10 +1361,11 @@ class MAGNUM_GL_EXPORT Renderer { * @see @fn_gl_keyword{ClipControl} * @requires_gl45 Extension @gl_extension{ARB,clip_control} * @requires_es_extension Extension @gl_extension{EXT,clip_control} - * @requires_gles Clip control is not available in WebGL. + * @requires_webgl_extension Extension @webgl_extension{EXT,clip_control}. + * Note that this extension is only implemented since Emscripten + * 3.1.66 and thus it's not even advertised on older versions. */ static void setClipControl(ClipOrigin origin, ClipDepth depth); - #endif /* Since 1.8.17, the original short-hand group closing doesn't work anymore. FFS. */ diff --git a/src/Magnum/GL/Test/RendererGLTest.cpp b/src/Magnum/GL/Test/RendererGLTest.cpp index 8457f0be3..e3effc149 100644 --- a/src/Magnum/GL/Test/RendererGLTest.cpp +++ b/src/Magnum/GL/Test/RendererGLTest.cpp @@ -61,9 +61,7 @@ struct RendererGLTest: OpenGLTester { void maxLineWidth(); void pointCoord(); - #ifndef MAGNUM_TARGET_WEBGL void polygonMode(); - #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void patchParameters(); #endif @@ -72,9 +70,7 @@ struct RendererGLTest: OpenGLTester { void drawBuffersBlend(); #endif template void clearDepthDepthRange(); - #ifndef MAGNUM_TARGET_WEBGL void clipControl(); - #endif private: PluginManager::Manager _manager{"nonexistent"}; @@ -89,9 +85,7 @@ using namespace Math::Literals; RendererGLTest::RendererGLTest() { addTests({&RendererGLTest::maxLineWidth, &RendererGLTest::pointCoord, - #ifndef MAGNUM_TARGET_WEBGL &RendererGLTest::polygonMode, - #endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) &RendererGLTest::patchParameters, #endif @@ -103,10 +97,7 @@ RendererGLTest::RendererGLTest() { &RendererGLTest::clearDepthDepthRange, #endif &RendererGLTest::clearDepthDepthRange, - #ifndef MAGNUM_TARGET_WEBGL - &RendererGLTest::clipControl - #endif - }); + &RendererGLTest::clipControl}); /* Load the plugins directly from the build tree. Otherwise they're either static and already loaded or not present in the build tree */ @@ -259,9 +250,11 @@ void RendererGLTest::pointCoord() { (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } -#ifndef MAGNUM_TARGET_WEBGL void RendererGLTest::polygonMode() { - #ifdef MAGNUM_TARGET_GLES + #ifdef MAGNUM_TARGET_WEBGL + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::polygon_mode::string() << "is not supported."); + #elif defined(MAGNUM_TARGET_GLES) if(!Context::current().isExtensionSupported() && !Context::current().isExtensionSupported()) CORRADE_SKIP("Neither" << Extensions::NV::polygon_mode::string() << "nor" << Extensions::ANGLE::polygon_mode::string() << "is supported."); @@ -273,7 +266,6 @@ void RendererGLTest::polygonMode() { Renderer::setPolygonMode(Renderer::PolygonMode::Fill); MAGNUM_VERIFY_NO_GL_ERROR(); } -#endif #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void RendererGLTest::patchParameters() { @@ -343,7 +335,6 @@ template void RendererGLTest::clearDepthDepthRange() { MAGNUM_VERIFY_NO_GL_ERROR(); } -#ifndef MAGNUM_TARGET_WEBGL void RendererGLTest::clipControl() { #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) @@ -359,7 +350,6 @@ void RendererGLTest::clipControl() { MAGNUM_VERIFY_NO_GL_ERROR(); } -#endif }}}}