diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 6ec01fbe5..409d5e9d3 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -100,7 +100,7 @@ following: @extension{ARB,provoking_vertex} | done @extension{ARB,seamless_cube_map} | done @extension{ARB,sync} | | -@extension{ARB,texture_multisample} | | +@extension{ARB,texture_multisample} | missing sample location queries and sample mask @extension{ARB,vertex_array_bgra} | done @subsection opengl-support-33 OpenGL 3.3 @@ -187,7 +187,7 @@ following: @extension{ARB,stencil_texturing} | | @extension{ARB,texture_buffer_range} | done @extension{ARB,texture_query_levels} | done (shading language only) -@extension{ARB,texture_storage_multisample} | | +@extension{ARB,texture_storage_multisample} | done @extension{ARB,texture_view} | | @extension{ARB,vertex_attrib_binding} | | diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index c940f0580..70f053657 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -885,6 +885,36 @@ void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, Te } #endif +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::storageMultisampleImplementationFallback(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) { + bindInternal(); + glTexImage2DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations); +} + +void AbstractTexture::storageMultisampleImplementationDefault(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) { + bindInternal(); + glTexStorage2DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations); +} + +void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) { + glTextureStorage2DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations); +} + +void AbstractTexture::storageMultisampleImplementationFallback(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) { + bindInternal(); + glTexImage3DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations); +} + +void AbstractTexture::storageMultisampleImplementationDefault(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) { + bindInternal(); + glTexStorage3DMultisample(target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations); +} + +void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) { + glTextureStorage3DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations); +} +#endif + #ifndef MAGNUM_TARGET_GLES void AbstractTexture::getImageImplementationDefault(const GLenum target, const GLint level, const ColorFormat format, const ColorType type, const std::size_t, GLvoid* const data) { bindInternal(); @@ -1092,6 +1122,16 @@ void AbstractTexture::DataHelper<3>::setStorage(AbstractTexture& texture, const (texture.*Context::current()->state().texture->storage3DImplementation)(target, levels, internalFormat, size); } +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::DataHelper<2>::setStorageMultisample(AbstractTexture& texture, const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) { + (texture.*Context::current()->state().texture->storage2DMultisampleImplementation)(target, samples, internalFormat, size, fixedSampleLocations); +} + +void AbstractTexture::DataHelper<3>::setStorageMultisample(AbstractTexture& texture, const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) { + (texture.*Context::current()->state().texture->storage3DMultisampleImplementation)(target, samples, internalFormat, size, fixedSampleLocations); +} +#endif + #ifndef MAGNUM_TARGET_GLES void AbstractTexture::DataHelper<1>::setImage(AbstractTexture& texture, const GLenum target, const GLint level, const TextureFormat internalFormat, const ImageReference1D& image) { Buffer::unbind(Buffer::Target::PixelUnpack); diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index e6c62decf..c53b07b91 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -350,6 +350,16 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); #endif + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL storageMultisampleImplementationFallback(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations); + void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations); + void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedsamplelocations); + + void MAGNUM_LOCAL storageMultisampleImplementationFallback(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations); + void MAGNUM_LOCAL storageMultisampleImplementationDefault(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations); + void MAGNUM_LOCAL storageMultisampleImplementationDSA(GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedsamplelocations); + #endif + #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL getImageImplementationDefault(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); void MAGNUM_LOCAL getImageImplementationDSA(GLenum target, GLint level, ColorFormat format, ColorType type, std::size_t dataSize, GLvoid* data); @@ -446,6 +456,8 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); + static void setStorageMultisample(AbstractTexture& texture, GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector2i& size, GLboolean fixedSampleLocations); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference2D& image); #ifndef MAGNUM_TARGET_GLES2 static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage2D& image); @@ -481,6 +493,8 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { static void setStorage(AbstractTexture& texture, GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); + static void setStorageMultisample(AbstractTexture& texture, GLenum target, GLsizei samples, TextureFormat internalFormat, const Vector3i& size, GLboolean fixedSampleLocations); + static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, const ImageReference3D& image); #ifndef MAGNUM_TARGET_GLES2 static void setImage(AbstractTexture& texture, GLenum target, GLint level, TextureFormat internalFormat, BufferImage3D& image); diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index e83e195e5..60d362f43 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -179,6 +179,25 @@ TextureState::TextureState(Context& context, std::vector& extension } #endif + #ifndef MAGNUM_TARGET_GLES + /* Storage implementation for multisample textures. The fallback doesn't + have DSA alternative, so it must be handled specially. */ + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::ARB::texture_storage_multisample::string()); + + if(context.isExtensionSupported()) { + storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDSA; + storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDSA; + } else { + storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDefault; + storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationDefault; + } + } else { + storage2DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationFallback; + storage3DMultisampleImplementation = &AbstractTexture::storageMultisampleImplementationFallback; + } + #endif + /* Anisotropic filter implementation */ if(context.isExtensionSupported()) { extensions.push_back(Extensions::GL::EXT::texture_filter_anisotropic::string()); diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index 098080fb0..a3057eca4 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -54,6 +54,8 @@ struct TextureState { void(AbstractTexture::*storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&); void(AbstractTexture::*storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&); #ifndef MAGNUM_TARGET_GLES + void(AbstractTexture::*storage2DMultisampleImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&, GLboolean); + void(AbstractTexture::*storage3DMultisampleImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&, GLboolean); void(AbstractTexture::*getImageImplementation)(GLenum, GLint, ColorFormat, ColorType, std::size_t, GLvoid*); void(AbstractTexture::*image1DImplementation)(GLenum, GLint, TextureFormat, const Math::Vector<1, GLsizei>&, ColorFormat, ColorType, const GLvoid*); #endif diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index 9c676f40e..b48e0b054 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -594,6 +594,7 @@ class Mesh; class MeshView; #ifndef MAGNUM_TARGET_GLES +/* MultisampleTextureSampleLocations enum used only in the function */ template class MultisampleTexture; typedef MultisampleTexture<2> MultisampleTexture2D; typedef MultisampleTexture<3> MultisampleTexture2DArray; diff --git a/src/Magnum/MultisampleTexture.h b/src/Magnum/MultisampleTexture.h index 2ad0abc34..05d54a2c3 100644 --- a/src/Magnum/MultisampleTexture.h +++ b/src/Magnum/MultisampleTexture.h @@ -44,6 +44,16 @@ namespace Implementation { template<> inline constexpr GLenum multisampleTextureTarget<3>() { return GL_TEXTURE_2D_MULTISAMPLE_ARRAY; } } +/** +@brief Multisample texture sample locations + +@see @ref MultisampleTexture::setStorage() +*/ +enum class MultisampleTextureSampleLocations: GLboolean { + NotFixed = GL_FALSE, + Fixed = GL_TRUE +}; + /** @brief Mulitsample texture @@ -92,6 +102,46 @@ template class MultisampleTexture: public AbstractTextur return DataHelper::imageSize(*this, _target, 0); } + /** + * @brief Set storage + * @param samples Sample count + * @param internalFormat Internal format + * @param size %Texture size + * @param sampleLocations Whether to use fixed sample locations + * @return Reference to self (for method chaining) + * + * After calling this function the texture is immutable and calling + * @ref setStorage() again is not allowed. + * + * If @extension{EXT,direct_state_access} is not available, the texture + * is bound to some texture unit before the operation. If + * @extension{ARB,texture_storage_multisample} (part of OpenGL 4.3) is + * not available, the feature is emulated using plain + * @extension{ARB,texture_storage} functionality (which unfortunately + * doesn't have any DSA alternative, so the texture must be bound + * to some texture unit before). + * @see @ref maxColorSamples(), @ref maxDepthSamples(), + * @ref maxIntegerSamples(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} + * and @fn_gl{TexStorage2DMultisample}/@fn_gl{TexStorage3DMultisample} + * or @fn_gl_extension{TextureStorage2DMultisample,EXT,direct_state_access}/ + * @fn_gl_extension{TextureStorage3DMultisample,EXT,direct_state_access} + * eventually @fn_gl{TexImage2DMultisample}/@fn_gl{TexImage3DMultisample} + * @todoc Remove the workaround when it stops breaking Doxygen layout so badly + */ + /* The default parameter value was chosen based on discussion in + ARB_texture_multisample specs (fixed locations is treated as the + special case) */ + MultisampleTexture& setStorage(Int samples, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size, MultisampleTextureSampleLocations sampleLocations = + #ifndef DOXYGEN_GENERATING_OUTPUT + MultisampleTextureSampleLocations::NotFixed + #else + NotFixed + #endif + ) { + DataHelper::setStorageMultisample(*this, _target, samples, internalFormat, size, GLboolean(sampleLocations)); + return *this; + } + /** @copydoc RectangleTexture::invalidateImage() */ void invalidateImage() { AbstractTexture::invalidateImage(0); } diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp index dfbd2de98..e5b8115b4 100644 --- a/src/Magnum/Test/MultisampleTextureGLTest.cpp +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -26,6 +26,8 @@ #include #include "Magnum/MultisampleTexture.h" +#include "Magnum/TextureFormat.h" +#include "Magnum/Math/Vector3.h" #include "Magnum/Test/AbstractOpenGLTester.h" namespace Magnum { namespace Test { @@ -103,8 +105,8 @@ void MultisampleTextureGLTest::bind2D() { if(Context::current()->isExtensionSupported()) { CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); + texture.setStorage(4, TextureFormat::RGBA8, {16, 16}); CORRADE_VERIFY(false); - CORRADE_SKIP("...but we don't have any function to do that yet."); } texture.bind(15); @@ -128,8 +130,8 @@ void MultisampleTextureGLTest::bind2DArray() { if(Context::current()->isExtensionSupported()) { CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); + texture.setStorage(4, TextureFormat::RGBA8, {16, 16, 5}); CORRADE_VERIFY(false); - CORRADE_SKIP("...but we don't have any function to do that yet."); } texture.bind(15); @@ -149,42 +151,72 @@ void MultisampleTextureGLTest::storage2D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Not implemented yet."); + MultisampleTexture2D texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(), Vector2i(16, 16)); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::storage2DArray() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Not implemented yet."); + MultisampleTexture2DArray texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16, 5}); + + MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.imageSize(), Vector3i(16, 16, 5)); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::invalidateImage2D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Multisample storage is not implemented yet."); + MultisampleTexture2D texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16}); + texture.invalidateImage(); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::invalidateImage2DArray() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Multisample storage is not implemented yet."); + MultisampleTexture2DArray texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16, 5}); + texture.invalidateImage(); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::invalidateSubImage2D() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Multisample storage is not implemented yet."); + MultisampleTexture2D texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16}); + texture.invalidateSubImage({3, 4}, {5, 6}); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::invalidateSubImage2DArray() { if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); - CORRADE_SKIP("Multisample storage is not implemented yet."); + MultisampleTexture2DArray texture; + texture.setStorage(4, TextureFormat::RGBA8, {16, 16, 5}); + texture.invalidateSubImage({3, 4, 1}, {5, 6, 3}); + + MAGNUM_VERIFY_NO_ERROR(); } }}