postExtract = postExtractLibpng),
GitRepo(
"https://github.com/KhronosGroup/SPIRV-Tools.git",
- "7ef6da7b7f9175da509b4d71a881c0a04e0b701b",
+ "f7e63786a919040cb2e0e572d960a0650f2c2881",
"spirv-tools"),
GitRepo(
"https://github.com/KhronosGroup/glslang.git",
- "f2d8a5c53fda69a7e19defbda7964f380da54ad1",
+ "5639f3aca5b75cbe5419a623eecf5e3794fab917",
"glslang"),
]
message(FATAL_ERROR "Include Defs.cmake")
endif ()
-if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/include/libspirv/libspirv.h")
+if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/include/spirv-tools/libspirv.h")
set(DEFAULT_SPIRV_TOOLS_SRC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src)
else ()
set(DEFAULT_SPIRV_TOOLS_SRC_PATH "../spirv-tools")
return BuildConfig(buildPath, buildType, ["-DDEQP_TARGET=%s" % targetName])
def cleanDstDir (dstPath):
- binFiles = [f for f in os.listdir(dstPath) if os.path.isfile(os.path.join(dstPath, f)) and fnmatch.fnmatch(f, "*.spirv")]
+ binFiles = [f for f in os.listdir(dstPath) if os.path.isfile(os.path.join(dstPath, f)) and fnmatch.fnmatch(f, "*.spv")]
for binFile in binFiles:
print "Removing %s" % os.path.join(dstPath, binFile)
os.remove(os.path.join(dstPath, binFile))
-def execBuildPrograms (buildCfg, generator, module, mode, dstPath):
- workDir = os.path.join(buildCfg.getBuildDir(), "modules", module.dirName)
+def execBuildPrograms (buildCfg, generator, module, dstPath):
+ fullDstPath = os.path.realpath(dstPath)
+ workDir = os.path.join(buildCfg.getBuildDir(), "modules", module.dirName)
pushWorkingDir(workDir)
try:
binPath = generator.getBinaryPath(buildCfg.getBuildType(), os.path.join(".", "vk-build-programs"))
- execute([binPath, "--mode", mode, "--dst-path", dstPath])
+ execute([binPath, "--validate-spv", "--dst-path", fullDstPath])
finally:
popWorkingDir()
dest="targetName",
default=DEFAULT_TARGET,
help="dEQP build target")
- parser.add_argument("--mode",
- dest="mode",
- default="build",
- help="Build mode (build or verify)")
parser.add_argument("-d",
"--dst-path",
dest="dstPath",
build(buildCfg, generator, ["vk-build-programs"])
- if args.mode == "build":
- if os.path.exists(args.dstPath):
- cleanDstDir(args.dstPath)
- else:
- os.makedirs(args.dstPath)
+ if os.path.exists(args.dstPath):
+ cleanDstDir(args.dstPath)
+ else:
+ os.makedirs(args.dstPath)
- execBuildPrograms(buildCfg, generator, module, args.mode, args.dstPath)
+ execBuildPrograms(buildCfg, generator, module, args.dstPath)
{
const deUint32 indexSize = getIndexSize(root);
- DE_ASSERT(indexSize > 0);
-
- dst->resize(indexSize);
- addAndCountNodes(&(*dst)[0], 0, root);
+ if (indexSize > 0)
+ {
+ dst->resize(indexSize);
+ addAndCountNodes(&(*dst)[0], 0, root);
+ }
+ else
+ {
+ // Generate empty index
+ dst->resize(1);
+ (*dst)[0].word = 0u;
+ (*dst)[0].index = 0u;
+ }
}
} // anonymous
#include "vkGlslToSpirV.hpp"
#include "deArrayUtil.hpp"
+#include "deMutex.hpp"
+#include "deSingleton.h"
#include "deMemory.h"
#include "deClock.h"
#include "qpDebugOut.h"
#if defined(DEQP_HAVE_GLSLANG)
-# include "deSingleton.h"
-# include "deMutex.hpp"
-
# include "SPIRV/GlslangToSpv.h"
# include "SPIRV/disassemble.h"
# include "SPIRV/doc.h"
# include "glslang/Public/ShaderLang.h"
#endif
-#if defined(DEQP_HAVE_SPIRV_TOOLS)
-# include "libspirv/libspirv.h"
-#endif
-
namespace vk
{
} // anonymous
-void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo)
+bool getNumShaderStages (const glu::ProgramSources& program)
+{
+ int numShaderStages = 0;
+
+ for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
+ {
+ if (!program.sources[shaderType].empty())
+ numShaderStages += 1;
+ }
+
+ return numShaderStages;
+}
+
+bool compileGlslToSpirV (const glu::ProgramSources& program, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo)
{
TBuiltInResource builtinRes;
+ if (getNumShaderStages(program) > 1)
+ TCU_THROW(InternalError, "Linking multiple shader stages into a single SPIR-V binary is not supported");
+
prepareGlslang();
getDefaultBuiltInResources(&builtinRes);
const std::string& srcText = program.sources[shaderType][0];
const char* srcPtrs[] = { srcText.c_str() };
const int srcLengths[] = { (int)srcText.size() };
- vector<deUint32> spvBlob;
const EShLanguage shaderStage = getGlslangStage(glu::ShaderType(shaderType));
glslang::TShader shader (shaderStage);
glslang::TProgram program;
shaderBuildInfo.compileOk = (compileRes != 0);
buildInfo->shaders.push_back(shaderBuildInfo);
-
- if (compileRes == 0)
- TCU_FAIL("Failed to compile shader");
}
+ DE_ASSERT(buildInfo->shaders.size() == 1);
+ if (buildInfo->shaders[0].compileOk)
{
const deUint64 linkStartTime = deGetMicroseconds();
const int linkRes = program.link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
buildInfo->program.infoLog = program.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
buildInfo->program.linkOk = (linkRes != 0);
buildInfo->program.linkTimeUs = deGetMicroseconds()-linkStartTime;
-
- if (linkRes == 0)
- TCU_FAIL("Failed to link shader");
}
+ if (buildInfo->program.linkOk)
{
const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage);
- glslang::GlslangToSpv(*intermediate, spvBlob);
+ glslang::GlslangToSpv(*intermediate, *dst);
}
- dst->resize(spvBlob.size() * sizeof(deUint32));
-#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
- deMemcpy(&(*dst)[0], &spvBlob[0], dst->size());
-#else
-# error "Big-endian not supported"
-#endif
-
- return;
+ return buildInfo->program.linkOk;
}
}
#else // defined(DEQP_HAVE_GLSLANG)
-void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>*, glu::ShaderProgramInfo*)
+bool compileGlslToSpirV (const glu::ProgramSources&, std::vector<deUint32>*, glu::ShaderProgramInfo*)
{
TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
}
#endif // defined(DEQP_HAVE_GLSLANG)
-#if defined(DEQP_HAVE_SPIRV_TOOLS)
-void disassembleSpirV (size_t binarySize, const deUint8* binary, std::ostream* dst)
-{
- std::vector<deUint32> binForDisasm (binarySize/4);
-
- DE_ASSERT(binarySize%4 == 0);
-
-#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
- deMemcpy(&binForDisasm[0], binary, binarySize);
-#else
-# error "Big-endian not supported"
-#endif
-
- const spv_context context = spvContextCreate();
- if (!context)
- throw std::bad_alloc();
- spv_text text = DE_NULL;
- spv_diagnostic diagnostic;
- try
- {
- const spv_result_t error = spvBinaryToText(context, &binForDisasm[0], binForDisasm.size() , 0, &text, &diagnostic);
- TCU_CHECK_INTERNAL(!error);
- *dst << text->str;
- }
- catch (...)
- {
- spvTextDestroy(text);
- spvContextDestroy(context);
- throw;
- }
- spvTextDestroy(text);
- spvContextDestroy(context);
-}
-#else // defined(DEQP_HAVE_SPIRV_TOOLS)
-
-void disassembleSpirV (size_t, const deUint8*, std::ostream*)
-{
- TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
-}
-#endif // defined(DEQP_HAVE_SPIRV_TOOLS)
-
} // vk
namespace vk
{
-//! Compile GLSL program to SPIR-V. Will fail with NotSupportedError if compiler is not available.
-void glslToSpirV (const glu::ProgramSources& src, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo);
-
-//! Disassemble SPIR-V binary
-void disassembleSpirV (size_t binarySize, const deUint8* binary, std::ostream* dst);
+/*--------------------------------------------------------------------*//*!
+ * \brief Compile GLSL program to SPIR-V binary
+ * \param src
+ * \param dst
+ * \param buildInfo
+ * \return True if compilation and linking succeeded, false otherwise
+ *
+ * If deqp was built without glslang (and thus compiler is not available)
+ * tcu::NotSupportedError will be thrown instead.
+ *
+ * \note No linking is currently supported so src may contain source
+ * for only one shader stage.
+ *//*--------------------------------------------------------------------*/
+bool compileGlslToSpirV (const glu::ProgramSources& src, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo);
} // vk
#include "deArrayUtil.hpp"
#include "deMemory.h"
+#include "deInt32.h"
namespace vk
{
using std::vector;
using tcu::TestLog;
+#if defined(DE_DEBUG) && defined(DEQP_HAVE_SPIRV_TOOLS)
+# define VALIDATE_BINARIES true
+#else
+# define VALIDATE_BINARIES false
+#endif
+
+#define SPIRV_BINARY_ENDIANNESS DE_LITTLE_ENDIAN
+
// ProgramBinary
ProgramBinary::ProgramBinary (ProgramFormat format, size_t binarySize, const deUint8* binary)
// Utils
+namespace
+{
+
+bool isNativeSpirVBinaryEndianness (void)
+{
+#if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS)
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool isSaneSpirVBinary (const ProgramBinary& binary)
+{
+ const deUint32 spirvMagicWord = 0x07230203;
+ const deUint32 spirvMagicBytes = isNativeSpirVBinaryEndianness()
+ ? spirvMagicWord
+ : deReverseBytes32(spirvMagicWord);
+
+ DE_ASSERT(binary.getFormat() == PROGRAM_FORMAT_SPIRV);
+
+ if (binary.getSize() % sizeof(deUint32) != 0)
+ return false;
+
+ if (binary.getSize() < sizeof(deUint32))
+ return false;
+
+ if (*(const deUint32*)binary.getBinary() != spirvMagicBytes)
+ return false;
+
+ return true;
+}
+
+ProgramBinary* createProgramBinaryFromSpirV (const vector<deUint32>& binary)
+{
+ DE_ASSERT(!binary.empty());
+
+ if (isNativeSpirVBinaryEndianness())
+ return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size()*sizeof(deUint32), (const deUint8*)&binary[0]);
+ else
+ TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
+}
+
+} // anonymous
+
ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo)
{
+ const bool validateBinary = VALIDATE_BINARIES;
+
if (binaryFormat == PROGRAM_FORMAT_SPIRV)
{
- vector<deUint8> binary;
- glslToSpirV(program, &binary, buildInfo);
- // \todo[2016-02-10 dekimir]: Enable this when all glsl tests can pass it.
- //validateSpirV(binary, &buildInfo->program.infoLog);
- return new ProgramBinary(binaryFormat, binary.size(), &binary[0]);
+ vector<deUint32> binary;
+
+ if (!compileGlslToSpirV(program, &binary, buildInfo))
+ TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed");
+
+ if (validateBinary)
+ {
+ std::ostringstream validationLog;
+
+ if (!validateSpirV(binary.size(), &binary[0], &validationLog))
+ {
+ buildInfo->program.linkOk = false;
+ buildInfo->program.infoLog += "\n" + validationLog.str();
+
+ TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary");
+ }
+ }
+
+ return createProgramBinaryFromSpirV(binary);
}
else
TCU_THROW(NotSupportedError, "Unsupported program format");
ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo)
{
- vector<deUint8> binary;
- assembleSpirV(&program, &binary, buildInfo);
-#if defined(DE_DEBUG)
- buildInfo->compileOk &= validateSpirV(binary, &buildInfo->infoLog);
- if (!buildInfo->compileOk)
- TCU_FAIL("Failed to validate shader");
-#endif
- return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size(), &binary[0]);
+ const bool validateBinary = VALIDATE_BINARIES;
+ vector<deUint32> binary;
+
+ if (!assembleSpirV(&program, &binary, buildInfo))
+ TCU_THROW(InternalError, "Failed to assemble SPIR-V");
+
+ if (validateBinary)
+ {
+ std::ostringstream validationLog;
+
+ if (!validateSpirV(binary.size(), &binary[0], &validationLog))
+ {
+ buildInfo->compileOk = false;
+ buildInfo->infoLog += "\n" + validationLog.str();
+
+ TCU_THROW(InternalError, "Validation failed for assembled SPIR-V binary");
+ }
+ }
+
+ return createProgramBinaryFromSpirV(binary);
+}
+
+void disassembleProgram (const ProgramBinary& program, std::ostream* dst)
+{
+ if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
+ {
+ TCU_CHECK_INTERNAL(isSaneSpirVBinary(program));
+
+ if (isNativeSpirVBinaryEndianness())
+ disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
+ else
+ TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
+ }
+ else
+ TCU_THROW(NotSupportedError, "Unsupported program format");
+}
+
+bool validateProgram (const ProgramBinary& program, std::ostream* dst)
+{
+ if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
+ {
+ if (!isSaneSpirVBinary(program))
+ {
+ *dst << "Binary doesn't look like SPIR-V at all";
+ return false;
+ }
+
+ if (isNativeSpirVBinaryEndianness())
+ return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
+ else
+ TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
+ }
+ else
+ TCU_THROW(NotSupportedError, "Unsupported program format");
}
Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags)
typedef ProgramCollection<ProgramBinary> BinaryCollection;
-// \todo [2015-03-13 pyry] Likely need BinaryBuilder abstraction for this
ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo);
ProgramBinary* assembleProgram (const vk::SpirVAsmSource& program, SpirVProgramInfo* buildInfo);
+void disassembleProgram (const ProgramBinary& program, std::ostream* dst);
+bool validateProgram (const ProgramBinary& program, std::ostream* dst);
+
Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags);
glu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage);
#include "vkSpirVAsm.hpp"
#include "vkSpirVProgram.hpp"
-#include "deArrayUtil.hpp"
-#include "deMemory.h"
#include "deClock.h"
-#include "qpDebugOut.h"
+
+#include <algorithm>
#if defined(DEQP_HAVE_SPIRV_TOOLS)
-# include "libspirv/libspirv.h"
+# include "spirv-tools/libspirv.h"
#endif
namespace vk
#if defined(DEQP_HAVE_SPIRV_TOOLS)
-
-void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo)
+bool assembleSpirV (const SpirVAsmSource* program, std::vector<deUint32>* dst, SpirVProgramInfo* buildInfo)
{
- spv_context context = spvContextCreate();
+ const spv_context context = spvContextCreate();
+ spv_binary binary = DE_NULL;
+ spv_diagnostic diagnostic = DE_NULL;
- const std::string& spvSource = program->program.str();
- spv_binary binary = DE_NULL;
- spv_diagnostic diagnostic = DE_NULL;
- const deUint64 compileStartTime = deGetMicroseconds();
- const spv_result_t compileOk = spvTextToBinary(context, spvSource.c_str(), spvSource.size(), &binary, &diagnostic);
+ if (!context)
+ throw std::bad_alloc();
+ try
{
- buildInfo->source = program;
+ const std::string& spvSource = program->source;
+ const deUint64 compileStartTime = deGetMicroseconds();
+ const spv_result_t compileOk = spvTextToBinary(context, spvSource.c_str(), spvSource.size(), &binary, &diagnostic);
+
+ buildInfo->source = spvSource;
buildInfo->infoLog = diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
buildInfo->compileTimeUs = deGetMicroseconds() - compileStartTime;
buildInfo->compileOk = (compileOk == SPV_SUCCESS);
+
+ dst->resize(binary->wordCount);
+ std::copy(&binary->code[0], &binary->code[0] + binary->wordCount, dst->begin());
+
+ spvBinaryDestroy(binary);
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+
+ return compileOk == SPV_SUCCESS;
+ }
+ catch (...)
+ {
+ spvBinaryDestroy(binary);
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+
+ throw;
}
+}
- if (compileOk != SPV_SUCCESS)
- TCU_FAIL("Failed to compile shader");
+void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst)
+{
+ const spv_context context = spvContextCreate();
+ spv_text text = DE_NULL;
+ spv_diagnostic diagnostic = DE_NULL;
- dst->resize((int)binary->wordCount * sizeof(deUint32));
-#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
- deMemcpy(&(*dst)[0], &binary->code[0], dst->size());
-#else
-# error "Big-endian not supported"
-#endif
- spvBinaryDestroy(binary);
- spvDiagnosticDestroy(diagnostic);
- spvContextDestroy(context);
- return;
+ if (!context)
+ throw std::bad_alloc();
+
+ try
+ {
+ const spv_result_t result = spvBinaryToText(context, binary, binarySizeInWords, 0, &text, &diagnostic);
+
+ if (result != SPV_SUCCESS)
+ TCU_THROW(InternalError, "Disassembling SPIR-V failed");
+
+ *dst << text->str;
+
+ spvTextDestroy(text);
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+ }
+ catch (...)
+ {
+ spvTextDestroy(text);
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+
+ throw;
+ }
}
-bool validateSpirV (const std::vector<deUint8>& spirv, std::string* infoLog)
+bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog)
{
- const size_t bytesPerWord = sizeof(uint32_t) / sizeof(deUint8);
- DE_ASSERT(spirv.size() % bytesPerWord == 0);
- std::vector<uint32_t> words(spirv.size() / bytesPerWord);
- deMemcpy(words.data(), spirv.data(), spirv.size());
- spv_const_binary_t cbinary = { words.data(), words.size() };
+ const spv_context context = spvContextCreate();
spv_diagnostic diagnostic = DE_NULL;
- spv_context context = spvContextCreate();
- const spv_result_t valid = spvValidate(context, &cbinary, SPV_VALIDATE_ALL, &diagnostic);
- if (diagnostic)
- *infoLog += diagnostic->error;
- spvContextDestroy(context);
- spvDiagnosticDestroy(diagnostic);
- return valid == SPV_SUCCESS;
+
+ try
+ {
+ spv_const_binary_t cbinary = { binary, binarySizeInWords };
+ const spv_result_t valid = spvValidate(context, &cbinary, &diagnostic);
+
+ if (diagnostic)
+ *infoLog << diagnostic->error;
+
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+
+ return valid == SPV_SUCCESS;
+ }
+ catch (...)
+ {
+ spvDiagnosticDestroy(diagnostic);
+ spvContextDestroy(context);
+
+ throw;
+ }
}
#else // defined(DEQP_HAVE_SPIRV_TOOLS)
-void assembleSpirV (const SpirVAsmSource*, std::vector<deUint8>*, SpirVProgramInfo*)
+bool assembleSpirV (const SpirVAsmSource*, std::vector<deUint32>*, SpirVProgramInfo*)
{
TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
}
-bool validateSpirV (const std::vector<deUint8>&, std::string*)
+void disassembleSpirV (size_t, const deUint32*, std::ostream*)
+{
+ TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
+}
+
+bool validateSpirV (size_t, const deUint32*, std::ostream*)
{
TCU_THROW(NotSupportedError, "SPIR-V validation not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
}
#include "vkDefs.hpp"
#include "vkPrograms.hpp"
+#include <ostream>
+
namespace vk
{
//! Assemble SPIR-V program. Will fail with NotSupportedError if compiler is not available.
-void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo);
+bool assembleSpirV (const SpirVAsmSource* program, std::vector<deUint32>* dst, SpirVProgramInfo* buildInfo);
+
+//! Disassemble SPIR-V binary. Throws tcu::NotSupportedError if disassembler is not available
+void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst);
//! Validate SPIR-V binary, returning true if validation succeeds. Will fail with NotSupportedError if compiler is not available.
-bool validateSpirV (const std::vector<deUint8>& spirv, std::string* infoLog);
+bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog);
} // vk
tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo)
{
- log << tcu::TestLog::ShaderProgram(shaderInfo.compileOk , shaderInfo.infoLog) << tcu::TestLog::SpirVAssemblySource(shaderInfo.source->program.str()) << tcu::TestLog::EndShaderProgram;
+ log << tcu::TestLog::ShaderProgram(shaderInfo.compileOk , shaderInfo.infoLog)
+ << tcu::TestLog::SpirVAssemblySource(shaderInfo.source)
+ << tcu::TestLog::EndShaderProgram;
// Write statistics
log << tcu::TestLog::Float( "SpirVAssemblyTime",
tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVAsmSource& source)
{
- log << tcu::TestLog::KernelSource(source.program.str());
+ log << tcu::TestLog::ShaderProgram(true , "")
+ << tcu::TestLog::SpirVAssemblySource(source.source)
+ << tcu::TestLog::EndShaderProgram;
return log;
}
#include "vkDefs.hpp"
#include "tcuTestLog.hpp"
+#include "deStringUtil.hpp"
#include <string>
-#include <sstream>
namespace vk
{
struct SpirVAsmSource
{
- template<typename T>
- SpirVAsmSource& operator<<(const T& val)
+ SpirVAsmSource (void)
{
- program << val;
- return *this;
}
- std::ostringstream program;
+
+ SpirVAsmSource (const std::string& source_)
+ : source(source_)
+ {
+ }
+
+ std::string source;
};
struct SpirVProgramInfo
{
- SpirVProgramInfo()
- : source (DE_NULL)
- , compileTimeUs (0)
+ SpirVProgramInfo (void)
+ : compileTimeUs (0)
, compileOk (false)
{
}
- const SpirVAsmSource* source;
- std::string infoLog;
- deUint64 compileTimeUs;
- bool compileOk;
+ std::string source;
+ std::string infoLog;
+ deUint64 compileTimeUs;
+ bool compileOk;
};
-tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo);
-tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVAsmSource& program);
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo);
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVAsmSource& program);
+
+// Helper for constructing SpirVAsmSource
+template<typename T>
+SpirVAsmSource& operator<< (SpirVAsmSource& src, const T& val)
+{
+ src.source += de::toString(val);
+ return src;
+}
}
#include "vktTestPackage.hpp"
#include "deUniquePtr.hpp"
#include "deCommandLine.hpp"
+#include "deSharedPtr.hpp"
#include <iostream>
using std::string;
using de::UniquePtr;
using de::MovePtr;
+using de::SharedPtr;
namespace vkt
{
return new tcu::TestPackageRoot(testCtx, children);
}
-enum BuildMode
-{
- BUILDMODE_BUILD = 0,
- BUILDMODE_VERIFY,
-
- BUILDMODE_LAST
-};
-
struct BuildStats
{
int numSucceeded;
namespace // anonymous
{
-vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
-{
- return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
-}
-
-vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
-{
- return vk::assembleProgram(source, buildInfo);
-}
-
-void writeVerboseLogs (const glu::ShaderProgramInfo& buildInfo)
+void writeBuildLogs (const glu::ShaderProgramInfo& buildInfo, std::ostream& dst)
{
for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
{
const glu::ShaderInfo& shaderInfo = buildInfo.shaders[shaderNdx];
const char* const shaderName = getShaderTypeName(shaderInfo.type);
- tcu::print("%s source:\n---\n%s\n---\n", shaderName, shaderInfo.source.c_str());
- tcu::print("%s compile log:\n---\n%s\n---\n", shaderName, shaderInfo.infoLog.c_str());
+ dst << shaderName << " source:\n"
+ << "---\n"
+ << shaderInfo.source << "\n"
+ << "---\n"
+ << shaderName << " compile log:\n"
+ << "---\n"
+ << shaderInfo.infoLog << "\n"
+ << "---\n";
}
+
+ dst << "link log:\n"
+ << "---\n"
+ << buildInfo.program.infoLog << "\n"
+ << "---\n";
}
-void writeVerboseLogs (const vk::SpirVProgramInfo& buildInfo)
+void writeBuildLogs (const vk::SpirVProgramInfo& buildInfo, std::ostream& dst)
{
- tcu::print("source:\n---\n%s\n---\n", buildInfo.source->program.str().c_str());
- tcu::print("compile log:\n---\n%s\n---\n", buildInfo.infoLog.c_str());
+ dst << "source:\n"
+ << "---\n"
+ << buildInfo.source << "\n"
+ << "---\n";
}
-template <typename InfoType, typename IteratorType>
-void buildProgram (const std::string& casePath,
- bool printLogs,
- IteratorType iter,
- BuildMode mode,
- BuildStats* stats,
- vk::BinaryRegistryReader* reader,
- vk::BinaryRegistryWriter* writer)
+vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, std::ostream& buildLog)
{
- InfoType buildInfo;
+ glu::ShaderProgramInfo buildInfo;
+
try
{
- const vk::ProgramIdentifier progId (casePath, iter.getName());
- const UniquePtr<vk::ProgramBinary> binary (compileProgram(iter.getProgram(), &buildInfo));
+ return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, &buildInfo);
+ }
+ catch (const tcu::Exception&)
+ {
+ writeBuildLogs(buildInfo, buildLog);
+ throw;
+ }
+}
- if (mode == BUILDMODE_BUILD)
- writer->storeProgram(progId, *binary);
- else
- {
- DE_ASSERT(mode == BUILDMODE_VERIFY);
+vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, std::ostream& buildLog)
+{
+ vk::SpirVProgramInfo buildInfo;
+
+ try
+ {
+ return vk::assembleProgram(source, &buildInfo);
+ }
+ catch (const tcu::Exception&)
+ {
+ writeBuildLogs(buildInfo, buildLog);
+ throw;
+ }
+}
- const UniquePtr<vk::ProgramBinary> storedBinary (reader->loadProgram(progId));
+struct BuiltProgram
+{
+ vk::ProgramIdentifier id;
+ bool buildOk;
+ UniquePtr<vk::ProgramBinary> binary; // Null if build failed
+ std::string buildLog;
+
+ BuiltProgram (const vk::ProgramIdentifier& id_,
+ bool buildOk_,
+ MovePtr<vk::ProgramBinary> binary_,
+ const std::string& buildLog_)
+ : id (id_)
+ , buildOk (buildOk_)
+ , binary (binary_)
+ , buildLog (buildLog_)
+ {
+ }
+};
- if (binary->getSize() != storedBinary->getSize())
- throw tcu::Exception("Binary size doesn't match");
+typedef SharedPtr<BuiltProgram> BuiltProgramSp;
- if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
- throw tcu::Exception("Binary contents don't match");
- }
+template<typename IteratorType>
+BuiltProgramSp buildProgram (IteratorType progIter, const std::string& casePath)
+{
+ std::ostringstream buildLog;
+ MovePtr<vk::ProgramBinary> programBinary;
+ bool buildOk = false;
- tcu::print(" OK: %s\n", iter.getName().c_str());
- stats->numSucceeded += 1;
+ try
+ {
+ programBinary = MovePtr<vk::ProgramBinary>(compileProgram(progIter.getProgram(), buildLog));
+ buildOk = true;
}
- catch (const std::exception& e)
+ catch (const std::exception&)
{
- tcu::print(" ERROR: %s: %s\n", iter.getName().c_str(), e.what());
- if (printLogs)
- {
- writeVerboseLogs(buildInfo);
- }
- stats->numFailed += 1;
+ // Ignore, buildOk = false
+ DE_ASSERT(!programBinary);
}
+
+ return BuiltProgramSp(new BuiltProgram(vk::ProgramIdentifier(casePath, progIter.getName()),
+ buildOk,
+ programBinary,
+ buildLog.str()));
}
} // anonymous
-BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, BuildMode mode, bool verbose)
+
+BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, bool validateBinaries)
{
const UniquePtr<tcu::TestPackageRoot> root (createRoot(testCtx));
tcu::DefaultHierarchyInflater inflater (testCtx);
tcu::TestHierarchyIterator iterator (*root, inflater, testCtx.getCommandLine());
const tcu::DirArchive srcArchive (dstPath.c_str());
- UniquePtr<vk::BinaryRegistryWriter> writer (mode == BUILDMODE_BUILD ? new vk::BinaryRegistryWriter(dstPath) : DE_NULL);
- UniquePtr<vk::BinaryRegistryReader> reader (mode == BUILDMODE_VERIFY ? new vk::BinaryRegistryReader(srcArchive, "") : DE_NULL);
+ UniquePtr<vk::BinaryRegistryWriter> writer (new vk::BinaryRegistryWriter(dstPath));
BuildStats stats;
- const bool printLogs = verbose;
while (iterator.getState() != tcu::TestHierarchyIterator::STATE_FINISHED)
{
{
const TestCase* const testCase = dynamic_cast<TestCase*>(iterator.getNode());
const string casePath = iterator.getNodePath();
- vk::SourceCollections progs;
+ vk::SourceCollections sourcePrograms;
+ vector<BuiltProgramSp> builtPrograms;
tcu::print("%s\n", casePath.c_str());
- testCase->initPrograms(progs);
+ testCase->initPrograms(sourcePrograms);
- for (vk::GlslSourceCollection::Iterator progIter = progs.glslSources.begin(); progIter != progs.glslSources.end(); ++progIter)
+ for (vk::GlslSourceCollection::Iterator progIter = sourcePrograms.glslSources.begin();
+ progIter != sourcePrograms.glslSources.end();
+ ++progIter)
{
- buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
+ builtPrograms.push_back(buildProgram(progIter, casePath));
}
- for (vk::SpirVAsmCollection::Iterator progIter = progs.spirvAsmSources.begin(); progIter != progs.spirvAsmSources.end(); ++progIter)
+ for (vk::SpirVAsmCollection::Iterator progIter = sourcePrograms.spirvAsmSources.begin();
+ progIter != sourcePrograms.spirvAsmSources.end();
+ ++progIter)
{
- buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
+ builtPrograms.push_back(buildProgram(progIter, casePath));
+ }
+
+ // Process programs
+ for (vector<BuiltProgramSp>::const_iterator progIter = builtPrograms.begin();
+ progIter != builtPrograms.end();
+ ++progIter)
+ {
+ const BuiltProgram& program = **progIter;
+
+ if (program.buildOk)
+ {
+ std::ostringstream validationLog;
+
+ writer->storeProgram(program.id, *program.binary);
+
+ if (validateBinaries &&
+ !vk::validateProgram(*program.binary, &validationLog))
+ {
+ tcu::print("ERROR: validation failed for %s\n", program.id.programName.c_str());
+ tcu::print("%s\n", validationLog.str().c_str());
+ stats.numFailed += 1;
+ }
+ else
+ stats.numSucceeded += 1;
+ }
+ else
+ {
+ tcu::print("ERROR: failed to build %s\n", program.id.programName.c_str());
+ tcu::print("%s\n", program.buildLog.c_str());
+ stats.numFailed += 1;
+ }
}
}
iterator.next();
}
- if (mode == BUILDMODE_BUILD)
- writer->writeIndex();
+ writer->writeIndex();
return stats;
}
{
DE_DECLARE_COMMAND_LINE_OPT(DstPath, std::string);
-DE_DECLARE_COMMAND_LINE_OPT(Mode, vkt::BuildMode);
-DE_DECLARE_COMMAND_LINE_OPT(Verbose, bool);
DE_DECLARE_COMMAND_LINE_OPT(Cases, std::string);
+DE_DECLARE_COMMAND_LINE_OPT(Validate, bool);
} // opt
void registerOptions (de::cmdline::Parser& parser)
{
using de::cmdline::Option;
- using de::cmdline::NamedValue;
- static const NamedValue<vkt::BuildMode> s_modes[] =
- {
- { "build", vkt::BUILDMODE_BUILD },
- { "verify", vkt::BUILDMODE_VERIFY }
- };
-
- parser << Option<opt::DstPath> ("d", "dst-path", "Destination path", "out")
- << Option<opt::Mode> ("m", "mode", "Build mode", s_modes, "build")
- << Option<opt::Verbose> ("v", "verbose", "Verbose output")
- << Option<opt::Cases> ("n", "deqp-case", "Case path filter (works as in test binaries)");
+ parser << Option<opt::DstPath> ("d", "dst-path", "Destination path", "out")
+ << Option<opt::Cases> ("n", "deqp-case", "Case path filter (works as in test binaries)")
+ << Option<opt::Validate> ("v", "validate-spv", "Validate generated SPIR-V binaries");
}
int main (int argc, const char* argv[])
const vkt::BuildStats stats = vkt::buildPrograms(testCtx,
cmdLine.getOption<opt::DstPath>(),
- cmdLine.getOption<opt::Mode>(),
- cmdLine.getOption<opt::Verbose>());
+ cmdLine.getOption<opt::Validate>());
tcu::print("DONE: %d passed, %d failed\n", stats.numSucceeded, stats.numFailed);
#include "vkPrograms.hpp"
#include "vkBinaryRegistry.hpp"
#include "vkGlslToSpirV.hpp"
-#include "vkSpirVAsm.hpp"
#include "deUniquePtr.hpp"
{
std::ostringstream disasm;
- vk::disassembleSpirV(binProg->getSize(), binProg->getBinary(), &disasm);
+ vk::disassembleProgram(*binProg, &disasm);
- log << TestLog::KernelSource(disasm.str());
+ log << vk::SpirVAsmSource(disasm.str());
}
catch (const tcu::NotSupportedError& err)
{
for (vk::SpirVAsmCollection::Iterator asmIterator = sourceProgs.spirvAsmSources.begin(); asmIterator != sourceProgs.spirvAsmSources.end(); ++asmIterator)
{
buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, m_prebuiltBinRegistry, log, &m_progCollection);
- log << TestLog::KernelSource((*asmIterator).program.str());
}
DE_ASSERT(!m_instance);