diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index 134e247d..0c135b56 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -234,6 +234,8 @@ namespace MobileGL { // drives capture from its draw recording instead (DirectVulkan). End is // called while the frontend capture state is still active, so the backend // can still see the capture program and buffer bindings. + // GL_PATCH_VERTICES; ES 3.2 spells it the same way. + void (*PatchParameteri)(GLenum pname, GLint value); void (*BeginTransformFeedback)(GLenum primitiveMode); void (*EndTransformFeedback)(); // ARB_transform_feedback2. A backend that leaves these null keeps the single @@ -295,6 +297,9 @@ namespace MobileGL { Int MaxIntegerSamples = 1; Int MaxSamples = 1; Int MaxSampleMaskWords = 1; + // Tessellation limits; defaults are the GL 4.0 core minimums. + Int MaxPatchVertices = 32; + Int MaxTessGenLevel = 64; // GL_MIN/MAX_PROGRAM_TEXTURE_GATHER_OFFSET. Defaults are the GL 4.0 core // minimums, which every ES 3.1 driver also guarantees. Int MinProgramTextureGatherOffset = -8; diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index 6e8ef1a2..20070ff9 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -1034,6 +1034,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // Transform feedback is captured by the real ES driver rather than // reconstructed from the draw recording, so the frontend has to hand the // span boundaries over. + funcsTable.GL.PatchParameteri = DirectGLES::PatchParameteri; funcsTable.GL.BeginTransformFeedback = XfbImpl::BeginTransformFeedback; funcsTable.GL.EndTransformFeedback = XfbImpl::EndTransformFeedback; funcsTable.GL.PauseTransformFeedback = XfbImpl::PauseTransformFeedback; @@ -1080,6 +1081,8 @@ namespace MobileGL::MG_Backend::DirectGLES { m_dynamicParameters.MaxIntegerSamples = m_GLESCapabilities.MaxIntegerSamples; m_dynamicParameters.MaxSamples = m_GLESCapabilities.MaxSamples; m_dynamicParameters.MaxSampleMaskWords = m_GLESCapabilities.MaxSampleMaskWords; + m_dynamicParameters.MaxPatchVertices = m_GLESCapabilities.MaxPatchVertices; + m_dynamicParameters.MaxTessGenLevel = m_GLESCapabilities.MaxTessGenLevel; m_dynamicParameters.MinProgramTextureGatherOffset = m_GLESCapabilities.MinProgramTextureGatherOffset; m_dynamicParameters.MaxProgramTextureGatherOffset = m_GLESCapabilities.MaxProgramTextureGatherOffset; // Clamp the advertised sampler limits the same way the DirectVulkan backend does: per-stage diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index c7ceba56..e9bde988 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -4025,6 +4025,11 @@ namespace MobileGL::MG_Backend::DirectGLES { return true; } + void PatchParameteri(GLenum pname, GLint value) { + if (g_GLESFuncs.glPatchParameteri == nullptr) return; + g_GLESFuncs.glPatchParameteri(pname, value); + } + void GenerateMipmap(GLenum target) { #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER DebugImpl::OpenGLScopeMarker marker(__func__); diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h index fa2eaf14..9a11cfc6 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h @@ -169,6 +169,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // begin is deferred to the first draw of the span (ES needs the capturing // program current and the capture buffers bound), and the end also mirrors the // captured bytes back into the frontend buffer shadows. + void PatchParameteri(GLenum pname, GLint value); + namespace XfbImpl { Bool AreTransformFeedbacksSupported(); void BeginTransformFeedback(GLenum primitiveMode); diff --git a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp index 35abb221..94678efd 100644 --- a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp +++ b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.cpp @@ -11,6 +11,7 @@ #include #include #include +#include "../Getter/GL_Getter.h" namespace MobileGL::MG_Impl::GLImpl { static Bool ValidateCurrentProgramForExecution(const char* functionName) { @@ -486,6 +487,28 @@ namespace MobileGL::MG_Impl::GLImpl { dispatchComputeIndirect(indirect); } + void PatchParameteri(GLenum pname, GLint value) { + if (pname != GL_PATCH_VERTICES) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeUnique("MG_Impl/GLImpl", __func__, "pname must be GL_PATCH_VERTICES.")); + return; + } + GLint maxPatchVertices = 32; + GetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices); + if (value <= 0 || value > maxPatchVertices) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", __func__, + "value must be in [1, GL_MAX_PATCH_VERTICES].")); + return; + } + MG_State::pGLContext->SetPatchVertices(static_cast(value)); + if (const auto patchParameteri = MG_Backend::gBackendFunctionsTable.GL.PatchParameteri) { + patchParameteri(pname, value); + } + } + void MemoryBarrier(GLbitfield barriers) { auto memoryBarrier = MG_Backend::gBackendFunctionsTable.GL.MemoryBarrier; if (!memoryBarrier) { diff --git a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h index 688d27bd..94fe61cb 100644 --- a/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h +++ b/MobileGL/MG_Impl/GLImpl/Drawing/GL_Drawing.h @@ -25,6 +25,7 @@ namespace MobileGL::MG_Impl::GLImpl { void DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); void DispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void DispatchComputeIndirect(GLintptr indirect); + void PatchParameteri(GLenum pname, GLint value); void MemoryBarrier(GLbitfield barriers); void MemoryBarrierByRegion(GLbitfield barriers); void MultiDrawElementsIndirect(GLenum mode, GLenum type, const void* indirect, GLsizei drawcount, GLsizei stride); diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index 7024976a..2897364b 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -424,7 +424,7 @@ DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnUniformfv, GLuint program, GLint locatio DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnUniformiv, GLuint program, GLint location, GLsizei bufSize, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnUniformiv, program, location, bufSize, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, GetnUniformuiv, GLuint program, GLint location, GLsizei bufSize, GLuint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetnUniformuiv, program, location, bufSize, params) DECLARE_GL_FUNCTION_STUB_HEAD(void, MinSampleShading, GLfloat value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, MinSampleShading, value) -DECLARE_GL_FUNCTION_STUB_HEAD(void, PatchParameteri, GLenum pname, GLint value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, PatchParameteri, pname, value) +DECLARE_GL_FUNCTION_HEAD(void, PatchParameteri, GLenum pname, GLint value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, PatchParameteri, pname, value) DECLARE_GL_FUNCTION_HEAD(void, TexParameterIiv, GLenum target, GLenum pname, const GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexParameterIiv, target, pname, params) DECLARE_GL_FUNCTION_HEAD(void, TexParameterIuiv, GLenum target, GLenum pname, const GLuint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexParameterIuiv, target, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetTexParameterIiv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetTexParameterIiv, target, pname, params) diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index c70b3c07..e74dfd29 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -1917,6 +1917,15 @@ namespace MobileGL::MG_Impl::GLImpl { case GL_MAX_SAMPLE_MASK_WORDS: *params = dynamicParameters.MaxSampleMaskWords; break; + case GL_PATCH_VERTICES: + *params = static_cast(MG_State::pGLContext->GetPatchVertices()); + break; + case GL_MAX_PATCH_VERTICES: + *params = dynamicParameters.MaxPatchVertices; + break; + case GL_MAX_TESS_GEN_LEVEL: + *params = dynamicParameters.MaxTessGenLevel; + break; case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: *params = dynamicParameters.MinProgramTextureGatherOffset; break; diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index f4738080..2b62242e 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -424,6 +424,14 @@ namespace MobileGL::MG_State { m_renderState.SetPointSize(size); } + void GLContext::SetPatchVertices(Uint vertices) { + m_renderState.SetPatchVertices(vertices); + } + + Uint GLContext::GetPatchVertices() const { + return m_renderState.GetPatchVertices(); + } + Float GLContext::GetPointSize() const { return m_renderState.GetPointSize(); } diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index 0961f850..5d9dde65 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -138,6 +138,8 @@ namespace MobileGL { Float GetLineWidth() const; void SetPointSize(Float size); Float GetPointSize() const; + void SetPatchVertices(Uint vertices); + Uint GetPatchVertices() const; void SetPolygonOffset(Float factor, Float units); Float GetPolygonOffsetFactor() const; Float GetPolygonOffsetUnits() const; diff --git a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp index 81cf77f0..74bb7603 100644 --- a/MobileGL/MG_State/GLState/RenderState/RenderState.cpp +++ b/MobileGL/MG_State/GLState/RenderState/RenderState.cpp @@ -154,6 +154,17 @@ namespace MobileGL { return m_parameters.PointSize; } + void RenderState::SetPatchVertices(Uint vertices) { + if (m_parameters.PatchVertices == vertices) return; + + m_parameters.PatchVertices = vertices; + ++m_version; + } + + Uint RenderState::GetPatchVertices() const { + return m_parameters.PatchVertices; + } + void RenderState::SetPolygonOffset(Float factor, Float units) { if (m_parameters.PolygonOffsetFactor == factor && m_parameters.PolygonOffsetUnits == units) return; diff --git a/MobileGL/MG_State/GLState/RenderState/RenderState.h b/MobileGL/MG_State/GLState/RenderState/RenderState.h index 44b43a2d..65e22393 100644 --- a/MobileGL/MG_State/GLState/RenderState/RenderState.h +++ b/MobileGL/MG_State/GLState/RenderState/RenderState.h @@ -224,6 +224,8 @@ namespace MobileGL { IntVec4 Viewport = IntVec4(0, 0, 0, 0); // x, y, width, height Float LineWidth = 1.0f; Float PointSize = 1.0f; + // GL_PATCH_VERTICES: how many vertices one tessellation patch consumes. + Uint PatchVertices = 3; Float PolygonOffsetFactor = 0.0f; Float PolygonOffsetUnits = 0.0f; @@ -319,6 +321,8 @@ namespace MobileGL { Float GetLineWidth() const; void SetPointSize(Float size); Float GetPointSize() const; + void SetPatchVertices(Uint vertices); + Uint GetPatchVertices() const; void SetPolygonOffset(Float factor, Float units); Float GetPolygonOffsetFactor() const; Float GetPolygonOffsetUnits() const; diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index 2e367d80..cba00e44 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -920,6 +920,8 @@ namespace MobileGL::MG_Util::BackendLoader { // below only ever widens them. GLint minProgramTextureGatherOffset = -8; GLint maxProgramTextureGatherOffset = 7; + GLint maxPatchVertices = 32; + GLint maxTessGenLevel = 64; glesFuncs.glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, aliasedLineWidthRange); glesFuncs.glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, smoothLineWidthRange); glesFuncs.glGetFloatv(GL_SMOOTH_LINE_WIDTH_GRANULARITY, &smoothLineWidthGranularity); @@ -948,6 +950,8 @@ namespace MobileGL::MG_Util::BackendLoader { // single test case. 1 is a spec-legal value (the minimum required), so cap // to what is actually implemented instead of forwarding the raw driver limit. maxSampleMaskWords = std::min(maxSampleMaskWords, 1); + glesFuncs.glGetIntegerv(GL_MAX_PATCH_VERTICES, &maxPatchVertices); + glesFuncs.glGetIntegerv(GL_MAX_TESS_GEN_LEVEL, &maxTessGenLevel); glesFuncs.glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &minProgramTextureGatherOffset); glesFuncs.glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &maxProgramTextureGatherOffset); // A driver that leaves the probe untouched (pre-ES 3.1, or an ignored enum) must not @@ -1037,6 +1041,8 @@ namespace MobileGL::MG_Util::BackendLoader { caps.MaxIntegerSamples = maxIntegerSamples; caps.MaxSamples = maxSamples; caps.MaxSampleMaskWords = maxSampleMaskWords; + caps.MaxPatchVertices = maxPatchVertices; + caps.MaxTessGenLevel = maxTessGenLevel; caps.MinProgramTextureGatherOffset = minProgramTextureGatherOffset; caps.MaxProgramTextureGatherOffset = maxProgramTextureGatherOffset; caps.MaxTextureImageUnits = maxTextureImageUnits; diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h index 9971140f..3986965d 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h @@ -1102,6 +1102,8 @@ namespace MobileGL { Int MaxIntegerSamples = 1; Int MaxSamples = 1; Int MaxSampleMaskWords = 1; + Int MaxPatchVertices = 32; + Int MaxTessGenLevel = 64; Int MinProgramTextureGatherOffset = -8; Int MaxProgramTextureGatherOffset = 7; Int MaxTextureImageUnits = 32;