diff --git a/doc/changelog.dox b/doc/changelog.dox index b6d7e6171..5d5d4ae24 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -57,6 +57,11 @@ See also: @gl_extension{EXT,draw_buffers_indexed} ES extension and @webgl_extension{EXT,draw_buffers_indexed} WebGL 2 extension in @ref GL::Renderer +- Implemented @ref GL::Renderer::setPatchVertexCount(), + @ref GL::Renderer::setPatchDefaultInnerLevel() and + @ref GL::Renderer::setPatchDefaultOuterLevel() as the last missing bits for + @gl_extension{ARB,tessellation_shader} / @gl_extension{EXT,tessellation_shader} + support (see [mosra/magnum#164](https://github.com/mosra/magnum/issues/164)) - Recognizing @gl_extension{AMD,shader_explicit_vertex_parameter} desktop and @gl_extension{NV,fragment_shader_barycentric} desktop / ES extensions. These add only shading language features. diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 1848fdefc..bc485cc18 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -309,7 +309,7 @@ OpenGL function | Matching API OpenGL function | Matching API --------------------------------------- | ------------ -@fn_gl{PatchParameter} | | +@fn_gl{PatchParameter} | @ref GL::Renderer::setPatchVertexCount(), \n @ref GL::Renderer::setPatchDefaultInnerLevel(), \n @ref GL::Renderer::setPatchDefaultOuterLevel() @fn_gl{PauseTransformFeedback}, @fn_gl{ResumeTransformFeedback} | @ref GL::TransformFeedback::pause(), @ref GL::TransformFeedback::resume() @fn_gl{PixelStore} | @ref GL::Texture::setImage(), \n @ref GL::TextureArray::setImage(), \n @ref GL::CubeMapTexture::setImage(), \n @ref GL::CubeMapTextureArray::setImage(), \n @ref GL::RectangleTexture::setImage(), \n @ref GL::Texture::setSubImage(), \n @ref GL::TextureArray::setSubImage(), \n @ref GL::CubeMapTexture::setSubImage(), \n @ref GL::CubeMapTextureArray::setSubImage(), \n @ref GL::RectangleTexture::setSubImage(), \n @ref GL::Texture::image(), @ref GL::TextureArray::image(), \n @ref GL::CubeMapTexture::image(), \n @ref GL::CubeMapTextureArray::image(), \n @ref GL::RectangleTexture::image(), \n @ref GL::Texture::subImage(), \n @ref GL::TextureArray::subImage(), \n @ref GL::CubeMapTexture::subImage(), \n @ref GL::CubeMapTextureArray::subImage(), \n @ref GL::RectangleTexture::subImage(), \n @ref GL::Texture::setCompressedImage(), \n @ref GL::TextureArray::setCompressedImage(), \n @ref GL::CubeMapTexture::setCompressedImage(), \n @ref GL::CubeMapTextureArray::setCompressedImage(), \n @ref GL::Texture::setCompressedSubImage(), \n @ref GL::TextureArray::setCompressedSubImage(), \n @ref GL::CubeMapTexture::setCompressedSubImage(), \n @ref GL::CubeMapTextureArray::setCompressedSubImage(), \n @ref GL::RectangleTexture::setCompressedSubImage(), \n @ref GL::Texture::compressedImage(), \n @ref GL::TextureArray::compressedImage(), \n @ref GL::CubeMapTexture::compressedImage(), \n @ref GL::CubeMapTextureArray::compressedImage(), \n @ref GL::RectangleTexture::compressedImage(), \n @ref GL::DefaultFramebuffer::read(), \n @ref GL::Framebuffer::read() @fn_gl{PointParameter} | | @@ -501,7 +501,7 @@ glGet() parameter | Matching API @def_gl{MAX_IMAGE_SAMPLES} | @ref GL::AbstractShaderProgram::maxImageSamples() @def_gl{MAX_IMAGE_UNITS} | @ref GL::AbstractShaderProgram::maxImageUnits() @def_gl{MAX_LABEL_LENGTH} | @ref GL::AbstractObject::maxLabelLength() -@def_gl{MAX_PATCH_VERTICES} | | +@def_gl{MAX_PATCH_VERTICES} | @ref GL::Renderer::maxPatchVertexCount() @def_gl{MAX_RENDERBUFFER_SIZE} | @ref GL::Renderbuffer::maxSize() @def_gl{MAX_SAMPLE_MASK_WORDS} | | @def_gl{MAX_SERVER_WAIT_TIMEOUT} | | diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 330c84471..50e5ccba8 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -149,7 +149,7 @@ GLSL 4.00 | done @gl_extension{ARB,gpu_shader5} | missing limit queries @gl_extension{ARB,gpu_shader_fp64} | done @gl_extension{ARB,shader_subroutine} | | -@gl_extension{ARB,tessellation_shader} | missing some limit queries and patch parameter specification function +@gl_extension{ARB,tessellation_shader} | done except for `MAX_TESS_GEN_LEVEL` and `MAX_TESS_PATCH_COMPONENTS` queries @gl_extension{ARB,texture_buffer_object_rgb32} | done @gl_extension{ARB,transform_feedback2} | done @gl_extension{ARB,transform_feedback3} | missing indexed properties query @@ -358,7 +358,7 @@ Extension | Status @gl_extension{EXT,geometry_shader} | missing some ES-specific limit queries @gl_extension{EXT,gpu_shader5} | done (shading language only) @gl_extension{EXT,shader_io_blocks} | done (shading language only) -@gl_extension{EXT,tessellation_shader} | see above +@gl_extension{EXT,tessellation_shader} | done except for `MAX_TESS_GEN_LEVEL` and `MAX_TESS_PATCH_COMPONENTS` queries @gl_extension{EXT,texture_border_clamp} | done @gl_extension{EXT,texture_buffer} | done @gl_extension{EXT,texture_cube_map_array} | done diff --git a/src/Magnum/GL/Implementation/RendererState.cpp b/src/Magnum/GL/Implementation/RendererState.cpp index be1be5d57..d05a43b67 100644 --- a/src/Magnum/GL/Implementation/RendererState.cpp +++ b/src/Magnum/GL/Implementation/RendererState.cpp @@ -107,6 +107,23 @@ RendererState::RendererState(Context& context, ContextState& contextState, std:: minSampleShadingImplementation = nullptr; #endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + #ifdef MAGNUM_TARGET_GLES + if(context.isVersionSupported(Version::GLES320)) + #endif + { + patchParameteriImplementation = glPatchParameteri; + } + #ifdef MAGNUM_TARGET_GLES + else { + /* Not checking for the extension (nor adding it to the extension list) + as this is not any optional feature -- it can be only used when + the extension is present, and if it's not, the pointers are null */ + patchParameteriImplementation = glPatchParameteriEXT; + } + #endif + #endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) #ifdef MAGNUM_TARGET_GLES diff --git a/src/Magnum/GL/Implementation/RendererState.h b/src/Magnum/GL/Implementation/RendererState.h index 4a9661991..1300d6eca 100644 --- a/src/Magnum/GL/Implementation/RendererState.h +++ b/src/Magnum/GL/Implementation/RendererState.h @@ -43,6 +43,9 @@ struct RendererState { #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void(*minSampleShadingImplementation)(GLfloat); #endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void (*patchParameteriImplementation)(GLenum, GLint); + #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void(*enableiImplementation)(GLenum, GLuint); void(*disableiImplementation)(GLenum, GLuint); @@ -85,6 +88,9 @@ struct RendererState { PixelStorage packPixelStorage, unpackPixelStorage; Range1D lineWidthRange; + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + GLint maxPatchVertexCount{}; + #endif /* Bool parameter is ugly, but this is implementation detail of internal API so who cares */ diff --git a/src/Magnum/GL/Renderer.cpp b/src/Magnum/GL/Renderer.cpp index 79acd324f..6c2b5aec4 100644 --- a/src/Magnum/GL/Renderer.cpp +++ b/src/Magnum/GL/Renderer.cpp @@ -163,6 +163,40 @@ void Renderer::minSampleShadingImplementationOES(const GLfloat value) { #endif #endif +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +UnsignedInt Renderer::maxPatchVertexCount() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + return 0; + #else + if(!Context::current().isExtensionSupported()) + return 0; + #endif + + GLint& value = Context::current().state().renderer->maxPatchVertexCount; + + /* Get the value, if not already cached */ + if(value == 0) + glGetIntegerv(GL_MAX_PATCH_VERTICES, &value); + + return value; +} + +void Renderer::setPatchVertexCount(UnsignedInt count) { + Context::current().state().renderer->patchParameteriImplementation(GL_PATCH_VERTICES, count); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void Renderer::setPatchDefaultInnerLevel(const Vector2& levels) { + glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, levels.data()); +} + +void Renderer::setPatchDefaultOuterLevel(const Vector4& levels) { + glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, levels.data()); +} +#endif + void Renderer::setScissor(const Range2Di& rectangle) { glScissor(rectangle.left(), rectangle.bottom(), rectangle.sizeX(), rectangle.sizeY()); } diff --git a/src/Magnum/GL/Renderer.h b/src/Magnum/GL/Renderer.h index c7e6a4963..cf8025966 100644 --- a/src/Magnum/GL/Renderer.h +++ b/src/Magnum/GL/Renderer.h @@ -685,6 +685,69 @@ class MAGNUM_GL_EXPORT Renderer { static void setMinSampleShading(Float value); #endif + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /** + * @brief Max supported component patch vertex count + * @m_since_latest + * + * The result is cached, repeated queries don't result in repeated + * OpenGL calls. If neither @gl_extension{ARB,tessellation_shader} (part + * of OpenGL 4.0) nor @gl_extension{ANDROID,extension_pack_es31a} / + * @gl_extension{EXT,tessellation_shader} ES extension is available, + * returns @cpp 0 @ce. + * @see @fn_gl{Get} with @def_gl_keyword{MAX_PATCH_VERTICES} + * @requires_gles30 Not defined in OpenGL ES 2.0. + * @requires_gles Tessellation shaders are not available in WebGL. + */ + static UnsignedInt maxPatchVertexCount(); + + /** + * @brief Set tessellation patch vertex count + * @m_since_latest + * + * Specifies number of vertices that will be used to make up a single + * tessellation patch primitive. + * @see @ref maxPatchVertexCount(), + * @fn_gl_keyword{PatchParameter} with @def_gl{PATCH_VERTICES} + * @requires_gl40 Extension @gl_extension{ARB,tessellation_shader} + * @requires_gles30 Not defined in OpenGL ES 2.0. + * @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} / + * @gl_extension{EXT,tessellation_shader} + * @requires_gles Tessellation shaders are not available in WebGL. + */ + static void setPatchVertexCount(UnsignedInt count); + #endif + + #ifndef MAGNUM_TARGET_GLES + /** + * @brief Set default patch inner tessellation level + * @m_since_latest + * + * When no tessellation control shader is present, specifies the + * default inner tessellation levels to be used. + * @see @fn_gl_keyword{PatchParameter} with + * @def_gl{PATCH_DEFAULT_INNER_LEVEL} + * @requires_gl40 Extension @gl_extension{ARB,tessellation_shader} + * @requires_gl A tessellation control shader has to be always present + * in OpenGL ES. + */ + static void setPatchDefaultInnerLevel(const Vector2& levels); + + /** + * @brief Set default patch outer tessellation level + * @m_since_latest + * + * When no tessellation control shader is present, specifies the + * default outer tessellation levels to be used. + * @see @fn_gl_keyword{PatchParameter} with + * @def_gl{PATCH_DEFAULT_OUTER_LEVEL} + * @requires_gl40 Extension @gl_extension{ARB,tessellation_shader} + * @requires_gl A tessellation control shader has to be always present + * in OpenGL ES. + */ + static void setPatchDefaultOuterLevel(const Vector4& levels); + #endif + /*@}*/ /** @{ @name Scissor operations */ diff --git a/src/Magnum/GL/Test/RendererGLTest.cpp b/src/Magnum/GL/Test/RendererGLTest.cpp index 2c53b0fe5..7aef526db 100644 --- a/src/Magnum/GL/Test/RendererGLTest.cpp +++ b/src/Magnum/GL/Test/RendererGLTest.cpp @@ -55,6 +55,9 @@ struct RendererGLTest: OpenGLTester { void maxLineWidth(); void pointCoord(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void patchParameters(); + #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void drawBuffersIndexed(); void drawBuffersBlend(); @@ -73,6 +76,9 @@ using namespace Math::Literals; RendererGLTest::RendererGLTest() { addTests({&RendererGLTest::maxLineWidth, &RendererGLTest::pointCoord, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + &RendererGLTest::patchParameters, + #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) &RendererGLTest::drawBuffersIndexed, &RendererGLTest::drawBuffersBlend @@ -230,6 +236,26 @@ void RendererGLTest::pointCoord() { (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void RendererGLTest::patchParameters() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::tessellation_shader::string() + std::string(" is not available.")); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::tessellation_shader::string() + std::string(" is not available.")); + #endif + + /* All we can do is check for GL errors */ + Renderer::setPatchVertexCount(Renderer::maxPatchVertexCount()); + #ifndef MAGNUM_TARGET_GLES + Renderer::setPatchDefaultInnerLevel({0.3f, 1.2f}); + Renderer::setPatchDefaultOuterLevel({0.3f, 2.2f, 1.0f, 1.2f}); + #endif + MAGNUM_VERIFY_NO_GL_ERROR(); +} +#endif + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void RendererGLTest::drawBuffersIndexed() { #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Platform/gl-info.cpp b/src/Magnum/Platform/gl-info.cpp index 4221cd777..f1dc1e2d0 100644 --- a/src/Magnum/Platform/gl-info.cpp +++ b/src/Magnum/Platform/gl-info.cpp @@ -710,6 +710,7 @@ MagnumInfo::MagnumInfo(const Arguments& arguments): Platform::WindowlessApplicat _l(GL::Shader::maxTessellationControlTotalOutputComponents()) _l(GL::Shader::maxTessellationEvaluationInputComponents()) _l(GL::Shader::maxTessellationEvaluationOutputComponents()) + _l(GL::Renderer::maxPatchVertexCount()) } #endif