<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema_fwd.hh"
#include "query-request.hh"
#include "mutation_fragment.hh"
#include "partition_version.hh"
#include "tracing/tracing.hh"
#include "row_cache.hh"

namespace cache {

/*
* Represent a flat reader to the underlying source.
* This reader automatically makes sure that it's up to date with all cache updates
*/
class autoupdating_underlying_reader final {
    row_cache& _cache;
    read_context& _read_context;
    flat_mutation_reader_opt _reader;
    utils::phased_barrier::phase_type _reader_creation_phase = 0;
    dht::partition_range _range = { };
    std::optional<dht::decorated_key> _last_key;
    std::optional<dht::decorated_key> _new_last_key;
public:
    autoupdating_underlying_reader(row_cache& cache, read_context& context)
        : _cache(cache)
        , _read_context(context)
    { }
    future<mutation_fragment_opt> move_to_next_partition(db::timeout_clock::time_point timeout) {
        _last_key = std::move(_new_last_key);
        auto start = population_range_start();
        auto phase = _cache.phase_of(start);
        if (!_reader || _reader_creation_phase != phase) {
            if (_last_key) {
                auto cmp = dht::ring_position_comparator(*_cache._schema);
                auto&& new_range = _range.split_after(*_last_key, cmp);
                if (!new_range) {
                    _reader = {};
                    return make_ready_future<mutation_fragment_opt>();
                }
                _range = std::move(*new_range);
                _last_key = {};
            }
            if (_reader) {
                ++_cache._tracker._stats.underlying_recreations;
            }
            auto& snap = _cache.snapshot_for_phase(phase);
            _reader = {}; // See issue #2644
            _reader = _cache.create_underlying_reader(_read_context, snap, _range);
            _reader_creation_phase = phase;
        }

      return _reader->next_partition().then([this, timeout] {
        if (_reader->is_end_of_stream() && _reader->is_buffer_empty()) {
            return make_ready_future<mutation_fragment_opt>();
        }
        return (*_reader)(timeout).then([this] (auto&& mfopt) {
            if (mfopt) {
                assert(mfopt->is_partition_start());
                _new_last_key = mfopt->as_partition_start().key();
            }
            return std::move(mfopt);
        });
      });
    }
    future<> fast_forward_to(dht::partition_range&& range, db::timeout_clock::time_point timeout) {
        auto snapshot_and_phase = _cache.snapshot_of(dht::ring_position_view::for_range_start(_range));
        return fast_forward_to(std::move(range), snapshot_and_phase.snapshot, snapshot_and_phase.phase, timeout);
    }
    future<> fast_forward_to(dht::partition_range&& range, mutation_source& snapshot, row_cache::phase_type phase, db::timeout_clock::time_point timeout) {
        _range = std::move(range);
        _last_key = { };
        _new_last_key = { };
        if (_reader) {
            if (_reader_creation_phase == phase) {
                ++_cache._tracker._stats.underlying_partition_skips;
                return _reader->fast_forward_to(_range, timeout);
            } else {
                ++_cache._tracker._stats.underlying_recreations;
                _reader = {}; // See issue #2644
            }
        }
        _reader = _cache.create_underlying_reader(_read_context, snapshot, _range);
        _reader_creation_phase = phase;
        return make_ready_future<>();
    }
    utils::phased_barrier::phase_type creation_phase() const {
        return _reader_creation_phase;
    }
    const dht::partition_range& range() const {
        return _range;
    }
    flat_mutation_reader& underlying() { return *_reader; }
    dht::ring_position_view population_range_start() const {
        return _last_key ? dht::ring_position_view::for_after_key(*_last_key)
                         : dht::ring_position_view::for_range_start(_range);
    }
};

class read_context final : public enable_lw_shared_from_this<read_context> {
    row_cache& _cache;
    schema_ptr _schema;
    reader_permit _permit;
    const dht::partition_range& _range;
    const query::partition_slice& _slice;
    const io_priority_class& _pc;
    tracing::trace_state_ptr _trace_state;
    mutation_reader::forwarding _fwd_mr;
    bool _range_query;
    // When reader enters a partition, it must be set up for reading that
    // partition from the underlying mutation source (_underlying) in one of two ways:
    //
    //  1) either _underlying is already in that partition
    //
    //  2) _underlying is before the partition, then _underlying_snapshot and _key
    //     are set so that _underlying_flat can be fast forwarded to the right partition.
    //
    autoupdating_underlying_reader _underlying;
    uint64_t _underlying_created = 0;

    mutation_source_opt _underlying_snapshot;
    dht::partition_range _sm_range;
    std::optional<dht::decorated_key> _key;
    row_cache::phase_type _phase;
public:
    read_context(row_cache& cache,
            schema_ptr schema,
            reader_permit permit,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            mutation_reader::forwarding fwd_mr)
        : _cache(cache)
        , _schema(std::move(schema))
        , _permit(std::move(permit))
        , _range(range)
        , _slice(slice)
        , _pc(pc)
        , _trace_state(std::move(trace_state))
        , _fwd_mr(fwd_mr)
        , _range_query(!query::is_single_partition(range))
        , _underlying(_cache, *this)
    {
        ++_cache._tracker._stats.reads;
        if (!_range_query) {
            _key = range.start()->value().as_decorated_key();
        }
    }
    ~read_context() {
        ++_cache._tracker._stats.reads_done;
        if (_underlying_created) {
            _cache._stats.reads_with_misses.mark();
            ++_cache._tracker._stats.reads_with_misses;
        } else {
            _cache._stats.reads_with_no_misses.mark();
        }
    }
    read_context(const read_context&) = delete;
    row_cache& cache() { return _cache; }
    const schema_ptr& schema() const { return _schema; }
    reader_permit permit() const { return _permit; }
    const dht::partition_range& range() const { return _range; }
    const query::partition_slice& slice() const { return _slice; }
    const io_priority_class& pc() const { return _pc; }
    tracing::trace_state_ptr trace_state() const { return _trace_state; }
    mutation_reader::forwarding fwd_mr() const { return _fwd_mr; }
    bool is_range_query() const { return _range_query; }
    autoupdating_underlying_reader& underlying() { return _underlying; }
    row_cache::phase_type phase() const { return _phase; }
    const dht::decorated_key& key() const { return *_key; }
    void on_underlying_created() { ++_underlying_created; }
    bool digest_requested() const { return _slice.options.contains<query::partition_slice::option::with_digest>(); }
public:
    future<> ensure_underlying(db::timeout_clock::time_point timeout) {
        if (_underlying_snapshot) {
            return create_underlying(true, timeout);
        }
        return make_ready_future<>();
    }
public:
    future<> create_underlying(bool skip_first_fragment, db::timeout_clock::time_point timeout);
    void enter_partition(const dht::decorated_key& dk, mutation_source& snapshot, row_cache::phase_type phase) {
        _phase = phase;
        _underlying_snapshot = snapshot;
        _key = dk;
    }
    void enter_partition(const dht::decorated_key& dk, row_cache::phase_type phase) {
        _phase = phase;
        _underlying_snapshot = {};
        _key = dk;
    }
};

}
<commit_msg>read_context: skip first fragment in ensure_underlying<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema_fwd.hh"
#include "query-request.hh"
#include "mutation_fragment.hh"
#include "partition_version.hh"
#include "tracing/tracing.hh"
#include "row_cache.hh"

namespace cache {

/*
* Represent a flat reader to the underlying source.
* This reader automatically makes sure that it's up to date with all cache updates
*/
class autoupdating_underlying_reader final {
    row_cache& _cache;
    read_context& _read_context;
    flat_mutation_reader_opt _reader;
    utils::phased_barrier::phase_type _reader_creation_phase = 0;
    dht::partition_range _range = { };
    std::optional<dht::decorated_key> _last_key;
    std::optional<dht::decorated_key> _new_last_key;
public:
    autoupdating_underlying_reader(row_cache& cache, read_context& context)
        : _cache(cache)
        , _read_context(context)
    { }
    future<mutation_fragment_opt> move_to_next_partition(db::timeout_clock::time_point timeout) {
        _last_key = std::move(_new_last_key);
        auto start = population_range_start();
        auto phase = _cache.phase_of(start);
        if (!_reader || _reader_creation_phase != phase) {
            if (_last_key) {
                auto cmp = dht::ring_position_comparator(*_cache._schema);
                auto&& new_range = _range.split_after(*_last_key, cmp);
                if (!new_range) {
                    _reader = {};
                    return make_ready_future<mutation_fragment_opt>();
                }
                _range = std::move(*new_range);
                _last_key = {};
            }
            if (_reader) {
                ++_cache._tracker._stats.underlying_recreations;
            }
            auto& snap = _cache.snapshot_for_phase(phase);
            _reader = {}; // See issue #2644
            _reader = _cache.create_underlying_reader(_read_context, snap, _range);
            _reader_creation_phase = phase;
        }

      return _reader->next_partition().then([this, timeout] {
        if (_reader->is_end_of_stream() && _reader->is_buffer_empty()) {
            return make_ready_future<mutation_fragment_opt>();
        }
        return (*_reader)(timeout).then([this] (auto&& mfopt) {
            if (mfopt) {
                assert(mfopt->is_partition_start());
                _new_last_key = mfopt->as_partition_start().key();
            }
            return std::move(mfopt);
        });
      });
    }
    future<> fast_forward_to(dht::partition_range&& range, db::timeout_clock::time_point timeout) {
        auto snapshot_and_phase = _cache.snapshot_of(dht::ring_position_view::for_range_start(_range));
        return fast_forward_to(std::move(range), snapshot_and_phase.snapshot, snapshot_and_phase.phase, timeout);
    }
    future<> fast_forward_to(dht::partition_range&& range, mutation_source& snapshot, row_cache::phase_type phase, db::timeout_clock::time_point timeout) {
        _range = std::move(range);
        _last_key = { };
        _new_last_key = { };
        if (_reader) {
            if (_reader_creation_phase == phase) {
                ++_cache._tracker._stats.underlying_partition_skips;
                return _reader->fast_forward_to(_range, timeout);
            } else {
                ++_cache._tracker._stats.underlying_recreations;
                _reader = {}; // See issue #2644
            }
        }
        _reader = _cache.create_underlying_reader(_read_context, snapshot, _range);
        _reader_creation_phase = phase;
        return make_ready_future<>();
    }
    utils::phased_barrier::phase_type creation_phase() const {
        return _reader_creation_phase;
    }
    const dht::partition_range& range() const {
        return _range;
    }
    flat_mutation_reader& underlying() { return *_reader; }
    dht::ring_position_view population_range_start() const {
        return _last_key ? dht::ring_position_view::for_after_key(*_last_key)
                         : dht::ring_position_view::for_range_start(_range);
    }
};

class read_context final : public enable_lw_shared_from_this<read_context> {
    row_cache& _cache;
    schema_ptr _schema;
    reader_permit _permit;
    const dht::partition_range& _range;
    const query::partition_slice& _slice;
    const io_priority_class& _pc;
    tracing::trace_state_ptr _trace_state;
    mutation_reader::forwarding _fwd_mr;
    bool _range_query;
    // When reader enters a partition, it must be set up for reading that
    // partition from the underlying mutation source (_underlying) in one of two ways:
    //
    //  1) either _underlying is already in that partition
    //
    //  2) _underlying is before the partition, then _underlying_snapshot and _key
    //     are set so that _underlying_flat can be fast forwarded to the right partition.
    //
    autoupdating_underlying_reader _underlying;
    uint64_t _underlying_created = 0;

