<commit_before>#ifndef TAMER_HTTP_HH
#define TAMER_HTTP_HH 1
#include "fd.hh"
#include "http_parser.h"
#include <vector>
#include <string>
#include <sstream>
#include <memory>
#include <unordered_map>
#include <time.h>
namespace tamer {
class http_parser;

struct http_header {
    std::string name;
    std::string value;
    inline http_header(std::string n, std::string v)
        : name(TAMER_MOVE(n)), value(TAMER_MOVE(v)) {
    }
    inline bool is(const char* s, size_t len) const {
        return name.length() == len && memcmp(name.data(), s, len) == 0;
    }
    inline bool is(const std::string& s) const {
        return is(s.data(), s.length());
    }
    inline bool is_canonical(const char* s, size_t len) const {
        if (name.length() != len)
            return false;
        const char* names = name.data();
        const char* end = s + len;
        for (; s != end; ++s, ++names)
            if (*s != *names
                && (*s < 'A' || *s > 'Z' || (*s - 'A' + 'a') != *names))
                return false;
        return true;
    }
    inline bool is_canonical(const std::string& s) const {
        return is_canonical(s.data(), s.length());
    }
    inline bool is_content_length() const {
        return is_canonical("content-length", 14);
    }
};

class http_message {
  public:
    typedef std::vector<http_header>::const_iterator header_iterator;

    inline http_message();

    inline bool ok() const;
    inline bool operator!() const;
    inline enum http_errno error() const;

    inline unsigned http_major() const;
    inline unsigned http_minor() const;

    inline unsigned status_code() const;
    inline const std::string& status_message() const;
    inline enum http_method method() const;
    inline const std::string& url() const;
    header_iterator find_canonical_header(const std::string& name) const;
    inline header_iterator find_header(const std::string& name) const;
    inline bool has_canonical_header(const std::string& name) const;
    inline bool has_header(const std::string& name) const;
    inline const std::string& body() const;

    std::string host() const;
    inline std::string url_schema() const;
    inline std::string url_host() const;
    std::string url_host_port() const;
    inline std::string url_path() const;
    inline bool has_query() const;
    inline std::string query() const;
    bool has_query(const std::string& name) const;
    std::string query(const std::string& name) const;

    inline header_iterator header_begin() const;
    inline header_iterator header_end() const;
    inline header_iterator query_begin() const;
    inline header_iterator query_end() const;

    inline http_message& clear();
    void add_header(std::string key, std::string value);

    inline http_message& http_major(unsigned v);
    inline http_message& http_minor(unsigned v);
    inline http_message& error(enum http_errno e);
    inline http_message& status_code(unsigned code);
    inline http_message& status_code(unsigned code, std::string message);
    inline http_message& method(enum http_method method);
    inline http_message& url(std::string url);
    inline http_message& header(std::string key, std::string value);
    inline http_message& header(std::string key, size_t value);
    inline http_message& date_header(std::string key, time_t value);
    inline http_message& body(std::string body);

    static std::string canonicalize(std::string x);
    static const char* default_status_message(unsigned code);

  private:
    enum {
        info_url = 1, info_query = 2
    };

    struct info_type {
        unsigned flags;
        struct http_parser_url urlp;
        std::vector<http_header> raw_query;
        inline info_type()
            : flags(0) {
        }
    };

    unsigned short major_;
    unsigned short minor_;
    unsigned status_code_ : 16;
    unsigned method_ : 8;
    unsigned error_ : 7;
    unsigned upgrade_ : 1;

    std::string url_;
    std::string status_message_;
    std::vector<http_header> raw_headers_;
    std::string body_;

    mutable std::shared_ptr<info_type> info_;

    inline void kill_info(unsigned f) const;
    inline info_type& info(unsigned f) const;
    void make_info(unsigned f) const;
    inline bool has_url_field(int field) const;
    inline std::string url_field(int field) const;
    void do_clear();
    friend class http_parser;
};

class http_parser : public tamed_class {
  public:
    http_parser(enum http_parser_type type);

    void clear();
    inline bool ok() const;
    inline enum http_errno error() const;
    inline bool should_keep_alive() const;

    void receive(fd f, event<http_message> done);
    void send(fd f, const http_message& m, event<> done);
    static void send_request(fd f, const http_message& m, event<> done);
    static void send_response(fd f, const http_message& m, event<> done);
    static void send_response_headers(fd f, const http_message& m, event<> done);
    static void send_response_chunk(fd f, std::string s, event<> done);
    static void send_response_end(fd f, event<> done);

  private:
    ::http_parser hp_;

    struct message_data {
        http_message hm;
        std::string key;
        std::ostringstream sbuf;
        bool done;
    };

    static const http_parser_settings settings;
    static http_parser* get_parser(::http_parser* hp);
    static message_data* get_message_data(::http_parser* hp);
    static int on_message_begin(::http_parser* hp);
    static int on_url(::http_parser* hp, const char* s, size_t len);
    static int on_status(::http_parser* hp, const char* s, size_t len);
    static int on_header_field(::http_parser* hp, const char* s, size_t len);
    static int on_header_value(::http_parser* hp, const char* s, size_t len);
    static int on_headers_complete(::http_parser* hp);
    static int on_body(::http_parser* hp, const char* s, size_t len);
    static int on_message_complete(::http_parser* hp);
    inline void copy_parser_status(message_data& md);
    static void unparse_request_headers(std::ostringstream& buf,
                                        const http_message& m);
    static void unparse_response_headers(std::ostringstream& buf,
                                         const http_message& m,
                                         bool include_content_length);

    class closure__receive__2fdQ12http_message_; void receive(closure__receive__2fdQ12http_message_&);
    class closure__send_request__2fdRK12http_messageQ_; static void send_request(closure__send_request__2fdRK12http_messageQ_&);
    class closure__send_response__2fdRK12http_messageQ_; static void send_response(closure__send_response__2fdRK12http_messageQ_&);
    class closure__send_response_chunk__2fdSsQ_; static void send_response_chunk(closure__send_response_chunk__2fdSsQ_&);
};

inline http_message::http_message()
    : major_(1), minor_(1), status_code_(200), method_(HTTP_GET),
      error_(HPE_OK), upgrade_(0) {
}

inline void http_message::kill_info(unsigned f) const {
    if (info_)
        info_->flags &= ~f;
}

inline unsigned http_message::http_major() const {
    return major_;
}

inline unsigned http_message::http_minor() const {
    return minor_;
}

inline bool http_message::ok() const {
    return error_ == HPE_OK;
}

inline bool http_message::operator!() const {
    return !ok();
}

inline enum http_errno http_message::error() const {
    return (enum http_errno) error_;
}

inline unsigned http_message::status_code() const {
    return status_code_;
}

inline const std::string& http_message::status_message() const {
    return status_message_;
}

inline enum http_method http_message::method() const {
    return (enum http_method) method_;
}

inline const std::string& http_message::url() const {
    return url_;
}

inline http_message::header_iterator http_message::find_header(const std::string& key) const {
    return find_canonical_header(canonicalize(key));
}

inline bool http_message::has_canonical_header(const std::string& key) const {
    return find_canonical_header(key) != header_end();
}

inline bool http_message::has_header(const std::string& key) const {
    return has_canonical_header(canonicalize(key));
}

inline const std::string& http_message::body() const {
    return body_;
}

inline bool http_message::has_url_field(int field) const {
    return info(info_url).urlp.field_set & (1 << field);
}

inline std::string http_message::url_field(int field) const {
    const info_type& i = info(info_url);
    if (i.urlp.field_set & (1 << field))
        return url_.substr(i.urlp.field_data[field].off,
                           i.urlp.field_data[field].len);
    else
        return std::string();
}

inline bool http_message::has_query() const {
    return has_url_field(UF_QUERY);
}

inline std::string http_message::query() const {
    return url_field(UF_QUERY);
}

inline std::string http_message::url_schema() const {
    return url_field(UF_SCHEMA);
}

inline std::string http_message::url_host() const {
    return url_field(UF_HOST);
}

inline std::string http_message::url_path() const {
    return url_field(UF_PATH);
}

inline http_message& http_message::http_major(unsigned v) {
    major_ = v;
    return *this;
}

inline http_message& http_message::http_minor(unsigned v) {
    minor_ = v;
    return *this;
}

inline http_message& http_message::clear() {
    do_clear();
    return *this;
}

inline http_message& http_message::error(enum http_errno e) {
    error_ = e;
    return *this;
}

inline http_message& http_message::status_code(unsigned code) {
    status_code_ = code;
    status_message_ = std::string();
    return *this;
}

inline http_message& http_message::status_code(unsigned code, std::string message) {
    status_code_ = code;
    status_message_ = TAMER_MOVE(message);
    return *this;
}

inline http_message& http_message::method(enum http_method method) {
    method_ = (unsigned) method;
    return *this;
}

inline http_message& http_message::url(std::string url) {
    url_ = TAMER_MOVE(url);
    kill_info(info_url | info_query);
    return *this;
}

inline http_message& http_message::header(std::string key, std::string value) {
    add_header(TAMER_MOVE(key), TAMER_MOVE(value));
    return *this;
}

inline http_message& http_message::header(std::string key, size_t value) {
    std::ostringstream buf;
    buf << value;
    add_header(TAMER_MOVE(key), buf.str());
    return *this;
}

inline http_message& http_message::date_header(std::string key, time_t value) {
    char buf[128];
    // XXX current locale
    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&value));
    add_header(TAMER_MOVE(key), std::string(buf));
    return *this;
}

inline http_message& http_message::body(std::string body) {
    body_ = TAMER_MOVE(body);
    return *this;
}

inline http_message::info_type& http_message::info(unsigned f) const {
    if (!info_ || !info_.unique() || (info_->flags & f) != f)
        make_info(f);
    return *info_.get();
}

inline http_message::header_iterator http_message::header_begin() const {
    return raw_headers_.begin();
}

inline http_message::header_iterator http_message::header_end() const {
    return raw_headers_.end();
}

inline http_message::header_iterator http_message::query_begin() const {
    return info(info_query).raw_query.begin();
}

inline http_message::header_iterator http_message::query_end() const {
    return info(info_query).raw_query.end();
}

inline bool http_parser::ok() const {
    return hp_.http_errno == (unsigned) HPE_OK;
}

inline enum http_errno http_parser::error() const {
    return (enum http_errno) hp_.http_errno;
}

inline bool http_parser::should_keep_alive() const {
    return http_should_keep_alive(&hp_);
}

} // namespace tamer
#endif
<commit_msg>Add http_parser::clear_should_keep_alive().<commit_after>#ifndef TAMER_HTTP_HH
#define TAMER_HTTP_HH 1
#include "fd.hh"
#include "http_parser.h"
#include <vector>
#include <string>
#include <sstream>
#include <memory>
#include <unordered_map>
#include <time.h>
namespace tamer {
class http_parser;

struct http_header {
    std::string name;
    std::string value;
    inline http_header(std::string n, std::string v)
        : name(TAMER_MOVE(n)), value(TAMER_MOVE(v)) {
    }
    inline bool is(const char* s, size_t len) const {
        return name.length() == len && memcmp(name.data(), s, len) == 0;
    }
    inline bool is(const std::string& s) const {
        return is(s.data(), s.length());
    }
    inline bool is_canonical(const char* s, size_t len) const {
        if (name.length() != len)
            return false;
        const char* names = name.data();
        const char* end = s + len;
        for (; s != end; ++s, ++names)
            if (*s != *names
                && (*s < 'A' || *s > 'Z' || (*s - 'A' + 'a') != *names))
                return false;
        return true;
    }
    inline bool is_canonical(const std::string& s) const {
        return is_canonical(s.data(), s.length());
    }
    inline bool is_content_length() const {
        return is_canonical("content-length", 14);
    }
};

class http_message {
  public:
    typedef std::vector<http_header>::const_iterator header_iterator;

    inline http_message();

    inline bool ok() const;
    inline bool operator!() const;
    inline enum http_errno error() const;

    inline unsigned http_major() const;
    inline unsigned http_minor() const;

    inline unsigned status_code() const;
    inline const std::string& status_message() const;
    inline enum http_method method() const;
    inline const std::string& url() const;
    header_iterator find_canonical_header(const std::string& name) const;
    inline header_iterator find_header(const std::string& name) const;
    inline bool has_canonical_header(const std::string& name) const;
    inline bool has_header(const std::string& name) const;
    inline const std::string& body() const;

    std::string host() const;
    inline std::string url_schema() const;
    inline std::string url_host() const;
    std::string url_host_port() const;
    inline std::string url_path() const;
    inline bool has_query() const;
    inline std::string query() const;
    bool has_query(const std::string& name) const;
    std::string query(const std::string& name) const;

    inline header_iterator header_begin() const;
    inline header_iterator header_end() const;
    inline header_iterator query_begin() const;
    inline header_iterator query_end() const;

    inline http_message& clear();
    void add_header(std::string key, std::string value);

    inline http_message& http_major(unsigned v);
    inline http_message& http_minor(unsigned v);
    inline http_message& error(enum http_errno e);
    inline http_message& status_code(unsigned code);
    inline http_message& status_code(unsigned code, std::string message);
    inline http_message& method(enum http_method method);
    inline http_message& url(std::string url);
    inline http_message& header(std::string key, std::string value);
    inline http_message& header(std::string key, size_t value);
    inline http_message& date_header(std::string key, time_t value);
    inline http_message& body(std::string body);

    static std::string canonicalize(std::string x);
    static const char* default_status_message(unsigned code);

  private:
    enum {
        info_url = 1, info_query = 2
    };

    struct info_type {
        unsigned flags;
        struct http_parser_url urlp;
        std::vector<http_header> raw_query;
        inline info_type()
            : flags(0) {
        }
    };

    unsigned short major_;
    unsigned short minor_;
    unsigned status_code_ : 16;
    unsigned method_ : 8;
    unsigned error_ : 7;
    unsigned upgrade_ : 1;

    std::string url_;
    std::string status_message_;
    std::vector<http_header> raw_headers_;
    std::string body_;

    mutable std::shared_ptr<info_type> info_;

    inline void kill_info(unsigned f) const;
    inline info_type& info(unsigned f) const;
    void make_info(unsigned f) const;
    inline bool has_url_field(int field) const;
    inline std::string url_field(int field) const;
    void do_clear();
    friend class http_parser;
};

class http_parser : public tamed_class {
  public:
    http_parser(enum http_parser_type type);

    void clear();
    inline bool ok() const;
    inline enum http_errno error() const;
    inline bool should_keep_alive() const;

    void receive(fd f, event<http_message> done);
    void send(fd f, const http_message& m, event<> done);
    static void send_request(fd f, const http_message& m, event<> done);
    static void send_response(fd f, const http_message& m, event<> done);
    static void send_response_headers(fd f, const http_message& m, event<> done);
    static void send_response_chunk(fd f, std::string s, event<> done);
    static void send_response_end(fd f, event<> done);

    inline void clear_should_keep_alive();

  private:
    ::http_parser hp_;

    struct message_data {
        http_message hm;
        std::string key;
        std::ostringstream sbuf;
        bool done;
    };

    static const http_parser_settings settings;
    static http_parser* get_parser(::http_parser* hp);
    static message_data* get_message_data(::http_parser* hp);
    static int on_message_begin(::http_parser* hp);
    static int on_url(::http_parser* hp, const char* s, size_t len);
    static int on_status(::http_parser* hp, const char* s, size_t len);
    static int on_header_field(::http_parser* hp, const char* s, size_t len);
    static int on_header_value(::http_parser* hp, const char* s, size_t len);
    static int on_headers_complete(::http_parser* hp);
    static int on_body(::http_parser* hp, const char* s, size_t len);
    static int on_message_complete(::http_parser* hp);
    inline void copy_parser_status(message_data& md);
    static void unparse_request_headers(std::ostringstream& buf,
                                        const http_message& m);
    static void unparse_response_headers(std::ostringstream& buf,
                                         const http_message& m,
                                         bool include_content_length);

    class closure__receive__2fdQ12http_message_; void receive(closure__receive__2fdQ12http_message_&);
    class closure__send_request__2fdRK12http_messageQ_; static void send_request(closure__send_request__2fdRK12http_messageQ_&);
    class closure__send_response__2fdRK12http_messageQ_; static void send_response(closure__send_response__2fdRK12http_messageQ_&);
    class closure__send_response_chunk__2fdSsQ_; static void send_response_chunk(closure__send_response_chunk__2fdSsQ_&);
};

inline http_message::http_message()
    : major_(1), minor_(1), status_code_(200), method_(HTTP_GET),
      error_(HPE_OK), upgrade_(0) {
}

inline void http_message::kill_info(unsigned f) const {
    if (info_)
        info_->flags &= ~f;
}

inline unsigned http_message::http_major() const {
    return major_;
}

inline unsigned http_message::http_minor() const {
    return minor_;
}

inline bool http_message::ok() const {
    return error_ == HPE_OK;
}

inline bool http_message::operator!() const {
    return !ok();
}

inline enum http_errno http_message::error() const {
    return (enum http_errno) error_;
}

inline unsigned http_message::status_code() const {
    return status_code_;
}

inline const std::string& http_message::status_message() const {
    return status_message_;
}

inline enum http_method http_message::method() const {
    return (enum http_method) method_;
}

inline const std::string& http_message::url() const {
    return url_;
}

inline http_message::header_iterator http_message::find_header(const std::string& key) const {
    return find_canonical_header(canonicalize(key));
}

inline bool http_message::has_canonical_header(const std::string& key) const {
    return find_canonical_header(key) != header_end();
}

inline bool http_message::has_header(const std::string& key) const {
    return has_canonical_header(canonicalize(key));
}

inline const std::string& http_message::body() const {
    return body_;
}

inline bool http_message::has_url_field(int field) const {
    return info(info_url).urlp.field_set & (1 << field);
}

inline std::string http_message::url_field(int field) const {
    const info_type& i = info(info_url);
    if (i.urlp.field_set & (1 << field))
        return url_.substr(i.urlp.field_data[field].off,
                           i.urlp.field_data[field].len);
    else
        return std::string();
}

inline bool http_message::has_query() const {
    return has_url_field(UF_QUERY);
}

inline std::string http_message::query() const {
    return url_field(UF_QUERY);
}

inline std::string http_message::url_schema() const {
    return url_field(UF_SCHEMA);
}

inline std::string http_message::url_host() const {
    return url_field(UF_HOST);
}

inline std::string http_message::url_path() const {
    return url_field(UF_PATH);
}

inline http_message& http_message::http_major(unsigned v) {
    major_ = v;
    return *this;
}

inline http_message& http_message::http_minor(unsigned v) {
    minor_ = v;
    return *this;
}

inline http_message& http_message::clear() {
    do_clear();
    return *this;
}

inline http_message& http_message::error(enum http_errno e) {
    error_ = e;
    return *this;
}

inline http_message& http_message::status_code(unsigned code) {
    status_code_ = code;
    status_message_ = std::string();
    return *this;
}

inline http_message& http_message::status_code(unsigned code, std::string message) {
    status_code_ = code;
    status_message_ = TAMER_MOVE(message);
    return *this;
}

inline http_message& http_message::method(enum http_method method) {
    method_ = (unsigned) method;
    return *this;
}

inline http_message& http_message::url(std::string url) {
    url_ = TAMER_MOVE(url);
    kill_info(info_url | info_query);
    return *this;
}

inline http_message& http_message::header(std::string key, std::string value) {
    add_header(TAMER_MOVE(key), TAMER_MOVE(value));
    return *this;
}

inline http_message& http_message::header(std::string key, size_t value) {
    std::ostringstream buf;
    buf << value;
    add_header(TAMER_MOVE(key), buf.str());
    return *this;
}

inline http_message& http_message::date_header(std::string key, time_t value) {
    char buf[128];
    // XXX current locale
    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&value));
    add_header(TAMER_MOVE(key), std::string(buf));
    return *this;
}

