diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02f4084c7..390eeb583 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ set(Magnum_SRCS AbstractTexture.cpp AbstractShaderProgram.cpp BufferedTexture.cpp + Context.cpp Framebuffer.cpp IndexedMesh.cpp Mesh.cpp @@ -42,8 +43,10 @@ set(Magnum_HEADERS BufferedTexture.h Buffer.h Color.h + Context.h CubeMapTextureArray.h CubeMapTexture.h + Extensions.h Framebuffer.h Image.h ImageWrapper.h diff --git a/src/Context.cpp b/src/Context.cpp new file mode 100644 index 000000000..bb484f8dc --- /dev/null +++ b/src/Context.cpp @@ -0,0 +1,188 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "Context.h" + +#include +#include +#include + +#include "Extensions.h" + +using namespace std; + +namespace Magnum { + +const std::vector& Extension::extensions(Version version) { + #define _extension(prefix, vendor, extension) \ + {Extensions::prefix::vendor::extension::Index, Extensions::prefix::vendor::extension::requiredVersion(), Extensions::prefix::vendor::extension::coreVersion(), Extensions::prefix::vendor::extension::string()} + static std::vector empty; + static std::vector extensions{ + _extension(GL,EXT,texture_filter_anisotropic)}; + static std::vector extensions300{ + _extension(GL,APPLE,flush_buffer_range), + _extension(GL,APPLE,vertex_array_object), + _extension(GL,ARB,color_buffer_float), + _extension(GL,ARB,half_float_pixel), + _extension(GL,ARB,texture_float), + _extension(GL,ARB,depth_buffer_float), + _extension(GL,ARB,texture_rg), + _extension(GL,EXT,framebuffer_object), + _extension(GL,EXT,packed_depth_stencil), + _extension(GL,EXT,framebuffer_blit), + _extension(GL,EXT,framebuffer_multisample), + _extension(GL,EXT,gpu_shader4), + _extension(GL,EXT,packed_float), + _extension(GL,EXT,texture_array), + _extension(GL,EXT,texture_compression_rgtc), + _extension(GL,EXT,texture_shared_exponent), + _extension(GL,EXT,framebuffer_sRGB), + _extension(GL,EXT,draw_buffers2), + _extension(GL,EXT,texture_integer), + _extension(GL,EXT,transform_feedback), + _extension(GL,NV,half_float), + _extension(GL,NV,depth_buffer_float), + _extension(GL,NV,conditional_render)}; + static std::vector extensions310{ + _extension(GL,ARB,texture_rectangle), + _extension(GL,ARB,draw_instanced), + _extension(GL,ARB,texture_buffer_object), + _extension(GL,ARB,uniform_buffer_object), + _extension(GL,ARB,copy_buffer), + _extension(GL,EXT,texture_snorm), + _extension(GL,NV,primitive_restart)}; + static std::vector extensions320{ + _extension(GL,ARB,geometry_shader4), + _extension(GL,ARB,depth_clamp), + _extension(GL,ARB,draw_elements_base_vertex), + _extension(GL,ARB,fragment_coord_conventions), + _extension(GL,ARB,provoking_vertex), + _extension(GL,ARB,seamless_cube_map), + _extension(GL,ARB,sync), + _extension(GL,ARB,texture_multisample), + _extension(GL,ARB,vertex_array_bgra)}; + static std::vector extensions330{ + _extension(GL,ARB,instanced_arrays), + _extension(GL,ARB,blend_func_extended), + _extension(GL,ARB,explicit_attrib_location), + _extension(GL,ARB,occlusion_query2), + _extension(GL,ARB,sampler_objects), + _extension(GL,ARB,shader_bit_encoding), + _extension(GL,ARB,texture_rgb10_a2ui), + _extension(GL,ARB,texture_swizzle), + _extension(GL,ARB,timer_query), + _extension(GL,ARB,vertex_type_2_10_10_10_rev)}; + static std::vector extensions400{ + _extension(GL,ARB,draw_buffers_blend), + _extension(GL,ARB,sample_shading), + _extension(GL,ARB,texture_cube_map_array), + _extension(GL,ARB,texture_gather), + _extension(GL,ARB,texture_query_lod), + _extension(GL,ARB,draw_indirect), + _extension(GL,ARB,gpu_shader5), + _extension(GL,ARB,gpu_shader_fp64), + _extension(GL,ARB,shader_subroutine), + _extension(GL,ARB,tessellation_shader), + _extension(GL,ARB,texture_buffer_object_rgb32), + _extension(GL,ARB,transform_feedback2), + _extension(GL,ARB,transform_feedback3)}; + static std::vector extensions410{ + _extension(GL,ARB,ES2_compatibility), + _extension(GL,ARB,get_program_binary), + _extension(GL,ARB,separate_shader_objects), + _extension(GL,ARB,shader_precision), + _extension(GL,ARB,vertex_attrib_64bit), + _extension(GL,ARB,viewport_array)}; + static std::vector extensions420{ + _extension(GL,ARB,texture_compression_bptc), + _extension(GL,ARB,base_instance), + _extension(GL,ARB,shading_language_420pack), + _extension(GL,ARB,transform_feedback_instanced), + _extension(GL,ARB,compressed_texture_pixel_storage), + _extension(GL,ARB,conservative_depth), + _extension(GL,ARB,internalformat_query), + _extension(GL,ARB,map_buffer_alignment), + _extension(GL,ARB,shader_atomic_counters), + _extension(GL,ARB,shader_image_load_store), + _extension(GL,ARB,texture_storage)}; + static std::vector extensions430; + #undef _extension + + switch(version) { + case Version::None: return extensions; + case Version::GL300: return extensions300; + case Version::GL310: return extensions310; + case Version::GL320: return extensions320; + case Version::GL330: return extensions330; + case Version::GL400: return extensions400; + case Version::GL410: return extensions410; + case Version::GL420: return extensions420; + case Version::GL430: return extensions430; + default: return empty; + } +} + +Context* Context::_current = nullptr; + +Context::Context() { + /* Version */ + glGetIntegerv(GL_MAJOR_VERSION, &_majorVersion); + glGetIntegerv(GL_MINOR_VERSION, &_minorVersion); + _version = static_cast(_majorVersion*100+_minorVersion*10); + + /* Future versions */ + vector versions{ + Version::GL300, + Version::GL310, + Version::GL320, + Version::GL330, + Version::GL400, + Version::GL410, + Version::GL420, + Version::GL430, + Version::None + }; + size_t future = 0; + while(versions[future] != Version::None && versions[future] < _version) + ++future; + + /* Extensions */ + unordered_map futureExtensions; + for(size_t i = future; i != versions.size(); ++i) + for(const Extension& extension: Extension::extensions(versions[i])) + futureExtensions.insert(make_pair(extension._string, extension)); + + /* Check for presence of extensions in future versions */ + GLuint index = 0; + const char* extension; + while((extension = reinterpret_cast(glGetStringi(GL_EXTENSIONS, index++)))) { + auto found = futureExtensions.find(extension); + if(found != futureExtensions.end()) { + _supportedExtensions.push_back(found->second); + extensionStatus.set(found->second._index); + } + } + + /* Set this context as current */ + CORRADE_ASSERT(!_current, "Context: Another context currently active", ); + _current = this; +} + +Context::~Context() { + CORRADE_ASSERT(_current == this, "Context: Cannot destroy context which is not currently active", ); + _current = nullptr; +} + +} diff --git a/src/Context.h b/src/Context.h new file mode 100644 index 000000000..1b9dd0b8d --- /dev/null +++ b/src/Context.h @@ -0,0 +1,216 @@ +#ifndef Magnum_Context_h +#define Magnum_Context_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Enum Version, class Magnum::Context, Magnum::Extension + */ + +#include +#include + +#include "Magnum.h" + +#include "magnumVisibility.h" + +namespace Magnum { + +/** @brief OpenGL version */ +enum class Version: GLint { + None = 0, /**< @brief Unspecified */ + #ifndef MAGNUM_TARGET_GLES + GL210 = 210, /**< @brief OpenGL 2.1 / GLSL 1.20 */ + GL300 = 300, /**< @brief OpenGL 3.0 / GLSL 1.30 */ + GL310 = 310, /**< @brief OpenGL 3.1 / GLSL 1.40 */ + GL320 = 320, /**< @brief OpenGL 3.2 / GLSL 1.50 */ + GL330 = 330, /**< @brief OpenGL 3.3, GLSL 3.30 */ + GL400 = 400, /**< @brief OpenGL 4.0, GLSL 4.00 */ + GL410 = 410, /**< @brief OpenGL 4.1, GLSL 4.10 */ + GL420 = 420, /**< @brief OpenGL 4.2, GLSL 4.20 */ + GL430 = 430 /**< @brief OpenGL 4.3, GLSL 4.30 */ + #else + GLES200 = 200, /**< @brief OpenGL ES 2.0, GLSL ES 1.00 */ + GLES300 = 300 /**< @brief OpenGL ES 3.0, GLSL ES 3.00 */ + #endif +}; + +/** +@brief Run-time information about OpenGL extension + +Encapsulates runtime information about OpenGL extension, such as name string, +minimal required OpenGL version and version in which the extension was adopted +to core. + +See also Extensions namespace, which contain compile-time information about +OpenGL extensions. +*/ +class MAGNUM_EXPORT Extension { + friend class Context; + + public: + /** @brief All extensions for given OpenGL version */ + static const std::vector& extensions(Version version); + + /** @brief Minimal version required by this extension */ + inline constexpr Version requiredVersion() const { return _requiredVersion; } + + /** @brief Version in which this extension was adopted to core */ + inline constexpr Version coreVersion() const { return _coreVersion; } + + /** @brief %Extension string */ + inline constexpr const char* string() const { return _string; } + + private: + const size_t _index; + const Version _requiredVersion; + const Version _coreVersion; + const char* const _string; + + inline constexpr Extension(size_t index, Version requiredVersion, Version coreVersion, const char* string): _index(index), _requiredVersion(requiredVersion), _coreVersion(coreVersion), _string(string) {} +}; + +/** +@brief OpenGL context + +Provides access to version and extension information. +*/ +class MAGNUM_EXPORT Context { + Context(const Context&) = delete; + Context(Context&&) = delete; + Context& operator=(const Context&) = delete; + Context& operator=(Context&&) = delete; + + public: + /** + * @brief Constructor + * + * @see @fn_gl{Get} with @def_gl{MAJOR_VERSION}, @def_gl{MINOR_VERSION}, + * @fn_gl{GetString} with @def_gl{EXTENSIONS} + */ + Context(); + ~Context(); + + /** @brief Current context */ + inline static Context* current() { return _current; } + + /** @brief OpenGL version */ + inline Version version() const { return _version; } + + /** @brief Major OpenGL version (e.g. `4`) */ + inline GLint majorVersion() const { return _majorVersion; } + + /** @brief Minor OpenGL version (e.g. `3`) */ + inline GLint minorVersion() const { return _minorVersion; } + + /** + * @brief Vendor string + * + * @see @fn_gl{GetString} with @def_gl{VENDOR} + */ + inline std::string vendorString() const { + return reinterpret_cast(glGetString(GL_VENDOR)); + } + + /** + * @brief Renderer string + * + * @see @fn_gl{GetString} with @def_gl{RENDERER} + */ + inline std::string rendererString() const { + return reinterpret_cast(glGetString(GL_RENDERER)); + } + + /** + * @brief Version string + * + * @see @fn_gl{GetString} with @def_gl{VERSION} + */ + inline std::string versionString() const { + return reinterpret_cast(glGetString(GL_VERSION)); + } + + /** + * @brief Shading language version string + * + * @see @fn_gl{GetString} with @def_gl{SHADING_LANGUAGE_VERSION} + */ + inline std::string shadingLanguageVersionString() const { + return reinterpret_cast(glGetString(GL_SHADING_LANGUAGE_VERSION)); + } + + /** + * @brief Supported extensions + * + * The list contains only extensions from OpenGL versions newer than + * the current. + * + * @see isExtensionSupported(), Extension::extensions() + */ + inline const std::vector& supportedExtensions() const { + return _supportedExtensions; + } + + /** @brief Whether given OpenGL version is supported */ + inline bool isVersionSupported(Version version) const { + return _version >= version; + } + + /** + * @brief Whether given extension is supported + * + * %Extensions usable with this function are listed in Extensions + * namespace in header Extensions.h. Example usage: + * @code + * if(Context::current()->isExtensionSupported()) { + * // draw fancy detailed model + * } else { + * // texture fallback + * } + * @endcode + * + * @see isExtensionSupported(const Extension&) const + */ + template inline bool isExtensionSupported() const { + return _version >= T::coreVersion() || (_version >= T::requiredVersion() && extensionStatus[T::Index]); + } + + /** + * @brief Whether given extension is supported + * + * Can be used e.g. for listing extensions available on current + * hardware, but for general usage prefer isExtensionSupported() const, + * as it does most operations in compile time. + * + * @see supportedExtensions(), Extension::extensions() + */ + inline bool isExtensionSupported(const Extension& extension) const { + return _version >= extension._coreVersion || (_version >= extension._requiredVersion && extensionStatus[extension._index]); + } + + private: + static Context* _current; + + Version _version; + GLint _majorVersion; + GLint _minorVersion; + + std::bitset<128> extensionStatus; + std::vector _supportedExtensions; +}; + +} + +#endif diff --git a/src/Extensions.h b/src/Extensions.h new file mode 100644 index 000000000..44385b8be --- /dev/null +++ b/src/Extensions.h @@ -0,0 +1,141 @@ +#ifndef Magnum_Extensions_h +#define Magnum_Extensions_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Namespace Magnum::Extensions + */ + +#include "Context.h" + +namespace Magnum { + +/** +@brief Compile-time information about OpenGL extensions + +Each extension is `struct` named hierarchically by prefix, vendor and +extension name, for example `GL::APPLE::vertex_array_object`. Each struct has +the same public methods as Extension class (requiredVersion(), coreVersion() +and string(), but these structs are better suited for compile-time decisions +rather than Extension instances. See Context::isExtensionSupported() for +example usage. +*/ +namespace Extensions { + +#ifndef DOXYGEN_GENERATING_OUTPUT +#define _extension(prefix, vendor, extension, _requiredVersion, _coreVersion) \ + struct extension { \ + enum: size_t { Index = __LINE__-1 }; \ + constexpr static Version requiredVersion() { return Version::_requiredVersion; } \ + constexpr static Version coreVersion() { return Version::_coreVersion; } \ + constexpr static const char* string() { return #prefix "_" #vendor "_" #extension; } \ + }; +namespace GL { + #line 1 + namespace APPLE { + _extension(GL,APPLE,flush_buffer_range, GL210, GL300) // #321 + _extension(GL,APPLE,vertex_array_object, GL210, GL300) // #273 + } namespace ARB { + _extension(GL,ARB,texture_rectangle, GL210, GL310) // #38 + _extension(GL,ARB,color_buffer_float, GL210, GL300) // #39 + _extension(GL,ARB,half_float_pixel, GL210, GL300) // #40 + _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,geometry_shader4, GL210, GL320) // #47 + _extension(GL,ARB,instanced_arrays, GL210, GL330) // #49 + _extension(GL,ARB,texture_buffer_object, GL210, GL310) // #51 + _extension(GL,ARB,texture_rg, GL210, GL300) // #53 + _extension(GL,ARB,uniform_buffer_object, GL210, GL310) // #57 + _extension(GL,ARB,copy_buffer, /*?*/ GL210, GL310) // #59 + _extension(GL,ARB,depth_clamp, /*?*/ GL210, GL320) // #61 + _extension(GL,ARB,draw_elements_base_vertex, /*?*/ GL210, GL320) // #62 + _extension(GL,ARB,fragment_coord_conventions, /*?*/ GL210, GL320) // #63 + _extension(GL,ARB,provoking_vertex, /*?*/ GL210, GL320) // #64 + _extension(GL,ARB,seamless_cube_map, GL210, GL320) // #65 + _extension(GL,ARB,sync, GL310, GL320) // #66 + _extension(GL,ARB,texture_multisample, /*?*/ GL210, GL320) // #67 + _extension(GL,ARB,vertex_array_bgra, GL210, GL320) // #68 + _extension(GL,ARB,draw_buffers_blend, GL210, GL400) // #69 + _extension(GL,ARB,sample_shading, GL210, GL400) // #70 + _extension(GL,ARB,texture_cube_map_array, /*?*/ GL210, GL400) // #71 + _extension(GL,ARB,texture_gather, GL210, GL400) // #72 + _extension(GL,ARB,texture_query_lod, GL210, GL400) // #73 + _extension(GL,ARB,texture_compression_bptc, GL310, GL420) // #77 + _extension(GL,ARB,blend_func_extended, GL210, GL330) // #78 + _extension(GL,ARB,explicit_attrib_location, GL210, GL330) // #79 + _extension(GL,ARB,occlusion_query2, GL210, GL330) // #80 + _extension(GL,ARB,sampler_objects, GL210, GL330) // #81 + _extension(GL,ARB,shader_bit_encoding, /*?*/ GL210, GL330) // #82 + _extension(GL,ARB,texture_rgb10_a2ui, GL210, GL330) // #83 + _extension(GL,ARB,texture_swizzle, /*?*/ GL210, GL330) // #84 + _extension(GL,ARB,timer_query, /*?*/ GL210, GL330) // #85 + _extension(GL,ARB,vertex_type_2_10_10_10_rev, GL210, GL330) // #86 + _extension(GL,ARB,draw_indirect, GL310, GL400) // #87 + _extension(GL,ARB,gpu_shader5, GL320, GL400) // #88 + _extension(GL,ARB,gpu_shader_fp64, GL320, GL400) // #89 + _extension(GL,ARB,shader_subroutine, GL320, GL400) // #90 + _extension(GL,ARB,tessellation_shader, GL320, GL400) // #91 + _extension(GL,ARB,texture_buffer_object_rgb32, /*?*/ GL210, GL400) // #92 + _extension(GL,ARB,transform_feedback2, GL210, GL400) // #93 + _extension(GL,ARB,transform_feedback3, GL210, GL400) // #94 + _extension(GL,ARB,ES2_compatibility, /*?*/ GL210, GL410) // #95 + _extension(GL,ARB,get_program_binary, GL300, GL410) // #96 + _extension(GL,ARB,separate_shader_objects, GL210, GL410) // #97 + _extension(GL,ARB,shader_precision, GL400, GL410) // #98 + _extension(GL,ARB,vertex_attrib_64bit, GL300, GL410) // #99 + _extension(GL,ARB,viewport_array, GL210, GL410) // #100 + _extension(GL,ARB,base_instance, GL210, GL420) // #107 + _extension(GL,ARB,shading_language_420pack, GL300, GL420) // #108 + _extension(GL,ARB,transform_feedback_instanced, GL210, GL420) // #109 + _extension(GL,ARB,compressed_texture_pixel_storage, GL210, GL420) // #110 + _extension(GL,ARB,conservative_depth, GL300, GL420) // #111 + _extension(GL,ARB,internalformat_query, GL210, GL420) // #112 + _extension(GL,ARB,map_buffer_alignment, GL210, GL420) // #113 + _extension(GL,ARB,shader_atomic_counters, GL300, GL420) // #114 + _extension(GL,ARB,shader_image_load_store, GL300, GL420) // #115 + _extension(GL,ARB,texture_storage, GL210, GL420) // #117 + } 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 + _extension(GL,EXT,gpu_shader4, GL210, GL300) // #326 + _extension(GL,EXT,packed_float, GL210, GL300) // #328 + _extension(GL,EXT,texture_array, GL210, GL300) // #329 + _extension(GL,EXT,texture_compression_rgtc, GL210, GL300) // #332 + _extension(GL,EXT,texture_shared_exponent, GL210, GL300) // #333 + _extension(GL,EXT,framebuffer_sRGB, GL210, GL300) // #337 + _extension(GL,EXT,draw_buffers2, GL210, GL300) // #340 + _extension(GL,EXT,texture_integer, GL210, GL300) // #343 + _extension(GL,EXT,transform_feedback, GL210, GL300) // #352 + _extension(GL,EXT,texture_snorm, GL300, GL310) // #365 + } namespace NV { + _extension(GL,NV,half_float, GL210, GL300) // #283 + _extension(GL,NV,primitive_restart, GL210, GL310) // #285 + _extension(GL,NV,depth_buffer_float, GL210, GL300) // #334 + _extension(GL,NV,conditional_render, GL210, GL300) // #346 + } +} +#undef _extension +#endif + +} + +} + +#endif