1 /*
2 * Copyright 2024 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/sksl/codegen/SkSLSPIRVValidator.h"
9
10 #include "src/sksl/SkSLErrorReporter.h"
11 #include "src/sksl/SkSLPosition.h"
12
13 #include "spirv-tools/libspirv.hpp"
14
15 namespace SkSL {
16
validate_spirv(ErrorReporter & reporter,std::string_view program,bool disassemble)17 static bool validate_spirv(ErrorReporter& reporter, std::string_view program, bool disassemble) {
18 SkASSERT(0 == program.size() % 4);
19 const uint32_t* programData = reinterpret_cast<const uint32_t*>(program.data());
20 size_t programSize = program.size() / 4;
21
22 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
23 std::string errors;
24 auto msgFn = [&errors](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
25 errors += "SPIR-V validation error: ";
26 errors += m;
27 errors += '\n';
28 };
29 tools.SetMessageConsumer(msgFn);
30
31 bool result = tools.Validate(programData, programSize);
32 if (result) {
33 return true;
34 }
35 // If disassemble is set, we won't abort but instead append the errors. This allows
36 // us to keep going and show all the errors, which is used by skslc to make sure
37 // expected validation errors fail as expected..
38 if (disassemble) {
39 // Send the message, plus the entire disassembled SPIR-V (for easier context & debugging)
40 // as if were an SkSL compile error message.
41 std::string disassembly;
42 uint32_t options = spvtools::SpirvTools::kDefaultDisassembleOption;
43 options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
44 if (tools.Disassemble(programData, programSize, &disassembly, options)) {
45 errors.append(disassembly);
46 }
47 reporter.error(Position(), errors);
48 } else {
49 // Normal validation mode - abort() in a debug build with an error message.
50 SkDEBUGFAILF("%s", errors.c_str());
51 }
52 return false;
53 }
54
ValidateSPIRV(ErrorReporter & reporter,std::string_view program)55 bool ValidateSPIRV(ErrorReporter& reporter, std::string_view program) {
56 return validate_spirv(reporter, program, false);
57 }
58
ValidateSPIRVAndDissassemble(ErrorReporter & reporter,std::string_view program)59 bool ValidateSPIRVAndDissassemble(ErrorReporter& reporter, std::string_view program) {
60 return validate_spirv(reporter, program, true);
61 }
62
63 } // namespace SkSL
64