<commit_before>/**
 * Implementation of the wayfire-shell-unstable-v2 protocol
 */
#include "wayfire/output.hpp"
#include "wayfire/core.hpp"
#include "wayfire/debug.hpp"
#include "wayfire/output-layout.hpp"
#include "wayfire/render-manager.hpp"
#include "wayfire-shell.hpp"
#include "wayfire-shell-unstable-v2-protocol.h"
#include "wayfire/signal-definitions.hpp"
#include "../view/view-impl.hpp"
#include <wayfire/util/log.hpp>

/* ----------------------------- wfs_hotspot -------------------------------- */
static void handle_hotspot_destroy(wl_resource *resource);

/**
 * Represents a zwf_shell_hotspot_v2.
 * Lifetime is managed by the resource.
 */
class wfs_hotspot : public noncopyable_t
{
  private:
    wf::geometry_t hotspot_geometry;

    bool hotspot_triggered = false;
    wf::wl_idle_call idle_check_input;
    wf::wl_timer timer;

    uint32_t timeout_ms;
    wl_resource *hotspot_resource;

    wf::signal_callback_t on_motion_event = [=] (wf::signal_data_t *data)
    {
        idle_check_input.run_once([=] () {
            auto gcf = wf::get_core().get_cursor_position();
            wf::point_t gc{(int)gcf.x, (int)gcf.y};
            process_input_motion(gc);
        });
    };

    wf::signal_callback_t on_touch_motion_event = [=] (wf::signal_data_t *data)
    {
        idle_check_input.run_once([=] () {
            auto gcf = wf::get_core().get_touch_position(0);
            wf::point_t gc{(int)gcf.x, (int)gcf.y};
            process_input_motion(gc);
        });
    };

    wf::signal_callback_t on_output_removed;

    void process_input_motion(wf::point_t gc)
    {
        if (!(hotspot_geometry & gc))
        {
            if (hotspot_triggered)
                zwf_hotspot_v2_send_leave(hotspot_resource);

            /* Cursor outside of the hotspot */
            hotspot_triggered = false;
            timer.disconnect();
            return;
        }

        if (hotspot_triggered)
        {
            /* Hotspot was already triggered, wait for the next time the cursor
             * enters the hotspot area to trigger again */
            return;
        }

        if (!timer.is_connected())
        {
            timer.set_timeout(timeout_ms, [=] () {
                hotspot_triggered = true;
                zwf_hotspot_v2_send_enter(hotspot_resource);
            });
        }
    }

    wf::geometry_t calculate_hotspot_geometry(wf::output_t *output,
        uint32_t edge_mask, uint32_t distance) const
    {
        wf::geometry_t slot = output->get_layout_geometry();
        if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_TOP)
        {
            slot.height = distance;
        } else if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_BOTTOM)
        {
            slot.y += slot.height - distance;
            slot.height = distance;
        }

        if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_LEFT)
        {
            slot.width = distance;
        } else if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_RIGHT)
        {
            slot.x += slot.width - distance;
            slot.width = distance;
        }

        return slot;
    }

  public:
    /**
     * Create a new hotspot.
     * It is guaranteedd that edge_mask contains at most 2 non-opposing edges.
     */
    wfs_hotspot(wf::output_t *output, uint32_t edge_mask,
        uint32_t distance, uint32_t timeout, wl_client *client, uint32_t id)
    {
        this->timeout_ms = timeout;
        this->hotspot_geometry =
            calculate_hotspot_geometry(output, edge_mask, distance);

        hotspot_resource =
            wl_resource_create(client, &zwf_hotspot_v2_interface, 1, id);
        wl_resource_set_implementation(hotspot_resource, NULL, this,
            handle_hotspot_destroy);

        // setup output destroy listener
        on_output_removed = [this, output] (wf::signal_data_t* data)
        {
            auto ev = static_cast<output_removed_signal*> (data);
            if (ev->output == output)
            {
                /* Make hotspot inactive by setting the region to empty */
                hotspot_geometry = {0, 0, 0, 0};
                process_input_motion({0, 0});
            }
        };

        wf::get_core().connect_signal("pointer_motion", &on_motion_event);
        wf::get_core().connect_signal("tablet_axis", &on_motion_event);
        wf::get_core().connect_signal("touch_motion", &on_touch_motion_event);

        wf::get_core().output_layout->connect_signal("output-removed",
            &on_output_removed);
    }

    ~wfs_hotspot()
    {
        wf::get_core().disconnect_signal("pointer_motion", &on_motion_event);
        wf::get_core().disconnect_signal("tablet_axis", &on_motion_event);
        wf::get_core().disconnect_signal("touch_motion", &on_touch_motion_event);

        wf::get_core().output_layout->disconnect_signal("output-removed",
            &on_output_removed);
    }
};

static void handle_hotspot_destroy(wl_resource *resource)
{
    auto *hotspot = (wfs_hotspot*)wl_resource_get_user_data(resource);
    delete hotspot;

    wl_resource_set_user_data(resource, nullptr);
}

/* ------------------------------ wfs_output -------------------------------- */
static void handle_output_destroy(wl_resource *resource);
static void handle_zwf_output_inhibit_output(wl_client*, wl_resource *resource);
static void handle_zwf_output_inhibit_output_done(wl_client*,
    wl_resource *resource);
static void handle_zwf_output_create_hotspot(wl_client*, wl_resource *resource,
    uint32_t hotspot, uint32_t threshold, uint32_t timeout, uint32_t id);

static struct zwf_output_v2_interface zwf_output_impl = {
	.inhibit_output = handle_zwf_output_inhibit_output,
	.inhibit_output_done = handle_zwf_output_inhibit_output_done,
	.create_hotspot = handle_zwf_output_create_hotspot,
};

/**
 * Represents a zwf_output_v2.
 * Lifetime is managed by the wl_resource
 */
class wfs_output : public noncopyable_t
{
    uint32_t num_inhibits = 0;
    wl_resource *resource;
    wf::output_t *output;

    void disconnect_from_output()
    {
        wf::get_core().output_layout->disconnect_signal("output-removed",
            &on_output_removed);
        output->disconnect_signal("fullscreen-layer-focused", &on_fullscreen_layer_focused);
        this->output = nullptr;
    }

    wf::signal_callback_t on_output_removed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<output_removed_signal*> (data);
        if (ev->output == this->output)
            disconnect_from_output();
       };

    wf::signal_callback_t on_fullscreen_layer_focused = [=] (wf::signal_data_t *data)
    {
        if (data != nullptr) {
            zwf_output_v2_send_enter_fullscreen(resource);
        } else {
            zwf_output_v2_send_leave_fullscreen(resource);
        }
    };

  public:
    wfs_output(wf::output_t *output, wl_client *client, int id)
    {
        this->output = output;

        resource = wl_resource_create(client, &zwf_output_v2_interface, 1, id);
        wl_resource_set_implementation(resource, &zwf_output_impl,
            this, handle_output_destroy);

        output->connect_signal("fullscreen-layer-focused", &on_fullscreen_layer_focused);
        wf::get_core().output_layout->connect_signal("output-removed",
            &on_output_removed);
    }

    ~wfs_output()
    {
        if (!this->output)
        {
            /* The wayfire output was destroyed. Gracefully do nothing */
            return;
        }

        disconnect_from_output();
        /* Remove any remaining inhibits, otherwise the compositor will never
         * be "unlocked" */
        while (num_inhibits > 0)
        {
            this->output->render->add_inhibit(false);
            --num_inhibits;
        }
    }

    void inhibit_output()
    {
        ++this->num_inhibits;
        this->output->render->add_inhibit(true);
    }

    void inhibit_output_done()
    {
        if (this->num_inhibits == 0)
        {
            wl_resource_post_no_memory(resource);
            return;
        }

        --this->num_inhibits;
        this->output->render->add_inhibit(false);
    }

    void create_hotspot(uint32_t hotspot, uint32_t threshold, uint32_t timeout,
        uint32_t id)
    {
        // will be auto-deleted when the resource is destroyed by the client
        new wfs_hotspot(this->output, hotspot, threshold, timeout,
            wl_resource_get_client(this->resource), id);
    }
};

static void handle_zwf_output_inhibit_output(wl_client*, wl_resource *resource)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->inhibit_output();
}

static void handle_zwf_output_inhibit_output_done(
    wl_client*, wl_resource *resource)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->inhibit_output_done();
}

static void handle_zwf_output_create_hotspot(wl_client*, wl_resource *resource,
    uint32_t hotspot, uint32_t threshold, uint32_t timeout, uint32_t id)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->create_hotspot(hotspot, threshold, timeout, id);
}

static void handle_output_destroy(wl_resource *resource)
{
    auto *output = (wfs_output*)wl_resource_get_user_data(resource);
    delete output;

    wl_resource_set_user_data(resource, nullptr);
}

/* ------------------------------ wfs_surface ------------------------------- */
static void handle_surface_destroy(wl_resource *resource);
static void handle_zwf_surface_interactive_move(wl_client*,
    wl_resource *resource);

static struct zwf_surface_v2_interface zwf_surface_impl = {
    .interactive_move = handle_zwf_surface_interactive_move,
};

/**
 * Represents a zwf_surface_v2.
 * Lifetime is managed by the wl_resource
 */
class wfs_surface : public noncopyable_t
{
    wl_resource *resource;
    wayfire_view view;

    wf::signal_callback_t on_unmap = [=] (wf::signal_data_t *data)
    {
        view = nullptr;
    };

  public:
    wfs_surface(wayfire_view view, wl_client *client, int id)
    {
        this->view = view;

        resource = wl_resource_create(client, &zwf_surface_v2_interface, 1, id);
        wl_resource_set_implementation(resource, &zwf_surface_impl,
            this, handle_surface_destroy);

        view->connect_signal("unmap", &on_unmap);
    }

    ~wfs_surface()
    {
        if (this->view)
            view->disconnect_signal("unmap", &on_unmap);
    }

    void interactive_move()
    {
        if (view) view->move_request();
    }
};

static void handle_zwf_surface_interactive_move(wl_client*, wl_resource *resource)
{
    auto surface = (wfs_surface*)wl_resource_get_user_data(resource);
    surface->interactive_move();
}

static void handle_surface_destroy(wl_resource *resource)
{
    auto surface = (wfs_surface*)wl_resource_get_user_data(resource);
    delete surface;
    wl_resource_set_user_data(resource, nullptr);
}

static void zwf_shell_manager_get_wf_output(wl_client *client,
    wl_resource *resource, wl_resource *output, uint32_t id)
{
    auto wlr_out = (wlr_output*) wl_resource_get_user_data(output);
    auto wo = wf::get_core().output_layout->find_output(wlr_out);

    if (wo)
    {
        // will be deleted when the resource is destroyed
        new wfs_output(wo, client, id);
    }
}

static void zwf_shell_manager_get_wf_surface(wl_client *client,
    wl_resource *resource, wl_resource *surface, uint32_t id)
{
    auto view = wf::wl_surface_to_wayfire_view(surface);
    if (view)
    {
        /* Will be freed when the resource is destroyed */
        new wfs_surface(view, client, id);
    }
}

const struct zwf_shell_manager_v2_interface zwf_shell_manager_v2_impl =
{
    zwf_shell_manager_get_wf_output,
    zwf_shell_manager_get_wf_surface,
};

void bind_zwf_shell_manager(wl_client *client, void *data,
    uint32_t version, uint32_t id)
{
    auto resource =
        wl_resource_create(client, &zwf_shell_manager_v2_interface, 1, id);
    wl_resource_set_implementation(resource,
        &zwf_shell_manager_v2_impl, NULL, NULL);
}

struct wayfire_shell
{
    wl_global *shell_manager;
};

wayfire_shell* wayfire_shell_create(wl_display *display)
{
    wayfire_shell *ws = new wayfire_shell;

    ws->shell_manager = wl_global_create(display,
        &zwf_shell_manager_v2_interface, 1, NULL, bind_zwf_shell_manager);

    if (ws->shell_manager == NULL)
    {
        LOGE("Failed to create wayfire_shell interface");
        return NULL;
    }

    return ws;
}
<commit_msg>wayfire-shell: fix crash when a client disconnects<commit_after>/**
 * Implementation of the wayfire-shell-unstable-v2 protocol
 */