inline http_message& http_message::body(std::string body) {
    body_ = TAMER_MOVE(body);
    return *this;
}

inline http_message::info_type& http_message::info(unsigned f) const {
    if (!info_ || !info_.unique() || (info_->flags & f) != f)
        make_info(f);
    return *info_.get();
}

inline http_message::header_iterator http_message::header_begin() const {
    return raw_headers_.begin();
}

inline http_message::header_iterator http_message::header_end() const {
    return raw_headers_.end();
}

inline http_message::header_iterator http_message::query_begin() const {
    return info(info_query).raw_query.begin();
}

inline http_message::header_iterator http_message::query_end() const {
    return info(info_query).raw_query.end();
}

inline bool http_parser::ok() const {
    return hp_.http_errno == (unsigned) HPE_OK;
}

inline enum http_errno http_parser::error() const {
    return (enum http_errno) hp_.http_errno;
}

inline bool http_parser::should_keep_alive() const {
    return http_should_keep_alive(&hp_);
}

inline void http_parser::clear_should_keep_alive() {
    hp_.flags = (hp_.flags & ~F_CONNECTION_KEEP_ALIVE) | F_CONNECTION_CLOSE;
}

} // namespace tamer
#endif
<|endoftext|>


<commit_before>#include "template.hpp"
#include <gtest/gtest.h>

// The fixture for testing class Foo.
class MultipleTest : public ::testing::Test
{
 protected:
    string result;
    string template_string;
    string expected;
    map<string, string> ctx;

    MultipleTest()
    {
    }

    virtual ~MultipleTest()
    {
    }

    virtual void SetUp()
    {
        template_string = "<title>{{title}}</title>\n";
        template_string += "Hi I am {{name}}.\n";
        template_string += "I like {{pet}}.";
        ctx["title"] = "Multiple Mustaches";
        ctx["name"] = "Daniel";
        ctx["pet"] = "turtles";
        template_t t;
        result = t.render(template_string, ctx);
    }

    virtual void TearDown()
    {
    }

};

// Tests that a simple mustache tag is replaced
TEST_F(MultipleTest, TestMultipleMustache)
{
    expected = "<title>Multiple Mustaches</title>\n";
    expected += "Hi I am Daniel.\n";
    expected += "I like turtles.";
    EXPECT_EQ(expected, result);
}

<commit_msg>adapt unit testing for comments and non-existent tags<commit_after>#include "template.hpp"
#include <gtest/gtest.h>

// The fixture for testing class Foo.
class MultipleTest : public ::testing::Test
{
 protected:
    string result;
    string template_string;
    string expected;
    map<string, string> ctx;

    MultipleTest()
    {
    }

    virtual ~MultipleTest()
    {
    }

    virtual void SetUp()
    {
        template_string = "<title>{{title}}</title>\n";
        template_string += "Hi I am {{name}}{{lastname}}.\n";
        template_string += "I like {{pet}}.{{!comment}}";
        ctx["title"] = "Multiple Mustaches";
        ctx["name"] = "Daniel";
        ctx["pet"] = "turtles";
        template_t t;
        result = t.render(template_string, ctx);
    }

    virtual void TearDown()
    {
    }

};

// Tests that a simple mustache tag is replaced
TEST_F(MultipleTest, TestMultipleMustache)
{
    expected = "<title>Multiple Mustaches</title>\n";
    expected += "Hi I am Daniel.\n";
    expected += "I like turtles.";
    EXPECT_EQ(expected, result);
}

<|endoftext|>


<commit_before>#include "SkWindow.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkOSMenu.h"
#include "SkSystemEventTypes.h"
#include "SkTime.h"

#define SK_EventDelayInval "\xd" "n" "\xa" "l"

#define TEST_BOUNDERx

#include "SkBounder.h"
class test_bounder : public SkBounder {
public:
	test_bounder(const SkBitmap& bm) : fCanvas(bm) {}
protected:
	virtual bool onIRect(const SkIRect& r)
	{
		SkRect	rr;

		rr.set(SkIntToScalar(r.fLeft), SkIntToScalar(r.fTop),
				SkIntToScalar(r.fRight), SkIntToScalar(r.fBottom));

		SkPaint	p;

		p.setStyle(SkPaint::kStroke_Style);
		p.setColor(SK_ColorYELLOW);

#if 0
		rr.inset(SK_ScalarHalf, SK_ScalarHalf);
#else
		rr.inset(-SK_ScalarHalf, -SK_ScalarHalf);
#endif

		fCanvas.drawRect(rr, p);
		return true;
	}
private:
	SkCanvas	fCanvas;
};

SkWindow::SkWindow() : fFocusView(NULL)
{
	fClick = NULL;
	fWaitingOnInval = false;

#ifdef SK_BUILD_FOR_WINCE
	fConfig = SkBitmap::kRGB_565_Config;
#else
	fConfig = SkBitmap::kARGB_8888_Config;
#endif

    fMatrix.reset();
}

SkWindow::~SkWindow()
{
	delete fClick;

	fMenus.deleteAll();
}

void SkWindow::setMatrix(const SkMatrix& matrix) {
    if (fMatrix != matrix) {
        fMatrix = matrix;
        this->inval(NULL);
    }
}

void SkWindow::preConcat(const SkMatrix& matrix) {
    SkMatrix m;
    m.setConcat(fMatrix, matrix);
    this->setMatrix(m);
}

void SkWindow::postConcat(const SkMatrix& matrix) {
    SkMatrix m;
    m.setConcat(matrix, fMatrix);
    this->setMatrix(m);
}

void SkWindow::setConfig(SkBitmap::Config config)
{
	this->resize(fBitmap.width(), fBitmap.height(), config);
}

void SkWindow::resize(int width, int height, SkBitmap::Config config)
{
	if (config == SkBitmap::kNo_Config)
		config = fConfig;

	if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
	{
		fConfig = config;
		fBitmap.setConfig(config, width, height);
		fBitmap.allocPixels();
        fBitmap.setIsOpaque(true);

		this->setSize(SkIntToScalar(width), SkIntToScalar(height));
		this->inval(NULL);
	}
}

void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
{
	fBitmap.eraseARGB(a, r, g, b);
}

void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
{
	fBitmap.eraseRGB(r, g, b);
}

bool SkWindow::handleInval(const SkRect* localR)
{
	SkIRect	ir;

    if (localR) {
        SkRect devR;
        SkMatrix inverse;
        if (!fMatrix.invert(&inverse)) {
            return false;
        }
        fMatrix.mapRect(&devR, *localR);
        devR.round(&ir);
    } else {
        ir.set(0, 0, this->width(), this->height());
    }
	fDirtyRgn.op(ir, SkRegion::kUnion_Op);

	this->onHandleInval(ir);
	return true;
}

void SkWindow::forceInvalAll() {
    fDirtyRgn.setRect(0, 0, this->width(), this->height());
}

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
	#include <windows.h>
	#include <gx.h>
	extern GXDisplayProperties gDisplayProps;
#endif

#ifdef SK_SIMULATE_FAILED_MALLOC
extern bool gEnableControlledThrow;
#endif

bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
{
	if (!fDirtyRgn.isEmpty())
	{
		SkBitmap bm = this->getBitmap();

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
		char* buffer = (char*)GXBeginDraw();
		SkASSERT(buffer);

		RECT	rect;
		GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
		buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;

		bm.setPixels(buffer);
#endif

		SkCanvas	rasterCanvas;
        SkDevice*   device;

        if (NULL == canvas) {
            canvas = &rasterCanvas;
            device = new SkDevice(canvas, bm, false);
            canvas->setDevice(device)->unref();
        } else {
            canvas->setBitmapDevice(bm);
        }

		canvas->clipRegion(fDirtyRgn);
		if (updateArea)
			*updateArea = fDirtyRgn.getBounds();

        SkAutoCanvasRestore acr(canvas, true);
        canvas->concat(fMatrix);

		// empty this now, so we can correctly record any inval calls that
		// might be made during the draw call.
		fDirtyRgn.setEmpty();

#ifdef TEST_BOUNDER
		test_bounder	b(bm);
		canvas->setBounder(&b);
#endif
#ifdef SK_SIMULATE_FAILED_MALLOC
		gEnableControlledThrow = true;
#endif
#ifdef SK_BUILD_FOR_WIN32
		//try {
			this->draw(canvas);
		//}
		//catch (...) {
		//}
#else
		this->draw(canvas);
#endif
#ifdef SK_SIMULATE_FAILED_MALLOC
		gEnableControlledThrow = false;
#endif
#ifdef TEST_BOUNDER
		canvas->setBounder(NULL);
#endif

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
		GXEndDraw();
#endif

		return true;
	}
	return false;
}

bool SkWindow::handleChar(SkUnichar uni)
{
	if (this->onHandleChar(uni))
		return true;

	SkView* focus = this->getFocusView();
	if (focus == NULL)
		focus = this;

	SkEvent evt(SK_EventType_Unichar);
	evt.setFast32(uni);
	return focus->doEvent(evt);
}

bool SkWindow::handleKey(SkKey key)
{
	if (key == kNONE_SkKey)
		return false;

	if (this->onHandleKey(key))
		return true;

	// send an event to the focus-view
	{
		SkView* focus = this->getFocusView();
		if (focus == NULL)
			focus = this;

		SkEvent evt(SK_EventType_Key);
		evt.setFast32(key);
		if (focus->doEvent(evt))
			return true;
	}

	if (key == kUp_SkKey || key == kDown_SkKey)
	{
		if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
			this->onSetFocusView(NULL);
		return true;
	}
	return false;
}

bool SkWindow::handleKeyUp(SkKey key)
{
    if (key == kNONE_SkKey)
        return false;

    if (this->onHandleKeyUp(key))
        return true;

    //send an event to the focus-view
    {
        SkView* focus = this->getFocusView();
        if (focus == NULL)
            focus = this;

        //should this one be the same?
        SkEvent evt(SK_EventType_KeyUp);
        evt.setFast32(key);
        if (focus->doEvent(evt))
            return true;
    }
    return false;
}

void SkWindow::addMenu(SkOSMenu* menu)
{
	*fMenus.append() = menu;
	this->onAddMenu(menu);
}

void SkWindow::setTitle(const char title[]) {
    if (NULL == title) {
        title = "";
    }
    fTitle.set(title);
    this->onSetTitle(title);
}

bool SkWindow::handleMenu(uint32_t cmd)
{
	for (int i = 0; i < fMenus.count(); i++)
	{
		SkEvent* evt = fMenus[i]->createEvent(cmd);
		if (evt)
		{
			evt->post(this->getSinkID());
			return true;
		}
	}
	return false;
}

//////////////////////////////////////////////////////////////////////

bool SkWindow::onEvent(const SkEvent& evt)
{
	if (evt.isType(SK_EventDelayInval))
	{
		SkRegion::Iterator	iter(fDirtyRgn);

		for (; !iter.done(); iter.next())
			this->onHandleInval(iter.rect());
		fWaitingOnInval = false;
		return true;
	}
	return this->INHERITED::onEvent(evt);
}

bool SkWindow::onGetFocusView(SkView** focus) const
{
	if (focus)
		*focus = fFocusView;
	return true;
}

bool SkWindow::onSetFocusView(SkView* focus)
{
	if (fFocusView != focus)
	{
		if (fFocusView)
			fFocusView->onFocusChange(false);
		fFocusView = focus;
		if (focus)
			focus->onFocusChange(true);
	}
	return true;
}

//////////////////////////////////////////////////////////////////////

void SkWindow::onHandleInval(const SkIRect&)
{
}

bool SkWindow::onHandleChar(SkUnichar)
{
	return false;
}

bool SkWindow::onHandleKey(SkKey key)
{
	return false;
}

bool SkWindow::onHandleKeyUp(SkKey key)
{
    return false;
}

bool SkWindow::handleClick(int x, int y, Click::State state)
{
	bool handled = false;

	switch (state) {
	case Click::kDown_State:
		if (fClick)
			delete fClick;
		fClick = this->findClickHandler(SkIntToScalar(x), SkIntToScalar(y));
		if (fClick)
		{
			SkView::DoClickDown(fClick, x, y);
			handled = true;
		}
		break;
	case Click::kMoved_State:
		if (fClick)
		{
			SkView::DoClickMoved(fClick, x, y);
			handled = true;
		}
		break;
	case Click::kUp_State:
		if (fClick)
		{
			SkView::DoClickUp(fClick, x, y);
			delete fClick;
			fClick = NULL;
			handled = true;
		}
		break;
	}
	return handled;
}

<commit_msg>fix float->int warning<commit_after>#include "SkWindow.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkOSMenu.h"
#include "SkSystemEventTypes.h"
#include "SkTime.h"

#define SK_EventDelayInval "\xd" "n" "\xa" "l"

#define TEST_BOUNDERx

#include "SkBounder.h"
class test_bounder : public SkBounder {
public:
	test_bounder(const SkBitmap& bm) : fCanvas(bm) {}
protected:
	virtual bool onIRect(const SkIRect& r)
	{
		SkRect	rr;

		rr.set(SkIntToScalar(r.fLeft), SkIntToScalar(r.fTop),
				SkIntToScalar(r.fRight), SkIntToScalar(r.fBottom));

		SkPaint	p;

		p.setStyle(SkPaint::kStroke_Style);
		p.setColor(SK_ColorYELLOW);

#if 0
		rr.inset(SK_ScalarHalf, SK_ScalarHalf);
#else
		rr.inset(-SK_ScalarHalf, -SK_ScalarHalf);
#endif

		fCanvas.drawRect(rr, p);
		return true;
	}
private:
	SkCanvas	fCanvas;
};

SkWindow::SkWindow() : fFocusView(NULL)
{
	fClick = NULL;
	fWaitingOnInval = false;

#ifdef SK_BUILD_FOR_WINCE
	fConfig = SkBitmap::kRGB_565_Config;
#else
	fConfig = SkBitmap::kARGB_8888_Config;
#endif

    fMatrix.reset();
}

SkWindow::~SkWindow()
{
	delete fClick;

	fMenus.deleteAll();
}

void SkWindow::setMatrix(const SkMatrix& matrix) {
    if (fMatrix != matrix) {
        fMatrix = matrix;
        this->inval(NULL);
    }
}

void SkWindow::preConcat(const SkMatrix& matrix) {
    SkMatrix m;
    m.setConcat(fMatrix, matrix);
    this->setMatrix(m);
}

void SkWindow::postConcat(const SkMatrix& matrix) {
    SkMatrix m;
    m.setConcat(matrix, fMatrix);
    this->setMatrix(m);
}

void SkWindow::setConfig(SkBitmap::Config config)
{
	this->resize(fBitmap.width(), fBitmap.height(), config);
}

void SkWindow::resize(int width, int height, SkBitmap::Config config)
{
	if (config == SkBitmap::kNo_Config)
		config = fConfig;

	if (width != fBitmap.width() || height != fBitmap.height() || config != fConfig)
	{
		fConfig = config;
		fBitmap.setConfig(config, width, height);
		fBitmap.allocPixels();
        fBitmap.setIsOpaque(true);

		this->setSize(SkIntToScalar(width), SkIntToScalar(height));
		this->inval(NULL);
	}
}

void SkWindow::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
{
	fBitmap.eraseARGB(a, r, g, b);
}

void SkWindow::eraseRGB(U8CPU r, U8CPU g, U8CPU b)
{
	fBitmap.eraseRGB(r, g, b);
}

bool SkWindow::handleInval(const SkRect* localR)
{
	SkIRect	ir;

    if (localR) {
        SkRect devR;
        SkMatrix inverse;
        if (!fMatrix.invert(&inverse)) {
            return false;
        }
        fMatrix.mapRect(&devR, *localR);
        devR.round(&ir);
    } else {
        ir.set(0, 0,
			   SkScalarRound(this->width()),
			   SkScalarRound(this->height()));
    }
	fDirtyRgn.op(ir, SkRegion::kUnion_Op);

	this->onHandleInval(ir);
	return true;
}

void SkWindow::forceInvalAll() {
    fDirtyRgn.setRect(0, 0, this->width(), this->height());
}

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
	#include <windows.h>
	#include <gx.h>
	extern GXDisplayProperties gDisplayProps;
#endif

#ifdef SK_SIMULATE_FAILED_MALLOC
extern bool gEnableControlledThrow;
#endif

bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
{
	if (!fDirtyRgn.isEmpty())
	{
		SkBitmap bm = this->getBitmap();

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
		char* buffer = (char*)GXBeginDraw();
		SkASSERT(buffer);

		RECT	rect;
		GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect);
		buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch;

		bm.setPixels(buffer);
#endif

		SkCanvas	rasterCanvas;
        SkDevice*   device;

        if (NULL == canvas) {
            canvas = &rasterCanvas;
            device = new SkDevice(canvas, bm, false);
            canvas->setDevice(device)->unref();
        } else {
            canvas->setBitmapDevice(bm);
        }

		canvas->clipRegion(fDirtyRgn);
		if (updateArea)
			*updateArea = fDirtyRgn.getBounds();

        SkAutoCanvasRestore acr(canvas, true);
        canvas->concat(fMatrix);

		// empty this now, so we can correctly record any inval calls that
		// might be made during the draw call.
		fDirtyRgn.setEmpty();

#ifdef TEST_BOUNDER
		test_bounder	b(bm);
		canvas->setBounder(&b);
#endif
#ifdef SK_SIMULATE_FAILED_MALLOC
		gEnableControlledThrow = true;
#endif
#ifdef SK_BUILD_FOR_WIN32
		//try {
			this->draw(canvas);
		//}
		//catch (...) {
		//}
#else
		this->draw(canvas);
#endif
#ifdef SK_SIMULATE_FAILED_MALLOC
		gEnableControlledThrow = false;
#endif
#ifdef TEST_BOUNDER
		canvas->setBounder(NULL);
#endif

#if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN)
		GXEndDraw();
#endif

		return true;
	}
	return false;
}

bool SkWindow::handleChar(SkUnichar uni)
{
	if (this->onHandleChar(uni))
		return true;

	SkView* focus = this->getFocusView();
	if (focus == NULL)
		focus = this;

	SkEvent evt(SK_EventType_Unichar);
	evt.setFast32(uni);
	return focus->doEvent(evt);
}

bool SkWindow::handleKey(SkKey key)
{
	if (key == kNONE_SkKey)
		return false;

	if (this->onHandleKey(key))
		return true;

	// send an event to the focus-view
	{
		SkView* focus = this->getFocusView();
		if (focus == NULL)
			focus = this;

		SkEvent evt(SK_EventType_Key);
		evt.setFast32(key);
		if (focus->doEvent(evt))
			return true;
	}

	if (key == kUp_SkKey || key == kDown_SkKey)
	{
		if (this->moveFocus(key == kUp_SkKey ? kPrev_FocusDirection : kNext_FocusDirection) == NULL)
			this->onSetFocusView(NULL);
		return true;
	}
	return false;
}

bool SkWindow::handleKeyUp(SkKey key)
{
    if (key == kNONE_SkKey)
        return false;

    if (this->onHandleKeyUp(key))
        return true;

    //send an event to the focus-view
    {
        SkView* focus = this->getFocusView();
        if (focus == NULL)
            focus = this;

        //should this one be the same?
        SkEvent evt(SK_EventType_KeyUp);
        evt.setFast32(key);
        if (focus->doEvent(evt))
            return true;
    }
    return false;
}

void SkWindow::addMenu(SkOSMenu* menu)
{
	*fMenus.append() = menu;
	this->onAddMenu(menu);
}

void SkWindow::setTitle(const char title[]) {
    if (NULL == title) {
        title = "";
    }
    fTitle.set(title);
    this->onSetTitle(title);
}

bool SkWindow::handleMenu(uint32_t cmd)
{
	for (int i = 0; i < fMenus.count(); i++)
	{
		SkEvent* evt = fMenus[i]->createEvent(cmd);
		if (evt)
		{
			evt->post(this->getSinkID());
			return true;
		}
	}
	return false;
}

//////////////////////////////////////////////////////////////////////

bool SkWindow::onEvent(const SkEvent& evt)
{
	if (evt.isType(SK_EventDelayInval))
	{
		SkRegion::Iterator	iter(fDirtyRgn);

		for (; !iter.done(); iter.next())
			this->onHandleInval(iter.rect());
		fWaitingOnInval = false;
		return true;
	}
	return this->INHERITED::onEvent(evt);
}

bool SkWindow::onGetFocusView(SkView** focus) const
{
	if (focus)
		*focus = fFocusView;
	return true;
}

bool SkWindow::onSetFocusView(SkView* focus)
{
	if (fFocusView != focus)
	{
		if (fFocusView)
			fFocusView->onFocusChange(false);
		fFocusView = focus;
		if (focus)
			focus->onFocusChange(true);
	}
	return true;
}

//////////////////////////////////////////////////////////////////////

void SkWindow::onHandleInval(const SkIRect&)
{
}

bool SkWindow::onHandleChar(SkUnichar)
{
	return false;
}

bool SkWindow::onHandleKey(SkKey key)
{
	return false;
}

bool SkWindow::onHandleKeyUp(SkKey key)
{
    return false;
}

bool SkWindow::handleClick(int x, int y, Click::State state)
{
	bool handled = false;

	switch (state) {
	case Click::kDown_State:
		if (fClick)
			delete fClick;
		fClick = this->findClickHandler(SkIntToScalar(x), SkIntToScalar(y));
		if (fClick)
		{
			SkView::DoClickDown(fClick, x, y);
			handled = true;
		}
		break;
	case Click::kMoved_State:
		if (fClick)
		{
			SkView::DoClickMoved(fClick, x, y);
			handled = true;
		}
		break;
	case Click::kUp_State:
		if (fClick)
		{
			SkView::DoClickUp(fClick, x, y);
			delete fClick;
			fClick = NULL;
			handled = true;
		}
		break;
	}
	return handled;
}

<|endoftext|>


<commit_before>#include "vision_methods.hpp"
//#include <oepncv2/features2d.hpp>
#include <opencv2/opencv.hpp>

vision_methods::vision_methods () {
}

vision_methods::~vision_methods () {
}

cv::Mat vision_methods::preprocessing (const cv::Mat& image_in) {
    cv::Mat image_out;
    cvtColor (image_in, image_out, CV_BGR2GRAY);
    cv::GaussianBlur (image_out, image_out, cv::Size (_ksize_x, _ksize_y), _sigma_x, _sigma_y);
    return image_out;
}

