提交 128cc242 编写于 作者: S Simon Fels

Add unit tests for LayerComposer

上级 dbbb8ab7
......@@ -118,6 +118,7 @@ set(SOURCES
anbox/graphics/layer_composer.cpp
anbox/graphics/program_family.cpp
anbox/graphics/primitives.h
anbox/graphics/renderer.h
anbox/graphics/emugl/ColorBuffer.cpp
anbox/graphics/emugl/DisplayManager.cpp
......
......@@ -47,3 +47,9 @@ void Renderable::set_screen_position(
const anbox::graphics::Rect &screen_position) {
screen_position_ = screen_position;
}
std::ostream &operator<<(std::ostream &out, const Renderable &r) {
return out << "{ name " << r.name() << " buffer " << r.buffer()
<< " screen position " << r.screen_position() << " crop "
<< r.crop() << " alpha " << r.alpha();
}
......@@ -43,6 +43,16 @@ class Renderable {
void set_screen_position(const anbox::graphics::Rect &screen_position);
inline bool operator==(const Renderable &rhs) const {
return (name_ == rhs.name() && buffer_ == rhs.buffer() &&
screen_position_ == rhs.screen_position() && crop_ == rhs.crop() &&
transformation_ == rhs.transformation() && alpha_ == rhs.alpha());
}
inline bool operator!=(const Renderable &rhs) const {
return !operator==(rhs);
}
private:
std::string name_;
std::uint32_t buffer_;
......@@ -52,6 +62,8 @@ class Renderable {
float alpha_;
};
std::ostream &operator<<(std::ostream &out, const Renderable &r);
typedef std::vector<Renderable> RenderableList;
#endif
......@@ -27,6 +27,7 @@
#include "anbox/graphics/primitives.h"
#include "anbox/graphics/program_family.h"
#include "anbox/graphics/renderer.h"
#include <EGL/egl.h>
......@@ -71,10 +72,10 @@ struct RendererWindow;
// There is only one global instance, that can be retrieved with getFB(),
// and which must be previously setup by calling initialize().
//
class Renderer {
class Renderer : public anbox::graphics::Renderer {
public:
Renderer();
~Renderer();
virtual ~Renderer();
// Initialize the global instance.
// |width| and |height| are the dimensions of the emulator GPU display
......@@ -223,7 +224,7 @@ class Renderer {
bool draw(EGLNativeWindowType native_window,
const anbox::graphics::Rect& window_frame,
const RenderableList& renderables);
const RenderableList& renderables) override;
// Return the host EGLDisplay used by this instance.
EGLDisplay getDisplay() const { return m_eglDisplay; }
......
......@@ -43,10 +43,9 @@ void logger_write(const char *format, ...) {
namespace anbox {
namespace graphics {
GLRendererServer::GLRendererServer(const std::shared_ptr<wm::Manager> &wm)
: renderer_(std::make_shared<Renderer>()),
: renderer_(std::make_shared<::Renderer>()),
wm_(wm),
composer_(std::make_shared<LayerComposer>(renderer_, wm)) {
if (utils::is_env_set("USE_HOST_GLES")) {
// Force the host EGL/GLES libraries as translator implementation
::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 0);
......@@ -83,8 +82,6 @@ GLRendererServer::GLRendererServer(const std::shared_ptr<wm::Manager> &wm)
registerLayerComposer(composer_);
}
GLRendererServer::~GLRendererServer() {
renderer_->finalize();
}
GLRendererServer::~GLRendererServer() { renderer_->finalize(); }
} // namespace graphics
} // namespace anbox
......@@ -22,7 +22,8 @@
namespace anbox {
namespace graphics {
LayerComposer::LayerComposer(const std::shared_ptr<Renderer> renderer, const std::shared_ptr<wm::Manager> &wm)
LayerComposer::LayerComposer(const std::shared_ptr<Renderer> renderer,
const std::shared_ptr<wm::Manager> &wm)
: renderer_(renderer), wm_(wm) {}
LayerComposer::~LayerComposer() {}
......@@ -85,10 +86,9 @@ void LayerComposer::submit_layers(const RenderableList &renderables) {
final_renderables.push_back(new_renderable);
}
renderer_->draw(
window->native_handle(),
Rect{0, 0, window->frame().width(), window->frame().height()},
final_renderables);
renderer_->draw(window->native_handle(), Rect{0, 0, window->frame().width(),
window->frame().height()},
final_renderables);
}
}
} // namespace graphics
......
......@@ -18,12 +18,10 @@
#ifndef ANBOX_GRAPHICS_LAYER_COMPOSER_H_
#define ANBOX_GRAPHICS_LAYER_COMPOSER_H_
#include "anbox/graphics/emugl/Renderable.h"
#include "anbox/graphics/renderer.h"
#include <memory>
class Renderer;
namespace anbox {
namespace wm {
class Manager;
......@@ -31,7 +29,8 @@ class Manager;
namespace graphics {
class LayerComposer {
public:
LayerComposer(const std::shared_ptr<Renderer> renderer, const std::shared_ptr<wm::Manager> &wm);
LayerComposer(const std::shared_ptr<Renderer> renderer,
const std::shared_ptr<wm::Manager> &wm);
~LayerComposer();
void submit_layers(const RenderableList &renderables);
......
/*
* 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 ANBOX_GRAPHICS_RENDERER_H_
#define ANBOX_GRAPHICS_RENDERER_H_
#include "anbox/graphics/emugl/Renderable.h"
#include <EGL/egl.h>
namespace anbox {
namespace graphics {
class Renderer {
public:
virtual ~Renderer() {}
virtual bool draw(EGLNativeWindowType native_window,
const anbox::graphics::Rect& window_frame,
const RenderableList& renderables) = 0;
};
} // namespace graphics
} // namespace anbox
#endif
......@@ -24,7 +24,7 @@ class NullWindow : public anbox::wm::Window {
public:
NullWindow(const anbox::wm::Task::Id &task,
const anbox::graphics::Rect &frame)
: anbox::wm::Window(nullptr, 0, frame) {}
: anbox::wm::Window(nullptr, task, frame) {}
};
}
......@@ -34,7 +34,6 @@ DefaultPlatformPolicy::DefaultPlatformPolicy() {}
std::shared_ptr<Window> DefaultPlatformPolicy::create_window(
const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) {
DEBUG("");
return std::make_shared<::NullWindow>(task, frame);
}
} // namespace wm
......
ANBOX_ADD_TEST(buffer_queue_tests buffer_queue_tests.cpp)
ANBOX_ADD_TEST(buffered_io_stream_tests buffered_io_stream_tests.cpp)
ANBOX_ADD_TEST(layer_composer_tests layer_composer_tests.cpp)
/*
* 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/>.
*
*/
// Both includes need to go first as otherwise they can conflict with EGL.h
// being included by the following includes.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "anbox/wm/default_platform_policy.h"
#include "anbox/wm/manager.h"
#include "anbox/wm/window_state.h"
#include "anbox/graphics/layer_composer.h"
using namespace ::testing;
namespace {
class MockRenderer : public anbox::graphics::Renderer {
public:
MOCK_METHOD3(draw, bool(EGLNativeWindowType, const anbox::graphics::Rect&,
const RenderableList&));
};
}
namespace anbox {
namespace graphics {
TEST(LayerComposer, FindsNoSuitableWindowForLayer) {
auto renderer = std::make_shared<MockRenderer>();
// The default policy will create a dumb window instance when requested
// from the manager.
auto platform_policy = std::make_shared<wm::DefaultPlatformPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy);
auto single_window = wm::WindowState{
wm::Display::Id{1},
true,
graphics::Rect{0, 0, 1024, 768},
"org.anbox.test.1",
wm::Task::Id{1},
wm::Stack::Freeform,
};
wm->apply_window_state_update({single_window}, {});
LayerComposer composer(renderer, wm);
// A single renderable which has a different task id then the window we know
// about
RenderableList renderables = {
{"org.anbox.surface.2", 0, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
};
// The renderer should not be called for a layer which doesn't exist
EXPECT_CALL(*renderer, draw(_, _, _)).Times(0);
composer.submit_layers(renderables);
}
TEST(LayerComposer, MapsLayersToWindows) {
auto renderer = std::make_shared<MockRenderer>();
// The default policy will create a dumb window instance when requested
// from the manager.
auto platform_policy = std::make_shared<wm::DefaultPlatformPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy);
auto first_window = wm::WindowState{
wm::Display::Id{1},
true,
graphics::Rect{0, 0, 1024, 768},
"org.anbox.foo",
wm::Task::Id{1},
wm::Stack::Freeform,
};
auto second_window = wm::WindowState{
wm::Display::Id{1},
true,
graphics::Rect{300, 400, 1324, 1168},
"org.anbox.bar",
wm::Task::Id{2},
wm::Stack::Freeform,
};
wm->apply_window_state_update({first_window, second_window}, {});
LayerComposer composer(renderer, wm);
// A single renderable which has a different task id then the window we know
// about
RenderableList renderables = {
{"org.anbox.surface.1", 0, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
{"org.anbox.surface.2", 1, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
};
RenderableList first_window_renderables{
{"org.anbox.surface.1", 0, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
};
RenderableList second_window_renderables{
{"org.anbox.surface.2", 1, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
};
EXPECT_CALL(*renderer, draw(_, Rect{0, 0, first_window.frame().width(),
first_window.frame().height()},
first_window_renderables))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*renderer, draw(_, Rect{0, 0, second_window.frame().width(),
second_window.frame().height()},
second_window_renderables))
.Times(1)
.WillOnce(Return(true));
composer.submit_layers(renderables);
}
TEST(LayerComposer, WindowPartiallyOffscreen) {
auto renderer = std::make_shared<MockRenderer>();
// The default policy will create a dumb window instance when requested
// from the manager.
auto platform_policy = std::make_shared<wm::DefaultPlatformPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy);
auto window = wm::WindowState{
wm::Display::Id{1},
true,
graphics::Rect{-100, -100, 924, 668},
"org.anbox.foo",
wm::Task::Id{1},
wm::Stack::Freeform,
};
wm->apply_window_state_update({window}, {});
LayerComposer composer(renderer, wm);
// Window is build out of two layers where one is placed inside the other
// 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, {-100, -100, 924, 668}, {0, 0, 1024, 768}},
{"org.anbox.surface.1", 1, {0, 0, 100, 200}, {0, 0, 100, 200}},
};
RenderableList expected_renderables{
{"org.anbox.surface.1", 0, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
{"org.anbox.surface.1", 1, {100, 100, 200, 300}, {0, 0, 100, 200}},
};
EXPECT_CALL(*renderer, draw(_, Rect{0, 0,
window.frame().width(),
window.frame().height()},
expected_renderables))
.Times(1)
.WillOnce(Return(true));
composer.submit_layers(renderables);
}
TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) {
auto renderer = std::make_shared<MockRenderer>();
// The default policy will create a dumb window instance when requested
// from the manager.
auto platform_policy = std::make_shared<wm::DefaultPlatformPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy);
auto window = wm::WindowState{
wm::Display::Id{1},
true,
graphics::Rect{1120, 270, 2144, 1038},
"org.anbox.foo",
wm::Task::Id{3},
wm::Stack::Freeform,
};
wm->apply_window_state_update({window}, {});
LayerComposer composer(renderer, wm);
// Having two renderables where the second smaller one overlaps the bigger
// one and goes a bit offscreen. This should be still placed correctly and
// the small layer should go offscreen as it is supposed to. This typically
// happens when a popup window appears which has a shadow attached which goes
// out of the window area. In our case this is not possible as the area the
// window has available is static.
RenderableList renderables = {
{"org.anbox.surface.3", 0, {1120,270,2144,1038}, {0, 0, 1024, 768}},
{"org.anbox.surface.3", 1, {1904, 246, 2164, 406}, {0, 0, 260, 160}},
};
RenderableList expected_renderables{
{"org.anbox.surface.3", 0, {0, 0, 1024, 768}, {0, 0, 1024, 768}},
{"org.anbox.surface.3", 1, {784, -24, 1044, 136}, {0, 0, 260, 160}},
};
EXPECT_CALL(*renderer, draw(_, Rect{0, 0,
window.frame().width(),
window.frame().height()},
expected_renderables))
.Times(1)
.WillOnce(Return(true));
composer.submit_layers(renderables);
}
} // namespace graphics
} // namespace anbox
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册