[Feat] (GL): advertise ARB_cull_distance where the backend has cull distances

This commit is contained in:
2026-10-12 08:10:50 -04:00
parent 454083bf57
commit c83d27a668
4 changed files with 39 additions and 2 deletions
+4
View File
@@ -316,6 +316,10 @@ namespace MobileGL {
struct AdvertisedFeatureSupport {
// ES 3.2 or GL_EXT_tessellation_shader; VkPhysicalDeviceFeatures::tessellationShader.
Bool TessellationShader = false;
// At least one cull distance: GL_EXT_clip_cull_distance with a non-zero
// GL_MAX_CULL_DISTANCES; VkPhysicalDeviceFeatures::shaderCullDistance with a non-zero
// maxCullDistances.
Bool CullDistance = false;
};
// Coarse GPU vendor identity for gating device-specific quirks. Detected from the
@@ -842,7 +842,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
capabilities.SupportsDrawIndirect,
capabilities.SupportsDrawIndirect && capabilities.SupportsBaseInstance,
capabilities.SupportsTextureView, capabilities.SupportsTextureCubeMapArray,
AdvertisedFeatureSupport{.TessellationShader = capabilities.SupportsTessellationShader});
AdvertisedFeatureSupport{.TessellationShader = capabilities.SupportsTessellationShader,
.CullDistance = capabilities.MaxCullDistances > 0});
// Exactly what InitCapabilities forwards into the dynamic parameters: the base
// extension and _primitive when the driver has them, _attachment not yet.
auto& extensions = MutableRendererInfo().RendererGLInfo.Extensions;
@@ -1523,6 +1524,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
if (features.TessellationShader) {
extensions.push_back(E_GL_ARB_tessellation_shader);
}
// gl_CullDistance goes through GL_EXT_clip_cull_distance, whose cull half the loader only
// reports where the driver answers a non-zero GL_MAX_CULL_DISTANCES.
if (features.CullDistance) {
extensions.push_back(E_GL_ARB_cull_distance);
}
// Minecraft 26.3 checks this prerequisite before it even considers
// GL_ARB_multi_draw_indirect. ES 3.1 supplies both single-draw entry points; the loader
// folds the version and pointer checks into SupportsDrawIndirect.
@@ -925,6 +925,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (features.TessellationShader) {
extensions.push_back(E_GL_ARB_tessellation_shader);
}
// Follows the shaderCullDistance device feature, the same gate GL_MAX_CULL_DISTANCES uses.
if (features.CullDistance) {
extensions.push_back(E_GL_ARB_cull_distance);
}
// Vulkan's drawIndirectFirstInstance feature is optional. Direct base-instance calls work
// without it, but ARB_base_instance also promises non-zero firstInstance in GPU indirect
// commands; the renderer supplies true only when that word is legal and gl_InstanceID can
@@ -1106,7 +1110,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
pVulkanRenderer && pVulkanRenderer->IsSamplerAnisotropySupported(),
pVulkanRenderer && pVulkanRenderer->IsNonZeroIndirectBaseInstanceSupported(),
m_vulkanCaps.SupportsImageCubeArray,
AdvertisedFeatureSupport{.TessellationShader = m_vulkanCaps.SupportsTessellationShader});
AdvertisedFeatureSupport{.TessellationShader = m_vulkanCaps.SupportsTessellationShader,
.CullDistance = m_vulkanCaps.SupportsShaderCullDistance &&
m_vulkanCaps.MaxCullDistances > 0});
// GL_EXT_fragment_shading_rate rides on VK_KHR_fragment_shading_rate's pipeline rate, and
// its _primitive companion on the primitive rate; both only when the renderer enabled them.
// _attachment is not advertised: no framebuffer carries a rate attachment to this backend.
@@ -1281,6 +1281,27 @@ TEST(CoreSurfaceAdvertisement, BatchIsUnconditionalAndTessellationFollowsTheDevi
MobileGL::E_GL_ARB_tessellation_shader));
}
// ARB_cull_distance follows the backend's cull-distance capability, never the context version.
TEST(CoreSurfaceAdvertisement, CullDistanceFollowsTheDevice) {
const auto contains = [](const MobileGL::Vector<MobileGL::GLExtension>& extensions,
MobileGL::GLExtension wanted) {
return std::find(extensions.begin(), extensions.end(), wanted) != extensions.end();
};
EXPECT_FALSE(contains(MobileGL::MG_Backend::DirectGLES::BuildAdvertisedExtensions(false, false, false, false,
false, false),
MobileGL::E_GL_ARB_cull_distance));
EXPECT_FALSE(contains(MobileGL::MG_Backend::DirectVulkan::BuildAdvertisedExtensions(false, false, false, false,
false),
MobileGL::E_GL_ARB_cull_distance));
const MobileGL::MG_Backend::AdvertisedFeatureSupport cull{.CullDistance = true};
EXPECT_TRUE(contains(MobileGL::MG_Backend::DirectGLES::BuildAdvertisedExtensions(false, false, false, false,
false, false, cull),
MobileGL::E_GL_ARB_cull_distance));
EXPECT_TRUE(contains(MobileGL::MG_Backend::DirectVulkan::BuildAdvertisedExtensions(false, false, false, false,
false, cull),
MobileGL::E_GL_ARB_cull_distance));
}
// ES 3.2 has tessellation in core; ES 3.1 only through GL_EXT_tessellation_shader. Either way the
// patch-size entry point has to have resolved.
TEST(TessellationCapabilities, FollowTheVersionOrTheExtension) {