TestFixture.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. #ifndef GLSLANG_GTESTS_TEST_FIXTURE_H
  35. #define GLSLANG_GTESTS_TEST_FIXTURE_H
  36. #include <algorithm>
  37. #include <cstdint>
  38. #include <fstream>
  39. #include <sstream>
  40. #include <streambuf>
  41. #include <tuple>
  42. #include <string>
  43. #include <gtest/gtest.h>
  44. #include "SPIRV/GlslangToSpv.h"
  45. #include "SPIRV/disassemble.h"
  46. #include "SPIRV/doc.h"
  47. #include "glslang/Include/Types.h"
  48. #include "glslang/Public/ResourceLimits.h"
  49. #include "glslang/Public/ShaderLang.h"
  50. #include "Initializer.h"
  51. #include "Settings.h"
  52. namespace glslangtest {
  53. // This function is used to provide custom test name suffixes based on the
  54. // shader source file names. Otherwise, the test name suffixes will just be
  55. // numbers, which are not quite obvious.
  56. std::string FileNameAsCustomTestSuffix(
  57. const ::testing::TestParamInfo<std::string>& info);
  58. enum class Source {
  59. GLSL,
  60. HLSL,
  61. };
  62. // Enum for shader compilation semantics.
  63. enum class Semantics {
  64. OpenGL,
  65. Vulkan
  66. };
  67. // Enum for compilation target.
  68. enum class Target {
  69. AST,
  70. Spv,
  71. BothASTAndSpv,
  72. };
  73. EShLanguage GetShaderStage(const std::string& stage);
  74. EShMessages DeriveOptions(Source, Semantics, Target);
  75. // Reads the content of the file at the given |path|. On success, returns true
  76. // and the contents; otherwise, returns false and an empty string.
  77. std::pair<bool, std::string> ReadFile(const std::string& path);
  78. std::pair<bool, std::vector<std::uint32_t> > ReadSpvBinaryFile(const std::string& path);
  79. // Writes the given |contents| into the file at the given |path|. Returns true
  80. // on successful output.
  81. bool WriteFile(const std::string& path, const std::string& contents);
  82. // Returns the suffix of the given |name|.
  83. std::string GetSuffix(const std::string& name);
  84. // Base class for glslang integration tests. It contains many handy utility-like
  85. // methods such as reading shader source files, compiling into AST/SPIR-V, and
  86. // comparing with expected outputs.
  87. //
  88. // To write value-Parameterized tests:
  89. // using ValueParamTest = GlslangTest<::testing::TestWithParam<std::string>>;
  90. // To use as normal fixture:
  91. // using FixtureTest = GlslangTest<::testing::Test>;
  92. template <typename GT>
  93. class GlslangTest : public GT {
  94. public:
  95. GlslangTest()
  96. : defaultVersion(100),
  97. defaultProfile(ENoProfile),
  98. forceVersionProfile(false),
  99. isForwardCompatible(false) {
  100. // Perform validation by default.
  101. spirvOptions.validate = true;
  102. }
  103. // Tries to load the contents from the file at the given |path|. On success,
  104. // writes the contents into |contents|. On failure, errors out.
  105. void tryLoadFile(const std::string& path, const std::string& tag,
  106. std::string* contents)
  107. {
  108. bool fileReadOk;
  109. std::tie(fileReadOk, *contents) = ReadFile(path);
  110. ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path;
  111. }
  112. // Tries to load the contents from the file at the given |path|. On success,
  113. // writes the contents into |contents|. On failure, errors out.
  114. void tryLoadSpvFile(const std::string& path, const std::string& tag,
  115. std::vector<uint32_t>& contents)
  116. {
  117. bool fileReadOk;
  118. std::tie(fileReadOk, contents) = ReadSpvBinaryFile(path);
  119. ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path;
  120. }
  121. // Checks the equality of |expected| and |real|. If they are not equal,
  122. // write |real| to the given file named as |fname| if update mode is on.
  123. void checkEqAndUpdateIfRequested(const std::string& expected,
  124. const std::string& real,
  125. const std::string& fname,
  126. const std::string& errorsAndWarnings = "")
  127. {
  128. // In order to output the message we want under proper circumstances,
  129. // we need the following operator<< stuff.
  130. EXPECT_EQ(expected, real)
  131. << (GlobalTestSettings.updateMode
  132. ? ("Mismatch found and update mode turned on - "
  133. "flushing expected result output.\n")
  134. : "")
  135. << "The following warnings/errors occurred:\n"
  136. << errorsAndWarnings;
  137. // Update the expected output file if requested.
  138. // It looks weird to duplicate the comparison between expected_output
  139. // and stream.str(). However, if creating a variable for the comparison
  140. // result, we cannot have pretty print of the string diff in the above.
  141. if (GlobalTestSettings.updateMode && expected != real) {
  142. EXPECT_TRUE(WriteFile(fname, real)) << "Flushing failed";
  143. }
  144. }
  145. struct ShaderResult {
  146. std::string shaderName;
  147. std::string output;
  148. std::string error;
  149. };
  150. // A struct for holding all the information returned by glslang compilation
  151. // and linking.
  152. struct GlslangResult {
  153. std::vector<ShaderResult> shaderResults;
  154. std::string linkingOutput;
  155. std::string linkingError;
  156. bool validationResult;
  157. std::string spirvWarningsErrors;
  158. std::string spirv; // Optional SPIR-V disassembly text.
  159. };
  160. // Compiles and the given source |code| of the given shader |stage| into
  161. // the target under the semantics conveyed via |controls|. Returns true
  162. // and modifies |shader| on success.
  163. bool compile(glslang::TShader* shader, const std::string& code,
  164. const std::string& entryPointName, EShMessages controls,
  165. const TBuiltInResource* resources=nullptr,
  166. const std::string* shaderName=nullptr)
  167. {
  168. const char* shaderStrings = code.data();
  169. const int shaderLengths = static_cast<int>(code.size());
  170. const char* shaderNames = nullptr;
  171. if ((controls & EShMsgDebugInfo) && shaderName != nullptr) {
  172. shaderNames = shaderName->data();
  173. shader->setStringsWithLengthsAndNames(
  174. &shaderStrings, &shaderLengths, &shaderNames, 1);
  175. } else
  176. shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
  177. if (!entryPointName.empty()) shader->setEntryPoint(entryPointName.c_str());
  178. // A includer that always assumes header name is a relative path to the test folder.
  179. class GlslangTestIncluder : public glslang::TShader::Includer {
  180. public:
  181. virtual IncludeResult* includeLocal(const char* headerName, const char* /*includerName*/,
  182. size_t /*inclusionDepth*/) override
  183. {
  184. std::string path = GLSLANG_TEST_DIRECTORY;
  185. path += '/';
  186. path += headerName;
  187. std::replace(path.begin(), path.end(), '\\', '/');
  188. auto [success, fileContent] = ReadFile(path);
  189. if (success) {
  190. auto buffer = new char[fileContent.size() + 1];
  191. std::copy(fileContent.begin(), fileContent.end(), buffer);
  192. buffer[fileContent.size()] = '\0';
  193. return new IncludeResult(headerName, buffer, fileContent.size(), buffer);
  194. }
  195. return nullptr;
  196. }
  197. virtual void releaseInclude(IncludeResult* result) override
  198. {
  199. if (result != nullptr) {
  200. delete[] static_cast<char*>(result->userData);
  201. delete result;
  202. }
  203. }
  204. };
  205. GlslangTestIncluder includer;
  206. return shader->parse((resources ? resources : GetDefaultResources()), defaultVersion, isForwardCompatible,
  207. controls, includer);
  208. }
  209. // Compiles and links the given source |code| of the given shader
  210. // |stage| into the target under the semantics specified via |controls|.
  211. // Returns a GlslangResult instance containing all the information generated
  212. // during the process. If the target includes SPIR-V, also disassembles
  213. // the result and returns disassembly text.
  214. GlslangResult compileAndLink(
  215. const std::string& shaderName, const std::string& code,
  216. const std::string& entryPointName, EShMessages controls,
  217. glslang::EShTargetClientVersion clientTargetVersion,
  218. glslang::EShTargetLanguageVersion targetLanguageVersion,
  219. bool flattenUniformArrays = false,
  220. EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep,
  221. bool enableOptimizer = false,
  222. bool enableDebug = false,
  223. bool enableNonSemanticShaderDebugInfo = false,
  224. bool automap = true)
  225. {
  226. const EShLanguage stage = GetShaderStage(GetSuffix(shaderName));
  227. glslang::TShader shader(stage);
  228. if (automap) {
  229. shader.setAutoMapLocations(true);
  230. shader.setAutoMapBindings(true);
  231. }
  232. if (enableDebug) {
  233. shader.setDebugInfo(true);
  234. }
  235. if (enableNonSemanticShaderDebugInfo) {
  236. assert(enableDebug && "Debug must be on for non-semantic debug info");
  237. }
  238. shader.setTextureSamplerTransformMode(texSampTransMode);
  239. #ifdef ENABLE_HLSL
  240. shader.setFlattenUniformArrays(flattenUniformArrays);
  241. #endif
  242. if (controls & EShMsgSpvRules) {
  243. if (controls & EShMsgVulkanRules) {
  244. shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl
  245. : glslang::EShSourceGlsl,
  246. stage, glslang::EShClientVulkan, 100);
  247. shader.setEnvClient(glslang::EShClientVulkan, clientTargetVersion);
  248. shader.setEnvTarget(glslang::EShTargetSpv, targetLanguageVersion);
  249. } else {
  250. shader.setEnvInput((controls & EShMsgReadHlsl) ? glslang::EShSourceHlsl
  251. : glslang::EShSourceGlsl,
  252. stage, glslang::EShClientOpenGL, 100);
  253. shader.setEnvClient(glslang::EShClientOpenGL, clientTargetVersion);
  254. shader.setEnvTarget(glslang::EshTargetSpv, glslang::EShTargetSpv_1_0);
  255. }
  256. }
  257. if (options().compileOnly)
  258. shader.setCompileOnly();
  259. bool success = compile(
  260. &shader, code, entryPointName, controls, nullptr, &shaderName);
  261. glslang::TProgram program;
  262. spv::SpvBuildLogger logger;
  263. std::vector<uint32_t> spirv_binary;
  264. if (!options().compileOnly) {
  265. program.addShader(&shader);
  266. success &= program.link(controls);
  267. if (success)
  268. program.mapIO();
  269. if (success && (controls & EShMsgSpvRules)) {
  270. options().disableOptimizer = !enableOptimizer;
  271. options().generateDebugInfo = enableDebug;
  272. options().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo;
  273. options().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo;
  274. glslang::GlslangToSpv(*program.getIntermediate(stage), spirv_binary, &logger, &options());
  275. } else {
  276. return {{
  277. {shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},
  278. },
  279. program.getInfoLog(),
  280. program.getInfoDebugLog(),
  281. true,
  282. "",
  283. ""};
  284. }
  285. } else {
  286. options().disableOptimizer = !enableOptimizer;
  287. options().generateDebugInfo = enableDebug;
  288. options().emitNonSemanticShaderDebugInfo = enableNonSemanticShaderDebugInfo;
  289. options().emitNonSemanticShaderDebugSource = enableNonSemanticShaderDebugInfo;
  290. glslang::GlslangToSpv(*shader.getIntermediate(), spirv_binary, &logger, &options());
  291. }
  292. std::ostringstream disassembly_stream;
  293. spv::Disassemble(disassembly_stream, spirv_binary);
  294. bool validation_result = !options().validate || logger.getAllMessages().empty();
  295. return {{
  296. {shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},
  297. },
  298. program.getInfoLog(),
  299. program.getInfoDebugLog(),
  300. validation_result,
  301. logger.getAllMessages(),
  302. disassembly_stream.str()};
  303. }
  304. // Compiles and links the given source |code| of the given shader
  305. // |stage| into the target under the semantics specified via |controls|.
  306. // Returns a GlslangResult instance containing all the information generated
  307. // during the process. If the target includes SPIR-V, also disassembles
  308. // the result and returns disassembly text.
  309. GlslangResult compileLinkIoMap(
  310. const std::string shaderName, const std::string& code,
  311. const std::string& entryPointName, EShMessages controls,
  312. int baseSamplerBinding,
  313. int baseTextureBinding,
  314. int baseImageBinding,
  315. int baseUboBinding,
  316. int baseSsboBinding,
  317. bool autoMapBindings,
  318. bool flattenUniformArrays)
  319. {
  320. const EShLanguage stage = GetShaderStage(GetSuffix(shaderName));
  321. glslang::TShader shader(stage);
  322. shader.setShiftSamplerBinding(baseSamplerBinding);
  323. shader.setShiftTextureBinding(baseTextureBinding);
  324. shader.setShiftImageBinding(baseImageBinding);
  325. shader.setShiftUboBinding(baseUboBinding);
  326. shader.setShiftSsboBinding(baseSsboBinding);
  327. shader.setAutoMapBindings(autoMapBindings);
  328. shader.setAutoMapLocations(true);
  329. #ifdef ENABLE_HLSL
  330. shader.setFlattenUniformArrays(flattenUniformArrays);
  331. #endif
  332. bool success = compile(&shader, code, entryPointName, controls);
  333. glslang::TProgram program;
  334. program.addShader(&shader);
  335. success &= program.link(controls);
  336. if (success)
  337. program.mapIO();
  338. spv::SpvBuildLogger logger;
  339. if (success && (controls & EShMsgSpvRules)) {
  340. std::vector<uint32_t> spirv_binary;
  341. glslang::GlslangToSpv(*program.getIntermediate(stage),
  342. spirv_binary, &logger, &options());
  343. std::ostringstream disassembly_stream;
  344. spv::Disassemble(disassembly_stream, spirv_binary);
  345. bool validation_result = !options().validate || logger.getAllMessages().empty();
  346. return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
  347. program.getInfoLog(), program.getInfoDebugLog(),
  348. validation_result, logger.getAllMessages(), disassembly_stream.str()};
  349. } else {
  350. return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
  351. program.getInfoLog(), program.getInfoDebugLog(), true, "", ""};
  352. }
  353. }
  354. void outputResultToStream(std::ostringstream* stream,
  355. const GlslangResult& result,
  356. EShMessages controls)
  357. {
  358. const auto outputIfNotEmpty = [&stream](const std::string& str) {
  359. if (!str.empty()) *stream << str << "\n";
  360. };
  361. for (const auto& shaderResult : result.shaderResults) {
  362. *stream << shaderResult.shaderName << "\n";
  363. outputIfNotEmpty(shaderResult.output);
  364. outputIfNotEmpty(shaderResult.error);
  365. }
  366. outputIfNotEmpty(result.linkingOutput);
  367. outputIfNotEmpty(result.linkingError);
  368. if (!result.validationResult) {
  369. *stream << "Validation failed\n";
  370. }
  371. if (controls & EShMsgSpvRules) {
  372. *stream
  373. << (result.spirv.empty()
  374. ? "SPIR-V is not generated for failed compile or link\n"
  375. : result.spirv);
  376. }
  377. }
  378. void loadFileCompileAndCheck(const std::string& testDir,
  379. const std::string& testName,
  380. Source source,
  381. Semantics semantics,
  382. glslang::EShTargetClientVersion clientTargetVersion,
  383. glslang::EShTargetLanguageVersion targetLanguageVersion,
  384. Target target,
  385. bool automap = true,
  386. const std::string& entryPointName="",
  387. const std::string& baseDir="/baseResults/",
  388. const bool enableOptimizer = false,
  389. const bool enableDebug = false,
  390. const bool enableNonSemanticShaderDebugInfo = false)
  391. {
  392. const std::string inputFname = testDir + "/" + testName;
  393. const std::string expectedOutputFname =
  394. testDir + baseDir + testName + ".out";
  395. std::string input, expectedOutput;
  396. tryLoadFile(inputFname, "input", &input);
  397. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  398. EShMessages controls = DeriveOptions(source, semantics, target);
  399. if (enableOptimizer)
  400. controls = static_cast<EShMessages>(controls & ~EShMsgHlslLegalization);
  401. if (enableDebug)
  402. controls = static_cast<EShMessages>(controls | EShMsgDebugInfo);
  403. GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion,
  404. targetLanguageVersion, false, EShTexSampTransKeep, enableOptimizer, enableDebug,
  405. enableNonSemanticShaderDebugInfo, automap);
  406. // Generate the hybrid output in the way of glslang.
  407. std::ostringstream stream;
  408. outputResultToStream(&stream, result, controls);
  409. checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
  410. expectedOutputFname, result.spirvWarningsErrors);
  411. }
  412. void loadFileCompileAndCheckWithOptions(const std::string &testDir,
  413. const std::string &testName,
  414. Source source,
  415. Semantics semantics,
  416. glslang::EShTargetClientVersion clientTargetVersion,
  417. glslang::EShTargetLanguageVersion targetLanguageVersion,
  418. Target target, bool automap = true, const std::string &entryPointName = "",
  419. const std::string &baseDir = "/baseResults/",
  420. const EShMessages additionalOptions = EShMessages::EShMsgDefault)
  421. {
  422. const std::string inputFname = testDir + "/" + testName;
  423. const std::string expectedOutputFname = testDir + baseDir + testName + ".out";
  424. std::string input, expectedOutput;
  425. tryLoadFile(inputFname, "input", &input);
  426. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  427. EShMessages controls = DeriveOptions(source, semantics, target);
  428. controls = static_cast<EShMessages>(controls | additionalOptions);
  429. GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion,
  430. targetLanguageVersion, false, EShTexSampTransKeep, false, false, false, automap);
  431. // Generate the hybrid output in the way of glslang.
  432. std::ostringstream stream;
  433. outputResultToStream(&stream, result, controls);
  434. checkEqAndUpdateIfRequested(expectedOutput, stream.str(), expectedOutputFname);
  435. }
  436. void loadFileCompileFlattenUniformsAndCheck(const std::string& testDir,
  437. const std::string& testName,
  438. Source source,
  439. Semantics semantics,
  440. Target target,
  441. const std::string& entryPointName="")
  442. {
  443. const std::string inputFname = testDir + "/" + testName;
  444. const std::string expectedOutputFname =
  445. testDir + "/baseResults/" + testName + ".out";
  446. std::string input, expectedOutput;
  447. tryLoadFile(inputFname, "input", &input);
  448. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  449. const EShMessages controls = DeriveOptions(source, semantics, target);
  450. GlslangResult result = compileAndLink(testName, input, entryPointName, controls,
  451. glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, true);
  452. // Generate the hybrid output in the way of glslang.
  453. std::ostringstream stream;
  454. outputResultToStream(&stream, result, controls);
  455. checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
  456. expectedOutputFname, result.spirvWarningsErrors);
  457. }
  458. void loadFileCompileIoMapAndCheck(const std::string& testDir,
  459. const std::string& testName,
  460. Source source,
  461. Semantics semantics,
  462. Target target,
  463. const std::string& entryPointName,
  464. int baseSamplerBinding,
  465. int baseTextureBinding,
  466. int baseImageBinding,
  467. int baseUboBinding,
  468. int baseSsboBinding,
  469. bool autoMapBindings,
  470. bool flattenUniformArrays)
  471. {
  472. const std::string inputFname = testDir + "/" + testName;
  473. const std::string expectedOutputFname =
  474. testDir + "/baseResults/" + testName + ".out";
  475. std::string input, expectedOutput;
  476. tryLoadFile(inputFname, "input", &input);
  477. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  478. const EShMessages controls = DeriveOptions(source, semantics, target);
  479. GlslangResult result = compileLinkIoMap(testName, input, entryPointName, controls,
  480. baseSamplerBinding, baseTextureBinding, baseImageBinding,
  481. baseUboBinding, baseSsboBinding,
  482. autoMapBindings,
  483. flattenUniformArrays);
  484. // Generate the hybrid output in the way of glslang.
  485. std::ostringstream stream;
  486. outputResultToStream(&stream, result, controls);
  487. checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
  488. expectedOutputFname, result.spirvWarningsErrors);
  489. }
  490. // Preprocesses the given |source| code. On success, returns true, the
  491. // preprocessed shader, and warning messages. Otherwise, returns false, an
  492. // empty string, and error messages.
  493. std::tuple<bool, std::string, std::string> preprocess(
  494. const std::string& source)
  495. {
  496. const char* shaderStrings = source.data();
  497. const int shaderLengths = static_cast<int>(source.size());
  498. glslang::TShader shader(EShLangVertex);
  499. shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
  500. std::string ppShader;
  501. glslang::TShader::ForbidIncluder includer;
  502. const bool success = shader.preprocess(
  503. GetDefaultResources(), defaultVersion, defaultProfile, forceVersionProfile, isForwardCompatible,
  504. (EShMessages)(EShMsgOnlyPreprocessor | EShMsgCascadingErrors),
  505. &ppShader, includer);
  506. std::string log = shader.getInfoLog();
  507. log += shader.getInfoDebugLog();
  508. if (success) {
  509. return std::make_tuple(true, ppShader, log);
  510. } else {
  511. return std::make_tuple(false, "", log);
  512. }
  513. }
  514. void loadFilePreprocessAndCheck(const std::string& testDir,
  515. const std::string& testName)
  516. {
  517. const std::string inputFname = testDir + "/" + testName;
  518. const std::string expectedOutputFname =
  519. testDir + "/baseResults/" + testName + ".out";
  520. const std::string expectedErrorFname =
  521. testDir + "/baseResults/" + testName + ".err";
  522. std::string input, expectedOutput, expectedError;
  523. tryLoadFile(inputFname, "input", &input);
  524. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  525. tryLoadFile(expectedErrorFname, "expected error", &expectedError);
  526. bool ppOk;
  527. std::string output, error;
  528. std::tie(ppOk, output, error) = preprocess(input);
  529. if (!output.empty()) output += '\n';
  530. if (!error.empty()) error += '\n';
  531. checkEqAndUpdateIfRequested(expectedOutput, output,
  532. expectedOutputFname);
  533. checkEqAndUpdateIfRequested(expectedError, error,
  534. expectedErrorFname);
  535. }
  536. void loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(const std::string& testDir,
  537. const std::string& testName,
  538. Source source,
  539. Semantics semantics,
  540. Target target,
  541. const std::string& entryPointName = "")
  542. {
  543. const std::string inputFname = testDir + "/" + testName;
  544. const std::string expectedOutputFname = testDir + "/baseResults/" + testName + ".out";
  545. std::string input, expectedOutput;
  546. tryLoadFile(inputFname, "input", &input);
  547. tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
  548. const EShMessages controls = DeriveOptions(source, semantics, target);
  549. GlslangResult result = compileAndLink(testName, input, entryPointName, controls,
  550. glslang::EShTargetVulkan_1_0, glslang::EShTargetSpv_1_0, false,
  551. EShTexSampTransUpgradeTextureRemoveSampler);
  552. // Generate the hybrid output in the way of glslang.
  553. std::ostringstream stream;
  554. outputResultToStream(&stream, result, controls);
  555. checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
  556. expectedOutputFname, result.spirvWarningsErrors);
  557. }
  558. glslang::SpvOptions& options() { return spirvOptions; }
  559. private:
  560. const int defaultVersion;
  561. const EProfile defaultProfile;
  562. const bool forceVersionProfile;
  563. const bool isForwardCompatible;
  564. glslang::SpvOptions spirvOptions;
  565. };
  566. } // namespace glslangtest
  567. #endif // GLSLANG_GTESTS_TEST_FIXTURE_H