yum-mirror/glslang
git clone https://git.yummers.dev/yum-mirror/glslang
5336e80d
main
1// 2// Copyright (C) 2016 Google, Inc. 3// 4// All rights reserved. 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions 8// are met: 9// 10// Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// 13// Redistributions in binary form must reproduce the above 14// copyright notice, this list of conditions and the following 15// disclaimer in the documentation and/or other materials provided 16// with the distribution. 17// 18// Neither the name of Google Inc. nor the names of its 19// contributors may be used to endorse or promote products derived 20// from this software without specific prior written permission. 21// 22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33// POSSIBILITY OF SUCH DAMAGE. 34 35#ifndef GLSLANG_GTESTS_TEST_FIXTURE_H 36#define GLSLANG_GTESTS_TEST_FIXTURE_H 37 38#include <algorithm> 39#include <cstdint> 40#include <fstream> 41#include <sstream> 42#include <streambuf> 43#include <tuple> 44#include <string> 45 46#include <gtest/gtest.h> 47 48#include "SPIRV/GlslangToSpv.h" 49#include "SPIRV/disassemble.h" 50#include "SPIRV/doc.h" 51#include "glslang/Include/Types.h" 52#include "glslang/Public/ResourceLimits.h" 53#include "glslang/Public/ShaderLang.h" 54 55#include "Initializer.h" 56#include "Settings.h" 57 58namespace glslangtest { 59 60// This function is used to provide custom test name suffixes based on the 61// shader source file names. Otherwise, the test name suffixes will just be 62// numbers, which are not quite obvious. 63std ::string FileNameAsCustomTestSuffix ( 64const ::testing ::TestParamInfo < std ::string >& info ); 65 66enum class Source { 67GLSL , 68HLSL , 69}; 70 71// Enum for shader compilation semantics. 72enum class Semantics { 73OpenGL , 74Vulkan 75}; 76 77// Enum for compilation target. 78enum class Target { 79AST , 80Spv , 81BothASTAndSpv , 82}; 83 84EShLanguage GetShaderStage (const std ::string & stage ); 85 86EShMessages DeriveOptions (Source ,Semantics ,Target ); 87 88// Reads the content of the file at the given |path|. On success, returns true 89// and the contents; otherwise, returns false and an empty string. 90std ::pair < bool ,std ::string > ReadFile (const std ::string & path ); 91std ::pair < bool ,std ::vector < std ::uint32_t > > ReadSpvBinaryFile (const std ::string & path ); 92 93// Writes the given |contents| into the file at the given |path|. Returns true 94// on successful output. 95bool WriteFile (const std ::string & path ,const std ::string & contents ); 96 97// Returns the suffix of the given |name|. 98std ::string GetSuffix (const std ::string & name ); 99 100// Base class for glslang integration tests. It contains many handy utility-like 101// methods such as reading shader source files, compiling into AST/SPIR-V, and 102// comparing with expected outputs. 103// 104// To write value-Parameterized tests: 105// using ValueParamTest = GlslangTest<::testing::TestWithParam<std::string>>; 106// To use as normal fixture: 107// using FixtureTest = GlslangTest<::testing::Test>; 108template < typename GT > 109class GlslangTest :public GT { 110public : 111GlslangTest () 112 :defaultVersion (100 ), 113defaultProfile (ENoProfile ), 114forceVersionProfile (false), 115isForwardCompatible (false) { 116// Perform validation by default. 117spirvOptions .validate = true; 118 } 119 120// Tries to load the contents from the file at the given |path|. On success, 121// writes the contents into |contents|. On failure, errors out. 122void tryLoadFile (const std ::string & path ,const std ::string & tag , 123std ::string * contents ) 124 { 125bool fileReadOk ; 126std ::tie (fileReadOk ,* contents )= ReadFile (path ); 127ASSERT_TRUE (fileReadOk ) <<"Cannot open " <<tag <<" file: " <<path ; 128 } 129 130// Tries to load the contents from the file at the given |path|. On success, 131// writes the contents into |contents|. On failure, errors out. 132void tryLoadSpvFile (const std ::string & path ,const std ::string & tag , 133std ::vector < uint32_t >& contents ) 134 { 135bool fileReadOk ; 136std ::tie (fileReadOk ,contents )= ReadSpvBinaryFile (path ); 137ASSERT_TRUE (fileReadOk ) <<"Cannot open " <<tag <<" file: " <<path ; 138 } 139 140// Checks the equality of |expected| and |real|. If they are not equal, 141// write |real| to the given file named as |fname| if update mode is on. 142void checkEqAndUpdateIfRequested (const std ::string & expected , 143const std ::string & real , 144const std ::string & fname , 145const std ::string & errorsAndWarnings = "" ) 146 { 147// In order to output the message we want under proper circumstances, 148// we need the following operator<< stuff. 149EXPECT_EQ (expected ,real ) 150 << (GlobalTestSettings .updateMode 151 ? ("Mismatch found and update mode turned on - " 152"flushing expected result output.\n" ) 153 :"" ) 154 <<"The following warnings/errors occurred:\n" 155 <<errorsAndWarnings ; 156 157// Update the expected output file if requested. 158// It looks weird to duplicate the comparison between expected_output 159// and stream.str(). However, if creating a variable for the comparison 160// result, we cannot have pretty print of the string diff in the above. 161if (GlobalTestSettings .updateMode && expected != real ) { 162EXPECT_TRUE (WriteFile (fname ,real )) <<"Flushing failed" ; 163 } 164 } 165 166struct ShaderResult { 167std ::string shaderName ; 168std ::string output ; 169std ::string error ; 170 }; 171 172// A struct for holding all the information returned by glslang compilation 173// and linking. 174struct GlslangResult { 175std ::vector < ShaderResult > shaderResults ; 176std ::string linkingOutput ; 177std ::string linkingError ; 178bool validationResult ; 179std ::string spirvWarningsErrors ; 180std ::string spirv ;// Optional SPIR-V disassembly text. 181 }; 182 183// Compiles and the given source |code| of the given shader |stage| into 184// the target under the semantics conveyed via |controls|. Returns true 185// and modifies |shader| on success. 186bool compile (glslang ::TShader * shader ,const std ::string & code , 187const std ::string & entryPointName ,EShMessages controls , 188const TBuiltInResource * resources = nullptr , 189const std ::string * shaderName = nullptr ) 190 { 191const char * shaderStrings = code .data (); 192const int shaderLengths = static_cast < int > (code .size ()); 193const char * shaderNames = nullptr ; 194 195if ((controls & EShMsgDebugInfo )&& shaderName != nullptr ) { 196shaderNames = shaderName -> data (); 197shader -> setStringsWithLengthsAndNames ( 198& shaderStrings ,& shaderLengths ,& shaderNames ,1 ); 199 }else 200shader -> setStringsWithLengths (& shaderStrings ,& shaderLengths ,1 ); 201if (!entryPointName .empty ())shader -> setEntryPoint (entryPointName .c_str ()); 202 203// A includer that always assumes header name is a relative path to the test folder. 204class GlslangTestIncluder :public glslang ::TShader ::Includer { 205public : 206virtual IncludeResult * includeLocal (const char * headerName ,const char * /*includerName*/ , 207size_t /*inclusionDepth*/ )override 208 { 209std ::string path = GLSLANG_TEST_DIRECTORY ; 210path += '/' ; 211path += headerName ; 212std ::replace (path .begin (),path .end (),'\\' ,'/' ); 213 214 auto [success ,fileContent ]= ReadFile (path ); 215if (success ) { 216 autobuffer = new char [fileContent .size ()+ 1 ]; 217std ::copy (fileContent .begin (),fileContent .end (),buffer ); 218buffer [fileContent .size ()]= '\0' ; 219 220return new IncludeResult (headerName ,buffer ,fileContent .size (),buffer ); 221 } 222 223return nullptr ; 224 } 225 226virtual void releaseInclude (IncludeResult * result )override 227 { 228if (result != nullptr ) { 229delete []static_cast < char *> (result -> userData ); 230delete result ; 231 } 232 } 233 }; 234 235GlslangTestIncluder includer ; 236return shader -> parse ((resources ?resources :GetDefaultResources ()),defaultVersion ,isForwardCompatible , 237controls ,includer ); 238 } 239 240// Compiles and links the given source |code| of the given shader 241// |stage| into the target under the semantics specified via |controls|. 242// Returns a GlslangResult instance containing all the information generated 243// during the process. If the target includes SPIR-V, also disassembles 244// the result and returns disassembly text. 245GlslangResult compileAndLink ( 246const std ::string & shaderName ,const std ::string & code , 247const std ::string & entryPointName ,EShMessages controls , 248glslang ::EShTargetClientVersion clientTargetVersion , 249glslang ::EShTargetLanguageVersion targetLanguageVersion , 250bool flattenUniformArrays = false, 251EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep , 252bool enableOptimizer = false, 253bool enableDebug = false, 254bool enableNonSemanticShaderDebugInfo = false, 255bool automap = true) 256 { 257const EShLanguage stage = GetShaderStage (GetSuffix (shaderName )); 258 259glslang ::TShader shader (stage ); 260if (automap ) { 261shader .setAutoMapLocations (true); 262shader .setAutoMapBindings (true); 263 } 264 265if (enableDebug ) { 266shader .setDebugInfo (true); 267 } 268if (enableNonSemanticShaderDebugInfo ) { 269assert (enableDebug && "Debug must be on for non-semantic debug info" ); 270 } 271 272shader .setTextureSamplerTransformMode (texSampTransMode ); 273#ifdef ENABLE_HLSL 274shader .setFlattenUniformArrays (flattenUniformArrays ); 275#endif 276 277if (controls & EShMsgSpvRules ) { 278if (controls & EShMsgVulkanRules ) { 279shader .setEnvInput ((controls & EShMsgReadHlsl ) ?glslang ::EShSourceHlsl 280 :glslang ::EShSourceGlsl , 281stage ,glslang ::EShClientVulkan ,100 ); 282shader .setEnvClient (glslang ::EShClientVulkan ,clientTargetVersion ); 283shader .setEnvTarget (glslang ::EShTargetSpv ,targetLanguageVersion ); 284 }else { 285shader .setEnvInput ((controls & EShMsgReadHlsl ) ?glslang ::EShSourceHlsl 286 :glslang ::EShSourceGlsl , 287stage ,glslang ::EShClientOpenGL ,100 ); 288shader .setEnvClient (glslang ::EShClientOpenGL ,clientTargetVersion ); 289shader .setEnvTarget (glslang ::EshTargetSpv ,glslang ::EShTargetSpv_1_0 ); 290 } 291 } 292 293if (options ().compileOnly ) 294shader .setCompileOnly (); 295 296bool success = compile ( 297& shader ,code ,entryPointName ,controls ,nullptr ,& shaderName ); 298 299glslang ::TProgram program ; 300spv ::SpvBuildLogger logger ; 301std ::vector < uint32_t > spirv_binary ; 302 303if (!options ().compileOnly ) { 304program .addShader (& shader ); 305success &=program .link (controls ); 306if (success ) 307program .mapIO (); 308 309if (success && (controls & EShMsgSpvRules )) { 310options ().disableOptimizer = !enableOptimizer ; 311options ().generateDebugInfo = enableDebug ; 312options ().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo ; 313options ().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo ; 314glslang ::GlslangToSpv (* program .getIntermediate (stage ),spirv_binary ,& logger ,& options ()); 315 }else { 316return {{ 317 {shaderName ,shader .getInfoLog (),shader .getInfoDebugLog ()}, 318 }, 319program .getInfoLog (), 320program .getInfoDebugLog (), 321 true, 322"" , 323"" }; 324 } 325 }else { 326options ().disableOptimizer = !enableOptimizer ; 327options ().generateDebugInfo = enableDebug ; 328options ().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo ; 329options ().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo ; 330glslang ::GlslangToSpv (* shader .getIntermediate (),spirv_binary ,& logger ,& options ()); 331 } 332 333std ::ostringstream disassembly_stream ; 334spv ::Disassemble (disassembly_stream ,spirv_binary ); 335bool validation_result = !options ().validate || logger .getAllMessages ().empty (); 336return {{ 337 {shaderName ,shader .getInfoLog (),shader .getInfoDebugLog ()}, 338 }, 339program .getInfoLog (), 340program .getInfoDebugLog (), 341validation_result , 342logger .getAllMessages (), 343disassembly_stream .str ()}; 344 } 345 346// Compiles and links the given source |code| of the given shader 347// |stage| into the target under the semantics specified via |controls|. 348// Returns a GlslangResult instance containing all the information generated 349// during the process. If the target includes SPIR-V, also disassembles 350// the result and returns disassembly text. 351GlslangResult compileLinkIoMap ( 352const std ::string shaderName ,const std ::string & code , 353const std ::string & entryPointName ,EShMessages controls , 354int baseSamplerBinding , 355int baseTextureBinding , 356int baseImageBinding , 357int baseUboBinding , 358int baseSsboBinding , 359bool autoMapBindings , 360bool flattenUniformArrays ) 361 { 362const EShLanguage stage = GetShaderStage (GetSuffix (shaderName )); 363 364glslang ::TShader shader (stage ); 365shader .setShiftSamplerBinding (baseSamplerBinding ); 366shader .setShiftTextureBinding (baseTextureBinding ); 367shader .setShiftImageBinding (baseImageBinding ); 368shader .setShiftUboBinding (baseUboBinding ); 369shader .setShiftSsboBinding (baseSsboBinding ); 370shader .setAutoMapBindings (autoMapBindings ); 371shader .setAutoMapLocations (true); 372#ifdef ENABLE_HLSL 373shader .setFlattenUniformArrays (flattenUniformArrays ); 374#endif 375 376bool success = compile (& shader ,code ,entryPointName ,controls ); 377 378glslang ::TProgram program ; 379program .addShader (& shader ); 380 381success &=program .link (controls ); 382if (success ) 383program .mapIO (); 384 385spv ::SpvBuildLogger logger ; 386 387if (success && (controls & EShMsgSpvRules )) { 388std ::vector < uint32_t > spirv_binary ; 389glslang ::GlslangToSpv (* program .getIntermediate (stage ), 390spirv_binary ,& logger ,& options ()); 391 392std ::ostringstream disassembly_stream ; 393spv ::Disassemble (disassembly_stream ,spirv_binary ); 394bool validation_result = !options ().validate || logger .getAllMessages ().empty (); 395return {{{shaderName ,shader .getInfoLog (),shader .getInfoDebugLog ()},}, 396program .getInfoLog (),program .getInfoDebugLog (), 397validation_result ,logger .getAllMessages (),disassembly_stream .str ()}; 398 }else { 399return {{{shaderName ,shader .getInfoLog (),shader .getInfoDebugLog ()},}, 400program .getInfoLog (),program .getInfoDebugLog (), true,"" ,"" }; 401 } 402 } 403 404void outputResultToStream (std ::ostringstream * stream , 405const GlslangResult & result , 406EShMessages controls ) 407 { 408const autooutputIfNotEmpty = [& stream ](const std ::string & str ) { 409if (!str .empty ())* stream <<str <<"\n" ; 410 }; 411 412for (const auto& shaderResult :result .shaderResults ) { 413* stream <<shaderResult .shaderName <<"\n" ; 414outputIfNotEmpty (shaderResult .output ); 415outputIfNotEmpty (shaderResult .error ); 416 } 417outputIfNotEmpty (result .linkingOutput ); 418outputIfNotEmpty (result .linkingError ); 419if (!result .validationResult ) { 420* stream <<"Validation failed\n" ; 421 } 422 423if (controls & EShMsgSpvRules ) { 424* stream 425 << (result .spirv .empty () 426 ?"SPIR-V is not generated for failed compile or link\n" 427 :result .spirv ); 428 } 429 } 430 431void loadFileCompileAndCheck (const std ::string & testDir , 432const std ::string & testName , 433Source source , 434Semantics semantics , 435glslang ::EShTargetClientVersion clientTargetVersion , 436glslang ::EShTargetLanguageVersion targetLanguageVersion , 437Target target , 438bool automap = true, 439const std ::string & entryPointName = "" , 440const std ::string & baseDir = "/baseResults/" , 441const bool enableOptimizer = false, 442const bool enableDebug = false, 443const bool enableNonSemanticShaderDebugInfo = false) 444 { 445#ifndef ENABLE_HLSL 446if (source == Source ::HLSL ) { 447return ; 448 } 449#endif 450const std ::string inputFname = testDir + "/" + testName ; 451const std ::string expectedOutputFname = 452testDir + baseDir + testName + ".out" ; 453std ::string input ,expectedOutput ; 454 455tryLoadFile (inputFname , "input ",& input ); 456tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 457 458EShMessages controls = DeriveOptions (source ,semantics ,target ); 459if (enableOptimizer ) 460controls = static_cast < EShMessages > (controls & ~EShMsgHlslLegalization ); 461if (enableDebug ) 462controls = static_cast < EShMessages > (controls |EShMsgDebugInfo ); 463GlslangResult result = compileAndLink (testName ,input ,entryPointName ,controls ,clientTargetVersion , 464targetLanguageVersion , false,EShTexSampTransKeep ,enableOptimizer ,enableDebug , 465enableNonSemanticShaderDebugInfo ,automap ); 466 467// Generate the hybrid output in the way of glslang. 468std ::ostringstream stream ; 469outputResultToStream (& stream ,result ,controls ); 470 471checkEqAndUpdateIfRequested (expectedOutput ,stream .str (), 472expectedOutputFname ,result .spirvWarningsErrors ); 473 } 474 475void loadFileCompileAndCheckWithOptions (const std ::string & testDir , 476const std ::string & testName , 477Source source , 478Semantics semantics , 479glslang ::EShTargetClientVersion clientTargetVersion , 480glslang ::EShTargetLanguageVersion targetLanguageVersion , 481Target target ,bool automap = true,const std ::string & entryPointName = "" , 482const std ::string & baseDir = "/baseResults/" , 483const EShMessages additionalOptions = EShMessages ::EShMsgDefault ) 484 { 485#ifndef ENABLE_HLSL 486if (source == Source ::HLSL ) { 487return ; 488 } 489#endif 490const std ::string inputFname = testDir + "/" + testName ; 491const std ::string expectedOutputFname = testDir + baseDir + testName + ".out" ; 492std ::string input ,expectedOutput ; 493 494tryLoadFile (inputFname ,"input" ,& input ); 495tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 496 497EShMessages controls = DeriveOptions (source ,semantics ,target ); 498controls = static_cast < EShMessages > (controls |additionalOptions ); 499GlslangResult result = compileAndLink (testName ,input ,entryPointName ,controls ,clientTargetVersion , 500targetLanguageVersion , false,EShTexSampTransKeep , false, false, false,automap ); 501 502// Generate the hybrid output in the way of glslang. 503std ::ostringstream stream ; 504outputResultToStream (& stream ,result ,controls ); 505 506checkEqAndUpdateIfRequested (expectedOutput ,stream .str (),expectedOutputFname ); 507 } 508 509void loadFileCompileFlattenUniformsAndCheck (const std ::string & testDir , 510const std ::string & testName , 511Source source , 512Semantics semantics , 513Target target , 514const std ::string & entryPointName = "" ) 515 { 516#ifndef ENABLE_HLSL 517if (source == Source ::HLSL ) { 518return ; 519 } 520#endif 521const std ::string inputFname = testDir + "/" + testName ; 522const std ::string expectedOutputFname = 523testDir + "/baseResults/" + testName + ".out" ; 524std ::string input ,expectedOutput ; 525 526tryLoadFile (inputFname ,"input" ,& input ); 527tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 528 529const EShMessages controls = DeriveOptions (source ,semantics ,target ); 530GlslangResult result = compileAndLink (testName ,input ,entryPointName ,controls , 531glslang ::EShTargetVulkan_1_0 ,glslang ::EShTargetSpv_1_0 , true); 532 533// Generate the hybrid output in the way of glslang. 534std ::ostringstream stream ; 535outputResultToStream (& stream ,result ,controls ); 536 537checkEqAndUpdateIfRequested (expectedOutput ,stream .str (), 538expectedOutputFname ,result .spirvWarningsErrors ); 539 } 540 541void loadFileCompileIoMapAndCheck (const std ::string & testDir , 542const std ::string & testName , 543Source source , 544Semantics semantics , 545Target target , 546const std ::string & entryPointName , 547int baseSamplerBinding , 548int baseTextureBinding , 549int baseImageBinding , 550int baseUboBinding , 551int baseSsboBinding , 552bool autoMapBindings , 553bool flattenUniformArrays , 554bool relaxSetBindingLimits ) 555 { 556#ifndef ENABLE_HLSL 557if (source == Source ::HLSL ) { 558return ; 559 } 560#endif 561const std ::string inputFname = testDir + "/" + testName ; 562const std ::string expectedOutputFname = 563testDir + "/baseResults/" + testName + ".out" ; 564std ::string input ,expectedOutput ; 565 566tryLoadFile (inputFname ,"input" ,& input ); 567tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 568 569EShMessages controls = DeriveOptions (source ,semantics ,target ); 570if (relaxSetBindingLimits ) 571controls = static_cast < EShMessages > (controls |EShMsgRelaxSetBindingLimits ); 572GlslangResult result = compileLinkIoMap (testName ,input ,entryPointName ,controls , 573baseSamplerBinding ,baseTextureBinding ,baseImageBinding , 574baseUboBinding ,baseSsboBinding , 575autoMapBindings , 576flattenUniformArrays ); 577 578// Generate the hybrid output in the way of glslang. 579std ::ostringstream stream ; 580outputResultToStream (& stream ,result ,controls ); 581 582checkEqAndUpdateIfRequested (expectedOutput ,stream .str (), 583expectedOutputFname ,result .spirvWarningsErrors ); 584 } 585 586// Preprocesses the given |source| code. On success, returns true, the 587// preprocessed shader, and warning messages. Otherwise, returns false, an 588// empty string, and error messages. 589std ::tuple < bool ,std ::string ,std ::string > preprocess ( 590const std ::string & source ) 591 { 592const char * shaderStrings = source .data (); 593const int shaderLengths = static_cast < int > (source .size ()); 594 595glslang ::TShader shader (EShLangVertex ); 596shader .setStringsWithLengths (& shaderStrings ,& shaderLengths ,1 ); 597std ::string ppShader ; 598glslang ::TShader ::ForbidIncluder includer ; 599const bool success = shader .preprocess ( 600GetDefaultResources (),defaultVersion ,defaultProfile ,forceVersionProfile ,isForwardCompatible , 601 (EShMessages )(EShMsgOnlyPreprocessor |EShMsgCascadingErrors ), 602& ppShader ,includer ); 603 604std ::string log = shader .getInfoLog (); 605log += shader .getInfoDebugLog (); 606if (success ) { 607return std ::make_tuple (true,ppShader ,log ); 608 }else { 609return std ::make_tuple (false,"" ,log ); 610 } 611 } 612 613void loadFilePreprocessAndCheck (const std ::string & testDir , 614const std ::string & testName ) 615 { 616const std ::string inputFname = testDir + "/" + testName ; 617const std ::string expectedOutputFname = 618testDir + "/baseResults/" + testName + ".out" ; 619const std ::string expectedErrorFname = 620testDir + "/baseResults/" + testName + ".err" ; 621std ::string input ,expectedOutput ,expectedError ; 622 623tryLoadFile (inputFname ,"input" ,& input ); 624tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 625tryLoadFile (expectedErrorFname ,"expected error" ,& expectedError ); 626 627bool ppOk ; 628std ::string output ,error ; 629std ::tie (ppOk ,output ,error )= preprocess (input ); 630if (!output .empty ())output += '\n' ; 631if (!error .empty ())error += '\n' ; 632 633checkEqAndUpdateIfRequested (expectedOutput ,output , 634expectedOutputFname ); 635checkEqAndUpdateIfRequested (expectedError ,error , 636expectedErrorFname ); 637 } 638 639void loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck (const std ::string & testDir , 640const std ::string & testName , 641Source source , 642Semantics semantics , 643Target target , 644const std ::string & entryPointName = "" ) 645 { 646const std ::string inputFname = testDir + "/" + testName ; 647const std ::string expectedOutputFname = testDir + "/baseResults/" + testName + ".out" ; 648std ::string input ,expectedOutput ; 649 650tryLoadFile (inputFname ,"input" ,& input ); 651tryLoadFile (expectedOutputFname ,"expected output" ,& expectedOutput ); 652 653const EShMessages controls = DeriveOptions (source ,semantics ,target ); 654GlslangResult result = compileAndLink (testName ,input ,entryPointName ,controls , 655glslang ::EShTargetVulkan_1_0 ,glslang ::EShTargetSpv_1_0 , false, 656EShTexSampTransUpgradeTextureRemoveSampler ); 657 658// Generate the hybrid output in the way of glslang. 659std ::ostringstream stream ; 660outputResultToStream (& stream ,result ,controls ); 661 662checkEqAndUpdateIfRequested (expectedOutput ,stream .str (), 663expectedOutputFname ,result .spirvWarningsErrors ); 664 } 665 666glslang ::SpvOptions & options () {return spirvOptions ; } 667 668private : 669const int defaultVersion ; 670const EProfile defaultProfile ; 671const bool forceVersionProfile ; 672const bool isForwardCompatible ; 673glslang ::SpvOptions spirvOptions ; 674}; 675 676}// namespace glslangtest 677 678#endif // GLSLANG_GTESTS_TEST_FIXTURE_H