blob: 4585218e5471084feacc1e85044027998f01173e [file] [log] [blame]
/*
* Copyright 2024 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/sksl/codegen/SkSLSPIRVValidator.h"
#include "src/sksl/SkSLErrorReporter.h"
#include "src/sksl/SkSLPosition.h"
#include "spirv-tools/libspirv.hpp"
namespace SkSL {
static bool validate_spirv(ErrorReporter& reporter,
SkSpan<const uint32_t> program,
bool disassemble) {
spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
std::string errors;
auto msgFn = [&errors](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
errors += "SPIR-V validation error: ";
errors += m;
errors += '\n';
};
tools.SetMessageConsumer(msgFn);
bool result = tools.Validate(program.data(), program.size());
if (result) {
return true;
}
// If disassemble is set, we won't abort but instead append the errors. This allows
// us to keep going and show all the errors, which is used by skslc to make sure
// expected validation errors fail as expected..
if (disassemble) {
// Send the message, plus the entire disassembled SPIR-V (for easier context & debugging)
// as if were an SkSL compile error message.
std::string disassembly;
uint32_t options = spvtools::SpirvTools::kDefaultDisassembleOption;
options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT | SPV_BINARY_TO_TEXT_OPTION_INDENT |
SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT;
if (tools.Disassemble(program.data(), program.size(), &disassembly, options)) {
errors.append(disassembly);
}
reporter.error(Position(), errors);
} else {
// Normal validation mode - abort() in a debug build with an error message.
SkDEBUGFAILF("%s", errors.c_str());
}
return false;
}
bool ValidateSPIRV(ErrorReporter& reporter, SkSpan<const uint32_t> program) {
return validate_spirv(reporter, program, false);
}
bool ValidateSPIRVAndDissassemble(ErrorReporter& reporter, SkSpan<const uint32_t> program) {
return validate_spirv(reporter, program, true);
}
} // namespace SkSL