#include "wayfire/output.hpp"
#include "wayfire/core.hpp"
#include "wayfire/debug.hpp"
#include "wayfire/output-layout.hpp"
#include "wayfire/render-manager.hpp"
#include "wayfire-shell.hpp"
#include "wayfire-shell-unstable-v2-protocol.h"
#include "wayfire/signal-definitions.hpp"
#include "../view/view-impl.hpp"
#include <wayfire/util/log.hpp>

/* ----------------------------- wfs_hotspot -------------------------------- */
static void handle_hotspot_destroy(wl_resource *resource);

/**
 * Represents a zwf_shell_hotspot_v2.
 * Lifetime is managed by the resource.
 */
class wfs_hotspot : public noncopyable_t
{
  private:
    wf::geometry_t hotspot_geometry;

    bool hotspot_triggered = false;
    wf::wl_idle_call idle_check_input;
    wf::wl_timer timer;

    uint32_t timeout_ms;
    wl_resource *hotspot_resource;

    wf::signal_callback_t on_motion_event = [=] (wf::signal_data_t *data)
    {
        idle_check_input.run_once([=] () {
            auto gcf = wf::get_core().get_cursor_position();
            wf::point_t gc{(int)gcf.x, (int)gcf.y};
            process_input_motion(gc);
        });
    };

    wf::signal_callback_t on_touch_motion_event = [=] (wf::signal_data_t *data)
    {
        idle_check_input.run_once([=] () {
            auto gcf = wf::get_core().get_touch_position(0);
            wf::point_t gc{(int)gcf.x, (int)gcf.y};
            process_input_motion(gc);
        });
    };

    wf::signal_callback_t on_output_removed;

    void process_input_motion(wf::point_t gc)
    {
        if (!(hotspot_geometry & gc))
        {
            if (hotspot_triggered)
                zwf_hotspot_v2_send_leave(hotspot_resource);

            /* Cursor outside of the hotspot */
            hotspot_triggered = false;
            timer.disconnect();
            return;
        }

        if (hotspot_triggered)
        {
            /* Hotspot was already triggered, wait for the next time the cursor
             * enters the hotspot area to trigger again */
            return;
        }

        if (!timer.is_connected())
        {
            timer.set_timeout(timeout_ms, [=] () {
                hotspot_triggered = true;
                zwf_hotspot_v2_send_enter(hotspot_resource);
            });
        }
    }

    wf::geometry_t calculate_hotspot_geometry(wf::output_t *output,
        uint32_t edge_mask, uint32_t distance) const
    {
        wf::geometry_t slot = output->get_layout_geometry();
        if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_TOP)
        {
            slot.height = distance;
        } else if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_BOTTOM)
        {
            slot.y += slot.height - distance;
            slot.height = distance;
        }

        if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_LEFT)
        {
            slot.width = distance;
        } else if (edge_mask & ZWF_OUTPUT_V2_HOTSPOT_EDGE_RIGHT)
        {
            slot.x += slot.width - distance;
            slot.width = distance;
        }

        return slot;
    }

  public:
    /**
     * Create a new hotspot.
     * It is guaranteedd that edge_mask contains at most 2 non-opposing edges.
     */
    wfs_hotspot(wf::output_t *output, uint32_t edge_mask,
        uint32_t distance, uint32_t timeout, wl_client *client, uint32_t id)
    {
        this->timeout_ms = timeout;
        this->hotspot_geometry =
            calculate_hotspot_geometry(output, edge_mask, distance);

        hotspot_resource =
            wl_resource_create(client, &zwf_hotspot_v2_interface, 1, id);
        wl_resource_set_implementation(hotspot_resource, NULL, this,
            handle_hotspot_destroy);

        // setup output destroy listener
        on_output_removed = [this, output] (wf::signal_data_t* data)
        {
            auto ev = static_cast<output_removed_signal*> (data);
            if (ev->output == output)
            {
                /* Make hotspot inactive by setting the region to empty */
                hotspot_geometry = {0, 0, 0, 0};
                process_input_motion({0, 0});
            }
        };

        wf::get_core().connect_signal("pointer_motion", &on_motion_event);
        wf::get_core().connect_signal("tablet_axis", &on_motion_event);
        wf::get_core().connect_signal("touch_motion", &on_touch_motion_event);

        wf::get_core().output_layout->connect_signal("output-removed",
            &on_output_removed);
    }

    ~wfs_hotspot()
    {
        wf::get_core().disconnect_signal("pointer_motion", &on_motion_event);
        wf::get_core().disconnect_signal("tablet_axis", &on_motion_event);
        wf::get_core().disconnect_signal("touch_motion", &on_touch_motion_event);

        wf::get_core().output_layout->disconnect_signal("output-removed",
            &on_output_removed);
    }
};

static void handle_hotspot_destroy(wl_resource *resource)
{
    auto *hotspot = (wfs_hotspot*)wl_resource_get_user_data(resource);
    delete hotspot;

    wl_resource_set_user_data(resource, nullptr);
}

/* ------------------------------ wfs_output -------------------------------- */
static void handle_output_destroy(wl_resource *resource);
static void handle_zwf_output_inhibit_output(wl_client*, wl_resource *resource);
static void handle_zwf_output_inhibit_output_done(wl_client*,
    wl_resource *resource);
static void handle_zwf_output_create_hotspot(wl_client*, wl_resource *resource,
    uint32_t hotspot, uint32_t threshold, uint32_t timeout, uint32_t id);

static struct zwf_output_v2_interface zwf_output_impl = {
	.inhibit_output = handle_zwf_output_inhibit_output,
	.inhibit_output_done = handle_zwf_output_inhibit_output_done,
	.create_hotspot = handle_zwf_output_create_hotspot,
};

/**
 * Represents a zwf_output_v2.
 * Lifetime is managed by the wl_resource
 */
class wfs_output : public noncopyable_t
{
    uint32_t num_inhibits = 0;
    wl_resource *resource;
    wf::output_t *output;

    void disconnect_from_output()
    {
        wf::get_core().output_layout->disconnect_signal("output-removed",
            &on_output_removed);
        output->disconnect_signal("fullscreen-layer-focused", &on_fullscreen_layer_focused);
    }

    wf::signal_callback_t on_output_removed = [=] (wf::signal_data_t *data)
    {
        auto ev = static_cast<output_removed_signal*> (data);
        if (ev->output == this->output)
        {
            disconnect_from_output();
            this->output = nullptr;
        }
    };

    wf::signal_callback_t on_fullscreen_layer_focused = [=] (wf::signal_data_t *data)
    {
        if (data != nullptr) {
            zwf_output_v2_send_enter_fullscreen(resource);
        } else {
            zwf_output_v2_send_leave_fullscreen(resource);
        }
    };

  public:
    wfs_output(wf::output_t *output, wl_client *client, int id)
    {
        this->output = output;

        resource = wl_resource_create(client, &zwf_output_v2_interface, 1, id);
        wl_resource_set_implementation(resource, &zwf_output_impl,
            this, handle_output_destroy);

        output->connect_signal("fullscreen-layer-focused", &on_fullscreen_layer_focused);
        wf::get_core().output_layout->connect_signal("output-removed",
            &on_output_removed);
    }

    ~wfs_output()
    {
        if (!this->output)
        {
            /* The wayfire output was destroyed. Gracefully do nothing */
            return;
        }

        disconnect_from_output();
        /* Remove any remaining inhibits, otherwise the compositor will never
         * be "unlocked" */
        while (num_inhibits > 0)
        {
            this->output->render->add_inhibit(false);
            --num_inhibits;
        }
    }

    void inhibit_output()
    {
        ++this->num_inhibits;
        if (this->output)
            this->output->render->add_inhibit(true);
    }

    void inhibit_output_done()
    {
        if (this->num_inhibits == 0)
        {
            wl_resource_post_no_memory(resource);
            return;
        }

        --this->num_inhibits;
        if (this->output)
            this->output->render->add_inhibit(false);
    }

    void create_hotspot(uint32_t hotspot, uint32_t threshold, uint32_t timeout,
        uint32_t id)
    {
        // will be auto-deleted when the resource is destroyed by the client
        new wfs_hotspot(this->output, hotspot, threshold, timeout,
            wl_resource_get_client(this->resource), id);
    }
};

static void handle_zwf_output_inhibit_output(wl_client*, wl_resource *resource)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->inhibit_output();
}

static void handle_zwf_output_inhibit_output_done(
    wl_client*, wl_resource *resource)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->inhibit_output_done();
}

static void handle_zwf_output_create_hotspot(wl_client*, wl_resource *resource,
    uint32_t hotspot, uint32_t threshold, uint32_t timeout, uint32_t id)
{
    auto output = (wfs_output*)wl_resource_get_user_data(resource);
    output->create_hotspot(hotspot, threshold, timeout, id);
}

static void handle_output_destroy(wl_resource *resource)
{
    auto *output = (wfs_output*)wl_resource_get_user_data(resource);
    delete output;

    wl_resource_set_user_data(resource, nullptr);
}

/* ------------------------------ wfs_surface ------------------------------- */
static void handle_surface_destroy(wl_resource *resource);
static void handle_zwf_surface_interactive_move(wl_client*,
    wl_resource *resource);

static struct zwf_surface_v2_interface zwf_surface_impl = {
    .interactive_move = handle_zwf_surface_interactive_move,
};

/**
 * Represents a zwf_surface_v2.
 * Lifetime is managed by the wl_resource
 */
class wfs_surface : public noncopyable_t
{
    wl_resource *resource;
    wayfire_view view;

    wf::signal_callback_t on_unmap = [=] (wf::signal_data_t *data)
    {
        view = nullptr;
    };

  public:
    wfs_surface(wayfire_view view, wl_client *client, int id)
    {
        this->view = view;

        resource = wl_resource_create(client, &zwf_surface_v2_interface, 1, id);
        wl_resource_set_implementation(resource, &zwf_surface_impl,
            this, handle_surface_destroy);

        view->connect_signal("unmap", &on_unmap);
    }

    ~wfs_surface()
    {
        if (this->view)
            view->disconnect_signal("unmap", &on_unmap);
    }

    void interactive_move()
    {
        if (view) view->move_request();
    }
};

static void handle_zwf_surface_interactive_move(wl_client*, wl_resource *resource)
{
    auto surface = (wfs_surface*)wl_resource_get_user_data(resource);
    surface->interactive_move();
}

static void handle_surface_destroy(wl_resource *resource)
{
    auto surface = (wfs_surface*)wl_resource_get_user_data(resource);
    delete surface;
    wl_resource_set_user_data(resource, nullptr);
}

static void zwf_shell_manager_get_wf_output(wl_client *client,
    wl_resource *resource, wl_resource *output, uint32_t id)
{
    auto wlr_out = (wlr_output*) wl_resource_get_user_data(output);
    auto wo = wf::get_core().output_layout->find_output(wlr_out);

    if (wo)
    {
        // will be deleted when the resource is destroyed
        new wfs_output(wo, client, id);
    }
}

static void zwf_shell_manager_get_wf_surface(wl_client *client,
    wl_resource *resource, wl_resource *surface, uint32_t id)
{
    auto view = wf::wl_surface_to_wayfire_view(surface);
    if (view)
    {
        /* Will be freed when the resource is destroyed */
        new wfs_surface(view, client, id);
    }
}

const struct zwf_shell_manager_v2_interface zwf_shell_manager_v2_impl =
{
    zwf_shell_manager_get_wf_output,
    zwf_shell_manager_get_wf_surface,
};

void bind_zwf_shell_manager(wl_client *client, void *data,
    uint32_t version, uint32_t id)
{
    auto resource =
        wl_resource_create(client, &zwf_shell_manager_v2_interface, 1, id);
    wl_resource_set_implementation(resource,
        &zwf_shell_manager_v2_impl, NULL, NULL);
}

