diff --git a/Android.mk b/Android.mk index a03d70a..d476f9e 100644 --- a/Android.mk +++ b/Android.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \ android/service/host_connector.cpp \ android/service/local_socket_connection.cpp \ android/service/message_processor.cpp \ + android/service/activity_manager_interface.cpp \ android/service/android_api_skeleton.cpp \ android/service/platform_service_interface.cpp \ android/service/platform_service.cpp \ @@ -59,6 +60,15 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_CFLAGS := \ -fexceptions \ -std=c++1y +# Drop a few packages we don't want in our images as they +# are not needed (e.g. a home/launcher application as we +# don't have this concept). +LOCAL_OVERRIDES_PACKAGES := \ + Launcher \ + Launcher2 \ + LatinIME \ + Home \ + QuickSearchBox include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) @@ -97,5 +107,3 @@ include $(BUILD_SHARED_LIBRARY) # Include the Android.mk files below will override LOCAL_PATH so we # have to take a copy of it here. TMP_PATH := $(LOCAL_PATH) - -include $(TMP_PATH)/android/app_manager/Android.mk diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 3e86232..86103d8 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -7,6 +7,7 @@ set(ANBOXD_SOURCES ${CMAKE_SOURCE_DIR}/src/anbox/rpc/message_processor.cpp ${CMAKE_SOURCE_DIR}/src/anbox/rpc/pending_call_cache.cpp ${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp + service/activity_manager_interface.cpp service/platform_service.cpp service/platform_service_interface.cpp service/platform_api_stub.cpp diff --git a/android/app_manager/.idea/vcs.xml b/android/app_manager/.idea/vcs.xml deleted file mode 100644 index b2bdec2..0000000 --- a/android/app_manager/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/app_manager/Android.mk b/android/app_manager/Android.mk deleted file mode 100644 index bd37d10..0000000 --- a/android/app_manager/Android.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_PACKAGE_NAME := AnboxAppManager -LOCAL_CERTIFICATE := platform -LOCAL_PRIVILEGED_MODULE := true -LOCAL_OVERRIDES_PACKAGES := \ - Home \ - Launcher2 \ - Launcher3 -include $(BUILD_PACKAGE) diff --git a/android/app_manager/AndroidManifest.xml b/android/app_manager/AndroidManifest.xml deleted file mode 100644 index db222a5..0000000 --- a/android/app_manager/AndroidManifest.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - diff --git a/android/app_manager/res/values/strings.xml b/android/app_manager/res/values/strings.xml deleted file mode 100644 index 8926490..0000000 --- a/android/app_manager/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - Anbox Application Manager - diff --git a/android/hwcomposer/hwcomposer.cpp b/android/hwcomposer/hwcomposer.cpp index d501029..91b2945 100644 --- a/android/hwcomposer/hwcomposer.cpp +++ b/android/hwcomposer/hwcomposer.cpp @@ -18,7 +18,12 @@ #include #include -#define LOG_NDEBUG 0 +#include +#include +#include +#include + +#define LOG_NDEBUG 1 #include #include "HostConnection.h" @@ -67,8 +72,8 @@ struct HwcContext { }; static void dump_layer(hwc_layer_1_t const* l) { - ALOGI("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", - l->compositionType, l->flags, l->handle, l->transform, l->blending, + ALOGD("\tname='%s', type=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}", + l->name, l->compositionType, l->flags, l->handle, l->transform, l->blending, l->sourceCrop.left, l->sourceCrop.top, l->sourceCrop.right, @@ -83,8 +88,6 @@ static int hwc_prepare(hwc_composer_device_1_t* dev, size_t numDisplays, hwc_display_contents_1_t** displays) { auto context = reinterpret_cast(dev); - ALOGI("%s", __PRETTY_FUNCTION__); - if (displays == NULL || displays[0] == NULL) return -EINVAL; @@ -102,7 +105,9 @@ static int hwc_prepare(hwc_composer_device_1_t* dev, size_t numDisplays, for (; i < num_hw_layers; i++) { hwc_layer_1_t* layer = &displays[0]->hwLayers[num_hw_layers - 1 - i]; +#if 0 dump_layer(layer); +#endif if (layer->flags & HWC_SKIP_LAYER) { // All layers below and including this one will be drawn into the @@ -165,8 +170,6 @@ static int hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays, hwc_display_contents_1_t** displays) { auto context = reinterpret_cast(dev); - ALOGI("%s", __PRETTY_FUNCTION__); - if (displays == NULL || displays[0] == NULL) return -EFAULT; @@ -175,7 +178,13 @@ static int hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays, for (size_t i = 0 ; i < displays[0]->numHwLayers ; i++) { const auto layer = &displays[0]->hwLayers[i]; + if (layer->flags & HWC_SKIP_LAYER || + layer->flags & HWC_IS_CURSOR_LAYER) + continue; + +#if 0 dump_layer(layer); +#endif // FIXME this is just dirty ... but layer->handle is a const native_handle_t and canBePosted // can't be called with a const. @@ -185,11 +194,22 @@ static int hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays, return -EINVAL; } - ALOGI("Posting buffer %p\n", cb->hostHandle); - rcEnc->rcFBPost(rcEnc, cb->hostHandle); + rcEnc->rcPostLayer(rcEnc, + layer->name, + cb->hostHandle, + layer->sourceCrop.left, + layer->sourceCrop.top, + layer->sourceCrop.right, + layer->sourceCrop.bottom, + layer->displayFrame.left, + layer->displayFrame.top, + layer->displayFrame.right, + layer->displayFrame.bottom); hostCon->flush(); } + rcEnc->rcPostAllLayersDone(rcEnc); + check_sync_fds(numDisplays, displays); return 0; @@ -197,37 +217,81 @@ static int hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays, static int hwc_event_control(hwc_composer_device_1* dev, int disp, int event, int enabled) { - ALOGI("%s", __PRETTY_FUNCTION__); - return -EFAULT; } static void hwc_register_procs(hwc_composer_device_1* dev, hwc_procs_t const* procs) { - ALOGI("%s", __PRETTY_FUNCTION__); } static int hwc_blank(hwc_composer_device_1* dev, int disp, int blank) { - ALOGI("%s", __PRETTY_FUNCTION__); - return 0; } static int hwc_query(hwc_composer_device_1* dev, int what, int* value) { - ALOGI("%s", __PRETTY_FUNCTION__); - return 0; } static int hwc_device_close(hw_device_t* dev) { - ALOGI("%s", __PRETTY_FUNCTION__); auto context = reinterpret_cast(dev); delete context; return 0; } +static int hwc_get_display_configs(hwc_composer_device_1* dev, int disp, + uint32_t* configs, size_t* numConfigs) { + if (disp != 0) { + return -EINVAL; + } + + if (*numConfigs > 0) { + // Config[0] will be passed in to getDisplayAttributes as the disp + // parameter. The ARC display supports only 1 configuration. + configs[0] = 0; + *numConfigs = 1; + } + return 0; +} + +static int hwc_get_display_attributes(hwc_composer_device_1* dev, + int disp, uint32_t config, + const uint32_t* attributes, + int32_t* values) { + if (disp != 0 || config != 0) { + return -EINVAL; + } + + DEFINE_AND_VALIDATE_HOST_CONNECTION(); + + while (*attributes != HWC_DISPLAY_NO_ATTRIBUTE) { + switch (*attributes) { + case HWC_DISPLAY_VSYNC_PERIOD: + *values = rcEnc->rcGetDisplayVsyncPeriod(rcEnc, disp); + break; + case HWC_DISPLAY_WIDTH: + *values = rcEnc->rcGetDisplayWidth(rcEnc, disp); + break; + case HWC_DISPLAY_HEIGHT: + *values = rcEnc->rcGetDisplayHeight(rcEnc, disp); + break; + case HWC_DISPLAY_DPI_X: + *values = 1000 * rcEnc->rcGetDisplayDpiX(rcEnc, disp); + break; + case HWC_DISPLAY_DPI_Y: + *values = 1000 * rcEnc->rcGetDisplayDpiY(rcEnc, disp); + break; + default: + ALOGE("Unknown attribute value 0x%02x", *attributes); + } + ++attributes; + ++values; + } + return 0; +} + static int hwc_device_open(const hw_module_t* module, const char* name, hw_device_t** device) { - ALOGI("%s", __PRETTY_FUNCTION__); + ALOGD("%s", __PRETTY_FUNCTION__); + if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) return -EINVAL; @@ -241,9 +305,9 @@ static int hwc_device_open(const hw_module_t* module, const char* name, hw_devic dev->device.eventControl = hwc_event_control; dev->device.blank = hwc_blank; dev->device.query = hwc_query; + dev->device.getDisplayConfigs = hwc_get_display_configs; + dev->device.getDisplayAttributes = hwc_get_display_attributes; dev->device.registerProcs = hwc_register_procs; - // FIXME: eventually implement to dump specific information - dev->device.dump = nullptr; *device = &dev->device.common; diff --git a/android/service/activity_manager_interface.cpp b/android/service/activity_manager_interface.cpp new file mode 100644 index 0000000..84dce86 --- /dev/null +++ b/android/service/activity_manager_interface.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#define LOG_TAG "Anboxd" + +#include "android/service/activity_manager_interface.h" + +namespace android { +BpActivityManager::BpActivityManager(const sp &binder) : + BpInterface(binder) { +} + +status_t BpActivityManager::setFocusedTask(int32_t id) { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(id); + return remote()->transact(IActivityManager::SET_FOCUSED_TASK, data, &reply); +} + +IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager"); +} // namespace android diff --git a/android/service/activity_manager_interface.h b/android/service/activity_manager_interface.h new file mode 100644 index 0000000..655fdb6 --- /dev/null +++ b/android/service/activity_manager_interface.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_ +#define ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_ + +#include +#include +#include + +#include +#include + +#include + +namespace android { +class IActivityManager : public IInterface { +public: + DECLARE_META_INTERFACE(ActivityManager); + + enum { + // This needs to stay synchronized with frameworks/base/core/java/android/app/IActivityManager.java + SET_FOCUSED_TASK = IBinder::FIRST_CALL_TRANSACTION + 130, + }; + + virtual status_t setFocusedTask(int32_t id) = 0; +}; + +class BpActivityManager : public BpInterface { +public: + BpActivityManager(const sp &binder); + + status_t setFocusedTask(int32_t id) override; +}; +} // namespace android +#endif diff --git a/android/service/android_api_skeleton.cpp b/android/service/android_api_skeleton.cpp index 3181787..f692721 100644 --- a/android/service/android_api_skeleton.cpp +++ b/android/service/android_api_skeleton.cpp @@ -15,6 +15,8 @@ * */ +#define LOG_TAG "Anboxd" + #include "android/service/android_api_skeleton.h" #include "anbox_rpc.pb.h" @@ -23,6 +25,8 @@ #include #include +#include + namespace { std::map common_env = { {"ANDROID_DATA", "/data"}, @@ -48,6 +52,14 @@ void AndroidApiSkeleton::wait_for_process(core::posix::ChildProcess &process, } } +void AndroidApiSkeleton::connect_services() { + if (!activity_manager_.get()) { + auto am = android::defaultServiceManager()->getService(android::String16("activity")); + if (am.get()) + activity_manager_ = new android::BpActivityManager(am); + } +} + void AndroidApiSkeleton::install_application(anbox::protobuf::bridge::InstallApplication const *request, anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) { @@ -106,4 +118,19 @@ void AndroidApiSkeleton::set_dns_servers(anbox::protobuf::bridge::SetDnsServers done->Run(); } + +void AndroidApiSkeleton::set_focused_task(anbox::protobuf::bridge::SetFocusedTask const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done) { + (void) response; + + connect_services(); + + if (activity_manager_.get()) + activity_manager_->setFocusedTask(request->id()); + else + response->set_error("ActivityManager is not available"); + + done->Run(); +} } // namespace anbox diff --git a/android/service/android_api_skeleton.h b/android/service/android_api_skeleton.h index 8e8787b..4cdd582 100644 --- a/android/service/android_api_skeleton.h +++ b/android/service/android_api_skeleton.h @@ -18,6 +18,8 @@ #ifndef ANBOX_PLATFORM_API_SKELETON_H_ #define ANBOX_PLATFORM_API_SKELETON_H_ +#include "android/service/activity_manager_interface.h" + namespace google { namespace protobuf { class Closure; @@ -36,6 +38,7 @@ namespace bridge { class InstallApplication; class LaunchApplication; class SetDnsServers; +class SetFocusedTask; } // namespace bridge namespace rpc { class Void; @@ -58,9 +61,17 @@ public: anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done); + void set_focused_task(anbox::protobuf::bridge::SetFocusedTask const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done); + private: void wait_for_process(core::posix::ChildProcess &process, anbox::protobuf::rpc::Void *response); + + void connect_services(); + + android::sp activity_manager_; }; } // namespace anbox diff --git a/android/service/local_socket_connection.cpp b/android/service/local_socket_connection.cpp index 9b8dbea..c2ff040 100644 --- a/android/service/local_socket_connection.cpp +++ b/android/service/local_socket_connection.cpp @@ -23,7 +23,7 @@ #include #include -#define LOG_TAG "Anbox" +#define LOG_TAG "Anboxd" #include namespace { diff --git a/android/service/message_processor.cpp b/android/service/message_processor.cpp index 3a035be..4036917 100644 --- a/android/service/message_processor.cpp +++ b/android/service/message_processor.cpp @@ -41,6 +41,8 @@ void MessageProcessor::dispatch(rpc::Invocation const& invocation) { invoke(this, platform_api_.get(), &AndroidApiSkeleton::launch_application, invocation); else if (invocation.method_name() == "set_dns_servers") invoke(this, platform_api_.get(), &AndroidApiSkeleton::set_dns_servers, invocation); + else if (invocation.method_name() == "set_focused_task") + invoke(this, platform_api_.get(), &AndroidApiSkeleton::set_focused_task, invocation); } void MessageProcessor::process_event_sequence(const std::string&) { diff --git a/android/service/platform_api_stub.cpp b/android/service/platform_api_stub.cpp index 373df0f..fd2d605 100644 --- a/android/service/platform_api_stub.cpp +++ b/android/service/platform_api_stub.cpp @@ -21,38 +21,44 @@ #include "anbox_rpc.pb.h" #include "anbox_bridge.pb.h" -#define LOG_TAG "Anbox" -#include - namespace anbox { PlatformApiStub::PlatformApiStub(const std::shared_ptr &rpc_channel) : rpc_channel_(rpc_channel) { } void PlatformApiStub::boot_finished() { - auto c = std::make_shared>(); + protobuf::bridge::EventSequence seq; + auto event = seq.mutable_boot_finished(); + (void) event; + rpc_channel_->send_event(seq); +} - ALOGI("Boot finished"); +void PlatformApiStub::update_window_state(const WindowStateUpdate &state) { + protobuf::bridge::EventSequence seq; + auto event = seq.mutable_window_state_update(); - { - std::lock_guard lock(mutex_); - boot_finished_wait_handle_.expect_result(); + auto convert_window = [](WindowStateUpdate::Window in, anbox::protobuf::bridge::WindowStateUpdateEvent_WindowState *out) { + out->set_display_id(in.display_id); + out->set_has_surface(in.has_surface); + out->set_package_name(in.package_name); + out->set_frame_left(in.frame.left); + out->set_frame_top(in.frame.top); + out->set_frame_right(in.frame.right); + out->set_frame_bottom(in.frame.bottom); + out->set_task_id(in.task_id); + out->set_stack_id(in.stack_id); + }; + + for (const auto &window : state.updated_windows) { + auto w = event->add_windows(); + convert_window(window, w); } - protobuf::rpc::Void message; + for (const auto &window : state.removed_windows) { + auto w = event->add_removed_windows(); + convert_window(window, w); + } - rpc_channel_->call_method( - "boot_finished", - &message, c->response.get(), - google::protobuf::NewCallback(this, &PlatformApiStub::handle_boot_finished_response, c.get())); - - boot_finished_wait_handle_.wait_for_all(); - - ALOGI("Boot finished sent successfully!"); -} - -void PlatformApiStub::handle_boot_finished_response(Request*) { - ALOGI("handle_boot_finished_response"); - boot_finished_wait_handle_.result_received(); + rpc_channel_->send_event(seq); } } // namespace anbox diff --git a/android/service/platform_api_stub.h b/android/service/platform_api_stub.h index a18bc55..436facf 100644 --- a/android/service/platform_api_stub.h +++ b/android/service/platform_api_stub.h @@ -21,6 +21,8 @@ #include "anbox/common/wait_handle.h" #include +#include +#include namespace anbox { namespace protobuf { @@ -37,6 +39,27 @@ public: void boot_finished(); + struct WindowStateUpdate { + struct Window { + int display_id; + bool has_surface; + std::string package_name; + struct Frame { + int left; + int top; + int right; + int bottom; + }; + Frame frame; + int task_id; + int stack_id; + }; + std::vector updated_windows; + std::vector removed_windows; + }; + + void update_window_state(const WindowStateUpdate &state); + private: template struct Request { @@ -45,10 +68,7 @@ private: bool success; }; - void handle_boot_finished_response(Request *request); - mutable std::mutex mutex_; - common::WaitHandle boot_finished_wait_handle_; std::shared_ptr rpc_channel_; }; diff --git a/android/service/platform_service.cpp b/android/service/platform_service.cpp index 78d45d0..8ab0013 100644 --- a/android/service/platform_service.cpp +++ b/android/service/platform_service.cpp @@ -16,12 +16,16 @@ */ #include "android/service/platform_service.h" -#include "android/service/platform_api_stub.h" #include "anbox/rpc/channel.h" +#include "anbox_rpc.pb.h" +#include "anbox_bridge.pb.h" + #define LOG_TAG "Anboxd" #include +#include + using namespace android; namespace android { @@ -33,4 +37,59 @@ status_t PlatformService::boot_finished() { platform_api_stub_->boot_finished(); return OK; } + +anbox::PlatformApiStub::WindowStateUpdate::Window PlatformService::unpack_window_state(const Parcel &data) { + bool has_surface = data.readByte() != 0; + + String8 package_name(data.readString16()); + + auto frame_left = data.readInt32(); + auto frame_top = data.readInt32(); + auto frame_right = data.readInt32(); + auto frame_bottom = data.readInt32(); + auto task_id = data.readInt32(); + auto stack_id = data.readInt32(); + + ALOGI(" Window: package=%s frame={%d,%d,%d,%d} task=%d stack=%d", + package_name.string(), frame_left, frame_top, frame_right, frame_bottom, + task_id, stack_id); + + return anbox::PlatformApiStub::WindowStateUpdate::Window{ + -1, // Display id will be added by the caller + has_surface, + package_name.string(), + {frame_left, frame_top, frame_right, frame_bottom}, + task_id, + stack_id, + }; +} + +status_t PlatformService::update_window_state(const Parcel &data) { + anbox::PlatformApiStub::WindowStateUpdate state; + + ALOGI("Udated windows:"); + const auto num_displays = data.readInt32(); + for (auto n = 0; n < num_displays; n++) { + const auto display_id = data.readInt32(); + const auto num_windows = data.readInt32(); + ALOGI(" Display: id=%d", display_id); + + for (auto m = 0; m < num_windows; m++) { + auto window = unpack_window_state(data); + window.display_id = display_id; + state.updated_windows.push_back(window); + } + } + + ALOGI("Removed windows:"); + const auto num_removed_windows = data.readInt32(); + for (auto n = 0; n < num_removed_windows; n++) { + auto window = unpack_window_state(data); + state.removed_windows.push_back(window); + } + + platform_api_stub_->update_window_state(state); + + return OK; +} } // namespace android diff --git a/android/service/platform_service.h b/android/service/platform_service.h index 6fff224..8a4eadf 100644 --- a/android/service/platform_service.h +++ b/android/service/platform_service.h @@ -19,23 +19,24 @@ #define ANBOX_ANDROID_PLATFORM_SERVICE_H_ #include "android/service/platform_service_interface.h" +#include "android/service/platform_api_stub.h" + +#include #include -namespace anbox { -class PlatformApiStub; -} // namespace anbox - namespace android { class PlatformService : public BnPlatformService { public: - static const char* service_name() { return "anbox.PlatformService"; } + static const char* service_name() { return "org.anbox.PlatformService"; } PlatformService(const std::shared_ptr &platform_api_stub); status_t boot_finished() override; + status_t update_window_state(const Parcel &data) override; private: + anbox::PlatformApiStub::WindowStateUpdate::Window unpack_window_state(const Parcel &data); std::shared_ptr platform_api_stub_; }; } // namespace android diff --git a/android/service/platform_service_interface.cpp b/android/service/platform_service_interface.cpp index f523738..ff2e92c 100644 --- a/android/service/platform_service_interface.cpp +++ b/android/service/platform_service_interface.cpp @@ -28,7 +28,13 @@ status_t BpPlatformService::boot_finished() { return remote()->transact(IPlatformService::BOOT_FINISHED, data, &reply); } -IMPLEMENT_META_INTERFACE(PlatformService, "anbox.IPlatformService"); +status_t BpPlatformService::update_window_state(const Parcel&) { + Parcel data, reply; + data.writeInterfaceToken(IPlatformService::getInterfaceDescriptor()); + return remote()->transact(IPlatformService::UPDATE_WINDOW_STATE, data, &reply); +} + +IMPLEMENT_META_INTERFACE(PlatformService, "org.anbox.IPlatformService"); status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) { @@ -36,6 +42,9 @@ status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data, case BOOT_FINISHED: CHECK_INTERFACE(IPlatformService, data, reply); return boot_finished(); + case UPDATE_WINDOW_STATE: + CHECK_INTERFACE(IPlatformService, data, reply); + return update_window_state(data); default: break; } diff --git a/android/service/platform_service_interface.h b/android/service/platform_service_interface.h index 0a6c75a..876cf95 100644 --- a/android/service/platform_service_interface.h +++ b/android/service/platform_service_interface.h @@ -33,10 +33,13 @@ public: DECLARE_META_INTERFACE(PlatformService); enum { + // Keep this synchronized with frameworks/base/services/java/com/android/server/wm/AnboxPlatformServiceProxy.java BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, + UPDATE_WINDOW_STATE = IBinder::FIRST_CALL_TRANSACTION + 1, }; virtual status_t boot_finished() = 0; + virtual status_t update_window_state(const Parcel &data) = 0; }; class BpPlatformService : public BpInterface { @@ -44,6 +47,7 @@ public: BpPlatformService(const sp &binder); status_t boot_finished() override; + status_t update_window_state(const Parcel &data) override; }; class BnPlatformService : public BnInterface { diff --git a/external/android-emugl/host/include/OpenglRender/render_api_functions.h b/external/android-emugl/host/include/OpenglRender/render_api_functions.h index b68deee..59237a8 100644 --- a/external/android-emugl/host/include/OpenglRender/render_api_functions.h +++ b/external/android-emugl/host/include/OpenglRender/render_api_functions.h @@ -25,7 +25,7 @@ typedef void (*emugl_crash_func_t)(const char* format, ...); #define LIST_RENDER_API_FUNCTIONS(X) \ X(int, initLibrary, (), ()) \ X(int, setStreamMode, (int mode), (mode)) \ - X(int, initOpenGLRenderer, (EGLNativeDisplayType native_display, int width, int height, bool useSubWindow, char* addr, size_t addrLen, emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc), (width, height, useSubWindow, addr, addrLen, logfuncs, crashfunc)) \ + X(int, initOpenGLRenderer, (EGLNativeDisplayType native_display, char* addr, size_t addrLen, emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc), (native_display, addr, addrLen, logfuncs, crashfunc)) \ X(void, getHardwareStrings, (const char** vendor, const char** renderer, const char** version), (vendor, renderer, version)) \ X(void, setPostCallback, (OnPostFn onPost, void* onPostContext), (onPost, onPostContext)) \ X(bool, showOpenGLSubwindow, (FBNativeWindowType window, int wx, int wy, int ww, int wh, int fbw, int fbh, float dpr, float zRot), (window, wx, wy, ww, wh, fbw, fbh, dpr, zRot)) \ diff --git a/external/android-emugl/host/libs/CMakeLists.txt b/external/android-emugl/host/libs/CMakeLists.txt index 2e7bf51..09b6e09 100644 --- a/external/android-emugl/host/libs/CMakeLists.txt +++ b/external/android-emugl/host/libs/CMakeLists.txt @@ -1,6 +1,5 @@ add_subdirectory(GLESv1_dec) add_subdirectory(GLESv2_dec) add_subdirectory(libOpenGLESDispatch) -add_subdirectory(libOpenglRender) add_subdirectory(renderControl_dec) add_subdirectory(Translator) diff --git a/external/android-emugl/host/libs/Translator/include/GLcommon/GLESmacros.h b/external/android-emugl/host/libs/Translator/include/GLcommon/GLESmacros.h index 15e5d04..c66602c 100644 --- a/external/android-emugl/host/libs/Translator/include/GLcommon/GLESmacros.h +++ b/external/android-emugl/host/libs/Translator/include/GLcommon/GLESmacros.h @@ -33,14 +33,12 @@ #define SET_ERROR_IF(condition,err) if((condition)) { \ - fprintf(stderr, "%s:%s:%d error 0x%x\n", __FILE__, __FUNCTION__, __LINE__, err); \ ctx->setGLerror(err); \ return; \ } #define RET_AND_SET_ERROR_IF(condition,err,ret) if((condition)) { \ - fprintf(stderr, "%s:%s:%d error 0x%x\n", __FILE__, __FUNCTION__, __LINE__, err); \ ctx->setGLerror(err); \ return ret; \ } diff --git a/external/android-emugl/host/libs/libOpenglRender/CMakeLists.txt b/external/android-emugl/host/libs/libOpenglRender/CMakeLists.txt deleted file mode 100644 index 7a25973..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -set(SOURCES - ColorBuffer.cpp - FbConfig.cpp - FrameBuffer.cpp - NativeSubWindow_delegate.cpp - ReadBuffer.cpp - RenderContext.cpp - RenderControl.cpp - RenderServer.cpp - RenderThread.cpp - RenderThreadInfo.cpp - render_api.cpp - RenderWindow.cpp - SocketStream.cpp - TcpStream.cpp - TextureDraw.cpp - TextureResize.cpp - TimeUtils.cpp - UnixStream.cpp - WindowSurface.cpp) - -add_library(OpenglRender ${SOURCES}) -target_link_libraries(OpenglRender - emugl_common - GLESv1_dec - GLESv2_dec - renderControl_dec - OpenGLESDispatch - OpenglCodecCommon - ${EGL_LDFLAGS} - ${EGL_LIBRARIES}) diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h deleted file mode 100644 index 49af52b..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#ifndef NATIVE_SUB_WINDOW_H -#define NATIVE_SUB_WINDOW_H - -#include "OpenglRender/render_api_platform_types.h" - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -class SubWindowHandler { -public: - virtual ~SubWindowHandler() { } - virtual EGLNativeWindowType create_window(int x, int y, int width, int height) = 0; - virtual void destroy_window(EGLNativeWindowType win) = 0; -}; - -void registerSubWindowHandler(const std::shared_ptr &handler); - -typedef void (*SubWindowRepaintCallback)(void*); - -// Create a new sub-window that will be used to display the content of the -// emulated GPU on top of the regular UI window. -// |p_window| is the platform-specific handle to the main UI window. -// |x|, |y| is the position sub-window relative to the top-left corner of the -// main window. -// |width| and |height| are the dimensions of the sub-window, as well as of -// the emulated framebuffer. -// |repaint_callback| may be invoked every time the window has to be repainted -// (such as receiving a WM_PAINT event on Windows). If the provided argument is -// NULL, nothing will be invoked. -// |repaint_callback_param| an additional parameter that will be passed to the -// repaint callback when/if it's invoked. -// On success, return a new platform-specific window handle, cast as an -// EGLNativeWindowType. Or 0/NULL in case of failure. -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param); - -// Destroy a sub-window previously created through createSubWindow() above. -void destroySubWindow(EGLNativeWindowType win); - -// Moves a sub-window previously created through createSubWindow() above. -// |p_parent_window| is the platform-specific handle to the main UI window. -// |p_sub_window| is the platform-specific handle to the EGL subwindow. -// |x|,|y|,|width|,|height| are the new location and dimensions of the -// subwindow. -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_cocoa.m b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_cocoa.m deleted file mode 100644 index 54674b5..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_cocoa.m +++ /dev/null @@ -1,101 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "NativeSubWindow.h" -#include - -/* - * EmuGLView inherit from NSView and override the isOpaque - * method to return YES. That prevents drawing of underlying window/view - * when the view needs to be redrawn. - */ -@interface EmuGLView : NSView { -} @end - -@implementation EmuGLView - - - (BOOL)isOpaque { - return YES; - } - -@end - - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param) { - NSWindow* win = (NSWindow *)p_window; - if (!win) { - return NULL; - } - - /* (x,y) assume an upper-left origin, but Cocoa uses a lower-left origin */ - NSRect content_rect = [win contentRectForFrameRect:[win frame]]; - int cocoa_y = (int)content_rect.size.height - (y + height); - NSRect contentRect = NSMakeRect(x, cocoa_y, width, height); - - NSView *glView = [[EmuGLView alloc] initWithFrame:contentRect]; - if (glView) { - [glView setWantsBestResolutionOpenGLSurface:YES]; - [[win contentView] addSubview:glView]; - [win makeKeyAndOrderFront:nil]; - } - - return (EGLNativeWindowType)glView; -} - -void destroySubWindow(EGLNativeWindowType win) { - if(win){ - NSView *glView = (NSView *)win; - [glView removeFromSuperview]; - [glView release]; - } -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - NSWindow *win = (NSWindow *)p_parent_window; - if (!win) { - return 0; - } - - NSView *glView = (NSView *)p_sub_window; - if (!glView) { - return 0; - } - - /* The view must be removed from the hierarchy to be properly resized */ - [glView removeFromSuperview]; - - /* (x,y) assume an upper-left origin, but Cocoa uses a lower-left origin */ - NSRect content_rect = [win contentRectForFrameRect:[win frame]]; - int cocoa_y = (int)content_rect.size.height - (y + height); - NSRect newFrame = NSMakeRect(x, cocoa_y, width, height); - [glView setFrame:newFrame]; - - /* Re-add the sub-window to the view hierarchy */ - [[win contentView] addSubview:glView]; - [win makeKeyAndOrderFront:nil]; - - return 1; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_delegate.cpp b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_delegate.cpp deleted file mode 100644 index 8984d2f..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_delegate.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "NativeSubWindow.h" - -#include -#include -#include - -namespace { -static std::shared_ptr current_handler = nullptr; -} - -void registerSubWindowHandler(const std::shared_ptr &handler) { - if (current_handler) - throw std::runtime_error("A sub window handle is already registered"); - - current_handler = handler; -} - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param) { - (void) p_window; - (void) repaint_callback; - (void) repaint_callback_param; - - if (!current_handler) - return (EGLNativeWindowType) 0; - - return current_handler->create_window(x, y, width, height); -} - -void destroySubWindow(EGLNativeWindowType win) { - if (!current_handler) - return; - - return current_handler->destroy_window(win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - (void) p_parent_window; - (void) p_sub_window; - (void) x; - (void) y; - (void) width; - (void) height; - - return true; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_mir.cpp b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_mir.cpp deleted file mode 100644 index 1bbf0b3..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_mir.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#define MIR_EGL_PLATFORM - -#include "mir_support/shared_state.h" - -#include "NativeSubWindow.h" - -#include "OpenglCodecCommon/ErrorLog.h" - -#include -#include -#include - -#include - -namespace { -std::map surfaces; - -static const MirDisplayOutput *find_active_output( - const MirDisplayConfiguration *conf) -{ - const MirDisplayOutput *output = NULL; - int d; - - for (d = 0; d < (int)conf->num_outputs; d++) - { - const MirDisplayOutput *out = conf->outputs + d; - - if (out->used && - out->connected && - out->num_modes && - out->current_mode < out->num_modes) - { - output = out; - break; - } - } - - return output; -} -} - -MirPixelFormat defaultPixelFormatFor(MirConnection *connection) -{ - MirPixelFormat format; - unsigned int nformats; - mir_connection_get_available_surface_formats(connection, &format, 1, &nformats); - return format; -} - -void handleSurfaceEvent(const MirSurfaceEvent *event) { - MirSurfaceAttrib attrib = mir_surface_event_get_attribute(event); - if (attrib != mir_surface_attrib_visibility) - return; - switch (mir_surface_event_get_attribute(event)) { - case mir_surface_visibility_exposed: - ERR("Surface exposed\n"); - break; - case mir_surface_visibility_occluded: - ERR("Surface occluded\n"); - break; - default: - break; - } -} - -void surfaceEventHandler(MirSurface *surface, MirEvent const *event, void *context) { - switch (mir_event_get_type(event)) { - case mir_event_type_input: - break; - case mir_event_type_surface: - handleSurfaceEvent(mir_event_get_surface_event(event)); - break; - case mir_event_type_resize: - { - MirResizeEvent const *resize_event = mir_event_get_resize_event(event); - ERR("Resized to %dx%d\n", - mir_resize_event_get_width(resize_event), - mir_resize_event_get_height(resize_event)); - } - break; - case mir_event_type_close_surface: - break; - case mir_event_type_surface_output: - { - MirSurfaceOutputEvent const *output_event = mir_event_get_surface_output_event(event); - ERR("dpi %i output id %d\n", - mir_surface_output_event_get_dpi(output_event), - mir_surface_output_event_get_output_id(output_event)); - } - break; - default: - break; - } -} - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param) { - - (void) p_window; - (void) x; - (void) y; - (void) width; - (void) height; - (void) repaint_callback; - (void) repaint_callback_param; - - mir::support::SharedState::get()->ensure_connection(); - - const auto pixel_format = defaultPixelFormatFor(mir::support::SharedState::get()->connection()); - - ERR("Selected pixel format %d\n", pixel_format); - - MirDisplayConfiguration* display_config = - mir_connection_create_display_config(mir::support::SharedState::get()->connection()); - - const MirDisplayOutput *output = find_active_output(display_config); - if (!output) - throw new std::runtime_error("Failed to find active output display"); - - const MirDisplayMode *mode = &output->modes[output->current_mode]; - - auto spec = mir_connection_create_spec_for_normal_surface( - mir::support::SharedState::get()->connection(), - mode->vertical_resolution, - mode->horizontal_resolution, - pixel_format); - - mir_surface_spec_set_name(spec, "anbox"); - mir_surface_spec_set_event_handler(spec, surfaceEventHandler, nullptr); - ERR("Selecting output id %d", output->output_id); - mir_surface_spec_set_fullscreen_on_output(spec, output->output_id); - mir_surface_spec_set_buffer_usage(spec, mir_buffer_usage_hardware); - - mir_display_config_destroy(display_config); - - auto surface = mir_surface_create_sync(spec); - mir_surface_spec_release(spec); - - if (!mir_surface_is_valid(surface)) { - ERR("surface error: %s\n", mir_surface_get_error_message(surface)); - throw std::runtime_error("Failed to create a Mir surface"); - } - - MirSurfaceParameters parameters; - mir_surface_get_parameters(surface, ¶meters); - ERR("width %i height %i output id %i\n", - parameters.width, - parameters.height, - parameters.output_id); - - auto surface_buffer_stream = mir_surface_get_buffer_stream(surface); - auto native_window = reinterpret_cast( - mir_buffer_stream_get_egl_native_window(surface_buffer_stream)); - - surfaces.insert({ native_window, surface }); - - return native_window; -} - -void destroySubWindow(EGLNativeWindowType win) { - if (surfaces.find(win) == surfaces.end()) - return; - - auto surface = surfaces[win]; - surfaces.erase(win); - - mir_surface_release_sync(surface); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - - ERR("%s: Not implemented", __func__); - - return true; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_null.cpp b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_null.cpp deleted file mode 100644 index 46bee10..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_null.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "NativeSubWindow.h" - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param) { - return NULL; -} - -void destroySubWindow(EGLNativeWindowType win) { -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - return false; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_win32.cpp b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_win32.cpp deleted file mode 100644 index 344459a..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_win32.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "NativeSubWindow.h" - -struct SubWindowUserData { - SubWindowRepaintCallback repaint_callback; - void* repaint_callback_param; -}; - -static LRESULT CALLBACK subWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_PAINT) { - auto user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (user_data && user_data->repaint_callback) { - user_data->repaint_callback(user_data->repaint_callback_param); - } - } else if (uMsg == WM_NCDESTROY) { - SubWindowUserData* user_data = - (SubWindowUserData*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - delete user_data; - } - return DefWindowProc(hwnd, uMsg, wParam, lParam); -} - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, int y,int width, int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param){ - static const char className[] = "subWin"; - - WNDCLASS wc = {}; - if (!GetClassInfo(GetModuleHandle(NULL), className, &wc)) { - wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// redraw if size changes - wc.lpfnWndProc = &subWindowProc; // points to window procedure - wc.cbWndExtra = sizeof(void*) ; // save extra window memory - wc.lpszClassName = className; // name of window class - RegisterClass(&wc); - } - - EGLNativeWindowType ret = CreateWindowEx( - WS_EX_NOPARENTNOTIFY, // do not bother our parent window - className, - "sub", - WS_CHILD|WS_DISABLED, - x,y,width,height, - p_window, - NULL, - NULL, - NULL); - - auto user_data = new SubWindowUserData(); - user_data->repaint_callback = repaint_callback; - user_data->repaint_callback_param = repaint_callback_param; - - SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR)user_data); - ShowWindow(ret, SW_SHOW); - return ret; -} - -void destroySubWindow(EGLNativeWindowType win){ - PostMessage(win, WM_CLOSE, 0, 0); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - BOOL ret = MoveWindow(p_sub_window, - x, - y, - width, - height, - TRUE); - return ret; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_x11.cpp b/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_x11.cpp deleted file mode 100644 index be2d4d3..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_x11.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "NativeSubWindow.h" - -#include - -static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) { - if (e->type == MapNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Bool WaitForConfigureNotify(Display *d, XEvent *e, char *arg) { - if (e->type == ConfigureNotify && e->xmap.window == (Window)arg) { - return 1; - } - return 0; -} - -static Display *s_display = NULL; - -EGLNativeWindowType createSubWindow(FBNativeWindowType p_window, - int x, - int y, - int width, - int height, - SubWindowRepaintCallback repaint_callback, - void* repaint_callback_param) { - // The call to this function is protected by a lock - // in FrameBuffer so it is safe to check and initialize s_display here - if (!s_display) { - s_display = XOpenDisplay(NULL); - } - - XSetWindowAttributes wa; - wa.event_mask = StructureNotifyMask; - wa.override_redirect = True; - Window win = XCreateWindow(s_display, - p_window, - x, - y, - width, - height, - 0, - CopyFromParent, - CopyFromParent, - CopyFromParent, - CWEventMask, - &wa); - XMapWindow(s_display,win); - XSetWindowBackground(s_display, win, BlackPixel(s_display, 0)); - XEvent e; - XIfEvent(s_display, &e, WaitForMapNotify, (char *)win); - return win; -} - -void destroySubWindow(EGLNativeWindowType win) { - if (!s_display) { - return; - } - XDestroyWindow(s_display, win); -} - -int moveSubWindow(FBNativeWindowType p_parent_window, - EGLNativeWindowType p_sub_window, - int x, - int y, - int width, - int height) { - // This value is set during create, so if it is still null, simply - // return because the global state is corrupted - if (!s_display) { - return false; - } - - // This prevents flicker on resize. - XSetWindowBackgroundPixmap(s_display, p_sub_window, None); - - int ret = XMoveResizeWindow( - s_display, - p_sub_window, - x, - y, - width, - height); - - XEvent e; - XIfEvent(s_display, &e, WaitForConfigureNotify, (char *)p_sub_window); - - return ret; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.cpp b/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.cpp deleted file mode 100644 index 81ee202..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#include "Win32PipeStream.h" - -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#error ONLY BUILD THIS SOURCE FILE FOR WINDOWS! -#endif - -/* The official documentation states that the name of a given named - * pipe cannot be more than 256 characters long. - */ -#define NAMED_PIPE_MAX 256 - -Win32PipeStream::Win32PipeStream(size_t bufSize) : - SocketStream(bufSize), - m_pipe(INVALID_HANDLE_VALUE) -{ -} - -Win32PipeStream::Win32PipeStream(HANDLE pipe, size_t bufSize) : - SocketStream(-1, bufSize), - m_pipe(pipe) -{ -} - -Win32PipeStream::~Win32PipeStream() -{ - if (m_pipe != INVALID_HANDLE_VALUE) { - CloseHandle(m_pipe); - m_pipe = INVALID_HANDLE_VALUE; - } -} - -/* Initialize the pipe name corresponding to a given port - */ -static void -make_pipe_name(char *path, size_t pathlen, int port_number) -{ - snprintf(path, pathlen, "\\\\.\\pipe\\qemu-gles-%d", port_number); -} - - -/* Technical note: Named pipes work differently from BSD Sockets. - * One does not create/bind a pipe, and collect a new handle each - * time a client connects with accept(). - * - * Instead, the server creates a new pipe instance each time it wants - * to get a new client connection, then calls ConnectNamedPipe() to - * wait for a connection. - * - * So listen() is a no-op, and accept() really creates the pipe handle. - * - * Also, connect() must create a pipe handle with CreateFile() and - * wait for a server instance with WaitNamedPipe() - */ -int Win32PipeStream::listen(char addrstr[MAX_ADDRSTR_LEN]) -{ - m_port = GetCurrentProcessId(); - make_pipe_name(addrstr, MAX_ADDRSTR_LEN, m_port); - return 0; -} - -SocketStream * Win32PipeStream::accept() -{ - char path[NAMED_PIPE_MAX+1]; - SocketStream* clientStream; - HANDLE pipe; - - make_pipe_name(path, sizeof(path), m_port); - - pipe = ::CreateNamedPipe( - path, // pipe name - PIPE_ACCESS_DUPLEX, // read-write access - PIPE_TYPE_BYTE | // byte-oriented writes - PIPE_READMODE_BYTE | // byte-oriented reads - PIPE_WAIT, // blocking operations - PIPE_UNLIMITED_INSTANCES, // no limit on clients - 4096, // input buffer size - 4096, // output buffer size - 0, // client time-out - NULL); // default security attributes - - if (pipe == INVALID_HANDLE_VALUE) { - ERR("%s: CreateNamedPipe failed %d\n", __FUNCTION__, (int)GetLastError()); - return NULL; - } - - // Stupid Win32 API design: If a client is already connected, then - // ConnectNamedPipe will return 0, and GetLastError() will return - // ERROR_PIPE_CONNECTED. This is not an error! It just means that the - // function didn't have to wait. - // - if (::ConnectNamedPipe(pipe, NULL) == 0 && GetLastError() != ERROR_PIPE_CONNECTED) { - ERR("%s: ConnectNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); - CloseHandle(pipe); - return NULL; - } - - clientStream = new Win32PipeStream(pipe, m_bufsize); - return clientStream; -} - -int Win32PipeStream::connect(const char* addr) -{ - HANDLE pipe; - int tries = 10; - - /* We're going to loop in order to wait for the pipe server to - * be setup properly. - */ - for (; tries > 0; tries--) { - pipe = ::CreateFile( - addr, // pipe name - GENERIC_READ | GENERIC_WRITE, // read & write - 0, // no sharing - NULL, // default security attrs - OPEN_EXISTING, // open existing pipe - 0, // default attributes - NULL); // no template file - - /* If we have a valid pipe handle, break from the loop */ - if (pipe != INVALID_HANDLE_VALUE) { - break; - } - - /* We can get here if the pipe is busy, i.e. if the server hasn't - * create a new pipe instance to service our request. In which case - * GetLastError() will return ERROR_PIPE_BUSY. - * - * If so, then use WaitNamedPipe() to wait for a decent time - * to try again. - */ - if (GetLastError() != ERROR_PIPE_BUSY) { - /* Not ERROR_PIPE_BUSY */ - ERR("%s: CreateFile failed: %d\n", __FUNCTION__, (int)GetLastError()); - errno = EINVAL; - return -1; - } - - /* Wait for 5 seconds */ - if ( !WaitNamedPipe(addr, 5000) ) { - ERR("%s: WaitNamedPipe failed: %d\n", __FUNCTION__, (int)GetLastError()); - errno = EINVAL; - return -1; - } - } - - m_pipe = pipe; - return 0; -} - -/* Special buffer methods, since we can't use socket functions here */ - -int Win32PipeStream::commitBuffer(size_t size) -{ - if (m_pipe == INVALID_HANDLE_VALUE) - return -1; - - size_t res = size; - int retval = 0; - - while (res > 0) { - DWORD written; - if (! ::WriteFile(m_pipe, (const char *)m_buf + (size - res), res, &written, NULL)) { - retval = -1; - ERR("%s: failed: %d\n", __FUNCTION__, (int)GetLastError()); - break; - } - res -= written; - } - return retval; -} - -const unsigned char *Win32PipeStream::readFully(void *buf, size_t len) -{ - if (m_pipe == INVALID_HANDLE_VALUE) - return NULL; - - if (!buf) { - return NULL; // do not allow NULL buf in that implementation - } - - size_t res = len; - while (res > 0) { - DWORD readcount = 0; - if (! ::ReadFile(m_pipe, (char *)buf + (len - res), res, &readcount, NULL) || readcount == 0) { - errno = (int)GetLastError(); - return NULL; - } - res -= readcount; - } - return (const unsigned char *)buf; -} - -const unsigned char *Win32PipeStream::read( void *buf, size_t *inout_len) -{ - size_t len = *inout_len; - DWORD readcount; - - if (m_pipe == INVALID_HANDLE_VALUE) - return NULL; - - if (!buf) { - return NULL; // do not allow NULL buf in that implementation - } - - if (!::ReadFile(m_pipe, (char *)buf, len, &readcount, NULL)) { - errno = (int)GetLastError(); - return NULL; - } - - *inout_len = (size_t)readcount; - return (const unsigned char *)buf; -} - -void Win32PipeStream::forceStop() -{ - HANDLE handle = m_pipe; - m_pipe = INVALID_HANDLE_VALUE; - CloseHandle(handle); -} diff --git a/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.h b/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.h deleted file mode 100644 index be44074..0000000 --- a/external/android-emugl/host/libs/libOpenglRender/Win32PipeStream.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#ifndef __WIN32_PIPE_STREAM_H -#define __WIN32_PIPE_STREAM_H - -#include "SocketStream.h" -#include - -class Win32PipeStream : public SocketStream { -public: - explicit Win32PipeStream(size_t bufsize = 10000); - virtual ~Win32PipeStream(); - virtual int listen(char addrstr[MAX_ADDRSTR_LEN]); - virtual SocketStream *accept(); - virtual int connect(const char* addr); - - 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 forceStop(); - -private: - Win32PipeStream(HANDLE pipe, size_t bufSize); - HANDLE m_pipe; - int m_port; -}; - - -#endif diff --git a/external/android-emugl/host/libs/renderControl_dec/renderControl.attrib b/external/android-emugl/host/libs/renderControl_dec/renderControl.attrib index 0afa9d3..4a3bb18 100644 --- a/external/android-emugl/host/libs/renderControl_dec/renderControl.attrib +++ b/external/android-emugl/host/libs/renderControl_dec/renderControl.attrib @@ -42,3 +42,6 @@ rcUpdateColorBuffer rcCloseColorBuffer flag flushOnEncode + +rcPostLayer + len name (strlen(name) + 1) diff --git a/external/android-emugl/host/libs/renderControl_dec/renderControl.in b/external/android-emugl/host/libs/renderControl_dec/renderControl.in index 2cc4031..a632a0a 100644 --- a/external/android-emugl/host/libs/renderControl_dec/renderControl.in +++ b/external/android-emugl/host/libs/renderControl_dec/renderControl.in @@ -27,3 +27,11 @@ GL_ENTRY(int, rcOpenColorBuffer2, uint32_t colorbuffer) GL_ENTRY(uint32_t, rcCreateClientImage, uint32_t context, EGLenum target, GLuint buffer) GL_ENTRY(int, rcDestroyClientImage, uint32_t image) GL_ENTRY(void, rcSelectChecksumCalculator, uint32_t newProtocol, uint32_t reserved) +GL_ENTRY(int, rcGetNumDisplays) +GL_ENTRY(int, rcGetDisplayWidth, uint32_t displayId) +GL_ENTRY(int, rcGetDisplayHeight, uint32_t displayId) +GL_ENTRY(int, rcGetDisplayDpiX, uint32_t displayId) +GL_ENTRY(int, rcGetDisplayDpiY, uint32_t displayId) +GL_ENTRY(int, rcGetDisplayVsyncPeriod, uint32_t displayId) +GL_ENTRY(void, rcPostLayer, const char* name, uint32_t colorBuffer, int32_t sourceCropLeft, int32_t sourceCropTop, int32_t sourceCropRight, int32_t sourceCropBottom, int32_t displayFrameLeft, int32_t displayFrameTop, int32_t displayFrameRight, int32_t displayFrameBottom) +GL_ENTRY(void, rcPostAllLayersDone) diff --git a/external/android-emugl/host/libs/renderControl_dec/renderControl.types b/external/android-emugl/host/libs/renderControl_dec/renderControl.types index 2b38470..9bb0546 100644 --- a/external/android-emugl/host/libs/renderControl_dec/renderControl.types +++ b/external/android-emugl/host/libs/renderControl_dec/renderControl.types @@ -1,4 +1,5 @@ uint32_t 32 0x%08x +int32_t 32 0x%08x EGLint 32 0x%08x GLint 32 0x%08x GLuint 32 0x%08x @@ -9,3 +10,4 @@ EGLint* 32 0x%08x GLint* 32 0x%08x GLuint* 32 0x%08x void* 32 0x%08x +char* 32 0x%08x diff --git a/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt b/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt index 1dda791..67606d7 100644 --- a/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt +++ b/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt @@ -1,6 +1,15 @@ set(SOURCES - glUtils.cpp ChecksumCalculator.cpp - ChecksumCalculatorThreadInfo.cpp) + ChecksumCalculator.h + ChecksumCalculatorThreadInfo.cpp + ChecksumCalculatorThreadInfo.h + CMakeLists.txt + ErrorLog.h + gl_base_types.h + GLDecoderContextData.h + glUtils.cpp + glUtils.h + Makefile + ProtocolUtils.h) add_library(OpenglCodecCommon ${SOURCES}) diff --git a/external/android-emugl/shared/emugl/common/CMakeLists.txt b/external/android-emugl/shared/emugl/common/CMakeLists.txt index a479a9b..ef8b6d2 100644 --- a/external/android-emugl/shared/emugl/common/CMakeLists.txt +++ b/external/android-emugl/shared/emugl/common/CMakeLists.txt @@ -1,15 +1,32 @@ set(COMMON_SOURCES + condition_variable.h crash_reporter.cpp + crash_reporter.h id_to_object_map.cpp + id_to_object_map.h lazy_instance.cpp + lazy_instance.h logging.cpp + logging.h message_channel.cpp + message_channel.h + mutex.h + mutex_unittest.cpp pod_vector.cpp + pod_vector.h + scoped_pointer_vector.h shared_library.cpp + shared_library.h smart_ptr.cpp + smart_ptr.h sockets.cpp + sockets.h + thread.h + thread_pthread.cpp thread_store.cpp - thread_pthread.cpp) + thread_store.h + thread_unittest.cpp + unique_integer_map.h) add_library(emugl_common ${COMMON_SOURCES}) target_link_libraries(emugl_common diff --git a/scripts/android-sync.sh b/scripts/android-sync.sh new file mode 100755 index 0000000..a3b23de --- /dev/null +++ b/scripts/android-sync.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -ex + +if [ -z "$ANDROID_PRODUCT_OUT" ]; then + echo "ANDROID_PRODUCT_OUT is not set!" + exit 1 +fi + +target=$1 +if [ -z "$target" ]; then + echo "No target path provided!" + exit 1 +fi + +sudo cp -rv $ANDROID_PRODUCT_OUT/system $target +sudo rm /var/lib/anbox/rootfs/.anbox_setup_done diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 75eeffe..84d5209 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,17 @@ include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/external/process-cpp-minimal/include + ${CMAKE_SOURCE_DIR}/external/android-emugl/shared ${CMAKE_SOURCE_DIR}/external/android-emugl/host/include + ${CMAKE_SOURCE_DIR}/external/android-emugl/shared/OpenglCodecCommon + ${CMAKE_SOURCE_DIR}/external/android-emugl/host/libs + ${CMAKE_SOURCE_DIR}/external/android-emugl/host/include/libOpenglRender + ${CMAKE_SOURCE_DIR}/external/android-emugl/host/libs/GLESv1_dec + ${CMAKE_BINARY_DIR}/external/android-emugl/host/libs/GLESv1_dec + ${CMAKE_SOURCE_DIR}/external/android-emugl/host/libs/GLESv2_dec + ${CMAKE_BINARY_DIR}/external/android-emugl/host/libs/GLESv2_dec + ${CMAKE_SOURCE_DIR}/external/android-emugl/host/libs/renderControl_dec + ${CMAKE_BINARY_DIR}/external/android-emugl/host/libs/renderControl_dec ) protobuf_generate_cpp( @@ -93,8 +103,41 @@ set(SOURCES anbox/graphics/opengles_message_processor.cpp anbox/graphics/gl_renderer_server.cpp - anbox/graphics/window_creator.cpp anbox/graphics/density.h + anbox/graphics/rect.cpp + anbox/graphics/layer_composer.cpp + anbox/graphics/program_family.cpp + anbox/graphics/primitives.h + + anbox/graphics/emugl/ColorBuffer.cpp + anbox/graphics/emugl/DisplayManager.cpp + anbox/graphics/emugl/RendererConfig.cpp + anbox/graphics/emugl/Renderable.cpp + anbox/graphics/emugl/Renderer.cpp + anbox/graphics/emugl/ReadBuffer.cpp + anbox/graphics/emugl/RenderApi.cpp + anbox/graphics/emugl/RenderContext.cpp + anbox/graphics/emugl/RenderControl.cpp + anbox/graphics/emugl/RenderServer.cpp + anbox/graphics/emugl/RenderThread.cpp + anbox/graphics/emugl/RenderThreadInfo.cpp + anbox/graphics/emugl/RenderWindow.cpp + anbox/graphics/emugl/SocketStream.cpp + anbox/graphics/emugl/TcpStream.cpp + anbox/graphics/emugl/TextureDraw.cpp + anbox/graphics/emugl/TextureResize.cpp + anbox/graphics/emugl/TimeUtils.cpp + anbox/graphics/emugl/UnixStream.cpp + anbox/graphics/emugl/WindowSurface.cpp + + anbox/wm/display.cpp + anbox/wm/task.cpp + anbox/wm/stack.cpp + anbox/wm/manager.cpp + anbox/wm/window_state.cpp + anbox/wm/window.cpp + anbox/wm/platform_policy.cpp + anbox/wm/default_platform_policy.cpp anbox/input/manager.cpp anbox/input/device.cpp @@ -116,9 +159,9 @@ set(SOURCES anbox/bridge/platform_api_skeleton.cpp anbox/bridge/android_api_stub.cpp - anbox/ubuntu/platform_api_skeleton.cpp - anbox/ubuntu/window_creator.cpp anbox/ubuntu/window.cpp + anbox/ubuntu/keycode_converter.cpp + anbox/ubuntu/platform_policy.cpp anbox/dbus/interface.h anbox/dbus/skeleton/service.cpp @@ -144,7 +187,12 @@ target_link_libraries(anbox-core ${LXC_LIBRARIES} pthread process-cpp - OpenglRender + emugl_common + GLESv1_dec + GLESv2_dec + renderControl_dec + OpenGLESDispatch + OpenglCodecCommon anbox-protobuf) add_executable(anbox main.cpp) diff --git a/src/anbox/bridge/android_api_stub.cpp b/src/anbox/bridge/android_api_stub.cpp index e7bb5f7..92c4370 100644 --- a/src/anbox/bridge/android_api_stub.cpp +++ b/src/anbox/bridge/android_api_stub.cpp @@ -82,6 +82,7 @@ void AndroidApiStub::install(const std::string &path) { } void AndroidApiStub::application_installed(Request *request) { + (void) request; install_wait_handle_.result_received(); } @@ -110,6 +111,7 @@ void AndroidApiStub::launch(const std::string &package, const std::string &activ } void AndroidApiStub::application_launched(Request *request) { + (void) request; launch_wait_handle_.result_received(); } @@ -143,7 +145,37 @@ void AndroidApiStub::set_dns_servers(const std::string &domain, const std::vecto } void AndroidApiStub::dns_servers_set(Request *request) { + (void) request; set_dns_servers_wait_handle_.result_received(); } + +void AndroidApiStub::set_focused_task(const std::int32_t &id) { + ensure_rpc_channel(); + + auto c = std::make_shared>(); + + protobuf::bridge::SetFocusedTask message; + message.set_id(id); + + { + std::lock_guard 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())); + + set_focused_task_handle_.wait_for_all(); + + if (c->response->has_error()) + throw std::runtime_error(c->response->error()); +} + +void AndroidApiStub::focused_task_set(Request *request) { + (void) request; + set_focused_task_handle_.result_received(); +} } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/android_api_stub.h b/src/anbox/bridge/android_api_stub.h index 58e1a92..73cff7c 100644 --- a/src/anbox/bridge/android_api_stub.h +++ b/src/anbox/bridge/android_api_stub.h @@ -46,6 +46,7 @@ public: void launch(const std::string &package, const std::string &activity) override; void set_dns_servers(const std::string &domain, const std::vector &servers); + void set_focused_task(const std::int32_t &id); private: void ensure_rpc_channel(); @@ -60,12 +61,14 @@ private: void application_installed(Request *request); void application_launched(Request *request); void dns_servers_set(Request *request); + void focused_task_set(Request *request); mutable std::mutex mutex_; std::shared_ptr channel_; common::WaitHandle install_wait_handle_; common::WaitHandle launch_wait_handle_; common::WaitHandle set_dns_servers_wait_handle_; + common::WaitHandle set_focused_task_handle_; }; } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/platform_api_skeleton.cpp b/src/anbox/bridge/platform_api_skeleton.cpp index e9e53e8..cb21e67 100644 --- a/src/anbox/bridge/platform_api_skeleton.cpp +++ b/src/anbox/bridge/platform_api_skeleton.cpp @@ -16,17 +16,58 @@ */ #include "anbox/bridge/platform_api_skeleton.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 &pending_calls) : - pending_calls_(pending_calls) { +PlatformApiSkeleton::PlatformApiSkeleton(const std::shared_ptr &pending_calls, + const std::shared_ptr &window_manager) : + pending_calls_(pending_calls), + window_manager_(window_manager) { } PlatformApiSkeleton::~PlatformApiSkeleton() { } + +void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event) { + (void) event; + + if (boot_finished_handler_) + boot_finished_handler_(); +} + +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 &action) { + boot_finished_handler_ = action; +} } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/platform_api_skeleton.h b/src/anbox/bridge/platform_api_skeleton.h index aafe417..030e7ea 100644 --- a/src/anbox/bridge/platform_api_skeleton.h +++ b/src/anbox/bridge/platform_api_skeleton.h @@ -32,28 +32,32 @@ namespace rpc { class Void; } // namespace rpc namespace bridge { -class Notification; +class BootFinishedEvent; +class WindowStateUpdateEvent; } // namespace bridge } // namespace protobuf namespace rpc { class PendingCallCache; } // namespace rpc +namespace wm { +class Manager; +} // namespace wm namespace bridge { class PlatformApiSkeleton { public: - PlatformApiSkeleton(const std::shared_ptr &pending_calls); + PlatformApiSkeleton(const std::shared_ptr &pending_calls, + const std::shared_ptr &window_manager); virtual ~PlatformApiSkeleton(); - virtual void boot_finished(anbox::protobuf::rpc::Void const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) = 0; + void handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event); + void handle_window_state_update_event(const anbox::protobuf::bridge::WindowStateUpdateEvent &event); - virtual void handle_notification(anbox::protobuf::bridge::Notification const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) = 0; + void register_boot_finished_handler(const std::function &action); private: std::shared_ptr pending_calls_; + std::shared_ptr window_manager_; + std::function boot_finished_handler_; }; } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/platform_message_processor.cpp b/src/anbox/bridge/platform_message_processor.cpp index 599a3cb..5b9892c 100644 --- a/src/anbox/bridge/platform_message_processor.cpp +++ b/src/anbox/bridge/platform_message_processor.cpp @@ -18,6 +18,7 @@ #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_bridge.pb.h" @@ -34,13 +35,20 @@ PlatformMessageProcessor::~PlatformMessageProcessor() { } void PlatformMessageProcessor::dispatch(rpc::Invocation const& invocation) { - if (invocation.method_name() == "handle_notification") - invoke(this, server_.get(), &PlatformApiSkeleton::handle_notification, invocation); - else if (invocation.method_name() == "boot_finished") - invoke(this, server_.get(), &PlatformApiSkeleton::boot_finished, invocation); } -void PlatformMessageProcessor::process_event_sequence(const std::string&) { +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_window_state_update()) + server_->handle_window_state_update_event(seq.window_state_update()); + + if (seq.has_boot_finished()) + server_->handle_boot_finished_event(seq.boot_finished()); } } // namespace anbox } // namespace network diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index 7fffe26..f32c522 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -32,10 +32,11 @@ #include "anbox/rpc/channel.h" #include "anbox/bridge/platform_message_processor.h" #include "anbox/bridge/android_api_stub.h" -#include "anbox/ubuntu/platform_api_skeleton.h" -#include "anbox/ubuntu/window_creator.h" +#include "anbox/bridge/platform_api_skeleton.h" #include "anbox/dbus/skeleton/service.h" #include "anbox/container/client.h" +#include "anbox/wm/manager.h" +#include "anbox/ubuntu/platform_policy.h" #include @@ -88,8 +89,15 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory) auto input_manager = std::make_shared(rt); - auto window_creator = std::make_shared(input_manager); - auto renderer = std::make_shared(window_creator); + auto android_api_stub = std::make_shared(); + + auto policy = std::make_shared(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(policy); + + auto renderer = std::make_shared(window_manager); renderer->start(); // Socket which will be used by the qemud service inside the Android @@ -110,7 +118,6 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory) renderer->socket_path(), icon_)); - auto android_api_stub = std::make_shared(); auto bridge_connector = std::make_shared( utils::string_format("%s/anbox_bridge", config::socket_path()), @@ -123,8 +130,9 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory) // 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(pending_calls); - server->on_boot_finished([&]() { + auto server = std::make_shared(pending_calls, window_manager); + server->register_boot_finished_handler([&]() { + DEBUG("Android successfully booted"); dispatcher->dispatch([&]() { // FIXME make this configurable or once we have a bridge let the host // act as a DNS proxy. diff --git a/external/android-emugl/host/libs/libOpenglRender/ColorBuffer.cpp b/src/anbox/graphics/emugl/ColorBuffer.cpp similarity index 97% rename from external/android-emugl/host/libs/libOpenglRender/ColorBuffer.cpp rename to src/anbox/graphics/emugl/ColorBuffer.cpp index 95de4dd..2537503 100644 --- a/external/android-emugl/host/libs/libOpenglRender/ColorBuffer.cpp +++ b/src/anbox/graphics/emugl/ColorBuffer.cpp @@ -127,8 +127,6 @@ ColorBuffer* ColorBuffer::create(EGLDisplay p_display, Helper* helper) { GLenum texInternalFormat = 0; - printf("Creating new color buffer width %i height %i\n", p_width, p_height); - switch (p_internalFormat) { case GL_RGB: case GL_RGB565_OES: @@ -335,7 +333,7 @@ bool ColorBuffer::blitFromCurrentReadBuffer() s_gles2.glViewport(0, 0, m_width, m_height); // render m_blitTex - m_helper->getTextureDraw()->draw(m_blitTex, 0., 0, 0); + m_helper->getTextureDraw()->draw(m_blitTex); // Restore previous viewport. s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]); @@ -378,11 +376,6 @@ bool ColorBuffer::bindToRenderbuffer() { return true; } -bool ColorBuffer::post(float rotation, float dx, float dy) { - // NOTE: Do not call m_helper->setupContext() here! - return m_helper->getTextureDraw()->draw(m_resizer->update(m_tex), rotation, dx, dy); -} - void ColorBuffer::readback(unsigned char* img) { ScopedHelperContext context(m_helper); if (!context.isOk()) { @@ -394,3 +387,8 @@ void ColorBuffer::readback(unsigned char* img) { unbindFbo(); } } + +void ColorBuffer::bind() { + const auto id = m_resizer->update(m_tex); + s_gles2.glBindTexture(GL_TEXTURE_2D, id); +} diff --git a/external/android-emugl/host/libs/libOpenglRender/ColorBuffer.h b/src/anbox/graphics/emugl/ColorBuffer.h similarity index 93% rename from external/android-emugl/host/libs/libOpenglRender/ColorBuffer.h rename to src/anbox/graphics/emugl/ColorBuffer.h index a9ce3c5..6eb48a3 100644 --- a/external/android-emugl/host/libs/libOpenglRender/ColorBuffer.h +++ b/src/anbox/graphics/emugl/ColorBuffer.h @@ -23,7 +23,6 @@ #include - class TextureDraw; class TextureResize; @@ -109,15 +108,6 @@ public: GLenum p_type, void *pixels); - // Draw a ColorBuffer instance, i.e. blit it to the current guest - // framebuffer object / window surface. This doesn't display anything. - bool draw(); - - // Post this ColorBuffer to the host native sub-window. - // |rotation| is the rotation angle in degrees, clockwise in the GL - // coordinate space. - bool post(float rotation, float dx, float dy); - // Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's // EGLImage. This is intended to implement glEGLImageTargetTexture2DOES() // for all GLES versions. @@ -137,6 +127,7 @@ public: // |img| must be a buffer large enough (i.e. width * height * 4). void readback(unsigned char* img); + void bind(); private: ColorBuffer(); // no default constructor. diff --git a/external/android-emugl/host/libs/libOpenglRender/DispatchTables.h b/src/anbox/graphics/emugl/DispatchTables.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/DispatchTables.h rename to src/anbox/graphics/emugl/DispatchTables.h diff --git a/src/anbox/graphics/emugl/DisplayManager.cpp b/src/anbox/graphics/emugl/DisplayManager.cpp new file mode 100644 index 0000000..2e26a81 --- /dev/null +++ b/src/anbox/graphics/emugl/DisplayManager.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "DisplayManager.h" + +namespace { +std::shared_ptr display_mgr; + +class NullDisplayManager : public DisplayManager { +public: + DisplayInfo display_info() const override { + return {1280, 720}; + } +}; +} + +DisplayManager::~DisplayManager() { +} + +std::shared_ptr DisplayManager::get() { + if (!display_mgr) + display_mgr = std::make_shared(); + return display_mgr; +} + +void registerDisplayManager(const std::shared_ptr &mgr) { + display_mgr = mgr; +} diff --git a/src/anbox/graphics/window_creator.h b/src/anbox/graphics/emugl/DisplayManager.h similarity index 59% rename from src/anbox/graphics/window_creator.h rename to src/anbox/graphics/emugl/DisplayManager.h index 00cd8be..beb678a 100644 --- a/src/anbox/graphics/window_creator.h +++ b/src/anbox/graphics/emugl/DisplayManager.h @@ -15,20 +15,14 @@ * */ -#ifndef ANBOX_GRAPHICS_WINDOW_CREATOR_H_ -#define ANBOX_GRAPHICS_WINDOW_CREATOR_H_ +#ifndef DISPLAY_MANAGER_H_ +#define DISPLAY_MANAGER_H_ -#include "external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h" +#include -namespace anbox { -namespace input { -class Manager; -} // namespace input -namespace graphics { -class WindowCreator : public SubWindowHandler { +class DisplayManager { public: - WindowCreator(const std::shared_ptr &input_manager); - virtual ~WindowCreator(); + virtual ~DisplayManager(); struct DisplayInfo { int horizontal_resolution; @@ -36,11 +30,10 @@ public: }; virtual DisplayInfo display_info() const = 0; - virtual EGLNativeDisplayType native_display() const = 0; -protected: - std::shared_ptr input_manager_; + static std::shared_ptr get(); }; -} // namespace graphics -} // namespace anbox + +void registerDisplayManager(const std::shared_ptr &mgr); + #endif diff --git a/external/android-emugl/host/libs/libOpenglRender/ReadBuffer.cpp b/src/anbox/graphics/emugl/ReadBuffer.cpp similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/ReadBuffer.cpp rename to src/anbox/graphics/emugl/ReadBuffer.cpp diff --git a/external/android-emugl/host/libs/libOpenglRender/ReadBuffer.h b/src/anbox/graphics/emugl/ReadBuffer.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/ReadBuffer.h rename to src/anbox/graphics/emugl/ReadBuffer.h diff --git a/external/android-emugl/host/libs/libOpenglRender/render_api.cpp b/src/anbox/graphics/emugl/RenderApi.cpp similarity index 73% rename from external/android-emugl/host/libs/libOpenglRender/render_api.cpp rename to src/anbox/graphics/emugl/RenderApi.cpp index 228119f..d0b40e9 100644 --- a/external/android-emugl/host/libs/libOpenglRender/render_api.cpp +++ b/src/anbox/graphics/emugl/RenderApi.cpp @@ -21,11 +21,7 @@ #include "TimeUtils.h" #include "TcpStream.h" -#ifdef _WIN32 -#include "Win32PipeStream.h" -#else #include "UnixStream.h" -#endif #include "DispatchTables.h" @@ -78,8 +74,7 @@ RENDER_APICALL int RENDER_APIENTRY initLibrary(void) } RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer( - EGLNativeDisplayType native_display, - int width, int height, bool useSubWindow, char* addr, size_t addrLen, + 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); @@ -117,7 +112,7 @@ RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer( // initialize the renderer and listen to connections // on a thread in the current process. // - s_renderWindow = new RenderWindow(native_display, width, height, kUseThread, useSubWindow); + 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"); @@ -142,15 +137,6 @@ RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer( return true; } -RENDER_APICALL void RENDER_APIENTRY setPostCallback( - OnPostFn onPost, void* onPostContext) { - if (s_renderWindow) { - s_renderWindow->setPostCallback(onPost, onPostContext); - } else { - ERR("Calling setPostCallback() before creating render window!"); - } -} - RENDER_APICALL void RENDER_APIENTRY getHardwareStrings( const char** vendor, const char** renderer, @@ -228,53 +214,7 @@ RENDER_APICALL bool RENDER_APIENTRY destroyOpenGLSubwindow(void) return false; } -RENDER_APICALL void RENDER_APIENTRY setOpenGLDisplayRotation(float zRot) -{ - RenderWindow* window = s_renderWindow; - - if (window) { - window->setRotation(zRot); - return; - } - // XXX: should be implemented by sending the renderer process - // a request - ERR("%s not implemented for separate renderer process !!!\n", - __FUNCTION__); -} - -RENDER_APICALL void RENDER_APIENTRY setOpenGLDisplayTranslation(float px, float py) -{ - RenderWindow* window = s_renderWindow; - - if (window) { - window->setTranslation(px, py); - return; - } - // XXX: should be implemented by sending the renderer process - // a request - ERR("%s not implemented for separate renderer process !!!\n", - __FUNCTION__); -} - -RENDER_APICALL void RENDER_APIENTRY repaintOpenGLDisplay(void) -{ - RenderWindow* window = s_renderWindow; - - if (window) { - window->repaint(); - return; - } - // XXX: should be implemented by sending the renderer process - // a request - ERR("%s not implemented for separate renderer process !!!\n", - __FUNCTION__); -} - - -/* NOTE: For now, always use TCP mode by default, until the emulator - * has been updated to support Unix and Win32 pipes - */ -#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_TCP +#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_UNIX int gRendererStreamMode = DEFAULT_STREAM_MODE; @@ -285,11 +225,7 @@ IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) { stream = new TcpStream(p_stream_buffer_size); } else { -#ifdef _WIN32 - stream = new Win32PipeStream(p_stream_buffer_size); -#else /* !_WIN32 */ stream = new UnixStream(p_stream_buffer_size); -#endif } if (!stream) { @@ -312,28 +248,3 @@ IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags) return stream; } - -RENDER_APICALL int RENDER_APIENTRY setStreamMode(int mode) -{ - switch (mode) { - case RENDER_API_STREAM_MODE_DEFAULT: - mode = DEFAULT_STREAM_MODE; - break; - - case RENDER_API_STREAM_MODE_TCP: - break; - -#ifndef _WIN32 - case RENDER_API_STREAM_MODE_UNIX: - break; -#else /* _WIN32 */ - case RENDER_API_STREAM_MODE_PIPE: - break; -#endif /* _WIN32 */ - default: - // Invalid stream mode - return false; - } - gRendererStreamMode = mode; - return true; -} diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderContext.cpp b/src/anbox/graphics/emugl/RenderContext.cpp similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderContext.cpp rename to src/anbox/graphics/emugl/RenderContext.cpp diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderContext.h b/src/anbox/graphics/emugl/RenderContext.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderContext.h rename to src/anbox/graphics/emugl/RenderContext.h diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderControl.cpp b/src/anbox/graphics/emugl/RenderControl.cpp similarity index 75% rename from external/android-emugl/host/libs/libOpenglRender/RenderControl.cpp rename to src/anbox/graphics/emugl/RenderControl.cpp index 44fd113..ef32831 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderControl.cpp +++ b/src/anbox/graphics/emugl/RenderControl.cpp @@ -16,14 +16,27 @@ #include "RenderControl.h" #include "DispatchTables.h" -#include "FbConfig.h" -#include "FrameBuffer.h" +#include "RendererConfig.h" +#include "Renderer.h" #include "RenderThreadInfo.h" #include "ChecksumCalculatorThreadInfo.h" +#include "DisplayManager.h" #include "OpenGLESDispatch/EGLDispatch.h" +#include "anbox/graphics/layer_composer.h" +#include "anbox/logger.h" + +#include +#include + static const GLint rendererVersion = 1; +static std::shared_ptr composer; + +void registerLayerComposer(const std::shared_ptr &c) +{ + composer = c; +} static GLint rcGetRendererVersion() { @@ -32,7 +45,7 @@ static GLint rcGetRendererVersion() static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return EGL_FALSE; } @@ -44,7 +57,7 @@ static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor) static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -118,7 +131,7 @@ static EGLint rcGetNumConfigs(uint32_t* p_numAttribs) { int numConfigs = 0, numAttribs = 0; - FrameBuffer::getFB()->getConfigs()->getPackInfo(&numConfigs, &numAttribs); + Renderer::get()->getConfigs()->getPackInfo(&numConfigs, &numAttribs); if (p_numAttribs) { *p_numAttribs = static_cast(numAttribs); } @@ -128,7 +141,7 @@ static EGLint rcGetNumConfigs(uint32_t* p_numAttribs) static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer) { GLuint bufferSize = (GLuint)bufSize; - return FrameBuffer::getFB()->getConfigs()->packConfigs(bufferSize, buffer); + return Renderer::get()->getConfigs()->packConfigs(bufferSize, buffer); } static EGLint rcChooseConfig(EGLint *attribs, @@ -136,7 +149,7 @@ static EGLint rcChooseConfig(EGLint *attribs, uint32_t *configs, uint32_t configs_size) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb || attribs_size==0) { return 0; } @@ -147,7 +160,7 @@ static EGLint rcChooseConfig(EGLint *attribs, static EGLint rcGetFBParam(EGLint param) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -156,10 +169,10 @@ static EGLint rcGetFBParam(EGLint param) switch(param) { case FB_WIDTH: - ret = fb->getWidth(); + ret = DisplayManager::get()->display_info().horizontal_resolution; break; case FB_HEIGHT: - ret = fb->getHeight(); + ret = DisplayManager::get()->display_info().vertical_resolution; break; case FB_XDPI: ret = 72; // XXX: should be implemented @@ -186,7 +199,7 @@ static EGLint rcGetFBParam(EGLint param) static uint32_t rcCreateContext(uint32_t config, uint32_t share, uint32_t glVersion) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -199,7 +212,7 @@ static uint32_t rcCreateContext(uint32_t config, static void rcDestroyContext(uint32_t context) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -210,7 +223,7 @@ static void rcDestroyContext(uint32_t context) static uint32_t rcCreateWindowSurface(uint32_t config, uint32_t width, uint32_t height) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -220,7 +233,7 @@ static uint32_t rcCreateWindowSurface(uint32_t config, static void rcDestroyWindowSurface(uint32_t windowSurface) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -231,7 +244,7 @@ static void rcDestroyWindowSurface(uint32_t windowSurface) static uint32_t rcCreateColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -241,7 +254,7 @@ static uint32_t rcCreateColorBuffer(uint32_t width, static int rcOpenColorBuffer2(uint32_t colorbuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return -1; } @@ -257,7 +270,7 @@ static void rcOpenColorBuffer(uint32_t colorbuffer) static void rcCloseColorBuffer(uint32_t colorbuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -266,7 +279,7 @@ static void rcCloseColorBuffer(uint32_t colorbuffer) static int rcFlushWindowColorBuffer(uint32_t windowSurface) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return -1; } @@ -279,7 +292,7 @@ static int rcFlushWindowColorBuffer(uint32_t windowSurface) static void rcSetWindowColorBuffer(uint32_t windowSurface, uint32_t colorBuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -289,7 +302,7 @@ static void rcSetWindowColorBuffer(uint32_t windowSurface, static EGLint rcMakeCurrent(uint32_t context, uint32_t drawSurf, uint32_t readSurf) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return EGL_FALSE; } @@ -301,12 +314,7 @@ static EGLint rcMakeCurrent(uint32_t context, static void rcFBPost(uint32_t colorBuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); - if (!fb) { - return; - } - - fb->post(colorBuffer); + WARNING("Not implemented"); } static void rcFBSetSwapInterval(EGLint interval) @@ -316,7 +324,7 @@ static void rcFBSetSwapInterval(EGLint interval) static void rcBindTexture(uint32_t colorBuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -326,7 +334,7 @@ static void rcBindTexture(uint32_t colorBuffer) static void rcBindRenderbuffer(uint32_t colorBuffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -346,7 +354,7 @@ static void rcReadColorBuffer(uint32_t colorBuffer, GLint width, GLint height, GLenum format, GLenum type, void* pixels) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return; } @@ -359,7 +367,7 @@ static int rcUpdateColorBuffer(uint32_t colorBuffer, GLint width, GLint height, GLenum format, GLenum type, void* pixels) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return -1; } @@ -370,7 +378,7 @@ static int rcUpdateColorBuffer(uint32_t colorBuffer, static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -380,7 +388,7 @@ static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buf static int rcDestroyClientImage(uint32_t image) { - FrameBuffer *fb = FrameBuffer::getFB(); + Renderer *fb = Renderer::get(); if (!fb) { return 0; } @@ -392,6 +400,62 @@ static void rcSelectChecksumCalculator(uint32_t protocol, uint32_t reserved) { ChecksumCalculatorThreadInfo::setVersion(protocol); } +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; +} + +int rcGetDisplayHeight(uint32_t display_id) { + 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; +} + +int rcGetDisplayDpiY(uint32_t display_id) { + 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; +} + +static std::vector frame_layers; + +bool is_layer_blacklisted(const std::string &name) { + static std::vector 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}}; + frame_layers.push_back(r); +} + +void rcPostAllLayersDone() +{ + if (composer) + composer->submit_layers(frame_layers); + + frame_layers.clear(); +} + void initRenderControlContext(renderControl_decoder_context_t *dec) { dec->rcGetRendererVersion = rcGetRendererVersion; @@ -423,4 +487,12 @@ void initRenderControlContext(renderControl_decoder_context_t *dec) 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; } diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderControl.h b/src/anbox/graphics/emugl/RenderControl.h similarity index 78% rename from external/android-emugl/host/libs/libOpenglRender/RenderControl.h rename to src/anbox/graphics/emugl/RenderControl.h index 87fe1e0..2867acc 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderControl.h +++ b/src/anbox/graphics/emugl/RenderControl.h @@ -18,6 +18,15 @@ #include "renderControl_dec.h" +#include + +namespace anbox { +namespace graphics { +class LayerComposer; +} // namespace graphics +} // namespace anbox + void initRenderControlContext(renderControl_decoder_context_t *dec); +void registerLayerComposer(const std::shared_ptr &c); #endif diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderServer.cpp b/src/anbox/graphics/emugl/RenderServer.cpp similarity index 90% rename from external/android-emugl/host/libs/libOpenglRender/RenderServer.cpp rename to src/anbox/graphics/emugl/RenderServer.cpp index bb09a40..5f23093 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderServer.cpp +++ b/src/anbox/graphics/emugl/RenderServer.cpp @@ -17,14 +17,9 @@ #include "RenderThread.h" #include "TcpStream.h" -#ifndef _WIN32 #include "UnixStream.h" #include #include -#endif -#ifdef _WIN32 -#include "Win32PipeStream.h" -#endif #include "OpenglRender/render_api.h" @@ -59,11 +54,7 @@ RenderServer *RenderServer::create(char* addr, size_t addrLen) if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) { server->m_listenSock = new TcpStream(); } else { -#ifdef _WIN32 - server->m_listenSock = new Win32PipeStream(); -#else server->m_listenSock = new UnixStream(); -#endif } char addrstr[SocketStream::MAX_ADDRSTR_LEN]; @@ -89,12 +80,6 @@ intptr_t RenderServer::main() { RenderThreadsSet threads; -#ifndef _WIN32 - sigset_t set; - sigfillset(&set); - pthread_sigmask(SIG_SETMASK, &set, NULL); -#endif - while(1) { SocketStream *stream = m_listenSock->accept(); if (!stream) { @@ -109,8 +94,6 @@ intptr_t RenderServer::main() continue; } - DBG("RenderServer: Got new stream!\n"); - // check if we have been requested to exit while waiting on accept if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) { m_exiting = true; @@ -148,10 +131,8 @@ intptr_t RenderServer::main() } // if the thread has been created and started, insert it to the list - if (rt) { + if (rt) threads.insert(rt); - DBG("Started new RenderThread\n"); - } } // diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderServer.h b/src/anbox/graphics/emugl/RenderServer.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderServer.h rename to src/anbox/graphics/emugl/RenderServer.h diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderThread.cpp b/src/anbox/graphics/emugl/RenderThread.cpp similarity index 68% rename from external/android-emugl/host/libs/libOpenglRender/RenderThread.cpp rename to src/anbox/graphics/emugl/RenderThread.cpp index 22cd9e2..2185e8c 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderThread.cpp +++ b/src/anbox/graphics/emugl/RenderThread.cpp @@ -15,7 +15,7 @@ */ #include "RenderThread.h" -#include "FrameBuffer.h" +#include "Renderer.h" #include "ReadBuffer.h" #include "RenderControl.h" #include "RenderThreadInfo.h" @@ -59,25 +59,6 @@ intptr_t RenderThread::main() { ReadBuffer readBuf(STREAM_BUFFER_SIZE); - int stats_totalBytes = 0; - long long stats_t0 = GetCurrentTimeMS(); - - // - // open dump file if RENDER_DUMP_DIR is defined - // - const char *dump_dir = getenv("RENDERER_DUMP_DIR"); - FILE *dumpFP = NULL; - if (dump_dir) { - size_t bsize = strlen(dump_dir) + 32; - char *fname = new char[bsize]; - snprintf(fname,bsize,"%s/stream_%p", dump_dir, this); - dumpFP = fopen(fname, "wb"); - if (!dumpFP) { - fprintf(stderr,"Warning: stream dump failed to open file %s\n",fname); - } - delete [] fname; - } - while (1) { int stat = readBuf.getData(m_stream); @@ -85,29 +66,6 @@ intptr_t RenderThread::main() { break; } -#if 0 - // - // log received bandwidth statistics - // - stats_totalBytes += readBuf.validData(); - long long dt = GetCurrentTimeMS() - stats_t0; - if (dt > 1000) { - float dts = (float)dt / 1000.0f; - printf("Used Bandwidth %5.3f MB/s\n", ((float)stats_totalBytes / dts) / (1024.0f*1024.0f)); - stats_totalBytes = 0; - stats_t0 = GetCurrentTimeMS(); - } -#endif - - // - // dump stream to file if needed - // - if (dumpFP) { - int skip = readBuf.validData() - stat; - fwrite(readBuf.buf()+skip, 1, readBuf.validData()-skip, dumpFP); - fflush(dumpFP); - } - bool progress; do { progress = false; @@ -147,21 +105,17 @@ intptr_t RenderThread::main() { } - if (dumpFP) { - fclose(dumpFP); - } - // // Release references to the current thread's context/surfaces if any // - FrameBuffer::getFB()->bindContext(0, 0, 0); + Renderer::get()->bindContext(0, 0, 0); if (tInfo.currContext || tInfo.currDrawSurf || tInfo.currReadSurf) { fprintf(stderr, "ERROR: RenderThread exiting with current context/surfaces\n"); } - FrameBuffer::getFB()->drainWindowSurface(); + Renderer::get()->drainWindowSurface(); - FrameBuffer::getFB()->drainRenderContext(); + Renderer::get()->drainRenderContext(); return 0; } diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderThread.h b/src/anbox/graphics/emugl/RenderThread.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderThread.h rename to src/anbox/graphics/emugl/RenderThread.h diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderThreadInfo.cpp b/src/anbox/graphics/emugl/RenderThreadInfo.cpp similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderThreadInfo.cpp rename to src/anbox/graphics/emugl/RenderThreadInfo.cpp diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderThreadInfo.h b/src/anbox/graphics/emugl/RenderThreadInfo.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/RenderThreadInfo.h rename to src/anbox/graphics/emugl/RenderThreadInfo.h diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderWindow.cpp b/src/anbox/graphics/emugl/RenderWindow.cpp similarity index 72% rename from external/android-emugl/host/libs/libOpenglRender/RenderWindow.cpp rename to src/anbox/graphics/emugl/RenderWindow.cpp index ced43de..a734045 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderWindow.cpp +++ b/src/anbox/graphics/emugl/RenderWindow.cpp @@ -18,14 +18,12 @@ #include "emugl/common/message_channel.h" #include "emugl/common/mutex.h" #include "emugl/common/thread.h" -#include "FrameBuffer.h" +#include "Renderer.h" #include #include -#ifndef _WIN32 #include #include -#endif #define DEBUG 0 @@ -73,9 +71,6 @@ struct RenderWindowMessage { // CMD_INITIALIZE struct { EGLNativeDisplayType nativeDisplay; - int width; - int height; - bool useSubWindow; } init; // CMD_SET_POST_CALLBACK @@ -114,17 +109,13 @@ struct RenderWindowMessage { // Returns true on success, or false on failure. bool process() const { const RenderWindowMessage& msg = *this; - FrameBuffer* fb; + Renderer* fb; bool result = false; switch (msg.cmd) { case CMD_INITIALIZE: - D("CMD_INITIALIZE w=%d h=%d\n", msg.init.width, msg.init.height); - GL_LOG("RenderWindow: CMD_INITIALIZE w=%d h=%d", - msg.init.width, msg.init.height); - result = FrameBuffer::initialize(msg.init.nativeDisplay, - msg.init.width, - msg.init.height, - msg.init.useSubWindow); + D("CMD_INITIALIZE\n"); + GL_LOG("RenderWindow: CMD_INITIALIZE"); + result = Renderer::initialize(msg.init.nativeDisplay); break; case CMD_FINALIZE: @@ -132,75 +123,12 @@ struct RenderWindowMessage { // 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 = FrameBuffer::getFB()) { + if (const auto fb = Renderer::get()) { fb->finalize(); } result = true; break; - case CMD_SET_POST_CALLBACK: - D("CMD_SET_POST_CALLBACK\n"); - fb = FrameBuffer::getFB(); - fb->setPostCallback(msg.set_post_callback.on_post, - msg.set_post_callback.on_post_context); - result = true; - break; - - case CMD_SETUP_SUBWINDOW: - D("CMD_SETUP_SUBWINDOW: parent=%p wx=%d wy=%d ww=%d wh=%d fbw=%d fbh=%d dpr=%f rotation=%f\n", - (void*)msg.subwindow.parent, - msg.subwindow.wx, - msg.subwindow.wy, - msg.subwindow.ww, - msg.subwindow.wh, - msg.subwindow.fbw, - msg.subwindow.fbh, - msg.subwindow.dpr, - msg.subwindow.rotation); - result = FrameBuffer::getFB()->setupSubWindow( - msg.subwindow.parent, - msg.subwindow.wx, - msg.subwindow.wy, - msg.subwindow.ww, - msg.subwindow.wh, - msg.subwindow.fbw, - msg.subwindow.fbh, - msg.subwindow.dpr, - msg.subwindow.rotation); - break; - - case CMD_REMOVE_SUBWINDOW: - D("CMD_REMOVE_SUBWINDOW\n"); - result = FrameBuffer::getFB()->removeSubWindow(); - break; - - case CMD_SET_ROTATION: - D("CMD_SET_ROTATION rotation=%f\n", msg.rotation); - fb = FrameBuffer::getFB(); - if (fb) { - fb->setDisplayRotation(msg.rotation); - result = true; - } - break; - - case CMD_SET_TRANSLATION: - D("CMD_SET_TRANSLATION translation=%f,%f\n", msg.trans.px, msg.trans.py); - fb = FrameBuffer::getFB(); - if (fb) { - fb->setDisplayTranslation(msg.trans.px, msg.trans.py); - result = true; - } - break; - - case CMD_REPAINT: - D("CMD_REPAINT\n"); - fb = FrameBuffer::getFB(); - if (fb) { - fb->repost(); - result = true; - } - break; - default: ; } @@ -284,11 +212,9 @@ public: virtual intptr_t main() { D("Entering render window thread thread\n"); -#ifndef _WIN32 sigset_t set; sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); -#endif bool running = true; while (running) { RenderWindowMessage msg; @@ -315,10 +241,7 @@ private: } // namespace RenderWindow::RenderWindow(EGLNativeDisplayType native_display, - int width, - int height, - bool use_thread, - bool use_sub_window) : + bool use_thread) : mValid(false), mHasSubWindow(false), mThread(NULL), @@ -332,9 +255,6 @@ RenderWindow::RenderWindow(EGLNativeDisplayType native_display, RenderWindowMessage msg; msg.cmd = CMD_INITIALIZE; msg.init.nativeDisplay = native_display; - msg.init.width = width; - msg.init.height = height; - msg.init.useSubWindow = use_sub_window; mValid = processMessage(msg); } @@ -358,7 +278,7 @@ bool RenderWindow::getHardwareStrings(const char** vendor, const char** version) { D("Entering\n"); // TODO(digit): Move this to render window thread. - FrameBuffer* fb = FrameBuffer::getFB(); + Renderer* fb = Renderer::get(); if (!fb) { D("No framebuffer!\n"); return false; @@ -370,16 +290,6 @@ bool RenderWindow::getHardwareStrings(const char** vendor, return true; } -void RenderWindow::setPostCallback(OnPostFn onPost, void* onPostContext) { - D("Entering\n"); - RenderWindowMessage msg; - msg.cmd = CMD_SET_POST_CALLBACK; - msg.set_post_callback.on_post = onPost; - msg.set_post_callback.on_post_context = onPostContext; - (void) processMessage(msg); - D("Exiting\n"); -} - bool RenderWindow::setupSubWindow(FBNativeWindowType window, int wx, int wy, diff --git a/external/android-emugl/host/libs/libOpenglRender/RenderWindow.h b/src/anbox/graphics/emugl/RenderWindow.h similarity index 94% rename from external/android-emugl/host/libs/libOpenglRender/RenderWindow.h rename to src/anbox/graphics/emugl/RenderWindow.h index 1443688..dd2eb2f 100644 --- a/external/android-emugl/host/libs/libOpenglRender/RenderWindow.h +++ b/src/anbox/graphics/emugl/RenderWindow.h @@ -59,7 +59,7 @@ public: // // Note that this call doesn't display anything, it just initializes // the library, use setupSubWindow() to display something. - RenderWindow(EGLNativeDisplayType native_display, int width, int height, bool use_thread, bool use_sub_window); + RenderWindow(EGLNativeDisplayType native_display, bool use_thread); // Destructor. This will automatically call removeSubWindow() is needed. ~RenderWindow(); @@ -75,11 +75,6 @@ public: const char** renderer, const char** version); - // Specify a function that will be called everytime a new frame is - // displayed. This is relatively slow but allows one to capture the - // output. - void setPostCallback(OnPostFn onPost, void* onPostContext); - // 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. diff --git a/src/anbox/graphics/emugl/Renderable.cpp b/src/anbox/graphics/emugl/Renderable.cpp new file mode 100644 index 0000000..232f3a1 --- /dev/null +++ b/src/anbox/graphics/emugl/Renderable.cpp @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2016 Simon Fels +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "Renderable.h" + +Renderable::Renderable(const std::string &name, + const std::uint32_t &buffer, + const anbox::graphics::Rect &screen_position, + const glm::mat4 &transformation, + const float &alpha) : + name_(name), + buffer_(buffer), + screen_position_(screen_position), + 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_; +} + +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; +} diff --git a/src/anbox/graphics/emugl/Renderable.h b/src/anbox/graphics/emugl/Renderable.h new file mode 100644 index 0000000..819f1b7 --- /dev/null +++ b/src/anbox/graphics/emugl/Renderable.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2016 Simon Fels +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef ANBOX_GRAPHICS_EMUGL_RENDERABLE_H_ +#define ANBOX_GRAPHICS_EMUGL_RENDERABLE_H_ + +#include "anbox/graphics/rect.h" + +#include +#include + +#include + +#include + +class Renderable +{ +public: + Renderable(const std::string &name, + const std::uint32_t &buffer, + const anbox::graphics::Rect &screen_position, + 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; + glm::mat4 transformation() const; + float alpha() const; + + void set_screen_position(const anbox::graphics::Rect &screen_position); + +private: + std::string name_; + std::uint32_t buffer_; + anbox::graphics::Rect screen_position_; + glm::mat4 transformation_; + float alpha_; +}; + +typedef std::vector RenderableList; + +#endif diff --git a/external/android-emugl/host/libs/libOpenglRender/FrameBuffer.cpp b/src/anbox/graphics/emugl/Renderer.cpp similarity index 68% rename from external/android-emugl/host/libs/libOpenglRender/FrameBuffer.cpp rename to src/anbox/graphics/emugl/Renderer.cpp index bff43b3..3e26991 100644 --- a/external/android-emugl/host/libs/libOpenglRender/FrameBuffer.cpp +++ b/src/anbox/graphics/emugl/Renderer.cpp @@ -14,10 +14,9 @@ * limitations under the License. */ -#include "FrameBuffer.h" +#include "Renderer.h" #include "DispatchTables.h" -#include "NativeSubWindow.h" #include "RenderThreadInfo.h" #include "TimeUtils.h" #include "gles2_dec.h" @@ -26,8 +25,14 @@ #include "emugl/common/logging.h" +#include "anbox/logger.h" + #include +#include +#include +#include + namespace { // Helper class to call the bind_locked() / unbind_locked() properly. @@ -35,7 +40,7 @@ class ScopedBind { public: // Constructor will call bind_locked() on |fb|. // Use isValid() to check for errors. - ScopedBind(FrameBuffer* fb) : mFb(fb) { + ScopedBind(Renderer* fb) : mFb(fb) { if (!mFb->bind_locked()) { mFb = NULL; } @@ -59,14 +64,14 @@ public: } private: - FrameBuffer* mFb; + Renderer* mFb; }; // Implementation of a ColorBuffer::Helper instance that redirects calls // to a FrameBuffer instance. class ColorBufferHelper : public ColorBuffer::Helper { public: - ColorBufferHelper(FrameBuffer* fb) : mFb(fb) {} + ColorBufferHelper(Renderer* fb) : mFb(fb) {} virtual bool setupContext() { return mFb->bind_locked(); @@ -80,13 +85,13 @@ public: return mFb->getTextureDraw(); } private: - FrameBuffer* mFb; + Renderer* mFb; }; } // namespace -FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL; -HandleType FrameBuffer::s_nextHandle = 0; +Renderer *Renderer::s_renderer = NULL; +HandleType Renderer::s_nextHandle = 0; static char* getGLES1ExtensionString(EGLDisplay p_dpy) { @@ -152,11 +157,8 @@ static char* getGLES1ExtensionString(EGLDisplay p_dpy) return extString; } -void FrameBuffer::finalize(){ +void Renderer::finalize(){ m_colorbuffers.clear(); - if (m_useSubWindow) { - removeSubWindow(); - } m_windows.clear(); m_contexts.clear(); s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL); @@ -165,17 +167,17 @@ void FrameBuffer::finalize(){ s_egl.eglDestroySurface(m_eglDisplay, m_pbufSurface); } -bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int height, bool useSubWindow) +bool Renderer::initialize(EGLNativeDisplayType nativeDisplay) { GL_LOG("FrameBuffer::initialize"); - if (s_theFrameBuffer != NULL) { + if (s_renderer != NULL) { return true; } // // allocate space for the FrameBuffer object // - FrameBuffer *fb = new FrameBuffer(width, height, useSubWindow); + Renderer *fb = new Renderer(); if (!fb) { ERR("Failed to create fb\n"); return false; @@ -221,7 +223,7 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int // // Create EGL context for framebuffer post rendering. // - GLint surfaceType = (useSubWindow ? EGL_WINDOW_BIT : 0) | EGL_PBUFFER_BIT; + GLint surfaceType = EGL_WINDOW_BIT| EGL_PBUFFER_BIT; const GLint configAttribs[] = { EGL_RED_SIZE, 1, EGL_GREEN_SIZE, 1, @@ -358,7 +360,7 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int // // Initialize set of configs // - fb->m_configs = new FbConfigList(fb->m_eglDisplay); + fb->m_configs = new RendererConfigList(fb->m_eglDisplay); if (fb->m_configs->empty()) { ERR("Failed: Initialize set of configs\n"); bind.release(); @@ -419,44 +421,46 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int return false; } + fb->m_defaultProgram = fb->m_family.add_program(vshader, defaultFShader); + fb->m_alphaProgram = fb->m_family.add_program(vshader, alphaFShader); + // release the FB context bind.release(); // // Keep the singleton framebuffer pointer // - s_theFrameBuffer = fb; + s_renderer = fb; GL_LOG("basic EGL initialization successful"); return true; } -FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow) : - m_framebufferWidth(p_width), - m_framebufferHeight(p_height), - m_windowWidth(p_width), - m_windowHeight(p_height), - m_useSubWindow(useSubWindow), +Renderer::Program::Program(GLuint program_id) +{ + id = program_id; + position_attr = s_gles2.glGetAttribLocation(id, "position"); + texcoord_attr = s_gles2.glGetAttribLocation(id, "texcoord"); + tex_uniform = s_gles2.glGetUniformLocation(id, "tex"); + center_uniform = s_gles2.glGetUniformLocation(id, "centre"); + display_transform_uniform = s_gles2.glGetUniformLocation(id, "display_transform"); + transform_uniform = s_gles2.glGetUniformLocation(id, "transform"); + screen_to_gl_coords_uniform = s_gles2.glGetUniformLocation(id, "screen_to_gl_coords"); + alpha_uniform = s_gles2.glGetUniformLocation(id, "alpha"); +} + +Renderer::Renderer() : m_configs(NULL), m_eglDisplay(EGL_NO_DISPLAY), m_colorBufferHelper(new ColorBufferHelper(this)), - m_eglSurface(EGL_NO_SURFACE), m_eglContext(EGL_NO_CONTEXT), m_pbufContext(EGL_NO_CONTEXT), m_prevContext(EGL_NO_CONTEXT), m_prevReadSurf(EGL_NO_SURFACE), m_prevDrawSurf(EGL_NO_SURFACE), - m_subWin((EGLNativeWindowType)0), m_textureDraw(NULL), m_lastPostedColorBuffer(0), - m_zRot(0.0f), - m_px(0), - m_py(0), - m_eglContextInitialized(false), m_statsNumFrames(0), m_statsStartTime(0LL), - m_onPost(NULL), - m_onPostContext(NULL), - m_fbImage(NULL), m_glVendor(NULL), m_glRenderer(NULL), m_glVersion(NULL) @@ -464,154 +468,76 @@ FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow) : m_fpsStats = getenv("SHOW_FPS_STATS") != NULL; } -FrameBuffer::~FrameBuffer() { +Renderer::~Renderer() { delete m_textureDraw; delete m_configs; delete m_colorBufferHelper; - free(m_fbImage); } -void FrameBuffer::setPostCallback(OnPostFn onPost, void* onPostContext) +struct RendererWindow { + EGLNativeWindowType native_window = 0; + EGLSurface surface = EGL_NO_SURFACE; + anbox::graphics::Rect viewport; + glm::mat4 screen_to_gl_coords; + glm::mat4 display_transform; +}; + +RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window) { - emugl::Mutex::AutoLock mutex(m_lock); - m_onPost = onPost; - m_onPostContext = onPostContext; - if (m_onPost && !m_fbImage) { - m_fbImage = (unsigned char*)malloc(4 * m_framebufferWidth * m_framebufferHeight); - if (!m_fbImage) { - ERR("out of memory, cancelling OnPost callback"); - m_onPost = NULL; - m_onPostContext = NULL; - return; - } + m_lock.lock(); + + auto window = new RendererWindow; + window->native_window = native_window; + window->surface = s_egl.eglCreateWindowSurface( + m_eglDisplay, m_eglConfig, window->native_window, nullptr); + if (window->surface == EGL_NO_SURFACE) + { + delete window; + m_lock.unlock(); + return nullptr; } + + if (!bindWindow_locked(window)) + { + s_egl.eglDestroySurface(m_eglDisplay, window->surface); + delete window; + m_lock.unlock(); + return nullptr; + } + + s_gles2.glClear(GL_COLOR_BUFFER_BIT | + GL_DEPTH_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT); + s_egl.eglSwapBuffers(m_eglDisplay, window->surface); + + unbind_locked(); + + m_nativeWindows.insert({native_window, window}); + + m_lock.unlock(); + + return window; } -static void subWindowRepaint(void* param) { - auto fb = static_cast(param); - fb->repost(); -} - -bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window, - int wx, - int wy, - int ww, - int wh, - int fbw, - int fbh, - float dpr, - float zRot) { - bool success = false; - - if (!m_useSubWindow) { - ERR("%s: Cannot create native sub-window in this configuration\n", - __FUNCTION__); - return false; - } +void Renderer::destroyNativeWindow(EGLNativeWindowType native_window) { + auto w = m_nativeWindows.find(native_window); + if (w == m_nativeWindows.end()) + return; m_lock.lock(); - // If the subwindow doesn't exist, create it with the appropriate dimensions - if (!m_subWin) { + s_egl.eglMakeCurrent(m_eglDisplay, nullptr, nullptr, nullptr); - // Create native subwindow for FB display output - m_x = wx; - m_y = wy; - m_windowWidth = ww; - m_windowHeight = wh; + if (w->second->surface != EGL_NO_SURFACE) + s_egl.eglDestroySurface(m_eglDisplay, w->second->surface); - m_subWin = createSubWindow(p_window, m_x, m_y, - m_windowWidth, m_windowHeight, subWindowRepaint, this); - if (m_subWin) { - m_nativeWindow = p_window; - - // create EGLSurface from the generated subwindow - m_eglSurface = s_egl.eglCreateWindowSurface(m_eglDisplay, - m_eglConfig, - m_subWin, - NULL); - - if (m_eglSurface == EGL_NO_SURFACE) { - // NOTE: This can typically happen with software-only renderers like OSMesa. - destroySubWindow(m_subWin); - m_subWin = (EGLNativeWindowType)0; - } else { - m_px = 0; - m_py = 0; - - success = true; - } - } - } - - // At this point, if the subwindow doesn't exist, it is because it either couldn't be created - // in the first place or the EGLSurface couldn't be created. - if (m_subWin && bindSubwin_locked()) { - - // Only attempt to update window geometry if anything has actually changed. - if (!(m_x == wx && - m_y == wy && - m_windowWidth == ww && - m_windowHeight == wh)) { - - m_x = wx; - m_y = wy; - m_windowWidth = ww; - m_windowHeight = wh; - - success = ::moveSubWindow(m_nativeWindow, m_subWin, - m_x, m_y, m_windowWidth, m_windowHeight); - - // Otherwise, ensure that at least viewport parameters are properly updated. - } else { - success = true; - } - - if (success) { - // Subwin creation or movement was successful, - // update viewport and z rotation and draw - // the last posted color buffer. - s_gles2.glViewport(0, 0, fbw * dpr, fbh * dpr); - m_dpr = dpr; - m_zRot = zRot; - if (m_lastPostedColorBuffer) { - post(m_lastPostedColorBuffer, false); - } else { - s_gles2.glClear(GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT | - GL_STENCIL_BUFFER_BIT); - s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); - } - } - unbind_locked(); - } + delete w->second; + m_nativeWindows.erase(w); m_lock.unlock(); - return success; } -bool FrameBuffer::removeSubWindow() { - if (!m_useSubWindow) { - ERR("%s: Cannot remove native sub-window in this configuration\n", - __FUNCTION__); - return false; - } - bool removed = false; - m_lock.lock(); - if (m_subWin) { - s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL); - s_egl.eglDestroySurface(m_eglDisplay, m_eglSurface); - destroySubWindow(m_subWin); - - m_eglSurface = EGL_NO_SURFACE; - m_subWin = (EGLNativeWindowType)0; - removed = true; - } - m_lock.unlock(); - return removed; -} - -HandleType FrameBuffer::genHandle() +HandleType Renderer::genHandle() { HandleType id; do { @@ -623,7 +549,7 @@ HandleType FrameBuffer::genHandle() return id; } -HandleType FrameBuffer::createColorBuffer(int p_width, int p_height, +HandleType Renderer::createColorBuffer(int p_width, int p_height, GLenum p_internalFormat) { emugl::Mutex::AutoLock mutex(m_lock); @@ -644,13 +570,13 @@ HandleType FrameBuffer::createColorBuffer(int p_width, int p_height, return ret; } -HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share, +HandleType Renderer::createRenderContext(int p_config, HandleType p_share, bool p_isGL2) { emugl::Mutex::AutoLock mutex(m_lock); HandleType ret = 0; - const FbConfig* config = getConfigs()->get(p_config); + const RendererConfig* config = getConfigs()->get(p_config); if (!config) { return ret; } @@ -677,13 +603,13 @@ HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share, return ret; } -HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_height) +HandleType Renderer::createWindowSurface(int p_config, int p_width, int p_height) { emugl::Mutex::AutoLock mutex(m_lock); HandleType ret = 0; - const FbConfig* config = getConfigs()->get(p_config); + const RendererConfig* config = getConfigs()->get(p_config); if (!config) { return ret; } @@ -700,7 +626,7 @@ HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_hei return ret; } -void FrameBuffer::drainRenderContext() +void Renderer::drainRenderContext() { emugl::Mutex::AutoLock mutex(m_lock); RenderThreadInfo *tinfo = RenderThreadInfo::get(); @@ -713,7 +639,7 @@ void FrameBuffer::drainRenderContext() tinfo->m_contextSet.clear(); } -void FrameBuffer::drainWindowSurface() +void Renderer::drainWindowSurface() { emugl::Mutex::AutoLock mutex(m_lock); RenderThreadInfo *tinfo = RenderThreadInfo::get(); @@ -735,7 +661,7 @@ void FrameBuffer::drainWindowSurface() tinfo->m_windowSet.clear(); } -void FrameBuffer::DestroyRenderContext(HandleType p_context) +void Renderer::DestroyRenderContext(HandleType p_context) { emugl::Mutex::AutoLock mutex(m_lock); m_contexts.erase(p_context); @@ -744,7 +670,7 @@ void FrameBuffer::DestroyRenderContext(HandleType p_context) tinfo->m_contextSet.erase(p_context); } -void FrameBuffer::DestroyWindowSurface(HandleType p_surface) +void Renderer::DestroyWindowSurface(HandleType p_surface) { emugl::Mutex::AutoLock mutex(m_lock); if (m_windows.find(p_surface) != m_windows.end()) { @@ -755,7 +681,7 @@ void FrameBuffer::DestroyWindowSurface(HandleType p_surface) } } -int FrameBuffer::openColorBuffer(HandleType p_colorbuffer) +int Renderer::openColorBuffer(HandleType p_colorbuffer) { emugl::Mutex::AutoLock mutex(m_lock); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); @@ -768,7 +694,7 @@ int FrameBuffer::openColorBuffer(HandleType p_colorbuffer) return 0; } -void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer) +void Renderer::closeColorBuffer(HandleType p_colorbuffer) { emugl::Mutex::AutoLock mutex(m_lock); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); @@ -784,7 +710,7 @@ void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer) } } -bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface) +bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) { emugl::Mutex::AutoLock mutex(m_lock); @@ -801,7 +727,7 @@ bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface) return true; } -bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface, +bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface, HandleType p_colorbuffer) { emugl::Mutex::AutoLock mutex(m_lock); @@ -825,7 +751,7 @@ bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface, return true; } -void FrameBuffer::readColorBuffer(HandleType p_colorbuffer, +void Renderer::readColorBuffer(HandleType p_colorbuffer, int x, int y, int width, int height, GLenum format, GLenum type, void *pixels) { @@ -840,7 +766,7 @@ void FrameBuffer::readColorBuffer(HandleType p_colorbuffer, (*c).second.cb->readPixels(x, y, width, height, format, type, pixels); } -bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer, +bool Renderer::updateColorBuffer(HandleType p_colorbuffer, int x, int y, int width, int height, GLenum format, GLenum type, void *pixels) { @@ -857,7 +783,7 @@ bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer, return true; } -bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) +bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer) { emugl::Mutex::AutoLock mutex(m_lock); @@ -870,7 +796,7 @@ bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer) return (*c).second.cb->bindToTexture(); } -bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) +bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) { emugl::Mutex::AutoLock mutex(m_lock); @@ -883,7 +809,7 @@ bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) return (*c).second.cb->bindToRenderbuffer(); } -bool FrameBuffer::bindContext(HandleType p_context, +bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface, HandleType p_readSurface) { @@ -972,7 +898,7 @@ bool FrameBuffer::bindContext(HandleType p_context, return true; } -HandleType FrameBuffer::createClientImage(HandleType context, EGLenum target, GLuint buffer) +HandleType Renderer::createClientImage(HandleType context, EGLenum target, GLuint buffer) { RenderContextPtr ctx(NULL); @@ -994,7 +920,7 @@ HandleType FrameBuffer::createClientImage(HandleType context, EGLenum target, GL return (HandleType)reinterpret_cast(image); } -EGLBoolean FrameBuffer::destroyClientImage(HandleType image) +EGLBoolean Renderer::destroyClientImage(HandleType image) { return s_egl.eglDestroyImageKHR(m_eglDisplay, reinterpret_cast(image)); @@ -1003,7 +929,7 @@ EGLBoolean FrameBuffer::destroyClientImage(HandleType image) // // The framebuffer lock should be held when calling this function ! // -bool FrameBuffer::bind_locked() +bool Renderer::bind_locked() { EGLContext prevContext = s_egl.eglGetCurrentContext(); EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); @@ -1021,32 +947,25 @@ bool FrameBuffer::bind_locked() return true; } -bool FrameBuffer::bindSubwin_locked() +bool Renderer::bindWindow_locked(RendererWindow *window) { EGLContext prevContext = s_egl.eglGetCurrentContext(); EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ); EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW); - if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface, - m_eglSurface, m_eglContext)) { + if (!s_egl.eglMakeCurrent(m_eglDisplay, window->surface, + window->surface, m_eglContext)) { ERR("eglMakeCurrent failed\n"); return false; } - // - // initialize GL state in eglContext if not yet initilaized - // - if (!m_eglContextInitialized) { - m_eglContextInitialized = true; - } - m_prevContext = prevContext; m_prevReadSurf = prevReadSurf; m_prevDrawSurf = prevDrawSurf; return true; } -bool FrameBuffer::unbind_locked() +bool Renderer::unbind_locked() { if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf, m_prevReadSurf, m_prevContext)) { @@ -1059,102 +978,199 @@ bool FrameBuffer::unbind_locked() return true; } -bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock) +const GLchar* const Renderer::vshader = { - if (needLock) { - m_lock.lock(); - } - bool ret = false; + "attribute vec3 position;\n" + "attribute vec2 texcoord;\n" + "uniform mat4 screen_to_gl_coords;\n" + "uniform mat4 display_transform;\n" + "uniform mat4 transform;\n" + "uniform vec2 center;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " vec4 mid = vec4(center, 0.0, 0.0);\n" + " vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid;\n" + " gl_Position = display_transform * screen_to_gl_coords * transformed;\n" + " v_texcoord = texcoord;\n" + "}\n" +}; - ColorBufferMap::iterator c( m_colorbuffers.find(p_colorbuffer) ); - if (c == m_colorbuffers.end()) { - goto EXIT; - } +const GLchar* const Renderer::alphaFShader = +{ + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "uniform float alpha;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " vec4 frag = texture2D(tex, v_texcoord);\n" + " gl_FragColor = alpha*frag;\n" + "}\n" +}; - m_lastPostedColorBuffer = p_colorbuffer; +const GLchar* const Renderer::defaultFShader = +{ // This is the fastest fragment shader. Use it when you can. + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "varying vec2 v_texcoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(tex, v_texcoord);\n" + "}\n" +}; - if (m_subWin) { - // bind the subwindow eglSurface - if (!bindSubwin_locked()) { - ERR("FrameBuffer::post(): eglMakeCurrent failed\n"); - goto EXIT; - } +void Renderer::setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect) +{ + /* + * Here we provide a 3D perspective projection with a default 30 degrees + * vertical field of view. This projection matrix is carefully designed + * such that any vertices at depth z=0 will fit the screen coordinates. So + * client texels will fit screen pixels perfectly as long as the surface is + * at depth zero. But if you want to do anything fancy, you can also choose + * a different depth and it will appear to come out of or go into the + * screen. + */ + window->screen_to_gl_coords = glm::translate(glm::mat4(1.0f), glm::vec3{-1.0f, 1.0f, 0.0f}); - // get the viewport - GLint vp[4]; - s_gles2.glGetIntegerv(GL_VIEWPORT, vp); + /* + * Perspective division is one thing that can't be done in a matrix + * multiplication. It happens after the matrix multiplications. GL just + * scales {x,y} by 1/w. So modify the final part of the projection matrix + * to set w ([3]) to be the incoming z coordinate ([2]). + */ + window->screen_to_gl_coords[2][3] = -1.0f; - // divide by device pixel ratio because windowing coordinates ignore DPR, - // but the framebuffer includes DPR - vp[2] = vp[2] / m_dpr; - vp[3] = vp[3] / m_dpr; + float const vertical_fov_degrees = 30.0f; + float const near = + (rect.height() / 2.0f) / + std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f); + float const far = -near; - // find the x and y values at the origin when "fully scrolled" - // multiply by 2 because the texture goes from -1 to 1, not 0 to 1 - float fx = 2.f * (vp[2] - m_windowWidth) / (float) vp[2]; - float fy = 2.f * (vp[3] - m_windowHeight) / (float) vp[3]; + window->screen_to_gl_coords = glm::scale(window->screen_to_gl_coords, + glm::vec3{2.0f / rect.width(), + -2.0f / rect.height(), + 2.0f / (near - far)}); + window->screen_to_gl_coords = glm::translate(window->screen_to_gl_coords, + glm::vec3{-rect.left(), + -rect.top(), + 0.0f}); - // finally, compute translation values - float dx = m_px * fx; - float dy = m_py * fy; - - // - // render the color buffer to the window - // - if (m_zRot != 0.0f) { - s_gles2.glClear(GL_COLOR_BUFFER_BIT); - } - ret = (*c).second.cb->post(m_zRot, dx, dy); - if (ret) { - s_egl.eglSwapBuffers(m_eglDisplay, m_eglSurface); - } - - // restore previous binding - unbind_locked(); - } else { - // If there is no sub-window, don't display anything, the client will - // rely on m_onPost to get the pixels instead. - ret = true; - } - - // - // output FPS statistics - // - if (m_fpsStats) { - long long currTime = GetCurrentTimeMS(); - m_statsNumFrames++; - if (currTime - m_statsStartTime >= 1000) { - float dt = (float)(currTime - m_statsStartTime) / 1000.0f; - printf("FPS: %5.3f\n", (float)m_statsNumFrames / dt); - m_statsStartTime = currTime; - m_statsNumFrames = 0; - } - } - - // - // Send framebuffer (without FPS overlay) to callback - // - if (m_onPost) { - (*c).second.cb->readback(m_fbImage); - m_onPost(m_onPostContext, - m_framebufferWidth, - m_framebufferHeight, - -1, - GL_RGBA, - GL_UNSIGNED_BYTE, - m_fbImage); - } - -EXIT: - if (needLock) { - m_lock.unlock(); - } - return ret; + window->viewport = rect; } -bool FrameBuffer::repost() { - if (m_lastPostedColorBuffer) { - return post(m_lastPostedColorBuffer); +void Renderer::tessellate(std::vector& primitives, + const anbox::graphics::Rect &buf_size, + const Renderable &renderable) +{ + auto rect = renderable.screen_position(); + GLfloat left = rect.left(); + GLfloat right = rect.right(); + GLfloat top = rect.top(); + GLfloat bottom = rect.bottom(); + + anbox::graphics::Primitive rectangle; + rectangle.tex_id = 0; + rectangle.type = GL_TRIANGLE_STRIP; + + GLfloat tex_right = static_cast(rect.width()) / + buf_size.width(); + GLfloat tex_bottom = static_cast(rect.height()) / + buf_size.height(); + + auto& vertices = rectangle.vertices; + vertices[0] = {{left, top, 0.0f}, {0.0f, 0.0f}}; + vertices[1] = {{left, bottom, 0.0f}, {0.0f, tex_bottom}}; + vertices[2] = {{right, top, 0.0f}, {tex_right, 0.0f}}; + vertices[3] = {{right, bottom, 0.0f}, {tex_right, tex_bottom}}; + + primitives.resize(1); + primitives[0] = rectangle; +} + +void Renderer::draw(RendererWindow *window, const Renderable &renderable, const Program &prog) +{ + const auto &color_buffer = m_colorbuffers.find(renderable.buffer()); + if (color_buffer == m_colorbuffers.end()) + return; + + const auto &cb = color_buffer->second.cb; + + s_gles2.glUseProgram(prog.id); + s_gles2.glUniform1i(prog.tex_uniform, 0); + s_gles2.glUniformMatrix4fv(prog.display_transform_uniform, 1, GL_FALSE, + glm::value_ptr(window->display_transform)); + s_gles2.glUniformMatrix4fv(prog.screen_to_gl_coords_uniform, 1, GL_FALSE, + glm::value_ptr(window->screen_to_gl_coords)); + + s_gles2.glActiveTexture(GL_TEXTURE0); + + auto const& rect = renderable.screen_position(); + GLfloat centerx = rect.left() + + rect.width() / 2.0f; + GLfloat centery = rect.top() + + rect.height() / 2.0f; + s_gles2.glUniform2f(prog.center_uniform, centerx, centery); + + s_gles2.glUniformMatrix4fv(prog.transform_uniform, 1, GL_FALSE, + glm::value_ptr(renderable.transformation())); + + if (prog.alpha_uniform >= 0) + s_gles2.glUniform1f(prog.alpha_uniform, renderable.alpha()); + + s_gles2.glEnableVertexAttribArray(prog.position_attr); + s_gles2.glEnableVertexAttribArray(prog.texcoord_attr); + + m_primitives.clear(); + tessellate(m_primitives, {cb->getWidth(), cb->getHeight()}, renderable); + + for (auto const& p : m_primitives) + { + cb->bind(); + + s_gles2.glVertexAttribPointer(prog.position_attr, 3, GL_FLOAT, + GL_FALSE, sizeof(anbox::graphics::Vertex), + &p.vertices[0].position); + s_gles2.glVertexAttribPointer(prog.texcoord_attr, 2, GL_FLOAT, + GL_FALSE, sizeof(anbox::graphics::Vertex), + &p.vertices[0].texcoord); + + s_gles2.glEnable(GL_BLEND); + s_gles2.glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, + GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + s_gles2.glDrawArrays(p.type, 0, p.nvertices); } + + s_gles2.glDisableVertexAttribArray(prog.texcoord_attr); + s_gles2.glDisableVertexAttribArray(prog.position_attr); +} + +bool Renderer::draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables) +{ + auto w = m_nativeWindows.find(native_window); + if (w == m_nativeWindows.end()) + return false; + + if (!bindWindow_locked(w->second)) + { + m_lock.unlock(); + return false; + } + + setupViewport(w->second, window_frame); + s_gles2.glViewport(0, 0, window_frame.width(), window_frame.height()); + s_gles2.glClearColor(0.0, 0.0, 0.0, 1.0); + s_gles2.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + s_gles2.glClear(GL_COLOR_BUFFER_BIT); + + for (const auto &r : renderables) + draw(w->second, r, r.alpha() < 1.0f ? m_alphaProgram : m_defaultProgram); + + s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface); + + unbind_locked(); + + m_lock.lock(); + + m_lock.unlock(); + return false; } diff --git a/external/android-emugl/host/libs/libOpenglRender/FrameBuffer.h b/src/anbox/graphics/emugl/Renderer.h similarity index 73% rename from external/android-emugl/host/libs/libOpenglRender/FrameBuffer.h rename to src/anbox/graphics/emugl/Renderer.h index b581a44..b0bc2c2 100644 --- a/external/android-emugl/host/libs/libOpenglRender/FrameBuffer.h +++ b/src/anbox/graphics/emugl/Renderer.h @@ -18,13 +18,18 @@ #include "ColorBuffer.h" #include "emugl/common/mutex.h" -#include "FbConfig.h" +#include "RendererConfig.h" #include "RenderContext.h" #include "TextureDraw.h" #include "WindowSurface.h" #include "OpenglRender/render_api.h" +#include "Renderable.h" + +#include "anbox/graphics/program_family.h" +#include "anbox/graphics/primitives.h" + #include #include @@ -51,13 +56,15 @@ typedef std::map ColorBufferMap; // extension is supported. // |eglMajor| and |eglMinor| are the major and minor version numbers of // the underlying EGL implementation. -struct FrameBufferCaps { +struct RendererCaps { bool has_eglimage_texture_2d; bool has_eglimage_renderbuffer; EGLint eglMajor; EGLint eglMinor; }; +struct RendererWindow; + // The FrameBuffer class holds the global state of the emulation library on // top of the underlying EGL/GLES implementation. It should probably be // named "Display" instead of "FrameBuffer". @@ -65,7 +72,7 @@ struct FrameBufferCaps { // There is only one global instance, that can be retrieved with getFB(), // and which must be previously setup by calling initialize(). // -class FrameBuffer { +class Renderer { public: // Initialize the global instance. // |width| and |height| are the dimensions of the emulator GPU display @@ -74,53 +81,20 @@ public: // 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, int width, int height, bool useSubWindow); - - // Setup a sub-window to display the content of the emulated GPU - // on-top of an existing UI window. |p_window| is the platform-specific - // parent window handle. |wx|, |wy|, |ww| and |wh| are the - // dimensions in pixels of the sub-window, relative to the parent window's - // coordinate. |fbw| and |fbh| are the dimensions used to initialize - // the framebuffer, which may be different from the dimensions of the - // sub-window (in which case scaling will be applied automatically). - // |dpr| is the device pixel ratio of the monitor, which is needed for - // proper panning on high-density displays (like retina) - // |zRot| is a rotation angle in degrees, (clockwise in the Y-upwards GL - // coordinate space). - // - // If a sub-window already exists, this function updates the subwindow - // and framebuffer properties to match the given values. - // - // Return true on success, false otherwise. - // - // NOTE: This can return false for software-only EGL engines like OSMesa. - bool setupSubWindow(FBNativeWindowType p_window, - int wx, int wy, - int ww, int wh, - int fbw, int fbh, float dpr, float zRot); - - // Remove the sub-window created by setupSubWindow(), if any. - // Return true on success, false otherwise. - bool removeSubWindow(); + static bool initialize(EGLNativeDisplayType nativeDisplay); // Finalize the instance. void finalize(); // Return a pointer to the global instance. initialize() must be called // previously, or this will return NULL. - static FrameBuffer *getFB() { return s_theFrameBuffer; } + static Renderer *get() { return s_renderer; } // Return the capabilities of the underlying display. - const FrameBufferCaps &getCaps() const { return m_caps; } - - // Return the emulated GPU display width in pixels. - int getWidth() const { return m_framebufferWidth; } - - // Return the emulated GPU display height in pixels. - int getHeight() const { return m_framebufferHeight; } + const RendererCaps &getCaps() const { return m_caps; } // Return the list of configs available from this display. - const FbConfigList* getConfigs() const { return m_configs; } + 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, @@ -138,6 +112,10 @@ public: *version = m_glVersion; } + 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. @@ -254,41 +232,11 @@ public: int x, int y, int width, int height, GLenum format, GLenum type, void *pixels); - // Display the content of a given ColorBuffer into the framebuffer's - // sub-window. |p_colorbuffer| is a handle value. - // |needLock| is used to indicate whether the operation requires - // acquiring/releasing the FrameBuffer instance's lock. It should be - // false only when called internally. - bool post(HandleType p_colorbuffer, bool needLock = true); - - // Re-post the last ColorBuffer that was displayed through post(). - // This is useful if you detect that the sub-window content needs to - // be re-displayed for any reason. - bool repost(); + 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; } - // Change the rotation of the displayed GPU sub-window. - void setDisplayRotation(float zRot) { - m_zRot = zRot; - repost(); - } - - // Changes what coordinate of this framebuffer will be displayed at the - // corner of the GPU sub-window. Specifically, |px| and |py| = 0 means - // align the bottom-left of the framebuffer with the bottom-left of the - // sub-window, and |px| and |py| = 1 means align the top right of the - // framebuffer with the top right of the sub-window. Intermediate values - // interpolate between these states. - void setDisplayTranslation(float px, float py) { - - // Sanity check the values to ensure they are between 0 and 1 - m_px = px > 1 ? 1 : (px < 0 ? 0 : px); - m_py = py > 1 ? 1 : (py < 0 ? 0 : py); - repost(); - } - // Return a TextureDraw instance that can be used with this surfaces // and windows created by this instance. TextureDraw* getTextureDraw() const { return m_textureDraw; } @@ -301,34 +249,32 @@ public: bool unbind_locked(); private: - FrameBuffer(int p_width, int p_height, bool useSubWindow); - ~FrameBuffer(); + Renderer(); + ~Renderer(); HandleType genHandle(); - bool bindSubwin_locked(); + 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& primitives, + const anbox::graphics::Rect &buf_size, + const Renderable &renderable); private: - static FrameBuffer *s_theFrameBuffer; + static Renderer *s_renderer; static HandleType s_nextHandle; - int m_x; - int m_y; - int m_framebufferWidth; - int m_framebufferHeight; - int m_windowWidth; - int m_windowHeight; - float m_dpr; - bool m_useSubWindow; emugl::Mutex m_lock; - FbConfigList* m_configs; + RendererConfigList* m_configs; FBNativeWindowType m_nativeWindow; - FrameBufferCaps m_caps; + RendererCaps m_caps; EGLDisplay m_eglDisplay; RenderContextMap m_contexts; WindowSurfaceMap m_windows; ColorBufferMap m_colorbuffers; ColorBuffer::Helper* m_colorBufferHelper; - EGLSurface m_eglSurface; EGLContext m_eglContext; EGLSurface m_pbufSurface; EGLContext m_pbufContext; @@ -336,25 +282,43 @@ private: EGLContext m_prevContext; EGLSurface m_prevReadSurf; EGLSurface m_prevDrawSurf; - EGLNativeWindowType m_subWin; TextureDraw* m_textureDraw; EGLConfig m_eglConfig; HandleType m_lastPostedColorBuffer; - float m_zRot; - float m_px; - float m_py; - bool m_eglContextInitialized; int m_statsNumFrames; long long m_statsStartTime; bool m_fpsStats; - OnPostFn m_onPost; - void* m_onPostContext; - unsigned char* m_fbImage; - const char* m_glVendor; const char* m_glRenderer; const char* m_glVersion; + + std::map 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; + + Program(GLuint program_id); + Program() {} + }; + Program m_defaultProgram, m_alphaProgram; + + std::vector m_primitives; + + static const GLchar* const vshader; + static const GLchar* const defaultFShader; + static const GLchar* const alphaFShader; }; #endif diff --git a/external/android-emugl/host/libs/libOpenglRender/FbConfig.cpp b/src/anbox/graphics/emugl/RendererConfig.cpp similarity index 93% rename from external/android-emugl/host/libs/libOpenglRender/FbConfig.cpp rename to src/anbox/graphics/emugl/RendererConfig.cpp index a49a984..09f227a 100644 --- a/external/android-emugl/host/libs/libOpenglRender/FbConfig.cpp +++ b/src/anbox/graphics/emugl/RendererConfig.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "FbConfig.h" +#include "RendererConfig.h" #include "OpenGLESDispatch/EGLDispatch.h" @@ -92,11 +92,11 @@ bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) { } // namespace -FbConfig::~FbConfig() { +RendererConfig::~RendererConfig() { delete [] mAttribValues; } -FbConfig::FbConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) : +RendererConfig::RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) : mEglConfig(hostConfig), mAttribValues(NULL) { mAttribValues = new GLint[kConfigAttributesLen]; for (size_t i = 0; i < kConfigAttributesLen; ++i) { @@ -114,7 +114,7 @@ FbConfig::FbConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) : } } -FbConfigList::FbConfigList(EGLDisplay display) : +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", @@ -130,27 +130,27 @@ FbConfigList::FbConfigList(EGLDisplay display) : EGLConfig* hostConfigs = new EGLConfig[numHostConfigs]; s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs); - mConfigs = new FbConfig*[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 FbConfig(hostConfigs[i], display); + mConfigs[mCount] = new RendererConfig(hostConfigs[i], display); mCount++; } delete [] hostConfigs; } -FbConfigList::~FbConfigList() { +RendererConfigList::~RendererConfigList() { for (int n = 0; n < mCount; ++n) { delete mConfigs[n]; } delete [] mConfigs; } -int FbConfigList::chooseConfig(const EGLint* attribs, +int RendererConfigList::chooseConfig(const EGLint* attribs, EGLint* configs, EGLint configsSize) const { EGLint numHostConfigs = 0; @@ -245,7 +245,7 @@ int FbConfigList::chooseConfig(const EGLint* attribs, } -void FbConfigList::getPackInfo(EGLint* numConfigs, +void RendererConfigList::getPackInfo(EGLint* numConfigs, EGLint* numAttributes) const { if (numConfigs) { *numConfigs = mCount; @@ -255,7 +255,7 @@ void FbConfigList::getPackInfo(EGLint* numConfigs, } } -EGLint FbConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const { +EGLint RendererConfigList::packConfigs(GLuint bufferByteSize, GLuint* buffer) const { GLuint numAttribs = static_cast(kConfigAttributesLen); GLuint kGLuintSize = static_cast(sizeof(GLuint)); GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize; diff --git a/external/android-emugl/host/libs/libOpenglRender/FbConfig.h b/src/anbox/graphics/emugl/RendererConfig.h similarity index 91% rename from external/android-emugl/host/libs/libOpenglRender/FbConfig.h rename to src/anbox/graphics/emugl/RendererConfig.h index 2a653e8..c49ee1a 100644 --- a/external/android-emugl/host/libs/libOpenglRender/FbConfig.h +++ b/src/anbox/graphics/emugl/RendererConfig.h @@ -32,10 +32,10 @@ // One doesn't create an FbConfig instance. Instead, create and initialize // an FbConfigList from the host EGLDisplay, and use its size() and get() // methods to access it. -class FbConfig { +class RendererConfig { public: // Destructor - ~FbConfig(); + ~RendererConfig(); // Retrieve host EGLConfig. EGLConfig getEglConfig() const { return mEglConfig; } @@ -57,12 +57,12 @@ public: GLint getConfigId() const { return (GLint)getAttribValue(4); } private: - FbConfig(); - FbConfig(FbConfig& other); + RendererConfig(); + RendererConfig(RendererConfig& other); - explicit FbConfig(EGLConfig hostConfig, EGLDisplay hostDisplay); + explicit RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay); - friend class FbConfigList; + friend class RendererConfigList; GLuint getAttribValue(int n) const { return mAttribValues ? mAttribValues[n] : 0U; @@ -91,7 +91,7 @@ private: // // 5) Use getPackInfo() and packConfigs() to retrieve information about // available configs to the guest. -class FbConfigList { +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 @@ -99,10 +99,10 @@ public: // // After construction, call empty() to check if there are items. // An empty list means there was an error during construction. - explicit FbConfigList(EGLDisplay display); + explicit RendererConfigList(EGLDisplay display); // Destructor. - ~FbConfigList(); + ~RendererConfigList(); // Return true iff the list is empty. true means there was an error // during construction. @@ -116,7 +116,7 @@ public: // Retrieve the FbConfig instance associated with |guestId|, // which must be an integer between 0 and |size() - 1|. Returns // NULL in case of failure. - const FbConfig* get(int guestId) const { + const RendererConfig* get(int guestId) const { if (guestId >= 0 && guestId < mCount) { return mConfigs[guestId]; } else { @@ -152,11 +152,11 @@ public: EGLint packConfigs(GLuint bufferByteSize, GLuint* buffer) const; private: - FbConfigList(); - FbConfigList(const FbConfigList& other); + RendererConfigList(); + RendererConfigList(const RendererConfigList& other); int mCount; - FbConfig** mConfigs; + RendererConfig** mConfigs; EGLDisplay mDisplay; }; diff --git a/external/android-emugl/host/libs/libOpenglRender/SocketStream.cpp b/src/anbox/graphics/emugl/SocketStream.cpp similarity index 88% rename from external/android-emugl/host/libs/libOpenglRender/SocketStream.cpp rename to src/anbox/graphics/emugl/SocketStream.cpp index 3121e81..24f5436 100644 --- a/external/android-emugl/host/libs/libOpenglRender/SocketStream.cpp +++ b/src/anbox/graphics/emugl/SocketStream.cpp @@ -19,14 +19,9 @@ #include #include #include - -#ifndef _WIN32 #include #include #include -#else -#include -#endif SocketStream::SocketStream(size_t bufSize) : IOStream(bufSize), @@ -48,10 +43,8 @@ SocketStream::~SocketStream() { if (m_sock >= 0) { forceStop(); -#ifndef _WIN32 if(close(m_sock) < 0) perror("Closing SocketStream failed"); -#endif // DBG("SocketStream::~close @ %d \n", m_sock); m_sock = -1; } @@ -169,15 +162,5 @@ int SocketStream::recv(void *buf, size_t len) void SocketStream::forceStop() { // Shutdown socket to force read/write errors. -#ifdef _WIN32 - ::shutdown(m_sock, SD_BOTH); - // As documented by programmers on MSDN, shutdown implementation in Windows does - // NOT result to unblocking threads that are blocked on a recv on the socket - // being shut down. The only way to actually implement this behavior (expected - // by this forceStop() implementation) is to rudely close the socket. - ::closesocket(m_sock); - m_sock = -1; -#else ::shutdown(m_sock, SHUT_RDWR); -#endif } diff --git a/external/android-emugl/host/libs/libOpenglRender/SocketStream.h b/src/anbox/graphics/emugl/SocketStream.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/SocketStream.h rename to src/anbox/graphics/emugl/SocketStream.h diff --git a/external/android-emugl/host/libs/libOpenglRender/TcpStream.cpp b/src/anbox/graphics/emugl/TcpStream.cpp similarity index 97% rename from external/android-emugl/host/libs/libOpenglRender/TcpStream.cpp rename to src/anbox/graphics/emugl/TcpStream.cpp index ba355ab..de97c02 100644 --- a/external/android-emugl/host/libs/libOpenglRender/TcpStream.cpp +++ b/src/anbox/graphics/emugl/TcpStream.cpp @@ -22,12 +22,8 @@ #include #include -#ifndef _WIN32 #include #include -#else -#include -#endif #define LISTEN_BACKLOG 4 diff --git a/external/android-emugl/host/libs/libOpenglRender/TcpStream.h b/src/anbox/graphics/emugl/TcpStream.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/TcpStream.h rename to src/anbox/graphics/emugl/TcpStream.h diff --git a/external/android-emugl/host/libs/libOpenglRender/TextureDraw.cpp b/src/anbox/graphics/emugl/TextureDraw.cpp similarity index 89% rename from external/android-emugl/host/libs/libOpenglRender/TextureDraw.cpp rename to src/anbox/graphics/emugl/TextureDraw.cpp index 9e2a16a..d0f8dd7 100644 --- a/external/android-emugl/host/libs/libOpenglRender/TextureDraw.cpp +++ b/src/anbox/graphics/emugl/TextureDraw.cpp @@ -57,20 +57,14 @@ GLuint createShader(GLint shaderType, const char* shaderText) { } // No scaling / projection since we want to fill the whole viewport with -// the texture, hence a trivial vertex shader that only supports clockwise -// rotation. +// the texture, hence a trivial vertex shader. const char kVertexShaderSource[] = "attribute vec4 position;\n" "attribute vec2 inCoord;\n" "varying lowp vec2 outCoord;\n" - "uniform float rotation;\n" - "uniform vec2 translation;\n" - "void main(void) {\n" - " float cs = cos(rotation);\n" - " float sn = sin(rotation);\n" - " gl_Position.x = position.x * cs + position.y * sn - translation.x;\n" - " gl_Position.y = position.y * cs - position.x * sn - translation.y;\n" + " gl_Position.x = position.x;\n" + " gl_Position.y = position.y;\n" " gl_Position.zw = position.zw;\n" " outCoord = inCoord;\n" "}\n"; @@ -142,15 +136,8 @@ TextureDraw::TextureDraw(EGLDisplay display) : mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord"); s_gles2.glEnableVertexAttribArray(mInCoordSlot); - mRotationSlot = s_gles2.glGetUniformLocation(mProgram, "rotation"); - mTranslationSlot = s_gles2.glGetUniformLocation(mProgram, "translation"); mTextureSlot = s_gles2.glGetUniformLocation(mProgram, "texture"); -#if 0 - printf("SLOTS position=%d inCoord=%d texture=%d rotation=%d\n", - mPositionSlot, mInCoordSlot, mTextureSlot, mRotationSlot); -#endif - // Create vertex and index buffers. s_gles2.glGenBuffers(1, &mVertexBuffer); s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer); @@ -165,7 +152,7 @@ TextureDraw::TextureDraw(EGLDisplay display) : GL_STATIC_DRAW); } -bool TextureDraw::draw(GLuint texture, float rotation, float dx, float dy) { +bool TextureDraw::draw(GLuint texture) { if (!mProgram) { ERR("%s: no program\n", __FUNCTION__); return false; @@ -220,11 +207,6 @@ bool TextureDraw::draw(GLuint texture, float rotation, float dx, float dy) { s_gles2.glBindTexture(GL_TEXTURE_2D, texture); s_gles2.glUniform1i(mTextureSlot, 0); - // setup the |rotation| uniform value. - s_gles2.glUniform1f(mRotationSlot, rotation * M_PI / 180.); - s_gles2.glUniform2f(mTranslationSlot, dx, dy); - -#if 1 // Validate program, just to be sure. s_gles2.glValidateProgram(mProgram); GLint validState = 0; @@ -236,7 +218,6 @@ bool TextureDraw::draw(GLuint texture, float rotation, float dx, float dy) { ERR("%s: Could not run program: %s\n", __FUNCTION__, messages); return false; } -#endif // Do the rendering. s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); diff --git a/external/android-emugl/host/libs/libOpenglRender/TextureDraw.h b/src/anbox/graphics/emugl/TextureDraw.h similarity index 84% rename from external/android-emugl/host/libs/libOpenglRender/TextureDraw.h rename to src/anbox/graphics/emugl/TextureDraw.h index ee9371f..b8cc7c3 100644 --- a/external/android-emugl/host/libs/libOpenglRender/TextureDraw.h +++ b/src/anbox/graphics/emugl/TextureDraw.h @@ -38,11 +38,8 @@ public: ~TextureDraw(); // Fill the current framebuffer with the content of |texture|, which must - // be the name of a GLES 2.x texture object. |rotationDegrees| is a - // clockwise rotation angle in degrees (clockwise in the GL Y-upwards - // coordinate space). |dx,dy| is the translation of the image towards the - // origin. - bool draw(GLuint texture, float rotationDegrees, float dx, float dy); + // be the name of a GLES 2.x texture object. + bool draw(GLuint texture); private: EGLDisplay mDisplay; diff --git a/external/android-emugl/host/libs/libOpenglRender/TextureResize.cpp b/src/anbox/graphics/emugl/TextureResize.cpp similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/TextureResize.cpp rename to src/anbox/graphics/emugl/TextureResize.cpp diff --git a/external/android-emugl/host/libs/libOpenglRender/TextureResize.h b/src/anbox/graphics/emugl/TextureResize.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/TextureResize.h rename to src/anbox/graphics/emugl/TextureResize.h diff --git a/external/android-emugl/host/libs/libOpenglRender/TimeUtils.cpp b/src/anbox/graphics/emugl/TimeUtils.cpp similarity index 57% rename from external/android-emugl/host/libs/libOpenglRender/TimeUtils.cpp rename to src/anbox/graphics/emugl/TimeUtils.cpp index 50aeb03..1a7fbf9 100644 --- a/external/android-emugl/host/libs/libOpenglRender/TimeUtils.cpp +++ b/src/anbox/graphics/emugl/TimeUtils.cpp @@ -15,55 +15,21 @@ */ #include "TimeUtils.h" -#ifdef _WIN32 -#include -#include -#include -#elif defined(__linux__) + #include #include #include #include -#else -#include -#include -#endif long long GetCurrentTimeMS() { -#ifdef _WIN32 - static LARGE_INTEGER freq; - static bool bNotInit = true; - if ( bNotInit ) { - bNotInit = (QueryPerformanceFrequency( &freq ) == FALSE); - } - LARGE_INTEGER currVal; - QueryPerformanceCounter( &currVal ); - - return currVal.QuadPart / (freq.QuadPart / 1000); - -#elif defined(__linux__) - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec/1000000LL; return iDiff; - -#else /* Others, e.g. OS X */ - - struct timeval now; - gettimeofday(&now, NULL); - long long iDiff = (now.tv_sec * 1000LL) + now.tv_usec/1000LL; - return iDiff; - -#endif } void TimeSleepMS(int p_mili) { -#ifdef _WIN32 - Sleep(p_mili); -#else usleep(p_mili * 1000); -#endif } diff --git a/external/android-emugl/host/libs/libOpenglRender/TimeUtils.h b/src/anbox/graphics/emugl/TimeUtils.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/TimeUtils.h rename to src/anbox/graphics/emugl/TimeUtils.h diff --git a/external/android-emugl/host/libs/libOpenglRender/UnixStream.cpp b/src/anbox/graphics/emugl/UnixStream.cpp similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/UnixStream.cpp rename to src/anbox/graphics/emugl/UnixStream.cpp diff --git a/external/android-emugl/host/libs/libOpenglRender/UnixStream.h b/src/anbox/graphics/emugl/UnixStream.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/UnixStream.h rename to src/anbox/graphics/emugl/UnixStream.h diff --git a/external/android-emugl/host/libs/libOpenglRender/WindowSurface.cpp b/src/anbox/graphics/emugl/WindowSurface.cpp similarity index 99% rename from external/android-emugl/host/libs/libOpenglRender/WindowSurface.cpp rename to src/anbox/graphics/emugl/WindowSurface.cpp index 553b109..caf7609 100644 --- a/external/android-emugl/host/libs/libOpenglRender/WindowSurface.cpp +++ b/src/anbox/graphics/emugl/WindowSurface.cpp @@ -16,7 +16,7 @@ #include "WindowSurface.h" #include "ErrorLog.h" -#include "FbConfig.h" +#include "RendererConfig.h" #include "OpenGLESDispatch/EGLDispatch.h" diff --git a/external/android-emugl/host/libs/libOpenglRender/WindowSurface.h b/src/anbox/graphics/emugl/WindowSurface.h similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/WindowSurface.h rename to src/anbox/graphics/emugl/WindowSurface.h diff --git a/external/android-emugl/host/libs/libOpenglRender/render_api.entries b/src/anbox/graphics/emugl/render_api.entries similarity index 100% rename from external/android-emugl/host/libs/libOpenglRender/render_api.entries rename to src/anbox/graphics/emugl/render_api.entries diff --git a/src/anbox/graphics/gl_renderer_server.cpp b/src/anbox/graphics/gl_renderer_server.cpp index 50624f0..e770c79 100644 --- a/src/anbox/graphics/gl_renderer_server.cpp +++ b/src/anbox/graphics/gl_renderer_server.cpp @@ -17,7 +17,9 @@ #include "anbox/logger.h" #include "anbox/graphics/gl_renderer_server.h" -#include "anbox/graphics/window_creator.h" +#include "anbox/graphics/layer_composer.h" +#include "anbox/graphics/emugl/RenderControl.h" +#include "anbox/wm/manager.h" #include "OpenglRender/render_api.h" @@ -27,8 +29,10 @@ namespace anbox { namespace graphics { -GLRendererServer::GLRendererServer(const std::shared_ptr &window_creator) : - window_creator_(window_creator) { +GLRendererServer::GLRendererServer(const std::shared_ptr &wm) : + wm_(wm), + composer_(std::make_shared(wm)) +{ if (utils::is_env_set("USE_HOST_GLES")) { // Force the host EGL/GLES libraries as translator implementation @@ -45,13 +49,10 @@ GLRendererServer::GLRendererServer(const std::shared_ptr &window_ if (!initLibrary()) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer")); - setStreamMode(RENDER_API_STREAM_MODE_UNIX); - - registerSubWindowHandler(window_creator_); + registerLayerComposer(composer_); } GLRendererServer::~GLRendererServer() { - destroyOpenGLSubwindow(); stopOpenGLRenderer(); } @@ -71,24 +72,14 @@ void GLRendererServer::start() { log_funcs.coarse = logger_write; log_funcs.fine = logger_write; - auto display_info = window_creator_->display_info(); - const auto width = display_info.horizontal_resolution; - const auto height = display_info.vertical_resolution; - char server_addr[256] = { 0 }; // The width & height we supply here are the dimensions the internal framebuffer // will use. Making this static prevents us for now to resize the window we create // later for the actual display. - if (!initOpenGLRenderer(window_creator_->native_display(), width, height, true, server_addr, sizeof(server_addr), log_funcs, logger_write)) + if (!initOpenGLRenderer(0, server_addr, sizeof(server_addr), log_funcs, logger_write)) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to setup OpenGL renderer")); socket_path_ = server_addr; - - // Create the window we use for rendering the output we get from the - // Android container. This will internally construct a Mir surface - // and use the host EGL/GLES libraries for rendering. - if (!showOpenGLSubwindow(0, 0, 0, width, height, width, height, 1.0f, 0)) - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to setup GL based window")); } std::string GLRendererServer::socket_path() const { diff --git a/src/anbox/graphics/gl_renderer_server.h b/src/anbox/graphics/gl_renderer_server.h index 4b5fad9..7bee80d 100644 --- a/src/anbox/graphics/gl_renderer_server.h +++ b/src/anbox/graphics/gl_renderer_server.h @@ -25,11 +25,14 @@ namespace anbox { namespace input { class Manager; } // namespace input +namespace wm { +class Manager; +} // namespace wm namespace graphics { -class WindowCreator; +class LayerComposer; class GLRendererServer { public: - GLRendererServer(const std::shared_ptr &window_creator); + GLRendererServer(const std::shared_ptr &wm); ~GLRendererServer(); void start(); @@ -38,7 +41,8 @@ public: private: std::string socket_path_; - std::shared_ptr window_creator_; + std::shared_ptr wm_; + std::shared_ptr composer_; }; } // namespace graphics diff --git a/src/anbox/graphics/layer_composer.cpp b/src/anbox/graphics/layer_composer.cpp new file mode 100644 index 0000000..9d31c3f --- /dev/null +++ b/src/anbox/graphics/layer_composer.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/graphics/layer_composer.h" +#include "anbox/graphics/emugl/Renderer.h" +#include "anbox/wm/manager.h" +#include "anbox/logger.h" + +namespace anbox { +namespace graphics { +LayerComposer::LayerComposer(const std::shared_ptr &wm) : + wm_(wm) +{ +} + +LayerComposer::~LayerComposer() +{ +} + +void LayerComposer::submit_layers(const RenderableList &renderables) +{ + std::map,RenderableList> win_layers; + for (const auto &renderable : renderables) + { + // Ignore all surfaces which are not meant for a task + if (!utils::string_starts_with(renderable.name(), "org.anbox.surface.")) + continue; + + wm::Task::Id task_id = 0; + if (sscanf(renderable.name().c_str(), "org.anbox.surface.%d", &task_id) != 1 || !task_id) + continue; + + auto w = wm_->find_window_for_task(task_id); + if (!w) + continue; + + if (win_layers.find(w) == win_layers.end()) { + win_layers.insert({w, {renderable}}); + continue; + } + + win_layers[w].push_back(renderable); + } + + for (const auto &w : win_layers) + { + const auto &window = w.first; + const auto &renderables = w.second; + RenderableList final_renderables; + auto new_window_frame = Rect::Invalid; + + // As we get absolute display coordinates from the Android hwcomposer we + // need to recalculate all layer coordinates into relatives ones to the + // window they are drawn into. + for (auto &r : renderables) + { + if (new_window_frame == Rect::Invalid) + new_window_frame = r.screen_position(); + else + new_window_frame.merge(r.screen_position()); + } + + for (auto &r : renderables) + { + auto left = r.screen_position().left() - new_window_frame.left(); + auto top = r.screen_position().top() - new_window_frame.top(); + + auto rect = Rect{ + left, top, + r.screen_position().width() + left, + r.screen_position().height() + top, + }; + + auto new_renderable = r; + new_renderable.set_screen_position(rect); + final_renderables.push_back(new_renderable); + } + + w.first->update_frame(new_window_frame); + + Renderer::get()->draw(window->native_handle(), + Rect{0, 0, window->frame().width(), window->frame().height()}, + final_renderables); + } +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/graphics/layer_composer.h b/src/anbox/graphics/layer_composer.h new file mode 100644 index 0000000..9127b2d --- /dev/null +++ b/src/anbox/graphics/layer_composer.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_GRAPHICS_LAYER_COMPOSER_H_ +#define ANBOX_GRAPHICS_LAYER_COMPOSER_H_ + +#include "anbox/graphics/emugl/Renderable.h" + +#include + +namespace anbox { +namespace wm { +class Manager; +} // namespace wm +namespace graphics { +class LayerComposer { +public: + LayerComposer(const std::shared_ptr &wm); + ~LayerComposer(); + + void submit_layers(const RenderableList &renderables); + +private: + std::shared_ptr wm_; +}; +} // namespace graphics +} // namespace anbox + +#endif diff --git a/src/anbox/graphics/primitives.h b/src/anbox/graphics/primitives.h new file mode 100644 index 0000000..5529f95 --- /dev/null +++ b/src/anbox/graphics/primitives.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Daniel van Vugt + * Kevin DuBois + */ + + +#ifndef ANBOX_GRAPHICS_PRIMITIVES_H_ +#define ANBOX_GRAPHICS_PRIMITIVES_H_ + +#include + +namespace anbox { +namespace graphics { +struct Vertex +{ + GLfloat position[3]; + GLfloat texcoord[2]; +}; + +struct Primitive +{ + enum {max_vertices = 4}; + + Primitive() + : type(GL_TRIANGLE_FAN), nvertices(4) + { + // Default is a quad. Just need to assign vertices[] and tex_id. + } + + GLenum type; // GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES etc + GLuint tex_id; // GL texture ID (or 0 to represent the surface itself) + int nvertices; + Vertex vertices[max_vertices]; +}; +} // namespace graphics +} // namespace anbox + +#endif diff --git a/src/anbox/graphics/program_family.cpp b/src/anbox/graphics/program_family.cpp new file mode 100644 index 0000000..c47e49e --- /dev/null +++ b/src/anbox/graphics/program_family.cpp @@ -0,0 +1,107 @@ +/* + * Copyright © 2015 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Daniel van Vugt + */ + +#include "anbox/graphics/program_family.h" + +#include "anbox/graphics/emugl/DispatchTables.h" + +namespace anbox { +namespace graphics { +void ProgramFamily::Shader::init(GLenum type, const GLchar* src) +{ + if (!id) + { + id = s_gles2.glCreateShader(type); + if (id) + { + s_gles2.glShaderSource(id, 1, &src, NULL); + s_gles2.glCompileShader(id); + GLint ok; + s_gles2.glGetShaderiv(id, GL_COMPILE_STATUS, &ok); + if (!ok) + { + GLchar log[1024]; + s_gles2.glGetShaderInfoLog(id, sizeof log - 1, NULL, log); + log[sizeof log - 1] = '\0'; + s_gles2.glDeleteShader(id); + id = 0; + throw std::runtime_error(std::string("Compile failed: ")+ + log + " for:\n" + src); + } + } + } +} + +ProgramFamily::~ProgramFamily() noexcept +{ + // shader and program lifetimes are managed manually, so that we don't + // need any reference counting or to worry about how many copy constructions + // might have been followed by destructor calls during container resizes. + + for (auto& p : program) + { + if (p.second.id) + s_gles2.glDeleteProgram(p.second.id); + } + + for (auto& v : vshader) + { + if (v.second.id) + s_gles2.glDeleteShader(v.second.id); + } + + for (auto& f : fshader) + { + if (f.second.id) + s_gles2.glDeleteShader(f.second.id); + } +} + +GLuint ProgramFamily::add_program(const GLchar* const vshader_src, + const GLchar* const fshader_src) +{ + auto& v = vshader[vshader_src]; + if (!v.id) v.init(GL_VERTEX_SHADER, vshader_src); + + auto& f = fshader[fshader_src]; + if (!f.id) f.init(GL_FRAGMENT_SHADER, fshader_src); + + auto& p = program[{v.id, f.id}]; + if (!p.id) + { + p.id = s_gles2.glCreateProgram(); + s_gles2.glAttachShader(p.id, v.id); + s_gles2.glAttachShader(p.id, f.id); + s_gles2.glLinkProgram(p.id); + GLint ok; + s_gles2.glGetProgramiv(p.id, GL_LINK_STATUS, &ok); + if (!ok) + { + GLchar log[1024]; + s_gles2.glGetProgramInfoLog(p.id, sizeof log - 1, NULL, log); + log[sizeof log - 1] = '\0'; + s_gles2.glDeleteShader(p.id); + p.id = 0; + throw std::runtime_error(std::string("Link failed: ")+log); + } + } + + return p.id; +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/graphics/program_family.h b/src/anbox/graphics/program_family.h new file mode 100644 index 0000000..98e7f88 --- /dev/null +++ b/src/anbox/graphics/program_family.h @@ -0,0 +1,68 @@ +/* + * Copyright © 2015 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authored by: Daniel van Vugt + */ + +#ifndef ANBOX_GRAPHICS_PROGRAM_FAMILY_H_ +#define ANBOX_GRAPHICS_PROGRAM_FAMILY_H_ + +#include +#include +#include + +#include + +namespace anbox { +namespace graphics { +/** + * ProgramFamily represents a set of GLSL programs that are closely + * related. Programs which point to the same shader source strings will be + * made to share the same compiled shader objects. + * A secondary intention is that this class may be extended to allow the + * different programs within the family to share common patterns of uniform + * usage too. + */ +class ProgramFamily +{ +public: + ProgramFamily() = default; + ProgramFamily(ProgramFamily const&) = delete; + ProgramFamily& operator=(ProgramFamily const&) = delete; + ~ProgramFamily() noexcept; + + GLuint add_program(const GLchar* const static_vshader_src, + const GLchar* const static_fshader_src); + +private: + struct Shader + { + GLuint id = 0; + void init(GLenum type, const GLchar* src); + }; + typedef std::unordered_map ShaderMap; + ShaderMap vshader, fshader; + + typedef std::pair ShaderPair; + struct Program + { + GLuint id = 0; + }; + std::map program; +}; +} // namespace graphics +} // namespace anbox + +#endif // MIR_RENDERER_GL_PROGRAM_FAMILY_H_ diff --git a/android/app_manager/src/org/anbox/app_manager/MainApplication.java b/src/anbox/graphics/rect.cpp similarity index 59% rename from android/app_manager/src/org/anbox/app_manager/MainApplication.java rename to src/anbox/graphics/rect.cpp index ca0f6b3..e8cbb13 100644 --- a/android/app_manager/src/org/anbox/app_manager/MainApplication.java +++ b/src/anbox/graphics/rect.cpp @@ -15,21 +15,21 @@ * */ -package org.anbox.app_manager; +#include "anbox/graphics/rect.h" -import java.lang.reflect.Method; +#include -import android.app.Application; -import android.os.IBinder; +namespace anbox { +namespace graphics { +const Rect Rect::Invalid{-1,-1,-1,-1}; +const Rect Rect::Empty{0,0,0,0}; -public class MainApplication extends Application { - public void startServices() { - Method addService; - try { - addService = Class.forName("android.os.ServiceManager").getMethod("addService", String.class, IBinder.class); - } - catch (Exception e) { - e.printStackTrace(); - } - } -} \ No newline at end of file +void Rect::merge(const Rect &rhs) +{ + left_ = std::min(left_, rhs.left()); + top_ = std::min(top_, rhs.top()); + right_ = std::max(right_, rhs.right()); + bottom_ = std::max(bottom_, rhs.bottom()); +} +} // namespace graphics +} // namespace anbox diff --git a/src/anbox/graphics/rect.h b/src/anbox/graphics/rect.h new file mode 100644 index 0000000..15949c2 --- /dev/null +++ b/src/anbox/graphics/rect.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_GRAPHICS_RECT_H_ +#define ANBOX_GRAPHICS_RECT_H_ + +#include + +namespace anbox { +namespace graphics { +class Rect { +public: + static const Rect Invalid; + static const Rect Empty; + + inline Rect() : Rect(Empty) {} + + inline Rect(const std::int32_t &left, + const std::int32_t &top, + const std::int32_t &right, + const std::int32_t &bottom) : + left_(left), + top_(top), + right_(right), + bottom_(bottom) { + } + + inline Rect(const std::int32_t &width, const std::int32_t &height) : + left_(0), + top_(0), + right_(width), + bottom_(height) { + } + + inline void clear() { + left_ = top_ = right_ = bottom_ = 0; + } + + inline bool valid() const { + return width() >= 0 && height() >= 0; + } + + inline std::int32_t width() const { + return right_ - left_; + } + + inline std::int32_t height() const { + return bottom_ - top_; + } + + inline std::int32_t left() const { + return left_; + } + + inline std::int32_t top() const { + return top_; + } + + inline std::int32_t right() const { + return right_; + } + + inline std::int32_t bottom() const { + return bottom_; + } + + inline bool operator == (const Rect &rhs) const { + return (left_ == rhs.left() && + top_ == rhs.top() && + right_ == rhs.right() && + bottom_ == rhs.bottom()); + } + + inline bool operator != (const Rect &rhs) const { + return !operator == (rhs); + } + + void merge(const Rect &rhs); + +private: + std::int32_t left_; + std::int32_t top_; + std::int32_t right_; + std::int32_t bottom_; +}; +} // namespace graphics +} // namespace anbox + +#endif diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto index 2102278..382a2b8 100644 --- a/src/anbox/protobuf/anbox_bridge.proto +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -2,6 +2,11 @@ option optimize_for = LITE_RUNTIME; package anbox.protobuf.bridge; +message StructuredError { + optional uint32 domain = 1; + optional uint32 code = 2; +} + message Notification { required string package_name = 1; required string category = 2; @@ -26,3 +31,34 @@ message SetDnsServers { } repeated Server servers = 2; } + +message SetFocusedTask { + required int32 id = 1; +} + +message BootFinishedEvent { +} + +message WindowStateUpdateEvent { + message WindowState { + required int32 display_id = 1; + required bool has_surface = 2; + required string package_name = 3; + required int32 frame_left = 4; + required int32 frame_top = 5; + required int32 frame_right = 6; + required int32 frame_bottom = 7; + required int32 task_id = 8; + required int32 stack_id = 9; + } + repeated WindowState windows = 1; + repeated WindowState removed_windows = 2; +} + +message EventSequence { + optional BootFinishedEvent boot_finished = 1; + optional WindowStateUpdateEvent window_state_update = 2; + + optional string error = 127; + optional StructuredError structured_error = 128; +} diff --git a/src/anbox/protobuf/anbox_rpc.proto b/src/anbox/protobuf/anbox_rpc.proto index dddbd41..dc5f8a9 100644 --- a/src/anbox/protobuf/anbox_rpc.proto +++ b/src/anbox/protobuf/anbox_rpc.proto @@ -12,6 +12,7 @@ message Invocation { message Result { optional uint32 id = 1; optional bytes response = 2; + repeated bytes events = 3; } message StructuredError { diff --git a/src/anbox/qemu/boot_properties_message_processor.cpp b/src/anbox/qemu/boot_properties_message_processor.cpp index d5b54c2..0165942 100644 --- a/src/anbox/qemu/boot_properties_message_processor.cpp +++ b/src/anbox/qemu/boot_properties_message_processor.cpp @@ -28,7 +28,6 @@ BootPropertiesMessageProcessor::BootPropertiesMessageProcessor(const std::shared BootPropertiesMessageProcessor::~BootPropertiesMessageProcessor() { } - void BootPropertiesMessageProcessor::handle_command(const std::string &command) { if (command == "list") list_properties(); @@ -36,43 +35,11 @@ void BootPropertiesMessageProcessor::handle_command(const std::string &command) void BootPropertiesMessageProcessor::list_properties() { std::vector properties = { - // Simple indicator to say we're anbox and if needed things in the container - // can adjust to this. Normally everything should detect we're qemu which - // should be enough for the simple cases. - "ro.anbox=1", - - // Needed for identification within the system. Normally retrieve from - // kernel configuration which isn't possible in our case. - "ro.hardware=goldfish", - - // Needed to let the gralloc HAL load the right implementation - "ro.kernel.qemu.gles=1", - - // Needed from different parts of the system in order to load - // the right implementation for qemu - "ro.kernel.qemu=1", - // TODO(morphis): Using HDPI here for now but should be adjusted to the device // we're running on. - utils::string_format("ro.sf.lcd_density=%d", static_cast(graphics::DensityType::high)), - - // Disable on-screen virtual keys as we can use the hardware keyboard - "qemu.hw.mainkeys=1", - - // Android has builtin detection (inside Zygote) for proper container - // detection support - "ro.boot.container=1", - - // Mark us as a device without telephony support (as we don't have a RIL) - "ro.radio.noril=yes", + utils::string_format("ro.sf.lcd_density=%d", static_cast(graphics::DensityType::medium)), }; - if (utils::is_env_set("USE_HWCOMPOSER")) { - // To let surfaceflinger load our hwcomposer implementation we specify - // the correct subkey of the module here. - properties.push_back("ro.hardware.hwcomposer=anbox"); - } - for (const auto &prop : properties) { send_header(prop.length()); messenger_->send(prop.c_str(), prop.length()); diff --git a/src/anbox/qemu/bootanimation_message_processor.cpp b/src/anbox/qemu/bootanimation_message_processor.cpp index 398cbce..c166a21 100644 --- a/src/anbox/qemu/bootanimation_message_processor.cpp +++ b/src/anbox/qemu/bootanimation_message_processor.cpp @@ -32,7 +32,6 @@ BootAnimationMessageProcessor::~BootAnimationMessageProcessor() { } void BootAnimationMessageProcessor::handle_command(const std::string &command) { - DEBUG("command %s", command); if (command == "retrieve-icon") retrieve_icon(); } diff --git a/src/anbox/qemu/camera_message_processor.cpp b/src/anbox/qemu/camera_message_processor.cpp index c7c9c6b..c936044 100644 --- a/src/anbox/qemu/camera_message_processor.cpp +++ b/src/anbox/qemu/camera_message_processor.cpp @@ -28,8 +28,6 @@ CameraMessageProcessor::~CameraMessageProcessor() { } bool CameraMessageProcessor::process_data(const std::vector &data) { - DEBUG("Received: %s", utils::hex_dump(data.data(), data.size())); - for (const auto &byte : data) buffer_.push_back(byte); diff --git a/src/anbox/qemu/gsm_message_processor.cpp b/src/anbox/qemu/gsm_message_processor.cpp index 1973587..dc3c945 100644 --- a/src/anbox/qemu/gsm_message_processor.cpp +++ b/src/anbox/qemu/gsm_message_processor.cpp @@ -78,7 +78,6 @@ void GsmMessageProcessor::handle_ctec(const std::string &command) { } void GsmMessageProcessor::handle_cmgf(const std::string &command) { - DEBUG("command %s", command); if (command == "+CMGF=0") send_reply(""); } diff --git a/src/anbox/qemu/hwcontrol_message_processor.cpp b/src/anbox/qemu/hwcontrol_message_processor.cpp index 39f7a30..ebe0369 100644 --- a/src/anbox/qemu/hwcontrol_message_processor.cpp +++ b/src/anbox/qemu/hwcontrol_message_processor.cpp @@ -28,6 +28,7 @@ HwControlMessageProcessor::~HwControlMessageProcessor() { } void HwControlMessageProcessor::handle_command(const std::string &command) { +#if 0 if (command == "power:screen_state:wake") DEBUG("Got screen wake command"); else if (command == "power:screen_state:standby") @@ -36,6 +37,9 @@ void HwControlMessageProcessor::handle_command(const std::string &command) { DEBUG("Got LCD backligh brightness control command"); else DEBUG("Unknown command '%s'", command); +#else + (void) command; +#endif } } // namespace qemu } // namespace anbox diff --git a/src/anbox/qemu/null_message_processor.cpp b/src/anbox/qemu/null_message_processor.cpp index 798e2b7..90a211d 100644 --- a/src/anbox/qemu/null_message_processor.cpp +++ b/src/anbox/qemu/null_message_processor.cpp @@ -30,7 +30,7 @@ NullMessageProcessor::~NullMessageProcessor() { } bool NullMessageProcessor::process_data(const std::vector &data) { - DEBUG("Received: %s", utils::hex_dump(data.data(), data.size())); + (void) data; return true; } } // namespace qemu diff --git a/src/anbox/qemu/pipe_connection_creator.cpp b/src/anbox/qemu/pipe_connection_creator.cpp index 5d81e89..0273d86 100644 --- a/src/anbox/qemu/pipe_connection_creator.cpp +++ b/src/anbox/qemu/pipe_connection_creator.cpp @@ -109,8 +109,6 @@ PipeConnectionCreator::client_type PipeConnectionCreator::identify_client( std::string identifier_and_args = buffer.data(); - DEBUG("identifier %s", identifier_and_args); - if (utils::string_starts_with(identifier_and_args, "pipe:opengles")) return client_type::opengles; // Even if 'boot-properties' is an argument to the service 'qemud' here we diff --git a/src/anbox/qemu/qemud_message_processor.cpp b/src/anbox/qemu/qemud_message_processor.cpp index 80fa4b6..7a39afa 100644 --- a/src/anbox/qemu/qemud_message_processor.cpp +++ b/src/anbox/qemu/qemud_message_processor.cpp @@ -35,8 +35,6 @@ QemudMessageProcessor::~QemudMessageProcessor() { } bool QemudMessageProcessor::process_data(const std::vector &data) { - DEBUG("Received: %s", utils::hex_dump(data.data(), data.size())); - for (const auto &byte : data) buffer_.push_back(byte); diff --git a/src/anbox/qemu/sensors_message_processor.cpp b/src/anbox/qemu/sensors_message_processor.cpp index 4aca92b..5843164 100644 --- a/src/anbox/qemu/sensors_message_processor.cpp +++ b/src/anbox/qemu/sensors_message_processor.cpp @@ -28,7 +28,6 @@ SensorsMessageProcessor::~SensorsMessageProcessor() { } void SensorsMessageProcessor::handle_command(const std::string &command) { - DEBUG("command %s", command); if (command == "list-sensors") list_sensors(); } diff --git a/src/anbox/rpc/channel.cpp b/src/anbox/rpc/channel.cpp index a99da5a..d613996 100644 --- a/src/anbox/rpc/channel.cpp +++ b/src/anbox/rpc/channel.cpp @@ -42,7 +42,17 @@ void Channel::call_method(std::string const& method_name, google::protobuf::Closure *complete) { auto const &invocation = invocation_for(method_name, parameters); pending_calls_->save_completion_details(invocation, response, complete); - send_message(invocation); + send_message(MessageType::invocation, invocation); +} + +void Channel::send_event(google::protobuf::MessageLite const& event) { + VariableLengthArray<2048> buffer{static_cast(event.ByteSize())}; + event.SerializeWithCachedSizesToArray(buffer.data()); + + anbox::protobuf::rpc::Result response; + response.add_events(buffer.data(), buffer.size()); + + send_message(MessageType::response, response); } protobuf::rpc::Invocation Channel::invocation_for(std::string const& method_name, @@ -62,17 +72,17 @@ protobuf::rpc::Invocation Channel::invocation_for(std::string const& method_name return invoke; } -void Channel::send_message(anbox::protobuf::rpc::Invocation const& invocation) { - const size_t size = invocation.ByteSize(); +void Channel::send_message(const std::uint8_t &type, google::protobuf::MessageLite const& message) { + const size_t size = message.ByteSize(); const unsigned char header_bytes[header_size] = { static_cast((size >> 8) & 0xff), static_cast((size >> 0) & 0xff), - MessageType::invocation, + type, }; std::vector send_buffer(sizeof(header_bytes) + size); std::copy(header_bytes, header_bytes + sizeof(header_bytes), send_buffer.begin()); - invocation.SerializeToArray(send_buffer.data() + sizeof(header_bytes), size); + message.SerializeToArray(send_buffer.data() + sizeof(header_bytes), size); try { std::lock_guard lock(write_mutex_); @@ -88,8 +98,9 @@ void Channel::notify_disconnected() { pending_calls_->force_completion(); } -int Channel::next_id() { - return next_message_id_.fetch_add(1); +std::uint32_t Channel::next_id() { + static std::uint32_t next_message_id = 0; + return next_message_id++; } } // namespace rpc } // namespace anbox diff --git a/src/anbox/rpc/channel.h b/src/anbox/rpc/channel.h index 36a350b..3dc9e11 100644 --- a/src/anbox/rpc/channel.h +++ b/src/anbox/rpc/channel.h @@ -52,15 +52,16 @@ public: google::protobuf::MessageLite *response, google::protobuf::Closure *complete); + void send_event(google::protobuf::MessageLite const& event); + private: protobuf::rpc::Invocation invocation_for( std::string const& method_name, google::protobuf::MessageLite const* request); - void send_message(anbox::protobuf::rpc::Invocation const& invocation); - int next_id(); + void send_message(const std::uint8_t &type, google::protobuf::MessageLite const& message); + std::uint32_t next_id(); void notify_disconnected(); - std::atomic next_message_id_; std::shared_ptr pending_calls_; std::shared_ptr sender_; std::mutex write_mutex_; diff --git a/src/anbox/rpc/message_processor.cpp b/src/anbox/rpc/message_processor.cpp index e19066b..c3b190d 100644 --- a/src/anbox/rpc/message_processor.cpp +++ b/src/anbox/rpc/message_processor.cpp @@ -20,6 +20,7 @@ #include "anbox/rpc/make_protobuf_object.h" #include "anbox/rpc/constants.h" #include "anbox/common/variable_length_array.h" +#include "anbox/utils.h" #include "anbox_rpc.pb.h" @@ -50,35 +51,38 @@ bool MessageProcessor::process_data(const std::vector &data) { for (const auto &byte : data) buffer_.push_back(byte); - buffer_.shrink_to_fit(); + while (buffer_.size() > 0) { + const auto high = buffer_[0]; + const auto low = buffer_[1]; + size_t const message_size = (high << 8) + low; + const auto message_type = buffer_[2]; - const auto high = buffer_[0]; - const auto low = buffer_[1]; - size_t const message_size = (high << 8) + low; - const auto message_type = buffer_[2]; + // If we don't have yet all bytes for a new message return and wait + // until we have all. + if (buffer_.size() - header_size < message_size) { + WARNING("Don't have enough bytes yet (buffer %d header %d message %d)", + buffer_.size(), header_size, message_size); + break; + } - // If we don't have yet all bytes for a new message return and wait - // until we have all. - if (buffer_.size() - header_size < message_size) - return true; + if (message_type == MessageType::invocation) { + anbox::protobuf::rpc::Invocation raw_invocation; + raw_invocation.ParseFromArray(buffer_.data() + header_size, message_size); - buffer_.erase(buffer_.begin(), buffer_.begin() + header_size); + dispatch(Invocation(raw_invocation)); + } + else if (message_type == MessageType::response) { + auto result = make_protobuf_object(); + result->ParseFromArray(buffer_.data() + header_size, message_size); - if (message_type == MessageType::invocation) { - anbox::protobuf::rpc::Invocation raw_invocation; - raw_invocation.ParseFromArray(buffer_.data(), message_size); + if (result->has_id()) + pending_calls_->complete_response(*result); - buffer_.erase(buffer_.begin(), buffer_.begin() + message_size); + for (int n = 0; n < result->events_size(); n++) + process_event_sequence(result->events(n)); + } - dispatch(Invocation(raw_invocation)); - } - else if (message_type == MessageType::response) { - auto result = make_protobuf_object(); - result->ParseFromArray(buffer_.data(), message_size); - - buffer_.erase(buffer_.begin(), buffer_.begin() + message_size); - - pending_calls_->complete_response(*result); + buffer_.erase(buffer_.begin(), buffer_.begin() + header_size + message_size); } return true; diff --git a/src/anbox/ubuntu/keycode_converter.cpp b/src/anbox/ubuntu/keycode_converter.cpp new file mode 100644 index 0000000..ac2d46d --- /dev/null +++ b/src/anbox/ubuntu/keycode_converter.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/ubuntu/keycode_converter.h" + +#include + +namespace anbox { +namespace ubuntu { +std::uint16_t KeycodeConverter::convert(const SDL_Scancode &scan_code) { + for (std::uint16_t n = 0; n < code_map.size(); n++) { + if (code_map[n] == scan_code) + return n; + } + return KEY_RESERVED; +} + +const std::array KeycodeConverter::code_map = {{ + SDL_SCANCODE_UNKNOWN, /* KEY_RESERVED 0 */ + SDL_SCANCODE_ESCAPE, /* KEY_ESC 1 */ + SDL_SCANCODE_1, /* KEY_1 2 */ + SDL_SCANCODE_2, /* KEY_2 3 */ + SDL_SCANCODE_3, /* KEY_3 4 */ + SDL_SCANCODE_4, /* KEY_4 5 */ + SDL_SCANCODE_5, /* KEY_5 6 */ + SDL_SCANCODE_6, /* KEY_6 7 */ + SDL_SCANCODE_7, /* KEY_7 8 */ + SDL_SCANCODE_8, /* KEY_8 9 */ + SDL_SCANCODE_9, /* KEY_9 10 */ + SDL_SCANCODE_0, /* KEY_0 11 */ + SDL_SCANCODE_MINUS, /* KEY_MINUS 12 */ + SDL_SCANCODE_EQUALS, /* KEY_EQUAL 13 */ + SDL_SCANCODE_BACKSPACE, /* KEY_BACKSPACE 14 */ + SDL_SCANCODE_TAB, /* KEY_TAB 15 */ + SDL_SCANCODE_Q, /* KEY_Q 16 */ + SDL_SCANCODE_W, /* KEY_W 17 */ + SDL_SCANCODE_E, /* KEY_E 18 */ + SDL_SCANCODE_R, /* KEY_R 19 */ + SDL_SCANCODE_T, /* KEY_T 20 */ + SDL_SCANCODE_Y, /* KEY_Y 21 */ + SDL_SCANCODE_U, /* KEY_U 22 */ + SDL_SCANCODE_I, /* KEY_I 23 */ + SDL_SCANCODE_O, /* KEY_O 24 */ + SDL_SCANCODE_P, /* KEY_P 25 */ + SDL_SCANCODE_LEFTBRACKET, /* KEY_LEFTBRACE 26 */ + SDL_SCANCODE_RIGHTBRACKET, /* KEY_RIGHTBRACE 27 */ + SDL_SCANCODE_RETURN, /* KEY_ENTER 28 */ + SDL_SCANCODE_LCTRL, /* KEY_LEFTCTRL 29 */ + SDL_SCANCODE_A, /* KEY_A 30 */ + SDL_SCANCODE_S, /* KEY_S 31 */ + SDL_SCANCODE_D, /* KEY_D 32 */ + SDL_SCANCODE_F, /* KEY_F 33 */ + SDL_SCANCODE_G, /* KEY_G 34 */ + SDL_SCANCODE_H, /* KEY_H 35 */ + SDL_SCANCODE_J, /* KEY_J 36 */ + SDL_SCANCODE_K, /* KEY_K 37 */ + SDL_SCANCODE_L, /* KEY_L 38 */ + SDL_SCANCODE_SEMICOLON, /* KEY_SEMICOLON 39 */ + SDL_SCANCODE_APOSTROPHE, /* KEY_APOSTROPHE 40 */ + SDL_SCANCODE_GRAVE, /* KEY_GRAVE 41 */ + SDL_SCANCODE_LSHIFT, /* KEY_LEFTSHIFT 42 */ + SDL_SCANCODE_BACKSLASH, /* KEY_BACKSLASH 43 */ + SDL_SCANCODE_Z, /* KEY_Z 44 */ + SDL_SCANCODE_X, /* KEY_X 45 */ + SDL_SCANCODE_C, /* KEY_C 46 */ + SDL_SCANCODE_V, /* KEY_V 47 */ + SDL_SCANCODE_B, /* KEY_B 48 */ + SDL_SCANCODE_N, /* KEY_N 49 */ + SDL_SCANCODE_M, /* KEY_M 50 */ + SDL_SCANCODE_COMMA, /* KEY_COMMA 51 */ + SDL_SCANCODE_PERIOD, /* KEY_DOT 52 */ + SDL_SCANCODE_SLASH, /* KEY_SLASH 53 */ + SDL_SCANCODE_RSHIFT, /* KEY_RIGHTSHIFT 54 */ + SDL_SCANCODE_KP_MULTIPLY, /* KEY_KPASTERISK 55 */ + SDL_SCANCODE_LALT, /* KEY_LEFTALT 56 */ + SDL_SCANCODE_SPACE, /* KEY_SPACE 57 */ + SDL_SCANCODE_CAPSLOCK, /* KEY_CAPSLOCK 58 */ + SDL_SCANCODE_F1, /* KEY_F1 59 */ + SDL_SCANCODE_F2, /* KEY_F2 60 */ + SDL_SCANCODE_F3, /* KEY_F3 61 */ + SDL_SCANCODE_F4, /* KEY_F4 62 */ + SDL_SCANCODE_F5, /* KEY_F5 63 */ + SDL_SCANCODE_F6, /* KEY_F6 64 */ + SDL_SCANCODE_F7, /* KEY_F7 65 */ + SDL_SCANCODE_F8, /* KEY_F8 66 */ + SDL_SCANCODE_F9, /* KEY_F9 67 */ + SDL_SCANCODE_F10, /* KEY_F10 68 */ + SDL_SCANCODE_NUMLOCKCLEAR, /* KEY_NUMLOCK 69 */ + SDL_SCANCODE_SCROLLLOCK, /* KEY_SCROLLLOCK 70 */ + SDL_SCANCODE_KP_7, /* KEY_KP7 71 */ + SDL_SCANCODE_KP_8, /* KEY_KP8 72 */ + SDL_SCANCODE_KP_9, /* KEY_KP9 73 */ + SDL_SCANCODE_KP_MINUS, /* KEY_KPMINUS 74 */ + SDL_SCANCODE_KP_4, /* KEY_KP4 75 */ + SDL_SCANCODE_KP_5, /* KEY_KP5 76 */ + SDL_SCANCODE_KP_6, /* KEY_KP6 77 */ + SDL_SCANCODE_KP_PLUS, /* KEY_KPPLUS 78 */ + SDL_SCANCODE_KP_1, /* KEY_KP1 79 */ + SDL_SCANCODE_KP_2, /* KEY_KP2 80 */ + SDL_SCANCODE_KP_3, /* KEY_KP3 81 */ + SDL_SCANCODE_KP_0, /* KEY_KP0 82 */ + SDL_SCANCODE_KP_PERIOD, /* KEY_KPDOT 83 */ + SDL_SCANCODE_UNKNOWN, /* 84 */ + SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU 85 */ + SDL_SCANCODE_UNKNOWN, /* KEY_102ND 86 */ + SDL_SCANCODE_F11, /* KEY_F11 87 */ + SDL_SCANCODE_F12, /* KEY_F12 88 */ + SDL_SCANCODE_UNKNOWN, /* KEY_RO 89 */ + SDL_SCANCODE_LANG3, /* KEY_KATAKANA 90 */ + SDL_SCANCODE_LANG4, /* KEY_HIRAGANA 91 */ + SDL_SCANCODE_UNKNOWN, /* KEY_HENKAN 92 */ + SDL_SCANCODE_LANG3, /* KEY_KATAKANAHIRAGANA 93 */ + SDL_SCANCODE_UNKNOWN, /* KEY_MUHENKAN 94 */ + SDL_SCANCODE_KP_COMMA, /* KEY_KPJPCOMMA 95 */ + SDL_SCANCODE_KP_ENTER, /* KEY_KPENTER 96 */ + SDL_SCANCODE_RCTRL, /* KEY_RIGHTCTRL 97 */ + SDL_SCANCODE_KP_DIVIDE, /* KEY_KPSLASH 98 */ + SDL_SCANCODE_SYSREQ, /* KEY_SYSRQ 99 */ + SDL_SCANCODE_RALT, /* KEY_RIGHTALT 100 */ + SDL_SCANCODE_UNKNOWN, /* KEY_LINEFEED 101 */ + SDL_SCANCODE_HOME, /* KEY_HOME 102 */ + SDL_SCANCODE_UP, /* KEY_UP 103 */ + SDL_SCANCODE_PAGEUP, /* KEY_PAGEUP 104 */ + SDL_SCANCODE_LEFT, /* KEY_LEFT 105 */ + SDL_SCANCODE_RIGHT, /* KEY_RIGHT 106 */ + SDL_SCANCODE_END, /* KEY_END 107 */ + SDL_SCANCODE_DOWN, /* KEY_DOWN 108 */ + SDL_SCANCODE_PAGEDOWN, /* KEY_PAGEDOWN 109 */ + SDL_SCANCODE_INSERT, /* KEY_INSERT 110 */ + SDL_SCANCODE_DELETE, /* KEY_DELETE 111 */ + SDL_SCANCODE_UNKNOWN, /* KEY_MACRO 112 */ + SDL_SCANCODE_MUTE, /* KEY_MUTE 113 */ + SDL_SCANCODE_VOLUMEDOWN, /* KEY_VOLUMEDOWN 114 */ + SDL_SCANCODE_VOLUMEUP, /* KEY_VOLUMEUP 115 */ + SDL_SCANCODE_POWER, /* KEY_POWER 116 SC System Power Down */ + SDL_SCANCODE_KP_EQUALS, /* KEY_KPEQUAL 117 */ + SDL_SCANCODE_KP_MINUS, /* KEY_KPPLUSMINUS 118 */ + SDL_SCANCODE_PAUSE, /* KEY_PAUSE 119 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SCALE 120 AL Compiz Scale (Expose) */ + SDL_SCANCODE_KP_COMMA, /* KEY_KPCOMMA 121 */ + SDL_SCANCODE_LANG1, /* KEY_HANGEUL,KEY_HANGUEL 122 */ + SDL_SCANCODE_LANG2, /* KEY_HANJA 123 */ + SDL_SCANCODE_INTERNATIONAL3,/* KEY_YEN 124 */ + SDL_SCANCODE_LGUI, /* KEY_LEFTMETA 125 */ + SDL_SCANCODE_RGUI, /* KEY_RIGHTMETA 126 */ + SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE 127 */ + SDL_SCANCODE_STOP, /* KEY_STOP 128 AC Stop */ + SDL_SCANCODE_AGAIN, /* KEY_AGAIN 129 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PROPS 130 AC Properties */ + SDL_SCANCODE_UNDO, /* KEY_UNDO 131 AC Undo */ + SDL_SCANCODE_UNKNOWN, /* KEY_FRONT 132 */ + SDL_SCANCODE_COPY, /* KEY_COPY 133 AC Copy */ + SDL_SCANCODE_UNKNOWN, /* KEY_OPEN 134 AC Open */ + SDL_SCANCODE_PASTE, /* KEY_PASTE 135 AC Paste */ + SDL_SCANCODE_FIND, /* KEY_FIND 136 AC Search */ + SDL_SCANCODE_CUT, /* KEY_CUT 137 AC Cut */ + SDL_SCANCODE_HELP, /* KEY_HELP 138 AL Integrated Help Center */ + SDL_SCANCODE_MENU, /* KEY_MENU 139 Menu (show menu) */ + SDL_SCANCODE_CALCULATOR, /* KEY_CALC 140 AL Calculator */ + SDL_SCANCODE_UNKNOWN, /* KEY_SETUP 141 */ + SDL_SCANCODE_SLEEP, /* KEY_SLEEP 142 SC System Sleep */ + SDL_SCANCODE_UNKNOWN, /* KEY_WAKEUP 143 System Wake Up */ + SDL_SCANCODE_UNKNOWN, /* KEY_FILE 144 AL Local Machine Browser */ + SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE 145 */ + SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE 146 */ + SDL_SCANCODE_UNKNOWN, /* KEY_XFER 147 */ + SDL_SCANCODE_APP1, /* KEY_PROG1 148 */ + SDL_SCANCODE_APP1, /* KEY_PROG2 149 */ + SDL_SCANCODE_WWW, /* KEY_WWW 150 AL Internet Browser */ + SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS 151 */ + SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE,KEY_SCREENLOCK 152 AL Terminal Lock/Screensaver */ + SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION 153 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CYCLEWINDOWS 154 */ + SDL_SCANCODE_MAIL, /* KEY_MAIL 155 */ + SDL_SCANCODE_AC_BOOKMARKS, /* KEY_BOOKMARKS 156 AC Bookmarks */ + SDL_SCANCODE_COMPUTER, /* KEY_COMPUTER 157 */ + SDL_SCANCODE_AC_BACK, /* KEY_BACK 158 AC Back */ + SDL_SCANCODE_AC_FORWARD, /* KEY_FORWARD 159 AC Forward */ + SDL_SCANCODE_UNKNOWN, /* KEY_CLOSECD 160 */ + SDL_SCANCODE_EJECT, /* KEY_EJECTCD 161 */ + SDL_SCANCODE_UNKNOWN, /* KEY_EJECTCLOSECD 162 */ + SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG 163 */ + SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE 164 */ + SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG 165 */ + SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD 166 */ + SDL_SCANCODE_UNKNOWN, /* KEY_RECORD 167 */ + SDL_SCANCODE_UNKNOWN, /* KEY_REWIND 168 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PHONE 169 Media Select Telephone */ + SDL_SCANCODE_UNKNOWN, /* KEY_ISO 170 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CONFIG 171 AL Consumer Control Configuration */ + SDL_SCANCODE_AC_HOME, /* KEY_HOMEPAGE 172 AC Home */ + SDL_SCANCODE_AC_REFRESH, /* KEY_REFRESH 173 AC Refresh */ + SDL_SCANCODE_UNKNOWN, /* KEY_EXIT 174 AC Exit */ + SDL_SCANCODE_UNKNOWN, /* KEY_MOVE 175 */ + SDL_SCANCODE_UNKNOWN, /* KEY_EDIT 176 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLUP 177 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLDOWN 178 */ + SDL_SCANCODE_KP_LEFTPAREN, /* KEY_KPLEFTPAREN 179 */ + SDL_SCANCODE_KP_RIGHTPAREN, /* KEY_KPRIGHTPAREN 180 */ + SDL_SCANCODE_UNKNOWN, /* KEY_NEW 181 AC New */ + SDL_SCANCODE_AGAIN, /* KEY_REDO 182 AC Redo/Repeat */ + SDL_SCANCODE_F13, /* KEY_F13 183 */ + SDL_SCANCODE_F14, /* KEY_F14 184 */ + SDL_SCANCODE_F15, /* KEY_F15 185 */ + SDL_SCANCODE_F16, /* KEY_F16 186 */ + SDL_SCANCODE_F17, /* KEY_F17 187 */ + SDL_SCANCODE_F18, /* KEY_F18 188 */ + SDL_SCANCODE_F19, /* KEY_F19 189 */ + SDL_SCANCODE_F20, /* KEY_F20 190 */ + SDL_SCANCODE_F21, /* KEY_F21 191 */ + SDL_SCANCODE_F22, /* KEY_F22 192 */ + SDL_SCANCODE_F23, /* KEY_F23 193 */ + SDL_SCANCODE_F24, /* KEY_F24 194 */ + SDL_SCANCODE_UNKNOWN, /* 195 */ + SDL_SCANCODE_UNKNOWN, /* 196 */ + SDL_SCANCODE_UNKNOWN, /* 197 */ + SDL_SCANCODE_UNKNOWN, /* 198 */ + SDL_SCANCODE_UNKNOWN, /* 199 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD 200 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD 201 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 202 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PROG4 203 */ + SDL_SCANCODE_UNKNOWN, /* KEY_DASHBOARD 204 AL Dashboard */ + SDL_SCANCODE_UNKNOWN, /* KEY_SUSPEND 205 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CLOSE 206 AC Close */ + SDL_SCANCODE_UNKNOWN, /* KEY_PLAY 207 */ + SDL_SCANCODE_UNKNOWN, /* KEY_FASTFORWARD 208 */ + SDL_SCANCODE_UNKNOWN, /* KEY_BASSBOOST 209 */ + SDL_SCANCODE_UNKNOWN, /* KEY_PRINT 210 AC Print */ + SDL_SCANCODE_UNKNOWN, /* KEY_HP 211 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CAMERA 212 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SOUND 213 */ + SDL_SCANCODE_UNKNOWN, /* KEY_QUESTION 214 */ + SDL_SCANCODE_UNKNOWN, /* KEY_EMAIL 215 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CHAT 216 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SEARCH 217 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CONNECT 218 */ + SDL_SCANCODE_UNKNOWN, /* KEY_FINANCE 219 AL Checkbook/Finance */ + SDL_SCANCODE_UNKNOWN, /* KEY_SPORT 220 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SHOP 221 */ + SDL_SCANCODE_UNKNOWN, /* KEY_ALTERASE 222 */ + SDL_SCANCODE_UNKNOWN, /* KEY_CANCEL 223 AC Cancel */ + SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSDOWN 224 */ + SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSUP 225 */ + SDL_SCANCODE_UNKNOWN, /* KEY_MEDIA 226 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ + SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMTOGGLE 228 */ + SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMDOWN 229 */ + SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMUP 230 */ + SDL_SCANCODE_UNKNOWN, /* KEY_SEND 231 AC Send */ + SDL_SCANCODE_UNKNOWN, /* KEY_REPLY 232 AC Reply */ + SDL_SCANCODE_UNKNOWN, /* KEY_FORWARDMAIL 233 AC Forward Msg */ + SDL_SCANCODE_UNKNOWN, /* KEY_SAVE 234 AC Save */ + SDL_SCANCODE_UNKNOWN, /* KEY_DOCUMENTS 235 */ + SDL_SCANCODE_UNKNOWN, /* KEY_BATTERY 236 */ + SDL_SCANCODE_UNKNOWN, /* KEY_BLUETOOTH 237 */ + SDL_SCANCODE_UNKNOWN, /* KEY_WLAN 238 */ + SDL_SCANCODE_UNKNOWN, /* KEY_UWB 239 */ + SDL_SCANCODE_UNKNOWN, /* KEY_UNKNOWN 240 */ + SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_NEXT 241 drive next video source */ + SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_PREV 242 drive previous video source */ + SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_CYCLE 243 brightness up, after max is min */ + SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */ + SDL_SCANCODE_UNKNOWN, /* KEY_DISPLAY_OFF 245 display device to off state */ + SDL_SCANCODE_UNKNOWN, /* KEY_WIMAX 246 */ + SDL_SCANCODE_UNKNOWN, /* KEY_RFKILL 247 Key that controls all radios */ + SDL_SCANCODE_UNKNOWN /* KEY_MICMUTE 248 Mute / unmute the microphone */ +}}; +} // namespace ubuntu +} // namespace anbox diff --git a/src/anbox/ubuntu/keycode_converter.h b/src/anbox/ubuntu/keycode_converter.h new file mode 100644 index 0000000..ae7d2df --- /dev/null +++ b/src/anbox/ubuntu/keycode_converter.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_UBUNTU_KEYCODE_CONVERTER_H_ +#define ANBOX_UBUNTU_KEYCODE_CONVERTER_H_ + +#include + +#include + +#include + +namespace anbox { +namespace ubuntu { +class KeycodeConverter { +public: + static std::uint16_t convert(const SDL_Scancode &scan_code); +private: + static const std::array code_map; +}; +} // namespace ubuntu +} // namespace anbox + +#endif diff --git a/src/anbox/ubuntu/platform_api_skeleton.cpp b/src/anbox/ubuntu/platform_api_skeleton.cpp deleted file mode 100644 index d7645cd..0000000 --- a/src/anbox/ubuntu/platform_api_skeleton.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2016 Simon Fels - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - */ - -#include "anbox/ubuntu/platform_api_skeleton.h" -#include "anbox/common/dispatcher.h" -#include "anbox/bridge/android_api_stub.h" -#include "anbox/rpc/pending_call_cache.h" -#include "anbox/logger.h" - -#include "anbox_rpc.pb.h" -#include "anbox_bridge.pb.h" - -namespace anbox { -namespace ubuntu { -PlatformApiSekeleton::PlatformApiSekeleton(const std::shared_ptr &pending_calls) : - bridge::PlatformApiSkeleton(pending_calls) { -} - -PlatformApiSekeleton::~PlatformApiSekeleton() { -} - -void PlatformApiSekeleton::handle_notification(anbox::protobuf::bridge::Notification const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) { - (void) request; - (void) response; - DEBUG(""); - done->Run(); -} - -void PlatformApiSekeleton::boot_finished(anbox::protobuf::rpc::Void const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) { - (void) request; - (void) response; - - if (on_boot_finished_action_) - on_boot_finished_action_(); - - done->Run(); -} - -void PlatformApiSekeleton::on_boot_finished(const std::function &action) { - on_boot_finished_action_ = action; -} -} // namespace ubuntu -} // namespace anbox diff --git a/src/anbox/ubuntu/platform_api_skeleton.h b/src/anbox/ubuntu/platform_api_skeleton.h deleted file mode 100644 index a00f391..0000000 --- a/src/anbox/ubuntu/platform_api_skeleton.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016 Simon Fels - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - */ - -#ifndef ANBOX_UBUNTU_PLATFORM_SERVER_H_ -#define ANBOX_UBUNTU_PLATFORM_SERVER_H_ - -#include "anbox/bridge/platform_api_skeleton.h" - -namespace anbox { -namespace common { -class Dispatcher; -} // namespace common -namespace bridge { -class AndroidApiStub; -} // namespace bridge -namespace rpc { -class PendingCallCache; -} // namespace rpc; -namespace ubuntu { -class PlatformApiSekeleton : public bridge::PlatformApiSkeleton { -public: - PlatformApiSekeleton(const std::shared_ptr &pending_calls); - virtual ~PlatformApiSekeleton(); - - void handle_notification(anbox::protobuf::bridge::Notification const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) override; - - void boot_finished(anbox::protobuf::rpc::Void const *request, - anbox::protobuf::rpc::Void *response, - google::protobuf::Closure *done) override; - - void on_boot_finished(const std::function &action); - -private: - std::function on_boot_finished_action_; -}; -} // namespace bridge -} // namespace anbox - -#endif diff --git a/src/anbox/ubuntu/platform_policy.cpp b/src/anbox/ubuntu/platform_policy.cpp new file mode 100644 index 0000000..2eefe38 --- /dev/null +++ b/src/anbox/ubuntu/platform_policy.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/ubuntu/platform_policy.h" +#include "anbox/ubuntu/window.h" +#include "anbox/ubuntu/keycode_converter.h" +#include "anbox/input/manager.h" +#include "anbox/input/device.h" +#include "anbox/bridge/android_api_stub.h" +#include "anbox/logger.h" + +#include + +#include +#include + +namespace anbox { +namespace ubuntu { +PlatformPolicy::PlatformPolicy(const std::shared_ptr &input_manager, + const std::shared_ptr &android_api) : + input_manager_(input_manager), + android_api_(android_api), + event_thread_running_(false) { + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) + BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize SDL")); + + event_thread_ = std::thread(&PlatformPolicy::process_events, this); + + SDL_DisplayMode display_mode; + // FIXME statically just check the first (primary) display for its mode; + // once we get multi-monitor support we need to do this better. + if (SDL_GetCurrentDisplayMode(0, &display_mode) == 0) { + display_info_.horizontal_resolution = display_mode.w; + display_info_.vertical_resolution = display_mode.h; + } + + pointer_ = input_manager->create_device(); + pointer_->set_name("anbox-pointer"); + pointer_->set_driver_version(1); + pointer_->set_input_id({ BUS_VIRTUAL, 2, 2, 2 }); + pointer_->set_physical_location("none"); + pointer_->set_key_bit(BTN_MOUSE); + // NOTE: We don't use REL_X/REL_Y in reality but have to specify them here + // to allow InputFlinger to detect we're a cursor device. + pointer_->set_rel_bit(REL_X); + pointer_->set_rel_bit(REL_Y); + pointer_->set_rel_bit(REL_HWHEEL); + pointer_->set_rel_bit(REL_WHEEL); + pointer_->set_prop_bit(INPUT_PROP_POINTER); + + keyboard_ = input_manager->create_device(); + keyboard_->set_name("anbox-keyboard"); + keyboard_->set_driver_version(1); + keyboard_->set_input_id({ BUS_VIRTUAL, 3, 3, 3 }); + keyboard_->set_physical_location("none"); + keyboard_->set_key_bit(BTN_MISC); + keyboard_->set_key_bit(KEY_OK); +} + +PlatformPolicy::~PlatformPolicy() { + event_thread_running_ = false; + event_thread_.join(); +} + +void PlatformPolicy::process_events() { + event_thread_running_ = true; + + while(event_thread_running_) { + SDL_Event event; + while (SDL_WaitEventTimeout(&event, 100)) { + switch (event.type) { + case SDL_QUIT: + // This is the best way to reliable terminate the whole application for now. It will + // trigger a correct shutdown in the main part. + ::kill(getpid(), SIGTERM); + break; + case SDL_WINDOWEVENT: + for (auto &iter : windows_) { + if (auto w = iter.second.lock()) { + if (w->window_id() == event.window.windowID) { + w->process_event(event); + break; + } + } + } + break; + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEWHEEL: + case SDL_KEYDOWN: + case SDL_KEYUP: + process_input_event(event); + break; + } + } + } +} + +void PlatformPolicy::process_input_event(const SDL_Event &event) { + std::vector mouse_events; + std::vector keyboard_events; + + std::int32_t x = 0; + std::int32_t y = 0; + SDL_Window *window = nullptr; + + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + mouse_events.push_back({ EV_KEY, BTN_LEFT, 1 }); + mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); + break; + case SDL_MOUSEBUTTONUP: + mouse_events.push_back({ EV_KEY, BTN_LEFT, 0 }); + mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); + break; + case SDL_MOUSEMOTION: + // As we get only absolute coordindates relative to our window we have to + // calculate the correct position based on the current focused window + window = SDL_GetWindowFromID(event.window.windowID); + if (!window) + break; + + SDL_GetWindowPosition(window, &x, &y); + x += event.motion.x; + y += event.motion.y; + + // NOTE: Sending relative move events doesn't really work and we have changes + // in libinputflinger to take ABS_X/ABS_Y instead for absolute position events. + mouse_events.push_back({ EV_ABS, ABS_X, x }); + mouse_events.push_back({ EV_ABS, ABS_Y, y }); + // We're sending relative position updates here too but they will be only used + // by the Android side EventHub/InputReader to determine if the cursor was + // moved. They are not used to find out the exact position. + mouse_events.push_back({ EV_REL, REL_X, event.motion.xrel }); + mouse_events.push_back({ EV_REL, REL_Y, event.motion.yrel }); + mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); + break; + case SDL_MOUSEWHEEL: + mouse_events.push_back({ EV_REL, REL_WHEEL, static_cast(event.wheel.y) }); + break; + case SDL_KEYDOWN: { + const auto code = KeycodeConverter::convert(event.key.keysym.scancode); + if (code == KEY_RESERVED) + break; + keyboard_events.push_back({ EV_KEY, code, 1 }); + break; + } + case SDL_KEYUP: { + const auto code = KeycodeConverter::convert(event.key.keysym.scancode); + if (code == KEY_RESERVED) + break; + keyboard_events.push_back({ EV_KEY, code, 0 }); + break; + } + default: + break; + } + + if (mouse_events.size() > 0) + pointer_->send_events(mouse_events); + + if (keyboard_events.size() > 0) + keyboard_->send_events(keyboard_events); +} + +Window::Id PlatformPolicy::next_window_id() { + static Window::Id next_id = 0; + return next_id++; +} + +std::shared_ptr PlatformPolicy::create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) { + auto id = next_window_id(); + auto w = std::make_shared(id, task, shared_from_this(), frame); + windows_.insert({id, w}); + return w; +} + +void PlatformPolicy::window_deleted(const Window::Id &id) { + auto w = windows_.find(id); + if (w == windows_.end()) { + WARNING("Got window removed event for unknown window (id %d)", id); + return; + } + windows_.erase(w); +} + +void PlatformPolicy::window_wants_focus(const Window::Id &id) { + auto w = windows_.find(id); + if (w == windows_.end()) + return; + + if (auto window = w->second.lock()) + android_api_->set_focused_task(window->task()); +} + +DisplayManager::DisplayInfo PlatformPolicy::display_info() const { + return display_info_; +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/ubuntu/platform_policy.h b/src/anbox/ubuntu/platform_policy.h new file mode 100644 index 0000000..7bab173 --- /dev/null +++ b/src/anbox/ubuntu/platform_policy.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_UBUNTU_PLATFORM_POLICY_H_ +#define ANBOX_UBUNTU_PLATFORM_POLICY_H_ + +#include "anbox/wm/platform_policy.h" +#include "anbox/ubuntu/window.h" + +#include "anbox/graphics/emugl/DisplayManager.h" + +#include +#include + +#include + +namespace anbox { +namespace input { +class Device; +class Manager; +} // namespace input +namespace bridge { +class AndroidApiStub; +} // namespace bridge +namespace ubuntu { +class PlatformPolicy : public std::enable_shared_from_this, + public wm::PlatformPolicy, + public Window::Observer, + public DisplayManager { +public: + PlatformPolicy(const std::shared_ptr &input_manager, + const std::shared_ptr &android_api); + ~PlatformPolicy(); + + std::shared_ptr create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) override; + + void window_deleted(const Window::Id &id) override; + void window_wants_focus(const Window::Id &id) override; + + DisplayInfo display_info() const override; + +private: + void process_events(); + void process_input_event(const SDL_Event &event); + + static Window::Id next_window_id(); + + std::shared_ptr input_manager_; + std::shared_ptr android_api_; + // We don't own the windows anymore after the got created by us so we + // need to be careful once we try to use them again. + std::map> windows_; + std::shared_ptr current_window_; + std::thread event_thread_; + bool event_thread_running_; + std::shared_ptr pointer_; + std::shared_ptr keyboard_; + DisplayManager::DisplayInfo display_info_; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/ubuntu/window.cpp b/src/anbox/ubuntu/window.cpp index 8a057bb..1864dcd 100644 --- a/src/anbox/ubuntu/window.cpp +++ b/src/anbox/ubuntu/window.cpp @@ -16,8 +16,7 @@ */ #include "anbox/ubuntu/window.h" -#include "anbox/input/manager.h" -#include "anbox/input/device.h" +#include "anbox/wm/window_state.h" #include "anbox/logger.h" #include @@ -25,335 +24,44 @@ #include namespace { -class SlotFingerMapper { -public: - int find_or_create(SDL_FingerID id) { - auto iter = std::find(slots_.begin(), slots_.end(), id); - if (iter != slots_.end()) - return std::distance(slots_.begin(), iter); - - std::vector::size_type i; - for(i = 0;i < slots_.size();i++) { - if (slots_[i] == -1) { - slots_[i] = id; - return i; - } - } - - slots_.resize(slots_.size() + 1); - slots_[slots_.size() - 1] = id; - - return slots_.size() - 1; - } - - void erase(SDL_FingerID id) - { - auto it = std::find(slots_.begin(), slots_.end(), id); - - if (it != slots_.end()) { - auto index = std::distance(slots_.begin(), it); - slots_[index] = -1; - if (index == slots_.size()-1) { - while (slots_[index] == -1) { - slots_.resize(index); - index--; - } - } - } - } - -private: - std::vector slots_; -}; - -const std::array kKeycodes {{ - SDL_SCANCODE_UNKNOWN, /* KEY_RESERVED 0 */ - SDL_SCANCODE_ESCAPE, /* KEY_ESC 1 */ - SDL_SCANCODE_1, /* KEY_1 2 */ - SDL_SCANCODE_2, /* KEY_2 3 */ - SDL_SCANCODE_3, /* KEY_3 4 */ - SDL_SCANCODE_4, /* KEY_4 5 */ - SDL_SCANCODE_5, /* KEY_5 6 */ - SDL_SCANCODE_6, /* KEY_6 7 */ - SDL_SCANCODE_7, /* KEY_7 8 */ - SDL_SCANCODE_8, /* KEY_8 9 */ - SDL_SCANCODE_9, /* KEY_9 10 */ - SDL_SCANCODE_0, /* KEY_0 11 */ - SDL_SCANCODE_MINUS, /* KEY_MINUS 12 */ - SDL_SCANCODE_EQUALS, /* KEY_EQUAL 13 */ - SDL_SCANCODE_BACKSPACE, /* KEY_BACKSPACE 14 */ - SDL_SCANCODE_TAB, /* KEY_TAB 15 */ - SDL_SCANCODE_Q, /* KEY_Q 16 */ - SDL_SCANCODE_W, /* KEY_W 17 */ - SDL_SCANCODE_E, /* KEY_E 18 */ - SDL_SCANCODE_R, /* KEY_R 19 */ - SDL_SCANCODE_T, /* KEY_T 20 */ - SDL_SCANCODE_Y, /* KEY_Y 21 */ - SDL_SCANCODE_U, /* KEY_U 22 */ - SDL_SCANCODE_I, /* KEY_I 23 */ - SDL_SCANCODE_O, /* KEY_O 24 */ - SDL_SCANCODE_P, /* KEY_P 25 */ - SDL_SCANCODE_LEFTBRACKET, /* KEY_LEFTBRACE 26 */ - SDL_SCANCODE_RIGHTBRACKET, /* KEY_RIGHTBRACE 27 */ - SDL_SCANCODE_RETURN, /* KEY_ENTER 28 */ - SDL_SCANCODE_LCTRL, /* KEY_LEFTCTRL 29 */ - SDL_SCANCODE_A, /* KEY_A 30 */ - SDL_SCANCODE_S, /* KEY_S 31 */ - SDL_SCANCODE_D, /* KEY_D 32 */ - SDL_SCANCODE_F, /* KEY_F 33 */ - SDL_SCANCODE_G, /* KEY_G 34 */ - SDL_SCANCODE_H, /* KEY_H 35 */ - SDL_SCANCODE_J, /* KEY_J 36 */ - SDL_SCANCODE_K, /* KEY_K 37 */ - SDL_SCANCODE_L, /* KEY_L 38 */ - SDL_SCANCODE_SEMICOLON, /* KEY_SEMICOLON 39 */ - SDL_SCANCODE_APOSTROPHE, /* KEY_APOSTROPHE 40 */ - SDL_SCANCODE_GRAVE, /* KEY_GRAVE 41 */ - SDL_SCANCODE_LSHIFT, /* KEY_LEFTSHIFT 42 */ - SDL_SCANCODE_BACKSLASH, /* KEY_BACKSLASH 43 */ - SDL_SCANCODE_Z, /* KEY_Z 44 */ - SDL_SCANCODE_X, /* KEY_X 45 */ - SDL_SCANCODE_C, /* KEY_C 46 */ - SDL_SCANCODE_V, /* KEY_V 47 */ - SDL_SCANCODE_B, /* KEY_B 48 */ - SDL_SCANCODE_N, /* KEY_N 49 */ - SDL_SCANCODE_M, /* KEY_M 50 */ - SDL_SCANCODE_COMMA, /* KEY_COMMA 51 */ - SDL_SCANCODE_PERIOD, /* KEY_DOT 52 */ - SDL_SCANCODE_SLASH, /* KEY_SLASH 53 */ - SDL_SCANCODE_RSHIFT, /* KEY_RIGHTSHIFT 54 */ - SDL_SCANCODE_KP_MULTIPLY, /* KEY_KPASTERISK 55 */ - SDL_SCANCODE_LALT, /* KEY_LEFTALT 56 */ - SDL_SCANCODE_SPACE, /* KEY_SPACE 57 */ - SDL_SCANCODE_CAPSLOCK, /* KEY_CAPSLOCK 58 */ - SDL_SCANCODE_F1, /* KEY_F1 59 */ - SDL_SCANCODE_F2, /* KEY_F2 60 */ - SDL_SCANCODE_F3, /* KEY_F3 61 */ - SDL_SCANCODE_F4, /* KEY_F4 62 */ - SDL_SCANCODE_F5, /* KEY_F5 63 */ - SDL_SCANCODE_F6, /* KEY_F6 64 */ - SDL_SCANCODE_F7, /* KEY_F7 65 */ - SDL_SCANCODE_F8, /* KEY_F8 66 */ - SDL_SCANCODE_F9, /* KEY_F9 67 */ - SDL_SCANCODE_F10, /* KEY_F10 68 */ - SDL_SCANCODE_NUMLOCKCLEAR, /* KEY_NUMLOCK 69 */ - SDL_SCANCODE_SCROLLLOCK, /* KEY_SCROLLLOCK 70 */ - SDL_SCANCODE_KP_7, /* KEY_KP7 71 */ - SDL_SCANCODE_KP_8, /* KEY_KP8 72 */ - SDL_SCANCODE_KP_9, /* KEY_KP9 73 */ - SDL_SCANCODE_KP_MINUS, /* KEY_KPMINUS 74 */ - SDL_SCANCODE_KP_4, /* KEY_KP4 75 */ - SDL_SCANCODE_KP_5, /* KEY_KP5 76 */ - SDL_SCANCODE_KP_6, /* KEY_KP6 77 */ - SDL_SCANCODE_KP_PLUS, /* KEY_KPPLUS 78 */ - SDL_SCANCODE_KP_1, /* KEY_KP1 79 */ - SDL_SCANCODE_KP_2, /* KEY_KP2 80 */ - SDL_SCANCODE_KP_3, /* KEY_KP3 81 */ - SDL_SCANCODE_KP_0, /* KEY_KP0 82 */ - SDL_SCANCODE_KP_PERIOD, /* KEY_KPDOT 83 */ - SDL_SCANCODE_UNKNOWN, /* 84 */ - SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU 85 */ - SDL_SCANCODE_UNKNOWN, /* KEY_102ND 86 */ - SDL_SCANCODE_F11, /* KEY_F11 87 */ - SDL_SCANCODE_F12, /* KEY_F12 88 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RO 89 */ - SDL_SCANCODE_LANG3, /* KEY_KATAKANA 90 */ - SDL_SCANCODE_LANG4, /* KEY_HIRAGANA 91 */ - SDL_SCANCODE_UNKNOWN, /* KEY_HENKAN 92 */ - SDL_SCANCODE_LANG3, /* KEY_KATAKANAHIRAGANA 93 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MUHENKAN 94 */ - SDL_SCANCODE_KP_COMMA, /* KEY_KPJPCOMMA 95 */ - SDL_SCANCODE_KP_ENTER, /* KEY_KPENTER 96 */ - SDL_SCANCODE_RCTRL, /* KEY_RIGHTCTRL 97 */ - SDL_SCANCODE_KP_DIVIDE, /* KEY_KPSLASH 98 */ - SDL_SCANCODE_SYSREQ, /* KEY_SYSRQ 99 */ - SDL_SCANCODE_RALT, /* KEY_RIGHTALT 100 */ - SDL_SCANCODE_UNKNOWN, /* KEY_LINEFEED 101 */ - SDL_SCANCODE_HOME, /* KEY_HOME 102 */ - SDL_SCANCODE_UP, /* KEY_UP 103 */ - SDL_SCANCODE_PAGEUP, /* KEY_PAGEUP 104 */ - SDL_SCANCODE_LEFT, /* KEY_LEFT 105 */ - SDL_SCANCODE_RIGHT, /* KEY_RIGHT 106 */ - SDL_SCANCODE_END, /* KEY_END 107 */ - SDL_SCANCODE_DOWN, /* KEY_DOWN 108 */ - SDL_SCANCODE_PAGEDOWN, /* KEY_PAGEDOWN 109 */ - SDL_SCANCODE_INSERT, /* KEY_INSERT 110 */ - SDL_SCANCODE_DELETE, /* KEY_DELETE 111 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MACRO 112 */ - SDL_SCANCODE_MUTE, /* KEY_MUTE 113 */ - SDL_SCANCODE_VOLUMEDOWN, /* KEY_VOLUMEDOWN 114 */ - SDL_SCANCODE_VOLUMEUP, /* KEY_VOLUMEUP 115 */ - SDL_SCANCODE_POWER, /* KEY_POWER 116 SC System Power Down */ - SDL_SCANCODE_KP_EQUALS, /* KEY_KPEQUAL 117 */ - SDL_SCANCODE_KP_MINUS, /* KEY_KPPLUSMINUS 118 */ - SDL_SCANCODE_PAUSE, /* KEY_PAUSE 119 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCALE 120 AL Compiz Scale (Expose) */ - SDL_SCANCODE_KP_COMMA, /* KEY_KPCOMMA 121 */ - SDL_SCANCODE_LANG1, /* KEY_HANGEUL,KEY_HANGUEL 122 */ - SDL_SCANCODE_LANG2, /* KEY_HANJA 123 */ - SDL_SCANCODE_INTERNATIONAL3,/* KEY_YEN 124 */ - SDL_SCANCODE_LGUI, /* KEY_LEFTMETA 125 */ - SDL_SCANCODE_RGUI, /* KEY_RIGHTMETA 126 */ - SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE 127 */ - SDL_SCANCODE_STOP, /* KEY_STOP 128 AC Stop */ - SDL_SCANCODE_AGAIN, /* KEY_AGAIN 129 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROPS 130 AC Properties */ - SDL_SCANCODE_UNDO, /* KEY_UNDO 131 AC Undo */ - SDL_SCANCODE_UNKNOWN, /* KEY_FRONT 132 */ - SDL_SCANCODE_COPY, /* KEY_COPY 133 AC Copy */ - SDL_SCANCODE_UNKNOWN, /* KEY_OPEN 134 AC Open */ - SDL_SCANCODE_PASTE, /* KEY_PASTE 135 AC Paste */ - SDL_SCANCODE_FIND, /* KEY_FIND 136 AC Search */ - SDL_SCANCODE_CUT, /* KEY_CUT 137 AC Cut */ - SDL_SCANCODE_HELP, /* KEY_HELP 138 AL Integrated Help Center */ - SDL_SCANCODE_MENU, /* KEY_MENU 139 Menu (show menu) */ - SDL_SCANCODE_CALCULATOR, /* KEY_CALC 140 AL Calculator */ - SDL_SCANCODE_UNKNOWN, /* KEY_SETUP 141 */ - SDL_SCANCODE_SLEEP, /* KEY_SLEEP 142 SC System Sleep */ - SDL_SCANCODE_UNKNOWN, /* KEY_WAKEUP 143 System Wake Up */ - SDL_SCANCODE_UNKNOWN, /* KEY_FILE 144 AL Local Machine Browser */ - SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE 145 */ - SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE 146 */ - SDL_SCANCODE_UNKNOWN, /* KEY_XFER 147 */ - SDL_SCANCODE_APP1, /* KEY_PROG1 148 */ - SDL_SCANCODE_APP1, /* KEY_PROG2 149 */ - SDL_SCANCODE_WWW, /* KEY_WWW 150 AL Internet Browser */ - SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS 151 */ - SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE,KEY_SCREENLOCK 152 AL Terminal Lock/Screensaver */ - SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION 153 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CYCLEWINDOWS 154 */ - SDL_SCANCODE_MAIL, /* KEY_MAIL 155 */ - SDL_SCANCODE_AC_BOOKMARKS, /* KEY_BOOKMARKS 156 AC Bookmarks */ - SDL_SCANCODE_COMPUTER, /* KEY_COMPUTER 157 */ - SDL_SCANCODE_AC_BACK, /* KEY_BACK 158 AC Back */ - SDL_SCANCODE_AC_FORWARD, /* KEY_FORWARD 159 AC Forward */ - SDL_SCANCODE_UNKNOWN, /* KEY_CLOSECD 160 */ - SDL_SCANCODE_EJECT, /* KEY_EJECTCD 161 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EJECTCLOSECD 162 */ - SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG 163 */ - SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE 164 */ - SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG 165 */ - SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD 166 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RECORD 167 */ - SDL_SCANCODE_UNKNOWN, /* KEY_REWIND 168 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PHONE 169 Media Select Telephone */ - SDL_SCANCODE_UNKNOWN, /* KEY_ISO 170 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CONFIG 171 AL Consumer Control Configuration */ - SDL_SCANCODE_AC_HOME, /* KEY_HOMEPAGE 172 AC Home */ - SDL_SCANCODE_AC_REFRESH, /* KEY_REFRESH 173 AC Refresh */ - SDL_SCANCODE_UNKNOWN, /* KEY_EXIT 174 AC Exit */ - SDL_SCANCODE_UNKNOWN, /* KEY_MOVE 175 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EDIT 176 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLUP 177 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLDOWN 178 */ - SDL_SCANCODE_KP_LEFTPAREN, /* KEY_KPLEFTPAREN 179 */ - SDL_SCANCODE_KP_RIGHTPAREN, /* KEY_KPRIGHTPAREN 180 */ - SDL_SCANCODE_UNKNOWN, /* KEY_NEW 181 AC New */ - SDL_SCANCODE_AGAIN, /* KEY_REDO 182 AC Redo/Repeat */ - SDL_SCANCODE_F13, /* KEY_F13 183 */ - SDL_SCANCODE_F14, /* KEY_F14 184 */ - SDL_SCANCODE_F15, /* KEY_F15 185 */ - SDL_SCANCODE_F16, /* KEY_F16 186 */ - SDL_SCANCODE_F17, /* KEY_F17 187 */ - SDL_SCANCODE_F18, /* KEY_F18 188 */ - SDL_SCANCODE_F19, /* KEY_F19 189 */ - SDL_SCANCODE_F20, /* KEY_F20 190 */ - SDL_SCANCODE_F21, /* KEY_F21 191 */ - SDL_SCANCODE_F22, /* KEY_F22 192 */ - SDL_SCANCODE_F23, /* KEY_F23 193 */ - SDL_SCANCODE_F24, /* KEY_F24 194 */ - SDL_SCANCODE_UNKNOWN, /* 195 */ - SDL_SCANCODE_UNKNOWN, /* 196 */ - SDL_SCANCODE_UNKNOWN, /* 197 */ - SDL_SCANCODE_UNKNOWN, /* 198 */ - SDL_SCANCODE_UNKNOWN, /* 199 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD 200 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD 201 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 202 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROG4 203 */ - SDL_SCANCODE_UNKNOWN, /* KEY_DASHBOARD 204 AL Dashboard */ - SDL_SCANCODE_UNKNOWN, /* KEY_SUSPEND 205 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CLOSE 206 AC Close */ - SDL_SCANCODE_UNKNOWN, /* KEY_PLAY 207 */ - SDL_SCANCODE_UNKNOWN, /* KEY_FASTFORWARD 208 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BASSBOOST 209 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PRINT 210 AC Print */ - SDL_SCANCODE_UNKNOWN, /* KEY_HP 211 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CAMERA 212 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SOUND 213 */ - SDL_SCANCODE_UNKNOWN, /* KEY_QUESTION 214 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EMAIL 215 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CHAT 216 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SEARCH 217 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CONNECT 218 */ - SDL_SCANCODE_UNKNOWN, /* KEY_FINANCE 219 AL Checkbook/Finance */ - SDL_SCANCODE_UNKNOWN, /* KEY_SPORT 220 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SHOP 221 */ - SDL_SCANCODE_UNKNOWN, /* KEY_ALTERASE 222 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CANCEL 223 AC Cancel */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSDOWN 224 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSUP 225 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MEDIA 226 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMTOGGLE 228 */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMDOWN 229 */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMUP 230 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SEND 231 AC Send */ - SDL_SCANCODE_UNKNOWN, /* KEY_REPLY 232 AC Reply */ - SDL_SCANCODE_UNKNOWN, /* KEY_FORWARDMAIL 233 AC Forward Msg */ - SDL_SCANCODE_UNKNOWN, /* KEY_SAVE 234 AC Save */ - SDL_SCANCODE_UNKNOWN, /* KEY_DOCUMENTS 235 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BATTERY 236 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BLUETOOTH 237 */ - SDL_SCANCODE_UNKNOWN, /* KEY_WLAN 238 */ - SDL_SCANCODE_UNKNOWN, /* KEY_UWB 239 */ - SDL_SCANCODE_UNKNOWN, /* KEY_UNKNOWN 240 */ - SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_NEXT 241 drive next video source */ - SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_PREV 242 drive previous video source */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_CYCLE 243 brightness up, after max is min */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */ - SDL_SCANCODE_UNKNOWN, /* KEY_DISPLAY_OFF 245 display device to off state */ - SDL_SCANCODE_UNKNOWN, /* KEY_WIMAX 246 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RFKILL 247 Key that controls all radios */ - SDL_SCANCODE_UNKNOWN /* KEY_MICMUTE 248 Mute / unmute the microphone */ -}}; - -std::uint16_t convert_sdl_scancode_to_evdev(const SDL_Scancode &scan_code) { - for (std::uint16_t n = 0; n < kKeycodes.size(); n++) { - if (kKeycodes[n] == scan_code) - return n; - } - return KEY_RESERVED; -} +constexpr const char* default_window_name{"anbox"}; } namespace anbox { namespace ubuntu { -Window::Window(const std::shared_ptr &input_manager, - int width, int height) : +Window::Id Window::Invalid{-1}; + +Window::Observer::~Observer() { +} + +Window::Window(const Id &id, + const wm::Task::Id &task, + const std::shared_ptr &observer, + const graphics::Rect &frame) : + wm::Window(task, frame), + id_(id), + observer_(observer), native_display_(0), native_window_(0) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - window_ = SDL_CreateWindow("anbox", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - width, - height, - SDL_WINDOW_OPENGL); + window_ = SDL_CreateWindow(default_window_name, + frame.left(), + frame.top(), + frame.width(), + frame.height(), + SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); if (!window_) { const auto message = utils::string_format("Failed to create window: %s", SDL_GetError()); BOOST_THROW_EXCEPTION(std::runtime_error(message)); } - SDL_SysWMinfo info; SDL_VERSION(&info.version); SDL_GetWindowWMInfo(window_, &info); switch (info.subsystem) { case SDL_SYSWM_X11: - DEBUG("Running on X11"); native_display_ = static_cast(info.info.x11.display); native_window_ = static_cast(info.info.x11.window); break; @@ -363,136 +71,58 @@ Window::Window(const std::shared_ptr &input_manager, } int actual_width = 0, actual_height = 0; + int actual_x = 0, actual_y = 0; SDL_GetWindowSize(window_, &actual_width, &actual_height); - - DEBUG("Window created with %d x %d", actual_width, actual_height); - - // Create our touch panel input device - touchpanel_ = input_manager->create_device(); - touchpanel_->set_name("anbox-touchpanel"); - touchpanel_->set_driver_version(1); - touchpanel_->set_input_id({ BUS_VIRTUAL, 1, 1, 1 }); - touchpanel_->set_physical_location("none"); - touchpanel_->set_abs_bit(ABS_MT_TRACKING_ID); - touchpanel_->set_abs_bit(ABS_MT_SLOT); - touchpanel_->set_abs_bit(ABS_MT_POSITION_X); - touchpanel_->set_abs_bit(ABS_MT_POSITION_Y); - touchpanel_->set_prop_bit(INPUT_PROP_DIRECT); - touchpanel_->set_abs_min(ABS_MT_POSITION_X, 0); - touchpanel_->set_abs_max(ABS_MT_POSITION_X, static_cast(actual_width)); - touchpanel_->set_abs_min(ABS_MT_POSITION_Y, 0); - touchpanel_->set_abs_max(ABS_MT_POSITION_Y, static_cast(actual_height)); - touchpanel_->set_abs_max(ABS_MT_SLOT, 10); - touchpanel_->set_abs_max(ABS_MT_TRACKING_ID, 255); - - pointer_ = input_manager->create_device(); - pointer_->set_name("anbox-pointer"); - pointer_->set_driver_version(1); - pointer_->set_input_id({ BUS_VIRTUAL, 2, 2, 2 }); - pointer_->set_physical_location("none"); - pointer_->set_key_bit(BTN_MOUSE); - // NOTE: We don't use REL_X/REL_Y in reality but have to specify them here - // to allow InputFlinger to detect we're a cursor device. - pointer_->set_rel_bit(REL_X); - pointer_->set_rel_bit(REL_Y); - pointer_->set_rel_bit(REL_HWHEEL); - pointer_->set_rel_bit(REL_WHEEL); - pointer_->set_prop_bit(INPUT_PROP_POINTER); - - keyboard_ = input_manager->create_device(); - keyboard_->set_name("anbox-keyboard"); - keyboard_->set_driver_version(1); - keyboard_->set_input_id({ BUS_VIRTUAL, 3, 3, 3 }); - keyboard_->set_physical_location("none"); - keyboard_->set_key_bit(BTN_MISC); - keyboard_->set_key_bit(KEY_OK); + SDL_GetWindowPosition(window_, &actual_x, &actual_y); } Window::~Window() { + if (window_) + SDL_DestroyWindow(window_); + + if (observer_) + observer_->window_deleted(id_); } -void Window::process_input_event(const SDL_Event &event) { - static SlotFingerMapper mapper; - std::vector touch_events; - std::vector mouse_events; - std::vector keyboard_events; - - const auto id = event.tfinger.fingerId; - const auto slot = mapper.find_or_create(id); - - switch (event.type) { - case SDL_FINGERUP: - touch_events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); - touch_events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, -1 }); - touch_events.push_back({ EV_KEY, BTN_TOUCH, 0 }); - touch_events.push_back({ EV_KEY, BTN_TOOL_FINGER, 0 }); - touch_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - mapper.erase(id); - break; - case SDL_FINGERDOWN: - touch_events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); - touch_events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, static_cast(id) }); - touch_events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast(event.tfinger.x) }); - touch_events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast(event.tfinger.y) }); - touch_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - break; - case SDL_FINGERMOTION: - touch_events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); - touch_events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, static_cast(id) }); - touch_events.push_back({ EV_KEY, BTN_TOUCH, 1 }); - touch_events.push_back({ EV_KEY, BTN_TOOL_FINGER, 1 }); - touch_events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast(event.tfinger.x) }); - touch_events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast(event.tfinger.y) }); - touch_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - break; - case SDL_MOUSEBUTTONDOWN: - mouse_events.push_back({ EV_KEY, BTN_LEFT, 1 }); - mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - break; - case SDL_MOUSEBUTTONUP: - mouse_events.push_back({ EV_KEY, BTN_LEFT, 0 }); - mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - break; - case SDL_MOUSEMOTION: - // NOTE: Sending relative move events doesn't really work and we have changes - // in libinputflinger to take ABS_X/ABS_Y instead for absolute position events. - mouse_events.push_back({ EV_ABS, ABS_X, static_cast(event.motion.x) }); - mouse_events.push_back({ EV_ABS, ABS_Y, static_cast(event.motion.y) }); - mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 }); - break; - case SDL_MOUSEWHEEL: - mouse_events.push_back({ EV_REL, REL_WHEEL, static_cast(event.wheel.y) }); - break; - case SDL_KEYDOWN: { - const auto code = convert_sdl_scancode_to_evdev(event.key.keysym.scancode); - if (code == KEY_RESERVED) - break; - keyboard_events.push_back({ EV_KEY, code, 1 }); - break; - } - case SDL_KEYUP: { - const auto code = convert_sdl_scancode_to_evdev(event.key.keysym.scancode); - if (code == KEY_RESERVED) - break; - keyboard_events.push_back({ EV_KEY, code, 0 }); - break; - } - default: - break; - } - - if (touch_events.size() > 0) - touchpanel_->send_events(touch_events); - - if (mouse_events.size() > 0) - pointer_->send_events(mouse_events); - - if (keyboard_events.size() > 0) - keyboard_->send_events(keyboard_events); +void Window::resize(int width, int height) { + SDL_SetWindowSize(window_, width, height); } -EGLNativeWindowType Window::native_window() const { +void Window::update_position(int x, int y) { + SDL_SetWindowPosition(window_, x, y); +} + +void Window::process_event(const SDL_Event &event) { + switch (event.window.event) { + case SDL_WINDOWEVENT_FOCUS_GAINED: + if (observer_) + observer_->window_wants_focus(id_); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + break; + case SDL_WINDOWEVENT_RESIZED: + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + break; + case SDL_WINDOWEVENT_MOVED: + break; + case SDL_WINDOWEVENT_SHOWN: + break; + case SDL_WINDOWEVENT_HIDDEN: + break; + } +} + +EGLNativeWindowType Window::native_handle() const { return native_window_; } + +Window::Id Window::id() const { + return id_; +} + +std::uint32_t Window::window_id() const { + return SDL_GetWindowID(window_); +} } // namespace bridge } // namespace anbox diff --git a/src/anbox/ubuntu/window.h b/src/anbox/ubuntu/window.h index 64782e7..a2fb444 100644 --- a/src/anbox/ubuntu/window.h +++ b/src/anbox/ubuntu/window.h @@ -18,6 +18,8 @@ #ifndef ANBOX_UBUNTU_WINDOW_H_ #define ANBOX_UBUNTU_WINDOW_H_ +#include "anbox/wm/window.h" + #include #include @@ -26,26 +28,36 @@ #include namespace anbox { -namespace input { -class Manager; -class Device; -class Event; -} // namespace input namespace ubuntu { -class Window { +class Window : public std::enable_shared_from_this, + public wm::Window { public: - Window(const std::shared_ptr &input_manager, - int width, int height); + typedef std::int32_t Id; + static Id Invalid; + + class Observer { + public: + virtual ~Observer(); + virtual void window_deleted(const Id &id) = 0; + virtual void window_wants_focus(const Id &id) = 0; + }; + + Window(const Id &id, const wm::Task::Id &task, const std::shared_ptr &observer, const graphics::Rect &frame); ~Window(); - void process_input_event(const SDL_Event &event); + void process_event(const SDL_Event &event); - EGLNativeWindowType native_window() const; + EGLNativeWindowType native_handle() const override; + Id id() const; + std::uint32_t window_id() const; + +protected: + void resize(int width, int height) override; + void update_position(int x, int y) override; private: - std::shared_ptr touchpanel_; - std::shared_ptr pointer_; - std::shared_ptr keyboard_; + Id id_; + std::shared_ptr observer_; EGLNativeDisplayType native_display_; EGLNativeWindowType native_window_; SDL_Window *window_; diff --git a/src/anbox/ubuntu/window_creator.cpp b/src/anbox/ubuntu/window_creator.cpp deleted file mode 100644 index 6e05691..0000000 --- a/src/anbox/ubuntu/window_creator.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2016 Simon Fels - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - */ - -#include "anbox/ubuntu/window_creator.h" -#include "anbox/ubuntu/window.h" -#include "anbox/logger.h" - -#include - -#include -#include - -namespace anbox { -namespace ubuntu { -WindowCreator::WindowCreator(const std::shared_ptr &input_manager) : - graphics::WindowCreator(input_manager), - input_manager_(input_manager), - event_thread_running_(false), - display_info_({1920, 1080}) { - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) - BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize SDL")); - - event_thread_ = std::thread(&WindowCreator::process_events, this); - - SDL_DisplayMode display_mode; - // FIXME statically just check the first (primary) display for its mode; - // once we get multi-monitor support we need to do this better. - if (SDL_GetCurrentDisplayMode(0, &display_mode) == 0) { - display_info_.horizontal_resolution = display_mode.w; - display_info_.vertical_resolution = display_mode.h; - } -} - -WindowCreator::~WindowCreator() { - event_thread_running_ = false; - event_thread_.join(); -} - -void WindowCreator::process_window_event(const SDL_Event &event) { -} - -void WindowCreator::process_events() { - event_thread_running_ = true; - - while(event_thread_running_) { - SDL_Event event; - while (SDL_WaitEventTimeout(&event, 100)) { - switch (event.type) { - case SDL_QUIT: - // This is the best way to reliable terminate the whole application for now. It will - // trigger a correct shutdown in the main part. - ::kill(getpid(), SIGTERM); - break; - case SDL_WINDOWEVENT: - process_window_event(event); - break; - case SDL_FINGERUP: - case SDL_FINGERMOTION: - case SDL_FINGERDOWN: - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEWHEEL: - case SDL_KEYDOWN: - case SDL_KEYUP: - if (current_window_) - current_window_->process_input_event(event); - break; - } - } - } -} - -EGLNativeWindowType WindowCreator::create_window(int x, int y, int width, int height) -try { - if (windows_.size() == 1) { - WARNING("Tried to create another window but we currently only allow one"); - return 0; - } - - auto window = std::make_shared(input_manager_, width, height); - if (not window) - BOOST_THROW_EXCEPTION(std::bad_alloc()); - - windows_.insert({window->native_window(), window}); - current_window_ = window; - - return window->native_window(); -} -catch (std::exception &err) { - DEBUG("Failed to create window: %s", err.what()); - return 0; -} - -void WindowCreator::destroy_window(EGLNativeWindowType win) { - auto iter = windows_.find(win); - if (iter == windows_.end()) - return; - - windows_.erase(iter); -} - -WindowCreator::DisplayInfo WindowCreator::display_info() const { - return display_info_; -} - -EGLNativeDisplayType WindowCreator::native_display() const { - return 0; -} -} // namespace bridge -} // namespace anbox diff --git a/src/anbox/ubuntu/window_creator.h b/src/anbox/ubuntu/window_creator.h deleted file mode 100644 index cef70c4..0000000 --- a/src/anbox/ubuntu/window_creator.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2016 Simon Fels - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranties of - * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - */ - -#ifndef ANBOX_UBUNTU_WINDOW_CREATOR_H_ -#define ANBOX_UBUNTU_WINDOW_CREATOR_H_ - -#include "anbox/graphics/window_creator.h" - -#include -#include - -#include -#include - -namespace anbox { -namespace ubuntu { -class MirDisplayConnection; -class Window; -class WindowCreator : public graphics::WindowCreator { -public: - WindowCreator(const std::shared_ptr &input_manager); - ~WindowCreator(); - - EGLNativeWindowType create_window(int x, int y, int width, int height) override; - void destroy_window(EGLNativeWindowType win) override; - - DisplayInfo display_info() const override; - EGLNativeDisplayType native_display() const override; - -private: - void process_events(); - void process_window_event(const SDL_Event &event); - - std::shared_ptr input_manager_; - std::map> windows_; - std::shared_ptr current_window_; - std::thread event_thread_; - bool event_thread_running_; - graphics::WindowCreator::DisplayInfo display_info_; -}; -} // namespace bridge -} // namespace anbox - -#endif diff --git a/src/anbox/wm/default_platform_policy.cpp b/src/anbox/wm/default_platform_policy.cpp new file mode 100644 index 0000000..0dce9e8 --- /dev/null +++ b/src/anbox/wm/default_platform_policy.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/default_platform_policy.h" +#include "anbox/wm/window.h" +#include "anbox/logger.h" + +namespace { +class NullWindow : public anbox::wm::Window { +public: + NullWindow(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) : + anbox::wm::Window(0, frame) { + } + +protected: + void resize(int width, int height) override { + WARNING("Not implemented"); + } + + void update_position(int x, int y) override { + WARNING("Not implemented"); + } +}; +} + +namespace anbox { +namespace wm { +DefaultPlatformPolicy::DefaultPlatformPolicy() { +} + +std::shared_ptr DefaultPlatformPolicy::create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) +{ + DEBUG(""); + return std::make_shared<::NullWindow>(task, frame); +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/default_platform_policy.h b/src/anbox/wm/default_platform_policy.h new file mode 100644 index 0000000..9476050 --- /dev/null +++ b/src/anbox/wm/default_platform_policy.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_DEFAULT_PLATFORM_POLICY_H_ +#define ANBOX_WM_DEFAULT_PLATFORM_POLICY_H_ + +#include "anbox/wm/platform_policy.h" + +namespace anbox { +namespace wm { +class DefaultPlatformPolicy : public PlatformPolicy { +public: + DefaultPlatformPolicy(); + std::shared_ptr create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) override; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/display.cpp b/src/anbox/wm/display.cpp new file mode 100644 index 0000000..671a166 --- /dev/null +++ b/src/anbox/wm/display.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/display.h" + +namespace anbox { +namespace wm { +Display::Id Display::Invalid = -1; +Display::Id Display::Default = 0; +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/display.h b/src/anbox/wm/display.h new file mode 100644 index 0000000..6b53baf --- /dev/null +++ b/src/anbox/wm/display.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_DISPLAY_H_ +#define ANBOX_WM_DISPLAY_H_ + +#include + +namespace anbox { +namespace wm { +class Display { +public: + typedef std::int32_t Id; + + static Id Invalid; + static Id Default; + + Display() = delete; + Display(const Display&) = delete; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/manager.cpp b/src/anbox/wm/manager.cpp new file mode 100644 index 0000000..67c7a24 --- /dev/null +++ b/src/anbox/wm/manager.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/manager.h" +#include "anbox/wm/platform_policy.h" +#include "anbox/logger.h" + +#include + +namespace anbox { +namespace wm { +Manager::Manager(const std::shared_ptr &platform) : + platform_(platform) { +} + +Manager::~Manager() { +} + +void Manager::apply_window_state_update(const WindowState::List &updated, + const WindowState::List &removed) +{ + std::lock_guard l(mutex_); + + // Base on the update we get from the Android WindowManagerService we will create + // different window instances with the properties supplied. Incoming layer updates + // from SurfaceFlinger will be mapped later into those windows and eventually + // composited there via GLES (e.g. for popups, ..) + + std::map task_updates; + + for (const auto &window : updated) + { + // Ignore all windows which are not part of the freeform task stack + if (window.stack() != Stack::Freeform) + continue; + + // And also those which don't have a surface mapped at the moment + if (!window.has_surface()) + continue; + + // If we know that task already we first collect all window updates + // for it so we can apply all of them together. + auto w = windows_.find(window.task()); + if (w != windows_.end()) + { + auto t = task_updates.find(window.task()); + if (t == task_updates.end()) + task_updates.insert({window.task(), {window}}); + else + task_updates[window.task()].push_back(window); + continue; + } + + auto platform_window = platform_->create_window(window.task(), window.frame()); + platform_window->attach(); + windows_.insert({window.task(), platform_window}); + } + + // Send updates we collected per task down to the corresponding window + // so that they can update themself. + for (const auto &u : task_updates) + { + auto w = windows_.find(u.first); + if (w == windows_.end()) + continue; + + w->second->update_state(u.second); + } + + // As final step we process all windows we need to remove as they + // got killed on the other side. We need to respect here that we + // also get removals for windows which are part of a task which is + // still in use by other windows. + for (const auto &window : removed) + { + auto w = windows_.find(window.task()); + if (w == windows_.end()) + continue; + + if (task_updates.find(window.task()) == task_updates.end()) + { + auto platform_window = w->second; + platform_window->release(); + windows_.erase(w); + } + } +} + +std::shared_ptr Manager::find_window_for_task(const Task::Id &task) +{ + std::lock_guard l(mutex_); + for (const auto &w : windows_) + { + if (w.second->task() == task) + return w.second; + } + return nullptr; +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h new file mode 100644 index 0000000..aa4eede --- /dev/null +++ b/src/anbox/wm/manager.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_MANAGER_H_ +#define ANBOX_WM_MANAGER_H_ + +#include "anbox/wm/window_state.h" +#include "anbox/wm/window.h" + +#include +#include +#include + +namespace anbox { +namespace wm { +class PlatformPolicy; +class Manager { +public: + Manager(const std::shared_ptr &platform); + ~Manager(); + + void apply_window_state_update(const WindowState::List &updated, + const WindowState::List &removed); + + std::shared_ptr find_window_for_task(const Task::Id &task); + +private: + std::mutex mutex_; + std::shared_ptr platform_; + std::map> windows_; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/android/app_manager/src/org/anbox/app_manager/IAppManager.aidl b/src/anbox/wm/platform_policy.cpp similarity index 82% rename from android/app_manager/src/org/anbox/app_manager/IAppManager.aidl rename to src/anbox/wm/platform_policy.cpp index 04fd299..922acf5 100644 --- a/android/app_manager/src/org/anbox/app_manager/IAppManager.aidl +++ b/src/anbox/wm/platform_policy.cpp @@ -15,8 +15,11 @@ * */ -package org.anbox.app_manager; +#include "anbox/wm/platform_policy.h" -interface IAppManager { - void launch(string name); +namespace anbox { +namespace wm { +PlatformPolicy::~PlatformPolicy() { } +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/platform_policy.h b/src/anbox/wm/platform_policy.h new file mode 100644 index 0000000..f9261e3 --- /dev/null +++ b/src/anbox/wm/platform_policy.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_PLATFORM_POLICY_H_ +#define ANBOX_WM_PLATFORM_POLICY_H_ + +#include "anbox/graphics/rect.h" +#include "anbox/wm/window_state.h" + +#include + +namespace anbox { +namespace wm { +class Window; +class PlatformPolicy { +public: + virtual ~PlatformPolicy(); + + virtual std::shared_ptr create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) = 0; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/stack.cpp b/src/anbox/wm/stack.cpp new file mode 100644 index 0000000..99af33f --- /dev/null +++ b/src/anbox/wm/stack.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/stack.h" + +namespace anbox { +namespace wm { +Stack::Id Stack::Invalid = -1; +Stack::Id Stack::Default = 0; +Stack::Id Stack::Fullscreen = 1; +Stack::Id Stack::Freeform = 2; +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/stack.h b/src/anbox/wm/stack.h new file mode 100644 index 0000000..ea15985 --- /dev/null +++ b/src/anbox/wm/stack.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_STACK_H_ +#define ANBOX_WM_STACK_H_ + +#include + +namespace anbox { +namespace wm { +class Stack { +public: + typedef std::int32_t Id; + + static Id Invalid; + static Id Default; + static Id Fullscreen; + static Id Freeform; + + Stack() = delete; + Stack(const Stack&) = delete; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/android/app_manager/src/org/anbox/app_manager/AppManagerService.java b/src/anbox/wm/task.cpp similarity index 84% rename from android/app_manager/src/org/anbox/app_manager/AppManagerService.java rename to src/anbox/wm/task.cpp index df500dd..46cecee 100644 --- a/android/app_manager/src/org/anbox/app_manager/AppManagerService.java +++ b/src/anbox/wm/task.cpp @@ -15,7 +15,10 @@ * */ -package org.anbox.app_manager; +#include "anbox/wm/task.h" -public class AppManagerService { -} +namespace anbox { +namespace wm { +Task::Id Task::Invalid = -1; +} // namespace wm +} // namespace anbox diff --git a/src/anbox/graphics/window_creator.cpp b/src/anbox/wm/task.h similarity index 74% rename from src/anbox/graphics/window_creator.cpp rename to src/anbox/wm/task.h index f93d73d..fa7e8f7 100644 --- a/src/anbox/graphics/window_creator.cpp +++ b/src/anbox/wm/task.h @@ -15,16 +15,23 @@ * */ -#include "anbox/graphics/window_creator.h" +#ifndef ANBOX_WM_TASK_H_ +#define ANBOX_WM_TASK_H_ +#include namespace anbox { -namespace graphics { -WindowCreator::WindowCreator(const std::shared_ptr &input_manager) : - input_manager_(input_manager) { -} +namespace wm { +class Task { +public: + typedef std::int32_t Id; -WindowCreator::~WindowCreator() { -} -} // namespace graphics + static Id Invalid; + + Task() = delete; + Task(const Task&) = delete; +}; +} // namespace wm } // namespace anbox + +#endif diff --git a/src/anbox/wm/window.cpp b/src/anbox/wm/window.cpp new file mode 100644 index 0000000..03968fb --- /dev/null +++ b/src/anbox/wm/window.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/window.h" +#include "anbox/graphics/emugl/Renderer.h" +#include "anbox/logger.h" + +namespace anbox { +namespace wm { +Window::Window(const Task::Id &task, const graphics::Rect &frame) : + task_(task), + frame_(frame) { +} + +Window::~Window() { +} + +void Window::update_state(const WindowState::List &states) +{ +} + +void Window::update_frame(const graphics::Rect &frame) +{ + if (frame == frame_) + return; + + if (frame.width() != frame_.width() || frame.height() != frame_.height()) + resize(frame.width(), frame.height()); + + if (frame.top() != frame_.top() || frame.left() != frame_.left()) + update_position(frame.left(), frame.top()); + + frame_ = frame; +} + +Task::Id Window::task() const { + return task_; +} + +graphics::Rect Window::frame() const { + return frame_; +} + +EGLNativeWindowType Window::native_handle() const { + return 0; +} + +bool Window::attach() { + return Renderer::get()->createNativeWindow(native_handle()); +} + +void Window::release() { + Renderer::get()->destroyNativeWindow(native_handle()); +} +} // namespace wm +} // namespace anbox + diff --git a/src/anbox/wm/window.h b/src/anbox/wm/window.h new file mode 100644 index 0000000..687e90d --- /dev/null +++ b/src/anbox/wm/window.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_WINDOW_H_ +#define ANBOX_WM_WINDOW_H_ + +#include "anbox/wm/window_state.h" + +#include +#include + +#include + +namespace anbox { +namespace wm { +// FIXME(morphis): move this somewhere else once we have the integration +// with the emugl layer. +class Layer { +public: + graphics::Rect frame() const { return frame_; } + +private: + graphics::Rect frame_; +}; + +class Window +{ +public: + typedef std::vector List; + + Window(const Task::Id &task, const graphics::Rect &frame); + virtual ~Window(); + + bool attach(); + void release(); + + void update_state(const WindowState::List &states); + void update_frame(const graphics::Rect &frame); + + virtual EGLNativeWindowType native_handle() const; + graphics::Rect frame() const; + Task::Id task() const; + +protected: + virtual void resize(int width, int height) = 0; + virtual void update_position(int x, int y) = 0; + +private: + Task::Id task_; + graphics::Rect frame_; +}; +} // namespace wm +} // namespace anbox + +#endif diff --git a/src/anbox/wm/window_state.cpp b/src/anbox/wm/window_state.cpp new file mode 100644 index 0000000..7067da6 --- /dev/null +++ b/src/anbox/wm/window_state.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/wm/window_state.h" + +namespace anbox { +namespace wm { +WindowState::WindowState() : + display_(Display::Invalid), + has_surface_(false), + frame_(graphics::Rect::Invalid), + package_name_(""), + task_(Task::Invalid), + stack_(Stack::Invalid) { +} + +WindowState::WindowState(const Display::Id &display, + bool has_surface, + const graphics::Rect &frame, + const std::string &package_name, + const Task::Id &task, + const Stack::Id &stack) : + display_(display), + has_surface_(has_surface), + frame_(frame), + package_name_(package_name), + task_(task), + stack_(stack) { +} + +WindowState::~WindowState() { +} +} // namespace wm +} // namespace anbox diff --git a/src/anbox/wm/window_state.h b/src/anbox/wm/window_state.h new file mode 100644 index 0000000..603ed3a --- /dev/null +++ b/src/anbox/wm/window_state.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_WM_WINDOW_STATE_H_ +#define ANBOX_WM_WINDOW_STATE_H_ + +#include "anbox/graphics/rect.h" +#include "anbox/wm/display.h" +#include "anbox/wm/task.h" +#include "anbox/wm/stack.h" + +#include +#include + +namespace anbox { +namespace wm { +class WindowState { +public: + typedef std::vector List; + + WindowState(); + WindowState(const Display::Id &display, + bool has_surface, + const graphics::Rect &frame, + const std::string &package_name, + const Task::Id &task, + const Stack::Id &stack); + ~WindowState(); + + Display::Id display() const { return display_; } + bool has_surface() const { return has_surface_; } + graphics::Rect frame() const { return frame_; } + std::string package_name() const { return package_name_; } + Task::Id task() const { return task_; } + Stack::Id stack() const { return stack_; } + +private: + Display::Id display_; + bool has_surface_; + graphics::Rect frame_; + std::string package_name_; + Task::Id task_; + Stack::Id stack_; + +}; +} // namespace wm +} // namespace anbox + +#endif