From 8453d01ffee0d6ab5d9ebff856f0e9a798d5b7b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 14:34:52 +0200 Subject: [PATCH 01/27] Added section for ES2-compatibility-only features into documentation. --- Doxyfile | 1 + doc/required-extensions.dox | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) 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/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" From f0db90c8efbd07140380fe0239973d32232875c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 14:35:51 +0200 Subject: [PATCH 02/27] Added ES2-only support for GL_LUMINANCE{,_ALPHA}. It is deprecated, but many ES2 implementations don't support EXT_texture_rg, thus this is the only way to have single- and two-component textures without wasting precious memory. The enum value isn't exposed on desktop OpenGL and ES3. GL_ALPHA is not supported, as it doesn't bring any new functionality (it is also single-component and thus can be interchanged with GL_LUMINANCE). --- doc/unsupported.dox | 2 -- src/AbstractImage.cpp | 6 ++++++ src/ImageFormat.cpp | 6 ++++++ src/ImageFormat.h | 24 +++++++++++++++++++++++- src/TextureFormat.h | 25 +++++++++++++++++++++++++ 5 files changed, 60 insertions(+), 3 deletions(-) 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/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/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..9420da939 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. diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 7857540f7..f27d2e864 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -475,7 +475,32 @@ enum class TextureFormat: GLenum { * @requires_gl Packed 8bit types are not available in OpenGL ES. */ R3B3G2 = GL_R3_G3_B2, + #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::RG" instead. + * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use + * @ref Magnum::TextureFormat "TextureFormat::RG" instead. + */ + LuminanceAlpha = GL_LUMINANCE_ALPHA, + #endif + #ifndef MAGNUM_TARGET_GLES /** * RGB, each component normalized unsigned 4bit. * @requires_gl Packed 12bit types are not available in OpenGL ES. From f0e9871f108d2744a2d8075c716a370154b3b852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 15:08:40 +0200 Subject: [PATCH 03/27] Platform: #undef another mess from Xorg headers. --- src/Platform/AbstractXApplication.h | 1 + 1 file changed, 1 insertion(+) 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 From fcc143b14edd1f204d515ecf9f9d53acfba01075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 15:09:30 +0200 Subject: [PATCH 04/27] Missing #include. --- src/Text/GlyphCache.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Text/GlyphCache.h b/src/Text/GlyphCache.h index bd6c55d5b..b87504f7a 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" From c38407c0bbd4075ccc0121e5e3522824bca04774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 15:10:49 +0200 Subject: [PATCH 05/27] Abort instead of exit from MAGNUM_ASSERT_*_SUPPORTED() macros. --- src/Context.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Context.h b/src/Context.h index 644b84ac8..d768897fc 100644 --- a/src/Context.h +++ b/src/Context.h @@ -378,8 +378,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 @@ -395,7 +395,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 @@ -408,8 +408,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 @@ -425,7 +425,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 From 153e5c784a0eb9fe50d10d414c404b2c6990ea6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Jun 2013 16:45:14 +0200 Subject: [PATCH 06/27] Sanity check for OpenGL version in Context. I though this check was present since forever, but isn't. Maybe it's hidden somewhere else. --- src/Context.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Context.cpp b/src/Context.cpp index d4d88cce8..49d5948c7 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -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 /** From 6ff652cbbdf70f8a1a40220ac16dcb621f992503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:04:29 +0200 Subject: [PATCH 07/27] Minor cleanup in image and texture format enums. Removed hierarchic and confusing `#ifdef`s. --- src/ImageFormat.h | 8 +++++--- src/TextureFormat.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ImageFormat.h b/src/ImageFormat.h index 9420da939..9219dcc0a 100644 --- a/src/ImageFormat.h +++ b/src/ImageFormat.h @@ -449,11 +449,13 @@ enum class ImageType: GLenum { * @requires_gl30 %Extension @extension{EXT,packed_depth_stencil} * @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/TextureFormat.h b/src/TextureFormat.h index f27d2e864..69a7c6339 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} From adaf8442e7a49095aa8d9f0b0b83fe65391cdb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:05:43 +0200 Subject: [PATCH 08/27] Fixed typo in TextureFormat::*Bptc* enum values. --- src/TextureFormat.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 69a7c6339..9642b3397 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -727,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 From 6346e128e17e96611dec988270e6f85345d7e612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:06:20 +0200 Subject: [PATCH 09/27] Always define TextureFormat::RGB565. Don't care if its defined or not, makes it very hard to use that value. --- src/TextureFormat.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 9642b3397..f80a29819 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -517,14 +517,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 From 73db7f8d38ea49e30f7157d3fba6e2bac05f95e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:10:29 +0200 Subject: [PATCH 10/27] Proper reference in TextureFormat enum value documentation. --- src/TextureFormat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TextureFormat.h b/src/TextureFormat.h index f80a29819..819817507 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -495,9 +495,9 @@ enum class TextureFormat: GLenum { * RGB channels, second value is used for alpha channel. Size * implementation-dependent. * @deprecated Included for compatibility reasons only, use - * @ref Magnum::TextureFormat "TextureFormat::RG" instead. + * @ref Magnum::TextureFormat "TextureFormat::RG8" instead. * @requires_gles20 Not available in ES 3.0 or desktop OpenGL. Use - * @ref Magnum::TextureFormat "TextureFormat::RG" instead. + * @ref Magnum::TextureFormat "TextureFormat::RG8" instead. */ LuminanceAlpha = GL_LUMINANCE_ALPHA, #endif From 6d6d6248ab08491bb96e3e7b9f8a4e7c8cd4b1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:11:16 +0200 Subject: [PATCH 11/27] Reorganize TextureFormat enum a bit. Special RGB values together, RGBA values together, Depth values together, DepthStencil values together. Left sized internal formats in the same order, though. --- src/TextureFormat.h | 130 ++++++++++++++++++++++---------------------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 819817507..2344cd7d7 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -471,14 +471,6 @@ enum class TextureFormat: GLenum { RGBA32F = GL_RGBA32F, #endif - #ifndef MAGNUM_TARGET_GLES - /** - * RGB, normalized unsigned, red and green component 3bit, blue 2bit. - * @requires_gl Packed 8bit types are not available in OpenGL ES. - */ - R3B3G2 = GL_R3_G3_B2, - #endif - #if defined(MAGNUM_TARGET_GLES2) || defined(DOXYGEN_GENERATING_OUTPUT) /** * Luminance, normalized unsigned, single value used for all RGB channels. @@ -503,6 +495,12 @@ enum class TextureFormat: GLenum { #endif #ifndef MAGNUM_TARGET_GLES + /** + * RGB, normalized unsigned, red and green component 3bit, blue 2bit. + * @requires_gl Packed 8bit types are not available in OpenGL ES. + */ + R3B3G2 = GL_R3_G3_B2, + /** * RGB, each component normalized unsigned 4bit. * @requires_gl Packed 12bit types are not available in OpenGL ES. @@ -548,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. @@ -597,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. @@ -768,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} @@ -823,6 +809,18 @@ 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} From e7fd8740bb1343c84879e0299c3adeec1eed0a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 8 Jun 2013 13:12:37 +0200 Subject: [PATCH 12/27] Fallback for texture storage feature. It's now possible to call *Texture::setStorage() even if OpenGL 4.2, ARB_texture_storage, OpenGL ES 3.0 or EXT_texture_storage in ES 2.0 is not available, the function will internally use sequence of setImage() calls as fallback. It seems to me that this behavior is better than forcing the user to always check for extension presence and then implementing this functionality again and again. The huge switches for setting proper image format and type are ugly though, but according to specs they must be set even if we are sending no data (which is weird). --- src/AbstractTexture.cpp | 497 +++++++++++++++++++++++++++++++++++++++- src/AbstractTexture.h | 12 + src/Texture.h | 13 +- 3 files changed, 510 insertions(+), 12 deletions(-) diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index ac34bac65..e085764ae 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; @@ -204,9 +206,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; @@ -229,9 +228,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); @@ -277,7 +663,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 @@ -291,11 +690,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 */ @@ -316,6 +760,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 fc2358124..b447d1f6f 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -72,6 +72,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 @@ -314,12 +321,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); @@ -327,6 +336,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); @@ -399,6 +409,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/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); From 252f489eaae3233e6dc241d3df86e0558e90966f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 00:51:07 +0200 Subject: [PATCH 13/27] Don't query shader info log if it contains only '\0' character. --- src/AbstractShaderProgram.cpp | 10 ++++------ src/Shader.cpp | 5 ++--- 2 files changed, 6 insertions(+), 9 deletions(-) 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/Shader.cpp b/src/Shader.cpp index f13b1d383..d71cea9bd 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -168,10 +168,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) { From 261250f0748f9f33ebc2b48c518fe99811c9d2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 00:53:22 +0200 Subject: [PATCH 14/27] Shaders: fix port of *Vector shaders to old GLSL. Texture layer binding was never set and there were various GLSL compilation errors. --- src/Shaders/DistanceFieldVector.cpp | 8 ++++++++ src/Shaders/DistanceFieldVector.frag | 5 +++-- src/Shaders/Vector.cpp | 4 +++- src/Shaders/Vector.frag | 5 +++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Shaders/DistanceFieldVector.cpp b/src/Shaders/DistanceFieldVector.cpp index da1e903da..506505f77 100644 --- a/src/Shaders/DistanceFieldVector.cpp +++ b/src/Shaders/DistanceFieldVector.cpp @@ -85,8 +85,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..1f525eca7 100644 --- a/src/Shaders/DistanceFieldVector.frag +++ b/src/Shaders/DistanceFieldVector.frag @@ -25,6 +25,7 @@ #ifndef NEW_GLSL #define in varying #define fragmentColor gl_FragColor +#define texture texture2D #endif #ifndef GL_ES @@ -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() { diff --git a/src/Shaders/Vector.cpp b/src/Shaders/Vector.cpp index c6cd27079..86181baa0 100644 --- a/src/Shaders/Vector.cpp +++ b/src/Shaders/Vector.cpp @@ -82,8 +82,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() { From eaa486a6e92e9cdbc127189f05bedb4b3db18edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 15:50:52 +0200 Subject: [PATCH 15/27] Added KHR_debug to ES2 extension list. --- src/Context.cpp | 1 + src/Extensions.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Context.cpp b/src/Context.cpp index 49d5948c7..327b6ea22 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -214,6 +214,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,separate_shader_objects), _extension(GL,EXT,sRGB), _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 diff --git a/src/Extensions.h b/src/Extensions.h index ea74900da..a7980afc0 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -210,6 +210,8 @@ namespace GL { _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 From 8ef1a9a0caaf6a644a9a20bde61c9c2b943744ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 15:51:52 +0200 Subject: [PATCH 16/27] Added Renderer::error(). --- src/Renderer.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/Renderer.h b/src/Renderer.h index 0ff490450..407c2e323 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{EXT,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 From 4380e95a67842c9f7fd0df9792831e7455d93be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 15:53:25 +0200 Subject: [PATCH 17/27] Added debug output for Renderer error and reset status queries. --- src/Renderer.cpp | 47 +++++++++++++++++++++++++ src/Renderer.h | 11 ++++++ src/Test/CMakeLists.txt | 1 + src/Test/RendererTest.cpp | 72 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 src/Test/RendererTest.cpp 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 407c2e323..0053c78a3 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -1043,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/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 78495259d..7e87a603e 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -27,6 +27,7 @@ corrade_add_test(AbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARI corrade_add_test(ArrayTest ArrayTest.cpp) corrade_add_test(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib) 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/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) From b5a6036d48ba96f9c0fc895ea34bfbcf88b89405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 17:50:20 +0200 Subject: [PATCH 18/27] Use proper ARB_framebuffer_object extension. Separated EXT_framebuffer_object, EXT_framebuffer_blit, EXT_framebuffer_multisample and EXT_packed_depth_stencil don't have the same functionality as ARB_framebuffer_object (e.g. missing GL_FRAMEBUFFER_UNDEFINED in glCheckFramebufferStatus()) and separated read/draw binding is only in EXT_framebuffer_blit, which complicates the internals. Checked with Mesa 8/9 and OpenGL 2.1, current one has ARB_framebuffer_object and also all these four, Mesa 7.7 didn't have EXT_framebuffer_multisample, but that's a long time ago, so not supporting these separate extensions shouldn't be an issue. The problem with unavailable separate binding points remains on OpenGL ES 2.0, there are three different extensions bringing that functionality, thus the code managing the available binding points remains there. --- src/AbstractFramebuffer.cpp | 66 +++++++++++++++++++++++++++++----- src/AbstractFramebuffer.h | 71 +++++++++++++++++++------------------ src/AbstractTexture.h | 2 +- src/Context.cpp | 9 +---- src/Extensions.h | 7 ++-- src/Framebuffer.h | 2 +- src/ImageFormat.h | 4 +-- src/Renderbuffer.h | 3 +- src/RenderbufferFormat.h | 2 +- src/Renderer.h | 2 +- src/TextureFormat.h | 2 +- 11 files changed, 106 insertions(+), 64 deletions(-) diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index bc9b20eb5..73de50537 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -40,8 +40,10 @@ AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersI 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; +#endif AbstractFramebuffer::~AbstractFramebuffer() {} @@ -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,13 +196,6 @@ 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"; @@ -193,6 +205,32 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) } #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()) @@ -219,7 +257,11 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) 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 +278,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 +302,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 3e7916dda..cfa47d6be 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -36,10 +36,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 */ @@ -47,21 +47,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 */ @@ -69,36 +69,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} */ @@ -110,7 +112,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} */ @@ -163,7 +164,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} */ @@ -182,7 +182,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} */ @@ -272,8 +271,10 @@ class MAGNUM_EXPORT AbstractFramebuffer { FramebufferTarget MAGNUM_LOCAL bindInternal(); void MAGNUM_LOCAL setViewportInternal(); + #ifdef MAGNUM_TARGET_GLES2 static MAGNUM_LOCAL FramebufferTarget readTarget; static MAGNUM_LOCAL FramebufferTarget drawTarget; + #endif typedef void(AbstractFramebuffer::*DrawBuffersImplementation)(GLsizei, const GLenum*); static MAGNUM_LOCAL DrawBuffersImplementation drawBuffersImplementation; diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index b447d1f6f..87179e638 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -253,7 +253,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(); diff --git a/src/Context.cpp b/src/Context.cpp index 327b6ea22..2c1596aa3 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), diff --git a/src/Extensions.h b/src/Extensions.h index a7980afc0..309c7b080 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 diff --git a/src/Framebuffer.h b/src/Framebuffer.h index e839d7488..975f96b14 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; diff --git a/src/ImageFormat.h b/src/ImageFormat.h index 9219dcc0a..2a358eca7 100644 --- a/src/ImageFormat.h +++ b/src/ImageFormat.h @@ -236,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}. @@ -446,7 +446,7 @@ 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}. */ #ifndef MAGNUM_TARGET_GLES2 diff --git a/src/Renderbuffer.h b/src/Renderbuffer.h index f35ac0bac..b4b425386 100644 --- a/src/Renderbuffer.h +++ b/src/Renderbuffer.h @@ -49,7 +49,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; @@ -105,7 +105,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.h b/src/Renderer.h index 0053c78a3..e66e8311b 100644 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -892,7 +892,7 @@ class MAGNUM_EXPORT Renderer { /** * The framebuffer object is not complete. * @see AbstractFramebuffer::checkStatus() - * @requires_gl30 %Extension @extension{EXT,framebuffer_object} + * @requires_gl30 %Extension @extension{ARB,framebuffer_object} */ InvalidFramebufferOperation = GL_INVALID_FRAMEBUFFER_OPERATION, diff --git a/src/TextureFormat.h b/src/TextureFormat.h index 2344cd7d7..86d68f36e 100644 --- a/src/TextureFormat.h +++ b/src/TextureFormat.h @@ -823,7 +823,7 @@ enum class TextureFormat: GLenum { /** * 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})) From 6f63b046eca06a1238f836cac7228d96678ae737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 11 Jun 2013 18:09:56 +0200 Subject: [PATCH 19/27] Fixed typo copypasted all over the place. --- src/DefaultFramebuffer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 8f0a38148..0ec1ce1d2 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -285,7 +285,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 +303,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 +323,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} From ac3cb1b470684bac15fc90c9cb5cadff7badc6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 13:31:07 +0200 Subject: [PATCH 20/27] Fixed extension numbers. --- src/Extensions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Extensions.h b/src/Extensions.h index 309c7b080..8122ef2f0 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -205,7 +205,7 @@ 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,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 @@ -239,7 +239,7 @@ 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 } #endif } From e923034dbf197dab1baf01676b3d34516c2e3006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 13:33:54 +0200 Subject: [PATCH 21/27] Added functions for checking (default) framebuffer state. --- src/AbstractFramebuffer.cpp | 14 ++++++ src/AbstractFramebuffer.h | 8 +++ src/Context.cpp | 8 ++- src/DefaultFramebuffer.cpp | 13 +++++ src/DefaultFramebuffer.h | 39 +++++++++++++++ src/Extensions.h | 2 + src/Framebuffer.cpp | 23 +++++++++ src/Framebuffer.h | 77 +++++++++++++++++++++++++++++ src/Test/CMakeLists.txt | 2 + src/Test/DefaultFramebufferTest.cpp | 52 +++++++++++++++++++ src/Test/FramebufferTest.cpp | 52 +++++++++++++++++++ 11 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 src/Test/DefaultFramebufferTest.cpp create mode 100644 src/Test/FramebufferTest.cpp diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index 73de50537..d64ea4b93 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -34,6 +34,8 @@ namespace Magnum { +AbstractFramebuffer::CheckStatusImplementation AbstractFramebuffer::checkStatusImplementation = &AbstractFramebuffer::checkStatusImplementationDefault; + AbstractFramebuffer::ReadImplementation AbstractFramebuffer::readImplementation = &AbstractFramebuffer::readImplementationDefault; AbstractFramebuffer::DrawBuffersImplementation AbstractFramebuffer::drawBuffersImplementation = &AbstractFramebuffer::drawBuffersImplementationDefault; @@ -199,6 +201,7 @@ void AbstractFramebuffer::initializeContextBasedFunctionality(Context* context) 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; @@ -254,6 +257,17 @@ 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 diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index cfa47d6be..1fa6aa4a1 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -276,6 +276,9 @@ class MAGNUM_EXPORT AbstractFramebuffer { 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; @@ -294,6 +297,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/Context.cpp b/src/Context.cpp index 2c1596aa3..775ddb65c 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -206,6 +206,11 @@ 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), @@ -247,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) { diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp index 895a12e74..fe7a7d75a 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 0ec1ce1d2..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 @@ -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 8122ef2f0..f1582d657 100644 --- a/src/Extensions.h +++ b/src/Extensions.h @@ -205,6 +205,7 @@ 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,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 @@ -240,6 +241,7 @@ namespace GL { _extension(GL,OES,standard_derivatives, GLES200, GLES300) // #45 _extension(GL,OES,vertex_array_object, GLES200, GLES300) // #71 _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 01c0a7d5f..ae727c33f 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 975f96b14..d7b66ca3e 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -212,6 +212,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 * @@ -228,6 +288,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) @@ -452,6 +526,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/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 7e87a603e..e9138989f 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -26,6 +26,8 @@ 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) 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) From b5743c94475c7af5aefc6d561778c85ff32b3bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 13:52:00 +0200 Subject: [PATCH 22/27] TextureTools: ported distanceField() to OpenGL 2.1 and OpenGL ES. * Older GLSL doesn't have texelFetch() and related things, working around it by using classical texture() and normalized floating-point coordinates. But that needs to have Texture::imageSize() passed, which is not available in OpenGL ES, thus the user must specify it explicitly there. On desktop OpenGL that parameter is ignored. * Older GLSL doesn't have gl_VertexID, thus vertex buffer must be created and vertex data passed expliticly. * GLSL ES 2.0 doesn't have one-component texture format and TextureFormat::Luminance probably isn't renderable anywhere, thus TextureFormat::RGB should be used, although it is inefficient. * Checking for framebuffer completeness, if not complete, nothing is done. * Re-eabled building of TextureTools library in all ES PKGBUILDs. --- PKGBUILD-es2 | 1 - PKGBUILD-es2desktop | 1 - PKGBUILD-es3 | 1 - src/Text/DistanceFieldGlyphCache.cpp | 2 +- src/TextureTools/DistanceField.cpp | 128 ++++++++++++++++++---- src/TextureTools/DistanceField.h | 20 +++- src/TextureTools/DistanceFieldShader.frag | 86 ++++++++++++--- src/TextureTools/DistanceFieldShader.vert | 8 ++ 8 files changed, 208 insertions(+), 39 deletions(-) diff --git a/PKGBUILD-es2 b/PKGBUILD-es2 index e4c937d64..8daa7c23c 100644 --- a/PKGBUILD-es2 +++ b/PKGBUILD-es2 @@ -27,7 +27,6 @@ build() { -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..3f58adf14 100644 --- a/PKGBUILD-es2desktop +++ b/PKGBUILD-es2desktop @@ -28,7 +28,6 @@ build() { -DTARGET_GLES2=ON \ -DTARGET_DESKTOP_GLES=ON \ -DWITH_TEXT=OFF \ - -DWITH_TEXTURETOOLS=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/PKGBUILD-es3 b/PKGBUILD-es3 index e567c82a8..4ff7500c4 100644 --- a/PKGBUILD-es3 +++ b/PKGBUILD-es3 @@ -27,7 +27,6 @@ build() { -DTARGET_GLES=ON \ -DTARGET_GLES2=OFF \ -DWITH_TEXT=OFF \ - -DWITH_TEXTURETOOLS=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp index 73ffcd4b7..0bda02670 100644 --- a/src/Text/DistanceFieldGlyphCache.cpp +++ b/src/Text/DistanceFieldGlyphCache.cpp @@ -57,7 +57,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/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..fba73a37a 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 @@ -66,8 +71,21 @@ 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. */ -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 } From 5c06009446fce163bf86f96bc058f8095973b257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 14:13:44 +0200 Subject: [PATCH 23/27] Reverted interval in distancefield-related things. 1.0 is taken as shape center (white), 0.0 as shape surroundings (black). It was unintuitive to have it reverted, updated documentation to make it right. --- src/Shaders/DistanceFieldVector.frag | 8 ++++---- src/Shaders/DistanceFieldVector.h | 8 ++++---- src/TextureTools/DistanceField.h | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Shaders/DistanceFieldVector.frag b/src/Shaders/DistanceFieldVector.frag index 1f525eca7..07d9bbe2a 100644 --- a/src/Shaders/DistanceFieldVector.frag +++ b/src/Shaders/DistanceFieldVector.frag @@ -32,12 +32,12 @@ #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 @@ -66,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..72ef45949 100644 --- a/src/Shaders/DistanceFieldVector.h +++ b/src/Shaders/DistanceFieldVector.h @@ -81,12 +81,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/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h index fba73a37a..6685395db 100644 --- a/src/TextureTools/DistanceField.h +++ b/src/TextureTools/DistanceField.h @@ -56,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 From 7187ccb48b69075a868f924ac617608428f0db36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 14:44:48 +0200 Subject: [PATCH 24/27] Text: ported GlyphCache to older OpenGL and OpenGL ES. * Not requiring ARB_texture_storage, as Texture::setStorage() has already implemented fallback. * Not requiring EXT_texture_rg for single-channel texture on ES2, as this extension might not be available everywhere (unlike in ES3 desktop OpenGL, where Mesa 8/9 with OpenGL 2.1 supports it), fallback to Luminance in GlyphCache and RGB in DistanceFieldGlyphCache, because Luminance might not be renderable everywhere. * Re-enabled building of Text library in all ES PKGBUILDs. --- PKGBUILD-es2 | 1 - PKGBUILD-es2desktop | 1 - PKGBUILD-es3 | 1 - src/Text/DistanceFieldGlyphCache.cpp | 40 ++++++++++++++++++++++------ src/Text/DistanceFieldGlyphCache.h | 5 +++- src/Text/GlyphCache.cpp | 22 +++++---------- src/Text/GlyphCache.h | 7 ++--- 7 files changed, 47 insertions(+), 30 deletions(-) diff --git a/PKGBUILD-es2 b/PKGBUILD-es2 index 8daa7c23c..5372804da 100644 --- a/PKGBUILD-es2 +++ b/PKGBUILD-es2 @@ -26,7 +26,6 @@ build() { -DBUILD_TESTS=ON \ -DTARGET_GLES=ON \ -DTARGET_GLES2=ON \ - -DWITH_TEXT=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/PKGBUILD-es2desktop b/PKGBUILD-es2desktop index 3f58adf14..821dcf6e3 100644 --- a/PKGBUILD-es2desktop +++ b/PKGBUILD-es2desktop @@ -27,7 +27,6 @@ build() { -DTARGET_GLES=ON \ -DTARGET_GLES2=ON \ -DTARGET_DESKTOP_GLES=ON \ - -DWITH_TEXT=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/PKGBUILD-es3 b/PKGBUILD-es3 index 4ff7500c4..6c8a8aef6 100644 --- a/PKGBUILD-es3 +++ b/PKGBUILD-es3 @@ -26,7 +26,6 @@ build() { -DBUILD_TESTS=ON \ -DTARGET_GLES=ON \ -DTARGET_GLES2=OFF \ - -DWITH_TEXT=OFF \ -DWITH_MAGNUMINFO=OFF \ -DWITH_XEGLAPPLICATION=ON make diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp index 0bda02670..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) diff --git a/src/Text/DistanceFieldGlyphCache.h b/src/Text/DistanceFieldGlyphCache.h index e9161a95f..360d34844 100644 --- a/src/Text/DistanceFieldGlyphCache.h +++ b/src/Text/DistanceFieldGlyphCache.h @@ -62,7 +62,10 @@ 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. */ explicit DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& distanceFieldSize, UnsignedInt radius); diff --git a/src/Text/GlyphCache.cpp b/src/Text/GlyphCache.cpp index f3f072132..8d96ef2a3 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 b87504f7a..e2a27a33e 100644 --- a/src/Text/GlyphCache.h +++ b/src/Text/GlyphCache.h @@ -69,9 +69,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); From 5200771066a27692df2df347f4ffff4624cd947a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 15:04:19 +0200 Subject: [PATCH 25/27] Added some TODOs. --- src/AbstractFramebuffer.h | 2 ++ src/Shaders/DistanceFieldVector.h | 3 +++ src/Text/DistanceFieldGlyphCache.h | 3 +++ src/Text/GlyphCache.h | 1 + src/TextureTools/DistanceField.h | 3 +++ 5 files changed, 12 insertions(+) diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 1fa6aa4a1..7472d4bbd 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -200,6 +200,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); diff --git a/src/Shaders/DistanceFieldVector.h b/src/Shaders/DistanceFieldVector.h index 72ef45949..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: diff --git a/src/Text/DistanceFieldGlyphCache.h b/src/Text/DistanceFieldGlyphCache.h index 360d34844..bb5d1194c 100644 --- a/src/Text/DistanceFieldGlyphCache.h +++ b/src/Text/DistanceFieldGlyphCache.h @@ -66,6 +66,9 @@ class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache { * 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.h b/src/Text/GlyphCache.h index e2a27a33e..35d93cf52 100644 --- a/src/Text/GlyphCache.h +++ b/src/Text/GlyphCache.h @@ -55,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: diff --git a/src/TextureTools/DistanceField.h b/src/TextureTools/DistanceField.h index 6685395db..e44e6ba8d 100644 --- a/src/TextureTools/DistanceField.h +++ b/src/TextureTools/DistanceField.h @@ -80,6 +80,9 @@ http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnifica 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) */ #ifndef MAGNUM_TARGET_GLES void MAGNUM_TEXTURETOOLS_EXPORT distanceField(Texture2D* input, Texture2D* output, const Rectanglei& rectangle, Int radius, const Vector2i& imageSize = Vector2i()); From 04d1586cdacf25c72f1f0535cd96b3c4f5fa889b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 15:05:09 +0200 Subject: [PATCH 26/27] ES2 emulation on desktop is done through GLX, not EGL. --- PKGBUILD-es2desktop | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/PKGBUILD-es2desktop b/PKGBUILD-es2desktop index 821dcf6e3..8467066d9 100644 --- a/PKGBUILD-es2desktop +++ b/PKGBUILD-es2desktop @@ -27,8 +27,9 @@ build() { -DTARGET_GLES=ON \ -DTARGET_GLES2=ON \ -DTARGET_DESKTOP_GLES=ON \ - -DWITH_MAGNUMINFO=OFF \ - -DWITH_XEGLAPPLICATION=ON + -DWITH_MAGNUMINFO=ON \ + -DWITH_GLXAPPLICATION=ON \ + -DWITH_WINDOWLESSGLXAPPLICATION=ON make } From 4a4e4927851b7e4e9ab54ea299aceecc31bc130a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 12 Jun 2013 19:56:37 +0200 Subject: [PATCH 27/27] No need to have virtual destructor in AbstractFramebuffer. --- src/AbstractFramebuffer.cpp | 2 -- src/AbstractFramebuffer.h | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AbstractFramebuffer.cpp b/src/AbstractFramebuffer.cpp index d64ea4b93..c410aac91 100644 --- a/src/AbstractFramebuffer.cpp +++ b/src/AbstractFramebuffer.cpp @@ -47,8 +47,6 @@ FramebufferTarget AbstractFramebuffer::readTarget = FramebufferTarget::ReadDraw; FramebufferTarget AbstractFramebuffer::drawTarget = FramebufferTarget::ReadDraw; #endif -AbstractFramebuffer::~AbstractFramebuffer() {} - void AbstractFramebuffer::bind(FramebufferTarget target) { bindInternal(target); setViewportInternal(); diff --git a/src/AbstractFramebuffer.h b/src/AbstractFramebuffer.h index 7472d4bbd..606ae8593 100644 --- a/src/AbstractFramebuffer.h +++ b/src/AbstractFramebuffer.h @@ -190,7 +190,6 @@ class MAGNUM_EXPORT AbstractFramebuffer { } explicit AbstractFramebuffer() = default; - virtual ~AbstractFramebuffer() = 0; /** * @brief Bind framebuffer for rendering @@ -269,6 +268,8 @@ class MAGNUM_EXPORT AbstractFramebuffer { #else protected: #endif + ~AbstractFramebuffer() = default; + void MAGNUM_LOCAL bindInternal(FramebufferTarget target); FramebufferTarget MAGNUM_LOCAL bindInternal(); void MAGNUM_LOCAL setViewportInternal();