struct wayfire_shell
{
    wl_global *shell_manager;
};

wayfire_shell* wayfire_shell_create(wl_display *display)
{
    wayfire_shell *ws = new wayfire_shell;

    ws->shell_manager = wl_global_create(display,
        &zwf_shell_manager_v2_interface, 1, NULL, bind_zwf_shell_manager);

    if (ws->shell_manager == NULL)
    {
        LOGE("Failed to create wayfire_shell interface");
        delete ws;
        return NULL;
    }

    return ws;
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2002  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#include "iodev.h"

#if BX_SUPPORT_APIC

#include "cpu/apic.h"

class bx_ioapic_c bx_ioapic;
#define LOG_THIS  bx_ioapic.

static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
  bx_ioapic.read(a20addr, data, len);
  return 1;
}

static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
  if (len != 4) {
    BX_PANIC (("I/O apic write with len=%d (should be 4)", len));
  }
  bx_ioapic.write(a20addr, (Bit32u*) data, len);
  return 1;
}

void bx_io_redirect_entry_t::sprintf_self(char *buf)
{
  sprintf(buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x",
     (unsigned) destination(),
     (unsigned) is_masked(),
     (unsigned) trigger_mode(),
     (unsigned) remote_irr(),
     (unsigned) pin_polarity(),
     (unsigned) delivery_status(),
     (unsigned) destination_mode(),
     (unsigned) delivery_mode(),
     (unsigned) vector());
}

void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
{
  BXRS_HEX_PARAM_SIMPLE(parent, lo);
  BXRS_HEX_PARAM_SIMPLE(parent, hi);
}

#define BX_IOAPIC_BASE_ADDR (0xfec00000)

bx_ioapic_c::bx_ioapic_c()
  : bx_generic_apic_c(BX_IOAPIC_BASE_ADDR)
{
  put("IOAP");
}

#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)

void bx_ioapic_c::init(void)
{
  bx_generic_apic_c::init();
  BX_INFO(("initializing I/O APIC"));
  base_addr = BX_IOAPIC_BASE_ADDR;
  set_id(BX_IOAPIC_DEFAULT_ID);
  DEV_register_memory_handlers(&bx_ioapic,
      ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
  reset(BX_RESET_HARDWARE);
}

void bx_ioapic_c::reset(unsigned type)
{
  // all interrupts masked
  for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    ioredtbl[i].set_lo_part(0x00010000);
    ioredtbl[i].set_hi_part(0x00000000);
  }
  intin = 0;
  irr = 0;
  ioregsel = 0;
}

void bx_ioapic_c::read_aligned(bx_phy_address address, Bit32u *data)
{
  BX_DEBUG(("IOAPIC: read aligned addr=%08x", address));
  address &= 0xff;
  if (address == 0x00) {
    // select register
    *data = ioregsel;
    return;
  } else {
    if (address != 0x10)
      BX_PANIC(("IOAPIC: read from unsupported address"));
  }
  // only reached when reading data register
  switch (ioregsel) {
  case 0x00:  // APIC ID, note this is 4bits, the upper 4 are reserved
    *data = ((id & APIC_ID_MASK) << 24);
    return;
  case 0x01:  // version
    *data = BX_IOAPIC_VERSION_ID;
    return;
  case 0x02:
    BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
    *data = 0;
    return;
  default:
    int index = (ioregsel - 0x10) >> 1;
    if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
      bx_io_redirect_entry_t *entry = ioredtbl + index;
      *data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
      return;
    }
    BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u *value)
{
  BX_DEBUG(("IOAPIC: write aligned addr=%08x, data=%08x", address, *value));
  address &= 0xff;
  if (address == 0x00)  {
    ioregsel = *value;
    return;
  } else {
    if (address != 0x10)
      BX_PANIC(("IOAPIC: write to unsupported address"));
  }
  // only reached when writing data register
  switch (ioregsel) {
    case 0x00: // set APIC ID
      {
	Bit8u newid = (*value >> 24) & APIC_ID_MASK;
	BX_INFO(("IOAPIC: setting id to 0x%x", newid));
	set_id (newid);
	return;
      }
    case 0x01: // version
    case 0x02: // arbitration id
      BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
      return;
    default:
      int index = (ioregsel - 0x10) >> 1;
      if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
	bx_io_redirect_entry_t *entry = ioredtbl + index;
	if (ioregsel&1)
	  entry->set_hi_part(*value);
	else
	  entry->set_lo_part(*value);
	char buf[1024];
	entry->sprintf_self(buf);
	BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
	service_ioapic();
	return;
      }
      BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::set_irq_level(Bit8u int_in, bx_bool level)
{
  BX_DEBUG(("set_irq_level(): INTIN%d: level=%d", int_in, level));
  if (int_in < BX_IOAPIC_NUM_PINS) {
    Bit32u bit = 1<<int_in;
    if ((level<<int_in) != (intin & bit)) {
      bx_io_redirect_entry_t *entry = ioredtbl + int_in;
      if (entry->trigger_mode()) {
        // level triggered
        if (level) {
          intin |= bit;
          irr |= bit;
          service_ioapic();
        } else {
          intin &= ~bit;
          irr &= ~bit;
        }
      } else {
        // edge triggered
        if (level) {
          intin |= bit;
          irr |= bit;
          service_ioapic();
        } else {
          intin &= ~bit;
        }
      }
    }
  }
}

void bx_ioapic_c::receive_eoi(Bit8u vector)
{
  BX_DEBUG(("IOAPIC: received EOI for vector %d", vector));
}

void bx_ioapic_c::service_ioapic()
{
  static unsigned int stuck = 0;
  Bit8u vector = 0;
  // look in IRR and deliver any interrupts that are not masked.
  BX_DEBUG(("IOAPIC: servicing"));
  for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
    Bit32u mask = 1<<bit;
    if (irr & mask) {
      bx_io_redirect_entry_t *entry = ioredtbl + bit;
      if (! entry->is_masked()) {
        // clear irr bit and deliver
        if (entry->delivery_mode() == 7) {
          vector = DEV_pic_iac();
        } else {
          vector = entry->vector();
        }
        bx_bool done = apic_bus_deliver_interrupt(vector, entry->destination(), entry->delivery_mode(), entry->destination_mode(), entry->pin_polarity(), entry->trigger_mode());
        if (done) {
          if (! entry->trigger_mode())
            irr &= ~mask;
          entry->clear_delivery_status();
          stuck = 0;
        } else {
          entry->set_delivery_status();
          stuck++;
          if (stuck > 5)
            BX_INFO(("vector %#x stuck?", vector));
        }
      }
      else {
        BX_DEBUG(("service_ioapic(): INTIN%d is masked", bit));
      }
    }
  }
}

void bx_ioapic_c::register_state(void)
{
  bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
  BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
  BXRS_HEX_PARAM_SIMPLE(list, intin);
  BXRS_HEX_PARAM_SIMPLE(list, irr);

  bx_list_c *table = new bx_list_c(list, "ioredtbl", BX_IOAPIC_NUM_PINS);
  for (unsigned i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    char name[6];
    sprintf(name, "0x%02x", i);
    bx_list_c *entry = new bx_list_c(table, name, 2);
    ioredtbl[i].register_state(entry);
  }
}

#endif /* if BX_SUPPORT_APIC */
<commit_msg>faster i/o apic write access<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2002  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#include "iodev.h"

#if BX_SUPPORT_APIC

#include "cpu/apic.h"

class bx_ioapic_c bx_ioapic;
#define LOG_THIS  bx_ioapic.

static bx_bool ioapic_read(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
  bx_ioapic.read(a20addr, data, len);
  return 1;
}

static bx_bool ioapic_write(bx_phy_address a20addr, unsigned len, void *data, void *param)
{
  if (len != 4) {
    BX_PANIC (("I/O apic write with len=%d (should be 4)", len));
    return 1;
  }

  if(a20addr & 3) {
    BX_PANIC(("I/O apic write at unaligned address 0x" FMT_PHY_ADDRX, a20addr));
    return 1;
  }

  bx_ioapic.write_aligned(a20addr, (Bit32u*) data);
  return 1;
}

void bx_io_redirect_entry_t::sprintf_self(char *buf)
{
  sprintf(buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x",
     (unsigned) destination(),
     (unsigned) is_masked(),
     (unsigned) trigger_mode(),
     (unsigned) remote_irr(),
     (unsigned) pin_polarity(),
     (unsigned) delivery_status(),
     (unsigned) destination_mode(),
     (unsigned) delivery_mode(),
     (unsigned) vector());
}

void bx_io_redirect_entry_t::register_state(bx_param_c *parent)
{
  BXRS_HEX_PARAM_SIMPLE(parent, lo);
  BXRS_HEX_PARAM_SIMPLE(parent, hi);
}

#define BX_IOAPIC_BASE_ADDR (0xfec00000)

bx_ioapic_c::bx_ioapic_c()
  : bx_generic_apic_c(BX_IOAPIC_BASE_ADDR)
{
  put("IOAP");
}

#define BX_IOAPIC_DEFAULT_ID (BX_SMP_PROCESSORS)

void bx_ioapic_c::init(void)
{
  bx_generic_apic_c::init();
  BX_INFO(("initializing I/O APIC"));
  base_addr = BX_IOAPIC_BASE_ADDR;
  set_id(BX_IOAPIC_DEFAULT_ID);
  DEV_register_memory_handlers(&bx_ioapic,
      ioapic_read, ioapic_write, base_addr, base_addr + 0xfff);
  reset(BX_RESET_HARDWARE);
}

void bx_ioapic_c::reset(unsigned type)
{
  // all interrupts masked
  for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    ioredtbl[i].set_lo_part(0x00010000);
    ioredtbl[i].set_hi_part(0x00000000);
  }
  intin = 0;
  irr = 0;
  ioregsel = 0;
}

void bx_ioapic_c::read_aligned(bx_phy_address address, Bit32u *data)
{
  BX_DEBUG(("IOAPIC: read aligned addr=%08x", address));
  address &= 0xff;
  if (address == 0x00) {
    // select register
    *data = ioregsel;
    return;
  } else {
    if (address != 0x10)
      BX_PANIC(("IOAPIC: read from unsupported address"));
  }
  // only reached when reading data register
  switch (ioregsel) {
  case 0x00:  // APIC ID, note this is 4bits, the upper 4 are reserved
    *data = ((id & APIC_ID_MASK) << 24);
    return;
  case 0x01:  // version
    *data = BX_IOAPIC_VERSION_ID;
    return;
  case 0x02:
    BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
    *data = 0;
    return;
  default:
    int index = (ioregsel - 0x10) >> 1;
    if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
      bx_io_redirect_entry_t *entry = ioredtbl + index;
      *data = (ioregsel&1) ? entry->get_hi_part() : entry->get_lo_part();
      return;
    }
    BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::write_aligned(bx_phy_address address, Bit32u *value)
{
  BX_DEBUG(("IOAPIC: write aligned addr=%08x, data=%08x", address, *value));
  address &= 0xff;
  if (address == 0x00)  {
    ioregsel = *value;
    return;
  } else {
    if (address != 0x10)
      BX_PANIC(("IOAPIC: write to unsupported address"));
  }
  // only reached when writing data register
  switch (ioregsel) {
    case 0x00: // set APIC ID
      {
	Bit8u newid = (*value >> 24) & APIC_ID_MASK;
	BX_INFO(("IOAPIC: setting id to 0x%x", newid));
	set_id (newid);
	return;
      }
    case 0x01: // version
    case 0x02: // arbitration id
      BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
      return;
    default:
      int index = (ioregsel - 0x10) >> 1;
      if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
	bx_io_redirect_entry_t *entry = ioredtbl + index;
	if (ioregsel&1)
	  entry->set_hi_part(*value);
	else
	  entry->set_lo_part(*value);
	char buf[1024];
	entry->sprintf_self(buf);
	BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
	service_ioapic();
	return;
      }
      BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
  }
}

