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

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

// appleseed.foundation headers.
#ifdef __APPLE__
#include "foundation/platform/types.h"
#endif

// boost headers.
#include "boost/filesystem/operations.hpp"

// Platform headers.
#if defined __APPLE__
#include <mach-o/dyld.h>
#elif defined __linux__
#include <unistd.h>
#endif

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

using namespace boost;
using namespace std;

namespace foundation
{

//
// Path class implementation.
//

const char* Path::get_executable_path()
{
    static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
    static bool path_initialized = false;

    if (!path_initialized)
    {
// Windows.
#if defined _WIN32

	    const DWORD result =
            GetModuleFileName(
		        GetModuleHandle(NULL),
		        path,
		        sizeof(path));
        assert(result);

// Mac OS X.
#elif defined __APPLE__

        uint32 path_len = MAXPATHLEN;
        const int result = _NSGetExecutablePath(path, &path_len);
        assert(result == 0);

// Linux.
#elif defined __linux__

        ssize_t result = readlink("/proc/self/exe", path, sizeof(path));
        assert(result > 0);
        path[result] = '\0';

#endif

        path_initialized = true;
    }

    return path;
}

const char* Path::get_executable_directory()
{
    static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
    static bool path_initialized = false;

    if (!path_initialized)
    {
        filesystem::path executable_path(get_executable_path());

        assert(executable_path.has_filename());
        executable_path.remove_filename();

        assert(executable_path.string().size() <= FOUNDATION_MAX_PATH_LENGTH);
        strcpy(path, executable_path.string().c_str());

        path_initialized = true;
    }

    return path;
}

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

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

// appleseed.foundation headers.
#ifdef __APPLE__
#include "foundation/platform/types.h"
#endif

// boost headers.
#include "boost/filesystem/operations.hpp"

// Platform headers.
#if defined __APPLE__
#include <mach-o/dyld.h>
#elif defined __linux__
#include <unistd.h>
#endif

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

using namespace boost;
using namespace std;

namespace foundation
{

//
// Path class implementation.
//

const char* Path::get_executable_path()
{
    static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
    static bool path_initialized = false;

    if (!path_initialized)
    {
// Windows.
#if defined _WIN32

	    const DWORD result =
            GetModuleFileName(
		        GetModuleHandle(NULL),
		        path,
		        sizeof(path));
        assert(result);

// Mac OS X.
#elif defined __APPLE__

        uint32 path_len = MAXPATHLEN;
        const int result = _NSGetExecutablePath(path, &path_len);
        assert(result == 0);

// Linux.
#elif defined __linux__

        ssize_t result = readlink("/proc/self/exe", path, sizeof(path) - 1);
        assert(result > 0);
        path[result] = '\0';

#endif

        path_initialized = true;
    }

    return path;
}

const char* Path::get_executable_directory()
{
    static char path[FOUNDATION_MAX_PATH_LENGTH + 1];
    static bool path_initialized = false;

    if (!path_initialized)
    {
        filesystem::path executable_path(get_executable_path());

        assert(executable_path.has_filename());
        executable_path.remove_filename();

        assert(executable_path.string().size() <= FOUNDATION_MAX_PATH_LENGTH);
        strcpy(path, executable_path.string().c_str());

        path_initialized = true;
    }

    return path;
}

}   // namespace foundation
<|endoftext|>


<commit_before>//
//  Copyright Silvin Lubecki 2010
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef OPENCLAM_FOR_EACH_HPP_INCLUDED
#define OPENCLAM_FOR_EACH_HPP_INCLUDED

#include "kernel.hpp"
#include <memory>

namespace openclam
{
    template< class InputIterator, class Kernel >
    void for_each( InputIterator first, InputIterator last, Kernel& k )
    {
        const unsigned int size = std::distance( first, last ); // $$$$ 2010-03-09 SILVIN: externalize these functions into openclam::buffer or vector object
        std::auto_ptr< InputIterator::value_type > data( new InputIterator::value_type[ size ] );
        InputIterator it = first;
        for( unsigned int i = 0; it != last; ++it, ++i )
            data.get()[ i ] = *it;
        k( data.get(), size );
        for( unsigned int i = 0; first != last; ++first, ++i )
            std::swap( *first, data.get()[ i ] );
    }
}

#endif // #ifndef OPENCLAM_CONTEXT_HPP_INCLUDED
<commit_msg>openclam::for_each simplified<commit_after>//
//  Copyright Silvin Lubecki 2010
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef OPENCLAM_FOR_EACH_HPP_INCLUDED
#define OPENCLAM_FOR_EACH_HPP_INCLUDED

#include "kernel.hpp"
#include <memory>

namespace openclam
{
    template< class InputIterator, class Kernel >
    void for_each( InputIterator first, InputIterator last, Kernel& k )
    {
        std::vector< InputIterator::value_type* > data;
        for( ; first != last; ++first )
            data.push_back( &*first );
        k( data[ 0 ], data.size() );
    }
}

#endif // #ifndef OPENCLAM_CONTEXT_HPP_INCLUDED
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/instantiate.h"
#include "kernel/abstract.h"
#include "library/util.h"
#include "library/locals.h"
#include "library/replace_visitor.h"
#include "library/congr_lemma_manager.h"

namespace lean {
class congr_lemma_manager::imp {
    app_builder &      m_builder;
    fun_info_manager & m_fmanager;
    type_context &     m_ctx;
    bool               m_ignore_inst_implicit;
    struct key {
        expr const & m_fn;
        unsigned     m_nargs;
        unsigned     m_hash;
        key(expr const & fn, unsigned nargs):
            m_fn(fn), m_nargs(nargs), m_hash(hash(m_fn.hash(), m_nargs)) {}
    };

    struct key_hash_fn {
        unsigned operator()(key const & k) const { return k.m_hash; }
    };

    struct key_eq_fn {
        bool operator()(key const & k1, key const & k2) const {
            return k1.m_fn == k2.m_fn && k1.m_nargs == k2.m_nargs;
        }
    };

    std::unordered_map<key, result, key_hash_fn, key_eq_fn> m_cache;

    struct failure {
        unsigned m_arg_idx;
        failure(unsigned i):m_arg_idx(i) {}
    };

    expr infer(expr const & e) { return m_ctx.infer(e); }
    expr whnf(expr const & e) { return m_ctx.whnf(e); }

    /** \brief (Try to) cast expression \c e to the given type using the equations \c eqs.
        \c deps contains the indices of the relevant equalities.
        \remark deps is sorted. */
    optional<expr> cast(expr const & e, expr const & type, list<unsigned> const & deps, buffer<optional<expr>> const & eqs) {
        if (!deps)
            return some_expr(e);
        unsigned d = head(deps);
        auto major = eqs[d];
        if (!major) {
            return cast(e, type, tail(deps), eqs);
        } else {
            expr lhs, rhs;
            lean_verify(is_eq(mlocal_type(*major), lhs, rhs));
            lean_assert(is_local(lhs));
            lean_assert(is_local(rhs));
            // We compute the new type by replacing rhs with lhs, and major with (refl lhs).
            expr motive, new_type;
            bool use_drec;
            if (depends_on(type, *major)) {
                // Since the type depends on the major, we must use dependent elimination.
                // and the motive just abstract rhs and *major
                use_drec  = true;
                motive    = Fun(rhs, Fun(*major, type));
                // We compute new_type by replacing rhs with lhs and *major with eq.refl(lhs) in type.
                new_type  = instantiate(abstract_local(type, rhs), lhs);
                auto refl = m_builder.mk_eq_refl(lhs);
                if (!refl)
                    return none_expr();
                new_type  = instantiate(abstract_local(new_type, *major), *refl);
            } else {
                // type does not depend on the *major.
                // So, the motive is just (fun rhs, type), and
                // new_type just replaces rhs with lhs.
                use_drec = false;
                motive   = Fun(rhs, type);
                new_type = instantiate(abstract_local(type, rhs), lhs);
            }
            auto minor = cast(e, new_type, tail(deps), eqs);
            if (!minor)
                return none_expr();
            if (use_drec) {
                return m_builder.mk_eq_drec(motive, *minor, *major);
            } else {
                return m_builder.mk_eq_rec(motive, *minor, *major);
            }
        }
    }

    bool has_cast(buffer<congr_arg_kind> const & kinds) {
        return std::find(kinds.begin(), kinds.end(), congr_arg_kind::Cast) != kinds.end();
    }

    optional<expr> mk_simple_congr_proof(expr const & fn, buffer<expr> const & lhss,
                                         buffer<optional<expr>> const & eqs, buffer<congr_arg_kind> const & kinds) {
        unsigned i = 0;
        for (; i < kinds.size(); i++) {
            if (kinds[i] != congr_arg_kind::Fixed)
                break;
        }
        expr g = mk_app(fn, i, lhss.data());
        if (i == kinds.size())
            return m_builder.mk_eq_refl(g);
        lean_assert(kinds[i] == congr_arg_kind::Eq);
        lean_assert(eqs[i]);
        optional<expr> pr = m_builder.mk_congr_arg(g, *eqs[i]);
        if (!pr) return none_expr();
        i++;
        for (; i < kinds.size(); i++) {
            if (kinds[i] == congr_arg_kind::Eq) {
                pr = m_builder.mk_congr(*pr, *eqs[i]);
            } else {
                lean_assert(kinds[i] == congr_arg_kind::Fixed);
                pr = m_builder.mk_congr_fun(*pr, lhss[i]);
            }
            if (!pr) return none_expr();
        }
        return pr;
    }

    optional<expr> mk_congr_proof(unsigned i, expr const & lhs, expr const & rhs, buffer<optional<expr>> const & eqs) {
        if (i == eqs.size()) {
            return m_builder.mk_eq_refl(rhs);
        } else if (!eqs[i]) {
            return mk_congr_proof(i+1, lhs, rhs, eqs);
        } else {
            expr major = *eqs[i];
            expr x_1, x_2;
            lean_verify(is_eq(mlocal_type(major), x_1, x_2));
            lean_assert(is_local(x_1));
            lean_assert(is_local(x_2));
            auto motive_eq = m_builder.mk_eq(lhs, rhs);
            if (!motive_eq) return none_expr();
            expr motive  = Fun(x_2, Fun(major, *motive_eq));
            // We compute the new_rhs by replacing x_2 with x_1 and major with (eq.refl x_1) in rhs.
            expr new_rhs = instantiate(abstract_local(rhs, x_2), x_1);
            auto x1_refl = m_builder.mk_eq_refl(x_1);
            if (!x1_refl) return none_expr();
            new_rhs      = instantiate(abstract_local(new_rhs, major), *x1_refl);
            auto minor   = mk_congr_proof(i+1, lhs, new_rhs, eqs);
            if (!minor) return none_expr();
            return m_builder.mk_eq_drec(motive, *minor, major);
        }
    }