cv::Mat vision_methods::segmentation (const cv::Mat& image_in) {
    cv::Mat image_out;

    cv::threshold (image_in, image_out, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    return image_out;
}

cv::Mat vision_methods::extraction (const cv::Mat& image_in,
std::map<unsigned int, cv::Point2f>& markers) {
    std::vector<cv::KeyPoint> key_points;
    cv::Mat image_out (image_in.rows, image_in.cols, CV_8UC1, cv::Scalar (0));

    // blob detection creation
    cv::SimpleBlobDetector::Params blob_detector_params;
    blob_detector_params.filterByArea = true;
    blob_detector_params.maxArea      = 10000.0;
    blob_detector_params.minArea      = 10.0;
    cv::SimpleBlobDetector blob_detector (blob_detector_params);

    blob_detector.detect (image_in, key_points);

    for (cv::KeyPoint point : key_points) {
        circle (image_out, point.pt, point.size * 2, cv::Scalar (255), -1);
    }
    cv::drawKeypoints (image_out, key_points, image_out);

    std::vector<std::vector<cv::KeyPoint>> potential_markers;
    extract_groups (key_points, potential_markers);
    extract_markers (potential_markers, markers);

    return image_out;
}

void vision_methods::extract_groups (std::vector<cv::KeyPoint> key_points,
std::vector<std::vector<cv::KeyPoint>>& potential_markers) {
    // group keypoints into markers by proximity
    while (!key_points.empty ()) {
        std::vector<cv::KeyPoint> grouped_points;
        cv::KeyPoint key_point = key_points.back ();
        key_points.pop_back ();
        float x = key_point.pt.x;
        float y = key_point.pt.y;

        // check distance against all other key points
        for (auto itr = key_points.cbegin (); itr != key_points.cend ();) {
            float dx       = x - itr->pt.x;
            float dy       = y - itr->pt.y;
            float distance = sqrt ((dx * dx) + (dy * dy));

            // if the point is in range, group it with current point
            if (distance < (key_point.size * _BLOB_SIZE_RATIO)) {
                grouped_points.push_back (*itr);
                key_points.erase (itr);
            } else {
                itr++;
            }
        }

        grouped_points.push_back (key_point);
        potential_markers.push_back (grouped_points);
    }
}

void vision_methods::extract_markers (std::vector<std::vector<cv::KeyPoint>>& potential_markers,
std::map<unsigned int, cv::Point2f>& markers) {
    // calculate marker properties (id, size, location)
    for (std::vector<cv::KeyPoint> marker_points : potential_markers) {
        const unsigned int marker_id = marker_points.size ();

        if (_MIN_MARKER_ID <= marker_id && marker_id <= _MAX_MARKER_ID) {
            cv::Point2f marker_pos;
            float average_x = 0;
            float average_y = 0;

            for (cv::KeyPoint key_point : marker_points) {
                //    average_size += key_point.size;
                average_x += key_point.pt.x;
                average_y += key_point.pt.y;
            }

            // average_size /= marker_id;
            marker_pos.x       = average_x / marker_id;
            marker_pos.y       = average_y / marker_id;
            markers[marker_id] = marker_pos;
        }
    }
}

/*    std::vector<cv::Vec4i> hierarchy;
    cv::RNG rng;
    cv::findContours (image_in, contours, hierarchy, CV_RETR_TREE,
 CV_CHAIN_APPROX_SIMPLE);

  cv::Mat drawing = cv::Mat::zeros (image_in.size (), CV_8UC3);
  for (unsigned int i = 0; i < contours.size (); i++) {
      cv::Scalar color =
      cv::Scalar (rng.uniform (0, 255), rng.uniform (0, 255), rng.uniform
 (0, 255));
      cv::drawContours (drawing, contours, i, color, 2, 8, hierarchy, 0);
  }

  return drawing;*/

/*
  // blob detection creation
    cv::SimpleBlobDetector::Params blob_detector_params;
    blob_detector_params.filterByArea        = true;
    blob_detector_params.maxArea             = 10000.0;
    blob_detector_params.minArea             = 10.0;
    blob_detector_params.minDistBetweenBlobs = 5.0; // 50?
    cv::SimpleBlobDetector blob_detector (blob_detector_params);

    blob_detector.detect (image_in, key_points);

    int i = 0;
    for (cv::KeyPoint point : key_points) {
        markers[i] = point;
        ++i;
    }

    cv::drawKeypoints (image_in, key_points, image_out);
*/
<commit_msg>remove old commented code<commit_after>#include "vision_methods.hpp"
//#include <oepncv2/features2d.hpp>
#include <opencv2/opencv.hpp>

vision_methods::vision_methods () {
}

vision_methods::~vision_methods () {
}

cv::Mat vision_methods::preprocessing (const cv::Mat& image_in) {
    cv::Mat image_out;
    cvtColor (image_in, image_out, CV_BGR2GRAY);
    cv::GaussianBlur (image_out, image_out, cv::Size (_ksize_x, _ksize_y), _sigma_x, _sigma_y);
    return image_out;
}

cv::Mat vision_methods::segmentation (const cv::Mat& image_in) {
    cv::Mat image_out;

    cv::threshold (image_in, image_out, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);

    return image_out;
}

cv::Mat vision_methods::extraction (const cv::Mat& image_in,
std::map<unsigned int, cv::Point2f>& markers) {
    std::vector<cv::KeyPoint> key_points;
    cv::Mat image_out (image_in.rows, image_in.cols, CV_8UC1, cv::Scalar (0));

    // blob detection creation
    cv::SimpleBlobDetector::Params blob_detector_params;
    blob_detector_params.filterByArea = true;
    blob_detector_params.maxArea      = 10000.0;
    blob_detector_params.minArea      = 10.0;
    cv::SimpleBlobDetector blob_detector (blob_detector_params);

    blob_detector.detect (image_in, key_points);

    for (cv::KeyPoint point : key_points) {
        circle (image_out, point.pt, point.size * 2, cv::Scalar (255), -1);
    }
    cv::drawKeypoints (image_out, key_points, image_out);

    std::vector<std::vector<cv::KeyPoint>> potential_markers;
    extract_groups (key_points, potential_markers);
    extract_markers (potential_markers, markers);

    return image_out;
}

void vision_methods::extract_groups (std::vector<cv::KeyPoint> key_points,
std::vector<std::vector<cv::KeyPoint>>& potential_markers) {
    // group keypoints into markers by proximity
    while (!key_points.empty ()) {
        std::vector<cv::KeyPoint> grouped_points;
        cv::KeyPoint key_point = key_points.back ();
        key_points.pop_back ();
        float x = key_point.pt.x;
        float y = key_point.pt.y;

        // check distance against all other key points
        for (auto itr = key_points.cbegin (); itr != key_points.cend ();) {
            float dx       = x - itr->pt.x;
            float dy       = y - itr->pt.y;
            float distance = sqrt ((dx * dx) + (dy * dy));

            // if the point is in range, group it with current point
            if (distance < (key_point.size * _BLOB_SIZE_RATIO)) {
                grouped_points.push_back (*itr);
                key_points.erase (itr);
            } else {
                itr++;
            }
        }

        grouped_points.push_back (key_point);
        potential_markers.push_back (grouped_points);
    }
}

void vision_methods::extract_markers (std::vector<std::vector<cv::KeyPoint>>& potential_markers,
std::map<unsigned int, cv::Point2f>& markers) {
    // calculate marker properties (id, size, location)
    for (std::vector<cv::KeyPoint> marker_points : potential_markers) {
        const unsigned int marker_id = marker_points.size ();

        if (_MIN_MARKER_ID <= marker_id && marker_id <= _MAX_MARKER_ID) {
            cv::Point2f marker_pos;
            float average_x = 0;
            float average_y = 0;

            for (cv::KeyPoint key_point : marker_points) {
                //    average_size += key_point.size;
                average_x += key_point.pt.x;
                average_y += key_point.pt.y;
            }

            // average_size /= marker_id;
            marker_pos.x       = average_x / marker_id;
            marker_pos.y       = average_y / marker_id;
            markers[marker_id] = marker_pos;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Amber Authors.
//
// 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 "src/vulkan/pipeline.h"

#include <algorithm>
#include <cassert>
#include <limits>
#include <utility>

#include "src/command.h"
#include "src/engine.h"
#include "src/make_unique.h"
#include "src/vulkan/buffer_descriptor.h"
#include "src/vulkan/compute_pipeline.h"
#include "src/vulkan/graphics_pipeline.h"

namespace amber {
namespace vulkan {

Pipeline::Pipeline(
    PipelineType type,
    VkDevice device,
    const VkPhysicalDeviceMemoryProperties& properties,
    uint32_t fence_timeout_ms,
    const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info)
    : device_(device),
      memory_properties_(properties),
      pipeline_type_(type),
      shader_stage_info_(shader_stage_info),
      fence_timeout_ms_(fence_timeout_ms) {}

Pipeline::~Pipeline() = default;

GraphicsPipeline* Pipeline::AsGraphics() {
  return static_cast<GraphicsPipeline*>(this);
}

ComputePipeline* Pipeline::AsCompute() {
  return static_cast<ComputePipeline*>(this);
}

Result Pipeline::InitializeCommandBuffer(VkCommandPool pool, VkQueue queue) {
  command_ = MakeUnique<CommandBuffer>(device_, pool, queue);
  Result r = command_->Initialize();
  if (!r.IsSuccess())
    return r;

  return {};
}

void Pipeline::Shutdown() {
  Result r = command_->End();
  if (r.IsSuccess())
    command_->SubmitAndReset(fence_timeout_ms_);

  DestoryDescriptorPools();
  DestoryDescriptorSetLayouts();
  command_->Shutdown();
  vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
  for (size_t i = 0; i < descriptors_.size(); ++i)
    descriptors_[i]->Shutdown();
  vkDestroyPipeline(device_, pipeline_, nullptr);
}

void Pipeline::DestoryDescriptorSetLayouts() {
  for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) {
    vkDestroyDescriptorSetLayout(device_, descriptor_set_layouts_[i], nullptr);
  }
  descriptor_set_layouts_.clear();
}

Result Pipeline::CreateDescriptorSetLayouts() {
  std::sort(descriptors_.begin(), descriptors_.end());

  size_t i = 0;
  while (i < descriptors_.size()) {
    std::vector<VkDescriptorSetLayoutBinding> bindings;
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      bindings.emplace_back();
      bindings.back().binding = descriptors_[i]->GetBinding();
      bindings.back().descriptorType =
          ToVkDescriptorType(descriptors_[i]->GetType());
      bindings.back().descriptorCount = 1;
      // TODO(jaebaek): Amber script must contain which stages use each
      //                descriptor. Set .stageFlags attribute based on it.
      bindings.back().stageFlags = VK_SHADER_STAGE_ALL;
      // TODO(jaebaek): Properly set .pImmutableSamplers attribute.
    }

    VkDescriptorSetLayoutCreateInfo desc_info = {};
    desc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    desc_info.bindingCount = bindings.size();
    desc_info.pBindings = bindings.data();

    VkDescriptorSetLayout desc_layout = VK_NULL_HANDLE;
    if (vkCreateDescriptorSetLayout(device_, &desc_info, nullptr,
                                    &desc_layout) != VK_SUCCESS) {
      return Result("Vulkan::Calling vkCreateDescriptorSetLayout Fail");
    }
    descriptor_set_layouts_.push_back(desc_layout);
  }

  return {};
}

void Pipeline::DestoryDescriptorPools() {
  for (size_t i = 0; i < descriptor_pools_.size(); ++i) {
    vkDestroyDescriptorPool(device_, descriptor_pools_[i], nullptr);
  }
  descriptor_pools_.clear();
}

Result Pipeline::CreateDescriptorPools() {
  size_t i = 0;
  while (i < descriptors_.size()) {
    std::vector<VkDescriptorPoolSize> pool_sizes;
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      auto type = ToVkDescriptorType(descriptors_[i]->GetType());
      auto it = find_if(pool_sizes.begin(), pool_sizes.end(),
                        [&type](const VkDescriptorPoolSize& size) {
                          return size.type == type;
                        });
      if (it != pool_sizes.end()) {
        it->descriptorCount += 1;
        continue;
      }

      pool_sizes.emplace_back();
      pool_sizes.back().type = type;
      pool_sizes.back().descriptorCount = 1;
    }

    VkDescriptorPoolCreateInfo pool_info = {};
    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    pool_info.maxSets = 1;
    pool_info.poolSizeCount = pool_sizes.size();
    pool_info.pPoolSizes = pool_sizes.data();

    VkDescriptorPool desc_pool = VK_NULL_HANDLE;
    if (vkCreateDescriptorPool(device_, &pool_info, nullptr, &desc_pool) !=
        VK_SUCCESS) {
      return Result("Vulkan::Calling vkCreateDescriptorPool Fail");
    }
    descriptor_pools_.push_back(desc_pool);
  }

  return {};
}

Result Pipeline::CreateDescriptorSets() {
  for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) {
    VkDescriptorSetAllocateInfo desc_set_info = {};
    desc_set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    desc_set_info.descriptorPool = descriptor_pools_[i];
    desc_set_info.descriptorSetCount = 1;
    desc_set_info.pSetLayouts = &descriptor_set_layouts_[i];

    VkDescriptorSet desc_set = VK_NULL_HANDLE;
    if (vkAllocateDescriptorSets(device_, &desc_set_info, &desc_set) !=
        VK_SUCCESS) {
      return Result("Vulkan::Calling vkAllocateDescriptorSets Fail");
    }
    descriptor_sets_.push_back(desc_set);
  }

  return {};
}

Result Pipeline::CreatePipelineLayout() {
  VkPipelineLayoutCreateInfo pipeline_layout_info = {};
  pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  pipeline_layout_info.setLayoutCount = descriptor_set_layouts_.size();
  pipeline_layout_info.pSetLayouts = descriptor_set_layouts_.data();
  // TODO(jaebaek): Push constant for pipeline_layout_info.

  if (vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr,
                             &pipeline_layout_) != VK_SUCCESS) {
    return Result("Vulkan::Calling vkCreatePipelineLayout Fail");
  }

  return {};
}

Result Pipeline::CreateVkDescriptorRelatedObjectsIfNeeded() {
  if (descriptor_related_objects_already_created_)
    return {};

  // TODO(jaebaek): Update SSBO dynamically.
  Result r = CreateDescriptorSetLayouts();
  if (!r.IsSuccess())
    return r;

  r = CreateDescriptorPools();
  if (!r.IsSuccess())
    return r;

  r = CreateDescriptorSets();
  if (!r.IsSuccess())
    return r;

  return CreatePipelineLayout();
}

Result Pipeline::UpdateDescriptorSetsIfNeeded() {
  for (size_t i = 0, j = 0;
       i < descriptors_.size() && j < descriptor_sets_.size(); ++j) {
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      Result r =
          descriptors_[i]->UpdateDescriptorSetIfNeeded(descriptor_sets_[j]);
      if (!r.IsSuccess())
        return r;
    }
  }

  descriptor_related_objects_already_created_ = true;
  return {};
}