void bx_ioapic_c::set_irq_level(Bit8u int_in, bx_bool level)
{
  BX_DEBUG(("set_irq_level(): INTIN%d: level=%d", int_in, level));
  if (int_in < BX_IOAPIC_NUM_PINS) {
    Bit32u bit = 1<<int_in;
    if ((level<<int_in) != (intin & bit)) {
      bx_io_redirect_entry_t *entry = ioredtbl + int_in;
      if (entry->trigger_mode()) {
        // level triggered
        if (level) {
          intin |= bit;
          irr |= bit;
          service_ioapic();
        } else {
          intin &= ~bit;
          irr &= ~bit;
        }
      } else {
        // edge triggered
        if (level) {
          intin |= bit;
          irr |= bit;
          service_ioapic();
        } else {
          intin &= ~bit;
        }
      }
    }
  }
}

void bx_ioapic_c::receive_eoi(Bit8u vector)
{
  BX_DEBUG(("IOAPIC: received EOI for vector %d", vector));
}

void bx_ioapic_c::service_ioapic()
{
  static unsigned int stuck = 0;
  Bit8u vector = 0;
  // look in IRR and deliver any interrupts that are not masked.
  BX_DEBUG(("IOAPIC: servicing"));
  for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
    Bit32u mask = 1<<bit;
    if (irr & mask) {
      bx_io_redirect_entry_t *entry = ioredtbl + bit;
      if (! entry->is_masked()) {
        // clear irr bit and deliver
        if (entry->delivery_mode() == 7) {
          vector = DEV_pic_iac();
        } else {
          vector = entry->vector();
        }
        bx_bool done = apic_bus_deliver_interrupt(vector, entry->destination(), entry->delivery_mode(), entry->destination_mode(), entry->pin_polarity(), entry->trigger_mode());
        if (done) {
          if (! entry->trigger_mode())
            irr &= ~mask;
          entry->clear_delivery_status();
          stuck = 0;
        } else {
          entry->set_delivery_status();
          stuck++;
          if (stuck > 5)
            BX_INFO(("vector %#x stuck?", vector));
        }
      }
      else {
        BX_DEBUG(("service_ioapic(): INTIN%d is masked", bit));
      }
    }
  }
}

void bx_ioapic_c::register_state(void)
{
  bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "ioapic", "IOAPIC State", 4);
  BXRS_HEX_PARAM_SIMPLE(list, ioregsel);
  BXRS_HEX_PARAM_SIMPLE(list, intin);
  BXRS_HEX_PARAM_SIMPLE(list, irr);

  bx_list_c *table = new bx_list_c(list, "ioredtbl", BX_IOAPIC_NUM_PINS);
  for (unsigned i=0; i<BX_IOAPIC_NUM_PINS; i++) {
    char name[6];
    sprintf(name, "0x%02x", i);
    bx_list_c *entry = new bx_list_c(table, name, 2);
    ioredtbl[i].register_state(entry);
  }
}

#endif /* if BX_SUPPORT_APIC */
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_FORALL_HPP
#define MFEM_FORALL_HPP

#include "../config/config.hpp"
#include "error.hpp"
#include "backends.hpp"
#include "device.hpp"
#include "mem_manager.hpp"
#include "../linalg/dtensor.hpp"

namespace mfem
{

// Maximum size of dofs and quads in 1D.
const int MAX_D1D = 14;
const int MAX_Q1D = 14;

// MFEM pragma macros that can be used inside MFEM_FORALL macros.
#define MFEM_PRAGMA(X) _Pragma(#X)

// MFEM_UNROLL pragma macro that can be used inside MFEM_FORALL macros.
#if defined(MFEM_USE_CUDA)
#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll N)
#else
#define MFEM_UNROLL(N)
#endif

// Implementation of MFEM's "parallel for" (forall) device/host kernel
// interfaces supporting RAJA, CUDA, OpenMP, and sequential backends.

// The MFEM_FORALL wrapper
#define MFEM_FORALL(i,N,...)                             \
   ForallWrap<1>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__})

// MFEM_FORALL with a 2D CUDA block
#define MFEM_FORALL_2D(i,N,X,Y,BZ,...)                   \
   ForallWrap<2>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__},\
                 X,Y,BZ)

// MFEM_FORALL with a 3D CUDA block
#define MFEM_FORALL_3D(i,N,X,Y,Z,...)                    \
   ForallWrap<3>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__},\
                 X,Y,Z)

// MFEM_FORALL that uses the basic CPU backend when use_dev is false. See for
// example the functions in vector.cpp, where we don't want to use the mfem
// device for operations on small vectors.
#define MFEM_FORALL_SWITCH(use_dev,i,N,...)              \
   ForallWrap<1>(use_dev,N,                              \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__})

/// OpenMP backend
template <typename HBODY>
void OmpWrap(const int N, HBODY &&h_body)
{
#ifdef MFEM_USE_OPENMP
   #pragma omp parallel for
   for (int k = 0; k < N; k++)
   {
      h_body(k);
   }
#else
   MFEM_CONTRACT_VAR(N);
   MFEM_CONTRACT_VAR(h_body);
   MFEM_ABORT("OpenMP requested for MFEM but OpenMP is not enabled!");
#endif
}

/// RAJA Cuda backend
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA)

using RAJA::statement::Segs;

template <const int BLOCKS = MFEM_CUDA_BLOCKS, typename DBODY>
void RajaCudaWrap1D(const int N, DBODY &&d_body)
{
   //true denotes asynchronous kernel
   RAJA::forall<RAJA::cuda_exec<BLOCKS,true>>(RAJA::RangeSegment(0,N),d_body);
}

template <typename DBODY>
void RajaCudaWrap2D(const int N, DBODY &&d_body,
                    const int X, const int Y, const int BZ)
{
   MFEM_VERIFY(N>0, "");
   MFEM_VERIFY(BZ>0, "");
   const int G = (N+BZ-1)/BZ;
   RAJA::kernel<RAJA::KernelPolicy<
   RAJA::statement::CudaKernelAsync<
   RAJA::statement::For<0, RAJA::cuda_block_x_direct,
        RAJA::statement::For<1, RAJA::cuda_thread_x_direct,
        RAJA::statement::For<2, RAJA::cuda_thread_y_direct,
        RAJA::statement::For<3, RAJA::cuda_thread_z_direct,
        RAJA::statement::Lambda<0, Segs<0>>>>>>>>>
        (RAJA::make_tuple(RAJA::RangeSegment(0,G), RAJA::RangeSegment(0,X),
                          RAJA::RangeSegment(0,Y), RAJA::RangeSegment(0,BZ)),
         [=] RAJA_DEVICE (const int n)
   {
      const int k = n*BZ + threadIdx.z;
      if (k >= N) { return; }
      d_body(k);
   });
   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void RajaCudaWrap3D(const int N, DBODY &&d_body,
                    const int X, const int Y, const int Z)
{
   MFEM_VERIFY(N>0, "");
   RAJA::kernel<RAJA::KernelPolicy<
   RAJA::statement::CudaKernelAsync<
   RAJA::statement::For<0, RAJA::cuda_block_x_direct,
        RAJA::statement::For<1, RAJA::cuda_thread_x_direct,
        RAJA::statement::For<2, RAJA::cuda_thread_y_direct,
        RAJA::statement::For<3, RAJA::cuda_thread_z_direct,
        RAJA::statement::Lambda<0, Segs<0>>>>>>>>>
        (RAJA::make_tuple(RAJA::RangeSegment(0,N), RAJA::RangeSegment(0,X),
                          RAJA::RangeSegment(0,Y), RAJA::RangeSegment(0,Z)),
   [=] RAJA_DEVICE (const int k) { d_body(k); });
   MFEM_GPU_CHECK(cudaGetLastError());
}

#endif

/// RAJA OpenMP backend
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)

using RAJA::statement::Segs;

template <typename HBODY>
void RajaOmpWrap(const int N, HBODY &&h_body)
{
   RAJA::forall<RAJA::omp_parallel_for_exec>(RAJA::RangeSegment(0,N), h_body);
}

#endif

/// RAJA sequential loop backend
template <typename HBODY>
void RajaSeqWrap(const int N, HBODY &&h_body)
{
#ifdef MFEM_USE_RAJA
   RAJA::forall<RAJA::loop_exec>(RAJA::RangeSegment(0,N), h_body);
#else
   MFEM_CONTRACT_VAR(N);
   MFEM_CONTRACT_VAR(h_body);
   MFEM_ABORT("RAJA requested but RAJA is not enabled!");
#endif
}

/// CUDA backend
#ifdef MFEM_USE_CUDA

template <typename BODY> __global__ static
void CuKernel1D(const int N, BODY body)
{
   const int k = blockDim.x*blockIdx.x + threadIdx.x;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void CuKernel2D(const int N, BODY body, const int BZ)
{
   const int k = blockIdx.x*BZ + threadIdx.z;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void CuKernel3D(const int N, BODY body)
{
   const int k = blockIdx.x;
   if (k >= N) { return; }
   body(k);
}

template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
void CuWrap1D(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLCK-1)/BLCK;
   CuKernel1D<<<GRID,BLCK>>>(N, d_body);
   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void CuWrap2D(const int N, DBODY &&d_body,
              const int X, const int Y, const int BZ)
{
   if (N==0) { return; }
   MFEM_VERIFY(BZ>0, "");
   const int GRID = (N+BZ-1)/BZ;
   const dim3 BLCK(X,Y,BZ);
   CuKernel2D<<<GRID,BLCK>>>(N,d_body,BZ);
   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void CuWrap3D(const int N, DBODY &&d_body,
              const int X, const int Y, const int Z)
{
   if (N==0) { return; }
   const int GRID = N;
   const dim3 BLCK(X,Y,Z);
   CuKernel3D<<<GRID,BLCK>>>(N,d_body);
   MFEM_GPU_CHECK(cudaGetLastError());
}

#endif // MFEM_USE_CUDA

/// HIP backend
#ifdef MFEM_USE_HIP

template <typename BODY> __global__ static
void HipKernel1D(const int N, BODY body)
{
   const int k = hipBlockDim_x*hipBlockIdx_x + hipThreadIdx_x;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void HipKernel2D(const int N, BODY body, const int BZ)
{
   const int k = hipBlockIdx_x*BZ + hipThreadIdx_z;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void HipKernel3D(const int N, BODY body)
{
   const int k = hipBlockIdx_x;
   if (k >= N) { return; }
   body(k);
}

template <const int BLCK = MFEM_HIP_BLOCKS, typename DBODY>
void HipWrap1D(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLCK-1)/BLCK;
   hipLaunchKernelGGL(HipKernel1D,GRID,BLCK,0,0,N,d_body);
   MFEM_GPU_CHECK(hipGetLastError());
}

template <typename DBODY>
void HipWrap2D(const int N, DBODY &&d_body,
               const int X, const int Y, const int BZ)
{
   if (N==0) { return; }
   const int GRID = (N+BZ-1)/BZ;
   const dim3 BLCK(X,Y,BZ);
   hipLaunchKernelGGL(HipKernel2D,GRID,BLCK,0,0,N,d_body,BZ);
   MFEM_GPU_CHECK(hipGetLastError());
}

template <typename DBODY>
void HipWrap3D(const int N, DBODY &&d_body,
               const int X, const int Y, const int Z)
{
   if (N==0) { return; }
   const int GRID = N;
   const dim3 BLCK(X,Y,Z);
   hipLaunchKernelGGL(HipKernel3D,GRID,BLCK,0,0,N,d_body);
   MFEM_GPU_CHECK(hipGetLastError());
}

#endif // MFEM_USE_HIP

/// The forall kernel body wrapper
template <const int DIM, typename DBODY, typename HBODY>
inline void ForallWrap(const bool use_dev, const int N,
                       DBODY &&d_body, HBODY &&h_body,
                       const int X=0, const int Y=0, const int Z=0)
{
   MFEM_CONTRACT_VAR(X);
   MFEM_CONTRACT_VAR(Y);
   MFEM_CONTRACT_VAR(Z);
   MFEM_CONTRACT_VAR(d_body);
   if (!use_dev) { goto backend_cpu; }

#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA)
   // Handle all allowed CUDA backends except Backend::CUDA
   if (DIM == 1 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap3D(N, d_body, X, Y, Z); }
#endif

#ifdef MFEM_USE_CUDA
   // Handle all allowed CUDA backends
   if (DIM == 1 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap3D(N, d_body, X, Y, Z); }
#endif

#ifdef MFEM_USE_HIP
   // Handle all allowed HIP backends
   if (DIM == 1 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap3D(N, d_body, X, Y, Z); }
#endif

   if (Device::Allows(Backend::DEBUG_DEVICE)) { goto backend_cpu; }

#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
   // Handle all allowed OpenMP backends except Backend::OMP
   if (Device::Allows(Backend::OMP_MASK & ~Backend::OMP))
   { return RajaOmpWrap(N, h_body); }
#endif

#ifdef MFEM_USE_OPENMP
   // Handle all allowed OpenMP backends
   if (Device::Allows(Backend::OMP_MASK)) { return OmpWrap(N, h_body); }
#endif

#ifdef MFEM_USE_RAJA
   // Handle all allowed CPU backends except Backend::CPU
   if (Device::Allows(Backend::CPU_MASK & ~Backend::CPU))
   { return RajaSeqWrap(N, h_body); }
#endif

backend_cpu:
   // Handle Backend::CPU. This is also a fallback for any allowed backends not
   // handled above, e.g. OCCA_CPU with configuration 'occa-cpu,cpu', or
   // OCCA_OMP with configuration 'occa-omp,cpu'.
   for (int k = 0; k < N; k++) { h_body(k); }
}

} // namespace mfem

#endif // MFEM_FORALL_HPP
<commit_msg>RAJA::Kernel->RAJA::Teams<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_FORALL_HPP
#define MFEM_FORALL_HPP

#include "../config/config.hpp"
#include "error.hpp"
#include "backends.hpp"
#include "device.hpp"
#include "mem_manager.hpp"
#include "../linalg/dtensor.hpp"

namespace mfem
{

// Maximum size of dofs and quads in 1D.
const int MAX_D1D = 14;
const int MAX_Q1D = 14;

// MFEM pragma macros that can be used inside MFEM_FORALL macros.
#define MFEM_PRAGMA(X) _Pragma(#X)

// MFEM_UNROLL pragma macro that can be used inside MFEM_FORALL macros.
#if defined(MFEM_USE_CUDA)
#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll N)
#else
#define MFEM_UNROLL(N)
#endif

// Implementation of MFEM's "parallel for" (forall) device/host kernel
// interfaces supporting RAJA, CUDA, OpenMP, and sequential backends.

// The MFEM_FORALL wrapper
#define MFEM_FORALL(i,N,...)                             \
   ForallWrap<1>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__})

// MFEM_FORALL with a 2D CUDA block
#define MFEM_FORALL_2D(i,N,X,Y,BZ,...)                   \
   ForallWrap<2>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__},\
                 X,Y,BZ)