    optional<result> mk_congr_simp(expr const & fn, buffer<param_info> const & pinfos, buffer<congr_arg_kind> const & kinds) {
        expr fn_type = whnf(infer(fn));
        name e_name("e");
        buffer<expr> lhss;
        buffer<expr> rhss;          // it contains the right-hand-side argument
        buffer<optional<expr>> eqs; // for Eq args, it contains the equality
        buffer<expr> hyps;          // contains lhss + rhss + eqs
        for (unsigned i = 0; i < pinfos.size(); i++) {
            if (!is_pi(fn_type)) {
                return optional<result>();
            }
            expr lhs = m_ctx.mk_tmp_local(binding_name(fn_type), binding_domain(fn_type));
            lhss.push_back(lhs);
            hyps.push_back(lhs);
            switch (kinds[i]) {
            case congr_arg_kind::Eq: {
                expr rhs = m_ctx.mk_tmp_local(binding_name(fn_type), binding_domain(fn_type));
                expr eq_type;
                if (auto it = m_builder.mk_eq(lhs, rhs))
                    eq_type = *it;
                else
                    return optional<result>();
                rhss.push_back(rhs);
                expr eq = m_ctx.mk_tmp_local(e_name.append_after(eqs.size()+1), eq_type);
                eqs.push_back(some_expr(eq));
                hyps.push_back(rhs);
                hyps.push_back(eq);
                break;
            }
            case congr_arg_kind::Fixed:
                rhss.push_back(lhs);
                eqs.push_back(none_expr());
                break;
            case congr_arg_kind::Cast: {
                expr rhs_type = mlocal_type(lhs);
                rhs_type = instantiate_rev(abstract_locals(rhs_type, lhss.size()-1, lhss.data()), rhss.size(), rhss.data());
                auto rhs = cast(lhs, rhs_type, pinfos[i].get_dependencies(), eqs);
                if (!rhs) {
                    return optional<result>();
                }
                rhss.push_back(*rhs);
                eqs.push_back(none_expr());
                break;
            }}
            fn_type  = whnf(instantiate(binding_body(fn_type), lhs));
        }
        expr lhs = mk_app(fn, lhss);
        expr rhs = mk_app(fn, rhss);
        auto eq  = m_builder.mk_eq(lhs, rhs);
        if (!eq)
            return optional<result>();
        expr congr_type  = Pi(hyps, *eq);
        optional<expr> congr_proof;
        if (has_cast(kinds)) {
            congr_proof = mk_congr_proof(0, lhs, rhs, eqs);
        } else {
            congr_proof = mk_simple_congr_proof(fn, lhss, eqs, kinds);
        }
        if (!congr_proof) return optional<result>();
        congr_proof = Fun(hyps, *congr_proof);
        return optional<result>(congr_type, *congr_proof, to_list(kinds));
    }

public:
    imp(app_builder & b, fun_info_manager & fm, bool ignore_inst_implicit):
        m_builder(b), m_fmanager(fm), m_ctx(fm.ctx()), m_ignore_inst_implicit(ignore_inst_implicit) {}

    optional<result> mk_congr_simp(expr const & fn) {
        fun_info finfo = m_fmanager.get(fn);
        return mk_congr_simp(fn, finfo.get_arity());
    }

    optional<result> mk_congr_simp(expr const & fn, unsigned nargs) {
        auto r = m_cache.find(key(fn, nargs));
        if (r != m_cache.end())
            return optional<result>(r->second);
        fun_info finfo = m_fmanager.get(fn, nargs);
        list<unsigned> const & result_deps = finfo.get_dependencies();
        buffer<congr_arg_kind> kinds;
        buffer<param_info>     pinfos;
        to_buffer(finfo.get_params_info(), pinfos);
        kinds.resize(pinfos.size(), congr_arg_kind::Eq);
        for (unsigned i = 0; i < pinfos.size(); i++) {
            if (std::find(result_deps.begin(), result_deps.end(), i) != result_deps.end()) {
                kinds[i] = congr_arg_kind::Fixed;
            } else if (pinfos[i].is_subsingleton()) {
                if (empty(pinfos[i].get_dependencies()))
                    kinds[i] = congr_arg_kind::Fixed;
                else
                    kinds[i] = congr_arg_kind::Cast;
            } else if (pinfos[i].is_inst_implicit()) {
                lean_assert(!pinfos[i].is_subsingleton());
                kinds[i] = congr_arg_kind::Fixed;
            }
        }
        for (unsigned i = 0; i < pinfos.size(); i++) {
            for (unsigned j = i+1; j < pinfos.size(); j++) {
                auto j_deps = pinfos[j].get_dependencies();
                if (std::find(j_deps.begin(), j_deps.end(), i) != j_deps.end() &&
                    kinds[j] == congr_arg_kind::Eq) {
                    // We must fix i because there is a j that depends on i,
                    // and j is not fixed nor a cast-fixed.
                    kinds[i] = congr_arg_kind::Fixed;
                    break;
                }
            }
        }
        while (true) {
            try {
                auto new_r = mk_congr_simp(fn, pinfos, kinds);
                if (new_r)
                    m_cache.insert(mk_pair(key(fn, nargs), *new_r));
                return new_r;
            } catch (failure & ex) {
                kinds[ex.m_arg_idx] = congr_arg_kind::Fixed;
            }
        }
    }
};

congr_lemma_manager::congr_lemma_manager(app_builder & b, fun_info_manager & fm, bool ignore_inst_implicit):
    m_ptr(new imp(b, fm, ignore_inst_implicit)) {
}

congr_lemma_manager::~congr_lemma_manager() {
}

auto congr_lemma_manager::mk_congr_simp(expr const & fn) -> optional<result> {
    return m_ptr->mk_congr_simp(fn);
}
auto congr_lemma_manager::mk_congr_simp(expr const & fn, unsigned nargs) -> optional<result> {
    return m_ptr->mk_congr_simp(fn, nargs);
}
}
<commit_msg>feat(library/congr_lemma_manager): fallback to simple congruence theorem if needed<commit_after>/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/instantiate.h"
#include "kernel/abstract.h"
#include "library/util.h"
#include "library/locals.h"
#include "library/replace_visitor.h"
#include "library/congr_lemma_manager.h"

namespace lean {
class congr_lemma_manager::imp {
    app_builder &      m_builder;
    fun_info_manager & m_fmanager;
    type_context &     m_ctx;
    bool               m_ignore_inst_implicit;
    struct key {
        expr const & m_fn;
        unsigned     m_nargs;
        unsigned     m_hash;
        key(expr const & fn, unsigned nargs):
            m_fn(fn), m_nargs(nargs), m_hash(hash(m_fn.hash(), m_nargs)) {}
    };

    struct key_hash_fn {
        unsigned operator()(key const & k) const { return k.m_hash; }
    };

    struct key_eq_fn {
        bool operator()(key const & k1, key const & k2) const {
            return k1.m_fn == k2.m_fn && k1.m_nargs == k2.m_nargs;
        }
    };

    std::unordered_map<key, result, key_hash_fn, key_eq_fn> m_cache;

    expr infer(expr const & e) { return m_ctx.infer(e); }
    expr whnf(expr const & e) { return m_ctx.whnf(e); }

    /** \brief (Try to) cast expression \c e to the given type using the equations \c eqs.
        \c deps contains the indices of the relevant equalities.
        \remark deps is sorted. */
    optional<expr> cast(expr const & e, expr const & type, list<unsigned> const & deps, buffer<optional<expr>> const & eqs) {
        if (!deps)
            return some_expr(e);
        unsigned d = head(deps);
        auto major = eqs[d];
        if (!major) {
            return cast(e, type, tail(deps), eqs);
        } else {
            expr lhs, rhs;
            lean_verify(is_eq(mlocal_type(*major), lhs, rhs));
            lean_assert(is_local(lhs));
            lean_assert(is_local(rhs));
            // We compute the new type by replacing rhs with lhs, and major with (refl lhs).
            expr motive, new_type;
            bool use_drec;
            if (depends_on(type, *major)) {
                // Since the type depends on the major, we must use dependent elimination.
                // and the motive just abstract rhs and *major
                use_drec  = true;
                motive    = Fun(rhs, Fun(*major, type));
                // We compute new_type by replacing rhs with lhs and *major with eq.refl(lhs) in type.
                new_type  = instantiate(abstract_local(type, rhs), lhs);
                auto refl = m_builder.mk_eq_refl(lhs);
                if (!refl)
                    return none_expr();
                new_type  = instantiate(abstract_local(new_type, *major), *refl);
            } else {
                // type does not depend on the *major.
                // So, the motive is just (fun rhs, type), and
                // new_type just replaces rhs with lhs.
                use_drec = false;
                motive   = Fun(rhs, type);
                new_type = instantiate(abstract_local(type, rhs), lhs);
            }
            auto minor = cast(e, new_type, tail(deps), eqs);
            if (!minor)
                return none_expr();
            if (use_drec) {
                return m_builder.mk_eq_drec(motive, *minor, *major);
            } else {
                return m_builder.mk_eq_rec(motive, *minor, *major);
            }
        }
    }

    bool has_cast(buffer<congr_arg_kind> const & kinds) {
        return std::find(kinds.begin(), kinds.end(), congr_arg_kind::Cast) != kinds.end();
    }

    optional<expr> mk_simple_congr_proof(expr const & fn, buffer<expr> const & lhss,
                                         buffer<optional<expr>> const & eqs, buffer<congr_arg_kind> const & kinds) {
        unsigned i = 0;
        for (; i < kinds.size(); i++) {
            if (kinds[i] != congr_arg_kind::Fixed)
                break;
        }
        expr g = mk_app(fn, i, lhss.data());
        if (i == kinds.size())
            return m_builder.mk_eq_refl(g);
        lean_assert(kinds[i] == congr_arg_kind::Eq);
        lean_assert(eqs[i]);
        optional<expr> pr = m_builder.mk_congr_arg(g, *eqs[i]);
        if (!pr) return none_expr();
        i++;
        for (; i < kinds.size(); i++) {
            if (kinds[i] == congr_arg_kind::Eq) {
                pr = m_builder.mk_congr(*pr, *eqs[i]);
            } else {
                lean_assert(kinds[i] == congr_arg_kind::Fixed);
                pr = m_builder.mk_congr_fun(*pr, lhss[i]);
            }
            if (!pr) return none_expr();
        }
        return pr;
    }

    optional<expr> mk_congr_proof(unsigned i, expr const & lhs, expr const & rhs, buffer<optional<expr>> const & eqs) {
        if (i == eqs.size()) {
            return m_builder.mk_eq_refl(rhs);
        } else if (!eqs[i]) {
            return mk_congr_proof(i+1, lhs, rhs, eqs);
        } else {
            expr major = *eqs[i];
            expr x_1, x_2;
            lean_verify(is_eq(mlocal_type(major), x_1, x_2));
            lean_assert(is_local(x_1));
            lean_assert(is_local(x_2));
            auto motive_eq = m_builder.mk_eq(lhs, rhs);
            if (!motive_eq) return none_expr();
            expr motive  = Fun(x_2, Fun(major, *motive_eq));
            // We compute the new_rhs by replacing x_2 with x_1 and major with (eq.refl x_1) in rhs.
            expr new_rhs = instantiate(abstract_local(rhs, x_2), x_1);
            auto x1_refl = m_builder.mk_eq_refl(x_1);
            if (!x1_refl) return none_expr();
            new_rhs      = instantiate(abstract_local(new_rhs, major), *x1_refl);
            auto minor   = mk_congr_proof(i+1, lhs, new_rhs, eqs);
            if (!minor) return none_expr();
            return m_builder.mk_eq_drec(motive, *minor, major);
        }
    }

    optional<result> mk_congr_simp(expr const & fn, buffer<param_info> const & pinfos, buffer<congr_arg_kind> const & kinds) {
        expr fn_type = whnf(infer(fn));
        name e_name("e");
        buffer<expr> lhss;
        buffer<expr> rhss;          // it contains the right-hand-side argument
        buffer<optional<expr>> eqs; // for Eq args, it contains the equality
        buffer<expr> hyps;          // contains lhss + rhss + eqs
        for (unsigned i = 0; i < pinfos.size(); i++) {
            if (!is_pi(fn_type)) {
                return optional<result>();
            }
            expr lhs = m_ctx.mk_tmp_local(binding_name(fn_type), binding_domain(fn_type));
            lhss.push_back(lhs);
            hyps.push_back(lhs);
            switch (kinds[i]) {
            case congr_arg_kind::Eq: {
                expr rhs = m_ctx.mk_tmp_local(binding_name(fn_type), binding_domain(fn_type));
                expr eq_type;
                if (auto it = m_builder.mk_eq(lhs, rhs))
                    eq_type = *it;
                else
                    return optional<result>();
                rhss.push_back(rhs);
                expr eq = m_ctx.mk_tmp_local(e_name.append_after(eqs.size()+1), eq_type);
                eqs.push_back(some_expr(eq));
                hyps.push_back(rhs);
                hyps.push_back(eq);
                break;
            }
            case congr_arg_kind::Fixed:
                rhss.push_back(lhs);
                eqs.push_back(none_expr());
                break;
            case congr_arg_kind::Cast: {
                expr rhs_type = mlocal_type(lhs);
                rhs_type = instantiate_rev(abstract_locals(rhs_type, lhss.size()-1, lhss.data()), rhss.size(), rhss.data());
                auto rhs = cast(lhs, rhs_type, pinfos[i].get_dependencies(), eqs);
                if (!rhs) {
                    return optional<result>();
                }
                rhss.push_back(*rhs);
                eqs.push_back(none_expr());
                break;
            }}
            fn_type  = whnf(instantiate(binding_body(fn_type), lhs));
        }
        expr lhs = mk_app(fn, lhss);
        expr rhs = mk_app(fn, rhss);
        auto eq  = m_builder.mk_eq(lhs, rhs);
        if (!eq)
            return optional<result>();
        expr congr_type  = Pi(hyps, *eq);
        optional<expr> congr_proof;
        if (has_cast(kinds)) {
            congr_proof = mk_congr_proof(0, lhs, rhs, eqs);
        } else {
            congr_proof = mk_simple_congr_proof(fn, lhss, eqs, kinds);
        }
        if (!congr_proof) return optional<result>();
        congr_proof = Fun(hyps, *congr_proof);
        return optional<result>(congr_type, *congr_proof, to_list(kinds));
    }

public:
    imp(app_builder & b, fun_info_manager & fm, bool ignore_inst_implicit):
        m_builder(b), m_fmanager(fm), m_ctx(fm.ctx()), m_ignore_inst_implicit(ignore_inst_implicit) {}

    optional<result> mk_congr_simp(expr const & fn) {
        fun_info finfo = m_fmanager.get(fn);
        return mk_congr_simp(fn, finfo.get_arity());
    }

    optional<result> mk_congr_simp(expr const & fn, unsigned nargs) {
        auto r = m_cache.find(key(fn, nargs));
        if (r != m_cache.end())
            return optional<result>(r->second);
        fun_info finfo = m_fmanager.get(fn, nargs);
        list<unsigned> const & result_deps = finfo.get_dependencies();
        buffer<congr_arg_kind> kinds;
        buffer<param_info>     pinfos;
        to_buffer(finfo.get_params_info(), pinfos);
        kinds.resize(pinfos.size(), congr_arg_kind::Eq);
        for (unsigned i = 0; i < pinfos.size(); i++) {
            if (std::find(result_deps.begin(), result_deps.end(), i) != result_deps.end()) {
                kinds[i] = congr_arg_kind::Fixed;
            } else if (pinfos[i].is_subsingleton()) {
                if (empty(pinfos[i].get_dependencies()))
                    kinds[i] = congr_arg_kind::Fixed;
                else
                    kinds[i] = congr_arg_kind::Cast;
            } else if (pinfos[i].is_inst_implicit()) {
                lean_assert(!pinfos[i].is_subsingleton());
                kinds[i] = congr_arg_kind::Fixed;
            }
        }
        for (unsigned i = 0; i < pinfos.size(); i++) {
            for (unsigned j = i+1; j < pinfos.size(); j++) {
                auto j_deps = pinfos[j].get_dependencies();
                if (std::find(j_deps.begin(), j_deps.end(), i) != j_deps.end() &&
                    kinds[j] == congr_arg_kind::Eq) {
                    // We must fix i because there is a j that depends on i,
                    // and j is not fixed nor a cast-fixed.
                    kinds[i] = congr_arg_kind::Fixed;
                    break;
                }
            }
        }
        auto new_r = mk_congr_simp(fn, pinfos, kinds);
        if (new_r) {
            m_cache.insert(mk_pair(key(fn, nargs), *new_r));
            return new_r;
        } if (has_cast(kinds)) {
            // remove casts and try again
            for (unsigned i = 0; i < kinds.size(); i++) {
                if (kinds[i] == congr_arg_kind::Cast)
                    kinds[i] = congr_arg_kind::Fixed;
            }
            auto new_r = mk_congr_simp(fn, pinfos, kinds);
            if (new_r) {
                m_cache.insert(mk_pair(key(fn, nargs), *new_r));
                return new_r;
            } else {
                return new_r;
            }
        } else {
            return new_r;
        }
    }
};

congr_lemma_manager::congr_lemma_manager(app_builder & b, fun_info_manager & fm, bool ignore_inst_implicit):
    m_ptr(new imp(b, fm, ignore_inst_implicit)) {
}

congr_lemma_manager::~congr_lemma_manager() {
}

auto congr_lemma_manager::mk_congr_simp(expr const & fn) -> optional<result> {
    return m_ptr->mk_congr_simp(fn);
}
auto congr_lemma_manager::mk_congr_simp(expr const & fn, unsigned nargs) -> optional<result> {
    return m_ptr->mk_congr_simp(fn, nargs);
}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. 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.

// This file implements the RPC stubs which bind the LoggerService RPC
// handlers to a Logger instance.

#include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"

#include <windows.h>
#include <winnt.h>

#include "base/process.h"
#include "base/win/scoped_handle.h"
#include "syzygy/common/com_utils.h"
#include "syzygy/trace/agent_logger/agent_logger.h"
#include "syzygy/trace/rpc/logger_rpc.h"

namespace {

using base::ProcessId;
using base::win::ScopedHandle;
using trace::agent_logger::RpcLoggerInstanceManager;
using trace::agent_logger::AgentLogger;

bool GetClientInfo(handle_t binding, ProcessId* pid, ScopedHandle* handle) {
  DCHECK(pid != NULL);
  DCHECK(handle != NULL);

  // Get the RPC call attributes.
  static const int kVersion = 2;
  RPC_CALL_ATTRIBUTES_V2 attribs = { kVersion, RPC_QUERY_CLIENT_PID };
  RPC_STATUS status = RpcServerInqCallAttributes(binding, &attribs);
  if (status != RPC_S_OK) {
    LOG(ERROR) << "Failed to query RPC call attributes: "
               << ::common::LogWe(status) << ".";
    return false;
  }

  // Extract the process id.
  ProcessId the_pid = reinterpret_cast<ProcessId>(attribs.ClientPID);

  // Open and return the handle to the process.
  static const DWORD kFlags =
      PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
  handle->Set(::OpenProcess(kFlags, FALSE, the_pid));
  if (!handle->IsValid()) {
    DWORD error = ::GetLastError();
    LOG(ERROR) << "Failed to open PID=" << the_pid << ": "
               << ::common::LogWe(error) << ".";
    return false;
  }

  // And we're done.
  *pid = the_pid;
  return true;
}

void InitContext(const ExecutionContext* ext_ctx, CONTEXT* ctx) {
  DCHECK(ext_ctx != NULL);
  DCHECK(ctx != NULL);

  ::memset(ctx, 0, sizeof(*ctx));
  ctx->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

  // Populate the integer registers.
  ctx->Edi = ext_ctx->edi;
  ctx->Esi = ext_ctx->esi;
  ctx->Ebx = ext_ctx->ebx;
  ctx->Edx = ext_ctx->edx;
  ctx->Ecx = ext_ctx->ecx;
  ctx->Eax = ext_ctx->eax;

  // Populate the control registers.
  ctx->Ebp = ext_ctx->ebp;
  ctx->Eip = ext_ctx->eip;
  ctx->SegCs = ext_ctx->seg_cs;
  ctx->EFlags = ext_ctx->eflags;
  ctx->Esp = ext_ctx->esp;
  ctx->SegSs = ext_ctx->seg_ss;
}

}  // namespace

// The instance to which the RPC callbacks are bound.
AgentLogger* RpcLoggerInstanceManager::instance_ = NULL;

// RPC entrypoint for AgentLogger::Write().
boolean LoggerService_Write(
    /* [in] */ handle_t binding,
    /* [string][in] */ const unsigned char *text) {
  if (binding == NULL || text == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Write the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

boolean LoggerService_WriteWithContext(
    /* [in] */ handle_t binding,
    /* [in, string] */ const unsigned char* text,
    /* [in */ const ExecutionContext* exc_context ) {
  if (binding == NULL || text == NULL || exc_context == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Capture the stack trace for the caller's context.
  CONTEXT context = {};
  InitContext(exc_context, &context);
  std::vector<DWORD> trace_data;
  if (!instance->CaptureRemoteTrace(handle, &context, &trace_data)) {
    return false;
  }

  // Create the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->AppendTrace(
          handle, trace_data.data(), trace_data.size(), &message)) {
    return false;
  }

  // Write the log message.
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

boolean LoggerService_WriteWithTrace(
    /* [in] */ handle_t binding,
    /* [in, string] */ const unsigned char* text,
    /* [in, size_is(trace_length)] */ const unsigned long* trace_data,
    /* [in] */ LONG trace_length) {
  if (binding == NULL || text == NULL || trace_data == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Create the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->AppendTrace(handle, trace_data, trace_length, &message))
    return false;

  // Write the log message.
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

// RPC entrypoint for AgentLogger::SaveMinidump().
boolean LoggerService_SaveMiniDump(
    /* [in] */ handle_t binding,
    /* [in] */ unsigned long thread_id,
    /* [in] */ unsigned long exception,
    /* [in] */ unsigned long flags) {
  if (binding == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
  if (!instance->SaveMiniDump(handle, pid, thread_id, exception, flags))
    return false;

  return true;
}

// RPC entrypoint for AgentLogger::Stop().
boolean LoggerService_Stop(/* [in] */ handle_t binding) {
  if (binding == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
  if (!instance->Stop())
    return false;

  return true;
}
<commit_msg>Make agent_logger XP compatible.<commit_after>// Copyright 2012 Google Inc. 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.

// This file implements the RPC stubs which bind the LoggerService RPC
// handlers to a Logger instance.

#include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"

#include <windows.h>
#include <winnt.h>

#include "base/process.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "syzygy/common/com_utils.h"
#include "syzygy/trace/agent_logger/agent_logger.h"
#include "syzygy/trace/rpc/logger_rpc.h"

namespace {

using base::ProcessId;
using base::win::ScopedHandle;
using trace::agent_logger::RpcLoggerInstanceManager;
using trace::agent_logger::AgentLogger;

bool GetClientInfo(handle_t binding, ProcessId* pid, ScopedHandle* handle) {
  DCHECK(pid != NULL);
  DCHECK(handle != NULL);

  ProcessId the_pid = 0;
  RPC_STATUS status = 0;
  // RPC_CALL_ATTRIBUTES_V2 isn't available before Windows Vista.
  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    // Get the RPC call attributes.
    static const int kVersion = 2;
    RPC_CALL_ATTRIBUTES_V2 attribs = { kVersion, RPC_QUERY_CLIENT_PID };
    status = RpcServerInqCallAttributes(binding, &attribs);
    the_pid = reinterpret_cast<ProcessId>(attribs.ClientPID);
  } else {
    status = I_RpcBindingInqLocalClientPID(binding,
        reinterpret_cast<unsigned long*>(&the_pid));
  }

  if (status != RPC_S_OK) {
    LOG(ERROR) << "Failed to query RPC call attributes: "
               << ::common::LogWe(status) << ".";
    return false;
  }

  // Open and return the handle to the process.
  static const DWORD kFlags =
      PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
  handle->Set(::OpenProcess(kFlags, FALSE, the_pid));
  if (!handle->IsValid()) {
    DWORD error = ::GetLastError();
    LOG(ERROR) << "Failed to open PID=" << the_pid << ": "
               << ::common::LogWe(error) << ".";
    return false;
  }

  // And we're done.
  *pid = the_pid;
  return true;
}

void InitContext(const ExecutionContext* ext_ctx, CONTEXT* ctx) {
  DCHECK(ext_ctx != NULL);
  DCHECK(ctx != NULL);

  ::memset(ctx, 0, sizeof(*ctx));
  ctx->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

  // Populate the integer registers.
  ctx->Edi = ext_ctx->edi;
  ctx->Esi = ext_ctx->esi;
  ctx->Ebx = ext_ctx->ebx;
  ctx->Edx = ext_ctx->edx;
  ctx->Ecx = ext_ctx->ecx;
  ctx->Eax = ext_ctx->eax;

  // Populate the control registers.
  ctx->Ebp = ext_ctx->ebp;
  ctx->Eip = ext_ctx->eip;
  ctx->SegCs = ext_ctx->seg_cs;
  ctx->EFlags = ext_ctx->eflags;
  ctx->Esp = ext_ctx->esp;
  ctx->SegSs = ext_ctx->seg_ss;
}

}  // namespace

// The instance to which the RPC callbacks are bound.
AgentLogger* RpcLoggerInstanceManager::instance_ = NULL;

// RPC entrypoint for AgentLogger::Write().
boolean LoggerService_Write(
    /* [in] */ handle_t binding,
    /* [string][in] */ const unsigned char *text) {
  if (binding == NULL || text == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Write the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

boolean LoggerService_WriteWithContext(
    /* [in] */ handle_t binding,
    /* [in, string] */ const unsigned char* text,
    /* [in */ const ExecutionContext* exc_context ) {
  if (binding == NULL || text == NULL || exc_context == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Capture the stack trace for the caller's context.
  CONTEXT context = {};
  InitContext(exc_context, &context);
  std::vector<DWORD> trace_data;
  if (!instance->CaptureRemoteTrace(handle, &context, &trace_data)) {
    return false;
  }

  // Create the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->AppendTrace(
          handle, trace_data.data(), trace_data.size(), &message)) {
    return false;
  }

  // Write the log message.
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

boolean LoggerService_WriteWithTrace(
    /* [in] */ handle_t binding,
    /* [in, string] */ const unsigned char* text,
    /* [in, size_is(trace_length)] */ const unsigned long* trace_data,
    /* [in] */ LONG trace_length) {
  if (binding == NULL || text == NULL || trace_data == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  // Get the logger instance.
  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();

  // Create the log message.
  std::string message(reinterpret_cast<const char*>(text));
  if (!instance->AppendTrace(handle, trace_data, trace_length, &message))
    return false;

  // Write the log message.
  if (!instance->Write(message))
    return false;

  // And we're done.
  return true;
}

// RPC entrypoint for AgentLogger::SaveMinidump().
boolean LoggerService_SaveMiniDump(
    /* [in] */ handle_t binding,
    /* [in] */ unsigned long thread_id,
    /* [in] */ unsigned long exception,
    /* [in] */ unsigned long flags) {
  if (binding == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
  if (!instance->SaveMiniDump(handle, pid, thread_id, exception, flags))
    return false;

  return true;
}

// RPC entrypoint for AgentLogger::Stop().
boolean LoggerService_Stop(/* [in] */ handle_t binding) {
  if (binding == NULL) {
    LOG(ERROR) << "Invalid input parameter(s).";
    return false;
  }

  // Get the caller's process info.
  ProcessId pid = 0;
  ScopedHandle handle;
  if (!GetClientInfo(binding, &pid, &handle))
    return false;

  AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
  if (!instance->Stop())
    return false;

  return true;
}
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
//  Mat edges;
  for (; ;) {
    Mat mask;
    Mat frame, hsv;
    cap >> frame; // get a new frame from camera

    cvtColor(frame, hsv, CV_BGR2HSV);

    double minH = 30;
    double minS = 0;
    double minV = 240;
    double maxH = 80;
    double maxS = 70;
    double maxV = 255;

    cv::Scalar lower(minH, minS, minV);
    cv::Scalar upper(maxH, maxS, maxV);
    cv::inRange(hsv, lower, upper, mask);

//    bitwise_and(frame, frame, frame, mask);

//    medianBlur(mask, mask, 5);

    erode(mask, mask, Mat(), Point(-1,-1), 20);
    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180.0, 10, 100, 10);

    printf("Adding in %d lines\n", (int) lines.size());
    for (size_t i = 0; i < lines.size(); i++) {
      Vec4i l = lines[i];
      line(frame, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
      // break;
    }
    if (lines.size() < 1) continue;

    imshow("edges", mask);
    if (waitKey(30) >= 0) break;

  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<commit_msg>messing with erode<commit_after>/*

*/

#include "lineFollowing.h"

using namespace std;
using namespace cv;

ControlMovements lineFollowingControl() {

  line_main();

  return ControlMovements();
}

void line_main() {
//  printf("Hello, this is Caleb\n");

  VideoCapture cap("../../tests/videos/top_down_4.m4v");
  if (!cap.isOpened())  // check if we succeeded
    return;

  namedWindow("edges", CV_WINDOW_NORMAL);
//  Mat edges;
  for (; ;) {
    Mat mask;
    Mat frame, hsv;
    cap >> frame; // get a new frame from camera

    cvtColor(frame, hsv, CV_BGR2HSV);

    double minH = 30;
    double minS = 0;
    double minV = 240;
    double maxH = 80;
    double maxS = 70;
    double maxV = 255;

    cv::Scalar lower(minH, minS, minV);
    cv::Scalar upper(maxH, maxS, maxV);
    cv::inRange(hsv, lower, upper, mask);

//    bitwise_and(frame, frame, frame, mask);

//    medianBlur(mask, mask, 5);

    erode(mask, mask, Mat(), Point(-1,-1), 20);
    vector <Vec4i> lines;
    HoughLinesP(mask, lines, 1, CV_PI / 180.0, 10, 100, 10);

    printf("Adding in %d lines\n", (int) lines.size());
    for (size_t i = 0; i < lines.size(); i++) {
      Vec4i l = lines[i];
      line(frame, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
      // break;
    }
//    if (lines.size() < 1) continue;

    imshow("edges", mask);
    if (waitKey(30) >= 0) break;

  }
  // the camera will be deinitialized automatically in VideoCapture destructor
  return;
}
<|endoftext|>


<commit_before>/*

*/

#include "lineFollowing.h"
#include "../control.h"

using namespace std;
using namespace cv;

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list);

void draw_lines(Mat &image, const vector<Vec2f> &lines);

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going);

double deg2rad(double deg);

vector<Point> to_points(float theta, float rho);

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y);

void LineFollowing::detect_lines(Mat &original_frame) {

  Mat hsv;
  Mat mask;
  width = original_frame.cols;
  height = original_frame.rows;

  cvtColor(original_frame, hsv, CV_BGR2HSV); // Image is now HSV

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(hsv, lower, upper, mask); // Create a mask of only the desired color
  Canny(mask, mask, 50, 200, 3);

  vector<Vec2f> lines;
  HoughLines(mask, lines, 1, CV_PI / 180, 100, 0, 0);

  // printf("Adding in %d lines\n", (int) lines.size());

  vector<Vec2f> tmp = condense_lines(lines, true);
  sort(tmp.begin(), tmp.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });
  if (tmp.size() > 0) {
    found_lines = tmp;
  }

  draw_lines(original_frame, found_lines);

}

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going) {
  vector<Vec2f> condensed;
  vector<Vec2f> tmp_list;
  double diff;
  for (int i = 0; i < (int) lines.size(); i++) {
    /*    if (lines[i][1] > CV_PI / 2) {
        lines[i][1] -= CV_PI;
        lines[i][0] *= -1;
      }
      else if (lines[i][1] < ((CV_PI / 2) * -1)) {
        lines[i][1] += CV_PI;
        lines[i][0] *= -1;
      }*/

    lines[i][1] -= deg2rad(360);

    while (lines[i][1] < 0) {
      lines[i][1] += deg2rad(360);
    }
    /*
      if (lines[i][1] >= deg2rad(90)) {
        lines[i][1] -= deg2rad(180);
        lines[i][0] *= -1;
      }
    */

    //put in order of theta, rho
    swap(lines[i][0], lines[i][1]);
  }

  //Order from least to greatest theta
  sort(lines.begin(), lines.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });

  while (!lines.empty()) {
    Vec2f to_manipulate = lines.front();
    lines.erase(lines.begin());

    if (tmp_list.empty()) {
      tmp_list.push_back(to_manipulate);
      continue;
    } else {
      diff = abs(to_manipulate[0] - tmp_list.front()[0]);
      if (diff > deg2rad(180)) {
        diff = deg2rad(360) - diff;
      }
      if (diff < deg2rad(20)) {
        //The angles are similar
        if (abs(to_manipulate[1] - tmp_list.front()[1]) < 50) {
          //the distances are similar
          tmp_list.push_back(to_manipulate);
          continue;
        }
      } else {
        //Need to clear out the tmp_list
        compress_lines(condensed, tmp_list);

        tmp_list.clear();
        tmp_list.push_back(to_manipulate);

      }
    }
  }
  if (!tmp_list.empty()) {
    compress_lines(condensed, tmp_list);
  }

  condensed.back()[0] -= 360;
  if (keep_going) {
    condensed = condense_lines(condensed, false);
  }
  return condensed;
}

double deg2rad(double deg) {
  return deg * (CV_PI / 180.0);
}

double rad2deg(double rad) {
  return rad * (180.0 / CV_PI);
}

void draw_lines(Mat &image, const vector<Vec2f> &lines) {
  for (size_t i = 0; i < lines.size(); i++) {
    float theta = lines[i][0], rho = lines[i][1];
    // float rho = lines[i][0], theta = lines[i][1];Point pt1;
    vector<Point> p = to_points(theta, rho);
    line(image, p[0], p[1], Scalar(255 * (i == 0), 255 * (i == 1), 255 * (i == 2)), 3, CV_AA);
  }
}

vector<Point> to_points(float theta, float rho) {
  vector<Point> rv = {Point(), Point()};
  double a = cos(theta), b = sin(theta);
  double x0 = a * rho, y0 = b * rho;
  rv[0].x = cvRound(x0 + 1000 * (-b));
  rv[0].y = cvRound(y0 + 1000 * (a));
  rv[1].x = cvRound(x0 - 1000 * (-b));
  rv[1].y = cvRound(y0 - 1000 * (a));
  return rv;
}

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list) {
  Vec2f new_point;
  float angle_sum = 0;
  float rho_sum = 0;
  for (int j = 0; j < (int) tmp_list.size(); ++j) {
    angle_sum += tmp_list[j][0];
    rho_sum += tmp_list[j][1];
  }
  angle_sum /= tmp_list.size();
  rho_sum /= tmp_list.size();

  new_point[0] = angle_sum;
  new_point[1] = rho_sum;

  condensed.push_back(new_point);
}

LineFollowing::LineFollowing(Control *control) {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  control_ptr = control;
  minH = 50;
  minS = 20;
  minV = 150;
  maxH = 125;
  maxS = 100;
  maxV = 255;
  return;
}

void LineFollowing::close() {
  return;
}

void LineFollowing::fly() {
  // cout << "line following\n";
  detect_lines(control_ptr->image);

  control_ptr->velocities.vx = 0;
  control_ptr->velocities.vy = 0;
  control_ptr->velocities.vz = 0;
  control_ptr->velocities.vr = 0;

  if (found_lines.size() < 1) {
    //I found no lines
    // printf("Found nothing\n");
    return;
  }
  double calculated_distance = distance_from_center(found_lines[0][1], found_lines[0][0], control_ptr->image.cols,
                                                    control_ptr->image.rows);

  // printf("calc dist of %f ", calculated_distance);
  int origin_x = 0 + (control_ptr->image.cols / 2);
  int origin_y = 0 + (control_ptr->image.rows / 2);
  Point pt1 = cvPoint(origin_x, origin_y);
  Point pt2 = cvPoint(origin_x + cvRound(calculated_distance), origin_y);
  line(control_ptr->image, pt1, pt2, Scalar(0, 0, 255), 3, CV_AA);

  if (found_lines.size() > 1) {
    // I need to turn
    //TODO: move until line is centered
    //TODO: look for symbol, and turn
    origin_x = 0;
    origin_y = 0;
    Vec2i point = find_intersection(found_lines[0], found_lines[1]);
    //printf("My coords are x: %3d y %3d\n", point[0], point[1]);
    line(control_ptr->image, cvPoint(origin_x + point[0] + 10, origin_y + point[1]),
         cvPoint(origin_x + point[0] - 10, origin_y + point[1]), Scalar(0, 255, 0), 3, CV_AA);
    line(control_ptr->image, cvPoint(origin_x + point[0], origin_y + point[1] + 10),
         cvPoint(origin_x + point[0], origin_y + point[1] - 10), Scalar(0, 255, 0), 3, CV_AA);
    if (found_lines.size() >= 4) {
      for (int j = 0; j < (int) found_lines.size(); j++) {
        printf("theta: %.1f rho: %.0f  ", found_lines[j][0] * (180 / CV_PI), found_lines[j][1]);
      }
      printf("\n");
    }
    return;
  }

  else {
    // I need to snap myself to the line
    if (found_lines[0][0] >= deg2rad(5)) {
      control_ptr->velocities.vr = -.2;
      printf("Turning Right\n");
    }
    else if (found_lines[0][0] <= deg2rad(-1 * 5)) {
      control_ptr->velocities.vr = .2;
      printf("Turning Left\n");
    } else {
      printf("Checking Distance\n");

      double offset = calculated_distance;
      // printf("Offset is: %5.2f with a distance of %5.2f and width of %5.2f halved to %5.2f\n", offset,
      // found_lines[0][1],
      // (double) control_ptr->image.cols, (control_ptr->image.cols / 2.0));
      if (-100 <= offset && offset <= 100) {
        printf("No need to move\n");
      } else if (offset < 0) {
        //we are to the right of the line
        //we need to move left
        control_ptr->velocities.vy = 1;
        printf("Move left\n");
      } else {
        //we need to move right
        control_ptr->velocities.vy = -1;
        printf("Move right\n");
      }
    }
  }

  return;
}

double LineFollowing::distance_from_center(float rho, float theta, double width, double height) {
  // printf("width: %f height: %f\n", width, height);
  theta = -1 * (theta);
  double rh = rho * cos(theta);
  double rv = rho * sin(theta);
  // rh = abs(rh);
  // rv *= -1;
  double excess = (width / 2.0) - rh;
  // excess *=-1;
  double lv = rv + (height / 2.0);
  double lh = lv * tan(theta);
  // lh = abs(lh);
  double x = lh - excess;

  // printf("ro: %4f th: %4f rh: %4f rv: %4f ex: %4f lv: %4f lh: %4f x: %4f\n", rho, theta ,rh, rv, excess, lv,lh,x);

  return x;
}

cv::Point LineFollowing::find_intersection(Vec2f a, Vec2f b) {
  Point rv;
  bool do_intersect = parametricIntersect(a[1], a[0], b[1], b[0], rv.x, rv.y);
  if (!do_intersect) {
    printf("No intersection!\n");
  }

  return rv;
}

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y) {
  float ct1 = cosf(t1);     //matrix element a
  float st1 = sinf(t1);     //b
  float ct2 = cosf(t2);     //c
  float st2 = sinf(t2);     //d
  float d = ct1 * st2 - st1 * ct2;        //determinative (rearranged matrix for inverse)
  if (d != 0.0f) {
    x = (int) ((st2 * r1 - st1 * r2) / d);
    y = (int) ((-ct2 * r1 + ct1 * r2) / d);
    return (true);
  } else { //lines are parallel and will NEVER intersect!
    return (false);
  }
}
<commit_msg>detects 3 lines robustly<commit_after>/*

*/

#include "lineFollowing.h"
#include "../control.h"

using namespace std;
using namespace cv;

double rad2deg(double rad);

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list);

void draw_lines(Mat &image, const vector<Vec2f> &lines);

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going);

double deg2rad(double deg);

vector<Point> to_points(float theta, float rho);

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y);

void LineFollowing::detect_lines(Mat &original_frame) {

  Mat hsv;
  Mat mask;
  width = original_frame.cols;
  height = original_frame.rows;

  cvtColor(original_frame, hsv, CV_BGR2HSV); // Image is now HSV

  Scalar lower(minH, minS, minV);
  Scalar upper(maxH, maxS, maxV);
  inRange(hsv, lower, upper, mask); // Create a mask of only the desired color
  Canny(mask, mask, 50, 200, 3);

  vector<Vec2f> lines;
  HoughLines(mask, lines, 1, CV_PI / 180, 100, 0, 0);

  // printf("Adding in %d lines\n", (int) lines.size());

  vector<Vec2f> tmp = condense_lines(lines, true);
  sort(tmp.begin(), tmp.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });
  if (tmp.size() > 0) {
    found_lines = tmp;
  }