    mutation_source_opt _underlying_snapshot;
    dht::partition_range _sm_range;
    std::optional<dht::decorated_key> _key;
    row_cache::phase_type _phase;
public:
    read_context(row_cache& cache,
            schema_ptr schema,
            reader_permit permit,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            mutation_reader::forwarding fwd_mr)
        : _cache(cache)
        , _schema(std::move(schema))
        , _permit(std::move(permit))
        , _range(range)
        , _slice(slice)
        , _pc(pc)
        , _trace_state(std::move(trace_state))
        , _fwd_mr(fwd_mr)
        , _range_query(!query::is_single_partition(range))
        , _underlying(_cache, *this)
    {
        ++_cache._tracker._stats.reads;
        if (!_range_query) {
            _key = range.start()->value().as_decorated_key();
        }
    }
    ~read_context() {
        ++_cache._tracker._stats.reads_done;
        if (_underlying_created) {
            _cache._stats.reads_with_misses.mark();
            ++_cache._tracker._stats.reads_with_misses;
        } else {
            _cache._stats.reads_with_no_misses.mark();
        }
    }
    read_context(const read_context&) = delete;
    row_cache& cache() { return _cache; }
    const schema_ptr& schema() const { return _schema; }
    reader_permit permit() const { return _permit; }
    const dht::partition_range& range() const { return _range; }
    const query::partition_slice& slice() const { return _slice; }
    const io_priority_class& pc() const { return _pc; }
    tracing::trace_state_ptr trace_state() const { return _trace_state; }
    mutation_reader::forwarding fwd_mr() const { return _fwd_mr; }
    bool is_range_query() const { return _range_query; }
    autoupdating_underlying_reader& underlying() { return _underlying; }
    row_cache::phase_type phase() const { return _phase; }
    const dht::decorated_key& key() const { return *_key; }
    void on_underlying_created() { ++_underlying_created; }
    bool digest_requested() const { return _slice.options.contains<query::partition_slice::option::with_digest>(); }
public:
    future<> ensure_underlying(db::timeout_clock::time_point timeout) {
        if (_underlying_snapshot) {
            return create_underlying(false, timeout).then([this, timeout] {
                return _underlying.underlying()(timeout).discard_result();
            });
        }
        return make_ready_future<>();
    }
public:
    future<> create_underlying(bool skip_first_fragment, db::timeout_clock::time_point timeout);
    void enter_partition(const dht::decorated_key& dk, mutation_source& snapshot, row_cache::phase_type phase) {
        _phase = phase;
        _underlying_snapshot = snapshot;
        _key = dk;
    }
    void enter_partition(const dht::decorated_key& dk, row_cache::phase_type phase) {
        _phase = phase;
        _underlying_snapshot = {};
        _key = dk;
    }
};

}
<|endoftext|>


<commit_before>#include "utils/logoutput.h"
#include "commandSocket.h"
#include "fffProcessor.h"

namespace cura {

#define CURA_IDENTIFIER "CuraEngine"
const static int CMD_REQUEST_IDENTIFIER = 0x00100000;
const static int CMD_IDENTIFIER_REPLY = 0x00100001;
const static int CMD_REQUEST_VERSION = 0x00100002;
const static int CMD_VERSION_REPLY = 0x00100003;

const static int CMD_SETTING = 0x00100004;
const static int CMD_MATRIX = 0x00300002;
const static int CMD_OBJECT_COUNT = 0x00300003;
const static int CMD_OBJECT_LIST = 0x00200000;
const static int CMD_MESH_LIST = 0x00200001;
const static int CMD_VERTEX_LIST = 0x00200002;
const static int CMD_NORMAL_LIST = 0x00200003;
const static int CMD_PROCESS_MESH = 0x00300000;

const static int CMD_PROGRESS_REPORT = 0x00300001;
const static int CMD_OBJECT_PRINT_TIME = 0x00300004;
const static int CMD_OBJECT_PRINT_MATERIAL = 0x00300005;
const static int CMD_LAYER_INFO = 0x00300007;
const static int CMD_POLYGON = 0x00300006;

CommandSocket::CommandSocket(int portNr)
{
    socket.connectTo("127.0.0.1", portNr);
    object_count = 1;
    current_object_number = 0;
}

void CommandSocket::handleIncommingData(fffProcessor* processor)
{
    std::vector<PrintObject*> object_list;
    PrintObject* object = NULL;
    Mesh* mesh = NULL;
    FMatrix3x3 matrix;
    float total_print_time = 0.0;
    float total_material_amount[MAX_EXTRUDERS];
    for(int n=0; n<MAX_EXTRUDERS; n++)
        total_material_amount[n] = 0.0;

    while(true)
    {
        int command = socket.recvInt32();
        int dataSize = socket.recvInt32();
        if (dataSize < 0)
            break;
        switch(command)
        {
        case CMD_REQUEST_IDENTIFIER:
            socket.sendInt32(CMD_IDENTIFIER_REPLY);
            socket.sendInt32(strlen(CURA_IDENTIFIER) + 1);
            socket.sendAll(CURA_IDENTIFIER, strlen(CURA_IDENTIFIER) + 1);
            break;
        case CMD_SETTING:
            {
                char buffer[dataSize+1];
                buffer[dataSize] = '\0';
                socket.recvAll(buffer, dataSize);
                char* value = (buffer + strlen(buffer)) + 1;
                if ((value - buffer) < dataSize)
                {
                    processor->getSetting(buffer);
                    if (object)
                        object->setSetting(buffer, value);
                    else
                        processor->setSetting(buffer, value);
                }
            }
            break;
        case CMD_MATRIX:
            {
                for(int x=0; x<3; x++)
                    for(int y=0; y<3; y++)
                        matrix.m[x][y] = socket.recvFloat32();
            }
            break;
        case CMD_OBJECT_COUNT:
            object_count = socket.recvInt32();
            current_object_number = 0;
            break;
        case CMD_OBJECT_LIST:
            socket.recvInt32(); //Number of following CMD_MESH_LIST commands
            if (object)
            {
                object->finalize();
                object_list.push_back(object);
            }
            object = new PrintObject(processor);
            mesh = NULL;
            break;
        case CMD_MESH_LIST:
            socket.recvInt32(); //Number of following CMD_?_LIST commands that fill this mesh with data
            if (object)
            {
                object->meshes.emplace_back(object);
                mesh = &object->meshes[object->meshes.size()-1];
            }
            break;
        case CMD_VERTEX_LIST:
            if (mesh)
            {
                int faceCount = dataSize / 4 / 3 / 3;
                logError("Reading %i faces\n", faceCount);
                for(int n=0; n<faceCount; n++)
                {
                    FPoint3 fv[3];
                    socket.recvAll(fv, 4 * 3 * 3);
                    Point3 v[3];
                    v[0] = matrix.apply(fv[0]);
                    v[1] = matrix.apply(fv[1]);
                    v[2] = matrix.apply(fv[2]);
                    mesh->addFace(v[0], v[1], v[2]);
                }
            }else{
                for(int n=0; n<dataSize; n++)
                    socket.recvAll(&command, 1);
            }
            break;
        case CMD_PROCESS_MESH:
            if (object)
            {
                object->finalize();
                for(PrintObject* obj : object_list)
                    for(Mesh& m : obj->meshes)
                        object->meshes.push_back(m);
                processor->processModel(object);
                for(PrintObject* obj : object_list)
                    delete obj;
                object_list.clear();
                sendPrintTimeForObject(current_object_number, processor->getTotalPrintTime() - total_print_time);
                total_print_time = processor->getTotalPrintTime();
                for(int n=0; n<MAX_EXTRUDERS; n++)
                {
                    if (processor->getTotalFilamentUsed(n) != total_material_amount[n])
                        sendPrintMaterialForObject(current_object_number, n, processor->getTotalFilamentUsed(n) - total_material_amount[n]);
                    total_material_amount[n] = processor->getTotalFilamentUsed(n);
                }
                current_object_number++;
                if (current_object_number >= object_count)
                    socket.close();
                delete object;
                object = NULL;
            }
            break;
        default:
            logError("Unknown command: %04x (%i)\n", command, dataSize);
            for(int n=0; n<dataSize; n++)
                socket.recvAll(&command, 1);
            break;
        }
    }
    if (object)
        delete object;
}

void CommandSocket::sendLayerInfo(int layer_nr, int32_t z, int32_t height)
{
    socket.sendInt32(CMD_LAYER_INFO);
    socket.sendInt32(4 * 4);
    socket.sendInt32(current_object_number);
    socket.sendInt32(layer_nr);
    socket.sendInt32(z);
    socket.sendInt32(height);
}

void CommandSocket::sendPolygons(const char* name, int layer_nr, Polygons& polygons)
{
    int size = (strlen(name) + 1) + 3 * 4 + polygons.size() * 4;
    for(unsigned int n=0; n<polygons.size(); n++)
        size += polygons[n].size() * sizeof(Point);
    if (polygons.size() < 1)
        return;

    socket.sendInt32(CMD_POLYGON);
    socket.sendInt32(size);
    socket.sendAll(name, strlen(name) + 1);
    socket.sendInt32(current_object_number);
    socket.sendInt32(layer_nr);
    socket.sendInt32(polygons.size());
    for(unsigned int n=0; n<polygons.size(); n++)
    {
        socket.sendInt32(polygons[n].size());
        socket.sendAll(polygons[n].data(), polygons[n].size() * sizeof(Point));
    }
}

void CommandSocket::sendProgress(float amount)
{
    socket.sendInt32(CMD_PROGRESS_REPORT);
    socket.sendInt32(4);
    socket.sendFloat32(float(current_object_number) / float(object_count) + amount / float(object_count));
}

void CommandSocket::sendPrintTimeForObject(int index, float print_time)
{
    socket.sendInt32(CMD_OBJECT_PRINT_TIME);
    socket.sendInt32(8);
    socket.sendInt32(index);
    socket.sendFloat32(print_time);
}

void CommandSocket::sendPrintMaterialForObject(int index, int extruder_nr, float print_time)
{
    socket.sendInt32(CMD_OBJECT_PRINT_MATERIAL);
    socket.sendInt32(12);
    socket.sendInt32(index);
    socket.sendInt32(extruder_nr);
    socket.sendFloat32(print_time);
}

}//namespace cura
<commit_msg>Call mesh->finish so the mesh gets properly optimized and slicing is a lot faster.<commit_after>#include "utils/logoutput.h"
#include "commandSocket.h"
#include "fffProcessor.h"

namespace cura {

#define CURA_IDENTIFIER "CuraEngine"
const static int CMD_REQUEST_IDENTIFIER = 0x00100000;
const static int CMD_IDENTIFIER_REPLY = 0x00100001;
const static int CMD_REQUEST_VERSION = 0x00100002;
const static int CMD_VERSION_REPLY = 0x00100003;

const static int CMD_SETTING = 0x00100004;
const static int CMD_MATRIX = 0x00300002;
const static int CMD_OBJECT_COUNT = 0x00300003;
const static int CMD_OBJECT_LIST = 0x00200000;
const static int CMD_MESH_LIST = 0x00200001;
const static int CMD_VERTEX_LIST = 0x00200002;
const static int CMD_NORMAL_LIST = 0x00200003;
const static int CMD_PROCESS_MESH = 0x00300000;

const static int CMD_PROGRESS_REPORT = 0x00300001;
const static int CMD_OBJECT_PRINT_TIME = 0x00300004;
const static int CMD_OBJECT_PRINT_MATERIAL = 0x00300005;
const static int CMD_LAYER_INFO = 0x00300007;
const static int CMD_POLYGON = 0x00300006;

CommandSocket::CommandSocket(int portNr)
{
    socket.connectTo("127.0.0.1", portNr);
    object_count = 1;
    current_object_number = 0;
}

void CommandSocket::handleIncommingData(fffProcessor* processor)
{
    std::vector<PrintObject*> object_list;
    PrintObject* object = NULL;
    Mesh* mesh = NULL;
    FMatrix3x3 matrix;
    float total_print_time = 0.0;
    float total_material_amount[MAX_EXTRUDERS];
    for(int n=0; n<MAX_EXTRUDERS; n++)
        total_material_amount[n] = 0.0;

    while(true)
    {
        int command = socket.recvInt32();
        int dataSize = socket.recvInt32();
        if (dataSize < 0)
            break;
        switch(command)
        {
        case CMD_REQUEST_IDENTIFIER:
            socket.sendInt32(CMD_IDENTIFIER_REPLY);
            socket.sendInt32(strlen(CURA_IDENTIFIER) + 1);
            socket.sendAll(CURA_IDENTIFIER, strlen(CURA_IDENTIFIER) + 1);
            break;
        case CMD_SETTING:
            {
                char buffer[dataSize+1];
                buffer[dataSize] = '\0';
                socket.recvAll(buffer, dataSize);
                char* value = (buffer + strlen(buffer)) + 1;
                if ((value - buffer) < dataSize)
                {
                    processor->getSetting(buffer);
                    if (object)
                        object->setSetting(buffer, value);
                    else
                        processor->setSetting(buffer, value);
                }
            }
            break;
        case CMD_MATRIX:
            {
                for(int x=0; x<3; x++)
                    for(int y=0; y<3; y++)
                        matrix.m[x][y] = socket.recvFloat32();
            }
            break;
        case CMD_OBJECT_COUNT:
            object_count = socket.recvInt32();
            current_object_number = 0;
            break;
        case CMD_OBJECT_LIST:
            socket.recvInt32(); //Number of following CMD_MESH_LIST commands
            if (object)
            {
                object->finalize();
                object_list.push_back(object);
            }
            object = new PrintObject(processor);
            mesh = NULL;
            break;
        case CMD_MESH_LIST:
            socket.recvInt32(); //Number of following CMD_?_LIST commands that fill this mesh with data
            if (object)
            {
                object->meshes.emplace_back(object);
                mesh = &object->meshes[object->meshes.size()-1];
            }
            break;
        case CMD_VERTEX_LIST:
            if (mesh)
            {
                int faceCount = dataSize / 4 / 3 / 3;
                logError("Reading %i faces\n", faceCount);
                for(int n=0; n<faceCount; n++)
                {
                    FPoint3 fv[3];
                    socket.recvAll(fv, 4 * 3 * 3);
                    Point3 v[3];
                    v[0] = matrix.apply(fv[0]);
                    v[1] = matrix.apply(fv[1]);
                    v[2] = matrix.apply(fv[2]);
                    mesh->addFace(v[0], v[1], v[2]);
                }
                mesh->finish();
            }else{
                for(int n=0; n<dataSize; n++)
                    socket.recvAll(&command, 1);
            }
            break;
        case CMD_PROCESS_MESH:
            if (object)
            {
                object->finalize();
                for(PrintObject* obj : object_list)
                    for(Mesh& m : obj->meshes)
                        object->meshes.push_back(m);
                processor->processModel(object);
                for(PrintObject* obj : object_list)
                    delete obj;
                object_list.clear();
                sendPrintTimeForObject(current_object_number, processor->getTotalPrintTime() - total_print_time);
                total_print_time = processor->getTotalPrintTime();
                for(int n=0; n<MAX_EXTRUDERS; n++)
                {
                    if (processor->getTotalFilamentUsed(n) != total_material_amount[n])
                        sendPrintMaterialForObject(current_object_number, n, processor->getTotalFilamentUsed(n) - total_material_amount[n]);
                    total_material_amount[n] = processor->getTotalFilamentUsed(n);
                }
                current_object_number++;
                if (current_object_number >= object_count)
                    socket.close();
                delete object;
                object = NULL;
            }
            break;
        default:
            logError("Unknown command: %04x (%i)\n", command, dataSize);
            for(int n=0; n<dataSize; n++)
                socket.recvAll(&command, 1);
            break;
        }
    }
    if (object)
        delete object;
}

void CommandSocket::sendLayerInfo(int layer_nr, int32_t z, int32_t height)
{
    socket.sendInt32(CMD_LAYER_INFO);
    socket.sendInt32(4 * 4);
    socket.sendInt32(current_object_number);
    socket.sendInt32(layer_nr);
    socket.sendInt32(z);
    socket.sendInt32(height);
}

void CommandSocket::sendPolygons(const char* name, int layer_nr, Polygons& polygons)
{
    int size = (strlen(name) + 1) + 3 * 4 + polygons.size() * 4;
    for(unsigned int n=0; n<polygons.size(); n++)
        size += polygons[n].size() * sizeof(Point);
    if (polygons.size() < 1)
        return;

    socket.sendInt32(CMD_POLYGON);
    socket.sendInt32(size);
    socket.sendAll(name, strlen(name) + 1);
    socket.sendInt32(current_object_number);
    socket.sendInt32(layer_nr);
    socket.sendInt32(polygons.size());
    for(unsigned int n=0; n<polygons.size(); n++)
    {
        socket.sendInt32(polygons[n].size());
        socket.sendAll(polygons[n].data(), polygons[n].size() * sizeof(Point));
    }
}

void CommandSocket::sendProgress(float amount)
{
    socket.sendInt32(CMD_PROGRESS_REPORT);
    socket.sendInt32(4);
    socket.sendFloat32(float(current_object_number) / float(object_count) + amount / float(object_count));
}

void CommandSocket::sendPrintTimeForObject(int index, float print_time)
{
    socket.sendInt32(CMD_OBJECT_PRINT_TIME);
    socket.sendInt32(8);
    socket.sendInt32(index);
    socket.sendFloat32(print_time);
}

void CommandSocket::sendPrintMaterialForObject(int index, int extruder_nr, float print_time)
{
    socket.sendInt32(CMD_OBJECT_PRINT_MATERIAL);
    socket.sendInt32(12);
    socket.sendInt32(index);
    socket.sendInt32(extruder_nr);
    socket.sendFloat32(print_time);
}

}//namespace cura
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/delegates/gpu/cl/kernels/conv_weights_converter.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/common/task/util.h"
#include "tensorflow/lite/delegates/gpu/common/task/work_group_picking.h"

namespace tflite {
namespace gpu {
namespace cl {

ConverterToConvWeights::ConverterToConvWeights(
    const OperationDef& definition, const WeightsDescription& weights_desc)
    : GPUOperation(definition), weights_desc_(weights_desc) {
  code_ = GetConverterToConvWeightsCode(definition_, weights_desc_);
}

ConverterToConvWeights::ConverterToConvWeights(
    ConverterToConvWeights&& operation)
    : GPUOperation(std::move(operation)),
      weights_desc_(std::move(operation.weights_desc_)) {}

ConverterToConvWeights& ConverterToConvWeights::operator=(
    ConverterToConvWeights&& operation) {
  if (this != &operation) {
    weights_desc_ = std::move(operation.weights_desc_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

std::string ConverterToConvWeights::GetConverterToConvWeightsCode(
    const OperationDef& op_def, const WeightsDescription& conv_weights_desc) {
  AddSrcTensor("src_tensor", op_def.src_tensors[0]);
  AddDstTensor("dst_tensor", op_def.dst_tensors[0]);
  args_.AddFloat("mask_x");
  args_.AddFloat("mask_y");
  args_.AddFloat("mask_z");
  args_.AddFloat("mask_w");

  std::string c;
  c += "__kernel void main_function(\n";
  c += "$0) {\n";
  c += "  int GROUP_SIZE = " +
       std::to_string(conv_weights_desc.output_group_size) + ";\n";
  c += "  int O = get_global_id(0) * 4;\n";
  c += "  int I = get_global_id(1);\n";
  c += "  int Z = get_global_id(2);\n";
  c += "  int W = Z % args.src_tensor.Width();\n";
  c += "  int H = Z / args.src_tensor.Width();\n";
  c += "  if (O >= args.src_tensor.Batch() || I >= args.src_tensor.Slices() || "
       "H >= args.src_tensor.Height()) return;\n";
  c += "  FLT4 v0 = args.src_tensor.Read(W, H, I, O + 0);\n";
  c += "  FLT4 v1 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v2 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v3 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  if (O + 1 < args.src_tensor.Batch()) {\n";
  c += "    v1 = args.src_tensor.Read(W, H, I, O + 1);\n";
  c += "  }\n";
  c += "  if (O + 2 < args.src_tensor.Batch()) {\n";
  c += "    v2 = args.src_tensor.Read(W, H, I, O + 2);\n";
  c += "  }\n";
  c += "  if (O + 3 < args.src_tensor.Batch()) {\n";
  c += "    v3 = args.src_tensor.Read(W, H, I, O + 3);\n";
  c += "  }\n";
  c += "  if (I == args.src_tensor.Slices() - 1) {\n";
  c += "    FLT4 mask = (FLT4)(args.mask_x, args.mask_y, args.mask_z, "
       "args.mask_w);\n";
  c += "    v0 *= mask;\n";
  c += "    v1 *= mask;\n";
  c += "    v2 *= mask;\n";
  c += "    v3 *= mask;\n";
  c += "  }\n";
  c += "  FLT4 r0 = (FLT4)(v0.x, v1.x, v2.x, v3.x);\n";
  c += "  FLT4 r1 = (FLT4)(v0.y, v1.y, v2.y, v3.y);\n";
  c += "  FLT4 r2 = (FLT4)(v0.z, v1.z, v2.z, v3.z);\n";
  c += "  FLT4 r3 = (FLT4)(v0.w, v1.w, v2.w, v3.w);\n";
  c += "  int d_index = O / (GROUP_SIZE * 4);\n";
  c += "  int k_index = (O % (GROUP_SIZE * 4)) / 4;\n";
  c += "  int dst_offset = (((d_index * args.src_tensor.Height() + H) * "
       "args.src_tensor.Width() + W) * "
       "args.src_tensor.Slices() + I) * GROUP_SIZE + "
       "k_index;\n";
  c += "  int address0 = dst_offset * 4 + 0;\n";
  c += "  int address1 = dst_offset * 4 + 1;\n";
  c += "  int address2 = dst_offset * 4 + 2;\n";
  c += "  int address3 = dst_offset * 4 + 3;\n";
  c += "  args.dst_tensor.WriteLinear(r0, dst_offset * 4 + 0)\n;";
  c += "  args.dst_tensor.WriteLinear(r1, dst_offset * 4 + 1)\n;";
  c += "  args.dst_tensor.WriteLinear(r2, dst_offset * 4 + 2)\n;";
  c += "  args.dst_tensor.WriteLinear(r3, dst_offset * 4 + 3)\n;";
  c += "}\n";
  return c;
}

absl::Status ConverterToConvWeights::BindArguments(ArgumentsBinder* args) {
  float4 mask = GetMaskForLastPlane(src_[0]->Channels());
  RETURN_IF_ERROR(args->SetFloat("mask_x", mask.x));
  RETURN_IF_ERROR(args->SetFloat("mask_y", mask.y));
  RETURN_IF_ERROR(args->SetFloat("mask_z", mask.z));
  return args->SetFloat("mask_w", mask.w);
}

int3 ConverterToConvWeights::GetGridSize() const {
  const int grid_x = DivideRoundUp(
      AlignByN(src_[0]->Batch(), 4 * weights_desc_.output_group_size), 4);
  const int grid_y = src_[0]->Slices();
  const int grid_z = src_[0]->Width() * src_[0]->Height();
  return int3(grid_x, grid_y, grid_z);
}

ConverterToConvWeights CreateConverterToConvWeights(
    const OperationDef& definition, const WeightsDescription& weights_desc) {
  return ConverterToConvWeights(definition, weights_desc);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Added implementation of converter for kOICustomSpatialI4O4.<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/delegates/gpu/cl/kernels/conv_weights_converter.h"

#include <cstring>
#include <string>

#include "tensorflow/lite/delegates/gpu/common/task/util.h"
#include "tensorflow/lite/delegates/gpu/common/task/work_group_picking.h"

namespace tflite {
namespace gpu {
namespace cl {

ConverterToConvWeights::ConverterToConvWeights(
    const OperationDef& definition, const WeightsDescription& weights_desc)
    : GPUOperation(definition), weights_desc_(weights_desc) {
  code_ = GetConverterToConvWeightsCode(definition_, weights_desc_);
}

ConverterToConvWeights::ConverterToConvWeights(
    ConverterToConvWeights&& operation)
    : GPUOperation(std::move(operation)),
      weights_desc_(std::move(operation.weights_desc_)) {}

ConverterToConvWeights& ConverterToConvWeights::operator=(
    ConverterToConvWeights&& operation) {
  if (this != &operation) {
    weights_desc_ = std::move(operation.weights_desc_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

std::string ConverterToConvWeights::GetConverterToConvWeightsCode(
    const OperationDef& op_def, const WeightsDescription& conv_weights_desc) {
  AddSrcTensor("src_tensor", op_def.src_tensors[0]);
  AddDstTensor("dst_tensor", op_def.dst_tensors[0]);
  args_.AddFloat("mask_x");
  args_.AddFloat("mask_y");
  args_.AddFloat("mask_z");
  args_.AddFloat("mask_w");

  const int out_group_size =
      conv_weights_desc.layout == WeightsLayout::kOHWIOGroupI4O4
          ? conv_weights_desc.output_group_size
          : 1;

  if (conv_weights_desc.layout == WeightsLayout::kOICustomSSpatialI4O4) {
    std::vector<int32_t> remap(conv_weights_desc.spatial_remap.size());
    for (int i = 0; i < remap.size(); ++i) {
      remap[i] = conv_weights_desc.spatial_remap[i];
    }
    BufferDescriptor desc;
    desc.element_type = DataType::INT32;
    desc.element_size = 1;
    desc.memory_type = MemoryType::GLOBAL;
    desc.size = remap.size() * sizeof(int32_t);
    desc.data.resize(desc.size);
    std::memcpy(desc.data.data(), remap.data(), desc.size);
    args_.AddObject("spatial_remap",
                    absl::make_unique<BufferDescriptor>(std::move(desc)));
  }

  std::string c;
  c += "__kernel void main_function(\n";
  c += "$0) {\n";
  c += "  int GROUP_SIZE = " + std::to_string(out_group_size) + ";\n";
  c += "  int O = get_global_id(0) * 4;\n";
  c += "  int I = get_global_id(1);\n";
  c += "  int Z = get_global_id(2);\n";
  c += "  int W = Z % args.src_tensor.Width();\n";
  c += "  int H = Z / args.src_tensor.Width();\n";
  c += "  if (O >= args.src_tensor.Batch() || I >= args.src_tensor.Slices() || "
       "H >= args.src_tensor.Height()) return;\n";
  std::string x_kern = "W";
  std::string y_kern = "H";
  if (conv_weights_desc.layout == WeightsLayout::kOICustomSSpatialI4O4) {
    c += "  int spatial_linear = H * args.src_tensor.Width() + W;\n";
    c += "  int linear_remap = args.spatial_remap.Read(spatial_linear);\n";
    c += "  int w_remap = linear_remap % args.src_tensor.Width();\n";
    c += "  int h_remap = linear_remap / args.src_tensor.Width();\n";
    x_kern = "w_remap";
    y_kern = "h_remap";
  }
  const std::string coords = x_kern + ", " + y_kern;
  c += "  FLT4 v0 = args.src_tensor.Read(" + coords + ", I, O + 0);\n";
  c += "  FLT4 v1 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v2 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v3 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  if (O + 1 < args.src_tensor.Batch()) {\n";
  c += "    v1 = args.src_tensor.Read(" + coords + ", I, O + 1);\n";
  c += "  }\n";
  c += "  if (O + 2 < args.src_tensor.Batch()) {\n";
  c += "    v2 = args.src_tensor.Read(" + coords + ", I, O + 2);\n";
  c += "  }\n";
  c += "  if (O + 3 < args.src_tensor.Batch()) {\n";
  c += "    v3 = args.src_tensor.Read(" + coords + ", I, O + 3);\n";
  c += "  }\n";
  c += "  if (I == args.src_tensor.Slices() - 1) {\n";
  c += "    FLT4 mask = (FLT4)(args.mask_x, args.mask_y, args.mask_z, "
       "args.mask_w);\n";
  c += "    v0 *= mask;\n";
  c += "    v1 *= mask;\n";
  c += "    v2 *= mask;\n";
  c += "    v3 *= mask;\n";
  c += "  }\n";
  c += "  FLT4 r0 = (FLT4)(v0.x, v1.x, v2.x, v3.x);\n";
  c += "  FLT4 r1 = (FLT4)(v0.y, v1.y, v2.y, v3.y);\n";
  c += "  FLT4 r2 = (FLT4)(v0.z, v1.z, v2.z, v3.z);\n";
  c += "  FLT4 r3 = (FLT4)(v0.w, v1.w, v2.w, v3.w);\n";
  c += "  int d_index = O / (GROUP_SIZE * 4);\n";
  c += "  int k_index = (O % (GROUP_SIZE * 4)) / 4;\n";
  std::string index;
  if (conv_weights_desc.layout == WeightsLayout::kOICustomSSpatialI4O4) {
    index =
        "((d_index * args.src_tensor.Slices() + I) * args.src_tensor.Height() "
        "+ H) * args.src_tensor.Width() + W";
  } else if (conv_weights_desc.layout == WeightsLayout::kOHWIOGroupI4O4) {
    index =
        "((d_index * args.src_tensor.Height() + H) * args.src_tensor.Width() + "
        "W) * args.src_tensor.Slices() + I";
  }
  c += "  int dst_offset = (" + index + ") * GROUP_SIZE + k_index;\n";
  c += "  int address0 = dst_offset * 4 + 0;\n";
  c += "  int address1 = dst_offset * 4 + 1;\n";
  c += "  int address2 = dst_offset * 4 + 2;\n";
  c += "  int address3 = dst_offset * 4 + 3;\n";
  c += "  args.dst_tensor.WriteLinear(r0, dst_offset * 4 + 0)\n;";
  c += "  args.dst_tensor.WriteLinear(r1, dst_offset * 4 + 1)\n;";
  c += "  args.dst_tensor.WriteLinear(r2, dst_offset * 4 + 2)\n;";
  c += "  args.dst_tensor.WriteLinear(r3, dst_offset * 4 + 3)\n;";
  c += "}\n";
  return c;
}

absl::Status ConverterToConvWeights::BindArguments(ArgumentsBinder* args) {
  float4 mask = GetMaskForLastPlane(src_[0]->Channels());
  RETURN_IF_ERROR(args->SetFloat("mask_x", mask.x));
  RETURN_IF_ERROR(args->SetFloat("mask_y", mask.y));
  RETURN_IF_ERROR(args->SetFloat("mask_z", mask.z));
  return args->SetFloat("mask_w", mask.w);
}

int3 ConverterToConvWeights::GetGridSize() const {
  const int out_group_size =
      weights_desc_.layout == WeightsLayout::kOHWIOGroupI4O4
          ? weights_desc_.output_group_size
          : 1;
  const int grid_x =
      DivideRoundUp(AlignByN(src_[0]->Batch(), 4 * out_group_size), 4);
  const int grid_y = src_[0]->Slices();
  const int grid_z = src_[0]->Width() * src_[0]->Height();
  return int3(grid_x, grid_y, grid_z);
}

ConverterToConvWeights CreateConverterToConvWeights(
    const OperationDef& definition, const WeightsDescription& weights_desc) {
  return ConverterToConvWeights(definition, weights_desc);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before><commit_msg>hashspace update<commit_after><|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2013 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 "bvh4_rotate.h"

namespace embree
{
  // FIXME: fast version 19.279 ms versus slow version 21.43 ms, not much difference!

  /*! Computes half surface area of box. */
  __forceinline float halfArea3f(const BBox<ssef>& box) {
    const ssef d = box.size();
    const ssef a = d*shuffle<1,2,0,3>(d);
    return a[0]+a[1]+a[2];
  }

  size_t BVH4Rotate::rotate(BVH4* bvh, NodeRef parentRef, size_t depth)
  {
#if 1
    /*! nothing to rotate if we reached a leaf node. */
    if (parentRef.isBarrier()) return 0;
    if (parentRef.isLeaf()) return 0;
    Node* parent = parentRef.node();

    /*! rotate all children first */
    ssei cdepth;
    for (size_t c=0; c<4; c++)
      cdepth[c] = (int)rotate(bvh,parent->child(c),depth+1);

    /* compute current area of all children */
    ssef sizeX = parent->upper_x-parent->lower_x;
    ssef sizeY = parent->upper_y-parent->lower_y;
    ssef sizeZ = parent->upper_z-parent->lower_z;
    ssef childArea = sizeX*(sizeY + sizeZ) + sizeY*sizeZ;

    /*! get node bounds */
    BBox<ssef> child1_0,child1_1,child1_2,child1_3;
    parent->bounds(child1_0,child1_1,child1_2,child1_3);

    /*! Find best rotation. We pick a first child (child1) and a sub-child
      (child2child) of a different second child (child2), and swap child1
      and child2child. We perform the best such swap. */
    float bestArea = 0;
    int bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1;
    for (size_t c2=0; c2<4; c2++)
    {
      /*! ignore leaf nodes as we cannot descent into them */
      if (parent->child(c2).isBarrier()) continue;
      if (parent->child(c2).isLeaf()) continue;
      Node* child2 = parent->child(c2).node();

      /*! transpose child bounds */
      BBox<ssef> child2c0,child2c1,child2c2,child2c3;
      child2->bounds(child2c0,child2c1,child2c2,child2c3);

      /*! put child1_0 at each child2 position */
      float cost00 = halfArea3f(merge(child1_0,child2c1,child2c2,child2c3));
      float cost01 = halfArea3f(merge(child2c0,child1_0,child2c2,child2c3));
      float cost02 = halfArea3f(merge(child2c0,child2c1,child1_0,child2c3));
      float cost03 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_0));
      ssef cost0 = ssef(cost00,cost01,cost02,cost03);
      ssef min0 = vreduce_min(cost0);
      int pos0 = (int)__bsf(movemask(min0 == cost0));

      /*! put child1_1 at each child2 position */
      float cost10 = halfArea3f(merge(child1_1,child2c1,child2c2,child2c3));
      float cost11 = halfArea3f(merge(child2c0,child1_1,child2c2,child2c3));
      float cost12 = halfArea3f(merge(child2c0,child2c1,child1_1,child2c3));
      float cost13 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_1));
      ssef cost1 = ssef(cost10,cost11,cost12,cost13);
      ssef min1 = vreduce_min(cost1);
      int pos1 = (int)__bsf(movemask(min1 == cost1));

      /*! put child1_2 at each child2 position */
      float cost20 = halfArea3f(merge(child1_2,child2c1,child2c2,child2c3));
      float cost21 = halfArea3f(merge(child2c0,child1_2,child2c2,child2c3));
      float cost22 = halfArea3f(merge(child2c0,child2c1,child1_2,child2c3));
      float cost23 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_2));
      ssef cost2 = ssef(cost20,cost21,cost22,cost23);
      ssef min2 = vreduce_min(cost2);
      int pos2 = (int)__bsf(movemask(min2 == cost2));

      /*! put child1_3 at each child2 position */
      float cost30 = halfArea3f(merge(child1_3,child2c1,child2c2,child2c3));
      float cost31 = halfArea3f(merge(child2c0,child1_3,child2c2,child2c3));
      float cost32 = halfArea3f(merge(child2c0,child2c1,child1_3,child2c3));
      float cost33 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_3));
      ssef cost3 = ssef(cost30,cost31,cost32,cost33);
      ssef min3 = vreduce_min(cost3);
      int pos3 = (int)__bsf(movemask(min3 == cost3));

      /*! find best other child */
      ssef area0123 = ssef(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)) - ssef(childArea[c2]);
      int pos[4] = { pos0,pos1,pos2,pos3 };
      sseb valid = ssei(int(depth+1))+cdepth <= ssei(BVH4::maxBuildDepth); // only select swaps that fulfill depth constraints
      //valid[c2] = false;
      valid &= sseb(c2 != 0, c2 != 1, c2 != 2, c2 != 3); // FIXME: optimize
      if (none(valid)) continue;
      size_t c1 = select_min(valid,area0123);
      float area = area0123[c1];
      assert(c1 != c2);

      /*! accept a swap when it reduces cost and is not swapping a node with itself */
      if (area < bestArea) {
        bestArea = area;
        bestChild1 = c1;
        bestChild2 = c2;
        bestChild2Child = pos[c1];
      }
    }

    /*! if we did not find a swap that improves the SAH then do nothing */
    if (bestChild1 == -1) return 1+reduce_max(cdepth);

    /*! perform the best found tree rotation */
    Node* child2 = parent->child(bestChild2).node();
    BVH4::swap(parent,bestChild1,child2,bestChild2Child);
    parent->set(bestChild2,child2->bounds());
    BVH4::compact(parent);
    BVH4::compact(child2);

    /*! This returned depth is conservative as the child that was
     *  pulled up in the tree could have been on the critical path. */
    cdepth[bestChild1]++; // bestChild1 was pushed down one level
    return 1+reduce_max(cdepth);

#else

    /*! nothing to rotate if we reached a leaf node. */
    if (parentRef.isBarrier()) return 0;
    if (parentRef.isLeaf()) return 0;
    Node* parent = parentRef.node();

    /*! rotate all children first */
    int max_cdepth = 0;
    int cdepth[4];
    for (size_t c=0; c<4; c++) {
      int d = (int)rotate(bvh,parent->child(c),depth+1);
      max_cdepth = max(max_cdepth,d);
      cdepth[c] = d;
    }

    /* compute bounds */
    float parentAreas[4]; BBox3f parentBounds[4];
    for (size_t i=0; i<4; i++) {
      const BBox3f bound = parent->bounds(i);
      parentBounds[i] = bound;
      parentAreas [i] = halfArea(bound);
    }

    /*! Find best rotation. We pick a first child a second child and a
      subchild of it. We perform the best swap of the subchild and the
      first child. */
    float bestArea = 0.0f;
    int bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1;

    /* iterate over all first children */
    for (size_t c1=0; c1<4; c1++)
    {
      if ((depth+1)+cdepth[c1] > BVH4::maxBuildDepth) continue;
      const BBox3f child1Bound = parentBounds[c1];

      /* iterate over all second children */
      for (size_t c2=0; c2<4; c2++)
      {
        if (c1 == c2) continue;

        /*! ignore leaf nodes as we cannot descent into them */
        NodeRef child2Ref = parent->child(c2);
        if (child2Ref.isBarrier()) continue;
        if (child2Ref.isLeaf()) continue;
        Node* child2 = child2Ref.node();

        /* compute child bounds */
        BBox3f child2Bounds[4];
        for (size_t i=0; i<4; i++)
          child2Bounds[i] = child2->bounds(i);

        /* iterate over all subchildren of the second child */
        for (size_t c2c=0; c2c<4; c2c++)
        {
          /* compute heuristic */
          BBox3f bounds = child1Bound;
          for (size_t i=0; i<4; i++) {
            if (i == c2c) continue;
            bounds = merge(bounds,child2Bounds[i]);
          }
          float area = halfArea(bounds)-parentAreas[c2];

          /* select best swap */
          if (area < bestArea) {
            bestArea = area;
            bestChild1 = (int)c1;
            bestChild2 = (int)c2;
            bestChild2Child = (int)c2c;
          }
        }
      }
    }

    /*! if we did not find a swap that improves the SAH then do nothing */
    if (bestChild1 == -1) return 1+max_cdepth;

    /*! perform the best found tree rotation */
    Node* child2 = parent->child(bestChild2).node();
    BVH4::swap(parent,bestChild1,child2,bestChild2Child);
    parent->set(bestChild2,child2->bounds());

      /*! This returned depth is conservative as the child that was
       *  pulled up in the tree could have been on the critical path. */
    cdepth[bestChild1]++; // bestChild1 was pushed down one level
    return 1+max_cdepth;
#endif
  }
}
<commit_msg>fixed in tree rotation<commit_after>// ======================================================================== //
// Copyright 2009-2013 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 "bvh4_rotate.h"

namespace embree
{
  /*! Computes half surface area of box. */
  __forceinline float halfArea3f(const BBox<ssef>& box) {
    const ssef d = box.size();
    const ssef a = d*shuffle<1,2,0,3>(d);
    return a[0]+a[1]+a[2];
  }

  size_t BVH4Rotate::rotate(BVH4* bvh, NodeRef parentRef, size_t depth)
  {
    /*! nothing to rotate if we reached a leaf node. */
    if (parentRef.isBarrier()) return 0;
    if (parentRef.isLeaf()) return 0;
    Node* parent = parentRef.node();

    /*! rotate all children first */
    ssei cdepth;
    for (size_t c=0; c<4; c++)
      cdepth[c] = (int)rotate(bvh,parent->child(c),depth+1);

    /* compute current area of all children */
    ssef sizeX = parent->upper_x-parent->lower_x;
    ssef sizeY = parent->upper_y-parent->lower_y;
    ssef sizeZ = parent->upper_z-parent->lower_z;
    ssef childArea = sizeX*(sizeY + sizeZ) + sizeY*sizeZ;

    /*! get node bounds */
    BBox<ssef> child1_0,child1_1,child1_2,child1_3;
    parent->bounds(child1_0,child1_1,child1_2,child1_3);

    /*! Find best rotation. We pick a first child (child1) and a sub-child
      (child2child) of a different second child (child2), and swap child1
      and child2child. We perform the best such swap. */
    float bestArea = 0;
    int bestChild1 = -1, bestChild2 = -1, bestChild2Child = -1;
    for (size_t c2=0; c2<4; c2++)
    {
      /*! ignore leaf nodes as we cannot descent into them */
      if (parent->child(c2).isBarrier()) continue;
      if (parent->child(c2).isLeaf()) continue;
      Node* child2 = parent->child(c2).node();

      /*! transpose child bounds */
      BBox<ssef> child2c0,child2c1,child2c2,child2c3;
      child2->bounds(child2c0,child2c1,child2c2,child2c3);

      /*! put child1_0 at each child2 position */
      float cost00 = halfArea3f(merge(child1_0,child2c1,child2c2,child2c3));
      float cost01 = halfArea3f(merge(child2c0,child1_0,child2c2,child2c3));
      float cost02 = halfArea3f(merge(child2c0,child2c1,child1_0,child2c3));
      float cost03 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_0));
      ssef cost0 = ssef(cost00,cost01,cost02,cost03);
      ssef min0 = vreduce_min(cost0);
      int pos0 = (int)__bsf(movemask(min0 == cost0));

      /*! put child1_1 at each child2 position */
      float cost10 = halfArea3f(merge(child1_1,child2c1,child2c2,child2c3));
      float cost11 = halfArea3f(merge(child2c0,child1_1,child2c2,child2c3));
      float cost12 = halfArea3f(merge(child2c0,child2c1,child1_1,child2c3));
      float cost13 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_1));
      ssef cost1 = ssef(cost10,cost11,cost12,cost13);
      ssef min1 = vreduce_min(cost1);
      int pos1 = (int)__bsf(movemask(min1 == cost1));

      /*! put child1_2 at each child2 position */
      float cost20 = halfArea3f(merge(child1_2,child2c1,child2c2,child2c3));
      float cost21 = halfArea3f(merge(child2c0,child1_2,child2c2,child2c3));
      float cost22 = halfArea3f(merge(child2c0,child2c1,child1_2,child2c3));
      float cost23 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_2));
      ssef cost2 = ssef(cost20,cost21,cost22,cost23);
      ssef min2 = vreduce_min(cost2);
      int pos2 = (int)__bsf(movemask(min2 == cost2));