// MFEM_FORALL with a 3D CUDA block
#define MFEM_FORALL_3D(i,N,X,Y,Z,...)                    \
   ForallWrap<3>(true,N,                                 \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__},\
                 X,Y,Z)

// MFEM_FORALL that uses the basic CPU backend when use_dev is false. See for
// example the functions in vector.cpp, where we don't want to use the mfem
// device for operations on small vectors.
#define MFEM_FORALL_SWITCH(use_dev,i,N,...)              \
   ForallWrap<1>(use_dev,N,                              \
                 [=] MFEM_DEVICE (int i) {__VA_ARGS__},  \
                 [&] MFEM_LAMBDA (int i) {__VA_ARGS__})

/// OpenMP backend
template <typename HBODY>
void OmpWrap(const int N, HBODY &&h_body)
{
#ifdef MFEM_USE_OPENMP
   #pragma omp parallel for
   for (int k = 0; k < N; k++)
   {
      h_body(k);
   }
#else
   MFEM_CONTRACT_VAR(N);
   MFEM_CONTRACT_VAR(h_body);
   MFEM_ABORT("OpenMP requested for MFEM but OpenMP is not enabled!");
#endif
}

/// RAJA Cuda backend
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA)

using launch_policy =
  RAJA::expt::LaunchPolicy<RAJA::expt::null_launch_t, RAJA::expt::cuda_launch_t<false>>;

using teams_x = RAJA::expt::LoopPolicy<RAJA::loop_exec,RAJA::cuda_block_x_direct>;
using threads_z = RAJA::expt::LoopPolicy<RAJA::loop_exec,RAJA::cuda_thread_z_direct>;

template <const int BLOCKS = MFEM_CUDA_BLOCKS, typename DBODY>
void RajaCudaWrap1D(const int N, DBODY &&d_body)
{
   //true denotes asynchronous kernel
   RAJA::forall<RAJA::cuda_exec<BLOCKS,true>>(RAJA::RangeSegment(0,N),d_body);
}

