diff --git a/hwcomposer/Android.bp b/hwcomposer/Android.bp index 74887e36..d9342d07 100644 --- a/hwcomposer/Android.bp +++ b/hwcomposer/Android.bp @@ -38,6 +38,7 @@ cc_library_shared { "libwayland_extension_client_protocols", ], srcs: [ + "wayland-egl.c", "extension.cpp", "hwcomposer.cpp", "wayland-hwc.cpp" diff --git a/hwcomposer/hwcomposer.cpp b/hwcomposer/hwcomposer.cpp index d818d220..c05266ba 100644 --- a/hwcomposer/hwcomposer.cpp +++ b/hwcomposer/hwcomposer.cpp @@ -533,26 +533,33 @@ static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays, continue; } + const hwc_rect_t frame = fb_layer->displayFrame; + const int width = frame.right - frame.left; + const int height = frame.bottom - frame.top; + struct window *window = NULL; std::string layer_name = pdev->display->layer_names[layer]; if (active_apps == "Waydroid") { // Show everything in a single window if (pdev->windows.find(active_apps) == pdev->windows.end()) { - pdev->windows[active_apps] = create_window(pdev->display, pdev->use_subsurface, active_apps, "0"); + pdev->windows[active_apps] = create_window(pdev->display, pdev->use_subsurface, active_apps, "0", width, height); property_set("waydroid.open_windows", std::to_string(pdev->windows.size()).c_str()); } window = pdev->windows[active_apps]; } else if (!pdev->use_subsurface) { if (single_layer_tid.length()) { if (pdev->windows.find(single_layer_tid) == pdev->windows.end()) { - pdev->windows[single_layer_tid] = create_window(pdev->display, pdev->use_subsurface, single_layer_aid, single_layer_tid); + pdev->windows[single_layer_tid] = create_window(pdev->display, pdev->use_subsurface, single_layer_aid, single_layer_tid, width, height); property_set("waydroid.open_windows", std::to_string(pdev->windows.size()).c_str()); } window = pdev->windows[single_layer_tid]; + // Window is closed, don't bother - if (!window->isActive) + if (window && !window->isActive) { + free(window); window = NULL; + } } } else { // Create windows based on Task ID in layer name @@ -573,12 +580,18 @@ static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays, if (showWindow) { if (pdev->windows.find(layer_tid) == pdev->windows.end()) { - pdev->windows[layer_tid] = create_window(pdev->display, pdev->use_subsurface, layer_aid, layer_tid); + pdev->windows[layer_tid] = create_window(pdev->display, pdev->use_subsurface, layer_aid, layer_tid, width, height); property_set("waydroid.open_windows", std::to_string(pdev->windows.size()).c_str()); } if (pdev->windows.find(layer_tid) != pdev->windows.end()) window = pdev->windows[layer_tid]; } + + // Window is closed, don't bother + if (window && !window->isActive) { + free(window); + window = NULL; + } } } @@ -628,7 +641,7 @@ static int hwc_set(struct hwc_composer_device_1* dev,size_t numDisplays, } if (LayerRawName == "InputMethod") { if (pdev->windows.find(LayerRawName) == pdev->windows.end()) { - pdev->windows[LayerRawName] = create_window(pdev->display, pdev->use_subsurface, LayerRawName, "none"); + pdev->windows[LayerRawName] = create_window(pdev->display, pdev->use_subsurface, LayerRawName, "none", width, height); property_set("waydroid.open_windows", std::to_string(pdev->windows.size()).c_str()); } if (pdev->windows.find(LayerRawName) != pdev->windows.end()) @@ -1002,6 +1015,9 @@ static int hwc_open(const struct hw_module_t* module, const char* name, if (!property_get_bool("persist.waydroid.cursor_on_subsurface", false)) pdev->display->cursor_surface = wl_compositor_create_surface(pdev->display->compositor); + else + pdev->display->cursor_surface = nullptr; + if (!pdev->display->height) { pdev->display->waiting_for_data = true; pthread_cond_timedwait(&pdev->display->data_available_cond, diff --git a/hwcomposer/wayland-egl-backend.h b/hwcomposer/wayland-egl-backend.h new file mode 100644 index 00000000..e5287b76 --- /dev/null +++ b/hwcomposer/wayland-egl-backend.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2011 Benjamin Franzke + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Benjamin Franzke + */ + +#ifndef _WAYLAND_EGL_PRIV_H +#define _WAYLAND_EGL_PRIV_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * NOTE: This version must be kept in sync with the version field in the + * wayland-egl-backend pkgconfig file generated in meson.build. + */ +#define WL_EGL_WINDOW_VERSION 3 + +struct wl_surface; + +struct wl_egl_window { + const intptr_t version; + + int width; + int height; + int dx; + int dy; + + int attached_width; + int attached_height; + + void *driver_private; + void (*resize_callback)(struct wl_egl_window *, void *); + void (*destroy_window_callback)(void *); + + struct wl_surface *surface; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hwcomposer/wayland-egl.c b/hwcomposer/wayland-egl.c new file mode 100644 index 00000000..a60f8991 --- /dev/null +++ b/hwcomposer/wayland-egl.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2011 Kristian Høgsberg + * Copyright © 2011 Benjamin Franzke + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Kristian Høgsberg + * Benjamin Franzke + */ + +#include +#include + +#include "wayland-egl.h" +#include "wayland-egl-backend.h" +#include "wayland-util.h" + + +WL_EXPORT void +wl_egl_window_resize(struct wl_egl_window *egl_window, + int width, int height, + int dx, int dy) +{ + if (width <= 0 || height <= 0) + return; + + egl_window->width = width; + egl_window->height = height; + egl_window->dx = dx; + egl_window->dy = dy; + + if (egl_window->resize_callback) + egl_window->resize_callback(egl_window, egl_window->driver_private); +} + +WL_EXPORT struct wl_egl_window * +wl_egl_window_create(struct wl_surface *surface, + int width, int height) +{ + struct wl_egl_window *egl_window; + + if (width <= 0 || height <= 0) + return NULL; + + egl_window = calloc(1, sizeof *egl_window); + if (!egl_window) + return NULL; + + /* Cast away the constness to set the version number. + * + * We want the const notation since it gives an explicit + * feedback to the backend implementation, should it try to + * change it. + * + * The latter in itself is not too surprising as these days APIs + * tend to provide bidirectional version field. + */ + intptr_t *version = (intptr_t *)&egl_window->version; + *version = WL_EGL_WINDOW_VERSION; + + egl_window->surface = surface; + + egl_window->width = width; + egl_window->height = height; + + return egl_window; +} + +WL_EXPORT void +wl_egl_window_destroy(struct wl_egl_window *egl_window) +{ + if (egl_window->destroy_window_callback) + egl_window->destroy_window_callback(egl_window->driver_private); + free(egl_window); +} + +WL_EXPORT void +wl_egl_window_get_attached_size(struct wl_egl_window *egl_window, + int *width, int *height) +{ + if (width) + *width = egl_window->attached_width; + if (height) + *height = egl_window->attached_height; +} diff --git a/hwcomposer/wayland-hwc.cpp b/hwcomposer/wayland-hwc.cpp index 6a9d9af2..d18e11b6 100644 --- a/hwcomposer/wayland-hwc.cpp +++ b/hwcomposer/wayland-hwc.cpp @@ -59,6 +59,7 @@ #include #include +#include #include "linux-dmabuf-unstable-v1-client-protocol.h" #include "presentation-time-client-protocol.h" #include "xdg-shell-client-protocol.h" @@ -399,6 +400,8 @@ destroy_window(struct window *window, bool keep) wl_subsurface_destroy(window->subsurfaces[it->first]); wl_surface_destroy(it->second); } + if (window->egl_window) + wl_egl_window_destroy(window->egl_window); if (window->xdg_toplevel) xdg_toplevel_destroy(window->xdg_toplevel); if (window->xdg_surface) @@ -412,10 +415,15 @@ destroy_window(struct window *window, bool keep) window->isActive = false; else free(window); + + if (!window->appID.empty()) { + const std::string prop = std::string("waydroid.open_window.") + window->appID; + property_set(prop.c_str(), "0"); + } } struct window * -create_window(struct display *display, bool with_dummy, std::string appID, std::string taskID) +create_window(struct display *display, bool with_egl_window, std::string appID, std::string taskID, const int width, const int height) { struct window *window = new struct window(); if (!window) @@ -426,6 +434,7 @@ create_window(struct display *display, bool with_dummy, std::string appID, std:: window->surface = wl_compositor_create_surface(display->compositor); window->taskID = taskID; window->isActive = true; + window->egl_window = nullptr; if (display->wm_base) { window->xdg_surface = @@ -479,29 +488,15 @@ create_window(struct display *display, bool with_dummy, std::string appID, std:: } else { assert(0); } - /* - * We should create a dummy transparent 1x1 buffer in 0x0 location - * This allows us to set initial location of windows by setting them as subsurface - * and ovarally helps is moving surfaces - * - * TODO: Drop this hack - */ - if (with_dummy) { - int fd = syscall(SYS_memfd_create, "buffer", 0); - ftruncate(fd, 4); - void *shm_data = mmap(NULL, 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (shm_data == MAP_FAILED) { - ALOGE("mmap failed"); - close(fd); - exit(1); - } - struct wl_shm_pool *pool = wl_shm_create_pool(display->shm, fd, 4); - struct wl_buffer *buffer_shm = wl_shm_pool_create_buffer(pool, 0, 1, 1, 4, WL_SHM_FORMAT_ARGB8888); - wl_shm_pool_destroy(pool); - close(fd); - wl_surface_attach(window->surface, buffer_shm, 0, 0); - wl_surface_damage(window->surface, 0, 0, 1, 1); + + if (with_egl_window) { + window->egl_window = wl_egl_window_create(window->surface, width, height); } + + window->appID = appID; + std::string prop = std::string("waydroid.open_window.") + appID; + property_set(prop.c_str(), "1"); + return window; } diff --git a/hwcomposer/wayland-hwc.h b/hwcomposer/wayland-hwc.h index b0dc44b5..ecf25654 100644 --- a/hwcomposer/wayland-hwc.h +++ b/hwcomposer/wayland-hwc.h @@ -150,12 +150,14 @@ struct window { struct wl_shell_surface *shell_surface; struct xdg_surface *xdg_surface; struct xdg_toplevel *xdg_toplevel; + struct wl_egl_window *egl_window; std::map surfaces; std::map subsurfaces; struct wl_callback *callback; int lastLayer; std::string taskID; bool isActive; + std::string appID; }; int @@ -180,4 +182,4 @@ destroy_display(struct display *display); void destroy_window(struct window *window, bool keep = false); struct window * -create_window(struct display *display, bool with_dummy, std::string appID, std::string taskID); +create_window(struct display *display, bool with_dummy, std::string appID, std::string taskID, const int width = 1, const int height = 1);