mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
Merge remote-tracking branch 'origin/Feat/Backend-Direct-Vulkan' into Agent/CodexAudit
# Conflicts: # MobileGL/MG_Backend/BackendObject.h # MobileGL/MG_Backend/DirectGLES/Managers.cpp # MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp # MobileGL/MG_Backend/DirectVulkan/Renderer/FrameContext.cpp # MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp # MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp # MobileGL/MG_Impl/GLImpl/Buffer/GL_Buffer.cpp # MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp # MobileGL/MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.cpp # MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp # MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.h # MobileGL/MG_Impl/GLImpl/Program/GL_Program.cpp # MobileGL/MG_Impl/GLImpl/Program/GL_Program.h # MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.cpp # MobileGL/MG_Impl/GLImpl/Sync/GL_Sync.h # MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp # MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.cpp # MobileGL/MG_Impl/GLImpl/VertexArray/GL_VertexArray.h # MobileGL/MG_State/GLState/BufferState/BufferObject.cpp # MobileGL/MG_State/GLState/BufferState/BufferObject.h # MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp # MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
|
||||
#include "Loader.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace MobileGL::MG_Util::BackendLoader {
|
||||
namespace {
|
||||
struct VulkanDynamicFunctions {
|
||||
@@ -56,6 +59,14 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
Bool IsShaderSubgroupForcedDisabled() {
|
||||
const char* value = std::getenv("MOBILEGL_DISABLE_SUBGROUP");
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(value, "true") == 0 || std::strcmp(value, "TRUE") == 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline Version DecodeApiVersion(uint32_t version) {
|
||||
@@ -69,6 +80,12 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline Bool HasUsableShaderSubgroupSupport(const VkPhysicalDeviceSubgroupProperties& subgroupProps) {
|
||||
return subgroupProps.subgroupSize > 0 &&
|
||||
(subgroupProps.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0 &&
|
||||
(subgroupProps.supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) != 0;
|
||||
}
|
||||
|
||||
Bool QueryVulkanCapabilities(MobileGL::MG_External::VulkanCapabilities& caps, VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice) {
|
||||
if (!physicalDevice) {
|
||||
@@ -92,8 +109,12 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceSubgroupProperties subgroupProps{};
|
||||
subgroupProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
|
||||
|
||||
VkPhysicalDeviceProperties2 props2{};
|
||||
props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
props2.pNext = &subgroupProps;
|
||||
if (vk.vkGetPhysicalDeviceProperties2) {
|
||||
vk.vkGetPhysicalDeviceProperties2(physicalDevice, &props2);
|
||||
} else {
|
||||
@@ -157,6 +178,29 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
VkPhysicalDeviceFeatures supportedFeatures{};
|
||||
vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures);
|
||||
caps.SupportsWideLines = supportedFeatures.wideLines == VK_TRUE;
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(p.limits.maxStorageBufferRange);
|
||||
const Bool supportsShaderSubgroup = vk.vkGetPhysicalDeviceProperties2 &&
|
||||
HasUsableShaderSubgroupSupport(subgroupProps);
|
||||
const Bool forceDisableShaderSubgroup = IsShaderSubgroupForcedDisabled();
|
||||
caps.SupportsShaderSubgroup = supportsShaderSubgroup && !forceDisableShaderSubgroup;
|
||||
if (caps.SupportsShaderSubgroup) {
|
||||
caps.SubgroupSize = subgroupProps.subgroupSize;
|
||||
caps.SubgroupSupportedStages = subgroupProps.supportedStages;
|
||||
caps.SubgroupSupportedOperations = subgroupProps.supportedOperations;
|
||||
caps.SubgroupQuadOperationsInAllStages = subgroupProps.quadOperationsInAllStages == VK_TRUE;
|
||||
} else {
|
||||
caps.SubgroupSize = 0;
|
||||
caps.SubgroupSupportedStages = 0;
|
||||
caps.SubgroupSupportedOperations = 0;
|
||||
caps.SubgroupQuadOperationsInAllStages = false;
|
||||
}
|
||||
|
||||
MGLOG_I("Vulkan shader subgroup support: detected=%s advertised=%s size=%u stages=0x%x operations=0x%x",
|
||||
supportsShaderSubgroup ? "true" : "false", caps.SupportsShaderSubgroup ? "true" : "false",
|
||||
subgroupProps.subgroupSize, subgroupProps.supportedStages, subgroupProps.supportedOperations);
|
||||
if (supportsShaderSubgroup && forceDisableShaderSubgroup) {
|
||||
MGLOG_W("Vulkan shader subgroup support forced off by MOBILEGL_DISABLE_SUBGROUP");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -215,5 +259,11 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.ViewportBoundsRangeMax = properties.limits.viewportBoundsRange[1];
|
||||
caps.ViewportSubpixelBits = static_cast<Int>(properties.limits.viewportSubPixelBits);
|
||||
caps.SupportsWideLines = false;
|
||||
caps.MaxShaderStorageBlockSize = static_cast<SizeT>(properties.limits.maxStorageBufferRange);
|
||||
caps.SupportsShaderSubgroup = false;
|
||||
caps.SubgroupSize = 0;
|
||||
caps.SubgroupSupportedStages = 0;
|
||||
caps.SubgroupSupportedOperations = 0;
|
||||
caps.SubgroupQuadOperationsInAllStages = false;
|
||||
}
|
||||
} // namespace MobileGL::MG_Util::BackendLoader
|
||||
|
||||
@@ -64,6 +64,12 @@ namespace MobileGL {
|
||||
Float ViewportBoundsRangeMax = 0.0f;
|
||||
Int ViewportSubpixelBits = 0;
|
||||
Bool SupportsWideLines = false;
|
||||
SizeT MaxShaderStorageBlockSize = 128 * 1024 * 1024;
|
||||
Bool SupportsShaderSubgroup = false;
|
||||
Uint32 SubgroupSize = 0;
|
||||
Uint32 SubgroupSupportedStages = 0;
|
||||
Uint32 SubgroupSupportedOperations = 0;
|
||||
Bool SubgroupQuadOperationsInAllStages = false;
|
||||
};
|
||||
} // namespace MG_External
|
||||
namespace MG_Util::BackendLoader {
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace MobileGL {
|
||||
return BufferTarget::DispatchIndirect;
|
||||
case GL_DRAW_INDIRECT_BUFFER:
|
||||
return BufferTarget::DrawIndirect;
|
||||
case GL_PARAMETER_BUFFER_ARB:
|
||||
return BufferTarget::Parameter;
|
||||
case GL_SHADER_STORAGE_BUFFER:
|
||||
return BufferTarget::ShaderStorage;
|
||||
case GL_UNKNOWN_MGL:
|
||||
@@ -84,4 +86,4 @@ namespace MobileGL {
|
||||
return result;
|
||||
}
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -210,6 +210,17 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
ProvokingVertexMode ConvertGLEnumToProvokingVertexMode(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_FIRST_VERTEX_CONVENTION:
|
||||
return ProvokingVertexMode::FirstVertex;
|
||||
case GL_LAST_VERTEX_CONVENTION:
|
||||
return ProvokingVertexMode::LastVertex;
|
||||
default:
|
||||
return ProvokingVertexMode::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
CapabilityInput ConvertGLEnumToCapabilityInput(GLenum v) {
|
||||
switch (v) {
|
||||
case GL_BLEND:
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace MobileGL {
|
||||
PixelStoreParam ConvertGLEnumToPixelStoreParam(GLenum value);
|
||||
CullFaceMode ConvertGLEnumToCullFaceMode(GLenum value);
|
||||
FrontFaceMode ConvertGLEnumToFrontFaceMode(GLenum value);
|
||||
ProvokingVertexMode ConvertGLEnumToProvokingVertexMode(GLenum value);
|
||||
CapabilityInput ConvertGLEnumToCapabilityInput(GLenum value);
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace MobileGL {
|
||||
return GL_DISPATCH_INDIRECT_BUFFER;
|
||||
case BufferTarget::DrawIndirect:
|
||||
return GL_DRAW_INDIRECT_BUFFER;
|
||||
case BufferTarget::Parameter:
|
||||
return GL_PARAMETER_BUFFER_ARB;
|
||||
case BufferTarget::ShaderStorage:
|
||||
return GL_SHADER_STORAGE_BUFFER;
|
||||
case BufferTarget::Unknown:
|
||||
@@ -84,4 +86,4 @@ namespace MobileGL {
|
||||
return result;
|
||||
}
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -211,6 +211,17 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
GLenum ConvertProvokingVertexModeToGLEnum(ProvokingVertexMode v) {
|
||||
switch (v) {
|
||||
case ProvokingVertexMode::FirstVertex:
|
||||
return GL_FIRST_VERTEX_CONVENTION;
|
||||
case ProvokingVertexMode::LastVertex:
|
||||
return GL_LAST_VERTEX_CONVENTION;
|
||||
default:
|
||||
return GL_UNKNOWN_MGL;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum ConvertCapabilityInputToGLEnum(CapabilityInput v) {
|
||||
switch (v) {
|
||||
case CapabilityInput::Blend:
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace MobileGL {
|
||||
GLenum ConvertPixelStoreParamToGLEnum(PixelStoreParam value);
|
||||
GLenum ConvertCullFaceModeToGLEnum(CullFaceMode value);
|
||||
GLenum ConvertFrontFaceModeToGLEnum(FrontFaceMode value);
|
||||
GLenum ConvertProvokingVertexModeToGLEnum(ProvokingVertexMode value);
|
||||
GLenum ConvertCapabilityInputToGLEnum(CapabilityInput value);
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace MobileGL {
|
||||
return "DispatchIndirect";
|
||||
case BufferTarget::DrawIndirect:
|
||||
return "DrawIndirect";
|
||||
case BufferTarget::Parameter:
|
||||
return "Parameter";
|
||||
case BufferTarget::ShaderStorage:
|
||||
return "ShaderStorage";
|
||||
case BufferTarget::Unknown:
|
||||
|
||||
@@ -193,6 +193,17 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
String ConvertProvokingVertexModeToString(ProvokingVertexMode v) {
|
||||
switch (v) {
|
||||
case ProvokingVertexMode::FirstVertex:
|
||||
return "FirstVertex";
|
||||
case ProvokingVertexMode::LastVertex:
|
||||
return "LastVertex";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
String ConvertCapabilityInputToString(CapabilityInput v) {
|
||||
switch (v) {
|
||||
case CapabilityInput::Blend:
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace MobileGL {
|
||||
String ConvertPixelStoreParamToString(PixelStoreParam value);
|
||||
String ConvertCullFaceModeToString(CullFaceMode value);
|
||||
String ConvertFrontFaceModeToString(FrontFaceMode value);
|
||||
String ConvertProvokingVertexModeToString(ProvokingVertexMode value);
|
||||
String ConvertCapabilityInputToString(CapabilityInput value);
|
||||
} // namespace MG_Util
|
||||
} // namespace MobileGL
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
#include "ShaderSourceProcessor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
|
||||
namespace {
|
||||
using MobileGL::SizeT;
|
||||
@@ -159,6 +161,106 @@ namespace {
|
||||
return lineEnd == MobileGL::String::npos ? source.size() : lineEnd + 1;
|
||||
}
|
||||
|
||||
bool IsExtensionAdvertised(MobileGL::GLExtension extension) {
|
||||
const auto& activeBackendObject = MobileGL::MG_Backend::pActiveBackendObject;
|
||||
if (!activeBackendObject) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto& extensions = activeBackendObject->GetRendererInfo().RendererGLInfo.Extensions;
|
||||
return std::find(extensions.begin(), extensions.end(), extension) != extensions.end();
|
||||
}
|
||||
|
||||
MobileGL::String TrimDirectiveToken(const MobileGL::String& token) {
|
||||
SizeT start = 0;
|
||||
while (start < token.size() && std::isspace(static_cast<unsigned char>(token[start]))) {
|
||||
start++;
|
||||
}
|
||||
|
||||
SizeT end = token.size();
|
||||
while (end > start && std::isspace(static_cast<unsigned char>(token[end - 1]))) {
|
||||
end--;
|
||||
}
|
||||
return token.substr(start, end - start);
|
||||
}
|
||||
|
||||
void FilterUnsupportedGpuShaderInt64(MobileGL::String& source) {
|
||||
if (IsExtensionAdvertised(MobileGL::E_GL_ARB_gpu_shader_int64)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SizeT lineStart = 0;
|
||||
while (lineStart < source.size()) {
|
||||
SizeT lineEnd = source.find('\n', lineStart);
|
||||
const bool hasLineBreak = lineEnd != MobileGL::String::npos;
|
||||
if (!hasLineBreak) {
|
||||
lineEnd = source.size();
|
||||
}
|
||||
|
||||
const MobileGL::String line = source.substr(lineStart, lineEnd - lineStart);
|
||||
SizeT probe = 0;
|
||||
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
|
||||
probe++;
|
||||
}
|
||||
|
||||
if (probe < line.size() && line[probe] == '#') {
|
||||
probe++;
|
||||
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
|
||||
probe++;
|
||||
}
|
||||
|
||||
constexpr const char* extensionToken = "extension";
|
||||
constexpr SizeT extensionLen = 9;
|
||||
const bool hasExtensionDirective =
|
||||
probe + extensionLen <= line.size() &&
|
||||
line.compare(probe, extensionLen, extensionToken) == 0 &&
|
||||
(probe + extensionLen == line.size() || !IsIdentifierChar(line[probe + extensionLen]));
|
||||
if (hasExtensionDirective) {
|
||||
probe += extensionLen;
|
||||
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
|
||||
probe++;
|
||||
}
|
||||
|
||||
constexpr const char* int64Extension = "GL_ARB_gpu_shader_int64";
|
||||
constexpr SizeT int64ExtensionLen = 23;
|
||||
const bool hasInt64Extension =
|
||||
probe + int64ExtensionLen <= line.size() &&
|
||||
line.compare(probe, int64ExtensionLen, int64Extension) == 0 &&
|
||||
(probe + int64ExtensionLen == line.size() ||
|
||||
!IsIdentifierChar(line[probe + int64ExtensionLen]));
|
||||
if (hasInt64Extension) {
|
||||
probe += int64ExtensionLen;
|
||||
while (probe < line.size() && std::isspace(static_cast<unsigned char>(line[probe]))) {
|
||||
probe++;
|
||||
}
|
||||
|
||||
if (probe < line.size() && line[probe] == ':') {
|
||||
probe++;
|
||||
const MobileGL::String behavior = TrimDirectiveToken(line.substr(probe));
|
||||
const SizeT replaceLen = lineEnd - lineStart + (hasLineBreak ? 1 : 0);
|
||||
if (behavior == "require") {
|
||||
const MobileGL::String replacement =
|
||||
"#error GL_ARB_gpu_shader_int64 is not advertised by MobileGL\n";
|
||||
source.replace(lineStart, replaceLen, replacement);
|
||||
lineStart += replacement.size();
|
||||
} else if (behavior == "enable" || behavior == "warn") {
|
||||
source.replace(lineStart, replaceLen, "\n");
|
||||
lineStart++;
|
||||
} else {
|
||||
lineStart = lineEnd + (hasLineBreak ? 1 : 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lineStart = lineEnd + (hasLineBreak ? 1 : 0);
|
||||
}
|
||||
|
||||
ReplaceIdentifier(source, "GL_ARB_gpu_shader_int64", "MG_DISABLED_GL_ARB_gpu_shader_int64");
|
||||
}
|
||||
|
||||
void ModernizeLegacyGLSL(MobileGL::ShaderStage stage, MobileGL::String& source) {
|
||||
RemoveDefineForIdentifier(source, "HIGHP_OR_DEFAULT");
|
||||
RemoveDefineForIdentifier(source, "MEDIUMP_OR_DEFAULT");
|
||||
@@ -190,6 +292,18 @@ namespace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InjectDepthRangeBuiltinShim(MobileGL::ShaderStage stage, MobileGL::String& source) {
|
||||
if (stage != MobileGL::ShaderStage::Fragment) return;
|
||||
if (source.find("gl_DepthRange") == MobileGL::String::npos) return;
|
||||
if (source.find("mg_DepthRangeParameters") != MobileGL::String::npos) return;
|
||||
|
||||
constexpr const char* shim =
|
||||
"struct mg_DepthRangeParameters { float near; float far; float diff; };\n"
|
||||
"const mg_DepthRangeParameters mg_DepthRange = mg_DepthRangeParameters(0.0, 1.0, 1.0);\n"
|
||||
"#define gl_DepthRange mg_DepthRange\n";
|
||||
source.insert(FindAfterVersionDirective(source), shim);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace MobileGL {
|
||||
@@ -270,12 +384,15 @@ namespace MobileGL {
|
||||
}
|
||||
}
|
||||
|
||||
FilterUnsupportedGpuShaderInt64(source);
|
||||
|
||||
// Some shader packs define helpers with built-in GLSL names such as round(), tanh(), or fma().
|
||||
// These may pass OpenGL-style validation but fail when recompiled for Vulkan/SPIR-V generation.
|
||||
RenameBuiltinShadowingFunction(source, "round", "mg_round");
|
||||
RenameBuiltinShadowingFunction(source, "tanh", "mg_tanh");
|
||||
RenameBuiltinShadowingFunction(source, "fma", "mg_fma");
|
||||
ModernizeLegacyGLSL(stage, source);
|
||||
InjectDepthRangeBuiltinShim(stage, source);
|
||||
}
|
||||
|
||||
} // namespace ShaderTranspiler
|
||||
|
||||
@@ -342,9 +342,12 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
|
||||
*outType = GL_UNSIGNED_INT_24_8;
|
||||
break;
|
||||
case GL_DEPTH32F_STENCIL8:
|
||||
case GL_DEPTH_STENCIL:
|
||||
*outType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
break;
|
||||
case GL_DEPTH24_STENCIL8:
|
||||
case GL_DEPTH_STENCIL:
|
||||
*outType = GL_UNSIGNED_INT_24_8;
|
||||
break;
|
||||
|
||||
default:
|
||||
MGLOG_E("NormalizePixelFormat: outType: unhandled internalFormat: %s",
|
||||
|
||||
Reference in New Issue
Block a user