template <typename DBODY>
void RajaCudaWrap2D(const int N, DBODY &&d_body,
                    const int X, const int Y, const int BZ)
{
   MFEM_VERIFY(N>0, "");
   MFEM_VERIFY(BZ>0, "");
   const int G = (N+BZ-1)/BZ;

   RAJA::expt::launch<launch_policy>(RAJA::expt::DEVICE,
     RAJA::expt::Resources(RAJA::expt::Teams(G), RAJA::expt::Threads(X, Y, BZ)),
     [=] RAJA_DEVICE (RAJA::expt::LaunchContext ctx) {

       RAJA::expt::loop<teams_x>(ctx, RAJA::RangeSegment(0, G), [&] (const int n) {

         RAJA::expt::loop<threads_z>(ctx, RAJA::RangeSegment(0, BZ), [&] (const int tz) {

             const int k = n*BZ + tz;
             if (k >= N) { return; }
             d_body(k);

           });

        });

    });

   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void RajaCudaWrap3D(const int N, DBODY &&d_body,
                    const int X, const int Y, const int Z)
{
   MFEM_VERIFY(N>0, "");

   RAJA::expt::launch<launch_policy>(RAJA::expt::DEVICE,
     RAJA::expt::Resources(RAJA::expt::Teams(N), RAJA::expt::Threads(X, Y, Z)),
     [=] RAJA_DEVICE (RAJA::expt::LaunchContext ctx) {

     RAJA::expt::loop<teams_x>(ctx, RAJA::RangeSegment(0, N), d_body);

    });

   MFEM_GPU_CHECK(cudaGetLastError());
}

#endif

/// RAJA OpenMP backend
#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)

using RAJA::Segs;

template <typename HBODY>
void RajaOmpWrap(const int N, HBODY &&h_body)
{
   RAJA::forall<RAJA::omp_parallel_for_exec>(RAJA::RangeSegment(0,N), h_body);
}

#endif

/// RAJA sequential loop backend
template <typename HBODY>
void RajaSeqWrap(const int N, HBODY &&h_body)
{
#ifdef MFEM_USE_RAJA
   RAJA::forall<RAJA::loop_exec>(RAJA::RangeSegment(0,N), h_body);
#else
   MFEM_CONTRACT_VAR(N);
   MFEM_CONTRACT_VAR(h_body);
   MFEM_ABORT("RAJA requested but RAJA is not enabled!");
#endif
}

/// CUDA backend
#ifdef MFEM_USE_CUDA

template <typename BODY> __global__ static
void CuKernel1D(const int N, BODY body)
{
   const int k = blockDim.x*blockIdx.x + threadIdx.x;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void CuKernel2D(const int N, BODY body, const int BZ)
{
   const int k = blockIdx.x*BZ + threadIdx.z;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void CuKernel3D(const int N, BODY body)
{
   const int k = blockIdx.x;
   if (k >= N) { return; }
   body(k);
}

template <const int BLCK = MFEM_CUDA_BLOCKS, typename DBODY>
void CuWrap1D(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLCK-1)/BLCK;
   CuKernel1D<<<GRID,BLCK>>>(N, d_body);
   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void CuWrap2D(const int N, DBODY &&d_body,
              const int X, const int Y, const int BZ)
{
   if (N==0) { return; }
   MFEM_VERIFY(BZ>0, "");
   const int GRID = (N+BZ-1)/BZ;
   const dim3 BLCK(X,Y,BZ);
   CuKernel2D<<<GRID,BLCK>>>(N,d_body,BZ);
   MFEM_GPU_CHECK(cudaGetLastError());
}

template <typename DBODY>
void CuWrap3D(const int N, DBODY &&d_body,
              const int X, const int Y, const int Z)
{
   if (N==0) { return; }
   const int GRID = N;
   const dim3 BLCK(X,Y,Z);
   CuKernel3D<<<GRID,BLCK>>>(N,d_body);
   MFEM_GPU_CHECK(cudaGetLastError());
}

#endif // MFEM_USE_CUDA

/// HIP backend
#ifdef MFEM_USE_HIP

template <typename BODY> __global__ static
void HipKernel1D(const int N, BODY body)
{
   const int k = hipBlockDim_x*hipBlockIdx_x + hipThreadIdx_x;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void HipKernel2D(const int N, BODY body, const int BZ)
{
   const int k = hipBlockIdx_x*BZ + hipThreadIdx_z;
   if (k >= N) { return; }
   body(k);
}

template <typename BODY> __global__ static
void HipKernel3D(const int N, BODY body)
{
   const int k = hipBlockIdx_x;
   if (k >= N) { return; }
   body(k);
}

template <const int BLCK = MFEM_HIP_BLOCKS, typename DBODY>
void HipWrap1D(const int N, DBODY &&d_body)
{
   if (N==0) { return; }
   const int GRID = (N+BLCK-1)/BLCK;
   hipLaunchKernelGGL(HipKernel1D,GRID,BLCK,0,0,N,d_body);
   MFEM_GPU_CHECK(hipGetLastError());
}

template <typename DBODY>
void HipWrap2D(const int N, DBODY &&d_body,
               const int X, const int Y, const int BZ)
{
   if (N==0) { return; }
   const int GRID = (N+BZ-1)/BZ;
   const dim3 BLCK(X,Y,BZ);
   hipLaunchKernelGGL(HipKernel2D,GRID,BLCK,0,0,N,d_body,BZ);
   MFEM_GPU_CHECK(hipGetLastError());
}

template <typename DBODY>
void HipWrap3D(const int N, DBODY &&d_body,
               const int X, const int Y, const int Z)
{
   if (N==0) { return; }
   const int GRID = N;
   const dim3 BLCK(X,Y,Z);
   hipLaunchKernelGGL(HipKernel3D,GRID,BLCK,0,0,N,d_body);
   MFEM_GPU_CHECK(hipGetLastError());
}

#endif // MFEM_USE_HIP

/// The forall kernel body wrapper
template <const int DIM, typename DBODY, typename HBODY>
inline void ForallWrap(const bool use_dev, const int N,
                       DBODY &&d_body, HBODY &&h_body,
                       const int X=0, const int Y=0, const int Z=0)
{
   MFEM_CONTRACT_VAR(X);
   MFEM_CONTRACT_VAR(Y);
   MFEM_CONTRACT_VAR(Z);
   MFEM_CONTRACT_VAR(d_body);
   if (!use_dev) { goto backend_cpu; }

#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA)
   // Handle all allowed CUDA backends except Backend::CUDA
   if (DIM == 1 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::CUDA_MASK & ~Backend::CUDA))
   { return RajaCudaWrap3D(N, d_body, X, Y, Z); }
#endif

#ifdef MFEM_USE_CUDA
   // Handle all allowed CUDA backends
   if (DIM == 1 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::CUDA_MASK))
   { return CuWrap3D(N, d_body, X, Y, Z); }
#endif

#ifdef MFEM_USE_HIP
   // Handle all allowed HIP backends
   if (DIM == 1 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap1D(N, d_body); }

   if (DIM == 2 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap2D(N, d_body, X, Y, Z); }

   if (DIM == 3 && Device::Allows(Backend::HIP_MASK))
   { return HipWrap3D(N, d_body, X, Y, Z); }
#endif

   if (Device::Allows(Backend::DEBUG_DEVICE)) { goto backend_cpu; }

#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP)
   // Handle all allowed OpenMP backends except Backend::OMP
   if (Device::Allows(Backend::OMP_MASK & ~Backend::OMP))
   { return RajaOmpWrap(N, h_body); }
#endif

#ifdef MFEM_USE_OPENMP
   // Handle all allowed OpenMP backends
   if (Device::Allows(Backend::OMP_MASK)) { return OmpWrap(N, h_body); }
#endif

#ifdef MFEM_USE_RAJA
   // Handle all allowed CPU backends except Backend::CPU
   if (Device::Allows(Backend::CPU_MASK & ~Backend::CPU))
   { return RajaSeqWrap(N, h_body); }
#endif

backend_cpu:
   // Handle Backend::CPU. This is also a fallback for any allowed backends not
   // handled above, e.g. OCCA_CPU with configuration 'occa-cpu,cpu', or
   // OCCA_OMP with configuration 'occa-omp,cpu'.
   for (int k = 0; k < N; k++) { h_body(k); }
}

} // namespace mfem

#endif // MFEM_FORALL_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Rene Herthel
 * Copyright (C) 2017 Jonas Fuhrmann
 *
 * This file is subject to the terms and conditions of the MIT License.
 * See the file LICENSE in the top level directory for more details.
 */

/**
 * @ingroup    height_measurement
 * @{
 *
 * @brief      Service function declaration of the HeightMeasurement component
 *
 * @author     Rene Herthel <rene.herthel@haw-hamburg.de>
 * @author     Jonas Fuhrmann <jonas.fuhrmann@haw-hamburg.de>
 */

#include "HeightMeasurementService.h"
#include "HeightMeasurementHal.h"
#include "Logger.h"
#include "LogScope.h"

#include <chrono>
#include <algorithm>

/*
 * @brief Macros to check if the measured data is in range of the corresponding state.
 *
 * @param [DATA] The measured data.
 * @param [CAL]  The reference value of the calibrated data.
 */
#define RANGE(DATA, CAL)    (((DATA - DELTA_VAL) < CAL) && ((DATA + DELTA_VAL) > CAL))

/*
 * @brief
 */
#define AMOUNT_OF_SIGNALS (6)

/*
 * @brief
 */
#define AMOUNT_OF_SAMPLES (50)

HeightMeasurementService::HeightMeasurementService(int receive_chid, int send_chid, CalibrationData *calibrationDataPtr)
    :    stateMachine(new HeightContext(send_chid, this))
    ,    calibrationDataPtr(calibrationDataPtr)
    ,    receive_chid(receive_chid)
{
    // Set this to true, so the statemachine thread will run his superloop.
    statemachineIsRunning = true;
    // Creates the thread for the statemachine with the receive channel to listen on it.
    stateMachineThread = std::thread(&HeightMeasurementService::stateMachineTask, this, receive_chid);
}

HeightMeasurementService::~HeightMeasurementService() {
    delete stateMachine;
}

void HeightMeasurementService::startMeasuring() {
    // Set this true, so the measurement thread will run his suoperloop.
    measurementIsRunning = true;
    // Creates the thread for the measurement with the receive channel to send on it.
    measurementThread = std::thread(&HeightMeasurementService::measuringTask, this, receive_chid);
}

void HeightMeasurementService::stopMeasuring() {
    measurementIsRunning = false;
}

void HeightMeasurementService::measuringTask(int receive_chid) {
    LOG_SCOPE;
    LOG_SET_LEVEL(DEBUG);
    LOG_DEBUG << "[HeightMeasurementService] measuringTask() Thread started\n";

    int16_t data = 0;             /*< The current measured data.*/
    Signal state = START;         /*< The current state of the statemachine.*/
    Signal oldState = state;      /*< The old state of the statemachine.*/
    HeightMeasurementHal hal;     /*< The hal object to access the HW.*/
    int err = 0;                  /*< Return value of msgSend.*/

    // Connect to the receive channel for sending pulse-messages on it.
    int coid = ConnectAttach_r(ND_LOCAL_NODE, 0, receive_chid, 0, 0);

    // Do error handling, if there is no channel available.
    if (coid < 0) {
        // TODO: Error handling.
        LOG_DEBUG << "[HeightMeasurementService] measuringTask() ConnectAttach_r failed\n";
    }

    /* Check if the current measured data is in a valid range of the
     * corresponding calibrated data. If it is so, send a signal to the receive-
     * channel, where the statemachine is listening and will do the next
     * transition.
     */
    int counters[AMOUNT_OF_SIGNALS] = {0};
    while (measurementIsRunning) {

        int inRow = 0;
        int heighestCount = 0;
        int heighestCountIndex = 0;
        Signal newSample = state;
        Signal oldSample = START;

        for (int i = 0; i < 64; i++) {
            hal.read(data);
            dataInRange(&newSample, data);

            if (oldSample != START && newSample == oldSample) {
                inRow++;

                if (inRow >= 8) {
                    counters[newSample]++;

                    if (counters[newSample] > heighestCount) {
                    	heighestCount = counters[newSample];
                    	heighestCountIndex = newSample;
                    }

                    inRow = 0;
                }
            }
            else {
            	inRow = 0;
            }

            oldSample = newSample;
        }

        state = Signal(heighestCountIndex);

    	/*
    	int currentCount = 0;
    	Signal tmpState = state;

    	for (int i = 0; i < AMOUNT_OF_SAMPLES; i++) {

			hal.read(data);
			dataInRange(&tmpState, data);

			if(tmpState != oldState) {

                if (++counters[tmpState] > currentCount) {

                    currentCount = counters[tmpState];
                    state = tmpState;
                }
			}

			//std::this_thread::sleep_for(std::chrono::microseconds(50));
    	}
    	*/

        // But send only a message if there is a new state.
        if (state != oldState) {
            err = MsgSendPulse_r(coid, sched_get_priority_min(0), 0, state);

            if (err < 0) {
                // TODO Error handling.
                LOG_DEBUG << "[HeightMeasurementService] measuringTask() MsgSendPulse_r failed.\n";
            }

            LOG_DEBUG << "[HeightMeasurementService] send measuring signal: " << state << "\n";
        }

        // Remember the current state as old state for the next loop.
        oldState = state;

        // Reset the counters
        std::fill(counters, counters + AMOUNT_OF_SIGNALS, 0);
    }

    LOG_DEBUG << "[HeightMeasurementService] measuringTask() Leaves superloop\n";
}

void HeightMeasurementService::dataInRange(Signal *state, int16_t data) {
    if (RANGE(data, REF_HEIGHT_VAL)) {
        *state = REF_HEIGHT;
    }
    else if (RANGE(data, HOLE_HEIGHT_VAL)) {
    	  *state = HOLE_HEIGHT;
    }
    else if (RANGE(data, SURFACE_HEIGHT_VAL)) {
    	  *state = SURFACE_HEIGHT;
    }
    else if (RANGE(data, LOW_HEIGHT_VAL)) {
    	  *state = LOW_HEIGHT;
    }
    else if (RANGE(data, HIGH_HEIGHT_VAL)) {
    	  *state = HIGH_HEIGHT;
    }
    else if (RANGE(data, INVALID_HEIGHT_VAL)){
        *state = INVALID;
    }
}

void HeightMeasurementService::stateMachineTask(int receive_chid) {
    LOG_SCOPE;
    LOG_SET_LEVEL(DEBUG);
    LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Thread started\n";

    struct _pulse pulse; /*< Structure that describes a pulse.*/

    // Wait for a new incoming pulse-message to do the next transition.
    while (statemachineIsRunning) {
        // Returns 0 on success and a negative value on error.
        int err = MsgReceivePulse_r(receive_chid, &pulse, sizeof(_pulse), NULL);

        // Do error handling, if there occurs an error.
        if (err < 0) {
            // TODO: Error handling.
            // EFAULT, EINTR, ESRCH, ETIMEDOUT -> see qnx-manual.
            LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Error on MsgReceivePulse_r\n";
        }

        LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Received pulse: " << pulse.value.sival_int << "\n";

        // Signalize the statemachine for the next transition.
        stateMachine->process((Signal) pulse.value.sival_int);
    }

    LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Leaves superloop\n";
}

/** @} */
<commit_msg>First implementation of median of three<commit_after>/*
 * Copyright (C) 2017 Rene Herthel
 * Copyright (C) 2017 Jonas Fuhrmann
 *
 * This file is subject to the terms and conditions of the MIT License.
 * See the file LICENSE in the top level directory for more details.
 */

/**
 * @ingroup    height_measurement
 * @{
 *
 * @brief      Service function declaration of the HeightMeasurement component
 *
 * @author     Rene Herthel <rene.herthel@haw-hamburg.de>
 * @author     Jonas Fuhrmann <jonas.fuhrmann@haw-hamburg.de>
 */

#include "HeightMeasurementService.h"
#include "HeightMeasurementHal.h"
#include "Logger.h"
#include "LogScope.h"

#include <chrono>
#include <algorithm>

/*
 * @brief Macros to check if the measured data is in range of the corresponding state.
 *
 * @param [DATA] The measured data.
 * @param [CAL]  The reference value of the calibrated data.
 */
#define RANGE(DATA, CAL)    (((DATA - DELTA_VAL) < CAL) && ((DATA + DELTA_VAL) > CAL))

/*
 * @brief
 */
#define AMOUNT_OF_SIGNALS (6)

/*
 * @brief
 */
#define SAMPLES_AMOUNT (30)

/*
 * @brief
 */
#define SAMPLES_WINDOW_SIZE (3)
#define SAMPLES_WINDOW_END  (SAMPLES_WINDOW_SIZE - 1)
#define SAMPLES_WINDOW_MID  (SAMPLES_WINDOW_SIZE / 2) // 1 in array on size of 3

/*
 * @brief Returns the maximum of two arguments.
 */
#define MAX(x, y)            ((x > y) ? (x) : (y))

/*
 * @brief Returns the minimum of two arguments.
 */
#define MIN(x, y)            ((x < y) ? (x) : (y))

/*
 * @brief
 */
#define MEDIAN_OF_THREE(x, y, z)     ( MAX( MIN( MAX( x, y), z), MIN(x, y)) )

HeightMeasurementService::HeightMeasurementService(int receive_chid, int send_chid, CalibrationData *calibrationDataPtr)
    :    stateMachine(new HeightContext(send_chid, this))
    ,    calibrationDataPtr(calibrationDataPtr)
    ,    receive_chid(receive_chid)
{
    // Set this to true, so the statemachine thread will run his superloop.
    statemachineIsRunning = true;
    // Creates the thread for the statemachine with the receive channel to listen on it.
    stateMachineThread = std::thread(&HeightMeasurementService::stateMachineTask, this, receive_chid);
}

HeightMeasurementService::~HeightMeasurementService() {
    delete stateMachine;
}

void HeightMeasurementService::startMeasuring() {
    // Set this true, so the measurement thread will run his suoperloop.
    measurementIsRunning = true;
    // Creates the thread for the measurement with the receive channel to send on it.
    measurementThread = std::thread(&HeightMeasurementService::measuringTask, this, receive_chid);
}

void HeightMeasurementService::stopMeasuring() {
    measurementIsRunning = false;
}

void HeightMeasurementService::measuringTask(int receive_chid) {
    LOG_SCOPE;
    LOG_SET_LEVEL(DEBUG);
    LOG_DEBUG << "[HeightMeasurementService] measuringTask() Thread started\n";

    int16_t data = 0;             /*< The current measured data.*/
    Signal state = START;         /*< The current state of the statemachine.*/
    Signal oldState = state;      /*< The old state of the statemachine.*/
    HeightMeasurementHal hal;     /*< The hal object to access the HW.*/
    int err = 0;                  /*< Return value of msgSend.*/

    // Connect to the receive channel for sending pulse-messages on it.
    int coid = ConnectAttach_r(ND_LOCAL_NODE, 0, receive_chid, 0, 0);

    // Do error handling, if there is no channel available.
    if (coid < 0) {
        // TODO: Error handling.
        LOG_DEBUG << "[HeightMeasurementService] measuringTask() ConnectAttach_r failed\n";
    }

    /* Check if the current measured data is in a valid range of the
     * corresponding calibrated data. If it is so, send a signal to the receive-
     * channel, where the statemachine is listening and will do the next
     * transition.
     */
    int counters[AMOUNT_OF_SIGNALS] = {0};
    int window[SAMPLES_WINDOW_SIZE]
    while (measurementIsRunning) {

        for (int i = 0; i < AMOUNT_OF_SAMPLES; i++) {

            hal.read(data);

            // Shift the data to the left by one.
            memmove(window, window + 1, sizeof(window) - sizeof(*window));

            /* Put the new data at the end of the window.
             *
             *        +----+----+----+ ... +----+
             * OUT << | 0  | 1  |  2 | ... | N  | << IN
             *        +----+----+----+ ... +----+
             */
            window[SAMPLES_WINDOW_END] = data;

            /* Calculate the median of three from the window.
             * example:
             * MAX( MIN ( MAX (3, 5), 4), MIN(3, 5))
             * MAX( MIN (5 , 4), 3)
             * MAX( 4, 3)
             * 4 <- median
             */
            int median = MEDIAN_OF_THREE(window[0], window[1], window[2]);

            dataInRange(&state, median);

            counters[state]++;
        }

        // TODO: get highest state?

        /*
        int inRow = 0;
        int heighestCount = 0;
        int heighestCountIndex = 0;
        Signal newSample = state;
        Signal oldSample = START;

        for (int i = 0; i < 64; i++) {
            hal.read(data);
            dataInRange(&newSample, data);

            if (oldSample != START && newSample == oldSample) {
                inRow++;

                if (inRow >= 8) {
                    counters[newSample]++;

                    if (counters[newSample] > heighestCount) {
                    	heighestCount = counters[newSample];
                    	heighestCountIndex = newSample;
                    }

                    inRow = 0;
                }
            }
            else {
            	inRow = 0;
            }

            oldSample = newSample;
        }

        state = Signal(heighestCountIndex);
        */

    	/*
    	int currentCount = 0;
    	Signal tmpState = state;

    	for (int i = 0; i < AMOUNT_OF_SAMPLES; i++) {
          hal.read(data);
          dataInRange(&tmpState, data);
          if(tmpState != oldState) {
                if (++counters[tmpState] > currentCount) {
                    currentCount = counters[tmpState];
                    state = tmpState;
                }
          }

          //std::this_thread::sleep_for(std::chrono::microseconds(50));
    	}
    	*/

        // But send only a message if there is a new state.
        if (state != oldState) {
            err = MsgSendPulse_r(coid, sched_get_priority_min(0), 0, state);

            if (err < 0) {
                // TODO Error handling.
                LOG_DEBUG << "[HeightMeasurementService] measuringTask() MsgSendPulse_r failed.\n";
            }

            LOG_DEBUG << "[HeightMeasurementService] send measuring signal: " << state << "\n";
        }

        // Remember the current state as old state for the next loop.
        oldState = state;

        // Reset the counters
        std::fill(counters, counters + AMOUNT_OF_SIGNALS, 0);
        std::fill(samples, samples + SAMPLES_AMOUNT, 0);
    }

    LOG_DEBUG << "[HeightMeasurementService] measuringTask() Leaves superloop\n";
}

void HeightMeasurementService::dataInRange(Signal *state, int16_t data) {
    if (RANGE(data, REF_HEIGHT_VAL)) {
        *state = REF_HEIGHT;
    }
    else if (RANGE(data, HOLE_HEIGHT_VAL)) {
    	  *state = HOLE_HEIGHT;
    }
    else if (RANGE(data, SURFACE_HEIGHT_VAL)) {
    	  *state = SURFACE_HEIGHT;
    }
    else if (RANGE(data, LOW_HEIGHT_VAL)) {
    	  *state = LOW_HEIGHT;
    }
    else if (RANGE(data, HIGH_HEIGHT_VAL)) {
    	  *state = HIGH_HEIGHT;
    }
    else if (RANGE(data, INVALID_HEIGHT_VAL)){
        *state = INVALID;
    }
}

void HeightMeasurementService::stateMachineTask(int receive_chid) {
    LOG_SCOPE;
    LOG_SET_LEVEL(DEBUG);
    LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Thread started\n";

    struct _pulse pulse; /*< Structure that describes a pulse.*/

    // Wait for a new incoming pulse-message to do the next transition.
    while (statemachineIsRunning) {
        // Returns 0 on success and a negative value on error.
        int err = MsgReceivePulse_r(receive_chid, &pulse, sizeof(_pulse), NULL);

        // Do error handling, if there occurs an error.
        if (err < 0) {
            // TODO: Error handling.
            // EFAULT, EINTR, ESRCH, ETIMEDOUT -> see qnx-manual.
            LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Error on MsgReceivePulse_r\n";
        }

        LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Received pulse: " << pulse.value.sival_int << "\n";

        // Signalize the statemachine for the next transition.
        stateMachine->process((Signal) pulse.value.sival_int);
    }

    LOG_DEBUG << "[HeightMeasurementService] stateMachineTask() Leaves superloop\n";
}

/** @} */
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include <ospray/ospray_cpp/Device.h>
#include "common/commandline/Utility.h"
#include "common/sg/SceneGraph.h"
#include "common/sg/Renderer.h"
#include "common/sg/importer/Importer.h"
#include "ospcommon/FileName.h"

#include "sg/geometry/TriangleMesh.h"

#include "widgets/imguiViewer.h"

#include <sstream>

using namespace ospray;

ospcommon::vec3f translate;
ospcommon::vec3f scale;
bool lockFirstFrame = false;
std::vector<std::string> files;
bool showGui = false;

void parseExtraParametersFromComandLine(int ac, const char **&av)
{
  for (int i = 1; i < ac; i++) {
    const std::string arg = av[i];
    if (arg == "--translate") {
      translate.x = atof(av[++i]);
      translate.y = atof(av[++i]);
      translate.z = atof(av[++i]);
    } else if (arg == "--scale") {
      scale.x = atof(av[++i]);
      scale.y = atof(av[++i]);
      scale.z = atof(av[++i]);
    } else if (arg == "--lockFirstFrame") {
      lockFirstFrame = true;
    } else if (arg == "--nogui") {
      showGui = false;
    }
    else //look for valid models
    {
      ospcommon::FileName fileName = std::string(av[i]);
      if (fileName.ext() == "obj" ||
        fileName.ext() == "osg" ||
        fileName.ext() == "ply"
        )
      {
        files.push_back(av[i]);
      }
    }
  }
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);

  ospray::imgui3D::init(&ac,av);

  auto ospObjs = parseWithDefaultParsers(ac, av);

  std::deque<ospcommon::box3f>   bbox;
  std::deque<ospray::cpp::Model> model;
  ospray::cpp::Renderer renderer;
  ospray::cpp::Camera   camera;

  std::tie(bbox, model, renderer, camera) = ospObjs;

  parseExtraParametersFromComandLine(ac, av);
  ospray::imgui3D::ImGui3DWidget::showGui = showGui;

  sg::RenderContext ctx;
  sg::NodeH root = sg::createNode("ospray");
  std::cout << root->getName() << std::endl;
  sg::NodeH rendererN = sg::createNode("renderer", "Renderer");
  root->add(rendererN);
  sg::NodeH sun =  sg::createNode("sun", "DirectionalLight");
  root["renderer"]["lights"] += sun;
  root["renderer"]["lights"]["sun"]["color"]->setValue(ospcommon::vec3f(1.f,232.f/255.f,166.f/255.f));
  root["renderer"]["lights"]["sun"]["direction"]->setValue(ospcommon::vec3f(0.462f,-1.f,-.1f));
  root["renderer"]["lights"]["sun"]["intensity"]->setValue(1.5f);
  root["renderer"]["lights"] += sg::createNode("bounce", "DirectionalLight");
  root["renderer"]["lights"]["bounce"]["color"]->setValue(ospcommon::vec3f(127.f/255.f,178.f/255.f,255.f/255.f));
  root["renderer"]["lights"]["bounce"]["direction"]->setValue(ospcommon::vec3f(-.93,-.54f,-.605f));
  root["renderer"]["lights"]["bounce"]["intensity"]->setValue(0.25f);
  root["renderer"]["lights"] += sg::createNode("ambient", "AmbientLight");
  root["renderer"]["lights"]["ambient"]["intensity"]->setValue(0.9f);
  root["renderer"]["lights"]["ambient"]["color"]->setValue(ospcommon::vec3f(174.f/255.f,218.f/255.f,255.f/255.f));
  root["renderer"]["shadowsEnabled"]->setValue(true);
  root["renderer"]["aoSamples"]->setValue(1);
  root["renderer"]["camera"]["fovy"]->setValue(60.f);

  std::shared_ptr<sg::World> world = std::static_pointer_cast<sg::World>(root["renderer"]["world"].get());
  for (auto file : files)
  {
    ospcommon::FileName fn = file;
    if (fn.ext() == "obj")
    {
      // sg::importOBJ(world, file);
      root["renderer"]["world"] += sg::createNode(fn.name(), "Importer");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
    }
    if (fn.ext() == "osg")
    {
      // root["renderer"]["world"] += createNode(file, "TriangleMesh");
      // root["renderer"]["world"][file]["fileName"]->setValue(file.str());
      // sg::NodeH osgH;
      // std::shared_ptr<sg::World> osg = sg::loadOSG(file);
      // osg->setName("world");
      // root["renderer"]["world"] = sg::NodeH(osg);
      root["renderer"]["world"] += sg::createNode(fn.name(), "VolumeImporter");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
    }
    if (fn.ext() == "ply")
    {
      root["renderer"]["world"] += sg::createNode(fn.name(), "Importer");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
      // sg::NodeH osgH;
      // sg::NodeH osg(root["renderer"]["world"]);
      // std::shared_ptr<sg::World> wsg(std::dynamic_pointer_cast<sg::World>(osg.get()));
      // sg::importPLY(wsg, file);
      // osg->setName("world");
      // osg->setType("world");
      // root["renderer"]["world"] = sg::NodeH(osg.get());
    }
  }

  bbox.push_back(std::static_pointer_cast<sg::World>(root["renderer"]["world"].get())->getBounds());
  //add plane
  osp::vec3f *vertices = new osp::vec3f[4];
  float ps = bbox[0].upper.x*5.f;
  float py = bbox[0].lower.z-0.01f;
  // vertices[0] = osp::vec3f{-ps, -ps, py};
  // vertices[1] = osp::vec3f{-ps,  ps, py};
  // vertices[2] = osp::vec3f{ ps, -ps, py};
  // vertices[3] = osp::vec3f{ ps,  ps, py};

  py = bbox[0].lower.y-0.01f;
  vertices[0] = osp::vec3f{-ps, py, -ps};
  vertices[1] = osp::vec3f{-ps, py, ps};
  vertices[2] = osp::vec3f{ps, py, -ps};
  vertices[3] = osp::vec3f{ps, py, ps};
  auto position = std::shared_ptr<sg::DataBuffer>(new sg::DataArray3f((ospcommon::vec3f*)&vertices[0],size_t(4),false));
  osp::vec3i *triangles = new osp::vec3i[2];
  triangles[0] = osp::vec3i{0,1,2};
  triangles[1] = osp::vec3i{1,2,3};
  auto index = std::shared_ptr<sg::DataBuffer>(new sg::DataArray3i((ospcommon::vec3i*)&triangles[0],size_t(2),false));
  root["renderer"]["world"] += sg::createNode("plane", "InstanceGroup");
  root["renderer"]["world"]["plane"] += sg::createNode("mesh", "TriangleMesh");
  std::shared_ptr<sg::TriangleMesh> plane =
    std::static_pointer_cast<sg::TriangleMesh>(root["renderer"]["world"]["plane"]["mesh"].get());
  plane->vertex = position;
  plane->index = index;
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Kd"]->setValue(ospcommon::vec3f(0.8f));
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Ks"]->setValue(ospcommon::vec3f(0.6f));
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Ns"]->setValue(2.f);

  for(int i=1;i < ac; i++)
  {
    std::string arg(av[i]);
    size_t f;
    std::string value("");
    std::cout << "parsing cl arg: \"" << arg <<"\"" << std::endl;
    while ( (f = arg.find(":")) != std::string::npos || (f = arg.find(",")) != std::string::npos)
      arg[f]=' ';
    f = arg.find("=");
    if (f != std::string::npos)
    {
      value = arg.substr(f+1,arg.size());
      std::cout << "found value: " << value << std::endl;
    }
    if (value != "")
    {
      std::stringstream ss;
      ss << arg.substr(0,f);
      std::string child;
      sg::NodeH node = root;
      while (ss >> child)
      {
        std::cout << "searching for node: " << child << std::endl;
        node = node->getChildRecursive(child);
        std::cout << "found node: " << node->getName() << std::endl;
      }
      try
      {
        node->getValue<std::string>();
        node->setValue(value);
      } catch(...) {};
      try
      {
        std::stringstream vals(value);
        float x;
        vals >> x;
        node->getValue<float>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x;
        vals >> x;
        node->getValue<int>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        bool x;
        vals >> x;
        node->getValue<bool>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        float x,y,z;
        vals >> x >> y >> z;
        node->getValue<ospcommon::vec3f>();
        node->setValue(ospcommon::vec3f(x,y,z));
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x,y,z;
        vals >> x >> y;
        node->getValue<ospcommon::vec2i>();
        node->setValue(ospcommon::vec2i(x,y));
      } catch(...) {}
    }
  }

  root->traverse(ctx, "verify");
  root->traverse(ctx,"print");
  rendererN->traverse(ctx, "commit");
  rendererN->traverse(ctx, "render");

  ospray::ImGuiViewer window(bbox, model, renderer, camera, root["renderer"]);
  window.setScale(scale);
  window.setLockFirstAnimationFrame(lockFirstFrame);
  window.setTranslation(translate);
  window.create("ospImGui: OSPRay ImGui Viewer App");

  ospray::imgui3D::run();
}
<commit_msg>Windows doesn't seem to load/find the ospray_sg symbols?<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include <ospray/ospray_cpp/Device.h>
#include "common/commandline/Utility.h"
#include "common/sg/SceneGraph.h"
#include "common/sg/Renderer.h"
#include "common/sg/importer/Importer.h"
#include "ospcommon/FileName.h"

