<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <atomic>
#include <cassert>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <type_traits>
#include <utility>

#include <visionaray/math/math.h>
#include <visionaray/matrix_camera.h>
#include <visionaray/pinhole_camera.h>
#include <visionaray/random_sampler.h>

#include "macros.h"
#include "sched_common.h"
#include "semaphore.h"

namespace visionaray
{

namespace detail
{

struct sync_params
{
    sync_params()
        : render_loop_exit(false)
    {
    }

    std::mutex mutex;
    std::condition_variable threads_start;
    visionaray::semaphore   threads_ready;

    std::atomic<long>       tile_idx_counter;
    std::atomic<long>       tile_fin_counter;
    std::atomic<long>       tile_num;

    std::atomic<bool>       render_loop_exit;
};


} // detail


//-------------------------------------------------------------------------------------------------
// Private implementation
//

template <typename R>
struct tiled_sched<R>::impl
{
    // TODO: any sampler
    typedef std::function<void(recti const&, random_sampler<typename R::scalar_type>&)> render_tile_func;

    void init_threads(unsigned num_threads);
    void destroy_threads();

    void render_loop();

    template <typename K, typename SP>
    void init_render_func(
            K kernel,
            SP sparams,
            unsigned frame_num,
            typename std::enable_if<std::is_same<typename SP::camera_type, matrix_camera>::value>::type* = nullptr
            );

    template <typename K, typename SP>
    void init_render_func(
            K kernel,
            SP sparams,
            unsigned frame_num,
            typename std::enable_if<std::is_same<typename SP::camera_type, pinhole_camera>::value>::type* = nullptr
            );

    template <typename K, typename SP, typename Sampler, typename ...Args>
    void call_sample_pixel(
            std::false_type /* has intersector */,
            K               kernel,
            SP              sparams,
            Sampler&        samp,
            unsigned        frame_num,
            Args&&...       args
            )
    {
        auto r = detail::make_primary_rays(
                R{},
                typename SP::pixel_sampler_type{},
                samp,
                std::forward<Args>(args)...
                );

        sample_pixel(
                kernel,
                typename SP::pixel_sampler_type(),
                r,
                samp,
                frame_num,
                sparams.rt.ref(),
                std::forward<Args>(args)...
                );
    }

    template <typename K, typename SP, typename Sampler, typename ...Args>
    void call_sample_pixel(
            std::true_type  /* has intersector */,
            K               kernel,
            SP              sparams,
            Sampler&        samp,
            unsigned        frame_num,
            Args&&...       args
            )
    {
        auto r = detail::make_primary_rays(
                R{},
                typename SP::pixel_sampler_type{},
                samp,
                std::forward<Args>(args)...
                );

        sample_pixel(
                detail::have_intersector_tag(),
                sparams.intersector,
                kernel,
                typename SP::pixel_sampler_type(),
                r,
                samp,
                frame_num,
                sparams.rt.ref(),
                std::forward<Args>(args)...
                );
    }

    std::vector<std::thread>    threads;
    detail::sync_params         sync_params;

    int                         width;
    int                         height;
    static const int            tile_width  = 16;
    static const int            tile_height = 16;
    recti                       scissor_box;