      /*! put child1_3 at each child2 position */
      float cost30 = halfArea3f(merge(child1_3,child2c1,child2c2,child2c3));
      float cost31 = halfArea3f(merge(child2c0,child1_3,child2c2,child2c3));
      float cost32 = halfArea3f(merge(child2c0,child2c1,child1_3,child2c3));
      float cost33 = halfArea3f(merge(child2c0,child2c1,child2c2,child1_3));
      ssef cost3 = ssef(cost30,cost31,cost32,cost33);
      ssef min3 = vreduce_min(cost3);
      int pos3 = (int)__bsf(movemask(min3 == cost3));

      /*! find best other child */
      ssef area0123 = ssef(extract<0>(min0),extract<0>(min1),extract<0>(min2),extract<0>(min3)) - ssef(childArea[c2]);
      int pos[4] = { pos0,pos1,pos2,pos3 };
      sseb valid = ssei(int(depth+1))+cdepth <= ssei(BVH4::maxBuildDepth); // only select swaps that fulfill depth constraints
      valid &= ssei(c2) != ssei(step);
      if (none(valid)) continue;
      size_t c1 = select_min(valid,area0123);
      float area = area0123[c1];
      assert(c1 != c2);

      /*! accept a swap when it reduces cost and is not swapping a node with itself */
      if (area < bestArea) {
        bestArea = area;
        bestChild1 = c1;
        bestChild2 = c2;
        bestChild2Child = pos[c1];
      }
    }

