mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (MG_State, MG_Impl, DirectGLES): implement glPatchParameteri
GL_PATCH_VERTICES decides how many vertices one tessellation patch consumes, and glPatchParameteri was a stub - so the value stayed at the driver's default of 3 no matter what the application asked for. KHR-GL40.texture_gather.gather-tesselation-shader sets it to 1 and then draws a single patch: with the request dropped the draw had too few vertices for one patch, produced nothing at all, and the case read back the clear colour. The value is context state on both sides and ES 3.2 spells the entry point exactly the same way, so it is stored in the render state (where glGetIntegerv(GL_PATCH_VERTICES) now finds it) and forwarded. Validation needs the real bound, so GL_MAX_PATCH_VERTICES and GL_MAX_TESS_GEN_LEVEL are probed off the host driver alongside the other limits and answered from there too; the defaults are the GL 4.0 core minimums. KHR-GL40.texture_gather is now 75/75.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <MG_State/GLState/Core.h>
|
||||
#include <MG_State/EGLState/Core.h>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"value must be in [1, GL_MAX_PATCH_VERTICES]."));
|
||||
return;
|
||||
}
|
||||
MG_State::pGLContext->SetPatchVertices(static_cast<Uint>(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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<GLint>(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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user