Add initial hwcomposer implementation
This commit is contained in:
parent
cda160b3b3
commit
f2d2a41b6c
3 changed files with 282 additions and 7 deletions
10
Android.mk
10
Android.mk
|
|
@ -74,3 +74,13 @@ LOCAL_SHARED_LIBRARIES := \
|
||||||
libcutils \
|
libcutils \
|
||||||
libutils
|
libutils
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
LOCAL_MODULE_RELATIVE_PATH := hw
|
||||||
|
LOCAL_SHARED_LIBRARIES := liblog
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
android/hwcomposer/hwcomposer.cpp
|
||||||
|
LOCAL_MODULE := hwcomposer.anbox
|
||||||
|
LOCAL_CFLAGS:= -DLOG_TAG=\"hwcomposer\"
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,26 @@ target_link_libraries(anboxd
|
||||||
pthread
|
pthread
|
||||||
process-cpp
|
process-cpp
|
||||||
anbox-protobuf)
|
anbox-protobuf)
|
||||||
|
|
||||||
|
set(TEST_PLATFORM_SERVICE
|
||||||
|
service/test_platform_service.cpp)
|
||||||
|
|
||||||
|
add_executable(test_platform_service ${TEST_PLATFORM_SERVICE})
|
||||||
|
|
||||||
|
set(HWCOMPOSER_SOURCES
|
||||||
|
hwcomposer/hwcomposer.cpp)
|
||||||
|
|
||||||
|
add_library(hwcomposer.anbox SHARED ${HWCOMPOSER_SOURCES})
|
||||||
|
|
||||||
# As we're adding Android specific bits in this project we can't
|
# As we're adding Android specific bits in this project we can't
|
||||||
# build this safely within default build anymore. We keep this
|
# build this safely within default build anymore. We keep this
|
||||||
# for easy integration into used IDEs.
|
# for easy integration into used IDEs.
|
||||||
set_target_properties(anboxd
|
set_target_properties(anboxd
|
||||||
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||||
|
|
||||||
set(TEST_PLATFORM_SERVICE
|
|
||||||
service/test_platform_service.cpp)
|
|
||||||
|
|
||||||
add_executable(test_platform_service ${TEST_PLATFORM_SERVICE})
|
|
||||||
# As we're adding Android specific bits in this project we can't
|
|
||||||
# build this safely within default build anymore. We keep this
|
|
||||||
# for easy integration into used IDEs.
|
|
||||||
set_target_properties(test_platform_service
|
set_target_properties(test_platform_service
|
||||||
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||||
|
|
||||||
|
set_target_properties(hwcomposer.anbox
|
||||||
|
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||||
|
|
||||||
|
|
|
||||||
257
android/hwcomposer/hwcomposer.cpp
Normal file
257
android/hwcomposer/hwcomposer.cpp
Normal file
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* 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 <hardware/hardware.h>
|
||||||
|
#include <hardware/hwcomposer.h>
|
||||||
|
|
||||||
|
#define LOG_NDEBUG 0
|
||||||
|
#include <cutils/log.h>
|
||||||
|
|
||||||
|
struct HwcContext {
|
||||||
|
hwc_composer_device_1_t device;
|
||||||
|
|
||||||
|
// These 3 variables could be reduced to first_overlay only, however it makes
|
||||||
|
// the conditions in the code more complicated. In order to keep things as
|
||||||
|
// simple as possible, there are 3 major ways to display a frame.
|
||||||
|
// 1. Show only the framebuffer.
|
||||||
|
// 2. Show the framebuffer with some overlays above it.
|
||||||
|
// 3. Show all overlays and hide the framebuffer.
|
||||||
|
//
|
||||||
|
// Since the framebuffer has no alpha channel and is opaque, it can only ever
|
||||||
|
// be the rearmost layer that we end up putting on screen, otherwise it will
|
||||||
|
// cover up all layers behind it, since its display frame is the whole window.
|
||||||
|
//
|
||||||
|
// Without framebuffer_visible, the condition of whether to display the
|
||||||
|
// frambuffer becomes more complex and possibly if (numHwLayers == 0 ||
|
||||||
|
// hwLayers[0]->compositionType != HWC_OVERLAY) but that might not be correct.
|
||||||
|
//
|
||||||
|
// The range [first_overlay, first_overlay+num_overlay) is a natural way to
|
||||||
|
// structure the loop and prevents requiring state and iterating through all
|
||||||
|
// the non-OVERLAY layers in hwc_set.
|
||||||
|
bool framebuffer_visible;
|
||||||
|
size_t first_overlay;
|
||||||
|
size_t num_overlays;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dump_layer(hwc_layer_1_t const* l) {
|
||||||
|
ALOGI("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, {%d,%d,%d,%d}, {%d,%d,%d,%d}",
|
||||||
|
l->compositionType, l->flags, l->handle, l->transform, l->blending,
|
||||||
|
l->sourceCrop.left,
|
||||||
|
l->sourceCrop.top,
|
||||||
|
l->sourceCrop.right,
|
||||||
|
l->sourceCrop.bottom,
|
||||||
|
l->displayFrame.left,
|
||||||
|
l->displayFrame.top,
|
||||||
|
l->displayFrame.right,
|
||||||
|
l->displayFrame.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_prepare(hwc_composer_device_1_t* dev, size_t numDisplays,
|
||||||
|
hwc_display_contents_1_t** displays) {
|
||||||
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
if (displays == NULL || displays[0] == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
// Anbox only supports the primary display.
|
||||||
|
if (displays[0]->flags & HWC_GEOMETRY_CHANGED) {
|
||||||
|
const size_t& num_hw_layers = displays[0]->numHwLayers;
|
||||||
|
size_t i = 1;
|
||||||
|
bool visible = (num_hw_layers == 1);
|
||||||
|
|
||||||
|
// Iterate backwards and skip the first (end) layer, which is the
|
||||||
|
// framebuffer target layer. According to the SurfaceFlinger folks, the
|
||||||
|
// actual location of this layer is up to the HWC implementation to
|
||||||
|
// decide, but is in the well know last slot of the list. This does not
|
||||||
|
// imply that the framebuffer target layer must be topmost.
|
||||||
|
for (; i < num_hw_layers; i++) {
|
||||||
|
hwc_layer_1_t* layer = &displays[0]->hwLayers[num_hw_layers - 1 - i];
|
||||||
|
if (layer->flags & HWC_SKIP_LAYER) {
|
||||||
|
// All layers below and including this one will be drawn into the
|
||||||
|
// framebuffer. Stop marking further layers as HWC_OVERLAY.
|
||||||
|
visible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (layer->compositionType) {
|
||||||
|
case HWC_OVERLAY:
|
||||||
|
case HWC_FRAMEBUFFER:
|
||||||
|
layer->compositionType = HWC_OVERLAY;
|
||||||
|
break;
|
||||||
|
case HWC_BACKGROUND:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ALOGE("hwcomposor: Invalid compositionType %d",
|
||||||
|
layer->compositionType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context->first_overlay = num_hw_layers - i;
|
||||||
|
context->num_overlays = i - 1;
|
||||||
|
context->framebuffer_visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_set(hwc_composer_device_1_t* dev, size_t numDisplays,
|
||||||
|
hwc_display_contents_1_t** displays) {
|
||||||
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
if (displays == NULL || displays[0] == NULL)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
// FIXME Here is the point where we have to collect all layers and sent
|
||||||
|
// them over to the Anbox rendering process
|
||||||
|
|
||||||
|
for (size_t i = 0 ; i < displays[0]->numHwLayers ; i++)
|
||||||
|
dump_layer(&displays[0]->hwLayers[i]);
|
||||||
|
|
||||||
|
displays[0]->retireFenceFd = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_event_control(hwc_composer_device_1* dev, int disp,
|
||||||
|
int event, int enabled) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_get_display_configs(hwc_composer_device_1* dev, int disp,
|
||||||
|
uint32_t* configs, size_t* numConfigs) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
if (disp != 0 || config != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
|
||||||
|
while (*attributes != HWC_DISPLAY_NO_ATTRIBUTE) {
|
||||||
|
switch (*attributes) {
|
||||||
|
case HWC_DISPLAY_VSYNC_PERIOD:
|
||||||
|
*values = 1;
|
||||||
|
break;
|
||||||
|
case HWC_DISPLAY_WIDTH:
|
||||||
|
*values = 1280;
|
||||||
|
break;
|
||||||
|
case HWC_DISPLAY_HEIGHT:
|
||||||
|
*values = 720;
|
||||||
|
break;
|
||||||
|
case HWC_DISPLAY_DPI_X:
|
||||||
|
*values = 1000 * 120;
|
||||||
|
break;
|
||||||
|
case HWC_DISPLAY_DPI_Y:
|
||||||
|
*values = 1000 * 120;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ALOGE("Unknown attribute value 0x%02x", *attributes);
|
||||||
|
}
|
||||||
|
++attributes;
|
||||||
|
++values;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hwc_register_procs(hwc_composer_device_1* dev,
|
||||||
|
hwc_procs_t const* procs) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_blank(hwc_composer_device_1* dev, int disp, int blank) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_query(hwc_composer_device_1* dev, int what, int* value) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_device_close(hw_device_t* dev) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
auto context = reinterpret_cast<HwcContext*>(dev);
|
||||||
|
delete context;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwc_device_open(const hw_module_t* module, const char* name, hw_device_t** device) {
|
||||||
|
ALOGI("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
auto dev = new HwcContext;
|
||||||
|
dev->device.common.tag = HARDWARE_DEVICE_TAG;
|
||||||
|
dev->device.common.version = HWC_DEVICE_API_VERSION_1_3;
|
||||||
|
dev->device.common.module = const_cast<hw_module_t*>(module);
|
||||||
|
dev->device.common.close = hwc_device_close;
|
||||||
|
dev->device.prepare = hwc_prepare;
|
||||||
|
dev->device.set = hwc_set;
|
||||||
|
dev->device.eventControl = hwc_event_control;
|
||||||
|
dev->device.blank = hwc_blank;
|
||||||
|
dev->device.query = hwc_query;
|
||||||
|
dev->device.getDisplayConfigs = hwc_get_display_configs;
|
||||||
|
dev->device.getDisplayAttributes = hwc_get_display_attributes;
|
||||||
|
dev->device.registerProcs = hwc_register_procs;
|
||||||
|
|
||||||
|
*device = &dev->device.common;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static hw_module_methods_t hwc_module_methods = {
|
||||||
|
.open = hwc_device_open
|
||||||
|
};
|
||||||
|
|
||||||
|
hwc_module_t HAL_MODULE_INFO_SYM = {
|
||||||
|
.common = {
|
||||||
|
.tag = HARDWARE_MODULE_TAG,
|
||||||
|
.version_major = 1,
|
||||||
|
.version_minor = 0,
|
||||||
|
.id = HWC_HARDWARE_MODULE_ID,
|
||||||
|
.name = "Hardware Composer Module",
|
||||||
|
.author = "Anbox Developers",
|
||||||
|
.methods = &hwc_module_methods,
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue