mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix] (Getter): answer the GL 4.6 limit surface honestly - tess/cull/subroutine pnames, TBuiltInResource drift, 84 UBO binding points, 64-bit GL_MAX_ELEMENT_INDEX, per-category sample truth
This commit is contained in:
@@ -1139,6 +1139,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
// optimistic 8 behind, so the frontend promised eight clip planes and every draw with a
|
||||
// clipping program silently rendered nothing. The guarded probe below only ever widens it.
|
||||
GLint maxClipDistances = 0;
|
||||
// The cull half of the same extension, and the same "zero is a legal answer" rule: a cull
|
||||
// distance discards the whole primitive, so promising eight on a driver that has none does
|
||||
// not fail loudly, it drops every draw of a culling program.
|
||||
GLint maxCullDistances = 0;
|
||||
GLint maxCombinedClipAndCullDistances = 0;
|
||||
GLint maxViewports = 16;
|
||||
// GL_UNDEFINED_VERTEX is what stands when the probes below cannot run, and it is a legal
|
||||
// answer rather than a placeholder: with neither geometry shaders nor a viewport array
|
||||
@@ -1333,6 +1338,23 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
"rejected; reporting no clip distances");
|
||||
maxClipDistances = 0;
|
||||
}
|
||||
// GL_MAX_CULL_DISTANCES_EXT (0x82F9) and GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT
|
||||
// (0x82FA) are the same tokens as their desktop spellings and arrive with the same
|
||||
// extension, so they are probed under the same guard and the same drain sandwich.
|
||||
drainErrors();
|
||||
glesFuncs.glGetIntegerv(GL_MAX_CULL_DISTANCES, &maxCullDistances);
|
||||
if (drainErrors()) {
|
||||
MGLOG_W("GL_EXT_clip_cull_distance is advertised but GL_MAX_CULL_DISTANCES was "
|
||||
"rejected; reporting no cull distances");
|
||||
maxCullDistances = 0;
|
||||
}
|
||||
drainErrors();
|
||||
glesFuncs.glGetIntegerv(GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES, &maxCombinedClipAndCullDistances);
|
||||
if (drainErrors()) {
|
||||
MGLOG_W("GL_EXT_clip_cull_distance is advertised but "
|
||||
"GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES was rejected; deriving it from the pair");
|
||||
maxCombinedClipAndCullDistances = 0;
|
||||
}
|
||||
}
|
||||
glesFuncs.glGetIntegerv(GL_MAX_VIEWPORT_DIMS, maxViewportDims);
|
||||
// GL_LAYER_PROVOKING_VERTEX is ES 3.2 core (it arrives with geometry shaders, which is
|
||||
@@ -1562,6 +1584,14 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
// A driver is free to write nonsense into an out-param it then rejects, and without the
|
||||
// extension the probe above never ran at all - so the flag, not the local, decides.
|
||||
caps.MaxClipDistances = caps.SupportsClipDistance ? std::max(maxClipDistances, 0) : 0;
|
||||
caps.MaxCullDistances = caps.SupportsClipDistance ? std::max(maxCullDistances, 0) : 0;
|
||||
// The combined limit can never be smaller than either half (GL 4.6 core 11.1.3.10 / the
|
||||
// EXT spec say so), so a driver that rejected the combined query but answered the other
|
||||
// two still gets a usable - and never over-stated - number.
|
||||
caps.MaxCombinedClipAndCullDistances =
|
||||
caps.SupportsClipDistance
|
||||
? std::max({maxCombinedClipAndCullDistances, caps.MaxClipDistances, caps.MaxCullDistances})
|
||||
: 0;
|
||||
caps.MaxViewports = maxViewports;
|
||||
caps.LayerProvokingVertex = layerProvokingVertex;
|
||||
caps.ViewportIndexProvokingVertex = viewportIndexProvokingVertex;
|
||||
@@ -1651,6 +1681,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
// and "this driver has no clip distances".
|
||||
MGLOG_I(" GL_MAX_CLIP_DISTANCES: %d%s", caps.MaxClipDistances,
|
||||
caps.SupportsClipDistance ? "" : " (no GL_EXT_clip_cull_distance on this driver)");
|
||||
MGLOG_I(" GL_MAX_CULL_DISTANCES: %d", caps.MaxCullDistances);
|
||||
MGLOG_I(" GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES: %d", caps.MaxCombinedClipAndCullDistances);
|
||||
MGLOG_I(" GL_MAX_VIEWPORTS: %d", caps.MaxViewports);
|
||||
MGLOG_I(" GL_MAX_VIEWPORT_DIMS: [%d, %d]", caps.MaxViewportWidth, caps.MaxViewportHeight);
|
||||
MGLOG_I(" GL_VIEWPORT_BOUNDS_RANGE: [%.3f, %.3f]", caps.ViewportBoundsRangeMin,
|
||||
|
||||
@@ -1299,6 +1299,11 @@ namespace MobileGL {
|
||||
// GL_EXT_clip_cull_distance, so a driver without it has none. See the guarded probe
|
||||
// in FillInGLESCapabilities.
|
||||
Int MaxClipDistances = 0;
|
||||
// Same contract, same reason, same extension: GL_MAX_CULL_DISTANCES_EXT and
|
||||
// GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT exist in ES only under
|
||||
// GL_EXT_clip_cull_distance, so zero is the honest answer without it.
|
||||
Int MaxCullDistances = 0;
|
||||
Int MaxCombinedClipAndCullDistances = 0;
|
||||
Int MaxViewports = 16;
|
||||
// GL_LAYER_PROVOKING_VERTEX (ES 3.2 core) and GL_VIEWPORT_INDEX_PROVOKING_VERTEX
|
||||
// (GL_OES_viewport_array). GL_UNDEFINED_VERTEX is a legal answer for both and is what
|
||||
|
||||
@@ -199,6 +199,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.MaxDrawBuffers = SaturateToInt(p.limits.maxFragmentOutputAttachments);
|
||||
caps.MaxColorAttachments = SaturateToInt(p.limits.maxColorAttachments);
|
||||
caps.MaxClipDistances = SaturateToInt(p.limits.maxClipDistances);
|
||||
caps.MaxCullDistances = SaturateToInt(p.limits.maxCullDistances);
|
||||
caps.MaxCombinedClipAndCullDistances = SaturateToInt(p.limits.maxCombinedClipAndCullDistances);
|
||||
caps.MaxViewports = SaturateToInt(p.limits.maxViewports);
|
||||
caps.MaxViewportWidth = SaturateToInt(p.limits.maxViewportDimensions[0]);
|
||||
caps.MaxViewportHeight = SaturateToInt(p.limits.maxViewportDimensions[1]);
|
||||
@@ -239,6 +241,7 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.SupportsFragmentStoresAndAtomics = supportedFeatures.fragmentStoresAndAtomics == VK_TRUE;
|
||||
caps.SupportsGeometryShader = supportedFeatures.geometryShader == VK_TRUE;
|
||||
caps.SupportsShaderClipDistance = supportedFeatures.shaderClipDistance == VK_TRUE;
|
||||
caps.SupportsShaderCullDistance = supportedFeatures.shaderCullDistance == VK_TRUE;
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(p.limits.maxStorageBufferRange);
|
||||
const Bool supportsShaderSubgroup = vk.vkGetPhysicalDeviceProperties2 &&
|
||||
HasUsableShaderSubgroupSupport(subgroupProps);
|
||||
@@ -319,6 +322,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.MaxDrawBuffers = SaturateToInt(properties.limits.maxFragmentOutputAttachments);
|
||||
caps.MaxColorAttachments = SaturateToInt(properties.limits.maxColorAttachments);
|
||||
caps.MaxClipDistances = SaturateToInt(properties.limits.maxClipDistances);
|
||||
caps.MaxCullDistances = SaturateToInt(properties.limits.maxCullDistances);
|
||||
caps.MaxCombinedClipAndCullDistances = SaturateToInt(properties.limits.maxCombinedClipAndCullDistances);
|
||||
caps.MaxViewports = SaturateToInt(properties.limits.maxViewports);
|
||||
caps.MaxViewportWidth = SaturateToInt(properties.limits.maxViewportDimensions[0]);
|
||||
caps.MaxViewportHeight = SaturateToInt(properties.limits.maxViewportDimensions[1]);
|
||||
@@ -336,6 +341,7 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.SupportsFragmentStoresAndAtomics = false;
|
||||
caps.SupportsGeometryShader = false;
|
||||
caps.SupportsShaderClipDistance = false;
|
||||
caps.SupportsShaderCullDistance = false;
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(properties.limits.maxStorageBufferRange);
|
||||
caps.SupportsShaderSubgroup = false;
|
||||
caps.SubgroupSize = 0;
|
||||
|
||||
@@ -68,6 +68,11 @@ namespace MobileGL {
|
||||
Int MaxDrawBuffers = 8;
|
||||
Int MaxColorAttachments = 8;
|
||||
Int MaxClipDistances = 8;
|
||||
// VkPhysicalDeviceLimits::maxCullDistances / maxCombinedClipAndCullDistances, gated
|
||||
// by SupportsShaderCullDistance exactly as the clip pair is gated by
|
||||
// SupportsShaderClipDistance.
|
||||
Int MaxCullDistances = 8;
|
||||
Int MaxCombinedClipAndCullDistances = 8;
|
||||
Int MaxViewports = 16;
|
||||
Int MaxViewportWidth = 16384;
|
||||
Int MaxViewportHeight = 16384;
|
||||
@@ -106,6 +111,11 @@ namespace MobileGL {
|
||||
// device has it, and without it a shader writing gl_ClipDistance is invalid. Very
|
||||
// widely supported, hence read from the device features and never assumed false.
|
||||
Bool SupportsShaderClipDistance = false;
|
||||
// VkPhysicalDeviceFeatures::shaderCullDistance, the same story one field down:
|
||||
// VulkanRenderer already ENABLES this feature where the device has it, but nobody
|
||||
// ever read the limits it unlocks, so the frontend advertised eight cull distances
|
||||
// from a literal instead of from the device.
|
||||
Bool SupportsShaderCullDistance = false;
|
||||
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
|
||||
Bool SupportsShaderSubgroup = false;
|
||||
Uint32 SubgroupSize = 0;
|
||||
|
||||
@@ -23,6 +23,13 @@ namespace MobileGL::MG_Util::ShaderTranspiler {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Int ResolveMaxVertexAttribs(const Bool hasBackend, const Int backendMaxVertexAttribs) {
|
||||
constexpr Int capacity = static_cast<Int>(MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS);
|
||||
if (!hasBackend) return capacity;
|
||||
if (backendMaxVertexAttribs <= 0) return capacity;
|
||||
return std::min(backendMaxVertexAttribs, capacity);
|
||||
}
|
||||
|
||||
Uint64 ComputeCompileEnvFingerprint(const CompileEnv& env) {
|
||||
Uint64 state = 0x9e3779b97f4a7c15ull;
|
||||
HashValue(state, env.maxComputeWorkGroupSize[0]);
|
||||
@@ -67,6 +74,24 @@ namespace MobileGL::MG_Util::ShaderTranspiler {
|
||||
// and expands gl_MaxClipDistances from the same number, so it decides both whether a
|
||||
// shader compiles at all and what a module that reads the constant generates.
|
||||
HashValue(state, env.params.MaxClipDistances);
|
||||
// The cull-distance pair, added when the GL 4.6 API-surface wave made them env-derived:
|
||||
// they were bare literals (8/8) in BuildTBuiltInResource while no backend had ever been
|
||||
// asked whether it can host a cull distance. Exactly the MaxClipDistances class - glslang
|
||||
// bounds gl_CullDistance[i] against maxCullDistances at parse and expands
|
||||
// gl_MaxCullDistances / gl_MaxCombinedClipAndCullDistances from the same numbers.
|
||||
HashValue(state, env.params.MaxCullDistances);
|
||||
HashValue(state, env.params.MaxCombinedClipAndCullDistances);
|
||||
// The texture-image-unit family, made env-derived in the same wave. They were stock
|
||||
// glslang defaults (32/32/80) that disagreed with what glGetIntegerv answered, and
|
||||
// gl_MaxTextureImageUnits / gl_MaxVertexTextureImageUnits / gl_MaxCombinedTextureImageUnits
|
||||
// expand from them.
|
||||
HashValue(state, env.params.MaxTextureImageUnits);
|
||||
HashValue(state, env.params.MaxVertexTextureImageUnits);
|
||||
HashValue(state, env.params.MaxCombinedTextureImageUnits);
|
||||
// gl_MaxSamples, which also sizes gl_SampleMask[] / gl_SampleMaskIn[] and bounds a
|
||||
// constant index into them, so a module that touches either generates different SPIR-V
|
||||
// on two backends that report different sample counts.
|
||||
HashValue(state, env.params.MaxSamples);
|
||||
// The compute work-group limits, likewise added by wave3 (cb155c5b). They used to be
|
||||
// hardcoded maxima in BuildTBuiltInResource, and the L1 key comment said in so many
|
||||
// words that the day they became backend-derived they would have to move in here -
|
||||
|
||||
@@ -84,11 +84,14 @@ namespace MobileGL::MG_Util::ShaderTranspiler {
|
||||
// * the DynamicBackendParameters fields BuildTBuiltInResource copies into
|
||||
// TBuiltInResource - MaxImageUnits, MaxDrawBuffers, MaxVertexImageUniforms,
|
||||
// MaxGeometryImageUniforms, MaxFragmentImageUniforms, MaxComputeImageUniforms,
|
||||
// MaxCombinedImageUniforms, MaxComputeTextureImageUnits, MaxClipDistances. glslang
|
||||
// MaxCombinedImageUniforms, MaxComputeTextureImageUnits, MaxClipDistances,
|
||||
// MaxCullDistances, MaxCombinedClipAndCullDistances, MaxTextureImageUnits,
|
||||
// MaxVertexTextureImageUnits, MaxCombinedTextureImageUnits, MaxSamples. glslang
|
||||
// enforces those at parse, so they decide whether a shader compiles at all and can
|
||||
// change the link result. MaxClipDistances moved in at the wave4 merge (4fc3531d),
|
||||
// the third time in three waves that a hardcoded TBuiltInResource field became
|
||||
// env-derived - assume the next wave does it again and re-audit.
|
||||
// change the link result. MaxClipDistances moved in at the wave4 merge (4fc3531d)
|
||||
// and the six after it at the GL 4.6 API-surface wave - the fourth time in four
|
||||
// waves that a hardcoded TBuiltInResource field became env-derived. Assume the next
|
||||
// wave does it again and re-audit.
|
||||
// * maxComputeWorkGroupSize and maxComputeWorkGroupCount, all three components each.
|
||||
// These moved IN at the dev merge that brought wave3's cb155c5b, which made
|
||||
// BuildTBuiltInResource read them from the env instead of hardcoding a permissive
|
||||
@@ -160,6 +163,18 @@ namespace MobileGL::MG_Util::ShaderTranspiler {
|
||||
}
|
||||
};
|
||||
|
||||
// How many vertex input locations exist, from the frontend's point of view: the backend's
|
||||
// advertised count bounded by the state layer's current-value storage capacity
|
||||
// (VertexArrayObject::MAX_VERTEX_ATTRIBS). ONE definition, because three places have to
|
||||
// agree on it and used to carry three copies of the formula - glGetIntegerv
|
||||
// (VertexArrayImpl::GetMaxVertexAttribs), the limit reflection records vertex inputs
|
||||
// against (ProgramLinkTask), and gl_MaxVertexAttribs (BuildTBuiltInResource, which had a
|
||||
// hardcoded 64 the other two never saw). A disagreement there is not cosmetic: glslang
|
||||
// ACCEPTS a vertex input at a location the runtime cannot bind, and the draw then silently
|
||||
// reads nothing. `hasBackend` false means "no backend to be bounded by" and yields the
|
||||
// storage capacity, matching what all three did before.
|
||||
Int ResolveMaxVertexAttribs(Bool hasBackend, Int backendMaxVertexAttribs);
|
||||
|
||||
// Hashes every semantically relevant member. Public so a test can assert that two
|
||||
// different envs really do produce different P0b cache keys.
|
||||
Uint64 ComputeCompileEnvFingerprint(const CompileEnv& env);
|
||||
|
||||
@@ -101,16 +101,11 @@ namespace MobileGL {
|
||||
Resources.maxClipPlanes = 6;
|
||||
Resources.maxTextureUnits = 32;
|
||||
Resources.maxTextureCoords = 32;
|
||||
Resources.maxVertexAttribs = 64;
|
||||
Resources.maxVertexUniformComponents = 4096;
|
||||
Resources.maxVaryingFloats = 64;
|
||||
Resources.maxVertexTextureImageUnits = 32;
|
||||
Resources.maxCombinedTextureImageUnits = 80;
|
||||
Resources.maxTextureImageUnits = 32;
|
||||
Resources.maxVertexUniformComponents = MAX_VERTEX_UNIFORM_COMPONENTS;
|
||||
Resources.maxVaryingFloats = MAX_VARYING_COMPONENTS;
|
||||
Resources.maxFragmentUniformComponents = 4096;
|
||||
Resources.maxDrawBuffers = 32;
|
||||
Resources.maxVertexUniformVectors = 128;
|
||||
Resources.maxVaryingVectors = 8;
|
||||
Resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
|
||||
Resources.maxVaryingVectors = MAX_VARYING_VECTORS;
|
||||
Resources.maxFragmentUniformVectors = 256;
|
||||
Resources.maxVertexOutputVectors = 16;
|
||||
Resources.maxFragmentInputVectors = 15;
|
||||
@@ -121,14 +116,12 @@ namespace MobileGL {
|
||||
Resources.maxComputeImageUniforms = 8;
|
||||
Resources.maxComputeAtomicCounters = MAX_ATOMIC_COUNTERS_PER_STAGE;
|
||||
Resources.maxComputeAtomicCounterBuffers = MAX_ATOMIC_COUNTER_BUFFERS_PER_STAGE;
|
||||
Resources.maxVaryingComponents = 60;
|
||||
Resources.maxVaryingComponents = MAX_VARYING_COMPONENTS;
|
||||
Resources.maxVertexOutputComponents = 64;
|
||||
Resources.maxGeometryInputComponents = 64;
|
||||
Resources.maxGeometryOutputComponents = 128;
|
||||
Resources.maxFragmentInputComponents = 128;
|
||||
Resources.maxImageUnits = 8;
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs = 8;
|
||||
Resources.maxCombinedShaderOutputResources = 8;
|
||||
Resources.maxImageSamples = 0;
|
||||
Resources.maxVertexImageUniforms = 0;
|
||||
Resources.maxTessControlImageUniforms = 0;
|
||||
@@ -141,16 +134,18 @@ namespace MobileGL {
|
||||
Resources.maxGeometryTotalOutputComponents = 1024;
|
||||
Resources.maxGeometryUniformComponents = 1024;
|
||||
Resources.maxGeometryVaryingComponents = 64;
|
||||
Resources.maxTessControlInputComponents = 128;
|
||||
Resources.maxTessControlOutputComponents = 128;
|
||||
Resources.maxTessControlTextureImageUnits = 16;
|
||||
Resources.maxTessControlUniformComponents = 1024;
|
||||
Resources.maxTessControlTotalOutputComponents = 4096;
|
||||
Resources.maxTessEvaluationInputComponents = 128;
|
||||
Resources.maxTessEvaluationOutputComponents = 128;
|
||||
Resources.maxTessEvaluationTextureImageUnits = 16;
|
||||
Resources.maxTessEvaluationUniformComponents = 1024;
|
||||
Resources.maxTessPatchComponents = 120;
|
||||
// The tessellation block is shared with glGetIntegerv through Types.h; see the
|
||||
// "Never move one of these without the other" note there.
|
||||
Resources.maxTessControlInputComponents = MAX_TESS_CONTROL_INPUT_COMPONENTS;
|
||||
Resources.maxTessControlOutputComponents = MAX_TESS_CONTROL_OUTPUT_COMPONENTS;
|
||||
Resources.maxTessControlTextureImageUnits = MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS;
|
||||
Resources.maxTessControlUniformComponents = MAX_TESS_CONTROL_UNIFORM_COMPONENTS;
|
||||
Resources.maxTessControlTotalOutputComponents = MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS;
|
||||
Resources.maxTessEvaluationInputComponents = MAX_TESS_EVALUATION_INPUT_COMPONENTS;
|
||||
Resources.maxTessEvaluationOutputComponents = MAX_TESS_EVALUATION_OUTPUT_COMPONENTS;
|
||||
Resources.maxTessEvaluationTextureImageUnits = MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS;
|
||||
Resources.maxTessEvaluationUniformComponents = MAX_TESS_EVALUATION_UNIFORM_COMPONENTS;
|
||||
Resources.maxTessPatchComponents = MAX_TESS_PATCH_COMPONENTS;
|
||||
Resources.maxPatchVertices = 32;
|
||||
Resources.maxTessGenLevel = 64;
|
||||
Resources.maxViewports = 16;
|
||||
@@ -176,9 +171,6 @@ namespace MobileGL {
|
||||
Resources.maxAtomicCounterBufferSize = MAX_ATOMIC_COUNTER_BUFFER_SIZE;
|
||||
Resources.maxTransformFeedbackBuffers = 4;
|
||||
Resources.maxTransformFeedbackInterleavedComponents = 64;
|
||||
Resources.maxCullDistances = 8;
|
||||
Resources.maxCombinedClipAndCullDistances = 8;
|
||||
Resources.maxSamples = 4;
|
||||
Resources.maxMeshOutputVerticesNV = 256;
|
||||
Resources.maxMeshOutputPrimitivesNV = 512;
|
||||
Resources.maxMeshWorkGroupSizeX_NV = 32;
|
||||
@@ -208,12 +200,37 @@ namespace MobileGL {
|
||||
Resources.maxImageUnits = dynamicParameters.MaxImageUnits;
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs =
|
||||
dynamicParameters.MaxImageUnits + dynamicParameters.MaxDrawBuffers;
|
||||
// GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES and
|
||||
// GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS are the SAME token (0x8F39), so
|
||||
// the two glslang fields have to carry the same value: glGetIntegerv answers this
|
||||
// expression while gl_MaxCombinedShaderOutputResources expanded from a stale
|
||||
// literal 8, and the CTS compares the two directly.
|
||||
Resources.maxCombinedShaderOutputResources =
|
||||
Resources.maxCombinedImageUnitsAndFragmentOutputs;
|
||||
Resources.maxVertexImageUniforms = dynamicParameters.MaxVertexImageUniforms;
|
||||
Resources.maxGeometryImageUniforms = dynamicParameters.MaxGeometryImageUniforms;
|
||||
Resources.maxFragmentImageUniforms = dynamicParameters.MaxFragmentImageUniforms;
|
||||
Resources.maxComputeImageUniforms = dynamicParameters.MaxComputeImageUniforms;
|
||||
Resources.maxCombinedImageUniforms = dynamicParameters.MaxCombinedImageUniforms;
|
||||
Resources.maxComputeTextureImageUnits = dynamicParameters.MaxComputeTextureImageUnits;
|
||||
// The texture-image-unit family and the draw-buffer count. These were stock
|
||||
// glslang defaults (32 / 32 / 80 / 32) that had nothing to do with what
|
||||
// glGetIntegerv answers off the same backend, and the divergence is a live
|
||||
// correctness bug rather than a reporting one: gl_MaxDrawBuffers = 32 makes
|
||||
// glslang ACCEPT a fragment output at location 8..31 that the runtime cannot
|
||||
// bind, and gl_MaxCombinedTextureImageUnits = 80 under-reports a device that
|
||||
// really has 96.
|
||||
Resources.maxTextureImageUnits = dynamicParameters.MaxTextureImageUnits;
|
||||
Resources.maxVertexTextureImageUnits = dynamicParameters.MaxVertexTextureImageUnits;
|
||||
Resources.maxCombinedTextureImageUnits = dynamicParameters.MaxCombinedTextureImageUnits;
|
||||
Resources.maxDrawBuffers = dynamicParameters.MaxDrawBuffers;
|
||||
// The same number glGetIntegerv(GL_MAX_VERTEX_ATTRIBS) reports and the same one
|
||||
// reflection records vertex inputs against - see ResolveMaxVertexAttribs.
|
||||
Resources.maxVertexAttribs = ResolveMaxVertexAttribs(
|
||||
env ? env->HasBackend() : (activeBackend != nullptr), dynamicParameters.MaxVertexAttribs);
|
||||
// gl_MaxSamples, floored exactly as GL_Getter::GetAdvertisedMaxSamples floors
|
||||
// GL_MAX_SAMPLES. It also sizes gl_SampleMask[] / gl_SampleMaskIn[].
|
||||
Resources.maxSamples = std::max(dynamicParameters.MaxSamples, MIN_ADVERTISED_MAX_SAMPLES);
|
||||
// Load-bearing, not cosmetic. glslang rejects gl_ClipDistance[i] for
|
||||
// i >= maxClipDistances (ParseHelper.cpp) and expands gl_MaxClipDistances from the
|
||||
// same number, so tracking the backend limit is what turns "the program links,
|
||||
@@ -222,6 +239,14 @@ namespace MobileGL {
|
||||
// also what makes glGetIntegerv(GL_MAX_CLIP_DISTANCES) and gl_MaxClipDistances
|
||||
// agree, which KHR-GLxx.clip_distance.coverage compares directly.
|
||||
Resources.maxClipDistances = dynamicParameters.MaxClipDistances;
|
||||
// The cull pair, for the same reason and with a sharper edge: cull distance
|
||||
// discards the WHOLE primitive, so a shader that gets to declare gl_CullDistance
|
||||
// on a backend that cannot host one does not render subtly wrong pixels, it
|
||||
// renders nothing at all. These were literal 8s that no backend was ever asked
|
||||
// about; a backend without cull distances now reports 0 and glslang rejects the
|
||||
// declaration with a diagnostic the application can read.
|
||||
Resources.maxCullDistances = dynamicParameters.MaxCullDistances;
|
||||
Resources.maxCombinedClipAndCullDistances = dynamicParameters.MaxCombinedClipAndCullDistances;
|
||||
|
||||
// The compute work-group limits are the env's, not the backend parameters': they
|
||||
// are the only ones that come from a REAL indexed driver query, which
|
||||
|
||||
@@ -80,6 +80,53 @@ namespace MobileGL {
|
||||
inline constexpr Int MAX_ATOMIC_COUNTER_BUFFERS_PER_STAGE = 8;
|
||||
inline constexpr Int MAX_ATOMIC_COUNTERS_PER_STAGE = 8;
|
||||
|
||||
// ---- Tessellation per-stage resource limits ----
|
||||
//
|
||||
// Here for exactly the reason the atomic-counter block above is here. GL 4.6 requires
|
||||
// glGetIntegerv and the matching gl_MaxTess* built-in constant to report the same
|
||||
// number (KHR-GL45.limits.max_tess_* reads the query and then compiles a shader that
|
||||
// writes the built-in into an SSBO and demands equality), and these numbers used to
|
||||
// exist ONLY inside BuildTBuiltInResource - so gl_MaxTessControlInputComponents
|
||||
// compiled fine while glGetIntegerv of the same limit had no case at all and answered
|
||||
// GL_INVALID_ENUM. Never move one of these without the other.
|
||||
//
|
||||
// The values are the GL 4.6 core minimums (table 23.55), which is what a frontend that
|
||||
// synthesizes the tessellation stages onto ES/Vulkan can honestly promise.
|
||||
inline constexpr Int MAX_TESS_CONTROL_INPUT_COMPONENTS = 128;
|
||||
inline constexpr Int MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 128;
|
||||
inline constexpr Int MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 16;
|
||||
inline constexpr Int MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 1024;
|
||||
inline constexpr Int MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 4096;
|
||||
inline constexpr Int MAX_TESS_EVALUATION_INPUT_COMPONENTS = 128;
|
||||
inline constexpr Int MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 128;
|
||||
inline constexpr Int MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 16;
|
||||
inline constexpr Int MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 1024;
|
||||
inline constexpr Int MAX_TESS_PATCH_COMPONENTS = 120;
|
||||
|
||||
// ---- Varying and default-block uniform capacities ----
|
||||
//
|
||||
// The *_VECTORS limits are the *_COMPONENTS ones counted in vec4s, so they are DERIVED
|
||||
// rather than typed independently: GL_MAX_VARYING_COMPONENTS said 64 while
|
||||
// GL_MAX_VARYING_VECTORS said 8, and GL_MAX_VERTEX_UNIFORM_COMPONENTS said 4096 while
|
||||
// GL_MAX_VERTEX_UNIFORM_VECTORS said 128 - two pairs that cannot both describe the
|
||||
// same capacity, and both *_VECTORS answers were below the GL 4.5 core minimum
|
||||
// (15 and 256 respectively). Shared with BuildTBuiltInResource because
|
||||
// gl_MaxVaryingVectors and gl_MaxVertexUniformVectors expand from the same numbers.
|
||||
inline constexpr Int MAX_VARYING_COMPONENTS = 64;
|
||||
inline constexpr Int MAX_VARYING_VECTORS = MAX_VARYING_COMPONENTS / 4;
|
||||
inline constexpr Int MAX_VERTEX_UNIFORM_COMPONENTS = 4096;
|
||||
inline constexpr Int MAX_VERTEX_UNIFORM_VECTORS = MAX_VERTEX_UNIFORM_COMPONENTS / 4;
|
||||
|
||||
// GL 4.6 core table 23.53 sets the GL_MAX_SAMPLES minimum at 4, and MobileGL floors
|
||||
// the backend's answer at it (GL_Getter's GetAdvertisedMaxSamples). gl_MaxSamples has
|
||||
// to expand to the SAME number - it is also what sizes gl_SampleMask[] /
|
||||
// gl_SampleMaskIn[] and what bounds a constant index into them - so the floor lives
|
||||
// here and both sides apply it. NOTE the deliberate asymmetry: only MAX_SAMPLES has a
|
||||
// floor of 4. MAX_INTEGER_SAMPLES, MAX_COLOR_TEXTURE_SAMPLES and
|
||||
// MAX_DEPTH_TEXTURE_SAMPLES have a minimum of ONE in the same table and are reported
|
||||
// as the backend probed them.
|
||||
inline constexpr Int MIN_ADVERTISED_MAX_SAMPLES = 4;
|
||||
|
||||
struct EmptyType {};
|
||||
|
||||
enum class ShaderCompileBits : Uint {
|
||||
|
||||
Reference in New Issue
Block a user