#include "sg/geometry/TriangleMesh.h"

#include "widgets/imguiViewer.h"

#include <sstream>

using namespace ospray;

ospcommon::vec3f translate;
ospcommon::vec3f scale;
bool lockFirstFrame = false;
std::vector<std::string> files;
bool showGui = false;

void parseExtraParametersFromComandLine(int ac, const char **&av)
{
  for (int i = 1; i < ac; i++) {
    const std::string arg = av[i];
    if (arg == "--translate") {
      translate.x = atof(av[++i]);
      translate.y = atof(av[++i]);
      translate.z = atof(av[++i]);
    } else if (arg == "--scale") {
      scale.x = atof(av[++i]);
      scale.y = atof(av[++i]);
      scale.z = atof(av[++i]);
    } else if (arg == "--lockFirstFrame") {
      lockFirstFrame = true;
    } else if (arg == "--nogui") {
      showGui = false;
    }
    else //look for valid models
    {
      ospcommon::FileName fileName = std::string(av[i]);
      if (fileName.ext() == "obj" ||
        fileName.ext() == "osg" ||
        fileName.ext() == "ply"
        )
      {
        files.push_back(av[i]);
      }
    }
  }
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);

#ifdef _WIN32
  // TODO: Why do we not have the sg symbols already available for us
  // since we link against it?
  loadLibrary("ospray_sg");
