Skip to content

wayland-hwc: Drop dummy window hack & QtMir integration improvements #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: lineage-17.1
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions hwcomposer/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ cc_library_shared {
"libwayland_extension_client_protocols",
],
srcs: [
"wayland-egl.c",
"extension.cpp",
"hwcomposer.cpp",
"wayland-hwc.cpp"
Expand Down
26 changes: 21 additions & 5 deletions hwcomposer/hwcomposer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're not removing the window from the list, which leads to crash. Also, I'd rather use destroy_window instead of freeing directly.

window = NULL;
}
}
} else {
// Create windows based on Task ID in layer name
Expand All @@ -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;
}
}
}

Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really well-versed in C++, but since the display is allocated with struct display *display = new struct display();, this should mean that all its members get value-initialized, which in case of pointers initializes them to nullptr already. Is that not the case here?


if (!pdev->display->height) {
pdev->display->waiting_for_data = true;
pthread_cond_timedwait(&pdev->display->data_available_cond,
Expand Down
67 changes: 67 additions & 0 deletions hwcomposer/wayland-egl-backend.h
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
*/

#ifndef _WAYLAND_EGL_PRIV_H
#define _WAYLAND_EGL_PRIV_H

#include <stdint.h>

#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
104 changes: 104 additions & 0 deletions hwcomposer/wayland-egl.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
* Benjamin Franzke <[email protected]>
*/

#include <stdlib.h>
#include <string.h>

#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;
}
41 changes: 18 additions & 23 deletions hwcomposer/wayland-hwc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

#include <wayland-client.h>
#include <wayland-android-client-protocol.h>
#include <wayland-egl-core.h>
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
#include "xdg-shell-client-protocol.h"
Expand Down Expand Up @@ -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)
Expand All @@ -412,10 +415,15 @@ destroy_window(struct window *window, bool keep)
window->isActive = false;
else
free(window);

if (!window->appID.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use after free.

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)
Expand All @@ -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 =
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 3 additions & 1 deletion hwcomposer/wayland-hwc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<size_t, struct wl_surface *> surfaces;
std::map<size_t, struct wl_subsurface *> subsurfaces;
struct wl_callback *callback;
int lastLayer;
std::string taskID;
bool isActive;
std::string appID;
};

int
Expand All @@ -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);