    /*! if we did not find a swap that improves the SAH then do nothing */
    if (bestChild1 == -1) return 1+reduce_max(cdepth);

    /*! perform the best found tree rotation */
    Node* child2 = parent->child(bestChild2).node();
    BVH4::swap(parent,bestChild1,child2,bestChild2Child);
    parent->set(bestChild2,child2->bounds());
    BVH4::compact(parent);
    BVH4::compact(child2);

    /*! This returned depth is conservative as the child that was
     *  pulled up in the tree could have been on the critical path. */
    cdepth[bestChild1]++; // bestChild1 was pushed down one level
    return 1+reduce_max(cdepth);
  }
}
<|endoftext|>


<commit_before>/*
    This file is part of the KOrganizer alarm daemon.

    Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qhbox.h>
#include <qvbox.h>
#include <qlabel.h>
#include <qfile.h>
#include <qspinbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qcstring.h>
#include <qdatastream.h>

#include <kapplication.h>
#include <dcopclient.h>
#include <klocale.h>
#include <kprocess.h>
#include <kaudioplayer.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <knotifyclient.h>
#include <kcombobox.h>
#include <kwin.h>

#include <libkcal/event.h>

#include "koeventviewer.h"

#include "alarmdialog.h"
#include "alarmdialog.moc"

AlarmDialog::AlarmDialog( QWidget *parent, const char *name )
  : KDialogBase( Plain, WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop |
                 WStyle_DialogBorder,
                 parent, name, false, i18n("Alarm"), Ok | User1 | User2/* | User3*/, Ok/*3*/,
                 false, i18n("Suspend"), i18n("Edit...") )
{
  QWidget *topBox = plainPage();

  QBoxLayout *topLayout = new QVBoxLayout( topBox );
  topLayout->setSpacing( spacingHint() );

  QLabel *label = new QLabel( i18n("The following events triggered alarms:"),
                              topBox );
  topLayout->addWidget( label );

  mIncidences.setAutoDelete( true );

  mEventViewer = new KOEventViewer( topBox );
  topLayout->addWidget( mEventViewer );

  QHBox *suspendBox = new QHBox( topBox );
  suspendBox->setSpacing( spacingHint() );
  topLayout->addWidget( suspendBox );

  new QLabel( i18n("Suspend duration:"), suspendBox );
  mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox );
  mSuspendSpin->setValue( 5 );  // default suspend duration

  mSuspendUnit = new KComboBox( suspendBox );
  mSuspendUnit->insertItem( i18n("minute(s)") );
  mSuspendUnit->insertItem( i18n("hour(s)") );
  mSuspendUnit->insertItem( i18n("day(s)") );
  mSuspendUnit->insertItem( i18n("week(s)") );

  connect( mSuspendSpin, SIGNAL( valueChanged(int) ), actionButton(User1), SLOT( setFocus() ) );
  connect( mSuspendUnit, SIGNAL( activated(int) ), actionButton(User1), SLOT( setFocus() ) );
  connect( mSuspendUnit, SIGNAL( activated(int) ), actionButton(User2), SLOT( setFocus() ) );

  // showButton( User2/*3*/, false );

  setMinimumSize( 300, 200 );
}

AlarmDialog::~AlarmDialog()
{
}

void AlarmDialog::appendEvent(Event *event)
{
  mEventViewer->appendEvent(event);
  mIncidences.append(event->clone());
}

void AlarmDialog::appendTodo(Todo *todo)
{
  mEventViewer->appendTodo(todo);
  mIncidences.append(todo->clone());
}

void AlarmDialog::clearEvents()
{
  mEventViewer->clearEvents();

  mIncidences.clear();
}

void AlarmDialog::slotOk()
{
  clearEvents();
  accept();
}

void AlarmDialog::slotUser1()
{
  int unit=1;
  switch (mSuspendUnit->currentItem()) {
    case 3: // weeks
      unit *=  7;
    case 2: // days
      unit *= 24;
    case 1: // hours
      unit *= 60;
    case 0: // minutes
      unit *= 60;
    default:
      break;
  }

  emit suspendSignal( unit * mSuspendSpin->value() );
  accept();
}

void AlarmDialog::slotUser2()
{
  if ( !kapp->dcopClient()->isApplicationRegistered( "korganizer" ) ) {
    if ( kapp->startServiceByDesktopName( "korganizer", QString::null ) )
      KMessageBox::error( 0, i18n("Could not start KOrganizer.") );
  }

  kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
                            "editIncidence(QString)",
                             mIncidences.first()->uid() );

  // get desktop # where korganizer (or kontact) runs
  QByteArray data, replyData;
  QCString object, replyType;
  object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
           "kontact-mainwindow#1" : "KOrganizer MainWindow";
  if (!kapp->dcopClient()->call( "korganizer", object,
                            "getWinID()", data, replyType, replyData, true, -1 ) ) {
  }

  if ( replyType == "int" ) {
    int desktop, window;
    QDataStream ds( replyData, IO_ReadOnly );
    ds >> window;
    desktop = KWin::windowInfo( window ).desktop();

    if ( KWin::currentDesktop() == desktop ) {
      KWin::iconifyWindow( winId(), false );
    }
    else
      KWin::setCurrentDesktop( desktop );

    KWin::activateWindow( KWin::transientFor( window ) );
  }

}

void AlarmDialog::eventNotification()
{
  bool beeped = false;

  Incidence *in;
  for (in = mIncidences.first(); in; in = mIncidences.next()) {
    Alarm::List alarms = in->alarms();
    Alarm::List::ConstIterator it;
    for ( it = alarms.begin(); it != alarms.end(); ++it ) {
      Alarm *alarm = *it;
// TODO: Check whether this should be done for all multiple alarms
      if (alarm->type() == Alarm::Procedure) {
        kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl;
        KProcess proc;
        proc << QFile::encodeName(alarm->programFile());
        proc.start(KProcess::DontCare);
      }
      else if (alarm->type() == Alarm::Audio) {
        beeped = true;
        KAudioPlayer::play(QFile::encodeName(alarm->audioFile()));
      }
    }
  }

  if ( !beeped ) {
    KNotifyClient::beep();
  }
}
<commit_msg>Minor cleanup.<commit_after>/*
    This file is part of the KOrganizer alarm daemon.

    Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qhbox.h>
#include <qvbox.h>
#include <qlabel.h>
#include <qfile.h>
#include <qspinbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qcstring.h>
#include <qdatastream.h>

#include <kapplication.h>
#include <dcopclient.h>
#include <klocale.h>
#include <kprocess.h>
#include <kaudioplayer.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <knotifyclient.h>
#include <kcombobox.h>
#include <kwin.h>

#include <libkcal/event.h>

#include "koeventviewer.h"

#include "alarmdialog.h"
#include "alarmdialog.moc"

AlarmDialog::AlarmDialog( QWidget *parent, const char *name )
  : KDialogBase( Plain, WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop |
                 WStyle_DialogBorder,
                 parent, name, false, i18n("Alarm"), Ok | User1 | User2/* | User3*/, Ok/*3*/,
                 false, i18n("Suspend"), i18n("Edit...") )
{
  QWidget *topBox = plainPage();

  QBoxLayout *topLayout = new QVBoxLayout( topBox );
  topLayout->setSpacing( spacingHint() );

  QLabel *label = new QLabel( i18n("The following events triggered alarms:"),
                              topBox );
  topLayout->addWidget( label );

  mIncidences.setAutoDelete( true );

  mEventViewer = new KOEventViewer( topBox );
  topLayout->addWidget( mEventViewer );

  QHBox *suspendBox = new QHBox( topBox );
  suspendBox->setSpacing( spacingHint() );
  topLayout->addWidget( suspendBox );

  new QLabel( i18n("Suspend duration:"), suspendBox );
  mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox );
  mSuspendSpin->setValue( 5 );  // default suspend duration

  mSuspendUnit = new KComboBox( suspendBox );
  mSuspendUnit->insertItem( i18n("minute(s)") );
  mSuspendUnit->insertItem( i18n("hour(s)") );
  mSuspendUnit->insertItem( i18n("day(s)") );
  mSuspendUnit->insertItem( i18n("week(s)") );

  connect( mSuspendSpin, SIGNAL( valueChanged(int) ), actionButton(User1), SLOT( setFocus() ) );
  connect( mSuspendUnit, SIGNAL( activated(int) ), actionButton(User1), SLOT( setFocus() ) );
  connect( mSuspendUnit, SIGNAL( activated(int) ), actionButton(User2), SLOT( setFocus() ) );

  // showButton( User2/*3*/, false );

  setMinimumSize( 300, 200 );
}

