#include "vkGlslToSpirV.hpp"
#include "deArrayUtil.hpp"
#include "deMemory.h"
+#include "deClock.h"
#include "qpDebugOut.h"
#if defined(DEQP_HAVE_GLSLANG)
# include "deMutex.hpp"
# include "SPIRV/GlslangToSpv.h"
+# include "SPIRV/disassemble.h"
+# include "SPIRV/GLSL450Lib.h"
+# include "SPIRV/doc.h"
# include "glslang/Include/InfoSink.h"
# include "glslang/Include/ShHandle.h"
# include "glslang/MachineIndependent/localintermediate.h"
# include "glslang/Public/ShaderLang.h"
+
+// Required by SPIR-V disassembler
+const char* GlslStd450DebugNames[GLSL_STD_450::Count];
+
#endif
namespace vk
void initGlslang (void*)
{
+ // Main compiler
ShInitialize();
+
+ // SPIR-V disassembly
+ spv::Parameterize();
+ GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
}
void prepareGlslang (void)
} // anonymous
-void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>& dst)
+void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo)
{
TBuiltInResource builtinRes;
{
if (!program.sources[shaderType].empty())
{
- de::ScopedLock compileLock (s_glslangLock);
- const char* const srcText = program.sources[shaderType][0].c_str();
- const int srcLen = (int)program.sources[shaderType][0].size();
+ de::ScopedLock compileLock (s_glslangLock);
+ const std::string& srcText = program.sources[shaderType][0];
+ const char* srcPtrs[] = { srcText.c_str() };
+ int srcLengths[] = { (int)srcText.size() };
vector<deUint32> spvBlob;
TInfoSink infoSink;
- SpvGenerator compiler (getGlslangStage(glu::ShaderType(shaderType)), spvBlob, infoSink);
- const int compileOk = ShCompile(static_cast<ShHandle>(&compiler), &srcText, 1, &srcLen, EShOptNone, &builtinRes, 0);
+ SpvGenerator compiler (getGlslangStage(glu::ShaderType(shaderType)), spvBlob, infoSink);
+ const deUint64 compileStartTime = deGetMicroseconds();
+ const int compileOk = ShCompile(static_cast<ShHandle>(&compiler), srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs), srcLengths, EShOptNone, &builtinRes, 0);
- if (compileOk == 0)
{
- // \todo [2015-06-19 pyry] Create special CompileException and pass error messages through that
- qpPrint(infoSink.info.c_str());
- TCU_FAIL("Failed to compile shader");
+ glu::ShaderInfo shaderBuildInfo;
+
+ shaderBuildInfo.type = (glu::ShaderType)shaderType;
+ shaderBuildInfo.source = srcText;
+ shaderBuildInfo.infoLog = infoSink.info.c_str(); // \todo [2015-07-13 pyry] Include debug log?
+ shaderBuildInfo.compileTimeUs = deGetMicroseconds()-compileStartTime;
+ shaderBuildInfo.compileOk = (compileOk != 0);
+
+ buildInfo->shaders.push_back(shaderBuildInfo);
}
- dst.resize(spvBlob.size() * sizeof(deUint32));
+ buildInfo->program.infoLog = "(No linking performed)";
+ buildInfo->program.linkOk = (compileOk != 0);
+ buildInfo->program.linkTimeUs = 0;
+
+ if (compileOk == 0)
+ TCU_FAIL("Failed to compile shader");
+
+ dst->resize(spvBlob.size() * sizeof(deUint32));
#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
- deMemcpy(&dst[0], &spvBlob[0], dst.size());
+ deMemcpy(&(*dst)[0], &spvBlob[0], dst->size());
#else
# error "Big-endian not supported"
#endif
+
return;
}
}
TCU_THROW(InternalError, "Can't compile empty program");
}
+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
+
+ spv::Disassemble(*dst, binForDisasm);
+}
+
#else // defined(DEQP_HAVE_GLSLANG)
-void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>&)
+void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>*, glu::ShaderProgramInfo*)
{
TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
}
+void disassembleSpirV (size_t, const deUint8*, std::ostream*)
+{
+ TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_GLSLANG not defined)");
+}
+
#endif
} // vk
#include "vktTestPackage.hpp"
#include "tcuPlatform.hpp"
+#include "tcuTestCase.hpp"
+#include "tcuTestLog.hpp"
+
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkBinaryRegistry.hpp"
+#include "vkGlslToSpirV.hpp"
+
#include "deUniquePtr.hpp"
#include "vktInfo.hpp"
#include "vktApiTests.hpp"
#include <vector>
+#include <sstream>
namespace vkt
{
using std::vector;
using de::UniquePtr;
using de::MovePtr;
+using tcu::TestLog;
// TestCaseExecutor
void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePath)
{
const TestCase* vktCase = dynamic_cast<TestCase*>(testCase);
+ tcu::TestLog& log = m_context.getTestContext().getLog();
vk::SourceCollection sourceProgs;
DE_UNREF(casePath); // \todo [2015-03-13 pyry] Use this to identify ProgramCollection storage path
for (vk::SourceCollection::Iterator progIter = sourceProgs.begin(); progIter != sourceProgs.end(); ++progIter)
{
const vk::ProgramIdentifier progId (casePath, progIter.getName());
+ const tcu::ScopedLogSection progSection (log, progIter.getName(), "Program: " + progIter.getName());
de::MovePtr<vk::ProgramBinary> binProg;
+ glu::ShaderProgramInfo buildInfo;
// \todo [2015-07-01 pyry] Command line parameter to control cache vs. build order?
try
{
- binProg = de::MovePtr<vk::ProgramBinary>(vk::buildProgram(progIter.getProgram(), vk::PROGRAM_FORMAT_SPIRV));
+ binProg = de::MovePtr<vk::ProgramBinary>(vk::buildProgram(progIter.getProgram(), vk::PROGRAM_FORMAT_SPIRV, &buildInfo));
+ log << buildInfo;
}
- catch (const tcu::NotSupportedError&)
+ catch (const tcu::NotSupportedError& err)
{
// Try to load from cache
const vk::BinaryRegistryReader registry (m_context.getTestContext().getArchive(), "vulkan/prebuilt");
+ log << err << TestLog::Message << "Building from source not supported, loading stored binary instead" << TestLog::EndMessage;
+
binProg = de::MovePtr<vk::ProgramBinary>(registry.loadProgram(progId));
+
+ log << progIter.getProgram();
+ }
+ catch (const tcu::Exception&)
+ {
+ // Build failed for other reason
+ log << buildInfo;
+ throw;
}
TCU_CHECK_INTERNAL(binProg);
+ try
+ {
+ std::ostringstream disasm;
+
+ vk::disassembleSpirV(binProg->getSize(), binProg->getBinary(), &disasm);
+
+ log << TestLog::KernelSource(disasm.str());
+ }
+ catch (const tcu::NotSupportedError& err)
+ {
+ log << err;
+ }
+
m_progCollection.add(progId.programName, binProg);
}