Result Pipeline::AddDescriptor(const BufferCommand* buffer_command) {
  if (!buffer_command->IsSSBO() && !buffer_command->IsUniform())
    return Result("Pipeline::AddDescriptor not supported buffer type");

  Descriptor* desc = nullptr;
  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() ==
            buffer_command->GetDescriptorSet() &&
        descriptors_[i]->GetBinding() == buffer_command->GetBinding()) {
      desc = descriptors_[i].get();
    }
  }

  if (desc == nullptr) {
    auto desc_type = buffer_command->IsSSBO() ? DescriptorType::kStorageBuffer
                                              : DescriptorType::kUniformBuffer;
    auto buffer_desc = MakeUnique<BufferDescriptor>(
        desc_type, device_, buffer_command->GetDescriptorSet(),
        buffer_command->GetBinding());
    descriptors_.push_back(std::move(buffer_desc));

    desc = descriptors_.back().get();
  }

  if (buffer_command->IsSSBO() && !desc->IsStorageBuffer()) {
    return Result(
        "Vulkan::AddDescriptor BufferCommand for SSBO uses wrong descriptor "
        "set and binding");
  }

  if (buffer_command->IsUniform() && !desc->IsUniformBuffer()) {
    return Result(
        "Vulkan::AddDescriptor BufferCommand for UBO uses wrong descriptor set "
        "and binding");
  }

  desc->AddToBufferDataQueue(
      buffer_command->GetDatumType().GetType(), buffer_command->GetOffset(),
      buffer_command->GetSize(), buffer_command->GetValues());

  return {};
}

Result Pipeline::SendDescriptorDataToDeviceIfNeeded() {
  if (descriptors_.size() == 0)
    return {};

  bool data_send_needed = false;
  for (const auto& desc : descriptors_) {
    if (desc->HasDataNotSent()) {
      data_send_needed = true;
      break;
    }
  }

  if (!data_send_needed)
    return {};

  Result r = command_->BeginIfNotInRecording();
  if (!r.IsSuccess())
    return r;

  for (const auto& desc : descriptors_) {
    r = desc->CreateOrResizeIfNeeded(command_->GetCommandBuffer(),
                                     memory_properties_);
    if (!r.IsSuccess())
      return r;

    desc->UpdateResourceIfNeeded(command_->GetCommandBuffer());
  }

  return {};
}

void Pipeline::BindVkDescriptorSets() {
  vkCmdBindDescriptorSets(command_->GetCommandBuffer(),
                          IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS
                                       : VK_PIPELINE_BIND_POINT_COMPUTE,
                          pipeline_layout_, 0, descriptor_sets_.size(),
                          descriptor_sets_.data(), 0, nullptr);
}

void Pipeline::BindVkPipeline() {
  vkCmdBindPipeline(command_->GetCommandBuffer(),
                    IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS
                                 : VK_PIPELINE_BIND_POINT_COMPUTE,
                    pipeline_);
}

Result Pipeline::CopyDescriptorToHost(const uint32_t descriptor_set,
                                      const uint32_t binding) {
  Result r = command_->BeginIfNotInRecording();
  if (!r.IsSuccess())
    return r;

  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() == descriptor_set &&
        descriptors_[i]->GetBinding() == binding) {
      return descriptors_[i]->SendDataToHostIfNeeded(
          command_->GetCommandBuffer());
    }
  }

  return Result("Vulkan::Pipeline descriptor with descriptor set: " +
                std::to_string(descriptor_set) +
                ", binding: " + std::to_string(binding) + " does not exist");
}

Result Pipeline::GetDescriptorInfo(const uint32_t descriptor_set,
                                   const uint32_t binding,
                                   ResourceInfo* info) {
  assert(info);
  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() == descriptor_set &&
        descriptors_[i]->GetBinding() == binding) {
      *info = descriptors_[i]->GetResourceInfo();
      return {};
    }
  }

  return Result("Vulkan::Pipeline descriptor with descriptor set: " +
                std::to_string(descriptor_set) +
                ", binding: " + std::to_string(binding) + " does not exist");
}

}  // namespace vulkan
}  // namespace amber
<commit_msg>Vulkan: submit commands after resizing buffers (#165)<commit_after>// Copyright 2018 The Amber Authors.
//
// 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 "src/vulkan/pipeline.h"

#include <algorithm>
#include <cassert>
#include <limits>
#include <utility>

#include "src/command.h"
#include "src/engine.h"
#include "src/make_unique.h"
#include "src/vulkan/buffer_descriptor.h"
#include "src/vulkan/compute_pipeline.h"
#include "src/vulkan/graphics_pipeline.h"

namespace amber {
namespace vulkan {

Pipeline::Pipeline(
    PipelineType type,
    VkDevice device,
    const VkPhysicalDeviceMemoryProperties& properties,
    uint32_t fence_timeout_ms,
    const std::vector<VkPipelineShaderStageCreateInfo>& shader_stage_info)
    : device_(device),
      memory_properties_(properties),
      pipeline_type_(type),
      shader_stage_info_(shader_stage_info),
      fence_timeout_ms_(fence_timeout_ms) {}

Pipeline::~Pipeline() = default;

GraphicsPipeline* Pipeline::AsGraphics() {
  return static_cast<GraphicsPipeline*>(this);
}

ComputePipeline* Pipeline::AsCompute() {
  return static_cast<ComputePipeline*>(this);
}

Result Pipeline::InitializeCommandBuffer(VkCommandPool pool, VkQueue queue) {
  command_ = MakeUnique<CommandBuffer>(device_, pool, queue);
  Result r = command_->Initialize();
  if (!r.IsSuccess())
    return r;

  return {};
}

void Pipeline::Shutdown() {
  Result r = command_->End();
  if (r.IsSuccess())
    command_->SubmitAndReset(fence_timeout_ms_);

  DestoryDescriptorPools();
  DestoryDescriptorSetLayouts();
  command_->Shutdown();
  vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
  for (size_t i = 0; i < descriptors_.size(); ++i)
    descriptors_[i]->Shutdown();
  vkDestroyPipeline(device_, pipeline_, nullptr);
}

void Pipeline::DestoryDescriptorSetLayouts() {
  for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) {
    vkDestroyDescriptorSetLayout(device_, descriptor_set_layouts_[i], nullptr);
  }
  descriptor_set_layouts_.clear();
}

Result Pipeline::CreateDescriptorSetLayouts() {
  std::sort(descriptors_.begin(), descriptors_.end());

  size_t i = 0;
  while (i < descriptors_.size()) {
    std::vector<VkDescriptorSetLayoutBinding> bindings;
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      bindings.emplace_back();
      bindings.back().binding = descriptors_[i]->GetBinding();
      bindings.back().descriptorType =
          ToVkDescriptorType(descriptors_[i]->GetType());
      bindings.back().descriptorCount = 1;
      // TODO(jaebaek): Amber script must contain which stages use each
      //                descriptor. Set .stageFlags attribute based on it.
      bindings.back().stageFlags = VK_SHADER_STAGE_ALL;
      // TODO(jaebaek): Properly set .pImmutableSamplers attribute.
    }

    VkDescriptorSetLayoutCreateInfo desc_info = {};
    desc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
    desc_info.bindingCount = bindings.size();
    desc_info.pBindings = bindings.data();

    VkDescriptorSetLayout desc_layout = VK_NULL_HANDLE;
    if (vkCreateDescriptorSetLayout(device_, &desc_info, nullptr,
                                    &desc_layout) != VK_SUCCESS) {
      return Result("Vulkan::Calling vkCreateDescriptorSetLayout Fail");
    }
    descriptor_set_layouts_.push_back(desc_layout);
  }

  return {};
}

void Pipeline::DestoryDescriptorPools() {
  for (size_t i = 0; i < descriptor_pools_.size(); ++i) {
    vkDestroyDescriptorPool(device_, descriptor_pools_[i], nullptr);
  }
  descriptor_pools_.clear();
}

Result Pipeline::CreateDescriptorPools() {
  size_t i = 0;
  while (i < descriptors_.size()) {
    std::vector<VkDescriptorPoolSize> pool_sizes;
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      auto type = ToVkDescriptorType(descriptors_[i]->GetType());
      auto it = find_if(pool_sizes.begin(), pool_sizes.end(),
                        [&type](const VkDescriptorPoolSize& size) {
                          return size.type == type;
                        });
      if (it != pool_sizes.end()) {
        it->descriptorCount += 1;
        continue;
      }

      pool_sizes.emplace_back();
      pool_sizes.back().type = type;
      pool_sizes.back().descriptorCount = 1;
    }

    VkDescriptorPoolCreateInfo pool_info = {};
    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    pool_info.maxSets = 1;
    pool_info.poolSizeCount = pool_sizes.size();
    pool_info.pPoolSizes = pool_sizes.data();

    VkDescriptorPool desc_pool = VK_NULL_HANDLE;
    if (vkCreateDescriptorPool(device_, &pool_info, nullptr, &desc_pool) !=
        VK_SUCCESS) {
      return Result("Vulkan::Calling vkCreateDescriptorPool Fail");
    }
    descriptor_pools_.push_back(desc_pool);
  }

  return {};
}

