<commit_before>/*
* Copyright (c) 2002 - present, H. Hernan Saez
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the copyright holders nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "VulkanSystem.hpp"

#include "Foundation/Containers/Array.hpp"
#include "Rendering/Programs/SkyboxShaderProgram.hpp"
#include "Rendering/Programs/UnlitShaderProgram.hpp"
#include "Rendering/ShaderProgram.hpp"
#include "Rendering/VulkanCommandBuffer.hpp"
#include "Rendering/VulkanCommandPool.hpp"
#include "Rendering/VulkanFence.hpp"
#include "Rendering/VulkanRenderDevice.hpp"
#include "Rendering/VulkanSwapchain.hpp"
#include "SceneGraph/Camera.hpp"
#include "Simulation/AssetManager.hpp"
#include "Simulation/FileSystem.hpp"
#include "Simulation/Simulation.hpp"
#include "Simulation/Systems/RenderSystem.hpp"

using namespace crimild;
using namespace crimild::vulkan;

void VulkanSystem::start( void ) noexcept
{
    initShaders();

    createInstance()
        && createDebugMessenger()
        && createSurface()
        && createPhysicalDevice()
        && createRenderDevice()
        && createCommandPool()
        && recreateSwapchain();
}

/*
 1. Acquire an image from the swapchain
 2. Execute command buffer with that image as attachment in the framebuffer
 3. Return the image to the swapchain for presentation
*/
void VulkanSystem::onRender( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );
    if ( renderDevice == nullptr ) {
        CRIMILD_LOG_ERROR( "No valid render device instance" );
        return;
    }

    // auto graphicsCommandBuffers = m_frameGraph->recordGraphicsCommands( m_currentFrame, m_recordWithNonConditionalPasses );
    // auto computeCommandBuffers = m_frameGraph->recordComputeCommands( m_currentFrame, m_recordWithNonConditionalPasses );

    auto renderSystem = RenderSystem::getInstance();
    auto &graphicsCommandBuffers = renderSystem->getGraphicsCommands( m_currentFrame, m_recordWithNonConditionalPasses );
    auto &computeCommandBuffers = renderSystem->getComputeCommands( m_currentFrame, m_recordWithNonConditionalPasses );

    auto swapchain = crimild::get_ptr( m_swapchain );

    auto wait = crimild::get_ptr( m_imageAvailableSemaphores[ m_currentFrame ] );
    auto signal = crimild::get_ptr( m_renderFinishedSemaphores[ m_currentFrame ] );
    auto fence = crimild::get_ptr( m_inFlightFences[ m_currentFrame ] );

    // Wait for any pending operations to complete
    fence->wait();
    fence->reset();

    // Acquire the next image available image from the swapchain
    // Execution of command buffers is asynchrounous. It must be set up to
    // wait on image adquisition to finish
    auto result = swapchain->acquireNextImage( wait );
    if ( !result.success ) {
        if ( result.outOfDate ) {
            // No image is available since environemnt has changed
            // Maybe window was resized.
            // Recreate swapchain and related objects
            cleanSwapchain();
            recreateSwapchain();
            return;
        } else {
            CRIMILD_LOG_ERROR( "No image available" );
            exit( -1 );
        }
    }

    auto imageIndex = result.imageIndex;

    // TODO: This migth be a bit slow...
    updateVertexBuffers();
    updateIndexBuffers();
    updateUniformBuffers();

    // Submit graphic commands to the render device, with the selected
    // image as attachment in the framebuffer
    renderDevice->submitGraphicsCommands(
        wait,
        graphicsCommandBuffers,
        imageIndex,
        signal,
        fence );

    // Return the image to the swapchain so it can be presented
    auto presentationResult = swapchain->presentImage( imageIndex, signal );
    if ( !presentationResult.success ) {
        if ( presentationResult.outOfDate ) {
            cleanSwapchain();
            recreateSwapchain();
            return;
        } else {
            CRIMILD_LOG_ERROR( "Failed to present image" );
            exit( -1 );
        }
    }

    computeCommandBuffers.each(
        [ & ]( auto commandBuffer ) {
            renderDevice->submitComputeCommands( crimild::get_ptr( commandBuffer ) );
            renderDevice->waitIdle();
        } );

    m_currentFrame = ( m_currentFrame + 1 ) % swapchain->getImages().size();

    if ( m_recordWithNonConditionalPasses && m_currentFrame == 0 ) {
        // We have been rendering using command buffers that included conditional render passes
        // We need to record all commands again now, without the conditional passes.
        // If m_currentFrame == 0, that means we have rendered all in-flight frames already
        m_recordWithNonConditionalPasses = false;
    }
}

void VulkanSystem::stop( void ) noexcept
{
    System::stop();

    cleanSwapchain();

    m_commandPool = nullptr;
    m_renderDevice = nullptr;
    m_physicalDevice = nullptr;
    m_debugMessenger = nullptr;
    m_surface = nullptr;
    m_instance = nullptr;

    RenderDeviceManager::cleanup();
    PhysicalDeviceManager::cleanup();
    VulkanDebugMessengerManager::cleanup();
    VulkanSurfaceManager::cleanup();
    VulkanInstanceManager::cleanup();
}

crimild::Bool VulkanSystem::createInstance( void ) noexcept
{
    auto settings = Simulation::getInstance()->getSettings();
    auto appName = settings->get< std::string >( Settings::SETTINGS_APP_NAME, "Crimild" );
    auto appVersionMajor = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_MAJOR, 1 );
    auto appVersionMinor = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_MINOR, 0 );
    auto appVersionPatch = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_PATCH, 0 );

    m_instance = create(
        VulkanInstance::Descriptor {
            .appName = appName,
            .appVersionMajor = appVersionMajor,
            .appVersionMinor = appVersionMinor,
            .appVersionPatch = appVersionPatch } );

    return m_instance != nullptr;
}

crimild::Bool VulkanSystem::createDebugMessenger( void ) noexcept
{
    m_debugMessenger = create(
        VulkanDebugMessenger::Descriptor {
            .instance = crimild::get_ptr( m_instance ) } );
    return m_debugMessenger != nullptr;
}

crimild::Bool VulkanSystem::createSurface( void ) noexcept
{
    m_surface = create(
        VulkanSurface::Descriptor {
            .instance = crimild::get_ptr( m_instance ) } );
    if ( m_surface == nullptr ) {
        return false;
    }

    attach( crimild::get_ptr( m_surface ) );
    return true;
}

crimild::Bool VulkanSystem::createPhysicalDevice( void ) noexcept
{
    m_physicalDevice = create(
        PhysicalDevice::Descriptor {
            .instance = crimild::get_ptr( m_instance ),
            .surface = crimild::get_ptr( m_surface ) } );
    return m_physicalDevice != nullptr;
}

crimild::Bool VulkanSystem::createRenderDevice( void ) noexcept
{
    m_renderDevice = m_physicalDevice->create( RenderDevice::Descriptor {} );
    return m_renderDevice != nullptr;
}

crimild::Bool VulkanSystem::createSwapchain( void ) noexcept
{
    auto settings = Simulation::getInstance()->getSettings();
    auto width = settings->get< crimild::UInt >( "video.width", 0 );
    auto height = settings->get< crimild::UInt >( "video.height", 0 );

    m_swapchain = m_renderDevice->create(
        Swapchain::Descriptor {
            .extent = Vector2ui { width, height } } );

    if ( m_swapchain == nullptr ) {
        return false;
    }

    settings->set( "video.width", m_swapchain->extent.width );
    settings->set( "video.height", m_swapchain->extent.height );

    if ( auto mainCamera = Camera::getMainCamera() ) {
        mainCamera->setAspectRatio( ( crimild::Real32 ) m_swapchain->extent.width / ( crimild::Real32 ) m_swapchain->extent.height );
    }

    // Reset existing command buffers
    m_recordWithNonConditionalPasses = true;

    return true;
}

void VulkanSystem::cleanSwapchain( void ) noexcept
{
    if ( auto renderDevice = crimild::get_ptr( m_renderDevice ) ) {
        CRIMILD_LOG_TRACE( "Waiting for pending operations" );
        m_renderDevice->waitIdle();

        static_cast< DescriptorSetManager * >( renderDevice )->clear();
        static_cast< DescriptorSetLayoutManager * >( renderDevice )->clear();
        static_cast< DescriptorPoolManager * >( renderDevice )->clear();
        static_cast< UniformBufferManager * >( renderDevice )->clear();
        static_cast< CommandBufferManager * >( renderDevice )->clear();
        static_cast< GraphicsPipelineManager * >( renderDevice )->clear();
        static_cast< ComputePipelineManager * >( renderDevice )->clear();
        static_cast< RenderPassManager * >( renderDevice )->clear();
        static_cast< ImageViewManager * >( renderDevice )->clear();
        static_cast< ImageManager * >( renderDevice )->clear();

        renderDevice->reset( crimild::get_ptr( m_commandPool ) );
    }

    m_inFlightFences.clear();
    m_imageAvailableSemaphores.clear();
    m_renderFinishedSemaphores.clear();
    m_swapchain = nullptr;
    m_currentFrame = 0;
}

crimild::Bool VulkanSystem::recreateSwapchain( void ) noexcept
{
    cleanSwapchain();

    return createSwapchain()
           && createSyncObjects();
}

crimild::Bool VulkanSystem::createSyncObjects( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );

    for ( auto i = 0l; i < m_swapchain->getImages().size(); i++ ) {
        m_imageAvailableSemaphores.push_back( renderDevice->create( Semaphore::Descriptor {} ) );
        m_renderFinishedSemaphores.push_back( renderDevice->create( Semaphore::Descriptor {} ) );
        m_inFlightFences.push_back( renderDevice->create( Fence::Descriptor {} ) );
    }

    return true;
}

crimild::Bool VulkanSystem::createCommandPool( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );
    auto queueFamilyIndices = utils::findQueueFamilies( m_physicalDevice->handler, m_surface->handler );
    m_commandPool = renderDevice->create(
        CommandPool::Descriptor {
            .queueFamilyIndex = queueFamilyIndices.graphicsFamily[ 0 ],
        } );

    return m_commandPool != nullptr;
}

void VulkanSystem::updateVertexBuffers( void ) noexcept
{
    getRenderDevice()->updateVertexBuffers();
}

void VulkanSystem::updateIndexBuffers( void ) noexcept
{
    getRenderDevice()->updateIndexBuffers();
}

void VulkanSystem::updateUniformBuffers( void ) noexcept
{
    getRenderDevice()->updateUniformBuffers( 0 );
}

void VulkanSystem::initShaders( void ) noexcept
{
    auto createShader = []( Shader::Stage stage, const unsigned char *rawData, crimild::Size size ) {
        std::vector< char > data( size + ( size % 4 ) );
        memcpy( &data[ 0 ], rawData, size );
        return crimild::alloc< Shader >( stage, data );
    };

    auto assets = AssetManager::getInstance();

    assets->get< UnlitShaderProgram >()->setShaders(
        {
            [ & ] {
#include "Rendering/Shaders/unlit/unlit.vert.inl"
                return createShader( Shader::Stage::VERTEX, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
            [ & ] {
#include "Rendering/Shaders/unlit/unlit.frag.inl"
                return createShader( Shader::Stage::FRAGMENT, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
        } );

    assets->get< SkyboxShaderProgram >()->setShaders(
        {
            [ & ] {
#include "Rendering/Shaders/unlit/skybox.vert.inl"
                return createShader( Shader::Stage::VERTEX, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
            [ & ] {
#include "Rendering/Shaders/unlit/skybox.frag.inl"
                return createShader( Shader::Stage::FRAGMENT, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
        } );
}
<commit_msg>Fix Vulkan issue in Release builds<commit_after>/*
* Copyright (c) 2002 - present, H. Hernan Saez
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the copyright holders nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "VulkanSystem.hpp"

#include "Foundation/Containers/Array.hpp"
#include "Rendering/Programs/SkyboxShaderProgram.hpp"
#include "Rendering/Programs/UnlitShaderProgram.hpp"
#include "Rendering/ShaderProgram.hpp"
#include "Rendering/VulkanCommandBuffer.hpp"
#include "Rendering/VulkanCommandPool.hpp"
#include "Rendering/VulkanFence.hpp"
#include "Rendering/VulkanRenderDevice.hpp"
#include "Rendering/VulkanSwapchain.hpp"
#include "SceneGraph/Camera.hpp"
#include "Simulation/AssetManager.hpp"
#include "Simulation/FileSystem.hpp"
#include "Simulation/Simulation.hpp"
#include "Simulation/Systems/RenderSystem.hpp"

using namespace crimild;
using namespace crimild::vulkan;

void VulkanSystem::start( void ) noexcept
{
    initShaders();

    createInstance()
        && createDebugMessenger()
        && createSurface()
        && createPhysicalDevice()
        && createRenderDevice()
        && createCommandPool()
        && recreateSwapchain();
}

/*
 1. Acquire an image from the swapchain
 2. Execute command buffer with that image as attachment in the framebuffer
 3. Return the image to the swapchain for presentation
*/
void VulkanSystem::onRender( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );
    if ( renderDevice == nullptr ) {
        CRIMILD_LOG_ERROR( "No valid render device instance" );
        return;
    }

    // auto graphicsCommandBuffers = m_frameGraph->recordGraphicsCommands( m_currentFrame, m_recordWithNonConditionalPasses );
    // auto computeCommandBuffers = m_frameGraph->recordComputeCommands( m_currentFrame, m_recordWithNonConditionalPasses );

    auto renderSystem = RenderSystem::getInstance();
    auto &graphicsCommandBuffers = renderSystem->getGraphicsCommands( m_currentFrame, m_recordWithNonConditionalPasses );
    auto &computeCommandBuffers = renderSystem->getComputeCommands( m_currentFrame, m_recordWithNonConditionalPasses );

    auto swapchain = crimild::get_ptr( m_swapchain );

    auto wait = crimild::get_ptr( m_imageAvailableSemaphores[ m_currentFrame ] );
    auto signal = crimild::get_ptr( m_renderFinishedSemaphores[ m_currentFrame ] );
    auto fence = crimild::get_ptr( m_inFlightFences[ m_currentFrame ] );

    // Wait for any pending operations to complete
    fence->wait();
    fence->reset();

    // Acquire the next image available image from the swapchain
    // Execution of command buffers is asynchrounous. It must be set up to
    // wait on image adquisition to finish
    auto result = swapchain->acquireNextImage( wait );
    if ( !result.success ) {
        if ( result.outOfDate ) {
            // No image is available since environemnt has changed
            // Maybe window was resized.
            // Recreate swapchain and related objects
            cleanSwapchain();
            recreateSwapchain();
            return;
        } else {
            CRIMILD_LOG_ERROR( "No image available" );
            exit( -1 );
        }
    }

    auto imageIndex = result.imageIndex;

    // TODO: This migth be a bit slow...
    updateVertexBuffers();
    updateIndexBuffers();
    updateUniformBuffers();

    // Submit graphic commands to the render device, with the selected
    // image as attachment in the framebuffer
    renderDevice->submitGraphicsCommands(
        wait,
        graphicsCommandBuffers,
        imageIndex,
        signal,
        fence );

    // Return the image to the swapchain so it can be presented
    auto presentationResult = swapchain->presentImage( imageIndex, signal );
    if ( !presentationResult.success ) {
        if ( presentationResult.outOfDate ) {
            cleanSwapchain();
            recreateSwapchain();
            return;
        } else {
            CRIMILD_LOG_ERROR( "Failed to present image" );
            exit( -1 );
        }
    }

    computeCommandBuffers.each(
        [ & ]( auto commandBuffer ) {
            renderDevice->submitComputeCommands( crimild::get_ptr( commandBuffer ) );
            renderDevice->waitIdle();
        } );

    m_currentFrame = ( m_currentFrame + 1 ) % swapchain->getImages().size();

    if ( m_recordWithNonConditionalPasses && m_currentFrame == 0 ) {
        // We have been rendering using command buffers that included conditional render passes
        // We need to record all commands again now, without the conditional passes.
        // If m_currentFrame == 0, that means we have rendered all in-flight frames already
        m_recordWithNonConditionalPasses = false;
    }
}

void VulkanSystem::stop( void ) noexcept
{
    System::stop();

    cleanSwapchain();

    m_commandPool = nullptr;
    m_renderDevice = nullptr;
    m_physicalDevice = nullptr;
    m_debugMessenger = nullptr;
    m_surface = nullptr;
    m_instance = nullptr;

    RenderDeviceManager::cleanup();
    PhysicalDeviceManager::cleanup();
    VulkanDebugMessengerManager::cleanup();
    VulkanSurfaceManager::cleanup();
    VulkanInstanceManager::cleanup();
}

crimild::Bool VulkanSystem::createInstance( void ) noexcept
{
    auto settings = Simulation::getInstance()->getSettings();
    auto appName = settings->get< std::string >( Settings::SETTINGS_APP_NAME, "Crimild" );
    auto appVersionMajor = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_MAJOR, 1 );
    auto appVersionMinor = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_MINOR, 0 );
    auto appVersionPatch = settings->get< crimild::UInt32 >( Settings::SETTINGS_APP_VERSION_PATCH, 0 );

    m_instance = create(
        VulkanInstance::Descriptor {
            .appName = appName,
            .appVersionMajor = appVersionMajor,
            .appVersionMinor = appVersionMinor,
            .appVersionPatch = appVersionPatch } );

    return m_instance != nullptr;
}

crimild::Bool VulkanSystem::createDebugMessenger( void ) noexcept
{
    m_debugMessenger = create(
        VulkanDebugMessenger::Descriptor {
            .instance = crimild::get_ptr( m_instance ) } );

    // Never fails (Debug messenger is disabled for Release builds)
	return true;
}

crimild::Bool VulkanSystem::createSurface( void ) noexcept
{
    CRIMILD_LOG_TRACE( "Creating Vulkan surface" );
    m_surface = create(
        VulkanSurface::Descriptor {
            .instance = crimild::get_ptr( m_instance ) } );
    if ( m_surface == nullptr ) {
        CRIMILD_LOG_ERROR( "Failed to create Vulkan surface" );
        return false;
    }

    attach( crimild::get_ptr( m_surface ) );
    CRIMILD_LOG_ERROR( "Vulkan Surface created" );
    return true;
}

crimild::Bool VulkanSystem::createPhysicalDevice( void ) noexcept
{
    m_physicalDevice = create(
        PhysicalDevice::Descriptor {
            .instance = crimild::get_ptr( m_instance ),
            .surface = crimild::get_ptr( m_surface ) } );
    return m_physicalDevice != nullptr;
}

crimild::Bool VulkanSystem::createRenderDevice( void ) noexcept
{
    m_renderDevice = m_physicalDevice->create( RenderDevice::Descriptor {} );
    return m_renderDevice != nullptr;
}

crimild::Bool VulkanSystem::createSwapchain( void ) noexcept
{
    auto settings = Simulation::getInstance()->getSettings();
    auto width = settings->get< crimild::UInt >( "video.width", 0 );
    auto height = settings->get< crimild::UInt >( "video.height", 0 );

    m_swapchain = m_renderDevice->create(
        Swapchain::Descriptor {
            .extent = Vector2ui { width, height } } );

    if ( m_swapchain == nullptr ) {
        return false;
    }

    settings->set( "video.width", m_swapchain->extent.width );
    settings->set( "video.height", m_swapchain->extent.height );

    if ( auto mainCamera = Camera::getMainCamera() ) {
        mainCamera->setAspectRatio( ( crimild::Real32 ) m_swapchain->extent.width / ( crimild::Real32 ) m_swapchain->extent.height );
    }

    // Reset existing command buffers
    m_recordWithNonConditionalPasses = true;

    return true;
}

void VulkanSystem::cleanSwapchain( void ) noexcept
{
    if ( auto renderDevice = crimild::get_ptr( m_renderDevice ) ) {
        CRIMILD_LOG_TRACE( "Waiting for pending operations" );
        m_renderDevice->waitIdle();

        static_cast< DescriptorSetManager * >( renderDevice )->clear();
        static_cast< DescriptorSetLayoutManager * >( renderDevice )->clear();
        static_cast< DescriptorPoolManager * >( renderDevice )->clear();
        static_cast< UniformBufferManager * >( renderDevice )->clear();
        static_cast< CommandBufferManager * >( renderDevice )->clear();
        static_cast< GraphicsPipelineManager * >( renderDevice )->clear();
        static_cast< ComputePipelineManager * >( renderDevice )->clear();
        static_cast< RenderPassManager * >( renderDevice )->clear();
        static_cast< ImageViewManager * >( renderDevice )->clear();
        static_cast< ImageManager * >( renderDevice )->clear();

        renderDevice->reset( crimild::get_ptr( m_commandPool ) );
    }

    m_inFlightFences.clear();
    m_imageAvailableSemaphores.clear();
    m_renderFinishedSemaphores.clear();
    m_swapchain = nullptr;
    m_currentFrame = 0;
}

crimild::Bool VulkanSystem::recreateSwapchain( void ) noexcept
{
    cleanSwapchain();

    return createSwapchain()
           && createSyncObjects();
}

crimild::Bool VulkanSystem::createSyncObjects( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );

    for ( auto i = 0l; i < m_swapchain->getImages().size(); i++ ) {
        m_imageAvailableSemaphores.push_back( renderDevice->create( Semaphore::Descriptor {} ) );
        m_renderFinishedSemaphores.push_back( renderDevice->create( Semaphore::Descriptor {} ) );
        m_inFlightFences.push_back( renderDevice->create( Fence::Descriptor {} ) );
    }

    return true;
}

crimild::Bool VulkanSystem::createCommandPool( void ) noexcept
{
    auto renderDevice = crimild::get_ptr( m_renderDevice );
    auto queueFamilyIndices = utils::findQueueFamilies( m_physicalDevice->handler, m_surface->handler );
    m_commandPool = renderDevice->create(
        CommandPool::Descriptor {
            .queueFamilyIndex = queueFamilyIndices.graphicsFamily[ 0 ],
        } );

    return m_commandPool != nullptr;
}

void VulkanSystem::updateVertexBuffers( void ) noexcept
{
    getRenderDevice()->updateVertexBuffers();
}

void VulkanSystem::updateIndexBuffers( void ) noexcept
{
    getRenderDevice()->updateIndexBuffers();
}

void VulkanSystem::updateUniformBuffers( void ) noexcept
{
    getRenderDevice()->updateUniformBuffers( 0 );
}

void VulkanSystem::initShaders( void ) noexcept
{
    auto createShader = []( Shader::Stage stage, const unsigned char *rawData, crimild::Size size ) {
        std::vector< char > data( size + ( size % 4 ) );
        memcpy( &data[ 0 ], rawData, size );
        return crimild::alloc< Shader >( stage, data );
    };

    auto assets = AssetManager::getInstance();

    assets->get< UnlitShaderProgram >()->setShaders(
        {
            [ & ] {
#include "Rendering/Shaders/unlit/unlit.vert.inl"
                return createShader( Shader::Stage::VERTEX, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
            [ & ] {
#include "Rendering/Shaders/unlit/unlit.frag.inl"
                return createShader( Shader::Stage::FRAGMENT, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
        } );

    assets->get< SkyboxShaderProgram >()->setShaders(
        {
            [ & ] {
#include "Rendering/Shaders/unlit/skybox.vert.inl"
                return createShader( Shader::Stage::VERTEX, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
            [ & ] {
#include "Rendering/Shaders/unlit/skybox.frag.inl"
                return createShader( Shader::Stage::FRAGMENT, RESOURCE_BYTES, sizeof( RESOURCE_BYTES ) );
            }(),
        } );
}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "configuration.h"

// appleseed.renderer headers.
#include "renderer/kernel/lighting/drt/drtlightingengine.h"
#include "renderer/kernel/lighting/pt/ptlightingengine.h"
#include "renderer/kernel/lighting/sppm/sppmlightingengine.h"
#include "renderer/kernel/rendering/final/uniformpixelrenderer.h"
#include "renderer/kernel/rendering/generic/genericframerenderer.h"
#include "renderer/kernel/rendering/progressive/progressiveframerenderer.h"
#include "renderer/kernel/texturing/texturestore.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <cassert>
#include <cstring>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// Configuration class implementation.
//

namespace
{
    const UniqueID g_class_uid = new_guid();
}

UniqueID Configuration::get_class_uid()
{
    return g_class_uid;
}

Configuration::Configuration(const char* name)
  : Entity(g_class_uid)
  , m_base(0)
{
    set_name(name);
}

void Configuration::release()
{
    delete this;
}

void Configuration::set_base(const Configuration* base)
{
    m_base = base;
}

const Configuration* Configuration::get_base() const
{
    return m_base;
}

ParamArray Configuration::get_inherited_parameters() const
{
    if (m_base)
    {
        ParamArray params = m_base->m_params;
        params.merge(m_params);
        return params;
    }
    else
    {
        return m_params;
    }
}

Dictionary Configuration::get_metadata()
{
    ParamArray metadata;

    metadata.insert(
        "sampling_mode",
        Dictionary()
            .insert("type", "enum")
            .insert("values", "rng|qmc")
            .insert("default", "rng")
            .insert("help", "Sampler to use when generating samples")
            .insert(
                "options",
                Dictionary()
                    .insert("rng", Dictionary().insert("help", "Random sampler"))
                    .insert("qmc", Dictionary().insert("help", "Quasi Monte Carlo sampler"))));

    metadata.insert(
        "lighting_engine",
        Dictionary()
            .insert("type", "enum")
            .insert("values", "drt|pt|sppm")
            .insert("default", "pt")
            .insert("help", "Lighting engine used when rendering")
            .insert(
                "options",
                Dictionary()
                    .insert("drt", Dictionary().insert("help", "Distribution ray tracing"))
                    .insert("pt", Dictionary().insert("help", "Unidirectional path tracing"))
                    .insert("sppm", Dictionary().insert("help", "Stochastic progressive photon mapping"))));

    metadata.insert(
        "rendering_threads",
        Dictionary()
            .insert("type", "int")
            .insert("help", "Number of threads to use for rendering"));

    metadata.dictionaries().insert(
        "texture_store",
        TextureStore::get_params_metadata());

    metadata.dictionaries().insert(
        "uniform_pixel_renderer",
        UniformPixelRendererFactory::get_params_metadata());

    metadata.dictionaries().insert(
        "generic_frame_renderer",
        GenericFrameRendererFactory::get_params_metadata());

    metadata.dictionaries().insert(
        "progressive_frame_renderer",
        ProgressiveFrameRendererFactory::get_params_metadata());

    metadata.dictionaries().insert("drt", DRTLightingEngineFactory::get_params_metadata());
    metadata.dictionaries().insert("pt", PTLightingEngineFactory::get_params_metadata());
    metadata.dictionaries().insert("sppm", SPPMLightingEngineFactory::get_params_metadata());

    return metadata;
}

//
// ConfigurationFactory class implementation.
//

auto_release_ptr<Configuration> ConfigurationFactory::create(const char* name)
{
    assert(name);

    return auto_release_ptr<Configuration>(new Configuration(name));
}

auto_release_ptr<Configuration> ConfigurationFactory::create(
    const char*         name,
    const ParamArray&   params)
{
    assert(name);

    auto_release_ptr<Configuration> configuration(new Configuration(name));

    configuration->get_parameters().merge(params);

    return configuration;
}

//
// BaseConfigurationFactory class implementation.
//

auto_release_ptr<Configuration> BaseConfigurationFactory::create_base_final()
{
    auto_release_ptr<Configuration> configuration(new Configuration("base_final"));

    ParamArray& parameters = configuration->get_parameters();

    parameters.insert("frame_renderer", "generic");
    parameters.insert("tile_renderer", "generic");

    parameters.insert("pixel_renderer", "uniform");
    parameters.dictionaries().insert(
        "uniform_pixel_renderer",
        ParamArray()
            .insert("samples", "64"));

    parameters.insert("sample_renderer", "generic");
    parameters.insert("lighting_engine", "pt");

    return configuration;
}

auto_release_ptr<Configuration> BaseConfigurationFactory::create_base_interactive()
{
    auto_release_ptr<Configuration> configuration(new Configuration("base_interactive"));

    ParamArray& parameters = configuration->get_parameters();

    parameters.insert("frame_renderer", "progressive");
    parameters.insert("sample_generator", "generic");
    parameters.insert("sample_renderer", "generic");
    parameters.insert("lighting_engine", "pt");

    return configuration;
}

bool BaseConfigurationFactory::is_base_final_configuration(const char* name)
{
    assert(name);
    return strcmp(name, "base_final") == 0;
}

bool BaseConfigurationFactory::is_base_interactive_configuration(const char* name)
{
    assert(name);
    return strcmp(name, "base_interactive") == 0;
}

bool BaseConfigurationFactory::is_base_configuration(const char* name)
{
    return is_base_final_configuration(name) || is_base_interactive_configuration(name);
}

}   // namespace renderer
<commit_msg>set the sampling mode (to RNG) in base final and interactive configurations.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "configuration.h"

// appleseed.renderer headers.
#include "renderer/kernel/lighting/drt/drtlightingengine.h"
#include "renderer/kernel/lighting/pt/ptlightingengine.h"
#include "renderer/kernel/lighting/sppm/sppmlightingengine.h"
#include "renderer/kernel/rendering/final/uniformpixelrenderer.h"
#include "renderer/kernel/rendering/generic/genericframerenderer.h"
#include "renderer/kernel/rendering/progressive/progressiveframerenderer.h"
#include "renderer/kernel/texturing/texturestore.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"

// Standard headers.
#include <cassert>
#include <cstring>

using namespace foundation;
using namespace std;

namespace renderer
{

//
// Configuration class implementation.
//

namespace
{
    const UniqueID g_class_uid = new_guid();
}

UniqueID Configuration::get_class_uid()
{
    return g_class_uid;
}

Configuration::Configuration(const char* name)
  : Entity(g_class_uid)
  , m_base(0)
{
    set_name(name);
}

void Configuration::release()
{
    delete this;
}

void Configuration::set_base(const Configuration* base)
{
    m_base = base;
}

const Configuration* Configuration::get_base() const
{
    return m_base;
}

ParamArray Configuration::get_inherited_parameters() const
{
    if (m_base)
    {
        ParamArray params = m_base->m_params;
        params.merge(m_params);
        return params;
    }
    else
    {
        return m_params;
    }
}

Dictionary Configuration::get_metadata()
{
    ParamArray metadata;

    metadata.insert(
        "sampling_mode",
        Dictionary()
            .insert("type", "enum")
            .insert("values", "rng|qmc")
            .insert("default", "rng")
            .insert("help", "Sampler to use when generating samples")
            .insert(
                "options",
                Dictionary()
                    .insert("rng", Dictionary().insert("help", "Random sampler"))
                    .insert("qmc", Dictionary().insert("help", "Quasi Monte Carlo sampler"))));

    metadata.insert(
        "lighting_engine",
        Dictionary()
            .insert("type", "enum")
            .insert("values", "drt|pt|sppm")
            .insert("default", "pt")
            .insert("help", "Lighting engine used when rendering")
            .insert(
                "options",
                Dictionary()
                    .insert("drt", Dictionary().insert("help", "Distribution ray tracing"))
                    .insert("pt", Dictionary().insert("help", "Unidirectional path tracing"))
                    .insert("sppm", Dictionary().insert("help", "Stochastic progressive photon mapping"))));

    metadata.insert(
        "rendering_threads",
        Dictionary()
            .insert("type", "int")
            .insert("help", "Number of threads to use for rendering"));

    metadata.dictionaries().insert(
        "texture_store",
        TextureStore::get_params_metadata());

    metadata.dictionaries().insert(
        "uniform_pixel_renderer",
        UniformPixelRendererFactory::get_params_metadata());

    metadata.dictionaries().insert(
        "generic_frame_renderer",
        GenericFrameRendererFactory::get_params_metadata());

    metadata.dictionaries().insert(
        "progressive_frame_renderer",
        ProgressiveFrameRendererFactory::get_params_metadata());

    metadata.dictionaries().insert("drt", DRTLightingEngineFactory::get_params_metadata());
    metadata.dictionaries().insert("pt", PTLightingEngineFactory::get_params_metadata());
    metadata.dictionaries().insert("sppm", SPPMLightingEngineFactory::get_params_metadata());

    return metadata;
}

//
// ConfigurationFactory class implementation.
//

auto_release_ptr<Configuration> ConfigurationFactory::create(const char* name)
{
    assert(name);

    return auto_release_ptr<Configuration>(new Configuration(name));
}

auto_release_ptr<Configuration> ConfigurationFactory::create(
    const char*         name,
    const ParamArray&   params)
{
    assert(name);

    auto_release_ptr<Configuration> configuration(new Configuration(name));

    configuration->get_parameters().merge(params);

    return configuration;
}

//
// BaseConfigurationFactory class implementation.
//

auto_release_ptr<Configuration> BaseConfigurationFactory::create_base_final()
{
    auto_release_ptr<Configuration> configuration(new Configuration("base_final"));

    ParamArray& parameters = configuration->get_parameters();

    parameters.insert("sampling_mode", "rng");

    parameters.insert("frame_renderer", "generic");
    parameters.insert("tile_renderer", "generic");

    parameters.insert("pixel_renderer", "uniform");
    parameters.dictionaries().insert(
        "uniform_pixel_renderer",
        ParamArray()
            .insert("samples", "64"));

    parameters.insert("sample_renderer", "generic");
    parameters.insert("lighting_engine", "pt");

    return configuration;
}

auto_release_ptr<Configuration> BaseConfigurationFactory::create_base_interactive()
{
    auto_release_ptr<Configuration> configuration(new Configuration("base_interactive"));

    ParamArray& parameters = configuration->get_parameters();

    parameters.insert("sampling_mode", "rng");

    parameters.insert("frame_renderer", "progressive");
    parameters.insert("sample_generator", "generic");
    parameters.insert("sample_renderer", "generic");
    parameters.insert("lighting_engine", "pt");

    return configuration;
}

bool BaseConfigurationFactory::is_base_final_configuration(const char* name)
{
    assert(name);
    return strcmp(name, "base_final") == 0;
}

bool BaseConfigurationFactory::is_base_interactive_configuration(const char* name)
{
    assert(name);
    return strcmp(name, "base_interactive") == 0;
}

bool BaseConfigurationFactory::is_base_configuration(const char* name)
{
    return is_base_final_configuration(name) || is_base_interactive_configuration(name);
}

}   // namespace renderer
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "frame_dropper.h"
#include "internal_defines.h"
#include "trace.h"

namespace webrtc
{

VCMFrameDropper::VCMFrameDropper(WebRtc_Word32 vcmId)
:
_vcmId(vcmId),
_keyFrameSizeAvgKbits(0.9f),
_keyFrameRatio(0.99f),
_dropRatio(0.9f, 0.96f)
{
    Reset();
}

void
VCMFrameDropper::Reset()
{
    _keyFrameRatio.Reset(0.99f);
    _keyFrameRatio.Apply(1.0f, 1.0f/300.0f); // 1 key frame every 10th second in 30 fps
    _keyFrameSizeAvgKbits.Reset(0.9f);
    _keyFrameCount = 0;
    _accumulator = 0.0f;
    _accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
    _targetBitRate = 300.0f;
    _incoming_frame_rate = 30;
    _keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
    _dropNext = false;
    _dropRatio.Reset(0.9f);
    _dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
    _dropCount = 0;
    _windowSize = 0.5f;
    _wasBelowMax = true;
    _enabled = true;
    _fastMode = false; // start with normal (non-aggressive) mode
    // Cap for the encoder buffer level/accumulator, in secs.
    _cap_buffer_size = 3.0f;
    // Cap on maximum amount of dropped frames between kept frames, in secs.
    _max_time_drops = 4.0f;
}

void
VCMFrameDropper::Enable(bool enable)
{
    _enabled = enable;
}

void
VCMFrameDropper::Fill(WebRtc_UWord32 frameSizeBytes, bool deltaFrame)
{
    if (!_enabled)
    {
        return;
    }
    float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
    if (!deltaFrame && !_fastMode) // fast mode does not treat key-frames any different
    {
        _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
        _keyFrameRatio.Apply(1.0, 1.0);
        if (frameSizeKbits > _keyFrameSizeAvgKbits.Value())
        {
            // Remove the average key frame size since we
            // compensate for key frames when adding delta
            // frames.
            frameSizeKbits -= _keyFrameSizeAvgKbits.Value();
        }
        else
        {
            // Shouldn't be negative, so zero is the lower bound.
            frameSizeKbits = 0;
        }
        if (_keyFrameRatio.Value() > 1e-5 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
        {
            // We are sending key frames more often than our upper bound for
            // how much we allow the key frame compensation to be spread
            // out in time. Therefor we must use the key frame ratio rather
            // than keyFrameSpreadFrames.
            _keyFrameCount = static_cast<WebRtc_Word32>(1 / _keyFrameRatio.Value() + 0.5);
        }
        else
        {
            // Compensate for the key frame the following frames
            _keyFrameCount = static_cast<WebRtc_Word32>(_keyFrameSpreadFrames + 0.5);
        }
    }
    else
    {
        // Decrease the keyFrameRatio
        _keyFrameRatio.Apply(1.0, 0.0);
    }
    // Change the level of the accumulator (bucket)
    _accumulator += frameSizeKbits;
    CapAccumulator();
}

void
VCMFrameDropper::Leak(WebRtc_UWord32 inputFrameRate)
{
    if (!_enabled)
    {
        return;
    }
    if (inputFrameRate < 1)
    {
        return;
    }
    if (_targetBitRate < 0.0f)
    {
        return;
    }
    _keyFrameSpreadFrames = 0.5f * inputFrameRate;
    // T is the expected bits per frame (target). If all frames were the same size,
    // we would get T bits per frame. Notice that T is also weighted to be able to
    // force a lower frame rate if wanted.
    float T = _targetBitRate / inputFrameRate;
    if (_keyFrameCount > 0)
    {
        // Perform the key frame compensation
        if (_keyFrameRatio.Value() > 0 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
        {
            T -= _keyFrameSizeAvgKbits.Value() * _keyFrameRatio.Value();
        }
        else
        {
            T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames;
        }
        _keyFrameCount--;
    }
    _accumulator -= T;
    UpdateRatio();
}

void
VCMFrameDropper::UpdateNack(WebRtc_UWord32 nackBytes)
{
    if (!_enabled)
    {
        return;
    }
    _accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
}

void
VCMFrameDropper::FillBucket(float inKbits, float outKbits)
{
    _accumulator += (inKbits - outKbits);
}

void
VCMFrameDropper::UpdateRatio()
{
    if (_accumulator > 1.3f * _accumulatorMax)
    {
        // Too far above accumulator max, react faster
        _dropRatio.UpdateBase(0.8f);
    }
    else
    {
        // Go back to normal reaction
        _dropRatio.UpdateBase(0.9f);
    }
    if (_accumulator > _accumulatorMax)
    {
        // We are above accumulator max, and should ideally
        // drop a frame. Increase the dropRatio and drop
        // the frame later.
        if (_wasBelowMax)
        {
            _dropNext = true;
        }
        if (_fastMode)
        {
            // always drop in aggressive mode
            _dropNext = true;
        }

        _dropRatio.Apply(1.0f, 1.0f);
        _dropRatio.UpdateBase(0.9f);
    }
    else
    {
        _dropRatio.Apply(1.0f, 0.0f);
    }
    if (_accumulator < 0.0f)
    {
        _accumulator = 0.0f;
    }
    _wasBelowMax = _accumulator < _accumulatorMax;
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId),  "FrameDropper: dropRatio = %f accumulator = %f, accumulatorMax = %f", _dropRatio.Value(), _accumulator, _accumulatorMax);
}

// This function signals when to drop frames to the caller. It makes use of the dropRatio
// to smooth out the drops over time.
bool
VCMFrameDropper::DropFrame()
{
    if (!_enabled)
    {
        return false;
    }
    if (_dropNext)
    {
        _dropNext = false;
        _dropCount = 0;
    }

    if (_dropRatio.Value() >= 0.5f) // Drops per keep
    {
        // limit is the number of frames we should drop between each kept frame
        // to keep our drop ratio. limit is positive in this case.
        float denom = 1.0f - _dropRatio.Value();
        if (denom < 1e-5)
        {
            denom = (float)1e-5;
        }
        WebRtc_Word32 limit = static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
        // Put a bound on the max amount of dropped frames between each kept
        // frame, in terms of frame rate and window size (secs).
        int max_limit = static_cast<int>(_incoming_frame_rate *
                                         _max_time_drops);
        if (limit > max_limit) {
          limit = max_limit;
        }
        if (_dropCount < 0)
        {
            // Reset the _dropCount since it was negative and should be positive.
            if (_dropRatio.Value() > 0.4f)
            {
                _dropCount = -_dropCount;
            }
            else
            {
                _dropCount = 0;
            }
        }
        if (_dropCount < limit)
        {
            // As long we are below the limit we should drop frames.
            _dropCount++;
            return true;
        }
        else
        {
            // Only when we reset _dropCount a frame should be kept.
            _dropCount = 0;
            return false;
        }
    }
    else if (_dropRatio.Value() > 0.0f && _dropRatio.Value() < 0.5f) // Keeps per drop
    {
        // limit is the number of frames we should keep between each drop
        // in order to keep the drop ratio. limit is negative in this case,
        // and the _dropCount is also negative.
        float denom = _dropRatio.Value();
        if (denom < 1e-5)
        {
            denom = (float)1e-5;
        }
        WebRtc_Word32 limit = -static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
        if (_dropCount > 0)
        {
            // Reset the _dropCount since we have a positive
            // _dropCount, and it should be negative.
            if (_dropRatio.Value() < 0.6f)
            {
                _dropCount = -_dropCount;
            }
            else
            {
                _dropCount = 0;
            }
        }
        if (_dropCount > limit)
        {
            if (_dropCount == 0)
            {
                // Drop frames when we reset _dropCount.
                _dropCount--;
                return true;
            }
            else
            {
                // Keep frames as long as we haven't reached limit.
                _dropCount--;
                return false;
            }
        }
        else
        {
            _dropCount = 0;
            return false;
        }
    }
    _dropCount = 0;
    return false;

    // A simpler version, unfiltered and quicker
    //bool dropNext = _dropNext;
    //_dropNext = false;
    //return dropNext;
}

void
VCMFrameDropper::SetRates(float bitRate, float incoming_frame_rate)
{
    // Bit rate of -1 means infinite bandwidth.
    _accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
    if (_targetBitRate > 0.0f && bitRate < _targetBitRate && _accumulator > _accumulatorMax)
    {
        // Rescale the accumulator level if the accumulator max decreases
        _accumulator = bitRate / _targetBitRate * _accumulator;
    }
    _targetBitRate = bitRate;
    CapAccumulator();
    _incoming_frame_rate = incoming_frame_rate;
}

float
VCMFrameDropper::ActualFrameRate(WebRtc_UWord32 inputFrameRate) const
{
    if (!_enabled)
    {
        return static_cast<float>(inputFrameRate);
    }
    return inputFrameRate * (1.0f - _dropRatio.Value());
}

// Put a cap on the accumulator, i.e., don't let it grow beyond some level.
// This is a temporary fix for screencasting where very large frames from
// encoder will cause very slow response (too many frame drops).
void VCMFrameDropper::CapAccumulator() {
  float max_accumulator = _targetBitRate * _cap_buffer_size;
  if (_accumulator > max_accumulator) {
    _accumulator = max_accumulator;
  }
}

}
<commit_msg>VCM: Removing frame drop enable from Reset call BUG = 1387<commit_after>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "frame_dropper.h"
#include "internal_defines.h"
#include "trace.h"

namespace webrtc
{

VCMFrameDropper::VCMFrameDropper(WebRtc_Word32 vcmId)
:
_vcmId(vcmId),
_keyFrameSizeAvgKbits(0.9f),
_keyFrameRatio(0.99f),
_dropRatio(0.9f, 0.96f),
_enabled(true)
{
    Reset();
}

void
VCMFrameDropper::Reset()
{
    _keyFrameRatio.Reset(0.99f);
    _keyFrameRatio.Apply(1.0f, 1.0f/300.0f); // 1 key frame every 10th second in 30 fps
    _keyFrameSizeAvgKbits.Reset(0.9f);
    _keyFrameCount = 0;
    _accumulator = 0.0f;
    _accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
    _targetBitRate = 300.0f;
    _incoming_frame_rate = 30;
    _keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
    _dropNext = false;
    _dropRatio.Reset(0.9f);
    _dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
    _dropCount = 0;
    _windowSize = 0.5f;
    _wasBelowMax = true;
    _fastMode = false; // start with normal (non-aggressive) mode
    // Cap for the encoder buffer level/accumulator, in secs.
    _cap_buffer_size = 3.0f;
    // Cap on maximum amount of dropped frames between kept frames, in secs.
    _max_time_drops = 4.0f;
}

void
VCMFrameDropper::Enable(bool enable)
{
    _enabled = enable;
}

void
VCMFrameDropper::Fill(WebRtc_UWord32 frameSizeBytes, bool deltaFrame)
{
    if (!_enabled)
    {
        return;
    }
    float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
    if (!deltaFrame && !_fastMode) // fast mode does not treat key-frames any different
    {
        _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
        _keyFrameRatio.Apply(1.0, 1.0);
        if (frameSizeKbits > _keyFrameSizeAvgKbits.Value())
        {
            // Remove the average key frame size since we
            // compensate for key frames when adding delta
            // frames.
            frameSizeKbits -= _keyFrameSizeAvgKbits.Value();
        }
        else
        {
            // Shouldn't be negative, so zero is the lower bound.
            frameSizeKbits = 0;
        }
        if (_keyFrameRatio.Value() > 1e-5 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
        {
            // We are sending key frames more often than our upper bound for
            // how much we allow the key frame compensation to be spread
            // out in time. Therefor we must use the key frame ratio rather
            // than keyFrameSpreadFrames.
            _keyFrameCount = static_cast<WebRtc_Word32>(1 / _keyFrameRatio.Value() + 0.5);
        }
        else
        {
            // Compensate for the key frame the following frames
            _keyFrameCount = static_cast<WebRtc_Word32>(_keyFrameSpreadFrames + 0.5);
        }
    }
    else
    {
        // Decrease the keyFrameRatio
        _keyFrameRatio.Apply(1.0, 0.0);
    }
    // Change the level of the accumulator (bucket)
    _accumulator += frameSizeKbits;
    CapAccumulator();
}

void
VCMFrameDropper::Leak(WebRtc_UWord32 inputFrameRate)
{
    if (!_enabled)
    {
        return;
    }
    if (inputFrameRate < 1)
    {
        return;
    }
    if (_targetBitRate < 0.0f)
    {
        return;
    }
    _keyFrameSpreadFrames = 0.5f * inputFrameRate;
    // T is the expected bits per frame (target). If all frames were the same size,
    // we would get T bits per frame. Notice that T is also weighted to be able to
    // force a lower frame rate if wanted.
    float T = _targetBitRate / inputFrameRate;
    if (_keyFrameCount > 0)
    {
        // Perform the key frame compensation
        if (_keyFrameRatio.Value() > 0 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
        {
            T -= _keyFrameSizeAvgKbits.Value() * _keyFrameRatio.Value();
        }
        else
        {
            T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames;
        }
        _keyFrameCount--;
    }
    _accumulator -= T;
    UpdateRatio();
}

void
VCMFrameDropper::UpdateNack(WebRtc_UWord32 nackBytes)
{
    if (!_enabled)
    {
        return;
    }
    _accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
}

void
VCMFrameDropper::FillBucket(float inKbits, float outKbits)
{
    _accumulator += (inKbits - outKbits);
}

void
VCMFrameDropper::UpdateRatio()
{
    if (_accumulator > 1.3f * _accumulatorMax)
    {
        // Too far above accumulator max, react faster
        _dropRatio.UpdateBase(0.8f);
    }
    else
    {
        // Go back to normal reaction
        _dropRatio.UpdateBase(0.9f);
    }
    if (_accumulator > _accumulatorMax)
    {
        // We are above accumulator max, and should ideally
        // drop a frame. Increase the dropRatio and drop
        // the frame later.
        if (_wasBelowMax)
        {
            _dropNext = true;
        }
        if (_fastMode)
        {
            // always drop in aggressive mode
            _dropNext = true;
        }

        _dropRatio.Apply(1.0f, 1.0f);
        _dropRatio.UpdateBase(0.9f);
    }
    else
    {
        _dropRatio.Apply(1.0f, 0.0f);
    }
    if (_accumulator < 0.0f)
    {
        _accumulator = 0.0f;
    }
    _wasBelowMax = _accumulator < _accumulatorMax;
    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId),  "FrameDropper: dropRatio = %f accumulator = %f, accumulatorMax = %f", _dropRatio.Value(), _accumulator, _accumulatorMax);
}

// This function signals when to drop frames to the caller. It makes use of the dropRatio
// to smooth out the drops over time.
bool
VCMFrameDropper::DropFrame()
{
    if (!_enabled)
    {
        return false;
    }
    if (_dropNext)
    {
        _dropNext = false;
        _dropCount = 0;
    }

    if (_dropRatio.Value() >= 0.5f) // Drops per keep
    {
        // limit is the number of frames we should drop between each kept frame
        // to keep our drop ratio. limit is positive in this case.
        float denom = 1.0f - _dropRatio.Value();
        if (denom < 1e-5)
        {
            denom = (float)1e-5;
        }
        WebRtc_Word32 limit = static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
        // Put a bound on the max amount of dropped frames between each kept
        // frame, in terms of frame rate and window size (secs).
        int max_limit = static_cast<int>(_incoming_frame_rate *
                                         _max_time_drops);
        if (limit > max_limit) {
          limit = max_limit;
        }
        if (_dropCount < 0)
        {
            // Reset the _dropCount since it was negative and should be positive.
            if (_dropRatio.Value() > 0.4f)
            {
                _dropCount = -_dropCount;
            }
            else
            {
                _dropCount = 0;
            }
        }
        if (_dropCount < limit)
        {
            // As long we are below the limit we should drop frames.
            _dropCount++;
            return true;
        }
        else
        {
            // Only when we reset _dropCount a frame should be kept.
            _dropCount = 0;
            return false;
        }
    }
    else if (_dropRatio.Value() > 0.0f && _dropRatio.Value() < 0.5f) // Keeps per drop
    {
        // limit is the number of frames we should keep between each drop
        // in order to keep the drop ratio. limit is negative in this case,
        // and the _dropCount is also negative.
        float denom = _dropRatio.Value();
        if (denom < 1e-5)
        {
            denom = (float)1e-5;
        }
        WebRtc_Word32 limit = -static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
        if (_dropCount > 0)
        {
            // Reset the _dropCount since we have a positive
            // _dropCount, and it should be negative.
            if (_dropRatio.Value() < 0.6f)
            {
                _dropCount = -_dropCount;
            }
            else
            {
                _dropCount = 0;
            }
        }
        if (_dropCount > limit)
        {
            if (_dropCount == 0)
            {
                // Drop frames when we reset _dropCount.
                _dropCount--;
                return true;
            }
            else
            {
                // Keep frames as long as we haven't reached limit.
                _dropCount--;
                return false;
            }
        }
        else
        {
            _dropCount = 0;
            return false;
        }
    }
    _dropCount = 0;
    return false;

    // A simpler version, unfiltered and quicker
    //bool dropNext = _dropNext;
    //_dropNext = false;
    //return dropNext;
}

void
VCMFrameDropper::SetRates(float bitRate, float incoming_frame_rate)
{
    // Bit rate of -1 means infinite bandwidth.
    _accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
    if (_targetBitRate > 0.0f && bitRate < _targetBitRate && _accumulator > _accumulatorMax)
    {
        // Rescale the accumulator level if the accumulator max decreases
        _accumulator = bitRate / _targetBitRate * _accumulator;
    }
    _targetBitRate = bitRate;
    CapAccumulator();
    _incoming_frame_rate = incoming_frame_rate;
}

float
VCMFrameDropper::ActualFrameRate(WebRtc_UWord32 inputFrameRate) const
{
    if (!_enabled)
    {
        return static_cast<float>(inputFrameRate);
    }
    return inputFrameRate * (1.0f - _dropRatio.Value());
}

// Put a cap on the accumulator, i.e., don't let it grow beyond some level.
// This is a temporary fix for screencasting where very large frames from
// encoder will cause very slow response (too many frame drops).
void VCMFrameDropper::CapAccumulator() {
  float max_accumulator = _targetBitRate * _cap_buffer_size;
  if (_accumulator > max_accumulator) {
    _accumulator = max_accumulator;
  }
}

}
<|endoftext|>


<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
//
// =============================================================================

#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_vehicle/ChVehicleModelData.h"
#include "chrono_vehicle/terrain/FlatTerrain.h"
#include "chrono_vehicle/powertrain/SimplePowertrain.h"
#include "chrono_vehicle/utils/ChVehicleIrrApp.h"

#include "chrono_vehicle/tracked_vehicle/utils/ChTrackTestRig.h"
#include "chrono_vehicle/tracked_vehicle/utils/ChIrrGuiDriverTTR.h"

#include "m113/M113_TrackAssembly.h"

using namespace chrono;
using namespace chrono::vehicle;
using namespace m113;

// =============================================================================
// USER SETTINGS
// =============================================================================
double post_limit = 0.2;

// Simulation step size
double step_size = 1e-3;
double render_step_size = 1.0 / 50;  // Time interval between two render frames

// =============================================================================
// JSON file for track test rig
std::string suspensionTest_file("hmmwv/suspensionTest/HMMWV_ST_front.json");

// JSON file for vehicle and vehicle side
std::string vehicle_file("hmmwv/vehicle/HMMWV_Vehicle.json");
int side = 0;

// Dummy powertrain
std::string simplepowertrain_file("generic/powertrain/SimplePowertrain.json");

// =============================================================================
int main(int argc, char* argv[]) {
    // Create an M113 track assembly.
    ChSharedPtr<M113_TrackAssembly> track_assembly(new M113_TrackAssembly(LEFT, MESH));

    // Create and initialize the testing mechanism.
    ChVector<> sprocket_loc(3, 1, 0);
    ChVector<> idler_loc(-3, 1, 0);
    std::vector<ChVector<> > susp_locs(5);
    susp_locs[0] = ChVector<>(2, 1, -0.5);
    susp_locs[1] = ChVector<>(1, 1, -0.5);
    susp_locs[2] = ChVector<>(0, 1, -0.5);
    susp_locs[3] = ChVector<>(-1, 1, -0.5);
    susp_locs[4] = ChVector<>(-2, 1, -0.5);

    ChTrackTestRig rig(track_assembly, sprocket_loc, idler_loc, susp_locs);
    rig.Initialize(ChCoordsys<>());

    // Create and initialize the powertrain system (not used).
    SimplePowertrain powertrain(vehicle::GetDataFile(simplepowertrain_file));
    powertrain.Initialize();

    // Create the vehicle Irrlicht application.
    ChVehicleIrrApp app(rig, powertrain, L"Suspension Test Rig");
    app.SetSkyBox();
    app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
    app.SetChaseCamera(rig.GetPostPosition(), 6.0, 2.0);
    app.SetTimestep(step_size);
    app.AssetBindAll();
    app.AssetUpdateAll();

    // Create the driver system and set the time response for keyboard inputs.
    ChIrrGuiDriverTTR driver(app, post_limit);
    double steering_time = 1.0;      // time to go from 0 to max
    double displacement_time = 2.0;  // time to go from 0 to max applied post motion
    driver.SetSteeringDelta(render_step_size / steering_time);
    driver.SetDisplacementDelta(render_step_size / displacement_time * post_limit);

    // ---------------
    // Simulation loop
    // ---------------

    // Inter-module communication data
    TireForces tire_forces(2);
    WheelStates wheel_states(2);

    // Number of simulation steps between two 3D view render frames
    int render_steps = (int)std::ceil(render_step_size / step_size);

    TrackShoeForces shoe_forces(1);

    // Initialize simulation frame counter
    int step_number = 0;
    ChRealtimeStepTimer realtime_timer;

    while (app.GetDevice()->run()) {
        // Render scene
        if (step_number % render_steps == 0) {
            app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
            app.DrawAll();
            app.EndScene();
        }

        // Collect output data from modules
        double steering_input = driver.GetSteering();
        double post_input = driver.GetDisplacement();

        // Update modules (process inputs from other modules)
        double time = rig.GetChTime();
        driver.Update(time);
        rig.Update(time, post_input, shoe_forces);
        app.Update("", steering_input, 0, 0);

        // Advance simulation for one timestep for all modules
        double step = realtime_timer.SuggestSimulationStep(step_size);
        driver.Advance(step);
        rig.Advance(step);
        app.Advance(step);

        // Increment frame number
        step_number++;
    }

    return 0;
}
<commit_msg>Set proper initial subsystem locations in demo_TrackTestRig<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
//
// =============================================================================

#include "chrono/utils/ChUtilsInputOutput.h"

#include "chrono_vehicle/ChVehicleModelData.h"
#include "chrono_vehicle/terrain/FlatTerrain.h"
#include "chrono_vehicle/powertrain/SimplePowertrain.h"
#include "chrono_vehicle/utils/ChVehicleIrrApp.h"

#include "chrono_vehicle/tracked_vehicle/utils/ChTrackTestRig.h"
#include "chrono_vehicle/tracked_vehicle/utils/ChIrrGuiDriverTTR.h"

#include "m113/M113_TrackAssembly.h"

using namespace chrono;
using namespace chrono::vehicle;
using namespace m113;

// =============================================================================
// USER SETTINGS
// =============================================================================
double post_limit = 0.2;

// Simulation step size
double step_size = 1e-3;
double render_step_size = 1.0 / 50;  // Time interval between two render frames

// =============================================================================
// JSON file for track test rig
std::string suspensionTest_file("hmmwv/suspensionTest/HMMWV_ST_front.json");

// JSON file for vehicle and vehicle side
std::string vehicle_file("hmmwv/vehicle/HMMWV_Vehicle.json");
int side = 0;

// Dummy powertrain
std::string simplepowertrain_file("generic/powertrain/SimplePowertrain.json");

// =============================================================================
int main(int argc, char* argv[]) {
    // Create an M113 track assembly.
    ChSharedPtr<M113_TrackAssembly> track_assembly(new M113_TrackAssembly(LEFT, PRIMITIVES));

    // Create and initialize the testing mechanism.
    ChVector<> sprocket_loc(0, 1, 0);
    ChVector<> idler_loc(-3.93, 1, -0.15);   //// Original x value: -3.97
    std::vector<ChVector<> > susp_locs(5);
    susp_locs[0] = ChVector<>(-0.65, 1, -0.215);
    susp_locs[1] = ChVector<>(-1.3175, 1, -0.215);
    susp_locs[2] = ChVector<>(-1.985, 1, -0.215);
    susp_locs[3] = ChVector<>(-2.6525, 1, -0.215);
    susp_locs[4] = ChVector<>(-3.32, 1, -0.215);

    ChTrackTestRig rig(track_assembly, sprocket_loc, idler_loc, susp_locs);
    rig.GetSystem()->Set_G_acc(ChVector<>(0, 0, 0));
    rig.Initialize(ChCoordsys<>());

    // Create and initialize the powertrain system (not used).
    SimplePowertrain powertrain(vehicle::GetDataFile(simplepowertrain_file));
    powertrain.Initialize();

    // Create the vehicle Irrlicht application.
    ChVector<> target_point = rig.GetPostPosition();
    ////ChVector<> target_point = idler_loc;
    ////ChVector<> target_point = sprocket_loc;

    ChVehicleIrrApp app(rig, powertrain, L"Suspension Test Rig");
    app.SetSkyBox();
    app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
    app.SetChaseCamera(target_point, 3.0, 1.0);
    app.SetChaseCameraPosition(target_point + ChVector<>(0, 3, 0));
    app.SetTimestep(step_size);
    app.AssetBindAll();
    app.AssetUpdateAll();

    // Create the driver system and set the time response for keyboard inputs.
    ChIrrGuiDriverTTR driver(app, post_limit);
    double steering_time = 1.0;      // time to go from 0 to max
    double displacement_time = 2.0;  // time to go from 0 to max applied post motion
    driver.SetSteeringDelta(render_step_size / steering_time);
    driver.SetDisplacementDelta(render_step_size / displacement_time * post_limit);

    // ---------------
    // Simulation loop
    // ---------------

    // Inter-module communication data
    TireForces tire_forces(2);
    WheelStates wheel_states(2);

    // Number of simulation steps between two 3D view render frames
    int render_steps = (int)std::ceil(render_step_size / step_size);

    TrackShoeForces shoe_forces(1);

    // Initialize simulation frame counter
    int step_number = 0;
    ChRealtimeStepTimer realtime_timer;

    while (app.GetDevice()->run()) {
        // Render scene
        if (step_number % render_steps == 0) {
            app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
            app.DrawAll();
            app.EndScene();
        }

        // Collect output data from modules
        double steering_input = driver.GetSteering();
        double post_input = driver.GetDisplacement();

        // Update modules (process inputs from other modules)
        double time = rig.GetChTime();
        driver.Update(time);
        rig.Update(time, post_input, shoe_forces);
        app.Update("", steering_input, 0, 0);

        // Advance simulation for one timestep for all modules
        double step = realtime_timer.SuggestSimulationStep(step_size);
        driver.Advance(step);
        rig.Advance(step);
        app.Advance(step);

        // Increment frame number
        step_number++;
    }

    return 0;
}
<|endoftext|>


<commit_before>#ifndef __TENSOR3_HPP_INCLUDED
#define __TENSOR3_HPP_INCLUDED

#include "matrix.hpp"

// Include standard headers
#include <stdint.h> // uint32_t etc.

namespace linear_algebra
{
    class Tensor3
    {
        // `class Tensor3` uses the same coordinate order as MATLAB,
        // to make testing easier. So: y, x, z.
        // y = 0 is the uppermost slice
        // x = 0 is the leftmost slice.
        // z = 0 is the front slice.

        public:
            // constructor.
            Tensor3(uint32_t height, uint32_t width, uint32_t depth);

            // copy constructor.
            Tensor3(Tensor3& old_tensor3);

            // constructor.
            Tensor3(Matrix& old_matrix);

            // destructor.
            ~Tensor3();

            // Inspired by http://stackoverflow.com/questions/6969881/operator-overload/6969904#6969904
            class Proxy2D
            {
                public:
                    Proxy2D(float** array_of_arrays) : array_of_arrays(array_of_arrays) { }

                    class Proxy
                    {
                        public:
                            Proxy(float* proxy_array) : proxy_array(proxy_array) { }

                            float& operator[](const uint32_t index)
                            {
                                return proxy_array[index];
                            }

                        private:
                            float* proxy_array;
                    };

                    Proxy operator[](const uint32_t index)
                    {
                        return array_of_arrays[index];
                    }

                private:
                    float** array_of_arrays;
            };

            void operator<<(const float rhs);
            void operator<<(const std::vector<float>& rhs);
            bool operator==(const Tensor3& rhs);
            bool operator!=(const Tensor3& rhs);
            Proxy2D operator[](const uint32_t index)
            {
                return Proxy2D(array_of_arrays_of_arrays[index]);
            }

        private:
            bool is_cube;
            uint32_t width;
            uint32_t height;
            uint32_t depth;

            bool is_fully_populated;

            // For populating, the order of coordinates from
            // the one changing fastest to the one changing slowest is:
            // x, y, z
            int32_t next_x_to_populate;
            int32_t next_y_to_populate;
            int32_t next_z_to_populate;

            float*** array_of_arrays_of_arrays;
    };
}

#endif
<commit_msg>Bugfix: Visual Studio seem to require `public` access when overloading.<commit_after>#ifndef __TENSOR3_HPP_INCLUDED
#define __TENSOR3_HPP_INCLUDED

#include "matrix.hpp"

// Include standard headers
#include <stdint.h> // uint32_t etc.

namespace linear_algebra
{
    class Tensor3
    {
        // `class Tensor3` uses the same coordinate order as MATLAB,
        // to make testing easier. So: y, x, z.
        // y = 0 is the uppermost slice
        // x = 0 is the leftmost slice.
        // z = 0 is the front slice.

        public:
            // constructor.
            Tensor3(uint32_t height, uint32_t width, uint32_t depth);

            // copy constructor.
            Tensor3(Tensor3& old_tensor3);

            // constructor.
            Tensor3(Matrix& old_matrix);

            // destructor.
            ~Tensor3();

            // Inspired by http://stackoverflow.com/questions/6969881/operator-overload/6969904#6969904
            class Proxy2D
            {
                public:
                    Proxy2D(float** array_of_arrays) : array_of_arrays(array_of_arrays) { }

                    class Proxy
                    {
                        public:
                            Proxy(float* proxy_array) : proxy_array(proxy_array) { }

                            float& operator[](const uint32_t index)
                            {
                                return proxy_array[index];
                            }

                        private:
                            float* proxy_array;
                    };

                    Proxy operator[](const uint32_t index)
                    {
                        return array_of_arrays[index];
                    }

                private:
                    float** array_of_arrays;
            };

            void operator<<(const float rhs);
            void operator<<(const std::vector<float>& rhs);
            bool operator==(const Tensor3& rhs);
            bool operator!=(const Tensor3& rhs);
            Proxy2D operator[](const uint32_t index)
            {
                return Proxy2D(array_of_arrays_of_arrays[index]);
            }

            bool is_cube;
            uint32_t width;
            uint32_t height;
            uint32_t depth;

        private:
            bool is_fully_populated;

            // For populating, the order of coordinates from
            // the one changing fastest to the one changing slowest is:
            // x, y, z
            int32_t next_x_to_populate;
            int32_t next_y_to_populate;
            int32_t next_z_to_populate;

            float*** array_of_arrays_of_arrays;
    };
}

#endif
<|endoftext|>


<commit_before>/*
 * FlightVars
 * Copyright (c) 2014 Alvaro Polo
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef FLIGHTVARS_MQTT_CODECS_H
#define FLIGHTVARS_MQTT_CODECS_H

#include <flightvars/mqtt/codecs/connect.hpp>
#include <flightvars/mqtt/codecs/fixed-header.hpp>
#include <flightvars/mqtt/codecs/types.hpp>

namespace flightvars { namespace mqtt {

/**
 * Decode a MQTT message from its fixed header and the buffer that contains the message content.
 *
 * The given buffer should be ready to extract the bytes corresponding to the message body.
 */
shared_message decode(const fixed_header& header, io::buffer& buff) {
    switch (header.msg_type) {
        case message_type::CONNECT: {
            auto connect = codecs::decoder<connect_message>::decode(buff);
            return std::make_shared<message>(header, connect);
            break;
        }
        default:
            throw std::runtime_error(util::format("cannot decode message of unknown type %s",
                message_type_str(header.msg_type)));
    }
}

}}

#endif
<commit_msg>Add `encode()` function in `codecs.hpp`<commit_after>/*
 * FlightVars
 * Copyright (c) 2014 Alvaro Polo
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef FLIGHTVARS_MQTT_CODECS_H
#define FLIGHTVARS_MQTT_CODECS_H

#include <flightvars/mqtt/codecs/connect.hpp>
#include <flightvars/mqtt/codecs/fixed-header.hpp>
#include <flightvars/mqtt/codecs/types.hpp>

namespace flightvars { namespace mqtt {

/**
 * Encode a MQTT message into the given buffer.
 *
 * The buffer is flipped after encoded bytes are transferred.
 */
void encode(const message& msg, io::buffer& buff) {
    auto header = msg.header();
    codecs::encoder<fixed_header>::encode(header, buff);
    switch (header.msg_type) {
        case message_type::CONNECT:
            codecs::encoder<connect_message>::encode(msg.connect().get(), buff);
            break;
        default:
            throw std::runtime_error(util::format("cannot encode message of unknown type %s",
                message_type_str(header.msg_type)));
    }
    buff.flip();
}

/**
 * Decode a MQTT message from its fixed header and the buffer that contains the message content.
 *
 * The given buffer should be ready to extract the bytes corresponding to the message body.
 */
shared_message decode(const fixed_header& header, io::buffer& buff) {
    switch (header.msg_type) {
        case message_type::CONNECT: {
            auto connect = codecs::decoder<connect_message>::decode(buff);
            return std::make_shared<message>(header, connect);
            break;
        }
        default:
            throw std::runtime_error(util::format("cannot decode message of unknown type %s",
                message_type_str(header.msg_type)));
    }
}

}}

#endif
<|endoftext|>