diff --git a/Doxyfile b/Doxyfile index c6ab1a574..257379fc2 100644 --- a/Doxyfile +++ b/Doxyfile @@ -220,6 +220,7 @@ ALIASES = \ "extension{2}=\1_\2" \ "requires_gles30=@xrefitem requires-gles30 \"Requires OpenGL ES 3.0\" \"Functionality requiring OpenGL ES 3.0\"" \ "requires_gl=@xrefitem requires-gl \"Requires desktop OpenGL\" \"Functionality requiring desktop OpenGL (not available in OpenGL ES)\"" \ + "requires_gles20=@xrefitem requires-gles20 \"Requires OpenGL ES 2.0\" \"Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL)\"" \ "requires_es_extension=@xrefitem requires-es-extension \"Requires OpenGL ES extension\" \"Functionality requiring specific OpenGL ES extension\"" \ "es_extension{2}=\1_\2" \ "es_extension2{3}=\1_\2" diff --git a/PKGBUILD-es2 b/PKGBUILD-es2 index e4c937d64..5372804da 100644 --- a/PKGBUILD-es2 +++ b/PKGBUILD-es2 @@ -26,8 +26,6 @@ build() { -DBUILD_TESTS=ON \ -DTARGET_GLES=ON \ -DTARGET_GLES2=ON \ - -DWITH_TEXT=OFF \ - -DWITH_TEXTURETOOLS=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/PKGBUILD-es2desktop b/PKGBUILD-es2desktop index 55fa9ccb9..8467066d9 100644 --- a/PKGBUILD-es2desktop +++ b/PKGBUILD-es2desktop @@ -27,10 +27,9 @@ build() { -DTARGET_GLES=ON \ -DTARGET_GLES2=ON \ -DTARGET_DESKTOP_GLES=ON \ - -DWITH_TEXT=OFF \ - -DWITH_TEXTURETOOLS=OFF \ - -DWITH_MAGNUMINFO=OFF \ - -DWITH_XEGLAPPLICATION=ON + -DWITH_MAGNUMINFO=ON \ + -DWITH_GLXAPPLICATION=ON \ + -DWITH_WINDOWLESSGLXAPPLICATION=ON make } diff --git a/PKGBUILD-es3 b/PKGBUILD-es3 index e567c82a8..6c8a8aef6 100644 --- a/PKGBUILD-es3 +++ b/PKGBUILD-es3 @@ -26,8 +26,6 @@ build() { -DBUILD_TESTS=ON \ -DTARGET_GLES=ON \ -DTARGET_GLES2=OFF \ - -DWITH_TEXT=OFF \ - -DWITH_TEXTURETOOLS=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/doc/required-extensions.dox b/doc/required-extensions.dox index 610e4542b..2d56cfa65 100644 --- a/doc/required-extensions.dox +++ b/doc/required-extensions.dox @@ -48,13 +48,11 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only). - @subpage requires-gl43 - @subpage requires-extension - @subpage requires-gl +- @subpage requires-gles20 - @subpage requires-gles30 - @subpage requires-es-extension - @subpage unsupported -@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES) -@see @ref MAGNUM_TARGET_GLES_ "MAGNUM_TARGET_GLES" - @page requires-gl30 Functionality requiring OpenGL 3.0 @page requires-gl31 Functionality requiring OpenGL 3.1 @page requires-gl32 Functionality requiring OpenGL 3.2 @@ -66,9 +64,15 @@ supported on Intel GPUs even if they are capable of OpenGL 2.1 only). @page requires-extension Functionality requiring specific OpenGL extension -@page requires-gles30 Functionality requiring OpenGL ES 3.0 +@page requires-gl Functionality requiring desktop OpenGL (not available on OpenGL ES) +@see @ref MAGNUM_TARGET_GLES_ "MAGNUM_TARGET_GLES" + +@page requires-gles20 Functionality requiring OpenGL ES 2.0 (not available in ES 3.0 and desktop OpenGL) @see @ref MAGNUM_TARGET_GLES2_ "MAGNUM_TARGET_GLES2" +@page requires-gles30 Functionality requiring OpenGL ES 3.0 +@see @ref MAGNUM_TARGET_GLES3_ "MAGNUM_TARGET_GLES3" + @page requires-es-extension Functionality requiring specific OpenGL ES extension @see @ref MAGNUM_TARGET_GLES2_ "MAGNUM_TARGET_GLES2" diff --git a/doc/unsupported.dox b/doc/unsupported.dox index 85a52c830..0c6efc4ec 100644 --- a/doc/unsupported.dox +++ b/doc/unsupported.dox @@ -29,8 +29,6 @@ add any performance gains, is not supported in %Magnum. @section unsupported-features Unsupported features -- Luminance texture formats (OpenGL ES) are not supported, as they are - deprecated in OpenGL ES 3.0 and not present in core desktop OpenGL. - Fixed precision data types (OpenGL ES) are not supported, as they occupy the same memory as floats and they aren't faster than floats on current hardware anymore. diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index bc9b20eb5..c410aac91 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -34,16 +34,18 @@ namespace Magnum { +AbstractFramebuffer::CheckStatusImplementation AbstractFramebuffer::checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; + AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault; AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; AbstractFramebuffer::DrawBufferImplementation AbstractFramebuffer::drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDefault; AbstractFramebuffer::ReadBufferImplementation AbstractFramebuffer::readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDefault; +#ifdef MAGNUM_TARGET_GLES2 FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw; FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw; - -AbstractFramebuffer::~AbstractFramebuffer() {} +#endif void AbstractFramebuffer::bind(FramebufferTarget target) { bindInternal(target); @@ -81,10 +83,15 @@ FramebufferTarget AbstractFramebuffer::bindInternal() { /* Or bind it, if not already */ state->readBinding = _id; - if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; + #ifndef MAGNUM_TARGET_GLES2 + glBindFramebuffer(GLenum(FramebufferTarget::Read), _id); + return FramebufferTarget::Read; + #else + if(readTarget == FramebufferTarget::ReadDraw) state->drawBinding = _id; glBindFramebuffer(GLenum(readTarget), _id); return readTarget; + #endif } void AbstractFramebuffer::blit(AbstractFramebuffer& source, AbstractFramebuffer& destination, const Rectanglei& sourceRectangle, const Rectanglei& destinationRectangle, FramebufferBlitMask mask, FramebufferBlitFilter filter) { @@ -126,12 +133,20 @@ void AbstractFramebuffer::setViewportInternal() { } void AbstractFramebuffer::clear(FramebufferClearMask mask) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif glClear(static_cast(mask)); } void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Image2D* image) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif const std::size_t dataSize = image->pixelSize()*size.product(); char* const data = new char[dataSize]; readImplementation(offset, size, image->format(), image->type(), dataSize, data); @@ -140,7 +155,11 @@ void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, Ima #ifndef MAGNUM_TARGET_GLES2 void AbstractFramebuffer::read(const Vector2i& offset, const Vector2i& size, BufferImage2D* image, Buffer::Usage usage) { + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif /* If the buffer doesn't have sufficient size, resize it */ /** @todo Explicitly reset also when buffer usage changes */ if(image->size() != size) @@ -177,22 +196,42 @@ void AbstractFramebuffer::invalidateImplementation(GLsizei count, GLenum* attach void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) { #ifndef MAGNUM_TARGET_GLES - if(context->isExtensionSupported()) { - Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::framebuffer_blit::string() << "features"; - - readTarget = FramebufferTarget::Read; - drawTarget = FramebufferTarget::Draw; - } - if(context->isExtensionSupported()) { Debug() << "AbstractFramebuffer: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDSA; drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDSA; drawBufferImplementation = &AbstractFramebuffer::drawBufferImplementationDSA; readBufferImplementation = &AbstractFramebuffer::readBufferImplementationDSA; } #endif + #ifdef MAGNUM_TARGET_GLES2 + /* Optimistically set separate binding targets and check if one of the + extensions providing them is available */ + readTarget = FramebufferTarget::Read; + drawTarget = FramebufferTarget::Draw; + + if(context->isExtensionSupported()) + Debug() << "AbstractFramebuffer: using" << Extensions::GL::ANGLE::framebuffer_blit::string() << "features"; + + else if(context->isExtensionSupported()) + Debug() << "AbstractFramebuffer: using" << Extensions::GL::APPLE::framebuffer_multisample::string() << "features"; + + else if(context->isExtensionSupported()) + Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_blit::string() << "features"; + + /* NV_framebuffer_multisample requires NV_framebuffer_blit, which has these + enums. However, on my system only NV_framebuffer_multisample is + supported, but NV_framebuffer_blit isn't. I will hold my breath and + assume these enums are available. */ + else if(context->isExtensionSupported()) + Debug() << "AbstractFramebuffer: using" << Extensions::GL::NV::framebuffer_multisample::string() << "features"; + + /* If no such extension is available, reset back to unified target */ + else readTarget = drawTarget = FramebufferTarget::ReadDraw; + #endif + #ifndef MAGNUM_TARGET_GLES3 #ifndef MAGNUM_TARGET_GLES if(context->isExtensionSupported()) @@ -216,10 +255,25 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) #endif } +GLenum AbstractFramebuffer::checkStatusImplementationDefault(const FramebufferTarget target) { + bindInternal(target); + return glCheckFramebufferStatus(GLenum(target)); +} + +#ifndef MAGNUM_TARGET_GLES +GLenum AbstractFramebuffer::checkStatusImplementationDSA(const FramebufferTarget target) { + return glCheckNamedFramebufferStatusEXT(_id, GLenum(target)); +} +#endif + void AbstractFramebuffer::drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers) { /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif glDrawBuffers(count, buffers); #else static_cast(count); @@ -236,7 +290,11 @@ void AbstractFramebuffer::drawBuffersImplementationDSA(GLsizei count, const GLen void AbstractFramebuffer::drawBufferImplementationDefault(GLenum buffer) { /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Draw); + #else bindInternal(drawTarget); + #endif #ifndef MAGNUM_TARGET_GLES3 glDrawBuffer(buffer); #else @@ -256,7 +314,11 @@ void AbstractFramebuffer::drawBufferImplementationDSA(GLenum buffer) { void AbstractFramebuffer::readBufferImplementationDefault(GLenum buffer) { /** @todo Get some extension wrangler instead to avoid undeclared glReadBuffer() on ES2 */ #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES2 + bindInternal(FramebufferTarget::Read); + #else bindInternal(readTarget); + #endif glReadBuffer(buffer); #else static_cast(buffer); diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 792ffa182..f9e486ff1 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -40,10 +40,10 @@ namespace Magnum { /** - * @brief Mask for framebuffer clearing - * - * @see AbstractFramebuffer, FramebufferClearMask - */ +@brief Mask for framebuffer clearing + +@see AbstractFramebuffer, FramebufferClearMask +*/ enum class FramebufferClear: GLbitfield { Color = GL_COLOR_BUFFER_BIT, /**< Color */ Depth = GL_DEPTH_BUFFER_BIT, /**< Depth value */ @@ -51,21 +51,21 @@ enum class FramebufferClear: GLbitfield { }; /** - * @brief Mask for clearing - * - * @see AbstractFramebuffer::clear() - */ +@brief Mask for clearing + +@see AbstractFramebuffer::clear() +*/ typedef Containers::EnumSet FramebufferClearMask; /** - * @brief Mask for framebuffer blitting - * - * @see AbstractFramebuffer, FramebufferBlitMask - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ +@brief Mask for framebuffer blitting + +@see AbstractFramebuffer, FramebufferBlitMask +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ enum class FramebufferBlit: GLbitfield { ColorBuffer = GL_COLOR_BUFFER_BIT, /**< Color buffer */ DepthBuffer = GL_DEPTH_BUFFER_BIT, /**< Depth buffer */ @@ -73,36 +73,38 @@ enum class FramebufferBlit: GLbitfield { }; /** - * @brief Mask for framebuffer blitting - * - * @see AbstractFramebuffer::blit() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or - * @es_extension{NV,framebuffer_blit} - */ +@brief Mask for framebuffer blitting + +@see AbstractFramebuffer::blit() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ typedef Containers::EnumSet FramebufferBlitMask; /** - * @brief %Framebuffer blit filtering - * - * @see AbstractFramebuffer::blit() - */ +@brief %Framebuffer blit filtering + +@see AbstractFramebuffer::blit() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +@requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or + @es_extension{NV,framebuffer_blit} +*/ enum class FramebufferBlitFilter: GLenum { Nearest = GL_NEAREST, /**< Nearest neighbor filtering */ Linear = GL_LINEAR /**< Linear interpolation filtering */ }; /** - * @brief Target for binding framebuffer - * - * @see DefaultFramebuffer::bind(), Framebuffer::bind() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} - */ +@brief Target for binding framebuffer + +@see DefaultFramebuffer::bind(), Framebuffer::bind() +@requires_gl30 %Extension @extension{ARB,framebuffer_object} +*/ enum class FramebufferTarget: GLenum { /** * For reading only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} */ @@ -114,7 +116,6 @@ enum class FramebufferTarget: GLenum { /** * For drawing only. - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{APPLE,framebuffer_multisample}, * @es_extension{ANGLE,framebuffer_blit} or @es_extension{NV,framebuffer_blit} */ @@ -167,7 +168,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Framebuffer::mapForDraw() for specifying particular buffers for * blitting operation. * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ @@ -186,7 +186,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { * @ref FramebufferBlitFilter "FramebufferBlitFilter::Nearest" * filtering is used by default. * @see @fn_gl{BlitFramebuffer} - * @requires_gl30 %Extension @extension{EXT,framebuffer_blit} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_blit} or * @es_extension{NV,framebuffer_blit} */ @@ -195,7 +194,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { } explicit AbstractFramebuffer(); - virtual ~AbstractFramebuffer() = 0; /** * @brief Bind framebuffer for rendering @@ -205,6 +203,8 @@ class MAGNUM_EXPORT AbstractFramebuffer { * Framebuffer::mapForRead(), DefaultFramebuffer::mapForDraw(), * Framebuffer::mapForDraw(), @fn_gl{BindFramebuffer}, * @fn_gl{Viewport} + * @todo Bind internally to ReadDraw if separate binding points are not + * supported */ void bind(FramebufferTarget target); @@ -272,12 +272,19 @@ class MAGNUM_EXPORT AbstractFramebuffer { #else protected: #endif + ~AbstractFramebuffer() = default; + void MAGNUM_LOCAL bindInternal(FramebufferTarget target); FramebufferTarget MAGNUM_LOCAL bindInternal(); void MAGNUM_LOCAL setViewportInternal(); + #ifdef MAGNUM_TARGET_GLES2 static MAGNUM_LOCAL FramebufferTarget readTarget; static MAGNUM_LOCAL FramebufferTarget drawTarget; + #endif + + typedef GLenum(AbstractFramebuffer::*CheckStatusImplementation)(FramebufferTarget); + static CheckStatusImplementation checkStatusImplementation; typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; @@ -297,6 +304,11 @@ class MAGNUM_EXPORT AbstractFramebuffer { private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + GLenum MAGNUM_LOCAL checkStatusImplementationDefault(FramebufferTarget target); + #ifndef MAGNUM_TARGET_GLES + GLenum MAGNUM_LOCAL checkStatusImplementationDSA(FramebufferTarget target); + #endif + void MAGNUM_LOCAL drawBuffersImplementationDefault(GLsizei count, const GLenum* buffers); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL drawBuffersImplementationDSA(GLsizei count, const GLenum* buffers); diff --git a/src/AbstractImage.cpp b/src/AbstractImage.cpp index 253f2ec37..0e3af2904 100644 --- a/src/AbstractImage.cpp +++ b/src/AbstractImage.cpp @@ -99,11 +99,17 @@ std::size_t AbstractImage::pixelSize(ImageFormat format, ImageType type) { case ImageFormat::Blue: case ImageFormat::GreenInteger: case ImageFormat::BlueInteger: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case ImageFormat::Luminance: #endif return 1*size; case ImageFormat::RG: #ifndef MAGNUM_TARGET_GLES2 case ImageFormat::RGInteger: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case ImageFormat::LuminanceAlpha: #endif return 2*size; case ImageFormat::RGB: diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index af7e6a218..6e892d7e8 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -116,10 +116,9 @@ std::pair AbstractShaderProgram::validate() { /* Error or warning message. The string is returned null-terminated, scrap the \0 at the end afterwards */ std::string message(logLength, '\n'); - if(!message.empty()) { + if(message.size() > 1) glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(logLength-1); - } + message.resize(std::max(logLength, 1)-1); return {success, std::move(message)}; } @@ -159,10 +158,9 @@ bool AbstractShaderProgram::link() { /* Error or warning message. The string is returned null-terminated, scrap the \0 at the end afterwards */ std::string message(logLength, '\n'); - if(!message.empty()) { + if(message.size() > 1) glGetProgramInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(logLength-1); - } + message.resize(std::max(logLength, 1)-1); /* Show error log and delete shader */ if(!success) { diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index 315cdd811..e96b931be 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -29,6 +29,8 @@ #include "Context.h" #include "Extensions.h" #include "Image.h" +#include "ImageFormat.h" +#include "TextureFormat.h" #include "Implementation/State.h" #include "Implementation/TextureState.h" @@ -50,12 +52,12 @@ AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation = &AbstractTexture::mipmapImplementationDefault; #ifndef MAGNUM_TARGET_GLES AbstractTexture::Storage1DImplementation AbstractTexture::storage1DImplementation = - &AbstractTexture::storageImplementationDefault; + &AbstractTexture::storageImplementationFallback; #endif AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementation = - &AbstractTexture::storageImplementationDefault; + &AbstractTexture::storageImplementationFallback; AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation = - &AbstractTexture::storageImplementationDefault; + &AbstractTexture::storageImplementationFallback; #ifndef MAGNUM_TARGET_GLES AbstractTexture::GetImageImplementation AbstractTexture::getImageImplementation = &AbstractTexture::getImageImplementationDefault; @@ -205,9 +207,6 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; - storage1DImplementation = &AbstractTexture::storageImplementationDSA; - storage2DImplementation = &AbstractTexture::storageImplementationDSA; - storage3DImplementation = &AbstractTexture::storageImplementationDSA; getImageImplementation = &AbstractTexture::getImageImplementationDSA; image1DImplementation = &AbstractTexture::imageImplementationDSA; image2DImplementation = &AbstractTexture::imageImplementationDSA; @@ -230,9 +229,396 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { getImageImplementation = &AbstractTexture::getImageImplementationRobustness; } + + if(context->isExtensionSupported()) { + Debug() << "AbstractTexture: using" << Extensions::GL::ARB::texture_storage::string() << "features"; + + if(context->isExtensionSupported()) { + storage1DImplementation = &AbstractTexture::storageImplementationDSA; + storage2DImplementation = &AbstractTexture::storageImplementationDSA; + storage3DImplementation = &AbstractTexture::storageImplementationDSA; + } else { + storage1DImplementation = &AbstractTexture::storageImplementationDefault; + storage2DImplementation = &AbstractTexture::storageImplementationDefault; + storage3DImplementation = &AbstractTexture::storageImplementationDefault; + } + } #endif } +ImageFormat AbstractTexture::imageFormatForInternalFormat(const TextureFormat internalFormat) { + switch(internalFormat) { + case TextureFormat::Red: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R8: + case TextureFormat::R8Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::R16: + case TextureFormat::R16Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R16F: + case TextureFormat::R32F: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedRed: + case TextureFormat::CompressedRedRtgc1: + case TextureFormat::CompressedSignedRedRgtc1: + #endif + return ImageFormat::Red; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R8UI: + case TextureFormat::R8I: + case TextureFormat::R16UI: + case TextureFormat::R16I: + case TextureFormat::R32UI: + case TextureFormat::R32I: + return ImageFormat::RedInteger; + #endif + + case TextureFormat::RG: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RG8: + case TextureFormat::RG8Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RG16: + case TextureFormat::RG16Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RG16F: + case TextureFormat::RG32F: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedRG: + case TextureFormat::CompressedRGRgtc2: + case TextureFormat::CompressedSignedRGRgtc2: + #endif + return ImageFormat::RG; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RG8UI: + case TextureFormat::RG8I: + case TextureFormat::RG16UI: + case TextureFormat::RG16I: + case TextureFormat::RG32UI: + case TextureFormat::RG32I: + return ImageFormat::RGInteger; + #endif + + case TextureFormat::RGB: + case TextureFormat::RGB8: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGB8Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGB16: + case TextureFormat::RGB16Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGB16F: + case TextureFormat::RGB32F: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::R3B3G2: + case TextureFormat::RGB4: + case TextureFormat::RGB5: + #endif + case TextureFormat::RGB565: + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::RGB10: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGB12: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R11FG11FB10F: + case TextureFormat::RGB9E5: + #endif + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::SRGB: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::SRGB8: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedRGB: + case TextureFormat::CompressedRGBBptcUnsignedFloat: + case TextureFormat::CompressedRGBBptcSignedFloat: + #endif + return ImageFormat::RGB; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGB8UI: + case TextureFormat::RGB8I: + case TextureFormat::RGB16UI: + case TextureFormat::RGB16I: + case TextureFormat::RGB32UI: + case TextureFormat::RGB32I: + return ImageFormat::RGBInteger; + #endif + + case TextureFormat::RGBA: + case TextureFormat::RGBA8: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGBA8Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGBA16: + case TextureFormat::RGBA16Snorm: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGBA16F: + case TextureFormat::RGBA32F: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGBA2: + #endif + case TextureFormat::RGBA4: + case TextureFormat::RGB5A1: + case TextureFormat::RGB10A2: + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGBA12: + #endif + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::SRGBAlpha: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::SRGB8Alpha8: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedRGBA: + case TextureFormat::CompressedRGBABptcUnorm: + case TextureFormat::CompressedSRGBAlphaBptcUnorm: + #endif + return ImageFormat::RGBA; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGBA8UI: + case TextureFormat::RGBA8I: + case TextureFormat::RGBA16UI: + case TextureFormat::RGBA16I: + case TextureFormat::RGBA32UI: + case TextureFormat::RGBA32I: + case TextureFormat::RGB10A2UI: + return ImageFormat::RGBAInteger; + #endif + + #ifdef MAGNUM_TARGET_GLES2 + case TextureFormat::Luminance: + return ImageFormat::Luminance; + case TextureFormat::LuminanceAlpha: + return ImageFormat::LuminanceAlpha; + #endif + + case TextureFormat::DepthComponent: + case TextureFormat::DepthComponent16: + case TextureFormat::DepthComponent24: + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::DepthComponent32: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::DepthComponent32F: + #endif + return ImageFormat::DepthComponent; + + case TextureFormat::DepthStencil: + case TextureFormat::Depth24Stencil8: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::Depth32FStencil8: + #endif + return ImageFormat::DepthStencil; + } + + CORRADE_ASSERT_UNREACHABLE(); +} + +ImageType AbstractTexture::imageTypeForInternalFormat(const TextureFormat internalFormat) { + switch(internalFormat) { + case TextureFormat::Red: + case TextureFormat::RG: + case TextureFormat::RGB: + case TextureFormat::RGBA: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R8: + case TextureFormat::RG8: + #endif + case TextureFormat::RGB8: + case TextureFormat::RGBA8: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R8UI: + case TextureFormat::RG8UI: + case TextureFormat::RGB8UI: + case TextureFormat::RGBA8UI: + #endif + #ifdef MAGNUM_TARGET_GLES2 + case TextureFormat::Luminance: + case TextureFormat::LuminanceAlpha: + #endif + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::SRGB: + case TextureFormat::SRGBAlpha: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::SRGB8: + case TextureFormat::SRGB8Alpha8: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGBA2: /**< @todo really? */ + case TextureFormat::CompressedRed: + case TextureFormat::CompressedRG: + case TextureFormat::CompressedRGB: + case TextureFormat::CompressedRGBA: + case TextureFormat::CompressedRedRtgc1: + case TextureFormat::CompressedRGRgtc2: + case TextureFormat::CompressedRGBABptcUnorm: + case TextureFormat::CompressedSRGBAlphaBptcUnorm: + #endif + return ImageType::UnsignedByte; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R8Snorm: + case TextureFormat::RG8Snorm: + case TextureFormat::RGB8Snorm: + case TextureFormat::RGBA8Snorm: + case TextureFormat::R8I: + case TextureFormat::RG8I: + case TextureFormat::RGB8I: + case TextureFormat::RGBA8I: + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedSignedRedRgtc1: + case TextureFormat::CompressedSignedRGRgtc2: + #endif + return ImageType::Byte; + #endif + + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::R16: + case TextureFormat::RG16: + case TextureFormat::RGB16: + case TextureFormat::RGBA16: + #endif + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R16UI: + case TextureFormat::RG16UI: + case TextureFormat::RGB16UI: + case TextureFormat::RGBA16UI: + #endif + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGB12: /**< @todo really? */ + #endif + case TextureFormat::RGBA4: /**< @todo really? */ + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGBA12: /**< @todo really? */ + #endif + return ImageType::UnsignedShort; + + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::R16Snorm: + case TextureFormat::RG16Snorm: + case TextureFormat::RGB16Snorm: + case TextureFormat::RGBA16Snorm: + #endif + case TextureFormat::R16I: + case TextureFormat::RG16I: + case TextureFormat::RGB16I: + case TextureFormat::RGBA16I: + return ImageType::Short; + #endif + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R16F: + case TextureFormat::RG16F: + case TextureFormat::RGB16F: + case TextureFormat::RGBA16F: + return ImageType::HalfFloat; + + case TextureFormat::R32UI: + case TextureFormat::RG32UI: + case TextureFormat::RGB32UI: + case TextureFormat::RGBA32UI: + return ImageType::UnsignedInt; + + case TextureFormat::R32I: + case TextureFormat::RG32I: + case TextureFormat::RGB32I: + case TextureFormat::RGBA32I: + return ImageType::Int; + + case TextureFormat::R32F: + case TextureFormat::RG32F: + case TextureFormat::RGB32F: + case TextureFormat::RGBA32F: + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::CompressedRGBBptcUnsignedFloat: + case TextureFormat::CompressedRGBBptcSignedFloat: + #endif + return ImageType::Float; + #endif + + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::R3B3G2: + return ImageType::UnsignedByte332; + case TextureFormat::RGB4: + return ImageType::UnsignedShort4444; + #endif + + #ifndef MAGNUM_TARGET_GLES + case TextureFormat::RGB5: + #endif + case TextureFormat::RGB5A1: + return ImageType::UnsignedShort5551; + + case TextureFormat::RGB565: + return ImageType::UnsignedShort565; + + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::RGB10: + #endif + case TextureFormat::RGB10A2: + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::RGB10A2UI: + #endif + return ImageType::UnsignedInt2101010Rev; /**< @todo Rev for all? */ + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::R11FG11FB10F: + return ImageType::UnsignedInt10F11F11FRev; + case TextureFormat::RGB9E5: + return ImageType::UnsignedInt5999Rev; + #endif + + case TextureFormat::DepthComponent16: + return ImageType::UnsignedShort; + + case TextureFormat::DepthComponent: + case TextureFormat::DepthComponent24: + #ifndef MAGNUM_TARGET_GLES3 + case TextureFormat::DepthComponent32: + #endif + return ImageType::UnsignedInt; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::DepthComponent32F: + return ImageType::Float; + #endif + + case TextureFormat::DepthStencil: + case TextureFormat::Depth24Stencil8: + return ImageType::UnsignedInt248; + + #ifndef MAGNUM_TARGET_GLES2 + case TextureFormat::Depth32FStencil8: + return ImageType::Float32UnsignedInt248Rev; + #endif + } + + CORRADE_ASSERT_UNREACHABLE(); +} + void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLint value) { bindInternal(); glTexParameteri(_target, parameter, value); @@ -278,7 +664,20 @@ void AbstractTexture::getLevelParameterImplementationDSA(GLenum target, GLint le #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { +void AbstractTexture::storageImplementationFallback(const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { + CORRADE_INTERNAL_ASSERT(target == GL_TEXTURE_1D); + + const ImageFormat format = imageFormatForInternalFormat(internalFormat); + const ImageType type = imageTypeForInternalFormat(internalFormat); + + auto levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + (this->*image1DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); + levelSize = Math::max(Math::Vector<1, GLsizei>(1), levelSize/2); + } +} + +void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 @@ -292,11 +691,56 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels #endif } -void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector< 1, GLsizei >& size) { +void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { glTextureStorage1DEXT(_id, target, levels, GLenum(internalFormat), size[0]); } #endif +void AbstractTexture::storageImplementationFallback(const GLenum target, const GLsizei levels, const TextureFormat internalFormat, const Vector2i& size) { + const ImageFormat format = imageFormatForInternalFormat(internalFormat); + const ImageType type = imageTypeForInternalFormat(internalFormat); + + /* Common code for classic types */ + #ifndef MAGNUM_TARGET_GLES + if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE) + #else + if(target == GL_TEXTURE_2D) + #endif + { + Vector2i levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + (this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); + levelSize = Math::max(Vector2i(1), levelSize/2); + } + + /* Cube map additionaly needs to specify all faces */ + } else if(target == GL_TEXTURE_CUBE_MAP) { + Vector2i levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + for(GLenum face: {GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}) + (this->*image2DImplementation)(face, level, internalFormat, levelSize, format, type, nullptr); + levelSize = Math::max(Vector2i(1), levelSize/2); + } + + #ifndef MAGNUM_TARGET_GLES + /* Array texture is not scaled in "layer" dimension */ + } else if(target == GL_TEXTURE_1D_ARRAY) { + Vector2i levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + (this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); + levelSize.x() = Math::max(1, levelSize.x()/2); + } + #endif + + /* No other targets are available */ + } else CORRADE_ASSERT_UNREACHABLE(); +} + void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ @@ -317,6 +761,43 @@ void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, Te } #endif +void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { + const ImageFormat format = imageFormatForInternalFormat(internalFormat); + const ImageType type = imageTypeForInternalFormat(internalFormat); + + /* Common code for classic type */ + #ifndef MAGNUM_TARGET_GLES2 + if(target == GL_TEXTURE_3D) + #else + if(target == GL_TEXTURE_3D_OES) + #endif + { + Vector3i levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + (this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); + levelSize = Math::max(Vector3i(1), levelSize/2); + } + + #ifndef MAGNUM_TARGET_GLES2 + /* Array texture is not scaled in "layer" dimension */ + } + #ifndef MAGNUM_TARGET_GLES + else if(target == GL_TEXTURE_2D_ARRAY || target == GL_TEXTURE_CUBE_MAP_ARRAY) + #else + else if(target == GL_TEXTURE_2D_ARRAY) + #endif + { + Vector3i levelSize = size; + for(GLsizei level = 0; level != levels; ++level) { + (this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); + levelSize.xy() = Math::max(Vector2i(1), levelSize.xy()/2); + } + #endif + + /* No other targets are available */ + } else CORRADE_ASSERT_UNREACHABLE(); +} + void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { bindInternal(); /** @todo Re-enable when extension wrangler is available for ES2 */ diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index 44292becc..018b2b228 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -77,6 +77,13 @@ avoid redundant consistency checks and memory reallocations when updating texture data, set texture storage at once using @ref Texture::setStorage() "setStorage()" and then set data using @ref Texture::setSubImage() "setSubImage()". +Function @ref Texture::setStorage() "setStorage()" creates immutable texture +storage, removing the need for additional consistency checks and memory +reallocations when updating the data later. If OpenGL 4.2, @extension{ARB,texture_storage}, +OpenGL ES 3.0 or @es_extension{EXT,texture_storage} in OpenGL ES 2.0 is not +available, the feature is emulated with sequence of @ref Texture::setImage() "setImage()" +calls. + You can use functions invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()" if you don't need texture data anymore to avoid unnecessary memory operations performed by OpenGL in order to preserve the data. If running on OpenGL ES or @@ -251,7 +258,7 @@ class MAGNUM_EXPORT AbstractTexture { * @see setMinificationFilter(), @fn_gl{ActiveTexture}, * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ AbstractTexture* generateMipmap(); @@ -319,12 +326,14 @@ class MAGNUM_EXPORT AbstractTexture { #ifndef MAGNUM_TARGET_GLES typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, TextureFormat, const Math::Vector<1, GLsizei>&); + void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size); static Storage1DImplementation storage1DImplementation; #endif typedef void(AbstractTexture::*Storage2DImplementation)(GLenum, GLsizei, TextureFormat, const Vector2i&); + void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size); @@ -332,6 +341,7 @@ class MAGNUM_EXPORT AbstractTexture { static Storage2DImplementation storage2DImplementation; typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, TextureFormat, const Vector3i&); + void MAGNUM_LOCAL storageImplementationFallback(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size); @@ -404,6 +414,8 @@ class MAGNUM_EXPORT AbstractTexture { void MAGNUM_LOCAL destroy(); void MAGNUM_LOCAL move(); + ImageFormat MAGNUM_LOCAL imageFormatForInternalFormat(TextureFormat internalFormat); + ImageType MAGNUM_LOCAL imageTypeForInternalFormat(TextureFormat internalFormat); GLuint _id; }; diff --git a/src/Context.cpp b/src/Context.cpp index c91bf90a5..25014c222 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -97,14 +97,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,ARB,texture_float), // done _extension(GL,ARB,depth_buffer_float), // done _extension(GL,ARB,texture_rg), // done - /** - * @todo Remove as it doesn't have the same functionality present in - * GL 3.0 and replace with ARB_framebuffer_object? - */ - _extension(GL,EXT,framebuffer_object), - _extension(GL,EXT,packed_depth_stencil), // done - _extension(GL,EXT,framebuffer_blit), // done - _extension(GL,EXT,framebuffer_multisample), + _extension(GL,ARB,framebuffer_object), _extension(GL,EXT,gpu_shader4), _extension(GL,EXT,packed_float), // done _extension(GL,EXT,texture_array), @@ -213,7 +206,13 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,disjoint_timer_query), _extension(GL,EXT,separate_shader_objects), _extension(GL,EXT,sRGB), + /** + * @todo Support also IMG_multisampled_render_to_texture? It has + * different enum values (!) + */ + _extension(GL,EXT,multisampled_render_to_texture), _extension(GL,EXT,robustness), + _extension(GL,KHR,debug), _extension(GL,NV,read_buffer_front), _extension(GL,NV,read_stencil), _extension(GL,NV,texture_border_clamp), // done @@ -253,7 +252,8 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,OES,depth_texture), _extension(GL,OES,standard_derivatives), // done _extension(GL,OES,vertex_array_object), - _extension(GL,OES,required_internalformat)}; + _extension(GL,OES,required_internalformat), + _extension(GL,OES,surfaceless_context)}; // done #endif switch(version) { @@ -292,6 +292,14 @@ Context::Context() { #endif _version = static_cast(_majorVersion*100+_minorVersion*10); + #ifndef MAGNUM_TARGET_GLES + CORRADE_ASSERT(isVersionSupported(Version::GL210), "Context: unsupported OpenGL version" << Int(_version), ); + #elif defined(MAGNUM_TARGET_GLES2) + CORRADE_ASSERT(isVersionSupported(Version::GLES200), "Context: unsupported OpenGL ES version" << Int(_version), ); + #else + CORRADE_ASSERT(isVersionSupported(Version::GLES300), "Context: unsupported OpenGL ES version" << Int(_version), ); + #endif + /* Context flags are supported since GL 3.0 */ #ifndef MAGNUM_TARGET_GLES /** diff --git a/src/Context.h b/src/Context.h index 5e42b8620..1ee1dad67 100644 --- a/src/Context.h +++ b/src/Context.h @@ -382,8 +382,8 @@ class MAGNUM_EXPORT Context { Useful for initial checks on availability of required features. By default, if assertion fails, an message is printed to error output and the -application exits with value `-3`. If `CORRADE_NO_ASSERT` is defined, this -macro does nothing. Example usage: +application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing. +Example usage: @code MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); @endcode @@ -399,7 +399,7 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); do { \ if(!Magnum::Context::current()->isVersionSupported(version)) { \ Corrade::Utility::Error() << "Magnum: required version" << version << "is not supported"; \ - std::exit(-3); \ + std::abort(); \ } \ } while(0) #endif @@ -412,8 +412,8 @@ MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); Useful for initial checks on availability of required features. By default, if assertion fails, an message is printed to error output and the -application exits with value `-3`. If `CORRADE_NO_ASSERT` is defined, this -macro does nothing. Example usage: +application aborts. If `CORRADE_NO_ASSERT` is defined, this macro does nothing. +Example usage: @code MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); @endcode @@ -429,7 +429,7 @@ MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); do { \ if(!Magnum::Context::current()->isExtensionSupported()) { \ Corrade::Utility::Error() << "Magnum: required extension" << extension::string() << "is not supported"; \ - std::exit(-3); \ + std::abort(); \ } \ } while(0) #endif diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp index 5e1c9e021..346bd6ad5 100644 --- a/src/DefaultFramebuffer.cpp +++ b/src/DefaultFramebuffer.cpp @@ -90,4 +90,17 @@ void DefaultFramebuffer::initializeContextBasedFunctionality(Context* context) { #endif } +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, const DefaultFramebuffer::Status value) { + switch(value) { + #define _c(value) case DefaultFramebuffer::Status::value: return debug << "DefaultFramebuffer::Status::" #value; + _c(Complete) + _c(Undefined) + #undef _c + } + + return debug << "DefaultFramebuffer::Status::(invalid)"; +} +#endif + } diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 8f0a38148..a7e4bb7c0 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -80,6 +80,27 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { friend class Context; public: + /** + * @brief Status + * + * @see checkStatus() + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} + */ + enum class Status: GLenum { + /** The framebuffer is complete */ + Complete = GL_FRAMEBUFFER_COMPLETE, + + /** + * The default framebuffer does not exist. + * @requires_es_extension %Extension @es_extension{OES,surfaceless_context} + */ + #ifndef MAGNUM_TARGET_GLES2 + Undefined = GL_FRAMEBUFFER_UNDEFINED + #else + Undefined = GL_FRAMEBUFFER_UNDEFINED_OES + #endif + }; + #ifndef MAGNUM_TARGET_GLES2 /** * @brief Draw attachment @@ -270,6 +291,21 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { explicit MAGNUM_LOCAL DefaultFramebuffer(); + /** + * @brief Check framebuffer status + * @param target Target for which to check the status + * + * If @extension{EXT,direct_state_access} is not available and the + * framebuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or + * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} + */ + Status checkStatus(FramebufferTarget target) { + return Status((this->*checkStatusImplementation)(target)); + } + #ifndef MAGNUM_TARGET_GLES2 /** * @brief Map shader outputs to buffer attachment @@ -285,7 +321,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @endcode * * If @extension{EXT,direct_state_access} is not available and the - * framebufferbuffer is not currently bound, it is bound before the + * framebuffer is not currently bound, it is bound before the * operation. * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or * @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} @@ -303,7 +339,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * only one (unnamed) output. * * If @extension{EXT,direct_state_access} is not available and the - * framebufferbuffer is not currently bound, it is bound before the + * framebuffer is not currently bound, it is bound before the * operation. * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or * @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access}, @@ -323,7 +359,7 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { * @return Pointer to self (for method chaining) * * If @extension{EXT,direct_state_access} is not available and the - * framebufferbuffer is not currently bound, it is bound before the + * framebuffer is not currently bound, it is bound before the * operation. * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or * @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} @@ -380,6 +416,9 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { /** @brief Default framebuffer instance */ extern DefaultFramebuffer MAGNUM_EXPORT defaultFramebuffer; +/** @debugoperator{DefaultFramebuffer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, DefaultFramebuffer::Status value); + } #endif diff --git a/src/Extensions.h b/src/Extensions.h index ea74900da..f1582d657 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -76,6 +76,7 @@ namespace GL { _extension(GL,ARB,texture_float, GL210, GL300) // #41 _extension(GL,ARB,depth_buffer_float, GL210, GL300) // #43 _extension(GL,ARB,draw_instanced, GL210, GL310) // #44 + _extension(GL,ARB,framebuffer_object, GL210, GL300) // #45 _extension(GL,ARB,geometry_shader4, GL210, GL320) // #47 _extension(GL,ARB,instanced_arrays, GL210, GL330) // #49 _extension(GL,ARB,map_buffer_range, GL210, GL300) // #50 @@ -154,10 +155,8 @@ namespace GL { _extension(GL,ARB,texture_storage_multisample, GL210, GL430) // #141 } namespace EXT { _extension(GL,EXT,texture_filter_anisotropic, GL210, None) // #187 - _extension(GL,EXT,framebuffer_object, GL210, GL300) // #310 - _extension(GL,EXT,packed_depth_stencil, GL210, GL300) // #312 - _extension(GL,EXT,framebuffer_blit, GL210, GL300) // #316 - _extension(GL,EXT,framebuffer_multisample, GL210, GL300) // #317 + /* EXT_framebuffer_object, EXT_packed_depth_stencil, EXT_framebuffer_blit, + EXT_framebuffer_multisample replaced with ARB_framebuffer_object */ _extension(GL,EXT,gpu_shader4, GL210, GL300) // #326 _extension(GL,EXT,packed_float, GL210, GL300) // #328 _extension(GL,EXT,texture_array, GL210, GL300) // #329 @@ -206,10 +205,13 @@ namespace GL { _extension(GL,EXT,separate_shader_objects, GLES200, None) // #101 _extension(GL,EXT,texture_rg, GLES200, GLES300) // #103 _extension(GL,EXT,sRGB, GLES200, None) // #105 - _extension(GL,EXT,robustness, GLES200, None) // #105 + _extension(GL,EXT,multisampled_render_to_texture, GLES200, None) // #106 + _extension(GL,EXT,robustness, GLES200, None) // #107 _extension(GL,EXT,texture_storage, GLES200, GLES300) // #108 _extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121 _extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150 + } namespace KHR { + _extension(GL,KHR,debug, GLES200, None) // #118 } namespace NV { _extension(GL,NV,draw_buffers, GLES200, GLES300) // #91 _extension(GL,NV,read_buffer, GLES200, GLES300) // #93 @@ -238,7 +240,8 @@ namespace GL { _extension(GL,OES,depth_texture, GLES200, GLES300) // #44 _extension(GL,OES,standard_derivatives, GLES200, GLES300) // #45 _extension(GL,OES,vertex_array_object, GLES200, GLES300) // #71 - _extension(GL,OES,required_internalformat, GLES200, GLES300) // #? + _extension(GL,OES,required_internalformat, GLES200, GLES300) // #115 + _extension(GL,OES,surfaceless_context, GLES200, GLES300) // #116 } #endif } diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index ba3c1ddc6..3e320306a 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -172,4 +172,27 @@ void Framebuffer::texture3DImplementationDSA(BufferAttachment attachment, Textur } #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, const Framebuffer::Status value) { + switch(value) { + #define _c(value) case Framebuffer::Status::value: return debug << "Framebuffer::Status::" #value; + _c(Complete) + _c(IncompleteAttachment) + _c(IncompleteMissingAttachment) + #ifndef MAGNUM_TARGET_GLES + _c(IncompleteDrawBuffer) + _c(IncompleteReadBuffer) + #endif + _c(Unsupported) + _c(IncompleteMultisample) + #ifndef MAGNUM_TARGET_GLES + _c(IncompleteLayerTargets) + #endif + #undef _c + } + + return debug << "Framebuffer::Status::(invalid)"; +} +#endif + } diff --git a/src/Framebuffer.h b/src/Framebuffer.h index 7991cc029..6941e3ec0 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -94,7 +94,7 @@ attachTexture2D(), attachCubeMapTexture() and attachTexture3D() use DSA to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective documentation for more information. -@requires_gl30 %Extension @extension{EXT,framebuffer_object} +@requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { friend class Context; @@ -228,6 +228,66 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { GLenum attachment; }; + /** + * @brief Status + * + * @see checkStatus() + */ + enum class Status: GLenum { + /** The framebuffer is complete */ + Complete = GL_FRAMEBUFFER_COMPLETE, + + /** Any of the attachment points are incomplete */ + IncompleteAttachment = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT, + + /** The framebuffer does not have at least one image attached to it */ + IncompleteMissingAttachment = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT, + + #ifndef MAGNUM_TARGET_GLES + /** @todo Why exactly this is not needed? */ + /** + * No object attached to any draw color attachment points + * @requires_gl Not available in OpenGL ES. + */ + IncompleteDrawBuffer = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER, + + /** + * No object attached to read color attachment point + * @requires_gl Not available in OpenGL ES. + */ + IncompleteReadBuffer = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER, + #endif + + /** + * Combination of internal formats of the attached images violates + * an implementation-dependent set of restrictions. + */ + Unsupported = GL_FRAMEBUFFER_UNSUPPORTED, + + /** + * Sample count or locations are not the same for all attached + * images. + * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample}, + * @es_extension{APPLE,framebuffer_multisample}, + * @es_extension{EXT,multisampled_render_to_texture} or + * @es_extension{NV,framebuffer_multisample} + */ + #ifndef MAGNUM_TARGET_GLES2 + IncompleteMultisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE, + #else + IncompleteMultisample = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE, + #endif + + #ifndef MAGNUM_TARGET_GLES + /** @todo Why exactly this is not needed? */ + /** + * Mismatched layered color attachments + * @requires_gl Not available in OpenGL ES. + */ + IncompleteLayerTargets = GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS + #endif + }; + /** * @brief Constructor * @@ -244,6 +304,20 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { */ ~Framebuffer(); + /** + * @brief Check framebuffer status + * @param target Target for which check the status + * + * If @extension{EXT,direct_state_access} is not available and the + * framebuffer is not currently bound, it is bound before the + * operation. + * @see @fn_gl{BindFramebuffer}, @fn_gl{CheckFramebufferStatus} or + * @fn_gl_extension{CheckNamedFramebufferStatus,EXT,direct_state_access} + */ + Status checkStatus(FramebufferTarget target) { + return Status((this->*checkStatusImplementation)(target)); + } + /** * @brief Map shader output to attachments * @return Pointer to self (for method chaining) @@ -468,6 +542,9 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { static Texture3DImplementation texture3DImplementation; }; +/** @debugoperator{DefaultFramebuffer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Framebuffer::Status value); + } #endif diff --git a/src/ImageFormat.cpp b/src/ImageFormat.cpp index 014cf25eb..0d8d1fb88 100644 --- a/src/ImageFormat.cpp +++ b/src/ImageFormat.cpp @@ -37,7 +37,13 @@ Debug operator<<(Debug debug, ImageFormat value) { _c(Green) _c(Blue) #endif + #ifdef MAGNUM_TARGET_GLES2 + _c(Luminance) + #endif _c(RG) + #ifdef MAGNUM_TARGET_GLES2 + _c(LuminanceAlpha) + #endif _c(RGB) _c(RGBA) #ifndef MAGNUM_TARGET_GLES diff --git a/src/ImageFormat.h b/src/ImageFormat.h index 23b2a58f8..2a358eca7 100644 --- a/src/ImageFormat.h +++ b/src/ImageFormat.h @@ -68,8 +68,18 @@ enum class ImageFormat: GLenum { * available in OpenGL ES. */ Blue = GL_BLUE, + #endif - /** @todo GL_ALPHA? */ + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Floating-point luminance channel. The value is used for all RGB + * channels. + * @deprecated Included for compatibility reasons only, use + * @ref Magnum::ImageFormat "ImageFormat::Red" instead. + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::ImageFormat "ImageFormat::Red" instead. + */ + Luminance = GL_LUMINANCE, #endif /** @@ -84,6 +94,18 @@ enum class ImageFormat: GLenum { RG = GL_RG_EXT, #endif + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Floating-point luminance and alpha channel. First value is used for all + * RGB channels, second value is used for alpha channel. + * @deprecated Included for compatibility reasons only, use + * @ref Magnum::ImageFormat "ImageFormat::RG" instead. + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::ImageFormat "ImageFormat::RG" instead. + */ + LuminanceAlpha = GL_LUMINANCE_ALPHA, + #endif + /** * Floating-point RGB. * @requires_gl Can't be used for framebuffer reading in OpenGL ES. @@ -214,7 +236,7 @@ enum class ImageFormat: GLenum { /** * Depth and stencil. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. * @requires_es_extension For framebuffer reading only, extension * @es_extension2{NV,read_depth_stencil,GL_NV_read_depth_stencil}. @@ -424,14 +446,16 @@ enum class ImageType: GLenum { /** * Unsigned int, depth component 24bit, stencil index 8bit. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 For texture data only, extension @es_extension{OES,packed_depth_stencil}. */ - #ifdef MAGNUM_TARGET_GLES2 - UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES - #else + #ifndef MAGNUM_TARGET_GLES2 UnsignedInt248 = GL_UNSIGNED_INT_24_8, + #else + UnsignedInt248 = GL_UNSIGNED_INT_24_8_OES, + #endif + #ifndef MAGNUM_TARGET_GLES2 /** * Float + unsigned int, depth component 32bit float, 24bit gap, stencil * index 8bit. diff --git a/src/Platform/AbstractXApplication.h b/src/Platform/AbstractXApplication.h index ac0710785..ba5bb5680 100644 --- a/src/Platform/AbstractXApplication.h +++ b/src/Platform/AbstractXApplication.h @@ -35,6 +35,7 @@ #include #include /* undef Xlib nonsense to avoid conflicts */ +#undef Complex #undef None #undef Always diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index cd41fb3fd..281a780f6 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -53,7 +53,7 @@ If extension @extension{EXT,direct_state_access} is available, function setStorage() uses DSA to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See its documentation for more information. -@requires_gl30 %Extension @extension{EXT,framebuffer_object} +@requires_gl30 %Extension @extension{ARB,framebuffer_object} */ class MAGNUM_EXPORT Renderbuffer { friend class Context; @@ -109,7 +109,6 @@ class MAGNUM_EXPORT Renderbuffer { * operation. * @see @fn_gl{BindRenderbuffer}, @fn_gl{RenderbufferStorage} or * @fn_gl_extension{NamedRenderbufferStorage,EXT,direct_state_access} - * @requires_gl30 %Extension @extension{EXT,framebuffer_multisample} * @requires_gles30 %Extension @es_extension{ANGLE,framebuffer_multisample} * or @es_extension{NV,framebuffer_multisample} * @todo How about @es_extension{APPLE,framebuffer_multisample}? diff --git a/src/RenderbufferFormat.h b/src/RenderbufferFormat.h index f0d3de92f..fdb935ba1 100644 --- a/src/RenderbufferFormat.h +++ b/src/RenderbufferFormat.h @@ -36,6 +36,7 @@ namespace Magnum { @brief Internal renderbuffer format @see Renderbuffer +@requires_gl30 %Extension @extension{ARB,framebuffer_object} @todo RGB, RGB8 ES only (ES3 + @es_extension{OES,rgb8_rgba8}) */ enum class RenderbufferFormat: GLenum { @@ -481,7 +482,6 @@ enum class RenderbufferFormat: GLenum { /** * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} */ #ifdef MAGNUM_TARGET_GLES2 diff --git a/src/Renderer.cpp b/src/Renderer.cpp index df9b41313..7fb8ed7a5 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -233,4 +233,51 @@ Renderer::GraphicsResetStatus Renderer::graphicsResetStatusImplementationRobustn } #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, const Renderer::Error value) { + switch(value) { + #define _c(value) case Renderer::Error::value: return debug << "Renderer::Error::" #value; + _c(NoError) + _c(InvalidEnum) + _c(InvalidValue) + _c(InvalidOperation) + _c(InvalidFramebufferOperation) + _c(OutOfMemory) + #ifndef MAGNUM_TARGET_GLES3 + _c(StackUnderflow) + _c(StackOverflow) + #endif + #undef _c + } + + return debug << "Renderer::Error::(invalid)"; +} + +#ifndef MAGNUM_TARGET_GLES3 +Debug operator<<(Debug debug, const Renderer::ResetNotificationStrategy value) { + switch(value) { + #define _c(value) case Renderer::ResetNotificationStrategy::value: return debug << "Renderer::ResetNotificationStrategy::" #value; + _c(NoResetNotification) + _c(LoseContextOnReset) + #undef _c + } + + return debug << "Renderer::ResetNotificationStrategy::(invalid)"; +} + +Debug operator<<(Debug debug, const Renderer::GraphicsResetStatus value) { + switch(value) { + #define _c(value) case Renderer::GraphicsResetStatus::value: return debug << "Renderer::GraphicsResetStatus::" #value; + _c(NoError) + _c(GuiltyContextReset) + _c(InnocentContextReset) + _c(UnknownContextReset) + #undef _c + } + + return debug << "Renderer::ResetNotificationStrategy::(invalid)"; +} +#endif +#endif + } diff --git a/src/Renderer.h b/src/Renderer.h index 0ff490450..e66e8311b 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -871,6 +871,69 @@ class MAGNUM_EXPORT Renderer { */ static void finish() { glFinish(); } + /** + * @brief Error status + * + * @see error() + */ + enum class Error: GLenum { + /** No error has been recorded */ + NoError = GL_NO_ERROR, + + /** An unacceptable value specified for enumerated argument */ + InvalidEnum = GL_INVALID_ENUM, + + /** A numeric argument is out of range */ + InvalidValue = GL_INVALID_VALUE, + + /** The specified operation is not allowed in the current state */ + InvalidOperation = GL_INVALID_OPERATION, + + /** + * The framebuffer object is not complete. + * @see AbstractFramebuffer::checkStatus() + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} + */ + InvalidFramebufferOperation = GL_INVALID_FRAMEBUFFER_OPERATION, + + /** There is not enough memory left to execute the command. */ + OutOfMemory = GL_OUT_OF_MEMORY, + + #ifndef MAGNUM_TARGET_GLES3 + /** + * Given operation would cause an internal stack to underflow. + * @requires_gl43 %Extension @extension{KHR,debug} + * @requires_es_extension %Extension @es_extension2{KHR,debug,debug} + */ + #ifndef MAGNUM_TARGET_GLES2 + StackUnderflow = GL_STACK_UNDERFLOW, + #else + StackUnderflow = GL_STACK_UNDERFLOW_KHR, + #endif + + /** + * Given operation would cause an internal stack to overflow. + * @requires_gl43 %Extension @extension{KHR,debug} + * @requires_es_extension %Extension @es_extension2{KHR,debug,debug} + */ + #ifndef MAGNUM_TARGET_GLES2 + StackOverflow = GL_STACK_OVERFLOW + #else + StackOverflow = GL_STACK_OVERFLOW_KHR + #endif + #endif + }; + + /** + * @brief Error status + * + * Returns error flag, if any set. If there aren't any more error + * flags, returns @ref Error "Error::NoError". Thus this function + * should be always called in a loop until it returns @ref Error "Error::NoError". + * @see @fn_gl{GetError} + */ + static Error error() { return static_cast(glGetError()); } + #ifndef MAGNUM_TARGET_GLES3 /** * @brief Graphics reset notification strategy @@ -980,6 +1043,17 @@ class MAGNUM_EXPORT Renderer { #endif }; +/** @debugoperator{Renderer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::Error value); + +#ifndef MAGNUM_TARGET_GLES3 +/** @debugoperator{Renderer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::ResetNotificationStrategy value); + +/** @debugoperator{Renderer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Renderer::GraphicsResetStatus value); +#endif + } #endif diff --git a/src/Shader.cpp b/src/Shader.cpp index 095cd0b0c..7e643db24 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -171,10 +171,9 @@ bool Shader::compile() { /* Error or warning message. The string is returned null-terminated, scrap the \0 at the end afterwards */ std::string message(logLength, '\0'); - if(!message.empty()) { + if(message.size() > 1) glGetShaderInfoLog(_id, message.size(), nullptr, &message[0]); - message.resize(logLength-1); - } + message.resize(std::max(logLength, 1)-1); /* Show error log */ if(!success) { diff --git a/src/Shaders/DistanceFieldVector.cpp b/src/Shaders/DistanceFieldVector.cpp index 3f2f34a27..af86822b8 100644 --- a/src/Shaders/DistanceFieldVector.cpp +++ b/src/Shaders/DistanceFieldVector.cpp @@ -88,8 +88,16 @@ template DistanceFieldVector::DistanceFieldV #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) + #endif + { AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer); + } + + /* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ + #ifdef MAGNUM_TARGET_GLES + setOutlineRange(0.5f, 1.0f); + setSmoothness(0.04f); #endif } diff --git a/src/Shaders/DistanceFieldVector.frag b/src/Shaders/DistanceFieldVector.frag index 1e0ae9f1f..07d9bbe2a 100644 --- a/src/Shaders/DistanceFieldVector.frag +++ b/src/Shaders/DistanceFieldVector.frag @@ -25,18 +25,19 @@ #ifndef NEW_GLSL #define in varying #define fragmentColor gl_FragColor +#define texture texture2D #endif #ifndef GL_ES #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 1) uniform lowp vec4 color; layout(location = 2) uniform lowp vec4 outlineColor; -layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 0.0); +layout(location = 3) uniform lowp vec2 outlineRange = vec2(0.5, 1.0); layout(location = 4) uniform lowp float smoothness = 0.04; #else uniform lowp vec4 color; uniform lowp vec4 outlineColor; -uniform lowp vec2 outlineRange = vec2(0.5, 0.0); +uniform lowp vec2 outlineRange = vec2(0.5, 1.0); uniform lowp float smoothness = 0.04; #endif #else @@ -52,10 +53,10 @@ layout(binding = 16) uniform sampler2D vectorTexture; uniform lowp sampler2D vectorTexture; #endif -in vec2 fragmentTextureCoordinates; +in mediump vec2 fragmentTextureCoordinates; #ifdef NEW_GLSL -out vec4 fragmentColor; +out lowp vec4 fragmentColor; #endif void main() { @@ -65,9 +66,9 @@ void main() { fragmentColor = smoothstep(outlineRange.x-smoothness, outlineRange.x+smoothness, intensity)*color; /* Outline */ - if(outlineRange.x < outlineRange.y) { + if(outlineRange.x > outlineRange.y) { lowp float mid = (outlineRange.x + outlineRange.y)/2.0; - lowp float half = (outlineRange.y - outlineRange.x)/2.0; + lowp float half = (outlineRange.x - outlineRange.y)/2.0; fragmentColor += smoothstep(half+smoothness, half-smoothness, distance(mid, intensity))*outlineColor; } } diff --git a/src/Shaders/DistanceFieldVector.h b/src/Shaders/DistanceFieldVector.h index 06bd4c8dc..ab6455e57 100644 --- a/src/Shaders/DistanceFieldVector.h +++ b/src/Shaders/DistanceFieldVector.h @@ -43,6 +43,9 @@ Renders vector art in form of signed distance field. See TextureTools::distanceF for more information. Note that the final rendered outlook will greatly depend on radius of input distance field and value passed to setSmoothness(). @see DistanceFieldVector2D, DistanceFieldVector3D +@todo Use fragment shader derivations to have proper smoothness in perspective/ + large zoom levels, make it optional as it might have negative performance + impact */ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector: public AbstractVector { public: @@ -81,12 +84,12 @@ template class MAGNUM_SHADERS_EXPORT DistanceFieldVector * @return Pointer to self (for method chaining) * * Parameter @p start describes where fill ends and possible outline - * starts. Initial value is `0.5f`, smaller values will make the vector - * art look thinner, larger will make it look thicker. + * starts. Initial value is `0.5f`, larger values will make the vector + * art look thinner, smaller will make it look thicker. * * Parameter @p end describes where outline ends. If set to value - * smaller than @p start the outline is not drawn. Initial value is - * `0.0f`. + * larger than @p start the outline is not drawn. Initial value is + * `1.0f`. * * @see setOutlineColor() */ diff --git a/src/Shaders/Vector.cpp b/src/Shaders/Vector.cpp index 802283f19..9faf712be 100644 --- a/src/Shaders/Vector.cpp +++ b/src/Shaders/Vector.cpp @@ -85,8 +85,10 @@ template Vector::Vector(): transformationPro #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) - AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer); #endif + { + AbstractShaderProgram::setUniform(AbstractShaderProgram::uniformLocation("vectorTexture"), AbstractVector::VectorTextureLayer); + } } template class Vector<2>; diff --git a/src/Shaders/Vector.frag b/src/Shaders/Vector.frag index 8384499a7..8dd88fd4c 100644 --- a/src/Shaders/Vector.frag +++ b/src/Shaders/Vector.frag @@ -25,6 +25,7 @@ #ifndef NEW_GLSL #define in varying #define fragmentColor gl_FragColor +#define texture texture2D #endif #ifdef EXPLICIT_UNIFORM_LOCATION @@ -39,10 +40,10 @@ layout(binding = 16) uniform sampler2D vectorTexture; uniform lowp sampler2D vectorTexture; #endif -in vec2 fragmentTextureCoordinates; +in mediump vec2 fragmentTextureCoordinates; #ifdef NEW_GLSL -out vec4 fragmentColor; +out lowp vec4 fragmentColor; #endif void main() { diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 78495259d..e9138989f 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -26,7 +26,10 @@ corrade_add_test(AbstractImageTest AbstractImageTest.cpp LIBRARIES Magnum) corrade_add_test(AbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES Magnum) corrade_add_test(ArrayTest ArrayTest.cpp) corrade_add_test(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib) +corrade_add_test(DefaultFramebufferTest DefaultFramebufferTest.cpp LIBRARIES Magnum) +corrade_add_test(FramebufferTest FramebufferTest.cpp LIBRARIES Magnum) corrade_add_test(MeshTest MeshTest.cpp LIBRARIES Magnum) +corrade_add_test(RendererTest RendererTest.cpp LIBRARIES Magnum) corrade_add_test(ResourceManagerTest ResourceManagerTest.cpp LIBRARIES MagnumTestLib) corrade_add_test(SwizzleTest SwizzleTest.cpp LIBRARIES MagnumMathTestLib) diff --git a/src/Test/DefaultFramebufferTest.cpp b/src/Test/DefaultFramebufferTest.cpp new file mode 100644 index 000000000..a0dceffbd --- /dev/null +++ b/src/Test/DefaultFramebufferTest.cpp @@ -0,0 +1,52 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "DefaultFramebuffer.h" + +namespace Magnum { namespace Test { + +class DefaultFramebufferTest: public TestSuite::Tester { + public: + explicit DefaultFramebufferTest(); + + void debugStatus(); +}; + +DefaultFramebufferTest::DefaultFramebufferTest() { + addTests({&DefaultFramebufferTest::debugStatus}); +} + +void DefaultFramebufferTest::debugStatus() { + std::ostringstream out; + + Debug(&out) << DefaultFramebuffer::Status::Undefined; + CORRADE_COMPARE(out.str(), "DefaultFramebuffer::Status::Undefined\n"); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::DefaultFramebufferTest) diff --git a/src/Test/FramebufferTest.cpp b/src/Test/FramebufferTest.cpp new file mode 100644 index 000000000..a3b43be21 --- /dev/null +++ b/src/Test/FramebufferTest.cpp @@ -0,0 +1,52 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Framebuffer.h" + +namespace Magnum { namespace Test { + +class FramebufferTest: public TestSuite::Tester { + public: + explicit FramebufferTest(); + + void debugStatus(); +}; + +FramebufferTest::FramebufferTest() { + addTests({&FramebufferTest::debugStatus}); +} + +void FramebufferTest::debugStatus() { + std::ostringstream out; + + Debug(&out) << Framebuffer::Status::IncompleteMissingAttachment; + CORRADE_COMPARE(out.str(), "Framebuffer::Status::IncompleteMissingAttachment\n"); +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::FramebufferTest) diff --git a/src/Test/RendererTest.cpp b/src/Test/RendererTest.cpp new file mode 100644 index 000000000..07a386634 --- /dev/null +++ b/src/Test/RendererTest.cpp @@ -0,0 +1,72 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Renderer.h" + +namespace Magnum { namespace Test { + +class RendererTest: public TestSuite::Tester { + public: + explicit RendererTest(); + + void debugError(); + #ifndef MAGNUM_TARGET_GLES3 + void debugResetNotificationStrategy(); + void debugGraphicsResetStatus(); + #endif +}; + +RendererTest::RendererTest() { + addTests({&RendererTest::debugError}); +} + +void RendererTest::debugError() { + std::ostringstream out; + + Debug(&out) << Renderer::Error::InvalidOperation; + CORRADE_COMPARE(out.str(), "Renderer::Error::InvalidOperation\n"); +} + +#ifndef MAGNUM_TARGET_GLES3 +void RendererTest::debugResetNotificationStrategy() { + std::ostringstream out; + + Debug(&out) << Renderer::ResetNotificationStrategy::LoseContextOnReset; + CORRADE_COMPARE(out.str(), "Renderer::ResetNotificationStrategy::LoseContextOnReset\n"); +} + +void RendererTest::debugGraphicsResetStatus() { + std::ostringstream out; + + Debug(&out) << Renderer::GraphicsResetStatus::GuiltyContextReset; + CORRADE_COMPARE(out.str(), "Renderer::GraphicsResetStatus::GuiltyContextReset\n"); +} +#endif + +}} + +CORRADE_TEST_MAIN(Magnum::Test::RendererTest) diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp index 73ffcd4b7..83daad155 100644 --- a/src/Text/DistanceFieldGlyphCache.cpp +++ b/src/Text/DistanceFieldGlyphCache.cpp @@ -26,30 +26,54 @@ #include "Extensions.h" #include "Image.h" +#ifndef CORRADE_NO_ASSERT +#include "ImageFormat.h" +#endif #include "TextureFormat.h" #include "TextureTools/DistanceField.h" namespace Magnum { namespace Text { -namespace { +DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius): GlyphCache(originalSize, Vector2i(radius)), scale(Vector2(distanceFieldSize)/originalSize), radius(radius) { + #ifndef MAGNUM_TARGET_GLES + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); + #endif + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) const TextureFormat internalFormat = TextureFormat::R8; #else - const TextureFormat internalFormat = TextureFormat::Red; + const TextureFormat internalFormat = + Context::current()->isExtensionSupported() ? + TextureFormat::Red : TextureFormat::RGB; + if(internalFormat == TextureFormat::RGB) + Warning() << "Text::DistanceFieldGlyphCache:" << Extensions::GL::EXT::texture_rg::string() << "not supported, using inefficient RGB format for glyph cache texture"; #endif + + initialize(internalFormat, distanceFieldSize); } -DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius): GlyphCache(originalSize, Vector2i(radius)), scale(Vector2(distanceFieldSize)/originalSize), radius(radius) { +void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const image) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); - #else - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg); #endif - initialize(internalFormat, distanceFieldSize); -} + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) + const TextureFormat internalFormat = TextureFormat::R8; + CORRADE_ASSERT(image->format() == ImageFormat::Red, + "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Red << "but got" << image->format(), ); + #else + TextureFormat internalFormat; + if(Context::current()->isExtensionSupported()) { + internalFormat = TextureFormat::Red; + CORRADE_ASSERT(image->format() == ImageFormat::Red, + "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Red << "but got" << image->format(), ); + } else { + internalFormat = TextureFormat::Luminance; + CORRADE_ASSERT(image->format() == ImageFormat::Luminance, + "Text::DistanceFieldGlyphCache::setImage(): expected" << ImageFormat::Luminance << "but got" << image->format(), ); + } + #endif -void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const image) { Texture2D input; input.setWrapping(Sampler::Wrapping::ClampToEdge) ->setMinificationFilter(Sampler::Filter::Linear) @@ -57,7 +81,7 @@ void DistanceFieldGlyphCache::setImage(const Vector2i& offset, Image2D* const im ->setImage(0, internalFormat, image); /* Create distance field from input texture */ - TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize(offset*scale, image->size()*scale), radius); + TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize(offset*scale, image->size()*scale), radius, image->size()); } void DistanceFieldGlyphCache::setDistanceFieldImage(const Vector2i& offset, Image2D* const image) { diff --git a/src/Text/DistanceFieldGlyphCache.h b/src/Text/DistanceFieldGlyphCache.h index e9161a95f..bb5d1194c 100644 --- a/src/Text/DistanceFieldGlyphCache.h +++ b/src/Text/DistanceFieldGlyphCache.h @@ -62,7 +62,13 @@ class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache { * @param radius Distance field computation radius * * See TextureTools::distanceField() for more information about the - * parameters. + * parameters. Sets internal texture format to red channel only. On + * desktop OpenGL requires @extension{ARB,texture_rg} (also part of + * OpenGL ES 3.0), in ES2 uses @es_extension{EXT,texture_rg} if + * available or @ref TextureFormat "TextureFormat::RGB" as fallback. + * @todo Is Luminance format renderable anywhere? Also would it be + * possible to convert the RGB texture to Luminance after it has + * been rendered when blitting is not supported to save memory? */ explicit DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius); diff --git a/src/Text/GlyphCache.cpp b/src/Text/GlyphCache.cpp index 1db6a252d..9caf7976f 100644 --- a/src/Text/GlyphCache.cpp +++ b/src/Text/GlyphCache.cpp @@ -31,19 +31,17 @@ namespace Magnum { namespace Text { -namespace { - #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) - const TextureFormat internalFormat = TextureFormat::R8; - #else - const TextureFormat internalFormat = TextureFormat::Red; - #endif -} - GlyphCache::GlyphCache(const Vector2i& size): _size(size) { #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); + #endif + + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES3) + const TextureFormat internalFormat = TextureFormat::R8; #else - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg); + const TextureFormat internalFormat = + Context::current()->isExtensionSupported() ? + TextureFormat::Red : TextureFormat::Luminance; #endif initialize(internalFormat, size); @@ -59,12 +57,6 @@ GlyphCache::~GlyphCache() = default; /** @todo Delegating constructor when support for GCC 4.6 is dropped */ void GlyphCache::initialize(const TextureFormat internalFormat, const Vector2i& size) { - #ifndef MAGNUM_TARGET_GLES - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_storage); - #else - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_storage); - #endif - _texture.setWrapping(Sampler::Wrapping::ClampToEdge) ->setMinificationFilter(Sampler::Filter::Linear) ->setMagnificationFilter(Sampler::Filter::Linear) diff --git a/src/Text/GlyphCache.h b/src/Text/GlyphCache.h index bd6c55d5b..35d93cf52 100644 --- a/src/Text/GlyphCache.h +++ b/src/Text/GlyphCache.h @@ -28,6 +28,7 @@ * @brief Class Magnum::Text::GlyphCache */ +#include #include #include "Math/Geometry/Rectangle.h" @@ -54,6 +55,7 @@ font->createGlyphCache(cache, "abcdefghijklmnopqrstuvwxyz" @endcode See TextRenderer for information about text rendering. +@todo Some way for Font to negotiate or check internal texture format */ class MAGNUM_TEXT_EXPORT GlyphCache { public: @@ -68,9 +70,10 @@ class MAGNUM_TEXT_EXPORT GlyphCache { * @brief Constructor * @param size Glyph cache texture size * - * Sets internal texture format to red channel only. Requires - * @extension{ARB,texture_rg} (also part of OpenGL ES 3.0 or available - * as @es_extension{EXT,texture_rg} in ES 2.0). + * Sets internal texture format to red channel only. On desktop OpenGL + * requires @extension{ARB,texture_rg} (also part of OpenGL ES 3.0), in + * ES2 uses @es_extension{EXT,texture_rg}, if available, or + * @ref TextureFormat "TextureFormat::Luminance" as fallback. */ explicit GlyphCache(const Vector2i& size); diff --git a/src/Texture.h b/src/Texture.h index 139dc7950..9cd269e5f 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -282,14 +282,19 @@ template class Texture: public AbstractTexture { * is immutable and calling setStorage() or setImage() is not allowed. * * If @extension{EXT,direct_state_access} is not available, the - * texture is bound to some layer before the operation. + * texture is bound to some layer before the operation. If + * OpenGL 4.2, @extension{ARB,texture_storage}, OpenGL ES 3.0 or @es_extension{EXT,texture_storage} + * in OpenGL ES 2.0 is not available, the feature is emulated with + * sequence of setImage() calls. * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and * @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} * or @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}/ * @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/ - * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access} - * @requires_gl42 %Extension @extension{ARB,texture_storage} - * @requires_gles30 %Extension @es_extension{EXT,texture_storage} + * @fn_gl_extension{TextureStorage3D,EXT,direct_state_access}, + * eventually @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or + * @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureImage3D,EXT,direct_state_access}. */ Texture* setStorage(Int levels, TextureFormat internalFormat, const typename DimensionTraits::VectorType& size) { DataHelper::setStorage(this, _target, levels, internalFormat, size); diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 7857540f7..86d68f36e 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -147,6 +147,7 @@ enum class TextureFormat: GLenum { * @requires_gles30 Only unsigned formats are available in OpenGL ES 2.0. */ RGBA8Snorm = GL_RGBA8_SNORM, + #endif #ifndef MAGNUM_TARGET_GLES /** @@ -212,6 +213,7 @@ enum class TextureFormat: GLenum { RGBA16Snorm = GL_RGBA16_SNORM, #endif + #ifndef MAGNUM_TARGET_GLES2 /** * Red component, non-normalized unsigned byte. * @requires_gl30 %Extension @extension{ARB,texture_rg} and @extension{EXT,texture_integer} @@ -469,6 +471,29 @@ enum class TextureFormat: GLenum { RGBA32F = GL_RGBA32F, #endif + #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) + /** + * Luminance, normalized unsigned, single value used for all RGB channels. + * Size implementation-dependent. + * @deprecated Included for compatibility reasons only, use + * @ref Magnum::TextureFormat "TextureFormat::R8" instead. + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::TextureFormat "TextureFormat::R8" instead. + */ + Luminance = GL_LUMINANCE, + + /** + * Floating-point luminance and alpha channel. First value is used for all + * RGB channels, second value is used for alpha channel. Size + * implementation-dependent. + * @deprecated Included for compatibility reasons only, use + * @ref Magnum::TextureFormat "TextureFormat::RG8" instead. + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::TextureFormat "TextureFormat::RG8" instead. + */ + LuminanceAlpha = GL_LUMINANCE_ALPHA, + #endif + #ifndef MAGNUM_TARGET_GLES /** * RGB, normalized unsigned, red and green component 3bit, blue 2bit. @@ -490,14 +515,16 @@ enum class TextureFormat: GLenum { RGB5 = GL_RGB5, #endif - /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is - GL_ARB_ES2_compatibility */ - #if defined(GL_RGB565) || defined(DOXYGEN_GENERATING_OUTPUT) /** * RGB, normalized unsigned, red and blue component 5bit, green 6bit. * @requires_gles30 %Extension @es_extension{OES,required_internalformat} */ + /* 1.5.6 <= GLEW < 1.8.0 doesn't have this, even if there is + GL_ARB_ES2_compatibility */ + #ifdef GL_RGB565 RGB565 = GL_RGB565, + #else + RGB565 = 0x8D62, #endif #ifndef MAGNUM_TARGET_GLES3 @@ -519,7 +546,53 @@ enum class TextureFormat: GLenum { * @requires_gl Packed 36bit types are not available in OpenGL ES. */ RGB12 = GL_RGB12, + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * RGB, float, red and green component 11bit, blue 10bit. + * @requires_gl30 %Extension @extension{EXT,packed_float} + * @requires_gles30 Only normalized integral formats are available in + * OpenGL ES 2.0. + */ + R11FG11FB10F = GL_R11F_G11F_B10F, + + /** + * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit. + * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RGB" in + * OpenGL ES 2.0 instead. + */ + RGB9E5 = GL_RGB9_E5, + #endif + + #ifndef MAGNUM_TARGET_GLES3 + /** + * sRGB, normalized unsigned, size implementation-dependent. + * @todo is this allowed in core? + * @deprecated Prefer to use the exactly specified version of this format, + * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8". + * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES + * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8" in + * OpenGL ES 3.0 instead. + */ + #ifndef MAGNUM_TARGET_GLES + SRGB = GL_SRGB, + #else + SRGB = GL_SRGB_EXT, + #endif + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * sRGB, each component normalized unsigned byte. + * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGB" in + * OpenGL ES 2.0 instead. + */ + SRGB8 = GL_SRGB8, + #endif + #ifndef MAGNUM_TARGET_GLES /** * RGBA, normalized unsigned, each component 2bit. * @requires_gl Packed 8bit types are not available in OpenGL ES. @@ -568,52 +641,6 @@ enum class TextureFormat: GLenum { RGBA12 = GL_RGBA12, #endif - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGB, float, red and green component 11bit, blue 10bit. - * @requires_gl30 %Extension @extension{EXT,packed_float} - * @requires_gles30 Only normalized integral formats are available in - * OpenGL ES 2.0. - */ - R11FG11FB10F = GL_R11F_G11F_B10F, - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * RGB, unsigned with exponent, each RGB component 9bit, exponent 5bit. - * @requires_gl30 %Extension @extension{EXT,texture_shared_exponent} - * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::RGB" in - * OpenGL ES 2.0 instead. - */ - RGB9E5 = GL_RGB9_E5, - #endif - - #ifndef MAGNUM_TARGET_GLES3 - /** - * sRGB, normalized unsigned, size implementation-dependent. - * @todo is this allowed in core? - * @deprecated Prefer to use the exactly specified version of this format, - * i.e. @ref Magnum::TextureFormat "TextureFormat::SRGB8". - * @requires_es_extension %Extension @es_extension{EXT,sRGB} in OpenGL ES - * 2.0, use @ref Magnum::TextureFormat "TextureFormat::SRGB8" in - * OpenGL ES 3.0 instead. - */ - #ifndef MAGNUM_TARGET_GLES - SRGB = GL_SRGB, - #else - SRGB = GL_SRGB_EXT, - #endif - #endif - - #ifndef MAGNUM_TARGET_GLES2 - /** - * sRGB, each component normalized unsigned byte. - * @requires_gles30 Use @ref Magnum::TextureFormat "TextureFormat::SRGB" in - * OpenGL ES 2.0 instead. - */ - SRGB8 = GL_SRGB8, - #endif - #ifndef MAGNUM_TARGET_GLES3 /** * sRGBA, normalized unsigned, size implementation-dependent. @@ -700,32 +727,32 @@ enum class TextureFormat: GLenum { late as of 1.8.0 { */ /** - * BPTC compressed RGBA, normalized unsigned. + * BPTC compressed RGB, unsigned float. * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} * @requires_gl BPTC texture compression is not available in OpenGL ES. */ - CompressedRGBABtpcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, + CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, /** - * BPTC compressed sRGBA, normalized unsigned. + * BPTC compressed RGB, signed float. * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} * @requires_gl BPTC texture compression is not available in OpenGL ES. */ - CompressedSRGBAlphaBtpcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, + CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, /** - * BPTC compressed RGB, unsigned float. + * BPTC compressed RGBA, normalized unsigned. * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} * @requires_gl BPTC texture compression is not available in OpenGL ES. */ - CompressedRGBBptcUnsignedFloat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, + CompressedRGBABptcUnorm = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, /** - * BPTC compressed RGB, signed float. + * BPTC compressed sRGBA, normalized unsigned. * @requires_gl42 %Extension @extension{ARB,texture_compression_bptc} * @requires_gl BPTC texture compression is not available in OpenGL ES. */ - CompressedRGBBptcSignedFloat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, + CompressedSRGBAlphaBptcUnorm = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, /*}*/ #endif @@ -739,18 +766,6 @@ enum class TextureFormat: GLenum { */ DepthComponent = GL_DEPTH_COMPONENT, - /** - * Depth and stencil component, size implementation-dependent. - * @deprecated Prefer to use exactly specified version of this format, e.g. - * @ref Magnum::TextureFormat "TextureFormat::Depth24Stencil8". - * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} - */ - #ifndef MAGNUM_TARGET_GLES2 - DepthStencil = GL_DEPTH_STENCIL, - #else - DepthStencil = GL_DEPTH_STENCIL_OES, - #endif - /** * Depth component, 16bit. * @requires_gles30 %Extension (@es_extension{OES,required_internalformat} @@ -794,9 +809,21 @@ enum class TextureFormat: GLenum { DepthComponent32F = GL_DEPTH_COMPONENT32F, #endif + /** + * Depth and stencil component, size implementation-dependent. + * @deprecated Prefer to use exactly specified version of this format, e.g. + * @ref Magnum::TextureFormat "TextureFormat::Depth24Stencil8". + * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} + */ + #ifndef MAGNUM_TARGET_GLES2 + DepthStencil = GL_DEPTH_STENCIL, + #else + DepthStencil = GL_DEPTH_STENCIL_OES, + #endif + /** * 24bit depth and 8bit stencil component. - * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} * @requires_gles30 %Extension @es_extension{OES,packed_depth_stencil} and * (@es_extension{OES,required_internalformat} or * (@es_extension{EXT,texture_storage} and @es_extension{ANGLE,depth_texture})) diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp index fbc1eeee6..521c86beb 100644 --- a/src/TextureTools/DistanceField.cpp +++ b/src/TextureTools/DistanceField.cpp @@ -39,6 +39,8 @@ namespace { class DistanceFieldShader: public AbstractShaderProgram { public: + typedef Attribute<0, Vector2> Position; + enum: Int { TextureLayer = 8 }; @@ -50,62 +52,148 @@ class DistanceFieldShader: public AbstractShaderProgram { return this; } - DistanceFieldShader* setScaling(Vector2 scaling) { + DistanceFieldShader* setScaling(const Vector2& scaling) { setUniform(scalingUniform, scaling); return this; } + DistanceFieldShader* setImageSizeInverted(const Vector2& size) { + setUniform(imageSizeInvertedUniform, size); + return this; + } + private: - static const Int radiusUniform = 0, - scalingUniform = 1; + Int radiusUniform, + scalingUniform, + imageSizeInvertedUniform; }; -DistanceFieldShader::DistanceFieldShader() { - MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL330); - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_attrib_location); - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::explicit_uniform_location); - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::shading_language_420pack); - - /** @todo compatibility! */ - +DistanceFieldShader::DistanceFieldShader(): radiusUniform(0), scalingUniform(1) { Utility::Resource rs("MagnumTextureTools"); - Shader vert(Version::GL330, Shader::Type::Vertex); - vert.addSource(rs.get("DistanceFieldShader.vert")); + #ifndef MAGNUM_TARGET_GLES + const Version v = Context::current()->supportedVersion({Version::GL320, Version::GL300, Version::GL210}); + #else + const Version v = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); + #endif + + Shader vert(v, Shader::Type::Vertex); + vert.addSource(rs.get("compatibility.glsl")) + .addSource(rs.get("DistanceFieldShader.vert")); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); attachShader(vert); - Shader frag(Version::GL330, Shader::Type::Fragment); + Shader frag(v, Shader::Type::Fragment); frag.addSource(rs.get("compatibility.glsl")) .addSource(rs.get("DistanceFieldShader.frag")); CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); attachShader(frag); + /* Older GLSL doesn't have gl_VertexID, vertices must be supplied explicitly */ + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isVersionSupported(Version::GL300)) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + bindAttributeLocation(Position::Location, "position"); + } + CORRADE_INTERNAL_ASSERT_OUTPUT(link()); -} + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + #endif + { + radiusUniform = uniformLocation("radius"); + scalingUniform = uniformLocation("scaling"); + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isVersionSupported(Version::GL300)) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + imageSizeInvertedUniform = uniformLocation("imageSizeInverted"); + } + } + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + #endif + { + setUniform(uniformLocation("textureData"), TextureLayer); + } } -void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius) { - MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::framebuffer_object); +} +#ifndef MAGNUM_TARGET_GLES +void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius, const Vector2i&) +#else +void distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, const Int radius, const Vector2i& imageSize) +#endif +{ + #ifndef MAGNUM_TARGET_GLES + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::framebuffer_object); + #endif /** @todo Disable depth test, blending and then enable it back (if was previously) */ + #ifndef MAGNUM_TARGET_GLES + Vector2i imageSize = input->imageSize(0); + #endif + Framebuffer framebuffer(rectangle); framebuffer.attachTexture2D(Framebuffer::ColorAttachment(0), output, 0); framebuffer.bind(FramebufferTarget::Draw); + framebuffer.clear(FramebufferClear::Color); + + const Framebuffer::Status status = framebuffer.checkStatus(FramebufferTarget::Draw); + if(status != Framebuffer::Status::Complete) { + Error() << "TextureTools::distanceField(): cannot render to given output texture, unexpected framebuffer status" + << status; + return; + } DistanceFieldShader shader; shader.setRadius(radius) - ->setScaling(Vector2(input->imageSize(0))/rectangle.size()) + ->setScaling(Vector2(imageSize)/rectangle.size()) ->use(); input->bind(DistanceFieldShader::TextureLayer); + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isVersionSupported(Version::GL300)) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + shader.setImageSizeInverted(Vector2(1)/imageSize); + } + Mesh mesh; mesh.setPrimitive(Mesh::Primitive::Triangles) - ->setVertexCount(3) - ->draw(); + ->setVertexCount(3); + + /* Older GLSL doesn't have gl_VertexID, vertices must be supplied explicitly */ + Buffer buffer; + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isVersionSupported(Version::GL300)) + #else + if(!Context::current()->isVersionSupported(Version::GLES300)) + #endif + { + constexpr Vector2 triangle[] = { + Vector2(-1.0, 1.0), + Vector2(-1.0, -3.0), + Vector2( 3.0, 1.0) + }; + buffer.setData(triangle, Buffer::Usage::StaticDraw); + mesh.addVertexBuffer(&buffer, 0, DistanceFieldShader::Position()); + } + + /* Draw the mesh */ + mesh.draw(); } }} diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h index dfe8c409d..e44e6ba8d 100644 --- a/src/TextureTools/DistanceField.h +++ b/src/TextureTools/DistanceField.h @@ -28,6 +28,9 @@ * @brief Function Magnum::TextureTools::distanceField() */ +#ifndef MAGNUM_TARGET_GLES +#include "Math/Vector2.h" +#endif #include "Magnum.h" #include "TextureTools/magnumTextureToolsVisibility.h" @@ -40,6 +43,8 @@ namespace Magnum { namespace TextureTools { @param output Output texture @param rectangle Rectangle in output texture where to render @param radius Max lookup radius in input texture +@param imageSize Input texture size. Needed only in OpenGL ES, in desktop + OpenGL the information is gathered automatically using Texture::imageSize(). Converts binary image (stored in red channel of @p input) to signed distance field (stored in red channel in @p rectangle of @p output). The purpose of this @@ -51,9 +56,9 @@ foundation for features like outlining, glow or drop shadow essentialy for free. For each pixel inside @p rectangle the algorithm looks at corresponding pixel in @p input and tries to find nearest pixel of opposite color in area given by @p radius. Signed distance between the points is then saved as value of given -pixel in @p output. Value of `0` means that the pixel was originally colored -white and nearest black pixel is farther than @p radius, value of `1` means that -the pixel was originally black and nearest white pixel is farther than +pixel in @p output. Value of `1.0` means that the pixel was originally colored +white and nearest black pixel is farther than @p radius, value of `0.0` means +that the pixel was originally black and nearest white pixel is farther than @p radius. Values around `0.5` are around edges. The resulting texture can be used with bilinear filtering. It can be converted @@ -66,8 +71,24 @@ and Special Effects, SIGGRAPH 2007, http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf* @attention This is GPU-only implementation, so it expects active context. + +@note If internal format of @p output texture is not renderable, this function + prints message to error output and does nothing. In desktop OpenGL and + OpenGL ES 3.0 it's common to render to @ref TextureFormat "TextureFormat::R8". + In OpenGL ES 2.0 you can use @ref TextureFormat "TextureFormat::Red" if + @es_extension{EXT,texture_rg} is available, if not, the smallest but still + inefficient supported format is in most cases @ref TextureFormat "TextureFormat::RGB", + rendering to @ref TextureFormat "TextureFormat::Luminance" is not supported + in most cases. + +@bug ES (and maybe GL < 3.20) implementation behaves slightly different + (jaggies, visible e.g. when rendering outlined fonts) */ -void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius); +#ifndef MAGNUM_TARGET_GLES +void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius, const Vector2i& imageSize = Vector2i()); +#else +void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius, const Vector2i& imageSize); +#endif }} diff --git a/src/TextureTools/DistanceFieldShader.frag b/src/TextureTools/DistanceFieldShader.frag index 9191f9525..c19273b79 100644 --- a/src/TextureTools/DistanceFieldShader.frag +++ b/src/TextureTools/DistanceFieldShader.frag @@ -22,40 +22,90 @@ DEALINGS IN THE SOFTWARE. */ +#ifndef NEW_GLSL +#define in varying +#define value gl_FragColor.x +#define const +#define texture texture2D +#endif + +#if (defined(GL_ES) && __VERSION__ >= 300) || (!defined(GL_ES) && __VERSION__ >= 150) +#define TEXELFETCH_USABLE +#endif + +#ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 0) uniform int radius; layout(location = 1) uniform vec2 scaling; -layout(binding = 8) uniform sampler2D texture; - -layout(pixel_center_integer) in vec4 gl_FragCoord; - -out float value; +layout(binding = 8) uniform sampler2D textureData; +#else +uniform lowp int radius; +uniform mediump vec2 scaling; +uniform lowp sampler2D textureData; +#endif + +#ifdef TEXELFETCH_USABLE +layout(pixel_center_integer) in mediump vec4 gl_FragCoord; +#else +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 2) uniform vec2 imageSizeInverted; +#else +uniform mediump vec2 imageSizeInverted; +#endif +#endif + +#ifdef NEW_GLSL +out lowp float value; +#endif + +#ifdef TEXELFETCH_USABLE +mediump ivec2 rotate(const mediump ivec2 vec) { + return mediump ivec2(-vec.y, vec.x); +} -ivec2 rotate(const ivec2 vec) { - return ivec2(-vec.y, vec.x); +bool hasValue(const mediump ivec2 position, const mediump ivec2 offset) { + return texelFetch(textureData, position+offset, 0).r > 0.5; +} +#else +mediump vec2 rotate(const mediump vec2 vec) { + return mediump vec2(-vec.y, vec.x); } -bool hasValue(const ivec2 position, const ivec2 offset) { - return texelFetch(texture, position+offset, 0).r > 0.5; +bool hasValue(const mediump vec2 position, const mediump vec2 offset) { + return texture(textureData, position+offset).r > 0.5; } +#endif void main() { - const ivec2 position = ivec2(gl_FragCoord.xy*scaling); + #ifdef TEXELFETCH_USABLE + const mediump ivec2 position = ivec2(gl_FragCoord.xy*scaling); + #else + const mediump vec2 position = gl_FragCoord.xy*scaling*imageSizeInverted; + #endif /* If pixel at the position is inside (1), we are looking for nearest pixel outside and the value will be positive (> 0.5). If it is outside (0), we are looking for nearest pixel inside and the value will be negative (< 0.5). */ + #ifdef TEXELFETCH_USABLE const bool isInside = hasValue(position, ivec2(0, 0)); - const float sign = isInside ? 1.0 : -1.0; + #else + const bool isInside = hasValue(position, vec2(0.0, 0.0)); + #endif + const highp float sign = isInside ? 1.0 : -1.0; /* Minimal found distance is just out of the radius (i.e. infinity) */ - float minDistanceSquared = float((radius+1)*(radius+1)); + highp float minDistanceSquared = float((radius+1)*(radius+1)); /* Go in circles around the point and find nearest value */ int radiusLimit = radius; for(int i = 1; i <= radiusLimit; ++i) { for(int j = 0, jmax = i*2; j != jmax; ++j) { - const ivec2 offset = {-i+j, i}; + #ifdef TEXELFETCH_USABLE + const lowp ivec2 offset = ivec2(-i+j, i); + #else + const lowp vec2 pixelOffset = vec2(float(-i+j), float(i)); + const lowp vec2 offset = pixelOffset*imageSizeInverted; + #endif /* If any of the four values is opposite of what is on the pixel, we found nearest value */ @@ -63,7 +113,11 @@ void main() { hasValue(position, rotate(offset)) == !isInside || hasValue(position, rotate(rotate(offset))) == !isInside || hasValue(position, rotate(rotate(rotate(offset)))) == !isInside) { - const float distanceSquared = dot(vec2(offset), vec2(offset)); + #ifdef TEXELFETCH_USABLE + const mediump float distanceSquared = dot(vec2(offset), vec2(offset)); + #else + const mediump float distanceSquared = dot(pixelOffset, pixelOffset); + #endif /* Set smaller distance, if found, or continue with lookup for smaller */ @@ -73,7 +127,11 @@ void main() { /* Set radius limit to max radius which can contain smaller value, e.g. for distance 3.5 we can find smaller value even in radius 3 */ + #ifdef NEW_GLSL radiusLimit = min(radius, int(floor(length(vec2(offset))))); + #else + radiusLimit = int(min(float(radius), floor(length(vec2(offset))))); + #endif } } } diff --git a/src/TextureTools/DistanceFieldShader.vert b/src/TextureTools/DistanceFieldShader.vert index a412a0a20..c7970fe47 100644 --- a/src/TextureTools/DistanceFieldShader.vert +++ b/src/TextureTools/DistanceFieldShader.vert @@ -22,7 +22,15 @@ DEALINGS IN THE SOFTWARE. */ +#ifndef NEW_GLSL +attribute lowp vec4 position; +#endif + void main() { + #ifdef NEW_GLSL gl_Position = vec4((gl_VertexID == 2) ? 3.0 : -1.0, (gl_VertexID == 1) ? -3.0 : 1.0, 0.0, 1.0); + #else + gl_Position = position; + #endif }