diff --git a/CMakeLists.txt b/CMakeLists.txt index 027fc35e..cdad1306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,6 +185,7 @@ set(SOURCE_FILES MobileGL/MG_Util/ShaderTranspiler/glslang/TMglGlslIoResolver.cpp MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/FlattenInterfaceStructPass.cpp MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/EliminateFloatEqualsZeroPass.cpp + MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.cpp MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp index 02056ad9..5e213084 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/PipelineFactory.cpp @@ -9,6 +9,91 @@ #include "PipelineFactory.h" namespace MobileGL::MG_Backend::DirectVulkan { + static const char* PrimitiveTopologyToString(VkPrimitiveTopology topology) { + switch (topology) { + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_POINT_LIST) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_LINE_LIST) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY) + ENUM_STR_CASE(VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) + default: + return "VK_PRIMITIVE_TOPOLOGY_UNKNOWN"; + } + } + + static const char* SampleCountToString(VkSampleCountFlagBits sampleCount) { + switch (sampleCount) { + ENUM_STR_CASE(VK_SAMPLE_COUNT_1_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_2_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_4_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_8_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_16_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_32_BIT) + ENUM_STR_CASE(VK_SAMPLE_COUNT_64_BIT) + default: + return "VK_SAMPLE_COUNT_UNKNOWN"; + } + } + + static const char* CullModeToString(VkCullModeFlags cullMode) { + switch (cullMode) { + case VK_CULL_MODE_NONE: + return "VK_CULL_MODE_NONE"; + case VK_CULL_MODE_FRONT_BIT: + return "VK_CULL_MODE_FRONT_BIT"; + case VK_CULL_MODE_BACK_BIT: + return "VK_CULL_MODE_BACK_BIT"; + case VK_CULL_MODE_FRONT_AND_BACK: + return "VK_CULL_MODE_FRONT_AND_BACK"; + default: + return "VK_CULL_MODE_UNKNOWN"; + } + } + + static const char* CompareOpToString(VkCompareOp compareOp) { + switch (compareOp) { + ENUM_STR_CASE(VK_COMPARE_OP_NEVER) + ENUM_STR_CASE(VK_COMPARE_OP_LESS) + ENUM_STR_CASE(VK_COMPARE_OP_EQUAL) + ENUM_STR_CASE(VK_COMPARE_OP_LESS_OR_EQUAL) + ENUM_STR_CASE(VK_COMPARE_OP_GREATER) + ENUM_STR_CASE(VK_COMPARE_OP_NOT_EQUAL) + ENUM_STR_CASE(VK_COMPARE_OP_GREATER_OR_EQUAL) + ENUM_STR_CASE(VK_COMPARE_OP_ALWAYS) + default: + return "VK_COMPARE_OP_UNKNOWN"; + } + } + + static const char* LogicOpToString(VkLogicOp logicOp) { + switch (logicOp) { + ENUM_STR_CASE(VK_LOGIC_OP_CLEAR) + ENUM_STR_CASE(VK_LOGIC_OP_AND) + ENUM_STR_CASE(VK_LOGIC_OP_AND_REVERSE) + ENUM_STR_CASE(VK_LOGIC_OP_COPY) + ENUM_STR_CASE(VK_LOGIC_OP_AND_INVERTED) + ENUM_STR_CASE(VK_LOGIC_OP_NO_OP) + ENUM_STR_CASE(VK_LOGIC_OP_XOR) + ENUM_STR_CASE(VK_LOGIC_OP_OR) + ENUM_STR_CASE(VK_LOGIC_OP_NOR) + ENUM_STR_CASE(VK_LOGIC_OP_EQUIVALENT) + ENUM_STR_CASE(VK_LOGIC_OP_INVERT) + ENUM_STR_CASE(VK_LOGIC_OP_OR_REVERSE) + ENUM_STR_CASE(VK_LOGIC_OP_COPY_INVERTED) + ENUM_STR_CASE(VK_LOGIC_OP_OR_INVERTED) + ENUM_STR_CASE(VK_LOGIC_OP_NAND) + ENUM_STR_CASE(VK_LOGIC_OP_SET) + default: + return "VK_LOGIC_OP_UNKNOWN"; + } + } + PipelineFactory::PipelineFactory(VkDevice device, const VulkanRendererConfig& config): m_device(device), m_config(config) { MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE, "PipelineFactory: device is null"); @@ -191,8 +276,52 @@ namespace MobileGL::MG_Backend::DirectVulkan { gpi.subpass = payload.subpass; VkPipeline pipeline = VK_NULL_HANDLE; - VK_VERIFY(vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &gpi, nullptr, &pipeline), - "vkCreateGraphicsPipelines"); + const VkResult result = vkCreateGraphicsPipelines(m_device, m_pipelineCache, 1, &gpi, nullptr, &pipeline); + if (result != VK_SUCCESS) { + MGLOG_F("PipelineFactory::CreatePipeline failed: result=%s (%d) programHash=0x%llx vertexInputHash=0x%llx stageCount=%u topology=%s(%d) colorAttachmentCount=%u samples=%s(%d) subpass=%u", + VkResultToString(result), + result, + static_cast(payload.programHash), + static_cast(payload.vertexInputHash), + gpi.stageCount, + PrimitiveTopologyToString(payload.topology), + payload.topology, + payload.colorAttachmentCount, + SampleCountToString(payload.rasterizationSamples), + payload.rasterizationSamples, + payload.subpass); + MGLOG_F("PipelineFactory::CreatePipeline state: cullMode=%s(0x%x) frontFace=%d depthTest=%d depthWrite=%d depthCompare=%s(%d) depthBias=%d rasterizerDiscard=%d stencilTest=%d logicOpEnable=%d logicOp=%s(%d)", + CullModeToString(payload.cullMode), + static_cast(payload.cullMode), + payload.frontFace, + payload.depthTestEnable ? 1 : 0, + payload.depthWriteEnable ? 1 : 0, + CompareOpToString(payload.depthCompareOp), + payload.depthCompareOp, + payload.depthBiasEnable ? 1 : 0, + payload.rasterizerDiscardEnable ? 1 : 0, + payload.stencilTestEnable ? 1 : 0, + payload.logicOpEnable ? 1 : 0, + LogicOpToString(payload.logicOp), + payload.logicOp); + MGLOG_F("PipelineFactory::CreatePipeline vertex input: bindingCount=%u attributeCount=%u", + payload.vertexInputState->vertexBindingDescriptionCount, + payload.vertexInputState->vertexAttributeDescriptionCount); + for (Uint32 i = 0; i < payload.colorAttachmentCount; ++i) { + const auto& attachment = payload.colorBlendAttachments[i]; + MGLOG_F("PipelineFactory::CreatePipeline colorAttachment[%u]: blend=%d colorWriteMask=0x%x srcColor=%d dstColor=%d colorOp=%d srcAlpha=%d dstAlpha=%d alphaOp=%d", + i, + attachment.blendEnable == VK_TRUE ? 1 : 0, + static_cast(attachment.colorWriteMask), + attachment.srcColorBlendFactor, + attachment.dstColorBlendFactor, + attachment.colorBlendOp, + attachment.srcAlphaBlendFactor, + attachment.dstAlphaBlendFactor, + attachment.alphaBlendOp); + } + } + VK_VERIFY(result, "vkCreateGraphicsPipelines"); return pipeline; } } // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/VkIncludes.h b/MobileGL/MG_Backend/DirectVulkan/VkIncludes.h index fc981291..b6bd9141 100644 --- a/MobileGL/MG_Backend/DirectVulkan/VkIncludes.h +++ b/MobileGL/MG_Backend/DirectVulkan/VkIncludes.h @@ -10,16 +10,61 @@ #include "VulkanRendererConfig.h" +#define ENUM_STR_CASE(c) case c: return #c; + +namespace MobileGL::MG_Backend::DirectVulkan { + inline const char* VkResultToString(VkResult result) { + switch (result) { + ENUM_STR_CASE(VK_SUCCESS) + ENUM_STR_CASE(VK_NOT_READY) + ENUM_STR_CASE(VK_TIMEOUT) + ENUM_STR_CASE(VK_EVENT_SET) + ENUM_STR_CASE(VK_EVENT_RESET) + ENUM_STR_CASE(VK_INCOMPLETE) + ENUM_STR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY) + ENUM_STR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY) + ENUM_STR_CASE(VK_ERROR_INITIALIZATION_FAILED) + ENUM_STR_CASE(VK_ERROR_DEVICE_LOST) + ENUM_STR_CASE(VK_ERROR_MEMORY_MAP_FAILED) + ENUM_STR_CASE(VK_ERROR_LAYER_NOT_PRESENT) + ENUM_STR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT) + ENUM_STR_CASE(VK_ERROR_FEATURE_NOT_PRESENT) + ENUM_STR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER) + ENUM_STR_CASE(VK_ERROR_TOO_MANY_OBJECTS) + ENUM_STR_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED) + ENUM_STR_CASE(VK_ERROR_FRAGMENTED_POOL) + ENUM_STR_CASE(VK_ERROR_UNKNOWN) + ENUM_STR_CASE(VK_ERROR_OUT_OF_POOL_MEMORY) + ENUM_STR_CASE(VK_ERROR_INVALID_EXTERNAL_HANDLE) + ENUM_STR_CASE(VK_ERROR_FRAGMENTATION) + ENUM_STR_CASE(VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS) + ENUM_STR_CASE(VK_PIPELINE_COMPILE_REQUIRED) + ENUM_STR_CASE(VK_ERROR_SURFACE_LOST_KHR) + ENUM_STR_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) + ENUM_STR_CASE(VK_SUBOPTIMAL_KHR) + ENUM_STR_CASE(VK_ERROR_OUT_OF_DATE_KHR) + ENUM_STR_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR) + ENUM_STR_CASE(VK_ERROR_VALIDATION_FAILED_EXT) + ENUM_STR_CASE(VK_ERROR_INVALID_SHADER_NV) + default: + return "VK_RESULT_UNKNOWN"; + } + } +} // namespace MobileGL::MG_Backend::DirectVulkan + #define VK_VERIFY(expr, ...) \ do { \ VkResult _vk_verify_result = (expr); \ - MOBILEGL_ASSERT(_vk_verify_result == VK_SUCCESS, "Vulkan error %d at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, _vk_verify_result, __FILE__, __LINE__); \ + if (_vk_verify_result != VK_SUCCESS) { \ + MGLOG_F("Vulkan error %s (%d) at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, \ + MobileGL::MG_Backend::DirectVulkan::VkResultToString(_vk_verify_result), \ + _vk_verify_result, __FILE__, __LINE__); \ + } \ + MOBILEGL_ASSERT(_vk_verify_result == VK_SUCCESS, "Vulkan error %s (%d) at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, MobileGL::MG_Backend::DirectVulkan::VkResultToString(_vk_verify_result), _vk_verify_result, __FILE__, __LINE__); \ } while (0) -#define ENUM_STR_CASE(c) case c: return #c; - #define XXHASH_VERIFY(expr, ...) \ do { \ XXH_errorcode _xxh_verify_result = (expr); \ MOBILEGL_ASSERT(_xxh_verify_result == XXH_OK, "XXHash error %d at %s:%d" __VA_OPT__(" - ") __VA_ARGS__, _xxh_verify_result, __FILE__, __LINE__); \ - } while (0) \ No newline at end of file + } while (0) diff --git a/MobileGL/MG_Test/Backend/DirectVulkan/CMakeLists.txt b/MobileGL/MG_Test/Backend/DirectVulkan/CMakeLists.txt index ca4113d4..0dd6ab9a 100644 --- a/MobileGL/MG_Test/Backend/DirectVulkan/CMakeLists.txt +++ b/MobileGL/MG_Test/Backend/DirectVulkan/CMakeLists.txt @@ -43,7 +43,7 @@ endif() target_compile_definitions(DirectVulkanSanityTest PRIVATE -DNOMINMAX) include(GoogleTest) -gtest_discover_tests(DirectVulkanSanityTest) +gtest_discover_tests(DirectVulkanSanityTest DISCOVERY_TIMEOUT 30) add_executable( DirectVulkanTestExec diff --git a/MobileGL/MG_Test/Buffer/CMakeLists.txt b/MobileGL/MG_Test/Buffer/CMakeLists.txt index cf72e015..0c59551f 100644 --- a/MobileGL/MG_Test/Buffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Buffer/CMakeLists.txt @@ -24,4 +24,4 @@ if (MSVC) endif() include(GoogleTest) -gtest_discover_tests(BufferTest) +gtest_discover_tests(BufferTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Test/CMakeLists.txt b/MobileGL/MG_Test/CMakeLists.txt index 0fee4f8c..d69298ea 100644 --- a/MobileGL/MG_Test/CMakeLists.txt +++ b/MobileGL/MG_Test/CMakeLists.txt @@ -62,7 +62,7 @@ set(LINK_LIBRARIES ) include(GoogleTest) -gtest_discover_tests(SanityTest) +gtest_discover_tests(SanityTest DISCOVERY_TIMEOUT 30) add_subdirectory(Buffer) add_subdirectory(EGLState) diff --git a/MobileGL/MG_Test/EGLState/CMakeLists.txt b/MobileGL/MG_Test/EGLState/CMakeLists.txt index 030e7db7..93fac362 100644 --- a/MobileGL/MG_Test/EGLState/CMakeLists.txt +++ b/MobileGL/MG_Test/EGLState/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(EGLStateTest) +gtest_discover_tests(EGLStateTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Test/Framebuffer/CMakeLists.txt b/MobileGL/MG_Test/Framebuffer/CMakeLists.txt index 191b1f5e..75d1fcb9 100644 --- a/MobileGL/MG_Test/Framebuffer/CMakeLists.txt +++ b/MobileGL/MG_Test/Framebuffer/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(FramebufferTest) +gtest_discover_tests(FramebufferTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Test/Program/CMakeLists.txt b/MobileGL/MG_Test/Program/CMakeLists.txt index 906d5e9a..0ccab535 100644 --- a/MobileGL/MG_Test/Program/CMakeLists.txt +++ b/MobileGL/MG_Test/Program/CMakeLists.txt @@ -39,5 +39,5 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(ProgramUtilTest) -gtest_discover_tests(ProgramTest) \ No newline at end of file +gtest_discover_tests(ProgramUtilTest DISCOVERY_TIMEOUT 30) +gtest_discover_tests(ProgramTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp index 291c4514..2aa1b3f7 100644 --- a/MobileGL/MG_Test/Program/ProgramUtilTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramUtilTest.cpp @@ -15,8 +15,11 @@ #include #include #include +#include #include #include +#include +#include using namespace MobileGL; @@ -31,6 +34,64 @@ TEST_F(ProgramUtilTest, Sanity) { ASSERT_TRUE(true); } +TEST_F(ProgramUtilTest, RenameSamplerFunctionParameterInSpirvPass) { + using namespace MG_Util::ShaderTranspiler; + + const String spirvText = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %outColor + OpExecutionMode %main OriginUpperLeft + OpName %globalSampler "sampler" + OpName %paramSampler "sampler" + OpName %main "main" + OpDecorate %outColor Location 0 + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %mainFn = OpTypeFunction %void + %paramFn = OpTypeFunction %void %float + %outV4Ptr = OpTypePointer Output %v4float + %privatePtr = OpTypePointer Private %float + %outColor = OpVariable %outV4Ptr Output +%globalSampler = OpVariable %privatePtr Private + %helper = OpFunction %void None %paramFn +%paramSampler = OpFunctionParameter %float + %helperBody = OpLabel + OpReturn + OpFunctionEnd + %main = OpFunction %void None %mainFn + %mainBody = OpLabel + OpReturn + OpFunctionEnd +)"; + + spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1); + Vector inputBinary; + ASSERT_TRUE(tools.Assemble(spirvText, &inputBinary)); + + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); + spvtools::OptimizerOptions options; + options.set_run_validator(false); + optimizer.RegisterPass(RenameSamplerFunctionParameterPass::CreateRenameSamplerFunctionParameterPass()); + + Vector outputBinary; + ASSERT_TRUE(optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options)); + + String outputText; + ASSERT_TRUE(tools.Disassemble(outputBinary, &outputText)); + + EXPECT_NE(outputText.find("\"MGL_COMPAT_sampler\""), String::npos); + + SizeT exactSamplerNameCount = 0; + SizeT searchOffset = 0; + while ((searchOffset = outputText.find("\"sampler\"", searchOffset)) != String::npos) { + ++exactSamplerNameCount; + searchOffset += std::strlen("\"sampler\""); + } + EXPECT_EQ(exactSamplerNameCount, 1u); +} + TEST_F(ProgramUtilTest, PreprocessLegacyVertexShaderModernizesGlmarkStyleSource) { using namespace MG_Util::ShaderTranspiler; diff --git a/MobileGL/MG_Test/Texture/CMakeLists.txt b/MobileGL/MG_Test/Texture/CMakeLists.txt index b1ca17ea..060e85b3 100644 --- a/MobileGL/MG_Test/Texture/CMakeLists.txt +++ b/MobileGL/MG_Test/Texture/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(TextureTest) +gtest_discover_tests(TextureTest DISCOVERY_TIMEOUT 30) add_executable( VkClearManagerTest @@ -35,4 +35,4 @@ target_link_libraries( ${LINK_LIBRARIES} ) -gtest_discover_tests(VkClearManagerTest) +gtest_discover_tests(VkClearManagerTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Test/VertexArray/CMakeLists.txt b/MobileGL/MG_Test/VertexArray/CMakeLists.txt index 2fb1bfeb..0221674e 100644 --- a/MobileGL/MG_Test/VertexArray/CMakeLists.txt +++ b/MobileGL/MG_Test/VertexArray/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries( ) include(GoogleTest) -gtest_discover_tests(VertexArrayTest) +gtest_discover_tests(VertexArrayTest DISCOVERY_TIMEOUT 30) diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index cd62fe9f..22d85ca8 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -10,6 +10,7 @@ #include "SpirvPasses/EliminateFloatEqualsZeroPass.h" #include "SpirvPasses/FlattenInterfaceStructPass.h" +#include "SpirvPasses/RenameSamplerFunctionParameterPass.h" #include "spirv-tools/libspirv.h" #include "spirv-tools/optimizer.hpp" @@ -240,6 +241,7 @@ namespace MobileGL { optimizer.RegisterPass(CreateAggressiveDCEPass(false)); optimizer.RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()); optimizer.RegisterPass(FlattenInterfaceStructPass::CreateFlattenInterfaceStructPass()); + optimizer.RegisterPass(RenameSamplerFunctionParameterPass::CreateRenameSamplerFunctionParameterPass()); optimizer.RegisterPass(EliminateFloatEqualsZeroPass::CreateEliminateFloatEqualsZeroPass()); return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options); diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.cpp b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.cpp new file mode 100644 index 00000000..d36d6013 --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.cpp @@ -0,0 +1,64 @@ +// MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.cpp +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#include "RenameSamplerFunctionParameterPass.h" + +#include "spirv.hpp" +#include "source/opt/def_use_manager.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/util/make_unique.h" + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + namespace { + constexpr const char* kConflictingName = "sampler"; + constexpr const char* kCompatName = "MGL_COMPAT_sampler"; + + Bool IsNamedSamplerFunctionParameter(spvtools::opt::IRContext* context, + spvtools::opt::Instruction& nameInst) { + if (nameInst.opcode() != spv::Op::OpName || nameInst.NumInOperands() < 2) { + return false; + } + + if (nameInst.GetInOperand(1).AsString() != kConflictingName) { + return false; + } + + auto* defUseMgr = context->get_def_use_mgr(); + const Uint32 targetId = nameInst.GetSingleWordInOperand(0); + const auto* target = defUseMgr->GetDef(targetId); + return target != nullptr && target->opcode() == spv::Op::OpFunctionParameter; + } + } // namespace + + spvtools::opt::Pass::Status RenameSamplerFunctionParameterPass::Process() { + Bool modified = false; + auto* irContext = context(); + + for (auto& debugInst : irContext->debugs2()) { + if (!IsNamedSamplerFunctionParameter(irContext, debugInst)) { + continue; + } + + debugInst.SetInOperand( + 1, spvtools::utils::MakeVector(kCompatName)); + modified = true; + } + + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + } + + spvtools::Optimizer::PassToken RenameSamplerFunctionParameterPass::CreateRenameSamplerFunctionParameterPass() { + return spvtools::Optimizer::PassToken(MakeUnique()); + } + } // namespace ShaderTranspiler + } // namespace MG_Util +} // namespace MobileGL diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.h b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.h new file mode 100644 index 00000000..087a08af --- /dev/null +++ b/MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.h @@ -0,0 +1,27 @@ +// MobileGL - MobileGL/MG_Util/ShaderTranspiler/SpirvPasses/RenameSamplerFunctionParameterPass.h +// Copyright (c) 2025-2026 MobileGL-Dev +// Licensed under the GNU Lesser General Public License v3.0: +// https://www.gnu.org/licenses/gpl-3.0.txt +// https://www.gnu.org/licenses/lgpl-3.0.txt +// SPDX-License-Identifier: LGPL-3.0-only +// End of Source File Header + +#pragma once +#include "source/opt/pass.h" +#include "spirv-tools/optimizer.hpp" + +#include + +namespace MobileGL { + namespace MG_Util { + namespace ShaderTranspiler { + class RenameSamplerFunctionParameterPass : public spvtools::opt::Pass { + public: + const char* name() const override { return "rename-sampler-function-parameter"; } + Status Process() override; + + static spvtools::Optimizer::PassToken CreateRenameSamplerFunctionParameterPass(); + }; + } // namespace ShaderTranspiler + } // namespace MG_Util +} // namespace MobileGL