AlarmDialog::~AlarmDialog()
{
}

void AlarmDialog::appendEvent(Event *event)
{
  mEventViewer->appendEvent(event);
  mIncidences.append(event->clone());
}

void AlarmDialog::appendTodo(Todo *todo)
{
  mEventViewer->appendTodo(todo);
  mIncidences.append(todo->clone());
}

void AlarmDialog::clearEvents()
{
  mEventViewer->clearEvents();

  mIncidences.clear();
}

void AlarmDialog::slotOk()
{
  clearEvents();
  accept();
}

void AlarmDialog::slotUser1()
{
  int unit=1;
  switch (mSuspendUnit->currentItem()) {
    case 3: // weeks
      unit *=  7;
    case 2: // days
      unit *= 24;
    case 1: // hours
      unit *= 60;
    case 0: // minutes
      unit *= 60;
    default:
      break;
  }

  emit suspendSignal( unit * mSuspendSpin->value() );
  accept();
}

void AlarmDialog::slotUser2()
{
  if ( !kapp->dcopClient()->isApplicationRegistered( "korganizer" ) ) {
    if ( kapp->startServiceByDesktopName( "korganizer", QString::null ) )
      KMessageBox::error( 0, i18n("Could not start KOrganizer.") );
  }

  kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
                            "editIncidence(QString)",
                             mIncidences.first()->uid() );

  // get desktop # where korganizer (or kontact) runs
  QByteArray replyData;
  QCString object, replyType;
  object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
           "kontact-mainwindow#1" : "KOrganizer MainWindow";
  if (!kapp->dcopClient()->call( "korganizer", object,
                            "getWinID()", QByteArray(), replyType, replyData, true, -1 ) ) {
  }

  if ( replyType == "int" ) {
    int desktop, window;
    QDataStream ds( replyData, IO_ReadOnly );
    ds >> window;
    desktop = KWin::windowInfo( window ).desktop();

    if ( KWin::currentDesktop() == desktop ) {
      KWin::iconifyWindow( winId(), false );
    }
    else
      KWin::setCurrentDesktop( desktop );

    KWin::activateWindow( KWin::transientFor( window ) );
  }

}

void AlarmDialog::eventNotification()
{
  bool beeped = false;

  Incidence *in;
  for (in = mIncidences.first(); in; in = mIncidences.next()) {
    Alarm::List alarms = in->alarms();
    Alarm::List::ConstIterator it;
    for ( it = alarms.begin(); it != alarms.end(); ++it ) {
      Alarm *alarm = *it;
// TODO: Check whether this should be done for all multiple alarms
      if (alarm->type() == Alarm::Procedure) {
        kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl;
        KProcess proc;
        proc << QFile::encodeName(alarm->programFile());
        proc.start(KProcess::DontCare);
      }
      else if (alarm->type() == Alarm::Audio) {
        beeped = true;
        KAudioPlayer::play(QFile::encodeName(alarm->audioFile()));
      }
    }
  }

  if ( !beeped ) {
    KNotifyClient::beep();
  }
}
<|endoftext|>


<commit_before>#include "AndroidServiceHandler.h"
#include "protocol/AmmoMessages.pb.h"
#include "AndroidMessageProcessor.h"

#include <iostream>

#include "ace/OS_NS_errno.h"

#include "log.h"

using namespace std;

extern std::string gatewayAddress;
extern int gatewayPort;

AndroidServiceHandler::AndroidServiceHandler() :
messageProcessor(NULL),
sendQueueMutex(),
receiveQueueMutex()
{

}

int AndroidServiceHandler::open(void *ptr) {
  if(super::open(ptr) == -1) {
    return -1;

  }
  state = READING_HEADER;
  collectedData = NULL;
  position = 0;

  dataToSend = NULL;
  position = 0;

  messageHeader.magicNumber = 0;
  messageHeader.size = 0;
  messageHeader.checksum = 0;
  messageHeader.headerChecksum = 0;

  sentMessageCount = 0;
  receivedMessageCount = 0;

  connectionClosing = false;

  messageProcessor = new AndroidMessageProcessor(this);
  messageProcessor->activate();

  this->peer().enable(ACE_NONBLOCK);

  return 0;
}

int AndroidServiceHandler::handle_close(ACE_HANDLE fd, ACE_Reactor_Mask m) {
  connectionClosing = true;
  LOG_TRACE(this << " Closing Message Processor");
  messageProcessor->close(0);
  LOG_TRACE(this << " Waiting for message processor thread to finish...");
  this->reactor()->lock().release(); //release the lock, or we'll hang if other threads try to do stuff with the reactor while we're waiting
  messageProcessor->wait();
  this->reactor()->lock().acquire(); //and put it back like it was
  LOG_TRACE(this << " Message processor finished.");
  super::handle_close(fd, m);

  return 0;
}

int AndroidServiceHandler::handle_input(ACE_HANDLE fd) {
  LOG_TRACE(this << " In handle_input");
  int count = 0;

  if(state == READING_HEADER) {
    count = this->peer().recv_n(&messageHeader, sizeof(messageHeader));
    //verify the message header (check its magic number and checksum)
    if(messageHeader.magicNumber == HEADER_MAGIC_NUMBER) {
      unsigned int calculatedChecksum = ACE::crc32(&messageHeader, sizeof(messageHeader) - sizeof(messageHeader.headerChecksum));
      if(calculatedChecksum != messageHeader.headerChecksum) {
        LOG_ERROR("Invalid header checksum");
      }
    } else {
      LOG_ERROR("Invalid magic number: 0x" << hex << messageHeader.magicNumber << dec);
    }
  } else if(state == READING_DATA) {
    count = this->peer().recv(collectedData + position, messageHeader.size - position);
    //LOG_TRACE("DATA Read " << count << " bytes");
  } else {
    LOG_ERROR(this << " Invalid state!");
  }

  if(count > 0) {
    if(state == READING_HEADER) {
      collectedData = new char[messageHeader.size];
      position = 0;
      //LOG_TRACE("Got data size (" << dataSize << ")");
      state = READING_DATA;
    } else if(state == READING_DATA) {
      LOG_TRACE(this << " Got some data...");
      position += count;
      if(position == messageHeader.size) {
        //LOG_TRACE("Got all the data... processing");
        processData(collectedData, messageHeader.size, messageHeader.checksum, messageHeader.priority);
        //LOG_TRACE("Processsing complete.  Deleting buffer.");
        delete[] collectedData;
        collectedData = NULL;
        messageHeader.magicNumber = 0;
        messageHeader.size = 0;
        messageHeader.checksum = 0;
        messageHeader.headerChecksum = 0;
        position = 0;
        state = READING_HEADER;
      }
    }
  } else if(count == 0) {
    LOG_INFO(this << " Connection closed.");
    return -1;
  } else if(count == -1 && ACE_OS::last_error () != EWOULDBLOCK) {
    LOG_ERROR(this << " Socket error occurred. (" << ACE_OS::last_error() << ")");
    return -1;
  }
  LOG_TRACE(this << " Leaving handle_input()");
  return 0;
}

int AndroidServiceHandler::handle_output(ACE_HANDLE fd) {
  int count = 0;

  do {
    if(dataToSend == NULL) {
      ammo::protocol::MessageWrapper *msg = getNextMessageToSend();
      if(msg != NULL) {
        LOG_TRACE("Getting a new message to send");
        if(!msg->IsInitialized()) {
          LOG_WARN(this << " Protocol Buffers message is missing a required element.");
        }
        unsigned int messageSize = msg->ByteSize();
        sendBufferSize = messageSize + sizeof(MessageHeader);
        dataToSend = new char[sendBufferSize];
        MessageHeader *headerToSend = (MessageHeader *) dataToSend;
        headerToSend->magicNumber = HEADER_MAGIC_NUMBER;
        headerToSend->size = messageSize;

        char *protobufSerializedMessage = dataToSend + sizeof(MessageHeader);
        msg->SerializeToArray(protobufSerializedMessage, messageSize);

        headerToSend->checksum = ACE::crc32(protobufSerializedMessage, messageSize);
        headerToSend->headerChecksum = ACE::crc32(headerToSend, sizeof(messageHeader) - sizeof(messageHeader.headerChecksum));

        sendPosition = 0;

        delete msg;
      } else {
        //don't wake up the reactor when there's no data that needs to be sent
        //(wake-up will be rescheduled when data becomes available in sendMessage
        //below)
        this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
        return 0;
      }
    }

    //timeout after ten seconds when sending data (in case connection drops
    //in the middle, we don't want to wait until the socket connection dies)
    //ACE_Time_Value timeout(10);
    count = this->peer().send(dataToSend + sendPosition, sendBufferSize - sendPosition);
    if(count >= 0) {
      sendPosition += count;
    }
    LOG_TRACE("Sent " << count << " bytes (current postition " << sendPosition << "/" << sendBufferSize);

    if(sendPosition >= (sendBufferSize)) {
      delete[] dataToSend;
      dataToSend = NULL;
      sendBufferSize = 0;
      sendPosition = 0;
    }
  } while(count != -1);

  if(count == -1 && ACE_OS::last_error () == EWOULDBLOCK) {
    LOG_TRACE("Received EWOULDBLOCK");
    this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);
  } else {
    LOG_ERROR(this << " Socket error occurred. (" << ACE_OS::last_error() << ")");
    return -1;
  }

  return 0;
}

int AndroidServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum, char priority) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if(calculatedChecksum != messageChecksum) {
    LOG_ERROR(this << " Mismatched checksum " << std::hex << calculatedChecksum << " : " << messageChecksum);
    LOG_ERROR(this << " size " << std::dec << messageSize ); // << " payload: " < );
    return -1;
  }

  //checksum is valid; parse the data
  ammo::protocol::MessageWrapper *msg = new ammo::protocol::MessageWrapper();
  bool result = msg->ParseFromArray(data, messageSize);
  if(result == false) {
    LOG_ERROR(this << " MessageWrapper could not be deserialized.");
    LOG_ERROR(this << " Client must have sent something that isn't a protocol buffer (or the wrong type).");
    delete msg;
    return -1;
  }
  addReceivedMessage(msg, priority);
  messageProcessor->signalNewMessageAvailable();

  return 0;
}

void AndroidServiceHandler::sendMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN("Priority mismatch when adding message to send queue: Header = " << priority << ", Message = " << msg->message_priority());
  }

  sendQueueMutex.acquire();
  queuedMsg.messageCount = sentMessageCount;
  sentMessageCount++;
  if(!connectionClosing) {
    sendQueue.push(queuedMsg);
    LOG_TRACE(this << " Queued a message to send.  " << sendQueue.size() << " messages in queue.");
  }
  sendQueueMutex.release();
  if(!connectionClosing) {
    this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);
  }
}

