From 0e50f0feeab2c829487c68ece8f546d4bc93f555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 6 Feb 2020 11:31:41 +0100 Subject: [PATCH] GL: implement {EXT,ARB}_draw_buffers{2,_blend,_indexed}. I also figured out a new, faster & less verbose way to handle multiple code paths in some cases -- why didn't I think of that earlier? --- doc/changelog.dox | 5 + doc/opengl-mapping.dox | 10 +- doc/opengl-support.dox | 7 +- src/Magnum/GL/Context.cpp | 3 + src/Magnum/GL/Extensions.h | 3 + src/Magnum/GL/Framebuffer.h | 2 +- .../GL/Implementation/RendererState.cpp | 45 +++++ src/Magnum/GL/Implementation/RendererState.h | 9 + src/Magnum/GL/Renderer.cpp | 38 ++++ src/Magnum/GL/Renderer.h | 165 +++++++++++++++++- src/Magnum/GL/Test/RendererGLTest.cpp | 49 +++++- .../OpenGL/GLES3/Emscripten/extensions.txt | 1 + .../OpenGL/GLES3/flextGLEmscripten.h | 42 +++++ 13 files changed, 368 insertions(+), 11 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 1a0f366e0..b6d7e6171 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -52,6 +52,11 @@ See also: @webgl_extension{OVR,multiview2} extension. See also [mosra/magnum#385](https://github.com/mosra/magnum/issues/385). - @gl_extension{ARB,sample_locations} desktop extension +- Implemented @gl_extension{EXT,draw_buffers2}, + @gl_extension{ARB,draw_buffers_blend} desktop extensions, + @gl_extension{EXT,draw_buffers_indexed} ES extension and + @webgl_extension{EXT,draw_buffers_indexed} WebGL 2 extension in + @ref GL::Renderer - Recognizing @gl_extension{AMD,shader_explicit_vertex_parameter} desktop and @gl_extension{NV,fragment_shader_barycentric} desktop / ES extensions. These add only shading language features. diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index bc9f3726c..932f690d6 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -80,8 +80,8 @@ OpenGL function | Matching API @fn_gl{BindVertexBuffer}, \n `glVertexArrayVertexBuffer()`, \n @fn_gl{BindVertexBuffers}, \n `glVertexArrayVertexBuffers()` | | @fn_gl_extension{BlendBarrier,KHR,blend_equation_advanced} | @ref GL::Renderer::blendBarrier() @fn_gl{BlendColor} | @ref GL::Renderer::setBlendColor() -@fn_gl{BlendEquation}, \n @fn_gl{BlendEquationSeparate} | @ref GL::Renderer::setBlendEquation() -@fn_gl{BlendFunc}, \n @fn_gl{BlendFuncSeparate} | @ref GL::Renderer::setBlendFunction() +@fn_gl{BlendEquation}, \n `glBlendEquationi()`, \n @fn_gl{BlendEquationSeparate}, \n `glBlendEquationSeparatei()` | @ref GL::Renderer::setBlendEquation() +@fn_gl{BlendFunc}, \n `glBlendFunci()`, \n @fn_gl{BlendFuncSeparate}, \n `glBlendFuncSeparatei()` | @ref GL::Renderer::setBlendFunction() @fn_gl{BlitFramebuffer}, \n `glBlitNamedFramebuffer()` | @ref GL::AbstractFramebuffer::blit() @fn_gl{BufferData}, \n `glNamedBufferData()` | @ref GL::Buffer::setData() @fn_gl_extension{BufferPageCommitment,ARB,sparse_buffer}, \n `glNamedBufferPageCommitmentEXT()`, \n `glNamedBufferPageCommitmentARB()` | | @@ -107,7 +107,7 @@ OpenGL function | Matching API @fn_gl{ClearTexSubImage} | | @fn_gl{ClientWaitSync} | | @fn_gl{ClipControl} | | -@fn_gl{ColorMask} | @ref GL::Renderer::setColorMask() +@fn_gl{ColorMask}, \n `glColorMaski()` | @ref GL::Renderer::setColorMask() @fn_gl{CompileShader} | @ref GL::Shader::compile() @fn_gl{CompressedTexImage1D}, \n @fn_gl{CompressedTexImage2D}, \n @fn_gl{CompressedTexImage3D} | @ref GL::Texture::setCompressedImage(), \n @ref GL::TextureArray::setCompressedImage(), \n @ref GL::CubeMapTexture::setCompressedImage(), \n @ref GL::CubeMapTextureArray::setCompressedImage(), \n @ref GL::RectangleTexture::setCompressedImage() @fn_gl{CompressedTexSubImage1D}, \n `glCompressedTextureSubImage1D()`, \n @fn_gl{CompressedTexSubImage2D}, \n `glCompressedTextureSubImage2D()`, \n @fn_gl{CompressedTexSubImage3D}, \n `glCompressedTextureSubImage3D()` | @ref GL::Texture::setCompressedSubImage(), \n @ref GL::TextureArray::setCompressedSubImage(), \n @ref GL::CubeMapTexture::setCompressedSubImage(), \n @ref GL::CubeMapTextureArray::setCompressedSubImage(), \n @ref GL::RectangleTexture::setCompressedSubImage() @@ -149,7 +149,7 @@ OpenGL function | Matching API OpenGL function | Matching API --------------------------------------- | ------------ -@fn_gl{Enable}, `glDisable()` | @ref GL::Renderer::setFeature() +@fn_gl{Enable} `glEnablei()`, \n `glDisable()`, `glDisablei()` | @ref GL::Renderer::enable(), \n @ref GL::Renderer::disable(), \n @ref GL::Renderer::setFeature() @fn_gl{EnableVertexAttribArray}, \n `glEnableVertexArrayAttrib()`, \n `glDisableVertexAttribArray()`, \n `glDisableVertexArrayAttrib()`, \n `glDisableVertexArrayAttribEXT()` | @ref GL::Mesh::addVertexBuffer() @fn_gl_extension{EvaluateDepthValues,ARB,sample_locations} | | @@ -265,7 +265,7 @@ OpenGL function | Matching API @fn_gl{InvalidateTexImage} | @ref GL::Texture::invalidateImage(), \n @ref GL::TextureArray::invalidateImage(), \n @ref GL::CubeMapTexture::invalidateImage(), \n @ref GL::CubeMapTextureArray::invalidateImage(), \n @ref GL::RectangleTexture::invalidateImage(), \n @ref GL::MultisampleTexture::invalidateImage() @fn_gl{InvalidateTexSubImage} | @ref GL::Texture::invalidateSubImage(), \n @ref GL::TextureArray::invalidateSubImage(), \n @ref GL::CubeMapTexture::invalidateSubImage(), \n @ref GL::CubeMapTextureArray::invalidateSubImage(), \n @ref GL::RectangleTexture::invalidateSubImage(), \n @ref GL::MultisampleTexture::invalidateSubImage() @fn_gl{IsBuffer}, \n @fn_gl{IsFramebuffer}, \n @fn_gl{IsProgram}, \n @fn_gl{IsProgramPipeline}, \n @fn_gl{IsQuery}, \n @fn_gl{IsRenderbuffer}, \n @fn_gl{IsSampler}, \n @fn_gl{IsShader}, \n @fn_gl{IsSync}, \n @fn_gl{IsTexture}, \n @fn_gl{IsTransformFeedback}, \n @fn_gl{IsVertexArray} | not needed, objects are strongly typed -@fn_gl{IsEnabled} | not queryable, @ref GL::Renderer::setFeature() setter only +@fn_gl{IsEnabled}, `glIsEnabledi()` | not queryable, @ref GL::Renderer::setFeature() setter only @fn_gl_extension{IsImageHandleResident,ARB,bindless_texture} | | @fn_gl_extension{IsTextureHandleResident,ARB,bindless_texture} | | diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 94fcdb77b..330c84471 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -76,7 +76,7 @@ GLSL 1.30 | done @gl_extension{EXT,texture_array} | done @gl_extension{EXT,texture_compression_rgtc} | done @gl_extension{EXT,texture_shared_exponent} | done -@gl_extension{EXT,draw_buffers2} | | +@gl_extension{EXT,draw_buffers2} | done (GL 3.0 subset) @gl_extension{EXT,texture_integer} | done (GL 3.0 subset) @gl_extension{EXT,transform_feedback} | done `MAGNUM_shader_vertex_id` \n @m_span{m-text m-dim} Pseudo-extension denoting support for the @glsl gl_VertexID @ce GLSL builtin. @m_endspan | done @@ -140,7 +140,7 @@ GLSL 3.30 | done Extension | Status ------------------------------------------- | ------ GLSL 4.00 | done -@gl_extension{ARB,draw_buffers_blend} | | +@gl_extension{ARB,draw_buffers_blend} | done @gl_extension{ARB,sample_shading} | done @gl_extension{ARB,texture_cube_map_array} | done @gl_extension{ARB,texture_gather} | missing limit queries @@ -354,7 +354,7 @@ Extension | Status @gl_extension{EXT,color_buffer_half_float} | | @gl_extension{EXT,color_buffer_float} | | @gl_extension{EXT,copy_image} | | -@gl_extension{EXT,draw_buffers_indexed} | | +@gl_extension{EXT,draw_buffers_indexed} | done @gl_extension{EXT,geometry_shader} | missing some ES-specific limit queries @gl_extension{EXT,gpu_shader5} | done (shading language only) @gl_extension{EXT,shader_io_blocks} | done (shading language only) @@ -546,6 +546,7 @@ Extension | Status @webgl_extension{EXT,color_buffer_float} | | @webgl_extension{EXT,texture_compression_rgtc} | done @webgl_extension{EXT,texture_compression_bptc} | done +@webgl_extension{EXT,draw_buffers_indexed} | done @webgl_extension{OES,texture_float_linear} | done @webgl_extension{OVR,multiview2} | | @webgl_extension{WEBGL,compressed_texture_s3tc} | done diff --git a/src/Magnum/GL/Context.cpp b/src/Magnum/GL/Context.cpp index b4015a884..e362e9dc3 100644 --- a/src/Magnum/GL/Context.cpp +++ b/src/Magnum/GL/Context.cpp @@ -265,6 +265,9 @@ constexpr Extension ExtensionList[]{ #endif _extension(EXT,texture_compression_rgtc), _extension(EXT,texture_compression_bptc), + #ifndef MAGNUM_TARGET_GLES2 + _extension(EXT,draw_buffers_indexed), + #endif _extension(OES,texture_float_linear), #ifndef MAGNUM_TARGET_GLES2 _extension(OVR,multiview2), diff --git a/src/Magnum/GL/Extensions.h b/src/Magnum/GL/Extensions.h index 86dc722de..e18d13f83 100644 --- a/src/Magnum/GL/Extensions.h +++ b/src/Magnum/GL/Extensions.h @@ -295,6 +295,9 @@ namespace ANGLE { #endif _extension(10,EXT,texture_compression_rgtc, GLES200, None) // #38 _extension(11,EXT,texture_compression_bptc, GLES200, None) // #39 + #ifndef MAGNUM_TARGET_GLES2 + _extension(12,EXT,draw_buffers_indexed, GLES300, None) // #45 + #endif } namespace OES { #ifdef MAGNUM_TARGET_GLES2 _extension(15,OES,texture_float, GLES200, GLES300) // #1 diff --git a/src/Magnum/GL/Framebuffer.h b/src/Magnum/GL/Framebuffer.h index 26b3ee2f8..1395b10ec 100644 --- a/src/Magnum/GL/Framebuffer.h +++ b/src/Magnum/GL/Framebuffer.h @@ -80,7 +80,7 @@ possible to achieve the same with a @ref MultisampleTexture2D, support for it is rather sparse on OpenGL ES and completely nonexistent on WebGL or macOS / iOS. -@section GL-Framebuffer-usage-multiple-output Multiple fragment shader outputs +@section GL-Framebuffer-usage-multiple-outputs Multiple fragment shader outputs In a deferred rendering setup for example, a shader usually has more than one output. That's finally where non-zero @ref ColorAttachment and @ref mapForDraw() diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index 6bd57608d..be1be5d57 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/src/Magnum/GL/Implementation/RendererState.cpp @@ -107,6 +107,51 @@ RendererState::RendererState(Context& context, ContextState& contextState, std:: minSampleShadingImplementation = nullptr; #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + #ifdef MAGNUM_TARGET_GLES + if(context.isVersionSupported(Version::GLES320)) + #endif + { + enableiImplementation = glEnablei; + disableiImplementation = glDisablei; + colorMaskiImplementation = glColorMaski; + blendFunciImplementation = glBlendFunci; + blendFuncSeparateiImplementation = glBlendFuncSeparatei; + blendEquationiImplementation = glBlendEquationi; + blendEquationSeparateiImplementation = glBlendEquationSeparatei; + } + #endif + #ifdef MAGNUM_TARGET_GLES + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + else + #endif + { + /* Not checking for the extension (nor adding it to the extension list) + as this is not any optional feature -- it can be only used when + the extension is present, and if it's not, the pointers are null */ + #ifndef MAGNUM_TARGET_WEBGL + enableiImplementation = glEnableiEXT; + disableiImplementation = glDisableiEXT; + colorMaskiImplementation = glColorMaskiEXT; + blendFunciImplementation = glBlendFunciEXT; + blendFuncSeparateiImplementation = glBlendFuncSeparateiEXT; + blendEquationiImplementation = glBlendEquationiEXT; + blendEquationSeparateiImplementation = glBlendEquationSeparateiEXT; + #else + /* Emscripten doesn't support these yet (last checked Feb 2020) */ + enableiImplementation = nullptr; + disableiImplementation = nullptr; + colorMaskiImplementation = nullptr; + blendFunciImplementation = nullptr; + blendFuncSeparateiImplementation = nullptr; + blendEquationiImplementation = nullptr; + blendEquationSeparateiImplementation = nullptr; + #endif + } + #endif + #endif + #ifndef MAGNUM_TARGET_GLES /* On compatibility profile we need to explicitly enable GL_POINT_SPRITE in order to have gl_PointCoord working (on NVidia at least, Mesa behaves diff --git a/src/Magnum/GL/Implementation/RendererState.h b/src/Magnum/GL/Implementation/RendererState.h index 76a045e06..4a9661991 100644 --- a/src/Magnum/GL/Implementation/RendererState.h +++ b/src/Magnum/GL/Implementation/RendererState.h @@ -43,6 +43,15 @@ struct RendererState { #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void(*minSampleShadingImplementation)(GLfloat); #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + void(*enableiImplementation)(GLenum, GLuint); + void(*disableiImplementation)(GLenum, GLuint); + void(*blendEquationiImplementation)(GLuint, GLenum); + void(*blendEquationSeparateiImplementation)(GLuint, GLenum, GLenum); + void(*blendFunciImplementation)(GLuint, GLenum, GLenum); + void(*blendFuncSeparateiImplementation)(GLuint, GLenum, GLenum, GLenum, GLenum); + void(*colorMaskiImplementation)(GLuint, GLboolean, GLboolean, GLboolean, GLboolean); + #endif #ifndef MAGNUM_TARGET_WEBGL Renderer::GraphicsResetStatus(*graphicsResetStatusImplementation)(); diff --git a/src/Magnum/GL/Renderer.cpp b/src/Magnum/GL/Renderer.cpp index f8e27457f..79acd324f 100644 --- a/src/Magnum/GL/Renderer.cpp +++ b/src/Magnum/GL/Renderer.cpp @@ -72,6 +72,20 @@ void Renderer::setFeature(const Feature feature, const bool enabled) { enabled ? enable(feature) : disable(feature); } +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +void Renderer::enable(const Feature feature, const UnsignedInt drawBuffer) { + Context::current().state().renderer->enableiImplementation(GLenum(feature), drawBuffer); +} + +void Renderer::disable(const Feature feature, const UnsignedInt drawBuffer) { + Context::current().state().renderer->disableiImplementation(GLenum(feature), drawBuffer); +} + +void Renderer::setFeature(const Feature feature, const UnsignedInt drawBuffer, const bool enabled) { + enabled ? enable(feature, drawBuffer) : disable(feature, drawBuffer); +} +#endif + void Renderer::setHint(const Hint target, const HintMode mode) { glHint(GLenum(target), GLenum(mode)); } @@ -177,6 +191,12 @@ void Renderer::setColorMask(const GLboolean allowRed, const GLboolean allowGreen glColorMask(allowRed, allowGreen, allowBlue, allowAlpha); } +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +void Renderer::setColorMask(const UnsignedInt drawBuffer, const GLboolean allowRed, const GLboolean allowGreen, const GLboolean allowBlue, const GLboolean allowAlpha) { + Context::current().state().renderer->colorMaskiImplementation(drawBuffer, allowRed, allowGreen, allowBlue, allowAlpha); +} +#endif + void Renderer::setDepthMask(const GLboolean allow) { glDepthMask(allow); } @@ -205,6 +225,24 @@ void Renderer::setBlendFunction(const BlendFunction sourceRgb, const BlendFuncti glBlendFuncSeparate(GLenum(sourceRgb), GLenum(destinationRgb), GLenum(sourceAlpha), GLenum(destinationAlpha)); } +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +void Renderer::setBlendEquation(const UnsignedInt drawBuffer, const BlendEquation equation) { + Context::current().state().renderer->blendEquationiImplementation(drawBuffer, GLenum(equation)); +} + +void Renderer::setBlendEquation(const UnsignedInt drawBuffer, const BlendEquation rgb, const BlendEquation alpha) { + Context::current().state().renderer->blendEquationSeparateiImplementation(drawBuffer, GLenum(rgb), GLenum(alpha)); +} + +void Renderer::setBlendFunction(const UnsignedInt drawBuffer, const BlendFunction source, const BlendFunction destination) { + Context::current().state().renderer->blendFunciImplementation(drawBuffer, GLenum(source), GLenum(destination)); +} + +void Renderer::setBlendFunction(const UnsignedInt drawBuffer, const BlendFunction sourceRgb, const BlendFunction destinationRgb, const BlendFunction sourceAlpha, const BlendFunction destinationAlpha) { + Context::current().state().renderer->blendFuncSeparateiImplementation(drawBuffer, GLenum(sourceRgb), GLenum(destinationRgb), GLenum(sourceAlpha), GLenum(destinationAlpha)); +} +#endif + void Renderer::setBlendColor(const Color4& color) { glBlendColor(color.r(), color.g(), color.b(), color.a()); } diff --git a/src/Magnum/GL/Renderer.h b/src/Magnum/GL/Renderer.h index 14fb40bd7..c7e6a4963 100644 --- a/src/Magnum/GL/Renderer.h +++ b/src/Magnum/GL/Renderer.h @@ -324,6 +324,25 @@ class MAGNUM_GL_EXPORT Renderer { */ static void enable(Feature feature); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Enable a feature for given draw buffer + * @param feature Feature to enable + * @param drawBuffer Draw buffer index + * @m_since_latest + * + * @see @ref disable(Feature, UnsignedInt), + * @ref setFeature(Feature, UnsignedInt, bool), + * @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{Enablei,Enable} + * @requires_gl30 Extension @gl_extension{EXT,draw_buffers2} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void enable(Feature feature, UnsignedInt drawBuffer); + #endif + /** * @brief Disable a feature * @@ -331,6 +350,25 @@ class MAGNUM_GL_EXPORT Renderer { */ static void disable(Feature feature); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Disable a feature for given draw buffer + * @param feature Feature to disable + * @param drawBuffer Draw buffer index + * @m_since_latest + * + * @see @ref enable(Feature, UnsignedInt), + * @ref setFeature(Feature, UnsignedInt, bool), + * @ref GL-Framebuffer-usage-multiple-outputs + * @fn_gl2_keyword{Disablei,Disable} + * @requires_gl30 Extension @gl_extension{EXT,draw_buffers2} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void disable(Feature feature, UnsignedInt drawBuffer); + #endif + /** * @brief Enable or disable a feature * @@ -343,6 +381,24 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setFeature(Feature feature, bool enabled); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Enable or disable a feature for given draw buffer + * @param feature Feature to toggle + * @param drawBuffer Draw buffer index + * @param enabled Enable or disable + * + * @see @ref enable(Feature, UnsignedInt), + * @ref disable(Feature, UnsignedInt), + * @ref GL-Framebuffer-usage-multiple-outputs + * @requires_gl30 Extension @gl_extension{EXT,draw_buffers2} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setFeature(Feature feature, UnsignedInt drawBuffer, bool enabled); + #endif + /** * @brief Hint * @@ -784,15 +840,38 @@ class MAGNUM_GL_EXPORT Renderer { /** * @brief Mask color writes + * @param allowRed Allow red channel to be written + * @param allowGreen Allow green channel to be written + * @param allowBlue Allow blue channel to be written + * @param allowAlpha Allow alpha channel to be written * * Set to @cpp false @ce to disallow writing to given color channel. * Initial values are all @cpp true @ce. * @see @ref setDepthMask(), @ref setStencilMask(), * @fn_gl_keyword{ColorMask} - * @todo Masking only given draw buffer */ static void setColorMask(GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Mask color writes for given draw buffer + * @param drawBuffer Draw buffer index + * @param allowRed Allow red channel to be written + * @param allowGreen Allow green channel to be written + * @param allowBlue Allow blue channel to be written + * @param allowAlpha Allow alpha channel to be written + * @m_since_latest + * + * @see @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{ColorMaski,ColorMask} + * @requires_gl30 Extension @gl_extension{EXT,draw_buffers2} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setColorMask(UnsignedInt drawBuffer, GLboolean allowRed, GLboolean allowGreen, GLboolean allowBlue, GLboolean allowAlpha); + #endif + /** * @brief Mask depth writes * @@ -1200,6 +1279,7 @@ class MAGNUM_GL_EXPORT Renderer { /** * @brief Set blend equation + * @param equation Blend equation * * How to combine source color (pixel value) with destination color * (framebuffer). Initial value is @ref BlendEquation::Add. @@ -1209,8 +1289,27 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setBlendEquation(BlendEquation equation); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Set blend equation for given draw buffer + * @param drawBuffer Draw buffer index + * @param equation Blend equation + * @m_since_latest + * + * @see @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{BlendEquationi,BlendEquation} + * @requires_gl40 Extension @gl_extension{ARB,draw_buffers_blend} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setBlendEquation(UnsignedInt drawBuffer, BlendEquation equation); + #endif + /** * @brief Set blend equation separately for RGB and alpha components + * @param rgb Blend equation for RGB components + * @param alpha Blend equation for the alpha component * * See @ref setBlendEquation(BlendEquation) for more information. * @see @ref Feature::Blending, @ref setBlendFunction(), @@ -1218,6 +1317,24 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setBlendEquation(BlendEquation rgb, BlendEquation alpha); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Set blend equation for given draw buffer + * @param drawBuffer Draw buffer index + * @param rgb Blend equation for RGB components + * @param alpha Blend equation for the alpha component + * @m_since_latest + * + * @see @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{BlendEquationSeparatei,BlendEquationSeparate} + * @requires_gl40 Extension @gl_extension{ARB,draw_buffers_blend} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setBlendEquation(UnsignedInt drawBuffer, BlendEquation rgb, BlendEquation alpha); + #endif + /** * @brief Set blend function * @param source How the source blending factor is computed @@ -1233,6 +1350,28 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setBlendFunction(BlendFunction source, BlendFunction destination); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + /** + * @brief Set blend function for given draw buffer + * @param drawBuffer Draw buffer index + * @param source How the source blending factor is computed + * from pixel value + * @param destination How the destination blending factor is + * computed from framebuffer + * @m_since_latest + * + * See @ref setBlendFunction(BlendFunction, BlendFunction) for more + * information. + * @see @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{BlendFunci,BlendFunc} + * @requires_gl40 Extension @gl_extension{ARB,draw_buffers_blend} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setBlendFunction(UnsignedInt drawBuffer, BlendFunction source, BlendFunction destination); + #endif + /** * @brief Set blend function separately for RGB and alpha components * @@ -1243,6 +1382,30 @@ class MAGNUM_GL_EXPORT Renderer { */ static void setBlendFunction(BlendFunction sourceRgb, BlendFunction destinationRgb, BlendFunction sourceAlpha, BlendFunction destinationAlpha); + /** + * @brief Set blend function separately for RGB and alpha components for given draw buffer + * @param drawBuffer Draw buffer index + * @param sourceRgb How the source blending factor is computed + * from pixel value for RGB components + * @param sourceAlpha How the source blending factor is computed + * from pixel value for the alpha component + * @param destinationRgb How the destination blending factor is + * computed from framebuffer for RGB components + * @param destinationAlpha How the destination blending factor is + * computed from framebuffer for the alpha component + * @m_since_latest + * + * See @ref setBlendFunction(BlendFunction, BlendFunction) for more + * information. + * @see @ref GL-Framebuffer-usage-multiple-outputs, + * @fn_gl2_keyword{BlendFuncSeparatei,BlendFuncSeparate} + * @requires_gl40 Extension @gl_extension{ARB,draw_buffers_blend} + * @requires_gles32 Extension @gl_extension{EXT,draw_buffers_indexed} + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{EXT,draw_buffers_indexed} + */ + static void setBlendFunction(UnsignedInt drawBuffer, BlendFunction sourceRgb, BlendFunction destinationRgb, BlendFunction sourceAlpha, BlendFunction destinationAlpha); + /** * @brief Set blend color * diff --git a/src/Magnum/GL/Test/RendererGLTest.cpp b/src/Magnum/GL/Test/RendererGLTest.cpp index 64bada9ab..2c53b0fe5 100644 --- a/src/Magnum/GL/Test/RendererGLTest.cpp +++ b/src/Magnum/GL/Test/RendererGLTest.cpp @@ -32,6 +32,7 @@ #include "Magnum/DebugTools/CompareImage.h" #include "Magnum/GL/AbstractShaderProgram.h" #include "Magnum/GL/Context.h" +#include "Magnum/GL/Extensions.h" #include "Magnum/GL/Framebuffer.h" #include "Magnum/GL/Mesh.h" #include "Magnum/GL/OpenGLTester.h" @@ -54,6 +55,10 @@ struct RendererGLTest: OpenGLTester { void maxLineWidth(); void pointCoord(); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + void drawBuffersIndexed(); + void drawBuffersBlend(); + #endif private: PluginManager::Manager _manager{"nonexistent"}; @@ -67,7 +72,12 @@ using namespace Math::Literals; RendererGLTest::RendererGLTest() { addTests({&RendererGLTest::maxLineWidth, - &RendererGLTest::pointCoord}); + &RendererGLTest::pointCoord, + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + &RendererGLTest::drawBuffersIndexed, + &RendererGLTest::drawBuffersBlend + #endif + }); /* Load the plugins directly from the build tree. Otherwise they're either static and already loaded or not present in the build tree */ @@ -220,6 +230,43 @@ void RendererGLTest::pointCoord() { (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +void RendererGLTest::drawBuffersIndexed() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_buffers2::string() + std::string(" is not available.")); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_buffers_indexed::string() + std::string(" is not available.")); + #endif + + /* Call the draw-buffer dependent functions, only expect that no GL error + is emitted to ensure we didn't mess up argument order or something */ + Renderer::enable(Renderer::Feature::Blending, 1); + Renderer::disable(Renderer::Feature::Blending, 1); + Renderer::setColorMask(1, true, false, true, false); + MAGNUM_VERIFY_NO_GL_ERROR(); +} + +void RendererGLTest::drawBuffersBlend() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::draw_buffers_blend::string() + std::string(" is not available.")); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_buffers_indexed::string() + std::string(" is not available.")); + #endif + + /* Call the draw-buffer dependent functions, only expect that no GL error + is emitted to ensure we didn't mess up argument order or something */ + Renderer::setBlendFunction(1, Renderer::BlendFunction::One, Renderer::BlendFunction::OneMinusSourceAlpha); + Renderer::setBlendFunction(1, Renderer::BlendFunction::One, Renderer::BlendFunction::Zero, Renderer::BlendFunction::OneMinusSourceAlpha, Renderer::BlendFunction::SourceAlpha); + Renderer::setBlendEquation(1, Renderer::BlendEquation::Subtract); + Renderer::setBlendEquation(1, Renderer::BlendEquation::Add, Renderer::BlendEquation::Subtract); + MAGNUM_VERIFY_NO_GL_ERROR(); +} +#endif + }}}} CORRADE_TEST_MAIN(Magnum::GL::Test::RendererGLTest) diff --git a/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt b/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt index f6f35a822..9e8e9b8b8 100644 --- a/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt +++ b/src/MagnumExternal/OpenGL/GLES3/Emscripten/extensions.txt @@ -10,6 +10,7 @@ extension EXT_disjoint_timer_query optional extension EXT_color_buffer_float optional extension EXT_texture_compression_rgtc optional extension EXT_texture_compression_bptc optional +extension EXT_draw_buffers_indexed optional # WebGL has only OVR_multiview2, but we need the definitions from OVR_multiview extension OVR_multiview optional extension OVR_multiview2 optional diff --git a/src/MagnumExternal/OpenGL/GLES3/flextGLEmscripten.h b/src/MagnumExternal/OpenGL/GLES3/flextGLEmscripten.h index 4fcba4c89..3545cb2aa 100644 --- a/src/MagnumExternal/OpenGL/GLES3/flextGLEmscripten.h +++ b/src/MagnumExternal/OpenGL/GLES3/flextGLEmscripten.h @@ -745,6 +745,37 @@ typedef struct __GLsync *GLsync; #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT 0x8E8F +/* GL_EXT_draw_buffers_indexed */ + +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_BLEND 0x0BE2 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_SRC_ALPHA_SATURATE 0x0308 + /* GL_OVR_multiview */ #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630 @@ -1073,6 +1104,17 @@ GLAPI void glGetQueryivEXT(GLenum, GLenum, GLint *); GLAPI GLboolean glIsQueryEXT(GLuint); GLAPI void glQueryCounterEXT(GLuint, GLenum); +/* GL_EXT_draw_buffers_indexed */ + +GLAPI void glBlendEquationSeparateiEXT(GLuint, GLenum, GLenum); +GLAPI void glBlendEquationiEXT(GLuint, GLenum); +GLAPI void glBlendFuncSeparateiEXT(GLuint, GLenum, GLenum, GLenum, GLenum); +GLAPI void glBlendFunciEXT(GLuint, GLenum, GLenum); +GLAPI void glColorMaskiEXT(GLuint, GLboolean, GLboolean, GLboolean, GLboolean); +GLAPI void glDisableiEXT(GLenum, GLuint); +GLAPI void glEnableiEXT(GLenum, GLuint); +GLAPI GLboolean glIsEnablediEXT(GLenum, GLuint); + /* GL_OVR_multiview */ GLAPI void glFramebufferTextureMultiviewOVR(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);