mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 16:35:28 +00:00
nitpicker: improve GUI client resize handling
This patch replaces meta-data allocation during the resize handling by a new 'Resizeable_texture' type that has all meta data preallocated. It also replaces the use of pointer return values with the 'Resizeable_texture::with_texture' method. Issue #3812
This commit is contained in:
parent
4cad1a87df
commit
320387db89
@ -28,6 +28,8 @@ struct Nitpicker::Background : private Texture_base, View
|
||||
|
||||
Color color = default_color();
|
||||
|
||||
Resizeable_texture<Pixel> _texture { };
|
||||
|
||||
/*
|
||||
* The background uses no texture. Therefore we can pass a null pointer as
|
||||
* texture argument to the Session constructor.
|
||||
@ -35,7 +37,7 @@ struct Nitpicker::Background : private Texture_base, View
|
||||
Background(View_owner &owner, Area size)
|
||||
:
|
||||
Texture_base(Area(0, 0)),
|
||||
View(owner, View::NOT_TRANSPARENT, View::BACKGROUND, 0)
|
||||
View(owner, _texture, View::NOT_TRANSPARENT, View::BACKGROUND, 0)
|
||||
{
|
||||
View::geometry(Rect(Point(0, 0), size));
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ namespace Nitpicker { struct Buffer_provider; }
|
||||
*/
|
||||
struct Nitpicker::Buffer_provider : Interface
|
||||
{
|
||||
virtual Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0;
|
||||
virtual Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0;
|
||||
};
|
||||
|
||||
#endif /* _BUFFER_H_ */
|
||||
|
@ -59,15 +59,15 @@ class Nitpicker::Chunky_texture : public Buffer, public Texture<PT>
|
||||
return bytes_per_pixel*size.w()*size.h();
|
||||
}
|
||||
|
||||
unsigned char *input_mask_buffer()
|
||||
unsigned char const *input_mask_buffer() const
|
||||
{
|
||||
if (!Texture<PT>::alpha()) return 0;
|
||||
|
||||
Area const size = Texture<PT>::size();
|
||||
|
||||
/* input-mask values come right after the alpha values */
|
||||
return (unsigned char *)local_addr() + calc_num_bytes(size, false)
|
||||
+ size.count();
|
||||
return (unsigned char const *)local_addr() + calc_num_bytes(size, false)
|
||||
+ size.count();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,6 @@ class Framebuffer::Session_component : public Rpc_object<Session>
|
||||
Session_component(Session_component const &);
|
||||
Session_component &operator = (Session_component const &);
|
||||
|
||||
Buffer *_buffer = 0;
|
||||
View_stack &_view_stack;
|
||||
Nitpicker::Gui_session &_session;
|
||||
Buffer_provider &_buffer_provider;
|
||||
@ -94,9 +93,7 @@ class Framebuffer::Session_component : public Rpc_object<Session>
|
||||
|
||||
Dataspace_capability dataspace() override
|
||||
{
|
||||
_buffer = _buffer_provider.realloc_buffer(_mode, _alpha);
|
||||
|
||||
return _buffer ? _buffer->ds_cap() : Ram_dataspace_capability();
|
||||
return _buffer_provider.realloc_buffer(_mode, _alpha);
|
||||
}
|
||||
|
||||
Mode mode() const override { return _mode; }
|
||||
|
@ -16,26 +16,6 @@
|
||||
using namespace Nitpicker;
|
||||
|
||||
|
||||
void Gui_session::_release_buffer()
|
||||
{
|
||||
if (!_texture)
|
||||
return;
|
||||
|
||||
typedef Pixel_rgb888 PT;
|
||||
|
||||
Chunky_texture<PT> const *cdt = static_cast<Chunky_texture<PT> const *>(_texture);
|
||||
|
||||
_texture = nullptr;
|
||||
_uses_alpha = false;
|
||||
_input_mask = nullptr;
|
||||
|
||||
destroy(&_session_alloc, const_cast<Chunky_texture<PT> *>(cdt));
|
||||
|
||||
replenish(Ram_quota{_buffer_size});
|
||||
_buffer_size = 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gui_session::_views_are_equal(View_handle v1, View_handle v2)
|
||||
{
|
||||
if (!v1.valid() || !v2.valid())
|
||||
@ -266,7 +246,7 @@ Gui_session::View_handle Gui_session::create_view(View_handle parent_handle)
|
||||
return View_handle();
|
||||
|
||||
view = new (_view_alloc)
|
||||
View(*this, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, &(*parent));
|
||||
View(*this, _texture, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, &(*parent));
|
||||
|
||||
parent->add_child(*view);
|
||||
}
|
||||
@ -280,7 +260,7 @@ Gui_session::View_handle Gui_session::create_view(View_handle parent_handle)
|
||||
else {
|
||||
try {
|
||||
view = new (_view_alloc)
|
||||
View(*this, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, nullptr);
|
||||
View(*this, _texture, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, nullptr);
|
||||
}
|
||||
catch (Allocator::Out_of_memory) { throw Out_of_ram(); }
|
||||
}
|
||||
@ -462,79 +442,60 @@ void Gui_session::session_control(Label suffix, Session_control control)
|
||||
}
|
||||
|
||||
|
||||
Buffer *Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha)
|
||||
Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha)
|
||||
{
|
||||
typedef Pixel_rgb888 PT;
|
||||
|
||||
size_t const buffer_size = Chunky_texture<PT>::calc_num_bytes(mode.area, use_alpha);
|
||||
Ram_quota const next_buffer_size { Chunky_texture<Pixel>::calc_num_bytes(mode.area, use_alpha) };
|
||||
Ram_quota const orig_buffer_size { _buffer_size };
|
||||
|
||||
/*
|
||||
* Preserve the content of the original buffer if nitpicker has
|
||||
* enough slack memory to temporarily keep the original pixels.
|
||||
*/
|
||||
Texture<PT> const *src_texture = nullptr;
|
||||
if (texture()) {
|
||||
|
||||
enum { PRESERVED_RAM = 128*1024 };
|
||||
if (_env.pd().avail_ram().value > buffer_size + PRESERVED_RAM) {
|
||||
src_texture = static_cast<Texture<PT> const *>(texture());
|
||||
} else {
|
||||
warning("not enough RAM to preserve buffer content during resize");
|
||||
_release_buffer();
|
||||
}
|
||||
enum { PRESERVED_RAM = 128*1024 };
|
||||
bool const preserve_content =
|
||||
(_env.pd().avail_ram().value > next_buffer_size.value + PRESERVED_RAM);
|
||||
|
||||
if (!preserve_content) {
|
||||
warning("not enough RAM to preserve buffer content during resize");
|
||||
_texture.release_current();
|
||||
replenish(orig_buffer_size);
|
||||
}
|
||||
|
||||
/* set new buffer_size after _release_buffer(), which changes _buffer_size also */
|
||||
_buffer_size = buffer_size;
|
||||
_buffer_size = 0;
|
||||
_uses_alpha = false;
|
||||
_input_mask = nullptr;
|
||||
|
||||
Ram_quota const temporary_ram_upgrade = src_texture
|
||||
? Ram_quota{_buffer_size} : Ram_quota{0};
|
||||
Ram_quota const temporary_ram_upgrade = _texture.valid()
|
||||
? next_buffer_size : Ram_quota{0};
|
||||
|
||||
_ram_quota_guard().upgrade(temporary_ram_upgrade);
|
||||
|
||||
auto try_alloc_texture = [&] ()
|
||||
{
|
||||
try {
|
||||
return new (&_session_alloc)
|
||||
Chunky_texture<PT>(_env.ram(), _env.rm(), mode.area, use_alpha);
|
||||
} catch (...) {
|
||||
return (Chunky_texture<PT>*)nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
Chunky_texture<PT> * const texture = try_alloc_texture();
|
||||
|
||||
if (!texture) {
|
||||
_release_buffer();
|
||||
if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode.area, use_alpha)) {
|
||||
_texture.release_current();
|
||||
replenish(orig_buffer_size);
|
||||
_ram_quota_guard().try_downgrade(temporary_ram_upgrade);
|
||||
return nullptr;
|
||||
return Dataspace_capability();
|
||||
}
|
||||
|
||||
/* copy old buffer content into new buffer and release old buffer */
|
||||
if (src_texture) {
|
||||
_texture.switch_to_next();
|
||||
|
||||
Surface<PT> surface(texture->pixel(),
|
||||
texture->Texture_base::size());
|
||||
/* 'switch_to_next' has released the current texture */
|
||||
if (preserve_content)
|
||||
replenish(orig_buffer_size);
|
||||
|
||||
Texture_painter::paint(surface, *src_texture, Color(), Point(0, 0),
|
||||
Texture_painter::SOLID, false);
|
||||
_release_buffer();
|
||||
if (!_ram_quota_guard().try_downgrade(temporary_ram_upgrade))
|
||||
warning("accounting error during framebuffer realloc");
|
||||
|
||||
if (!_ram_quota_guard().try_downgrade(temporary_ram_upgrade))
|
||||
warning("accounting error during framebuffer realloc");
|
||||
|
||||
}
|
||||
|
||||
try { withdraw(Ram_quota{_buffer_size}); }
|
||||
try { withdraw(next_buffer_size); }
|
||||
catch (...) {
|
||||
destroy(&_session_alloc, texture);
|
||||
_buffer_size = 0;
|
||||
return nullptr;
|
||||
_texture.release_current();
|
||||
return Dataspace_capability();
|
||||
}
|
||||
|
||||
_texture = texture;
|
||||
_uses_alpha = use_alpha;
|
||||
_input_mask = texture->input_mask_buffer();
|
||||
_buffer_size = next_buffer_size.value;
|
||||
_uses_alpha = use_alpha;
|
||||
_input_mask = _texture.input_mask_buffer();
|
||||
|
||||
return texture;
|
||||
return _texture.dataspace();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <os/session_policy.h>
|
||||
#include <os/reporter.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <blit/painter.h>
|
||||
#include <gui_session/gui_session.h>
|
||||
|
||||
/* local includes */
|
||||
@ -29,7 +30,6 @@
|
||||
#include "framebuffer_session.h"
|
||||
#include "input_session.h"
|
||||
#include "focus.h"
|
||||
#include "chunky_texture.h"
|
||||
#include "view.h"
|
||||
|
||||
namespace Nitpicker {
|
||||
@ -73,8 +73,9 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
|
||||
Constrained_ram_allocator _ram;
|
||||
|
||||
Resizeable_texture<Pixel> _texture { };
|
||||
|
||||
Domain_registry::Entry const *_domain = nullptr;
|
||||
Texture_base const *_texture = nullptr;
|
||||
View *_background = nullptr;
|
||||
|
||||
/*
|
||||
@ -152,8 +153,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
return _domain ? _domain->phys_pos(pos, screen_area) : Point(0, 0);
|
||||
}
|
||||
|
||||
void _release_buffer();
|
||||
|
||||
/**
|
||||
* Helper for performing sanity checks in OP_TO_FRONT and OP_TO_BACK
|
||||
*
|
||||
@ -203,8 +202,6 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
_env.ep().dissolve(_input_session_component);
|
||||
|
||||
destroy_all_views();
|
||||
|
||||
_release_buffer();
|
||||
}
|
||||
|
||||
using Session_list::Element::next;
|
||||
@ -261,9 +258,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
|
||||
View const *background() const override { return _background; }
|
||||
|
||||
Texture_base const *texture() const override { return _texture; }
|
||||
|
||||
bool uses_alpha() const override { return _texture && _uses_alpha; }
|
||||
bool uses_alpha() const override { return _texture.valid() && _uses_alpha; }
|
||||
|
||||
unsigned layer() const override { return _domain ? _domain->layer() : ~0UL; }
|
||||
|
||||
@ -274,14 +269,14 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
*/
|
||||
unsigned char input_mask_at(Point p) const override
|
||||
{
|
||||
if (!_input_mask || !_texture) return 0;
|
||||
if (!_input_mask || !_texture.valid()) return 0;
|
||||
|
||||
/* check boundaries */
|
||||
if ((unsigned)p.x() >= _texture->size().w()
|
||||
|| (unsigned)p.y() >= _texture->size().h())
|
||||
if ((unsigned)p.x() >= _texture.size().w()
|
||||
|| (unsigned)p.y() >= _texture.size().h())
|
||||
return 0;
|
||||
|
||||
return _input_mask[p.y()*_texture->size().w() + p.x()];
|
||||
return _input_mask[p.y()*_texture.size().w() + p.x()];
|
||||
}
|
||||
|
||||
void submit_input_event(Input::Event e) override;
|
||||
@ -392,7 +387,7 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
|
||||
** Buffer_provider interface **
|
||||
*******************************/
|
||||
|
||||
Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override;
|
||||
Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override;
|
||||
};
|
||||
|
||||
#endif /* _GUI_SESSION_H_ */
|
||||
|
@ -22,9 +22,11 @@ namespace Nitpicker { struct Pointer_origin; }
|
||||
|
||||
struct Nitpicker::Pointer_origin : View
|
||||
{
|
||||
Resizeable_texture<Pixel> _texture { };
|
||||
|
||||
Pointer_origin(View_owner &owner)
|
||||
:
|
||||
View(owner, View::TRANSPARENT, View::NOT_BACKGROUND, 0)
|
||||
View(owner, _texture, View::TRANSPARENT, View::NOT_BACKGROUND, 0)
|
||||
{ }
|
||||
|
||||
|
||||
|
109
repos/os/src/server/nitpicker/resizeable_texture.h
Normal file
109
repos/os/src/server/nitpicker/resizeable_texture.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* \brief Texture that preserves content across resize
|
||||
* \author Norman Feske
|
||||
* \date 2020-07-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _RESIZEABLE_TEXTURE_H_
|
||||
#define _RESIZEABLE_TEXTURE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <blit/painter.h>
|
||||
|
||||
/* local includes */
|
||||
#include "chunky_texture.h"
|
||||
|
||||
namespace Nitpicker { template <typename> class Resizeable_texture; }
|
||||
|
||||
|
||||
template <typename PT>
|
||||
class Nitpicker::Resizeable_texture
|
||||
{
|
||||
private:
|
||||
|
||||
unsigned _current = 0;
|
||||
|
||||
using Constructible_texture = Constructible<Chunky_texture<PT>>;
|
||||
|
||||
struct Element : Constructible_texture
|
||||
{
|
||||
Element() : Constructible_texture() { }
|
||||
};
|
||||
|
||||
Element _textures[2];
|
||||
|
||||
public:
|
||||
|
||||
bool valid() const { return _textures[_current].constructed(); }
|
||||
|
||||
Area size() const
|
||||
{
|
||||
return valid() ? _textures[_current]->Texture_base::size()
|
||||
: Area { };
|
||||
}
|
||||
|
||||
void release_current() { _textures[_current].destruct(); }
|
||||
|
||||
bool try_construct_next(Ram_allocator &ram, Region_map &rm,
|
||||
Area size, bool use_alpha)
|
||||
{
|
||||
try {
|
||||
unsigned const next = !_current;
|
||||
_textures[next].construct(ram, rm, size, use_alpha);
|
||||
return true;
|
||||
} catch (...) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the next texture the current one
|
||||
*
|
||||
* This method destructs the previous current one.
|
||||
*/
|
||||
void switch_to_next()
|
||||
{
|
||||
unsigned const next = !_current;
|
||||
|
||||
/* copy content from current to next texture */
|
||||
if (_textures[next].constructed() && _textures[_current].constructed()) {
|
||||
|
||||
Surface<PT> surface(_textures[next]->pixel(),
|
||||
_textures[next]->Texture_base::size());
|
||||
|
||||
Texture<PT> const &texture = *_textures[_current];
|
||||
|
||||
Blit_painter::paint(surface, texture, Point(0, 0));
|
||||
}
|
||||
|
||||
_textures[_current].destruct();
|
||||
|
||||
_current = next;
|
||||
}
|
||||
|
||||
template <typename FN>
|
||||
void with_texture(FN const &fn) const
|
||||
{
|
||||
if (valid())
|
||||
fn(*_textures[_current]);
|
||||
}
|
||||
|
||||
Dataspace_capability dataspace()
|
||||
{
|
||||
return valid() ? _textures[_current]->ds_cap() : Ram_dataspace_capability();
|
||||
}
|
||||
|
||||
unsigned char const *input_mask_buffer() const
|
||||
{
|
||||
return valid() ? _textures[_current]->input_mask_buffer()
|
||||
: nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _RESIZEABLE_TEXTURE_H_ */
|
@ -20,6 +20,7 @@
|
||||
#include <base/allocator.h>
|
||||
#include <base/log.h>
|
||||
#include <os/surface.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
|
||||
namespace Gui { }
|
||||
|
||||
@ -27,6 +28,7 @@ namespace Nitpicker {
|
||||
|
||||
using namespace Genode;
|
||||
using namespace Gui;
|
||||
using Pixel = Pixel_rgb888;
|
||||
|
||||
typedef Surface_base::Point Point;
|
||||
typedef Surface_base::Area Area;
|
||||
|
@ -125,13 +125,12 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f
|
||||
owner_color.g >> 1,
|
||||
owner_color.b >> 1);
|
||||
|
||||
Texture_base const *texture = _owner.texture();
|
||||
if (texture) {
|
||||
canvas.draw_texture(_buffer_off + view_rect.p1(), *texture, op,
|
||||
mix_color, allow_alpha);
|
||||
} else {
|
||||
_texture.with_texture([&] (Texture_base const &texture) {
|
||||
canvas.draw_texture(_buffer_off + view_rect.p1(), texture, op,
|
||||
mix_color, allow_alpha); });
|
||||
|
||||
if (!_texture.valid())
|
||||
canvas.draw_box(view_rect, black());
|
||||
}
|
||||
|
||||
if (!_owner.label_visible()) return;
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
/* local includes */
|
||||
#include "canvas.h"
|
||||
#include "view_owner.h"
|
||||
#include "resizeable_texture.h"
|
||||
|
||||
namespace Nitpicker {
|
||||
|
||||
@ -102,6 +103,8 @@ class Nitpicker::View : private Same_buffer_list_elem,
|
||||
View_owner &_owner;
|
||||
Title _title { "" };
|
||||
|
||||
Resizeable_texture<Pixel> const &_texture;
|
||||
|
||||
List<View_parent_elem> _children { };
|
||||
|
||||
/**
|
||||
@ -127,9 +130,11 @@ class Nitpicker::View : private Same_buffer_list_elem,
|
||||
|
||||
public:
|
||||
|
||||
View(View_owner &owner, Transparent transparent, Background bg, View *parent)
|
||||
View(View_owner &owner, Resizeable_texture<Pixel> const &texture,
|
||||
Transparent transparent, Background bg, View *parent)
|
||||
:
|
||||
_transparent(transparent), _background(bg), _parent(parent), _owner(owner)
|
||||
_transparent(transparent), _background(bg), _parent(parent),
|
||||
_owner(owner), _texture(texture)
|
||||
{ }
|
||||
|
||||
virtual ~View()
|
||||
|
@ -79,11 +79,6 @@ struct Nitpicker::View_owner : Interface
|
||||
*/
|
||||
virtual View const *background() const { return nullptr; }
|
||||
|
||||
/**
|
||||
* Teturn texture containing the owners virtual frame buffer
|
||||
*/
|
||||
virtual Texture_base const *texture() const { return nullptr; }
|
||||
|
||||
/**
|
||||
* Return input-mask value at given position
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user