mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Feat] (MG_Config, MG_Util): a preference knob and POST rows for Magma's multi-draw tiers
MOBILEGL_MAGMA_MULTIDRAW_MODE=ext|indirect|unroll|auto selects the DirectVulkan multi-draw dispatch tier, clamped to what the device supports with one INFO line when it falls back; auto (and unset) picks the best supported tier. Invalid values keep auto. Magma-only: the variable has no effect on DirectGLES. Note for the escape hatch: mode=unroll also forces the GL indirect multi-draw paths onto their per-command loop, where gl_DrawID reads 0 for every sub-draw - Flywheel-style content that keys on flw_drawId renders accordingly. Three DriverPost rows per the POST rule: VK_EXT_multi_draw (PASS/INFO), the multiDrawIndirect feature (WARN downgraded to INFO - there is always a fallback tier), and the resolved dispatch tier with the full chain. drawIndirectFirstInstance gains a row too, since the indirect tier's legality check now relies on it.
This commit is contained in:
@@ -29,6 +29,16 @@ namespace MobileGL::MG_Config {
|
|||||||
ForceOff,
|
ForceOff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Preferred DirectVulkan dispatch tier for the glMultiDraw* families. A preference,
|
||||||
|
// never a demand: the renderer clamps it to what the device supports at device
|
||||||
|
// creation, falling down the chain ext -> indirect -> unroll with one log line.
|
||||||
|
enum class MultiDrawMode : Uint8 {
|
||||||
|
Auto = 0, // unset: best supported tier
|
||||||
|
Ext, // VK_EXT_multi_draw: one vkCmdDrawMultiEXT / vkCmdDrawMultiIndexedEXT
|
||||||
|
Indirect, // multiDrawIndirect feature: one vkCmdDraw*Indirect over a transient command array
|
||||||
|
Unroll, // one vkCmdDraw* per sub-draw
|
||||||
|
};
|
||||||
|
|
||||||
// Feature toggles parsed once from environment variables in MG_ConfigLoader::Init()
|
// Feature toggles parsed once from environment variables in MG_ConfigLoader::Init()
|
||||||
// (ConfigLoader.cpp), before the accepted-env map is destroyed. All Bool fields share
|
// (ConfigLoader.cpp), before the accepted-env map is destroyed. All Bool fields share
|
||||||
// one truthy rule: the variable is set, non-empty, not "0", and not "false"
|
// one truthy rule: the variable is set, non-empty, not "0", and not "false"
|
||||||
@@ -91,6 +101,10 @@ namespace MobileGL::MG_Config {
|
|||||||
// feature off. It is enabled by default to match GL's defined out-of-range fetch
|
// feature off. It is enabled by default to match GL's defined out-of-range fetch
|
||||||
// behavior; this escape hatch exists to measure or dodge its GPU cost on a device.
|
// behavior; this escape hatch exists to measure or dodge its GPU cost on a device.
|
||||||
Bool DisableRobustBufferAccess = false;
|
Bool DisableRobustBufferAccess = false;
|
||||||
|
// MOBILEGL_MAGMA_MULTIDRAW_MODE: preferred DirectVulkan multi-draw dispatch tier
|
||||||
|
// ("ext" | "indirect" | "unroll", see MultiDrawMode). Clamped to device support;
|
||||||
|
// unset picks the best supported tier.
|
||||||
|
MultiDrawMode MagmaMultiDrawMode = MultiDrawMode::Auto;
|
||||||
};
|
};
|
||||||
extern FeaturesTable Features;
|
extern FeaturesTable Features;
|
||||||
} // namespace MobileGL::MG_Config
|
} // namespace MobileGL::MG_Config
|
||||||
|
|||||||
@@ -97,6 +97,25 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
: MG_Config::QuirkOverride::ForceOff;
|
: MG_Config::QuirkOverride::ForceOff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Multi-draw mode is a named-value preference: unset keeps Auto (best supported tier),
|
||||||
|
// a recognized name selects that tier as the ceiling, anything else warns and keeps Auto.
|
||||||
|
inline MG_Config::MultiDrawMode QueryEnvMultiDrawMode(const String& key) {
|
||||||
|
auto it = acceptedEnvVariablesMap->find(key);
|
||||||
|
if (it == acceptedEnvVariablesMap->end()) {
|
||||||
|
return MG_Config::MultiDrawMode::Auto;
|
||||||
|
}
|
||||||
|
String lowered = it->second;
|
||||||
|
std::transform(lowered.begin(), lowered.end(), lowered.begin(),
|
||||||
|
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||||
|
if (lowered == "ext") return MG_Config::MultiDrawMode::Ext;
|
||||||
|
if (lowered == "indirect") return MG_Config::MultiDrawMode::Indirect;
|
||||||
|
if (lowered == "unroll") return MG_Config::MultiDrawMode::Unroll;
|
||||||
|
if (lowered.empty() || lowered == "auto") return MG_Config::MultiDrawMode::Auto;
|
||||||
|
MGLOG_W("Config: Ignoring invalid env variable %s='%s'; expected ext|indirect|unroll|auto, using auto",
|
||||||
|
key.c_str(), it->second.c_str());
|
||||||
|
return MG_Config::MultiDrawMode::Auto;
|
||||||
|
}
|
||||||
|
|
||||||
inline Uint32 QueryEnvUint32(const String& key, Uint32 defaultValue, Uint32 minValue, Uint32 maxValue) {
|
inline Uint32 QueryEnvUint32(const String& key, Uint32 defaultValue, Uint32 minValue, Uint32 maxValue) {
|
||||||
auto it = acceptedEnvVariablesMap->find(key);
|
auto it = acceptedEnvVariablesMap->find(key);
|
||||||
if (it == acceptedEnvVariablesMap->end()) {
|
if (it == acceptedEnvVariablesMap->end()) {
|
||||||
@@ -138,6 +157,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
features.MagmaDisableBlendedDepthWriteQuirk =
|
features.MagmaDisableBlendedDepthWriteQuirk =
|
||||||
QueryEnvQuirkOverride("MOBILEGL_MAGMA_DISABLE_BLENDED_DEPTH_WRITE");
|
QueryEnvQuirkOverride("MOBILEGL_MAGMA_DISABLE_BLENDED_DEPTH_WRITE");
|
||||||
features.DisableRobustBufferAccess = QueryEnvFlag("MOBILEGL_DISABLE_ROBUST_BUFFER_ACCESS");
|
features.DisableRobustBufferAccess = QueryEnvFlag("MOBILEGL_DISABLE_ROBUST_BUFFER_ACCESS");
|
||||||
|
features.MagmaMultiDrawMode = QueryEnvMultiDrawMode("MOBILEGL_MAGMA_MULTIDRAW_MODE");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void InitBackendType() {
|
inline void InitBackendType() {
|
||||||
|
|||||||
@@ -1426,8 +1426,9 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
if (features.multiDrawIndirect == VK_TRUE) {
|
if (features.multiDrawIndirect == VK_TRUE) {
|
||||||
builder.Pass("multiDrawIndirect", "indirect multi-draw batches run as single native commands");
|
builder.Pass("multiDrawIndirect", "indirect multi-draw batches run as single native commands");
|
||||||
} else {
|
} else {
|
||||||
builder.Warn("multiDrawIndirect",
|
builder.Info("multiDrawIndirect",
|
||||||
"unsupported; indirect multi-draw batches fall back to one draw per command");
|
"unsupported; multi-draw batches fall back to one draw per command (tier "
|
||||||
|
"\"indirect\" of the multi-draw dispatch is unavailable)");
|
||||||
}
|
}
|
||||||
if (features.drawIndirectFirstInstance == VK_TRUE) {
|
if (features.drawIndirectFirstInstance == VK_TRUE) {
|
||||||
builder.Pass("drawIndirectFirstInstance", "indirect commands may carry a non-zero firstInstance");
|
builder.Pass("drawIndirectFirstInstance", "indirect commands may carry a non-zero firstInstance");
|
||||||
@@ -1435,6 +1436,42 @@ namespace MobileGL::MG_Util::SelfTest {
|
|||||||
builder.Warn("drawIndirectFirstInstance",
|
builder.Warn("drawIndirectFirstInstance",
|
||||||
"unsupported; indirect commands with a non-zero baseInstance cannot run natively");
|
"unsupported; indirect commands with a non-zero baseInstance cannot run natively");
|
||||||
}
|
}
|
||||||
|
// Multi-draw dispatch tiers (ext -> indirect -> unroll). INFO on the missing
|
||||||
|
// pieces: every tier has a fallback, nothing is lost, only batched into more
|
||||||
|
// commands. The renderer resolves the same chain at device creation, clamped
|
||||||
|
// by MOBILEGL_MAGMA_MULTIDRAW_MODE.
|
||||||
|
{
|
||||||
|
Bool multiDrawExtUsable = false;
|
||||||
|
if (HasVkExtension(deviceExtensions, VK_EXT_MULTI_DRAW_EXTENSION_NAME) &&
|
||||||
|
vkGetPhysicalDeviceFeatures2Fn != nullptr) {
|
||||||
|
VkPhysicalDeviceMultiDrawFeaturesEXT multiDrawFeatures{};
|
||||||
|
multiDrawFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT;
|
||||||
|
VkPhysicalDeviceFeatures2 features2{};
|
||||||
|
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||||
|
features2.pNext = &multiDrawFeatures;
|
||||||
|
vkGetPhysicalDeviceFeatures2Fn(physicalDevice, &features2);
|
||||||
|
multiDrawExtUsable = multiDrawFeatures.multiDraw == VK_TRUE;
|
||||||
|
}
|
||||||
|
if (multiDrawExtUsable) {
|
||||||
|
builder.Pass("VK_EXT_multi_draw",
|
||||||
|
"supported; a glMultiDraw* batch runs as one vkCmdDrawMulti(Indexed)EXT");
|
||||||
|
} else {
|
||||||
|
builder.Info("VK_EXT_multi_draw",
|
||||||
|
"unsupported; glMultiDraw* batches use the indirect or unrolled tier");
|
||||||
|
}
|
||||||
|
const char* resolvedTier = multiDrawExtUsable ? "ext"
|
||||||
|
: features.multiDrawIndirect == VK_TRUE ? "indirect"
|
||||||
|
: "unroll";
|
||||||
|
String tierDetail = format("default tier \"{}\" (chain: ext -> indirect -> unroll)", resolvedTier);
|
||||||
|
const MG_Config::MultiDrawMode multiDrawMode = MG_Config::Features.MagmaMultiDrawMode;
|
||||||
|
if (multiDrawMode != MG_Config::MultiDrawMode::Auto) {
|
||||||
|
tierDetail += format("; MOBILEGL_MAGMA_MULTIDRAW_MODE={} caps it (clamped to device support)",
|
||||||
|
multiDrawMode == MG_Config::MultiDrawMode::Ext ? "ext"
|
||||||
|
: multiDrawMode == MG_Config::MultiDrawMode::Indirect ? "indirect"
|
||||||
|
: "unroll");
|
||||||
|
}
|
||||||
|
builder.Info("Multi-draw dispatch tier", tierDetail);
|
||||||
|
}
|
||||||
if (features.vertexPipelineStoresAndAtomics == VK_TRUE) {
|
if (features.vertexPipelineStoresAndAtomics == VK_TRUE) {
|
||||||
builder.Pass("vertexPipelineStoresAndAtomics",
|
builder.Pass("vertexPipelineStoresAndAtomics",
|
||||||
"supported by driver (not currently enabled by the DirectVulkan backend)");
|
"supported by driver (not currently enabled by the DirectVulkan backend)");
|
||||||
|
|||||||
Reference in New Issue
Block a user