#endif

  ospray::imgui3D::init(&ac,av);

  auto ospObjs = parseWithDefaultParsers(ac, av);

  std::deque<ospcommon::box3f>   bbox;
  std::deque<ospray::cpp::Model> model;
  ospray::cpp::Renderer renderer;
  ospray::cpp::Camera   camera;

  std::tie(bbox, model, renderer, camera) = ospObjs;

  parseExtraParametersFromComandLine(ac, av);
  ospray::imgui3D::ImGui3DWidget::showGui = showGui;

  sg::RenderContext ctx;
  sg::NodeH root = sg::createNode("ospray");
  std::cout << root->getName() << std::endl;
  sg::NodeH rendererN = sg::createNode("renderer", "Renderer");
  root->add(rendererN);
  sg::NodeH sun =  sg::createNode("sun", "DirectionalLight");
  root["renderer"]["lights"] += sun;
  root["renderer"]["lights"]["sun"]["color"]->setValue(ospcommon::vec3f(1.f,232.f/255.f,166.f/255.f));
  root["renderer"]["lights"]["sun"]["direction"]->setValue(ospcommon::vec3f(0.462f,-1.f,-.1f));
  root["renderer"]["lights"]["sun"]["intensity"]->setValue(1.5f);
  root["renderer"]["lights"] += sg::createNode("bounce", "DirectionalLight");
  root["renderer"]["lights"]["bounce"]["color"]->setValue(ospcommon::vec3f(127.f/255.f,178.f/255.f,255.f/255.f));
  root["renderer"]["lights"]["bounce"]["direction"]->setValue(ospcommon::vec3f(-.93,-.54f,-.605f));
  root["renderer"]["lights"]["bounce"]["intensity"]->setValue(0.25f);
  root["renderer"]["lights"] += sg::createNode("ambient", "AmbientLight");
  root["renderer"]["lights"]["ambient"]["intensity"]->setValue(0.9f);
  root["renderer"]["lights"]["ambient"]["color"]->setValue(ospcommon::vec3f(174.f/255.f,218.f/255.f,255.f/255.f));
  root["renderer"]["shadowsEnabled"]->setValue(true);
  root["renderer"]["aoSamples"]->setValue(1);
  root["renderer"]["camera"]["fovy"]->setValue(60.f);

  std::shared_ptr<sg::World> world = std::static_pointer_cast<sg::World>(root["renderer"]["world"].get());
  for (auto file : files)
  {
    ospcommon::FileName fn = file;
    if (fn.ext() == "obj")
    {
      // sg::importOBJ(world, file);
      root["renderer"]["world"] += sg::createNode(fn.name(), "Importer");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
    }
    if (fn.ext() == "osg")
    {
      // root["renderer"]["world"] += createNode(file, "TriangleMesh");
      // root["renderer"]["world"][file]["fileName"]->setValue(file.str());
      // sg::NodeH osgH;
      // std::shared_ptr<sg::World> osg = sg::loadOSG(file);
      // osg->setName("world");
      // root["renderer"]["world"] = sg::NodeH(osg);
      root["renderer"]["world"] += sg::createNode(fn.name(), "VolumeImporter");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
    }
    if (fn.ext() == "ply")
    {
      root["renderer"]["world"] += sg::createNode(fn.name(), "Importer");
      root["renderer"]["world"][fn.name()]["fileName"]->setValue(fn.str());
      // sg::NodeH osgH;
      // sg::NodeH osg(root["renderer"]["world"]);
      // std::shared_ptr<sg::World> wsg(std::dynamic_pointer_cast<sg::World>(osg.get()));
      // sg::importPLY(wsg, file);
      // osg->setName("world");
      // osg->setType("world");
      // root["renderer"]["world"] = sg::NodeH(osg.get());
    }
  }

  bbox.push_back(std::static_pointer_cast<sg::World>(root["renderer"]["world"].get())->getBounds());
  //add plane
  osp::vec3f *vertices = new osp::vec3f[4];
  float ps = bbox[0].upper.x*5.f;
  float py = bbox[0].lower.z-0.01f;
  // vertices[0] = osp::vec3f{-ps, -ps, py};
  // vertices[1] = osp::vec3f{-ps,  ps, py};
  // vertices[2] = osp::vec3f{ ps, -ps, py};
  // vertices[3] = osp::vec3f{ ps,  ps, py};

  py = bbox[0].lower.y-0.01f;
  vertices[0] = osp::vec3f{-ps, py, -ps};
  vertices[1] = osp::vec3f{-ps, py, ps};
  vertices[2] = osp::vec3f{ps, py, -ps};
  vertices[3] = osp::vec3f{ps, py, ps};
  auto position = std::shared_ptr<sg::DataBuffer>(new sg::DataArray3f((ospcommon::vec3f*)&vertices[0],size_t(4),false));
  osp::vec3i *triangles = new osp::vec3i[2];
  triangles[0] = osp::vec3i{0,1,2};
  triangles[1] = osp::vec3i{1,2,3};
  auto index = std::shared_ptr<sg::DataBuffer>(new sg::DataArray3i((ospcommon::vec3i*)&triangles[0],size_t(2),false));
  root["renderer"]["world"] += sg::createNode("plane", "InstanceGroup");
  root["renderer"]["world"]["plane"] += sg::createNode("mesh", "TriangleMesh");
  std::shared_ptr<sg::TriangleMesh> plane =
    std::static_pointer_cast<sg::TriangleMesh>(root["renderer"]["world"]["plane"]["mesh"].get());
  plane->vertex = position;
  plane->index = index;
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Kd"]->setValue(ospcommon::vec3f(0.8f));
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Ks"]->setValue(ospcommon::vec3f(0.6f));
  root["renderer"]["world"]["plane"]["mesh"]["material"]["Ns"]->setValue(2.f);

  for(int i=1;i < ac; i++)
  {
    std::string arg(av[i]);
    size_t f;
    std::string value("");
    std::cout << "parsing cl arg: \"" << arg <<"\"" << std::endl;
    while ( (f = arg.find(":")) != std::string::npos || (f = arg.find(",")) != std::string::npos)
      arg[f]=' ';
    f = arg.find("=");
    if (f != std::string::npos)
    {
      value = arg.substr(f+1,arg.size());
      std::cout << "found value: " << value << std::endl;
    }
    if (value != "")
    {
      std::stringstream ss;
      ss << arg.substr(0,f);
      std::string child;
      sg::NodeH node = root;
      while (ss >> child)
      {
        std::cout << "searching for node: " << child << std::endl;
        node = node->getChildRecursive(child);
        std::cout << "found node: " << node->getName() << std::endl;
      }
      try
      {
        node->getValue<std::string>();
        node->setValue(value);
      } catch(...) {};
      try
      {
        std::stringstream vals(value);
        float x;
        vals >> x;
        node->getValue<float>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x;
        vals >> x;
        node->getValue<int>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        bool x;
        vals >> x;
        node->getValue<bool>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        float x,y,z;
        vals >> x >> y >> z;
        node->getValue<ospcommon::vec3f>();
        node->setValue(ospcommon::vec3f(x,y,z));
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x,y,z;
        vals >> x >> y;
        node->getValue<ospcommon::vec2i>();
        node->setValue(ospcommon::vec2i(x,y));
      } catch(...) {}
    }
  }

  root->traverse(ctx, "verify");
  root->traverse(ctx,"print");
  rendererN->traverse(ctx, "commit");
  rendererN->traverse(ctx, "render");

  ospray::ImGuiViewer window(bbox, model, renderer, camera, root["renderer"]);
  window.setScale(scale);
  window.setLockFirstAnimationFrame(lockFirstFrame);
  window.setTranslation(translate);
  window.create("ospImGui: OSPRay ImGui Viewer App");

  ospray::imgui3D::run();
}
<|endoftext|>