  draw_lines(original_frame, found_lines);

}

vector<Vec2f> condense_lines(vector<Vec2f> lines, bool keep_going) {
  vector<Vec2f> condensed;
  vector<Vec2f> tmp_list;
  double diff;
  if (keep_going){
  for (int i = 0; i < (int) lines.size(); i++) {
    /*    if (lines[i][1] > CV_PI / 2) {
        lines[i][1] -= CV_PI;
        lines[i][0] *= -1;
      }
      else if (lines[i][1] < ((CV_PI / 2) * -1)) {
        lines[i][1] += CV_PI;
        lines[i][0] *= -1;
      }*/

    lines[i][1] -= deg2rad(360);

    while (lines[i][1] < 0) {
      lines[i][1] += deg2rad(360);
    }

      if (lines[i][1] >= deg2rad(90)) {
        lines[i][1] -= deg2rad(180);
        lines[i][0] *= -1;
      }

    //put in order of theta, rho
    swap(lines[i][0], lines[i][1]);

  }
  // return lines;
}
  //Order from least to greatest theta
  sort(lines.begin(), lines.end(),
       [](const Vec2f &a, const Vec2f &b) {
         return a[0] < b[0];
       });

  while (!lines.empty()) {
    Vec2f to_manipulate = lines.front();
    lines.erase(lines.begin());

    if (tmp_list.empty()) {
      tmp_list.push_back(to_manipulate);
      continue;
    } else {
      diff = abs(to_manipulate[0] - tmp_list.front()[0]);
      if (diff > deg2rad(180)) {
        diff = deg2rad(360) - diff;
      }
      if (diff < deg2rad(10)) {
        //The angles are similar
        if (abs(to_manipulate[1] - tmp_list.front()[1]) < 5) {
          //the distances are similar
          tmp_list.push_back(to_manipulate);
          continue;
        }
      } else {
        //Need to clear out the tmp_list
        compress_lines(condensed, tmp_list);

        tmp_list.clear();
        tmp_list.push_back(to_manipulate);

      }
    }
  }
  if (!tmp_list.empty()) {
    compress_lines(condensed, tmp_list);
  }
  if (condensed.size() >= 2)
  {
    // printf("changing %.1f", rad2deg(condensed.back()[0]));
  condensed.back()[0] -= deg2rad(180);
  condensed.back()[1] *= -1;
  // printf(" to %.1f\n", rad2deg(condensed.back()[0]));
  if (keep_going) {
    condensed = condense_lines(condensed, false);
  }
}
  return condensed;
}

double deg2rad(double deg) {
  return deg * (CV_PI / 180.0);
}

double rad2deg(double rad) {
  return rad * (180.0 / CV_PI);
}

void draw_lines(Mat &image, const vector<Vec2f> &lines) {
  for (size_t i = 0; i < lines.size(); i++) {
    float theta = lines[i][0], rho = lines[i][1];
    // float rho = lines[i][0], theta = lines[i][1];Point pt1;
    vector<Point> p = to_points(theta, rho);
    line(image, p[0], p[1], Scalar(255 * (i == 0), 255 * (i == 1), 255 * (i == 2)), 3, CV_AA);
  }
}

vector<Point> to_points(float theta, float rho) {
  vector<Point> rv = {Point(), Point()};
  double a = cos(theta), b = sin(theta);
  double x0 = a * rho, y0 = b * rho;
  rv[0].x = cvRound(x0 + 1000 * (-b));
  rv[0].y = cvRound(y0 + 1000 * (a));
  rv[1].x = cvRound(x0 - 1000 * (-b));
  rv[1].y = cvRound(y0 - 1000 * (a));
  return rv;
}

void compress_lines(vector<Vec2f> &condensed, const vector<Vec2f> &tmp_list) {
  Vec2f new_point;
  float angle_sum = 0;
  float rho_sum = 0;
  for (int j = 0; j < (int) tmp_list.size(); ++j) {
    angle_sum += tmp_list[j][0];
    rho_sum += tmp_list[j][1];
  }
  angle_sum /= tmp_list.size();
  rho_sum /= tmp_list.size();

  new_point[0] = angle_sum;
  new_point[1] = rho_sum;

  condensed.push_back(new_point);
}

LineFollowing::LineFollowing(Control *control) {
  namedWindow("line_window", CV_WINDOW_NORMAL);
  control_ptr = control;
  minH = 50;
  minS = 20;
  minV = 150;
  maxH = 125;
  maxS = 100;
  maxV = 255;
  return;
}

void LineFollowing::close() {
  return;
}

void LineFollowing::fly() {
  // cout << "line following\n";
  detect_lines(control_ptr->image);

  control_ptr->velocities.vx = 0;
  control_ptr->velocities.vy = 0;
  control_ptr->velocities.vz = 0;
  control_ptr->velocities.vr = 0;

  if (found_lines.size() < 1) {
    //I found no lines
    // printf("Found nothing\n");
    return;
  }
  double calculated_distance = distance_from_center(found_lines[0][1], found_lines[0][0], control_ptr->image.cols,
                                                    control_ptr->image.rows);

  // printf("calc dist of %f ", calculated_distance);
  int origin_x = 0 + (control_ptr->image.cols / 2);
  int origin_y = 0 + (control_ptr->image.rows / 2);
  Point pt1 = cvPoint(origin_x, origin_y);
  Point pt2 = cvPoint(origin_x + cvRound(calculated_distance), origin_y);
  line(control_ptr->image, pt1, pt2, Scalar(255, 255, 255), 3, CV_AA);

  if (found_lines.size() > 1) {
    // I need to turn
    //TODO: move until line is centered
    //TODO: look for symbol, and turn
    origin_x = 0;
    origin_y = 0;
    Vec2i point = find_intersection(found_lines[0], found_lines[1]);
    //printf("My coords are x: %3d y %3d\n", point[0], point[1]);
    line(control_ptr->image, cvPoint(origin_x + point[0] + 10, origin_y + point[1]),
         cvPoint(origin_x + point[0] - 10, origin_y + point[1]), Scalar(255, 255, 255), 3, CV_AA);
    line(control_ptr->image, cvPoint(origin_x + point[0], origin_y + point[1] + 10),
         cvPoint(origin_x + point[0], origin_y + point[1] - 10), Scalar(255, 255, 255), 3, CV_AA);
    if (found_lines.size() >= 3) {
      for (int j = 0; j < (int) found_lines.size(); j++) {
        printf("(%.1f, %.0f) ", rad2deg(found_lines[j][0]) + 90, found_lines[j][1]);
      }
      printf("\n");
    }
    return;
  }

  else {
    // I need to snap myself to the line
    if (found_lines[0][0] >= deg2rad(5)) {
      control_ptr->velocities.vr = -.2;
      // printf("Turning Right\n");
    }
    else if (found_lines[0][0] <= deg2rad(-1 * 5)) {
      control_ptr->velocities.vr = .2;
      // printf("Turning Left\n");
    } else {
      // printf("Checking Distance\n");

      double offset = calculated_distance;
      // printf("Offset is: %5.2f with a distance of %5.2f and width of %5.2f halved to %5.2f\n", offset,
      // found_lines[0][1],
      // (double) control_ptr->image.cols, (control_ptr->image.cols / 2.0));
      if (-100 <= offset && offset <= 100) {
        // printf("No need to move\n");
      } else if (offset < 0) {
        //we are to the right of the line
        //we need to move left
        control_ptr->velocities.vy = 1;
        // printf("Move left\n");
      } else {
        //we need to move right
        control_ptr->velocities.vy = -1;
        // printf("Move right\n");
      }
    }
  }

  return;
}

