diff --git a/Test/preprocessor.line_return.glsl.comp b/Test/preprocessor.line_return.glsl.comp new file mode 100644 index 0000000000..e9770f2171 --- /dev/null +++ b/Test/preprocessor.line_return.glsl.comp @@ -0,0 +1,5 @@ +#version 450 +#extension GL_EXT_debug_printf : require +void main() { + debugPrintfEXT("global thread id %v3u\n", gl_GlobalInvocationID); +} \ No newline at end of file diff --git a/glslang/CInterface/glslang_c_interface.cpp b/glslang/CInterface/glslang_c_interface.cpp index 97f5a86d56..c5d2a54565 100644 --- a/glslang/CInterface/glslang_c_interface.cpp +++ b/glslang/CInterface/glslang_c_interface.cpp @@ -431,15 +431,34 @@ GLSLANG_EXPORT int glslang_shader_preprocess(glslang_shader_t* shader, const gls GLSLANG_EXPORT int glslang_shader_parse(glslang_shader_t* shader, const glslang_input_t* input) { - const char* preprocessedCStr = shader->preprocessedGLSL.c_str(); - shader->shader->setStrings(&preprocessedCStr, 1); - - return shader->shader->parse( - reinterpret_cast(input->resource), - input->default_version, - input->forward_compatible != 0, - (EShMessages)c_shader_messages(input->messages) - ); + // Seems glslang is preprocessing files twice if we call preprocess then parse on the preprocessed string. + // As we are forcing the use of preprocess before parse, this could lead to some issues with line return being preprocessed twice for example. + // Should avoid preprocessing twice in this case ideally, but just allow using C Api without preprocess for now. + if (shader->preprocessedGLSL.length() > 0) { + const char* preprocessedCStr = shader->preprocessedGLSL.c_str(); + shader->shader->setStrings(&preprocessedCStr, 1); + + return shader->shader->parse( + reinterpret_cast(input->resource), + input->default_version, + input->forward_compatible != 0, + (EShMessages)c_shader_messages(input->messages) + ); + } else { + DirStackFileIncluder dirStackFileIncluder; + CallbackIncluder callbackIncluder(input->callbacks, input->callbacks_ctx); + glslang::TShader::Includer& Includer = (input->callbacks.include_local||input->callbacks.include_system) + ? static_cast(callbackIncluder) + : static_cast(dirStackFileIncluder); + shader->shader->setStrings(&input->code, 1); + return shader->shader->parse( + reinterpret_cast(input->resource), + input->default_version, + input->forward_compatible != 0, + (EShMessages)c_shader_messages(input->messages), + Includer + ); + } } GLSLANG_EXPORT const char* glslang_shader_get_info_log(glslang_shader_t* shader) { return shader->shader->getInfoLog(); } diff --git a/gtests/Pp.FromFile.cpp b/gtests/Pp.FromFile.cpp index 9cadd226ee..aaa2ee8c64 100644 --- a/gtests/Pp.FromFile.cpp +++ b/gtests/Pp.FromFile.cpp @@ -40,13 +40,26 @@ namespace glslangtest { namespace { using PreprocessingTest = GlslangTest<::testing::TestWithParam>; +using PreprocessingReturnLineTest = GlslangTest<::testing::TestWithParam>; TEST_P(PreprocessingTest, FromFile) { loadFilePreprocessAndCheck(GlobalTestSettings.testRoot, GetParam()); } +TEST_P(PreprocessingReturnLineTest, FromFile) +{ + loadFilePreprocessFileReturn(GlobalTestSettings.testRoot, GetParam()); +} + // clang-format off +INSTANTIATE_TEST_SUITE_P( + Glsl, PreprocessingReturnLineTest, + ::testing::ValuesIn(std::vector({ + "preprocessor.line_return.glsl.comp", + })), + FileNameAsCustomTestSuffix +); INSTANTIATE_TEST_SUITE_P( Glsl, PreprocessingTest, ::testing::ValuesIn(std::vector({ diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index 68bb3c6a85..ccc1da907e 100644 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -52,6 +52,7 @@ #include "glslang/Include/Types.h" #include "glslang/Public/ResourceLimits.h" #include "glslang/Public/ShaderLang.h" +#include "glslang/Include/glslang_c_interface.h" #include "Initializer.h" #include "Settings.h" @@ -708,6 +709,183 @@ class GlslangTest : public GT { } } + std::tuple preprocessAndCompileWithCAPI(const std::string& source) + { + const char * shaderStrings = source.data(); + const int shaderLengths = static_cast(source.size()); + + // Done by framework + //glslang_initialize_process(); + + glslang_resource_t resources = glslang_resource_t{ + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxMeshOutputVerticesEXT = */ 256, + /* .maxMeshOutputPrimitivesEXT = */ 512, + /* .maxMeshWorkGroupSizeX_EXT = */ 32, + /* .maxMeshWorkGroupSizeY_EXT = */ 1, + /* .maxMeshWorkGroupSizeZ_EXT = */ 1, + /* .maxTaskWorkGroupSizeX_EXT = */ 32, + /* .maxTaskWorkGroupSizeY_EXT = */ 1, + /* .maxTaskWorkGroupSizeZ_EXT = */ 1, + /* .maxMeshViewCountEXT = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + + /* .limits = */ + { + /* .nonInductiveForLoops = */ 1, + /* .whileLoops = */ 1, + /* .doWhileLoops = */ 1, + /* .generalUniformIndexing = */ 1, + /* .generalAttributeMatrixVectorIndexing = */ 1, + /* .generalVaryingIndexing = */ 1, + /* .generalSamplerIndexing = */ 1, + /* .generalVariableIndexing = */ 1, + /* .generalConstantMatrixVectorIndexing = */ 1, + }}; + + glslang_input_t shader_input{}; + shader_input.language = GLSLANG_SOURCE_GLSL; + shader_input.stage = GLSLANG_STAGE_COMPUTE; + shader_input.client = GLSLANG_CLIENT_VULKAN; + shader_input.client_version = GLSLANG_TARGET_VULKAN_1_3; + shader_input.target_language = GLSLANG_TARGET_SPV; + shader_input.target_language_version = GLSLANG_TARGET_SPV_1_6; + shader_input.code = source.data(); + shader_input.default_version = 100; + shader_input.default_profile = GLSLANG_NO_PROFILE; + shader_input.force_default_version_and_profile = 0; + shader_input.forward_compatible = GLSLANG_MSG_DEFAULT_BIT; + shader_input.messages = GLSLANG_MSG_DEFAULT_BIT; + shader_input.resource = &resources; + shader_input.callbacks = glsl_include_callbacks_s{ + NULL, + NULL, + NULL + }; + shader_input.callbacks_ctx = NULL; + + glslang_shader_t* shader = glslang_shader_create(&shader_input); + // Uncommenting following code will make code being preprocessed twice + /*if (glslang_shader_preprocess(shader, &shader_input) != 1) { + const std::string logs = std::string(glslang_shader_get_info_log(shader)); + glslang_shader_delete(shader); + return std::make_tuple(false, logs); + }*/ + if (glslang_shader_parse(shader, &shader_input) != 1) { + const std::string logs = std::string(glslang_shader_get_info_log(shader)); + glslang_shader_delete(shader); + return std::make_tuple(false, logs); + } + const std::string logs = std::string(glslang_shader_get_info_log(shader)); + glslang_shader_delete(shader); + + return std::make_tuple(true, logs); + } + + void loadFilePreprocessFileReturn(const std::string& testDir, const std::string& testName) + { + const std::string inputFname = testDir + "/" + testName; + std::string input; + tryLoadFile(inputFname, "input", &input); + + bool ppOk; + std::string error; + std::tie(ppOk, error) = preprocessAndCompileWithCAPI(input); + EXPECT_TRUE(error.empty()); + EXPECT_TRUE(ppOk); + } + void loadFilePreprocessAndCheck(const std::string& testDir, const std::string& testName) {