Merge pull request #1 from morphis/multi-window
First attempt on multi window support
This commit is contained in:
commit
5660b308a6
135 changed files with 3271 additions and 2816 deletions
12
Android.mk
12
Android.mk
|
|
@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \
|
||||||
android/service/host_connector.cpp \
|
android/service/host_connector.cpp \
|
||||||
android/service/local_socket_connection.cpp \
|
android/service/local_socket_connection.cpp \
|
||||||
android/service/message_processor.cpp \
|
android/service/message_processor.cpp \
|
||||||
|
android/service/activity_manager_interface.cpp \
|
||||||
android/service/android_api_skeleton.cpp \
|
android/service/android_api_skeleton.cpp \
|
||||||
android/service/platform_service_interface.cpp \
|
android/service/platform_service_interface.cpp \
|
||||||
android/service/platform_service.cpp \
|
android/service/platform_service.cpp \
|
||||||
|
|
@ -59,6 +60,15 @@ LOCAL_SHARED_LIBRARIES := \
|
||||||
LOCAL_CFLAGS := \
|
LOCAL_CFLAGS := \
|
||||||
-fexceptions \
|
-fexceptions \
|
||||||
-std=c++1y
|
-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 $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
@ -97,5 +107,3 @@ include $(BUILD_SHARED_LIBRARY)
|
||||||
# Include the Android.mk files below will override LOCAL_PATH so we
|
# Include the Android.mk files below will override LOCAL_PATH so we
|
||||||
# have to take a copy of it here.
|
# have to take a copy of it here.
|
||||||
TMP_PATH := $(LOCAL_PATH)
|
TMP_PATH := $(LOCAL_PATH)
|
||||||
|
|
||||||
include $(TMP_PATH)/android/app_manager/Android.mk
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ set(ANBOXD_SOURCES
|
||||||
${CMAKE_SOURCE_DIR}/src/anbox/rpc/message_processor.cpp
|
${CMAKE_SOURCE_DIR}/src/anbox/rpc/message_processor.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/anbox/rpc/pending_call_cache.cpp
|
${CMAKE_SOURCE_DIR}/src/anbox/rpc/pending_call_cache.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp
|
${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp
|
||||||
|
service/activity_manager_interface.cpp
|
||||||
service/platform_service.cpp
|
service/platform_service.cpp
|
||||||
service/platform_service_interface.cpp
|
service/platform_service_interface.cpp
|
||||||
service/platform_api_stub.cpp
|
service/platform_api_stub.cpp
|
||||||
|
|
|
||||||
6
android/app_manager/.idea/vcs.xml
generated
6
android/app_manager/.idea/vcs.xml
generated
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="org.anbox.app_manager">
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:name=".MainApplication">
|
|
||||||
<service
|
|
||||||
android:name=".AppManagerService"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="true">
|
|
||||||
</service>
|
|
||||||
</application>
|
|
||||||
</manifest>
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<resources>
|
|
||||||
<string name="app_name">Anbox Application Manager</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -18,7 +18,12 @@
|
||||||
#include <hardware/hardware.h>
|
#include <hardware/hardware.h>
|
||||||
#include <hardware/hwcomposer.h>
|
#include <hardware/hwcomposer.h>
|
||||||
|
|
||||||
#define LOG_NDEBUG 0
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define LOG_NDEBUG 1
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
|
|
||||||
#include "HostConnection.h"
|
#include "HostConnection.h"
|
||||||
|
|
@ -67,8 +72,8 @@ struct HwcContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dump_layer(hwc_layer_1_t const* l) {
|
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}",
|
ALOGD("\tname='%s', type=%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,
|
l->name, l->compositionType, l->flags, l->handle, l->transform, l->blending,
|
||||||
l->sourceCrop.left,
|
l->sourceCrop.left,
|
||||||
l->sourceCrop.top,
|
l->sourceCrop.top,
|
||||||
l->sourceCrop.right,
|
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) {
|
hwc_display_contents_1_t** displays) {
|
||||||
auto context = reinterpret_cast<HwcContext*>(dev);
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
if (displays == NULL || displays[0] == NULL)
|
if (displays == NULL || displays[0] == NULL)
|
||||||
return -EINVAL;
|
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++) {
|
for (; i < num_hw_layers; i++) {
|
||||||
hwc_layer_1_t* layer = &displays[0]->hwLayers[num_hw_layers - 1 - i];
|
hwc_layer_1_t* layer = &displays[0]->hwLayers[num_hw_layers - 1 - i];
|
||||||
|
|
||||||
|
#if 0
|
||||||
dump_layer(layer);
|
dump_layer(layer);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (layer->flags & HWC_SKIP_LAYER) {
|
if (layer->flags & HWC_SKIP_LAYER) {
|
||||||
// All layers below and including this one will be drawn into the
|
// 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) {
|
hwc_display_contents_1_t** displays) {
|
||||||
auto context = reinterpret_cast<HwcContext*>(dev);
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
if (displays == NULL || displays[0] == NULL)
|
if (displays == NULL || displays[0] == NULL)
|
||||||
return -EFAULT;
|
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++) {
|
for (size_t i = 0 ; i < displays[0]->numHwLayers ; i++) {
|
||||||
const auto layer = &displays[0]->hwLayers[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);
|
dump_layer(layer);
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME this is just dirty ... but layer->handle is a const native_handle_t and canBePosted
|
// FIXME this is just dirty ... but layer->handle is a const native_handle_t and canBePosted
|
||||||
// can't be called with a const.
|
// 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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALOGI("Posting buffer %p\n", cb->hostHandle);
|
rcEnc->rcPostLayer(rcEnc,
|
||||||
rcEnc->rcFBPost(rcEnc, cb->hostHandle);
|
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();
|
hostCon->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rcEnc->rcPostAllLayersDone(rcEnc);
|
||||||
|
|
||||||
check_sync_fds(numDisplays, displays);
|
check_sync_fds(numDisplays, displays);
|
||||||
|
|
||||||
return 0;
|
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,
|
static int hwc_event_control(hwc_composer_device_1* dev, int disp,
|
||||||
int event, int enabled) {
|
int event, int enabled) {
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hwc_register_procs(hwc_composer_device_1* dev,
|
static void hwc_register_procs(hwc_composer_device_1* dev,
|
||||||
hwc_procs_t const* procs) {
|
hwc_procs_t const* procs) {
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hwc_blank(hwc_composer_device_1* dev, int disp, int blank) {
|
static int hwc_blank(hwc_composer_device_1* dev, int disp, int blank) {
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hwc_query(hwc_composer_device_1* dev, int what, int* value) {
|
static int hwc_query(hwc_composer_device_1* dev, int what, int* value) {
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hwc_device_close(hw_device_t* dev) {
|
static int hwc_device_close(hw_device_t* dev) {
|
||||||
ALOGI("%s", __PRETTY_FUNCTION__);
|
|
||||||
auto context = reinterpret_cast<HwcContext*>(dev);
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
delete context;
|
delete context;
|
||||||
return 0;
|
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) {
|
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)
|
if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0)
|
||||||
return -EINVAL;
|
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.eventControl = hwc_event_control;
|
||||||
dev->device.blank = hwc_blank;
|
dev->device.blank = hwc_blank;
|
||||||
dev->device.query = hwc_query;
|
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;
|
dev->device.registerProcs = hwc_register_procs;
|
||||||
// FIXME: eventually implement to dump specific information
|
|
||||||
dev->device.dump = nullptr;
|
|
||||||
|
|
||||||
*device = &dev->device.common;
|
*device = &dev->device.common;
|
||||||
|
|
||||||
|
|
|
||||||
35
android/service/activity_manager_interface.cpp
Normal file
35
android/service/activity_manager_interface.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "Anboxd"
|
||||||
|
|
||||||
|
#include "android/service/activity_manager_interface.h"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
BpActivityManager::BpActivityManager(const sp<IBinder> &binder) :
|
||||||
|
BpInterface<IActivityManager>(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
|
||||||
50
android/service/activity_manager_interface.h
Normal file
50
android/service/activity_manager_interface.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_
|
||||||
|
#define ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <binder/IBinder.h>
|
||||||
|
#include <binder/IInterface.h>
|
||||||
|
#include <binder/Parcel.h>
|
||||||
|
|
||||||
|
#include <utils/String16.h>
|
||||||
|
#include <utils/StrongPointer.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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<IActivityManager> {
|
||||||
|
public:
|
||||||
|
BpActivityManager(const sp<IBinder> &binder);
|
||||||
|
|
||||||
|
status_t setFocusedTask(int32_t id) override;
|
||||||
|
};
|
||||||
|
} // namespace android
|
||||||
|
#endif
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "Anboxd"
|
||||||
|
|
||||||
#include "android/service/android_api_skeleton.h"
|
#include "android/service/android_api_skeleton.h"
|
||||||
|
|
||||||
#include "anbox_rpc.pb.h"
|
#include "anbox_rpc.pb.h"
|
||||||
|
|
@ -23,6 +25,8 @@
|
||||||
#include <core/posix/exec.h>
|
#include <core/posix/exec.h>
|
||||||
#include <core/posix/child_process.h>
|
#include <core/posix/child_process.h>
|
||||||
|
|
||||||
|
#include <binder/IServiceManager.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::map<std::string,std::string> common_env = {
|
std::map<std::string,std::string> common_env = {
|
||||||
{"ANDROID_DATA", "/data"},
|
{"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,
|
void AndroidApiSkeleton::install_application(anbox::protobuf::bridge::InstallApplication const *request,
|
||||||
anbox::protobuf::rpc::Void *response,
|
anbox::protobuf::rpc::Void *response,
|
||||||
google::protobuf::Closure *done) {
|
google::protobuf::Closure *done) {
|
||||||
|
|
@ -106,4 +118,19 @@ void AndroidApiSkeleton::set_dns_servers(anbox::protobuf::bridge::SetDnsServers
|
||||||
|
|
||||||
done->Run();
|
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
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
#ifndef ANBOX_PLATFORM_API_SKELETON_H_
|
#ifndef ANBOX_PLATFORM_API_SKELETON_H_
|
||||||
#define ANBOX_PLATFORM_API_SKELETON_H_
|
#define ANBOX_PLATFORM_API_SKELETON_H_
|
||||||
|
|
||||||
|
#include "android/service/activity_manager_interface.h"
|
||||||
|
|
||||||
namespace google {
|
namespace google {
|
||||||
namespace protobuf {
|
namespace protobuf {
|
||||||
class Closure;
|
class Closure;
|
||||||
|
|
@ -36,6 +38,7 @@ namespace bridge {
|
||||||
class InstallApplication;
|
class InstallApplication;
|
||||||
class LaunchApplication;
|
class LaunchApplication;
|
||||||
class SetDnsServers;
|
class SetDnsServers;
|
||||||
|
class SetFocusedTask;
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
namespace rpc {
|
namespace rpc {
|
||||||
class Void;
|
class Void;
|
||||||
|
|
@ -58,9 +61,17 @@ public:
|
||||||
anbox::protobuf::rpc::Void *response,
|
anbox::protobuf::rpc::Void *response,
|
||||||
google::protobuf::Closure *done);
|
google::protobuf::Closure *done);
|
||||||
|
|
||||||
|
void set_focused_task(anbox::protobuf::bridge::SetFocusedTask const *request,
|
||||||
|
anbox::protobuf::rpc::Void *response,
|
||||||
|
google::protobuf::Closure *done);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void wait_for_process(core::posix::ChildProcess &process,
|
void wait_for_process(core::posix::ChildProcess &process,
|
||||||
anbox::protobuf::rpc::Void *response);
|
anbox::protobuf::rpc::Void *response);
|
||||||
|
|
||||||
|
void connect_services();
|
||||||
|
|
||||||
|
android::sp<android::BpActivityManager> activity_manager_;
|
||||||
};
|
};
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define LOG_TAG "Anbox"
|
#define LOG_TAG "Anboxd"
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ void MessageProcessor::dispatch(rpc::Invocation const& invocation) {
|
||||||
invoke(this, platform_api_.get(), &AndroidApiSkeleton::launch_application, invocation);
|
invoke(this, platform_api_.get(), &AndroidApiSkeleton::launch_application, invocation);
|
||||||
else if (invocation.method_name() == "set_dns_servers")
|
else if (invocation.method_name() == "set_dns_servers")
|
||||||
invoke(this, platform_api_.get(), &AndroidApiSkeleton::set_dns_servers, invocation);
|
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&) {
|
void MessageProcessor::process_event_sequence(const std::string&) {
|
||||||
|
|
|
||||||
|
|
@ -21,38 +21,44 @@
|
||||||
#include "anbox_rpc.pb.h"
|
#include "anbox_rpc.pb.h"
|
||||||
#include "anbox_bridge.pb.h"
|
#include "anbox_bridge.pb.h"
|
||||||
|
|
||||||
#define LOG_TAG "Anbox"
|
|
||||||
#include <cutils/log.h>
|
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
PlatformApiStub::PlatformApiStub(const std::shared_ptr<rpc::Channel> &rpc_channel) :
|
PlatformApiStub::PlatformApiStub(const std::shared_ptr<rpc::Channel> &rpc_channel) :
|
||||||
rpc_channel_(rpc_channel) {
|
rpc_channel_(rpc_channel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformApiStub::boot_finished() {
|
void PlatformApiStub::boot_finished() {
|
||||||
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
|
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();
|
||||||
|
|
||||||
{
|
auto convert_window = [](WindowStateUpdate::Window in, anbox::protobuf::bridge::WindowStateUpdateEvent_WindowState *out) {
|
||||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
out->set_display_id(in.display_id);
|
||||||
boot_finished_wait_handle_.expect_result();
|
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(
|
rpc_channel_->send_event(seq);
|
||||||
"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<protobuf::rpc::Void>*) {
|
|
||||||
ALOGI("handle_boot_finished_response");
|
|
||||||
boot_finished_wait_handle_.result_received();
|
|
||||||
}
|
}
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@
|
||||||
#include "anbox/common/wait_handle.h"
|
#include "anbox/common/wait_handle.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace protobuf {
|
namespace protobuf {
|
||||||
|
|
@ -37,6 +39,27 @@ public:
|
||||||
|
|
||||||
void boot_finished();
|
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<Window> updated_windows;
|
||||||
|
std::vector<Window> removed_windows;
|
||||||
|
};
|
||||||
|
|
||||||
|
void update_window_state(const WindowStateUpdate &state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Response>
|
template<typename Response>
|
||||||
struct Request {
|
struct Request {
|
||||||
|
|
@ -45,10 +68,7 @@ private:
|
||||||
bool success;
|
bool success;
|
||||||
};
|
};
|
||||||
|
|
||||||
void handle_boot_finished_response(Request<protobuf::rpc::Void> *request);
|
|
||||||
|
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
common::WaitHandle boot_finished_wait_handle_;
|
|
||||||
|
|
||||||
std::shared_ptr<rpc::Channel> rpc_channel_;
|
std::shared_ptr<rpc::Channel> rpc_channel_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "android/service/platform_service.h"
|
#include "android/service/platform_service.h"
|
||||||
#include "android/service/platform_api_stub.h"
|
|
||||||
#include "anbox/rpc/channel.h"
|
#include "anbox/rpc/channel.h"
|
||||||
|
|
||||||
|
#include "anbox_rpc.pb.h"
|
||||||
|
#include "anbox_bridge.pb.h"
|
||||||
|
|
||||||
#define LOG_TAG "Anboxd"
|
#define LOG_TAG "Anboxd"
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
|
|
||||||
|
#include <utils/String8.h>
|
||||||
|
|
||||||
using namespace android;
|
using namespace android;
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
@ -33,4 +37,59 @@ status_t PlatformService::boot_finished() {
|
||||||
platform_api_stub_->boot_finished();
|
platform_api_stub_->boot_finished();
|
||||||
return OK;
|
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
|
} // namespace android
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,24 @@
|
||||||
#define ANBOX_ANDROID_PLATFORM_SERVICE_H_
|
#define ANBOX_ANDROID_PLATFORM_SERVICE_H_
|
||||||
|
|
||||||
#include "android/service/platform_service_interface.h"
|
#include "android/service/platform_service_interface.h"
|
||||||
|
#include "android/service/platform_api_stub.h"
|
||||||
|
|
||||||
|
#include <binder/Parcel.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace anbox {
|
|
||||||
class PlatformApiStub;
|
|
||||||
} // namespace anbox
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
class PlatformService : public BnPlatformService {
|
class PlatformService : public BnPlatformService {
|
||||||
public:
|
public:
|
||||||
static const char* service_name() { return "anbox.PlatformService"; }
|
static const char* service_name() { return "org.anbox.PlatformService"; }
|
||||||
|
|
||||||
PlatformService(const std::shared_ptr<anbox::PlatformApiStub> &platform_api_stub);
|
PlatformService(const std::shared_ptr<anbox::PlatformApiStub> &platform_api_stub);
|
||||||
|
|
||||||
status_t boot_finished() override;
|
status_t boot_finished() override;
|
||||||
|
status_t update_window_state(const Parcel &data) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
anbox::PlatformApiStub::WindowStateUpdate::Window unpack_window_state(const Parcel &data);
|
||||||
std::shared_ptr<anbox::PlatformApiStub> platform_api_stub_;
|
std::shared_ptr<anbox::PlatformApiStub> platform_api_stub_;
|
||||||
};
|
};
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,13 @@ status_t BpPlatformService::boot_finished() {
|
||||||
return remote()->transact(IPlatformService::BOOT_FINISHED, data, &reply);
|
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,
|
status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data,
|
||||||
Parcel *reply, uint32_t flags) {
|
Parcel *reply, uint32_t flags) {
|
||||||
|
|
@ -36,6 +42,9 @@ status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data,
|
||||||
case BOOT_FINISHED:
|
case BOOT_FINISHED:
|
||||||
CHECK_INTERFACE(IPlatformService, data, reply);
|
CHECK_INTERFACE(IPlatformService, data, reply);
|
||||||
return boot_finished();
|
return boot_finished();
|
||||||
|
case UPDATE_WINDOW_STATE:
|
||||||
|
CHECK_INTERFACE(IPlatformService, data, reply);
|
||||||
|
return update_window_state(data);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,13 @@ public:
|
||||||
DECLARE_META_INTERFACE(PlatformService);
|
DECLARE_META_INTERFACE(PlatformService);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
// Keep this synchronized with frameworks/base/services/java/com/android/server/wm/AnboxPlatformServiceProxy.java
|
||||||
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
|
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
|
||||||
|
UPDATE_WINDOW_STATE = IBinder::FIRST_CALL_TRANSACTION + 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual status_t boot_finished() = 0;
|
virtual status_t boot_finished() = 0;
|
||||||
|
virtual status_t update_window_state(const Parcel &data) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BpPlatformService : public BpInterface<IPlatformService> {
|
class BpPlatformService : public BpInterface<IPlatformService> {
|
||||||
|
|
@ -44,6 +47,7 @@ public:
|
||||||
BpPlatformService(const sp<IBinder> &binder);
|
BpPlatformService(const sp<IBinder> &binder);
|
||||||
|
|
||||||
status_t boot_finished() override;
|
status_t boot_finished() override;
|
||||||
|
status_t update_window_state(const Parcel &data) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BnPlatformService : public BnInterface<IPlatformService> {
|
class BnPlatformService : public BnInterface<IPlatformService> {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ typedef void (*emugl_crash_func_t)(const char* format, ...);
|
||||||
#define LIST_RENDER_API_FUNCTIONS(X) \
|
#define LIST_RENDER_API_FUNCTIONS(X) \
|
||||||
X(int, initLibrary, (), ()) \
|
X(int, initLibrary, (), ()) \
|
||||||
X(int, setStreamMode, (int mode), (mode)) \
|
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, getHardwareStrings, (const char** vendor, const char** renderer, const char** version), (vendor, renderer, version)) \
|
||||||
X(void, setPostCallback, (OnPostFn onPost, void* onPostContext), (onPost, onPostContext)) \
|
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)) \
|
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)) \
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
add_subdirectory(GLESv1_dec)
|
add_subdirectory(GLESv1_dec)
|
||||||
add_subdirectory(GLESv2_dec)
|
add_subdirectory(GLESv2_dec)
|
||||||
add_subdirectory(libOpenGLESDispatch)
|
add_subdirectory(libOpenGLESDispatch)
|
||||||
add_subdirectory(libOpenglRender)
|
|
||||||
add_subdirectory(renderControl_dec)
|
add_subdirectory(renderControl_dec)
|
||||||
add_subdirectory(Translator)
|
add_subdirectory(Translator)
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,12 @@
|
||||||
|
|
||||||
|
|
||||||
#define SET_ERROR_IF(condition,err) if((condition)) { \
|
#define SET_ERROR_IF(condition,err) if((condition)) { \
|
||||||
fprintf(stderr, "%s:%s:%d error 0x%x\n", __FILE__, __FUNCTION__, __LINE__, err); \
|
|
||||||
ctx->setGLerror(err); \
|
ctx->setGLerror(err); \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define RET_AND_SET_ERROR_IF(condition,err,ret) if((condition)) { \
|
#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); \
|
ctx->setGLerror(err); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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})
|
|
||||||
|
|
@ -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 <EGL/egl.h>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#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<SubWindowHandler> &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
|
|
||||||
|
|
@ -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 <Cocoa/Cocoa.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
@ -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 <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
static std::shared_ptr<SubWindowHandler> current_handler = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerSubWindowHandler(const std::shared_ptr<SubWindowHandler> &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;
|
|
||||||
}
|
|
||||||
|
|
@ -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 <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <mirclient/mir_toolkit/mir_client_library.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
std::map<EGLNativeWindowType,MirSurface*> 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<EGLNativeWindowType>(
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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 <stdio.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -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 <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
@ -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 <windows.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -42,3 +42,6 @@ rcUpdateColorBuffer
|
||||||
|
|
||||||
rcCloseColorBuffer
|
rcCloseColorBuffer
|
||||||
flag flushOnEncode
|
flag flushOnEncode
|
||||||
|
|
||||||
|
rcPostLayer
|
||||||
|
len name (strlen(name) + 1)
|
||||||
|
|
|
||||||
|
|
@ -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(uint32_t, rcCreateClientImage, uint32_t context, EGLenum target, GLuint buffer)
|
||||||
GL_ENTRY(int, rcDestroyClientImage, uint32_t image)
|
GL_ENTRY(int, rcDestroyClientImage, uint32_t image)
|
||||||
GL_ENTRY(void, rcSelectChecksumCalculator, uint32_t newProtocol, uint32_t reserved)
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
uint32_t 32 0x%08x
|
uint32_t 32 0x%08x
|
||||||
|
int32_t 32 0x%08x
|
||||||
EGLint 32 0x%08x
|
EGLint 32 0x%08x
|
||||||
GLint 32 0x%08x
|
GLint 32 0x%08x
|
||||||
GLuint 32 0x%08x
|
GLuint 32 0x%08x
|
||||||
|
|
@ -9,3 +10,4 @@ EGLint* 32 0x%08x
|
||||||
GLint* 32 0x%08x
|
GLint* 32 0x%08x
|
||||||
GLuint* 32 0x%08x
|
GLuint* 32 0x%08x
|
||||||
void* 32 0x%08x
|
void* 32 0x%08x
|
||||||
|
char* 32 0x%08x
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
glUtils.cpp
|
|
||||||
ChecksumCalculator.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})
|
add_library(OpenglCodecCommon ${SOURCES})
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,32 @@
|
||||||
set(COMMON_SOURCES
|
set(COMMON_SOURCES
|
||||||
|
condition_variable.h
|
||||||
crash_reporter.cpp
|
crash_reporter.cpp
|
||||||
|
crash_reporter.h
|
||||||
id_to_object_map.cpp
|
id_to_object_map.cpp
|
||||||
|
id_to_object_map.h
|
||||||
lazy_instance.cpp
|
lazy_instance.cpp
|
||||||
|
lazy_instance.h
|
||||||
logging.cpp
|
logging.cpp
|
||||||
|
logging.h
|
||||||
message_channel.cpp
|
message_channel.cpp
|
||||||
|
message_channel.h
|
||||||
|
mutex.h
|
||||||
|
mutex_unittest.cpp
|
||||||
pod_vector.cpp
|
pod_vector.cpp
|
||||||
|
pod_vector.h
|
||||||
|
scoped_pointer_vector.h
|
||||||
shared_library.cpp
|
shared_library.cpp
|
||||||
|
shared_library.h
|
||||||
smart_ptr.cpp
|
smart_ptr.cpp
|
||||||
|
smart_ptr.h
|
||||||
sockets.cpp
|
sockets.cpp
|
||||||
|
sockets.h
|
||||||
|
thread.h
|
||||||
|
thread_pthread.cpp
|
||||||
thread_store.cpp
|
thread_store.cpp
|
||||||
thread_pthread.cpp)
|
thread_store.h
|
||||||
|
thread_unittest.cpp
|
||||||
|
unique_integer_map.h)
|
||||||
|
|
||||||
add_library(emugl_common ${COMMON_SOURCES})
|
add_library(emugl_common ${COMMON_SOURCES})
|
||||||
target_link_libraries(emugl_common
|
target_link_libraries(emugl_common
|
||||||
|
|
|
||||||
17
scripts/android-sync.sh
Executable file
17
scripts/android-sync.sh
Executable file
|
|
@ -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
|
||||||
|
|
@ -12,7 +12,17 @@ include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/src
|
${CMAKE_SOURCE_DIR}/src
|
||||||
${CMAKE_SOURCE_DIR}/external/process-cpp-minimal/include
|
${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/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(
|
protobuf_generate_cpp(
|
||||||
|
|
@ -93,8 +103,41 @@ set(SOURCES
|
||||||
|
|
||||||
anbox/graphics/opengles_message_processor.cpp
|
anbox/graphics/opengles_message_processor.cpp
|
||||||
anbox/graphics/gl_renderer_server.cpp
|
anbox/graphics/gl_renderer_server.cpp
|
||||||
anbox/graphics/window_creator.cpp
|
|
||||||
anbox/graphics/density.h
|
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/manager.cpp
|
||||||
anbox/input/device.cpp
|
anbox/input/device.cpp
|
||||||
|
|
@ -116,9 +159,9 @@ set(SOURCES
|
||||||
anbox/bridge/platform_api_skeleton.cpp
|
anbox/bridge/platform_api_skeleton.cpp
|
||||||
anbox/bridge/android_api_stub.cpp
|
anbox/bridge/android_api_stub.cpp
|
||||||
|
|
||||||
anbox/ubuntu/platform_api_skeleton.cpp
|
|
||||||
anbox/ubuntu/window_creator.cpp
|
|
||||||
anbox/ubuntu/window.cpp
|
anbox/ubuntu/window.cpp
|
||||||
|
anbox/ubuntu/keycode_converter.cpp
|
||||||
|
anbox/ubuntu/platform_policy.cpp
|
||||||
|
|
||||||
anbox/dbus/interface.h
|
anbox/dbus/interface.h
|
||||||
anbox/dbus/skeleton/service.cpp
|
anbox/dbus/skeleton/service.cpp
|
||||||
|
|
@ -144,7 +187,12 @@ target_link_libraries(anbox-core
|
||||||
${LXC_LIBRARIES}
|
${LXC_LIBRARIES}
|
||||||
pthread
|
pthread
|
||||||
process-cpp
|
process-cpp
|
||||||
OpenglRender
|
emugl_common
|
||||||
|
GLESv1_dec
|
||||||
|
GLESv2_dec
|
||||||
|
renderControl_dec
|
||||||
|
OpenGLESDispatch
|
||||||
|
OpenglCodecCommon
|
||||||
anbox-protobuf)
|
anbox-protobuf)
|
||||||
|
|
||||||
add_executable(anbox main.cpp)
|
add_executable(anbox main.cpp)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ void AndroidApiStub::install(const std::string &path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidApiStub::application_installed(Request<protobuf::rpc::Void> *request) {
|
void AndroidApiStub::application_installed(Request<protobuf::rpc::Void> *request) {
|
||||||
|
(void) request;
|
||||||
install_wait_handle_.result_received();
|
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<protobuf::rpc::Void> *request) {
|
void AndroidApiStub::application_launched(Request<protobuf::rpc::Void> *request) {
|
||||||
|
(void) request;
|
||||||
launch_wait_handle_.result_received();
|
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<protobuf::rpc::Void> *request) {
|
void AndroidApiStub::dns_servers_set(Request<protobuf::rpc::Void> *request) {
|
||||||
|
(void) request;
|
||||||
set_dns_servers_wait_handle_.result_received();
|
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<Request<protobuf::rpc::Void>>();
|
||||||
|
|
||||||
|
protobuf::bridge::SetFocusedTask message;
|
||||||
|
message.set_id(id);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||||
|
set_focused_task_handle_.expect_result();
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_->call_method("set_focused_task",
|
||||||
|
&message,
|
||||||
|
c->response.get(),
|
||||||
|
google::protobuf::NewCallback(this, &AndroidApiStub::focused_task_set, c.get()));
|
||||||
|
|
||||||
|
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<protobuf::rpc::Void> *request) {
|
||||||
|
(void) request;
|
||||||
|
set_focused_task_handle_.result_received();
|
||||||
|
}
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ public:
|
||||||
void launch(const std::string &package, const std::string &activity) override;
|
void launch(const std::string &package, const std::string &activity) override;
|
||||||
|
|
||||||
void set_dns_servers(const std::string &domain, const std::vector<std::string> &servers);
|
void set_dns_servers(const std::string &domain, const std::vector<std::string> &servers);
|
||||||
|
void set_focused_task(const std::int32_t &id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ensure_rpc_channel();
|
void ensure_rpc_channel();
|
||||||
|
|
@ -60,12 +61,14 @@ private:
|
||||||
void application_installed(Request<protobuf::rpc::Void> *request);
|
void application_installed(Request<protobuf::rpc::Void> *request);
|
||||||
void application_launched(Request<protobuf::rpc::Void> *request);
|
void application_launched(Request<protobuf::rpc::Void> *request);
|
||||||
void dns_servers_set(Request<protobuf::rpc::Void> *request);
|
void dns_servers_set(Request<protobuf::rpc::Void> *request);
|
||||||
|
void focused_task_set(Request<protobuf::rpc::Void> *request);
|
||||||
|
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
std::shared_ptr<rpc::Channel> channel_;
|
std::shared_ptr<rpc::Channel> channel_;
|
||||||
common::WaitHandle install_wait_handle_;
|
common::WaitHandle install_wait_handle_;
|
||||||
common::WaitHandle launch_wait_handle_;
|
common::WaitHandle launch_wait_handle_;
|
||||||
common::WaitHandle set_dns_servers_wait_handle_;
|
common::WaitHandle set_dns_servers_wait_handle_;
|
||||||
|
common::WaitHandle set_focused_task_handle_;
|
||||||
};
|
};
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -16,17 +16,58 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "anbox/bridge/platform_api_skeleton.h"
|
#include "anbox/bridge/platform_api_skeleton.h"
|
||||||
|
#include "anbox/wm/manager.h"
|
||||||
|
#include "anbox/wm/window_state.h"
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include "anbox_bridge.pb.h"
|
#include "anbox_bridge.pb.h"
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace bridge {
|
namespace bridge {
|
||||||
PlatformApiSkeleton::PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls) :
|
PlatformApiSkeleton::PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
|
||||||
pending_calls_(pending_calls) {
|
const std::shared_ptr<wm::Manager> &window_manager) :
|
||||||
|
pending_calls_(pending_calls),
|
||||||
|
window_manager_(window_manager) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformApiSkeleton::~PlatformApiSkeleton() {
|
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<void()> &action) {
|
||||||
|
boot_finished_handler_ = action;
|
||||||
|
}
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -32,28 +32,32 @@ namespace rpc {
|
||||||
class Void;
|
class Void;
|
||||||
} // namespace rpc
|
} // namespace rpc
|
||||||
namespace bridge {
|
namespace bridge {
|
||||||
class Notification;
|
class BootFinishedEvent;
|
||||||
|
class WindowStateUpdateEvent;
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
} // namespace protobuf
|
} // namespace protobuf
|
||||||
namespace rpc {
|
namespace rpc {
|
||||||
class PendingCallCache;
|
class PendingCallCache;
|
||||||
} // namespace rpc
|
} // namespace rpc
|
||||||
|
namespace wm {
|
||||||
|
class Manager;
|
||||||
|
} // namespace wm
|
||||||
namespace bridge {
|
namespace bridge {
|
||||||
class PlatformApiSkeleton {
|
class PlatformApiSkeleton {
|
||||||
public:
|
public:
|
||||||
PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls);
|
PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
|
||||||
|
const std::shared_ptr<wm::Manager> &window_manager);
|
||||||
virtual ~PlatformApiSkeleton();
|
virtual ~PlatformApiSkeleton();
|
||||||
|
|
||||||
virtual void boot_finished(anbox::protobuf::rpc::Void const *request,
|
void handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event);
|
||||||
anbox::protobuf::rpc::Void *response,
|
void handle_window_state_update_event(const anbox::protobuf::bridge::WindowStateUpdateEvent &event);
|
||||||
google::protobuf::Closure *done) = 0;
|
|
||||||
|
|
||||||
virtual void handle_notification(anbox::protobuf::bridge::Notification const *request,
|
void register_boot_finished_handler(const std::function<void()> &action);
|
||||||
anbox::protobuf::rpc::Void *response,
|
|
||||||
google::protobuf::Closure *done) = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
|
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
|
||||||
|
std::shared_ptr<wm::Manager> window_manager_;
|
||||||
|
std::function<void()> boot_finished_handler_;
|
||||||
};
|
};
|
||||||
} // namespace bridge
|
} // namespace bridge
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "anbox/bridge/platform_message_processor.h"
|
#include "anbox/bridge/platform_message_processor.h"
|
||||||
#include "anbox/bridge/platform_api_skeleton.h"
|
#include "anbox/bridge/platform_api_skeleton.h"
|
||||||
#include "anbox/rpc/template_message_processor.h"
|
#include "anbox/rpc/template_message_processor.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include "anbox_bridge.pb.h"
|
#include "anbox_bridge.pb.h"
|
||||||
|
|
||||||
|
|
@ -34,13 +35,20 @@ PlatformMessageProcessor::~PlatformMessageProcessor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformMessageProcessor::dispatch(rpc::Invocation const& invocation) {
|
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 anbox
|
||||||
} // namespace network
|
} // namespace network
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,11 @@
|
||||||
#include "anbox/rpc/channel.h"
|
#include "anbox/rpc/channel.h"
|
||||||
#include "anbox/bridge/platform_message_processor.h"
|
#include "anbox/bridge/platform_message_processor.h"
|
||||||
#include "anbox/bridge/android_api_stub.h"
|
#include "anbox/bridge/android_api_stub.h"
|
||||||
#include "anbox/ubuntu/platform_api_skeleton.h"
|
#include "anbox/bridge/platform_api_skeleton.h"
|
||||||
#include "anbox/ubuntu/window_creator.h"
|
|
||||||
#include "anbox/dbus/skeleton/service.h"
|
#include "anbox/dbus/skeleton/service.h"
|
||||||
#include "anbox/container/client.h"
|
#include "anbox/container/client.h"
|
||||||
|
#include "anbox/wm/manager.h"
|
||||||
|
#include "anbox/ubuntu/platform_policy.h"
|
||||||
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
|
|
@ -88,8 +89,15 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
||||||
|
|
||||||
auto input_manager = std::make_shared<input::Manager>(rt);
|
auto input_manager = std::make_shared<input::Manager>(rt);
|
||||||
|
|
||||||
auto window_creator = std::make_shared<ubuntu::WindowCreator>(input_manager);
|
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
||||||
auto renderer = std::make_shared<graphics::GLRendererServer>(window_creator);
|
|
||||||
|
auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager, android_api_stub);
|
||||||
|
// FIXME this needs to be removed and solved differently behind the scenes
|
||||||
|
registerDisplayManager(policy);
|
||||||
|
|
||||||
|
auto window_manager = std::make_shared<wm::Manager>(policy);
|
||||||
|
|
||||||
|
auto renderer = std::make_shared<graphics::GLRendererServer>(window_manager);
|
||||||
renderer->start();
|
renderer->start();
|
||||||
|
|
||||||
// Socket which will be used by the qemud service inside the Android
|
// 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(),
|
renderer->socket_path(),
|
||||||
icon_));
|
icon_));
|
||||||
|
|
||||||
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
|
||||||
|
|
||||||
auto bridge_connector = std::make_shared<network::PublishedSocketConnector>(
|
auto bridge_connector = std::make_shared<network::PublishedSocketConnector>(
|
||||||
utils::string_format("%s/anbox_bridge", config::socket_path()),
|
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.
|
// more than one one day we need proper dispatching to the right one.
|
||||||
android_api_stub->set_rpc_channel(rpc_channel);
|
android_api_stub->set_rpc_channel(rpc_channel);
|
||||||
|
|
||||||
auto server = std::make_shared<ubuntu::PlatformApiSekeleton>(pending_calls);
|
auto server = std::make_shared<bridge::PlatformApiSkeleton>(pending_calls, window_manager);
|
||||||
server->on_boot_finished([&]() {
|
server->register_boot_finished_handler([&]() {
|
||||||
|
DEBUG("Android successfully booted");
|
||||||
dispatcher->dispatch([&]() {
|
dispatcher->dispatch([&]() {
|
||||||
// FIXME make this configurable or once we have a bridge let the host
|
// FIXME make this configurable or once we have a bridge let the host
|
||||||
// act as a DNS proxy.
|
// act as a DNS proxy.
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,6 @@ ColorBuffer* ColorBuffer::create(EGLDisplay p_display,
|
||||||
Helper* helper) {
|
Helper* helper) {
|
||||||
GLenum texInternalFormat = 0;
|
GLenum texInternalFormat = 0;
|
||||||
|
|
||||||
printf("Creating new color buffer width %i height %i\n", p_width, p_height);
|
|
||||||
|
|
||||||
switch (p_internalFormat) {
|
switch (p_internalFormat) {
|
||||||
case GL_RGB:
|
case GL_RGB:
|
||||||
case GL_RGB565_OES:
|
case GL_RGB565_OES:
|
||||||
|
|
@ -335,7 +333,7 @@ bool ColorBuffer::blitFromCurrentReadBuffer()
|
||||||
s_gles2.glViewport(0, 0, m_width, m_height);
|
s_gles2.glViewport(0, 0, m_width, m_height);
|
||||||
|
|
||||||
// render m_blitTex
|
// render m_blitTex
|
||||||
m_helper->getTextureDraw()->draw(m_blitTex, 0., 0, 0);
|
m_helper->getTextureDraw()->draw(m_blitTex);
|
||||||
|
|
||||||
// Restore previous viewport.
|
// Restore previous viewport.
|
||||||
s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
|
s_gles2.glViewport(vport[0], vport[1], vport[2], vport[3]);
|
||||||
|
|
@ -378,11 +376,6 @@ bool ColorBuffer::bindToRenderbuffer() {
|
||||||
return true;
|
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) {
|
void ColorBuffer::readback(unsigned char* img) {
|
||||||
ScopedHelperContext context(m_helper);
|
ScopedHelperContext context(m_helper);
|
||||||
if (!context.isOk()) {
|
if (!context.isOk()) {
|
||||||
|
|
@ -394,3 +387,8 @@ void ColorBuffer::readback(unsigned char* img) {
|
||||||
unbindFbo();
|
unbindFbo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ColorBuffer::bind() {
|
||||||
|
const auto id = m_resizer->update(m_tex);
|
||||||
|
s_gles2.glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
class TextureDraw;
|
class TextureDraw;
|
||||||
class TextureResize;
|
class TextureResize;
|
||||||
|
|
||||||
|
|
@ -109,15 +108,6 @@ public:
|
||||||
GLenum p_type,
|
GLenum p_type,
|
||||||
void *pixels);
|
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
|
// Bind the current context's EGL_TEXTURE_2D texture to this ColorBuffer's
|
||||||
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
|
// EGLImage. This is intended to implement glEGLImageTargetTexture2DOES()
|
||||||
// for all GLES versions.
|
// for all GLES versions.
|
||||||
|
|
@ -137,6 +127,7 @@ public:
|
||||||
// |img| must be a buffer large enough (i.e. width * height * 4).
|
// |img| must be a buffer large enough (i.e. width * height * 4).
|
||||||
void readback(unsigned char* img);
|
void readback(unsigned char* img);
|
||||||
|
|
||||||
|
void bind();
|
||||||
private:
|
private:
|
||||||
ColorBuffer(); // no default constructor.
|
ColorBuffer(); // no default constructor.
|
||||||
|
|
||||||
42
src/anbox/graphics/emugl/DisplayManager.cpp
Normal file
42
src/anbox/graphics/emugl/DisplayManager.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DisplayManager.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::shared_ptr<DisplayManager> display_mgr;
|
||||||
|
|
||||||
|
class NullDisplayManager : public DisplayManager {
|
||||||
|
public:
|
||||||
|
DisplayInfo display_info() const override {
|
||||||
|
return {1280, 720};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayManager::~DisplayManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<DisplayManager> DisplayManager::get() {
|
||||||
|
if (!display_mgr)
|
||||||
|
display_mgr = std::make_shared<NullDisplayManager>();
|
||||||
|
return display_mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr) {
|
||||||
|
display_mgr = mgr;
|
||||||
|
}
|
||||||
|
|
@ -15,20 +15,14 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ANBOX_GRAPHICS_WINDOW_CREATOR_H_
|
#ifndef DISPLAY_MANAGER_H_
|
||||||
#define ANBOX_GRAPHICS_WINDOW_CREATOR_H_
|
#define DISPLAY_MANAGER_H_
|
||||||
|
|
||||||
#include "external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h"
|
#include <memory>
|
||||||
|
|
||||||
namespace anbox {
|
class DisplayManager {
|
||||||
namespace input {
|
|
||||||
class Manager;
|
|
||||||
} // namespace input
|
|
||||||
namespace graphics {
|
|
||||||
class WindowCreator : public SubWindowHandler {
|
|
||||||
public:
|
public:
|
||||||
WindowCreator(const std::shared_ptr<input::Manager> &input_manager);
|
virtual ~DisplayManager();
|
||||||
virtual ~WindowCreator();
|
|
||||||
|
|
||||||
struct DisplayInfo {
|
struct DisplayInfo {
|
||||||
int horizontal_resolution;
|
int horizontal_resolution;
|
||||||
|
|
@ -36,11 +30,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual DisplayInfo display_info() const = 0;
|
virtual DisplayInfo display_info() const = 0;
|
||||||
virtual EGLNativeDisplayType native_display() const = 0;
|
|
||||||
|
|
||||||
protected:
|
static std::shared_ptr<DisplayManager> get();
|
||||||
std::shared_ptr<input::Manager> input_manager_;
|
|
||||||
};
|
};
|
||||||
} // namespace graphics
|
|
||||||
} // namespace anbox
|
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -21,11 +21,7 @@
|
||||||
#include "TimeUtils.h"
|
#include "TimeUtils.h"
|
||||||
|
|
||||||
#include "TcpStream.h"
|
#include "TcpStream.h"
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Win32PipeStream.h"
|
|
||||||
#else
|
|
||||||
#include "UnixStream.h"
|
#include "UnixStream.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "DispatchTables.h"
|
#include "DispatchTables.h"
|
||||||
|
|
||||||
|
|
@ -78,8 +74,7 @@ RENDER_APICALL int RENDER_APIENTRY initLibrary(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer(
|
RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer(
|
||||||
EGLNativeDisplayType native_display,
|
EGLNativeDisplayType native_display, char* addr, size_t addrLen,
|
||||||
int width, int height, bool useSubWindow, char* addr, size_t addrLen,
|
|
||||||
emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc) {
|
emugl_logger_struct logfuncs, emugl_crash_func_t crashfunc) {
|
||||||
set_emugl_crash_reporter(crashfunc);
|
set_emugl_crash_reporter(crashfunc);
|
||||||
set_emugl_logger(logfuncs.coarse);
|
set_emugl_logger(logfuncs.coarse);
|
||||||
|
|
@ -117,7 +112,7 @@ RENDER_APICALL int RENDER_APIENTRY initOpenGLRenderer(
|
||||||
// initialize the renderer and listen to connections
|
// initialize the renderer and listen to connections
|
||||||
// on a thread in the current process.
|
// 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) {
|
if (!s_renderWindow) {
|
||||||
ERR("Could not create rendering window class");
|
ERR("Could not create rendering window class");
|
||||||
GL_LOG("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;
|
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(
|
RENDER_APICALL void RENDER_APIENTRY getHardwareStrings(
|
||||||
const char** vendor,
|
const char** vendor,
|
||||||
const char** renderer,
|
const char** renderer,
|
||||||
|
|
@ -228,53 +214,7 @@ RENDER_APICALL bool RENDER_APIENTRY destroyOpenGLSubwindow(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RENDER_APICALL void RENDER_APIENTRY setOpenGLDisplayRotation(float zRot)
|
#define DEFAULT_STREAM_MODE RENDER_API_STREAM_MODE_UNIX
|
||||||
{
|
|
||||||
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
|
|
||||||
|
|
||||||
int gRendererStreamMode = DEFAULT_STREAM_MODE;
|
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) {
|
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
|
||||||
stream = new TcpStream(p_stream_buffer_size);
|
stream = new TcpStream(p_stream_buffer_size);
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
|
||||||
stream = new Win32PipeStream(p_stream_buffer_size);
|
|
||||||
#else /* !_WIN32 */
|
|
||||||
stream = new UnixStream(p_stream_buffer_size);
|
stream = new UnixStream(p_stream_buffer_size);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
|
|
@ -312,28 +248,3 @@ IOStream *createRenderThread(int p_stream_buffer_size, unsigned int clientFlags)
|
||||||
|
|
||||||
return stream;
|
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;
|
|
||||||
}
|
|
||||||
|
|
@ -16,14 +16,27 @@
|
||||||
#include "RenderControl.h"
|
#include "RenderControl.h"
|
||||||
|
|
||||||
#include "DispatchTables.h"
|
#include "DispatchTables.h"
|
||||||
#include "FbConfig.h"
|
#include "RendererConfig.h"
|
||||||
#include "FrameBuffer.h"
|
#include "Renderer.h"
|
||||||
#include "RenderThreadInfo.h"
|
#include "RenderThreadInfo.h"
|
||||||
#include "ChecksumCalculatorThreadInfo.h"
|
#include "ChecksumCalculatorThreadInfo.h"
|
||||||
|
#include "DisplayManager.h"
|
||||||
|
|
||||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||||
|
|
||||||
|
#include "anbox/graphics/layer_composer.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
static const GLint rendererVersion = 1;
|
static const GLint rendererVersion = 1;
|
||||||
|
static std::shared_ptr<anbox::graphics::LayerComposer> composer;
|
||||||
|
|
||||||
|
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c)
|
||||||
|
{
|
||||||
|
composer = c;
|
||||||
|
}
|
||||||
|
|
||||||
static GLint rcGetRendererVersion()
|
static GLint rcGetRendererVersion()
|
||||||
{
|
{
|
||||||
|
|
@ -32,7 +45,7 @@ static GLint rcGetRendererVersion()
|
||||||
|
|
||||||
static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor)
|
static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +57,7 @@ static EGLint rcGetEGLVersion(EGLint* major, EGLint* minor)
|
||||||
|
|
||||||
static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize)
|
static EGLint rcQueryEGLString(EGLenum name, void* buffer, EGLint bufferSize)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +131,7 @@ static EGLint rcGetNumConfigs(uint32_t* p_numAttribs)
|
||||||
{
|
{
|
||||||
int numConfigs = 0, numAttribs = 0;
|
int numConfigs = 0, numAttribs = 0;
|
||||||
|
|
||||||
FrameBuffer::getFB()->getConfigs()->getPackInfo(&numConfigs, &numAttribs);
|
Renderer::get()->getConfigs()->getPackInfo(&numConfigs, &numAttribs);
|
||||||
if (p_numAttribs) {
|
if (p_numAttribs) {
|
||||||
*p_numAttribs = static_cast<uint32_t>(numAttribs);
|
*p_numAttribs = static_cast<uint32_t>(numAttribs);
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +141,7 @@ static EGLint rcGetNumConfigs(uint32_t* p_numAttribs)
|
||||||
static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer)
|
static EGLint rcGetConfigs(uint32_t bufSize, GLuint* buffer)
|
||||||
{
|
{
|
||||||
GLuint bufferSize = (GLuint)bufSize;
|
GLuint bufferSize = (GLuint)bufSize;
|
||||||
return FrameBuffer::getFB()->getConfigs()->packConfigs(bufferSize, buffer);
|
return Renderer::get()->getConfigs()->packConfigs(bufferSize, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EGLint rcChooseConfig(EGLint *attribs,
|
static EGLint rcChooseConfig(EGLint *attribs,
|
||||||
|
|
@ -136,7 +149,7 @@ static EGLint rcChooseConfig(EGLint *attribs,
|
||||||
uint32_t *configs,
|
uint32_t *configs,
|
||||||
uint32_t configs_size)
|
uint32_t configs_size)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb || attribs_size==0) {
|
if (!fb || attribs_size==0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +160,7 @@ static EGLint rcChooseConfig(EGLint *attribs,
|
||||||
|
|
||||||
static EGLint rcGetFBParam(EGLint param)
|
static EGLint rcGetFBParam(EGLint param)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -156,10 +169,10 @@ static EGLint rcGetFBParam(EGLint param)
|
||||||
|
|
||||||
switch(param) {
|
switch(param) {
|
||||||
case FB_WIDTH:
|
case FB_WIDTH:
|
||||||
ret = fb->getWidth();
|
ret = DisplayManager::get()->display_info().horizontal_resolution;
|
||||||
break;
|
break;
|
||||||
case FB_HEIGHT:
|
case FB_HEIGHT:
|
||||||
ret = fb->getHeight();
|
ret = DisplayManager::get()->display_info().vertical_resolution;
|
||||||
break;
|
break;
|
||||||
case FB_XDPI:
|
case FB_XDPI:
|
||||||
ret = 72; // XXX: should be implemented
|
ret = 72; // XXX: should be implemented
|
||||||
|
|
@ -186,7 +199,7 @@ static EGLint rcGetFBParam(EGLint param)
|
||||||
static uint32_t rcCreateContext(uint32_t config,
|
static uint32_t rcCreateContext(uint32_t config,
|
||||||
uint32_t share, uint32_t glVersion)
|
uint32_t share, uint32_t glVersion)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +212,7 @@ static uint32_t rcCreateContext(uint32_t config,
|
||||||
|
|
||||||
static void rcDestroyContext(uint32_t context)
|
static void rcDestroyContext(uint32_t context)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +223,7 @@ static void rcDestroyContext(uint32_t context)
|
||||||
static uint32_t rcCreateWindowSurface(uint32_t config,
|
static uint32_t rcCreateWindowSurface(uint32_t config,
|
||||||
uint32_t width, uint32_t height)
|
uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +233,7 @@ static uint32_t rcCreateWindowSurface(uint32_t config,
|
||||||
|
|
||||||
static void rcDestroyWindowSurface(uint32_t windowSurface)
|
static void rcDestroyWindowSurface(uint32_t windowSurface)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +244,7 @@ static void rcDestroyWindowSurface(uint32_t windowSurface)
|
||||||
static uint32_t rcCreateColorBuffer(uint32_t width,
|
static uint32_t rcCreateColorBuffer(uint32_t width,
|
||||||
uint32_t height, GLenum internalFormat)
|
uint32_t height, GLenum internalFormat)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +254,7 @@ static uint32_t rcCreateColorBuffer(uint32_t width,
|
||||||
|
|
||||||
static int rcOpenColorBuffer2(uint32_t colorbuffer)
|
static int rcOpenColorBuffer2(uint32_t colorbuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -257,7 +270,7 @@ static void rcOpenColorBuffer(uint32_t colorbuffer)
|
||||||
|
|
||||||
static void rcCloseColorBuffer(uint32_t colorbuffer)
|
static void rcCloseColorBuffer(uint32_t colorbuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -266,7 +279,7 @@ static void rcCloseColorBuffer(uint32_t colorbuffer)
|
||||||
|
|
||||||
static int rcFlushWindowColorBuffer(uint32_t windowSurface)
|
static int rcFlushWindowColorBuffer(uint32_t windowSurface)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -279,7 +292,7 @@ static int rcFlushWindowColorBuffer(uint32_t windowSurface)
|
||||||
static void rcSetWindowColorBuffer(uint32_t windowSurface,
|
static void rcSetWindowColorBuffer(uint32_t windowSurface,
|
||||||
uint32_t colorBuffer)
|
uint32_t colorBuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +302,7 @@ static void rcSetWindowColorBuffer(uint32_t windowSurface,
|
||||||
static EGLint rcMakeCurrent(uint32_t context,
|
static EGLint rcMakeCurrent(uint32_t context,
|
||||||
uint32_t drawSurf, uint32_t readSurf)
|
uint32_t drawSurf, uint32_t readSurf)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return EGL_FALSE;
|
return EGL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
@ -301,12 +314,7 @@ static EGLint rcMakeCurrent(uint32_t context,
|
||||||
|
|
||||||
static void rcFBPost(uint32_t colorBuffer)
|
static void rcFBPost(uint32_t colorBuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
WARNING("Not implemented");
|
||||||
if (!fb) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb->post(colorBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcFBSetSwapInterval(EGLint interval)
|
static void rcFBSetSwapInterval(EGLint interval)
|
||||||
|
|
@ -316,7 +324,7 @@ static void rcFBSetSwapInterval(EGLint interval)
|
||||||
|
|
||||||
static void rcBindTexture(uint32_t colorBuffer)
|
static void rcBindTexture(uint32_t colorBuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +334,7 @@ static void rcBindTexture(uint32_t colorBuffer)
|
||||||
|
|
||||||
static void rcBindRenderbuffer(uint32_t colorBuffer)
|
static void rcBindRenderbuffer(uint32_t colorBuffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +354,7 @@ static void rcReadColorBuffer(uint32_t colorBuffer,
|
||||||
GLint width, GLint height,
|
GLint width, GLint height,
|
||||||
GLenum format, GLenum type, void* pixels)
|
GLenum format, GLenum type, void* pixels)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -359,7 +367,7 @@ static int rcUpdateColorBuffer(uint32_t colorBuffer,
|
||||||
GLint width, GLint height,
|
GLint width, GLint height,
|
||||||
GLenum format, GLenum type, void* pixels)
|
GLenum format, GLenum type, void* pixels)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +378,7 @@ static int rcUpdateColorBuffer(uint32_t colorBuffer,
|
||||||
|
|
||||||
static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer)
|
static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -380,7 +388,7 @@ static uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buf
|
||||||
|
|
||||||
static int rcDestroyClientImage(uint32_t image)
|
static int rcDestroyClientImage(uint32_t image)
|
||||||
{
|
{
|
||||||
FrameBuffer *fb = FrameBuffer::getFB();
|
Renderer *fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -392,6 +400,62 @@ static void rcSelectChecksumCalculator(uint32_t protocol, uint32_t reserved) {
|
||||||
ChecksumCalculatorThreadInfo::setVersion(protocol);
|
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<Renderable> frame_layers;
|
||||||
|
|
||||||
|
bool is_layer_blacklisted(const std::string &name) {
|
||||||
|
static std::vector<std::string> blacklist = {
|
||||||
|
"Sprite",
|
||||||
|
};
|
||||||
|
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
void initRenderControlContext(renderControl_decoder_context_t *dec)
|
||||||
{
|
{
|
||||||
dec->rcGetRendererVersion = rcGetRendererVersion;
|
dec->rcGetRendererVersion = rcGetRendererVersion;
|
||||||
|
|
@ -423,4 +487,12 @@ void initRenderControlContext(renderControl_decoder_context_t *dec)
|
||||||
dec->rcCreateClientImage = rcCreateClientImage;
|
dec->rcCreateClientImage = rcCreateClientImage;
|
||||||
dec->rcDestroyClientImage = rcDestroyClientImage;
|
dec->rcDestroyClientImage = rcDestroyClientImage;
|
||||||
dec->rcSelectChecksumCalculator = rcSelectChecksumCalculator;
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,15 @@
|
||||||
|
|
||||||
#include "renderControl_dec.h"
|
#include "renderControl_dec.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace graphics {
|
||||||
|
class LayerComposer;
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
void initRenderControlContext(renderControl_decoder_context_t *dec);
|
void initRenderControlContext(renderControl_decoder_context_t *dec);
|
||||||
|
void registerLayerComposer(const std::shared_ptr<anbox::graphics::LayerComposer> &c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -17,14 +17,9 @@
|
||||||
|
|
||||||
#include "RenderThread.h"
|
#include "RenderThread.h"
|
||||||
#include "TcpStream.h"
|
#include "TcpStream.h"
|
||||||
#ifndef _WIN32
|
|
||||||
#include "UnixStream.h"
|
#include "UnixStream.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "Win32PipeStream.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "OpenglRender/render_api.h"
|
#include "OpenglRender/render_api.h"
|
||||||
|
|
||||||
|
|
@ -59,11 +54,7 @@ RenderServer *RenderServer::create(char* addr, size_t addrLen)
|
||||||
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
|
if (gRendererStreamMode == RENDER_API_STREAM_MODE_TCP) {
|
||||||
server->m_listenSock = new TcpStream();
|
server->m_listenSock = new TcpStream();
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
|
||||||
server->m_listenSock = new Win32PipeStream();
|
|
||||||
#else
|
|
||||||
server->m_listenSock = new UnixStream();
|
server->m_listenSock = new UnixStream();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char addrstr[SocketStream::MAX_ADDRSTR_LEN];
|
char addrstr[SocketStream::MAX_ADDRSTR_LEN];
|
||||||
|
|
@ -89,12 +80,6 @@ intptr_t RenderServer::main()
|
||||||
{
|
{
|
||||||
RenderThreadsSet threads;
|
RenderThreadsSet threads;
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
sigset_t set;
|
|
||||||
sigfillset(&set);
|
|
||||||
pthread_sigmask(SIG_SETMASK, &set, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
SocketStream *stream = m_listenSock->accept();
|
SocketStream *stream = m_listenSock->accept();
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
|
|
@ -109,8 +94,6 @@ intptr_t RenderServer::main()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG("RenderServer: Got new stream!\n");
|
|
||||||
|
|
||||||
// check if we have been requested to exit while waiting on accept
|
// check if we have been requested to exit while waiting on accept
|
||||||
if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) {
|
if ((clientFlags & IOSTREAM_CLIENT_EXIT_SERVER) != 0) {
|
||||||
m_exiting = true;
|
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 the thread has been created and started, insert it to the list
|
||||||
if (rt) {
|
if (rt)
|
||||||
threads.insert(rt);
|
threads.insert(rt);
|
||||||
DBG("Started new RenderThread\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include "RenderThread.h"
|
#include "RenderThread.h"
|
||||||
|
|
||||||
#include "FrameBuffer.h"
|
#include "Renderer.h"
|
||||||
#include "ReadBuffer.h"
|
#include "ReadBuffer.h"
|
||||||
#include "RenderControl.h"
|
#include "RenderControl.h"
|
||||||
#include "RenderThreadInfo.h"
|
#include "RenderThreadInfo.h"
|
||||||
|
|
@ -59,25 +59,6 @@ intptr_t RenderThread::main() {
|
||||||
|
|
||||||
ReadBuffer readBuf(STREAM_BUFFER_SIZE);
|
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) {
|
while (1) {
|
||||||
|
|
||||||
int stat = readBuf.getData(m_stream);
|
int stat = readBuf.getData(m_stream);
|
||||||
|
|
@ -85,29 +66,6 @@ intptr_t RenderThread::main() {
|
||||||
break;
|
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;
|
bool progress;
|
||||||
do {
|
do {
|
||||||
progress = false;
|
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
|
// 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) {
|
if (tInfo.currContext || tInfo.currDrawSurf || tInfo.currReadSurf) {
|
||||||
fprintf(stderr, "ERROR: RenderThread exiting with current context/surfaces\n");
|
fprintf(stderr, "ERROR: RenderThread exiting with current context/surfaces\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameBuffer::getFB()->drainWindowSurface();
|
Renderer::get()->drainWindowSurface();
|
||||||
|
|
||||||
FrameBuffer::getFB()->drainRenderContext();
|
Renderer::get()->drainRenderContext();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -18,14 +18,12 @@
|
||||||
#include "emugl/common/message_channel.h"
|
#include "emugl/common/message_channel.h"
|
||||||
#include "emugl/common/mutex.h"
|
#include "emugl/common/mutex.h"
|
||||||
#include "emugl/common/thread.h"
|
#include "emugl/common/thread.h"
|
||||||
#include "FrameBuffer.h"
|
#include "Renderer.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifndef _WIN32
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
||||||
|
|
@ -73,9 +71,6 @@ struct RenderWindowMessage {
|
||||||
// CMD_INITIALIZE
|
// CMD_INITIALIZE
|
||||||
struct {
|
struct {
|
||||||
EGLNativeDisplayType nativeDisplay;
|
EGLNativeDisplayType nativeDisplay;
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
bool useSubWindow;
|
|
||||||
} init;
|
} init;
|
||||||
|
|
||||||
// CMD_SET_POST_CALLBACK
|
// CMD_SET_POST_CALLBACK
|
||||||
|
|
@ -114,17 +109,13 @@ struct RenderWindowMessage {
|
||||||
// Returns true on success, or false on failure.
|
// Returns true on success, or false on failure.
|
||||||
bool process() const {
|
bool process() const {
|
||||||
const RenderWindowMessage& msg = *this;
|
const RenderWindowMessage& msg = *this;
|
||||||
FrameBuffer* fb;
|
Renderer* fb;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
switch (msg.cmd) {
|
switch (msg.cmd) {
|
||||||
case CMD_INITIALIZE:
|
case CMD_INITIALIZE:
|
||||||
D("CMD_INITIALIZE w=%d h=%d\n", msg.init.width, msg.init.height);
|
D("CMD_INITIALIZE\n");
|
||||||
GL_LOG("RenderWindow: CMD_INITIALIZE w=%d h=%d",
|
GL_LOG("RenderWindow: CMD_INITIALIZE");
|
||||||
msg.init.width, msg.init.height);
|
result = Renderer::initialize(msg.init.nativeDisplay);
|
||||||
result = FrameBuffer::initialize(msg.init.nativeDisplay,
|
|
||||||
msg.init.width,
|
|
||||||
msg.init.height,
|
|
||||||
msg.init.useSubWindow);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_FINALIZE:
|
case CMD_FINALIZE:
|
||||||
|
|
@ -132,75 +123,12 @@ struct RenderWindowMessage {
|
||||||
// this command may be issued even when frame buffer is not
|
// this command may be issued even when frame buffer is not
|
||||||
// yet created (e.g. if CMD_INITIALIZE failed),
|
// yet created (e.g. if CMD_INITIALIZE failed),
|
||||||
// so make sure we check if it is there before finalizing
|
// 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();
|
fb->finalize();
|
||||||
}
|
}
|
||||||
result = true;
|
result = true;
|
||||||
break;
|
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:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
@ -284,11 +212,9 @@ public:
|
||||||
|
|
||||||
virtual intptr_t main() {
|
virtual intptr_t main() {
|
||||||
D("Entering render window thread thread\n");
|
D("Entering render window thread thread\n");
|
||||||
#ifndef _WIN32
|
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
pthread_sigmask(SIG_SETMASK, &set, NULL);
|
pthread_sigmask(SIG_SETMASK, &set, NULL);
|
||||||
#endif
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
RenderWindowMessage msg;
|
RenderWindowMessage msg;
|
||||||
|
|
@ -315,10 +241,7 @@ private:
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RenderWindow::RenderWindow(EGLNativeDisplayType native_display,
|
RenderWindow::RenderWindow(EGLNativeDisplayType native_display,
|
||||||
int width,
|
bool use_thread) :
|
||||||
int height,
|
|
||||||
bool use_thread,
|
|
||||||
bool use_sub_window) :
|
|
||||||
mValid(false),
|
mValid(false),
|
||||||
mHasSubWindow(false),
|
mHasSubWindow(false),
|
||||||
mThread(NULL),
|
mThread(NULL),
|
||||||
|
|
@ -332,9 +255,6 @@ RenderWindow::RenderWindow(EGLNativeDisplayType native_display,
|
||||||
RenderWindowMessage msg;
|
RenderWindowMessage msg;
|
||||||
msg.cmd = CMD_INITIALIZE;
|
msg.cmd = CMD_INITIALIZE;
|
||||||
msg.init.nativeDisplay = native_display;
|
msg.init.nativeDisplay = native_display;
|
||||||
msg.init.width = width;
|
|
||||||
msg.init.height = height;
|
|
||||||
msg.init.useSubWindow = use_sub_window;
|
|
||||||
mValid = processMessage(msg);
|
mValid = processMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,7 +278,7 @@ bool RenderWindow::getHardwareStrings(const char** vendor,
|
||||||
const char** version) {
|
const char** version) {
|
||||||
D("Entering\n");
|
D("Entering\n");
|
||||||
// TODO(digit): Move this to render window thread.
|
// TODO(digit): Move this to render window thread.
|
||||||
FrameBuffer* fb = FrameBuffer::getFB();
|
Renderer* fb = Renderer::get();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
D("No framebuffer!\n");
|
D("No framebuffer!\n");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -370,16 +290,6 @@ bool RenderWindow::getHardwareStrings(const char** vendor,
|
||||||
return true;
|
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,
|
bool RenderWindow::setupSubWindow(FBNativeWindowType window,
|
||||||
int wx,
|
int wx,
|
||||||
int wy,
|
int wy,
|
||||||
|
|
@ -59,7 +59,7 @@ public:
|
||||||
//
|
//
|
||||||
// Note that this call doesn't display anything, it just initializes
|
// Note that this call doesn't display anything, it just initializes
|
||||||
// the library, use setupSubWindow() to display something.
|
// 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.
|
// Destructor. This will automatically call removeSubWindow() is needed.
|
||||||
~RenderWindow();
|
~RenderWindow();
|
||||||
|
|
@ -75,11 +75,6 @@ public:
|
||||||
const char** renderer,
|
const char** renderer,
|
||||||
const char** version);
|
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
|
// Start displaying the emulated framebuffer using a sub-window of a
|
||||||
// parent |window| id. |wx|, |wy|, |ww| and |wh| are the position
|
// parent |window| id. |wx|, |wy|, |ww| and |wh| are the position
|
||||||
// and dimension of the sub-window, relative to its parent.
|
// and dimension of the sub-window, relative to its parent.
|
||||||
64
src/anbox/graphics/emugl/Renderable.cpp
Normal file
64
src/anbox/graphics/emugl/Renderable.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
57
src/anbox/graphics/emugl/Renderable.h
Normal file
57
src/anbox/graphics/emugl/Renderable.h
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
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<Renderable> RenderableList;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -14,10 +14,9 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FrameBuffer.h"
|
#include "Renderer.h"
|
||||||
|
|
||||||
#include "DispatchTables.h"
|
#include "DispatchTables.h"
|
||||||
#include "NativeSubWindow.h"
|
|
||||||
#include "RenderThreadInfo.h"
|
#include "RenderThreadInfo.h"
|
||||||
#include "TimeUtils.h"
|
#include "TimeUtils.h"
|
||||||
#include "gles2_dec.h"
|
#include "gles2_dec.h"
|
||||||
|
|
@ -26,8 +25,14 @@
|
||||||
|
|
||||||
#include "emugl/common/logging.h"
|
#include "emugl/common/logging.h"
|
||||||
|
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Helper class to call the bind_locked() / unbind_locked() properly.
|
// Helper class to call the bind_locked() / unbind_locked() properly.
|
||||||
|
|
@ -35,7 +40,7 @@ class ScopedBind {
|
||||||
public:
|
public:
|
||||||
// Constructor will call bind_locked() on |fb|.
|
// Constructor will call bind_locked() on |fb|.
|
||||||
// Use isValid() to check for errors.
|
// Use isValid() to check for errors.
|
||||||
ScopedBind(FrameBuffer* fb) : mFb(fb) {
|
ScopedBind(Renderer* fb) : mFb(fb) {
|
||||||
if (!mFb->bind_locked()) {
|
if (!mFb->bind_locked()) {
|
||||||
mFb = NULL;
|
mFb = NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -59,14 +64,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameBuffer* mFb;
|
Renderer* mFb;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation of a ColorBuffer::Helper instance that redirects calls
|
// Implementation of a ColorBuffer::Helper instance that redirects calls
|
||||||
// to a FrameBuffer instance.
|
// to a FrameBuffer instance.
|
||||||
class ColorBufferHelper : public ColorBuffer::Helper {
|
class ColorBufferHelper : public ColorBuffer::Helper {
|
||||||
public:
|
public:
|
||||||
ColorBufferHelper(FrameBuffer* fb) : mFb(fb) {}
|
ColorBufferHelper(Renderer* fb) : mFb(fb) {}
|
||||||
|
|
||||||
virtual bool setupContext() {
|
virtual bool setupContext() {
|
||||||
return mFb->bind_locked();
|
return mFb->bind_locked();
|
||||||
|
|
@ -80,13 +85,13 @@ public:
|
||||||
return mFb->getTextureDraw();
|
return mFb->getTextureDraw();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
FrameBuffer* mFb;
|
Renderer* mFb;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
FrameBuffer *FrameBuffer::s_theFrameBuffer = NULL;
|
Renderer *Renderer::s_renderer = NULL;
|
||||||
HandleType FrameBuffer::s_nextHandle = 0;
|
HandleType Renderer::s_nextHandle = 0;
|
||||||
|
|
||||||
static char* getGLES1ExtensionString(EGLDisplay p_dpy)
|
static char* getGLES1ExtensionString(EGLDisplay p_dpy)
|
||||||
{
|
{
|
||||||
|
|
@ -152,11 +157,8 @@ static char* getGLES1ExtensionString(EGLDisplay p_dpy)
|
||||||
return extString;
|
return extString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::finalize(){
|
void Renderer::finalize(){
|
||||||
m_colorbuffers.clear();
|
m_colorbuffers.clear();
|
||||||
if (m_useSubWindow) {
|
|
||||||
removeSubWindow();
|
|
||||||
}
|
|
||||||
m_windows.clear();
|
m_windows.clear();
|
||||||
m_contexts.clear();
|
m_contexts.clear();
|
||||||
s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
|
s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL);
|
||||||
|
|
@ -165,17 +167,17 @@ void FrameBuffer::finalize(){
|
||||||
s_egl.eglDestroySurface(m_eglDisplay, m_pbufSurface);
|
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");
|
GL_LOG("FrameBuffer::initialize");
|
||||||
if (s_theFrameBuffer != NULL) {
|
if (s_renderer != NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// allocate space for the FrameBuffer object
|
// allocate space for the FrameBuffer object
|
||||||
//
|
//
|
||||||
FrameBuffer *fb = new FrameBuffer(width, height, useSubWindow);
|
Renderer *fb = new Renderer();
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
ERR("Failed to create fb\n");
|
ERR("Failed to create fb\n");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -221,7 +223,7 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int
|
||||||
//
|
//
|
||||||
// Create EGL context for framebuffer post rendering.
|
// 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[] = {
|
const GLint configAttribs[] = {
|
||||||
EGL_RED_SIZE, 1,
|
EGL_RED_SIZE, 1,
|
||||||
EGL_GREEN_SIZE, 1,
|
EGL_GREEN_SIZE, 1,
|
||||||
|
|
@ -358,7 +360,7 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int
|
||||||
//
|
//
|
||||||
// Initialize set of configs
|
// 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()) {
|
if (fb->m_configs->empty()) {
|
||||||
ERR("Failed: Initialize set of configs\n");
|
ERR("Failed: Initialize set of configs\n");
|
||||||
bind.release();
|
bind.release();
|
||||||
|
|
@ -419,44 +421,46 @@ bool FrameBuffer::initialize(EGLNativeDisplayType nativeDisplay, int width, int
|
||||||
return false;
|
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
|
// release the FB context
|
||||||
bind.release();
|
bind.release();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Keep the singleton framebuffer pointer
|
// Keep the singleton framebuffer pointer
|
||||||
//
|
//
|
||||||
s_theFrameBuffer = fb;
|
s_renderer = fb;
|
||||||
GL_LOG("basic EGL initialization successful");
|
GL_LOG("basic EGL initialization successful");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameBuffer::FrameBuffer(int p_width, int p_height, bool useSubWindow) :
|
Renderer::Program::Program(GLuint program_id)
|
||||||
m_framebufferWidth(p_width),
|
{
|
||||||
m_framebufferHeight(p_height),
|
id = program_id;
|
||||||
m_windowWidth(p_width),
|
position_attr = s_gles2.glGetAttribLocation(id, "position");
|
||||||
m_windowHeight(p_height),
|
texcoord_attr = s_gles2.glGetAttribLocation(id, "texcoord");
|
||||||
m_useSubWindow(useSubWindow),
|
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_configs(NULL),
|
||||||
m_eglDisplay(EGL_NO_DISPLAY),
|
m_eglDisplay(EGL_NO_DISPLAY),
|
||||||
m_colorBufferHelper(new ColorBufferHelper(this)),
|
m_colorBufferHelper(new ColorBufferHelper(this)),
|
||||||
m_eglSurface(EGL_NO_SURFACE),
|
|
||||||
m_eglContext(EGL_NO_CONTEXT),
|
m_eglContext(EGL_NO_CONTEXT),
|
||||||
m_pbufContext(EGL_NO_CONTEXT),
|
m_pbufContext(EGL_NO_CONTEXT),
|
||||||
m_prevContext(EGL_NO_CONTEXT),
|
m_prevContext(EGL_NO_CONTEXT),
|
||||||
m_prevReadSurf(EGL_NO_SURFACE),
|
m_prevReadSurf(EGL_NO_SURFACE),
|
||||||
m_prevDrawSurf(EGL_NO_SURFACE),
|
m_prevDrawSurf(EGL_NO_SURFACE),
|
||||||
m_subWin((EGLNativeWindowType)0),
|
|
||||||
m_textureDraw(NULL),
|
m_textureDraw(NULL),
|
||||||
m_lastPostedColorBuffer(0),
|
m_lastPostedColorBuffer(0),
|
||||||
m_zRot(0.0f),
|
|
||||||
m_px(0),
|
|
||||||
m_py(0),
|
|
||||||
m_eglContextInitialized(false),
|
|
||||||
m_statsNumFrames(0),
|
m_statsNumFrames(0),
|
||||||
m_statsStartTime(0LL),
|
m_statsStartTime(0LL),
|
||||||
m_onPost(NULL),
|
|
||||||
m_onPostContext(NULL),
|
|
||||||
m_fbImage(NULL),
|
|
||||||
m_glVendor(NULL),
|
m_glVendor(NULL),
|
||||||
m_glRenderer(NULL),
|
m_glRenderer(NULL),
|
||||||
m_glVersion(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;
|
m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameBuffer::~FrameBuffer() {
|
Renderer::~Renderer() {
|
||||||
delete m_textureDraw;
|
delete m_textureDraw;
|
||||||
delete m_configs;
|
delete m_configs;
|
||||||
delete m_colorBufferHelper;
|
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_lock.lock();
|
||||||
m_onPost = onPost;
|
|
||||||
m_onPostContext = onPostContext;
|
auto window = new RendererWindow;
|
||||||
if (m_onPost && !m_fbImage) {
|
window->native_window = native_window;
|
||||||
m_fbImage = (unsigned char*)malloc(4 * m_framebufferWidth * m_framebufferHeight);
|
window->surface = s_egl.eglCreateWindowSurface(
|
||||||
if (!m_fbImage) {
|
m_eglDisplay, m_eglConfig, window->native_window, nullptr);
|
||||||
ERR("out of memory, cancelling OnPost callback");
|
if (window->surface == EGL_NO_SURFACE)
|
||||||
m_onPost = NULL;
|
{
|
||||||
m_onPostContext = NULL;
|
delete window;
|
||||||
return;
|
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) {
|
void Renderer::destroyNativeWindow(EGLNativeWindowType native_window) {
|
||||||
auto fb = static_cast<FrameBuffer*>(param);
|
auto w = m_nativeWindows.find(native_window);
|
||||||
fb->repost();
|
if (w == m_nativeWindows.end())
|
||||||
}
|
return;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lock.lock();
|
m_lock.lock();
|
||||||
|
|
||||||
// If the subwindow doesn't exist, create it with the appropriate dimensions
|
s_egl.eglMakeCurrent(m_eglDisplay, nullptr, nullptr, nullptr);
|
||||||
if (!m_subWin) {
|
|
||||||
|
|
||||||
// Create native subwindow for FB display output
|
if (w->second->surface != EGL_NO_SURFACE)
|
||||||
m_x = wx;
|
s_egl.eglDestroySurface(m_eglDisplay, w->second->surface);
|
||||||
m_y = wy;
|
|
||||||
m_windowWidth = ww;
|
|
||||||
m_windowHeight = wh;
|
|
||||||
|
|
||||||
m_subWin = createSubWindow(p_window, m_x, m_y,
|
delete w->second;
|
||||||
m_windowWidth, m_windowHeight, subWindowRepaint, this);
|
m_nativeWindows.erase(w);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_lock.unlock();
|
m_lock.unlock();
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::removeSubWindow() {
|
HandleType Renderer::genHandle()
|
||||||
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 id;
|
HandleType id;
|
||||||
do {
|
do {
|
||||||
|
|
@ -623,7 +549,7 @@ HandleType FrameBuffer::genHandle()
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleType FrameBuffer::createColorBuffer(int p_width, int p_height,
|
HandleType Renderer::createColorBuffer(int p_width, int p_height,
|
||||||
GLenum p_internalFormat)
|
GLenum p_internalFormat)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
@ -644,13 +570,13 @@ HandleType FrameBuffer::createColorBuffer(int p_width, int p_height,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
|
HandleType Renderer::createRenderContext(int p_config, HandleType p_share,
|
||||||
bool p_isGL2)
|
bool p_isGL2)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
HandleType ret = 0;
|
HandleType ret = 0;
|
||||||
|
|
||||||
const FbConfig* config = getConfigs()->get(p_config);
|
const RendererConfig* config = getConfigs()->get(p_config);
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -677,13 +603,13 @@ HandleType FrameBuffer::createRenderContext(int p_config, HandleType p_share,
|
||||||
return ret;
|
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);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
||||||
HandleType ret = 0;
|
HandleType ret = 0;
|
||||||
|
|
||||||
const FbConfig* config = getConfigs()->get(p_config);
|
const RendererConfig* config = getConfigs()->get(p_config);
|
||||||
if (!config) {
|
if (!config) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -700,7 +626,7 @@ HandleType FrameBuffer::createWindowSurface(int p_config, int p_width, int p_hei
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::drainRenderContext()
|
void Renderer::drainRenderContext()
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
RenderThreadInfo *tinfo = RenderThreadInfo::get();
|
RenderThreadInfo *tinfo = RenderThreadInfo::get();
|
||||||
|
|
@ -713,7 +639,7 @@ void FrameBuffer::drainRenderContext()
|
||||||
tinfo->m_contextSet.clear();
|
tinfo->m_contextSet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::drainWindowSurface()
|
void Renderer::drainWindowSurface()
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
RenderThreadInfo *tinfo = RenderThreadInfo::get();
|
RenderThreadInfo *tinfo = RenderThreadInfo::get();
|
||||||
|
|
@ -735,7 +661,7 @@ void FrameBuffer::drainWindowSurface()
|
||||||
tinfo->m_windowSet.clear();
|
tinfo->m_windowSet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::DestroyRenderContext(HandleType p_context)
|
void Renderer::DestroyRenderContext(HandleType p_context)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
m_contexts.erase(p_context);
|
m_contexts.erase(p_context);
|
||||||
|
|
@ -744,7 +670,7 @@ void FrameBuffer::DestroyRenderContext(HandleType p_context)
|
||||||
tinfo->m_contextSet.erase(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);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
if (m_windows.find(p_surface) != m_windows.end()) {
|
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);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
|
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
|
||||||
|
|
@ -768,7 +694,7 @@ int FrameBuffer::openColorBuffer(HandleType p_colorbuffer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::closeColorBuffer(HandleType p_colorbuffer)
|
void Renderer::closeColorBuffer(HandleType p_colorbuffer)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
|
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);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
||||||
|
|
@ -801,7 +727,7 @@ bool FrameBuffer::flushWindowSurfaceColorBuffer(HandleType p_surface)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
|
bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface,
|
||||||
HandleType p_colorbuffer)
|
HandleType p_colorbuffer)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
@ -825,7 +751,7 @@ bool FrameBuffer::setWindowSurfaceColorBuffer(HandleType p_surface,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBuffer::readColorBuffer(HandleType p_colorbuffer,
|
void Renderer::readColorBuffer(HandleType p_colorbuffer,
|
||||||
int x, int y, int width, int height,
|
int x, int y, int width, int height,
|
||||||
GLenum format, GLenum type, void *pixels)
|
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);
|
(*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,
|
int x, int y, int width, int height,
|
||||||
GLenum format, GLenum type, void *pixels)
|
GLenum format, GLenum type, void *pixels)
|
||||||
{
|
{
|
||||||
|
|
@ -857,7 +783,7 @@ bool FrameBuffer::updateColorBuffer(HandleType p_colorbuffer,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
|
bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
||||||
|
|
@ -870,7 +796,7 @@ bool FrameBuffer::bindColorBufferToTexture(HandleType p_colorbuffer)
|
||||||
return (*c).second.cb->bindToTexture();
|
return (*c).second.cb->bindToTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
|
bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
|
||||||
{
|
{
|
||||||
emugl::Mutex::AutoLock mutex(m_lock);
|
emugl::Mutex::AutoLock mutex(m_lock);
|
||||||
|
|
||||||
|
|
@ -883,7 +809,7 @@ bool FrameBuffer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer)
|
||||||
return (*c).second.cb->bindToRenderbuffer();
|
return (*c).second.cb->bindToRenderbuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::bindContext(HandleType p_context,
|
bool Renderer::bindContext(HandleType p_context,
|
||||||
HandleType p_drawSurface,
|
HandleType p_drawSurface,
|
||||||
HandleType p_readSurface)
|
HandleType p_readSurface)
|
||||||
{
|
{
|
||||||
|
|
@ -972,7 +898,7 @@ bool FrameBuffer::bindContext(HandleType p_context,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleType FrameBuffer::createClientImage(HandleType context, EGLenum target, GLuint buffer)
|
HandleType Renderer::createClientImage(HandleType context, EGLenum target, GLuint buffer)
|
||||||
{
|
{
|
||||||
RenderContextPtr ctx(NULL);
|
RenderContextPtr ctx(NULL);
|
||||||
|
|
||||||
|
|
@ -994,7 +920,7 @@ HandleType FrameBuffer::createClientImage(HandleType context, EGLenum target, GL
|
||||||
return (HandleType)reinterpret_cast<uintptr_t>(image);
|
return (HandleType)reinterpret_cast<uintptr_t>(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
EGLBoolean FrameBuffer::destroyClientImage(HandleType image)
|
EGLBoolean Renderer::destroyClientImage(HandleType image)
|
||||||
{
|
{
|
||||||
return s_egl.eglDestroyImageKHR(m_eglDisplay,
|
return s_egl.eglDestroyImageKHR(m_eglDisplay,
|
||||||
reinterpret_cast<EGLImageKHR>(image));
|
reinterpret_cast<EGLImageKHR>(image));
|
||||||
|
|
@ -1003,7 +929,7 @@ EGLBoolean FrameBuffer::destroyClientImage(HandleType image)
|
||||||
//
|
//
|
||||||
// The framebuffer lock should be held when calling this function !
|
// The framebuffer lock should be held when calling this function !
|
||||||
//
|
//
|
||||||
bool FrameBuffer::bind_locked()
|
bool Renderer::bind_locked()
|
||||||
{
|
{
|
||||||
EGLContext prevContext = s_egl.eglGetCurrentContext();
|
EGLContext prevContext = s_egl.eglGetCurrentContext();
|
||||||
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
|
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
|
||||||
|
|
@ -1021,32 +947,25 @@ bool FrameBuffer::bind_locked()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::bindSubwin_locked()
|
bool Renderer::bindWindow_locked(RendererWindow *window)
|
||||||
{
|
{
|
||||||
EGLContext prevContext = s_egl.eglGetCurrentContext();
|
EGLContext prevContext = s_egl.eglGetCurrentContext();
|
||||||
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
|
EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
|
||||||
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
|
EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
|
||||||
|
|
||||||
if (!s_egl.eglMakeCurrent(m_eglDisplay, m_eglSurface,
|
if (!s_egl.eglMakeCurrent(m_eglDisplay, window->surface,
|
||||||
m_eglSurface, m_eglContext)) {
|
window->surface, m_eglContext)) {
|
||||||
ERR("eglMakeCurrent failed\n");
|
ERR("eglMakeCurrent failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// initialize GL state in eglContext if not yet initilaized
|
|
||||||
//
|
|
||||||
if (!m_eglContextInitialized) {
|
|
||||||
m_eglContextInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_prevContext = prevContext;
|
m_prevContext = prevContext;
|
||||||
m_prevReadSurf = prevReadSurf;
|
m_prevReadSurf = prevReadSurf;
|
||||||
m_prevDrawSurf = prevDrawSurf;
|
m_prevDrawSurf = prevDrawSurf;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::unbind_locked()
|
bool Renderer::unbind_locked()
|
||||||
{
|
{
|
||||||
if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
|
if (!s_egl.eglMakeCurrent(m_eglDisplay, m_prevDrawSurf,
|
||||||
m_prevReadSurf, m_prevContext)) {
|
m_prevReadSurf, m_prevContext)) {
|
||||||
|
|
@ -1059,102 +978,199 @@ bool FrameBuffer::unbind_locked()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::post(HandleType p_colorbuffer, bool needLock)
|
const GLchar* const Renderer::vshader =
|
||||||
{
|
{
|
||||||
if (needLock) {
|
"attribute vec3 position;\n"
|
||||||
m_lock.lock();
|
"attribute vec2 texcoord;\n"
|
||||||
}
|
"uniform mat4 screen_to_gl_coords;\n"
|
||||||
bool ret = false;
|
"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) );
|
const GLchar* const Renderer::alphaFShader =
|
||||||
if (c == m_colorbuffers.end()) {
|
{
|
||||||
goto EXIT;
|
"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) {
|
void Renderer::setupViewport(RendererWindow *window, const anbox::graphics::Rect &rect)
|
||||||
// bind the subwindow eglSurface
|
{
|
||||||
if (!bindSubwin_locked()) {
|
/*
|
||||||
ERR("FrameBuffer::post(): eglMakeCurrent failed\n");
|
* Here we provide a 3D perspective projection with a default 30 degrees
|
||||||
goto EXIT;
|
* 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];
|
* Perspective division is one thing that can't be done in a matrix
|
||||||
s_gles2.glGetIntegerv(GL_VIEWPORT, vp);
|
* 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,
|
float const vertical_fov_degrees = 30.0f;
|
||||||
// but the framebuffer includes DPR
|
float const near =
|
||||||
vp[2] = vp[2] / m_dpr;
|
(rect.height() / 2.0f) /
|
||||||
vp[3] = vp[3] / m_dpr;
|
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"
|
window->screen_to_gl_coords = glm::scale(window->screen_to_gl_coords,
|
||||||
// multiply by 2 because the texture goes from -1 to 1, not 0 to 1
|
glm::vec3{2.0f / rect.width(),
|
||||||
float fx = 2.f * (vp[2] - m_windowWidth) / (float) vp[2];
|
-2.0f / rect.height(),
|
||||||
float fy = 2.f * (vp[3] - m_windowHeight) / (float) vp[3];
|
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
|
window->viewport = rect;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FrameBuffer::repost() {
|
void Renderer::tessellate(std::vector<anbox::graphics::Primitive>& primitives,
|
||||||
if (m_lastPostedColorBuffer) {
|
const anbox::graphics::Rect &buf_size,
|
||||||
return post(m_lastPostedColorBuffer);
|
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<GLfloat>(rect.width()) /
|
||||||
|
buf_size.width();
|
||||||
|
GLfloat tex_bottom = static_cast<GLfloat>(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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -18,13 +18,18 @@
|
||||||
|
|
||||||
#include "ColorBuffer.h"
|
#include "ColorBuffer.h"
|
||||||
#include "emugl/common/mutex.h"
|
#include "emugl/common/mutex.h"
|
||||||
#include "FbConfig.h"
|
#include "RendererConfig.h"
|
||||||
#include "RenderContext.h"
|
#include "RenderContext.h"
|
||||||
#include "TextureDraw.h"
|
#include "TextureDraw.h"
|
||||||
#include "WindowSurface.h"
|
#include "WindowSurface.h"
|
||||||
|
|
||||||
#include "OpenglRender/render_api.h"
|
#include "OpenglRender/render_api.h"
|
||||||
|
|
||||||
|
#include "Renderable.h"
|
||||||
|
|
||||||
|
#include "anbox/graphics/program_family.h"
|
||||||
|
#include "anbox/graphics/primitives.h"
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -51,13 +56,15 @@ typedef std::map<HandleType, ColorBufferRef> ColorBufferMap;
|
||||||
// extension is supported.
|
// extension is supported.
|
||||||
// |eglMajor| and |eglMinor| are the major and minor version numbers of
|
// |eglMajor| and |eglMinor| are the major and minor version numbers of
|
||||||
// the underlying EGL implementation.
|
// the underlying EGL implementation.
|
||||||
struct FrameBufferCaps {
|
struct RendererCaps {
|
||||||
bool has_eglimage_texture_2d;
|
bool has_eglimage_texture_2d;
|
||||||
bool has_eglimage_renderbuffer;
|
bool has_eglimage_renderbuffer;
|
||||||
EGLint eglMajor;
|
EGLint eglMajor;
|
||||||
EGLint eglMinor;
|
EGLint eglMinor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RendererWindow;
|
||||||
|
|
||||||
// The FrameBuffer class holds the global state of the emulation library on
|
// The FrameBuffer class holds the global state of the emulation library on
|
||||||
// top of the underlying EGL/GLES implementation. It should probably be
|
// top of the underlying EGL/GLES implementation. It should probably be
|
||||||
// named "Display" instead of "FrameBuffer".
|
// named "Display" instead of "FrameBuffer".
|
||||||
|
|
@ -65,7 +72,7 @@ struct FrameBufferCaps {
|
||||||
// There is only one global instance, that can be retrieved with getFB(),
|
// There is only one global instance, that can be retrieved with getFB(),
|
||||||
// and which must be previously setup by calling initialize().
|
// and which must be previously setup by calling initialize().
|
||||||
//
|
//
|
||||||
class FrameBuffer {
|
class Renderer {
|
||||||
public:
|
public:
|
||||||
// Initialize the global instance.
|
// Initialize the global instance.
|
||||||
// |width| and |height| are the dimensions of the emulator GPU display
|
// |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
|
// own sub-windows. If false, this means the caller will use
|
||||||
// setPostCallback() instead to retrieve the content.
|
// setPostCallback() instead to retrieve the content.
|
||||||
// Returns true on success, false otherwise.
|
// Returns true on success, false otherwise.
|
||||||
static bool initialize(EGLNativeDisplayType nativeDisplay, int width, int height, bool useSubWindow);
|
static bool initialize(EGLNativeDisplayType nativeDisplay);
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
// Finalize the instance.
|
// Finalize the instance.
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
// Return a pointer to the global instance. initialize() must be called
|
// Return a pointer to the global instance. initialize() must be called
|
||||||
// previously, or this will return NULL.
|
// 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.
|
// Return the capabilities of the underlying display.
|
||||||
const FrameBufferCaps &getCaps() const { return m_caps; }
|
const RendererCaps &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; }
|
|
||||||
|
|
||||||
// Return the list of configs available from this display.
|
// 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
|
// 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,
|
// is updated. This can be relatively slow with host-based GPU emulation,
|
||||||
|
|
@ -138,6 +112,10 @@ public:
|
||||||
*version = m_glVersion;
|
*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.
|
// Create a new RenderContext instance for this display instance.
|
||||||
// |p_config| is the index of one of the configs returned by getConfigs().
|
// |p_config| is the index of one of the configs returned by getConfigs().
|
||||||
// |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
|
// |p_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,
|
int x, int y, int width, int height,
|
||||||
GLenum format, GLenum type, void *pixels);
|
GLenum format, GLenum type, void *pixels);
|
||||||
|
|
||||||
// Display the content of a given ColorBuffer into the framebuffer's
|
bool draw(EGLNativeWindowType native_window, const anbox::graphics::Rect &window_frame, const RenderableList &renderables);
|
||||||
// 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();
|
|
||||||
|
|
||||||
// Return the host EGLDisplay used by this instance.
|
// Return the host EGLDisplay used by this instance.
|
||||||
EGLDisplay getDisplay() const { return m_eglDisplay; }
|
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
|
// Return a TextureDraw instance that can be used with this surfaces
|
||||||
// and windows created by this instance.
|
// and windows created by this instance.
|
||||||
TextureDraw* getTextureDraw() const { return m_textureDraw; }
|
TextureDraw* getTextureDraw() const { return m_textureDraw; }
|
||||||
|
|
@ -301,34 +249,32 @@ public:
|
||||||
bool unbind_locked();
|
bool unbind_locked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameBuffer(int p_width, int p_height, bool useSubWindow);
|
Renderer();
|
||||||
~FrameBuffer();
|
~Renderer();
|
||||||
HandleType genHandle();
|
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<anbox::graphics::Primitive>& primitives,
|
||||||
|
const anbox::graphics::Rect &buf_size,
|
||||||
|
const Renderable &renderable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static FrameBuffer *s_theFrameBuffer;
|
static Renderer *s_renderer;
|
||||||
static HandleType s_nextHandle;
|
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;
|
emugl::Mutex m_lock;
|
||||||
FbConfigList* m_configs;
|
RendererConfigList* m_configs;
|
||||||
FBNativeWindowType m_nativeWindow;
|
FBNativeWindowType m_nativeWindow;
|
||||||
FrameBufferCaps m_caps;
|
RendererCaps m_caps;
|
||||||
EGLDisplay m_eglDisplay;
|
EGLDisplay m_eglDisplay;
|
||||||
RenderContextMap m_contexts;
|
RenderContextMap m_contexts;
|
||||||
WindowSurfaceMap m_windows;
|
WindowSurfaceMap m_windows;
|
||||||
ColorBufferMap m_colorbuffers;
|
ColorBufferMap m_colorbuffers;
|
||||||
ColorBuffer::Helper* m_colorBufferHelper;
|
ColorBuffer::Helper* m_colorBufferHelper;
|
||||||
|
|
||||||
EGLSurface m_eglSurface;
|
|
||||||
EGLContext m_eglContext;
|
EGLContext m_eglContext;
|
||||||
EGLSurface m_pbufSurface;
|
EGLSurface m_pbufSurface;
|
||||||
EGLContext m_pbufContext;
|
EGLContext m_pbufContext;
|
||||||
|
|
@ -336,25 +282,43 @@ private:
|
||||||
EGLContext m_prevContext;
|
EGLContext m_prevContext;
|
||||||
EGLSurface m_prevReadSurf;
|
EGLSurface m_prevReadSurf;
|
||||||
EGLSurface m_prevDrawSurf;
|
EGLSurface m_prevDrawSurf;
|
||||||
EGLNativeWindowType m_subWin;
|
|
||||||
TextureDraw* m_textureDraw;
|
TextureDraw* m_textureDraw;
|
||||||
EGLConfig m_eglConfig;
|
EGLConfig m_eglConfig;
|
||||||
HandleType m_lastPostedColorBuffer;
|
HandleType m_lastPostedColorBuffer;
|
||||||
float m_zRot;
|
|
||||||
float m_px;
|
|
||||||
float m_py;
|
|
||||||
bool m_eglContextInitialized;
|
|
||||||
|
|
||||||
int m_statsNumFrames;
|
int m_statsNumFrames;
|
||||||
long long m_statsStartTime;
|
long long m_statsStartTime;
|
||||||
bool m_fpsStats;
|
bool m_fpsStats;
|
||||||
|
|
||||||
OnPostFn m_onPost;
|
|
||||||
void* m_onPostContext;
|
|
||||||
unsigned char* m_fbImage;
|
|
||||||
|
|
||||||
const char* m_glVendor;
|
const char* m_glVendor;
|
||||||
const char* m_glRenderer;
|
const char* m_glRenderer;
|
||||||
const char* m_glVersion;
|
const char* m_glVersion;
|
||||||
|
|
||||||
|
std::map<EGLNativeWindowType,RendererWindow*> m_nativeWindows;
|
||||||
|
|
||||||
|
anbox::graphics::ProgramFamily m_family;
|
||||||
|
struct Program
|
||||||
|
{
|
||||||
|
GLuint id = 0;
|
||||||
|
GLint tex_uniform = -1;
|
||||||
|
GLint position_attr = -1;
|
||||||
|
GLint texcoord_attr = -1;
|
||||||
|
GLint center_uniform = -1;
|
||||||
|
GLint display_transform_uniform = -1;
|
||||||
|
GLint transform_uniform = -1;
|
||||||
|
GLint screen_to_gl_coords_uniform = -1;
|
||||||
|
GLint alpha_uniform = -1;
|
||||||
|
mutable long long last_used_frameno = 0;
|
||||||
|
|
||||||
|
Program(GLuint program_id);
|
||||||
|
Program() {}
|
||||||
|
};
|
||||||
|
Program m_defaultProgram, m_alphaProgram;
|
||||||
|
|
||||||
|
std::vector<anbox::graphics::Primitive> m_primitives;
|
||||||
|
|
||||||
|
static const GLchar* const vshader;
|
||||||
|
static const GLchar* const defaultFShader;
|
||||||
|
static const GLchar* const alphaFShader;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "FbConfig.h"
|
#include "RendererConfig.h"
|
||||||
|
|
||||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||||
|
|
||||||
|
|
@ -92,11 +92,11 @@ bool isCompatibleHostConfig(EGLConfig config, EGLDisplay display) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
FbConfig::~FbConfig() {
|
RendererConfig::~RendererConfig() {
|
||||||
delete [] mAttribValues;
|
delete [] mAttribValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
FbConfig::FbConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) :
|
RendererConfig::RendererConfig(EGLConfig hostConfig, EGLDisplay hostDisplay) :
|
||||||
mEglConfig(hostConfig), mAttribValues(NULL) {
|
mEglConfig(hostConfig), mAttribValues(NULL) {
|
||||||
mAttribValues = new GLint[kConfigAttributesLen];
|
mAttribValues = new GLint[kConfigAttributesLen];
|
||||||
for (size_t i = 0; i < kConfigAttributesLen; ++i) {
|
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) {
|
mCount(0), mConfigs(NULL), mDisplay(display) {
|
||||||
if (display == EGL_NO_DISPLAY) {
|
if (display == EGL_NO_DISPLAY) {
|
||||||
E("%s: Invalid display value %p (EGL_NO_DISPLAY)\n",
|
E("%s: Invalid display value %p (EGL_NO_DISPLAY)\n",
|
||||||
|
|
@ -130,27 +130,27 @@ FbConfigList::FbConfigList(EGLDisplay display) :
|
||||||
EGLConfig* hostConfigs = new EGLConfig[numHostConfigs];
|
EGLConfig* hostConfigs = new EGLConfig[numHostConfigs];
|
||||||
s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs);
|
s_egl.eglGetConfigs(display, hostConfigs, numHostConfigs, &numHostConfigs);
|
||||||
|
|
||||||
mConfigs = new FbConfig*[numHostConfigs];
|
mConfigs = new RendererConfig*[numHostConfigs];
|
||||||
for (EGLint i = 0; i < numHostConfigs; ++i) {
|
for (EGLint i = 0; i < numHostConfigs; ++i) {
|
||||||
// Filter out configs that are not compatible with our implementation.
|
// Filter out configs that are not compatible with our implementation.
|
||||||
if (!isCompatibleHostConfig(hostConfigs[i], display)) {
|
if (!isCompatibleHostConfig(hostConfigs[i], display)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
mConfigs[mCount] = new FbConfig(hostConfigs[i], display);
|
mConfigs[mCount] = new RendererConfig(hostConfigs[i], display);
|
||||||
mCount++;
|
mCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete [] hostConfigs;
|
delete [] hostConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
FbConfigList::~FbConfigList() {
|
RendererConfigList::~RendererConfigList() {
|
||||||
for (int n = 0; n < mCount; ++n) {
|
for (int n = 0; n < mCount; ++n) {
|
||||||
delete mConfigs[n];
|
delete mConfigs[n];
|
||||||
}
|
}
|
||||||
delete [] mConfigs;
|
delete [] mConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FbConfigList::chooseConfig(const EGLint* attribs,
|
int RendererConfigList::chooseConfig(const EGLint* attribs,
|
||||||
EGLint* configs,
|
EGLint* configs,
|
||||||
EGLint configsSize) const {
|
EGLint configsSize) const {
|
||||||
EGLint numHostConfigs = 0;
|
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 {
|
EGLint* numAttributes) const {
|
||||||
if (numConfigs) {
|
if (numConfigs) {
|
||||||
*numConfigs = mCount;
|
*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<GLuint>(kConfigAttributesLen);
|
GLuint numAttribs = static_cast<GLuint>(kConfigAttributesLen);
|
||||||
GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
|
GLuint kGLuintSize = static_cast<GLuint>(sizeof(GLuint));
|
||||||
GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize;
|
GLuint neededByteSize = (mCount + 1) * numAttribs * kGLuintSize;
|
||||||
|
|
@ -32,10 +32,10 @@
|
||||||
// One doesn't create an FbConfig instance. Instead, create and initialize
|
// One doesn't create an FbConfig instance. Instead, create and initialize
|
||||||
// an FbConfigList from the host EGLDisplay, and use its size() and get()
|
// an FbConfigList from the host EGLDisplay, and use its size() and get()
|
||||||
// methods to access it.
|
// methods to access it.
|
||||||
class FbConfig {
|
class RendererConfig {
|
||||||
public:
|
public:
|
||||||
// Destructor
|
// Destructor
|
||||||
~FbConfig();
|
~RendererConfig();
|
||||||
|
|
||||||
// Retrieve host EGLConfig.
|
// Retrieve host EGLConfig.
|
||||||
EGLConfig getEglConfig() const { return mEglConfig; }
|
EGLConfig getEglConfig() const { return mEglConfig; }
|
||||||
|
|
@ -57,12 +57,12 @@ public:
|
||||||
GLint getConfigId() const { return (GLint)getAttribValue(4); }
|
GLint getConfigId() const { return (GLint)getAttribValue(4); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FbConfig();
|
RendererConfig();
|
||||||
FbConfig(FbConfig& other);
|
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 {
|
GLuint getAttribValue(int n) const {
|
||||||
return mAttribValues ? mAttribValues[n] : 0U;
|
return mAttribValues ? mAttribValues[n] : 0U;
|
||||||
|
|
@ -91,7 +91,7 @@ private:
|
||||||
//
|
//
|
||||||
// 5) Use getPackInfo() and packConfigs() to retrieve information about
|
// 5) Use getPackInfo() and packConfigs() to retrieve information about
|
||||||
// available configs to the guest.
|
// available configs to the guest.
|
||||||
class FbConfigList {
|
class RendererConfigList {
|
||||||
public:
|
public:
|
||||||
// Create a new list of FbConfig instance, by querying all compatible
|
// Create a new list of FbConfig instance, by querying all compatible
|
||||||
// host configs from |display|. A compatible config is one that supports
|
// 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.
|
// After construction, call empty() to check if there are items.
|
||||||
// An empty list means there was an error during construction.
|
// An empty list means there was an error during construction.
|
||||||
explicit FbConfigList(EGLDisplay display);
|
explicit RendererConfigList(EGLDisplay display);
|
||||||
|
|
||||||
// Destructor.
|
// Destructor.
|
||||||
~FbConfigList();
|
~RendererConfigList();
|
||||||
|
|
||||||
// Return true iff the list is empty. true means there was an error
|
// Return true iff the list is empty. true means there was an error
|
||||||
// during construction.
|
// during construction.
|
||||||
|
|
@ -116,7 +116,7 @@ public:
|
||||||
// Retrieve the FbConfig instance associated with |guestId|,
|
// Retrieve the FbConfig instance associated with |guestId|,
|
||||||
// which must be an integer between 0 and |size() - 1|. Returns
|
// which must be an integer between 0 and |size() - 1|. Returns
|
||||||
// NULL in case of failure.
|
// NULL in case of failure.
|
||||||
const FbConfig* get(int guestId) const {
|
const RendererConfig* get(int guestId) const {
|
||||||
if (guestId >= 0 && guestId < mCount) {
|
if (guestId >= 0 && guestId < mCount) {
|
||||||
return mConfigs[guestId];
|
return mConfigs[guestId];
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -152,11 +152,11 @@ public:
|
||||||
EGLint packConfigs(GLuint bufferByteSize, GLuint* buffer) const;
|
EGLint packConfigs(GLuint bufferByteSize, GLuint* buffer) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FbConfigList();
|
RendererConfigList();
|
||||||
FbConfigList(const FbConfigList& other);
|
RendererConfigList(const RendererConfigList& other);
|
||||||
|
|
||||||
int mCount;
|
int mCount;
|
||||||
FbConfig** mConfigs;
|
RendererConfig** mConfigs;
|
||||||
EGLDisplay mDisplay;
|
EGLDisplay mDisplay;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -19,14 +19,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#else
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SocketStream::SocketStream(size_t bufSize) :
|
SocketStream::SocketStream(size_t bufSize) :
|
||||||
IOStream(bufSize),
|
IOStream(bufSize),
|
||||||
|
|
@ -48,10 +43,8 @@ SocketStream::~SocketStream()
|
||||||
{
|
{
|
||||||
if (m_sock >= 0) {
|
if (m_sock >= 0) {
|
||||||
forceStop();
|
forceStop();
|
||||||
#ifndef _WIN32
|
|
||||||
if(close(m_sock) < 0)
|
if(close(m_sock) < 0)
|
||||||
perror("Closing SocketStream failed");
|
perror("Closing SocketStream failed");
|
||||||
#endif
|
|
||||||
// DBG("SocketStream::~close @ %d \n", m_sock);
|
// DBG("SocketStream::~close @ %d \n", m_sock);
|
||||||
m_sock = -1;
|
m_sock = -1;
|
||||||
}
|
}
|
||||||
|
|
@ -169,15 +162,5 @@ int SocketStream::recv(void *buf, size_t len)
|
||||||
|
|
||||||
void SocketStream::forceStop() {
|
void SocketStream::forceStop() {
|
||||||
// Shutdown socket to force read/write errors.
|
// 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);
|
::shutdown(m_sock, SHUT_RDWR);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
@ -22,12 +22,8 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#else
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LISTEN_BACKLOG 4
|
#define LISTEN_BACKLOG 4
|
||||||
|
|
||||||
|
|
@ -57,20 +57,14 @@ GLuint createShader(GLint shaderType, const char* shaderText) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No scaling / projection since we want to fill the whole viewport with
|
// No scaling / projection since we want to fill the whole viewport with
|
||||||
// the texture, hence a trivial vertex shader that only supports clockwise
|
// the texture, hence a trivial vertex shader.
|
||||||
// rotation.
|
|
||||||
const char kVertexShaderSource[] =
|
const char kVertexShaderSource[] =
|
||||||
"attribute vec4 position;\n"
|
"attribute vec4 position;\n"
|
||||||
"attribute vec2 inCoord;\n"
|
"attribute vec2 inCoord;\n"
|
||||||
"varying lowp vec2 outCoord;\n"
|
"varying lowp vec2 outCoord;\n"
|
||||||
"uniform float rotation;\n"
|
|
||||||
"uniform vec2 translation;\n"
|
|
||||||
|
|
||||||
"void main(void) {\n"
|
"void main(void) {\n"
|
||||||
" float cs = cos(rotation);\n"
|
" gl_Position.x = position.x;\n"
|
||||||
" float sn = sin(rotation);\n"
|
" gl_Position.y = position.y;\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.zw = position.zw;\n"
|
" gl_Position.zw = position.zw;\n"
|
||||||
" outCoord = inCoord;\n"
|
" outCoord = inCoord;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
@ -142,15 +136,8 @@ TextureDraw::TextureDraw(EGLDisplay display) :
|
||||||
mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord");
|
mInCoordSlot = s_gles2.glGetAttribLocation(mProgram, "inCoord");
|
||||||
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
|
s_gles2.glEnableVertexAttribArray(mInCoordSlot);
|
||||||
|
|
||||||
mRotationSlot = s_gles2.glGetUniformLocation(mProgram, "rotation");
|
|
||||||
mTranslationSlot = s_gles2.glGetUniformLocation(mProgram, "translation");
|
|
||||||
mTextureSlot = s_gles2.glGetUniformLocation(mProgram, "texture");
|
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.
|
// Create vertex and index buffers.
|
||||||
s_gles2.glGenBuffers(1, &mVertexBuffer);
|
s_gles2.glGenBuffers(1, &mVertexBuffer);
|
||||||
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
s_gles2.glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
|
||||||
|
|
@ -165,7 +152,7 @@ TextureDraw::TextureDraw(EGLDisplay display) :
|
||||||
GL_STATIC_DRAW);
|
GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureDraw::draw(GLuint texture, float rotation, float dx, float dy) {
|
bool TextureDraw::draw(GLuint texture) {
|
||||||
if (!mProgram) {
|
if (!mProgram) {
|
||||||
ERR("%s: no program\n", __FUNCTION__);
|
ERR("%s: no program\n", __FUNCTION__);
|
||||||
return false;
|
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.glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
s_gles2.glUniform1i(mTextureSlot, 0);
|
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.
|
// Validate program, just to be sure.
|
||||||
s_gles2.glValidateProgram(mProgram);
|
s_gles2.glValidateProgram(mProgram);
|
||||||
GLint validState = 0;
|
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);
|
ERR("%s: Could not run program: %s\n", __FUNCTION__, messages);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Do the rendering.
|
// Do the rendering.
|
||||||
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
|
s_gles2.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
|
||||||
|
|
@ -38,11 +38,8 @@ public:
|
||||||
~TextureDraw();
|
~TextureDraw();
|
||||||
|
|
||||||
// Fill the current framebuffer with the content of |texture|, which must
|
// Fill the current framebuffer with the content of |texture|, which must
|
||||||
// be the name of a GLES 2.x texture object. |rotationDegrees| is a
|
// be the name of a GLES 2.x texture object.
|
||||||
// clockwise rotation angle in degrees (clockwise in the GL Y-upwards
|
bool draw(GLuint texture);
|
||||||
// coordinate space). |dx,dy| is the translation of the image towards the
|
|
||||||
// origin.
|
|
||||||
bool draw(GLuint texture, float rotationDegrees, float dx, float dy);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EGLDisplay mDisplay;
|
EGLDisplay mDisplay;
|
||||||
|
|
@ -15,55 +15,21 @@
|
||||||
*/
|
*/
|
||||||
#include "TimeUtils.h"
|
#include "TimeUtils.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#else
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
long long GetCurrentTimeMS()
|
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;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec/1000000LL;
|
long long iDiff = (now.tv_sec * 1000LL) + now.tv_nsec/1000000LL;
|
||||||
return iDiff;
|
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)
|
void TimeSleepMS(int p_mili)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
|
||||||
Sleep(p_mili);
|
|
||||||
#else
|
|
||||||
usleep(p_mili * 1000);
|
usleep(p_mili * 1000);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
#include "WindowSurface.h"
|
#include "WindowSurface.h"
|
||||||
|
|
||||||
#include "ErrorLog.h"
|
#include "ErrorLog.h"
|
||||||
#include "FbConfig.h"
|
#include "RendererConfig.h"
|
||||||
|
|
||||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||||
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
#include "anbox/graphics/gl_renderer_server.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"
|
#include "OpenglRender/render_api.h"
|
||||||
|
|
||||||
|
|
@ -27,8 +29,10 @@
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
GLRendererServer::GLRendererServer(const std::shared_ptr<WindowCreator> &window_creator) :
|
GLRendererServer::GLRendererServer(const std::shared_ptr<wm::Manager> &wm) :
|
||||||
window_creator_(window_creator) {
|
wm_(wm),
|
||||||
|
composer_(std::make_shared<LayerComposer>(wm))
|
||||||
|
{
|
||||||
|
|
||||||
if (utils::is_env_set("USE_HOST_GLES")) {
|
if (utils::is_env_set("USE_HOST_GLES")) {
|
||||||
// Force the host EGL/GLES libraries as translator implementation
|
// Force the host EGL/GLES libraries as translator implementation
|
||||||
|
|
@ -45,13 +49,10 @@ GLRendererServer::GLRendererServer(const std::shared_ptr<WindowCreator> &window_
|
||||||
if (!initLibrary())
|
if (!initLibrary())
|
||||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
||||||
|
|
||||||
setStreamMode(RENDER_API_STREAM_MODE_UNIX);
|
registerLayerComposer(composer_);
|
||||||
|
|
||||||
registerSubWindowHandler(window_creator_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLRendererServer::~GLRendererServer() {
|
GLRendererServer::~GLRendererServer() {
|
||||||
destroyOpenGLSubwindow();
|
|
||||||
stopOpenGLRenderer();
|
stopOpenGLRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,24 +72,14 @@ void GLRendererServer::start() {
|
||||||
log_funcs.coarse = logger_write;
|
log_funcs.coarse = logger_write;
|
||||||
log_funcs.fine = 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 };
|
char server_addr[256] = { 0 };
|
||||||
// The width & height we supply here are the dimensions the internal framebuffer
|
// 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
|
// will use. Making this static prevents us for now to resize the window we create
|
||||||
// later for the actual display.
|
// 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"));
|
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to setup OpenGL renderer"));
|
||||||
|
|
||||||
socket_path_ = server_addr;
|
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 {
|
std::string GLRendererServer::socket_path() const {
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@ namespace anbox {
|
||||||
namespace input {
|
namespace input {
|
||||||
class Manager;
|
class Manager;
|
||||||
} // namespace input
|
} // namespace input
|
||||||
|
namespace wm {
|
||||||
|
class Manager;
|
||||||
|
} // namespace wm
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
class WindowCreator;
|
class LayerComposer;
|
||||||
class GLRendererServer {
|
class GLRendererServer {
|
||||||
public:
|
public:
|
||||||
GLRendererServer(const std::shared_ptr<WindowCreator> &window_creator);
|
GLRendererServer(const std::shared_ptr<wm::Manager> &wm);
|
||||||
~GLRendererServer();
|
~GLRendererServer();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
@ -38,7 +41,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string socket_path_;
|
std::string socket_path_;
|
||||||
std::shared_ptr<WindowCreator> window_creator_;
|
std::shared_ptr<wm::Manager> wm_;
|
||||||
|
std::shared_ptr<LayerComposer> composer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
|
|
||||||
101
src/anbox/graphics/layer_composer.cpp
Normal file
101
src/anbox/graphics/layer_composer.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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::Manager> &wm) :
|
||||||
|
wm_(wm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerComposer::~LayerComposer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerComposer::submit_layers(const RenderableList &renderables)
|
||||||
|
{
|
||||||
|
std::map<std::shared_ptr<wm::Window>,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
|
||||||
43
src/anbox/graphics/layer_composer.h
Normal file
43
src/anbox/graphics/layer_composer.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_LAYER_COMPOSER_H_
|
||||||
|
#define ANBOX_GRAPHICS_LAYER_COMPOSER_H_
|
||||||
|
|
||||||
|
#include "anbox/graphics/emugl/Renderable.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace wm {
|
||||||
|
class Manager;
|
||||||
|
} // namespace wm
|
||||||
|
namespace graphics {
|
||||||
|
class LayerComposer {
|
||||||
|
public:
|
||||||
|
LayerComposer(const std::shared_ptr<wm::Manager> &wm);
|
||||||
|
~LayerComposer();
|
||||||
|
|
||||||
|
void submit_layers(const RenderableList &renderables);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<wm::Manager> wm_;
|
||||||
|
};
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif
|
||||||
52
src/anbox/graphics/primitives.h
Normal file
52
src/anbox/graphics/primitives.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
* Kevin DuBois <kevin.dubois@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_PRIMITIVES_H_
|
||||||
|
#define ANBOX_GRAPHICS_PRIMITIVES_H_
|
||||||
|
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
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
|
||||||
107
src/anbox/graphics/program_family.cpp
Normal file
107
src/anbox/graphics/program_family.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
||||||
68
src/anbox/graphics/program_family.h
Normal file
68
src/anbox/graphics/program_family.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_PROGRAM_FAMILY_H_
|
||||||
|
#define ANBOX_GRAPHICS_PROGRAM_FAMILY_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <GLES2/gl2.h>
|
||||||
|
|
||||||
|
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<const GLchar*, Shader> ShaderMap;
|
||||||
|
ShaderMap vshader, fshader;
|
||||||
|
|
||||||
|
typedef std::pair<GLuint, GLuint> ShaderPair;
|
||||||
|
struct Program
|
||||||
|
{
|
||||||
|
GLuint id = 0;
|
||||||
|
};
|
||||||
|
std::map<ShaderPair, Program> program;
|
||||||
|
};
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif // MIR_RENDERER_GL_PROGRAM_FAMILY_H_
|
||||||
|
|
@ -15,21 +15,21 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.anbox.app_manager;
|
#include "anbox/graphics/rect.h"
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
#include <algorithm>
|
||||||
|
|
||||||
import android.app.Application;
|
namespace anbox {
|
||||||
import android.os.IBinder;
|
namespace graphics {
|
||||||
|
const Rect Rect::Invalid{-1,-1,-1,-1};
|
||||||
|
const Rect Rect::Empty{0,0,0,0};
|
||||||
|
|
||||||
public class MainApplication extends Application {
|
void Rect::merge(const Rect &rhs)
|
||||||
public void startServices() {
|
{
|
||||||
Method addService;
|
left_ = std::min(left_, rhs.left());
|
||||||
try {
|
top_ = std::min(top_, rhs.top());
|
||||||
addService = Class.forName("android.os.ServiceManager").getMethod("addService", String.class, IBinder.class);
|
right_ = std::max(right_, rhs.right());
|
||||||
}
|
bottom_ = std::max(bottom_, rhs.bottom());
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace graphics
|
||||||
|
} // namespace anbox
|
||||||
103
src/anbox/graphics/rect.h
Normal file
103
src/anbox/graphics/rect.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_GRAPHICS_RECT_H_
|
||||||
|
#define ANBOX_GRAPHICS_RECT_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -2,6 +2,11 @@ option optimize_for = LITE_RUNTIME;
|
||||||
|
|
||||||
package anbox.protobuf.bridge;
|
package anbox.protobuf.bridge;
|
||||||
|
|
||||||
|
message StructuredError {
|
||||||
|
optional uint32 domain = 1;
|
||||||
|
optional uint32 code = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message Notification {
|
message Notification {
|
||||||
required string package_name = 1;
|
required string package_name = 1;
|
||||||
required string category = 2;
|
required string category = 2;
|
||||||
|
|
@ -26,3 +31,34 @@ message SetDnsServers {
|
||||||
}
|
}
|
||||||
repeated Server servers = 2;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ message Invocation {
|
||||||
message Result {
|
message Result {
|
||||||
optional uint32 id = 1;
|
optional uint32 id = 1;
|
||||||
optional bytes response = 2;
|
optional bytes response = 2;
|
||||||
|
repeated bytes events = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StructuredError {
|
message StructuredError {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ BootPropertiesMessageProcessor::BootPropertiesMessageProcessor(const std::shared
|
||||||
BootPropertiesMessageProcessor::~BootPropertiesMessageProcessor() {
|
BootPropertiesMessageProcessor::~BootPropertiesMessageProcessor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BootPropertiesMessageProcessor::handle_command(const std::string &command) {
|
void BootPropertiesMessageProcessor::handle_command(const std::string &command) {
|
||||||
if (command == "list")
|
if (command == "list")
|
||||||
list_properties();
|
list_properties();
|
||||||
|
|
@ -36,43 +35,11 @@ void BootPropertiesMessageProcessor::handle_command(const std::string &command)
|
||||||
|
|
||||||
void BootPropertiesMessageProcessor::list_properties() {
|
void BootPropertiesMessageProcessor::list_properties() {
|
||||||
std::vector<std::string> properties = {
|
std::vector<std::string> 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
|
// TODO(morphis): Using HDPI here for now but should be adjusted to the device
|
||||||
// we're running on.
|
// we're running on.
|
||||||
utils::string_format("ro.sf.lcd_density=%d", static_cast<int>(graphics::DensityType::high)),
|
utils::string_format("ro.sf.lcd_density=%d", static_cast<int>(graphics::DensityType::medium)),
|
||||||
|
|
||||||
// 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",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
for (const auto &prop : properties) {
|
||||||
send_header(prop.length());
|
send_header(prop.length());
|
||||||
messenger_->send(prop.c_str(), prop.length());
|
messenger_->send(prop.c_str(), prop.length());
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ BootAnimationMessageProcessor::~BootAnimationMessageProcessor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BootAnimationMessageProcessor::handle_command(const std::string &command) {
|
void BootAnimationMessageProcessor::handle_command(const std::string &command) {
|
||||||
DEBUG("command %s", command);
|
|
||||||
if (command == "retrieve-icon")
|
if (command == "retrieve-icon")
|
||||||
retrieve_icon();
|
retrieve_icon();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ CameraMessageProcessor::~CameraMessageProcessor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CameraMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
bool CameraMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||||
DEBUG("Received: %s", utils::hex_dump(data.data(), data.size()));
|
|
||||||
|
|
||||||
for (const auto &byte : data)
|
for (const auto &byte : data)
|
||||||
buffer_.push_back(byte);
|
buffer_.push_back(byte);
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue