Merge vk-gl-cts/dev/VK_KHR_fragment_shader_barycentric into vk-gl-cts/main
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / vktTestPackage.cpp
index 711dedb..112b2fa 100644 (file)
@@ -23,6 +23,9 @@
 
 #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)
@@ -228,16 +215,104 @@ static vk::VkPhysicalDeviceProperties getPhysicalDeviceProperties(vkt::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());
@@ -246,7 +321,43 @@ TestCaseExecutor::TestCaseExecutor (tcu::TestContext& testCtx)
                                                        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)
@@ -256,24 +367,53 @@ 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();
 
@@ -285,7 +425,7 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
                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)
                {
@@ -309,7 +449,7 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
                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)
                {
@@ -333,14 +473,14 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
                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)
@@ -348,14 +488,39 @@ 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)
@@ -390,7 +555,7 @@ 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;
                }
        }
 }
@@ -404,24 +569,379 @@ tcu::TestNode::IterateResult TestCaseExecutor::iterate (tcu::TestCase*)
        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;
 }
@@ -478,7 +998,9 @@ void createGlslTests (tcu::TestCaseGroup* glslTests)
        // 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));
@@ -498,9 +1020,11 @@ void createGlslTests (tcu::TestCaseGroup* glslTests)
        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
@@ -514,6 +1038,8 @@ BaseTestPackage::~BaseTestPackage (void)
 {
 }
 
+#ifdef CTS_USES_VULKAN
+
 TestPackage::TestPackage (tcu::TestContext& testCtx)
        : BaseTestPackage(testCtx, "dEQP-VK", "dEQP Vulkan Tests")
 {
@@ -532,11 +1058,28 @@ ExperimentalTestPackage::~ExperimentalTestPackage (void)
 {
 }
 
+#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));
@@ -594,4 +1137,58 @@ void ExperimentalTestPackage::init (void)
        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