RenderResultPacket RenderServerRenderer::createRenderResultPacket(const RenderServerRenderRequest & request)
{
    QByteArray outputBuffer;
    int bufferSizeBytes = m_renderer.getScreenBufferSizeBytes();
    outputBuffer.resize(bufferSizeBytes);
    m_renderer.getOutputBuffer(outputBuffer.data());
    RenderResultPacket result = RenderResultPacket(request.getSequenceNumber(), request.getIterationNumbers(), outputBuffer);
    return result;
}
void RenderServerRenderer::pushCommandToQueue( RenderServerRenderRequest renderRequest )
{
    m_queueMutex.lock();
    if(renderRequest.getSequenceNumber() > m_currentSequenceNumber)
    {
        m_currentSequenceNumber = renderRequest.getSequenceNumber();
        m_renderTime.restart();
        m_totalTime.restart();
    }
    m_queue.enqueue(renderRequest);
    m_queueMutex.unlock();
    m_waitCondition.wakeAll();
}
void StandaloneRenderManager::renderNextIteration()
{
    try
    {
        if(m_application.getRunningStatus() == RunningStatus::RUNNING && m_currentScene != NULL)
        {
            m_noEmittedSignals = true;

            if(m_compileScene)
            {
                m_application.setRendererStatus(RendererStatus::INITIALIZING_SCENE);
                m_renderer.initScene(*m_currentScene);
                m_compileScene = false;
                m_application.setRendererStatus(RendererStatus::RENDERING);
            }

            // We only diplay one every X frames on screen (to make fair comparison with distributed renderer)
            bool shouldOutputIteration = m_nextIterationNumber % 5 == 0;

            const double PPMAlpha = 2.0/3.0;
            QVector<unsigned long long> iterationNumbers;
            QVector<double> ppmRadii;

            RenderServerRenderRequestDetails details (m_camera, QByteArray(m_currentScene->getSceneName()), 
                m_application.getRenderMethod(), m_application.getWidth(), m_application.getHeight(), PPMAlpha);

            RenderServerRenderRequest renderRequest (m_application.getSequenceNumber(), iterationNumbers, ppmRadii, details);

            m_renderer.renderNextIteration(m_nextIterationNumber, m_nextIterationNumber, m_PPMRadius, shouldOutputIteration, renderRequest.getDetails());
            const double ppmRadiusSquared = m_PPMRadius*m_PPMRadius;
            const double ppmRadiusSquaredNew = ppmRadiusSquared*(m_nextIterationNumber+PPMAlpha)/double(m_nextIterationNumber+1);
            m_PPMRadius = sqrt(ppmRadiusSquaredNew);

            // Transfer the output buffer to CPU and signal ready for display

            if(shouldOutputIteration)
            {
                if(m_outputBuffer == NULL)
                {
                    m_outputBuffer = new float[2000*2000*3];
                }
                m_renderer.getOutputBuffer(m_outputBuffer);
                emit newFrameReadyForDisplay(m_outputBuffer, m_nextIterationNumber);
            }

            fillRenderStatistics();
            m_nextIterationNumber++;
        }
    }
    catch(const std::exception & E)
    {
        m_application.setRunningStatus(RunningStatus::PAUSE);
        QString error = QString("%1").arg(E.what());
        emit renderManagerError(error);
    }
}
void RenderServerRenderer::onNewRenderCommandInQueue()
{
    while(true)
    {
        // Process queued up events/slots, in case we quit
        QCoreApplication::processEvents();

        if(m_quit)
        {
            return;
        }

        // If queue is empty, we wait until we get a new request
        if(m_queue.size() == 0)
        {
            m_waitCondition.wait(&m_waitConditionMutex);
            continue;
        }
        // Process the next RenderServerRenderRequest

        RenderServerRenderRequest renderRequest = m_queue.dequeue();
        QString iterationNumbersInPacketString = "";

        for(int i = 0; i < renderRequest.getNumIterations(); i++)
        {
            // If the packet we are working has become old during this rendering for-loop, then break out of this loop
            if(m_currentSequenceNumber != renderRequest.getSequenceNumber())
            {
                break;
            }
            // Else we'll render this frame
            else
            {
                // This renderRequest has a new scene name, so we'll load the new scene
                if(m_scene == NULL || m_scene->getSceneName() != renderRequest.getDetails().getSceneName())
                {
                    loadNewScene(renderRequest.getDetails().getSceneName());
                }

                // Render the frame with local iteration number going from 0 to renderRequestsCurrentPacket.size()
                // We only need to create the output buffer for the last iteration of the packet
                bool createOutputBuffer = i == renderRequest.getNumIterations() - 1;
                renderFrame(renderRequest.getIterationNumbers().at(i), i, renderRequest.getPPMRadii().at(i), createOutputBuffer, renderRequest.getDetails());
                iterationNumbersInPacketString += " " + QString::number(renderRequest.getIterationNumbers().at(i));
            }
        }

        // If the packet we have just rendered is old (m_currentSequenceNumber is newer)
        // then we drop this packet. This can happen if we have started on a RenderServerRenderRequest but later found out about
        // a new sequence, in which case we have break-ed out of the loop above.

        if(renderRequest.getSequenceNumber() == m_currentSequenceNumber)
        {
            RenderResultPacket result = createRenderResultPacket(renderRequest);
            QString logString = QString("TRANSFERRING packet (%1 iteration:%2) in sequence %3 to client.")
                                .arg(result.getNumIterationsInPacket())
                                .arg(iterationNumbersInPacketString)
                                .arg(result.getSequenceNumber());
            emit newLogString(logString);
            emit newRenderResultPacket(result);
        }
        else
        {
            QString logString = QString("IGNORED package with %1 iterations since sequence %3 != %4.")
                                .arg(renderRequest.getNumIterations())
                                .arg(renderRequest.getSequenceNumber())
                                .arg(m_currentSequenceNumber);
            emit newLogString(logString);
        }
    }
}
void StandaloneRenderManager::renderNextIteration()
{
    try
    {
        if(m_application.getRunningStatus() == RunningStatus::RUNNING && m_currentScene != NULL)
        {
            m_noEmittedSignals = true;

            if(m_compileScene)
            {
                m_application.setRendererStatus(RendererStatus::INITIALIZING_SCENE);
                m_renderer.initScene(*m_currentScene);
                m_compileScene = false;
                m_application.setRendererStatus(RendererStatus::STARTING_RENDERING);
            }

            // We only display one every X frames on screen (to make fair comparison with distributed renderer)
            bool shouldOutputIteration = m_nextIterationNumber % 5 == 0;
            //bool shouldOutputIteration = m_nextIterationNumber % 1 == 0;

            const double PPMAlpha = 2.0/3.0;
            QVector<unsigned long long> iterationNumbers;
            QVector<double> ppmRadii;

            RenderServerRenderRequestDetails details (m_camera, QByteArray(m_currentScene->getSceneName()), 
                m_application.getRenderMethod(), m_application.getWidth(), m_application.getHeight(), PPMAlpha);

            RenderServerRenderRequest renderRequest (m_application.getSequenceNumber(), iterationNumbers, ppmRadii, details);

            m_renderer.renderNextIteration(m_nextIterationNumber, m_nextIterationNumber, m_PPMRadius, shouldOutputIteration, renderRequest.getDetails());
            const double ppmRadiusSquared = m_PPMRadius*m_PPMRadius;
            const double ppmRadiusSquaredNew = ppmRadiusSquared*(m_nextIterationNumber+PPMAlpha)/double(m_nextIterationNumber+1);
            m_PPMRadius = sqrt(ppmRadiusSquaredNew);

            // set as rendering only after first iteration, since that one can slow due init and sync with gpu
            if (m_application.getRendererStatus() != RendererStatus::RENDERING)
                m_application.setRendererStatus(RendererStatus::RENDERING);

            // Transfer the output buffer to CPU and signal ready for display
            m_outputBufferMutex.lock();
            m_lastRendererIterationNumber = m_nextIterationNumber;
            if(shouldOutputIteration)
            {
                if(m_outputBuffer == NULL)
                {
                    m_outputBuffer = new float[MAX_OUTPUT_X*MAX_OUTPUT_Y*3];
                }
                m_renderer.getOutputBuffer(m_outputBuffer);
                // FIXME
                // vmarz: m_lastRendererIterationNumber shouldn't be exposed like that, but passed next iteration number
                // can be invalid (already incremented) when render widget is updating and accumulated values get scaled incorrectly
                emit newFrameReadyForDisplay(m_outputBuffer, &m_lastRendererIterationNumber, &m_outputBufferMutex);
            }
            m_outputBufferMutex.unlock();

            fillRenderStatistics();
            m_nextIterationNumber++;
        }
    }
    catch(const std::exception & E)
    {
        m_application.setRunningStatus(RunningStatus::PAUSE);
        QString error = QString("%1").arg(E.what());
        emit renderManagerError(error);
    }
}