    render_tile_func            render_tile;
};

template <typename R>
void tiled_sched<R>::impl::init_threads(unsigned num_threads)
{
    for (unsigned i = 0; i < num_threads; ++i)
    {
        threads.emplace_back([this](){ render_loop(); });
    }
}

template <typename R>
void tiled_sched<R>::impl::destroy_threads()
{
    if (threads.size() == 0)
    {
        return;
    }

    sync_params.render_loop_exit = true;
    sync_params.threads_start.notify_all();

    for (auto& t : threads)
    {
        if (t.joinable())
        {
            t.join();
        }
    }

    sync_params.render_loop_exit = false;
    threads.clear();
}

//-------------------------------------------------------------------------------------------------
// Main render loop
//

template <typename R>
void tiled_sched<R>::impl::render_loop()
{
    for (;;)
    {
        {
            std::unique_lock<std::mutex> l( sync_params.mutex );
            sync_params.threads_start.wait(l);
        }

    // case event.exit:
        if (sync_params.render_loop_exit)
        {
            break;
        }

    // case event.render:
        random_sampler<typename R::scalar_type> samp(detail::tic());
        for (;;)
        {
            auto tile_idx = sync_params.tile_idx_counter.fetch_add(1);

            if (tile_idx >= sync_params.tile_num)
            {
                break;
            }

            auto tilew = tile_width;
            auto tileh = tile_height;
            auto numtilesx = div_up( width, tilew );

            recti tile(
                    (tile_idx % numtilesx) * tilew,
                    (tile_idx / numtilesx) * tileh,
                    tilew,
                    tileh
                    );

            render_tile(tile, samp);

            auto num_tiles_fin = sync_params.tile_fin_counter.fetch_add(1);

            if (num_tiles_fin >= sync_params.tile_num - 1)
            {
                assert(num_tiles_fin == sync_params.tile_num - 1);
                sync_params.threads_ready.notify();
                break;
            }
        }
    }
}

template <typename R>
template <typename K, typename SP>
void tiled_sched<R>::impl::init_render_func(
        K kernel,
        SP sparams,
        unsigned frame_num,
        typename std::enable_if<std::is_same<typename SP::camera_type, matrix_camera>::value>::type*
        )
{
    // overload for two matrices

    using T = typename R::scalar_type;
    using matrix_type = matrix<4, 4, T>;

    width       = sparams.rt.width();
    height      = sparams.rt.height();
    scissor_box = sparams.scissor_box;

    matrix_type view_matrix( sparams.cam.get_view_matrix() );
    matrix_type proj_matrix( sparams.cam.get_proj_matrix() );
    matrix_type inv_view_matrix( inverse(sparams.cam.get_view_matrix()) );
    matrix_type inv_proj_matrix( inverse(sparams.get_proj_matrix()) );

    recti clip_rect(scissor_box.x, scissor_box.y, scissor_box.w - 1, scissor_box.h - 1);

    render_tile = [=](recti const& tile, random_sampler<T>& samp)
    {
        unsigned numx = tile_width  / packet_size<T>::w;
        unsigned numy = tile_height / packet_size<T>::h;<commit_msg>Fix comment<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <atomic>
#include <cassert>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <type_traits>
#include <utility>

#include <visionaray/math/math.h>
#include <visionaray/matrix_camera.h>
#include <visionaray/pinhole_camera.h>
#include <visionaray/random_sampler.h>

#include "macros.h"
#include "sched_common.h"
#include "semaphore.h"

namespace visionaray
{

namespace detail
{

struct sync_params
{
    sync_params()
        : render_loop_exit(false)
    {
    }

    std::mutex mutex;
    std::condition_variable threads_start;
    visionaray::semaphore   threads_ready;

    std::atomic<long>       tile_idx_counter;
    std::atomic<long>       tile_fin_counter;
    std::atomic<long>       tile_num;

    std::atomic<bool>       render_loop_exit;
};


} // detail


//-------------------------------------------------------------------------------------------------
// Private implementation
//

template <typename R>
struct tiled_sched<R>::impl
{
    // TODO: any sampler
    typedef std::function<void(recti const&, random_sampler<typename R::scalar_type>&)> render_tile_func;

    void init_threads(unsigned num_threads);
    void destroy_threads();

    void render_loop();

    template <typename K, typename SP>
    void init_render_func(
            K kernel,
            SP sparams,
            unsigned frame_num,
            typename std::enable_if<std::is_same<typename SP::camera_type, matrix_camera>::value>::type* = nullptr
            );

    template <typename K, typename SP>
    void init_render_func(
            K kernel,
            SP sparams,
            unsigned frame_num,
            typename std::enable_if<std::is_same<typename SP::camera_type, pinhole_camera>::value>::type* = nullptr
            );

    template <typename K, typename SP, typename Sampler, typename ...Args>
    void call_sample_pixel(
            std::false_type /* has intersector */,
            K               kernel,
            SP              sparams,
            Sampler&        samp,
            unsigned        frame_num,
            Args&&...       args
            )
    {
        auto r = detail::make_primary_rays(
                R{},
                typename SP::pixel_sampler_type{},
                samp,
                std::forward<Args>(args)...
                );

        sample_pixel(
                kernel,
                typename SP::pixel_sampler_type(),
                r,
                samp,
                frame_num,
                sparams.rt.ref(),
                std::forward<Args>(args)...
                );
    }

    template <typename K, typename SP, typename Sampler, typename ...Args>
    void call_sample_pixel(
            std::true_type  /* has intersector */,
            K               kernel,
            SP              sparams,
            Sampler&        samp,
            unsigned        frame_num,
            Args&&...       args
            )
    {
        auto r = detail::make_primary_rays(
                R{},
                typename SP::pixel_sampler_type{},
                samp,
                std::forward<Args>(args)...
                );

        sample_pixel(
                detail::have_intersector_tag(),
                sparams.intersector,
                kernel,
                typename SP::pixel_sampler_type(),
                r,
                samp,
                frame_num,
                sparams.rt.ref(),
                std::forward<Args>(args)...
                );
    }

    std::vector<std::thread>    threads;
    detail::sync_params         sync_params;

    int                         width;
    int                         height;
    static const int            tile_width  = 16;
    static const int            tile_height = 16;
    recti                       scissor_box;

    render_tile_func            render_tile;
};

template <typename R>
void tiled_sched<R>::impl::init_threads(unsigned num_threads)
{
    for (unsigned i = 0; i < num_threads; ++i)
    {
        threads.emplace_back([this](){ render_loop(); });
    }
}

template <typename R>
void tiled_sched<R>::impl::destroy_threads()
{
    if (threads.size() == 0)
    {
        return;
    }

    sync_params.render_loop_exit = true;
    sync_params.threads_start.notify_all();

    for (auto& t : threads)
    {
        if (t.joinable())
        {
            t.join();
        }
    }

    sync_params.render_loop_exit = false;
    threads.clear();
}

//-------------------------------------------------------------------------------------------------
// Main render loop
//

template <typename R>
void tiled_sched<R>::impl::render_loop()
{
    for (;;)
    {
        {
            std::unique_lock<std::mutex> l( sync_params.mutex );
            sync_params.threads_start.wait(l);
        }

    // case event.exit:
        if (sync_params.render_loop_exit)
        {
            break;
        }

    // case event.render:
        random_sampler<typename R::scalar_type> samp(detail::tic());
        for (;;)
        {
            auto tile_idx = sync_params.tile_idx_counter.fetch_add(1);

            if (tile_idx >= sync_params.tile_num)
            {
                break;
            }

            auto tilew = tile_width;
            auto tileh = tile_height;
            auto numtilesx = div_up( width, tilew );

            recti tile(
                    (tile_idx % numtilesx) * tilew,
                    (tile_idx / numtilesx) * tileh,
                    tilew,
                    tileh
                    );

            render_tile(tile, samp);

            auto num_tiles_fin = sync_params.tile_fin_counter.fetch_add(1);

            if (num_tiles_fin >= sync_params.tile_num - 1)
            {
                assert(num_tiles_fin == sync_params.tile_num - 1);
                sync_params.threads_ready.notify();
                break;
            }
        }
    }
}

template <typename R>
template <typename K, typename SP>
void tiled_sched<R>::impl::init_render_func(
        K kernel,
        SP sparams,
        unsigned frame_num,
        typename std::enable_if<std::is_same<typename SP::camera_type, matrix_camera>::value>::type*
        )
{
    // overload for matrix cam

    using T = typename R::scalar_type;
    using matrix_type = matrix<4, 4, T>;

    width       = sparams.rt.width();
    height      = sparams.rt.height();
    scissor_box = sparams.scissor_box;

    matrix_type view_matrix( sparams.cam.get_view_matrix() );
    matrix_type proj_matrix( sparams.cam.get_proj_matrix() );
    matrix_type inv_view_matrix( inverse(sparams.cam.get_view_matrix()) );
    matrix_type inv_proj_matrix( inverse(sparams.get_proj_matrix()) );

    recti clip_rect(scissor_box.x, scissor_box.y, scissor_box.w - 1, scissor_box.h - 1);

    render_tile = [=](recti const& tile, random_sampler<T>& samp)
    {
        unsigned numx = tile_width  / packet_size<T>::w;
        unsigned numy = tile_height / packet_size<T>::h;
{'fraction_non_alphanumeric': 0.13233634311512416, 'fraction_numerical': 0.0019751693002257337, 'mean_word_length': 1.6185814554857776, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4542501', 'n_tokens_mistral': 4286, 'n_tokens_neox': 4050, 'n_words': 816}