ammo::protocol::MessageWrapper *AndroidServiceHandler::getNextMessageToSend() {
  ammo::protocol::MessageWrapper *msg = NULL;
  sendQueueMutex.acquire();
  if(!sendQueue.empty()) {
    msg = sendQueue.top().message;
    sendQueue.pop();
  }

  int size = sendQueue.size();
  sendQueueMutex.release();
  LOG_TRACE(this << " Dequeued a message to send.  " << size << " messages remain in queue.");

  return msg;
}

ammo::protocol::MessageWrapper *AndroidServiceHandler::getNextReceivedMessage() {
  ammo::protocol::MessageWrapper *msg = NULL;
  receiveQueueMutex.acquire();
  if(!receiveQueue.empty()) {
    msg = receiveQueue.top().message;
    receiveQueue.pop();
  }
  receiveQueueMutex.release();

  return msg;
}

void AndroidServiceHandler::addReceivedMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN("Priority mismatch on received message: Header = " << priority << ", Message = " << msg->message_priority());
  }

  receiveQueueMutex.acquire();
  queuedMsg.messageCount = receivedMessageCount;
  receivedMessageCount++;
  receiveQueue.push(queuedMsg);
  receiveQueueMutex.release();
}

AndroidServiceHandler::~AndroidServiceHandler() {
  LOG_TRACE(this << " In ~AndroidServiceHandler");
  delete messageProcessor;
}
<commit_msg>Terminate connection on header magic number or checksum failure<commit_after>#include "AndroidServiceHandler.h"
#include "protocol/AmmoMessages.pb.h"
#include "AndroidMessageProcessor.h"

#include <iostream>

#include "ace/OS_NS_errno.h"

#include "log.h"

using namespace std;

extern std::string gatewayAddress;
extern int gatewayPort;

AndroidServiceHandler::AndroidServiceHandler() :
messageProcessor(NULL),
sendQueueMutex(),
receiveQueueMutex()
{

}

int AndroidServiceHandler::open(void *ptr) {
  if(super::open(ptr) == -1) {
    return -1;

  }
  state = READING_HEADER;
  collectedData = NULL;
  position = 0;

  dataToSend = NULL;
  position = 0;

  messageHeader.magicNumber = 0;
  messageHeader.size = 0;
  messageHeader.checksum = 0;
  messageHeader.headerChecksum = 0;

  sentMessageCount = 0;
  receivedMessageCount = 0;

  connectionClosing = false;

  messageProcessor = new AndroidMessageProcessor(this);
  messageProcessor->activate();

  this->peer().enable(ACE_NONBLOCK);

  return 0;
}

int AndroidServiceHandler::handle_close(ACE_HANDLE fd, ACE_Reactor_Mask m) {
  connectionClosing = true;
  LOG_TRACE(this << " Closing Message Processor");
  messageProcessor->close(0);
  LOG_TRACE(this << " Waiting for message processor thread to finish...");
  this->reactor()->lock().release(); //release the lock, or we'll hang if other threads try to do stuff with the reactor while we're waiting
  messageProcessor->wait();
  this->reactor()->lock().acquire(); //and put it back like it was
  LOG_TRACE(this << " Message processor finished.");
  super::handle_close(fd, m);

  return 0;
}

int AndroidServiceHandler::handle_input(ACE_HANDLE fd) {
  LOG_TRACE(this << " In handle_input");
  int count = 0;

  if(state == READING_HEADER) {
    count = this->peer().recv_n(&messageHeader, sizeof(messageHeader));
    //verify the message header (check its magic number and checksum)
    if(messageHeader.magicNumber == HEADER_MAGIC_NUMBER) {
      unsigned int calculatedChecksum = ACE::crc32(&messageHeader, sizeof(messageHeader) - sizeof(messageHeader.headerChecksum));
      if(calculatedChecksum != messageHeader.headerChecksum) {
        LOG_ERROR("Invalid header checksum");
        return -1;
      }
    } else {
      LOG_ERROR("Invalid magic number: " << hex << messageHeader.magicNumber << dec);
      return -1;
    }
  } else if(state == READING_DATA) {
    count = this->peer().recv(collectedData + position, messageHeader.size - position);
    //LOG_TRACE("DATA Read " << count << " bytes");
  } else {
    LOG_ERROR(this << " Invalid state!");
    return -1;
  }

  if(count > 0) {
    if(state == READING_HEADER) {
      collectedData = new char[messageHeader.size];
      position = 0;
      //LOG_TRACE("Got data size (" << dataSize << ")");
      state = READING_DATA;
    } else if(state == READING_DATA) {
      LOG_TRACE(this << " Got some data...");
      position += count;
      if(position == messageHeader.size) {
        //LOG_TRACE("Got all the data... processing");
        processData(collectedData, messageHeader.size, messageHeader.checksum, messageHeader.priority);
        //LOG_TRACE("Processsing complete.  Deleting buffer.");
        delete[] collectedData;
        collectedData = NULL;
        messageHeader.magicNumber = 0;
        messageHeader.size = 0;
        messageHeader.checksum = 0;
        messageHeader.headerChecksum = 0;
        position = 0;
        state = READING_HEADER;
      }
    }
  } else if(count == 0) {
    LOG_INFO(this << " Connection closed.");
    return -1;
  } else if(count == -1 && ACE_OS::last_error () != EWOULDBLOCK) {
    LOG_ERROR(this << " Socket error occurred. (" << ACE_OS::last_error() << ")");
    return -1;
  }
  LOG_TRACE(this << " Leaving handle_input()");
  return 0;
}

int AndroidServiceHandler::handle_output(ACE_HANDLE fd) {
  int count = 0;

  do {
    if(dataToSend == NULL) {
      ammo::protocol::MessageWrapper *msg = getNextMessageToSend();
      if(msg != NULL) {
        LOG_TRACE("Getting a new message to send");
        if(!msg->IsInitialized()) {
          LOG_WARN(this << " Protocol Buffers message is missing a required element.");
        }
        unsigned int messageSize = msg->ByteSize();
        sendBufferSize = messageSize + sizeof(MessageHeader);
        dataToSend = new char[sendBufferSize];
        MessageHeader *headerToSend = (MessageHeader *) dataToSend;
        headerToSend->magicNumber = HEADER_MAGIC_NUMBER;
        headerToSend->size = messageSize;

        char *protobufSerializedMessage = dataToSend + sizeof(MessageHeader);
        msg->SerializeToArray(protobufSerializedMessage, messageSize);

        headerToSend->checksum = ACE::crc32(protobufSerializedMessage, messageSize);
        headerToSend->headerChecksum = ACE::crc32(headerToSend, sizeof(messageHeader) - sizeof(messageHeader.headerChecksum));

        sendPosition = 0;

        delete msg;
      } else {
        //don't wake up the reactor when there's no data that needs to be sent
        //(wake-up will be rescheduled when data becomes available in sendMessage
        //below)
        this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
        return 0;
      }
    }

    //timeout after ten seconds when sending data (in case connection drops
    //in the middle, we don't want to wait until the socket connection dies)
    //ACE_Time_Value timeout(10);
    count = this->peer().send(dataToSend + sendPosition, sendBufferSize - sendPosition);
    if(count >= 0) {
      sendPosition += count;
    }
    LOG_TRACE("Sent " << count << " bytes (current postition " << sendPosition << "/" << sendBufferSize);

    if(sendPosition >= (sendBufferSize)) {
      delete[] dataToSend;
      dataToSend = NULL;
      sendBufferSize = 0;
      sendPosition = 0;
    }
  } while(count != -1);

  if(count == -1 && ACE_OS::last_error () == EWOULDBLOCK) {
    LOG_TRACE("Received EWOULDBLOCK");
    this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);
  } else {
    LOG_ERROR(this << " Socket error occurred. (" << ACE_OS::last_error() << ")");
    return -1;
  }

  return 0;
}

int AndroidServiceHandler::processData(char *data, unsigned int messageSize, unsigned int messageChecksum, char priority) {
  //Validate checksum
  unsigned int calculatedChecksum = ACE::crc32(data, messageSize);
  if(calculatedChecksum != messageChecksum) {
    LOG_ERROR(this << " Mismatched checksum " << std::hex << calculatedChecksum << " : " << messageChecksum);
    LOG_ERROR(this << " size " << std::dec << messageSize ); // << " payload: " < );
    return -1;
  }

  //checksum is valid; parse the data
  ammo::protocol::MessageWrapper *msg = new ammo::protocol::MessageWrapper();
  bool result = msg->ParseFromArray(data, messageSize);
  if(result == false) {
    LOG_ERROR(this << " MessageWrapper could not be deserialized.");
    LOG_ERROR(this << " Client must have sent something that isn't a protocol buffer (or the wrong type).");
    delete msg;
    return -1;
  }
  addReceivedMessage(msg, priority);
  messageProcessor->signalNewMessageAvailable();

  return 0;
}

void AndroidServiceHandler::sendMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN("Priority mismatch when adding message to send queue: Header = " << priority << ", Message = " << msg->message_priority());
  }

  sendQueueMutex.acquire();
  queuedMsg.messageCount = sentMessageCount;
  sentMessageCount++;
  if(!connectionClosing) {
    sendQueue.push(queuedMsg);
    LOG_TRACE(this << " Queued a message to send.  " << sendQueue.size() << " messages in queue.");
  }
  sendQueueMutex.release();
  if(!connectionClosing) {
    this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK);
  }
}

ammo::protocol::MessageWrapper *AndroidServiceHandler::getNextMessageToSend() {
  ammo::protocol::MessageWrapper *msg = NULL;
  sendQueueMutex.acquire();
  if(!sendQueue.empty()) {
    msg = sendQueue.top().message;
    sendQueue.pop();
  }

  int size = sendQueue.size();
  sendQueueMutex.release();
  LOG_TRACE(this << " Dequeued a message to send.  " << size << " messages remain in queue.");

  return msg;
}

ammo::protocol::MessageWrapper *AndroidServiceHandler::getNextReceivedMessage() {
  ammo::protocol::MessageWrapper *msg = NULL;
  receiveQueueMutex.acquire();
  if(!receiveQueue.empty()) {
    msg = receiveQueue.top().message;
    receiveQueue.pop();
  }
  receiveQueueMutex.release();

  return msg;
}

void AndroidServiceHandler::addReceivedMessage(ammo::protocol::MessageWrapper *msg, char priority) {
  QueuedMessage queuedMsg;
  queuedMsg.priority = priority;
  queuedMsg.message = msg;

  if(priority != msg->message_priority()) {
    LOG_WARN("Priority mismatch on received message: Header = " << priority << ", Message = " << msg->message_priority());
  }

  receiveQueueMutex.acquire();
  queuedMsg.messageCount = receivedMessageCount;
  receivedMessageCount++;
  receiveQueue.push(queuedMsg);
  receiveQueueMutex.release();
}

AndroidServiceHandler::~AndroidServiceHandler() {
  LOG_TRACE(this << " In ~AndroidServiceHandler");
  delete messageProcessor;
}
<|endoftext|>