示例#1
0
VkBool32 VKTS_APIENTRY engineAddUpdateThread(const IUpdateThreadSP& updateThread)
{
    if (g_engineState != VKTS_ENGINE_INIT_STATE)
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Not in initialize state.");

        return VK_FALSE;
    }

    if (!updateThread.get())
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! No update thread.");

        return VK_FALSE;
    }

    if (engineGetNumberUpdateThreads() >= VKTS_MAX_UPDATE_THREADS)
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Adding update thread failed! Too many update threads.");

        return VK_FALSE;
    }

    g_allUpdateThreads.append(updateThread);

    return VK_TRUE;
}
示例#2
0
VkBool32 VKTS_APIENTRY barrierSync()
{
    std::unique_lock<std::mutex> barrierUniqueLock(g_barrierMutex);

    if (g_barrierGeneration < 0)
    {
        return VK_FALSE;
    }

    // If there is no executing thread, start new barrier ...
    if (g_barrierExecutingUpdateThreads == 0)
    {
        // ... by setting the total number of threads.
        g_barrierExecutingUpdateThreads = engineGetNumberUpdateThreads();

        // Error case, so just return.
        if (g_barrierExecutingUpdateThreads < VKTS_MIN_UPDATE_THREADS)
        {
            return VK_FALSE;
        }
    }

    // Remove this executing thread.
    g_barrierExecutingUpdateThreads--;

    // Are there any executing threads?
    if (g_barrierExecutingUpdateThreads > 0)
    {
        int32_t currentBarrierGeneration = g_barrierGeneration;

        // Yes, so wait until all have reached the barrier.
        do
        {
            g_barrierConditionVariable.wait(barrierUniqueLock);
        }
        while (currentBarrierGeneration == g_barrierGeneration);
    }
    else
    {
        // No, so all have reached the barrier.

        // Initiate next barrier generation. This allows the other threads to proceed.
        g_barrierGeneration++;
        if (g_barrierGeneration < 0)
        {
            g_barrierGeneration = 0;
        }

        // Wake up the rest.
        g_barrierConditionVariable.notify_all();

        return VK_TRUE;
    }

    return VK_TRUE;
}
示例#3
0
VkBool32 VKTS_APIENTRY engineRun()
{
    if (g_engineState != VKTS_ENGINE_INIT_STATE)
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Not in initialize state.");

        return VK_FALSE;
    }

    if (engineGetNumberUpdateThreads() < VKTS_MIN_UPDATE_THREADS || engineGetNumberUpdateThreads() > VKTS_MAX_UPDATE_THREADS)
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Number of update threads not correct.");

        return VK_FALSE;
    }

    //
    // Main thread gets all displays and windows attached.
    //

    const auto& displayList = _visualGetActiveDisplays();

    for (size_t i = 0; i < displayList.size(); i++)
    {
        engineAttachDisplayToUpdateThread(displayList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]);
    }

    const auto& windowList = _visualGetActiveWindows();

    for (size_t i = 0; i < windowList.size(); i++)
    {
        engineAttachWindowToUpdateThread(windowList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]);
    }

    //

    g_engineState = VKTS_ENGINE_UPDATE_STATE;

    logPrint(VKTS_LOG_INFO, "Engine: Started.");

    // Task queue creation.

    TaskQueueSP sendTaskQueue;
    TaskQueueSP executedTaskQueue;

    if (g_taskExecutorCount > 0)
    {
        sendTaskQueue = TaskQueueSP(new TaskQueue);

        if (!sendTaskQueue.get())
        {
            logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue.");

            return VK_FALSE;
        }

        executedTaskQueue = TaskQueueSP(new TaskQueue);

        if (!executedTaskQueue.get())
        {
            logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue.");

            return VK_FALSE;
        }
    }

    // Message dispatcher creation.

    MessageDispatcherSP messageDispatcher = MessageDispatcherSP(new MessageDispatcher());

    if (!messageDispatcher.get())
    {
        logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create message dispatcher.");

        return VK_FALSE;
    }

    // Object, needed for synchronizing the executors.

    ExecutorSync executorSync;

    //
    // Task executor creation and launching,
    //

    SmartPointerVector<TaskExecutorSP> realTaskExecutors;
    SmartPointerVector<ThreadSP> realTaskThreads;

    for (uint32_t i = 0; i < g_taskExecutorCount; i++)
    {
        auto currentTaskExecutor = TaskExecutorSP(new TaskExecutor(i, executorSync, sendTaskQueue, executedTaskQueue));

        if (!currentTaskExecutor.get())
        {
            logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current task executor.");

            return VK_FALSE;
        }

        auto currentRealThread = ThreadSP(new std::thread(&TaskExecutor::run, currentTaskExecutor));

        if (!currentRealThread.get())
        {
            logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread.");

            return VK_FALSE;
        }

        //

        realTaskExecutors.append(currentTaskExecutor);
        realTaskThreads.append(currentRealThread);

        logPrint(VKTS_LOG_INFO, "Engine: Task %d started.", currentTaskExecutor->getIndex());
    }

    //
    // Update Thread creation and launching.
    //

    UpdateThreadExecutorSP mainUpdateThreadExecutor;

    SmartPointerVector<UpdateThreadExecutorSP> realUpdateThreadExecutors;
    SmartPointerVector<ThreadSP> realUpdateThreads;

    int32_t index = 0;

    for (size_t updateThreadIndex = 0; updateThreadIndex < g_allUpdateThreads.size(); updateThreadIndex++)
    {
        const auto& currentUpdateThread = g_allUpdateThreads[updateThreadIndex];

        //

        const auto currentMessageDispatcher = (index == engineGetNumberUpdateThreads() - 1) ? messageDispatcher : MessageDispatcherSP();

        //

        auto currentUpdateThreadContext = UpdateThreadContextSP(new UpdateThreadContext((int32_t) updateThreadIndex, (int32_t) g_allUpdateThreads.size(), g_tickTime, sendTaskQueue, executedTaskQueue));

        if (!currentUpdateThreadContext.get())
        {
            logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create update thread context.");

            return VK_FALSE;
        }

        //

        for (auto currentDisplayWalker = g_allAttachedDisplays.lower_bound(currentUpdateThread); currentDisplayWalker != g_allAttachedDisplays.upper_bound(currentUpdateThread); currentDisplayWalker++)
        {
            currentUpdateThreadContext->attachDisplay(currentDisplayWalker->second);
        }

        //

        for (auto currentWindowWalker = g_allAttachedWindows.lower_bound(currentUpdateThread); currentWindowWalker != g_allAttachedWindows.upper_bound(currentUpdateThread); currentWindowWalker++)
        {
            currentUpdateThreadContext->attachWindow(currentWindowWalker->second);
        }

        //

        if (index == engineGetNumberUpdateThreads() - 1)
        {
            // Last thread is the main thread.
            mainUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher));

            if (!mainUpdateThreadExecutor.get())
            {
                logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create main update thread executor.");

                return VK_FALSE;
            }
        }
        else
        {
            // Receive queue is the threads send queue.
            auto currentUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher));

            if (!currentUpdateThreadExecutor.get())
            {
                logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current update thread executor.");

                return VK_FALSE;
            }

            realUpdateThreadExecutors.append(currentUpdateThreadExecutor);

            logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", currentUpdateThreadExecutor->getIndex());

            auto currentRealThread = ThreadSP(new std::thread(&UpdateThreadExecutor::run, currentUpdateThreadExecutor));

            if (!currentRealThread.get())
            {
                logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread.");

                return VK_FALSE;
            }
            realUpdateThreads.append(currentRealThread);
        }
        index++;
    }

    // Run last thread and loop.
    logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", mainUpdateThreadExecutor->getIndex());

    mainUpdateThreadExecutor->run();

    //
    // Stopping everything.
    //

    logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", mainUpdateThreadExecutor->getIndex());

    // Wait for all threads to finish in the reverse order they were created.
    for (auto reverseIndex = static_cast<int32_t>(realUpdateThreads.size()) - 1; reverseIndex >= 0; reverseIndex--)
    {
        const auto& currentRealThread = realUpdateThreads[reverseIndex];

        currentRealThread->join();

        logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", reverseIndex);
    }

    realUpdateThreadExecutors.clear();
    realUpdateThreads.clear();

    //

    if (sendTaskQueue.get())
    {
    	// Empty the queue.
    	// As no update thread can feed the queue anymore, it is save to call reset.

    	sendTaskQueue->reset();

    	//

    	ITaskSP stopTask;

        logPrint(VKTS_LOG_SEVERE, "Engine: Disabling task queue.");

    	for (uint32_t i = 0; i < g_taskExecutorCount; i++)
    	{
    		// Send an empty task to the queue, to exit the thread.
    		sendTaskQueue->addTask(stopTask);
    	}
    }

    // Wait for all tasks to finish in the reverse order they were created.
    for (auto reverseIndex = static_cast<int32_t>(realTaskThreads.size()) - 1; reverseIndex >= 0; reverseIndex--)
    {
        const auto& currentRealThread = realTaskThreads[reverseIndex];

        currentRealThread->join();

        logPrint(VKTS_LOG_INFO, "Engine: Task %d stopped.", reverseIndex);
    }

    realTaskExecutors.clear();
    realTaskThreads.clear();

    //

    g_engineState = VKTS_ENGINE_INIT_STATE;

    logPrint(VKTS_LOG_INFO, "Engine: Stopped.");

    return VK_TRUE;
}