Result Pipeline::CreateDescriptorSets() {
  for (size_t i = 0; i < descriptor_set_layouts_.size(); ++i) {
    VkDescriptorSetAllocateInfo desc_set_info = {};
    desc_set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
    desc_set_info.descriptorPool = descriptor_pools_[i];
    desc_set_info.descriptorSetCount = 1;
    desc_set_info.pSetLayouts = &descriptor_set_layouts_[i];

    VkDescriptorSet desc_set = VK_NULL_HANDLE;
    if (vkAllocateDescriptorSets(device_, &desc_set_info, &desc_set) !=
        VK_SUCCESS) {
      return Result("Vulkan::Calling vkAllocateDescriptorSets Fail");
    }
    descriptor_sets_.push_back(desc_set);
  }

  return {};
}

Result Pipeline::CreatePipelineLayout() {
  VkPipelineLayoutCreateInfo pipeline_layout_info = {};
  pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
  pipeline_layout_info.setLayoutCount = descriptor_set_layouts_.size();
  pipeline_layout_info.pSetLayouts = descriptor_set_layouts_.data();
  // TODO(jaebaek): Push constant for pipeline_layout_info.

  if (vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr,
                             &pipeline_layout_) != VK_SUCCESS) {
    return Result("Vulkan::Calling vkCreatePipelineLayout Fail");
  }

  return {};
}

Result Pipeline::CreateVkDescriptorRelatedObjectsIfNeeded() {
  if (descriptor_related_objects_already_created_)
    return {};

  // TODO(jaebaek): Update SSBO dynamically.
  Result r = CreateDescriptorSetLayouts();
  if (!r.IsSuccess())
    return r;

  r = CreateDescriptorPools();
  if (!r.IsSuccess())
    return r;

  r = CreateDescriptorSets();
  if (!r.IsSuccess())
    return r;

  return CreatePipelineLayout();
}

Result Pipeline::UpdateDescriptorSetsIfNeeded() {
  for (size_t i = 0, j = 0;
       i < descriptors_.size() && j < descriptor_sets_.size(); ++j) {
    for (const uint32_t current_desc = descriptors_[i]->GetDescriptorSet();
         i < descriptors_.size() &&
         current_desc == descriptors_[i]->GetDescriptorSet();
         ++i) {
      Result r =
          descriptors_[i]->UpdateDescriptorSetIfNeeded(descriptor_sets_[j]);
      if (!r.IsSuccess())
        return r;
    }
  }

  descriptor_related_objects_already_created_ = true;
  return {};
}

Result Pipeline::AddDescriptor(const BufferCommand* buffer_command) {
  if (!buffer_command->IsSSBO() && !buffer_command->IsUniform())
    return Result("Pipeline::AddDescriptor not supported buffer type");

  Descriptor* desc = nullptr;
  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() ==
            buffer_command->GetDescriptorSet() &&
        descriptors_[i]->GetBinding() == buffer_command->GetBinding()) {
      desc = descriptors_[i].get();
    }
  }

  if (desc == nullptr) {
    auto desc_type = buffer_command->IsSSBO() ? DescriptorType::kStorageBuffer
                                              : DescriptorType::kUniformBuffer;
    auto buffer_desc = MakeUnique<BufferDescriptor>(
        desc_type, device_, buffer_command->GetDescriptorSet(),
        buffer_command->GetBinding());
    descriptors_.push_back(std::move(buffer_desc));

    desc = descriptors_.back().get();
  }

  if (buffer_command->IsSSBO() && !desc->IsStorageBuffer()) {
    return Result(
        "Vulkan::AddDescriptor BufferCommand for SSBO uses wrong descriptor "
        "set and binding");
  }

  if (buffer_command->IsUniform() && !desc->IsUniformBuffer()) {
    return Result(
        "Vulkan::AddDescriptor BufferCommand for UBO uses wrong descriptor set "
        "and binding");
  }

  desc->AddToBufferDataQueue(
      buffer_command->GetDatumType().GetType(), buffer_command->GetOffset(),
      buffer_command->GetSize(), buffer_command->GetValues());

  return {};
}

Result Pipeline::SendDescriptorDataToDeviceIfNeeded() {
  if (descriptors_.size() == 0)
    return {};

  bool data_send_needed = false;
  for (const auto& desc : descriptors_) {
    if (desc->HasDataNotSent()) {
      data_send_needed = true;
      break;
    }
  }

  if (!data_send_needed)
    return {};

  Result r = command_->BeginIfNotInRecording();
  if (!r.IsSuccess())
    return r;

  for (const auto& desc : descriptors_) {
    r = desc->CreateOrResizeIfNeeded(command_->GetCommandBuffer(),
                                     memory_properties_);
    if (!r.IsSuccess())
      return r;
  }

  r = command_->End();
  if (!r.IsSuccess())
    return r;

  // Note that if a buffer for a descriptor is host accessible and
  // does not need to record a command to copy data to device, it
  // directly writes data to the buffer. The direct write must be
  // done after resizing backed buffer i.e., copying data to the new
  // buffer from the old one. Thus, we must submit commands here to
  // guarantee this.
  r = command_->SubmitAndReset(GetFenceTimeout());
  if (!r.IsSuccess())
    return r;

  r = command_->BeginIfNotInRecording();
  if (!r.IsSuccess())
    return r;

  for (const auto& desc : descriptors_) {
    desc->UpdateResourceIfNeeded(command_->GetCommandBuffer());
  }

  return {};
}

void Pipeline::BindVkDescriptorSets() {
  vkCmdBindDescriptorSets(command_->GetCommandBuffer(),
                          IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS
                                       : VK_PIPELINE_BIND_POINT_COMPUTE,
                          pipeline_layout_, 0, descriptor_sets_.size(),
                          descriptor_sets_.data(), 0, nullptr);
}

void Pipeline::BindVkPipeline() {
  vkCmdBindPipeline(command_->GetCommandBuffer(),
                    IsGraphics() ? VK_PIPELINE_BIND_POINT_GRAPHICS
                                 : VK_PIPELINE_BIND_POINT_COMPUTE,
                    pipeline_);
}

Result Pipeline::CopyDescriptorToHost(const uint32_t descriptor_set,
                                      const uint32_t binding) {
  Result r = command_->BeginIfNotInRecording();
  if (!r.IsSuccess())
    return r;

  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() == descriptor_set &&
        descriptors_[i]->GetBinding() == binding) {
      return descriptors_[i]->SendDataToHostIfNeeded(
          command_->GetCommandBuffer());
    }
  }

  return Result("Vulkan::Pipeline descriptor with descriptor set: " +
                std::to_string(descriptor_set) +
                ", binding: " + std::to_string(binding) + " does not exist");
}

Result Pipeline::GetDescriptorInfo(const uint32_t descriptor_set,
                                   const uint32_t binding,
                                   ResourceInfo* info) {
  assert(info);
  for (size_t i = 0; i < descriptors_.size(); ++i) {
    if (descriptors_[i]->GetDescriptorSet() == descriptor_set &&
        descriptors_[i]->GetBinding() == binding) {
      *info = descriptors_[i]->GetResourceInfo();
      return {};
    }
  }

  return Result("Vulkan::Pipeline descriptor with descriptor set: " +
                std::to_string(descriptor_set) +
                ", binding: " + std::to_string(binding) + " does not exist");
}

}  // namespace vulkan
}  // namespace amber
<|endoftext|>