Restructure window creation and mangement

This commit is contained in:
Simon Fels 2016-11-20 17:08:05 +01:00
commit d4b4a795c3
28 changed files with 398 additions and 506 deletions

View file

@ -103,17 +103,14 @@ set(SOURCES
anbox/graphics/opengles_message_processor.cpp
anbox/graphics/gl_renderer_server.cpp
anbox/graphics/window_creator.cpp
anbox/graphics/density.h
anbox/graphics/rect.cpp
anbox/graphics/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/LayerManager.cpp
anbox/graphics/emugl/NativeSubWindow_delegate.cpp
anbox/graphics/emugl/NativeSubWindow.h
anbox/graphics/emugl/ReadBuffer.cpp
anbox/graphics/emugl/RenderApi.cpp
anbox/graphics/emugl/RenderContext.cpp
@ -132,6 +129,7 @@ set(SOURCES
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
@ -158,9 +156,9 @@ set(SOURCES
anbox/bridge/platform_api_skeleton.cpp
anbox/bridge/android_api_stub.cpp
anbox/ubuntu/window_creator.cpp
anbox/ubuntu/window.cpp
anbox/ubuntu/keycode_converter.cpp
anbox/ubuntu/platform_policy.cpp
anbox/dbus/interface.h
anbox/dbus/skeleton/service.cpp

View file

@ -51,12 +51,17 @@ void PlatformApiSkeleton::update_window_state(anbox::protobuf::bridge::WindowSta
(void) response;
auto convert_window_state = [](const ::anbox::protobuf::bridge::WindowStateUpdate_WindowState &window) {
DEBUG("Window: display=%d has_surface=%d frame={%d,%d,%d,%d} package=%s task=%d stack=-1",
window.display_id(), window.has_surface(),
window.frame_left(), window.frame_top(), window.frame_right(), window.frame_bottom(),
window.package_name(), window.task_id());
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::Task::Id(window.task_id()),
wm::Stack::Id(wm::Stack::Invalid));
};
wm::WindowState::List updated;
@ -68,7 +73,7 @@ void PlatformApiSkeleton::update_window_state(anbox::protobuf::bridge::WindowSta
wm::WindowState::List removed;
for (int n = 0; n < request->removed_windows_size(); n++) {
const auto window = request->removed_windows(n);
updated.push_back(convert_window_state(window));
removed.push_back(convert_window_state(window));
}
window_manager_->apply_window_state_update(updated, removed);

View file

@ -33,11 +33,10 @@
#include "anbox/bridge/platform_message_processor.h"
#include "anbox/bridge/android_api_stub.h"
#include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/ubuntu/window_creator.h"
#include "anbox/dbus/skeleton/service.h"
#include "anbox/container/client.h"
#include "anbox/wm/manager.h"
#include "anbox/wm/default_platform_policy.h"
#include "anbox/ubuntu/platform_policy.h"
#include <sys/prctl.h>
@ -90,11 +89,13 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
auto input_manager = std::make_shared<input::Manager>(rt);
auto policy = std::make_shared<wm::DefaultPlatformPolicy>();
auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager);
// FIXME this needs to be removed and solved differently behind the scenes
registerDisplayManager(policy);
auto window_manager = std::make_shared<wm::Manager>(policy);
auto window_creator = std::make_shared<ubuntu::WindowCreator>(input_manager);
auto renderer = std::make_shared<graphics::GLRendererServer>(window_creator);
auto renderer = std::make_shared<graphics::GLRendererServer>();
renderer->start();
// Socket which will be used by the qemud service inside the Android

View file

@ -23,7 +23,6 @@
#include <memory>
class TextureDraw;
class TextureResize;

View file

@ -1,130 +0,0 @@
/*
* 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 "LayerManager.h"
#include <algorithm>
#include <boost/algorithm/string.hpp>
namespace {
std::string get_package_name(const std::string &name) {
return name;
}
bool is_layer_blacklisted(const std::string &name) {
static std::vector<std::string> blacklist = {
// The boot animation should be disabled already but we blacklist it
// here too to ensure it is never visible.
"BootAnimation",
"StatusBar",
"Sprite",
"KeyguardScrim",
"com.android.launcher/com.android.launcher2.Launcher",
"com.android.settings/com.android.settings.FallbackHome",
"com.android.systemui.ImageWallpaper",
"InputMethod",
"com.android.quicksearchbox/com.android.quicksearchbox.SearchActivity",
};
return std::find(blacklist.begin(), blacklist.end(), name) != blacklist.end();
}
struct ActivityInfo {
ActivityInfo(const std::string &name) :
name(name) {
std::vector<std::string> parts;
boost::split(parts, name, boost::is_any_of("/"));
if (parts.size() > 1)
package = parts[0];
}
std::string package;
std::string name;
};
bool from_same_package(const std::string &a, const std::string &b) {
return ActivityInfo(a).package == ActivityInfo(b).package;
}
}
std::shared_ptr<LayerManager> LayerManager::get() {
static auto self = std::shared_ptr<LayerManager>{new LayerManager};
return self;
}
LayerManager::LayerManager() {
}
LayerManager::~LayerManager() {
}
void LayerManager::post_layer(const LayerInfo &layer) {
if (is_layer_blacklisted(layer.name))
return;
RendererWindow *window = nullptr;
for (auto &l : layers_) {
if (l.first == layer.name || from_same_package(l.first, layer.name)) {
window = l.second.window;
l.second.updated = true;
}
}
auto width = layer.display_frame.right - layer.display_frame.left;
auto height = layer.display_frame.bottom - layer.display_frame.top;
if (!window) {
printf("New layer '%s' display_frame={%d,%d,%d,%d} source_crop={%d,%d,%d,%d}\n",
layer.name.c_str(),
layer.display_frame.left,
layer.display_frame.top,
layer.display_frame.right,
layer.display_frame.bottom,
layer.source_crop.left,
layer.source_crop.top,
layer.source_crop.right,
layer.source_crop.bottom);
window = Renderer::get()->createWindow(layer.display_frame.left,
layer.display_frame.top,
width, height);
if (!window) {
printf("Failed to create window for layer '%s'\n", layer.name.c_str());
return;
}
layers_.insert({ layer.name, Layer{window, true}});
}
Renderer::get()->updateWindow(window,
layer.display_frame.left,
layer.display_frame.top,
width, height);
Renderer::get()->post(window, layer.buffer_handle);
}
void LayerManager::finish_cycle() {
for (auto iter = layers_.begin(); iter != layers_.end(); ++iter) {
if (!iter->second.updated) {
Renderer::get()->destroyWindow(iter->second.window);
layers_.erase(iter);
}
}
for (auto &layer : layers_)
layer.second.updated = false;
}

View file

@ -1,63 +0,0 @@
/*
* 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 LAYER_MANAGER_H_
#define LAYER_MANAGER_H_
#include <memory>
#include <map>
#include <vector>
#include <string>
#include "Renderer.h"
struct LayerRect {
int left;
int top;
int right;
int bottom;
};
struct LayerInfo {
std::string name;
LayerRect source_crop;
LayerRect display_frame;
HandleType buffer_handle;
};
class LayerManager {
public:
static std::shared_ptr<LayerManager> get();
~LayerManager();
void post_layer(const LayerInfo &layer);
void finish_cycle();
private:
LayerManager();
struct Layer {
RendererWindow *window;
bool updated;
};
std::map<std::string,Layer> layers_;
};
#endif

View file

@ -1,68 +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 update_window(EGLNativeWindowType win, int x, int y, int width, int height) = 0;
virtual void destroy_window(EGLNativeWindowType win) = 0;
};
void registerSubWindowHandler(const std::shared_ptr<SubWindowHandler> &handler);
// 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);
void updateSubWindow(EGLNativeWindowType win, int x, int y, int width, int height);
// Destroy a sub-window previously created through createSubWindow() above.
void destroySubWindow(EGLNativeWindowType win);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,59 +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) {
(void) p_window;
if (!current_handler)
return (EGLNativeWindowType) 0;
return current_handler->create_window(x, y, width, height);
}
void updateSubWindow(EGLNativeWindowType win, int x, int y, int width, int height) {
if (!current_handler)
return;
return current_handler->update_window(win, x, y, width, height);
}
void destroySubWindow(EGLNativeWindowType win) {
if (!current_handler)
return;
return current_handler->destroy_window(win);
}

View file

@ -20,7 +20,6 @@
#include "Renderer.h"
#include "RenderThreadInfo.h"
#include "ChecksumCalculatorThreadInfo.h"
#include "LayerManager.h"
#include "DisplayManager.h"
#include "OpenGLESDispatch/EGLDispatch.h"
@ -432,14 +431,9 @@ void rcPostLayer(const char *name, uint32_t color_buffer,
int32_t displayFrameLeft, int32_t displayFrameTop,
int32_t displayFrameRight, int32_t displayFrameBottom) {
LayerRect source_crop{sourceCropLeft, sourceCropTop, sourceCropRight, sourceCropBottom};
LayerRect display_frame{displayFrameLeft, displayFrameTop, displayFrameRight, displayFrameBottom};
LayerManager::get()->post_layer({name, source_crop, display_frame, color_buffer});
}
void rcPostAllLayersDone()
{
LayerManager::get()->finish_cycle();
void rcPostAllLayersDone() {
}
void initRenderControlContext(renderControl_decoder_context_t *dec)

View file

@ -0,0 +1,38 @@
/*
* 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::uint32_t &buffer,
const anbox::graphics::Rect &screen_position) :
buffer_(buffer),
screen_position_(screen_position)
{
}
Renderable::~Renderable()
{
}
std::uint32_t Renderable::buffer() const
{
return buffer_;
}
anbox::graphics::Rect Renderable::screen_position() const
{
return screen_position_;
}

View file

@ -0,0 +1,43 @@
/*
* 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 <vector>
#include <cstdint>
class Renderable
{
public:
Renderable(const std::uint32_t &buffer,
const anbox::graphics::Rect &screen_position);
~Renderable();
std::uint32_t buffer() const;
anbox::graphics::Rect screen_position() const;
private:
std::uint32_t buffer_;
anbox::graphics::Rect screen_position_;
};
typedef std::vector<Renderable> RenderableList;
#endif

View file

@ -17,7 +17,6 @@
#include "Renderer.h"
#include "DispatchTables.h"
#include "NativeSubWindow.h"
#include "RenderThreadInfo.h"
#include "TimeUtils.h"
#include "gles2_dec.h"
@ -456,40 +455,32 @@ Renderer::~Renderer() {
struct RendererWindow {
EGLNativeWindowType native_window = 0;
EGLSurface surface = EGL_NO_SURFACE;
bool needViewportUpdate = false;
int width;
int height;
};
RendererWindow* Renderer::createWindow(int x, int y, int width, int height) {
RendererWindow* Renderer::createNativeWindow(EGLNativeWindowType native_window)
{
m_lock.lock();
auto native_window = createSubWindow(0, x, y, width, height);
if (!native_window) {
m_lock.unlock();
return nullptr;
}
auto window = new RendererWindow;
window->native_window = native_window;
window->width = width;
window->height = height;
window->surface = s_egl.eglCreateWindowSurface(
m_eglDisplay, m_eglConfig, window->native_window, nullptr);
if (window->surface == EGL_NO_SURFACE) {
destroyWindow(window);
if (window->surface == EGL_NO_SURFACE)
{
delete window;
m_lock.unlock();
return nullptr;
}
if (!bindWindow_locked(window)) {
destroyWindow(window);
if (!bindWindow_locked(window))
{
s_egl.eglDestroySurface(m_eglDisplay, window->surface);
delete window;
m_lock.unlock();
return nullptr;
}
s_gles2.glViewport(0, 0, width, height);
// s_gles2.glViewport(0, 0, width, height);
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
@ -497,35 +488,27 @@ RendererWindow* Renderer::createWindow(int x, int y, int width, int height) {
unbind_locked();
m_nativeWindows.insert({native_window, window});
m_lock.unlock();
return window;
}
void Renderer::updateWindow(RendererWindow *window, int x, int y, int width, int height) {
if (!window)
return;
updateSubWindow(window->native_window, x, y, width, height);
window->width = width;
window->height = height;
window->needViewportUpdate = true;
}
void Renderer::destroyWindow(RendererWindow *window) {
if (!window)
void Renderer::destroyNativeWindow(EGLNativeWindowType native_window) {
auto w = m_nativeWindows.find(native_window);
if (w == m_nativeWindows.end())
return;
m_lock.lock();
s_egl.eglMakeCurrent(m_eglDisplay, nullptr, nullptr, nullptr);
if (window->surface != EGL_NO_SURFACE)
s_egl.eglDestroySurface(m_eglDisplay, window->surface);
if (w->second->surface != EGL_NO_SURFACE)
s_egl.eglDestroySurface(m_eglDisplay, w->second->surface);
destroySubWindow(window->native_window);
delete window;
delete w->second;
m_nativeWindows.erase(w);
m_lock.unlock();
}
@ -990,10 +973,12 @@ bool Renderer::post(RendererWindow *window, HandleType p_colorbuffer, bool needL
if (!bindWindow_locked(window))
goto EXIT;
#if 0
if (window->needViewportUpdate) {
s_gles2.glViewport(0, 0, window->width, window->height);
window->needViewportUpdate = false;
}
#endif
s_gles2.glClearColor(0.0, 0.0, 1.0, 0.0);
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
@ -1029,3 +1014,39 @@ EXIT:
}
return ret;
}
bool Renderer::draw(EGLNativeWindowType native_window, 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;
}
s_gles2.glClearColor(0.0, 0.0, 1.0, 0.0);
s_gles2.glClear(GL_COLOR_BUFFER_BIT);
for (const auto &renderable : renderables)
{
const auto &color_buffer = m_colorbuffers.find(renderable.buffer());
if (color_buffer == m_colorbuffers.end())
continue;
color_buffer->second.cb->post(0.0f,
renderable.screen_position().left(), renderable.screen_position().top());
}
s_egl.eglSwapBuffers(m_eglDisplay, w->second->surface);
unbind_locked();
m_lock.lock();
m_lock.unlock();
return false;
}

View file

@ -25,6 +25,8 @@
#include "OpenglRender/render_api.h"
#include "Renderable.h"
#include <EGL/egl.h>
#include <map>
@ -78,10 +80,6 @@ public:
// Returns true on success, false otherwise.
static bool initialize(EGLNativeDisplayType nativeDisplay);
RendererWindow* createWindow(int x, int y, int width, int height);
void updateWindow(RendererWindow *window, int x, int y, int width, int height);
void destroyWindow(RendererWindow *window);
// Finalize the instance.
void finalize();
@ -111,6 +109,10 @@ public:
*version = m_glVersion;
}
RendererWindow* createNativeWindow(EGLNativeWindowType native_window);
void destroyNativeWindow(RendererWindow *window);
void destroyNativeWindow(EGLNativeWindowType native_window);
// Create a new RenderContext instance for this display instance.
// |p_config| is the index of one of the configs returned by getConfigs().
// |p_share| is either EGL_NO_CONTEXT or the handle of a shared context.
@ -234,6 +236,8 @@ public:
// false only when called internally.
bool post(RendererWindow *window, HandleType p_colorbuffer, bool needLock = true);
bool draw(EGLNativeWindowType native_window, const RenderableList &renderables);
// Return the host EGLDisplay used by this instance.
EGLDisplay getDisplay() const { return m_eglDisplay; }
@ -286,5 +290,7 @@ private:
const char* m_glVendor;
const char* m_glRenderer;
const char* m_glVersion;
std::map<EGLNativeWindowType,RendererWindow*> m_nativeWindows;
};
#endif

View file

@ -17,7 +17,6 @@
#include "anbox/logger.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "anbox/graphics/window_creator.h"
#include "OpenglRender/render_api.h"
@ -27,8 +26,8 @@
namespace anbox {
namespace graphics {
GLRendererServer::GLRendererServer(const std::shared_ptr<WindowCreator> &window_creator) :
window_creator_(window_creator) {
GLRendererServer::GLRendererServer()
{
if (utils::is_env_set("USE_HOST_GLES")) {
// Force the host EGL/GLES libraries as translator implementation
@ -44,13 +43,9 @@ GLRendererServer::GLRendererServer(const std::shared_ptr<WindowCreator> &window_
if (!initLibrary())
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
registerSubWindowHandler(window_creator_);
registerDisplayManager(window_creator_);
}
GLRendererServer::~GLRendererServer() {
// destroyOpenGLSubwindow();
stopOpenGLRenderer();
}
@ -70,15 +65,11 @@ void GLRendererServer::start() {
log_funcs.coarse = logger_write;
log_funcs.fine = logger_write;
auto display_info = window_creator_->display_info();
const auto width = display_info.horizontal_resolution;
const auto height = display_info.vertical_resolution;
char server_addr[256] = { 0 };
// The width & height we supply here are the dimensions the internal framebuffer
// will use. Making this static prevents us for now to resize the window we create
// later for the actual display.
if (!initOpenGLRenderer(window_creator_->native_display(), server_addr, sizeof(server_addr), log_funcs, logger_write))
if (!initOpenGLRenderer(0, server_addr, sizeof(server_addr), log_funcs, logger_write))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to setup OpenGL renderer"));
socket_path_ = server_addr;

View file

@ -29,7 +29,7 @@ namespace graphics {
class WindowCreator;
class GLRendererServer {
public:
GLRendererServer(const std::shared_ptr<WindowCreator> &window_creator);
GLRendererServer();
~GLRendererServer();
void start();
@ -38,7 +38,6 @@ public:
private:
std::string socket_path_;
std::shared_ptr<WindowCreator> window_creator_;
};
} // namespace graphics

View file

@ -15,7 +15,7 @@
*
*/
#include "anbox/ubuntu/window_creator.h"
#include "anbox/ubuntu/platform_policy.h"
#include "anbox/ubuntu/window.h"
#include "anbox/ubuntu/keycode_converter.h"
#include "anbox/input/manager.h"
@ -29,16 +29,14 @@
namespace anbox {
namespace ubuntu {
WindowCreator::WindowCreator(const std::shared_ptr<input::Manager> &input_manager) :
graphics::WindowCreator(input_manager),
PlatformPolicy::PlatformPolicy(const std::shared_ptr<input::Manager> &input_manager) :
input_manager_(input_manager),
event_thread_running_(false),
display_info_({1920, 1080}) {
event_thread_running_(false) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize SDL"));
event_thread_ = std::thread(&WindowCreator::process_events, this);
event_thread_ = std::thread(&PlatformPolicy::process_events, this);
SDL_DisplayMode display_mode;
// FIXME statically just check the first (primary) display for its mode;
@ -71,12 +69,12 @@ WindowCreator::WindowCreator(const std::shared_ptr<input::Manager> &input_manage
keyboard_->set_key_bit(KEY_OK);
}
WindowCreator::~WindowCreator() {
PlatformPolicy::~PlatformPolicy() {
event_thread_running_ = false;
event_thread_.join();
}
void WindowCreator::process_events() {
void PlatformPolicy::process_events() {
event_thread_running_ = true;
while(event_thread_running_) {
@ -90,9 +88,11 @@ void WindowCreator::process_events() {
break;
case SDL_WINDOWEVENT:
for (auto &iter : windows_) {
if (iter.second->id() == event.window.windowID) {
iter.second->process_event(event);
break;
if (auto w = iter.second.lock()) {
if (w->window_id() == event.window.windowID) {
w->process_event(event);
break;
}
}
}
break;
@ -109,7 +109,7 @@ void WindowCreator::process_events() {
}
}
void WindowCreator::process_input_event(const SDL_Event &event) {
void PlatformPolicy::process_input_event(const SDL_Event &event) {
std::vector<input::Event> mouse_events;
std::vector<input::Event> keyboard_events;
@ -176,44 +176,29 @@ void WindowCreator::process_input_event(const SDL_Event &event) {
keyboard_->send_events(keyboard_events);
}
EGLNativeWindowType WindowCreator::create_window(int x, int y, int width, int height)
try {
auto window = std::make_shared<Window>(x, y, width, height);
if (not window)
BOOST_THROW_EXCEPTION(std::bad_alloc());
windows_.insert({window->native_window(), window});
return window->native_window();
}
catch (std::exception &err) {
DEBUG("Failed to create window: %s", err.what());
return 0;
Window::Id PlatformPolicy::next_window_id() {
static Window::Id next_id = 0;
return next_id++;
}
void WindowCreator::update_window(EGLNativeWindowType win, int x, int y, int width, int height) {
auto iter = windows_.find(win);
if (iter == windows_.end())
std::shared_ptr<wm::Window> PlatformPolicy::create_window(const wm::WindowState &state) {
auto id = next_window_id();
auto w = std::make_shared<Window>(id, shared_from_this(), state);
windows_.insert({id, w});
return w;
}
void PlatformPolicy::window_deleted(const Window::Id &id) {
auto w = windows_.find(id);
if (w == windows_.end()) {
WARNING("Got window removed event for unknown window (id %d)", id);
return;
iter->second->resize(width, height);
iter->second->update_position(x, y);
}
windows_.erase(w);
}
void WindowCreator::destroy_window(EGLNativeWindowType win) {
auto iter = windows_.find(win);
if (iter == windows_.end())
return;
windows_.erase(iter);
}
WindowCreator::DisplayInfo WindowCreator::display_info() const {
DisplayManager::DisplayInfo PlatformPolicy::display_info() const {
return display_info_;
}
EGLNativeDisplayType WindowCreator::native_display() const {
return 0;
}
} // namespace bridge
} // namespace wm
} // namespace anbox

View file

@ -15,15 +15,17 @@
*
*/
#ifndef ANBOX_UBUNTU_WINDOW_CREATOR_H_
#define ANBOX_UBUNTU_WINDOW_CREATOR_H_
#ifndef ANBOX_UBUNTU_PLATFORM_POLICY_H_
#define ANBOX_UBUNTU_PLATFORM_POLICY_H_
#include "anbox/graphics/window_creator.h"
#include "anbox/wm/platform_policy.h"
#include "anbox/ubuntu/window.h"
#include "anbox/graphics/emugl/DisplayManager.h"
#include <map>
#include <thread>
#include <map>
#include <EGL/egl.h>
#include <SDL.h>
namespace anbox {
@ -32,34 +34,38 @@ class Device;
class Manager;
} // namespace input
namespace ubuntu {
class MirDisplayConnection;
class Window;
class WindowCreator : public graphics::WindowCreator {
class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>,
public wm::PlatformPolicy,
public Window::Observer,
public DisplayManager {
public:
WindowCreator(const std::shared_ptr<input::Manager> &input_manager);
~WindowCreator();
PlatformPolicy(const std::shared_ptr<input::Manager> &input_manager);
~PlatformPolicy();
EGLNativeWindowType create_window(int x, int y, int width, int height) override;
void update_window(EGLNativeWindowType win, int x, int y, int width, int height) override;
void destroy_window(EGLNativeWindowType win) override;
std::shared_ptr<wm::Window> create_window(const wm::WindowState &state) override;
void window_deleted(const Window::Id &id) override;
DisplayInfo display_info() const override;
EGLNativeDisplayType native_display() const override;
private:
void process_events();
void process_input_event(const SDL_Event &event);
static Window::Id next_window_id();
std::shared_ptr<input::Manager> input_manager_;
std::map<EGLNativeWindowType,std::shared_ptr<Window>> windows_;
// We don't own the windows anymore after the got created by us so we
// need to be careful once we try to use them again.
std::map<Window::Id, std::weak_ptr<Window>> windows_;
std::shared_ptr<Window> current_window_;
std::thread event_thread_;
bool event_thread_running_;
graphics::WindowCreator::DisplayInfo display_info_;
std::shared_ptr<input::Device> pointer_;
std::shared_ptr<input::Device> keyboard_;
DisplayManager::DisplayInfo display_info_;
};
} // namespace ubuntu
} // namespace wm
} // namespace anbox
#endif

View file

@ -16,15 +16,69 @@
*/
#include "anbox/ubuntu/window.h"
#include "anbox/wm/window_state.h"
#include "anbox/logger.h"
#include <boost/throw_exception.hpp>
#include <SDL_syswm.h>
namespace {
constexpr const char* default_window_name{"anbox"};
}
namespace anbox {
namespace ubuntu {
Window::Id Window::Invalid{-1};
Window::Observer::~Observer() {
}
Window::Window(const Id &id,
const std::shared_ptr<Observer> &observer,
const wm::WindowState &state) :
wm::Window(state),
id_(id),
observer_(observer),
native_display_(0),
native_window_(0) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
window_ = SDL_CreateWindow(default_window_name,
state.frame().left(),
state.frame().top(),
state.frame().width(),
state.frame().height(),
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
if (!window_) {
const auto message = utils::string_format("Failed to create window: %s", SDL_GetError());
BOOST_THROW_EXCEPTION(std::runtime_error(message));
}
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(window_, &info);
switch (info.subsystem) {
case SDL_SYSWM_X11:
DEBUG("Running on X11");
native_display_ = static_cast<EGLNativeDisplayType>(info.info.x11.display);
native_window_ = static_cast<EGLNativeWindowType>(info.info.x11.window);
break;
default:
ERROR("Unknown subsystem (%d)", info.subsystem);
BOOST_THROW_EXCEPTION(std::runtime_error("SDL subsystem not suported"));
}
int actual_width = 0, actual_height = 0;
int actual_x = 0, actual_y = 0;
SDL_GetWindowSize(window_, &actual_width, &actual_height);
SDL_GetWindowPosition(window_, &actual_x, &actual_y);
DEBUG("Window created {%d,%d,%d,%d}", actual_x, actual_y, actual_width, actual_height);
}
Window::Window(int x, int y, int width, int height) :
wm::Window(wm::WindowState()),
native_display_(0),
native_window_(0) {
@ -60,6 +114,9 @@ Window::Window(int x, int y, int width, int height) :
Window::~Window() {
if (window_)
SDL_DestroyWindow(window_);
if (observer_)
observer_->window_deleted(id_);
}
void Window::resize(int width, int height) {
@ -89,11 +146,15 @@ void Window::process_event(const SDL_Event &event) {
}
}
EGLNativeWindowType Window::native_window() const {
EGLNativeWindowType Window::native_handle() const {
return native_window_;
}
std::uint32_t Window::id() const {
Window::Id Window::id() const {
return id_;
}
std::uint32_t Window::window_id() const {
return SDL_GetWindowID(window_);
}
} // namespace bridge

View file

@ -18,6 +18,8 @@
#ifndef ANBOX_UBUNTU_WINDOW_H_
#define ANBOX_UBUNTU_WINDOW_H_
#include "anbox/wm/window.h"
#include <EGL/egl.h>
#include <memory>
@ -27,8 +29,19 @@
namespace anbox {
namespace ubuntu {
class Window {
class Window : public std::enable_shared_from_this<Window>,
public wm::Window {
public:
typedef std::int32_t Id;
static Id Invalid;
class Observer {
public:
virtual ~Observer();
virtual void window_deleted(const Id &id) = 0;
};
Window(const Id &id, const std::shared_ptr<Observer> &observer, const wm::WindowState &state);
Window(int x, int y, int width, int height);
~Window();
@ -37,10 +50,13 @@ public:
void process_event(const SDL_Event &event);
EGLNativeWindowType native_window() const;
std::uint32_t id() const;
EGLNativeWindowType native_handle() const override;
Id id() const;
std::uint32_t window_id() const;
private:
Id id_;
std::shared_ptr<Observer> observer_;
EGLNativeDisplayType native_display_;
EGLNativeWindowType native_window_;
SDL_Window *window_;

View file

@ -17,11 +17,12 @@
#include "anbox/wm/default_platform_policy.h"
#include "anbox/wm/window.h"
#include "anbox/logger.h"
namespace {
class Window : public anbox::wm::Window {
class NullWindow : public anbox::wm::Window {
public:
Window(const anbox::wm::WindowState &state) :
NullWindow(const anbox::wm::WindowState &state) :
anbox::wm::Window(state) {
}
};
@ -32,8 +33,10 @@ namespace wm {
DefaultPlatformPolicy::DefaultPlatformPolicy() {
}
std::shared_ptr<Window> DefaultPlatformPolicy::create_window(const WindowState &state) {
return std::make_shared<::Window>(state);
std::shared_ptr<Window> DefaultPlatformPolicy::create_window(const WindowState &state)
{
DEBUG("");
return std::make_shared<::NullWindow>(state);
}
} // namespace wm
} // namespace anbox

View file

@ -16,6 +16,7 @@
*/
#include "anbox/wm/manager.h"
#include "anbox/wm/platform_policy.h"
#include "anbox/logger.h"
namespace anbox {
@ -28,11 +29,39 @@ Manager::~Manager() {
}
void Manager::apply_window_state_update(const WindowState::List &updated,
const WindowState::List &removed) {
(void) updated;
(void) removed;
const WindowState::List &removed)
{
DEBUG("updated %d removed %d", updated.size(), removed.size());
// Base on the update we get from the Android WindowManagerService we will create
// different window instances with the properties supplied. Incoming layer updates
// from SurfaceFlinger will be mapped later into those windows and eventually
// composited there via GLES (e.g. for popups, ..)
for (const auto &window : updated) {
auto w = windows_.find(window.task());
if (w != windows_.end()) {
DEBUG("Found existing window for task %d", window.task());
w->second->update_state(window);
continue;
}
DEBUG("Found new window for task %d", window.task());
auto platform_window = platform_->create_window(window);
platform_window->attach();
windows_.insert({window.task(), platform_window});
}
for (const auto &window : removed) {
auto w = windows_.find(window.task());
if (w == windows_.end()) {
WARNING("Got remove request for window we don't know about (task id %d)", window.task());
continue;
}
DEBUG("Removing window for task %d", window.task());
auto platform_window = w->second;
platform_window->release();
windows_.erase(w);
}
}
} // namespace wm
} // namespace anbox

View file

@ -19,8 +19,10 @@
#define ANBOX_WM_MANAGER_H_
#include "anbox/wm/window_state.h"
#include "anbox/wm/window.h"
#include <memory>
#include <map>
namespace anbox {
namespace wm {
@ -35,6 +37,7 @@ public:
private:
std::shared_ptr<PlatformPolicy> platform_;
std::map<Task::Id, std::shared_ptr<Window>> windows_;
};
} // namespace wm
} // namespace anbox

View file

@ -15,16 +15,13 @@
*
*/
#include "anbox/graphics/window_creator.h"
#include "anbox/wm/stack.h"
namespace anbox {
namespace graphics {
WindowCreator::WindowCreator(const std::shared_ptr<input::Manager> &input_manager) :
input_manager_(input_manager) {
}
WindowCreator::~WindowCreator() {
}
} // namespace graphics
namespace wm {
Stack::Id Stack::Invalid = -1;
Stack::Id Stack::Default = 0;
Stack::Id Stack::Fullscreen = 1;
Stack::Id Stack::Freeform = 2;
} // namespace wm
} // namespace anbox

View file

@ -15,28 +15,26 @@
*
*/
#ifndef ANBOX_GRAPHICS_WINDOW_CREATOR_H_
#define ANBOX_GRAPHICS_WINDOW_CREATOR_H_
#ifndef ANBOX_WM_STACK_H_
#define ANBOX_WM_STACK_H_
#include "anbox/graphics/emugl/NativeSubWindow.h"
#include "anbox/graphics/emugl/DisplayManager.h"
#include <cstdint>
namespace anbox {
namespace input {
class Manager;
} // namespace input
namespace graphics {
class WindowCreator : public SubWindowHandler,
public DisplayManager {
namespace wm {
class Stack {
public:
WindowCreator(const std::shared_ptr<input::Manager> &input_manager);
virtual ~WindowCreator();
typedef std::int32_t Id;
virtual EGLNativeDisplayType native_display() const = 0;
static Id Invalid;
static Id Default;
static Id Fullscreen;
static Id Freeform;
protected:
std::shared_ptr<input::Manager> input_manager_;
Stack() = delete;
Stack(const Stack&) = delete;
};
} // namespace graphics
} // namespace wm
} // namespace anbox
#endif

View file

@ -16,6 +16,7 @@
*/
#include "anbox/wm/window.h"
#include "anbox/graphics/emugl/Renderer.h"
namespace anbox {
namespace wm {
@ -30,8 +31,16 @@ void Window::update_state(const WindowState &state) {
state_ = state;
}
void Window::render_layer(const Layer &layer) {
(void) layer;
EGLNativeWindowType Window::native_handle() const {
return 0;
}
bool Window::attach() {
return Renderer::get()->createNativeWindow(native_handle());
}
void Window::release() {
Renderer::get()->destroyNativeWindow(native_handle());
}
} // namespace wm
} // namespace anbox

View file

@ -23,6 +23,8 @@
#include <vector>
#include <string>
#include <EGL/egl.h>
namespace anbox {
namespace wm {
// FIXME(morphis): move this somewhere else once we have the integration
@ -35,19 +37,20 @@ private:
graphics::Rect frame_;
};
class Window {
class Window
{
public:
typedef std::vector<Window> List;
Window(const WindowState &state);
virtual ~Window();
bool attach();
void release();
void update_state(const WindowState &state);
// Render a layer into the window. The layer itself includes all
// necessary information for correct rendering.
void render_layer(const Layer &layer);
virtual EGLNativeWindowType native_handle() const;
WindowState state() const;
private:

View file

@ -24,19 +24,22 @@ WindowState::WindowState() :
has_surface_(false),
frame_(graphics::Rect::Invalid),
package_name_(""),
task_(Task::Invalid) {
task_(Task::Invalid),
stack_(Stack::Invalid) {
}
WindowState::WindowState(const Display::Id &display,
bool has_surface,
const graphics::Rect &frame,
const std::string &package_name,
const Task::Id &task) :
const Task::Id &task,
const Stack::Id &stack) :
display_(display),
has_surface_(has_surface),
frame_(frame),
package_name_(package_name),
task_(task) {
task_(task),
stack_(stack) {
}
WindowState::~WindowState() {

View file

@ -21,6 +21,7 @@
#include "anbox/graphics/rect.h"
#include "anbox/wm/display.h"
#include "anbox/wm/task.h"
#include "anbox/wm/stack.h"
#include <vector>
#include <string>
@ -36,7 +37,8 @@ public:
bool has_surface,
const graphics::Rect &frame,
const std::string &package_name,
const Task::Id &task);
const Task::Id &task,
const Stack::Id &stack);
~WindowState();
Display::Id display() const { return display_; }
@ -44,6 +46,7 @@ public:
graphics::Rect frame() const { return frame_; }
std::string package_name() const { return package_name_; }
Task::Id task() const { return task_; }
Stack::Id stack() const { return stack_; }
private:
Display::Id display_;
@ -51,6 +54,7 @@ private:
graphics::Rect frame_;
std::string package_name_;
Task::Id task_;
Stack::Id stack_;
};
} // namespace wm