From 796fe1c52ec8d629e16c59947c2cfce415a5979a Mon Sep 17 00:00:00 2001 From: night_xiaoye <2260737534@qq.com> Date: Tue, 25 Aug 2020 11:29:36 +0800 Subject: [PATCH] renderer: solve black border appearing one of four sides of the window. fix problem, some apps's main window renderers will overflow window, this will cause black areas appearing four sides of the window, solve it. tests: change two layer_composer test cases to make sucess, and add new two test cases. --- .../multi_window_composer_strategy.cpp | 75 ++++++------ .../graphics/multi_window_composer_strategy.h | 1 + src/anbox/platform/sdl/window.cpp | 25 +++- src/anbox/platform/sdl/window.h | 4 + src/anbox/wm/window.cpp | 7 +- src/anbox/wm/window.h | 8 +- tests/anbox/graphics/layer_composer_tests.cpp | 108 +++++++++++++++++- 7 files changed, 186 insertions(+), 42 deletions(-) diff --git a/src/anbox/graphics/multi_window_composer_strategy.cpp b/src/anbox/graphics/multi_window_composer_strategy.cpp index 5023891d..c660bd71 100644 --- a/src/anbox/graphics/multi_window_composer_strategy.cpp +++ b/src/anbox/graphics/multi_window_composer_strategy.cpp @@ -48,51 +48,60 @@ std::map, RenderableList> MultiWindowComposerStrateg for (auto &w : win_layers) { const auto &renderables = w.second; RenderableList final_renderables; - int top = 1080; - int left = 1920; - - for (auto &r : renderables) { - // We always prioritize layers which are lower in the list we got - // from SurfaceFlinger as they are already ordered. - int current_left = r.screen_position().left(); - int current_top = r.screen_position().top(); - int half_diff = 2; - if (r.screen_position().width() > w.first->frame().width()) { - auto diff = r.screen_position().width() - w.first->frame().width(); - current_left += diff / half_diff; - } - if (r.screen_position().height() > w.first->frame().height()) { - auto diff = r.screen_position().height() - w.first->frame().height(); - current_top += diff / half_diff; - } - - if (current_left < left) { - left = current_left; - } - if (current_top < top) { - top = current_top; - } - } - + auto window_frame = w.first->frame(); + bool resizeable = w.first->checkResizeable(); + auto old_frame = w.first->last_frame(); + int max_area = 0; + Rect max_rect; for (auto &r : renderables) { // 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. auto rect = Rect{ - r.screen_position().left() - left + r.crop().left(), - r.screen_position().top() - top + r.crop().top(), - r.screen_position().right() - left + r.crop().left(), - r.screen_position().bottom() - top + r.crop().top()}; + r.screen_position().left() - window_frame.left(), + r.screen_position().top() - window_frame.top(), + r.screen_position().right() - window_frame.left(), + r.screen_position().bottom() - window_frame.top()}; + if (rect.width() * rect.height() > max_area) { + max_area = rect.width() * rect.height(); + max_rect = Rect(r.screen_position().left() - old_frame.left(), + r.screen_position().top() - old_frame.top(), + r.screen_position().right() - old_frame.left(), + r.screen_position().bottom() - old_frame.top()); + } auto new_renderable = r; new_renderable.set_screen_position(rect); final_renderables.push_back(new_renderable); } - w.second = final_renderables; - } + bool changed = false; + if (resizeable) { + int max_old_area = 0; + Rect max_old_rect; + auto it = last_renderables.find(w.first); + if (it != last_renderables.end()) { + for (auto &rt : it->second) { + if (max_old_area < rt.screen_position().width() * rt.screen_position().height()) { + max_old_area = rt.screen_position().width() * rt.screen_position().height(); + max_old_rect = rt.screen_position(); + } + } + } + if (max_old_rect == max_rect) { + w.second = it->second; + changed = true; + } else { + w.first->setResizing(false); + } + } - return win_layers; + if(!changed) { + w.second = final_renderables; + } + } + last_renderables.swap(win_layers); + return last_renderables; } } // namespace graphics } // namespace anbox diff --git a/src/anbox/graphics/multi_window_composer_strategy.h b/src/anbox/graphics/multi_window_composer_strategy.h index e7dbdf96..0205df52 100644 --- a/src/anbox/graphics/multi_window_composer_strategy.h +++ b/src/anbox/graphics/multi_window_composer_strategy.h @@ -33,6 +33,7 @@ class MultiWindowComposerStrategy : public LayerComposer::Strategy { private: std::shared_ptr wm_; + WindowRenderableList last_renderables; }; } // namespace graphics } // namespace anbox diff --git a/src/anbox/platform/sdl/window.cpp b/src/anbox/platform/sdl/window.cpp index f380e008..b3b14f75 100755 --- a/src/anbox/platform/sdl/window.cpp +++ b/src/anbox/platform/sdl/window.cpp @@ -279,11 +279,19 @@ void Window::process_event(const SDL_Event &event) { // SDL_WINDOWEVENT_SIZE_CHANGED is always sent. case SDL_WINDOWEVENT_SIZE_CHANGED: if (observer_) { + struct timeval now = (struct timeval) { 0 }; + gettimeofday(&now, NULL); + last_resize_time_ = USEC_PER_SEC * (now.tv_sec) + now.tv_usec; + resizing_ = true; observer_->window_resized(id_, event.window.data1, event.window.data2); } break; case SDL_WINDOWEVENT_MOVED: if (observer_) { + struct timeval now = (struct timeval) { 0 }; + gettimeofday(&now, NULL); + last_resize_time_ = USEC_PER_SEC * (now.tv_sec) + now.tv_usec; + resizing_ = true; observer_->window_moved(id_, event.window.data1, event.window.data2); } break; @@ -305,6 +313,22 @@ Window::Id Window::id() const { return id_; } std::uint32_t Window::window_id() const { return SDL_GetWindowID(window_); } +bool Window::checkResizeable() { + struct timeval now = (struct timeval) { 0 }; + gettimeofday(&now, NULL); + long long time_now = USEC_PER_SEC * (now.tv_sec) + now.tv_usec; + if (resizing_ && time_now - last_resize_time_ > RESIZE_TIMESPAN) { + last_frame_ = frame(); + resizing_ = false; + } + return resizing_; +} + +void Window::setResizing(bool resizing) { + last_frame_ = frame(); + resizing_ = resizing; +} + void Window::update_state(const wm::WindowState::List &states) { if (!initialized.load() && !states.empty()) { int w = 0; @@ -330,7 +354,6 @@ void Window::update_state(const wm::WindowState::List &states) { y == rect.top()) { return; } - struct timeval now = (struct timeval) { 0 }; gettimeofday(&now, NULL); long long current_time = USEC_PER_SEC * (now.tv_sec) + now.tv_usec; diff --git a/src/anbox/platform/sdl/window.h b/src/anbox/platform/sdl/window.h index 6a6d9043..05af468e 100755 --- a/src/anbox/platform/sdl/window.h +++ b/src/anbox/platform/sdl/window.h @@ -41,6 +41,7 @@ class Window : public std::enable_shared_from_this, public wm::Window { static const long long USEC_PER_SEC = 1000000; static const long long APP_START_MAX_TIME = 15 * USEC_PER_SEC; static const long long timespan_db_click = 500000; + static const long long RESIZE_TIMESPAN = USEC_PER_SEC / 2; struct mini_size { int minimum_width; @@ -77,6 +78,8 @@ class Window : public std::enable_shared_from_this, public wm::Window { void update_state(const wm::WindowState::List &states) override; bool check_db_clicked(int x, int y); + bool checkResizeable() override; + void setResizing(bool resizing) override; void restore_window(); Id id() const; @@ -93,6 +96,7 @@ class Window : public std::enable_shared_from_this, public wm::Window { std::atomic initialized{false}; long long last_update_time{ 0 }; + long long last_resize_time_{ 0 }; Id id_; std::shared_ptr observer_; EGLNativeDisplayType native_display_; diff --git a/src/anbox/wm/window.cpp b/src/anbox/wm/window.cpp index 7169e643..05c6a48c 100644 --- a/src/anbox/wm/window.cpp +++ b/src/anbox/wm/window.cpp @@ -21,8 +21,9 @@ namespace anbox { namespace wm { -Window::Window(const std::shared_ptr &renderer, const Task::Id &task, const graphics::Rect &frame, const std::string &title) - : renderer_(renderer), task_(task), frame_(frame), title_(title), native_window_(0) {} +Window::Window(const std::shared_ptr &renderer, const Task::Id &task, + const graphics::Rect &frame, const std::string &title) + : renderer_(renderer), task_(task), frame_(frame), title_(title), native_window_(0), last_frame_(frame) {} Window::~Window() { release(); @@ -44,6 +45,8 @@ Task::Id Window::task() const { return task_; } graphics::Rect Window::frame() const { return frame_; } +graphics::Rect Window::last_frame() const { return last_frame_; } + EGLNativeWindowType Window::native_handle() const { return native_window_; } std::string Window::title() const { return title_; } diff --git a/src/anbox/wm/window.h b/src/anbox/wm/window.h index 1788621d..f149bb17 100644 --- a/src/anbox/wm/window.h +++ b/src/anbox/wm/window.h @@ -53,15 +53,21 @@ class Window { virtual void update_state(const WindowState::List &states); void update_frame(const graphics::Rect &frame); + void update_last_frame(const graphics::Rect &frame); virtual bool title_event_filter(int y); void set_native_handle(const EGLNativeWindowType &handle); EGLNativeWindowType native_handle() const; graphics::Rect frame() const; + graphics::Rect last_frame() const; Task::Id task() const; std::string title() const; - + virtual bool checkResizeable() { return resizing_; } + virtual void setResizing(bool resizing) { resizing_ = resizing; } + protected: + graphics::Rect last_frame_; + bool resizing_{false}; private: EGLNativeWindowType native_window_; std::shared_ptr renderer_; diff --git a/tests/anbox/graphics/layer_composer_tests.cpp b/tests/anbox/graphics/layer_composer_tests.cpp index 98342971..8fe5957e 100644 --- a/tests/anbox/graphics/layer_composer_tests.cpp +++ b/tests/anbox/graphics/layer_composer_tests.cpp @@ -125,7 +125,7 @@ TEST(LayerComposer, MapsLayersToWindows) { }; RenderableList second_window_renderables{ - {"org.anbox.surface.2", 1, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + {"org.anbox.surface.2", 1, 1.0f, {-300, -400, 724, 368}, {0, 0, 1024, 768}}, }; EXPECT_CALL(*renderer, draw(_, Rect{0, 0, first_window.frame().width(), @@ -171,12 +171,12 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { // but the layer covering the whole window is placed with its top left // origin outside of the visible display area. RenderableList renderables = { - {"org.anbox.surface.1", 0, 1.0f, {-100, -100, 924, 668}, {0, 0, 1024, 768}}, + {"org.anbox.surface.1", 0, 1.0f, {0, 0, 924, 668}, {100, 100, 1024, 768}}, {"org.anbox.surface.1", 1, 1.0f, {0, 0, 100, 200}, {0, 0, 100, 200}}, }; RenderableList expected_renderables{ - {"org.anbox.surface.1", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + {"org.anbox.surface.1", 0, 1.0f, {100, 100, 1024, 768}, {100, 100, 1024, 768}}, {"org.anbox.surface.1", 1, 1.0f, {100, 100, 200, 300}, {0, 0, 100, 200}}, }; @@ -227,8 +227,8 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { }; RenderableList expected_renderables{ - {"org.anbox.surface.3", 0, 1.0f, {0, 24, 1024, 792}, {0, 0, 1024, 768}}, - {"org.anbox.surface.3", 1, 1.0f, {784, 0, 1044, 160}, {0, 0, 260, 160}}, + {"org.anbox.surface.3", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + {"org.anbox.surface.3", 1, 1.0f, {784, -24, 1044, 136}, {0, 0, 260, 160}}, }; EXPECT_CALL(*renderer, draw(_, Rect{0, 0, @@ -241,5 +241,103 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { composer.submit_layers(renderables); } +TEST(LayerComposer, ResizingShouldUseOldRender) { + auto renderer = std::make_shared(); + + platform::Configuration config; + // The default policy will create a dumb window instance when requested + // from the manager. + auto platform = platform::create(std::string(), nullptr, config); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform, nullptr, app_db); + + auto single_window = wm::WindowState{ + wm::Display::Id{1}, + true, + graphics::Rect{1120, 270, 2144, 1038}, + "org.anbox.foo", + wm::Task::Id{3}, + wm::Stack::Id::Freeform, + }; + + auto window = platform->create_window(single_window.task(), single_window.frame(), single_window.package_name()); + window->attach(); + wm->insert_task(single_window.task(), window); + + LayerComposer composer(renderer, std::make_shared(wm)); + + RenderableList renderables_first = { + {"org.anbox.surface.3", 0, 1.0f, {1120,270,2144,1038}, {0, 0, 1024, 768}}, + }; + + composer.submit_layers(renderables_first); + window->update_frame(graphics::Rect{0, 0, 1024, 768}); + window->setResizing(true); + composer.submit_layers(renderables_first); + RenderableList expected_renderables{ + {"org.anbox.surface.3", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + }; + + EXPECT_CALL(*renderer, draw(_, Rect{0, 0, + single_window.frame().width(), + single_window.frame().height()}, + expected_renderables)) + .Times(1) + .WillOnce(Return(true)); + + composer.submit_layers(renderables_first); +} + +TEST(LayerComposer, ResizeOverShouldUseNewRender) { + auto renderer = std::make_shared(); + + platform::Configuration config; + // The default policy will create a dumb window instance when requested + // from the manager. + auto platform = platform::create(std::string(), nullptr, config); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform, nullptr, app_db); + + auto single_window = wm::WindowState{ + wm::Display::Id{1}, + true, + graphics::Rect{1120, 270, 2144, 1038}, + "org.anbox.foo", + wm::Task::Id{3}, + wm::Stack::Id::Freeform, + }; + + auto window = platform->create_window(single_window.task(), single_window.frame(), single_window.package_name()); + window->attach(); + wm->insert_task(single_window.task(), window); + + LayerComposer composer(renderer, std::make_shared(wm)); + + RenderableList renderables_first = { + {"org.anbox.surface.3", 0, 1.0f, {1120,270,2144,1038}, {0, 0, 1024, 768}}, + }; + + RenderableList renderables_second = { + {"org.anbox.surface.3", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + }; + + composer.submit_layers(renderables_first); + window->update_frame(graphics::Rect{0, 0, 1024, 768}); + window->setResizing(true); + composer.submit_layers(renderables_first); + RenderableList expected_renderables{ + {"org.anbox.surface.3", 0, 1.0f, {0, 0, 1024, 768}, {0, 0, 1024, 768}}, + }; + + EXPECT_CALL(*renderer, draw(_, Rect{0, 0, + single_window.frame().width(), + single_window.frame().height()}, + expected_renderables)) + .Times(1) + .WillOnce(Return(true)); + + composer.submit_layers(renderables_second); + EXPECT_TRUE(window->checkResizeable() == false); +} } // namespace graphics } // namespace anbox -- GitLab