diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index 5e581074e..a290dd070 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -76,8 +76,8 @@ AbstractShaderProgram::UniformMatrix3x4dvImplementation AbstractShaderProgram::u AbstractShaderProgram::UniformMatrix4x3dvImplementation AbstractShaderProgram::uniformMatrix4x3dvImplementation = &AbstractShaderProgram::uniformImplementationDefault; #endif -Int AbstractShaderProgram::maxSupportedVertexAttributeCount() { - GLint& value = Context::current()->state().shaderProgram->maxSupportedVertexAttributeCount; +Int AbstractShaderProgram::maxVertexAttributes() { + GLint& value = Context::current()->state().shaderProgram->maxVertexAttributes; /* Get the value, if not already cached */ if(value == 0) @@ -86,6 +86,153 @@ Int AbstractShaderProgram::maxSupportedVertexAttributeCount() { return value; } +#ifndef MAGNUM_TARGET_GLES +Int AbstractShaderProgram::maxAtomicCounterBufferSize() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxAtomicCounterBufferSize; + + if(value == 0) + glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &value); + + return value; +} + +Int AbstractShaderProgram::maxComputeSharedMemorySize() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxComputeSharedMemorySize; + + if(value == 0) + glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &value); + + return value; +} + +Int AbstractShaderProgram::maxComputeWorkGroupInvocations() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxComputeWorkGroupInvocations; + + /** @todo Fix when glLoadGen has `GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS` */ + if(value == 0) + glGetIntegerv(/*GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS*/0x90EB, &value); + + return value; +} + +Int AbstractShaderProgram::maxImageUnits() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxImageUnits; + + if(value == 0) + glGetIntegerv(GL_MAX_IMAGE_UNITS, &value); + + return value; +} + +Int AbstractShaderProgram::maxImageSamples() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxImageSamples; + + if(value == 0) + glGetIntegerv(GL_MAX_IMAGE_SAMPLES, &value); + + return value; +} + +Int AbstractShaderProgram::maxCombinedShaderOutputResources() { + if(!Context::current()->isExtensionSupported() || !Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxCombinedShaderOutputResources; + + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &value); + + return value; +} + +Long AbstractShaderProgram::maxShaderStorageBlockSize() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint64& value = Context::current()->state().shaderProgram->maxShaderStorageBlockSize; + + if(value == 0) + glGetInteger64v(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &value); + + return value; +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +Int AbstractShaderProgram::maxUniformBlockSize() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + return 0; + #endif + + GLint& value = Context::current()->state().shaderProgram->maxUniformBlockSize; + + if(value == 0) + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &value); + + return value; +} +#endif + +#ifndef MAGNUM_TARGET_GLES +Int AbstractShaderProgram::maxUniformLocations() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shaderProgram->maxUniformLocations; + + if(value == 0) + glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &value); + + return value; +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +Int AbstractShaderProgram::minTexelOffset() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + return 0; + #endif + + GLint& value = Context::current()->state().shaderProgram->minTexelOffset; + + if(value == 0) + glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &value); + + return value; +} + +Int AbstractShaderProgram::maxTexelOffset() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + return 0; + #endif + + GLint& value = Context::current()->state().shaderProgram->maxTexelOffset; + + if(value == 0) + glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &value); + + return value; +} +#endif + AbstractShaderProgram::AbstractShaderProgram(): _id(glCreateProgram()) {} AbstractShaderProgram::AbstractShaderProgram(AbstractShaderProgram&& other) noexcept: _id(other._id) { diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index 4caf92be4..90eff3d60 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -149,6 +149,7 @@ bindFragmentDataLocationIndexed(NormalOutput, 1, "normal"); // Link... @endcode +@see @ref Mesh::maxVertexAttributes(), @ref AbstractFramebuffer::maxDrawBuffers() @requires_gl30 %Extension @extension{EXT,gpu_shader4} for using bindFragmentDataLocation(). @requires_gl33 %Extension @extension{ARB,blend_func_extended} for using @@ -180,6 +181,7 @@ Int transformationUniform = uniformLocation("transformation"); Int projectionUniform = uniformLocation("projection"); @endcode +@see @ref maxUniformLocations() @requires_gl43 %Extension @extension{ARB,explicit_uniform_location} for explicit uniform location instead of using uniformLocation(). @requires_gl Explicit uniform location is not supported in OpenGL ES. Use @@ -203,6 +205,7 @@ setUniform(DiffuseTextureUniform, DiffuseTextureLayer); setUniform(SpecularTextureUniform, SpecularTextureLayer); @endcode +@see @ref Shader::maxTextureImageUnits() @requires_gl42 %Extension @extension{ARB,shading_language_420pack} for explicit texture layer binding instead of using setUniform(Int, Int). @requires_gl Explicit texture layer binding is not supported in OpenGL ES. Use @@ -272,7 +275,7 @@ See @ref types for more information, only types with GLSL equivalent can be used @section AbstractShaderProgram-performance-optimization Performance optimizations The engine tracks currently used shader program to avoid unnecessary calls to -@fn_gl{UseProgram}. %Shader limits (such as maxSupportedVertexAttributeCount()) +@fn_gl{UseProgram}. %Shader limits (such as @ref maxVertexAttributes()) are cached, so repeated queries don't result in repeated @fn_gl{Get} calls. If extension @extension{ARB,separate_shader_objects} or @@ -287,6 +290,7 @@ comes in handy. @todo Compiling and linking more than one shader in parallel, then checking status, should be faster -- https://twitter.com/g_truc/status/352778836657700866 +@todo `GL_NUM_{PROGRAM,SHADER}_BINARY_FORMATS` + `GL_{PROGRAM,SHADER}_BINARY_FORMATS` (vector), (@extension{ARB,ES2_compatibility}) */ class MAGNUM_EXPORT AbstractShaderProgram { friend class Context; @@ -299,9 +303,152 @@ class MAGNUM_EXPORT AbstractShaderProgram { * * The result is cached, repeated queries don't result in repeated * OpenGL calls. - * @see Attribute, @fn_gl{Get} with @def_gl{MAX_VERTEX_ATTRIBS} + * @see @ref Mesh::maxVertexAttributes(), + * @ref AbstractShaderProgram::Attribute, @fn_gl{Get} with + * @def_gl{MAX_VERTEX_ATTRIBS} */ - static Int maxSupportedVertexAttributeCount(); + static Int maxVertexAttributes(); + + /** + * @copydoc maxVertexAttributes() + * @deprecated Use @ref Magnum::AbstractShaderProgram::maxVertexAttributes() "maxVertexAttributes()" + * instead. + */ + static Int maxSupportedVertexAttributeCount() { return maxVertexAttributes(); } + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Max supported atomic counter buffer size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} is + * not available, returns `0`. + * @requires_gl Atomic counters are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_ATOMIC_COUNTER_BUFFER_SIZE} + */ + static Int maxAtomicCounterBufferSize(); + + /** + * @brief Max supported compute shared memory size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,compute_shader} is not + * available, returns `0`. + * @requires_gl Compute shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_COMPUTE_SHARED_MEMORY_SIZE} + */ + static Int maxComputeSharedMemorySize(); + + /** + * @brief Max supported compute work group invocation count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,compute_shader} is not + * available, returns `0`. + * @requires_gl Compute shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_COMPUTE_WORK_GROUP_INVOCATIONS} + */ + static Int maxComputeWorkGroupInvocations(); + + /** @todo MAX_COMPUTE_WORK_GROUP_COUNT, MAX_COMPUTE_WORK_GROUP_SIZE */ + + /** + * @brief Max supported image unit count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_image_load_store} + * is not available, returns `0`. + * @requires_gl Image load/store is not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_IMAGE_UNITS} + */ + static Int maxImageUnits(); + + /** + * @brief Max supported image sample count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_image_load_store} + * is not available, returns `0`. + * @requires_gl Image load/store is not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_IMAGE_SAMPLES} + */ + static Int maxImageSamples(); + + /** + * @brief Max supported combined shader output resource count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If neither @extension{ARB,shader_image_load_store} + * nor @extension{ARB,shader_storage_buffer_object} extension is + * available, returns `0`. + * @requires_gl Image load/store is not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_COMBINED_SHADER_OUTPUT_RESOURCES} + */ + static Int maxCombinedShaderOutputResources(); + + /** + * @brief Max supported shader storage block size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_storage_buffer_object} + * is not available, returns `0`. + * @requires_gl Shader storage is not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_SHADER_STORAGE_BLOCK_SIZE} + */ + static Long maxShaderStorageBlockSize(); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Max supported uniform block size + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,uniform_buffer_object} + * is not available, returns `0`. + * @requires_gles30 Uniform blocks are not available in OpenGL ES 2.0. + * @see @fn_gl{Get} with @def_gl{MAX_UNIFORM_BLOCK_SIZE} + */ + static Int maxUniformBlockSize(); + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Max supported explicit uniform location count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,explicit_uniform_location} + * is not available, returns `0`. + * @requires_gl Explicit uniform location is not supported in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_UNIFORM_LOCATIONS} + */ + static Int maxUniformLocations(); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Min supported program texel offset + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{EXT,gpu_shader4} is not + * available, returns `0`. + * @requires_gles30 Texture lookup with offset is not available in + * OpenGL ES 2.0. + * @see @fn_gl{Get} with @def_gl{MIN_PROGRAM_TEXEL_OFFSET} + */ + static Int minTexelOffset(); + + /** + * @brief Max supported program texel offset + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{EXT,gpu_shader4} is not + * available, returns `0`. + * @requires_gles30 Texture lookup with offset is not available in + * OpenGL ES 2.0. + * @see @fn_gl{Get} with @def_gl{MAX_PROGRAM_TEXEL_OFFSET} + */ + static Int maxTexelOffset(); + #endif /** * @brief Constructor @@ -947,8 +1094,8 @@ class MAGNUM_EXPORT AbstractShaderProgram { @brief Base struct for attribute location and type Template parameter @p location is vertex attribute location, number between `0` -and maxSupportedVertexAttributeCount(). To ensure compatibility, you should -always have vertex attribute with location `0`. +and @ref maxVertexAttributes(). To ensure compatibility, you should always have +vertex attribute with location `0`. Template parameter @p T is the type which is used for shader attribute, e.g. @ref Vector4i for `ivec4`. DataType is type of passed data when adding vertex diff --git a/src/Implementation/ShaderProgramState.h b/src/Implementation/ShaderProgramState.h index a3c02205d..dd3afc347 100644 --- a/src/Implementation/ShaderProgramState.h +++ b/src/Implementation/ShaderProgramState.h @@ -29,11 +29,33 @@ namespace Magnum { namespace Implementation { struct ShaderProgramState { - constexpr ShaderProgramState(): current(0), maxSupportedVertexAttributeCount(0) {} + constexpr ShaderProgramState(): current(0), maxVertexAttributes(0) + #ifndef MAGNUM_TARGET_GLES + , maxAtomicCounterBufferSize(0), maxComputeSharedMemorySize(0), maxComputeWorkGroupInvocations(0), maxImageUnits(0), maxImageSamples(0), maxCombinedShaderOutputResources(0), maxUniformLocations(0), maxShaderStorageBlockSize(0) + #endif + #ifndef MAGNUM_TARGET_GLES2 + , minTexelOffset(0), maxTexelOffset(0), maxUniformBlockSize(0) + #endif + {} /* Currently used program */ GLuint current; - GLint maxSupportedVertexAttributeCount; + + GLint maxVertexAttributes; + #ifndef MAGNUM_TARGET_GLES + GLint maxAtomicCounterBufferSize, + maxComputeSharedMemorySize, + maxComputeWorkGroupInvocations, + maxImageUnits, + maxImageSamples, + maxCombinedShaderOutputResources, + maxUniformLocations; + GLint64 maxShaderStorageBlockSize; + #endif + + #ifndef MAGNUM_TARGET_GLES2 + GLint minTexelOffset, maxTexelOffset, maxUniformBlockSize; + #endif }; }} diff --git a/src/Implementation/ShaderState.h b/src/Implementation/ShaderState.h new file mode 100644 index 000000000..678c114c9 --- /dev/null +++ b/src/Implementation/ShaderState.h @@ -0,0 +1,92 @@ +#ifndef Magnum_Implementation_ShaderState_h +#define Magnum_Implementation_ShaderState_h +/* + 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 "OpenGL.h" +#include "Types.h" +#include "magnumConfigure.h" + +namespace Magnum { namespace Implementation { + +struct ShaderState { + explicit ShaderState(): + maxVertexOutputComponents{}, maxFragmentInputComponents{}, + #ifndef MAGNUM_TARGET_GLES + maxTessellationControlInputComponents{}, maxTessellationControlOutputComponents{}, maxTessellationControlTotalOutputComponents{}, maxTessellationEvaluationInputComponents{}, maxTessellationEvaluationOutputComponents{}, maxGeometryInputComponents{}, maxGeometryOutputComponents{}, maxGeometryTotalOutputComponents{}, maxAtomicCounterBuffers{}, maxCombinedAtomicCounterBuffers{}, maxAtomicCounters{}, maxCombinedAtomicCounters{}, maxImageUniforms{}, maxCombinedImageUniforms{}, maxShaderStorageBlocks{}, maxCombinedShaderStorageBlocks{}, + #endif + maxTextureImageUnits{}, maxTextureImageUnitsCombined{}, + #ifndef MAGNUM_TARGET_GLES2 + maxUniformBlocks{}, maxCombinedUniformBlocks{}, + #endif + maxUniformComponents{}, maxUniformComponentsCombined{} + #ifndef MAGNUM_TARGET_GLES2 + , maxCombinedUniformComponents{} + #endif + {} + + enum: std::size_t { + #ifndef MAGNUM_TARGET_GLES + StageCount = 5 + #else + StageCount = 2 + #endif + }; + + GLint maxVertexOutputComponents, + maxFragmentInputComponents; + #ifndef MAGNUM_TARGET_GLES + GLint maxTessellationControlInputComponents, + maxTessellationControlOutputComponents, + maxTessellationControlTotalOutputComponents, + maxTessellationEvaluationInputComponents, + maxTessellationEvaluationOutputComponents, + maxGeometryInputComponents, + maxGeometryOutputComponents, + maxGeometryTotalOutputComponents; + GLint maxAtomicCounterBuffers[StageCount]; + GLint maxCombinedAtomicCounterBuffers; + GLint maxAtomicCounters[StageCount]; + GLint maxCombinedAtomicCounters; + GLint maxImageUniforms[StageCount]; + GLint maxCombinedImageUniforms; + GLint maxShaderStorageBlocks[StageCount]; + GLint maxCombinedShaderStorageBlocks; + #endif + GLint maxTextureImageUnits[StageCount]; + GLint maxTextureImageUnitsCombined; + #ifndef MAGNUM_TARGET_GLES2 + GLint maxUniformBlocks[StageCount]; + GLint maxCombinedUniformBlocks; + #endif + GLint maxUniformComponents[StageCount]; + GLint maxUniformComponentsCombined; + #ifndef MAGNUM_TARGET_GLES2 + GLint maxCombinedUniformComponents[StageCount]; + #endif +}; + +}} + +#endif diff --git a/src/Implementation/State.cpp b/src/Implementation/State.cpp index a218a3f46..7fd1619f8 100644 --- a/src/Implementation/State.cpp +++ b/src/Implementation/State.cpp @@ -24,12 +24,13 @@ #include "State.h" -#include "BufferState.h" -#include "FramebufferState.h" -#include "MeshState.h" -#include "RendererState.h" -#include "ShaderProgramState.h" -#include "TextureState.h" +#include "Implementation/BufferState.h" +#include "Implementation/FramebufferState.h" +#include "Implementation/MeshState.h" +#include "Implementation/RendererState.h" +#include "Implementation/ShaderState.h" +#include "Implementation/ShaderProgramState.h" +#include "Implementation/TextureState.h" namespace Magnum { namespace Implementation { @@ -38,12 +39,14 @@ State::State(): framebuffer(new FramebufferState), mesh(new MeshState), renderer(new RendererState), + shader(new ShaderState), shaderProgram(new ShaderProgramState), texture(new TextureState) {} State::~State() { delete texture; delete shaderProgram; + delete shader; delete renderer; delete mesh; delete framebuffer; diff --git a/src/Implementation/State.h b/src/Implementation/State.h index 17a31f398..79b322d76 100644 --- a/src/Implementation/State.h +++ b/src/Implementation/State.h @@ -30,6 +30,7 @@ struct BufferState; struct FramebufferState; struct MeshState; struct RendererState; +struct ShaderState; struct ShaderProgramState; struct TextureState; @@ -41,6 +42,7 @@ struct State { FramebufferState* const framebuffer; MeshState* const mesh; RendererState* const renderer; + ShaderState* const shader; ShaderProgramState* const shaderProgram; TextureState* const texture; }; diff --git a/src/Platform/magnum-info.cpp b/src/Platform/magnum-info.cpp index 166f25d87..00be9155a 100644 --- a/src/Platform/magnum-info.cpp +++ b/src/Platform/magnum-info.cpp @@ -29,7 +29,10 @@ #include #endif +#include "AbstractShaderProgram.h" #include "Context.h" +#include "Extensions.h" +#include "Shader.h" #ifndef CORRADE_TARGET_NACL #include "Platform/WindowlessGlxApplication.h" #else @@ -169,6 +172,142 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat Debug() << ""; } + + /* Limits and implementation-defined values */ + #define _h(val) Debug() << "\n " << Extensions::GL::val::string() + std::string(":"); + #define _l(val) Debug() << " " << #val << (sizeof(#val) > 64 ? "\n" + std::string(68, ' ') : std::string(64 - sizeof(#val), ' ')) << val; + + Debug() << "Limits and implementation-defined values:"; + _l(Shader::maxVertexOutputComponents()) + _l(Shader::maxFragmentInputComponents()) + _l(Shader::maxTextureImageUnits(Shader::Type::Vertex)) + #ifndef MAGNUM_TARGET_GLES + _l(Shader::maxTextureImageUnits(Shader::Type::TessellationControl)) + _l(Shader::maxTextureImageUnits(Shader::Type::TessellationEvaluation)) + _l(Shader::maxTextureImageUnits(Shader::Type::Geometry)) + _l(Shader::maxTextureImageUnits(Shader::Type::Compute)) + #endif + _l(Shader::maxTextureImageUnits(Shader::Type::Fragment)) + _l(Shader::maxCombinedTextureImageUnits()) + _l(Shader::maxUniformComponents(Shader::Type::Vertex)) + #ifndef MAGNUM_TARGET_GLES + _l(Shader::maxUniformComponents(Shader::Type::TessellationControl)) + _l(Shader::maxUniformComponents(Shader::Type::TessellationEvaluation)) + _l(Shader::maxUniformComponents(Shader::Type::Geometry)) + _l(Shader::maxUniformComponents(Shader::Type::Compute)) + #endif + _l(Shader::maxUniformComponents(Shader::Type::Fragment)) + #ifndef MAGNUM_TARGET_GLES + _l(AbstractShaderProgram::maxUniformLocations()) + #endif + _l(AbstractShaderProgram::maxVertexAttributes()) + + #ifndef MAGNUM_TARGET_GLES + if(c->isExtensionSupported()) { + _h(ARB::compute_shader) + + _l(AbstractShaderProgram::maxComputeSharedMemorySize()) + _l(AbstractShaderProgram::maxComputeWorkGroupInvocations()) + } + + if(c->isExtensionSupported()) { + _h(ARB::geometry_shader4) + + _l(Shader::maxGeometryInputComponents()) + _l(Shader::maxGeometryOutputComponents()) + _l(Shader::maxGeometryTotalOutputComponents()) + } + + if(c->isExtensionSupported()) { + _h(ARB::shader_atomic_counters) + + _l(Shader::maxAtomicCounterBuffers(Shader::Type::Vertex)) + _l(Shader::maxAtomicCounterBuffers(Shader::Type::TessellationControl)) + _l(Shader::maxAtomicCounterBuffers(Shader::Type::TessellationEvaluation)) + _l(Shader::maxAtomicCounterBuffers(Shader::Type::Geometry)) + _l(Shader::maxAtomicCounterBuffers(Shader::Type::Compute)) + _l(Shader::maxAtomicCounterBuffers(Shader::Type::Fragment)) + _l(Shader::maxCombinedAtomicCounterBuffers()) + _l(Shader::maxAtomicCounters(Shader::Type::Vertex)) + _l(Shader::maxAtomicCounters(Shader::Type::TessellationControl)) + _l(Shader::maxAtomicCounters(Shader::Type::TessellationEvaluation)) + _l(Shader::maxAtomicCounters(Shader::Type::Geometry)) + _l(Shader::maxAtomicCounters(Shader::Type::Compute)) + _l(Shader::maxAtomicCounters(Shader::Type::Fragment)) + _l(Shader::maxCombinedAtomicCounters()) + _l(AbstractShaderProgram::maxAtomicCounterBufferSize()) + } + + if(c->isExtensionSupported()) { + _h(ARB::shader_image_load_store) + + _l(Shader::maxImageUniforms(Shader::Type::Vertex)) + _l(Shader::maxImageUniforms(Shader::Type::TessellationControl)) + _l(Shader::maxImageUniforms(Shader::Type::TessellationEvaluation)) + _l(Shader::maxImageUniforms(Shader::Type::Geometry)) + _l(Shader::maxImageUniforms(Shader::Type::Compute)) + _l(Shader::maxImageUniforms(Shader::Type::Fragment)) + _l(Shader::maxCombinedImageUniforms()) + _l(AbstractShaderProgram::maxCombinedShaderOutputResources()) + _l(AbstractShaderProgram::maxImageUnits()) + _l(AbstractShaderProgram::maxImageSamples()) + } + + if(c->isExtensionSupported()) { + _h(ARB::shader_storage_buffer_object) + + _l(Shader::maxShaderStorageBlocks(Shader::Type::Vertex)) + _l(Shader::maxShaderStorageBlocks(Shader::Type::TessellationControl)) + _l(Shader::maxShaderStorageBlocks(Shader::Type::TessellationEvaluation)) + _l(Shader::maxShaderStorageBlocks(Shader::Type::Geometry)) + _l(Shader::maxShaderStorageBlocks(Shader::Type::Compute)) + _l(Shader::maxShaderStorageBlocks(Shader::Type::Fragment)) + _l(Shader::maxCombinedShaderStorageBlocks()) + /* AbstractShaderProgram::maxCombinedShaderOutputResources() already in shader_image_load_store */ + _l(AbstractShaderProgram::maxShaderStorageBlockSize()) + } + + if(c->isExtensionSupported()) { + _h(ARB::tessellation_shader) + + _l(Shader::maxTessellationControlInputComponents()) + _l(Shader::maxTessellationControlOutputComponents()) + _l(Shader::maxTessellationControlTotalOutputComponents()) + _l(Shader::maxTessellationEvaluationInputComponents()) + _l(Shader::maxTessellationEvaluationOutputComponents()) + } + #endif + + #ifndef MAGNUM_TARGET_GLES2 + if(c->isExtensionSupported()) { + _h(ARB::uniform_buffer_object) + + _l(Shader::maxUniformBlocks(Shader::Type::Vertex)) + _l(Shader::maxUniformBlocks(Shader::Type::TessellationControl)) + _l(Shader::maxUniformBlocks(Shader::Type::TessellationEvaluation)) + _l(Shader::maxUniformBlocks(Shader::Type::Geometry)) + _l(Shader::maxUniformBlocks(Shader::Type::Compute)) + _l(Shader::maxUniformBlocks(Shader::Type::Fragment)) + _l(Shader::maxCombinedUniformBlocks()) + _l(Shader::maxCombinedUniformComponents(Shader::Type::Vertex)) + _l(Shader::maxCombinedUniformComponents(Shader::Type::TessellationControl)) + _l(Shader::maxCombinedUniformComponents(Shader::Type::TessellationEvaluation)) + _l(Shader::maxCombinedUniformComponents(Shader::Type::Geometry)) + _l(Shader::maxCombinedUniformComponents(Shader::Type::Compute)) + _l(Shader::maxCombinedUniformComponents(Shader::Type::Fragment)) + _l(AbstractShaderProgram::maxUniformBlockSize()) + } + + if(c->isExtensionSupported()) { + _h(EXT::gpu_shader4) + + _l(AbstractShaderProgram::minTexelOffset()) + _l(AbstractShaderProgram::maxTexelOffset()) + } + #endif + + #undef _l + #undef _h } } diff --git a/src/Shader.cpp b/src/Shader.cpp index 47063e848..c93c3c63a 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -27,6 +27,10 @@ #include #include +#include "Extensions.h" +#include "Implementation/State.h" +#include "Implementation/ShaderState.h" + #if defined(CORRADE_TARGET_NACL_NEWLIB) || defined(_WIN32) #include #endif @@ -55,7 +59,479 @@ std::string shaderName(const Shader::Type type) { CORRADE_ASSERT_UNREACHABLE(); } +UnsignedInt typeToIndex(const Shader::Type type) { + switch(type) { + case Shader::Type::Vertex: return 0; + case Shader::Type::Fragment: return 1; + #ifndef MAGNUM_TARGET_GLES + case Shader::Type::Geometry: return 2; + case Shader::Type::TessellationControl: return 3; + case Shader::Type::TessellationEvaluation: return 4; + case Shader::Type::Compute: return 5; + #endif + } + + CORRADE_ASSERT_UNREACHABLE(); +} + +#ifndef MAGNUM_TARGET_GLES +bool isTypeSupported(const Shader::Type type) { + if(type == Shader::Type::Geometry && !Context::current()->isExtensionSupported()) + return false; + + if((type == Shader::Type::TessellationControl || type == Shader::Type::TessellationEvaluation) && !Context::current()->isExtensionSupported()) + return false; + + if(type == Shader::Type::Compute && !Context::current()->isExtensionSupported()) + return false; + + return true; } +#else +constexpr bool isTypeSupported(Shader::Type) { return true; } +#endif + +} + +Int Shader::maxVertexOutputComponents() { + GLint& value = Context::current()->state().shader->maxVertexOutputComponents; + + /* Get the value, if not already cached */ + if(value == 0) { + #ifndef MAGNUM_TARGET_GLES + if(Context::current()->isVersionSupported(Version::GL320)) + glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &value); + else + glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &value); + #elif defined(MAGNUM_TARGET_GLES2) + glGetIntegerv(GL_MAX_VARYING_VECTORS, &value); + value *= 4; + #else + glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &value); + #endif + } + + return value; +} + +#ifndef MAGNUM_TARGET_GLES +Int Shader::maxTessellationControlInputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxTessellationControlInputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxTessellationControlOutputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxTessellationControlOutputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxTessellationControlTotalOutputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxTessellationControlTotalOutputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxTessellationEvaluationInputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxTessellationEvaluationInputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxTessellationEvaluationOutputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxTessellationEvaluationOutputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxGeometryInputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxGeometryInputComponents; + + /* Get the value, if not already cached */ + /** @todo The extension has only `GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB`, this is supported since GL 3.2 (wtf?) */ + if(value == 0) + glGetIntegerv(GL_MAX_GEOMETRY_INPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxGeometryOutputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxGeometryOutputComponents; + + /* Get the value, if not already cached */ + /** @todo The extension has only `GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB`, this is supported since GL 3.2 (wtf?) */ + if(value == 0) + glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, &value); + + return value; +} + +Int Shader::maxGeometryTotalOutputComponents() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxGeometryTotalOutputComponents; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, &value); + + return value; +} +#endif + +Int Shader::maxFragmentInputComponents() { + GLint& value = Context::current()->state().shader->maxFragmentInputComponents; + + /* Get the value, if not already cached */ + if(value == 0) { + #ifndef MAGNUM_TARGET_GLES + if(Context::current()->isVersionSupported(Version::GL320)) + glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &value); + else + glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &value); + #elif defined(MAGNUM_TARGET_GLES2) + glGetIntegerv(GL_MAX_VARYING_VECTORS, &value); + value *= 4; + #else + glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &value); + #endif + } + + return value; +} + +#ifndef MAGNUM_TARGET_GLES +Int Shader::maxAtomicCounterBuffers(const Type type) { + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxAtomicCounterBuffers[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, + GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, + GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, + GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, + GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, + GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedAtomicCounterBuffers() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxCombinedAtomicCounterBuffers; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &value); + + return value; +} + +Int Shader::maxAtomicCounters(const Type type) { + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxAtomicCounters[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_ATOMIC_COUNTERS, + GL_MAX_FRAGMENT_ATOMIC_COUNTERS, + GL_MAX_GEOMETRY_ATOMIC_COUNTERS, + GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, + GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, + GL_MAX_COMPUTE_ATOMIC_COUNTERS + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedAtomicCounters() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxCombinedAtomicCounters; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &value); + + return value; +} + +Int Shader::maxImageUniforms(const Type type) { + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxImageUniforms[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_IMAGE_UNIFORMS, + GL_MAX_FRAGMENT_IMAGE_UNIFORMS, + GL_MAX_GEOMETRY_IMAGE_UNIFORMS, + GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, + GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, + GL_MAX_COMPUTE_IMAGE_UNIFORMS + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedImageUniforms() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxCombinedImageUniforms; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &value); + + return value; +} + +Int Shader::maxShaderStorageBlocks(const Type type) { + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxShaderStorageBlocks[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, + GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, + GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, + GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, + GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, + GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedShaderStorageBlocks() { + if(!Context::current()->isExtensionSupported()) + return 0; + + GLint& value = Context::current()->state().shader->maxCombinedShaderStorageBlocks; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &value); + + return value; +} +#endif + +Int Shader::maxTextureImageUnits(const Type type) { + if(!isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxTextureImageUnits[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, + GL_MAX_TEXTURE_IMAGE_UNITS, + #ifndef MAGNUM_TARGET_GLES + GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, + GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, + GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, + GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS + #endif + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedTextureImageUnits() { + GLint& value = Context::current()->state().shader->maxTextureImageUnitsCombined; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value); + + return value; +} + +#ifndef MAGNUM_TARGET_GLES2 +Int Shader::maxUniformBlocks(const Type type) { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + #else + if(!isTypeSupported(type)) + #endif + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxUniformBlocks[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_UNIFORM_BLOCKS, + GL_MAX_FRAGMENT_UNIFORM_BLOCKS, + #ifndef MAGNUM_TARGET_GLES + /** @todo Fix this when glLoadGen has GL_MAX_GEOMETRY_UNIFORM_BLOCKS enum */ + 0x8A2C /*GL_MAX_GEOMETRY_UNIFORM_BLOCKS*/, + GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, + GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, + GL_MAX_COMPUTE_UNIFORM_BLOCKS + #endif + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} + +Int Shader::maxCombinedUniformBlocks() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + return 0; + #endif + + GLint& value = Context::current()->state().shader->maxCombinedUniformBlocks; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &value); + + return value; +} +#endif + +Int Shader::maxUniformComponents(const Type type) { + if(!isTypeSupported(type)) + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxUniformComponents[index]; + + /* Get the value, if not already cached */ + #ifndef MAGNUM_TARGET_GLES2 + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_UNIFORM_COMPONENTS, + GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, + #ifndef MAGNUM_TARGET_GLES + GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, + GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, + GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, + GL_MAX_COMPUTE_UNIFORM_COMPONENTS + #endif + }; + if(value == 0) + glGetIntegerv(what[index], &value); + #else + /* For ES2 we need to multiply _VECTORS by 4 */ + constexpr static const GLenum what[] = { + GL_MAX_VERTEX_UNIFORM_VECTORS, + GL_MAX_FRAGMENT_UNIFORM_VECTORS + }; + if(value == 0) { + GLint vectors; + glGetIntegerv(what[index], &vectors); + value = vectors*4; + } + #endif + + return value; +} + +#ifndef MAGNUM_TARGET_GLES2 +Int Shader::maxCombinedUniformComponents(const Type type) { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported() || !isTypeSupported(type)) + #else + if(!isTypeSupported(type)) + #endif + return 0; + + const UnsignedInt index = typeToIndex(type); + GLint& value = Context::current()->state().shader->maxCombinedUniformComponents[index]; + + /* Get the value, if not already cached */ + constexpr static const GLenum what[] = { + GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, + GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, + #ifndef MAGNUM_TARGET_GLES + /** @todo Fix this when glLoadGen has GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS enum */ + 0x8A32 /*GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS*/, + GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, + GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, + GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS + #endif + }; + if(value == 0) + glGetIntegerv(what[index], &value); + + return value; +} +#endif Shader::Shader(const Version version, const Type type): _type(type), _id(0) { _id = glCreateShader(static_cast(_type)); diff --git a/src/Shader.h b/src/Shader.h index 838671e70..5bfb732f3 100644 --- a/src/Shader.h +++ b/src/Shader.h @@ -48,7 +48,19 @@ class MAGNUM_EXPORT Shader { Shader& operator=(const Shader&) = delete; public: - /** @brief %Shader type */ + /** + * @brief %Shader type + * + * @see @ref Shader(Version, Type), + * @ref maxAtomicCounterBuffers(), + * @ref maxAtomicCounters(), + * @ref maxImageUniforms() + * @ref maxShaderStorageBlocks(), + * @ref maxTextureImageUnits(), + * @ref maxUniformBlocks(), + * @ref maxUniformComponents(), + * @ref maxCombinedUniformComponents() + */ enum class Type: GLenum { Vertex = GL_VERTEX_SHADER, /**< Vertex shader */ @@ -85,6 +97,337 @@ class MAGNUM_EXPORT Shader { Fragment = GL_FRAGMENT_SHADER /**< Fragment shader */ }; + /** + * @brief Max supported component count on vertex shader output + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. In OpenGL ES 2.0 the four-component vector count is + * queried and multiplied with 4. + * @see @fn_gl{Get} with @def_gl{MAX_VERTEX_OUTPUT_COMPONENTS}, + * @def_gl{MAX_VARYING_COMPONENTS} in OpenGL <3.2 or + * @def_gl{MAX_VARYING_VECTORS} in OpenGL ES 2.0 + */ + static Int maxVertexOutputComponents(); + + /** @todo `GL_MAX_PATCH_VERTICES`, `GL_MAX_TESS_GEN_LEVEL`, `GL_MAX_TESS_PATCH_COMPONENTS` when @extension{ARB,tessellation_shader} is done */ + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Max supported component count of tessellation control shader input vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,tessellation_shader} + * is not available, returns `0`. + * @requires_gl Tessellation shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_TESS_CONTROL_INPUT_COMPONENTS} + */ + static Int maxTessellationControlInputComponents(); + + /** + * @brief Max supported component count of tessellation control shader output vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,tessellation_shader} + * is not available, returns `0`. + * @requires_gl Tessellation shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_TESS_CONTROL_OUTPUT_COMPONENTS} + */ + static Int maxTessellationControlOutputComponents(); + + /** + * @brief Max supported component count of all tessellation control shader output vertices combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,tessellation_shader} + * is not available, returns `0`. + * @requires_gl Tessellation shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS} + */ + static Int maxTessellationControlTotalOutputComponents(); + + /** + * @brief Max supported component count of tessellation evaluation shader input vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,tessellation_shader} + * is not available, returns `0`. + * @requires_gl Tessellation shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_TESS_EVALUATION_INPUT_COMPONENTS} + */ + static Int maxTessellationEvaluationInputComponents(); + + /** + * @brief Max supported component count of tessellation evaluation shader output vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,tessellation_shader} + * is not available, returns `0`. + * @requires_gl Tessellation shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_TESS_EVALUATION_OUTPUT_COMPONENTS} + */ + static Int maxTessellationEvaluationOutputComponents(); + + /** + * @brief Max supported component count of geometry shader input vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,geometry_shader4} + * is not available, returns `0`. + * @requires_gl Geometry shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_GEOMETRY_INPUT_COMPONENTS} + */ + static Int maxGeometryInputComponents(); + + /** + * @brief Max supported component count of geometry shader output vertex + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,geometry_shader4} + * is not available, returns `0`. + * @requires_gl Geometry shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_GEOMETRY_OUTPUT_COMPONENTS} + */ + static Int maxGeometryOutputComponents(); + + /** + * @brief Max supported component count of all geometry shader output vertices combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,geometry_shader4} + * is not available, returns `0`. + * @requires_gl Geometry shaders are not available in OpenGL ES. + * @see @fn_gl{Get} with @def_gl{MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS} + */ + static Int maxGeometryTotalOutputComponents(); + #endif + + /** + * @brief Max supported component count on fragment shader input + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. In OpenGL ES 2.0 the four-component vector count is + * queried and multiplied with 4. + * @see @fn_gl{Get} with @def_gl{MAX_FRAGMENT_INPUT_COMPONENTS}, + * @def_gl{MAX_VARYING_COMPONENTS} in OpenGL <3.2 or + * @def_gl{MAX_VARYING_VECTORS} in OpenGL ES 2.0 + */ + static Int maxFragmentInputComponents(); + + /** + * @brief Max supported uniform component count in default block + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If particular shader stage is not available, returns + * `0`. In OpenGL ES 2.0 the four-component vector count is queried and + * multiplied with 4. + * @see @ref maxCombinedUniformComponents(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_UNIFORM_COMPONENTS}, + * @def_gl{MAX_TESS_CONTROL_UNIFORM_COMPOENTS}, + * @def_gl{MAX_TESS_EVALUATION_UNIFORM_COMPONENTS}, + * @def_gl{MAX_GEOMETRY_UNIFORM_COMPONENTS}, + * @def_gl{MAX_COMPUTE_UNIFORM_COMPONENTS}, + * @def_gl{MAX_FRAGMENT_UNIFORM_COMPONENTS} or + * @def_gl{MAX_VERTEX_UNIFORM_VECTORS}, + * @def_gl{MAX_FRAGMENT_UNIFORM_VECTORS} in OpenGL ES 2.0 + */ + static Int maxUniformComponents(Type type); + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Max supported atomic counter buffer count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} or + * particular shader stage is not available, returns `0`. + * @requires_gl Atomic counters are not available in OpenGL ES. + * @see @ref maxCombinedAtomicCounterBuffers(), @ref maxAtomicCounters(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_ATOMIC_COUNTER_BUFFERS}, + * @def_gl{MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS}, + * @def_gl{MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS}, + * @def_gl{MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS}, + * @def_gl{MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS} or + * @def_gl{MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS} + */ + static Int maxAtomicCounterBuffers(Type type); + + /** + * @brief Max supported atomic counter buffer count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} is + * not available, returns `0`. + * @requires_gl Atomic counters are not available in OpenGL ES. + * @see @ref maxAtomicCounterBuffers(), @ref maxCombinedAtomicCounters(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_ATOMIC_COUNTER_BUFFERS} + */ + static Int maxCombinedAtomicCounterBuffers(); + + /** + * @brief Max supported atomic counter count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} or + * particular shader stage is not available, returns `0`. + * @requires_gl Atomic counters are not available in OpenGL ES. + * @see @ref maxCombinedAtomicCounters(), @ref maxAtomicCounterBuffers(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_ATOMIC_COUNTERS}, + * @def_gl{MAX_TESS_CONTROL_ATOMIC_COUNTERS}, + * @def_gl{MAX_TESS_EVALUATION_ATOMIC_COUNTERS}, + * @def_gl{MAX_GEOMETRY_ATOMIC_COUNTERS}, + * @def_gl{MAX_COMPUTE_ATOMIC_COUNTERS} or + * @def_gl{MAX_FRAGMENT_ATOMIC_COUNTERS} + */ + static Int maxAtomicCounters(Type type); + + /** + * @brief Max supported atomic counter count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_atomic_counters} is + * not available, returns `0`. + * @requires_gl Atomic counters are not available in OpenGL ES. + * @see @ref maxAtomicCounters(), @ref maxCombinedAtomicCounterBuffers(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_ATOMIC_COUNTERS} + */ + static Int maxCombinedAtomicCounters(); + + /** + * @brief Max supported image uniform count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_image_load_store} + * or particular shader stage is not available, returns `0`. + * @requires_gl Image load/store is not available in OpenGL ES. + * @see @ref maxCombinedImageUniforms(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_IMAGE_UNIFORMS}, + * @def_gl{MAX_TESS_CONTROL_IMAGE_UNIFORMS}, + * @def_gl{MAX_TESS_EVALUATION_IMAGE_UNIFORMS}, + * @def_gl{MAX_GEOMETRY_IMAGE_UNIFORMS}, + * @def_gl{MAX_COMPUTE_IMAGE_UNIFORMS} or + * @def_gl{MAX_FRAGMENT_IMAGE_UNIFORMS} + */ + static Int maxImageUniforms(Type type); + + /** + * @brief Max supported image uniform count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_image_load_store} + * is not available, returns `0`. + * @requires_gl Image load/store is not available in OpenGL ES. + * @see @ref maxImageUniforms(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_IMAGE_UNIFORMS} + */ + static Int maxCombinedImageUniforms(); + + /** + * @brief Max supported shader storage block count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_storage_buffer_object} + * or particular shader stage is not available, returns `0`. + * @requires_gl Shader storage is not available in OpenGL ES. + * @see @ref maxCombinedShaderStorageBlocks(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_SHADER_STORAGE_BLOCKS}, + * @def_gl{MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS}, + * @def_gl{MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS}, + * @def_gl{MAX_GEOMETRY_SHADER_STORAGE_BLOCKS}, + * @def_gl{MAX_COMPUTE_SHADER_STORAGE_BLOCKS} or + * @def_gl{MAX_FRAGMENT_SHADER_STORAGE_BLOCKS} + */ + static Int maxShaderStorageBlocks(Type type); + + /** + * @brief Max supported shader storage block count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,shader_storage_buffer_object} + * is not available, returns `0`. + * @requires_gl Shader storage is not available in OpenGL ES. + * @see @ref maxShaderStorageBlocks(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_SHADER_STORAGE_BLOCKS} + */ + static Int maxCombinedShaderStorageBlocks(); + #endif + + /** + * @brief Max supported texture image unit count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If particular shader stage is not available, returns + * `0`. + * @see @ref maxCombinedTextureImageUnits(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_TEXTURE_IMAGE_UNITS}, + * @fn_gl{MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS}, + * @fn_gl{MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS}, + * @fn_gl{MAX_GEOMETRY_TEXTURE_IMAGE_UNITS}, + * @fn_gl{MAX_COMPUTE_TEXTURE_IMAGE_UNITS}, + * @fn_gl{MAX_TEXTURE_IMAGE_UNITS} + */ + static Int maxTextureImageUnits(Type type); + + /** + * @brief Max supported texture image unit count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. + * @see @ref AbstractTexture::maxLayers(), @ref maxTextureImageUnits(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS} + */ + static Int maxCombinedTextureImageUnits(); + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Max supported uniform block count + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,uniform_buffer_objects} or + * particular shader stage is not available, returns `0`. + * @requires_gles30 Uniform blocks are not available in OpenGL ES 2.0. + * @see @ref maxCombinedUniformBlocks(), @ref maxUniformComponents(), + * @ref maxCombinedUniformComponents(), + * @fn_gl{Get} with @def_gl{MAX_VERTEX_UNIFORM_BLOCKS}, + * @def_gl{MAX_TESS_CONTROL_UNIFORM_BLOCKS}, + * @def_gl{MAX_TESS_EVALUATION_UNIFORM_BLOCKS}, + * @def_gl{MAX_GEOMETRY_UNIFORM_BLOCKS}, + * @def_gl{MAX_COMPUTE_UNIFORM_BLOCKS} or + * @def_gl{MAX_FRAGMENT_UNIFORM_BLOCKS} + */ + static Int maxUniformBlocks(Type type); + + /** + * @brief Max supported uniform block count for all stages combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,uniform_buffer_objects} is + * not available, returns `0`. + * @requires_gles30 Uniform blocks are not available in OpenGL ES 2.0. + * @see @ref maxUniformBlocks(), @ref maxUniformComponents(), + * @ref maxCombinedUniformComponents(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_UNIFORM_BLOCKS} + */ + static Int maxCombinedUniformBlocks(); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Max supported uniform component count in all blocks combined + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If extension @extension{ARB,uniform_buffer_objects} + * or particular shader stage is not available, returns `0`. + * @requires_gles30 Uniform blocks are not available in OpenGL ES 2.0. + * @see @ref maxUniformComponents(), @ref maxUniformBlocks(), + * @fn_gl{Get} with @def_gl{MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS}, + * @def_gl{MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS}, + * @def_gl{MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS}, + * @def_gl{MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS}, + * @def_gl{MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS} or + * @def_gl{MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS} + */ + static Int maxCombinedUniformComponents(Type type); + #endif + /** * @brief Constructor * @param version Target version