Reformat all code and use the Google cpp code style

This commit is contained in:
Simon Fels 2016-12-02 17:36:54 +01:00
commit b10382d2d8
222 changed files with 8739 additions and 9281 deletions

8
.clang-format Normal file
View file

@ -0,0 +1,8 @@
# Defines the Chromium style for automatic reformatting.
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Google
# This defaults to 'Auto'. Explicitly set it for a while, so that
# 'vector<vector<int> >' in existing files gets formatted to
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
# 'int>>' if the file already contains at least one such instance.)
Standard: Cpp11

3
scripts/clean-format.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
find src -name "*.h" | xargs clang-format -style=file -i
find src -name "*.cpp" | xargs clang-format -style=file -i

View file

@ -21,21 +21,18 @@
namespace anbox {
namespace android {
std::ostream& operator<<(std::ostream &out, const Intent &intent)
{
out << "["
<< "action=" << intent.action << " "
<< "uri=" << intent.uri << " "
<< "type=" << intent.type << " "
<< "flags=" << intent.flags << " "
<< "package=" << intent.package << " "
<< "component=" << intent.component << " "
<< "categories=[ ";
for (const auto &category : intent.categories)
out << category << " ";
out << "]]";
return out;
std::ostream &operator<<(std::ostream &out, const Intent &intent) {
out << "["
<< "action=" << intent.action << " "
<< "uri=" << intent.uri << " "
<< "type=" << intent.type << " "
<< "flags=" << intent.flags << " "
<< "package=" << intent.package << " "
<< "component=" << intent.component << " "
<< "categories=[ ";
for (const auto &category : intent.categories) out << category << " ";
out << "]]";
return out;
}
} // namespace android
} // namespace anbox
} // namespace android
} // namespace anbox

View file

@ -24,18 +24,17 @@
namespace anbox {
namespace android {
struct Intent {
std::string action;
std::string uri;
std::string type;
int flags = 0;
std::string package;
std::string component;
std::vector<std::string> categories;
std::string action;
std::string uri;
std::string type;
int flags = 0;
std::string package;
std::string component;
std::vector<std::string> categories;
};
std::ostream& operator<<(std::ostream &out, const Intent &intent);
} // namespace android
} // namespace anbox
std::ostream &operator<<(std::ostream &out, const Intent &intent);
} // namespace android
} // namespace anbox
#endif

View file

@ -19,53 +19,51 @@
#include "anbox/utils.h"
#include <algorithm>
#include <iostream>
#include <fstream>
#include <iostream>
namespace fs = boost::filesystem;
namespace anbox {
namespace application {
LauncherStorage::LauncherStorage(const fs::path &path) :
path_(path) {
}
LauncherStorage::LauncherStorage(const fs::path &path) : path_(path) {}
LauncherStorage::~LauncherStorage() {
}
LauncherStorage::~LauncherStorage() {}
void LauncherStorage::add(const Item &item) {
if (!fs::exists(path_))
fs::create_directories(path_);
if (!fs::exists(path_)) fs::create_directories(path_);
auto package_name = item.package;
std::replace(package_name.begin(), package_name.end(), '.', '-');
auto package_name = item.package;
std::replace(package_name.begin(), package_name.end(), '.', '-');
const auto item_path = path_ / utils::string_format("anbox-%s.desktop", package_name);
std::string exec = "anbox launch ";
const auto item_path =
path_ / utils::string_format("anbox-%s.desktop", package_name);
std::string exec = "anbox launch ";
if (!item.launch_intent.action.empty())
exec += utils::string_format("--action=%s ", item.launch_intent.action);
if (!item.launch_intent.action.empty())
exec += utils::string_format("--action=%s ", item.launch_intent.action);
if (!item.launch_intent.type.empty())
exec += utils::string_format("--type=%s ", item.launch_intent.type);
if (!item.launch_intent.type.empty())
exec += utils::string_format("--type=%s ", item.launch_intent.type);
if (!item.launch_intent.uri.empty())
exec += utils::string_format("--uri=%s ", item.launch_intent.uri);
if (!item.launch_intent.uri.empty())
exec += utils::string_format("--uri=%s ", item.launch_intent.uri);
if (!item.launch_intent.package.empty())
exec += utils::string_format("--package=%s ", item.launch_intent.package);
if (!item.launch_intent.package.empty())
exec += utils::string_format("--package=%s ", item.launch_intent.package);
if (!item.launch_intent.component.empty())
exec += utils::string_format("--component=%s ", item.launch_intent.component);
if (!item.launch_intent.component.empty())
exec +=
utils::string_format("--component=%s ", item.launch_intent.component);
std::ofstream f(item_path.string());
f << "[Desktop Entry]" << std::endl
<< "Name=" << item.package << std::endl
<< "Exec=" << exec << std::endl
<< "Terminal=false" << std::endl
<< "Type=Application" << std::endl
<< "Encoding=UTF-8" << std::endl;
f.close();
std::ofstream f(item_path.string());
f << "[Desktop Entry]" << std::endl
<< "Name=" << item.package << std::endl
<< "Exec=" << exec << std::endl
<< "Terminal=false" << std::endl
<< "Type=Application" << std::endl
<< "Encoding=UTF-8" << std::endl;
f.close();
}
} // namespace application
} // namespace anbox
} // namespace application
} // namespace anbox

View file

@ -28,22 +28,22 @@
namespace anbox {
namespace application {
class LauncherStorage {
public:
LauncherStorage(const boost::filesystem::path &path);
~LauncherStorage();
public:
LauncherStorage(const boost::filesystem::path &path);
~LauncherStorage();
struct Item {
std::string name;
std::string package;
android::Intent launch_intent;
};
struct Item {
std::string name;
std::string package;
android::Intent launch_intent;
};
void add(const Item &item);
void add(const Item &item);
private:
boost::filesystem::path path_;
private:
boost::filesystem::path path_;
};
} // namespace application
} // namespace anbox
} // namespace application
} // namespace anbox
#endif

View file

@ -18,16 +18,16 @@
#ifndef ANBOX_APPLICATION_MANAGER_H_
#define ANBOX_APPLICATION_MANAGER_H_
#include "anbox/do_not_copy_or_move.h"
#include "anbox/android/intent.h"
#include "anbox/do_not_copy_or_move.h"
#include <string>
namespace anbox {
class ApplicationManager : public DoNotCopyOrMove {
public:
virtual void launch(const android::Intent &intent) = 0;
public:
virtual void launch(const android::Intent &intent) = 0;
};
} // namespace anbox
} // namespace anbox
#endif

View file

@ -16,13 +16,13 @@
*/
#include "anbox/bridge/android_api_stub.h"
#include "anbox/rpc/channel.h"
#include "anbox/utils.h"
#include "anbox/config.h"
#include "anbox/logger.h"
#include "anbox/rpc/channel.h"
#include "anbox/utils.h"
#include "anbox_rpc.pb.h"
#include "anbox_bridge.pb.h"
#include "anbox_rpc.pb.h"
#include <boost/filesystem.hpp>
@ -30,101 +30,90 @@ namespace fs = boost::filesystem;
namespace anbox {
namespace bridge {
AndroidApiStub::AndroidApiStub() {
AndroidApiStub::AndroidApiStub() {}
AndroidApiStub::~AndroidApiStub() {}
void AndroidApiStub::set_rpc_channel(
const std::shared_ptr<rpc::Channel> &channel) {
channel_ = channel;
}
AndroidApiStub::~AndroidApiStub() {
}
void AndroidApiStub::set_rpc_channel(const std::shared_ptr<rpc::Channel> &channel) {
channel_ = channel;
}
void AndroidApiStub::reset_rpc_channel() {
channel_.reset();
}
void AndroidApiStub::reset_rpc_channel() { channel_.reset(); }
void AndroidApiStub::ensure_rpc_channel() {
if (!channel_)
throw std::runtime_error("No remote client connected");
if (!channel_) throw std::runtime_error("No remote client connected");
}
void AndroidApiStub::launch(const android::Intent &intent) {
ensure_rpc_channel();
ensure_rpc_channel();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::LaunchApplication message;
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::LaunchApplication message;
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
launch_wait_handle_.expect_result();
}
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
launch_wait_handle_.expect_result();
}
auto launch_intent = message.mutable_intent();
auto launch_intent = message.mutable_intent();
if (!intent.action.empty())
launch_intent->set_action(intent.action);
if (!intent.action.empty()) launch_intent->set_action(intent.action);
if (!intent.uri.empty())
launch_intent->set_uri(intent.uri);
if (!intent.uri.empty()) launch_intent->set_uri(intent.uri);
if (!intent.type.empty())
launch_intent->set_type(intent.type);
if (!intent.type.empty()) launch_intent->set_type(intent.type);
if (!intent.package.empty())
launch_intent->set_package(intent.package);
if (!intent.package.empty()) launch_intent->set_package(intent.package);
if (!intent.component.empty())
launch_intent->set_component(intent.component);
if (!intent.component.empty()) launch_intent->set_component(intent.component);
for (const auto &category : intent.categories) {
auto c = launch_intent->add_categories();
*c = category;
}
for (const auto &category : intent.categories) {
auto c = launch_intent->add_categories();
*c = category;
}
channel_->call_method("launch_application",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &AndroidApiStub::application_launched, c.get()));
channel_->call_method(
"launch_application", &message, c->response.get(),
google::protobuf::NewCallback(this, &AndroidApiStub::application_launched,
c.get()));
launch_wait_handle_.wait_for_all();
launch_wait_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
if (c->response->has_error()) throw std::runtime_error(c->response->error());
}
void AndroidApiStub::application_launched(Request<protobuf::rpc::Void> *request) {
(void) request;
launch_wait_handle_.result_received();
void AndroidApiStub::application_launched(
Request<protobuf::rpc::Void> *request) {
(void)request;
launch_wait_handle_.result_received();
}
void AndroidApiStub::set_focused_task(const std::int32_t &id) {
ensure_rpc_channel();
ensure_rpc_channel();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::SetFocusedTask message;
message.set_id(id);
protobuf::bridge::SetFocusedTask message;
message.set_id(id);
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
set_focused_task_handle_.expect_result();
}
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
set_focused_task_handle_.expect_result();
}
channel_->call_method("set_focused_task",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &AndroidApiStub::focused_task_set, c.get()));
channel_->call_method("set_focused_task", &message, c->response.get(),
google::protobuf::NewCallback(
this, &AndroidApiStub::focused_task_set, c.get()));
set_focused_task_handle_.wait_for_all();
set_focused_task_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
if (c->response->has_error()) throw std::runtime_error(c->response->error());
}
void AndroidApiStub::focused_task_set(Request<protobuf::rpc::Void> *request) {
(void) request;
set_focused_task_handle_.result_received();
(void)request;
set_focused_task_handle_.result_received();
}
} // namespace bridge
} // namespace anbox
} // namespace bridge
} // namespace anbox

View file

@ -28,43 +28,43 @@ namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace bridge
} // namespace protobuf
} // namespace bridge
} // namespace protobuf
namespace rpc {
class Channel;
} // namespace rpc
} // namespace rpc
namespace bridge {
class AndroidApiStub : public anbox::ApplicationManager {
public:
AndroidApiStub();
~AndroidApiStub();
public:
AndroidApiStub();
~AndroidApiStub();
void set_rpc_channel(const std::shared_ptr<rpc::Channel> &channel);
void reset_rpc_channel();
void set_rpc_channel(const std::shared_ptr<rpc::Channel> &channel);
void reset_rpc_channel();
void launch(const android::Intent &intent) override;
void launch(const android::Intent &intent) override;
void set_focused_task(const std::int32_t &id);
void set_focused_task(const std::int32_t &id);
private:
void ensure_rpc_channel();
private:
void ensure_rpc_channel();
template<typename Response>
struct Request {
Request() : response(std::make_shared<Response>()), success(true) { }
std::shared_ptr<Response> response;
bool success;
};
template <typename Response>
struct Request {
Request() : response(std::make_shared<Response>()), success(true) {}
std::shared_ptr<Response> response;
bool success;
};
void application_launched(Request<protobuf::rpc::Void> *request);
void focused_task_set(Request<protobuf::rpc::Void> *request);
void application_launched(Request<protobuf::rpc::Void> *request);
void focused_task_set(Request<protobuf::rpc::Void> *request);
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle launch_wait_handle_;
common::WaitHandle set_focused_task_handle_;
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle launch_wait_handle_;
common::WaitHandle set_focused_task_handle_;
};
} // namespace bridge
} // namespace anbox
} // namespace bridge
} // namespace anbox
#endif

View file

@ -17,83 +17,86 @@
#include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/application/launcher_storage.h"
#include "anbox/logger.h"
#include "anbox/wm/manager.h"
#include "anbox/wm/window_state.h"
#include "anbox/logger.h"
#include "anbox_bridge.pb.h"
namespace anbox {
namespace bridge {
PlatformApiSkeleton::PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage) :
pending_calls_(pending_calls),
window_manager_(window_manager),
launcher_storage_(launcher_storage) {
PlatformApiSkeleton::PlatformApiSkeleton(
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage)
: pending_calls_(pending_calls),
window_manager_(window_manager),
launcher_storage_(launcher_storage) {}
PlatformApiSkeleton::~PlatformApiSkeleton() {}
void PlatformApiSkeleton::handle_boot_finished_event(
const anbox::protobuf::bridge::BootFinishedEvent &event) {
(void)event;
if (boot_finished_handler_) boot_finished_handler_();
}
PlatformApiSkeleton::~PlatformApiSkeleton() {
void PlatformApiSkeleton::handle_window_state_update_event(
const anbox::protobuf::bridge::WindowStateUpdateEvent &event) {
auto convert_window_state = [](
const ::anbox::protobuf::bridge::WindowStateUpdateEvent_WindowState
&window) {
return wm::WindowState(
wm::Display::Id(window.display_id()), window.has_surface(),
graphics::Rect(window.frame_left(), window.frame_top(),
window.frame_right(), window.frame_bottom()),
window.package_name(), wm::Task::Id(window.task_id()),
wm::Stack::Id(window.stack_id()));
};
wm::WindowState::List updated;
for (int n = 0; n < event.windows_size(); n++) {
const auto window = event.windows(n);
updated.push_back(convert_window_state(window));
}
wm::WindowState::List removed;
for (int n = 0; n < event.removed_windows_size(); n++) {
const auto window = event.removed_windows(n);
removed.push_back(convert_window_state(window));
}
window_manager_->apply_window_state_update(updated, removed);
}
void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event) {
(void) event;
void PlatformApiSkeleton::handle_application_list_update_event(
const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) {
for (int n = 0; n < event.applications_size(); n++) {
application::LauncherStorage::Item item;
if (boot_finished_handler_)
boot_finished_handler_();
const auto app = event.applications(n);
item.name = app.name();
item.package = app.package();
const auto li = app.launch_intent();
item.launch_intent.action = li.action();
item.launch_intent.uri = li.uri();
item.launch_intent.type = li.uri();
item.launch_intent.package = li.package();
item.launch_intent.component = li.component();
for (int m = 0; m < li.categories_size(); m++)
item.launch_intent.categories.push_back(li.categories(m));
// If the item is already stored it will be updated
launcher_storage_->add(item);
}
}
void PlatformApiSkeleton::handle_window_state_update_event(const anbox::protobuf::bridge::WindowStateUpdateEvent &event) {
auto convert_window_state = [](const ::anbox::protobuf::bridge::WindowStateUpdateEvent_WindowState &window) {
return wm::WindowState(
wm::Display::Id(window.display_id()),
window.has_surface(),
graphics::Rect(window.frame_left(), window.frame_top(), window.frame_right(), window.frame_bottom()),
window.package_name(),
wm::Task::Id(window.task_id()),
wm::Stack::Id(window.stack_id()));
};
wm::WindowState::List updated;
for (int n = 0; n < event.windows_size(); n++) {
const auto window = event.windows(n);
updated.push_back(convert_window_state(window));
}
wm::WindowState::List removed;
for (int n = 0; n < event.removed_windows_size(); n++) {
const auto window = event.removed_windows(n);
removed.push_back(convert_window_state(window));
}
window_manager_->apply_window_state_update(updated, removed);
void PlatformApiSkeleton::register_boot_finished_handler(
const std::function<void()> &action) {
boot_finished_handler_ = action;
}
void PlatformApiSkeleton::handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) {
for (int n = 0; n < event.applications_size(); n++) {
application::LauncherStorage::Item item;
const auto app = event.applications(n);
item.name = app.name();
item.package = app.package();
const auto li = app.launch_intent();
item.launch_intent.action = li.action();
item.launch_intent.uri = li.uri();
item.launch_intent.type = li.uri();
item.launch_intent.package = li.package();
item.launch_intent.component = li.component();
for (int m = 0; m < li.categories_size(); m++)
item.launch_intent.categories.push_back(li.categories(m));
// If the item is already stored it will be updated
launcher_storage_->add(item);
}
}
void PlatformApiSkeleton::register_boot_finished_handler(const std::function<void()> &action) {
boot_finished_handler_ = action;
}
} // namespace bridge
} // namespace anbox
} // namespace bridge
} // namespace anbox

View file

@ -23,50 +23,54 @@
namespace google {
namespace protobuf {
class Closure;
} // namespace protobuf
} // namespace google
} // namespace protobuf
} // namespace google
namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace rpc
} // namespace rpc
namespace bridge {
class BootFinishedEvent;
class WindowStateUpdateEvent;
class ApplicationListUpdateEvent;
} // namespace bridge
} // namespace protobuf
} // namespace bridge
} // namespace protobuf
namespace rpc {
class PendingCallCache;
} // namespace rpc
} // namespace rpc
namespace wm {
class Manager;
} // namespace wm
} // namespace wm
namespace application {
class LauncherStorage;
} // namespace application
} // namespace application
namespace bridge {
class PlatformApiSkeleton {
public:
PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage);
virtual ~PlatformApiSkeleton();
public:
PlatformApiSkeleton(
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage);
virtual ~PlatformApiSkeleton();
void handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event);
void handle_window_state_update_event(const anbox::protobuf::bridge::WindowStateUpdateEvent &event);
void handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event);
void handle_boot_finished_event(
const anbox::protobuf::bridge::BootFinishedEvent &event);
void handle_window_state_update_event(
const anbox::protobuf::bridge::WindowStateUpdateEvent &event);
void handle_application_list_update_event(
const anbox::protobuf::bridge::ApplicationListUpdateEvent &event);
void register_boot_finished_handler(const std::function<void()> &action);
void register_boot_finished_handler(const std::function<void()> &action);
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<wm::Manager> window_manager_;
std::shared_ptr<application::LauncherStorage> launcher_storage_;
std::function<void()> boot_finished_handler_;
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<wm::Manager> window_manager_;
std::shared_ptr<application::LauncherStorage> launcher_storage_;
std::function<void()> boot_finished_handler_;
};
} // namespace bridge
} // namespace anbox
} // namespace bridge
} // namespace anbox
#endif

View file

@ -17,41 +17,40 @@
#include "anbox/bridge/platform_message_processor.h"
#include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/rpc/template_message_processor.h"
#include "anbox/logger.h"
#include "anbox/rpc/template_message_processor.h"
#include "anbox_bridge.pb.h"
namespace anbox {
namespace bridge {
PlatformMessageProcessor::PlatformMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<PlatformApiSkeleton> &server,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls) :
rpc::MessageProcessor(sender, pending_calls),
server_(server) {
PlatformMessageProcessor::PlatformMessageProcessor(
const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<PlatformApiSkeleton> &server,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls)
: rpc::MessageProcessor(sender, pending_calls), server_(server) {}
PlatformMessageProcessor::~PlatformMessageProcessor() {}
void PlatformMessageProcessor::dispatch(rpc::Invocation const &invocation) {}
void PlatformMessageProcessor::process_event_sequence(
const std::string &raw_events) {
anbox::protobuf::bridge::EventSequence seq;
if (!seq.ParseFromString(raw_events)) {
WARNING("Failed to parse events from raw string");
return;
}
if (seq.has_boot_finished())
server_->handle_boot_finished_event(seq.boot_finished());
if (seq.has_window_state_update())
server_->handle_window_state_update_event(seq.window_state_update());
if (seq.has_application_list_update())
server_->handle_application_list_update_event(
seq.application_list_update());
}
PlatformMessageProcessor::~PlatformMessageProcessor() {
}
void PlatformMessageProcessor::dispatch(rpc::Invocation const& invocation) {
}
void PlatformMessageProcessor::process_event_sequence(const std::string &raw_events) {
anbox::protobuf::bridge::EventSequence seq;
if (!seq.ParseFromString(raw_events)) {
WARNING("Failed to parse events from raw string");
return;
}
if (seq.has_boot_finished())
server_->handle_boot_finished_event(seq.boot_finished());
if (seq.has_window_state_update())
server_->handle_window_state_update_event(seq.window_state_update());
if (seq.has_application_list_update())
server_->handle_application_list_update_event(seq.application_list_update());
}
} // namespace anbox
} // namespace network
} // namespace anbox
} // namespace network

View file

@ -24,19 +24,20 @@ namespace anbox {
namespace bridge {
class PlatformApiSkeleton;
class PlatformMessageProcessor : public rpc::MessageProcessor {
public:
PlatformMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<PlatformApiSkeleton> &server,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls);
~PlatformMessageProcessor();
public:
PlatformMessageProcessor(
const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<PlatformApiSkeleton> &server,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls);
~PlatformMessageProcessor();
void dispatch(rpc::Invocation const& invocation) override;
void process_event_sequence(const std::string &event) override;
void dispatch(rpc::Invocation const &invocation) override;
void process_event_sequence(const std::string &event) override;
private:
std::shared_ptr<PlatformApiSkeleton> server_;
private:
std::shared_ptr<PlatformApiSkeleton> server_;
};
} // namespace anbox
} // namespace network
} // namespace anbox
} // namespace network
#endif

View file

@ -28,258 +28,216 @@ namespace po = boost::program_options;
namespace {
namespace pattern {
static constexpr const char* help_for_command_with_subcommands =
"NAME:\n"
" %1% - %2%\n"
"\n"
"USAGE:\n"
" %3% [command options] [arguments...]";
"NAME:\n"
" %1% - %2%\n"
"\n"
"USAGE:\n"
" %3% [command options] [arguments...]";
static constexpr const char* commands = "COMMANDS:";
static constexpr const char* command = " %1% %2%";
static constexpr const char* commands = "COMMANDS:";
static constexpr const char* command = " %1% %2%";
static constexpr const char* options = "OPTIONS:";
static constexpr const char* option = " --%1% %2%";
static constexpr const char* options = "OPTIONS:";
static constexpr const char* option = " --%1% %2%";
}
void add_to_desc_for_flags(po::options_description& desc, const std::set<cli::Flag::Ptr>& flags)
{
for (auto flag : flags)
{
auto v = po::value<std::string>()->notifier([flag](const std::string& s)
{
flag->notify(s);
});
desc.add_options()(flag->name().as_string().c_str(), v, flag->description().as_string().c_str());
}
void add_to_desc_for_flags(po::options_description& desc,
const std::set<cli::Flag::Ptr>& flags) {
for (auto flag : flags) {
auto v = po::value<std::string>()->notifier(
[flag](const std::string& s) { flag->notify(s); });
desc.add_options()(flag->name().as_string().c_str(), v,
flag->description().as_string().c_str());
}
}
}
std::vector<std::string> cli::args(int argc, char **argv)
{
std::vector<std::string> result;
for (int i = 1; i < argc; i++) result.push_back(argv[i]);
return result;
std::vector<std::string> cli::args(int argc, char** argv) {
std::vector<std::string> result;
for (int i = 1; i < argc; i++) result.push_back(argv[i]);
return result;
}
const cli::Name& cli::Flag::name() const
{
return name_;
}
const cli::Name& cli::Flag::name() const { return name_; }
const cli::Description& cli::Flag::description() const
{
return description_;
}
const cli::Description& cli::Flag::description() const { return description_; }
cli::Flag::Flag(const Name& name, const Description& description)
: name_{name},
description_{description}
{
: name_{name}, description_{description} {}
cli::Command::FlagsWithInvalidValue::FlagsWithInvalidValue()
: std::runtime_error{"Flags with invalid value"} {}
cli::Command::FlagsMissing::FlagsMissing()
: std::runtime_error{"Flags are missing in command invocation"} {}
cli::Name cli::Command::name() const { return name_; }
cli::Usage cli::Command::usage() const { return usage_; }
cli::Description cli::Command::description() const { return description_; }
cli::Command::Command(const cli::Name& name, const cli::Usage& usage,
const cli::Description& description)
: name_(name), usage_(usage), description_(description) {}
cli::CommandWithSubcommands::CommandWithSubcommands(
const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description} {
command(std::make_shared<cmd::Help>(*this));
}
cli::Command::FlagsWithInvalidValue::FlagsWithInvalidValue() : std::runtime_error{"Flags with invalid value"}
{
cli::CommandWithSubcommands& cli::CommandWithSubcommands::command(
const Command::Ptr& command) {
commands_[command->name().as_string()] = command;
return *this;
}
cli::Command::FlagsMissing::FlagsMissing() : std::runtime_error{"Flags are missing in command invocation"}
{
cli::CommandWithSubcommands& cli::CommandWithSubcommands::flag(
const Flag::Ptr& flag) {
flags_.insert(flag);
return *this;
}
cli::Name cli::Command::name() const
{
return name_;
void cli::CommandWithSubcommands::help(std::ostream& out) {
out << boost::format(pattern::help_for_command_with_subcommands) %
name().as_string() % usage().as_string() % name().as_string()
<< std::endl;
if (flags_.size() > 0) {
out << std::endl << pattern::options << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description()
<< std::endl;
}
if (commands_.size() > 0) {
out << std::endl << pattern::commands << std::endl;
for (const auto& cmd : commands_) {
if (cmd.second)
out << boost::format(pattern::command) % cmd.second->name() %
cmd.second->description()
<< std::endl;
}
}
}
cli::Usage cli::Command::usage() const
{
return usage_;
}
int cli::CommandWithSubcommands::run(const cli::Command::Context& ctxt) {
po::positional_options_description pdesc;
pdesc.add("command", 1);
cli::Description cli::Command::description() const
{
return description_;
}
po::options_description desc("Options");
desc.add_options()("command", po::value<std::string>()->required(),
"the command to be executed");
cli::Command::Command(const cli::Name& name, const cli::Usage& usage, const cli::Description& description)
: name_(name),
usage_(usage),
description_(description)
{
}
add_to_desc_for_flags(desc, flags_);
cli::CommandWithSubcommands::CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description}
{
command(std::make_shared<cmd::Help>(*this));
}
try {
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args)
.options(desc)
.positional(pdesc)
.style(po::command_line_style::unix_style)
.allow_unregistered()
.run();
cli::CommandWithSubcommands& cli::CommandWithSubcommands::command(const Command::Ptr& command)
{
commands_[command->name().as_string()] = command;
return *this;
}
po::store(parsed, vm);
po::notify(vm);
cli::CommandWithSubcommands& cli::CommandWithSubcommands::flag(const Flag::Ptr& flag)
{
flags_.insert(flag);
return *this;
}
void cli::CommandWithSubcommands::help(std::ostream& out)
{
out << boost::format(pattern::help_for_command_with_subcommands)
% name().as_string() % usage().as_string()
% name().as_string() << std::endl;
if (flags_.size() > 0)
{
out << std::endl << pattern::options << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl;
}
if (commands_.size() > 0)
{
out << std::endl << pattern::commands << std::endl;
for (const auto& cmd : commands_) {
if (cmd.second)
out << boost::format(pattern::command) % cmd.second->name() % cmd.second->description() << std::endl;
}
}
}
int cli::CommandWithSubcommands::run(const cli::Command::Context& ctxt)
{
po::positional_options_description pdesc;
pdesc.add("command", 1);
po::options_description desc("Options");
desc.add_options()("command", po::value<std::string>()->required(), "the command to be executed");
add_to_desc_for_flags(desc, flags_);
try
{
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args)
.options(desc)
.positional(pdesc)
.style(po::command_line_style::unix_style)
.allow_unregistered()
.run();
po::store(parsed, vm);
po::notify(vm);
auto cmd = commands_[vm["command"].as<std::string>()];
if (!cmd)
{
ctxt.cout << "Unknown command '" << vm["command"].as<std::string>() << "'" << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return cmd->run(cli::Command::Context
{
ctxt.cin,
ctxt.cout,
po::collect_unrecognized(parsed.options, po::include_positional)
});
}
catch (const po::error& e)
{
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
auto cmd = commands_[vm["command"].as<std::string>()];
if (!cmd) {
ctxt.cout << "Unknown command '" << vm["command"].as<std::string>() << "'"
<< std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return cmd->run(cli::Command::Context{
ctxt.cin, ctxt.cout,
po::collect_unrecognized(parsed.options, po::include_positional)});
} catch (const po::error& e) {
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
cli::CommandWithFlagsAndAction::CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description}
{
cli::CommandWithFlagsAndAction::CommandWithFlagsAndAction(
const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description} {}
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::flag(
const Flag::Ptr& flag) {
flags_.insert(flag);
return *this;
}
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::flag(const Flag::Ptr& flag)
{
flags_.insert(flag);
return *this;
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::action(
const Action& action) {
action_ = action;
return *this;
}
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::action(const Action& action)
{
action_ = action;
return *this;
}
int cli::CommandWithFlagsAndAction::run(const Context& ctxt) {
po::options_description cd(name().as_string());
int cli::CommandWithFlagsAndAction::run(const Context& ctxt)
{
po::options_description cd(name().as_string());
bool help_requested{false};
cd.add_options()("help", po::bool_switch(&help_requested),
"produces a help message");
bool help_requested{false};
cd.add_options()("help", po::bool_switch(&help_requested), "produces a help message");
add_to_desc_for_flags(cd, flags_);
add_to_desc_for_flags(cd, flags_);
try {
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args)
.options(cd)
.style(po::command_line_style::unix_style)
.allow_unregistered()
.run();
po::store(parsed, vm);
po::notify(vm);
try
{
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args).options(cd).style(po::command_line_style::unix_style).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
if (help_requested)
{
help(ctxt.cout);
return EXIT_SUCCESS;
}
return action_(cli::Command::Context
{
ctxt.cin,
ctxt.cout,
po::collect_unrecognized(parsed.options, po::exclude_positional)
});
}
catch (const po::error& e)
{
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
if (help_requested) {
help(ctxt.cout);
return EXIT_SUCCESS;
}
return action_(cli::Command::Context{
ctxt.cin, ctxt.cout,
po::collect_unrecognized(parsed.options, po::exclude_positional)});
} catch (const po::error& e) {
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
void cli::CommandWithFlagsAndAction::help(std::ostream& out)
{
out << boost::format(pattern::help_for_command_with_subcommands)
% name().as_string() % description().as_string()
% name().as_string() << std::endl;
void cli::CommandWithFlagsAndAction::help(std::ostream& out) {
out << boost::format(pattern::help_for_command_with_subcommands) %
name().as_string() % description().as_string() % name().as_string()
<< std::endl;
if (flags_.size() > 0)
{
out << std::endl << boost::format(pattern::options) << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl;
}
if (flags_.size() > 0) {
out << std::endl << boost::format(pattern::options) << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description()
<< std::endl;
}
}
cli::cmd::Help::Help(Command& cmd)
: Command{cli::Name{"help"}, cli::Usage{"prints a short help message"}, cli::Description{"prints a short help message"}},
command{cmd}
{
}
: Command{cli::Name{"help"}, cli::Usage{"prints a short help message"},
cli::Description{"prints a short help message"}},
command{cmd} {}
// From Command
int cli::cmd::Help::run(const Context &context)
{
command.help(context.cout);
return EXIT_FAILURE;
int cli::cmd::Help::run(const Context& context) {
command.help(context.cout);
return EXIT_FAILURE;
}
void cli::cmd::Help::help(std::ostream &out)
{
command.help(out);
}
void cli::cmd::Help::help(std::ostream& out) { command.help(out); }

View file

@ -34,46 +34,38 @@
namespace anbox {
namespace cli {
template<std::size_t max>
class SizeConstrainedString
{
public:
SizeConstrainedString(const std::string& s) : s{s}
{
if(s.size() > max)
throw std::logic_error{"Max size exceeded " + std::to_string(max)};
}
template <std::size_t max>
class SizeConstrainedString {
public:
SizeConstrainedString(const std::string& s) : s{s} {
if (s.size() > max)
throw std::logic_error{"Max size exceeded " + std::to_string(max)};
}
const std::string& as_string() const
{
return s;
}
const std::string& as_string() const { return s; }
operator std::string() const
{
return s;
}
operator std::string() const { return s; }
private:
std::string s;
private:
std::string s;
};
template<std::size_t max>
bool operator<(const SizeConstrainedString<max>& lhs, const SizeConstrainedString<max>& rhs)
{
return lhs.as_string() < rhs.as_string();
template <std::size_t max>
bool operator<(const SizeConstrainedString<max>& lhs,
const SizeConstrainedString<max>& rhs) {
return lhs.as_string() < rhs.as_string();
}
template<std::size_t max>
bool operator==(const SizeConstrainedString<max>& lhs, const SizeConstrainedString<max>& rhs)
{
return lhs.as_string() == rhs.as_string();
template <std::size_t max>
bool operator==(const SizeConstrainedString<max>& lhs,
const SizeConstrainedString<max>& rhs) {
return lhs.as_string() == rhs.as_string();
}
template<std::size_t max>
std::ostream& operator<<(std::ostream& out, const SizeConstrainedString<max>& scs)
{
return out << std::setw(max) << std::left << scs.as_string();
template <std::size_t max>
std::ostream& operator<<(std::ostream& out,
const SizeConstrainedString<max>& scs) {
return out << std::setw(max) << std::left << scs.as_string();
}
// We are imposing size constraints to ensure a consistent CLI layout.
@ -82,246 +74,238 @@ typedef SizeConstrainedString<60> Usage;
typedef SizeConstrainedString<60> Description;
/// @brief Flag models an input parameter to a command.
class Flag : public DoNotCopyOrMove
{
public:
// Safe us some typing.
typedef std::shared_ptr<Flag> Ptr;
class Flag : public DoNotCopyOrMove {
public:
// Safe us some typing.
typedef std::shared_ptr<Flag> Ptr;
/// @brief notify announces a new value to the flag.
virtual void notify(const std::string& value) = 0;
/// @brief name returns the name of the Flag.
const Name& name() const;
/// @brief description returns a human-readable description of the flag.
const Description& description() const;
/// @brief notify announces a new value to the flag.
virtual void notify(const std::string& value) = 0;
/// @brief name returns the name of the Flag.
const Name& name() const;
/// @brief description returns a human-readable description of the flag.
const Description& description() const;
protected:
/// @brief Flag creates a new instance, initializing name and description
/// from the given values.
Flag(const Name& name, const Description& description);
protected:
/// @brief Flag creates a new instance, initializing name and description
/// from the given values.
Flag(const Name& name, const Description& description);
private:
Name name_;
Description description_;
private:
Name name_;
Description description_;
};
/// @brief TypedFlag implements Flag relying on operator<< and operator>> to read/write values to/from strings.
template<typename T>
class TypedFlag : public Flag
{
public:
typedef std::shared_ptr<TypedFlag<T>> Ptr;
/// @brief TypedFlag implements Flag relying on operator<< and operator>> to
/// read/write values to/from strings.
template <typename T>
class TypedFlag : public Flag {
public:
typedef std::shared_ptr<TypedFlag<T>> Ptr;
TypedFlag(const Name& name, const Description& description) : Flag{name, description}
{
}
TypedFlag(const Name& name, const Description& description)
: Flag{name, description} {}
/// @brief value installs the given value in the flag.
TypedFlag& value(const T& value)
{
value_ = value;
return *this;
}
/// @brief value installs the given value in the flag.
TypedFlag& value(const T& value) {
value_ = value;
return *this;
}
/// @brief value returns the optional value associated with the flag.
const Optional<T>& value() const
{
return value_;
}
/// @brief value returns the optional value associated with the flag.
const Optional<T>& value() const { return value_; }
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override
{
std::stringstream ss{s};
T value; ss >> value;
value_ = value;
}
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override {
std::stringstream ss{s};
T value;
ss >> value;
value_ = value;
}
private:
Optional<T> value_;
private:
Optional<T> value_;
};
/// @brief TypedReferenceFlag implements Flag, relying on operator<</>> to convert to/from string representations,
/// @brief TypedReferenceFlag implements Flag, relying on operator<</>> to
/// convert to/from string representations,
/// updating the given mutable reference to a value of type T.
template<typename T>
class TypedReferenceFlag : public Flag
{
public:
// Safe us some typing.
typedef std::shared_ptr<TypedReferenceFlag<T>> Ptr;
template <typename T>
class TypedReferenceFlag : public Flag {
public:
// Safe us some typing.
typedef std::shared_ptr<TypedReferenceFlag<T>> Ptr;
/// @brief TypedReferenceFlag initializes a new instance with name, description and value.
TypedReferenceFlag(const Name& name, const Description& description, T& value)
: Flag{name, description},
value_{value}
{
}
/// @brief TypedReferenceFlag initializes a new instance with name,
/// description and value.
TypedReferenceFlag(const Name& name, const Description& description, T& value)
: Flag{name, description}, value_{value} {}
/// @brief notify tries to unwrap a value of type T from value,
/// relying on operator>> to read from given string s.
void notify(const std::string& s) override
{
std::stringstream ss{s};
ss >> value_.get();
}
/// @brief notify tries to unwrap a value of type T from value,
/// relying on operator>> to read from given string s.
void notify(const std::string& s) override {
std::stringstream ss{s};
ss >> value_.get();
}
private:
std::reference_wrapper<T> value_;
private:
std::reference_wrapper<T> value_;
};
/// @brief OptionalTypedReferenceFlag handles Optional<T> references, making sure that
/// a value is always read on notify, even if the Optional<T> wasn't initialized previously.
template<typename T>
class OptionalTypedReferenceFlag : public Flag
{
public:
typedef std::shared_ptr<OptionalTypedReferenceFlag<T>> Ptr;
/// @brief OptionalTypedReferenceFlag handles Optional<T> references, making
/// sure that
/// a value is always read on notify, even if the Optional<T> wasn't initialized
/// previously.
template <typename T>
class OptionalTypedReferenceFlag : public Flag {
public:
typedef std::shared_ptr<OptionalTypedReferenceFlag<T>> Ptr;
OptionalTypedReferenceFlag(const Name& name, const Description& description, Optional<T>& value)
: Flag{name, description},
value_{value}
{
}
OptionalTypedReferenceFlag(const Name& name, const Description& description,
Optional<T>& value)
: Flag{name, description}, value_{value} {}
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override
{
std::stringstream ss{s}; T value; ss >> value;
value_.get() = value;
}
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override {
std::stringstream ss{s};
T value;
ss >> value;
value_.get() = value;
}
private:
std::reference_wrapper<Optional<T>> value_;
private:
std::reference_wrapper<Optional<T>> value_;
};
/// @brief Command abstracts an individual command available from the daemon.
class Command : public DoNotCopyOrMove
{
public:
// Safe us some typing
typedef std::shared_ptr<Command> Ptr;
class Command : public DoNotCopyOrMove {
public:
// Safe us some typing
typedef std::shared_ptr<Command> Ptr;
/// @brief FlagsMissing is thrown if at least one required flag is missing.
struct FlagsMissing : public std::runtime_error
{
/// @brief FlagsMissing initializes a new instance.
FlagsMissing();
};
/// @brief FlagsMissing is thrown if at least one required flag is missing.
struct FlagsMissing : public std::runtime_error {
/// @brief FlagsMissing initializes a new instance.
FlagsMissing();
};
/// @brief FlagsWithWrongValue is thrown if a value passed on the command line is invalid.
struct FlagsWithInvalidValue : public std::runtime_error
{
/// @brief FlagsWithInvalidValue initializes a new instance.
FlagsWithInvalidValue();
};
/// @brief FlagsWithWrongValue is thrown if a value passed on the command line
/// is invalid.
struct FlagsWithInvalidValue : public std::runtime_error {
/// @brief FlagsWithInvalidValue initializes a new instance.
FlagsWithInvalidValue();
};
/// @brief Context bundles information passed to Command::run invocations.
struct Context
{
std::istream& cin; ///< The std::istream that should be used for reading.
std::ostream& cout; ///< The std::ostream that should be used for writing.
std::vector<std::string> args; ///< The command line args.
};
/// @brief Context bundles information passed to Command::run invocations.
struct Context {
std::istream& cin; ///< The std::istream that should be used for reading.
std::ostream& cout; ///< The std::ostream that should be used for writing.
std::vector<std::string> args; ///< The command line args.
};
/// @brief name returns the Name of the command.
virtual Name name() const;
/// @brief name returns the Name of the command.
virtual Name name() const;
/// @brief usage returns a short usage string for the command.
virtual Usage usage() const;
/// @brief usage returns a short usage string for the command.
virtual Usage usage() const;
/// @brief description returns a longer string explaining the command.
virtual Description description() const;
/// @brief description returns a longer string explaining the command.
virtual Description description() const;
/// @brief run puts the command to execution.
virtual int run(const Context& context) = 0;
/// @brief run puts the command to execution.
virtual int run(const Context& context) = 0;
/// @brief help prints information about a command to out.
virtual void help(std::ostream& out) = 0;
/// @brief help prints information about a command to out.
virtual void help(std::ostream& out) = 0;
protected:
/// @brief Command initializes a new instance with the given name, usage and description.
Command(const Name& name, const Usage& usage, const Description& description);
protected:
/// @brief Command initializes a new instance with the given name, usage and
/// description.
Command(const Name& name, const Usage& usage, const Description& description);
/// @brief name adjusts the name of the command to n.
// virtual void name(const Name& n);
/// @brief usage adjusts the usage string of the comand to u.
// virtual void usage(const Usage& u);
/// @brief description adjusts the description string of the command to d.
// virtual void description(const Description& d);
/// @brief name adjusts the name of the command to n.
// virtual void name(const Name& n);
/// @brief usage adjusts the usage string of the comand to u.
// virtual void usage(const Usage& u);
/// @brief description adjusts the description string of the command to d.
// virtual void description(const Description& d);
private:
Name name_;
Usage usage_;
Description description_;
private:
Name name_;
Usage usage_;
Description description_;
};
/// @brief CommandWithSubcommands implements Command, selecting one of a set of actions.
class CommandWithSubcommands : public Command
{
public:
typedef std::shared_ptr<CommandWithSubcommands> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithSubcommands implements Command, selecting one of a set of
/// actions.
class CommandWithSubcommands : public Command {
public:
typedef std::shared_ptr<CommandWithSubcommands> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithSubcommands initializes a new instance with the given name, usage and description
CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description);
/// @brief CommandWithSubcommands initializes a new instance with the given
/// name, usage and description
CommandWithSubcommands(const Name& name, const Usage& usage,
const Description& description);
/// @brief command adds the given command to the set of known commands.
CommandWithSubcommands& command(const Command::Ptr& command);
/// @brief command adds the given command to the set of known commands.
CommandWithSubcommands& command(const Command::Ptr& command);
/// @brief flag adds the given flag to the set of known flags.
CommandWithSubcommands& flag(const Flag::Ptr& flag);
/// @brief flag adds the given flag to the set of known flags.
CommandWithSubcommands& flag(const Flag::Ptr& flag);
// From Command
int run(const Context& context) override;
void help(std::ostream &out) override;
// From Command
int run(const Context& context) override;
void help(std::ostream& out) override;
private:
std::unordered_map<std::string, Command::Ptr> commands_;
std::set<Flag::Ptr> flags_;
private:
std::unordered_map<std::string, Command::Ptr> commands_;
std::set<Flag::Ptr> flags_;
};
/// @brief CommandWithFlagsAction implements Command, executing an Action after handling
class CommandWithFlagsAndAction : public Command
{
public:
typedef std::shared_ptr<CommandWithFlagsAndAction> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithFlagsAction implements Command, executing an Action after
/// handling
class CommandWithFlagsAndAction : public Command {
public:
typedef std::shared_ptr<CommandWithFlagsAndAction> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithFlagsAndAction initializes a new instance with the given name, usage and description
CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description);
/// @brief CommandWithFlagsAndAction initializes a new instance with the given
/// name, usage and description
CommandWithFlagsAndAction(const Name& name, const Usage& usage,
const Description& description);
/// @brief flag adds the given flag to the set of known flags.
CommandWithFlagsAndAction& flag(const Flag::Ptr& flag);
/// @brief flag adds the given flag to the set of known flags.
CommandWithFlagsAndAction& flag(const Flag::Ptr& flag);
/// @brief action installs the given action.
CommandWithFlagsAndAction& action(const Action& action);
/// @brief action installs the given action.
CommandWithFlagsAndAction& action(const Action& action);
// From Command
int run(const Context& context) override;
void help(std::ostream &out) override;
// From Command
int run(const Context& context) override;
void help(std::ostream& out) override;
private:
std::set<Flag::Ptr> flags_;
Action action_;
private:
std::set<Flag::Ptr> flags_;
Action action_;
};
namespace cmd
{
namespace cmd {
/// @brief HelpFor prints a help message for the given command on execution.
class Help : public Command
{
public:
/// @brief HelpFor initializes a new instance with the given reference to a cmd.
explicit Help(Command& cmd);
class Help : public Command {
public:
/// @brief HelpFor initializes a new instance with the given reference to a
/// cmd.
explicit Help(Command& cmd);
// From Command
int run(const Context &context) override;
void help(std::ostream &out) override;
// From Command
int run(const Context& context) override;
void help(std::ostream& out) override;
private:
/// @cond
Command& command;
/// @endcond
private:
/// @cond
Command& command;
/// @endcond
};
}
@ -329,28 +313,31 @@ private:
std::vector<std::string> args(int argc, char** argv);
/// @brief make_flag returns a flag with the given name and description.
template<typename T>
typename TypedFlag<T>::Ptr make_flag(const Name& name, const Description& description)
{
return std::make_shared<TypedFlag<T>>(name, description);
template <typename T>
typename TypedFlag<T>::Ptr make_flag(const Name& name,
const Description& description) {
return std::make_shared<TypedFlag<T>>(name, description);
}
/// @brief make_flag returns a flag with the given name and description, notifying updates to value.
template<typename T>
typename TypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, T& value)
{
return std::make_shared<TypedReferenceFlag<T>>(name, desc, value);
/// @brief make_flag returns a flag with the given name and description,
/// notifying updates to value.
template <typename T>
typename TypedReferenceFlag<T>::Ptr make_flag(const Name& name,
const Description& desc,
T& value) {
return std::make_shared<TypedReferenceFlag<T>>(name, desc, value);
}
/// @brief make_flag returns a flag with the given name and description, updating the given optional value.
template<typename T>
typename OptionalTypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, Optional<T>& value)
{
return std::make_shared<OptionalTypedReferenceFlag<T>>(name, desc, value);
/// @brief make_flag returns a flag with the given name and description,
/// updating the given optional value.
template <typename T>
typename OptionalTypedReferenceFlag<T>::Ptr make_flag(const Name& name,
const Description& desc,
Optional<T>& value) {
return std::make_shared<OptionalTypedReferenceFlag<T>>(name, desc, value);
}
} // namespace cli
} // namespace anbox
} // namespace cli
} // namespace anbox
#endif

View file

@ -17,29 +17,30 @@
#include "anbox/cmds/container_manager.h"
#include "anbox/container/service.h"
#include "anbox/runtime.h"
#include "anbox/logger.h"
#include "anbox/runtime.h"
#include "core/posix/signal.h"
anbox::cmds::ContainerManager::ContainerManager()
: CommandWithFlagsAndAction{cli::Name{"container-manager"}, cli::Usage{"container-manager"}, cli::Description{"Start the container manager service"}}
{
action([](const cli::Command::Context& ctxt) {
auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term,
core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal &signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal));
trap->stop();
});
auto rt = Runtime::create();
auto service = container::Service::create(rt);
rt->start();
trap->run();
rt->stop();
return 0;
: CommandWithFlagsAndAction{
cli::Name{"container-manager"}, cli::Usage{"container-manager"},
cli::Description{"Start the container manager service"}} {
action([](const cli::Command::Context& ctxt) {
auto trap = core::posix::trap_signals_for_process(
{core::posix::Signal::sig_term, core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal& signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal));
trap->stop();
});
auto rt = Runtime::create();
auto service = container::Service::create(rt);
rt->start();
trap->run();
rt->stop();
return 0;
});
}

View file

@ -27,10 +27,10 @@
namespace anbox {
namespace cmds {
class ContainerManager : public cli::CommandWithFlagsAndAction {
public:
ContainerManager();
public:
ContainerManager();
};
} // namespace cmds
} // namespace anbox
} // namespace cmds
} // namespace anbox
#endif

View file

@ -25,22 +25,27 @@
namespace fs = boost::filesystem;
anbox::cmds::Install::Install()
: CommandWithFlagsAndAction{cli::Name{"install"}, cli::Usage{"install"}, cli::Description{"Install specified application in the Android container"}}
{
flag(cli::make_flag(cli::Name{"apk"}, cli::Description{"Path to APK to install"}, apk_));
action([this](const cli::Command::Context&) {
if (apk_.length() == 0)
BOOST_THROW_EXCEPTION(std::runtime_error("No APK to install specified"));
: CommandWithFlagsAndAction{
cli::Name{"install"}, cli::Usage{"install"},
cli::Description{
"Install specified application in the Android container"}} {
flag(cli::make_flag(cli::Name{"apk"},
cli::Description{"Path to APK to install"}, apk_));
action([this](const cli::Command::Context&) {
if (apk_.length() == 0)
BOOST_THROW_EXCEPTION(std::runtime_error("No APK to install specified"));
if (!fs::is_regular_file(apk_))
BOOST_THROW_EXCEPTION(std::runtime_error("Specified APK file does not exist"));
if (!fs::is_regular_file(apk_))
BOOST_THROW_EXCEPTION(
std::runtime_error("Specified APK file does not exist"));
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus));
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
auto bus =
std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus));
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
stub->install(apk_);
stub->install(apk_);
return EXIT_SUCCESS;
});
return EXIT_SUCCESS;
});
}

View file

@ -27,13 +27,13 @@
namespace anbox {
namespace cmds {
class Install : public cli::CommandWithFlagsAndAction {
public:
Install();
public:
Install();
private:
std::string apk_;
private:
std::string apk_;
};
} // namespace cmds
} // namespace anbox
} // namespace cmds
} // namespace anbox
#endif

View file

@ -25,21 +25,34 @@
namespace fs = boost::filesystem;
anbox::cmds::Launch::Launch()
: CommandWithFlagsAndAction{cli::Name{"launch"}, cli::Usage{"launch"}, cli::Description{"Launch an Activity by sending an intent"}}
{
flag(cli::make_flag(cli::Name{"action"}, cli::Description{"Action of the intent"}, intent_.action));
flag(cli::make_flag(cli::Name{"type"}, cli::Description{"MIME type for the intent"}, intent_.type));
flag(cli::make_flag(cli::Name{"uri"}, cli::Description{"URI used as data within the intent"}, intent_.uri));
flag(cli::make_flag(cli::Name{"package"}, cli::Description{"Package the intent should go to"}, intent_.package));
flag(cli::make_flag(cli::Name{"component"}, cli::Description{"Component of a package the intent should go"}, intent_.component));
: CommandWithFlagsAndAction{
cli::Name{"launch"}, cli::Usage{"launch"},
cli::Description{"Launch an Activity by sending an intent"}} {
flag(cli::make_flag(cli::Name{"action"},
cli::Description{"Action of the intent"},
intent_.action));
flag(cli::make_flag(cli::Name{"type"},
cli::Description{"MIME type for the intent"},
intent_.type));
flag(cli::make_flag(cli::Name{"uri"},
cli::Description{"URI used as data within the intent"},
intent_.uri));
flag(cli::make_flag(cli::Name{"package"},
cli::Description{"Package the intent should go to"},
intent_.package));
flag(cli::make_flag(
cli::Name{"component"},
cli::Description{"Component of a package the intent should go"},
intent_.component));
action([this](const cli::Command::Context&) {
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus));
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
action([this](const cli::Command::Context&) {
auto bus =
std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus));
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
stub->launch(intent_);
stub->launch(intent_);
return EXIT_SUCCESS;
});
return EXIT_SUCCESS;
});
}

View file

@ -22,19 +22,19 @@
#include <iostream>
#include <memory>
#include "anbox/cli.h"
#include "anbox/android/intent.h"
#include "anbox/cli.h"
namespace anbox {
namespace cmds {
class Launch : public cli::CommandWithFlagsAndAction {
public:
Launch();
public:
Launch();
private:
android::Intent intent_;
private:
android::Intent intent_;
};
} // namespace cmds
} // namespace anbox
} // namespace cmds
} // namespace anbox
#endif

View file

@ -19,95 +19,103 @@
#include "core/posix/signal.h"
#include "anbox/logger.h"
#include "anbox/runtime.h"
#include "anbox/config.h"
#include "anbox/common/dispatcher.h"
#include "anbox/cmds/run.h"
#include "anbox/network/published_socket_connector.h"
#include "anbox/qemu/pipe_connection_creator.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "anbox/input/manager.h"
#include "anbox/rpc/connection_creator.h"
#include "anbox/rpc/channel.h"
#include "anbox/bridge/platform_message_processor.h"
#include "anbox/application/launcher_storage.h"
#include "anbox/bridge/android_api_stub.h"
#include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/dbus/skeleton/service.h"
#include "anbox/bridge/platform_message_processor.h"
#include "anbox/cmds/run.h"
#include "anbox/common/dispatcher.h"
#include "anbox/config.h"
#include "anbox/container/client.h"
#include "anbox/wm/manager.h"
#include "anbox/dbus/skeleton/service.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "anbox/input/manager.h"
#include "anbox/logger.h"
#include "anbox/network/published_socket_connector.h"
#include "anbox/qemu/pipe_connection_creator.h"
#include "anbox/rpc/channel.h"
#include "anbox/rpc/connection_creator.h"
#include "anbox/runtime.h"
#include "anbox/ubuntu/platform_policy.h"
#include "anbox/application/launcher_storage.h"
#include "anbox/wm/manager.h"
#include "external/xdg/xdg.h"
#include <sys/prctl.h>
#include <core/dbus/bus.h>
#include <core/dbus/asio/executor.h>
#include <core/dbus/bus.h>
namespace fs = boost::filesystem;
namespace {
class NullConnectionCreator : public anbox::network::ConnectionCreator<boost::asio::local::stream_protocol> {
public:
void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) override {
WARNING("Not implemented");
socket->close();
}
class NullConnectionCreator : public anbox::network::ConnectionCreator<
boost::asio::local::stream_protocol> {
public:
void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const
&socket) override {
WARNING("Not implemented");
socket->close();
}
};
}
anbox::cmds::Run::BusFactory anbox::cmds::Run::session_bus_factory() {
return []() {
return std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
};
return []() {
return std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
};
}
anbox::cmds::Run::Run(const BusFactory& bus_factory)
: CommandWithFlagsAndAction{cli::Name{"run"}, cli::Usage{"run"}, cli::Description{"Run the the anbox system"}},
bus_factory_(bus_factory)
{
// Just for the purpose to allow QtMir (or unity8) to find this on our /proc/*/cmdline
// for proper confinement etc.
flag(cli::make_flag(cli::Name{"desktop_file_hint"}, cli::Description{"Desktop file hint for QtMir/Unity8"}, desktop_file_hint_));
flag(cli::make_flag(cli::Name{"icon"}, cli::Description{"Icon of the application to run"}, icon_));
anbox::cmds::Run::Run(const BusFactory &bus_factory)
: CommandWithFlagsAndAction{cli::Name{"run"}, cli::Usage{"run"},
cli::Description{"Run the the anbox system"}},
bus_factory_(bus_factory) {
// Just for the purpose to allow QtMir (or unity8) to find this on our
// /proc/*/cmdline
// for proper confinement etc.
flag(cli::make_flag(cli::Name{"desktop_file_hint"},
cli::Description{"Desktop file hint for QtMir/Unity8"},
desktop_file_hint_));
flag(cli::make_flag(cli::Name{"icon"},
cli::Description{"Icon of the application to run"},
icon_));
action([this](const cli::Command::Context &ctx) {
auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term,
core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal &signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal));
trap->stop();
});
action([this](const cli::Command::Context &ctx) {
auto trap = core::posix::trap_signals_for_process(
{core::posix::Signal::sig_term, core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal &signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal));
trap->stop();
});
utils::ensure_paths({
config::socket_path(),
config::host_input_device_path(),
});
utils::ensure_paths({
config::socket_path(), config::host_input_device_path(),
});
auto rt = Runtime::create();
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
auto rt = Runtime::create();
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
auto input_manager = std::make_shared<input::Manager>(rt);
auto input_manager = std::make_shared<input::Manager>(rt);
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager, android_api_stub);
// FIXME this needs to be removed and solved differently behind the scenes
registerDisplayManager(policy);
auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager,
android_api_stub);
// FIXME this needs to be removed and solved differently behind the scenes
registerDisplayManager(policy);
auto window_manager = std::make_shared<wm::Manager>(policy);
auto window_manager = std::make_shared<wm::Manager>(policy);
auto launcher_storage = std::make_shared<application::LauncherStorage>(
xdg::data().home() / "applications");
auto launcher_storage = std::make_shared<application::LauncherStorage>(
xdg::data().home() / "applications");
auto renderer = std::make_shared<graphics::GLRendererServer>(window_manager);
renderer->start();
auto renderer =
std::make_shared<graphics::GLRendererServer>(window_manager);
renderer->start();
// Socket which will be used by the qemud service inside the Android
// container for things like sensors, vibrtator etc.
// Socket which will be used by the qemud service inside the Android
// container for things like sensors, vibrtator etc.
#if 0
auto qemud_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/qemud", config::socket_path()),
@ -115,60 +123,59 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
std::make_shared<NullConnectionCreator>());
#endif
// The qemu pipe is used as a very fast communication channel between guest
// and host for things like the GLES emulation/translation, the RIL or ADB.
auto qemu_pipe_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/qemu_pipe", config::socket_path()),
rt,
std::make_shared<qemu::PipeConnectionCreator>(rt,
renderer->socket_path(),
icon_));
// The qemu pipe is used as a very fast communication channel between guest
// and host for things like the GLES emulation/translation, the RIL or ADB.
auto qemu_pipe_connector =
std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/qemu_pipe", config::socket_path()), rt,
std::make_shared<qemu::PipeConnectionCreator>(
rt, renderer->socket_path(), icon_));
auto bridge_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/anbox_bridge", config::socket_path()), rt,
std::make_shared<rpc::ConnectionCreator>(
rt, [&](const std::shared_ptr<network::MessageSender> &sender) {
auto pending_calls = std::make_shared<rpc::PendingCallCache>();
auto rpc_channel =
std::make_shared<rpc::Channel>(pending_calls, sender);
// This is safe as long as we only support a single client. If we
// support
// more than one one day we need proper dispatching to the right
// one.
android_api_stub->set_rpc_channel(rpc_channel);
auto bridge_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/anbox_bridge", config::socket_path()),
rt,
std::make_shared<rpc::ConnectionCreator>(rt,
[&](const std::shared_ptr<network::MessageSender> &sender) {
auto pending_calls = std::make_shared<rpc::PendingCallCache>();
auto rpc_channel = std::make_shared<rpc::Channel>(pending_calls, sender);
// This is safe as long as we only support a single client. If we support
// more than one one day we need proper dispatching to the right one.
android_api_stub->set_rpc_channel(rpc_channel);
auto server = std::make_shared<bridge::PlatformApiSkeleton>(
pending_calls, window_manager, launcher_storage);
server->register_boot_finished_handler(
[&]() { DEBUG("Android successfully booted"); });
return std::make_shared<bridge::PlatformMessageProcessor>(
sender, server, pending_calls);
}));
auto server = std::make_shared<bridge::PlatformApiSkeleton>(pending_calls,
window_manager,
launcher_storage);
server->register_boot_finished_handler([&]() {
DEBUG("Android successfully booted");
});
return std::make_shared<bridge::PlatformMessageProcessor>(sender, server, pending_calls);
}));
container::Client container(rt);
container::Configuration container_configuration;
container_configuration.bind_mounts = {
// { qemud_connector->socket_file(), "/dev/qemud" },
{qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"},
{bridge_connector->socket_file(), "/dev/anbox_bridge"},
{config::host_input_device_path(), "/dev/input"},
{"/dev/binder", "/dev/binder"},
{"/dev/ashmem", "/dev/ashmem"},
};
container::Client container(rt);
container::Configuration container_configuration;
container_configuration.bind_mounts = {
// { qemud_connector->socket_file(), "/dev/qemud" },
{ qemu_pipe_connector->socket_file(), "/dev/qemu_pipe" },
{ bridge_connector->socket_file(), "/dev/anbox_bridge" },
{ config::host_input_device_path(), "/dev/input" },
{ "/dev/binder", "/dev/binder" },
{ "/dev/ashmem", "/dev/ashmem" },
};
dispatcher->dispatch(
[&]() { container.start_container(container_configuration); });
dispatcher->dispatch([&]() {
container.start_container(container_configuration);
});
auto bus = bus_factory_();
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
auto bus = bus_factory_();
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
auto skeleton =
anbox::dbus::skeleton::Service::create_for_bus(bus, android_api_stub);
auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, android_api_stub);
rt->start();
trap->run();
rt->stop();
rt->start();
trap->run();
rt->stop();
return EXIT_SUCCESS;
});
return EXIT_SUCCESS;
});
}

View file

@ -29,19 +29,19 @@
namespace anbox {
namespace cmds {
class Run : public cli::CommandWithFlagsAndAction {
public:
typedef std::function<core::dbus::Bus::Ptr()> BusFactory;
public:
typedef std::function<core::dbus::Bus::Ptr()> BusFactory;
static BusFactory session_bus_factory();
static BusFactory session_bus_factory();
Run(const BusFactory& bus_factory = session_bus_factory());
Run(const BusFactory& bus_factory = session_bus_factory());
private:
BusFactory bus_factory_;
std::string desktop_file_hint_;
std::string icon_;
private:
BusFactory bus_factory_;
std::string desktop_file_hint_;
std::string icon_;
};
} // namespace cmds
} // namespace anbox
} // namespace cmds
} // namespace anbox
#endif

View file

@ -21,13 +21,13 @@
#include "anbox/version.h"
anbox::cmds::Version::Version()
: CommandWithFlagsAndAction{cli::Name{"version"}, cli::Usage{"version"}, cli::Description{"print the version of the daemon"}}
{
action([](const cli::Command::Context& ctxt)
{
std::uint32_t major, minor, patch;
anbox::version(major, minor, patch);
ctxt.cout << "anbox " << major << "." << minor << "." << patch << std::endl;
return 0;
});
: CommandWithFlagsAndAction{
cli::Name{"version"}, cli::Usage{"version"},
cli::Description{"print the version of the daemon"}} {
action([](const cli::Command::Context& ctxt) {
std::uint32_t major, minor, patch;
anbox::version(major, minor, patch);
ctxt.cout << "anbox " << major << "." << minor << "." << patch << std::endl;
return 0;
});
}

View file

@ -29,10 +29,10 @@
namespace anbox {
namespace cmds {
class Version : public cli::CommandWithFlagsAndAction {
public:
Version();
public:
Version();
};
} // namespace cmds
} // namespace anbox
} // namespace cmds
} // namespace anbox
#endif

View file

@ -21,23 +21,20 @@
namespace {
struct AsioStrandDispatcher : public anbox::common::Dispatcher {
public:
AsioStrandDispatcher(const std::shared_ptr<anbox::Runtime>& rt)
: rt{rt},
strand{rt->service()} {
}
public:
AsioStrandDispatcher(const std::shared_ptr<anbox::Runtime>& rt)
: rt{rt}, strand{rt->service()} {}
void dispatch(const Task &task) override {
strand.post(task);
}
void dispatch(const Task& task) override { strand.post(task); }
private:
std::shared_ptr<anbox::Runtime> rt;
boost::asio::io_service::strand strand;
private:
std::shared_ptr<anbox::Runtime> rt;
boost::asio::io_service::strand strand;
};
}
std::shared_ptr<anbox::common::Dispatcher> anbox::common::create_dispatcher_for_runtime(
const std::shared_ptr<anbox::Runtime>& rt) {
return std::make_shared<AsioStrandDispatcher>(rt);
std::shared_ptr<anbox::common::Dispatcher>
anbox::common::create_dispatcher_for_runtime(
const std::shared_ptr<anbox::Runtime>& rt) {
return std::make_shared<AsioStrandDispatcher>(rt);
}

View file

@ -28,16 +28,17 @@
namespace anbox {
namespace common {
class Dispatcher : public DoNotCopyOrMove {
public:
typedef std::function<void()> Task;
virtual void dispatch(const Task& task) = 0;
public:
typedef std::function<void()> Task;
virtual void dispatch(const Task& task) = 0;
protected:
Dispatcher() = default;
protected:
Dispatcher() = default;
};
std::shared_ptr<Dispatcher> create_dispatcher_for_runtime(const std::shared_ptr<Runtime>&);
} // namespace common
} // namespace anbox
std::shared_ptr<Dispatcher> create_dispatcher_for_runtime(
const std::shared_ptr<Runtime>&);
} // namespace common
} // namespace anbox
#endif

View file

@ -21,41 +21,27 @@
#include <algorithm>
namespace anbox {
Fd::Fd() :
Fd{invalid}
{
Fd::Fd() : Fd{invalid} {}
Fd::Fd(IntOwnedFd fd) : fd{std::make_shared<int>(fd.int_owned_fd)} {}
Fd::Fd(int raw_fd)
: fd{new int{raw_fd},
[](int* fd) {
if (!fd) return;
if (*fd > Fd::invalid) ::close(*fd);
delete fd;
}} {}
Fd::Fd(Fd&& other) : fd{std::move(other.fd)} {}
Fd& Fd::operator=(Fd other) {
std::swap(fd, other.fd);
return *this;
}
Fd::Fd(IntOwnedFd fd) :
fd{std::make_shared<int>(fd.int_owned_fd)}
{
Fd::operator int() const {
if (fd) return *fd;
return invalid;
}
Fd::Fd(int raw_fd) :
fd{new int{raw_fd},
[](int* fd)
{
if (!fd) return;
if (*fd > Fd::invalid) ::close(*fd);
delete fd;
}}
{
}
Fd::Fd(Fd&& other) :
fd{std::move(other.fd)}
{
}
Fd& Fd::operator=(Fd other)
{
std::swap(fd, other.fd);
return *this;
}
Fd::operator int() const
{
if (fd) return *fd;
return invalid;
}
} // namespace anbox
} // namespace anbox

View file

@ -22,29 +22,29 @@
#include <memory>
namespace anbox {
struct IntOwnedFd
{
int int_owned_fd;
struct IntOwnedFd {
int int_owned_fd;
};
class Fd
{
public:
//transfer ownership of the POD-int to the object. The int no longer needs close()ing,
//and has the lifetime of the Fd object.
explicit Fd(int fd);
explicit Fd(IntOwnedFd);
static int const invalid{-1};
Fd(); //Initializes fd to the anbox::Fd::invalid;
Fd(Fd&&);
Fd(Fd const&) = default;
Fd& operator=(Fd);
class Fd {
public:
// transfer ownership of the POD-int to the object. The int no longer needs
// close()ing,
// and has the lifetime of the Fd object.
explicit Fd(int fd);
explicit Fd(IntOwnedFd);
static int const invalid{-1};
Fd(); // Initializes fd to the anbox::Fd::invalid;
Fd(Fd&&);
Fd(Fd const&) = default;
Fd& operator=(Fd);
//bit of a convenient kludge. take care not to close or otherwise destroy the FD.
operator int() const;
// bit of a convenient kludge. take care not to close or otherwise destroy the
// FD.
operator int() const;
private:
std::shared_ptr<int> fd;
private:
std::shared_ptr<int> fd;
};
} // namespace anbox
} // namespace anbox
#endif

View file

@ -19,13 +19,13 @@
#ifndef ANBOX_COMMON_FD_SETS_H_
#define ANBOX_COMMON_FD_SETS_H_
#include <vector>
#include <initializer_list>
#include <vector>
#include "anbox/common/fd.h"
namespace anbox {
typedef std::vector<std::vector<Fd>> FdSets;
} // namespace anbox
} // namespace anbox
#endif

View file

@ -24,38 +24,35 @@
namespace anbox {
template <size_t BuiltInBufferSize>
class VariableLengthArray
{
public:
explicit VariableLengthArray(size_t size) : size_{size}
{
/* Don't call resize if the initial values of member variables are valid */
if (size > BuiltInBufferSize) resize(size);
}
class VariableLengthArray {
public:
explicit VariableLengthArray(size_t size) : size_{size} {
/* Don't call resize if the initial values of member variables are valid */
if (size > BuiltInBufferSize) resize(size);
}
void resize(size_t size)
{
if (size > BuiltInBufferSize)
effective_buffer = BufferUPtr{new unsigned char[size], heap_deleter};
else
effective_buffer = BufferUPtr{builtin_buffer, null_deleter};
void resize(size_t size) {
if (size > BuiltInBufferSize)
effective_buffer = BufferUPtr{new unsigned char[size], heap_deleter};
else
effective_buffer = BufferUPtr{builtin_buffer, null_deleter};
size_ = size;
}
size_ = size;
}
unsigned char* data() const { return effective_buffer.get(); }
size_t size() const { return size_; }
unsigned char* data() const { return effective_buffer.get(); }
size_t size() const { return size_; }
private:
typedef std::unique_ptr<unsigned char,void (*)(unsigned char*)> BufferUPtr;
private:
typedef std::unique_ptr<unsigned char, void (*)(unsigned char*)> BufferUPtr;
static void null_deleter(unsigned char*) {}
static void heap_deleter(unsigned char* b) { delete[] b; }
static void null_deleter(unsigned char*) {}
static void heap_deleter(unsigned char* b) { delete[] b; }
unsigned char builtin_buffer[BuiltInBufferSize];
BufferUPtr effective_buffer{builtin_buffer, null_deleter};
size_t size_;
unsigned char builtin_buffer[BuiltInBufferSize];
BufferUPtr effective_buffer{builtin_buffer, null_deleter};
size_t size_;
};
} // namespace anbox
} // namespace anbox
#endif

View file

@ -21,72 +21,59 @@
namespace anbox {
namespace common {
WaitHandle::WaitHandle() :
guard(),
wait_condition(),
expecting(0),
received(0)
{
WaitHandle::WaitHandle()
: guard(), wait_condition(), expecting(0), received(0) {}
WaitHandle::~WaitHandle() {}
void WaitHandle::expect_result() {
std::lock_guard<std::mutex> lock(guard);
expecting++;
}
WaitHandle::~WaitHandle()
{
}
void WaitHandle::result_received() {
std::lock_guard<std::mutex> lock(guard);
void WaitHandle::expect_result()
{
std::lock_guard<std::mutex> lock(guard);
expecting++;
}
void WaitHandle::result_received()
{
std::lock_guard<std::mutex> lock(guard);
received++;
wait_condition.notify_all();
received++;
wait_condition.notify_all();
}
void WaitHandle::wait_for_all() // wait for all results you expect
{
std::unique_lock<std::mutex> lock(guard);
std::unique_lock<std::mutex> lock(guard);
wait_condition.wait(lock, [&]{ return received == expecting; });
wait_condition.wait(lock, [&] { return received == expecting; });
received = 0;
expecting = 0;
received = 0;
expecting = 0;
}
void WaitHandle::wait_for_pending(std::chrono::milliseconds limit)
{
std::unique_lock<std::mutex> lock(guard);
void WaitHandle::wait_for_pending(std::chrono::milliseconds limit) {
std::unique_lock<std::mutex> lock(guard);
wait_condition.wait_for(lock, limit, [&]{ return received == expecting; });
wait_condition.wait_for(lock, limit, [&] { return received == expecting; });
}
void WaitHandle::wait_for_one() // wait for any single result
{
std::unique_lock<std::mutex> lock(guard);
std::unique_lock<std::mutex> lock(guard);
wait_condition.wait(lock, [&]{ return received != 0; });
wait_condition.wait(lock, [&] { return received != 0; });
--received;
--expecting;
--received;
--expecting;
}
bool WaitHandle::has_result()
{
std::lock_guard<std::mutex> lock(guard);
bool WaitHandle::has_result() {
std::lock_guard<std::mutex> lock(guard);
return received > 0;
return received > 0;
}
bool WaitHandle::is_pending()
{
std::unique_lock<std::mutex> lock(guard);
return expecting > 0 && received != expecting;
bool WaitHandle::is_pending() {
std::unique_lock<std::mutex> lock(guard);
return expecting > 0 && received != expecting;
}
} // namespace common
} // namespace anbox
} // namespace common
} // namespace anbox

View file

@ -26,29 +26,28 @@
namespace anbox {
namespace common {
struct WaitHandle
{
public:
WaitHandle();
~WaitHandle();
struct WaitHandle {
public:
WaitHandle();
~WaitHandle();
void expect_result();
void result_received();
void wait_for_all();
void wait_for_one();
void wait_for_pending(std::chrono::milliseconds limit);
void expect_result();
void result_received();
void wait_for_all();
void wait_for_one();
void wait_for_pending(std::chrono::milliseconds limit);
bool has_result();
bool is_pending();
bool has_result();
bool is_pending();
private:
std::mutex guard;
std::condition_variable wait_condition;
private:
std::mutex guard;
std::condition_variable wait_condition;
int expecting;
int received;
int expecting;
int received;
};
} // namespace common
} // namespace anbox
} // namespace common
} // namespace anbox
#endif

View file

@ -27,76 +27,81 @@ namespace fs = boost::filesystem;
namespace anbox {
namespace config {
std::string in_snap_dir(const std::string &path) {
return utils::prefix_dir_from_env(path, "SNAP");
return utils::prefix_dir_from_env(path, "SNAP");
}
std::string in_snap_data_dir(const std::string &path) {
return utils::prefix_dir_from_env(path, "SNAP_COMMON");
return utils::prefix_dir_from_env(path, "SNAP_COMMON");
}
std::string in_snap_user_data_dir(const std::string &path) {
return utils::prefix_dir_from_env(path, "SNAP_USER_COMMON");
return utils::prefix_dir_from_env(path, "SNAP_USER_COMMON");
}
std::string home_dir() {
static std::string path;
if (path.empty()) {
path = utils::get_env_value("HOME", "");
if (path.empty())
BOOST_THROW_EXCEPTION(std::runtime_error("No home directory specified"));
}
return path;
static std::string path;
if (path.empty()) {
path = utils::get_env_value("HOME", "");
if (path.empty())
BOOST_THROW_EXCEPTION(std::runtime_error("No home directory specified"));
}
return path;
}
std::string runtime_dir() {
static std::string path;
if (path.empty()) {
path = utils::get_env_value("XDG_RUNTIME_DIR", "");
if (path.empty())
BOOST_THROW_EXCEPTION(std::runtime_error("No runtime directory specified"));
}
return path;
static std::string path;
if (path.empty()) {
path = utils::get_env_value("XDG_RUNTIME_DIR", "");
if (path.empty())
BOOST_THROW_EXCEPTION(
std::runtime_error("No runtime directory specified"));
}
return path;
}
std::string state_dir() {
static std::string path = "/var/lib";
return path;
static std::string path = "/var/lib";
return path;
}
std::string log_path() {
static std::string path = in_snap_data_dir(utils::string_format("%s/anbox/", state_dir()));
return path;
static std::string path =
in_snap_data_dir(utils::string_format("%s/anbox/", state_dir()));
return path;
}
std::string socket_path() {
static std::string path = utils::string_format("%s/anbox/sockets", runtime_dir());
return path;
static std::string path =
utils::string_format("%s/anbox/sockets", runtime_dir());
return path;
}
std::string data_path() {
static std::string path = utils::string_format("%s/.anbox/data", home_dir());
return path;
static std::string path = utils::string_format("%s/.anbox/data", home_dir());
return path;
}
std::string rootfs_path() {
static std::string path = in_snap_data_dir(utils::string_format("%s/anbox/rootfs", state_dir()));
return path;
static std::string path =
in_snap_data_dir(utils::string_format("%s/anbox/rootfs", state_dir()));
return path;
}
std::string container_config_path() {
static std::string path = in_snap_data_dir(utils::string_format("%s/anbox/containers", state_dir()));
return path;
static std::string path = in_snap_data_dir(
utils::string_format("%s/anbox/containers", state_dir()));
return path;
}
std::string container_socket_path() {
std::string path = "/run/anbox-container.socket";
return path;
std::string path = "/run/anbox-container.socket";
return path;
}
std::string host_input_device_path() {
static std::string path = utils::string_format("%s/anbox/input-devices", runtime_dir());
return path;
static std::string path =
utils::string_format("%s/anbox/input-devices", runtime_dir());
return path;
}
} // namespace config
} // namespace anbox
} // namespace config
} // namespace anbox

View file

@ -32,7 +32,7 @@ std::string socket_path();
std::string container_config_path();
std::string container_socket_path();
std::string host_input_device_path();
} // namespace config
} // namespace anbox
} // namespace config
} // namespace anbox
#endif

View file

@ -16,53 +16,50 @@
*/
#include "anbox/container/client.h"
#include "anbox/config.h"
#include "anbox/container/management_api_stub.h"
#include "anbox/logger.h"
#include "anbox/network/local_socket_messenger.h"
#include "anbox/rpc/pending_call_cache.h"
#include "anbox/rpc/channel.h"
#include "anbox/rpc/message_processor.h"
#include "anbox/config.h"
#include "anbox/logger.h"
#include "anbox/rpc/pending_call_cache.h"
namespace ba = boost::asio;
namespace bs = boost::system;
namespace anbox {
namespace container {
Client::Client(const std::shared_ptr<Runtime> &rt) :
messenger_(std::make_shared<network::LocalSocketMessenger>(config::container_socket_path(), rt)),
pending_calls_(std::make_shared<rpc::PendingCallCache>()),
rpc_channel_(std::make_shared<rpc::Channel>(pending_calls_, messenger_)),
management_api_(std::make_shared<ManagementApiStub>(rpc_channel_)),
processor_(std::make_shared<rpc::MessageProcessor>(messenger_, pending_calls_)) {
read_next_message();
Client::Client(const std::shared_ptr<Runtime> &rt)
: messenger_(std::make_shared<network::LocalSocketMessenger>(
config::container_socket_path(), rt)),
pending_calls_(std::make_shared<rpc::PendingCallCache>()),
rpc_channel_(std::make_shared<rpc::Channel>(pending_calls_, messenger_)),
management_api_(std::make_shared<ManagementApiStub>(rpc_channel_)),
processor_(
std::make_shared<rpc::MessageProcessor>(messenger_, pending_calls_)) {
read_next_message();
}
Client::~Client() {
}
Client::~Client() {}
void Client::start_container(const Configuration &configuration) {
management_api_->start_container(configuration);
management_api_->start_container(configuration);
}
void Client::read_next_message()
{
auto callback = std::bind(&Client::on_read_size,
this, std::placeholders::_1, std::placeholders::_2);
messenger_->async_receive_msg(callback, ba::buffer(buffer_));
void Client::read_next_message() {
auto callback = std::bind(&Client::on_read_size, this, std::placeholders::_1,
std::placeholders::_2);
messenger_->async_receive_msg(callback, ba::buffer(buffer_));
}
void Client::on_read_size(const boost::system::error_code& error, std::size_t bytes_read)
{
if (error)
BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
void Client::on_read_size(const boost::system::error_code &error,
std::size_t bytes_read) {
if (error) BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
std::vector<std::uint8_t> data(bytes_read);
std::copy(buffer_.data(), buffer_.data() + bytes_read, data.data());
std::vector<std::uint8_t> data(bytes_read);
std::copy(buffer_.data(), buffer_.data() + bytes_read, data.data());
if (processor_->process_data(data))
read_next_message();
if (processor_->process_data(data)) read_next_message();
}
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox

View file

@ -18,39 +18,40 @@
#ifndef ANBOX_CONTAINER_CLIENT_H_
#define ANBOX_CONTAINER_CLIENT_H_
#include "anbox/runtime.h"
#include "anbox/container/configuration.h"
#include "anbox/runtime.h"
namespace anbox {
namespace rpc {
class PendingCallCache;
class Channel;
class MessageProcessor;
} // namespace rpc
} // namespace rpc
namespace network {
class LocalSocketMessenger;
} // namespace network
} // namespace network
namespace container {
class ManagementApiStub;
class Client {
public:
Client(const std::shared_ptr<Runtime> &rt);
~Client();
public:
Client(const std::shared_ptr<Runtime> &rt);
~Client();
void start_container(const Configuration &configuration);
void start_container(const Configuration &configuration);
private:
void read_next_message();
void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read);
private:
void read_next_message();
void on_read_size(const boost::system::error_code &ec,
std::size_t bytes_read);
std::shared_ptr<network::LocalSocketMessenger> messenger_;
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<rpc::Channel> rpc_channel_;
std::shared_ptr<ManagementApiStub> management_api_;
std::shared_ptr<rpc::MessageProcessor> processor_;
std::array<std::uint8_t, 8192> buffer_;
std::shared_ptr<network::LocalSocketMessenger> messenger_;
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<rpc::Channel> rpc_channel_;
std::shared_ptr<ManagementApiStub> management_api_;
std::shared_ptr<rpc::MessageProcessor> processor_;
std::array<std::uint8_t, 8192> buffer_;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -18,15 +18,15 @@
#ifndef ANBOX_CONTAINER_CONFIGURATION_H_
#define ANBOX_CONTAINER_CONFIGURATION_H_
#include <string>
#include <map>
#include <string>
namespace anbox {
namespace container {
struct Configuration {
std::map<std::string,std::string> bind_mounts;
std::map<std::string, std::string> bind_mounts;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -19,7 +19,6 @@
namespace anbox {
namespace container {
Container::~Container() {
}
} // namespace container
} // namespace anbox
Container::~Container() {}
} // namespace container
} // namespace anbox

View file

@ -20,30 +20,30 @@
#include "anbox/container/configuration.h"
#include <string>
#include <map>
#include <string>
namespace anbox {
namespace container {
class Container {
public:
virtual ~Container();
public:
virtual ~Container();
enum class State {
inactive,
running,
};
enum class State {
inactive,
running,
};
// Start the container in background
virtual void start(const Configuration &configuration) = 0;
// Start the container in background
virtual void start(const Configuration &configuration) = 0;
// Stop a running container
virtual void stop() = 0;
// Stop a running container
virtual void stop() = 0;
// Get the current container state
virtual State state() = 0;
// Get the current container state
virtual State state() = 0;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -16,158 +16,168 @@
*/
#include "anbox/container/lxc_container.h"
#include "anbox/utils.h"
#include "anbox/config.h"
#include "anbox/logger.h"
#include "anbox/utils.h"
#include <stdexcept>
#include <map>
#include <stdexcept>
#include <boost/throw_exception.hpp>
#include <boost/filesystem.hpp>
#include <boost/throw_exception.hpp>
#include <sys/wait.h>
#include <sys/capability.h>
#include <sys/types.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
namespace fs = boost::filesystem;
namespace anbox {
namespace container {
LxcContainer::LxcContainer() :
state_(State::inactive),
container_(nullptr) {
utils::ensure_paths({
config::container_config_path(),
config::log_path(),
});
LxcContainer::LxcContainer() : state_(State::inactive), container_(nullptr) {
utils::ensure_paths({
config::container_config_path(), config::log_path(),
});
}
LxcContainer::~LxcContainer() {
DEBUG("");
DEBUG("");
stop();
stop();
if (container_)
lxc_container_put(container_);
if (container_) lxc_container_put(container_);
}
void LxcContainer::start(const Configuration &configuration) {
if (getuid() != 0)
BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root"));
if (getuid() != 0)
BOOST_THROW_EXCEPTION(
std::runtime_error("You have to start the container as root"));
if (container_ && container_->is_running(container_)) {
BOOST_THROW_EXCEPTION(std::runtime_error("Container already started, stopping it now"));
container_->stop(container_);
}
if (container_ && container_->is_running(container_)) {
BOOST_THROW_EXCEPTION(
std::runtime_error("Container already started, stopping it now"));
container_->stop(container_);
}
if (!container_) {
DEBUG("Containers are stored in %s", config::container_config_path());
if (!container_) {
DEBUG("Containers are stored in %s", config::container_config_path());
// Remove container config to be be able to rewrite it
::unlink(utils::string_format("%s/default/config", config::container_config_path()).c_str());
// Remove container config to be be able to rewrite it
::unlink(utils::string_format("%s/default/config",
config::container_config_path())
.c_str());
container_ = lxc_container_new("default", config::container_config_path().c_str());
if (!container_)
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create LXC container instance"));
container_ =
lxc_container_new("default", config::container_config_path().c_str());
if (!container_)
BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to create LXC container instance"));
// If container is still running (for example after a crash) we stop it here to ensure
// its configuration is synchronized.
if (container_->is_running(container_))
container_->stop(container_);
}
// If container is still running (for example after a crash) we stop it here
// to ensure
// its configuration is synchronized.
if (container_->is_running(container_)) container_->stop(container_);
}
// We drop all not needed capabilities
set_config_item("lxc.cap.drop", "mac_admin mac_override sys_time sys_module sys_rawio");
// We drop all not needed capabilities
set_config_item("lxc.cap.drop",
"mac_admin mac_override sys_time sys_module sys_rawio");
// We can mount proc/sys as rw here as we will run the container unprivileged in the end
set_config_item("lxc.mount.auto", "proc:mixed sys:mixed cgroup:mixed");
// We can mount proc/sys as rw here as we will run the container unprivileged
// in the end
set_config_item("lxc.mount.auto", "proc:mixed sys:mixed cgroup:mixed");
set_config_item("lxc.autodev", "1");
set_config_item("lxc.pts", "1024");
set_config_item("lxc.tty", "0");
set_config_item("lxc.utsname", "anbox");
set_config_item("lxc.autodev", "1");
set_config_item("lxc.pts", "1024");
set_config_item("lxc.tty", "0");
set_config_item("lxc.utsname", "anbox");
set_config_item("lxc.group.devices.deny","");
set_config_item("lxc.group.devices.allow","");
set_config_item("lxc.group.devices.deny", "");
set_config_item("lxc.group.devices.allow", "");
// We can't move bind-mounts, so don't use /dev/lxc/
set_config_item("lxc.devttydir", "");
// We can't move bind-mounts, so don't use /dev/lxc/
set_config_item("lxc.devttydir", "");
set_config_item("lxc.environment", "PATH=/system/bin:/system/sbin:/system/xbin");
set_config_item("lxc.environment",
"PATH=/system/bin:/system/sbin:/system/xbin");
set_config_item("lxc.init_cmd", "/anbox-init.sh");
set_config_item("lxc.rootfs.backend", "dir");
set_config_item("lxc.init_cmd", "/anbox-init.sh");
set_config_item("lxc.rootfs.backend", "dir");
DEBUG("Using rootfs path %s", config::rootfs_path());
set_config_item("lxc.rootfs", config::rootfs_path());
DEBUG("Using rootfs path %s", config::rootfs_path());
set_config_item("lxc.rootfs", config::rootfs_path());
set_config_item("lxc.loglevel", "0");
set_config_item("lxc.logfile", utils::string_format("%s/container.log", config::log_path()).c_str());
set_config_item("lxc.loglevel", "0");
set_config_item(
"lxc.logfile",
utils::string_format("%s/container.log", config::log_path()).c_str());
set_config_item("lxc.network.type", "veth");
set_config_item("lxc.network.flags", "up");
set_config_item("lxc.network.link", "anboxbr0");
set_config_item("lxc.network.type", "veth");
set_config_item("lxc.network.flags", "up");
set_config_item("lxc.network.link", "anboxbr0");
#if 0
// Android uses namespaces as well so we have to allow nested namespaces for LXC
// which are otherwise forbidden by AppArmor.
set_config_item("lxc.aa_profile", "lxc-container-default-with-nesting");
#else
// FIXME: when using the nested profile we still get various denials from things
// Android tries to do but isn't allowed to. We need to look into those and see
// how we can switch back to a confined way of running the container.
set_config_item("lxc.aa_profile", "unconfined");
// FIXME: when using the nested profile we still get various denials from
// things
// Android tries to do but isn't allowed to. We need to look into those and
// see
// how we can switch back to a confined way of running the container.
set_config_item("lxc.aa_profile", "unconfined");
#endif
for (const auto &bind_mount : configuration.bind_mounts) {
std::string create_type = "file";
for (const auto &bind_mount : configuration.bind_mounts) {
std::string create_type = "file";
if (fs::is_directory(bind_mount.first))
create_type = "dir";
if (fs::is_directory(bind_mount.first)) create_type = "dir";
auto target_path = bind_mount.second;
// LXC wants target paths relative to the container rootfs so
// prividing an absolute path doesn't work.
if (utils::string_starts_with(target_path, "/"))
target_path.erase(0, 1);
auto target_path = bind_mount.second;
// LXC wants target paths relative to the container rootfs so
// prividing an absolute path doesn't work.
if (utils::string_starts_with(target_path, "/")) target_path.erase(0, 1);
set_config_item("lxc.mount.entry",
utils::string_format("%s %s none bind,create=%s,optional 0 0",
bind_mount.first, target_path, create_type));
}
set_config_item(
"lxc.mount.entry",
utils::string_format("%s %s none bind,create=%s,optional 0 0",
bind_mount.first, target_path, create_type));
}
if (!container_->save_config(container_, nullptr))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to save container configuration"));
if (!container_->save_config(container_, nullptr))
BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to save container configuration"));
if (not container_->start(container_, 0, nullptr))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container"));
if (not container_->start(container_, 0, nullptr))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container"));
state_ = Container::State::running;
state_ = Container::State::running;
DEBUG("Container successfully started");
DEBUG("Container successfully started");
}
void LxcContainer::stop() {
if (not container_ || not container_->is_running(container_))
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot stop container as it is not running"));
if (not container_ || not container_->is_running(container_))
BOOST_THROW_EXCEPTION(
std::runtime_error("Cannot stop container as it is not running"));
if (not container_->stop(container_))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container"));
if (not container_->stop(container_))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container"));
state_ = Container::State::inactive;
state_ = Container::State::inactive;
DEBUG("Container successfully stopped");
DEBUG("Container successfully stopped");
}
void LxcContainer::set_config_item(const std::string &key, const std::string &value) {
if (!container_->set_config_item(container_, key.c_str(), value.c_str()))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to configure LXC container"));
void LxcContainer::set_config_item(const std::string &key,
const std::string &value) {
if (!container_->set_config_item(container_, key.c_str(), value.c_str()))
BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to configure LXC container"));
}
Container::State LxcContainer::state() {
return state_;
}
} // namespace container
} // namespace anbox
Container::State LxcContainer::state() { return state_; }
} // namespace container
} // namespace anbox

View file

@ -27,21 +27,21 @@
namespace anbox {
namespace container {
class LxcContainer : public Container {
public:
LxcContainer();
~LxcContainer();
public:
LxcContainer();
~LxcContainer();
void start(const Configuration &configuration) override;
void stop() override;
State state() override;
void start(const Configuration &configuration) override;
void stop() override;
State state() override;
private:
void set_config_item(const std::string &key, const std::string &value);
private:
void set_config_item(const std::string &key, const std::string &value);
State state_;
lxc_container *container_;
State state_;
lxc_container *container_;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -24,22 +24,22 @@
namespace anbox {
namespace container {
ManagementApiMessageProcessor::ManagementApiMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server) :
rpc::MessageProcessor(sender, pending_calls),
server_(server) {
ManagementApiMessageProcessor::ManagementApiMessageProcessor(
const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server)
: rpc::MessageProcessor(sender, pending_calls), server_(server) {}
ManagementApiMessageProcessor::~ManagementApiMessageProcessor() {}
void ManagementApiMessageProcessor::dispatch(
rpc::Invocation const &invocation) {
if (invocation.method_name() == "start_container")
invoke(this, server_.get(), &ManagementApiSkeleton::start_container,
invocation);
}
ManagementApiMessageProcessor::~ManagementApiMessageProcessor() {
}
void ManagementApiMessageProcessor::dispatch(rpc::Invocation const& invocation) {
if (invocation.method_name() == "start_container")
invoke(this, server_.get(), &ManagementApiSkeleton::start_container, invocation);
}
void ManagementApiMessageProcessor::process_event_sequence(const std::string&) {
}
} // namespace container
} // namespace anbox
void ManagementApiMessageProcessor::process_event_sequence(
const std::string &) {}
} // namespace container
} // namespace anbox

View file

@ -24,19 +24,20 @@ namespace anbox {
namespace container {
class ManagementApiSkeleton;
class ManagementApiMessageProcessor : public rpc::MessageProcessor {
public:
ManagementApiMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server);
~ManagementApiMessageProcessor();
public:
ManagementApiMessageProcessor(
const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server);
~ManagementApiMessageProcessor();
void dispatch(rpc::Invocation const& invocation) override;
void process_event_sequence(const std::string &event) override;
void dispatch(rpc::Invocation const &invocation) override;
void process_event_sequence(const std::string &event) override;
private:
std::shared_ptr<ManagementApiSkeleton> server_;
private:
std::shared_ptr<ManagementApiSkeleton> server_;
};
} // namespace anbox
} // namespace network
} // namespace anbox
} // namespace network
#endif

View file

@ -16,54 +16,52 @@
*/
#include "anbox/container/management_api_skeleton.h"
#include "anbox/container/container.h"
#include "anbox/container/configuration.h"
#include "anbox/container/container.h"
#include "anbox/defer_action.h"
#include "anbox/utils.h"
#include "anbox/logger.h"
#include "anbox/utils.h"
#include "anbox_rpc.pb.h"
#include "anbox_container.pb.h"
#include "anbox_rpc.pb.h"
namespace anbox {
namespace container {
ManagementApiSkeleton::ManagementApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container) :
pending_calls_(pending_calls),
container_(container) {
}
ManagementApiSkeleton::ManagementApiSkeleton(
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container)
: pending_calls_(pending_calls), container_(container) {}
ManagementApiSkeleton::~ManagementApiSkeleton() {
}
void ManagementApiSkeleton::start_container(anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response,
google::protobuf::Closure *done) {
if (container_->state() == Container::State::running) {
response->set_error("Container is already running");
done->Run();
return;
}
Configuration container_configuration;
const auto configuration = request->configuration();
for (int n = 0; n < configuration.bind_mounts_size(); n++) {
const auto bind_mount = configuration.bind_mounts(n);
container_configuration.bind_mounts.insert({ bind_mount.source(), bind_mount.target() });
}
try {
container_->start(container_configuration);
}
catch (std::exception &err) {
response->set_error(utils::string_format("Failed to start container: %s", err.what()));
}
DEBUG("");
ManagementApiSkeleton::~ManagementApiSkeleton() {}
void ManagementApiSkeleton::start_container(
anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) {
if (container_->state() == Container::State::running) {
response->set_error("Container is already running");
done->Run();
return;
}
Configuration container_configuration;
const auto configuration = request->configuration();
for (int n = 0; n < configuration.bind_mounts_size(); n++) {
const auto bind_mount = configuration.bind_mounts(n);
container_configuration.bind_mounts.insert(
{bind_mount.source(), bind_mount.target()});
}
try {
container_->start(container_configuration);
} catch (std::exception &err) {
response->set_error(
utils::string_format("Failed to start container: %s", err.what()));
}
DEBUG("");
done->Run();
}
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox

View file

@ -23,38 +23,39 @@
namespace google {
namespace protobuf {
class Closure;
} // namespace protobuf
} // namespace google
} // namespace protobuf
} // namespace google
namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace rpc
} // namespace rpc
namespace container {
class StartContainer;
} // namespace container
} // namespace protobuf
} // namespace container
} // namespace protobuf
namespace rpc {
class PendingCallCache;
} // namespace rpc
} // namespace rpc
namespace container {
class Container;
class ManagementApiSkeleton {
public:
ManagementApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container);
~ManagementApiSkeleton();
public:
ManagementApiSkeleton(
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container);
~ManagementApiSkeleton();
void start_container(anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response,
google::protobuf::Closure *done);
void start_container(
anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done);
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<Container> container_;
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<Container> container_;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -16,55 +16,54 @@
*/
#include "anbox/container/management_api_stub.h"
#include "anbox/rpc/channel.h"
#include "anbox/logger.h"
#include "anbox/rpc/channel.h"
#include "anbox_rpc.pb.h"
#include "anbox_container.pb.h"
#include "anbox_rpc.pb.h"
namespace anbox {
namespace container {
ManagementApiStub::ManagementApiStub(const std::shared_ptr<rpc::Channel> &channel) :
channel_(channel) {
}
ManagementApiStub::ManagementApiStub(
const std::shared_ptr<rpc::Channel> &channel)
: channel_(channel) {}
ManagementApiStub::~ManagementApiStub() {
}
ManagementApiStub::~ManagementApiStub() {}
void ManagementApiStub::start_container(const Configuration &configuration) {
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::container::StartContainer message;
auto message_configuration = new protobuf::container::Configuration;
protobuf::container::StartContainer message;
auto message_configuration = new protobuf::container::Configuration;
for (const auto item : configuration.bind_mounts) {
auto bind_mount_message = message_configuration->add_bind_mounts();
bind_mount_message->set_source(item.first);
bind_mount_message->set_target(item.second);
}
for (const auto item : configuration.bind_mounts) {
auto bind_mount_message = message_configuration->add_bind_mounts();
bind_mount_message->set_source(item.first);
bind_mount_message->set_target(item.second);
}
message.set_allocated_configuration(message_configuration);
message.set_allocated_configuration(message_configuration);
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
start_wait_handle_.expect_result();
}
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
start_wait_handle_.expect_result();
}
channel_->call_method("start_container",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &ManagementApiStub::container_started, c.get()));
channel_->call_method(
"start_container", &message, c->response.get(),
google::protobuf::NewCallback(this, &ManagementApiStub::container_started,
c.get()));
start_wait_handle_.wait_for_all();
start_wait_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
if (c->response->has_error()) throw std::runtime_error(c->response->error());
}
void ManagementApiStub::container_started(Request<protobuf::rpc::Void> *request) {
(void) request;
DEBUG("");
start_wait_handle_.result_received();
void ManagementApiStub::container_started(
Request<protobuf::rpc::Void> *request) {
(void)request;
DEBUG("");
start_wait_handle_.result_received();
}
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox

View file

@ -18,9 +18,9 @@
#ifndef ANBOX_CONTAINER_MANAGEMENT_API_STUB_H_
#define ANBOX_CONTAINER_MANAGEMENT_API_STUB_H_
#include "anbox/do_not_copy_or_move.h"
#include "anbox/container/configuration.h"
#include "anbox/common/wait_handle.h"
#include "anbox/container/configuration.h"
#include "anbox/do_not_copy_or_move.h"
#include <memory>
@ -28,34 +28,34 @@ namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace rpc
} // namespace protobuf
} // namespace rpc
} // namespace protobuf
namespace rpc {
class Channel;
} // namespace rpc
} // namespace rpc
namespace container {
class ManagementApiStub : public DoNotCopyOrMove {
public:
ManagementApiStub(const std::shared_ptr<rpc::Channel> &channel);
~ManagementApiStub();
public:
ManagementApiStub(const std::shared_ptr<rpc::Channel> &channel);
~ManagementApiStub();
void start_container(const Configuration &configuration);
void start_container(const Configuration &configuration);
private:
template<typename Response>
struct Request {
Request() : response(std::make_shared<Response>()), success(true) { }
std::shared_ptr<Response> response;
bool success;
};
private:
template <typename Response>
struct Request {
Request() : response(std::make_shared<Response>()), success(true) {}
std::shared_ptr<Response> response;
bool success;
};
void container_started(Request<protobuf::rpc::Void> *request);
void container_started(Request<protobuf::rpc::Void> *request);
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle start_wait_handle_;
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle start_wait_handle_;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -16,76 +16,77 @@
*/
#include "anbox/container/service.h"
#include "anbox/config.h"
#include "anbox/container/lxc_container.h"
#include "anbox/container/management_api_message_processor.h"
#include "anbox/container/management_api_skeleton.h"
#include "anbox/logger.h"
#include "anbox/network/delegate_connection_creator.h"
#include "anbox/network/delegate_message_processor.h"
#include "anbox/network/local_socket_messenger.h"
#include "anbox/qemu/null_message_processor.h"
#include "anbox/rpc/pending_call_cache.h"
#include "anbox/rpc/channel.h"
#include "anbox/container/lxc_container.h"
#include "anbox/container/management_api_message_processor.h"
#include "anbox/container/management_api_skeleton.h"
#include "anbox/config.h"
#include "anbox/logger.h"
#include "anbox/rpc/pending_call_cache.h"
namespace anbox {
namespace container {
std::shared_ptr<Service> Service::create(const std::shared_ptr<Runtime> &rt) {
auto sp = std::make_shared<Service>(rt);
auto sp = std::make_shared<Service>(rt);
auto delegate_connector = std::make_shared<network::DelegateConnectionCreator<boost::asio::local::stream_protocol>>(
[sp](std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
sp->new_client(socket);
});
auto delegate_connector = std::make_shared<
network::DelegateConnectionCreator<boost::asio::local::stream_protocol>>(
[sp](std::shared_ptr<boost::asio::local::stream_protocol::socket> const
&socket) { sp->new_client(socket); });
sp->connector_ = std::make_shared<network::PublishedSocketConnector>(
config::container_socket_path(), rt, delegate_connector);
sp->connector_ = std::make_shared<network::PublishedSocketConnector>(
config::container_socket_path(), rt, delegate_connector);
// Make sure others can connect to our socket
::chmod(config::container_socket_path().c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
// Make sure others can connect to our socket
::chmod(config::container_socket_path().c_str(),
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
DEBUG("Everything setup. Waiting for incoming connections.");
DEBUG("Everything setup. Waiting for incoming connections.");
return sp;
return sp;
}
Service::Service(const std::shared_ptr<Runtime> &rt) :
dispatcher_(anbox::common::create_dispatcher_for_runtime(rt)),
next_connection_id_(0),
connections_(std::make_shared<network::Connections<network::SocketConnection>>()) {
Service::Service(const std::shared_ptr<Runtime> &rt)
: dispatcher_(anbox::common::create_dispatcher_for_runtime(rt)),
next_connection_id_(0),
connections_(
std::make_shared<network::Connections<network::SocketConnection>>()) {
}
Service::~Service() {
DEBUG("");
Service::~Service() { DEBUG(""); }
int Service::next_id() { return next_connection_id_++; }
void Service::new_client(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const
&socket) {
if (connections_->size() >= 1) {
socket->close();
return;
}
auto const messenger =
std::make_shared<network::LocalSocketMessenger>(socket);
DEBUG("Got connection from pid %d", messenger->creds().pid());
auto pending_calls = std::make_shared<rpc::PendingCallCache>();
auto rpc_channel = std::make_shared<rpc::Channel>(pending_calls, messenger);
auto server = std::make_shared<container::ManagementApiSkeleton>(
pending_calls, std::make_shared<LxcContainer>());
auto processor = std::make_shared<container::ManagementApiMessageProcessor>(
messenger, pending_calls, server);
auto const &connection = std::make_shared<network::SocketConnection>(
messenger, messenger, next_id(), connections_, processor);
connection->set_name("container-service");
connections_->add(connection);
connection->read_next_message();
}
int Service::next_id() {
return next_connection_id_++;
}
void Service::new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
if (connections_->size() >= 1) {
socket->close();
return;
}
auto const messenger = std::make_shared<network::LocalSocketMessenger>(socket);
DEBUG("Got connection from pid %d", messenger->creds().pid());
auto pending_calls = std::make_shared<rpc::PendingCallCache>();
auto rpc_channel = std::make_shared<rpc::Channel>(pending_calls, messenger);
auto server = std::make_shared<container::ManagementApiSkeleton>(
pending_calls, std::make_shared<LxcContainer>());
auto processor = std::make_shared<container::ManagementApiMessageProcessor>(
messenger, pending_calls, server);
auto const& connection = std::make_shared<network::SocketConnection>(
messenger, messenger, next_id(), connections_, processor);
connection->set_name("container-service");
connections_->add(connection);
connection->read_next_message();
}
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox

View file

@ -18,34 +18,35 @@
#ifndef ANBOX_CONTAINER_SERVICE_H_
#define ANBOX_CONTAINER_SERVICE_H_
#include "anbox/network/published_socket_connector.h"
#include "anbox/network/connections.h"
#include "anbox/network/socket_connection.h"
#include "anbox/network/credentials.h"
#include "anbox/container/container.h"
#include "anbox/common/dispatcher.h"
#include "anbox/container/container.h"
#include "anbox/network/connections.h"
#include "anbox/network/credentials.h"
#include "anbox/network/published_socket_connector.h"
#include "anbox/network/socket_connection.h"
#include "anbox/runtime.h"
namespace anbox {
namespace container {
class Service : public std::enable_shared_from_this<Service> {
public:
static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt);
public:
static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt);
Service(const std::shared_ptr<Runtime> &rt);
~Service();
Service(const std::shared_ptr<Runtime> &rt);
~Service();
private:
int next_id();
void new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket);
private:
int next_id();
void new_client(std::shared_ptr<
boost::asio::local::stream_protocol::socket> const &socket);
std::shared_ptr<common::Dispatcher> dispatcher_;
std::shared_ptr<network::PublishedSocketConnector> connector_;
std::atomic<int> next_connection_id_;
std::shared_ptr<network::Connections<network::SocketConnection>> connections_;
std::shared_ptr<Container> backend_;
std::shared_ptr<common::Dispatcher> dispatcher_;
std::shared_ptr<network::PublishedSocketConnector> connector_;
std::atomic<int> next_connection_id_;
std::shared_ptr<network::Connections<network::SocketConnection>> connections_;
std::shared_ptr<Container> backend_;
};
} // namespace container
} // namespace anbox
} // namespace container
} // namespace anbox
#endif

View file

@ -15,38 +15,36 @@
*
*/
#include <sys/prctl.h>
#include <signal.h>
#include <sys/prctl.h>
#include "anbox/logger.h"
#include "anbox/daemon.h"
#include "anbox/config.h"
#include "anbox/daemon.h"
#include "anbox/logger.h"
#include "anbox/cmds/version.h"
#include "anbox/cmds/run.h"
#include "anbox/cmds/launch.h"
#include "anbox/cmds/container_manager.h"
#include "anbox/cmds/launch.h"
#include "anbox/cmds/run.h"
#include "anbox/cmds/version.h"
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
namespace anbox {
Daemon::Daemon() :
cmd{cli::Name{"anbox"}, cli::Usage{"anbox"}, cli::Description{"The Android in a Box runtime"}} {
cmd.command(std::make_shared<cmds::Version>())
.command(std::make_shared<cmds::Run>())
.command(std::make_shared<cmds::Launch>())
.command(std::make_shared<cmds::ContainerManager>());
Daemon::Daemon()
: cmd{cli::Name{"anbox"}, cli::Usage{"anbox"},
cli::Description{"The Android in a Box runtime"}} {
cmd.command(std::make_shared<cmds::Version>())
.command(std::make_shared<cmds::Run>())
.command(std::make_shared<cmds::Launch>())
.command(std::make_shared<cmds::ContainerManager>());
}
int Daemon::Run(const std::vector<std::string> &arguments)
try {
return cmd.run({std::cin, std::cout, arguments});
int Daemon::Run(const std::vector<std::string> &arguments) try {
return cmd.run({std::cin, std::cout, arguments});
} catch (std::exception &err) {
ERROR("%s", err.what());
return EXIT_FAILURE;
}
catch(std::exception &err) {
ERROR("%s", err.what());
return EXIT_FAILURE;
}
} // namespace anbox
} // namespace anbox

View file

@ -18,22 +18,22 @@
#ifndef ANBOX_DAEMON_H_
#define ANBOX_DAEMON_H_
#include <vector>
#include <string>
#include <vector>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/cli.h"
#include "anbox/do_not_copy_or_move.h"
namespace anbox {
class Daemon : public DoNotCopyOrMove {
public:
Daemon();
public:
Daemon();
int Run(const std::vector<std::string> &arguments);
int Run(const std::vector<std::string> &arguments);
private:
cli::CommandWithSubcommands cmd;
private:
cli::CommandWithSubcommands cmd;
};
} // namespace anbox
} // namespace anbox
#endif

View file

@ -20,42 +20,45 @@
#include <core/dbus/macros.h>
#include <string>
#include <chrono>
#include <string>
namespace anbox {
namespace dbus {
namespace interface {
struct Service {
static inline std::string name() { return "org.anbox"; }
static inline std::string path() { return "/"; }
static inline std::string name() { return "org.anbox"; }
static inline std::string path() { return "/"; }
};
struct ApplicationManager {
static inline std::string name() { return "org.anbox.ApplicationManager"; }
struct Methods {
struct Launch {
static inline std::string name() { return "Launch"; }
typedef anbox::dbus::interface::ApplicationManager Interface;
typedef void ResultType;
static inline std::chrono::milliseconds default_timeout() { return std::chrono::seconds{1}; }
};
static inline std::string name() { return "org.anbox.ApplicationManager"; }
struct Methods {
struct Launch {
static inline std::string name() { return "Launch"; }
typedef anbox::dbus::interface::ApplicationManager Interface;
typedef void ResultType;
static inline std::chrono::milliseconds default_timeout() {
return std::chrono::seconds{1};
}
};
};
};
} // namespace interface
} // namespace dbus
} // namespace anbox
} // namespace interface
} // namespace dbus
} // namespace anbox
namespace core {
namespace dbus {
namespace traits {
template<> struct Service<anbox::dbus::interface::ApplicationManager> {
static inline const std::string& interface_name() {
static const std::string s{"org.anbox.ApplicationManager"};
return s;
}
template <>
struct Service<anbox::dbus::interface::ApplicationManager> {
static inline const std::string& interface_name() {
static const std::string s{"org.anbox.ApplicationManager"};
return s;
}
};
} // namespace traits
} // namespace dbus
} // namespace core
} // namespace traits
} // namespace dbus
} // namespace core
#endif

View file

@ -16,22 +16,20 @@
*/
#include "anbox/dbus/skeleton/application_manager.h"
#include "anbox/dbus/interface.h"
#include "anbox/android/intent.h"
#include "anbox/dbus/interface.h"
#include "anbox/logger.h"
namespace anbox {
namespace dbus {
namespace skeleton {
ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Object::Ptr& object,
const std::shared_ptr<anbox::ApplicationManager> &impl) :
bus_(bus),
object_(object),
impl_(impl) {
object_->install_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Launch>(
[this](const core::dbus::Message::Ptr &msg) {
ApplicationManager::ApplicationManager(
const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object,
const std::shared_ptr<anbox::ApplicationManager> &impl)
: bus_(bus), object_(object), impl_(impl) {
object_->install_method_handler<
anbox::dbus::interface::ApplicationManager::Methods::Launch>(
[this](const core::dbus::Message::Ptr &msg) {
auto reader = msg->reader();
android::Intent intent;
@ -45,25 +43,22 @@ ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
core::dbus::Message::Ptr reply;
try {
launch(intent);
reply = core::dbus::Message::make_method_return(msg);
}
catch (std::exception const &err) {
reply = core::dbus::Message::make_error(msg,
"org.anbox.Error.Failed",
err.what());
launch(intent);
reply = core::dbus::Message::make_method_return(msg);
} catch (std::exception const &err) {
reply = core::dbus::Message::make_error(msg, "org.anbox.Error.Failed",
err.what());
}
bus_->send(reply);
});
});
}
ApplicationManager::~ApplicationManager() {
}
ApplicationManager::~ApplicationManager() {}
void ApplicationManager::launch(const android::Intent &intent) {
impl_->launch(intent);
impl_->launch(intent);
}
} // namespace skeleton
} // namespace dbus
} // namespace anbox
} // namespace skeleton
} // namespace dbus
} // namespace anbox

View file

@ -28,22 +28,22 @@ namespace anbox {
namespace dbus {
namespace skeleton {
class ApplicationManager : public anbox::ApplicationManager {
public:
ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Object::Ptr& object,
const std::shared_ptr<anbox::ApplicationManager> &impl);
~ApplicationManager();
public:
ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Object::Ptr &object,
const std::shared_ptr<anbox::ApplicationManager> &impl);
~ApplicationManager();
void launch(const android::Intent &intent) override;
void launch(const android::Intent &intent) override;
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
std::shared_ptr<anbox::ApplicationManager> impl_;
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
std::shared_ptr<anbox::ApplicationManager> impl_;
};
} // namespace skeleton
} // namespace dbus
} // namespace anbox
} // namespace skeleton
} // namespace dbus
} // namespace anbox
#endif

View file

@ -16,31 +16,33 @@
*/
#include "anbox/dbus/skeleton/service.h"
#include "anbox/dbus/skeleton/application_manager.h"
#include "anbox/dbus/interface.h"
#include "anbox/dbus/skeleton/application_manager.h"
namespace anbox {
namespace dbus {
namespace skeleton {
std::shared_ptr<Service> Service::create_for_bus(const core::dbus::Bus::Ptr &bus,
const std::shared_ptr<anbox::ApplicationManager> &application_manager) {
auto service = core::dbus::Service::add_service(bus, anbox::dbus::interface::Service::name());
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<Service>(bus, service, object, application_manager);
std::shared_ptr<Service> Service::create_for_bus(
const core::dbus::Bus::Ptr &bus,
const std::shared_ptr<anbox::ApplicationManager> &application_manager) {
auto service = core::dbus::Service::add_service(
bus, anbox::dbus::interface::Service::name());
auto object =
service->add_object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<Service>(bus, service, object, application_manager);
}
Service::Service(const core::dbus::Bus::Ptr &bus,
const core::dbus::Service::Ptr& service,
const core::dbus::Object::Ptr& object,
const std::shared_ptr<anbox::ApplicationManager> &application_manager) :
bus_(bus),
service_(service),
object_(object),
application_manager_(std::make_shared<ApplicationManager>(bus_, object_, application_manager)) {
}
Service::Service(
const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service,
const core::dbus::Object::Ptr &object,
const std::shared_ptr<anbox::ApplicationManager> &application_manager)
: bus_(bus),
service_(service),
object_(object),
application_manager_(std::make_shared<ApplicationManager>(
bus_, object_, application_manager)) {}
Service::~Service() {
}
} // namespace skeleton
} // namespace dbus
} // namespace anbox
Service::~Service() {}
} // namespace skeleton
} // namespace dbus
} // namespace anbox

View file

@ -18,8 +18,8 @@
#ifndef ANBOX_DBUS_SKELETON_SERVICE_H_
#define ANBOX_DBUS_SKELETON_SERVICE_H_
#include "anbox/do_not_copy_or_move.h"
#include "anbox/application_manager.h"
#include "anbox/do_not_copy_or_move.h"
#include <core/dbus/bus.h>
#include <core/dbus/object.h>
@ -30,24 +30,25 @@ namespace dbus {
namespace skeleton {
class ApplicationManager;
class Service : public DoNotCopyOrMove {
public:
static std::shared_ptr<Service> create_for_bus(const core::dbus::Bus::Ptr &bus,
const std::shared_ptr<anbox::ApplicationManager> &application_manager);
public:
static std::shared_ptr<Service> create_for_bus(
const core::dbus::Bus::Ptr &bus,
const std::shared_ptr<anbox::ApplicationManager> &application_manager);
Service(const core::dbus::Bus::Ptr &bus,
const core::dbus::Service::Ptr& service,
const core::dbus::Object::Ptr& object,
const std::shared_ptr<anbox::ApplicationManager> &application_manager);
~Service();
Service(
const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service,
const core::dbus::Object::Ptr &object,
const std::shared_ptr<anbox::ApplicationManager> &application_manager);
~Service();
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
std::shared_ptr<ApplicationManager> application_manager_;
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
std::shared_ptr<ApplicationManager> application_manager_;
};
} // namespace skeleton
} // namespace dbus
} // namespace anbox
} // namespace skeleton
} // namespace dbus
} // namespace anbox
#endif

View file

@ -22,37 +22,31 @@
namespace anbox {
namespace dbus {
namespace stub {
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
auto service = core::dbus::Service::use_service(bus, anbox::dbus::interface::Service::name());
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<ApplicationManager>(bus, service, object);
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(
const core::dbus::Bus::Ptr &bus) {
auto service = core::dbus::Service::use_service(
bus, anbox::dbus::interface::Service::name());
auto object =
service->add_object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<ApplicationManager>(bus, service, object);
}
ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Service::Ptr& service,
const core::dbus::Object::Ptr& object) :
bus_(bus),
service_(service),
object_(object) {
}
const core::dbus::Service::Ptr &service,
const core::dbus::Object::Ptr &object)
: bus_(bus), service_(service), object_(object) {}
ApplicationManager::~ApplicationManager() {
}
ApplicationManager::~ApplicationManager() {}
void ApplicationManager::launch(const android::Intent &intent) {
auto result = object_->invoke_method_synchronously<
anbox::dbus::interface::ApplicationManager::Methods::Launch,
anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>(
intent.action,
intent.uri,
intent.type,
intent.flags,
intent.package,
intent.component);
auto result = object_->invoke_method_synchronously<
anbox::dbus::interface::ApplicationManager::Methods::Launch,
anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>(
intent.action, intent.uri, intent.type, intent.flags, intent.package,
intent.component);
if (result.is_error())
throw std::runtime_error(result.error().print());
if (result.is_error()) throw std::runtime_error(result.error().print());
}
} // namespace skeleton
} // namespace dbus
} // namespace anbox
} // namespace skeleton
} // namespace dbus
} // namespace anbox

View file

@ -28,23 +28,24 @@ namespace anbox {
namespace dbus {
namespace stub {
class ApplicationManager : public anbox::ApplicationManager {
public:
static std::shared_ptr<ApplicationManager> create_for_bus(const core::dbus::Bus::Ptr &bus);
public:
static std::shared_ptr<ApplicationManager> create_for_bus(
const core::dbus::Bus::Ptr &bus);
ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Service::Ptr& service,
const core::dbus::Object::Ptr& object);
~ApplicationManager();
ApplicationManager(const core::dbus::Bus::Ptr &bus,
const core::dbus::Service::Ptr &service,
const core::dbus::Object::Ptr &object);
~ApplicationManager();
void launch(const android::Intent &intent) override;
void launch(const android::Intent &intent) override;
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
private:
core::dbus::Bus::Ptr bus_;
core::dbus::Service::Ptr service_;
core::dbus::Object::Ptr object_;
};
} // namespace stub
} // namespace dbus
} // namespace anbox
} // namespace stub
} // namespace dbus
} // namespace anbox
#endif

View file

@ -25,20 +25,17 @@
namespace anbox {
class DeferAction : public DoNotCopyOrMove {
public:
DeferAction(const std::function<void()> action) :
action_(action) {
}
public:
DeferAction(const std::function<void()> action) : action_(action) {}
~DeferAction() {
if (action_)
action_();
}
~DeferAction() {
if (action_) action_();
}
private:
std::function<void()> action_;
private:
std::function<void()> action_;
};
} // namespace anbox
} // namespace anbox
#endif

View file

@ -20,19 +20,17 @@
namespace anbox {
class DoNotCopyOrMove
{
public:
DoNotCopyOrMove(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove(DoNotCopyOrMove&&) = delete;
virtual ~DoNotCopyOrMove() = default;
DoNotCopyOrMove& operator=(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove& operator=(DoNotCopyOrMove&&) = delete;
class DoNotCopyOrMove {
public:
DoNotCopyOrMove(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove(DoNotCopyOrMove&&) = delete;
virtual ~DoNotCopyOrMove() = default;
DoNotCopyOrMove& operator=(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove& operator=(DoNotCopyOrMove&&) = delete;
protected:
DoNotCopyOrMove() = default;
protected:
DoNotCopyOrMove() = default;
};
}
#endif

View file

@ -21,19 +21,21 @@
namespace anbox {
namespace graphics {
/**
* @brief Defines different types of density being used in an Android system. See the
* documentation in frameworks/base/core/java/android/util/DisplayMetrics.java
* @brief Defines different types of density being used in an Android system.
* See the
* documentation in
* frameworks/base/core/java/android/util/DisplayMetrics.java
* of the Android source tree which defines the different types.
*/
enum class DensityType {
low = 120,
medium = 160,
tv = 213,
high = 240,
xhigh = 360,
xxhigh = 480,
low = 120,
medium = 160,
tv = 213,
high = 240,
xhigh = 360,
xxhigh = 480,
};
} // namespace graphics
} // namespace anbox
} // namespace graphics
} // namespace anbox
#endif

View file

@ -30,23 +30,23 @@ namespace {
// implemented as unsigned integers. These convenience template functions
// help casting between them safely without generating compiler warnings.
inline void* SafePointerFromUInt(unsigned int handle) {
return (void*)(uintptr_t)(handle);
return (void*)(uintptr_t)(handle);
}
inline unsigned int SafeUIntFromPointer(const void* ptr) {
#if 1
// Ignore the assert below to avoid crashing when running older
// system images, which might have buggy encoder libraries. Print
// an error message though.
if ((uintptr_t)(ptr) != (unsigned int)(uintptr_t)(ptr)) {
fprintf(stderr, "EmuGL:WARNING: bad generic pointer %p\n", ptr);
}
// Ignore the assert below to avoid crashing when running older
// system images, which might have buggy encoder libraries. Print
// an error message though.
if ((uintptr_t)(ptr) != (unsigned int)(uintptr_t)(ptr)) {
fprintf(stderr, "EmuGL:WARNING: bad generic pointer %p\n", ptr);
}
#else
// Assertion error if the pointer contains a value that does not fit
// in an unsigned integer!
assert((uintptr_t)(ptr) == (unsigned int)(uintptr_t)(ptr));
// Assertion error if the pointer contains a value that does not fit
// in an unsigned integer!
assert((uintptr_t)(ptr) == (unsigned int)(uintptr_t)(ptr));
#endif
return (unsigned int)(uintptr_t)(ptr);
return (unsigned int)(uintptr_t)(ptr);
}
// Lazily create and bind a framebuffer object to the current host context.
@ -55,31 +55,28 @@ inline unsigned int SafeUIntFromPointer(const void* ptr) {
// on creation only. I.e. all rendering operations will target it.
// returns true in case of success, false on failure.
bool bindFbo(GLuint* fbo, GLuint tex) {
if (*fbo) {
// fbo already exist - just bind
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
return true;
}
s_gles2.glGenFramebuffers(1, fbo);
if (*fbo) {
// fbo already exist - just bind
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0_OES,
GL_TEXTURE_2D, tex, 0);
GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
ERR("ColorBuffer::bindFbo: FBO not complete: %#x\n", status);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
s_gles2.glDeleteFramebuffers(1, fbo);
*fbo = 0;
return false;
}
return true;
}
s_gles2.glGenFramebuffers(1, fbo);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, *fbo);
s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES,
GL_TEXTURE_2D, tex, 0);
GLenum status = s_gles2.glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
ERR("ColorBuffer::bindFbo: FBO not complete: %#x\n", status);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
s_gles2.glDeleteFramebuffers(1, fbo);
*fbo = 0;
return false;
}
return true;
}
void unbindFbo() {
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void unbindFbo() { s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0); }
// Helper class to use a ColorBuffer::Helper context.
// Usage is pretty simple:
@ -93,302 +90,268 @@ void unbindFbo() {
// } // automatically calls m_helper->teardownContext();
//
class ScopedHelperContext {
public:
ScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) {
if (!helper->setupContext()) {
mHelper = NULL;
}
public:
ScopedHelperContext(ColorBuffer::Helper* helper) : mHelper(helper) {
if (!helper->setupContext()) {
mHelper = NULL;
}
}
bool isOk() const { return mHelper != NULL; }
bool isOk() const { return mHelper != NULL; }
~ScopedHelperContext() {
release();
~ScopedHelperContext() { release(); }
void release() {
if (mHelper) {
mHelper->teardownContext();
mHelper = NULL;
}
}
void release() {
if (mHelper) {
mHelper->teardownContext();
mHelper = NULL;
}
}
private:
ColorBuffer::Helper* mHelper;
private:
ColorBuffer::Helper* mHelper;
};
} // namespace
// static
ColorBuffer* ColorBuffer::create(EGLDisplay p_display,
int p_width,
int p_height,
GLenum p_internalFormat,
bool has_eglimage_texture_2d,
Helper* helper) {
GLenum texInternalFormat = 0;
ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width,
int p_height, GLenum p_internalFormat,
bool has_eglimage_texture_2d, Helper* helper) {
GLenum texInternalFormat = 0;
switch (p_internalFormat) {
case GL_RGB:
case GL_RGB565_OES:
texInternalFormat = GL_RGB;
break;
switch (p_internalFormat) {
case GL_RGB:
case GL_RGB565_OES:
texInternalFormat = GL_RGB;
break;
case GL_RGBA:
case GL_RGB5_A1_OES:
case GL_RGBA4_OES:
texInternalFormat = GL_RGBA;
break;
case GL_RGBA:
case GL_RGB5_A1_OES:
case GL_RGBA4_OES:
texInternalFormat = GL_RGBA;
break;
default:
return NULL;
break;
}
default:
return NULL;
break;
}
ScopedHelperContext context(helper);
if (!context.isOk()) {
return NULL;
}
ScopedHelperContext context(helper);
if (!context.isOk()) {
return NULL;
}
ColorBuffer *cb = new ColorBuffer(p_display, helper);
ColorBuffer* cb = new ColorBuffer(p_display, helper);
s_gles2.glGenTextures(1, &cb->m_tex);
s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex);
s_gles2.glGenTextures(1, &cb->m_tex);
s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex);
int nComp = (texInternalFormat == GL_RGB ? 3 : 4);
int nComp = (texInternalFormat == GL_RGB ? 3 : 4);
char* zBuff = static_cast<char*>(::calloc(nComp * p_width * p_height, 1));
s_gles2.glTexImage2D(GL_TEXTURE_2D,
0,
texInternalFormat,
p_width,
p_height,
0,
texInternalFormat,
GL_UNSIGNED_BYTE,
zBuff);
::free(zBuff);
char* zBuff = static_cast<char*>(::calloc(nComp * p_width * p_height, 1));
s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height,
0, texInternalFormat, GL_UNSIGNED_BYTE, zBuff);
::free(zBuff);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//
// create another texture for that colorbuffer for blit
//
s_gles2.glGenTextures(1, &cb->m_blitTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex);
s_gles2.glTexImage2D(GL_TEXTURE_2D,
0,
texInternalFormat,
p_width,
p_height,
0,
texInternalFormat,
GL_UNSIGNED_BYTE,
NULL);
//
// create another texture for that colorbuffer for blit
//
s_gles2.glGenTextures(1, &cb->m_blitTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex);
s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat, p_width, p_height,
0, texInternalFormat, GL_UNSIGNED_BYTE, NULL);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
cb->m_width = p_width;
cb->m_height = p_height;
cb->m_internalFormat = texInternalFormat;
cb->m_width = p_width;
cb->m_height = p_height;
cb->m_internalFormat = texInternalFormat;
if (has_eglimage_texture_2d) {
cb->m_eglImage = s_egl.eglCreateImageKHR(
p_display,
s_egl.eglGetCurrentContext(),
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)SafePointerFromUInt(cb->m_tex),
NULL);
if (has_eglimage_texture_2d) {
cb->m_eglImage = s_egl.eglCreateImageKHR(
p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)SafePointerFromUInt(cb->m_tex), NULL);
cb->m_blitEGLImage = s_egl.eglCreateImageKHR(
p_display,
s_egl.eglGetCurrentContext(),
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)SafePointerFromUInt(cb->m_blitTex),
NULL);
}
cb->m_blitEGLImage = s_egl.eglCreateImageKHR(
p_display, s_egl.eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)SafePointerFromUInt(cb->m_blitTex), NULL);
}
cb->m_resizer = new TextureResize(p_width, p_height);
cb->m_resizer = new TextureResize(p_width, p_height);
return cb;
return cb;
}
ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper) :
m_tex(0),
m_blitTex(0),
m_eglImage(NULL),
m_blitEGLImage(NULL),
m_fbo(0),
m_internalFormat(0),
m_display(display),
m_helper(helper) {}
ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper)
: m_tex(0),
m_blitTex(0),
m_eglImage(NULL),
m_blitEGLImage(NULL),
m_fbo(0),
m_internalFormat(0),
m_display(display),
m_helper(helper) {}
ColorBuffer::~ColorBuffer() {
ScopedHelperContext context(m_helper);
ScopedHelperContext context(m_helper);
if (m_blitEGLImage) {
s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage);
}
if (m_eglImage) {
s_egl.eglDestroyImageKHR(m_display, m_eglImage);
}
if (m_blitEGLImage) {
s_egl.eglDestroyImageKHR(m_display, m_blitEGLImage);
}
if (m_eglImage) {
s_egl.eglDestroyImageKHR(m_display, m_eglImage);
}
if (m_fbo) {
s_gles2.glDeleteFramebuffers(1, &m_fbo);
}
if (m_fbo) {
s_gles2.glDeleteFramebuffers(1, &m_fbo);
}
GLuint tex[2] = {m_tex, m_blitTex};
s_gles2.glDeleteTextures(2, tex);
GLuint tex[2] = {m_tex, m_blitTex};
s_gles2.glDeleteTextures(2, tex);
delete m_resizer;
delete m_resizer;
}
void ColorBuffer::readPixels(int x,
int y,
int width,
int height,
GLenum p_format,
GLenum p_type,
void* pixels) {
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
void ColorBuffer::readPixels(int x, int y, int width, int height,
GLenum p_format, GLenum p_type, void* pixels) {
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
if (bindFbo(&m_fbo, m_tex)) {
s_gles2.glReadPixels(x, y, width, height, p_format, p_type, pixels);
unbindFbo();
}
}
void ColorBuffer::subUpdate(int x,
int y,
int width,
int height,
GLenum p_format,
GLenum p_type,
void* pixels) {
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
s_gles2.glTexSubImage2D(
GL_TEXTURE_2D, 0, x, y, width, height, p_format, p_type, pixels);
}
bool ColorBuffer::blitFromCurrentReadBuffer()
{
RenderThreadInfo *tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
// no Current context
return false;
}
// Copy the content of the current read surface into m_blitEGLImage.
// This is done by creating a temporary texture, bind it to the EGLImage
// then call glCopyTexSubImage2D().
GLuint tmpTex;
GLint currTexBind;
if (tInfo->currContext->isGL2()) {
s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gles2.glGenTextures(1,&tmpTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gles2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
m_width, m_height);
s_gles2.glDeleteTextures(1, &tmpTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, currTexBind);
}
else {
s_gles1.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gles1.glGenTextures(1,&tmpTex);
s_gles1.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gles1.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
m_width, m_height);
s_gles1.glDeleteTextures(1, &tmpTex);
s_gles1.glBindTexture(GL_TEXTURE_2D, currTexBind);
}
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return false;
}
if (!bindFbo(&m_fbo, m_tex)) {
return false;
}
// Save current viewport and match it to the current colorbuffer size.
GLint vport[4] = { 0, };
s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
s_gles2.glViewport(0, 0, m_width, m_height);
// render m_blitTex
m_helper->getTextureDraw()->draw(m_blitTex);
// Restore previous viewport.
s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
if (bindFbo(&m_fbo, m_tex)) {
s_gles2.glReadPixels(x, y, width, height, p_format, p_type, pixels);
unbindFbo();
}
}
return true;
void ColorBuffer::subUpdate(int x, int y, int width, int height,
GLenum p_format, GLenum p_type, void* pixels) {
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
s_gles2.glBindTexture(GL_TEXTURE_2D, m_tex);
s_gles2.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
s_gles2.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, p_format,
p_type, pixels);
}
bool ColorBuffer::blitFromCurrentReadBuffer() {
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
// no Current context
return false;
}
// Copy the content of the current read surface into m_blitEGLImage.
// This is done by creating a temporary texture, bind it to the EGLImage
// then call glCopyTexSubImage2D().
GLuint tmpTex;
GLint currTexBind;
if (tInfo->currContext->isGL2()) {
s_gles2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gles2.glGenTextures(1, &tmpTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gles2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width,
m_height);
s_gles2.glDeleteTextures(1, &tmpTex);
s_gles2.glBindTexture(GL_TEXTURE_2D, currTexBind);
} else {
s_gles1.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
s_gles1.glGenTextures(1, &tmpTex);
s_gles1.glBindTexture(GL_TEXTURE_2D, tmpTex);
s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
s_gles1.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_width,
m_height);
s_gles1.glDeleteTextures(1, &tmpTex);
s_gles1.glBindTexture(GL_TEXTURE_2D, currTexBind);
}
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return false;
}
if (!bindFbo(&m_fbo, m_tex)) {
return false;
}
// Save current viewport and match it to the current colorbuffer size.
GLint vport[4] = {
0,
};
s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
s_gles2.glViewport(0, 0, m_width, m_height);
// render m_blitTex
m_helper->getTextureDraw()->draw(m_blitTex);
// Restore previous viewport.
s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
unbindFbo();
return true;
}
bool ColorBuffer::bindToTexture() {
if (!m_eglImage) {
return false;
}
RenderThreadInfo *tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
return false;
}
if (tInfo->currContext->isGL2()) {
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
}
else {
s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
}
return true;
if (!m_eglImage) {
return false;
}
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
return false;
}
if (tInfo->currContext->isGL2()) {
s_gles2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
} else {
s_gles1.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
}
return true;
}
bool ColorBuffer::bindToRenderbuffer() {
if (!m_eglImage) {
return false;
}
RenderThreadInfo *tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
return false;
}
if (tInfo->currContext->isGL2()) {
s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, m_eglImage);
}
else {
s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, m_eglImage);
}
return true;
if (!m_eglImage) {
return false;
}
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
return false;
}
if (tInfo->currContext->isGL2()) {
s_gles2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES,
m_eglImage);
} else {
s_gles1.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES,
m_eglImage);
}
return true;
}
void ColorBuffer::readback(unsigned char* img) {
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
if (bindFbo(&m_fbo, m_tex)) {
s_gles2.glReadPixels(
0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, img);
unbindFbo();
}
ScopedHelperContext context(m_helper);
if (!context.isOk()) {
return;
}
if (bindFbo(&m_fbo, m_tex)) {
s_gles2.glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE,
img);
unbindFbo();
}
}
void ColorBuffer::bind() {
const auto id = m_resizer->update(m_tex);
s_gles2.glBindTexture(GL_TEXTURE_2D, id);
const auto id = m_resizer->update(m_tex);
s_gles2.glBindTexture(GL_TEXTURE_2D, id);
}

View file

@ -55,96 +55,84 @@ class TextureResize;
// As an additional twist.
class ColorBuffer {
public:
// Helper interface class used during ColorBuffer operations. This is
// introduced to remove coupling from the FrameBuffer class implementation.
class Helper {
public:
Helper() {}
virtual ~Helper() {}
virtual bool setupContext() = 0;
virtual void teardownContext() = 0;
virtual TextureDraw* getTextureDraw() const = 0;
};
public:
// Helper interface class used during ColorBuffer operations. This is
// introduced to remove coupling from the FrameBuffer class implementation.
class Helper {
public:
Helper() {}
virtual ~Helper() {}
virtual bool setupContext() = 0;
virtual void teardownContext() = 0;
virtual TextureDraw* getTextureDraw() const = 0;
};
// Create a new ColorBuffer instance.
// |p_display| is the host EGLDisplay handle.
// |p_width| and |p_height| are the buffer's dimensions in pixels.
// |p_internalFormat| is the internal pixel format to use, valid values
// are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES.
// Implementation is free to use something else though.
// |has_eglimage_texture_2d| should be true iff the display supports
// the EGL_KHR_gl_texture_2D_image extension.
// Returns NULL on failure.
static ColorBuffer* create(EGLDisplay p_display,
int p_width,
int p_height,
GLenum p_internalFormat,
bool has_eglimage_texture_2d,
Helper* helper);
// Create a new ColorBuffer instance.
// |p_display| is the host EGLDisplay handle.
// |p_width| and |p_height| are the buffer's dimensions in pixels.
// |p_internalFormat| is the internal pixel format to use, valid values
// are: GL_RGB, GL_RGB565, GL_RGBA, GL_RGB5_A1_OES and GL_RGBA4_OES.
// Implementation is free to use something else though.
// |has_eglimage_texture_2d| should be true iff the display supports
// the EGL_KHR_gl_texture_2D_image extension.
// Returns NULL on failure.
static ColorBuffer* create(EGLDisplay p_display, int p_width, int p_height,
GLenum p_internalFormat,
bool has_eglimage_texture_2d, Helper* helper);
// Destructor.
~ColorBuffer();
// Destructor.
~ColorBuffer();
// Return ColorBuffer width and height in pixels
GLuint getWidth() const { return m_width; }
GLuint getHeight() const { return m_height; }
// Return ColorBuffer width and height in pixels
GLuint getWidth() const { return m_width; }
GLuint getHeight() const { return m_height; }
// Read the ColorBuffer instance's pixel values into host memory.
void readPixels(int x,
int y,
int width,
int height,
GLenum p_format,
GLenum p_type,
void *pixels);
// Read the ColorBuffer instance's pixel values into host memory.
void readPixels(int x, int y, int width, int height, GLenum p_format,
GLenum p_type, void* pixels);
// Update the ColorBuffer instance's pixel values from host memory.
void subUpdate(int x,
int y,
int width,
int height,
GLenum p_format,
GLenum p_type,
void *pixels);
// Update the ColorBuffer instance's pixel values from host memory.
void subUpdate(int x, int y, int width, int height, GLenum p_format,
GLenum p_type, void* pixels);
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
// for all GLES versions.
bool bindToTexture();
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
// for all GLES versions.
bool bindToTexture();
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
// ColorBuffer's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
bool bindToRenderbuffer();
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
// ColorBuffer's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
bool bindToRenderbuffer();
// Copy the content of the current context's read surface to this
// ColorBuffer. This is used from WindowSurface::flushColorBuffer().
// Return true on success, false on failure (e.g. no current context).
bool blitFromCurrentReadBuffer();
// Copy the content of the current context's read surface to this
// ColorBuffer. This is used from WindowSurface::flushColorBuffer().
// Return true on success, false on failure (e.g. no current context).
bool blitFromCurrentReadBuffer();
// Read the content of the whole ColorBuffer as 32-bit RGBA pixels.
// |img| must be a buffer large enough (i.e. width * height * 4).
void readback(unsigned char* img);
// Read the content of the whole ColorBuffer as 32-bit RGBA pixels.
// |img| must be a buffer large enough (i.e. width * height * 4).
void readback(unsigned char* img);
void bind();
private:
ColorBuffer(); // no default constructor.
void bind();
explicit ColorBuffer(EGLDisplay display, Helper* helper);
private:
ColorBuffer(); // no default constructor.
private:
GLuint m_tex;
GLuint m_blitTex;
EGLImageKHR m_eglImage;
EGLImageKHR m_blitEGLImage;
GLuint m_width;
GLuint m_height;
GLuint m_fbo;
GLenum m_internalFormat;
EGLDisplay m_display;
Helper* m_helper;
TextureResize * m_resizer;
explicit ColorBuffer(EGLDisplay display, Helper* helper);
private:
GLuint m_tex;
GLuint m_blitTex;
EGLImageKHR m_eglImage;
EGLImageKHR m_blitEGLImage;
GLuint m_width;
GLuint m_height;
GLuint m_fbo;
GLenum m_internalFormat;
EGLDisplay m_display;
Helper* m_helper;
TextureResize* m_resizer;
};
typedef emugl::SmartPtr<ColorBuffer> ColorBufferPtr;

View file

@ -21,22 +21,18 @@ namespace {
std::shared_ptr<DisplayManager> display_mgr;
class NullDisplayManager : public DisplayManager {
public:
DisplayInfo display_info() const override {
return {1280, 720};
}
public:
DisplayInfo display_info() const override { return {1280, 720}; }
};
}
DisplayManager::~DisplayManager() {
}
DisplayManager::~DisplayManager() {}
std::shared_ptr<DisplayManager> DisplayManager::get() {
if (!display_mgr)
display_mgr = std::make_shared<NullDisplayManager>();
return display_mgr;
if (!display_mgr) display_mgr = std::make_shared<NullDisplayManager>();
return display_mgr;
}
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr) {
display_mgr = mgr;
display_mgr = mgr;
}

View file

@ -21,17 +21,17 @@
#include <memory>
class DisplayManager {
public:
virtual ~DisplayManager();
public:
virtual ~DisplayManager();
struct DisplayInfo {
int horizontal_resolution;
int vertical_resolution;
};
struct DisplayInfo {
int horizontal_resolution;
int vertical_resolution;
};
virtual DisplayInfo display_info() const = 0;
virtual DisplayInfo display_info() const = 0;
static std::shared_ptr<DisplayManager> get();
static std::shared_ptr<DisplayManager> get();
};
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr);

View file

@ -14,61 +14,54 @@
* limitations under the License.
*/
#include "ReadBuffer.h"
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include "ErrorLog.h"
ReadBuffer::ReadBuffer(size_t bufsize)
{
m_size = bufsize;
m_buf = (unsigned char*)malloc(m_size*sizeof(unsigned char));
m_validData = 0;
m_readPtr = m_buf;
ReadBuffer::ReadBuffer(size_t bufsize) {
m_size = bufsize;
m_buf = (unsigned char*)malloc(m_size * sizeof(unsigned char));
m_validData = 0;
m_readPtr = m_buf;
}
ReadBuffer::~ReadBuffer()
{
free(m_buf);
}
ReadBuffer::~ReadBuffer() { free(m_buf); }
int ReadBuffer::getData(IOStream *stream)
{
if(stream == NULL)
return -1;
if ((m_validData > 0) && (m_readPtr > m_buf)) {
memmove(m_buf, m_readPtr, m_validData);
int ReadBuffer::getData(IOStream* stream) {
if (stream == NULL) return -1;
if ((m_validData > 0) && (m_readPtr > m_buf)) {
memmove(m_buf, m_readPtr, m_validData);
}
// get fresh data into the buffer;
size_t len = m_size - m_validData;
if (len == 0) {
// we need to inc our buffer
size_t new_size = m_size * 2;
unsigned char* new_buf;
if (new_size < m_size) { // overflow check
new_size = INT_MAX;
}
// get fresh data into the buffer;
size_t len = m_size - m_validData;
if (len==0) {
//we need to inc our buffer
size_t new_size = m_size*2;
unsigned char* new_buf;
if (new_size < m_size) { // overflow check
new_size = INT_MAX;
}
new_buf = (unsigned char*)realloc(m_buf, new_size);
if (!new_buf) {
ERR("Failed to alloc %zu bytes for ReadBuffer\n", new_size);
return -1;
}
m_size = new_size;
m_buf = new_buf;
len = m_size - m_validData;
new_buf = (unsigned char*)realloc(m_buf, new_size);
if (!new_buf) {
ERR("Failed to alloc %zu bytes for ReadBuffer\n", new_size);
return -1;
}
m_readPtr = m_buf;
if (NULL != stream->read(m_buf + m_validData, &len)) {
m_validData += len;
return len;
}
return -1;
m_size = new_size;
m_buf = new_buf;
len = m_size - m_validData;
}
m_readPtr = m_buf;
if (NULL != stream->read(m_buf + m_validData, &len)) {
m_validData += len;
return len;
}
return -1;
}
void ReadBuffer::consume(size_t amount)
{
assert(amount <= m_validData);
m_validData -= amount;
m_readPtr += amount;
void ReadBuffer::consume(size_t amount) {
assert(amount <= m_validData);
m_validData -= amount;
m_readPtr += amount;
}

View file

@ -19,17 +19,19 @@
#include "IOStream.h"
class ReadBuffer {
public:
ReadBuffer(size_t bufSize);
~ReadBuffer();
int getData(IOStream *stream); // get fresh data from the stream
unsigned char *buf() { return m_readPtr; } // return the next read location
size_t validData() { return m_validData; } // return the amount of valid data in readptr
void consume(size_t amount); // notify that 'amount' data has been consumed;
private:
unsigned char *m_buf;
unsigned char *m_readPtr;
size_t m_size;
size_t m_validData;
public:
ReadBuffer(size_t bufSize);
~ReadBuffer();
int getData(IOStream *stream); // get fresh data from the stream
unsigned char *buf() { return m_readPtr; } // return the next read location
size_t validData() {
return m_validData;
} // return the amount of valid data in readptr
void consume(size_t amount); // notify that 'amount' data has been consumed;
private:
unsigned char *m_buf;
unsigned char *m_readPtr;
size_t m_size;
size_t m_validData;
};
#endif

View file

@ -41,210 +41,200 @@ static char s_renderAddr[256];
static RenderWindow* s_renderWindow = NULL;
static IOStream *createRenderThread(int p_stream_buffer_size,
static IOStream* createRenderThread(int p_stream_buffer_size,
unsigned int clientFlags);
RENDER_APICALL int RENDER_APIENTRY initLibrary(void)
{
//
// Load EGL Plugin
//
if (!init_egl_dispatch()) {
// Failed to load EGL
printf("Failed to init_egl_dispatch\n");
return false;
}
RENDER_APICALL int RENDER_APIENTRY initLibrary(void) {
//
// Load EGL Plugin
//
if (!init_egl_dispatch()) {
// Failed to load EGL
printf("Failed to init_egl_dispatch\n");
return false;
}
//
// Load GLES Plugin
//
if (!gles1_dispatch_init(&s_gles1)) {
// Failed to load GLES
ERR("Failed to gles1_dispatch_init\n");
return false;
}
//
// Load GLES Plugin
//
if (!gles1_dispatch_init(&s_gles1)) {
// Failed to load GLES
ERR("Failed to gles1_dispatch_init\n");
return false;
}
/* failure to init the GLES2 dispatch table is not fatal */
if (!gles2_dispatch_init(&s_gles2)) {
ERR("Failed to gles2_dispatch_init\n");
return false;
}
/* failure to init the GLES2 dispatch table is not fatal */
if (!gles2_dispatch_init(&s_gles2)) {
ERR("Failed to gles2_dispatch_init\n");
return false;
}
return true;
return true;
}
RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer(
EGLNativeDisplayType native_display, char* addr, size_t addrLen,
emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc) {
set_emugl_crash_reporter(crashfunc);
set_emugl_logger(logfuncs.coarse);
set_emugl_cxt_logger(logfuncs.fine);
//
// Fail if renderer is already initialized
//
if (s_renderThread) {
return false;
}
// kUseThread is used to determine whether the RenderWindow should use
// a separate thread to manage its subwindow GL/GLES context.
// For now, this feature is disabled entirely for the following
// reasons:
//
// - It must be disabled on Windows at all times, otherwise the main window becomes
// unresponsive after a few seconds of user interaction (e.g. trying to
// move it over the desktop). Probably due to the subtle issues around
// input on this platform (input-queue is global, message-queue is
// per-thread). Also, this messes considerably the display of the
// main window when running the executable under Wine.
//
// - On Linux/XGL and OSX/Cocoa, this used to be necessary to avoid corruption
// issues with the GL state of the main window when using the SDL UI.
// After the switch to Qt, this is no longer necessary and may actually cause
// undesired interactions between the UI thread and the RenderWindow thread:
// for example, in a multi-monitor setup the context might be recreated when
// dragging the window between monitors, triggering a Qt-specific callback
// in the context of RenderWindow thread, which will become blocked on the UI
// thread, which may in turn be blocked on something else.
bool kUseThread = false;
//
// initialize the renderer and listen to connections
// on a thread in the current process.
//
s_renderWindow = new RenderWindow(native_display, kUseThread);
if (!s_renderWindow) {
ERR("Could not create rendering window class");
GL_LOG("Could not create rendering window class");
return false;
}
if (!s_renderWindow->isValid()) {
ERR("Could not initialize emulated framebuffer\n");
delete s_renderWindow;
s_renderWindow = NULL;
return false;
}
s_renderThread = RenderServer::create(addr, addrLen);
if (!s_renderThread) {
return false;
}
strncpy(s_renderAddr, addr, sizeof(s_renderAddr));
s_renderThread->start();
GL_LOG("OpenGL renderer initialized successfully");
return true;
}
RENDER_APICALL void RENDER_APIENTRY getHardwareStrings(
const char** vendor,
const char** renderer,
const char** version) {
if (s_renderWindow &&
s_renderWindow->getHardwareStrings(vendor, renderer, version)) {
return;
}
*vendor = *renderer = *version = NULL;
}
RENDER_APICALL int RENDER_APIENTRY stopOpenGLRenderer(void)
{
bool ret = false;
// open a dummy connection to the renderer to make it
// realize the exit request.
// (send the exit request in clientFlags)
IOStream *dummy = createRenderThread(8, IOSTREAM_CLIENT_EXIT_SERVER);
if (!dummy) return false;
if (s_renderThread) {
// wait for the thread to exit
ret = s_renderThread->wait(NULL);
delete s_renderThread;
s_renderThread = NULL;
}
if (s_renderWindow != NULL) {
delete s_renderWindow;
s_renderWindow = NULL;
}
delete dummy;
return ret;
}
RENDER_APICALL bool RENDER_APIENTRY showOpenGLSubwindow(
FBNativeWindowType window_id,
int wx,
int wy,
int ww,
int wh,
int fbw,
int fbh,
float dpr,
float zRot)
{
RenderWindow* window = s_renderWindow;
if (window) {
return window->setupSubWindow(window_id,wx,wy,ww,wh,fbw,fbh,dpr,zRot);
}
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
EGLNativeDisplayType native_display, char* addr, size_t addrLen,
emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc) {
set_emugl_crash_reporter(crashfunc);
set_emugl_logger(logfuncs.coarse);
set_emugl_cxt_logger(logfuncs.fine);
//
// Fail if renderer is already initialized
//
if (s_renderThread) {
return false;
}
// kUseThread is used to determine whether the RenderWindow should use
// a separate thread to manage its subwindow GL/GLES context.
// For now, this feature is disabled entirely for the following
// reasons:
//
// - It must be disabled on Windows at all times, otherwise the main window
// becomes
// unresponsive after a few seconds of user interaction (e.g. trying to
// move it over the desktop). Probably due to the subtle issues around
// input on this platform (input-queue is global, message-queue is
// per-thread). Also, this messes considerably the display of the
// main window when running the executable under Wine.
//
// - On Linux/XGL and OSX/Cocoa, this used to be necessary to avoid corruption
// issues with the GL state of the main window when using the SDL UI.
// After the switch to Qt, this is no longer necessary and may actually
// cause
// undesired interactions between the UI thread and the RenderWindow thread:
// for example, in a multi-monitor setup the context might be recreated when
// dragging the window between monitors, triggering a Qt-specific callback
// in the context of RenderWindow thread, which will become blocked on the
// UI
// thread, which may in turn be blocked on something else.
bool kUseThread = false;
//
// initialize the renderer and listen to connections
// on a thread in the current process.
//
s_renderWindow = new RenderWindow(native_display, kUseThread);
if (!s_renderWindow) {
ERR("Could not create rendering window class");
GL_LOG("Could not create rendering window class");
return false;
}
if (!s_renderWindow->isValid()) {
ERR("Could not initialize emulated framebuffer\n");
delete s_renderWindow;
s_renderWindow = NULL;
return false;
}
s_renderThread = RenderServer::create(addr, addrLen);
if (!s_renderThread) {
return false;
}
strncpy(s_renderAddr, addr, sizeof(s_renderAddr));
s_renderThread->start();
GL_LOG("OpenGL renderer initialized successfully");
return true;
}
RENDER_APICALL bool RENDER_APIENTRY destroyOpenGLSubwindow(void)
{
RenderWindow* window = s_renderWindow;
RENDER_APICALL void RENDER_APIENTRY getHardwareStrings(const char** vendor,
const char** renderer,
const char** version) {
if (s_renderWindow &&
s_renderWindow->getHardwareStrings(vendor, renderer, version)) {
return;
}
*vendor = *renderer = *version = NULL;
}
if (window) {
return window->removeSubWindow();
}
RENDER_APICALL int RENDER_APIENTRY stopOpenGLRenderer(void) {
bool ret = false;
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n",
__FUNCTION__);
return false;
// open a dummy connection to the renderer to make it
// realize the exit request.
// (send the exit request in clientFlags)
IOStream* dummy = createRenderThread(8, IOSTREAM_CLIENT_EXIT_SERVER);
if (!dummy) return false;
if (s_renderThread) {
// wait for the thread to exit
ret = s_renderThread->wait(NULL);
delete s_renderThread;
s_renderThread = NULL;
}
if (s_renderWindow != NULL) {
delete s_renderWindow;
s_renderWindow = NULL;
}
delete dummy;
return ret;
}
RENDER_APICALL bool RENDER_APIENTRY
showOpenGLSubwindow(FBNativeWindowType window_id, int wx, int wy, int ww,
int wh, int fbw, int fbh, float dpr, float zRot) {
RenderWindow* window = s_renderWindow;
if (window) {
return window->setupSubWindow(window_id, wx, wy, ww, wh, fbw, fbh, dpr,
zRot);
}
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n", __FUNCTION__);
return false;
}
RENDER_APICALL bool RENDER_APIENTRY destroyOpenGLSubwindow(void) {
RenderWindow* window = s_renderWindow;
if (window) {
return window->removeSubWindow();
}
// XXX: should be implemented by sending the renderer process
// a request
ERR("%s not implemented for separate renderer process !!!\n", __FUNCTION__);
return false;
}
#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_UNIX
int gRendererStreamMode = DEFAULT_STREAM_MODE;
IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags)
{
SocketStream* stream = NULL;
IOStream* createRenderThread(int p_stream_buffer_size,
unsigned int clientFlags) {
SocketStream* stream = NULL;
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
stream = new TcpStream(p_stream_buffer_size);
} else {
stream = new UnixStream(p_stream_buffer_size);
}
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
stream = new TcpStream(p_stream_buffer_size);
} else {
stream = new UnixStream(p_stream_buffer_size);
}
if (!stream) {
ERR("createRenderThread failed to create stream\n");
return NULL;
}
if (stream->connect(s_renderAddr) < 0) {
ERR("createRenderThread failed to connect\n");
delete stream;
return NULL;
}
if (!stream) {
ERR("createRenderThread failed to create stream\n");
return NULL;
}
if (stream->connect(s_renderAddr) < 0) {
ERR("createRenderThread failed to connect\n");
delete stream;
return NULL;
}
//
// send clientFlags to the renderer
//
unsigned int *pClientFlags =
(unsigned int *)stream->allocBuffer(sizeof(unsigned int));
*pClientFlags = clientFlags;
stream->commitBuffer(sizeof(unsigned int));
//
// send clientFlags to the renderer
//
unsigned int* pClientFlags =
(unsigned int*)stream->allocBuffer(sizeof(unsigned int));
*pClientFlags = clientFlags;
stream->commitBuffer(sizeof(unsigned int));
return stream;
return stream;
}

View file

@ -17,33 +17,24 @@
#include "OpenGLESDispatch/EGLDispatch.h"
RenderContext* RenderContext::create(EGLDisplay display,
EGLConfig config,
EGLContext sharedContext,
bool isGl2) {
const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, isGl2 ? 2 : 1,
EGL_NONE
};
EGLContext context = s_egl.eglCreateContext(
display, config, sharedContext, contextAttribs);
if (context == EGL_NO_CONTEXT) {
return NULL;
}
RenderContext* RenderContext::create(EGLDisplay display, EGLConfig config,
EGLContext sharedContext, bool isGl2) {
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, isGl2 ? 2 : 1,
EGL_NONE};
EGLContext context =
s_egl.eglCreateContext(display, config, sharedContext, contextAttribs);
if (context == EGL_NO_CONTEXT) {
return NULL;
}
return new RenderContext(display, context, isGl2);
return new RenderContext(display, context, isGl2);
}
RenderContext::RenderContext(EGLDisplay display,
EGLContext context,
bool isGl2) :
mDisplay(display),
mContext(context),
mIsGl2(isGl2),
mContextData() {}
RenderContext::RenderContext(EGLDisplay display, EGLContext context, bool isGl2)
: mDisplay(display), mContext(context), mIsGl2(isGl2), mContextData() {}
RenderContext::~RenderContext() {
if (mContext != EGL_NO_CONTEXT) {
s_egl.eglDestroyContext(mDisplay, mContext);
}
if (mContext != EGL_NO_CONTEXT) {
s_egl.eglDestroyContext(mDisplay, mContext);
}
}

View file

@ -16,8 +16,8 @@
#ifndef _LIBRENDER_RENDER_CONTEXT_H
#define _LIBRENDER_RENDER_CONTEXT_H
#include "emugl/common/smart_ptr.h"
#include "GLDecoderContextData.h"
#include "emugl/common/smart_ptr.h"
#include <EGL/egl.h>
@ -25,43 +25,39 @@
// EGLContext, associated with an GLDecoderContextData instance that is
// used to store copies of guest-side arrays.
class RenderContext {
public:
// Create a new RenderContext instance.
// |display| is the host EGLDisplay handle.
// |config| is the host EGLConfig to use.
// |sharedContext| is either EGL_NO_CONTEXT of a host EGLContext handle.
// |isGl2| is true iff the new context will be used with GLESv2, or
// GLESv1 otherwise.
static RenderContext *create(EGLDisplay display,
EGLConfig config,
EGLContext sharedContext,
bool isGL2 = false);
public:
// Create a new RenderContext instance.
// |display| is the host EGLDisplay handle.
// |config| is the host EGLConfig to use.
// |sharedContext| is either EGL_NO_CONTEXT of a host EGLContext handle.
// |isGl2| is true iff the new context will be used with GLESv2, or
// GLESv1 otherwise.
static RenderContext* create(EGLDisplay display, EGLConfig config,
EGLContext sharedContext, bool isGL2 = false);
// Destructor.
~RenderContext();
// Destructor.
~RenderContext();
// Retrieve host EGLContext value.
EGLContext getEGLContext() const { return mContext; }
// Retrieve host EGLContext value.
EGLContext getEGLContext() const { return mContext; }
// Return true iff this is a GLESv2 context.
bool isGL2() const { return mIsGl2; }
// Return true iff this is a GLESv2 context.
bool isGL2() const { return mIsGl2; }
// Retrieve GLDecoderContextData instance reference for this
// RenderContext instance.
GLDecoderContextData& decoderContextData() { return mContextData; }
// Retrieve GLDecoderContextData instance reference for this
// RenderContext instance.
GLDecoderContextData& decoderContextData() { return mContextData; }
private:
RenderContext();
private:
RenderContext();
RenderContext(EGLDisplay display,
EGLContext context,
bool isGl2);
RenderContext(EGLDisplay display, EGLContext context, bool isGl2);
private:
EGLDisplay mDisplay;
EGLContext mContext;
bool mIsGl2;
GLDecoderContextData mContextData;
private:
EGLDisplay mDisplay;
EGLContext mContext;
bool mIsGl2;
GLDecoderContextData mContextData;
};
typedef emugl::SmartPtr<RenderContext> RenderContextPtr;

View file

@ -15,12 +15,12 @@
*/
#include "RenderControl.h"
#include "DispatchTables.h"
#include "RendererConfig.h"
#include "Renderer.h"
#include "RenderThreadInfo.h"
#include "ChecksumCalculatorThreadInfo.h"
#include "DispatchTables.h"
#include "DisplayManager.h"
#include "RenderThreadInfo.h"
#include "Renderer.h"
#include "RendererConfig.h"
#include "OpenGLESDispatch/EGLDispatch.h"
@ -33,471 +33,428 @@
static const GLint rendererVersion = 1;
static std::shared_ptr<anbox::graphics::LayerComposer> composer;
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c)
{
composer = c;
void registerLayerComposer(
const std::shared_ptr<anbox::graphics::LayerComposer> &c) {
composer = c;
}
static GLint rcGetRendererVersion()
{
return rendererVersion;
static GLint rcGetRendererVersion() { return rendererVersion; }
static EGLint rcGetEGLVersion(EGLint *major, EGLint *minor) {
Renderer *fb = Renderer::get();
if (!fb) {
return EGL_FALSE;
}
*major = (EGLint)fb->getCaps().eglMajor;
*minor = (EGLint)fb->getCaps().eglMinor;
return EGL_TRUE;
}
static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor)
{
Renderer *fb = Renderer::get();
if (!fb) {
return EGL_FALSE;
}
*major = (EGLint)fb->getCaps().eglMajor;
*minor = (EGLint)fb->getCaps().eglMinor;
static EGLint rcQueryEGLString(EGLenum name, void *buffer, EGLint bufferSize) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return EGL_TRUE;
const char *str = s_egl.eglQueryString(fb->getDisplay(), name);
if (!str) {
return 0;
}
int len = strlen(str) + 1;
if (!buffer || len > bufferSize) {
return -len;
}
strcpy((char *)buffer, str);
return len;
}
static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
static EGLint rcGetGLString(EGLenum name, void *buffer, EGLint bufferSize) {
RenderThreadInfo *tInfo = RenderThreadInfo::get();
std::string result;
if (tInfo && tInfo->currContext) {
const char *str = nullptr;
if (tInfo->currContext->isGL2())
str = reinterpret_cast<const char *>(s_gles2.glGetString(name));
else
str = reinterpret_cast<const char *>(s_gles1.glGetString(name));
if (str) result += str;
}
// We're forcing version 2.0 no matter what the host provides as
// our emulation layer isn't prepared for anything newer (yet).
// This goes in parallel with filtering the extension set for
// any unwanted extensions. If we don't force the right version
// here certain parts of the system will assume API conditions
// which aren't met.
if (name == GL_VERSION)
result = "OpenGL ES 2.0";
else if (name == GL_EXTENSIONS) {
std::string approved_extensions = result;
std::vector<std::string> unsupported_extensions = {
// Leaving this enabled gives crippeled text rendering when
// using the host mesa GLES drivers.
"GL_EXT_unpack_subimage",
};
for (const auto &extension : unsupported_extensions) {
size_t start_pos = approved_extensions.find(extension);
if (start_pos == std::string::npos) continue;
approved_extensions.replace(start_pos, extension.length(), "");
}
const char *str = s_egl.eglQueryString(fb->getDisplay(), name);
if (!str) {
return 0;
}
result = approved_extensions;
}
int len = strlen(str) + 1;
if (!buffer || len > bufferSize) {
return -len;
}
int nextBufferSize = result.size() + 1;
strcpy((char *)buffer, str);
return len;
if (!buffer || nextBufferSize > bufferSize) return -nextBufferSize;
snprintf(static_cast<char *>(buffer), nextBufferSize, "%s", result.c_str());
return nextBufferSize;
}
static EGLint rcGetGLString(EGLenum name, void* buffer, EGLint bufferSize)
{
RenderThreadInfo *tInfo = RenderThreadInfo::get();
std::string result;
static EGLint rcGetNumConfigs(uint32_t *p_numAttribs) {
int numConfigs = 0, numAttribs = 0;
if (tInfo && tInfo->currContext) {
const char *str = nullptr;
if (tInfo->currContext->isGL2())
str = reinterpret_cast<const char*>(s_gles2.glGetString(name));
else
str = reinterpret_cast<const char*>(s_gles1.glGetString(name));
if (str)
result += str;
}
// We're forcing version 2.0 no matter what the host provides as
// our emulation layer isn't prepared for anything newer (yet).
// This goes in parallel with filtering the extension set for
// any unwanted extensions. If we don't force the right version
// here certain parts of the system will assume API conditions
// which aren't met.
if (name == GL_VERSION)
result = "OpenGL ES 2.0";
else if (name == GL_EXTENSIONS) {
std::string approved_extensions = result;
std::vector<std::string> unsupported_extensions = {
// Leaving this enabled gives crippeled text rendering when
// using the host mesa GLES drivers.
"GL_EXT_unpack_subimage",
};
for (const auto &extension : unsupported_extensions) {
size_t start_pos = approved_extensions.find(extension);
if(start_pos == std::string::npos)
continue;
approved_extensions.replace(start_pos, extension.length(), "");
}
result = approved_extensions;
}
int nextBufferSize = result.size() + 1;
if (!buffer || nextBufferSize > bufferSize)
return -nextBufferSize;
snprintf(static_cast<char*>(buffer), nextBufferSize, "%s", result.c_str());
return nextBufferSize;
Renderer::get()->getConfigs()->getPackInfo(&numConfigs, &numAttribs);
if (p_numAttribs) {
*p_numAttribs = static_cast<uint32_t>(numAttribs);
}
return numConfigs;
}
static EGLint rcGetNumConfigs(uint32_t* p_numAttribs)
{
int numConfigs = 0, numAttribs = 0;
Renderer::get()->getConfigs()->getPackInfo(&numConfigs, &numAttribs);
if (p_numAttribs) {
*p_numAttribs = static_cast<uint32_t>(numAttribs);
}
return numConfigs;
static EGLint rcGetConfigs(uint32_t bufSize, GLuint *buffer) {
GLuint bufferSize = (GLuint)bufSize;
return Renderer::get()->getConfigs()->packConfigs(bufferSize, buffer);
}
static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer)
{
GLuint bufferSize = (GLuint)bufSize;
return Renderer::get()->getConfigs()->packConfigs(bufferSize, buffer);
static EGLint rcChooseConfig(EGLint *attribs, uint32_t attribs_size,
uint32_t *configs, uint32_t configs_size) {
Renderer *fb = Renderer::get();
if (!fb || attribs_size == 0) {
return 0;
}
return fb->getConfigs()->chooseConfig(attribs, (EGLint *)configs,
(EGLint)configs_size);
}
static EGLint rcChooseConfig(EGLint *attribs,
uint32_t attribs_size,
uint32_t *configs,
uint32_t configs_size)
{
Renderer *fb = Renderer::get();
if (!fb || attribs_size==0) {
return 0;
}
static EGLint rcGetFBParam(EGLint param) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return fb->getConfigs()->chooseConfig(
attribs, (EGLint*)configs, (EGLint)configs_size);
EGLint ret = 0;
switch (param) {
case FB_WIDTH:
ret = DisplayManager::get()->display_info().horizontal_resolution;
break;
case FB_HEIGHT:
ret = DisplayManager::get()->display_info().vertical_resolution;
break;
case FB_XDPI:
ret = 72; // XXX: should be implemented
break;
case FB_YDPI:
ret = 72; // XXX: should be implemented
break;
case FB_FPS:
ret = 60;
break;
case FB_MIN_SWAP_INTERVAL:
ret = 1; // XXX: should be implemented
break;
case FB_MAX_SWAP_INTERVAL:
ret = 1; // XXX: should be implemented
break;
default:
break;
}
return ret;
}
static EGLint rcGetFBParam(EGLint param)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
static uint32_t rcCreateContext(uint32_t config, uint32_t share,
uint32_t glVersion) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
EGLint ret = 0;
switch(param) {
case FB_WIDTH:
ret = DisplayManager::get()->display_info().horizontal_resolution;
break;
case FB_HEIGHT:
ret = DisplayManager::get()->display_info().vertical_resolution;
break;
case FB_XDPI:
ret = 72; // XXX: should be implemented
break;
case FB_YDPI:
ret = 72; // XXX: should be implemented
break;
case FB_FPS:
ret = 60;
break;
case FB_MIN_SWAP_INTERVAL:
ret = 1; // XXX: should be implemented
break;
case FB_MAX_SWAP_INTERVAL:
ret = 1; // XXX: should be implemented
break;
default:
break;
}
return ret;
// To make it consistent with the guest, create GLES2 context when GL
// version==2 or 3
HandleType ret =
fb->createRenderContext(config, share, glVersion == 2 || glVersion == 3);
return ret;
}
static uint32_t rcCreateContext(uint32_t config,
uint32_t share, uint32_t glVersion)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
static void rcDestroyContext(uint32_t context) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
// To make it consistent with the guest, create GLES2 context when GL
// version==2 or 3
HandleType ret = fb->createRenderContext(config, share, glVersion == 2 || glVersion == 3);
return ret;
fb->DestroyRenderContext(context);
}
static void rcDestroyContext(uint32_t context)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
static uint32_t rcCreateWindowSurface(uint32_t config, uint32_t width,
uint32_t height) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
fb->DestroyRenderContext(context);
return fb->createWindowSurface(config, width, height);
}
static uint32_t rcCreateWindowSurface(uint32_t config,
uint32_t width, uint32_t height)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
static void rcDestroyWindowSurface(uint32_t windowSurface) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
return fb->createWindowSurface(config, width, height);
fb->DestroyWindowSurface(windowSurface);
}
static void rcDestroyWindowSurface(uint32_t windowSurface)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
static uint32_t rcCreateColorBuffer(uint32_t width, uint32_t height,
GLenum internalFormat) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
fb->DestroyWindowSurface( windowSurface );
return fb->createColorBuffer(width, height, internalFormat);
}
static uint32_t rcCreateColorBuffer(uint32_t width,
uint32_t height, GLenum internalFormat)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return fb->createColorBuffer(width, height, internalFormat);
}
static int rcOpenColorBuffer2(uint32_t colorbuffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
return fb->openColorBuffer( colorbuffer );
static int rcOpenColorBuffer2(uint32_t colorbuffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
return fb->openColorBuffer(colorbuffer);
}
// Deprecated, kept for compatibility with old system images only.
// Use rcOpenColorBuffer2 instead.
static void rcOpenColorBuffer(uint32_t colorbuffer)
{
(void) rcOpenColorBuffer2(colorbuffer);
static void rcOpenColorBuffer(uint32_t colorbuffer) {
(void)rcOpenColorBuffer2(colorbuffer);
}
static void rcCloseColorBuffer(uint32_t colorbuffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->closeColorBuffer( colorbuffer );
static void rcCloseColorBuffer(uint32_t colorbuffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->closeColorBuffer(colorbuffer);
}
static int rcFlushWindowColorBuffer(uint32_t windowSurface)
{
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
if (!fb->flushWindowSurfaceColorBuffer(windowSurface)) {
return -1;
}
return 0;
static int rcFlushWindowColorBuffer(uint32_t windowSurface) {
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
if (!fb->flushWindowSurfaceColorBuffer(windowSurface)) {
return -1;
}
return 0;
}
static void rcSetWindowColorBuffer(uint32_t windowSurface,
uint32_t colorBuffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->setWindowSurfaceColorBuffer(windowSurface, colorBuffer);
uint32_t colorBuffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->setWindowSurfaceColorBuffer(windowSurface, colorBuffer);
}
static EGLint rcMakeCurrent(uint32_t context,
uint32_t drawSurf, uint32_t readSurf)
{
Renderer *fb = Renderer::get();
if (!fb) {
return EGL_FALSE;
}
static EGLint rcMakeCurrent(uint32_t context, uint32_t drawSurf,
uint32_t readSurf) {
Renderer *fb = Renderer::get();
if (!fb) {
return EGL_FALSE;
}
bool ret = fb->bindContext(context, drawSurf, readSurf);
bool ret = fb->bindContext(context, drawSurf, readSurf);
return (ret ? EGL_TRUE : EGL_FALSE);
return (ret ? EGL_TRUE : EGL_FALSE);
}
static void rcFBPost(uint32_t colorBuffer)
{
WARNING("Not implemented");
static void rcFBPost(uint32_t colorBuffer) { WARNING("Not implemented"); }
static void rcFBSetSwapInterval(EGLint interval) {
// XXX: TBD - should be implemented
}
static void rcFBSetSwapInterval(EGLint interval)
{
// XXX: TBD - should be implemented
static void rcBindTexture(uint32_t colorBuffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->bindColorBufferToTexture(colorBuffer);
}
static void rcBindTexture(uint32_t colorBuffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
static void rcBindRenderbuffer(uint32_t colorBuffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->bindColorBufferToTexture(colorBuffer);
fb->bindColorBufferToRenderbuffer(colorBuffer);
}
static void rcBindRenderbuffer(uint32_t colorBuffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->bindColorBufferToRenderbuffer(colorBuffer);
static EGLint rcColorBufferCacheFlush(uint32_t colorBuffer, EGLint postCount,
int forRead) {
// XXX: TBD - should be implemented
return 0;
}
static EGLint rcColorBufferCacheFlush(uint32_t colorBuffer,
EGLint postCount, int forRead)
{
// XXX: TBD - should be implemented
return 0;
static void rcReadColorBuffer(uint32_t colorBuffer, GLint x, GLint y,
GLint width, GLint height, GLenum format,
GLenum type, void *pixels) {
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
fb->readColorBuffer(colorBuffer, x, y, width, height, format, type, pixels);
}
static void rcReadColorBuffer(uint32_t colorBuffer,
GLint x, GLint y,
GLint width, GLint height,
GLenum format, GLenum type, void* pixels)
{
Renderer *fb = Renderer::get();
if (!fb) {
return;
}
static int rcUpdateColorBuffer(uint32_t colorBuffer, GLint x, GLint y,
GLint width, GLint height, GLenum format,
GLenum type, void *pixels) {
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
fb->readColorBuffer(colorBuffer, x, y, width, height, format, type, pixels);
fb->updateColorBuffer(colorBuffer, x, y, width, height, format, type, pixels);
return 0;
}
static int rcUpdateColorBuffer(uint32_t colorBuffer,
GLint x, GLint y,
GLint width, GLint height,
GLenum format, GLenum type, void* pixels)
{
Renderer *fb = Renderer::get();
if (!fb) {
return -1;
}
fb->updateColorBuffer(colorBuffer, x, y, width, height, format, type, pixels);
static uint32_t rcCreateClientImage(uint32_t context, EGLenum target,
GLuint buffer) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return fb->createClientImage(context, target, buffer);
}
static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
static int rcDestroyClientImage(uint32_t image) {
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return fb->createClientImage(context, target, buffer);
}
static int rcDestroyClientImage(uint32_t image)
{
Renderer *fb = Renderer::get();
if (!fb) {
return 0;
}
return fb->destroyClientImage(image);
return fb->destroyClientImage(image);
}
static void rcSelectChecksumCalculator(uint32_t protocol, uint32_t reserved) {
ChecksumCalculatorThreadInfo::setVersion(protocol);
ChecksumCalculatorThreadInfo::setVersion(protocol);
}
int rcGetNumDisplays() {
return 1;
}
int rcGetNumDisplays() { return 1; }
int rcGetDisplayWidth(uint32_t display_id) {
printf("%s: display_id=%d\n", __func__, display_id);
return DisplayManager::get()->display_info().horizontal_resolution;
printf("%s: display_id=%d\n", __func__, display_id);
return DisplayManager::get()->display_info().horizontal_resolution;
}
int rcGetDisplayHeight(uint32_t display_id) {
printf("%s: display_id=%d\n", __func__, display_id);
return DisplayManager::get()->display_info().vertical_resolution;
printf("%s: display_id=%d\n", __func__, display_id);
return DisplayManager::get()->display_info().vertical_resolution;
}
int rcGetDisplayDpiX(uint32_t display_id) {
printf("%s: display_id=%d\n", __func__, display_id);
return 120;
printf("%s: display_id=%d\n", __func__, display_id);
return 120;
}
int rcGetDisplayDpiY(uint32_t display_id) {
printf("%s: display_id=%d\n", __func__, display_id);
return 120;
printf("%s: display_id=%d\n", __func__, display_id);
return 120;
}
int rcGetDisplayVsyncPeriod(uint32_t display_id) {
printf("%s: display_id=%d\n", __func__, display_id);
return 1;
printf("%s: display_id=%d\n", __func__, display_id);
return 1;
}
static std::vector<Renderable> frame_layers;
bool is_layer_blacklisted(const std::string &name) {
static std::vector<std::string> blacklist = {
"Sprite",
};
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
static std::vector<std::string> blacklist = {
"Sprite",
};
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
}
void rcPostLayer(const char *name, uint32_t color_buffer,
int32_t sourceCropLeft, int32_t sourceCropTop,
int32_t sourceCropRight, int32_t sourceCropBottom,
int32_t displayFrameLeft, int32_t displayFrameTop,
int32_t displayFrameRight, int32_t displayFrameBottom)
{
Renderable r{
name,
color_buffer,
{displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom},
{sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom}
};
frame_layers.push_back(r);
int32_t displayFrameRight, int32_t displayFrameBottom) {
Renderable r{
name,
color_buffer,
{displayFrameLeft, displayFrameTop, displayFrameRight,
displayFrameBottom},
{sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom}};
frame_layers.push_back(r);
}
void rcPostAllLayersDone()
{
if (composer)
composer->submit_layers(frame_layers);
void rcPostAllLayersDone() {
if (composer) composer->submit_layers(frame_layers);
frame_layers.clear();
frame_layers.clear();
}
void initRenderControlContext(renderControl_decoder_context_t *dec)
{
dec->rcGetRendererVersion = rcGetRendererVersion;
dec->rcGetEGLVersion = rcGetEGLVersion;
dec->rcQueryEGLString = rcQueryEGLString;
dec->rcGetGLString = rcGetGLString;
dec->rcGetNumConfigs = rcGetNumConfigs;
dec->rcGetConfigs = rcGetConfigs;
dec->rcChooseConfig = rcChooseConfig;
dec->rcGetFBParam = rcGetFBParam;
dec->rcCreateContext = rcCreateContext;
dec->rcDestroyContext = rcDestroyContext;
dec->rcCreateWindowSurface = rcCreateWindowSurface;
dec->rcDestroyWindowSurface = rcDestroyWindowSurface;
dec->rcCreateColorBuffer = rcCreateColorBuffer;
dec->rcOpenColorBuffer = rcOpenColorBuffer;
dec->rcCloseColorBuffer = rcCloseColorBuffer;
dec->rcSetWindowColorBuffer = rcSetWindowColorBuffer;
dec->rcFlushWindowColorBuffer = rcFlushWindowColorBuffer;
dec->rcMakeCurrent = rcMakeCurrent;
dec->rcFBPost = rcFBPost;
dec->rcFBSetSwapInterval = rcFBSetSwapInterval;
dec->rcBindTexture = rcBindTexture;
dec->rcBindRenderbuffer = rcBindRenderbuffer;
dec->rcColorBufferCacheFlush = rcColorBufferCacheFlush;
dec->rcReadColorBuffer = rcReadColorBuffer;
dec->rcUpdateColorBuffer = rcUpdateColorBuffer;
dec->rcOpenColorBuffer2 = rcOpenColorBuffer2;
dec->rcCreateClientImage = rcCreateClientImage;
dec->rcDestroyClientImage = rcDestroyClientImage;
dec->rcSelectChecksumCalculator = rcSelectChecksumCalculator;
dec->rcGetNumDisplays = rcGetNumDisplays;
dec->rcGetDisplayWidth = rcGetDisplayWidth;
dec->rcGetDisplayHeight = rcGetDisplayHeight;
dec->rcGetDisplayDpiX = rcGetDisplayDpiX;
dec->rcGetDisplayDpiY = rcGetDisplayDpiY;
dec->rcGetDisplayVsyncPeriod = rcGetDisplayVsyncPeriod;
dec->rcPostLayer = rcPostLayer;
dec->rcPostAllLayersDone = rcPostAllLayersDone;
void initRenderControlContext(renderControl_decoder_context_t *dec) {
dec->rcGetRendererVersion = rcGetRendererVersion;
dec->rcGetEGLVersion = rcGetEGLVersion;
dec->rcQueryEGLString = rcQueryEGLString;
dec->rcGetGLString = rcGetGLString;
dec->rcGetNumConfigs = rcGetNumConfigs;
dec->rcGetConfigs = rcGetConfigs;
dec->rcChooseConfig = rcChooseConfig;
dec->rcGetFBParam = rcGetFBParam;
dec->rcCreateContext = rcCreateContext;
dec->rcDestroyContext = rcDestroyContext;
dec->rcCreateWindowSurface = rcCreateWindowSurface;
dec->rcDestroyWindowSurface = rcDestroyWindowSurface;
dec->rcCreateColorBuffer = rcCreateColorBuffer;
dec->rcOpenColorBuffer = rcOpenColorBuffer;
dec->rcCloseColorBuffer = rcCloseColorBuffer;
dec->rcSetWindowColorBuffer = rcSetWindowColorBuffer;
dec->rcFlushWindowColorBuffer = rcFlushWindowColorBuffer;
dec->rcMakeCurrent = rcMakeCurrent;
dec->rcFBPost = rcFBPost;
dec->rcFBSetSwapInterval = rcFBSetSwapInterval;
dec->rcBindTexture = rcBindTexture;
dec->rcBindRenderbuffer = rcBindRenderbuffer;
dec->rcColorBufferCacheFlush = rcColorBufferCacheFlush;
dec->rcReadColorBuffer = rcReadColorBuffer;
dec->rcUpdateColorBuffer = rcUpdateColorBuffer;
dec->rcOpenColorBuffer2 = rcOpenColorBuffer2;
dec->rcCreateClientImage = rcCreateClientImage;
dec->rcDestroyClientImage = rcDestroyClientImage;
dec->rcSelectChecksumCalculator = rcSelectChecksumCalculator;
dec->rcGetNumDisplays = rcGetNumDisplays;
dec->rcGetDisplayWidth = rcGetDisplayWidth;
dec->rcGetDisplayHeight = rcGetDisplayHeight;
dec->rcGetDisplayDpiX = rcGetDisplayDpiX;
dec->rcGetDisplayDpiY = rcGetDisplayDpiY;
dec->rcGetDisplayVsyncPeriod = rcGetDisplayVsyncPeriod;
dec->rcPostLayer = rcPostLayer;
dec->rcPostAllLayersDone = rcPostAllLayersDone;
}

View file

@ -23,10 +23,11 @@
namespace anbox {
namespace graphics {
class LayerComposer;
} // namespace graphics
} // namespace anbox
} // namespace graphics
} // namespace anbox
void initRenderControlContext(renderControl_decoder_context_t *dec);
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c);
void registerLayerComposer(
const std::shared_ptr<anbox::graphics::LayerComposer> &c);
#endif

View file

@ -15,11 +15,11 @@
*/
#include "RenderServer.h"
#include <pthread.h>
#include <signal.h>
#include "RenderThread.h"
#include "TcpStream.h"
#include "UnixStream.h"
#include <signal.h>
#include <pthread.h>
#include "OpenglRender/render_api.h"
@ -29,123 +29,109 @@
typedef std::set<RenderThread *> RenderThreadsSet;
RenderServer::RenderServer() :
m_lock(),
m_listenSock(NULL),
m_exiting(false)
{
}
RenderServer::~RenderServer()
{
delete m_listenSock;
}
RenderServer::RenderServer() : m_lock(), m_listenSock(NULL), m_exiting(false) {}
RenderServer::~RenderServer() { delete m_listenSock; }
extern "C" int gRendererStreamMode;
RenderServer *RenderServer::create(char* addr, size_t addrLen)
{
RenderServer *server = new RenderServer();
if (!server) {
return NULL;
}
RenderServer *RenderServer::create(char *addr, size_t addrLen) {
RenderServer *server = new RenderServer();
if (!server) {
return NULL;
}
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
server->m_listenSock = new TcpStream();
} else {
server->m_listenSock = new UnixStream();
}
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
server->m_listenSock = new TcpStream();
} else {
server->m_listenSock = new UnixStream();
}
char addrstr[SocketStream::MAX_ADDRSTR_LEN];
if (server->m_listenSock->listen(addrstr) < 0) {
ERR("RenderServer::create failed to listen\n");
delete server;
return NULL;
}
char addrstr[SocketStream::MAX_ADDRSTR_LEN];
if (server->m_listenSock->listen(addrstr) < 0) {
ERR("RenderServer::create failed to listen\n");
delete server;
return NULL;
}
size_t len = strlen(addrstr) + 1;
if (len > addrLen) {
ERR("RenderServer address name too big for provided buffer: %zu > %zu\n",
len, addrLen);
delete server;
return NULL;
}
memcpy(addr, addrstr, len);
size_t len = strlen(addrstr) + 1;
if (len > addrLen) {
ERR("RenderServer address name too big for provided buffer: %zu > %zu\n",
len, addrLen);
delete server;
return NULL;
}
memcpy(addr, addrstr, len);
return server;
return server;
}
intptr_t RenderServer::main()
{
RenderThreadsSet threads;
intptr_t RenderServer::main() {
RenderThreadsSet threads;
while(1) {
SocketStream *stream = m_listenSock->accept();
if (!stream) {
fprintf(stderr,"Error accepting gles connection, ignoring.\n");
continue;
}
while (1) {
SocketStream *stream = m_listenSock->accept();
if (!stream) {
fprintf(stderr, "Error accepting gles connection, ignoring.\n");
continue;
}
unsigned int clientFlags;
if (!stream->readFully(&clientFlags, sizeof(unsigned int))) {
fprintf(stderr,"Error reading clientFlags\n");
delete stream;
continue;
}
unsigned int clientFlags;
if (!stream->readFully(&clientFlags, sizeof(unsigned int))) {
fprintf(stderr, "Error reading clientFlags\n");
delete stream;
continue;
}
// check if we have been requested to exit while waiting on accept
if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) {
m_exiting = true;
delete stream;
break;
}
// check if we have been requested to exit while waiting on accept
if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) {
m_exiting = true;
delete stream;
break;
}
RenderThread *rt = RenderThread::create(stream, &m_lock);
if (!rt) {
fprintf(stderr,"Failed to create RenderThread\n");
delete stream;
} else if (!rt->start()) {
fprintf(stderr,"Failed to start RenderThread\n");
delete rt;
delete stream;
}
//
// remove from the threads list threads which are
// no longer running
//
for (RenderThreadsSet::iterator n,t = threads.begin();
t != threads.end();
t = n) {
// first find next iterator
n = t;
n++;
// delete and erase the current iterator
// if thread is no longer running
if ((*t)->isFinished()) {
delete (*t);
threads.erase(t);
}
}
// if the thread has been created and started, insert it to the list
if (rt)
threads.insert(rt);
RenderThread *rt = RenderThread::create(stream, &m_lock);
if (!rt) {
fprintf(stderr, "Failed to create RenderThread\n");
delete stream;
} else if (!rt->start()) {
fprintf(stderr, "Failed to start RenderThread\n");
delete rt;
delete stream;
}
//
// Wait for all threads to finish
// remove from the threads list threads which are
// no longer running
//
for (RenderThreadsSet::iterator t = threads.begin();
t != threads.end();
t++) {
(*t)->forceStop();
(*t)->wait(NULL);
for (RenderThreadsSet::iterator n, t = threads.begin(); t != threads.end();
t = n) {
// first find next iterator
n = t;
n++;
// delete and erase the current iterator
// if thread is no longer running
if ((*t)->isFinished()) {
delete (*t);
threads.erase(t);
}
}
threads.clear();
return 0;
// if the thread has been created and started, insert it to the list
if (rt) threads.insert(rt);
}
//
// Wait for all threads to finish
//
for (RenderThreadsSet::iterator t = threads.begin(); t != threads.end();
t++) {
(*t)->forceStop();
(*t)->wait(NULL);
delete (*t);
}
threads.clear();
return 0;
}

View file

@ -20,23 +20,22 @@
#include "emugl/common/mutex.h"
#include "emugl/common/thread.h"
class RenderServer : public emugl::Thread
{
public:
static RenderServer *create(char* addr, size_t addrLen);
virtual ~RenderServer();
class RenderServer : public emugl::Thread {
public:
static RenderServer *create(char *addr, size_t addrLen);
virtual ~RenderServer();
virtual intptr_t main();
virtual intptr_t main();
bool isExiting() const { return m_exiting; }
bool isExiting() const { return m_exiting; }
private:
RenderServer();
private:
RenderServer();
private:
emugl::Mutex m_lock;
SocketStream *m_listenSock;
bool m_exiting;
private:
emugl::Mutex m_lock;
SocketStream *m_listenSock;
bool m_exiting;
};
#endif

View file

@ -15,107 +15,102 @@
*/
#include "RenderThread.h"
#include "Renderer.h"
#include "ReadBuffer.h"
#include "RenderControl.h"
#include "RenderThreadInfo.h"
#include "Renderer.h"
#include "TimeUtils.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#include "OpenGLESDispatch/GLESv1Dispatch.h"
#include "../../../shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "OpenGLESDispatch/GLESv1Dispatch.h"
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#define STREAM_BUFFER_SIZE 4*1024*1024
#define STREAM_BUFFER_SIZE 4 * 1024 * 1024
RenderThread::RenderThread(IOStream *stream, emugl::Mutex *lock) :
emugl::Thread(),
m_lock(lock),
m_stream(stream) {}
RenderThread::RenderThread(IOStream *stream, emugl::Mutex *lock)
: emugl::Thread(), m_lock(lock), m_stream(stream) {}
RenderThread::~RenderThread() {
delete m_stream;
}
RenderThread::~RenderThread() { delete m_stream; }
// static
RenderThread* RenderThread::create(IOStream *stream, emugl::Mutex *lock) {
return new RenderThread(stream, lock);
RenderThread *RenderThread::create(IOStream *stream, emugl::Mutex *lock) {
return new RenderThread(stream, lock);
}
void RenderThread::forceStop() {
m_stream->forceStop();
}
void RenderThread::forceStop() { m_stream->forceStop(); }
intptr_t RenderThread::main() {
RenderThreadInfo tInfo;
ChecksumCalculatorThreadInfo tChecksumInfo;
RenderThreadInfo tInfo;
ChecksumCalculatorThreadInfo tChecksumInfo;
//
// initialize decoders
//
tInfo.m_glDec.initGL(gles1_dispatch_get_proc_func, NULL);
tInfo.m_gl2Dec.initGL(gles2_dispatch_get_proc_func, NULL);
initRenderControlContext(&tInfo.m_rcDec);
//
// initialize decoders
//
tInfo.m_glDec.initGL(gles1_dispatch_get_proc_func, NULL);
tInfo.m_gl2Dec.initGL(gles2_dispatch_get_proc_func, NULL);
initRenderControlContext(&tInfo.m_rcDec);
ReadBuffer readBuf(STREAM_BUFFER_SIZE);
while (1) {
int stat = readBuf.getData(m_stream);
if (stat <= 0) {
break;
}
bool progress;
do {
progress = false;
m_lock->lock();
//
// try to process some of the command buffer using the GLESv1 decoder
//
size_t last = tInfo.m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
progress = true;
readBuf.consume(last);
}
//
// try to process some of the command buffer using the GLESv2 decoder
//
last = tInfo.m_gl2Dec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
progress = true;
readBuf.consume(last);
}
//
// try to process some of the command buffer using the
// renderControl decoder
//
last = tInfo.m_rcDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
readBuf.consume(last);
progress = true;
}
m_lock->unlock();
} while( progress );
ReadBuffer readBuf(STREAM_BUFFER_SIZE);
while (1) {
int stat = readBuf.getData(m_stream);
if (stat <= 0) {
break;
}
//
// Release references to the current thread's context/surfaces if any
//
Renderer::get()->bindContext(0, 0, 0);
if (tInfo.currContext || tInfo.currDrawSurf || tInfo.currReadSurf) {
fprintf(stderr, "ERROR: RenderThread exiting with current context/surfaces\n");
}
bool progress;
do {
progress = false;
Renderer::get()->drainWindowSurface();
m_lock->lock();
//
// try to process some of the command buffer using the GLESv1 decoder
//
size_t last =
tInfo.m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
progress = true;
readBuf.consume(last);
}
Renderer::get()->drainRenderContext();
//
// try to process some of the command buffer using the GLESv2 decoder
//
last =
tInfo.m_gl2Dec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
progress = true;
readBuf.consume(last);
}
return 0;
//
// try to process some of the command buffer using the
// renderControl decoder
//
last = tInfo.m_rcDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
readBuf.consume(last);
progress = true;
}
m_lock->unlock();
} while (progress);
}
//
// Release references to the current thread's context/surfaces if any
//
Renderer::get()->bindContext(0, 0, 0);
if (tInfo.currContext || tInfo.currDrawSurf || tInfo.currReadSurf) {
fprintf(stderr,
"ERROR: RenderThread exiting with current context/surfaces\n");
}
Renderer::get()->drainWindowSurface();
Renderer::get()->drainRenderContext();
return 0;
}

View file

@ -24,35 +24,35 @@
// A class used to model a thread of the RenderServer. Each one of them
// handles a single guest client / protocol byte stream.
class RenderThread : public emugl::Thread {
public:
// Create a new RenderThread instance.
// |stream| is an input stream that will be read from the thread,
// and deleted by it when it exits.
// |mutex| is a pointer to a shared mutex used to serialize
// decoding operations between all threads.
// TODO(digit): Why is this needed here? Shouldn't this be handled
// by the decoders themselves or at a lower-level?
static RenderThread* create(IOStream* stream, emugl::Mutex* mutex);
public:
// Create a new RenderThread instance.
// |stream| is an input stream that will be read from the thread,
// and deleted by it when it exits.
// |mutex| is a pointer to a shared mutex used to serialize
// decoding operations between all threads.
// TODO(digit): Why is this needed here? Shouldn't this be handled
// by the decoders themselves or at a lower-level?
static RenderThread* create(IOStream* stream, emugl::Mutex* mutex);
// Destructor.
virtual ~RenderThread();
// Destructor.
virtual ~RenderThread();
// Returns true iff the thread has finished.
// Note that this also means that the thread's stack has been
bool isFinished() { return tryWait(NULL); }
// Returns true iff the thread has finished.
// Note that this also means that the thread's stack has been
bool isFinished() { return tryWait(NULL); }
// Force a thread to stop.
void forceStop();
// Force a thread to stop.
void forceStop();
private:
RenderThread(); // No default constructor
private:
RenderThread(); // No default constructor
RenderThread(IOStream* stream, emugl::Mutex* mutex);
RenderThread(IOStream* stream, emugl::Mutex* mutex);
virtual intptr_t main();
virtual intptr_t main();
emugl::Mutex* m_lock;
IOStream* m_stream;
emugl::Mutex* m_lock;
IOStream* m_stream;
};
#endif

View file

@ -22,22 +22,18 @@
namespace {
class ThreadInfoStore : public ::emugl::ThreadStore {
public:
ThreadInfoStore() : ::emugl::ThreadStore(NULL) {}
public:
ThreadInfoStore() : ::emugl::ThreadStore(NULL) {}
};
} // namespace
static ::emugl::LazyInstance<ThreadInfoStore> s_tls = LAZY_INSTANCE_INIT;
RenderThreadInfo::RenderThreadInfo() {
s_tls->set(this);
}
RenderThreadInfo::RenderThreadInfo() { s_tls->set(this); }
RenderThreadInfo::~RenderThreadInfo() {
s_tls->set(NULL);
}
RenderThreadInfo::~RenderThreadInfo() { s_tls->set(NULL); }
RenderThreadInfo* RenderThreadInfo::get() {
return static_cast<RenderThreadInfo*>(s_tls->get());
return static_cast<RenderThreadInfo*>(s_tls->get());
}

View file

@ -16,10 +16,10 @@
#ifndef _LIB_OPENGL_RENDER_THREAD_INFO_H
#define _LIB_OPENGL_RENDER_THREAD_INFO_H
#include "RenderContext.h"
#include "WindowSurface.h"
#include "GLESv1Decoder.h"
#include "GLESv2Decoder.h"
#include "RenderContext.h"
#include "WindowSurface.h"
#include "renderControl_dec.h"
#include <set>
@ -30,31 +30,31 @@ typedef std::set<HandleType> WindowSurfaceSet;
// A class used to model the state of each RenderThread related
struct RenderThreadInfo {
// Create new instance. Only call this once per thread.
// Future callls to get() will return this instance until
// it is destroyed.
RenderThreadInfo();
// Create new instance. Only call this once per thread.
// Future callls to get() will return this instance until
// it is destroyed.
RenderThreadInfo();
// Destructor.
~RenderThreadInfo();
// Destructor.
~RenderThreadInfo();
// Return the current thread's instance, if any, or NULL.
static RenderThreadInfo* get();
// Return the current thread's instance, if any, or NULL.
static RenderThreadInfo* get();
// Current EGL context, draw surface and read surface.
RenderContextPtr currContext;
WindowSurfacePtr currDrawSurf;
WindowSurfacePtr currReadSurf;
// Current EGL context, draw surface and read surface.
RenderContextPtr currContext;
WindowSurfacePtr currDrawSurf;
WindowSurfacePtr currReadSurf;
// Decoder states.
GLESv1Decoder m_glDec;
GLESv2Decoder m_gl2Dec;
renderControl_decoder_context_t m_rcDec;
// Decoder states.
GLESv1Decoder m_glDec;
GLESv2Decoder m_gl2Dec;
renderControl_decoder_context_t m_rcDec;
// all the contexts that are created by this render thread
ThreadContextSet m_contextSet;
// all the window surfaces that are created by this render thread
WindowSurfaceSet m_windowSet;
// all the contexts that are created by this render thread
ThreadContextSet m_contextSet;
// all the window surfaces that are created by this render thread
WindowSurfaceSet m_windowSet;
};
#endif

View file

@ -14,51 +14,51 @@
#include "RenderWindow.h"
#include "Renderer.h"
#include "emugl/common/logging.h"
#include "emugl/common/message_channel.h"
#include "emugl/common/mutex.h"
#include "emugl/common/thread.h"
#include "Renderer.h"
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#define DEBUG 0
#if DEBUG
# define D(...) my_debug(__PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)
#define D(...) my_debug(__PRETTY_FUNCTION__, __LINE__, __VA_ARGS__)
#else
# define D(...) ((void)0)
#define D(...) ((void)0)
#endif
namespace {
#if DEBUG
void my_debug(const char* function, int line, const char* format, ...) {
static ::emugl::Mutex mutex;
va_list args;
va_start(args, format);
mutex.lock();
fprintf(stderr, "%s:%d:", function, line);
vfprintf(stderr, format, args);
mutex.unlock();
va_end(args);
static ::emugl::Mutex mutex;
va_list args;
va_start(args, format);
mutex.lock();
fprintf(stderr, "%s:%d:", function, line);
vfprintf(stderr, format, args);
mutex.unlock();
va_end(args);
}
#endif
// List of possible commands to send to the render window thread from
// the main one.
enum Command {
CMD_INITIALIZE,
CMD_SET_POST_CALLBACK,
CMD_SETUP_SUBWINDOW,
CMD_REMOVE_SUBWINDOW,
CMD_SET_ROTATION,
CMD_SET_TRANSLATION,
CMD_REPAINT,
CMD_FINALIZE,
CMD_INITIALIZE,
CMD_SET_POST_CALLBACK,
CMD_SETUP_SUBWINDOW,
CMD_REMOVE_SUBWINDOW,
CMD_SET_ROTATION,
CMD_SET_TRANSLATION,
CMD_REPAINT,
CMD_FINALIZE,
};
} // namespace
@ -66,74 +66,73 @@ enum Command {
// A single message sent from the main thread to the render window thread.
// |cmd| determines which fields are valid to read.
struct RenderWindowMessage {
Command cmd;
union {
// CMD_INITIALIZE
struct {
EGLNativeDisplayType nativeDisplay;
} init;
Command cmd;
union {
// CMD_INITIALIZE
struct {
EGLNativeDisplayType nativeDisplay;
} init;
// CMD_SET_POST_CALLBACK
struct {
OnPostFn on_post;
void* on_post_context;
} set_post_callback;
// CMD_SET_POST_CALLBACK
struct {
OnPostFn on_post;
void* on_post_context;
} set_post_callback;
// CMD_SETUP_SUBWINDOW
struct {
FBNativeWindowType parent;
int wx;
int wy;
int ww;
int wh;
int fbw;
int fbh;
float dpr;
float rotation;
} subwindow;
// CMD_SETUP_SUBWINDOW
struct {
FBNativeWindowType parent;
int wx;
int wy;
int ww;
int wh;
int fbw;
int fbh;
float dpr;
float rotation;
} subwindow;
// CMD_SET_TRANSLATION;
struct {
float px;
float py;
} trans;
// CMD_SET_TRANSLATION;
struct {
float px;
float py;
} trans;
// CMD_SET_ROTATION
float rotation;
// CMD_SET_ROTATION
float rotation;
// result of operations.
bool result;
};
// result of operations.
bool result;
};
// Process the current message, and updates its |result| field.
// Returns true on success, or false on failure.
bool process() const {
const RenderWindowMessage& msg = *this;
Renderer* fb;
bool result = false;
switch (msg.cmd) {
case CMD_INITIALIZE:
D("CMD_INITIALIZE\n");
GL_LOG("RenderWindow: CMD_INITIALIZE");
result = Renderer::initialize(msg.init.nativeDisplay);
break;
// Process the current message, and updates its |result| field.
// Returns true on success, or false on failure.
bool process() const {
const RenderWindowMessage& msg = *this;
Renderer* fb;
bool result = false;
switch (msg.cmd) {
case CMD_INITIALIZE:
D("CMD_INITIALIZE\n");
GL_LOG("RenderWindow: CMD_INITIALIZE");
result = Renderer::initialize(msg.init.nativeDisplay);
break;
case CMD_FINALIZE:
D("CMD_FINALIZE\n");
// this command may be issued even when frame buffer is not
// yet created (e.g. if CMD_INITIALIZE failed),
// so make sure we check if it is there before finalizing
if (const auto fb = Renderer::get()) {
fb->finalize();
}
result = true;
break;
default:
;
case CMD_FINALIZE:
D("CMD_FINALIZE\n");
// this command may be issued even when frame buffer is not
// yet created (e.g. if CMD_INITIALIZE failed),
// so make sure we check if it is there before finalizing
if (const auto fb = Renderer::get()) {
fb->finalize();
}
return result;
result = true;
break;
default:;
}
return result;
}
};
// Simple synchronization structure used to exchange data between the
@ -159,43 +158,43 @@ struct RenderWindowMessage {
// canWriteCmd.signal()
//
class RenderWindowChannel {
public:
RenderWindowChannel() : mIn(), mOut() {}
~RenderWindowChannel() {}
public:
RenderWindowChannel() : mIn(), mOut() {}
~RenderWindowChannel() {}
// Send a message from the main thread.
// Note that the content of |msg| is copied into the channel.
// Returns with the command's result (true or false).
bool sendMessageAndGetResult(const RenderWindowMessage& msg) {
D("msg.cmd=%d\n", msg.cmd);
mIn.send(msg);
D("waiting for result\n");
bool result = false;
mOut.receive(&result);
D("result=%s\n", result ? "success" : "failure");
return result;
}
// Send a message from the main thread.
// Note that the content of |msg| is copied into the channel.
// Returns with the command's result (true or false).
bool sendMessageAndGetResult(const RenderWindowMessage& msg) {
D("msg.cmd=%d\n", msg.cmd);
mIn.send(msg);
D("waiting for result\n");
bool result = false;
mOut.receive(&result);
D("result=%s\n", result ? "success" : "failure");
return result;
}
// Receive a message from the render window thread.
// On exit, |*msg| gets a copy of the message. The caller
// must always call sendResult() after processing the message.
void receiveMessage(RenderWindowMessage* msg) {
D("entering\n");
mIn.receive(msg);
D("message cmd=%d\n", msg->cmd);
}
// Receive a message from the render window thread.
// On exit, |*msg| gets a copy of the message. The caller
// must always call sendResult() after processing the message.
void receiveMessage(RenderWindowMessage* msg) {
D("entering\n");
mIn.receive(msg);
D("message cmd=%d\n", msg->cmd);
}
// Send result from the render window thread to the main one.
// Must always be called after receiveMessage().
void sendResult(bool result) {
D("waiting to send result (%s)\n", result ? "success" : "failure");
mOut.send(result);
D("result sent\n");
}
// Send result from the render window thread to the main one.
// Must always be called after receiveMessage().
void sendResult(bool result) {
D("waiting to send result (%s)\n", result ? "success" : "failure");
mOut.send(result);
D("result sent\n");
}
private:
emugl::MessageChannel<RenderWindowMessage, 16U> mIn;
emugl::MessageChannel<bool, 16U> mOut;
private:
emugl::MessageChannel<RenderWindowMessage, 16U> mIn;
emugl::MessageChannel<bool, 16U> mOut;
};
namespace {
@ -207,162 +206,152 @@ namespace {
// The thread ends with a CMD_FINALIZE.
//
class RenderWindowThread : public emugl::Thread {
public:
RenderWindowThread(RenderWindowChannel* channel) : mChannel(channel) {}
public:
RenderWindowThread(RenderWindowChannel* channel) : mChannel(channel) {}
virtual intptr_t main() {
D("Entering render window thread thread\n");
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, NULL);
bool running = true;
while (running) {
RenderWindowMessage msg;
virtual intptr_t main() {
D("Entering render window thread thread\n");
sigset_t set;
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, NULL);
bool running = true;
while (running) {
RenderWindowMessage msg;
D("Waiting for message from main thread\n");
mChannel->receiveMessage(&msg);
D("Waiting for message from main thread\n");
mChannel->receiveMessage(&msg);
bool result = msg.process();
if (msg.cmd == CMD_FINALIZE) {
running = false;
}
bool result = msg.process();
if (msg.cmd == CMD_FINALIZE) {
running = false;
}
D("Sending result (%s) to main thread\n", result ? "success" : "failure");
mChannel->sendResult(result);
}
D("Exiting thread\n");
return 0;
D("Sending result (%s) to main thread\n", result ? "success" : "failure");
mChannel->sendResult(result);
}
D("Exiting thread\n");
return 0;
}
private:
RenderWindowChannel* mChannel;
private:
RenderWindowChannel* mChannel;
};
} // namespace
RenderWindow::RenderWindow(EGLNativeDisplayType native_display,
bool use_thread) :
mValid(false),
mHasSubWindow(false),
mThread(NULL),
mChannel(NULL) {
if (use_thread) {
mChannel = new RenderWindowChannel();
mThread = new RenderWindowThread(mChannel);
mThread->start();
}
RenderWindow::RenderWindow(EGLNativeDisplayType native_display, bool use_thread)
: mValid(false), mHasSubWindow(false), mThread(NULL), mChannel(NULL) {
if (use_thread) {
mChannel = new RenderWindowChannel();
mThread = new RenderWindowThread(mChannel);
mThread->start();
}
RenderWindowMessage msg;
msg.cmd = CMD_INITIALIZE;
msg.init.nativeDisplay = native_display;
mValid = processMessage(msg);
RenderWindowMessage msg;
msg.cmd = CMD_INITIALIZE;
msg.init.nativeDisplay = native_display;
mValid = processMessage(msg);
}
RenderWindow::~RenderWindow() {
D("Entering\n");
removeSubWindow();
D("Sending CMD_FINALIZE\n");
RenderWindowMessage msg;
msg.cmd = CMD_FINALIZE;
(void) processMessage(msg);
D("Entering\n");
removeSubWindow();
D("Sending CMD_FINALIZE\n");
RenderWindowMessage msg;
msg.cmd = CMD_FINALIZE;
(void)processMessage(msg);
if (mThread) {
mThread->wait(NULL);
delete mThread;
delete mChannel;
}
if (mThread) {
mThread->wait(NULL);
delete mThread;
delete mChannel;
}
}
bool RenderWindow::getHardwareStrings(const char** vendor,
const char** renderer,
const char** version) {
D("Entering\n");
// TODO(digit): Move this to render window thread.
Renderer* fb = Renderer::get();
if (!fb) {
D("No framebuffer!\n");
return false;
}
fb->getGLStrings(vendor, renderer, version);
D("Exiting vendor=[%s] renderer=[%s] version=[%s]\n",
*vendor, *renderer, *version);
D("Entering\n");
// TODO(digit): Move this to render window thread.
Renderer* fb = Renderer::get();
if (!fb) {
D("No framebuffer!\n");
return false;
}
fb->getGLStrings(vendor, renderer, version);
D("Exiting vendor=[%s] renderer=[%s] version=[%s]\n", *vendor, *renderer,
*version);
return true;
return true;
}
bool RenderWindow::setupSubWindow(FBNativeWindowType window,
int wx,
int wy,
int ww,
int wh,
int fbw,
int fbh,
float dpr,
bool RenderWindow::setupSubWindow(FBNativeWindowType window, int wx, int wy,
int ww, int wh, int fbw, int fbh, float dpr,
float zRot) {
D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
RenderWindowMessage msg;
msg.cmd = CMD_SETUP_SUBWINDOW;
msg.subwindow.parent = window;
msg.subwindow.wx = wx;
msg.subwindow.wy = wy;
msg.subwindow.ww = ww;
msg.subwindow.wh = wh;
msg.subwindow.fbw = fbw;
msg.subwindow.fbh = fbh;
msg.subwindow.dpr = dpr;
msg.subwindow.rotation = zRot;
RenderWindowMessage msg;
msg.cmd = CMD_SETUP_SUBWINDOW;
msg.subwindow.parent = window;
msg.subwindow.wx = wx;
msg.subwindow.wy = wy;
msg.subwindow.ww = ww;
msg.subwindow.wh = wh;
msg.subwindow.fbw = fbw;
msg.subwindow.fbh = fbh;
msg.subwindow.dpr = dpr;
msg.subwindow.rotation = zRot;
mHasSubWindow = processMessage(msg);
D("Exiting mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
return mHasSubWindow;
mHasSubWindow = processMessage(msg);
D("Exiting mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
return mHasSubWindow;
}
bool RenderWindow::removeSubWindow() {
D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
if (!mHasSubWindow) {
return false;
}
mHasSubWindow = false;
D("Entering mHasSubWindow=%s\n", mHasSubWindow ? "true" : "false");
if (!mHasSubWindow) {
return false;
}
mHasSubWindow = false;
RenderWindowMessage msg;
msg.cmd = CMD_REMOVE_SUBWINDOW;
bool result = processMessage(msg);
D("Exiting result=%s\n", result ? "success" : "failure");
return result;
RenderWindowMessage msg;
msg.cmd = CMD_REMOVE_SUBWINDOW;
bool result = processMessage(msg);
D("Exiting result=%s\n", result ? "success" : "failure");
return result;
}
void RenderWindow::setRotation(float zRot) {
D("Entering rotation=%f\n", zRot);
RenderWindowMessage msg;
msg.cmd = CMD_SET_ROTATION;
msg.rotation = zRot;
(void) processMessage(msg);
D("Exiting\n");
D("Entering rotation=%f\n", zRot);
RenderWindowMessage msg;
msg.cmd = CMD_SET_ROTATION;
msg.rotation = zRot;
(void)processMessage(msg);
D("Exiting\n");
}
void RenderWindow::setTranslation(float px, float py) {
D("Entering translation=%f,%f\n", px, py);
RenderWindowMessage msg;
msg.cmd = CMD_SET_TRANSLATION;
msg.trans.px = px;
msg.trans.py = py;
(void) processMessage(msg);
D("Exiting\n");
D("Entering translation=%f,%f\n", px, py);
RenderWindowMessage msg;
msg.cmd = CMD_SET_TRANSLATION;
msg.trans.px = px;
msg.trans.py = py;
(void)processMessage(msg);
D("Exiting\n");
}
void RenderWindow::repaint() {
D("Entering\n");
RenderWindowMessage msg;
msg.cmd = CMD_REPAINT;
(void) processMessage(msg);
D("Exiting\n");
D("Entering\n");
RenderWindowMessage msg;
msg.cmd = CMD_REPAINT;
(void)processMessage(msg);
D("Exiting\n");
}
bool RenderWindow::processMessage(const RenderWindowMessage& msg) {
if (mChannel) {
return mChannel->sendMessageAndGetResult(msg);
} else {
return msg.process();
}
if (mChannel) {
return mChannel->sendMessageAndGetResult(msg);
} else {
return msg.process();
}
}

View file

@ -47,84 +47,76 @@ struct RenderWindowMessage;
// 6) Call repaint() to force a repaint().
//
class RenderWindow {
public:
// Create new instance. |width| and |height| are the dimensions of the
// emulated accelerated framebuffer. |use_thread| can be true to force
// the use of a separate thread, which might be required on some platforms
// to avoid GL-realted corruption issues in the main window. Call
// isValid() after construction to verify that it worked properly.
//
// |use_sub_window| is true if the client will call setupSubWindow(),
// and false if it will call setPostCallback().
//
// Note that this call doesn't display anything, it just initializes
// the library, use setupSubWindow() to display something.
RenderWindow(EGLNativeDisplayType native_display, bool use_thread);
public:
// Create new instance. |width| and |height| are the dimensions of the
// emulated accelerated framebuffer. |use_thread| can be true to force
// the use of a separate thread, which might be required on some platforms
// to avoid GL-realted corruption issues in the main window. Call
// isValid() after construction to verify that it worked properly.
//
// |use_sub_window| is true if the client will call setupSubWindow(),
// and false if it will call setPostCallback().
//
// Note that this call doesn't display anything, it just initializes
// the library, use setupSubWindow() to display something.
RenderWindow(EGLNativeDisplayType native_display, bool use_thread);
// Destructor. This will automatically call removeSubWindow() is needed.
~RenderWindow();
// Destructor. This will automatically call removeSubWindow() is needed.
~RenderWindow();
// Returns true if the RenderWindow instance is valid, which really
// means that the constructor succeeded.
bool isValid() const { return mValid; }
// Returns true if the RenderWindow instance is valid, which really
// means that the constructor succeeded.
bool isValid() const { return mValid; }
// Return misc. GL strings to the caller. On success, return true and sets
// |*vendor| to the GL vendor string, |*renderer| to the GL renderer one,
// and |*version| to the GL version one. On failure, return false.
bool getHardwareStrings(const char** vendor,
const char** renderer,
const char** version);
// Return misc. GL strings to the caller. On success, return true and sets
// |*vendor| to the GL vendor string, |*renderer| to the GL renderer one,
// and |*version| to the GL version one. On failure, return false.
bool getHardwareStrings(const char** vendor, const char** renderer,
const char** version);
// Start displaying the emulated framebuffer using a sub-window of a
// parent |window| id. |wx|, |wy|, |ww| and |wh| are the position
// and dimension of the sub-window, relative to its parent.
// |fbw| and |fbh| are the dimensions of the underlying guest framebuffer.
// |dpr| is the device pixel ratio for the monitor, which is required for
// higher-density displays (such as retina).
// |rotation| is a clockwise-rotation for the content. Only multiples of
// 90. are accepted. Returns true on success, false otherwise.
//
// If the subwindow already exists, this function will update
// the dimensions of the subwindow, backing framebuffer, and rendering
// pipeline to reflect the new values.
//
// One can call removeSubWindow() to remove the sub-window.
bool setupSubWindow(FBNativeWindowType window,
int wx,
int wy,
int ww,
int wh,
int fbw,
int fbh,
float dpr,
float rotation);
// Start displaying the emulated framebuffer using a sub-window of a
// parent |window| id. |wx|, |wy|, |ww| and |wh| are the position
// and dimension of the sub-window, relative to its parent.
// |fbw| and |fbh| are the dimensions of the underlying guest framebuffer.
// |dpr| is the device pixel ratio for the monitor, which is required for
// higher-density displays (such as retina).
// |rotation| is a clockwise-rotation for the content. Only multiples of
// 90. are accepted. Returns true on success, false otherwise.
//
// If the subwindow already exists, this function will update
// the dimensions of the subwindow, backing framebuffer, and rendering
// pipeline to reflect the new values.
//
// One can call removeSubWindow() to remove the sub-window.
bool setupSubWindow(FBNativeWindowType window, int wx, int wy, int ww, int wh,
int fbw, int fbh, float dpr, float rotation);
// Remove the sub-window created by calling setupSubWindow().
// Note that this doesn't discard the content of the emulated framebuffer,
// it just hides it from the main window. Returns true on success, false
// otherwise.
bool removeSubWindow();
// Remove the sub-window created by calling setupSubWindow().
// Note that this doesn't discard the content of the emulated framebuffer,
// it just hides it from the main window. Returns true on success, false
// otherwise.
bool removeSubWindow();
// Change the display rotation on the fly. |zRot| is a clockwise rotation
// angle in degrees. Only multiples of 90. are accepted.
void setRotation(float zRot);
// Change the display rotation on the fly. |zRot| is a clockwise rotation
// angle in degrees. Only multiples of 90. are accepted.
void setRotation(float zRot);
// Change the display translation. |px|,|py| are numbers between 0 and 1,
// with (0,0) indicating "align the bottom left of the framebuffer with the
// bottom left of the subwindow", and (1,1) indicating "align the top right of
// the framebuffer with the top right of the subwindow."
void setTranslation(float px, float py);
// Change the display translation. |px|,|py| are numbers between 0 and 1,
// with (0,0) indicating "align the bottom left of the framebuffer with the
// bottom left of the subwindow", and (1,1) indicating "align the top right of
// the framebuffer with the top right of the subwindow."
void setTranslation(float px, float py);
// Force a repaint of the whole content into the sub-window.
void repaint();
// Force a repaint of the whole content into the sub-window.
void repaint();
private:
bool processMessage(const RenderWindowMessage& msg);
private:
bool processMessage(const RenderWindowMessage& msg);
bool mValid;
bool mHasSubWindow;
emugl::Thread* mThread;
RenderWindowChannel* mChannel;
bool mValid;
bool mHasSubWindow;
emugl::Thread* mThread;
RenderWindowChannel* mChannel;
};
#endif // ANDROID_EMUGL_LIBRENDER_RENDER_WINDOW_H

View file

@ -16,56 +16,34 @@
#include "Renderable.h"
Renderable::Renderable(const std::string &name,
const std::uint32_t &buffer,
Renderable::Renderable(const std::string &name, const std::uint32_t &buffer,
const anbox::graphics::Rect &screen_position,
const anbox::graphics::Rect &crop,
const glm::mat4 &transformation,
const float &alpha) :
name_(name),
buffer_(buffer),
screen_position_(screen_position),
crop_(crop),
transformation_(transformation),
alpha_(alpha)
{
const glm::mat4 &transformation, const float &alpha)
: name_(name),
buffer_(buffer),
screen_position_(screen_position),
crop_(crop),
transformation_(transformation),
alpha_(alpha) {}
Renderable::~Renderable() {}
std::string Renderable::name() const { return name_; }
std::uint32_t Renderable::buffer() const { return buffer_; }
anbox::graphics::Rect Renderable::screen_position() const {
return screen_position_;
}
Renderable::~Renderable()
{
}
anbox::graphics::Rect Renderable::crop() const { return crop_; }
std::string Renderable::name() const
{
return name_;
}
glm::mat4 Renderable::transformation() const { return transformation_; }
std::uint32_t Renderable::buffer() const
{
return buffer_;
}
float Renderable::alpha() const { return alpha_; }
anbox::graphics::Rect Renderable::screen_position() const
{
return screen_position_;
}
anbox::graphics::Rect Renderable::crop() const
{
return crop_;
}
glm::mat4 Renderable::transformation() const
{
return transformation_;
}
float Renderable::alpha() const
{
return alpha_;
}
void Renderable::set_screen_position(const anbox::graphics::Rect &screen_position)
{
screen_position_ = screen_position;
void Renderable::set_screen_position(
const anbox::graphics::Rect &screen_position) {
screen_position_ = screen_position;
}

View file

@ -26,33 +26,30 @@
#include <glm/glm.hpp>
class Renderable
{
public:
Renderable(const std::string &name,
const std::uint32_t &buffer,
const anbox::graphics::Rect &screen_position,
const anbox::graphics::Rect &crop = {},
const glm::mat4 &transformation = {},
const float &alpha = 1.0f);
~Renderable();
class Renderable {
public:
Renderable(const std::string &name, const std::uint32_t &buffer,
const anbox::graphics::Rect &screen_position,
const anbox::graphics::Rect &crop = {},
const glm::mat4 &transformation = {}, const float &alpha = 1.0f);
~Renderable();
std::string name() const;
std::uint32_t buffer() const;
anbox::graphics::Rect screen_position() const;
anbox::graphics::Rect crop() const;
glm::mat4 transformation() const;
float alpha() const;
std::string name() const;
std::uint32_t buffer() const;
anbox::graphics::Rect screen_position() const;
anbox::graphics::Rect crop() const;
glm::mat4 transformation() const;
float alpha() const;
void set_screen_position(const anbox::graphics::Rect &screen_position);
void set_screen_position(const anbox::graphics::Rect &screen_position);
private:
std::string name_;
std::uint32_t buffer_;
anbox::graphics::Rect screen_position_;
anbox::graphics::Rect crop_;
glm::mat4 transformation_;
float alpha_;
private:
std::string name_;
std::uint32_t buffer_;
anbox::graphics::Rect screen_position_;
anbox::graphics::Rect crop_;
glm::mat4 transformation_;
float alpha_;
};
typedef std::vector<Renderable> RenderableList;

File diff suppressed because it is too large Load diff

View file

@ -17,18 +17,18 @@
#define _LIBRENDER_FRAMEBUFFER_H
#include "ColorBuffer.h"
#include "emugl/common/mutex.h"
#include "RendererConfig.h"
#include "RenderContext.h"
#include "RendererConfig.h"
#include "TextureDraw.h"
#include "WindowSurface.h"
#include "emugl/common/mutex.h"
#include "OpenglRender/render_api.h"
#include "Renderable.h"
#include "anbox/graphics/program_family.h"
#include "anbox/graphics/primitives.h"
#include "anbox/graphics/program_family.h"
#include <EGL/egl.h>
@ -41,11 +41,12 @@
typedef uint32_t HandleType;
struct ColorBufferRef {
ColorBufferPtr cb;
uint32_t refcount; // number of client-side references
ColorBufferPtr cb;
uint32_t refcount; // number of client-side references
};
typedef std::map<HandleType, RenderContextPtr> RenderContextMap;
typedef std::map<HandleType, std::pair<WindowSurfacePtr, HandleType> > WindowSurfaceMap;
typedef std::map<HandleType, std::pair<WindowSurfacePtr, HandleType>>
WindowSurfaceMap;
typedef std::map<HandleType, ColorBufferRef> ColorBufferMap;
// A structure used to list the capabilities of the underlying EGL
@ -57,10 +58,10 @@ typedef std::map<HandleType, ColorBufferRef> ColorBufferMap;
// |eglMajor| and |eglMinor| are the major and minor version numbers of
// the underlying EGL implementation.
struct RendererCaps {
bool has_eglimage_texture_2d;
bool has_eglimage_renderbuffer;
EGLint eglMajor;
EGLint eglMinor;
bool has_eglimage_texture_2d;
bool has_eglimage_renderbuffer;
EGLint eglMajor;
EGLint eglMinor;
};
struct RendererWindow;
@ -73,252 +74,251 @@ struct RendererWindow;
// and which must be previously setup by calling initialize().
//
class Renderer {
public:
// Initialize the global instance.
// |width| and |height| are the dimensions of the emulator GPU display
// in pixels. |useSubWindow| is true to indicate that the caller
// will use setupSubWindow() to let EmuGL display the GPU content in its
// own sub-windows. If false, this means the caller will use
// setPostCallback() instead to retrieve the content.
// Returns true on success, false otherwise.
static bool initialize(EGLNativeDisplayType nativeDisplay);
public:
// Initialize the global instance.
// |width| and |height| are the dimensions of the emulator GPU display
// in pixels. |useSubWindow| is true to indicate that the caller
// will use setupSubWindow() to let EmuGL display the GPU content in its
// own sub-windows. If false, this means the caller will use
// setPostCallback() instead to retrieve the content.
// Returns true on success, false otherwise.
static bool initialize(EGLNativeDisplayType nativeDisplay);
// Finalize the instance.
void finalize();
// Finalize the instance.
void finalize();
// Return a pointer to the global instance. initialize() must be called
// previously, or this will return NULL.
static Renderer *get() { return s_renderer; }
// Return a pointer to the global instance. initialize() must be called
// previously, or this will return NULL.
static Renderer* get() { return s_renderer; }
// Return the capabilities of the underlying display.
const RendererCaps &getCaps() const { return m_caps; }
// Return the capabilities of the underlying display.
const RendererCaps& getCaps() const { return m_caps; }
// Return the list of configs available from this display.
const RendererConfigList* getConfigs() const { return m_configs; }
// Return the list of configs available from this display.
const RendererConfigList* getConfigs() const { return m_configs; }
// Set a callback that will be called each time the emulated GPU content
// is updated. This can be relatively slow with host-based GPU emulation,
// so only do this when you need to.
void setPostCallback(OnPostFn onPost, void* onPostContext);
// Set a callback that will be called each time the emulated GPU content
// is updated. This can be relatively slow with host-based GPU emulation,
// so only do this when you need to.
void setPostCallback(OnPostFn onPost, void* onPostContext);
// Retrieve the GL strings of the underlying EGL/GLES implementation.
// On return, |*vendor|, |*renderer| and |*version| will point to strings
// that are owned by the instance (and must not be freed by the caller).
void getGLStrings(const char** vendor,
const char** renderer,
const char** version) const {
*vendor = m_glVendor;
*renderer = m_glRenderer;
*version = m_glVersion;
}
// Retrieve the GL strings of the underlying EGL/GLES implementation.
// On return, |*vendor|, |*renderer| and |*version| will point to strings
// that are owned by the instance (and must not be freed by the caller).
void getGLStrings(const char** vendor, const char** renderer,
const char** version) const {
*vendor = m_glVendor;
*renderer = m_glRenderer;
*version = m_glVersion;
}
RendererWindow* createNativeWindow(EGLNativeWindowType native_window);
void destroyNativeWindow(RendererWindow *window);
void destroyNativeWindow(EGLNativeWindowType native_window);
RendererWindow* createNativeWindow(EGLNativeWindowType native_window);
void destroyNativeWindow(RendererWindow* window);
void destroyNativeWindow(EGLNativeWindowType native_window);
// Create a new RenderContext instance for this display instance.
// |p_config| is the index of one of the configs returned by getConfigs().
// |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
// |p_isGL2| is true to create a GLES 2.x context, or false for a GLES 1.x
// one.
// Return a new handle value, which will be 0 in case of error.
HandleType createRenderContext(
int p_config, HandleType p_share, bool p_isGL2 = false);
// Create a new RenderContext instance for this display instance.
// |p_config| is the index of one of the configs returned by getConfigs().
// |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
// |p_isGL2| is true to create a GLES 2.x context, or false for a GLES 1.x
// one.
// Return a new handle value, which will be 0 in case of error.
HandleType createRenderContext(int p_config, HandleType p_share,
bool p_isGL2 = false);
// Create a new WindowSurface instance from this display instance.
// |p_config| is the index of one of the configs returned by getConfigs().
// |p_width| and |p_height| are the window dimensions in pixels.
// Return a new handle value, or 0 in case of error.
HandleType createWindowSurface(int p_config, int p_width, int p_height);
// Create a new WindowSurface instance from this display instance.
// |p_config| is the index of one of the configs returned by getConfigs().
// |p_width| and |p_height| are the window dimensions in pixels.
// Return a new handle value, or 0 in case of error.
HandleType createWindowSurface(int p_config, int p_width, int p_height);
// Create a new ColorBuffer instance from this display instance.
// |p_width| and |p_height| are its dimensions in pixels.
// |p_internalFormat| is the pixel format. See ColorBuffer::create() for
// list of valid values. Note that ColorBuffer instances are reference-
// counted. Use openColorBuffer / closeColorBuffer to operate on the
// internal count.
HandleType createColorBuffer(
int p_width, int p_height, GLenum p_internalFormat);
// Create a new ColorBuffer instance from this display instance.
// |p_width| and |p_height| are its dimensions in pixels.
// |p_internalFormat| is the pixel format. See ColorBuffer::create() for
// list of valid values. Note that ColorBuffer instances are reference-
// counted. Use openColorBuffer / closeColorBuffer to operate on the
// internal count.
HandleType createColorBuffer(int p_width, int p_height,
GLenum p_internalFormat);
// Call this function when a render thread terminates to destroy all
// the remaining contexts it created. Necessary to avoid leaking host
// contexts when a guest application crashes, for example.
void drainRenderContext();
// Call this function when a render thread terminates to destroy all
// the remaining contexts it created. Necessary to avoid leaking host
// contexts when a guest application crashes, for example.
void drainRenderContext();
// Call this function when a render thread terminates to destroy all
// remaining window surfqce it created. Necessary to avoid leaking
// host buffers when a guest application crashes, for example.
void drainWindowSurface();
// Call this function when a render thread terminates to destroy all
// remaining window surfqce it created. Necessary to avoid leaking
// host buffers when a guest application crashes, for example.
void drainWindowSurface();
// Destroy a given RenderContext instance. |p_context| is its handle
// value as returned by createRenderContext().
void DestroyRenderContext(HandleType p_context);
// Destroy a given RenderContext instance. |p_context| is its handle
// value as returned by createRenderContext().
void DestroyRenderContext(HandleType p_context);
// Destroy a given WindowSurface instance. |p_surcace| is its handle
// value as returned by createWindowSurface().
void DestroyWindowSurface(HandleType p_surface);
// Destroy a given WindowSurface instance. |p_surcace| is its handle
// value as returned by createWindowSurface().
void DestroyWindowSurface(HandleType p_surface);
// Increment the reference count associated with a given ColorBuffer
// instance. |p_colorbuffer| is its handle value as returned by
// createColorBuffer().
int openColorBuffer(HandleType p_colorbuffer);
// Increment the reference count associated with a given ColorBuffer
// instance. |p_colorbuffer| is its handle value as returned by
// createColorBuffer().
int openColorBuffer(HandleType p_colorbuffer);
// Decrement the reference count associated with a given ColorBuffer
// instance. |p_colorbuffer| is its handle value as returned by
// createColorBuffer(). Note that if the reference count reaches 0,
// the instance is destroyed automatically.
void closeColorBuffer(HandleType p_colorbuffer);
// Decrement the reference count associated with a given ColorBuffer
// instance. |p_colorbuffer| is its handle value as returned by
// createColorBuffer(). Note that if the reference count reaches 0,
// the instance is destroyed automatically.
void closeColorBuffer(HandleType p_colorbuffer);
// Equivalent for eglMakeCurrent() for the current display.
// |p_context|, |p_drawSurface| and |p_readSurface| are the handle values
// of the context, the draw surface and the read surface, respectively.
// Returns true on success, false on failure.
// Note: if all handle values are 0, this is an unbind operation.
bool bindContext(HandleType p_context,
HandleType p_drawSurface,
HandleType p_readSurface);
// Equivalent for eglMakeCurrent() for the current display.
// |p_context|, |p_drawSurface| and |p_readSurface| are the handle values
// of the context, the draw surface and the read surface, respectively.
// Returns true on success, false on failure.
// Note: if all handle values are 0, this is an unbind operation.
bool bindContext(HandleType p_context, HandleType p_drawSurface,
HandleType p_readSurface);
// Attach a ColorBuffer to a WindowSurface instance.
// See the documentation for WindowSurface::setColorBuffer().
// |p_surface| is the target WindowSurface's handle value.
// |p_colorbuffer| is the ColorBuffer handle value.
// Returns true on success, false otherwise.
bool setWindowSurfaceColorBuffer(
HandleType p_surface, HandleType p_colorbuffer);
// Attach a ColorBuffer to a WindowSurface instance.
// See the documentation for WindowSurface::setColorBuffer().
// |p_surface| is the target WindowSurface's handle value.
// |p_colorbuffer| is the ColorBuffer handle value.
// Returns true on success, false otherwise.
bool setWindowSurfaceColorBuffer(HandleType p_surface,
HandleType p_colorbuffer);
// Copy the content of a WindowSurface's Pbuffer to its attached
// ColorBuffer. See the documentation for WindowSurface::flushColorBuffer()
// |p_surface| is the target WindowSurface's handle value.
// Returns true on success, false on failure.
bool flushWindowSurfaceColorBuffer(HandleType p_surface);
// Copy the content of a WindowSurface's Pbuffer to its attached
// ColorBuffer. See the documentation for WindowSurface::flushColorBuffer()
// |p_surface| is the target WindowSurface's handle value.
// Returns true on success, false on failure.
bool flushWindowSurfaceColorBuffer(HandleType p_surface);
// Bind the current context's EGL_TEXTURE_2D texture to a ColorBuffer
// instance's EGLImage. This is intended to implement
// glEGLImageTargetTexture2DOES() for all GLES versions.
// |p_colorbuffer| is the ColorBuffer's handle value.
// Returns true on success, false on failure.
bool bindColorBufferToTexture(HandleType p_colorbuffer);
// Bind the current context's EGL_TEXTURE_2D texture to a ColorBuffer
// instance's EGLImage. This is intended to implement
// glEGLImageTargetTexture2DOES() for all GLES versions.
// |p_colorbuffer| is the ColorBuffer's handle value.
// Returns true on success, false on failure.
bool bindColorBufferToTexture(HandleType p_colorbuffer);
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
// ColorBuffer's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
// |p_colorbuffer| is the ColorBuffer's handle value.
// Returns true on success, false on failure.
bool bindColorBufferToRenderbuffer(HandleType p_colorbuffer);
// Bind the current context's EGL_RENDERBUFFER_OES render buffer to this
// ColorBuffer's EGLImage. This is intended to implement
// glEGLImageTargetRenderbufferStorageOES() for all GLES versions.
// |p_colorbuffer| is the ColorBuffer's handle value.
// Returns true on success, false on failure.
bool bindColorBufferToRenderbuffer(HandleType p_colorbuffer);
// Read the content of a given ColorBuffer into client memory.
// |p_colorbuffer| is the ColorBuffer's handle value. Similar
// to glReadPixels(), this can be a slow operation.
// |x|, |y|, |width| and |height| are the position and dimensions of
// a rectangle whose pixel values will be transfered to the host.
// |format| indicates the format of the pixel data, e.g. GL_RGB or GL_RGBA.
// |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE.
// |pixels| is the address of a caller-provided buffer that will be filled
// with the pixel data.
void readColorBuffer(HandleType p_colorbuffer,
int x, int y, int width, int height,
GLenum format, GLenum type, void *pixels);
// Read the content of a given ColorBuffer into client memory.
// |p_colorbuffer| is the ColorBuffer's handle value. Similar
// to glReadPixels(), this can be a slow operation.
// |x|, |y|, |width| and |height| are the position and dimensions of
// a rectangle whose pixel values will be transfered to the host.
// |format| indicates the format of the pixel data, e.g. GL_RGB or GL_RGBA.
// |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE.
// |pixels| is the address of a caller-provided buffer that will be filled
// with the pixel data.
void readColorBuffer(HandleType p_colorbuffer, int x, int y, int width,
int height, GLenum format, GLenum type, void* pixels);
// Update the content of a given ColorBuffer from client data.
// |p_colorbuffer| is the ColorBuffer's handle value. Similar
// to glReadPixels(), this can be a slow operation.
// |x|, |y|, |width| and |height| are the position and dimensions of
// a rectangle whose pixel values will be transfered to the GPU
// |format| indicates the format of the pixel data, e.g. GL_RGB or GL_RGBA.
// |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE.
// |pixels| is the address of a buffer containing the new pixel data.
// Returns true on success, false otherwise.
bool updateColorBuffer(HandleType p_colorbuffer,
int x, int y, int width, int height,
GLenum format, GLenum type, void *pixels);
// Update the content of a given ColorBuffer from client data.
// |p_colorbuffer| is the ColorBuffer's handle value. Similar
// to glReadPixels(), this can be a slow operation.
// |x|, |y|, |width| and |height| are the position and dimensions of
// a rectangle whose pixel values will be transfered to the GPU
// |format| indicates the format of the pixel data, e.g. GL_RGB or GL_RGBA.
// |type| is the type of pixel data, e.g. GL_UNSIGNED_BYTE.
// |pixels| is the address of a buffer containing the new pixel data.
// Returns true on success, false otherwise.
bool updateColorBuffer(HandleType p_colorbuffer, int x, int y, int width,
int height, GLenum format, GLenum type, void* pixels);
bool draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables);
bool draw(EGLNativeWindowType native_window,
const anbox::graphics::Rect& window_frame,
const RenderableList& renderables);
// Return the host EGLDisplay used by this instance.
EGLDisplay getDisplay() const { return m_eglDisplay; }
// Return the host EGLDisplay used by this instance.
EGLDisplay getDisplay() const { return m_eglDisplay; }
// Return a TextureDraw instance that can be used with this surfaces
// and windows created by this instance.
TextureDraw* getTextureDraw() const { return m_textureDraw; }
// Return a TextureDraw instance that can be used with this surfaces
// and windows created by this instance.
TextureDraw* getTextureDraw() const { return m_textureDraw; }
HandleType createClientImage(HandleType context, EGLenum target, GLuint buffer);
EGLBoolean destroyClientImage(HandleType image);
HandleType createClientImage(HandleType context, EGLenum target,
GLuint buffer);
EGLBoolean destroyClientImage(HandleType image);
// Used internally.
bool bind_locked();
bool unbind_locked();
// Used internally.
bool bind_locked();
bool unbind_locked();
private:
Renderer();
~Renderer();
HandleType genHandle();
private:
Renderer();
~Renderer();
HandleType genHandle();
bool bindWindow_locked(RendererWindow *window);
bool bindWindow_locked(RendererWindow* window);
void setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect);
struct Program;
void draw(RendererWindow *window, const Renderable &renderable, const Program &prog);
void tessellate(std::vector<anbox::graphics::Primitive>& primitives,
const anbox::graphics::Rect &buf_size,
const Renderable &renderable);
void setupViewport(RendererWindow* window, const anbox::graphics::Rect& rect);
struct Program;
void draw(RendererWindow* window, const Renderable& renderable,
const Program& prog);
void tessellate(std::vector<anbox::graphics::Primitive>& primitives,
const anbox::graphics::Rect& buf_size,
const Renderable& renderable);
private:
static Renderer *s_renderer;
static HandleType s_nextHandle;
emugl::Mutex m_lock;
RendererConfigList* m_configs;
FBNativeWindowType m_nativeWindow;
RendererCaps m_caps;
EGLDisplay m_eglDisplay;
RenderContextMap m_contexts;
WindowSurfaceMap m_windows;
ColorBufferMap m_colorbuffers;
ColorBuffer::Helper* m_colorBufferHelper;
private:
static Renderer* s_renderer;
static HandleType s_nextHandle;
emugl::Mutex m_lock;
RendererConfigList* m_configs;
FBNativeWindowType m_nativeWindow;
RendererCaps m_caps;
EGLDisplay m_eglDisplay;
RenderContextMap m_contexts;
WindowSurfaceMap m_windows;
ColorBufferMap m_colorbuffers;
ColorBuffer::Helper* m_colorBufferHelper;
EGLContext m_eglContext;
EGLSurface m_pbufSurface;
EGLContext m_pbufContext;
EGLContext m_eglContext;
EGLSurface m_pbufSurface;
EGLContext m_pbufContext;
EGLContext m_prevContext;
EGLSurface m_prevReadSurf;
EGLSurface m_prevDrawSurf;
TextureDraw* m_textureDraw;
EGLConfig m_eglConfig;
HandleType m_lastPostedColorBuffer;
EGLContext m_prevContext;
EGLSurface m_prevReadSurf;
EGLSurface m_prevDrawSurf;
TextureDraw* m_textureDraw;
EGLConfig m_eglConfig;
HandleType m_lastPostedColorBuffer;
int m_statsNumFrames;
long long m_statsStartTime;
bool m_fpsStats;
int m_statsNumFrames;
long long m_statsStartTime;
bool m_fpsStats;
const char* m_glVendor;
const char* m_glRenderer;
const char* m_glVersion;
const char* m_glVendor;
const char* m_glRenderer;
const char* m_glVersion;
std::map<EGLNativeWindowType,RendererWindow*> m_nativeWindows;
std::map<EGLNativeWindowType, RendererWindow*> m_nativeWindows;
anbox::graphics::ProgramFamily m_family;
struct Program
{
GLuint id = 0;
GLint tex_uniform = -1;
GLint position_attr = -1;
GLint texcoord_attr = -1;
GLint center_uniform = -1;
GLint display_transform_uniform = -1;
GLint transform_uniform = -1;
GLint screen_to_gl_coords_uniform = -1;
GLint alpha_uniform = -1;
mutable long long last_used_frameno = 0;
anbox::graphics::ProgramFamily m_family;
struct Program {
GLuint id = 0;
GLint tex_uniform = -1;
GLint position_attr = -1;
GLint texcoord_attr = -1;
GLint center_uniform = -1;
GLint display_transform_uniform = -1;
GLint transform_uniform = -1;
GLint screen_to_gl_coords_uniform = -1;
GLint alpha_uniform = -1;
mutable long long last_used_frameno = 0;
Program(GLuint program_id);
Program() {}
};
Program m_defaultProgram, m_alphaProgram;
Program(GLuint program_id);
Program() {}
};
Program m_defaultProgram, m_alphaProgram;
std::vector<anbox::graphics::Primitive> m_primitives;
std::vector<anbox::graphics::Primitive> m_primitives;
static const GLchar* const vshader;
static const GLchar* const defaultFShader;
static const GLchar* const alphaFShader;
static const GLchar* const vshader;
static const GLchar* const defaultFShader;
static const GLchar* const alphaFShader;
};
#endif

View file

@ -21,255 +21,223 @@
namespace {
#define E(...) fprintf(stderr, __VA_ARGS__)
#define E(...) fprintf(stderr, __VA_ARGS__)
const GLuint kConfigAttributes[] = {
EGL_DEPTH_SIZE, // must be first - see getDepthSize()
EGL_STENCIL_SIZE, // must be second - see getStencilSize()
EGL_RENDERABLE_TYPE,// must be third - see getRenderableType()
EGL_SURFACE_TYPE, // must be fourth - see getSurfaceType()
EGL_CONFIG_ID, // must be fifth - see chooseConfig()
EGL_BUFFER_SIZE,
EGL_ALPHA_SIZE,
EGL_BLUE_SIZE,
EGL_GREEN_SIZE,
EGL_RED_SIZE,
EGL_CONFIG_CAVEAT,
EGL_LEVEL,
EGL_MAX_PBUFFER_HEIGHT,
EGL_MAX_PBUFFER_PIXELS,
EGL_MAX_PBUFFER_WIDTH,
EGL_NATIVE_RENDERABLE,
EGL_NATIVE_VISUAL_ID,
EGL_NATIVE_VISUAL_TYPE,
EGL_SAMPLES,
EGL_SAMPLE_BUFFERS,
EGL_TRANSPARENT_TYPE,
EGL_TRANSPARENT_BLUE_VALUE,
EGL_TRANSPARENT_GREEN_VALUE,
EGL_TRANSPARENT_RED_VALUE,
EGL_BIND_TO_TEXTURE_RGB,
EGL_BIND_TO_TEXTURE_RGBA,
EGL_MIN_SWAP_INTERVAL,
EGL_MAX_SWAP_INTERVAL,
EGL_LUMINANCE_SIZE,
EGL_ALPHA_MASK_SIZE,
EGL_DEPTH_SIZE, // must be first - see getDepthSize()
EGL_STENCIL_SIZE, // must be second - see getStencilSize()
EGL_RENDERABLE_TYPE, // must be third - see getRenderableType()
EGL_SURFACE_TYPE, // must be fourth - see getSurfaceType()
EGL_CONFIG_ID, // must be fifth - see chooseConfig()
EGL_BUFFER_SIZE, EGL_ALPHA_SIZE, EGL_BLUE_SIZE, EGL_GREEN_SIZE,
EGL_RED_SIZE, EGL_CONFIG_CAVEAT, EGL_LEVEL, EGL_MAX_PBUFFER_HEIGHT,
EGL_MAX_PBUFFER_PIXELS, EGL_MAX_PBUFFER_WIDTH, EGL_NATIVE_RENDERABLE,
EGL_NATIVE_VISUAL_ID, EGL_NATIVE_VISUAL_TYPE, EGL_SAMPLES,
EGL_SAMPLE_BUFFERS, EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_BLUE_VALUE,
EGL_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_RED_VALUE,
EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_MIN_SWAP_INTERVAL,
EGL_MAX_SWAP_INTERVAL, EGL_LUMINANCE_SIZE, EGL_ALPHA_MASK_SIZE,
EGL_COLOR_BUFFER_TYPE,
//EGL_MATCH_NATIVE_PIXMAP,
EGL_CONFORMANT
};
// EGL_MATCH_NATIVE_PIXMAP,
EGL_CONFORMANT};
const size_t kConfigAttributesLen =
sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
sizeof(kConfigAttributes) / sizeof(kConfigAttributes[0]);
bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) {
// Filter out configs which do not support pbuffers, since they
// are used to implement window surfaces.
EGLint surfaceType;
s_egl.eglGetConfigAttrib(
display, config, EGL_SURFACE_TYPE, &surfaceType);
if (!(surfaceType & EGL_PBUFFER_BIT)) {
return false;
}
// Filter out configs which do not support pbuffers, since they
// are used to implement window surfaces.
EGLint surfaceType;
s_egl.eglGetConfigAttrib(display, config, EGL_SURFACE_TYPE, &surfaceType);
if (!(surfaceType & EGL_PBUFFER_BIT)) {
return false;
}
// Filter out configs that do not support RGB pixel values.
EGLint redSize = 0, greenSize = 0, blueSize = 0, alphaSize = 0;
s_egl.eglGetConfigAttrib(
display, config,EGL_RED_SIZE, &redSize);
s_egl.eglGetConfigAttrib(
display, config, EGL_GREEN_SIZE, &greenSize);
s_egl.eglGetConfigAttrib(
display, config, EGL_BLUE_SIZE, &blueSize);
s_egl.eglGetConfigAttrib(
display, config, EGL_ALPHA_SIZE, &alphaSize);
// Filter out configs that do not support RGB pixel values.
EGLint redSize = 0, greenSize = 0, blueSize = 0, alphaSize = 0;
s_egl.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize);
s_egl.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize);
s_egl.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize);
s_egl.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize);
if (!redSize || !greenSize || !blueSize || !alphaSize) {
return false;
}
if (!redSize || !greenSize || !blueSize || !alphaSize) {
return false;
}
return true;
return true;
}
} // namespace
RendererConfig::~RendererConfig() {
delete [] mAttribValues;
RendererConfig::~RendererConfig() { delete[] mAttribValues; }
RendererConfig::RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay)
: mEglConfig(hostConfig), mAttribValues(NULL) {
mAttribValues = new GLint[kConfigAttributesLen];
for (size_t i = 0; i < kConfigAttributesLen; ++i) {
mAttribValues[i] = 0;
s_egl.eglGetConfigAttrib(hostDisplay, hostConfig, kConfigAttributes[i],
&mAttribValues[i]);
// This implementation supports guest window surfaces by wrapping
// them around host Pbuffers, so always report it to the guest.
if (kConfigAttributes[i] == EGL_SURFACE_TYPE) {
mAttribValues[i] |= EGL_WINDOW_BIT;
}
}
}
RendererConfig::RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) :
mEglConfig(hostConfig), mAttribValues(NULL) {
mAttribValues = new GLint[kConfigAttributesLen];
for (size_t i = 0; i < kConfigAttributesLen; ++i) {
mAttribValues[i] = 0;
s_egl.eglGetConfigAttrib(hostDisplay,
hostConfig,
kConfigAttributes[i],
&mAttribValues[i]);
RendererConfigList::RendererConfigList(EGLDisplay display)
: mCount(0), mConfigs(NULL), mDisplay(display) {
if (display == EGL_NO_DISPLAY) {
E("%s: Invalid display value %p (EGL_NO_DISPLAY)\n", __FUNCTION__,
(void*)display);
return;
}
// This implementation supports guest window surfaces by wrapping
// them around host Pbuffers, so always report it to the guest.
if (kConfigAttributes[i] == EGL_SURFACE_TYPE) {
mAttribValues[i] |= EGL_WINDOW_BIT;
}
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
return;
}
EGLConfig* hostConfigs = new EGLConfig[numHostConfigs];
s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs);
mConfigs = new RendererConfig*[numHostConfigs];
for (EGLint i = 0; i < numHostConfigs; ++i) {
// Filter out configs that are not compatible with our implementation.
if (!isCompatibleHostConfig(hostConfigs[i], display)) {
continue;
}
}
mConfigs[mCount] = new RendererConfig(hostConfigs[i], display);
mCount++;
}
RendererConfigList::RendererConfigList(EGLDisplay display) :
mCount(0), mConfigs(NULL), mDisplay(display) {
if (display == EGL_NO_DISPLAY) {
E("%s: Invalid display value %p (EGL_NO_DISPLAY)\n",
__FUNCTION__, (void*)display);
return;
}
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(display, NULL, 0, &numHostConfigs)) {
E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
return;
}
EGLConfig* hostConfigs = new EGLConfig[numHostConfigs];
s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs);
mConfigs = new RendererConfig*[numHostConfigs];
for (EGLint i = 0; i < numHostConfigs; ++i) {
// Filter out configs that are not compatible with our implementation.
if (!isCompatibleHostConfig(hostConfigs[i], display)) {
continue;
}
mConfigs[mCount] = new RendererConfig(hostConfigs[i], display);
mCount++;
}
delete [] hostConfigs;
delete[] hostConfigs;
}
RendererConfigList::~RendererConfigList() {
for (int n = 0; n < mCount; ++n) {
delete mConfigs[n];
}
delete [] mConfigs;
for (int n = 0; n < mCount; ++n) {
delete mConfigs[n];
}
delete[] mConfigs;
}
int RendererConfigList::chooseConfig(const EGLint* attribs,
EGLint* configs,
EGLint configsSize) const {
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
return 0;
int RendererConfigList::chooseConfig(const EGLint* attribs, EGLint* configs,
EGLint configsSize) const {
EGLint numHostConfigs = 0;
if (!s_egl.eglGetConfigs(mDisplay, NULL, 0, &numHostConfigs)) {
E("%s: Could not get number of host EGL configs\n", __FUNCTION__);
return 0;
}
EGLConfig* matchedConfigs = new EGLConfig[numHostConfigs];
// If EGL_SURFACE_TYPE appears in |attribs|, the value passed to
// eglChooseConfig should be forced to EGL_PBUFFER_BIT because that's
// what it used by the current implementation, exclusively. This forces
// the rewrite of |attribs| into a new array.
bool hasSurfaceType = false;
bool mustReplaceSurfaceType = false;
int numAttribs = 0;
while (attribs[numAttribs] != EGL_NONE) {
if (attribs[numAttribs] == EGL_SURFACE_TYPE) {
hasSurfaceType = true;
if (attribs[numAttribs + 1] != EGL_PBUFFER_BIT) {
mustReplaceSurfaceType = true;
}
}
numAttribs += 2;
}
EGLConfig* matchedConfigs = new EGLConfig[numHostConfigs];
EGLint* newAttribs = NULL;
// If EGL_SURFACE_TYPE appears in |attribs|, the value passed to
// eglChooseConfig should be forced to EGL_PBUFFER_BIT because that's
// what it used by the current implementation, exclusively. This forces
// the rewrite of |attribs| into a new array.
bool hasSurfaceType = false;
bool mustReplaceSurfaceType = false;
int numAttribs = 0;
while (attribs[numAttribs] != EGL_NONE) {
if (attribs[numAttribs] == EGL_SURFACE_TYPE) {
hasSurfaceType = true;
if (attribs[numAttribs + 1] != EGL_PBUFFER_BIT) {
mustReplaceSurfaceType = true;
}
}
numAttribs += 2;
if (mustReplaceSurfaceType) {
// There is at least on EGL_SURFACE_TYPE in |attribs|. Copy the
// array and replace all values with EGL_PBUFFER_BIT
newAttribs = new GLint[numAttribs + 1];
memcpy(newAttribs, attribs, numAttribs * sizeof(GLint));
newAttribs[numAttribs] = EGL_NONE;
for (int n = 0; n < numAttribs; n += 2) {
if (newAttribs[n] == EGL_SURFACE_TYPE) {
newAttribs[n + 1] = EGL_PBUFFER_BIT;
}
}
} else if (!hasSurfaceType) {
// There is no EGL_SURFACE_TYPE in |attribs|, then add one entry
// with the value EGL_PBUFFER_BIT.
newAttribs = new GLint[numAttribs + 3];
memcpy(newAttribs, attribs, numAttribs * sizeof(GLint));
newAttribs[numAttribs] = EGL_SURFACE_TYPE;
newAttribs[numAttribs + 1] = EGL_PBUFFER_BIT;
newAttribs[numAttribs + 2] = EGL_NONE;
}
EGLint* newAttribs = NULL;
if (!s_egl.eglChooseConfig(mDisplay, newAttribs ? newAttribs : attribs,
matchedConfigs, numHostConfigs, &numHostConfigs)) {
numHostConfigs = 0;
}
if (mustReplaceSurfaceType) {
// There is at least on EGL_SURFACE_TYPE in |attribs|. Copy the
// array and replace all values with EGL_PBUFFER_BIT
newAttribs = new GLint[numAttribs + 1];
memcpy(newAttribs, attribs, numAttribs * sizeof(GLint));
newAttribs[numAttribs] = EGL_NONE;
for (int n = 0; n < numAttribs; n += 2) {
if (newAttribs[n] == EGL_SURFACE_TYPE) {
newAttribs[n + 1] = EGL_PBUFFER_BIT;
}
}
} else if (!hasSurfaceType) {
// There is no EGL_SURFACE_TYPE in |attribs|, then add one entry
// with the value EGL_PBUFFER_BIT.
newAttribs = new GLint[numAttribs + 3];
memcpy(newAttribs, attribs, numAttribs * sizeof(GLint));
newAttribs[numAttribs] = EGL_SURFACE_TYPE;
newAttribs[numAttribs + 1] = EGL_PBUFFER_BIT;
newAttribs[numAttribs + 2] = EGL_NONE;
delete[] newAttribs;
int result = 0;
for (int n = 0; n < numHostConfigs; ++n) {
// Don't count or write more than |configsSize| items if |configs|
// is not NULL.
if (configs && configsSize > 0 && result >= configsSize) {
break;
}
if (!s_egl.eglChooseConfig(mDisplay,
newAttribs ? newAttribs : attribs,
matchedConfigs,
numHostConfigs,
&numHostConfigs)) {
numHostConfigs = 0;
// Skip incompatible host configs.
if (!isCompatibleHostConfig(matchedConfigs[n], mDisplay)) {
continue;
}
delete [] newAttribs;
int result = 0;
for (int n = 0; n < numHostConfigs; ++n) {
// Don't count or write more than |configsSize| items if |configs|
// is not NULL.
if (configs && configsSize > 0 && result >= configsSize) {
break;
}
// Skip incompatible host configs.
if (!isCompatibleHostConfig(matchedConfigs[n], mDisplay)) {
continue;
}
// Find the FbConfig with the same EGL_CONFIG_ID
EGLint hostConfigId;
s_egl.eglGetConfigAttrib(
mDisplay, matchedConfigs[n], EGL_CONFIG_ID, &hostConfigId);
for (int k = 0; k < mCount; ++k) {
int guestConfigId = mConfigs[k]->getConfigId();
if (guestConfigId == hostConfigId) {
// There is a match. Write it to |configs| if it is not NULL.
if (configs && result < configsSize) {
configs[result] = (uint32_t)k;
}
result ++;
break;
}
// Find the FbConfig with the same EGL_CONFIG_ID
EGLint hostConfigId;
s_egl.eglGetConfigAttrib(mDisplay, matchedConfigs[n], EGL_CONFIG_ID,
&hostConfigId);
for (int k = 0; k < mCount; ++k) {
int guestConfigId = mConfigs[k]->getConfigId();
if (guestConfigId == hostConfigId) {
// There is a match. Write it to |configs| if it is not NULL.
if (configs && result < configsSize) {
configs[result] = (uint32_t)k;
}
result++;
break;
}
}
}
delete [] matchedConfigs;
delete[] matchedConfigs;
return result;
return result;
}
void RendererConfigList::getPackInfo(EGLint* numConfigs,
EGLint* numAttributes) const {
if (numConfigs) {
*numConfigs = mCount;
}
if (numAttributes) {
*numAttributes = static_cast<EGLint>(kConfigAttributesLen);
}
EGLint* numAttributes) const {
if (numConfigs) {
*numConfigs = mCount;
}
if (numAttributes) {
*numAttributes = static_cast<EGLint>(kConfigAttributesLen);
}
}
EGLint RendererConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const {
GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize;
if (!buffer || bufferByteSize < neededByteSize) {
return -neededByteSize;
}
// Write to the buffer the config attribute ids, followed for each one
// of the configs, their values.
memcpy(buffer, kConfigAttributes, kConfigAttributesLen * kGLuintSize);
EGLint RendererConfigList::packConfigs(GLuint bufferByteSize,
GLuint* buffer) const {
GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize;
if (!buffer || bufferByteSize < neededByteSize) {
return -neededByteSize;
}
// Write to the buffer the config attribute ids, followed for each one
// of the configs, their values.
memcpy(buffer, kConfigAttributes, kConfigAttributesLen * kGLuintSize);
for (int i = 0; i < mCount; ++i) {
memcpy(buffer + (i + 1) * kConfigAttributesLen,
mConfigs[i]->mAttribValues,
kConfigAttributesLen * kGLuintSize);
}
return mCount;
for (int i = 0; i < mCount; ++i) {
memcpy(buffer + (i + 1) * kConfigAttributesLen, mConfigs[i]->mAttribValues,
kConfigAttributesLen * kGLuintSize);
}
return mCount;
}

View file

@ -33,43 +33,43 @@
// an FbConfigList from the host EGLDisplay, and use its size() and get()
// methods to access it.
class RendererConfig {
public:
// Destructor
~RendererConfig();
public:
// Destructor
~RendererConfig();
// Retrieve host EGLConfig.
EGLConfig getEglConfig() const { return mEglConfig; }
// Retrieve host EGLConfig.
EGLConfig getEglConfig() const { return mEglConfig; }
// Get depth size in bits.
GLuint getDepthSize() const { return getAttribValue(0); }
// Get depth size in bits.
GLuint getDepthSize() const { return getAttribValue(0); }
// Get stencil size in bits.
GLuint getStencilSize() const { return getAttribValue(1); }
// Get stencil size in bits.
GLuint getStencilSize() const { return getAttribValue(1); }
// Get renderable type mask.
GLuint getRenderableType() const { return getAttribValue(2); }
// Get renderable type mask.
GLuint getRenderableType() const { return getAttribValue(2); }
// Get surface type mask.
GLuint getSurfaceType() const { return getAttribValue(3); }
// Get surface type mask.
GLuint getSurfaceType() const { return getAttribValue(3); }
// Get the EGL_CONFIG_ID value. This is the same as the one of the
// underlying host EGLConfig handle.
GLint getConfigId() const { return (GLint)getAttribValue(4); }
// Get the EGL_CONFIG_ID value. This is the same as the one of the
// underlying host EGLConfig handle.
GLint getConfigId() const { return (GLint)getAttribValue(4); }
private:
RendererConfig();
RendererConfig(RendererConfig& other);
private:
RendererConfig();
RendererConfig(RendererConfig& other);
explicit RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay);
explicit RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay);
friend class RendererConfigList;
friend class RendererConfigList;
GLuint getAttribValue(int n) const {
return mAttribValues ? mAttribValues[n] : 0U;
}
GLuint getAttribValue(int n) const {
return mAttribValues ? mAttribValues[n] : 0U;
}
EGLConfig mEglConfig;
GLint* mAttribValues;
EGLConfig mEglConfig;
GLint* mAttribValues;
};
// A class to model the list of FbConfig for a given EGLDisplay, this is
@ -92,72 +92,71 @@ private:
// 5) Use getPackInfo() and packConfigs() to retrieve information about
// available configs to the guest.
class RendererConfigList {
public:
// Create a new list of FbConfig instance, by querying all compatible
// host configs from |display|. A compatible config is one that supports
// Pbuffers and RGB pixel values.
//
// After construction, call empty() to check if there are items.
// An empty list means there was an error during construction.
explicit RendererConfigList(EGLDisplay display);
public:
// Create a new list of FbConfig instance, by querying all compatible
// host configs from |display|. A compatible config is one that supports
// Pbuffers and RGB pixel values.
//
// After construction, call empty() to check if there are items.
// An empty list means there was an error during construction.
explicit RendererConfigList(EGLDisplay display);
// Destructor.
~RendererConfigList();
// Destructor.
~RendererConfigList();
// Return true iff the list is empty. true means there was an error
// during construction.
bool empty() const { return mCount == 0; }
// Return true iff the list is empty. true means there was an error
// during construction.
bool empty() const { return mCount == 0; }
// Return the number of FbConfig instances in the list.
// Each instance is identified by a number from 0 to N-1,
// where N is the result of this function.
size_t size() const { return static_cast<size_t>(mCount); }
// Return the number of FbConfig instances in the list.
// Each instance is identified by a number from 0 to N-1,
// where N is the result of this function.
size_t size() const { return static_cast<size_t>(mCount); }
// Retrieve the FbConfig instance associated with |guestId|,
// which must be an integer between 0 and |size() - 1|. Returns
// NULL in case of failure.
const RendererConfig* get(int guestId) const {
if (guestId >= 0 && guestId < mCount) {
return mConfigs[guestId];
} else {
return NULL;
}
// Retrieve the FbConfig instance associated with |guestId|,
// which must be an integer between 0 and |size() - 1|. Returns
// NULL in case of failure.
const RendererConfig* get(int guestId) const {
if (guestId >= 0 && guestId < mCount) {
return mConfigs[guestId];
} else {
return NULL;
}
}
// Use |attribs| a list of EGL attribute name/values terminated by
// EGL_NONE, to select a set of matching FbConfig instances.
//
// On success, returns the number of matching instances.
// If |configs| is not NULL, it will be populated with the guest IDs
// of the matched FbConfig instances.
//
// |configsSize| is the number of entries in the |configs| array. The
// function will never write more than |configsSize| entries into
// |configsSize|.
EGLint chooseConfig(const EGLint* attribs,
EGLint* configs,
EGLint configsSize) const;
// Use |attribs| a list of EGL attribute name/values terminated by
// EGL_NONE, to select a set of matching FbConfig instances.
//
// On success, returns the number of matching instances.
// If |configs| is not NULL, it will be populated with the guest IDs
// of the matched FbConfig instances.
//
// |configsSize| is the number of entries in the |configs| array. The
// function will never write more than |configsSize| entries into
// |configsSize|.
EGLint chooseConfig(const EGLint* attribs, EGLint* configs,
EGLint configsSize) const;
// Retrieve information that can be sent to the guest before packed
// config list information. If |numConfigs| is NULL, then |*numConfigs|
// will be set on return to the number of config instances.
// If |numAttribs| is not NULL, then |*numAttribs| will be set on return
// to the number of attribute values cached by each FbConfig instance.
void getPackInfo(EGLint* mumConfigs, EGLint* numAttribs) const;
// Retrieve information that can be sent to the guest before packed
// config list information. If |numConfigs| is NULL, then |*numConfigs|
// will be set on return to the number of config instances.
// If |numAttribs| is not NULL, then |*numAttribs| will be set on return
// to the number of attribute values cached by each FbConfig instance.
void getPackInfo(EGLint* mumConfigs, EGLint* numAttribs) const;
// Write the full list information into an array of EGLuint items.
// |buffer| is the output buffer that will receive the data.
// |bufferByteSize| is teh buffer size in bytes.
// On success, this returns
EGLint packConfigs(GLuint bufferByteSize, GLuint* buffer) const;
// Write the full list information into an array of EGLuint items.
// |buffer| is the output buffer that will receive the data.
// |bufferByteSize| is teh buffer size in bytes.
// On success, this returns
EGLint packConfigs(GLuint bufferByteSize, GLuint* buffer) const;
private:
RendererConfigList();
RendererConfigList(const RendererConfigList& other);
private:
RendererConfigList();
RendererConfigList(const RendererConfigList& other);
int mCount;
RendererConfig** mConfigs;
EGLDisplay mDisplay;
int mCount;
RendererConfig** mConfigs;
EGLDisplay mDisplay;
};
#endif // _LIBRENDER_FB_CONFIG_H

View file

@ -15,152 +15,130 @@
*/
#include "SocketStream.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/un.h>
#include <unistd.h>
SocketStream::SocketStream(size_t bufSize) :
IOStream(bufSize),
m_sock(-1),
m_bufsize(bufSize),
m_buf(NULL)
{
SocketStream::SocketStream(size_t bufSize)
: IOStream(bufSize), m_sock(-1), m_bufsize(bufSize), m_buf(NULL) {}
SocketStream::SocketStream(int sock, size_t bufSize)
: IOStream(bufSize), m_sock(sock), m_bufsize(bufSize), m_buf(NULL) {}
SocketStream::~SocketStream() {
if (m_sock >= 0) {
forceStop();
if (close(m_sock) < 0) perror("Closing SocketStream failed");
// DBG("SocketStream::~close @ %d \n", m_sock);
m_sock = -1;
}
if (m_buf != NULL) {
free(m_buf);
m_buf = NULL;
}
}
SocketStream::SocketStream(int sock, size_t bufSize) :
IOStream(bufSize),
m_sock(sock),
m_bufsize(bufSize),
m_buf(NULL)
{
}
SocketStream::~SocketStream()
{
if (m_sock >= 0) {
forceStop();
if(close(m_sock) < 0)
perror("Closing SocketStream failed");
// DBG("SocketStream::~close @ %d \n", m_sock);
m_sock = -1;
void *SocketStream::allocBuffer(size_t minSize) {
size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
if (!m_buf) {
m_buf = (unsigned char *)malloc(allocSize);
} else if (m_bufsize < allocSize) {
unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
if (p != NULL) {
m_buf = p;
m_bufsize = allocSize;
} else {
ERR("%s: realloc (%zu) failed\n", __FUNCTION__, allocSize);
free(m_buf);
m_buf = NULL;
m_bufsize = 0;
}
if (m_buf != NULL) {
free(m_buf);
m_buf = NULL;
}
}
}
void *SocketStream::allocBuffer(size_t minSize)
{
size_t allocSize = (m_bufsize < minSize ? minSize : m_bufsize);
if (!m_buf) {
m_buf = (unsigned char *)malloc(allocSize);
}
else if (m_bufsize < allocSize) {
unsigned char *p = (unsigned char *)realloc(m_buf, allocSize);
if (p != NULL) {
m_buf = p;
m_bufsize = allocSize;
} else {
ERR("%s: realloc (%zu) failed\n", __FUNCTION__, allocSize);
free(m_buf);
m_buf = NULL;
m_bufsize = 0;
}
}
return m_buf;
return m_buf;
};
int SocketStream::commitBuffer(size_t size)
{
return writeFully(m_buf, size);
}
int SocketStream::commitBuffer(size_t size) { return writeFully(m_buf, size); }
int SocketStream::writeFully(const void* buffer, size_t size)
{
if (!valid()) return -1;
int SocketStream::writeFully(const void *buffer, size_t size) {
if (!valid()) return -1;
size_t res = size;
int retval = 0;
size_t res = size;
int retval = 0;
while (res > 0) {
ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0);
if (stat < 0) {
if (errno != EINTR) {
retval = stat;
ERR("%s: failed: %s\n", __FUNCTION__, strerror(errno));
break;
}
} else {
res -= stat;
}
}
return retval;
}
const unsigned char *SocketStream::readFully(void *buf, size_t len)
{
if (!valid()) return NULL;
if (!buf) {
return NULL; // do not allow NULL buf in that implementation
}
size_t res = len;
while (res > 0) {
ssize_t stat = ::recv(m_sock, (char *)(buf) + len - res, res, 0);
if (stat > 0) {
res -= stat;
continue;
}
if (stat == 0 || errno != EINTR) { // client shutdown or error
return NULL;
}
}
return (const unsigned char *)buf;
}
const unsigned char *SocketStream::read( void *buf, size_t *inout_len)
{
if (!valid()) return NULL;
if (!buf) {
return NULL; // do not allow NULL buf in that implementation
}
int n;
do {
n = this->recv(buf, *inout_len);
} while( n < 0 && errno == EINTR );
if (n > 0) {
*inout_len = n;
return (const unsigned char *)buf;
}
return NULL;
}
int SocketStream::recv(void *buf, size_t len)
{
if (!valid()) return int(ERR_INVALID_SOCKET);
int res = 0;
while(true) {
res = ::recv(m_sock, (char *)buf, len, 0);
if (res < 0) {
if (errno == EINTR) {
continue;
}
}
while (res > 0) {
ssize_t stat = ::send(m_sock, (const char *)buffer + (size - res), res, 0);
if (stat < 0) {
if (errno != EINTR) {
retval = stat;
ERR("%s: failed: %s\n", __FUNCTION__, strerror(errno));
break;
}
} else {
res -= stat;
}
return res;
}
return retval;
}
const unsigned char *SocketStream::readFully(void *buf, size_t len) {
if (!valid()) return NULL;
if (!buf) {
return NULL; // do not allow NULL buf in that implementation
}
size_t res = len;
while (res > 0) {
ssize_t stat = ::recv(m_sock, (char *)(buf) + len - res, res, 0);
if (stat > 0) {
res -= stat;
continue;
}
if (stat == 0 || errno != EINTR) { // client shutdown or error
return NULL;
}
}
return (const unsigned char *)buf;
}
const unsigned char *SocketStream::read(void *buf, size_t *inout_len) {
if (!valid()) return NULL;
if (!buf) {
return NULL; // do not allow NULL buf in that implementation
}
int n;
do {
n = this->recv(buf, *inout_len);
} while (n < 0 && errno == EINTR);
if (n > 0) {
*inout_len = n;
return (const unsigned char *)buf;
}
return NULL;
}
int SocketStream::recv(void *buf, size_t len) {
if (!valid()) return int(ERR_INVALID_SOCKET);
int res = 0;
while (true) {
res = ::recv(m_sock, (char *)buf, len, 0);
if (res < 0) {
if (errno == EINTR) {
continue;
}
}
break;
}
return res;
}
void SocketStream::forceStop() {
// Shutdown socket to force read/write errors.
::shutdown(m_sock, SHUT_RDWR);
// Shutdown socket to force read/write errors.
::shutdown(m_sock, SHUT_RDWR);
}

View file

@ -20,34 +20,34 @@
#include "IOStream.h"
class SocketStream : public IOStream {
public:
typedef enum { ERR_INVALID_SOCKET = -1000 } SocketStreamError;
static const size_t MAX_ADDRSTR_LEN = 256;
public:
typedef enum { ERR_INVALID_SOCKET = -1000 } SocketStreamError;
static const size_t MAX_ADDRSTR_LEN = 256;
explicit SocketStream(size_t bufsize = 10000);
virtual ~SocketStream();
explicit SocketStream(size_t bufsize = 10000);
virtual ~SocketStream();
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]) = 0;
virtual SocketStream *accept() = 0;
virtual int connect(const char* addr) = 0;
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]) = 0;
virtual SocketStream *accept() = 0;
virtual int connect(const char *addr) = 0;
virtual void *allocBuffer(size_t minSize);
virtual int commitBuffer(size_t size);
virtual const unsigned char *readFully(void *buf, size_t len);
virtual const unsigned char *read(void *buf, size_t *inout_len);
virtual void *allocBuffer(size_t minSize);
virtual int commitBuffer(size_t size);
virtual const unsigned char *readFully(void *buf, size_t len);
virtual const unsigned char *read(void *buf, size_t *inout_len);
bool valid() { return m_sock >= 0; }
virtual int recv(void *buf, size_t len);
virtual int writeFully(const void *buf, size_t len);
bool valid() { return m_sock >= 0; }
virtual int recv(void *buf, size_t len);
virtual int writeFully(const void *buf, size_t len);
virtual void forceStop();
virtual void forceStop();
protected:
int m_sock;
size_t m_bufsize;
unsigned char *m_buf;
protected:
int m_sock;
size_t m_bufsize;
unsigned char *m_buf;
SocketStream(int sock, size_t bufSize);
SocketStream(int sock, size_t bufSize);
};
#endif /* __SOCKET_STREAM_H */

View file

@ -19,8 +19,8 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@ -29,46 +29,42 @@
TcpStream::TcpStream(size_t bufSize) : SocketStream(bufSize) {}
TcpStream::TcpStream(int sock, size_t bufSize) :
SocketStream(sock, bufSize) {
// disable Nagle algorithm to improve bandwidth of small
// packets which are quite common in our implementation.
emugl::socketTcpDisableNagle(sock);
TcpStream::TcpStream(int sock, size_t bufSize) : SocketStream(sock, bufSize) {
// disable Nagle algorithm to improve bandwidth of small
// packets which are quite common in our implementation.
emugl::socketTcpDisableNagle(sock);
}
int TcpStream::listen(char addrstr[MAX_ADDRSTR_LEN]) {
m_sock = emugl::socketTcpLoopbackServer(0, SOCK_STREAM);
if (!valid())
return int(ERR_INVALID_SOCKET);
m_sock = emugl::socketTcpLoopbackServer(0, SOCK_STREAM);
if (!valid()) return int(ERR_INVALID_SOCKET);
int port = emugl::socketGetPort(m_sock);
if (port < 0) {
::close(m_sock);
return int(ERR_INVALID_SOCKET);
}
int port = emugl::socketGetPort(m_sock);
if (port < 0) {
::close(m_sock);
return int(ERR_INVALID_SOCKET);
}
snprintf(addrstr, MAX_ADDRSTR_LEN - 1, "%hu", port);
addrstr[MAX_ADDRSTR_LEN-1] = '\0';
snprintf(addrstr, MAX_ADDRSTR_LEN - 1, "%hu", port);
addrstr[MAX_ADDRSTR_LEN - 1] = '\0';
return 0;
return 0;
}
SocketStream * TcpStream::accept() {
int clientSock = emugl::socketAccept(m_sock);
if (clientSock < 0)
return NULL;
SocketStream* TcpStream::accept() {
int clientSock = emugl::socketAccept(m_sock);
if (clientSock < 0) return NULL;
return new TcpStream(clientSock, m_bufsize);
return new TcpStream(clientSock, m_bufsize);
}
int TcpStream::connect(const char* addr) {
int port = atoi(addr);
m_sock = emugl::socketTcpLoopbackClient(port, SOCK_STREAM);
return valid() ? 0 : -1;
int port = atoi(addr);
m_sock = emugl::socketTcpLoopbackClient(port, SOCK_STREAM);
return valid() ? 0 : -1;
}
int TcpStream::connect(const char* hostname, unsigned short port)
{
m_sock = emugl::socketTcpClient(hostname, port, SOCK_STREAM);
return valid() ? 0 : -1;
int TcpStream::connect(const char* hostname, unsigned short port) {
m_sock = emugl::socketTcpClient(hostname, port, SOCK_STREAM);
return valid() ? 0 : -1;
}

View file

@ -19,14 +19,15 @@
#include "SocketStream.h"
class TcpStream : public SocketStream {
public:
explicit TcpStream(size_t bufsize = 10000);
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]);
virtual SocketStream *accept();
virtual int connect(const char* addr);
int connect(const char* hostname, unsigned short port);
private:
TcpStream(int sock, size_t bufSize);
public:
explicit TcpStream(size_t bufsize = 10000);
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]);
virtual SocketStream* accept();
virtual int connect(const char* addr);
int connect(const char* hostname, unsigned short port);
private:
TcpStream(int sock, size_t bufSize);
};
#endif

View file

@ -21,7 +21,7 @@
#include <vector>
#include <stdio.h>
#define ERR(...) fprintf(stderr, __VA_ARGS__)
#define ERR(...) fprintf(stderr, __VA_ARGS__)
// M_PI isn't defined in C++ (when strict ISO compliance is enabled)
#ifndef M_PI
@ -35,25 +35,25 @@ namespace {
// |shaderText| is a 0-terminated C string for the shader source to use.
// On success, return the handle of the new compiled shader, or 0 on failure.
GLuint createShader(GLint shaderType, const char* shaderText) {
// Create new shader handle and attach source.
GLuint shader = s_gles2.glCreateShader(shaderType);
if (!shader) {
return 0;
}
const GLchar* text = static_cast<const GLchar*>(shaderText);
const GLint textLen = ::strlen(shaderText);
s_gles2.glShaderSource(shader, 1, &text, &textLen);
// Create new shader handle and attach source.
GLuint shader = s_gles2.glCreateShader(shaderType);
if (!shader) {
return 0;
}
const GLchar* text = static_cast<const GLchar*>(shaderText);
const GLint textLen = ::strlen(shaderText);
s_gles2.glShaderSource(shader, 1, &text, &textLen);
// Compiler the shader.
GLint success;
s_gles2.glCompileShader(shader);
s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
s_gles2.glDeleteShader(shader);
return 0;
}
// Compiler the shader.
GLint success;
s_gles2.glCompileShader(shader);
s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
s_gles2.glDeleteShader(shader);
return 0;
}
return shader;
return shader;
}
// No scaling / projection since we want to fill the whole viewport with
@ -80,173 +80,156 @@ const char kFragmentShaderSource[] =
// Hard-coded arrays of vertex information.
struct Vertex {
float pos[3];
float coord[2];
float pos[3];
float coord[2];
};
const Vertex kVertices[] = {
{{ +1, -1, +0 }, { +1, +1 }},
{{ +1, +1, +0 }, { +1, +0 }},
{{ -1, +1, +0 }, { +0, +0 }},
{{ -1, -1, +0 }, { +0, +1 }},
{{+1, -1, +0}, {+1, +1}},
{{+1, +1, +0}, {+1, +0}},
{{-1, +1, +0}, {+0, +0}},
{{-1, -1, +0}, {+0, +1}},
};
const GLubyte kIndices[] = { 0, 1, 2, 2, 3, 0 };
const GLubyte kIndices[] = {0, 1, 2, 2, 3, 0};
const GLint kIndicesLen = sizeof(kIndices) / sizeof(kIndices[0]);
} // namespace
TextureDraw::TextureDraw(EGLDisplay display) :
mDisplay(display),
mVertexShader(0),
mFragmentShader(0),
mProgram(0),
mPositionSlot(-1),
mInCoordSlot(-1),
mTextureSlot(-1),
mRotationSlot(-1),
mTranslationSlot(-1) {
// Create shaders and program.
mVertexShader = createShader(GL_VERTEX_SHADER, kVertexShaderSource);
mFragmentShader = createShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
TextureDraw::TextureDraw(EGLDisplay display)
: mDisplay(display),
mVertexShader(0),
mFragmentShader(0),
mProgram(0),
mPositionSlot(-1),
mInCoordSlot(-1),
mTextureSlot(-1),
mRotationSlot(-1),
mTranslationSlot(-1) {
// Create shaders and program.
mVertexShader = createShader(GL_VERTEX_SHADER, kVertexShaderSource);
mFragmentShader = createShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
mProgram = s_gles2.glCreateProgram();
s_gles2.glAttachShader(mProgram, mVertexShader);
s_gles2.glAttachShader(mProgram, mFragmentShader);
mProgram = s_gles2.glCreateProgram();
s_gles2.glAttachShader(mProgram, mVertexShader);
s_gles2.glAttachShader(mProgram, mFragmentShader);
GLint success;
s_gles2.glLinkProgram(mProgram);
s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
if (success == GL_FALSE) {
GLchar messages[256];
s_gles2.glGetProgramInfoLog(
mProgram, sizeof(messages), 0, &messages[0]);
ERR("%s: Could not create/link program: %s\n", __FUNCTION__, messages);
s_gles2.glDeleteProgram(mProgram);
mProgram = 0;
return;
}
GLint success;
s_gles2.glLinkProgram(mProgram);
s_gles2.glGetProgramiv(mProgram, GL_LINK_STATUS, &success);
if (success == GL_FALSE) {
GLchar messages[256];
s_gles2.glGetProgramInfoLog(mProgram, sizeof(messages), 0, &messages[0]);
ERR("%s: Could not create/link program: %s\n", __FUNCTION__, messages);
s_gles2.glDeleteProgram(mProgram);
mProgram = 0;
return;
}
s_gles2.glUseProgram(mProgram);
s_gles2.glUseProgram(mProgram);
// Retrieve attribute/uniform locations.
mPositionSlot = s_gles2.glGetAttribLocation(mProgram, "position");
s_gles2.glEnableVertexAttribArray(mPositionSlot);
// Retrieve attribute/uniform locations.
mPositionSlot = s_gles2.glGetAttribLocation(mProgram, "position");
s_gles2.glEnableVertexAttribArray(mPositionSlot);
mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord");
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord");
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
mTextureSlot = s_gles2.glGetUniformLocation(mProgram, "texture");
mTextureSlot = s_gles2.glGetUniformLocation(mProgram, "texture");
// Create vertex and index buffers.
s_gles2.glGenBuffers(1, &mVertexBuffer);
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glBufferData(
GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW);
// Create vertex and index buffers.
s_gles2.glGenBuffers(1, &mVertexBuffer);
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices,
GL_STATIC_DRAW);
s_gles2.glGenBuffers(1, &mIndexBuffer);
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER,
sizeof(kIndices),
kIndices,
GL_STATIC_DRAW);
s_gles2.glGenBuffers(1, &mIndexBuffer);
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
s_gles2.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndices), kIndices,
GL_STATIC_DRAW);
}
bool TextureDraw::draw(GLuint texture) {
if (!mProgram) {
ERR("%s: no program\n", __FUNCTION__);
return false;
}
if (!mProgram) {
ERR("%s: no program\n", __FUNCTION__);
return false;
}
// TODO(digit): Save previous program state.
// TODO(digit): Save previous program state.
GLenum err;
GLenum err;
s_gles2.glUseProgram(mProgram);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not use program error=0x%x\n",
__FUNCTION__, err);
}
s_gles2.glUseProgram(mProgram);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not use program error=0x%x\n", __FUNCTION__, err);
}
// Setup the |position| attribute values.
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n", __FUNCTION__, err);
}
// Setup the |position| attribute values.
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not bind GL_ARRAY_BUFFER error=0x%x\n",
__FUNCTION__, err);
}
s_gles2.glEnableVertexAttribArray(mPositionSlot);
s_gles2.glVertexAttribPointer(mPositionSlot, 3, GL_FLOAT, GL_FALSE,
sizeof(Vertex), 0);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
__FUNCTION__, err);
}
s_gles2.glEnableVertexAttribArray(mPositionSlot);
s_gles2.glVertexAttribPointer(mPositionSlot,
3,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
0);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could glVertexAttribPointer with mPositionSlot error=0x%x\n",
__FUNCTION__, err);
}
// Setup the |inCoord| attribute values.
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
s_gles2.glVertexAttribPointer(
mInCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
reinterpret_cast<GLvoid*>(static_cast<uintptr_t>(sizeof(float) * 3)));
// Setup the |inCoord| attribute values.
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
s_gles2.glVertexAttribPointer(mInCoordSlot,
2,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
reinterpret_cast<GLvoid*>(
static_cast<uintptr_t>(
sizeof(float) * 3)));
// setup the |texture| uniform value.
s_gles2.glActiveTexture(GL_TEXTURE0);
s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
s_gles2.glUniform1i(mTextureSlot, 0);
// setup the |texture| uniform value.
s_gles2.glActiveTexture(GL_TEXTURE0);
s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
s_gles2.glUniform1i(mTextureSlot, 0);
// Validate program, just to be sure.
s_gles2.glValidateProgram(mProgram);
GLint validState = 0;
s_gles2.glGetProgramiv(mProgram, GL_VALIDATE_STATUS, &validState);
if (validState == GL_FALSE) {
GLchar messages[256];
s_gles2.glGetProgramInfoLog(mProgram, sizeof(messages), 0, &messages[0]);
ERR("%s: Could not run program: %s\n", __FUNCTION__, messages);
return false;
}
// Validate program, just to be sure.
s_gles2.glValidateProgram(mProgram);
GLint validState = 0;
s_gles2.glGetProgramiv(mProgram, GL_VALIDATE_STATUS, &validState);
if (validState == GL_FALSE) {
GLchar messages[256];
s_gles2.glGetProgramInfoLog(
mProgram, sizeof(messages), 0, &messages[0]);
ERR("%s: Could not run program: %s\n", __FUNCTION__, messages);
return false;
}
// Do the rendering.
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
__FUNCTION__, err);
}
// Do the rendering.
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) error=0x%x\n",
__FUNCTION__, err);
}
s_gles2.glDrawElements(GL_TRIANGLES, kIndicesLen, GL_UNSIGNED_BYTE, 0);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not glDrawElements() error=0x%x\n", __FUNCTION__, err);
}
s_gles2.glDrawElements(GL_TRIANGLES, kIndicesLen, GL_UNSIGNED_BYTE, 0);
err = s_gles2.glGetError();
if (err != GL_NO_ERROR) {
ERR("%s: Could not glDrawElements() error=0x%x\n",
__FUNCTION__, err);
}
// TODO(digit): Restore previous program state.
// TODO(digit): Restore previous program state.
return true;
return true;
}
TextureDraw::~TextureDraw() {
s_gles2.glDeleteBuffers(1, &mIndexBuffer);
s_gles2.glDeleteBuffers(1, &mVertexBuffer);
s_gles2.glDeleteBuffers(1, &mIndexBuffer);
s_gles2.glDeleteBuffers(1, &mVertexBuffer);
if (mFragmentShader) {
s_gles2.glDeleteShader(mFragmentShader);
}
if (mVertexShader) {
s_gles2.glDeleteShader(mVertexShader);
}
if (mFragmentShader) {
s_gles2.glDeleteShader(mFragmentShader);
}
if (mVertexShader) {
s_gles2.glDeleteShader(mVertexShader);
}
}

View file

@ -30,29 +30,29 @@
// framebuffer with texture content.
//
class TextureDraw {
public:
// Create a new instance.
TextureDraw(EGLDisplay display);
public:
// Create a new instance.
TextureDraw(EGLDisplay display);
// Destructor
~TextureDraw();
// Destructor
~TextureDraw();
// Fill the current framebuffer with the content of |texture|, which must
// be the name of a GLES 2.x texture object.
bool draw(GLuint texture);
// Fill the current framebuffer with the content of |texture|, which must
// be the name of a GLES 2.x texture object.
bool draw(GLuint texture);
private:
EGLDisplay mDisplay;
GLuint mVertexShader;
GLuint mFragmentShader;
GLuint mProgram;
GLint mPositionSlot;
GLint mInCoordSlot;
GLint mTextureSlot;
GLint mRotationSlot;
GLint mTranslationSlot;
GLuint mVertexBuffer;
GLuint mIndexBuffer;
private:
EGLDisplay mDisplay;
GLuint mVertexShader;
GLuint mFragmentShader;
GLuint mProgram;
GLint mPositionSlot;
GLint mInCoordSlot;
GLint mTextureSlot;
GLint mRotationSlot;
GLint mTranslationSlot;
GLuint mVertexBuffer;
GLuint mIndexBuffer;
};
#endif // TEXTURE_DRAW_H

View file

@ -22,7 +22,7 @@
#include <string>
#include <utility>
#define ERR(...) fprintf(stderr, __VA_ARGS__)
#define ERR(...) fprintf(stderr, __VA_ARGS__)
#define MAX_FACTOR_POWER 4
static const char kCommonShaderSource[] =
@ -126,219 +126,237 @@ const char kFragmentShaderSource[] =
static const float kVertexData[] = {-1, -1, 3, -1, -1, 3};
static void detachShaders(GLuint program) {
GLuint shaders[2] = {};
GLsizei count = 0;
s_gles2.glGetAttachedShaders(program, 2, &count, shaders);
if (s_gles2.glGetError() == GL_NO_ERROR) {
for (GLsizei i = 0; i < count; i++) {
s_gles2.glDetachShader(program, shaders[i]);
s_gles2.glDeleteShader(shaders[i]);
}
GLuint shaders[2] = {};
GLsizei count = 0;
s_gles2.glGetAttachedShaders(program, 2, &count, shaders);
if (s_gles2.glGetError() == GL_NO_ERROR) {
for (GLsizei i = 0; i < count; i++) {
s_gles2.glDetachShader(program, shaders[i]);
s_gles2.glDeleteShader(shaders[i]);
}
}
}
static GLuint createShader(GLenum type, const std::initializer_list<const char*>& source) {
GLint success, infoLength;
static GLuint createShader(GLenum type,
const std::initializer_list<const char*>& source) {
GLint success, infoLength;
GLuint shader = s_gles2.glCreateShader(type);
if (shader) {
s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
s_gles2.glCompileShader(shader);
s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
std::string infoLog(infoLength + 1, '\0');
s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
ERR("%s shader compile failed:\n%s\n",
(type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment",
infoLog.c_str());
s_gles2.glDeleteShader(shader);
shader = 0;
}
GLuint shader = s_gles2.glCreateShader(type);
if (shader) {
s_gles2.glShaderSource(shader, source.size(), source.begin(), nullptr);
s_gles2.glCompileShader(shader);
s_gles2.glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
s_gles2.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
std::string infoLog(infoLength + 1, '\0');
s_gles2.glGetShaderInfoLog(shader, infoLength, nullptr, &infoLog[0]);
ERR("%s shader compile failed:\n%s\n",
(type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment", infoLog.c_str());
s_gles2.glDeleteShader(shader);
shader = 0;
}
return shader;
}
return shader;
}
static void attachShaders(TextureResize::Framebuffer* fb, const char* factorDefine,
const char* dimensionDefine, GLuint width, GLuint height) {
static void attachShaders(TextureResize::Framebuffer* fb,
const char* factorDefine, const char* dimensionDefine,
GLuint width, GLuint height) {
std::ostringstream dimensionConst;
dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height
<< ");\n";
std::ostringstream dimensionConst;
dimensionConst << "const vec2 kDimension = vec2(" << width << ", " << height << ");\n";
GLuint vShader = createShader(
GL_VERTEX_SHADER, {factorDefine, dimensionDefine, kCommonShaderSource,
dimensionConst.str().c_str(), kVertexShaderSource});
GLuint fShader = createShader(
GL_FRAGMENT_SHADER, {factorDefine, dimensionDefine, kCommonShaderSource,
kFragmentShaderSource});
GLuint vShader = createShader(GL_VERTEX_SHADER, {
factorDefine, dimensionDefine,
kCommonShaderSource, dimensionConst.str().c_str(), kVertexShaderSource
});
GLuint fShader = createShader(GL_FRAGMENT_SHADER, {
factorDefine, dimensionDefine, kCommonShaderSource, kFragmentShaderSource
});
if (!vShader || !fShader) {
return;
}
if (!vShader || !fShader) {
return;
}
s_gles2.glAttachShader(fb->program, vShader);
s_gles2.glAttachShader(fb->program, fShader);
s_gles2.glLinkProgram(fb->program);
s_gles2.glAttachShader(fb->program, vShader);
s_gles2.glAttachShader(fb->program, fShader);
s_gles2.glLinkProgram(fb->program);
s_gles2.glUseProgram(fb->program);
fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
s_gles2.glUseProgram(fb->program);
fb->aPosition = s_gles2.glGetAttribLocation(fb->program, "aPosition");
fb->uTexture = s_gles2.glGetUniformLocation(fb->program, "uTexture");
}
TextureResize::TextureResize(GLuint width, GLuint height) :
mWidth(width),
mHeight(height),
mFactor(1),
mFBWidth({0,}),
mFBHeight({0,}) {
s_gles2.glGenTextures(1, &mFBWidth.texture);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
TextureResize::TextureResize(GLuint width, GLuint height)
: mWidth(width),
mHeight(height),
mFactor(1),
mFBWidth({
0,
}),
mFBHeight({
0,
}) {
s_gles2.glGenTextures(1, &mFBWidth.texture);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_gles2.glGenTextures(1, &mFBHeight.texture);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_gles2.glGenTextures(1, &mFBHeight.texture);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
s_gles2.glGenFramebuffers(1, &mFBWidth.framebuffer);
s_gles2.glGenFramebuffers(1, &mFBHeight.framebuffer);
mFBWidth.program = s_gles2.glCreateProgram();
mFBHeight.program = s_gles2.glCreateProgram();
mFBWidth.program = s_gles2.glCreateProgram();
mFBHeight.program = s_gles2.glCreateProgram();
s_gles2.glGenBuffers(1, &mVertexBuffer);
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STATIC_DRAW);
s_gles2.glGenBuffers(1, &mVertexBuffer);
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData,
GL_STATIC_DRAW);
}
TextureResize::~TextureResize() {
GLuint fb[2] = {mFBWidth.framebuffer, mFBHeight.framebuffer};
s_gles2.glDeleteFramebuffers(2, fb);
GLuint fb[2] = {mFBWidth.framebuffer, mFBHeight.framebuffer};
s_gles2.glDeleteFramebuffers(2, fb);
GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
s_gles2.glDeleteTextures(2, tex);
GLuint tex[2] = {mFBWidth.texture, mFBHeight.texture};
s_gles2.glDeleteTextures(2, tex);
s_gles2.glDeleteProgram(mFBWidth.program);
s_gles2.glDeleteProgram(mFBHeight.program);
s_gles2.glDeleteProgram(mFBWidth.program);
s_gles2.glDeleteProgram(mFBHeight.program);
s_gles2.glDeleteBuffers(1, &mVertexBuffer);
s_gles2.glDeleteBuffers(1, &mVertexBuffer);
}
GLuint TextureResize::update(GLuint texture) {
// Store the viewport. The viewport is clobbered due to the framebuffers.
GLint vport[4] = { 0, };
s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
// Store the viewport. The viewport is clobbered due to the framebuffers.
GLint vport[4] = {
0,
};
s_gles2.glGetIntegerv(GL_VIEWPORT, vport);
// Correctly deal with rotated screens.
GLint tWidth = vport[2], tHeight = vport[3];
if ((mWidth < mHeight) != (tWidth < tHeight)) {
std::swap(tWidth, tHeight);
}
// Correctly deal with rotated screens.
GLint tWidth = vport[2], tHeight = vport[3];
if ((mWidth < mHeight) != (tWidth < tHeight)) {
std::swap(tWidth, tHeight);
}
// Compute the scaling factor needed to get an image just larger than the target viewport.
unsigned int factor = 1;
for (int i = 0, w = mWidth / 2, h = mHeight / 2;
i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
i++, w /= 2, h /= 2, factor *= 2) {
}
// Compute the scaling factor needed to get an image just larger than the
// target viewport.
unsigned int factor = 1;
for (int i = 0, w = mWidth / 2, h = mHeight / 2;
i < MAX_FACTOR_POWER && w >= tWidth && h >= tHeight;
i++, w /= 2, h /= 2, factor *= 2) {
}
// No resizing needed.
if (factor == 1) {
return texture;
}
// No resizing needed.
if (factor == 1) {
return texture;
}
s_gles2.glGetError(); // Clear any GL errors.
setupFramebuffers(factor);
resize(texture);
s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); // Restore the viewport.
s_gles2.glGetError(); // Clear any GL errors.
setupFramebuffers(factor);
resize(texture);
s_gles2.glViewport(vport[0], vport[1], vport[2],
vport[3]); // Restore the viewport.
// If there was an error while resizing, just use the unscaled texture.
GLenum error = s_gles2.glGetError();
if (error != GL_NO_ERROR) {
ERR("GL error while resizing: 0x%x (ignored)\n", error);
return texture;
}
// If there was an error while resizing, just use the unscaled texture.
GLenum error = s_gles2.glGetError();
if (error != GL_NO_ERROR) {
ERR("GL error while resizing: 0x%x (ignored)\n", error);
return texture;
}
return mFBHeight.texture;
return mFBHeight.texture;
}
void TextureResize::setupFramebuffers(unsigned int factor) {
if (factor == mFactor) {
// The factor hasn't changed, no need to update the framebuffers.
return;
}
if (factor == mFactor) {
// The factor hasn't changed, no need to update the framebuffers.
return;
}
// Update the framebuffer sizes to match the new factor.
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor, mHeight, 0, GL_RGBA, GL_FLOAT, nullptr);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
s_gles2.glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBWidth.texture, 0);
// Update the framebuffer sizes to match the new factor.
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor, mHeight, 0,
GL_RGBA, GL_FLOAT, nullptr);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, mFBWidth.texture, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor, mHeight / factor, 0, GL_RGBA,
GL_UNSIGNED_BYTE, nullptr);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
s_gles2.glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFBHeight.texture, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBHeight.texture);
s_gles2.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mWidth / factor,
mHeight / factor, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
s_gles2.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, mFBHeight.texture, 0);
// Update the shaders to the new factor. First detach the old shaders...
detachShaders(mFBWidth.program);
detachShaders(mFBHeight.program);
// Update the shaders to the new factor. First detach the old shaders...
detachShaders(mFBWidth.program);
detachShaders(mFBHeight.program);
// ... then attach the new ones.
std::ostringstream factorDefine;
factorDefine << "#define FACTOR " << factor << "\n";
attachShaders(&mFBWidth, factorDefine.str().c_str(), "#define HORIZONTAL\n", mWidth, mHeight);
attachShaders(&mFBHeight, factorDefine.str().c_str(), "#define VERTICAL\n", mWidth, mHeight);
// ... then attach the new ones.
std::ostringstream factorDefine;
factorDefine << "#define FACTOR " << factor << "\n";
attachShaders(&mFBWidth, factorDefine.str().c_str(), "#define HORIZONTAL\n",
mWidth, mHeight);
attachShaders(&mFBHeight, factorDefine.str().c_str(), "#define VERTICAL\n",
mWidth, mHeight);
mFactor = factor;
mFactor = factor;
}
void TextureResize::resize(GLuint texture) {
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glActiveTexture(GL_TEXTURE0);
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
s_gles2.glActiveTexture(GL_TEXTURE0);
// First scale the horizontal dimension by rendering the input texture to a scaled framebuffer.
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
s_gles2.glUseProgram(mFBWidth.program);
s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
// First scale the horizontal dimension by rendering the input texture to a
// scaled framebuffer.
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBWidth.framebuffer);
s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight);
s_gles2.glUseProgram(mFBWidth.program);
s_gles2.glEnableVertexAttribArray(mFBWidth.aPosition);
s_gles2.glVertexAttribPointer(mFBWidth.aPosition, 2, GL_FLOAT, GL_FALSE, 0,
0);
s_gles2.glBindTexture(GL_TEXTURE_2D, texture);
// Store the current texture filters and set to nearest for scaling.
GLint mag_filter, min_filter;
s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &mag_filter);
s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &min_filter);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glUniform1i(mFBWidth.uTexture, 0);
s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
// Store the current texture filters and set to nearest for scaling.
GLint mag_filter, min_filter;
s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
&mag_filter);
s_gles2.glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
&min_filter);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
s_gles2.glUniform1i(mFBWidth.uTexture, 0);
s_gles2.glDrawArrays(GL_TRIANGLES, 0,
sizeof(kVertexData) / (2 * sizeof(float)));
// Restore the previous texture filters.
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
// Restore the previous texture filters.
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
s_gles2.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
// Secondly, scale the vertical dimension using the second framebuffer.
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
s_gles2.glUseProgram(mFBHeight.program);
s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glUniform1i(mFBHeight.uTexture, 0);
s_gles2.glDrawArrays(GL_TRIANGLES, 0, sizeof(kVertexData) / (2 * sizeof(float)));
// Secondly, scale the vertical dimension using the second framebuffer.
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, mFBHeight.framebuffer);
s_gles2.glViewport(0, 0, mWidth / mFactor, mHeight / mFactor);
s_gles2.glUseProgram(mFBHeight.program);
s_gles2.glEnableVertexAttribArray(mFBHeight.aPosition);
s_gles2.glVertexAttribPointer(mFBHeight.aPosition, 2, GL_FLOAT, GL_FALSE, 0,
0);
s_gles2.glBindTexture(GL_TEXTURE_2D, mFBWidth.texture);
s_gles2.glUniform1i(mFBHeight.uTexture, 0);
s_gles2.glDrawArrays(GL_TRIANGLES, 0,
sizeof(kVertexData) / (2 * sizeof(float)));
// Clear the bindings.
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
// Clear the bindings.
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, 0);
s_gles2.glBindFramebuffer(GL_FRAMEBUFFER, 0);
s_gles2.glBindTexture(GL_TEXTURE_2D, 0);
}

View file

@ -19,33 +19,33 @@
#include <GLES2/gl2.h>
class TextureResize {
public:
TextureResize(GLuint width, GLuint height);
~TextureResize();
public:
TextureResize(GLuint width, GLuint height);
~TextureResize();
// Scales the given texture for the current viewport and returns the scaled
// texture. May return the input if no scaling is required.
GLuint update(GLuint texture);
// Scales the given texture for the current viewport and returns the scaled
// texture. May return the input if no scaling is required.
GLuint update(GLuint texture);
struct Framebuffer {
GLuint texture;
GLuint framebuffer;
GLuint program;
GLuint aPosition;
GLuint uTexture;
};
struct Framebuffer {
GLuint texture;
GLuint framebuffer;
GLuint program;
GLuint aPosition;
GLuint uTexture;
};
private:
void setupFramebuffers(unsigned int factor);
void resize(GLuint texture);
private:
void setupFramebuffers(unsigned int factor);
void resize(GLuint texture);
private:
GLuint mWidth;
GLuint mHeight;
unsigned int mFactor;
Framebuffer mFBWidth;
Framebuffer mFBHeight;
GLuint mVertexBuffer;
private:
GLuint mWidth;
GLuint mHeight;
unsigned int mFactor;
Framebuffer mFBWidth;
Framebuffer mFBHeight;
GLuint mVertexBuffer;
};
#endif

View file

@ -15,21 +15,16 @@
*/
#include "TimeUtils.h"
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
long long GetCurrentTimeMS()
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec/1000000LL;
return iDiff;
long long GetCurrentTimeMS() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec / 1000000LL;
return iDiff;
}
void TimeSleepMS(int p_mili)
{
usleep(p_mili * 1000);
}
void TimeSleepMS(int p_mili) { usleep(p_mili * 1000); }

View file

@ -20,155 +20,141 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/un.h>
/* Not all systems define PATH_MAX, those who don't generally don't
* have a limit on the maximum path size, so use a value that is
* large enough for our very limited needs.
*/
#ifndef PATH_MAX
#define PATH_MAX 128
#define PATH_MAX 128
#endif
UnixStream::UnixStream(size_t bufSize) :
SocketStream(bufSize),
bound_socket_path(NULL)
{
}
UnixStream::UnixStream(size_t bufSize)
: SocketStream(bufSize), bound_socket_path(NULL) {}
UnixStream::UnixStream(int sock, size_t bufSize) :
SocketStream(sock, bufSize),
bound_socket_path(NULL)
{
}
UnixStream::UnixStream(int sock, size_t bufSize)
: SocketStream(sock, bufSize), bound_socket_path(NULL) {}
UnixStream::~UnixStream()
{
if (bound_socket_path != NULL) {
int ret = 0;
do {
ret = unlink(bound_socket_path);
} while (ret < 0 && errno == EINTR);
if(ret != 0) {
ERR("Failed to unlink UNIX socket at \"%s\"\n", bound_socket_path);
perror("UNIX socket could not be unlinked");
}
free(bound_socket_path);
UnixStream::~UnixStream() {
if (bound_socket_path != NULL) {
int ret = 0;
do {
ret = unlink(bound_socket_path);
} while (ret < 0 && errno == EINTR);
if (ret != 0) {
ERR("Failed to unlink UNIX socket at \"%s\"\n", bound_socket_path);
perror("UNIX socket could not be unlinked");
}
free(bound_socket_path);
}
}
/* Initialize a sockaddr_un with the appropriate values corresponding
* to a given 'virtual port'. Returns 0 on success, -1 on error.
*/
static int
make_unix_path(char *path, size_t pathlen, int port_number)
{
char tmp[PATH_MAX]; // temp directory
int ret = 0;
static int make_unix_path(char *path, size_t pathlen, int port_number) {
char tmp[PATH_MAX]; // temp directory
int ret = 0;
// First, create user-specific temp directory if needed
const char* user = getenv("XDG_RUNTIME_DIR");
if (user != NULL) {
struct stat st;
snprintf(tmp, sizeof(tmp), "%s/anbox", user);
do {
ret = ::lstat(tmp, &st);
} while (ret < 0 && errno == EINTR);
// First, create user-specific temp directory if needed
const char *user = getenv("XDG_RUNTIME_DIR");
if (user != NULL) {
struct stat st;
snprintf(tmp, sizeof(tmp), "%s/anbox", user);
do {
ret = ::lstat(tmp, &st);
} while (ret < 0 && errno == EINTR);
if (ret < 0 && errno == ENOENT) {
do {
ret = ::mkdir(tmp, 0766);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
ERR("Could not create temp directory: %s", tmp);
user = NULL; // will fall-back to /tmp
}
}
else if (ret < 0) {
user = NULL; // will fallback to /tmp
}
if (ret < 0 && errno == ENOENT) {
do {
ret = ::mkdir(tmp, 0766);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
ERR("Could not create temp directory: %s", tmp);
user = NULL; // will fall-back to /tmp
}
} else if (ret < 0) {
user = NULL; // will fallback to /tmp
}
}
if (user == NULL) { // fallback to /tmp in case of error
snprintf(tmp, sizeof(tmp), "/tmp");
if (user == NULL) { // fallback to /tmp in case of error
snprintf(tmp, sizeof(tmp), "/tmp");
}
// Now, initialize it properly
snprintf(path, pathlen, "%s/qemu-gles-%d", tmp, port_number);
// If the emulator is killed, it can leave the socket file behind.
// Since the filename has PID in it, we can be sure that this socket
// is not supposed to be here and delete it, to prevent EADDRINUSE
// later in bind()
if (::access(path, F_OK) == 0) {
ret = ::remove(path);
if (ret < 0) {
ERR("Failed to remove stale socket file at %s: %s\n", path,
strerror(errno));
} else {
DBG("Stale socket file at %s was removed.\n", path);
}
}
// Now, initialize it properly
snprintf(path, pathlen, "%s/qemu-gles-%d", tmp, port_number);
// If the emulator is killed, it can leave the socket file behind.
// Since the filename has PID in it, we can be sure that this socket
// is not supposed to be here and delete it, to prevent EADDRINUSE
// later in bind()
if (::access(path, F_OK) == 0) {
ret = ::remove(path);
if (ret < 0) {
ERR("Failed to remove stale socket file at %s: %s\n", path, strerror(errno));
} else {
DBG("Stale socket file at %s was removed.\n", path);
}
}
return 0;
return 0;
}
int UnixStream::listen(char addrstr[MAX_ADDRSTR_LEN]) {
if (make_unix_path(addrstr, MAX_ADDRSTR_LEN, getpid()) < 0) {
return -1;
}
int UnixStream::listen(char addrstr[MAX_ADDRSTR_LEN])
{
if (make_unix_path(addrstr, MAX_ADDRSTR_LEN, getpid()) < 0) {
return -1;
}
m_sock = emugl::socketLocalServer(addrstr, SOCK_STREAM);
m_sock = emugl::socketLocalServer(addrstr, SOCK_STREAM);
if (!valid()) return int(ERR_INVALID_SOCKET);
if (!valid())
return int(ERR_INVALID_SOCKET);
bound_socket_path = strdup(addrstr);
if (bound_socket_path == NULL) {
ERR("WARNING: UNIX socket at \"%s\" should be manually removed \n",
addrstr);
return -1;
}
bound_socket_path = strdup(addrstr);
if(bound_socket_path == NULL) {
ERR("WARNING: UNIX socket at \"%s\" should be manually removed \n",
addrstr);
return -1;
}
return 0;
return 0;
}
SocketStream * UnixStream::accept()
{
int clientSock = -1;
SocketStream *UnixStream::accept() {
int clientSock = -1;
while (true) {
struct sockaddr_un addr;
socklen_t len = sizeof(addr);
clientSock = ::accept(m_sock, (sockaddr *)&addr, &len);
// DBG("UnixStream::accept @ %d \n", clientSock);
while (true) {
struct sockaddr_un addr;
socklen_t len = sizeof(addr);
clientSock = ::accept(m_sock, (sockaddr *)&addr, &len);
// DBG("UnixStream::accept @ %d \n", clientSock);
if (clientSock < 0 && errno == EINTR) {
continue;
}
break;
if (clientSock < 0 && errno == EINTR) {
continue;
}
break;
}
UnixStream *clientStream = NULL;
UnixStream *clientStream = NULL;
if (clientSock >= 0) {
clientStream = new UnixStream(clientSock, m_bufsize);
}
return clientStream;
if (clientSock >= 0) {
clientStream = new UnixStream(clientSock, m_bufsize);
}
return clientStream;
}
int UnixStream::connect(const char* addr)
{
m_sock = emugl::socketLocalClient(addr, SOCK_STREAM);
// DBG("UnixStream::connect @ %d \n", m_sock);
if (!valid()) return -1;
int UnixStream::connect(const char *addr) {
m_sock = emugl::socketLocalClient(addr, SOCK_STREAM);
// DBG("UnixStream::connect @ %d \n", m_sock);
if (!valid()) return -1;
return 0;
return 0;
}

View file

@ -19,15 +19,16 @@
#include "SocketStream.h"
class UnixStream : public SocketStream {
public:
explicit UnixStream(size_t bufsize = 10000);
~UnixStream();
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]);
virtual SocketStream *accept();
virtual int connect(const char* addr);
private:
char *bound_socket_path;
UnixStream(int sock, size_t bufSize);
public:
explicit UnixStream(size_t bufsize = 10000);
~UnixStream();
virtual int listen(char addrstr[MAX_ADDRSTR_LEN]);
virtual SocketStream *accept();
virtual int connect(const char *addr);
private:
char *bound_socket_path;
UnixStream(int sock, size_t bufSize);
};
#endif

View file

@ -25,163 +25,150 @@
#include <stdio.h>
#include <string.h>
WindowSurface::WindowSurface(EGLDisplay display,
EGLConfig config) :
mSurface(NULL),
mAttachedColorBuffer(NULL),
mReadContext(NULL),
mDrawContext(NULL),
mWidth(0),
mHeight(0),
mConfig(config),
mDisplay(display) {}
WindowSurface::WindowSurface(EGLDisplay display, EGLConfig config)
: mSurface(NULL),
mAttachedColorBuffer(NULL),
mReadContext(NULL),
mDrawContext(NULL),
mWidth(0),
mHeight(0),
mConfig(config),
mDisplay(display) {}
WindowSurface::~WindowSurface() {
if (mSurface) {
s_egl.eglDestroySurface(mDisplay, mSurface);
}
if (mSurface) {
s_egl.eglDestroySurface(mDisplay, mSurface);
}
}
WindowSurface *WindowSurface::create(EGLDisplay display,
EGLConfig config,
int p_width,
int p_height) {
// allocate space for the WindowSurface object
WindowSurface *win = new WindowSurface(display, config);
if (!win) {
return NULL;
}
WindowSurface *WindowSurface::create(EGLDisplay display, EGLConfig config,
int p_width, int p_height) {
// allocate space for the WindowSurface object
WindowSurface *win = new WindowSurface(display, config);
if (!win) {
return NULL;
}
// Create a pbuffer to be used as the egl surface
// for that window.
if (!win->resize(p_width, p_height)) {
delete win;
return NULL;
}
// Create a pbuffer to be used as the egl surface
// for that window.
if (!win->resize(p_width, p_height)) {
delete win;
return NULL;
}
return win;
return win;
}
void WindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) {
mAttachedColorBuffer = p_colorBuffer;
mAttachedColorBuffer = p_colorBuffer;
// resize the window if the attached color buffer is of different
// size.
unsigned int cbWidth = mAttachedColorBuffer->getWidth();
unsigned int cbHeight = mAttachedColorBuffer->getHeight();
// resize the window if the attached color buffer is of different
// size.
unsigned int cbWidth = mAttachedColorBuffer->getWidth();
unsigned int cbHeight = mAttachedColorBuffer->getHeight();
if (cbWidth != mWidth || cbHeight != mHeight) {
resize(cbWidth, cbHeight);
}
if (cbWidth != mWidth || cbHeight != mHeight) {
resize(cbWidth, cbHeight);
}
}
void WindowSurface::bind(RenderContextPtr p_ctx, BindType p_bindType) {
if (p_bindType == BIND_READ) {
mReadContext = p_ctx;
} else if (p_bindType == BIND_DRAW) {
mDrawContext = p_ctx;
} else if (p_bindType == BIND_READDRAW) {
mReadContext = p_ctx;
mDrawContext = p_ctx;
}
if (p_bindType == BIND_READ) {
mReadContext = p_ctx;
} else if (p_bindType == BIND_DRAW) {
mDrawContext = p_ctx;
} else if (p_bindType == BIND_READDRAW) {
mReadContext = p_ctx;
mDrawContext = p_ctx;
}
}
bool WindowSurface::flushColorBuffer() {
if (!mAttachedColorBuffer.Ptr()) {
return true;
}
if (!mWidth || !mHeight) {
return false;
}
if (mAttachedColorBuffer->getWidth() != mWidth ||
mAttachedColorBuffer->getHeight() != mHeight) {
// XXX: should never happen - how this needs to be handled?
fprintf(stderr, "Dimensions do not match\n");
return false;
}
if (!mDrawContext.Ptr()) {
fprintf(stderr, "Draw context is NULL\n");
return false;
}
// Make the surface current
EGLContext prevContext = s_egl.eglGetCurrentContext();
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
if (!s_egl.eglMakeCurrent(mDisplay,
mSurface,
mSurface,
mDrawContext->getEGLContext())) {
fprintf(stderr, "Error making draw context current\n");
return false;
}
mAttachedColorBuffer->blitFromCurrentReadBuffer();
// restore current context/surface
s_egl.eglMakeCurrent(mDisplay, prevDrawSurf, prevReadSurf, prevContext);
if (!mAttachedColorBuffer.Ptr()) {
return true;
}
if (!mWidth || !mHeight) {
return false;
}
if (mAttachedColorBuffer->getWidth() != mWidth ||
mAttachedColorBuffer->getHeight() != mHeight) {
// XXX: should never happen - how this needs to be handled?
fprintf(stderr, "Dimensions do not match\n");
return false;
}
if (!mDrawContext.Ptr()) {
fprintf(stderr, "Draw context is NULL\n");
return false;
}
// Make the surface current
EGLContext prevContext = s_egl.eglGetCurrentContext();
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface,
mDrawContext->getEGLContext())) {
fprintf(stderr, "Error making draw context current\n");
return false;
}
mAttachedColorBuffer->blitFromCurrentReadBuffer();
// restore current context/surface
s_egl.eglMakeCurrent(mDisplay, prevDrawSurf, prevReadSurf, prevContext);
return true;
}
bool WindowSurface::resize(unsigned int p_width, unsigned int p_height)
{
if (mSurface && mWidth == p_width && mHeight == p_height) {
// no need to resize
return true;
}
EGLContext prevContext = s_egl.eglGetCurrentContext();
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
EGLSurface prevPbuf = mSurface;
bool needRebindContext = mSurface &&
(prevReadSurf == mSurface ||
prevDrawSurf == mSurface);
if (needRebindContext) {
s_egl.eglMakeCurrent(
mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
//
// Destroy previous surface
//
if (mSurface) {
s_egl.eglDestroySurface(mDisplay, mSurface);
mSurface = NULL;
}
//
// Create pbuffer surface.
//
const EGLint pbufAttribs[5] = {
EGL_WIDTH, (EGLint) p_width, EGL_HEIGHT, (EGLint) p_height, EGL_NONE,
};
mSurface = s_egl.eglCreatePbufferSurface(mDisplay,
mConfig,
pbufAttribs);
if (mSurface == EGL_NO_SURFACE) {
fprintf(stderr, "Renderer error: failed to create/resize pbuffer!!\n");
return false;
}
mWidth = p_width;
mHeight = p_height;
if (needRebindContext) {
s_egl.eglMakeCurrent(
mDisplay,
(prevDrawSurf == prevPbuf) ? mSurface : prevDrawSurf,
(prevReadSurf == prevPbuf) ? mSurface : prevReadSurf,
prevContext);
}
bool WindowSurface::resize(unsigned int p_width, unsigned int p_height) {
if (mSurface && mWidth == p_width && mHeight == p_height) {
// no need to resize
return true;
}
EGLContext prevContext = s_egl.eglGetCurrentContext();
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
EGLSurface prevPbuf = mSurface;
bool needRebindContext =
mSurface && (prevReadSurf == mSurface || prevDrawSurf == mSurface);
if (needRebindContext) {
s_egl.eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
//
// Destroy previous surface
//
if (mSurface) {
s_egl.eglDestroySurface(mDisplay, mSurface);
mSurface = NULL;
}
//
// Create pbuffer surface.
//
const EGLint pbufAttribs[5] = {
EGL_WIDTH, (EGLint)p_width, EGL_HEIGHT, (EGLint)p_height, EGL_NONE,
};
mSurface = s_egl.eglCreatePbufferSurface(mDisplay, mConfig, pbufAttribs);
if (mSurface == EGL_NO_SURFACE) {
fprintf(stderr, "Renderer error: failed to create/resize pbuffer!!\n");
return false;
}
mWidth = p_width;
mHeight = p_height;
if (needRebindContext) {
s_egl.eglMakeCurrent(
mDisplay, (prevDrawSurf == prevPbuf) ? mSurface : prevDrawSurf,
(prevReadSurf == prevPbuf) ? mSurface : prevReadSurf, prevContext);
}
return true;
}

View file

@ -27,75 +27,69 @@
// A class used to model a guest-side window surface. The implementation
// uses a host Pbuffer to act as the EGL rendering surface instead.
class WindowSurface {
public:
// Create a new WindowSurface instance.
// |display| is the host EGLDisplay value.
// |config| is the host EGLConfig value.
// |width| and |height| are the initial size of the Pbuffer.
// Return a new WindowSurface instance on success, or NULL on failure.
static WindowSurface* create(EGLDisplay display,
EGLConfig config,
int width,
int height);
public:
// Create a new WindowSurface instance.
// |display| is the host EGLDisplay value.
// |config| is the host EGLConfig value.
// |width| and |height| are the initial size of the Pbuffer.
// Return a new WindowSurface instance on success, or NULL on failure.
static WindowSurface* create(EGLDisplay display, EGLConfig config, int width,
int height);
// Destructor.
~WindowSurface();
// Destructor.
~WindowSurface();
// Retrieve the host EGLSurface of the WindowSurface's Pbuffer.
EGLSurface getEGLSurface() const { return mSurface; }
// Retrieve the host EGLSurface of the WindowSurface's Pbuffer.
EGLSurface getEGLSurface() const { return mSurface; }
// Attach a ColorBuffer to this WindowSurface.
// Once attached, calling flushColorBuffer() will copy the Pbuffer's
// pixels to the color buffer.
//
// IMPORTANT: This automatically resizes the Pbuffer's to the ColorBuffer's
// dimensions. Potentially losing pixel values in the process.
void setColorBuffer(ColorBufferPtr p_colorBuffer);
// Attach a ColorBuffer to this WindowSurface.
// Once attached, calling flushColorBuffer() will copy the Pbuffer's
// pixels to the color buffer.
//
// IMPORTANT: This automatically resizes the Pbuffer's to the ColorBuffer's
// dimensions. Potentially losing pixel values in the process.
void setColorBuffer(ColorBufferPtr p_colorBuffer);
// Copy the Pbuffer's pixels to the attached color buffer.
// Returns true on success, or false on error (e.g. if there is no
// attached color buffer).
bool flushColorBuffer();
// Copy the Pbuffer's pixels to the attached color buffer.
// Returns true on success, or false on error (e.g. if there is no
// attached color buffer).
bool flushColorBuffer();
// Used by bind() below.
enum BindType {
BIND_READ,
BIND_DRAW,
BIND_READDRAW
};
// Used by bind() below.
enum BindType { BIND_READ, BIND_DRAW, BIND_READDRAW };
// TODO(digit): What is this used for exactly? For example, the
// mReadContext is never used by this class. The mDrawContext is only
// used temporarily during flushColorBuffer() operation, and could be
// passed as a parameter to the function instead. Maybe this is only used
// to increment reference counts on the smart pointers.
//
// Bind a context to the WindowSurface (huh? Normally you would bind a
// surface to the context, not the other way around)
//
// |p_ctx| is a RenderContext pointer.
// |p_bindType| is the type of bind. For BIND_READ, this assigns |p_ctx|
// to mReadContext, for BIND_DRAW, it assigns it to mDrawContext, and for
// for BIND_READDRAW, it assigns it to both.
void bind(RenderContextPtr p_ctx, BindType p_bindType);
// TODO(digit): What is this used for exactly? For example, the
// mReadContext is never used by this class. The mDrawContext is only
// used temporarily during flushColorBuffer() operation, and could be
// passed as a parameter to the function instead. Maybe this is only used
// to increment reference counts on the smart pointers.
//
// Bind a context to the WindowSurface (huh? Normally you would bind a
// surface to the context, not the other way around)
//
// |p_ctx| is a RenderContext pointer.
// |p_bindType| is the type of bind. For BIND_READ, this assigns |p_ctx|
// to mReadContext, for BIND_DRAW, it assigns it to mDrawContext, and for
// for BIND_READDRAW, it assigns it to both.
void bind(RenderContextPtr p_ctx, BindType p_bindType);
private:
WindowSurface();
WindowSurface(const WindowSurface& other);
private:
WindowSurface();
WindowSurface(const WindowSurface& other);
explicit WindowSurface(EGLDisplay display, EGLConfig config);
explicit WindowSurface(EGLDisplay display, EGLConfig config);
bool resize(unsigned int p_width, unsigned int p_height);
bool resize(unsigned int p_width, unsigned int p_height);
private:
EGLSurface mSurface;
ColorBufferPtr mAttachedColorBuffer;
RenderContextPtr mReadContext;
RenderContextPtr mDrawContext;
GLuint mWidth;
GLuint mHeight;
EGLConfig mConfig;
EGLDisplay mDisplay;
private:
EGLSurface mSurface;
ColorBufferPtr mAttachedColorBuffer;
RenderContextPtr mReadContext;
RenderContextPtr mDrawContext;
GLuint mWidth;
GLuint mHeight;
EGLConfig mConfig;
EGLDisplay mDisplay;
};
typedef emugl::SmartPtr<WindowSurface> WindowSurfacePtr;

Some files were not shown because too many files have changed in this diff Show more