double LineFollowing::distance_from_center(float rho, float theta, double width, double height) {
  // printf("width: %f height: %f\n", width, height);
  theta = -1 * (theta);
  double rh = rho * cos(theta);
  double rv = rho * sin(theta);
  // rh = abs(rh);
  // rv *= -1;
  double excess = (width / 2.0) - rh;
  // excess *=-1;
  double lv = rv + (height / 2.0);
  double lh = lv * tan(theta);
  // lh = abs(lh);
  double x = lh - excess;

  // printf("ro: %4f th: %4f rh: %4f rv: %4f ex: %4f lv: %4f lh: %4f x: %4f\n", rho, theta ,rh, rv, excess, lv,lh,x);

  return x;
}

cv::Point LineFollowing::find_intersection(Vec2f a, Vec2f b) {
  Point rv;
  bool do_intersect = parametricIntersect(a[1], a[0], b[1], b[0], rv.x, rv.y);
  if (!do_intersect) {
    printf("No intersection!\n");
  }

  return rv;
}

bool parametricIntersect(float r1, float t1, float r2, float t2, int &x, int &y) {
  float ct1 = cosf(t1);     //matrix element a
  float st1 = sinf(t1);     //b
  float ct2 = cosf(t2);     //c
  float st2 = sinf(t2);     //d
  float d = ct1 * st2 - st1 * ct2;        //determinative (rearranged matrix for inverse)
  if (d != 0.0f) {
    x = (int) ((st2 * r1 - st1 * r2) / d);
    y = (int) ((-ct2 * r1 + ct1 * r2) / d);
    return (true);
  } else { //lines are parallel and will NEVER intersect!
    return (false);
  }
}
<|endoftext|>


<commit_before>/* Copyright 2019 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/opencl_wrapper.h"

#if defined(_WIN32)
#define __WINDOWS__
#endif

#ifdef __WINDOWS__
#include <windows.h>
#else
#include <dlfcn.h>
#endif

#include <string>

#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {

#ifdef __ANDROID__
#define LoadFunction(function)                                                 \
  if (is_pixel) {                                                              \
    function = reinterpret_cast<PFN_##function>(loadOpenCLPointer(#function)); \
  } else {                                                                     \
    function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));  \
  }
#elif defined(__WINDOWS__)
#define LoadFunction(function) \
  function =                   \
      reinterpret_cast<PFN_##function>(GetProcAddress(libopencl, #function));
#else
#define LoadFunction(function) \
  function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));
#endif

#ifdef __WINDOWS__
void LoadOpenCLFunctions(HMODULE libopencl);
#else
void LoadOpenCLFunctions(void* libopencl, bool is_pixel);
#endif

absl::Status LoadOpenCL() {
#ifdef __WINDOWS__
  HMODULE libopencl = LoadLibraryA("OpenCL.dll");
  if (libopencl) {
    LoadOpenCLFunctions(libopencl);
    return absl::OkStatus();
  } else {
    DWORD error_code = GetLastError();
    return absl::UnknownError(absl::StrCat(
        "Can not open OpenCL library on this device, error code - ",
        error_code));
  }
#else
  void* libopencl = dlopen("libOpenCL.so", RTLD_NOW | RTLD_LOCAL);
  if (libopencl) {
    LoadOpenCLFunctions(libopencl, false);
    return absl::OkStatus();
  }
  // record error
  std::string error(dlerror());
#ifdef __ANDROID__
  // Pixel phone?
  libopencl = dlopen("libOpenCL-pixel.so", RTLD_NOW | RTLD_LOCAL);
  if (libopencl) {
    typedef void (*enableOpenCL_t)();
    enableOpenCL_t enableOpenCL =
        reinterpret_cast<enableOpenCL_t>(dlsym(libopencl, "enableOpenCL"));
    enableOpenCL();
    LoadOpenCLFunctions(libopencl, true);
    return absl::OkStatus();
  }
#endif
  return absl::UnknownError(
      absl::StrCat("Can not open OpenCL library on this device - ", error));
#endif
}

#ifdef __WINDOWS__
void LoadOpenCLFunctions(HMODULE libopencl) {
#else
void LoadOpenCLFunctions(void* libopencl, bool is_pixel) {
#ifdef __ANDROID__
  typedef void* (*loadOpenCLPointer_t)(const char* name);
  loadOpenCLPointer_t loadOpenCLPointer;
  if (is_pixel) {
    loadOpenCLPointer = reinterpret_cast<loadOpenCLPointer_t>(
        dlsym(libopencl, "loadOpenCLPointer"));
  }
#endif
#endif

  LoadFunction(clGetPlatformIDs);
  LoadFunction(clGetPlatformInfo);
  LoadFunction(clGetDeviceIDs);
  LoadFunction(clGetDeviceInfo);
  LoadFunction(clCreateSubDevices);
  LoadFunction(clRetainDevice);
  LoadFunction(clReleaseDevice);
  LoadFunction(clCreateContext);
  LoadFunction(clCreateContextFromType);
  LoadFunction(clRetainContext);
  LoadFunction(clReleaseContext);
  LoadFunction(clGetContextInfo);
  LoadFunction(clCreateCommandQueueWithProperties);
  LoadFunction(clRetainCommandQueue);
  LoadFunction(clReleaseCommandQueue);
  LoadFunction(clGetCommandQueueInfo);
  LoadFunction(clCreateBuffer);
  LoadFunction(clCreateSubBuffer);
  LoadFunction(clCreateImage);
  LoadFunction(clCreatePipe);
  LoadFunction(clRetainMemObject);
  LoadFunction(clReleaseMemObject);
  LoadFunction(clGetSupportedImageFormats);
  LoadFunction(clGetMemObjectInfo);
  LoadFunction(clGetImageInfo);
  LoadFunction(clGetPipeInfo);
  LoadFunction(clSetMemObjectDestructorCallback);
  LoadFunction(clSVMAlloc);
  LoadFunction(clSVMFree);
  LoadFunction(clCreateSamplerWithProperties);
  LoadFunction(clRetainSampler);
  LoadFunction(clReleaseSampler);
  LoadFunction(clGetSamplerInfo);
  LoadFunction(clCreateProgramWithSource);
  LoadFunction(clCreateProgramWithBinary);
  LoadFunction(clCreateProgramWithBuiltInKernels);
  LoadFunction(clRetainProgram);
  LoadFunction(clReleaseProgram);
  LoadFunction(clBuildProgram);
  LoadFunction(clCompileProgram);
  LoadFunction(clLinkProgram);
  LoadFunction(clUnloadPlatformCompiler);
  LoadFunction(clGetProgramInfo);
  LoadFunction(clGetProgramBuildInfo);
  LoadFunction(clCreateKernel);
  LoadFunction(clCreateKernelsInProgram);
  LoadFunction(clRetainKernel);
  LoadFunction(clReleaseKernel);
  LoadFunction(clSetKernelArg);
  LoadFunction(clSetKernelArgSVMPointer);
  LoadFunction(clSetKernelExecInfo);
  LoadFunction(clGetKernelInfo);
  LoadFunction(clGetKernelArgInfo);
  LoadFunction(clGetKernelWorkGroupInfo);
  LoadFunction(clWaitForEvents);
  LoadFunction(clGetEventInfo);
  LoadFunction(clCreateUserEvent);
  LoadFunction(clRetainEvent);
  LoadFunction(clReleaseEvent);
  LoadFunction(clSetUserEventStatus);
  LoadFunction(clSetEventCallback);
  LoadFunction(clGetEventProfilingInfo);
  LoadFunction(clFlush);
  LoadFunction(clFinish);
  LoadFunction(clEnqueueReadBuffer);
  LoadFunction(clEnqueueReadBufferRect);
  LoadFunction(clEnqueueWriteBuffer);
  LoadFunction(clEnqueueWriteBufferRect);
  LoadFunction(clEnqueueFillBuffer);
  LoadFunction(clEnqueueCopyBuffer);
  LoadFunction(clEnqueueCopyBufferRect);
  LoadFunction(clEnqueueReadImage);
  LoadFunction(clEnqueueWriteImage);
  LoadFunction(clEnqueueFillImage);
  LoadFunction(clEnqueueCopyImage);
  LoadFunction(clEnqueueCopyImageToBuffer);
  LoadFunction(clEnqueueCopyBufferToImage);
  LoadFunction(clEnqueueMapBuffer);
  LoadFunction(clEnqueueMapImage);
  LoadFunction(clEnqueueUnmapMemObject);
  LoadFunction(clEnqueueMigrateMemObjects);
  LoadFunction(clEnqueueNDRangeKernel);
  LoadFunction(clEnqueueNativeKernel);
  LoadFunction(clEnqueueMarkerWithWaitList);
  LoadFunction(clEnqueueBarrierWithWaitList);
  LoadFunction(clEnqueueSVMFree);
  LoadFunction(clEnqueueSVMMemcpy);
  LoadFunction(clEnqueueSVMMemFill);
  LoadFunction(clEnqueueSVMMap);
  LoadFunction(clEnqueueSVMUnmap);
  LoadFunction(clGetExtensionFunctionAddressForPlatform);
  LoadFunction(clCreateImage2D);
  LoadFunction(clCreateImage3D);
  LoadFunction(clEnqueueMarker);
  LoadFunction(clEnqueueWaitForEvents);
  LoadFunction(clEnqueueBarrier);
  LoadFunction(clUnloadCompiler);
  LoadFunction(clGetExtensionFunctionAddress);
  LoadFunction(clCreateCommandQueue);
  LoadFunction(clCreateSampler);
  LoadFunction(clEnqueueTask);

  // OpenGL sharing
  LoadFunction(clCreateFromGLBuffer);
  LoadFunction(clCreateFromGLTexture);
  LoadFunction(clEnqueueAcquireGLObjects);
  LoadFunction(clEnqueueReleaseGLObjects);

  // cl_khr_egl_event extension
  LoadFunction(clCreateEventFromEGLSyncKHR);

  // EGL sharing
  LoadFunction(clCreateFromEGLImageKHR);
  LoadFunction(clEnqueueAcquireEGLObjectsKHR);
  LoadFunction(clEnqueueReleaseEGLObjectsKHR);
}

// No OpenCL support, do not set function addresses
PFN_clGetPlatformIDs clGetPlatformIDs;
PFN_clGetPlatformInfo clGetPlatformInfo;
PFN_clGetDeviceIDs clGetDeviceIDs;
PFN_clGetDeviceInfo clGetDeviceInfo;
PFN_clCreateSubDevices clCreateSubDevices;
PFN_clRetainDevice clRetainDevice;
PFN_clReleaseDevice clReleaseDevice;
PFN_clCreateContext clCreateContext;
PFN_clCreateContextFromType clCreateContextFromType;
PFN_clRetainContext clRetainContext;
PFN_clReleaseContext clReleaseContext;
PFN_clGetContextInfo clGetContextInfo;
PFN_clCreateCommandQueueWithProperties clCreateCommandQueueWithProperties;
PFN_clRetainCommandQueue clRetainCommandQueue;
PFN_clReleaseCommandQueue clReleaseCommandQueue;
PFN_clGetCommandQueueInfo clGetCommandQueueInfo;
PFN_clCreateBuffer clCreateBuffer;
PFN_clCreateSubBuffer clCreateSubBuffer;
PFN_clCreateImage clCreateImage;
PFN_clCreatePipe clCreatePipe;
PFN_clRetainMemObject clRetainMemObject;
PFN_clReleaseMemObject clReleaseMemObject;
PFN_clGetSupportedImageFormats clGetSupportedImageFormats;
PFN_clGetMemObjectInfo clGetMemObjectInfo;
PFN_clGetImageInfo clGetImageInfo;
PFN_clGetPipeInfo clGetPipeInfo;
PFN_clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback;
PFN_clSVMAlloc clSVMAlloc;
PFN_clSVMFree clSVMFree;
PFN_clCreateSamplerWithProperties clCreateSamplerWithProperties;
PFN_clRetainSampler clRetainSampler;
PFN_clReleaseSampler clReleaseSampler;
PFN_clGetSamplerInfo clGetSamplerInfo;
PFN_clCreateProgramWithSource clCreateProgramWithSource;
PFN_clCreateProgramWithBinary clCreateProgramWithBinary;
PFN_clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels;
PFN_clRetainProgram clRetainProgram;
PFN_clReleaseProgram clReleaseProgram;
PFN_clBuildProgram clBuildProgram;
PFN_clCompileProgram clCompileProgram;
PFN_clLinkProgram clLinkProgram;
PFN_clUnloadPlatformCompiler clUnloadPlatformCompiler;
PFN_clGetProgramInfo clGetProgramInfo;
PFN_clGetProgramBuildInfo clGetProgramBuildInfo;
PFN_clCreateKernel clCreateKernel;
PFN_clCreateKernelsInProgram clCreateKernelsInProgram;
PFN_clRetainKernel clRetainKernel;
PFN_clReleaseKernel clReleaseKernel;
PFN_clSetKernelArg clSetKernelArg;
PFN_clSetKernelArgSVMPointer clSetKernelArgSVMPointer;
PFN_clSetKernelExecInfo clSetKernelExecInfo;
PFN_clGetKernelInfo clGetKernelInfo;
PFN_clGetKernelArgInfo clGetKernelArgInfo;
PFN_clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo;
PFN_clWaitForEvents clWaitForEvents;
PFN_clGetEventInfo clGetEventInfo;
PFN_clCreateUserEvent clCreateUserEvent;
PFN_clRetainEvent clRetainEvent;
PFN_clReleaseEvent clReleaseEvent;
PFN_clSetUserEventStatus clSetUserEventStatus;
PFN_clSetEventCallback clSetEventCallback;
PFN_clGetEventProfilingInfo clGetEventProfilingInfo;
PFN_clFlush clFlush;
PFN_clFinish clFinish;
PFN_clEnqueueReadBuffer clEnqueueReadBuffer;
PFN_clEnqueueReadBufferRect clEnqueueReadBufferRect;
PFN_clEnqueueWriteBuffer clEnqueueWriteBuffer;
PFN_clEnqueueWriteBufferRect clEnqueueWriteBufferRect;
PFN_clEnqueueFillBuffer clEnqueueFillBuffer;
PFN_clEnqueueCopyBuffer clEnqueueCopyBuffer;
PFN_clEnqueueCopyBufferRect clEnqueueCopyBufferRect;
PFN_clEnqueueReadImage clEnqueueReadImage;
PFN_clEnqueueWriteImage clEnqueueWriteImage;
PFN_clEnqueueFillImage clEnqueueFillImage;
PFN_clEnqueueCopyImage clEnqueueCopyImage;
PFN_clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer;
PFN_clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage;
PFN_clEnqueueMapBuffer clEnqueueMapBuffer;
PFN_clEnqueueMapImage clEnqueueMapImage;
PFN_clEnqueueUnmapMemObject clEnqueueUnmapMemObject;
PFN_clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects;
PFN_clEnqueueNDRangeKernel clEnqueueNDRangeKernel;
PFN_clEnqueueNativeKernel clEnqueueNativeKernel;
PFN_clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList;
PFN_clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList;
PFN_clEnqueueSVMFree clEnqueueSVMFree;
PFN_clEnqueueSVMMemcpy clEnqueueSVMMemcpy;
PFN_clEnqueueSVMMemFill clEnqueueSVMMemFill;
PFN_clEnqueueSVMMap clEnqueueSVMMap;
PFN_clEnqueueSVMUnmap clEnqueueSVMUnmap;
PFN_clGetExtensionFunctionAddressForPlatform
    clGetExtensionFunctionAddressForPlatform;
PFN_clCreateImage2D clCreateImage2D;
PFN_clCreateImage3D clCreateImage3D;
PFN_clEnqueueMarker clEnqueueMarker;
PFN_clEnqueueWaitForEvents clEnqueueWaitForEvents;
PFN_clEnqueueBarrier clEnqueueBarrier;
PFN_clUnloadCompiler clUnloadCompiler;
PFN_clGetExtensionFunctionAddress clGetExtensionFunctionAddress;
PFN_clCreateCommandQueue clCreateCommandQueue;
PFN_clCreateSampler clCreateSampler;
PFN_clEnqueueTask clEnqueueTask;

// OpenGL sharing
PFN_clCreateFromGLBuffer clCreateFromGLBuffer;
PFN_clCreateFromGLTexture clCreateFromGLTexture;
PFN_clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects;
PFN_clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects;

// cl_khr_egl_event extension
PFN_clCreateEventFromEGLSyncKHR clCreateEventFromEGLSyncKHR;

// EGL sharing
PFN_clCreateFromEGLImageKHR clCreateFromEGLImageKHR;
PFN_clEnqueueAcquireEGLObjectsKHR clEnqueueAcquireEGLObjectsKHR;
PFN_clEnqueueReleaseEGLObjectsKHR clEnqueueReleaseEGLObjectsKHR;

cl_mem CreateImage2DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage2D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_row_pitch, host_ptr, errcode_ret);
  }
}

cl_mem CreateImage3DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage3D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_depth, image_desc->image_row_pitch,
                           image_desc->image_slice_pitch, host_ptr,
                           errcode_ret);
  }
}
}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Internal change<commit_after>/* Copyright 2019 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/opencl_wrapper.h"

#if defined(_WIN32)
#define __WINDOWS__
#endif

#ifdef __WINDOWS__
#include <windows.h>
#else
#include <dlfcn.h>
#endif

#include <string>

#include "absl/strings/str_cat.h"
#include "tensorflow/lite/delegates/gpu/common/status.h"

namespace tflite {
namespace gpu {
namespace cl {

#ifdef __ANDROID__
#define LoadFunction(function)                                                 \
  if (use_wrapper) {                                                           \
    function = reinterpret_cast<PFN_##function>(loadOpenCLPointer(#function)); \
  } else {                                                                     \
    function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));  \
  }
#elif defined(__WINDOWS__)
#define LoadFunction(function) \
  function =                   \
      reinterpret_cast<PFN_##function>(GetProcAddress(libopencl, #function));
#else
#define LoadFunction(function) \
  function = reinterpret_cast<PFN_##function>(dlsym(libopencl, #function));
#endif

#ifdef __WINDOWS__
void LoadOpenCLFunctions(HMODULE libopencl);
#else
void LoadOpenCLFunctions(void* libopencl, bool use_wrapper);
#endif

absl::Status LoadOpenCL() {
#ifdef __WINDOWS__
  HMODULE libopencl = LoadLibraryA("OpenCL.dll");
  if (libopencl) {
    LoadOpenCLFunctions(libopencl);
    return absl::OkStatus();
  } else {
    DWORD error_code = GetLastError();
    return absl::UnknownError(absl::StrCat(
        "Can not open OpenCL library on this device, error code - ",
        error_code));
  }
#else
  void* libopencl = dlopen("libOpenCL.so", RTLD_NOW | RTLD_LOCAL);
  if (libopencl) {
    LoadOpenCLFunctions(libopencl, false);
    return absl::OkStatus();
  }
  // record error
  std::string error(dlerror());
#ifdef __ANDROID__
  // Pixel phone or auto?
  libopencl = dlopen("libOpenCL-pixel.so", RTLD_NOW | RTLD_LOCAL);
  if (!libopencl) {
    libopencl = dlopen("libOpenCL-car.so", RTLD_NOW | RTLD_LOCAL);
  }
  if (libopencl) {
    typedef void (*enableOpenCL_t)();
    enableOpenCL_t enableOpenCL =
        reinterpret_cast<enableOpenCL_t>(dlsym(libopencl, "enableOpenCL"));
    enableOpenCL();
    LoadOpenCLFunctions(libopencl, true);
    return absl::OkStatus();
  }
#endif
  return absl::UnknownError(
      absl::StrCat("Can not open OpenCL library on this device - ", error));
#endif
}

#ifdef __WINDOWS__
void LoadOpenCLFunctions(HMODULE libopencl) {
#else
void LoadOpenCLFunctions(void* libopencl, bool use_wrapper) {
#ifdef __ANDROID__
  typedef void* (*loadOpenCLPointer_t)(const char* name);
  loadOpenCLPointer_t loadOpenCLPointer;
  if (use_wrapper) {
    loadOpenCLPointer = reinterpret_cast<loadOpenCLPointer_t>(
        dlsym(libopencl, "loadOpenCLPointer"));
  }
#endif
#endif

  LoadFunction(clGetPlatformIDs);
  LoadFunction(clGetPlatformInfo);
  LoadFunction(clGetDeviceIDs);
  LoadFunction(clGetDeviceInfo);
  LoadFunction(clCreateSubDevices);
  LoadFunction(clRetainDevice);
  LoadFunction(clReleaseDevice);
  LoadFunction(clCreateContext);
  LoadFunction(clCreateContextFromType);
  LoadFunction(clRetainContext);
  LoadFunction(clReleaseContext);
  LoadFunction(clGetContextInfo);
  LoadFunction(clCreateCommandQueueWithProperties);
  LoadFunction(clRetainCommandQueue);
  LoadFunction(clReleaseCommandQueue);
  LoadFunction(clGetCommandQueueInfo);
  LoadFunction(clCreateBuffer);
  LoadFunction(clCreateSubBuffer);
  LoadFunction(clCreateImage);
  LoadFunction(clCreatePipe);
  LoadFunction(clRetainMemObject);
  LoadFunction(clReleaseMemObject);
  LoadFunction(clGetSupportedImageFormats);
  LoadFunction(clGetMemObjectInfo);
  LoadFunction(clGetImageInfo);
  LoadFunction(clGetPipeInfo);
  LoadFunction(clSetMemObjectDestructorCallback);
  LoadFunction(clSVMAlloc);
  LoadFunction(clSVMFree);
  LoadFunction(clCreateSamplerWithProperties);
  LoadFunction(clRetainSampler);
  LoadFunction(clReleaseSampler);
  LoadFunction(clGetSamplerInfo);
  LoadFunction(clCreateProgramWithSource);
  LoadFunction(clCreateProgramWithBinary);
  LoadFunction(clCreateProgramWithBuiltInKernels);
  LoadFunction(clRetainProgram);
  LoadFunction(clReleaseProgram);
  LoadFunction(clBuildProgram);
  LoadFunction(clCompileProgram);
  LoadFunction(clLinkProgram);
  LoadFunction(clUnloadPlatformCompiler);
  LoadFunction(clGetProgramInfo);
  LoadFunction(clGetProgramBuildInfo);
  LoadFunction(clCreateKernel);
  LoadFunction(clCreateKernelsInProgram);
  LoadFunction(clRetainKernel);
  LoadFunction(clReleaseKernel);
  LoadFunction(clSetKernelArg);
  LoadFunction(clSetKernelArgSVMPointer);
  LoadFunction(clSetKernelExecInfo);
  LoadFunction(clGetKernelInfo);
  LoadFunction(clGetKernelArgInfo);
  LoadFunction(clGetKernelWorkGroupInfo);
  LoadFunction(clWaitForEvents);
  LoadFunction(clGetEventInfo);
  LoadFunction(clCreateUserEvent);
  LoadFunction(clRetainEvent);
  LoadFunction(clReleaseEvent);
  LoadFunction(clSetUserEventStatus);
  LoadFunction(clSetEventCallback);
  LoadFunction(clGetEventProfilingInfo);
  LoadFunction(clFlush);
  LoadFunction(clFinish);
  LoadFunction(clEnqueueReadBuffer);
  LoadFunction(clEnqueueReadBufferRect);
  LoadFunction(clEnqueueWriteBuffer);
  LoadFunction(clEnqueueWriteBufferRect);
  LoadFunction(clEnqueueFillBuffer);
  LoadFunction(clEnqueueCopyBuffer);
  LoadFunction(clEnqueueCopyBufferRect);
  LoadFunction(clEnqueueReadImage);
  LoadFunction(clEnqueueWriteImage);
  LoadFunction(clEnqueueFillImage);
  LoadFunction(clEnqueueCopyImage);
  LoadFunction(clEnqueueCopyImageToBuffer);
  LoadFunction(clEnqueueCopyBufferToImage);
  LoadFunction(clEnqueueMapBuffer);
  LoadFunction(clEnqueueMapImage);
  LoadFunction(clEnqueueUnmapMemObject);
  LoadFunction(clEnqueueMigrateMemObjects);
  LoadFunction(clEnqueueNDRangeKernel);
  LoadFunction(clEnqueueNativeKernel);
  LoadFunction(clEnqueueMarkerWithWaitList);
  LoadFunction(clEnqueueBarrierWithWaitList);
  LoadFunction(clEnqueueSVMFree);
  LoadFunction(clEnqueueSVMMemcpy);
  LoadFunction(clEnqueueSVMMemFill);
  LoadFunction(clEnqueueSVMMap);
  LoadFunction(clEnqueueSVMUnmap);
  LoadFunction(clGetExtensionFunctionAddressForPlatform);
  LoadFunction(clCreateImage2D);
  LoadFunction(clCreateImage3D);
  LoadFunction(clEnqueueMarker);
  LoadFunction(clEnqueueWaitForEvents);
  LoadFunction(clEnqueueBarrier);
  LoadFunction(clUnloadCompiler);
  LoadFunction(clGetExtensionFunctionAddress);
  LoadFunction(clCreateCommandQueue);
  LoadFunction(clCreateSampler);
  LoadFunction(clEnqueueTask);

  // OpenGL sharing
  LoadFunction(clCreateFromGLBuffer);
  LoadFunction(clCreateFromGLTexture);
  LoadFunction(clEnqueueAcquireGLObjects);
  LoadFunction(clEnqueueReleaseGLObjects);

  // cl_khr_egl_event extension
  LoadFunction(clCreateEventFromEGLSyncKHR);

  // EGL sharing
  LoadFunction(clCreateFromEGLImageKHR);
  LoadFunction(clEnqueueAcquireEGLObjectsKHR);
  LoadFunction(clEnqueueReleaseEGLObjectsKHR);
}

// No OpenCL support, do not set function addresses
PFN_clGetPlatformIDs clGetPlatformIDs;
PFN_clGetPlatformInfo clGetPlatformInfo;
PFN_clGetDeviceIDs clGetDeviceIDs;
PFN_clGetDeviceInfo clGetDeviceInfo;
PFN_clCreateSubDevices clCreateSubDevices;
PFN_clRetainDevice clRetainDevice;
PFN_clReleaseDevice clReleaseDevice;
PFN_clCreateContext clCreateContext;
PFN_clCreateContextFromType clCreateContextFromType;
PFN_clRetainContext clRetainContext;
PFN_clReleaseContext clReleaseContext;
PFN_clGetContextInfo clGetContextInfo;
PFN_clCreateCommandQueueWithProperties clCreateCommandQueueWithProperties;
PFN_clRetainCommandQueue clRetainCommandQueue;
PFN_clReleaseCommandQueue clReleaseCommandQueue;
PFN_clGetCommandQueueInfo clGetCommandQueueInfo;
PFN_clCreateBuffer clCreateBuffer;
PFN_clCreateSubBuffer clCreateSubBuffer;
PFN_clCreateImage clCreateImage;
PFN_clCreatePipe clCreatePipe;
PFN_clRetainMemObject clRetainMemObject;
PFN_clReleaseMemObject clReleaseMemObject;
PFN_clGetSupportedImageFormats clGetSupportedImageFormats;
PFN_clGetMemObjectInfo clGetMemObjectInfo;
PFN_clGetImageInfo clGetImageInfo;
PFN_clGetPipeInfo clGetPipeInfo;
PFN_clSetMemObjectDestructorCallback clSetMemObjectDestructorCallback;
PFN_clSVMAlloc clSVMAlloc;
PFN_clSVMFree clSVMFree;
PFN_clCreateSamplerWithProperties clCreateSamplerWithProperties;
PFN_clRetainSampler clRetainSampler;
PFN_clReleaseSampler clReleaseSampler;
PFN_clGetSamplerInfo clGetSamplerInfo;
PFN_clCreateProgramWithSource clCreateProgramWithSource;
PFN_clCreateProgramWithBinary clCreateProgramWithBinary;
PFN_clCreateProgramWithBuiltInKernels clCreateProgramWithBuiltInKernels;
PFN_clRetainProgram clRetainProgram;
PFN_clReleaseProgram clReleaseProgram;
PFN_clBuildProgram clBuildProgram;
PFN_clCompileProgram clCompileProgram;
PFN_clLinkProgram clLinkProgram;
PFN_clUnloadPlatformCompiler clUnloadPlatformCompiler;
PFN_clGetProgramInfo clGetProgramInfo;
PFN_clGetProgramBuildInfo clGetProgramBuildInfo;
PFN_clCreateKernel clCreateKernel;
PFN_clCreateKernelsInProgram clCreateKernelsInProgram;
PFN_clRetainKernel clRetainKernel;
PFN_clReleaseKernel clReleaseKernel;
PFN_clSetKernelArg clSetKernelArg;
PFN_clSetKernelArgSVMPointer clSetKernelArgSVMPointer;
PFN_clSetKernelExecInfo clSetKernelExecInfo;
PFN_clGetKernelInfo clGetKernelInfo;
PFN_clGetKernelArgInfo clGetKernelArgInfo;
PFN_clGetKernelWorkGroupInfo clGetKernelWorkGroupInfo;
PFN_clWaitForEvents clWaitForEvents;
PFN_clGetEventInfo clGetEventInfo;
PFN_clCreateUserEvent clCreateUserEvent;
PFN_clRetainEvent clRetainEvent;
PFN_clReleaseEvent clReleaseEvent;
PFN_clSetUserEventStatus clSetUserEventStatus;
PFN_clSetEventCallback clSetEventCallback;
PFN_clGetEventProfilingInfo clGetEventProfilingInfo;
PFN_clFlush clFlush;
PFN_clFinish clFinish;
PFN_clEnqueueReadBuffer clEnqueueReadBuffer;
PFN_clEnqueueReadBufferRect clEnqueueReadBufferRect;
PFN_clEnqueueWriteBuffer clEnqueueWriteBuffer;
PFN_clEnqueueWriteBufferRect clEnqueueWriteBufferRect;
PFN_clEnqueueFillBuffer clEnqueueFillBuffer;
PFN_clEnqueueCopyBuffer clEnqueueCopyBuffer;
PFN_clEnqueueCopyBufferRect clEnqueueCopyBufferRect;
PFN_clEnqueueReadImage clEnqueueReadImage;
PFN_clEnqueueWriteImage clEnqueueWriteImage;
PFN_clEnqueueFillImage clEnqueueFillImage;
PFN_clEnqueueCopyImage clEnqueueCopyImage;
PFN_clEnqueueCopyImageToBuffer clEnqueueCopyImageToBuffer;
PFN_clEnqueueCopyBufferToImage clEnqueueCopyBufferToImage;
PFN_clEnqueueMapBuffer clEnqueueMapBuffer;
PFN_clEnqueueMapImage clEnqueueMapImage;
PFN_clEnqueueUnmapMemObject clEnqueueUnmapMemObject;
PFN_clEnqueueMigrateMemObjects clEnqueueMigrateMemObjects;
PFN_clEnqueueNDRangeKernel clEnqueueNDRangeKernel;
PFN_clEnqueueNativeKernel clEnqueueNativeKernel;
PFN_clEnqueueMarkerWithWaitList clEnqueueMarkerWithWaitList;
PFN_clEnqueueBarrierWithWaitList clEnqueueBarrierWithWaitList;
PFN_clEnqueueSVMFree clEnqueueSVMFree;
PFN_clEnqueueSVMMemcpy clEnqueueSVMMemcpy;
PFN_clEnqueueSVMMemFill clEnqueueSVMMemFill;
PFN_clEnqueueSVMMap clEnqueueSVMMap;
PFN_clEnqueueSVMUnmap clEnqueueSVMUnmap;
PFN_clGetExtensionFunctionAddressForPlatform
    clGetExtensionFunctionAddressForPlatform;
PFN_clCreateImage2D clCreateImage2D;
PFN_clCreateImage3D clCreateImage3D;
PFN_clEnqueueMarker clEnqueueMarker;
PFN_clEnqueueWaitForEvents clEnqueueWaitForEvents;
PFN_clEnqueueBarrier clEnqueueBarrier;
PFN_clUnloadCompiler clUnloadCompiler;
PFN_clGetExtensionFunctionAddress clGetExtensionFunctionAddress;
PFN_clCreateCommandQueue clCreateCommandQueue;
PFN_clCreateSampler clCreateSampler;
PFN_clEnqueueTask clEnqueueTask;

// OpenGL sharing
PFN_clCreateFromGLBuffer clCreateFromGLBuffer;
PFN_clCreateFromGLTexture clCreateFromGLTexture;
PFN_clEnqueueAcquireGLObjects clEnqueueAcquireGLObjects;
PFN_clEnqueueReleaseGLObjects clEnqueueReleaseGLObjects;

// cl_khr_egl_event extension
PFN_clCreateEventFromEGLSyncKHR clCreateEventFromEGLSyncKHR;

// EGL sharing
PFN_clCreateFromEGLImageKHR clCreateFromEGLImageKHR;
PFN_clEnqueueAcquireEGLObjectsKHR clEnqueueAcquireEGLObjectsKHR;
PFN_clEnqueueReleaseEGLObjectsKHR clEnqueueReleaseEGLObjectsKHR;

cl_mem CreateImage2DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage2D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_row_pitch, host_ptr, errcode_ret);
  }
}

cl_mem CreateImage3DLegacy(cl_context context, cl_mem_flags flags,
                           const cl_image_format* image_format,
                           const cl_image_desc* image_desc, void* host_ptr,
                           cl_int* errcode_ret) {
  if (clCreateImage) {  // clCreateImage available since OpenCL 1.2
    return clCreateImage(context, flags, image_format, image_desc, host_ptr,
                         errcode_ret);
  } else {
    return clCreateImage3D(context, flags, image_format,
                           image_desc->image_width, image_desc->image_height,
                           image_desc->image_depth, image_desc->image_row_pitch,
                           image_desc->image_slice_pitch, host_ptr,
                           errcode_ret);
  }
}
}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>