client: display channel migration

(cherry picked from commit cad3c58544 branch 0.8)

Conflicts:

	client/display_channel.cpp
This commit is contained in:
Yonit Halperin 2011-09-18 21:50:06 +03:00
parent 87664af999
commit 00ff038cc9
2 changed files with 154 additions and 15 deletions

View File

@ -87,6 +87,28 @@ private:
DisplayChannel& _channel;
};
class DestroyAllSurfacesEvent: public SyncEvent {
public:
DestroyAllSurfacesEvent(DisplayChannel& channel, bool include_primary = true)
: _channel(channel)
, _include_primary(include_primary)
{
}
virtual void do_response(AbstractProcessLoop& events_loop)
{
if (_include_primary) {
_channel.do_destroy_all_surfaces();
} else {
_channel.do_destroy_off_screen_surfaces();
}
}
private:
DisplayChannel& _channel;
bool _include_primary;
};
class CreateSurfaceEvent: public SyncEvent {
public:
CreateSurfaceEvent(DisplayChannel& channel, int surface_id, int width, int height,
@ -547,6 +569,21 @@ void ResetTimer::response(AbstractProcessLoop& events_loop)
_client.deactivate_interval_timer(this);
}
#define MIGRATION_PRIMARY_SURFACE_TIMEOUT (1000 * 5)
class MigPrimarySurfaceTimer: public Timer {
public:
virtual void response(AbstractProcessLoop& events_loop)
{
DisplayChannel *channel = static_cast<DisplayChannel*>(events_loop.get_owner());
if (channel->_mig_wait_primary) {
channel->destroy_primary_surface();
channel->_mig_wait_primary = false;
}
channel->get_process_loop().deactivate_interval_timer(this);
}
};
class DisplayHandler: public MessageHandlerImp<DisplayChannel, SPICE_CHANNEL_DISPLAY> {
public:
DisplayHandler(DisplayChannel& channel)
@ -574,6 +611,7 @@ DisplayChannel::DisplayChannel(RedClient& client, uint32_t id,
, _gl_interrupt_recreate (*this)
#endif
, _interrupt_update (*this)
, _mig_wait_primary (false)
{
DisplayHandler* handler = static_cast<DisplayHandler*>(get_message_handler());
@ -621,11 +659,11 @@ DisplayChannel::~DisplayChannel()
screen()->set_update_interrupt_trigger(NULL);
}
//destroy_canvas(); fixme destroy all
destroy_strams();
destroy_streams();
do_destroy_all_surfaces();
}
void DisplayChannel::destroy_strams()
void DisplayChannel::destroy_streams()
{
Lock lock(_streams_lock);
for (unsigned int i = 0; i < _streams.size(); i++) {
@ -1024,6 +1062,75 @@ void DisplayChannel::on_disconnect()
(*sync_event)->wait();
}
void DisplayChannel::do_destroy_all_surfaces()
{
SurfacesCache::iterator s_iter;
for (s_iter = _surfaces_cache.begin(); s_iter != _surfaces_cache.end(); s_iter++) {
delete (*s_iter).second;
}
_surfaces_cache.clear();
}
void DisplayChannel::do_destroy_off_screen_surfaces()
{
SurfacesCache::iterator s_iter;
Canvas *primary_canvas = NULL;
for (s_iter = _surfaces_cache.begin(); s_iter != _surfaces_cache.end(); s_iter++) {
if (s_iter->first == 0) {
primary_canvas = s_iter->second;
} else {
delete s_iter->second;
}
}
_surfaces_cache.clear();
if (primary_canvas) {
_surfaces_cache[0] = primary_canvas;
}
}
void DisplayChannel::destroy_all_surfaces()
{
AutoRef<DestroyAllSurfacesEvent> destroy_event(new DestroyAllSurfacesEvent(*this));
get_client().push_event(*destroy_event);
(*destroy_event)->wait();
if (!(*destroy_event)->success()) {
THROW("destroy all surfaces failed");
}
}
void DisplayChannel::destroy_off_screen_surfaces()
{
AutoRef<DestroyAllSurfacesEvent> destroy_event(new DestroyAllSurfacesEvent(*this, false));
get_client().push_event(*destroy_event);
(*destroy_event)->wait();
if (!(*destroy_event)->success()) {
THROW("destroy all surfaces failed");
}
}
void DisplayChannel::on_disconnect_mig_src()
{
_palette_cache.clear();
destroy_streams();
if (screen()) {
screen()->set_update_interrupt_trigger(NULL);
}
_update_mark = 0;
_next_timer_time = 0;
get_client().deactivate_interval_timer(*_streams_timer);
destroy_off_screen_surfaces();
// Not clrearing the primary surface till we receive a new one (or a timeout).
if (_surfaces_cache.exist(0)) {
AutoRef<MigPrimarySurfaceTimer> mig_timer(new MigPrimarySurfaceTimer());
get_process_loop().activate_interval_timer(*mig_timer, MIGRATION_PRIMARY_SURFACE_TIMEOUT);
_mig_wait_primary = true;
}
}
bool DisplayChannel::create_sw_canvas(int surface_id, int width, int height, uint32_t format)
{
try {
@ -1365,26 +1472,50 @@ void DisplayChannel::handle_stream_destroy(RedPeer::InMessage* message)
void DisplayChannel::handle_stream_destroy_all(RedPeer::InMessage* message)
{
destroy_strams();
destroy_streams();
}
void DisplayChannel::create_primary_surface(int width, int height, uint32_t format)
{
bool do_create_primary = true;
#ifdef USE_OPENGL
Canvas *canvas;
Canvas *canvas;
#endif
_mark = false;
attach_to_screen(get_client().get_application(), get_id());
clear_area();
_mark = false;
AutoRef<CreatePrimarySurfaceEvent> event(new CreatePrimarySurfaceEvent(*this, width, height,
format));
get_client().push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
THROW("Create primary surface failed");
/*
* trying to avoid artifacts when the display hasn't changed much
* between the disconnection from the migration src and the
* connection to the target.
*/
if (_mig_wait_primary) {
ASSERT(_surfaces_cache.exist(0));
if (_x_res != width || _y_res != height || format != format) {
LOG_INFO("destroy the primary surface of the mig src session");
destroy_primary_surface();
} else {
LOG_INFO("keep the primary surface of the mig src session");
_surfaces_cache[0]->clear();
clear_area();
do_create_primary = false;
}
}
if (do_create_primary) {
LOG_INFO("");
attach_to_screen(get_client().get_application(), get_id());
clear_area();
AutoRef<CreatePrimarySurfaceEvent> event(new CreatePrimarySurfaceEvent(*this, width, height,
format));
get_client().push_event(*event);
(*event)->wait();
if (!(*event)->success()) {
THROW("Create primary surface failed");
}
}
_mig_wait_primary = false;
_x_res = width;
_y_res = height;
_format = format;

View File

@ -114,6 +114,7 @@ public:
protected:
virtual void on_connect();
virtual void on_disconnect();
virtual void on_disconnect_mig_src();
private:
void set_draw_handlers();
@ -129,13 +130,17 @@ private:
void destroy_canvas(int surface_id);
void create_canvas(int surface_id, const std::vector<int>& canvas_type, int width, int height,
uint32_t format);
void destroy_strams();
void destroy_streams();
void update_cursor();
void create_primary_surface(int width, int height, uint32_t format);
void create_surface(int surface_id, int width, int height, uint32_t format);
void destroy_primary_surface();
void destroy_surface(int surface_id);
void destroy_all_surfaces();
void do_destroy_all_surfaces();
void destroy_off_screen_surfaces();
void do_destroy_off_screen_surfaces();
void handle_mode(RedPeer::InMessage* message);
void handle_mark(RedPeer::InMessage* message);
@ -217,11 +222,13 @@ private:
#endif
InterruptUpdate _interrupt_update;
bool _mig_wait_primary;
friend class SetModeEvent;
friend class CreatePrimarySurfaceEvent;
friend class DestroyPrimarySurfaceEvent;
friend class CreateSurfaceEvent;
friend class DestroySurfaceEvent;
friend class DestroyAllSurfacesEvent;
friend class ActivateTimerEvent;
friend class VideoStream;
friend class StreamsTrigger;
@ -229,6 +236,7 @@ private:
friend class StreamsTimer;
friend class AttachChannelsEvent;
friend class DetachChannelsEvent;
friend class MigPrimarySurfaceTimer;
};
#endif