diff --git a/doc/changelog.dox b/doc/changelog.dox index ce80dd54f..bc50ffa16 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -94,6 +94,9 @@ See also: have undefined behavior and may cause stability issues. This option is also programatically settable via a new @ref GL::Context::Configuration::Flag::GpuValidationNoError flag. +- Implemented the GL 4.3 @gl_extension{ARB,framebuffer_no_attachments} + extension and matching GLES 3.1 functionality, exposed as + @ref GL::Framebuffer::setDefaultSize() and related APIs - 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 diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 1f99591e9..da929b376 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -163,7 +163,7 @@ OpenGL function | Matching API @fn_gl{Finish} | @ref GL::Renderer::finish() @fn_gl{Flush} | @ref GL::Renderer::flush() @fn_gl{FlushMappedBufferRange}, \n `glFlushMappedNamedBufferRange()` | @ref GL::Buffer::flushMappedRange() -@fn_gl2{FramebufferParameter,FramebufferParameteri}, \n `glNamedFramebufferParameter()` | | +@fn_gl2{FramebufferParameter,FramebufferParameteri}, \n `glNamedFramebufferParameter()` | @ref GL::Framebuffer::setDefaultSize(), \n @ref GL::Framebuffer::setDefaultLayerCount(), \n @ref GL::Framebuffer::setDefaultSampleCount(), \n @ref GL::Framebuffer::setDefaultFixedSampleLocations() @fn_gl{FramebufferRenderbuffer}, \n `glNamedFramebufferRenderbuffer()` | @ref GL::Framebuffer::attachRenderbuffer(), \n @ref GL::Framebuffer::detach() @fn_gl_extension{FramebufferSampleLocationsfv,ARB,sample_locations}, \n `glNamedFramebufferSampleLocationsfvARB` | | @fn_gl{FramebufferTexture}, \n `glNamedFramebufferTexture()` | @ref GL::Framebuffer::attachLayeredTexture() diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 7568a28fc..64485b459 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -203,7 +203,7 @@ GLSL 4.30 | done @gl_extension{KHR,debug} | missing log retrieval, sync, pipeline and sampler label @gl_extension{ARB,explicit_uniform_location} | done @gl_extension{ARB,fragment_layer_viewport} | done (shading language only) -@gl_extension{ARB,framebuffer_no_attachments} | | +@gl_extension{ARB,framebuffer_no_attachments} | done @gl_extension{ARB,internalformat_query2} | only compressed texture block queries @gl_extension{ARB,invalidate_subdata} | done @gl_extension{ARB,multi_draw_indirect} | | diff --git a/src/Magnum/GL/Framebuffer.cpp b/src/Magnum/GL/Framebuffer.cpp index 6b5c7ad20..e8fc49fe0 100644 --- a/src/Magnum/GL/Framebuffer.cpp +++ b/src/Magnum/GL/Framebuffer.cpp @@ -356,6 +356,29 @@ Framebuffer& Framebuffer::detach(const BufferAttachment attachment) { return *this; } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +Framebuffer& Framebuffer::setDefaultSize(const Vector2i& size) { + Context::current().state().framebuffer.parameterImplementation(*this, GL_FRAMEBUFFER_DEFAULT_WIDTH, size.x()); + Context::current().state().framebuffer.parameterImplementation(*this, GL_FRAMEBUFFER_DEFAULT_HEIGHT, size.y()); + return *this; +} + +Framebuffer& Framebuffer::setDefaultLayerCount(const Int count) { + Context::current().state().framebuffer.parameterImplementation(*this, GL_FRAMEBUFFER_DEFAULT_LAYERS, count); + return *this; +} + +Framebuffer& Framebuffer::setDefaultSampleCount(const Int count) { + Context::current().state().framebuffer.parameterImplementation(*this, GL_FRAMEBUFFER_DEFAULT_SAMPLES, count); + return *this; +} + +Framebuffer& Framebuffer::setDefaultFixedSampleLocations(bool fixed) { + Context::current().state().framebuffer.parameterImplementation(*this, GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS, fixed ? GL_TRUE : GL_FALSE); + return *this; +} +#endif + void Framebuffer::renderbufferImplementationDefault(Framebuffer& self, const BufferAttachment attachment, const GLuint renderbufferId) { glFramebufferRenderbuffer(GLenum(self.bindInternal()), GLenum(attachment), GL_RENDERBUFFER, renderbufferId); } @@ -419,6 +442,18 @@ void Framebuffer::textureLayerImplementationDSA(Framebuffer& self, const BufferA } #endif +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void Framebuffer::parameterImplementationDefault(Framebuffer& self, const GLenum parameter, const GLint value) { + glFramebufferParameteri(GLenum(self.bindInternal()), parameter, value); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void Framebuffer::parameterImplementationDSA(Framebuffer& self, const GLenum parameter, const GLint value) { + glNamedFramebufferParameteri(self._id, parameter, value); +} +#endif + #ifndef DOXYGEN_GENERATING_OUTPUT Debug& operator<<(Debug& debug, const Framebuffer::Status value) { debug << "GL::Framebuffer::Status" << Debug::nospace; diff --git a/src/Magnum/GL/Framebuffer.h b/src/Magnum/GL/Framebuffer.h index d437e9e09..b285fd953 100644 --- a/src/Magnum/GL/Framebuffer.h +++ b/src/Magnum/GL/Framebuffer.h @@ -904,6 +904,123 @@ class MAGNUM_GL_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractO */ Framebuffer& detach(BufferAttachment attachment); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /** + * @brief Set default framebuffer size + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Used in case the framebuffer has no attachments. Otherwise the size + * is inferred from renderbuffers or textures specified via + * @ref attachRenderbuffer(), @ref attachTexture(), + * @ref attachCubeMapTexture(), @ref attachTextureLayer() or + * @ref attachLayeredTexture() and this setting is ignored. Initial + * value is a zero vector. + * @see @ref setDefaultLayerCount(), @ref setDefaultSampleCount(), + * @ref setDefaultFixedSampleLocations(), + * @ref Renderbuffer::setStorage(), @ref Texture::setStorage(), + * @ref TextureArray::setStorage(), + * @ref CubeMapTexture::setStorage(), + * @ref CubeMapTextureArray::setStorage(), + * @ref MultisampleTexture::setStorage(), + * @ref RectangleTexture::setStorage(), + * @fn_gl2_keyword{NamedFramebufferParameteri,FramebufferParameteri}, + * eventually @fn_gl{BindFramebuffer} and + * @fn_gl_keyword{FramebufferParameteri} with + * @def_gl_keyword{FRAMEBUFFER_DEFAULT_WIDTH} and + * @def_gl_keyword{FRAMEBUFFER_DEFAULT_HEIGHT} + * @requires_gl43 @gl_extension{ARB,framebuffer_no_attachments} + * @requires_gles31 Attachment-less framebuffers are not available in + * OpenGL ES 3.0 and older. + * @requires_gles Attachment-less framebuffers are not available in + * WebGL. + */ + Framebuffer& setDefaultSize(const Vector2i& size); + + /** + * @brief Set default framebuffer layer count + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Used in case the framebuffer has no attachments. Otherwise the layer + * count is inferred from renderbuffers or textures specified via + * @ref attachRenderbuffer(), @ref attachTexture(), + * @ref attachCubeMapTexture(), @ref attachTextureLayer() or + * @ref attachLayeredTexture() and this setting is ignored. Initial + * value is @cpp 0 @ce. + * @see @ref setDefaultSize(), @ref setDefaultSampleCount(), + * @ref setDefaultFixedSampleLocations(), + * @ref Texture3D::setStorage(), @ref TextureArray::setStorage(), + * @ref CubeMapTexture::setStorage(), + * @ref CubeMapTextureArray::setStorage(), + * @ref MultisampleTexture2DArray::setStorage(), + * @fn_gl2_keyword{NamedFramebufferParameteri,FramebufferParameteri}, + * eventually @fn_gl{BindFramebuffer} and + * @fn_gl_keyword{FramebufferParameteri} with + * @def_gl_keyword{FRAMEBUFFER_DEFAULT_LAYERS} + * @requires_gl43 @gl_extension{ARB,framebuffer_no_attachments} + * @requires_gles31 Attachment-less framebuffers are not available in + * OpenGL ES 3.0 and older. + * @requires_gles Attachment-less framebuffers are not available in + * WebGL. + */ + Framebuffer& setDefaultLayerCount(Int count); + + /** + * @brief Set default framebuffer sample count + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Used in case the framebuffer has no attachments. Otherwise the + * sample count is inferred from renderbuffers or textures specified + * via @ref attachRenderbuffer(), @ref attachTexture(), + * @ref attachCubeMapTexture(), @ref attachTextureLayer() or + * @ref attachLayeredTexture() and this setting is ignored. Initial + * value is @cpp 0 @ce. + * @see @ref setDefaultSize(), @ref setDefaultLayerCount(), + * @ref setDefaultFixedSampleLocations(), + * @ref Renderbuffer::setStorageMultisample(), + * @ref MultisampleTexture::setStorage(), + * @fn_gl2_keyword{NamedFramebufferParameteri,FramebufferParameteri}, + * eventually @fn_gl{BindFramebuffer} and + * @fn_gl_keyword{FramebufferParameteri} with + * @def_gl_keyword{FRAMEBUFFER_DEFAULT_SAMPLES} + * @requires_gl43 @gl_extension{ARB,framebuffer_no_attachments} + * @requires_gles31 Attachment-less framebuffers are not available in + * OpenGL ES 3.0 and older. + * @requires_gles Attachment-less framebuffers are not available in + * WebGL. + */ + Framebuffer& setDefaultSampleCount(Int count); + + /** + * @brief Set default framebuffer fixed sample locations + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Used in case the framebuffer has no attachments. Otherwise the + * fixed sample locations setting is inferred from renderbuffers or + * textures specified via @ref attachRenderbuffer(), + * @ref attachTexture(), @ref attachCubeMapTexture(), + * @ref attachTextureLayer() or @ref attachLayeredTexture() and this + * setting is ignored. Initial value is @cpp false @ce. + * @see @ref setDefaultSize(), @ref setDefaultLayerCount(), + * @ref setDefaultSampleCount(), + * @ref MultisampleTexture::setStorage(), + * @ref MultisampleTextureSampleLocations, + * @fn_gl2_keyword{NamedFramebufferParameteri,FramebufferParameteri}, + * eventually @fn_gl{BindFramebuffer} and + * @fn_gl_keyword{FramebufferParameteri} with + * @def_gl_keyword{FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS} + * @requires_gl43 @gl_extension{ARB,framebuffer_no_attachments} + * @requires_gles31 Attachment-less framebuffers are not available in + * OpenGL ES 3.0 and older. + * @requires_gles Attachment-less framebuffers are not available in + * WebGL. + */ + Framebuffer& setDefaultFixedSampleLocations(bool fixed); + #endif + /* Overloads to remove WTF-factor from method chaining order */ #ifndef DOXYGEN_GENERATING_OUTPUT Framebuffer& setViewport(const Range2Di& rectangle) { @@ -969,6 +1086,13 @@ class MAGNUM_GL_EXPORT Framebuffer: public AbstractFramebuffer, public AbstractO #ifndef MAGNUM_TARGET_GLES static void MAGNUM_GL_LOCAL textureLayerImplementationDSA(Framebuffer& self, BufferAttachment attachment, GLuint textureId, GLint level, GLint layer); #endif + + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + static void MAGNUM_GL_LOCAL parameterImplementationDefault(Framebuffer& self, GLenum parameter, GLint value); + #endif + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_GL_LOCAL parameterImplementationDSA(Framebuffer& self, GLenum parameter, GLint value); + #endif }; /** @debugoperatorclassenum{Framebuffer,Framebuffer::Status} */ diff --git a/src/Magnum/GL/Implementation/FramebufferState.cpp b/src/Magnum/GL/Implementation/FramebufferState.cpp index 7fa825aef..da753866c 100644 --- a/src/Magnum/GL/Implementation/FramebufferState.cpp +++ b/src/Magnum/GL/Implementation/FramebufferState.cpp @@ -417,6 +417,33 @@ FramebufferState::FramebufferState(Context& context, Containers::StaticArrayView invalidateSubImplementation = &AbstractFramebuffer::invalidateImplementationDefault; #endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /* Attachment-less framebuffer implementation on desktop GL */ + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + extensions[Extensions::ARB::framebuffer_no_attachments::Index] = + Extensions::ARB::framebuffer_no_attachments::string(); + if(context.isExtensionSupported()) { + extensions[Extensions::ARB::direct_state_access::Index] = + Extensions::ARB::direct_state_access::string(); + parameterImplementation = &Framebuffer::parameterImplementationDSA; + } else { + parameterImplementation = &Framebuffer::parameterImplementationDefault; + } + } + + /* Attachment-less framebuffer implementation on ES3 */ + #else + if(context.isVersionSupported(Version::GLES310)) + parameterImplementation = &Framebuffer::parameterImplementationDefault; + + /* Not available otherwise */ + #endif + else { + parameterImplementation = nullptr; + } + #endif + /* Blit implementation on desktop GL */ #ifndef MAGNUM_TARGET_GLES if(context.isExtensionSupported()) { diff --git a/src/Magnum/GL/Implementation/FramebufferState.h b/src/Magnum/GL/Implementation/FramebufferState.h index c7f1ce701..24371d043 100644 --- a/src/Magnum/GL/Implementation/FramebufferState.h +++ b/src/Magnum/GL/Implementation/FramebufferState.h @@ -90,6 +90,9 @@ struct FramebufferState { #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void(*textureLayerImplementation)(Framebuffer&, Framebuffer::BufferAttachment, GLuint, GLint, GLint); #endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void(*parameterImplementation)(Framebuffer&, GLenum, GLint); + #endif void(*createRenderbufferImplementation)(Renderbuffer&); void(*renderbufferStorageImplementation)(Renderbuffer&, RenderbufferFormat, const Vector2i&); diff --git a/src/Magnum/GL/MultisampleTexture.h b/src/Magnum/GL/MultisampleTexture.h index 710c212a3..e9d68c25a 100644 --- a/src/Magnum/GL/MultisampleTexture.h +++ b/src/Magnum/GL/MultisampleTexture.h @@ -57,7 +57,8 @@ namespace Implementation { /** @brief Multisample texture sample locations -@see @ref MultisampleTexture::setStorage() +@see @ref MultisampleTexture::setStorage(), + @ref Framebuffer::setDefaultFixedSampleLocations() @m_enum_values_as_keywords */ enum class MultisampleTextureSampleLocations: GLboolean { diff --git a/src/Magnum/GL/Test/FramebufferGLTest.cpp b/src/Magnum/GL/Test/FramebufferGLTest.cpp index 6ea81610c..68ddfb7b4 100644 --- a/src/Magnum/GL/Test/FramebufferGLTest.cpp +++ b/src/Magnum/GL/Test/FramebufferGLTest.cpp @@ -114,6 +114,10 @@ struct FramebufferGLTest: OpenGLTester { void multipleColorOutputs(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void setDefaultSize(); + #endif + void clear(); #ifndef MAGNUM_TARGET_GLES2 void clearColorI(); @@ -260,6 +264,10 @@ FramebufferGLTest::FramebufferGLTest() { &FramebufferGLTest::multipleColorOutputs, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + &FramebufferGLTest::setDefaultSize, + #endif + &FramebufferGLTest::clear, #ifndef MAGNUM_TARGET_GLES2 &FramebufferGLTest::clearColorI, @@ -1041,6 +1049,31 @@ void FramebufferGLTest::detach() { MAGNUM_VERIFY_NO_GL_ERROR(); } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void FramebufferGLTest::setDefaultSize() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::framebuffer_no_attachments::string() << "is not supported."); + #else + if(!Context::current().isVersionSupported(Version::GLES310)) + CORRADE_SKIP(Version::GLES310 << "is not supported."); + #endif + + Framebuffer framebuffer{{{}, Vector2i{128}}}; + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::Draw), Framebuffer::Status::IncompleteMissingAttachment); + + framebuffer.setDefaultSize({256, 256}) + .setDefaultLayerCount(3) + .setDefaultSampleCount(1) + .setDefaultFixedSampleLocations(false); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(framebuffer.checkStatus(FramebufferTarget::Draw), Framebuffer::Status::Complete); +} +#endif + void FramebufferGLTest::multipleColorOutputs() { #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported())