#include "vktTestPackage.hpp"
+#include "qpDebugOut.h"
+#include "qpInfo.h"
+
#include "tcuPlatform.hpp"
#include "tcuTestCase.hpp"
#include "tcuTestLog.hpp"
#include "vkQueryUtil.hpp"
#include "vkApiVersion.hpp"
#include "vkRenderDocUtil.hpp"
+#include "vkResourceInterface.hpp"
#include "deUniquePtr.hpp"
+#include "deSharedPtr.hpp"
+#ifdef CTS_USES_VULKANSC
+ #include "deProcess.h"
+ #include "vksClient.hpp"
+ #include "vksIPC.hpp"
+#endif // CTS_USES_VULKANSC
#include "vktTestGroupUtil.hpp"
#include "vktApiTests.hpp"
#include "vktReconvergenceTests.hpp"
#include "vktMeshShaderTests.hpp"
#include "vktFragmentShadingBarycentricTests.hpp"
+#ifdef CTS_USES_VULKANSC
+#include "vktSafetyCriticalTests.hpp"
+#endif // CTS_USES_VULKANSC
#include <vector>
#include <sstream>
-
-namespace // compilation
-{
-
-vk::ProgramBinary* compileProgram (const vk::GlslSource& source, glu::ShaderProgramInfo* buildInfo, const tcu::CommandLine& commandLine)
-{
- return vk::buildProgram(source, buildInfo, commandLine);
-}
-
-vk::ProgramBinary* compileProgram (const vk::HlslSource& source, glu::ShaderProgramInfo* buildInfo, const tcu::CommandLine& commandLine)
-{
- return vk::buildProgram(source, buildInfo, commandLine);
-}
-
-vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo, const tcu::CommandLine& commandLine)
-{
- return vk::assembleProgram(source, buildInfo, commandLine);
-}
-
-template <typename InfoType, typename IteratorType>
-vk::ProgramBinary* buildProgram (const std::string& casePath,
- IteratorType iter,
- const vk::BinaryRegistryReader& prebuiltBinRegistry,
- tcu::TestLog& log,
- vk::BinaryCollection* progCollection,
- const tcu::CommandLine& commandLine)
-{
- const vk::ProgramIdentifier progId (casePath, iter.getName());
- const tcu::ScopedLogSection progSection (log, iter.getName(), "Program: " + iter.getName());
- de::MovePtr<vk::ProgramBinary> binProg;
- InfoType buildInfo;
-
- try
- {
- binProg = de::MovePtr<vk::ProgramBinary>(compileProgram(iter.getProgram(), &buildInfo, commandLine));
- log << buildInfo;
- }
- catch (const tcu::NotSupportedError& err)
- {
- // Try to load from cache
- log << err << tcu::TestLog::Message << "Building from source not supported, loading stored binary instead" << tcu::TestLog::EndMessage;
-
- binProg = de::MovePtr<vk::ProgramBinary>(prebuiltBinRegistry.loadProgram(progId));
-
- log << iter.getProgram();
- }
- catch (const tcu::Exception&)
- {
- // Build failed for other reason
- log << buildInfo;
- throw;
- }
-
- TCU_CHECK_INTERNAL(binProg);
-
- {
- vk::ProgramBinary* const returnBinary = binProg.get();
-
- progCollection->add(progId.programName, binProg);
-
- return returnBinary;
- }
-}
-
-} // anonymous(compilation)
+#include <fstream>
+#include <thread>
namespace vkt
{
using std::vector;
using de::UniquePtr;
+using de::SharedPtr;
using de::MovePtr;
using tcu::TestLog;
// TestCaseExecutor
+#ifdef CTS_USES_VULKANSC
+struct DetailedSubprocessTestCount
+{
+ std::string testPattern;
+ int testCount;
+};
+#endif // CTS_USES_VULKANSC
+
class TestCaseExecutor : public tcu::TestCaseExecutor
{
public:
- TestCaseExecutor (tcu::TestContext& testCtx);
- ~TestCaseExecutor (void);
+ TestCaseExecutor (tcu::TestContext& testCtx);
+ ~TestCaseExecutor (void);
- virtual void init (tcu::TestCase* testCase, const std::string& path);
- virtual void deinit (tcu::TestCase* testCase);
+ void init (tcu::TestCase* testCase, const std::string& path) override;
+ void deinit (tcu::TestCase* testCase) override;
- virtual tcu::TestNode::IterateResult iterate (tcu::TestCase* testCase);
+ tcu::TestNode::IterateResult iterate (tcu::TestCase* testCase) override;
+
+ void deinitTestPackage (tcu::TestContext& testCtx) override;
+ bool usesLocalStatus () override;
+ void updateGlobalStatus (tcu::TestRunStatus& status) override;
+ void reportDurations (tcu::TestContext& testCtx, const std::string& packageName, const deInt64& duration, const std::map<std::string, deUint64>& groupsDurationTime) override;
+ int getCurrentSubprocessCount (const std::string& casePath, int defaultSubprocessCount);
private:
- void logUnusedShaders (tcu::TestCase* testCase);
+ void logUnusedShaders (tcu::TestCase* testCase);
+
+ void runTestsInSubprocess (tcu::TestContext& testCtx);
+
+ bool spirvVersionSupported (vk::SpirvVersion);
- bool spirvVersionSupported(vk::SpirvVersion);
vk::BinaryCollection m_progCollection;
vk::BinaryRegistryReader m_prebuiltBinRegistry;
const UniquePtr<vk::Library> m_library;
- Context m_context;
+ MovePtr<Context> m_context;
const UniquePtr<vk::RenderDocUtil> m_renderDoc;
+ SharedPtr<vk::ResourceInterface> m_resourceInterface;
vk::VkPhysicalDeviceProperties m_deviceProperties;
tcu::WaiverUtil m_waiverMechanism;
TestInstance* m_instance; //!< Current test case instance
+ std::vector<std::string> m_testsForSubprocess;
+ tcu::TestRunStatus m_status;
+
+#ifdef CTS_USES_VULKANSC
+ int m_subprocessCount;
+
+ std::unique_ptr<vksc_server::ipc::Parent> m_parentIPC;
+ std::vector<DetailedSubprocessTestCount> m_detailedSubprocessTestCount;
+#endif // CTS_USES_VULKANSC
};
+#ifdef CTS_USES_VULKANSC
+static deBool supressedWrite (int, const char*) { return false; }
+static deBool supressedWriteFtm (int, const char*, va_list) { return false; }
+static deBool openWrite (int type, const char* message) { DE_UNREF(type); DE_UNREF(message); return true; }
+static deBool openWriteFtm (int type, const char* format, va_list args) { DE_UNREF(type); DE_UNREF(format); DE_UNREF(args); return true; }
+static void suppressStandardOutput () { qpRedirectOut(supressedWrite, supressedWriteFtm); }
+static void restoreStandardOutput () { qpRedirectOut(openWrite, openWriteFtm); }
+#endif // CTS_USES_VULKANSC
+
static MovePtr<vk::Library> createLibrary (tcu::TestContext& testCtx)
{
- return MovePtr<vk::Library>(testCtx.getPlatform().getVulkanPlatform().createLibrary());
+ return MovePtr<vk::Library>(testCtx.getPlatform().getVulkanPlatform().createLibrary(testCtx.getCommandLine().getVkLibraryPath()));
}
static vk::VkPhysicalDeviceProperties getPhysicalDeviceProperties(vkt::Context& context)
return properties;
}
+std::string trim (const std::string& original)
+{
+ static const std::string whiteSigns = " \t";
+ const auto beg = original.find_first_not_of(whiteSigns);
+ if (beg == std::string::npos)
+ return std::string();
+ const auto end = original.find_last_not_of(whiteSigns);
+ return original.substr(beg, end - beg + 1);
+}
+
TestCaseExecutor::TestCaseExecutor (tcu::TestContext& testCtx)
: m_prebuiltBinRegistry (testCtx.getArchive(), "vulkan/prebuilt")
, m_library (createLibrary(testCtx))
- , m_context (testCtx, m_library->getPlatformInterface(), m_progCollection)
, m_renderDoc (testCtx.getCommandLine().isRenderDocEnabled()
? MovePtr<vk::RenderDocUtil>(new vk::RenderDocUtil())
: MovePtr<vk::RenderDocUtil>(DE_NULL))
- , m_deviceProperties (getPhysicalDeviceProperties(m_context))
+#if defined CTS_USES_VULKANSC
+ , m_resourceInterface (new vk::ResourceInterfaceVKSC(testCtx))
+#else
+ , m_resourceInterface (new vk::ResourceInterfaceStandard(testCtx))
+#endif // CTS_USES_VULKANSC
, m_instance (DE_NULL)
+#if defined CTS_USES_VULKANSC
+ , m_subprocessCount (0)
+#endif // CTS_USES_VULKANSC
{
+#ifdef CTS_USES_VULKANSC
+ std::vector<int> caseFraction = testCtx.getCommandLine().getCaseFraction();
+ std::string jsonFileName;
+ int portOffset;
+ if (caseFraction.empty())
+ {
+ jsonFileName = "pipeline_data.txt";
+ portOffset = 0;
+ }
+ else
+ {
+ jsonFileName = "pipeline_data_" + std::to_string(caseFraction[0]) + ".txt";
+ portOffset = caseFraction[0];
+ }
+
+ if (testCtx.getCommandLine().isSubProcess())
+ {
+ std::vector<deUint8> input = vksc_server::ipc::Child{portOffset}.GetFile(jsonFileName);
+ m_resourceInterface->importData(input);
+ }
+ else
+ {
+ m_parentIPC.reset( new vksc_server::ipc::Parent{portOffset} );
+ }
+
+ // Load information about test tree branches that use subprocess test count other than default
+ // Expected file format:
+ if (!testCtx.getCommandLine().isSubProcess() && !std::string(testCtx.getCommandLine().getSubprocessConfigFile()).empty())
+ {
+ std::ifstream iFile(testCtx.getCommandLine().getSubprocessConfigFile(), std::ios::in);
+ if (!iFile)
+ TCU_THROW(InternalError, (std::string("Missing config file defining number of tests: ") + testCtx.getCommandLine().getSubprocessConfigFile()).c_str());
+ std::string line;
+ while (std::getline(iFile, line))
+ {
+ if (line.empty())
+ continue;
+ std::size_t pos = line.find_first_of(',');
+ if (pos == std::string::npos)
+ continue;
+ std::string testPattern, testNumber;
+ std::copy(line.begin(), line.begin() + pos, std::back_inserter(testPattern));
+ testPattern = trim(testPattern);
+ std::copy(line.begin() + pos + 1, line.end(), std::back_inserter(testNumber));
+ testNumber = trim(testNumber);
+ if (testPattern.empty() || testNumber.empty())
+ continue;
+ std::istringstream is(testNumber);
+ int testCount;
+ if ((is >> testCount).fail())
+ continue;
+ m_detailedSubprocessTestCount.push_back(DetailedSubprocessTestCount{ testPattern, testCount });
+ }
+ // sort test patterns
+ std::sort(m_detailedSubprocessTestCount.begin(), m_detailedSubprocessTestCount.end(), [](const DetailedSubprocessTestCount& lhs, const DetailedSubprocessTestCount& rhs)
+ {
+ return lhs.testCount < rhs.testCount;
+ } );
+ }
+
+ // If we are provided with remote location
+ if (!std::string(testCtx.getCommandLine().getServerAddress()).empty())
+ {
+ // Open connection with the server dedicated for standard output
+ vksc_server::OpenRemoteStandardOutput(testCtx.getCommandLine().getServerAddress());
+ restoreStandardOutput();
+ }
+#endif // CTS_USES_VULKANSC
+
+ m_context = MovePtr<Context>(new Context(testCtx, m_library->getPlatformInterface(), m_progCollection, m_resourceInterface));
+ m_deviceProperties = getPhysicalDeviceProperties(*m_context);
+
tcu::SessionInfo sessionInfo(m_deviceProperties.vendorID,
m_deviceProperties.deviceID,
testCtx.getCommandLine().getInitialCmdLine());
m_deviceProperties.vendorID,
m_deviceProperties.deviceID,
sessionInfo);
- testCtx.getLog().writeSessionInfo(sessionInfo.get());
+
+#ifdef CTS_USES_VULKANSC
+ if (!std::string(testCtx.getCommandLine().getServerAddress()).empty())
+ {
+ vksc_server::AppendRequest request;
+ request.fileName = testCtx.getCommandLine().getLogFileName();
+
+ std::ostringstream str;
+ str << "#sessionInfo releaseName " << qpGetReleaseName() << std::endl;
+ str << "#sessionInfo releaseId 0x" << std::hex << std::setw(8) << std::setfill('0') << qpGetReleaseId() << std::endl;
+ str << "#sessionInfo targetName \"" << qpGetTargetName() << "\"" << std::endl;
+ str << sessionInfo.get() << std::endl;
+ str << "#beginSession" << std::endl;
+
+ std::string output = str.str();
+ request.data.assign(output.begin(), output.end());
+ request.clear = true;
+ vksc_server::StandardOutputServerSingleton()->SendRequest(request);
+ }
+ else
+#endif // CTS_USES_VULKANSC
+ {
+ testCtx.getLog().writeSessionInfo(sessionInfo.get());
+ }
+
+#ifdef CTS_USES_VULKANSC
+ m_resourceInterface->initApiVersion(m_context->getUsedApiVersion());
+
+ // Real Vulkan SC tests are performed in subprocess.
+ // Tests run in main process are only used to collect data required by Vulkan SC.
+ // That's why we turn off any output in main process and copy output from subprocess when subprocess tests are performed
+ if (!testCtx.getCommandLine().isSubProcess())
+ {
+ suppressStandardOutput();
+ m_context->getTestContext().getLog().supressLogging(true);
+ }
+#endif // CTS_USES_VULKANSC
}
TestCaseExecutor::~TestCaseExecutor (void)
void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePath)
{
+ if (m_waiverMechanism.isOnWaiverList(casePath))
+ throw tcu::TestException("Waived test", QP_TEST_RESULT_WAIVER);
+
TestCase* vktCase = dynamic_cast<TestCase*>(testCase);
- tcu::TestLog& log = m_context.getTestContext().getLog();
- const deUint32 usedVulkanVersion = m_context.getUsedApiVersion();
+ tcu::TestLog& log = m_context->getTestContext().getLog();
+ const deUint32 usedVulkanVersion = m_context->getUsedApiVersion();
const vk::SpirvVersion baselineSpirvVersion = vk::getBaselineSpirvVersion(usedVulkanVersion);
vk::ShaderBuildOptions defaultGlslBuildOptions (usedVulkanVersion, baselineSpirvVersion, 0u);
vk::ShaderBuildOptions defaultHlslBuildOptions (usedVulkanVersion, baselineSpirvVersion, 0u);
vk::SpirVAsmBuildOptions defaultSpirvAsmBuildOptions (usedVulkanVersion, baselineSpirvVersion);
vk::SourceCollections sourceProgs (usedVulkanVersion, defaultGlslBuildOptions, defaultHlslBuildOptions, defaultSpirvAsmBuildOptions);
- const tcu::CommandLine& commandLine = m_context.getTestContext().getCommandLine();
+ const tcu::CommandLine& commandLine = m_context->getTestContext().getCommandLine();
const bool doShaderLog = commandLine.isLogDecompiledSpirvEnabled() && log.isShaderLoggingEnabled();
if (!vktCase)
TCU_THROW(InternalError, "Test node not an instance of vkt::TestCase");
+ {
+#ifdef CTS_USES_VULKANSC
+ int currentSubprocessCount = getCurrentSubprocessCount(casePath, m_context->getTestContext().getCommandLine().getSubprocessTestCount());
+ if (m_subprocessCount && currentSubprocessCount != m_subprocessCount)
+ {
+ runTestsInSubprocess(m_context->getTestContext());
+
+ // Clean up data after performing tests in subprocess and prepare system for another batch of tests
+ m_testsForSubprocess.clear();
+ const vk::DeviceInterface& vkd = m_context->getDeviceInterface();
+ const vk::DeviceDriverSC* dds = dynamic_cast<const vk::DeviceDriverSC*>(&vkd);
+ if (dds == DE_NULL)
+ TCU_THROW(InternalError, "Undefined device driver for Vulkan SC");
+ dds->reset();
+ m_resourceInterface->resetObjects();
+
+ suppressStandardOutput();
+ m_context->getTestContext().getLog().supressLogging(true);
+ }
+ m_subprocessCount = currentSubprocessCount;
+#endif // CTS_USES_VULKANSC
+ m_testsForSubprocess.push_back(casePath);
+ }
+
+ m_resourceInterface->initTestCase(casePath);
+
if (m_waiverMechanism.isOnWaiverList(casePath))
throw tcu::TestException("Waived test", QP_TEST_RESULT_WAIVER);
- vktCase->checkSupport(m_context);
+ vktCase->checkSupport(*m_context);
vktCase->delayedInit();
if (!spirvVersionSupported(progIter.getProgram().buildOptions.targetVersion))
TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
- const vk::ProgramBinary* const binProg = buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
+ const vk::ProgramBinary* const binProg = m_resourceInterface->buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, &m_progCollection);
if (doShaderLog)
{
if (!spirvVersionSupported(progIter.getProgram().buildOptions.targetVersion))
TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
- const vk::ProgramBinary* const binProg = buildProgram<glu::ShaderProgramInfo, vk::HlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
+ const vk::ProgramBinary* const binProg = m_resourceInterface->buildProgram<glu::ShaderProgramInfo, vk::HlslSourceCollection::Iterator>(casePath, progIter, m_prebuiltBinRegistry, &m_progCollection);
if (doShaderLog)
{
if (!spirvVersionSupported(asmIterator.getProgram().buildOptions.targetVersion))
TCU_THROW(NotSupportedError, "Shader requires SPIR-V higher than available");
- buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, m_prebuiltBinRegistry, log, &m_progCollection, commandLine);
+ m_resourceInterface->buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, m_prebuiltBinRegistry, &m_progCollection);
}
- if (m_renderDoc) m_renderDoc->startFrame(m_context.getInstance());
+ if (m_renderDoc) m_renderDoc->startFrame(m_context->getInstance());
DE_ASSERT(!m_instance);
- m_instance = vktCase->createInstance(m_context);
- m_context.resultSetOnValidation(false);
+ m_instance = vktCase->createInstance(*m_context);
+ m_context->resultSetOnValidation(false);
}
void TestCaseExecutor::deinit (tcu::TestCase* testCase)
delete m_instance;
m_instance = DE_NULL;
- if (m_renderDoc) m_renderDoc->endFrame(m_context.getInstance());
+ if (m_renderDoc) m_renderDoc->endFrame(m_context->getInstance());
// Collect and report any debug messages
- if (m_context.hasDebugReportRecorder())
- collectAndReportDebugMessages(m_context.getDebugReportRecorder(), m_context);
+#ifndef CTS_USES_VULKANSC
+ if (m_context->hasDebugReportRecorder())
+ collectAndReportDebugMessages(m_context->getDebugReportRecorder(), *m_context);
+#endif // CTS_USES_VULKANSC
if (testCase != DE_NULL)
logUnusedShaders(testCase);
+
+#ifdef CTS_USES_VULKANSC
+ if (!m_context->getTestContext().getCommandLine().isSubProcess())
+ {
+ int currentSubprocessCount = getCurrentSubprocessCount(m_context->getResourceInterface()->getCasePath(), m_context->getTestContext().getCommandLine().getSubprocessTestCount());
+ if (m_testsForSubprocess.size() >= std::size_t(currentSubprocessCount))
+ {
+ runTestsInSubprocess(m_context->getTestContext());
+
+ // Clean up data after performing tests in subprocess and prepare system for another batch of tests
+ m_testsForSubprocess.clear();
+ const vk::DeviceInterface& vkd = m_context->getDeviceInterface();
+ const vk::DeviceDriverSC* dds = dynamic_cast<const vk::DeviceDriverSC*>(&vkd);
+ if (dds == DE_NULL)
+ TCU_THROW(InternalError, "Undefined device driver for Vulkan SC");
+ dds->reset();
+ m_resourceInterface->resetObjects();
+
+ suppressStandardOutput();
+ m_context->getTestContext().getLog().supressLogging(true);
+ }
+ }
+#endif // CTS_USES_VULKANSC
}
void TestCaseExecutor::logUnusedShaders (tcu::TestCase* testCase)
message = std::string("Unused shaders: ") + message;
- m_context.getTestContext().getLog() << TestLog::Message << message << TestLog::EndMessage;
+ m_context->getTestContext().getLog() << TestLog::Message << message << TestLog::EndMessage;
}
}
}
if (result.isComplete())
{
// Vulkan tests shouldn't set result directly except when using a debug report messenger to catch validation errors.
- DE_ASSERT(m_context.getTestContext().getTestResult() == QP_TEST_RESULT_LAST || m_context.resultSetOnValidation());
+ DE_ASSERT(m_context->getTestContext().getTestResult() == QP_TEST_RESULT_LAST || m_context->resultSetOnValidation());
// Override result if not set previously by a debug report messenger.
- if (!m_context.resultSetOnValidation())
- m_context.getTestContext().setTestResult(result.getCode(), result.getDescription().c_str());
+ if (!m_context->resultSetOnValidation())
+ m_context->getTestContext().setTestResult(result.getCode(), result.getDescription().c_str());
return tcu::TestNode::STOP;
}
else
return tcu::TestNode::CONTINUE;
}
+void TestCaseExecutor::deinitTestPackage (tcu::TestContext& testCtx)
+{
+#ifdef CTS_USES_VULKANSC
+ if (!testCtx.getCommandLine().isSubProcess())
+ {
+ if (!m_testsForSubprocess.empty())
+ {
+ runTestsInSubprocess(testCtx);
+
+ // Clean up data after performing tests in subprocess and prepare system for another batch of tests
+ m_testsForSubprocess.clear();
+ const vk::DeviceInterface& vkd = m_context->getDeviceInterface();
+ const vk::DeviceDriverSC* dds = dynamic_cast<const vk::DeviceDriverSC*>(&vkd);
+ if (dds == DE_NULL)
+ TCU_THROW(InternalError, "Undefined device driver for Vulkan SC");
+ dds->reset();
+ m_resourceInterface->resetObjects();
+ }
+
+ // Tests are finished. Next tests ( if any ) will come from other test package and test executor
+ restoreStandardOutput();
+ m_context->getTestContext().getLog().supressLogging(false);
+ }
+ m_resourceInterface->resetPipelineCaches();
+#else
+ DE_UNREF(testCtx);
+#endif // CTS_USES_VULKANSC
+}
+
+bool TestCaseExecutor::usesLocalStatus ()
+{
+#ifdef CTS_USES_VULKANSC
+ return !m_context->getTestContext().getCommandLine().isSubProcess();
+#else
+ return false;
+#endif
+}
+
+void TestCaseExecutor::updateGlobalStatus (tcu::TestRunStatus& status)
+{
+ status.numExecuted += m_status.numExecuted;
+ status.numPassed += m_status.numPassed;
+ status.numNotSupported += m_status.numNotSupported;
+ status.numWarnings += m_status.numWarnings;
+ status.numWaived += m_status.numWaived;
+ status.numFailed += m_status.numFailed;
+ m_status.clear();
+}
+
+void TestCaseExecutor::reportDurations(tcu::TestContext& testCtx, const std::string& packageName, const deInt64& duration, const std::map<std::string, deUint64>& groupsDurationTime)
+{
+#ifdef CTS_USES_VULKANSC
+ // Send it to server to append to its log
+ vksc_server::AppendRequest request;
+ request.fileName = testCtx.getCommandLine().getLogFileName();
+
+ std::ostringstream str;
+
+ str << std::endl;
+ str << "#beginTestsCasesTime" << std::endl;
+
+ str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
+ str << "<TestsCasesTime>" << std::endl;
+
+ str << " <Number Name=\"" << packageName << "\" Description=\"Total tests case duration in microseconds\" Tag=\"Time\" Unit=\"us\">" << duration << "</Number>" << std::endl;
+ for (std::map<std::string, deUint64>::const_iterator it = groupsDurationTime.begin(); it != groupsDurationTime.end(); ++it)
+ str << " <Number Name=\"" << it->first << "\" Description=\"The test group case duration in microseconds\" Tag=\"Time\" Unit=\"us\">" << it->second << "</Number>" << std::endl;
+ str << "</TestsCasesTime>" << std::endl;
+ str << std::endl;
+ str << "#endTestsCasesTime" << std::endl;
+ str << std::endl;
+ str << "#endSession" << std::endl;
+
+ std::string output = str.str();
+ request.data.assign(output.begin(), output.end());
+ vksc_server::StandardOutputServerSingleton()->SendRequest(request);
+#else
+ DE_UNREF(testCtx);
+ DE_UNREF(packageName);
+ DE_UNREF(duration);
+ DE_UNREF(groupsDurationTime);
+#endif // CTS_USES_VULKANSC
+
+}
+
+int TestCaseExecutor::getCurrentSubprocessCount(const std::string& casePath, int defaultSubprocessCount)
+{
+#ifdef CTS_USES_VULKANSC
+ for (const auto& detailed : m_detailedSubprocessTestCount)
+ if (tcu::matchWildcards(detailed.testPattern.begin(), detailed.testPattern.end(), casePath.begin(), casePath.end(), false))
+ return detailed.testCount;
+#else
+ DE_UNREF(casePath);
+#endif // CTS_USES_VULKANSC
+ return defaultSubprocessCount;
+}
+
+void TestCaseExecutor::runTestsInSubprocess (tcu::TestContext& testCtx)
+{
+#ifdef CTS_USES_VULKANSC
+ if (testCtx.getCommandLine().isSubProcess())
+ TCU_THROW(InternalError, "Cannot run subprocess inside subprocess : ");
+
+ if (m_testsForSubprocess.empty())
+ return;
+
+ std::vector<int> caseFraction = testCtx.getCommandLine().getCaseFraction();
+ std::ostringstream jsonFileName, qpaFileName, pipelineCompilerOutFileName, pipelineCompilerLogFileName, pipelineCompilerPrefix;
+ if (caseFraction.empty())
+ {
+ jsonFileName << "pipeline_data.txt";
+ qpaFileName << "sub.qpa";
+ if (!std::string(testCtx.getCommandLine().getPipelineCompilerPath()).empty())
+ {
+ pipelineCompilerOutFileName << "pipeline_cache.bin";
+ pipelineCompilerLogFileName << "compiler.log";
+ pipelineCompilerPrefix << "";
+ }
+ }
+ else
+ {
+ jsonFileName << "pipeline_data_" << caseFraction[0] << ".txt";
+ qpaFileName << "sub_" << caseFraction[0] << ".qpa";
+ if (!std::string(testCtx.getCommandLine().getPipelineCompilerPath()).empty())
+ {
+ pipelineCompilerOutFileName << "pipeline_cache_" << caseFraction[0] <<".bin";
+ pipelineCompilerLogFileName << "compiler_" << caseFraction[0] << ".log";
+ pipelineCompilerPrefix << "sub_" << caseFraction[0] << "_";
+ }
+ }
+
+ // export data collected during statistics gathering to JSON file ( VkDeviceObjectReservationCreateInfo, SPIR-V shaders, pipelines )
+ {
+ m_resourceInterface->removeRedundantObjects();
+ m_resourceInterface->finalizeCommandBuffers();
+ std::vector<deUint8> data = m_resourceInterface->exportData();
+ m_parentIPC->SetFile(jsonFileName.str(), data);
+ }
+
+ // collect current application name, add it to new commandline with subprocess parameters
+ std::string newCmdLine;
+ {
+ std::string appName = testCtx.getCommandLine().getApplicationName();
+ if (appName.empty())
+ TCU_THROW(InternalError, "Application name is not defined");
+ // add --deqp-subprocess option to inform deqp-vksc process that it works as slave process
+ newCmdLine = appName + " --deqp-subprocess=enable --deqp-log-filename=" + qpaFileName.str();
+
+ // add offline pipeline compiler parameters if present
+ if (!std::string(testCtx.getCommandLine().getPipelineCompilerPath()).empty())
+ {
+ newCmdLine += " --deqp-pipeline-compiler=" + std::string(testCtx.getCommandLine().getPipelineCompilerPath());
+ newCmdLine += " --deqp-pipeline-file=" + pipelineCompilerOutFileName.str();
+ if (!std::string(testCtx.getCommandLine().getPipelineCompilerDataDir()).empty())
+ newCmdLine += " --deqp-pipeline-dir=" + std::string(testCtx.getCommandLine().getPipelineCompilerDataDir());
+ newCmdLine += " --deqp-pipeline-logfile=" + pipelineCompilerLogFileName.str();
+ if(!pipelineCompilerPrefix.str().empty())
+ newCmdLine += " --deqp-pipeline-prefix=" + pipelineCompilerPrefix.str();
+ if (!std::string(testCtx.getCommandLine().getPipelineCompilerArgs()).empty())
+ newCmdLine += " --deqp-pipeline-args=\"" + std::string( testCtx.getCommandLine().getPipelineCompilerArgs() ) + "\"";
+ }
+ }
+
+ // collect parameters, remove parameters associated with case filter and case fraction. We will provide our own case list
+ {
+ std::string originalCmdLine = testCtx.getCommandLine().getInitialCmdLine();
+
+ // brave ( but working ) assumption that each CTS parameter starts with "--deqp"
+
+ std::string paramStr ("--deqp");
+ std::vector<std::string> skipElements =
+ {
+ "--deqp-case",
+ "--deqp-stdin-caselist",
+ "--deqp-log-filename",
+ "--deqp-pipeline-compiler",
+ "--deqp-pipeline-dir",
+ "--deqp-pipeline-args",
+ "--deqp-pipeline-file",
+ "--deqp-pipeline-logfile",
+ "--deqp-pipeline-prefix"
+ };
+
+ std::size_t pos = 0;
+ std::vector<std::size_t> argPos;
+ while ((pos = originalCmdLine.find(paramStr, pos)) != std::string::npos)
+ argPos.push_back(pos++);
+ if (!argPos.empty())
+ argPos.push_back(originalCmdLine.size());
+
+ std::vector<std::string> args;
+ for (std::size_t i = 0; i < argPos.size()-1; ++i)
+ {
+ std::string s = originalCmdLine.substr(argPos[i], argPos[i + 1] - argPos[i]);
+ std::size_t found = s.find_last_not_of(' ');
+ if (found != std::string::npos)
+ {
+ s.erase(found + 1);
+ args.push_back(s);
+ }
+ }
+ for (std::size_t i = 0; i < args.size(); ++i)
+ {
+ bool skipElement = false;
+ for (const auto& elem : skipElements)
+ if (args[i].find(elem) == 0)
+ {
+ skipElement = true;
+ break;
+ }
+ if (skipElement)
+ continue;
+ newCmdLine = newCmdLine + " " + args[i];
+ }
+ }
+
+ // create --deqp-case list from tests collected in m_testsForSubprocess
+ std::string subprocessTestList;
+ for (auto it = begin(m_testsForSubprocess); it != end(m_testsForSubprocess); ++it)
+ {
+ auto nit = it; ++nit;
+
+ subprocessTestList += *it;
+ if (nit != end(m_testsForSubprocess))
+ subprocessTestList += "\n";
+ }
+
+ std::string caseListName = "subcaselist" + (caseFraction.empty() ? std::string("") : de::toString(caseFraction[0])) + ".txt";
+
+ deFile* exportFile = deFile_create(caseListName.c_str(), DE_FILEMODE_CREATE | DE_FILEMODE_OPEN | DE_FILEMODE_WRITE | DE_FILEMODE_TRUNCATE);
+ deInt64 numWritten = 0;
+ deFile_write(exportFile, subprocessTestList.c_str(), subprocessTestList.size(), &numWritten);
+ deFile_destroy(exportFile);
+ newCmdLine = newCmdLine + " --deqp-caselist-file=" + caseListName;
+
+ // restore cout and cerr
+ restoreStandardOutput();
+
+ // create subprocess which will perform real tests
+ std::string subProcessExitCodeInfo;
+ {
+ deProcess* process = deProcess_create();
+ if (deProcess_start(process, newCmdLine.c_str(), ".") != DE_TRUE)
+ {
+ std::string err = deProcess_getLastError(process);
+ deProcess_destroy(process);
+ process = DE_NULL;
+ TCU_THROW(InternalError, "Error while running subprocess : " + err);
+ }
+ std::string whole;
+ whole.reserve(1024 * 4);
+
+ // create a separate thread that captures std::err output
+ de::MovePtr<std::thread> errThread(new std::thread([&process]
+ {
+ deFile* subErr = deProcess_getStdErr(process);
+ char errBuffer[128] = { 0 };
+ deInt64 errNumRead = 0;
+ while (deFile_read(subErr, errBuffer, sizeof(errBuffer) - 1, &errNumRead) == DE_FILERESULT_SUCCESS)
+ {
+ errBuffer[errNumRead] = 0;
+ }
+ }));
+
+ deFile* subOutput = deProcess_getStdOut(process);
+ char outBuffer[128] = { 0 };
+ deInt64 numRead = 0;
+ while (deFile_read(subOutput, outBuffer, sizeof(outBuffer) - 1, &numRead) == DE_FILERESULT_SUCCESS)
+ {
+ outBuffer[numRead] = 0;
+ qpPrint(outBuffer);
+ whole += outBuffer;
+ }
+ errThread->join();
+ if (deProcess_waitForFinish(process))
+ {
+ const int exitCode = deProcess_getExitCode(process);
+ std::stringstream s;
+
+ s << " Subprocess failed with exit code " << exitCode << "(" << std::hex << exitCode << ")";
+
+ subProcessExitCodeInfo = s.str();
+ }
+ deProcess_destroy(process);
+
+ vksc_server::RemoteWrite(0, whole.c_str());
+ }
+
+ // copy test information from sub.qpa to main log
+ {
+ std::ifstream subQpa(qpaFileName.str(), std::ios::binary);
+ std::string subQpaText{std::istreambuf_iterator<char>(subQpa),
+ std::istreambuf_iterator<char>()};
+ {
+ std::string beginText ("#beginTestCaseResult");
+ std::string endText ("#endTestCaseResult");
+ std::size_t beginPos = subQpaText.find(beginText);
+ std::size_t endPos = subQpaText.rfind(endText);
+ if (beginPos == std::string::npos || endPos == std::string::npos)
+ TCU_THROW(InternalError, "Couldn't match tags from " + qpaFileName.str() + subProcessExitCodeInfo);
+
+ std::string subQpaCopy = "\n" + std::string(subQpaText.begin() + beginPos, subQpaText.begin() + endPos + endText.size()) + "\n";
+
+ if (!std::string(testCtx.getCommandLine().getServerAddress()).empty())
+ {
+ // Send it to server to append to its log
+ vksc_server::AppendRequest request;
+ request.fileName = testCtx.getCommandLine().getLogFileName();
+ request.data.assign(subQpaCopy.begin(), subQpaCopy.end());
+ vksc_server::StandardOutputServerSingleton()->SendRequest(request);
+ }
+ else
+ {
+ // Write it to parent's log
+ try
+ {
+ testCtx.getLog().supressLogging(false);
+ testCtx.getLog().writeRaw(subQpaCopy.c_str());
+ }
+ catch(...)
+ {
+ testCtx.getLog().supressLogging(true);
+ throw;
+ }
+ testCtx.getLog().supressLogging(true);
+ }
+ }
+
+ {
+ std::string beginStat ("#SubProcessStatus");
+ std::size_t beginPos = subQpaText.find(beginStat);
+ if (beginPos == std::string::npos)
+ TCU_THROW(InternalError, "Couldn't match #SubProcessStatus tag from " + qpaFileName.str() + subProcessExitCodeInfo);
+
+ std::string subQpaStat (subQpaText.begin() + beginPos + beginStat.size(), subQpaText.end());
+
+ std::istringstream str(subQpaStat);
+ int numExecuted, numPassed, numFailed, numNotSupported, numWarnings, numWaived;
+ str >> numExecuted >> numPassed >> numFailed >> numNotSupported >> numWarnings >> numWaived;
+
+ m_status.numExecuted += numExecuted;
+ m_status.numPassed += numPassed;
+ m_status.numNotSupported += numNotSupported;
+ m_status.numWarnings += numWarnings;
+ m_status.numWaived += numWaived;
+ m_status.numFailed += numFailed;
+ }
+
+ deDeleteFile(qpaFileName.str().c_str());
+ }
+#else
+ DE_UNREF(testCtx);
+#endif // CTS_USES_VULKANSC
+}
+
bool TestCaseExecutor::spirvVersionSupported (vk::SpirvVersion spirvVersion)
{
- if (spirvVersion <= vk::getMaxSpirvVersionForVulkan(m_context.getUsedApiVersion()))
+ if (spirvVersion <= vk::getMaxSpirvVersionForVulkan(m_context->getUsedApiVersion()))
return true;
if (spirvVersion <= vk::SPIRV_VERSION_1_4)
- return m_context.isDeviceFunctionalitySupported("VK_KHR_spirv_1_4");
+ return m_context->isDeviceFunctionalitySupported("VK_KHR_spirv_1_4");
return false;
}
// ShaderRenderCase-based tests
glslTests->addChild(sr::createDerivateTests (testCtx));
glslTests->addChild(sr::createDiscardTests (testCtx));
+#ifndef CTS_USES_VULKANSC
glslTests->addChild(sr::createDemoteTests (testCtx));
+#endif // CTS_USES_VULKANSC
glslTests->addChild(sr::createIndexingTests (testCtx));
glslTests->addChild(sr::createShaderInvarianceTests (testCtx));
glslTests->addChild(sr::createLimitTests (testCtx));
glslTests->addChild(shaderexecutor::createAtomicOperationTests (testCtx));
glslTests->addChild(shaderexecutor::createShaderClockTests (testCtx));
+#ifndef CTS_USES_VULKANSC
// Amber GLSL tests.
glslTests->addChild(cts_amber::createCombinedOperationsGroup (testCtx));
glslTests->addChild(cts_amber::createCrashTestGroup (testCtx));
+#endif // CTS_USES_VULKANSC
}
// TestPackage
{
}
+#ifdef CTS_USES_VULKAN
+
TestPackage::TestPackage (tcu::TestContext& testCtx)
: BaseTestPackage(testCtx, "dEQP-VK", "dEQP Vulkan Tests")
{
{
}
+#endif
+
+#ifdef CTS_USES_VULKANSC
+
+TestPackageSC::TestPackageSC (tcu::TestContext& testCtx)
+ : BaseTestPackage(testCtx, "dEQP-VKSC", "dEQP Vulkan SC Tests")
+{
+}
+
+TestPackageSC::~TestPackageSC (void)
+{
+}
+
+#endif // CTS_USES_VULKANSC
+
tcu::TestCaseExecutor* BaseTestPackage::createExecutor (void) const
{
return new TestCaseExecutor(m_testCtx);
}
+#ifdef CTS_USES_VULKAN
+
void TestPackage::init (void)
{
addChild(createTestGroup (m_testCtx, "info", "Build and Device Info Tests", createInfoTests));
addChild(Reconvergence::createTests (m_testCtx, true));
}
+#endif
+
+#ifdef CTS_USES_VULKANSC
+
+void TestPackageSC::init (void)
+{
+ addChild(createTestGroup (m_testCtx, "info", "Build and Device Info Tests", createInfoTests));
+ addChild(api::createTests (m_testCtx));
+ addChild(memory::createTests (m_testCtx));
+ addChild(pipeline::createTests (m_testCtx));
+ addChild(BindingModel::createTests (m_testCtx));
+ addChild(SpirVAssembly::createTests (m_testCtx));
+ addChild(createTestGroup (m_testCtx, "glsl", "GLSL shader execution tests", createGlslTests));
+ addChild(createRenderPassTests (m_testCtx));
+ addChild(createRenderPass2Tests (m_testCtx));
+ addChild(ubo::createTests (m_testCtx));
+ addChild(DynamicState::createTests (m_testCtx));
+ addChild(ssbo::createTests (m_testCtx));
+ addChild(QueryPool::createTests (m_testCtx));
+ addChild(Draw::createTests (m_testCtx));
+ addChild(compute::createTests (m_testCtx));
+ addChild(image::createTests (m_testCtx));
+// addChild(wsi::createTests (m_testCtx));
+ addChild(createSynchronizationTests (m_testCtx));
+ addChild(createSynchronization2Tests (m_testCtx));
+// addChild(sparse::createTests (m_testCtx));
+ addChild(tessellation::createTests (m_testCtx));
+ addChild(rasterization::createTests (m_testCtx));
+ addChild(clipping::createTests (m_testCtx));
+ addChild(FragmentOperations::createTests (m_testCtx));
+ addChild(texture::createTests (m_testCtx));
+ addChild(geometry::createTests (m_testCtx));
+ addChild(robustness::createTests (m_testCtx));
+ addChild(MultiView::createTests (m_testCtx));
+ addChild(subgroups::createTests (m_testCtx));
+ addChild(ycbcr::createTests (m_testCtx));
+ addChild(ProtectedMem::createTests (m_testCtx));
+ addChild(DeviceGroup::createTests (m_testCtx));
+ addChild(MemoryModel::createTests (m_testCtx));
+// addChild(conditional::createTests (m_testCtx));
+// addChild(cts_amber::createGraphicsFuzzTests (m_testCtx));
+ addChild(imageless::createTests (m_testCtx));
+// addChild(TransformFeedback::createTests (m_testCtx));
+ addChild(DescriptorIndexing::createTests (m_testCtx));
+ addChild(FragmentShaderInterlock::createTests(m_testCtx));
+// addChild(modifiers::createTests (m_testCtx));
+// addChild(RayTracing::createTests (m_testCtx));
+// addChild(RayQuery::createTests (m_testCtx));
+ addChild(FragmentShadingRate::createTests(m_testCtx));
+ addChild(sc::createTests(m_testCtx));
+}
+
+#endif // CTS_USES_VULKANSC
+
} // vkt