yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
aa165943
main
1// 2// Copyright (C) 2016-2017 Google, Inc. 3// Copyright (C) 2020 The Khronos Group Inc. 4// 5// All rights reserved. 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions 9// are met: 10// 11// Redistributions of source code must retain the above copyright 12// notice, this list of conditions and the following disclaimer. 13// 14// Redistributions in binary form must reproduce the above 15// copyright notice, this list of conditions and the following 16// disclaimer in the documentation and/or other materials provided 17// with the distribution. 18// 19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20// contributors may be used to endorse or promote products derived 21// from this software without specific prior written permission. 22// 23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34// POSSIBILITY OF SUCH DAMAGE. 35// 36#include <algorithm> 37 38#include <gtest/gtest.h> 39 40#include "TestFixture.h" 41 42#include "glslang/MachineIndependent/localintermediate.h" 43#include "glslang/MachineIndependent/iomapper.h" 44#include "glslang/MachineIndependent/reflection.h" 45 46namespace glslangtest { 47namespace { 48 49struct IoMapData { 50 std::vector < std::string > fileNames ; 51Semantics semantics ; 52}; 53 54using GlslMapIOTest = GlslangTest < ::testing::TestWithParam < IoMapData >> ; 55 56template < class T > 57std::string interfaceName (T symbol ) { 58return symbol .getType ()-> getBasicType ()== glslang::EbtBlock ? std::string (symbol .getType ()-> getTypeName ().c_str ()) :symbol .name ; 59} 60 61bool verifyIOMapping (std::string & linkingError , glslang::TProgram & program ) { 62bool success = true; 63 64// Verify IO Mapping by generating reflection for each stage individually 65// and comparing layout qualifiers on the results 66 67 68int reflectionOptions = EShReflectionDefault ; 69//reflectionOptions |= EShReflectionStrictArraySuffix; 70//reflectionOptions |= EShReflectionBasicArraySuffix; 71reflectionOptions |=EShReflectionIntermediateIO ; 72reflectionOptions |=EShReflectionSeparateBuffers ; 73reflectionOptions |=EShReflectionAllBlockVariables ; 74//reflectionOptions |= EShReflectionUnwrapIOBlocks; 75 76success &=program .buildReflection (reflectionOptions ); 77 78// check that the reflection output from the individual stages all makes sense.. 79 std::vector < glslang::TReflection > stageReflections ; 80for (int s = 0 ;s < EShLangCount ;++ s ) { 81if (program .getIntermediate ((EShLanguage )s )) { 82stageReflections .emplace_back ((EShReflectionOptions )reflectionOptions , (EShLanguage )s , (EShLanguage )s ); 83success &=stageReflections .back ().addStage ((EShLanguage )s ,* program .getIntermediate ((EShLanguage )s )); 84 } 85 } 86 87// check that input/output locations match between stages 88auto it = stageReflections .begin (); 89auto nextIt = it + 1 ; 90for (;nextIt != stageReflections .end ();it ++ ,nextIt ++ ) { 91int numOut = it -> getNumPipeOutputs (); 92 std::map < std::string ,const glslang::TObjectReflection *> pipeOut ; 93 94for (int i = 0 ;i < numOut ;i ++ ) { 95const glslang::TObjectReflection & out = it -> getPipeOutput (i ); 96 std::string name = interfaceName (out ); 97pipeOut [name ]= & out ; 98 } 99 100int numIn = nextIt -> getNumPipeInputs (); 101for (int i = 0 ;i < numIn ;i ++ ) { 102auto in = nextIt -> getPipeInput (i ); 103 std::string name = interfaceName (in ); 104auto out = pipeOut .find (name ); 105 106if (out != pipeOut .end ()) { 107auto inQualifier = in .getType ()-> getQualifier (); 108auto outQualifier = out -> second -> getType ()-> getQualifier (); 109success &=outQualifier .layoutLocation == inQualifier .layoutLocation ; 110 } 111else { 112if (!in .getType ()-> isStruct ()) { 113bool found = false; 114for (auto outIt :pipeOut ) { 115if (outIt .second -> getType ()-> isStruct ()) { 116unsigned int baseLoc = outIt .second -> getType ()-> getQualifier ().hasLocation () ? 117outIt .second -> getType ()-> getQualifier ().layoutLocation : 118 std::numeric_limits < unsigned int > ::max (); 119for (size_t j = 0 ;j < outIt .second -> getType ()-> getStruct ()-> size ();j ++ ) { 120baseLoc = (* outIt .second -> getType ()-> getStruct ())[j ].type -> getQualifier ().hasLocation () ? 121 (* outIt .second -> getType ()-> getStruct ())[j ].type -> getQualifier ().layoutLocation :baseLoc ; 122if (baseLoc != std::numeric_limits < unsigned int > ::max ()) { 123if (baseLoc == in .getType ()-> getQualifier ().layoutLocation ) { 124found = true; 125break ; 126 } 127baseLoc += glslang::TIntermediate ::computeTypeLocationSize (* (* outIt .second -> getType ()-> getStruct ())[j ].type ,EShLangVertex ); 128 } 129 } 130if (found ) { 131break ; 132 } 133 } 134 } 135success &=found ; 136 } 137else { 138unsigned int baseLoc = in .getType ()-> getQualifier ().hasLocation () ?in .getType ()-> getQualifier ().layoutLocation :-1 ; 139for (size_t j = 0 ;j < in .getType ()-> getStruct ()-> size ();j ++ ) { 140baseLoc = (* in .getType ()-> getStruct ())[j ].type -> getQualifier ().hasLocation () ? 141 (* in .getType ()-> getStruct ())[j ].type -> getQualifier ().layoutLocation :baseLoc ; 142if (baseLoc != std::numeric_limits < unsigned int > ::max ()) { 143bool isMemberFound = false; 144for (auto outIt :pipeOut ) { 145if (baseLoc == outIt .second -> getType ()-> getQualifier ().layoutLocation ) { 146isMemberFound = true; 147break ; 148 } 149 } 150if (!isMemberFound ) { 151success &= false; 152break ; 153 } 154baseLoc += glslang::TIntermediate ::computeTypeLocationSize (* (* in .getType ()-> getStruct ())[j ].type ,EShLangVertex ); 155 } 156 } 157 } 158 } 159 } 160 } 161 162// compare uniforms in each stage to the program 163 { 164int totalUniforms = program .getNumUniformVariables (); 165 std::map < std::string ,const glslang::TObjectReflection *> programUniforms ; 166for (int i = 0 ;i < totalUniforms ;i ++ ) { 167const glslang::TObjectReflection & uniform = program .getUniform (i ); 168 std::string name = interfaceName (uniform ); 169programUniforms [name ]= & uniform ; 170 } 171it = stageReflections .begin (); 172for (;it != stageReflections .end ();it ++ ) { 173int numUniform = it -> getNumUniforms (); 174 std::map < std::string , glslang::TObjectReflection > uniforms ; 175 176for (int i = 0 ;i < numUniform ;i ++ ) { 177 glslang::TObjectReflection uniform = it -> getUniform (i ); 178 std::string name = interfaceName (uniform ); 179auto programUniform = programUniforms .find (name ); 180 181if (programUniform != programUniforms .end ()) { 182auto stageQualifier = uniform .getType ()-> getQualifier (); 183auto programQualifier = programUniform -> second -> getType ()-> getQualifier (); 184 185success &=stageQualifier .layoutLocation == programQualifier .layoutLocation ; 186success &=stageQualifier .layoutBinding == programQualifier .layoutBinding ; 187success &=stageQualifier .layoutSet == programQualifier .layoutSet ; 188 } 189else { 190success &= false; 191 } 192 } 193 } 194 } 195 196// compare uniform blocks in each stage to the program table 197 { 198int totalUniforms = program .getNumUniformBlocks (); 199 std::map < std::string ,const glslang::TObjectReflection *> programUniforms ; 200for (int i = 0 ;i < totalUniforms ;i ++ ) { 201const glslang::TObjectReflection & uniform = program .getUniformBlock (i ); 202 std::string name = interfaceName (uniform ); 203programUniforms [name ]= & uniform ; 204 } 205it = stageReflections .begin (); 206for (;it != stageReflections .end ();it ++ ) { 207int numUniform = it -> getNumUniformBlocks (); 208 std::map < std::string , glslang::TObjectReflection > uniforms ; 209 210for (int i = 0 ;i < numUniform ;i ++ ) { 211 glslang::TObjectReflection uniform = it -> getUniformBlock (i ); 212 std::string name = interfaceName (uniform ); 213auto programUniform = programUniforms .find (name ); 214 215if (programUniform != programUniforms .end ()) { 216auto stageQualifier = uniform .getType ()-> getQualifier (); 217auto programQualifier = programUniform -> second -> getType ()-> getQualifier (); 218 219success &=stageQualifier .layoutLocation == programQualifier .layoutLocation ; 220success &=stageQualifier .layoutBinding == programQualifier .layoutBinding ; 221success &=stageQualifier .layoutSet == programQualifier .layoutSet ; 222 } 223else { 224success &= false; 225 } 226 } 227 } 228 } 229 230if (!success ) { 231linkingError += "Mismatched cross-stage IO\n" ; 232 } 233 234return success ; 235} 236 237TEST_P (GlslMapIOTest ,FromFile ) 238{ 239const auto & fileNames = GetParam ().fileNames ; 240Semantics semantics = GetParam ().semantics ; 241const size_t fileCount = fileNames .size (); 242const EShMessages controls = DeriveOptions (Source ::GLSL ,semantics ,Target ::BothASTAndSpv ); 243GlslangResult result ; 244 245// Compile each input shader file. 246bool success = true; 247 std::vector < std::unique_ptr < glslang::TShader >> shaders ; 248for (size_t i = 0 ;i < fileCount ;++ i ) { 249 std::string contents ; 250tryLoadFile (GlobalTestSettings .testRoot + "/" + fileNames [i ], 251"input" ,& contents ); 252shaders .emplace_back ( 253new glslang::TShader (GetShaderStage (GetSuffix (fileNames [i ])))); 254auto * shader = shaders .back ().get (); 255 256shader -> setAutoMapLocations (true); 257shader -> setAutoMapBindings (true); 258 259if (controls & EShMsgSpvRules ) { 260if (controls & EShMsgVulkanRules ) { 261shader -> setEnvInput ((controls & EShMsgReadHlsl ) ? glslang::EShSourceHlsl 262 : glslang::EShSourceGlsl , 263shader -> getStage (), glslang::EShClientVulkan ,100 ); 264shader -> setEnvClient (glslang::EShClientVulkan , glslang::EShTargetVulkan_1_1 ); 265shader -> setEnvTarget (glslang::EShTargetSpv , glslang::EShTargetSpv_1_0 ); 266 }else { 267shader -> setEnvInput ((controls & EShMsgReadHlsl ) ? glslang::EShSourceHlsl 268 : glslang::EShSourceGlsl , 269shader -> getStage (), glslang::EShClientOpenGL ,100 ); 270shader -> setEnvClient (glslang::EShClientOpenGL , glslang::EShTargetOpenGL_450 ); 271shader -> setEnvTarget (glslang::EshTargetSpv , glslang::EShTargetSpv_1_0 ); 272 } 273 } 274 275success &=compile (shader ,contents ,"" ,controls ); 276 277result .shaderResults .push_back ( 278 {fileNames [i ],shader -> getInfoLog (),shader -> getInfoDebugLog () }); 279 } 280 281// Link all of them. 282 glslang::TProgram program ; 283for (const auto & shader :shaders )program .addShader (shader .get ()); 284success &=program .link (controls ); 285result .linkingOutput = program .getInfoLog (); 286result .linkingError = program .getInfoDebugLog (); 287 288 glslang::TIoMapResolver * resolver ; 289for (unsigned stage = 0 ;stage < EShLangCount ;stage ++ ) { 290resolver = program .getGlslIoResolver ((EShLanguage )stage ); 291if (resolver ) 292break ; 293 } 294 glslang::TIoMapper * ioMapper = glslang::GetGlslIoMapper (); 295 296if (success ) { 297success &=program .mapIO (resolver ,ioMapper ); 298result .linkingOutput = program .getInfoLog (); 299result .linkingError = program .getInfoDebugLog (); 300 } 301delete ioMapper ; 302delete resolver ; 303 304success &=verifyIOMapping (result .linkingError ,program ); 305result .validationResult = success ; 306 307if (success && (controls & EShMsgSpvRules )) { 308for (int stage = 0 ;stage < EShLangCount ;++ stage ) { 309if (program .getIntermediate ((EShLanguage )stage )) { 310 spv::SpvBuildLogger logger ; 311 std::vector < uint32_t > spirv_binary ; 312options ().disableOptimizer = false; 313 glslang::GlslangToSpv (* program .getIntermediate ((EShLanguage )stage ), 314spirv_binary ,& logger ,& options ()); 315 316 std::ostringstream disassembly_stream ; 317 spv::Disassemble (disassembly_stream ,spirv_binary ); 318result .spirvWarningsErrors += logger .getAllMessages (); 319result .spirv += disassembly_stream .str (); 320result .validationResult &= !options ().validate || logger .getAllMessages ().empty (); 321 } 322 } 323 } 324 325 std::ostringstream stream ; 326outputResultToStream (& stream ,result ,controls ); 327 328// Check with expected results. 329const std::string expectedOutputFname = 330GlobalTestSettings .testRoot + "/baseResults/" + fileNames .front ()+ ".out" ; 331 std::string expectedOutput ; 332tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 333 334checkEqAndUpdateIfRequested (expectedOutput ,stream .str (),expectedOutputFname , 335result .spirvWarningsErrors ); 336} 337 338// clang-format off 339INSTANTIATE_TEST_SUITE_P ( 340Glsl ,GlslMapIOTest , 341 ::testing::ValuesIn (std::vector < IoMapData > ({ 342 {{"iomap.crossStage.vert" ,"iomap.crossStage.frag" },Semantics ::OpenGL }, 343 {{"iomap.crossStage.2.vert" ,"iomap.crossStage.2.geom" ,"iomap.crossStage.2.frag" },Semantics ::OpenGL }, 344 {{"iomap.blockOutVariableIn.vert" ,"iomap.blockOutVariableIn.frag" },Semantics ::OpenGL }, 345 {{"iomap.variableOutBlockIn.vert" ,"iomap.variableOutBlockIn.frag" },Semantics ::OpenGL }, 346 {{"iomap.blockOutVariableIn.2.vert" ,"iomap.blockOutVariableIn.geom" },Semantics ::OpenGL }, 347 {{"iomap.variableOutBlockIn.2.vert" ,"iomap.variableOutBlockIn.geom" },Semantics ::OpenGL }, 348 {{"iomap.mismatchedBufferTypes.vert" ,"iomap.mismatchedBufferTypes.frag" },Semantics ::OpenGL }, 349 {{"iomap.bindingPerResourceType.vert" ,"iomap.bindingPerResourceType.frag" },Semantics ::OpenGL }, 350 {{"iomap.atomicCounter.frag" },Semantics ::OpenGL }, 351// vulkan semantics 352 {{"iomap.crossStage.vk.vert" ,"iomap.crossStage.vk.geom" ,"iomap.crossStage.vk.frag" },Semantics ::Vulkan }, 353 })) 354); 355// clang-format on 356 357}// anonymous namespace 358}// namespace glslangtest